From dcc0e4d9a48ff60a25c119553d7463a3087360b2 Mon Sep 17 00:00:00 2001 From: EdricCua Date: Mon, 25 Nov 2024 18:31:04 +0000 Subject: [PATCH 01/12] Go: Implement Type, Touch and Unlink command Signed-off-by: EdricCua --- go/api/base_client.go | 26 ++++++++++++ go/api/generic_commands.go | 61 ++++++++++++++++++++++++++++ go/integTest/shared_commands_test.go | 54 ++++++++++++++++++++++++ 3 files changed, 141 insertions(+) diff --git a/go/api/base_client.go b/go/api/base_client.go index 7358dd5faf..11cfe5fae7 100644 --- a/go/api/base_client.go +++ b/go/api/base_client.go @@ -1102,3 +1102,29 @@ func (client *baseClient) PTTL(key string) (Result[int64], error) { return handleLongResponse(result) } + +func (client *baseClient) Unlink(keys []string) (Result[int64], error) { + result, err := client.executeCommand(C.Unlink, keys) + if err != nil { + return CreateNilInt64Result(), err + } + + return handleLongResponse(result) +} + +func (client *baseClient) Type(key string) (Result[string], error) { + result, err := client.executeCommand(C.Type, []string{key}) + if err != nil { + return CreateNilStringResult(), err + } + return handleStringOrNullResponse(result) +} + +func (client *baseClient) Touch(keys []string) (Result[int64], error) { + result, err := client.executeCommand(C.Touch, keys) + if err != nil { + return CreateNilInt64Result(), err + } + + return handleLongResponse(result) +} diff --git a/go/api/generic_commands.go b/go/api/generic_commands.go index 090442ec68..633d80381c 100644 --- a/go/api/generic_commands.go +++ b/go/api/generic_commands.go @@ -313,4 +313,65 @@ type GenericBaseCommands interface { // // [valkey.io]: https://valkey.io/commands/pttl/ PTTL(key string) (Result[int64], error) + + // Unlink (delete) multiple keys from the database. A key is ignored if it does not exist. + // This command, similar to Del However, this command does not block the server + // Note: + // + // Parameters: + // keys - One or more keys to unlink. + // + // Return value: + // Return the number of keys that were unlinked. + // + // Example: + // result, err := client.Unlink([]string{"key1", "key2", "key3"}) + // if err != nil { + // // handle error + // } + // fmt.Println(result) // Output: int + // + // [valkey.io]: Https://valkey.io/commands/touch/ + Unlink(keys []string) (Result[int64], error) + + // Alters the last access time of a key(s). A key is ignored if it does not exist. + // + // Note: + // + // Parameters: + // keys - One or more keys to touch. + // + // Return value: + // Returns the number of keys that were touched. + // + // Example: + // result, err := client.Touch([]string{"key1", "key2", "key3"}) + // if err != nil { + // // handle error + // } + // fmt.Println(result) // Output: int + // + // [valkey.io]: Https://valkey.io/commands/touch/ + Touch(keys []string) (Result[int64], error) + + // Type returns the string representation of the type of the value stored at key. + // The different types that can be returned are: string, list, set, zset, hash and stream. + // + // Note: + // + // Parameters: + // keys - string + // + // Return value: + // Return the type of the stored value iun sting representation . + // + // Example: + // result, err := client.Type([]string{"key"}) + // if err != nil { + // // handle error + // } + // fmt.Println(result) // Output: string + // + // [valkey.io]: Https://valkey.io/commands/type/ + Type(key string) (Result[string], error) } diff --git a/go/integTest/shared_commands_test.go b/go/integTest/shared_commands_test.go index fa79122354..b5149d9a8e 100644 --- a/go/integTest/shared_commands_test.go +++ b/go/integTest/shared_commands_test.go @@ -3241,3 +3241,57 @@ func (suite *GlideTestSuite) TestPTTL_WithExpiredKey() { assert.Equal(suite.T(), int64(-2), resPTTL.Value()) }) } + +func (suite *GlideTestSuite) TestType() { + suite.runWithDefaultClients(func(client api.BaseClient) { + // Test 1: Check if the value is string + suite.verifyOK(client.Set(keyName, initialValue)) + result, err := client.Type(keyName) + assert.Nil(suite.T(), err) + assert.IsType(suite.T(), result, api.CreateStringResult("string"), "Value is string") + + //Test 2: Check if the value is list + key1 := "{key}-1" + uuid.NewString() + resultLPush, err := client.LPush(key1, []string{"one", "two", "three"}) + assert.Equal(suite.T(), int64(3), resultLPush.Value()) + assert.Nil(suite.T(), err) + resultType, err := client.Type(key1) + assert.Nil(suite.T(), err) + assert.IsType(suite.T(), resultType, api.CreateStringResult("list"), "Value is list") + + }) +} + +func (suite *GlideTestSuite) TestTouch() { + suite.runWithDefaultClients(func(client api.BaseClient) { + // Test 1: Check if an touch valid key + suite.verifyOK(client.Set(keyName, initialValue)) + suite.verifyOK(client.Set("anotherKey", "anotherValue")) + result, err := client.Touch([]string{keyName, "anotherKey"}) + assert.Nil(suite.T(), err) + assert.Equal(suite.T(), int64(2), result.Value(), "The touch should be 2") + + // Test 1: Check if an touch invalid key + resultInvalidKey, err := client.Touch([]string{"invalidKey", "invalidKey1"}) + assert.Nil(suite.T(), err) + assert.Equal(suite.T(), int64(0), resultInvalidKey.Value(), "The touch should be 0") + + }) +} + +func (suite *GlideTestSuite) TestUnlink() { + suite.runWithDefaultClients(func(client api.BaseClient) { + // Test 1: Check if an unlink valid key + suite.verifyOK(client.Set(keyName, initialValue)) + suite.verifyOK(client.Set("anotherKey", "anotherValue")) + resultValidKey, err := client.Unlink([]string{keyName, "anotherKey"}) + assert.Nil(suite.T(), err) + assert.Equal(suite.T(), int64(2), resultValidKey.Value(), "The unlink should be 2") + + // Test 2: Check if an unlink for invalid key + resultInvalidKey, err := client.Unlink([]string{"invalidKey2", "invalidKey3"}) + assert.Nil(suite.T(), err) + assert.Equal(suite.T(), int64(0), resultInvalidKey.Value(), "The unlink should be 0") + + }) +} From c30630973224506c1ff0a1d244c8767826eb26dc Mon Sep 17 00:00:00 2001 From: EdricCua Date: Tue, 26 Nov 2024 08:56:32 +0000 Subject: [PATCH 02/12] Fix documentation and unit test Signed-off-by: EdricCua --- go/api/generic_commands.go | 12 ++- go/integTest/shared_commands_test.go | 151 +++------------------------ 2 files changed, 22 insertions(+), 141 deletions(-) diff --git a/go/api/generic_commands.go b/go/api/generic_commands.go index 633d80381c..0585e4cebe 100644 --- a/go/api/generic_commands.go +++ b/go/api/generic_commands.go @@ -316,7 +316,9 @@ type GenericBaseCommands interface { // Unlink (delete) multiple keys from the database. A key is ignored if it does not exist. // This command, similar to Del However, this command does not block the server + // // Note: + // When in cluster mode, the command may route to multiple nodes when keys map to different hash slots. // // Parameters: // keys - One or more keys to unlink. @@ -331,18 +333,19 @@ type GenericBaseCommands interface { // } // fmt.Println(result) // Output: int // - // [valkey.io]: Https://valkey.io/commands/touch/ + // [valkey.io]: Https://valkey.io/commands/unlink/ Unlink(keys []string) (Result[int64], error) // Alters the last access time of a key(s). A key is ignored if it does not exist. // // Note: + // When in cluster mode, the command may route to multiple nodes when `keys` map to different hash slots. // // Parameters: - // keys - One or more keys to touch. + // The keys to update last access time. // // Return value: - // Returns the number of keys that were touched. + // The number of keys that were updated. // // Example: // result, err := client.Touch([]string{"key1", "key2", "key3"}) @@ -358,12 +361,13 @@ type GenericBaseCommands interface { // The different types that can be returned are: string, list, set, zset, hash and stream. // // Note: + // When in cluster mode, the command may route to multiple nodes when `keys` map to different hash slots. // // Parameters: // keys - string // // Return value: - // Return the type of the stored value iun sting representation . + // If the key exists, the type of the stored value is returned. Otherwise, a none" string is returned. // // Example: // result, err := client.Type([]string{"key"}) diff --git a/go/integTest/shared_commands_test.go b/go/integTest/shared_commands_test.go index b5149d9a8e..a481f8e4c9 100644 --- a/go/integTest/shared_commands_test.go +++ b/go/integTest/shared_commands_test.go @@ -2468,137 +2468,6 @@ func (suite *GlideTestSuite) TestLMove() { }) } -func (suite *GlideTestSuite) TestBLMove() { - if suite.serverVersion < "6.2.0" { - suite.T().Skip("This feature is added in version 6.2.0") - } - suite.runWithDefaultClients(func(client api.BaseClient) { - key1 := "{key}-1" + uuid.NewString() - key2 := "{key}-2" + uuid.NewString() - nonExistentKey := "{key}-3" + uuid.NewString() - nonListKey := "{key}-4" + uuid.NewString() - - res1, err := client.BLMove(key1, key2, api.Left, api.Right, float64(0.1)) - assert.Equal(suite.T(), api.CreateNilStringResult(), res1) - assert.Nil(suite.T(), err) - - res2, err := client.LPush(key1, []string{"four", "three", "two", "one"}) - assert.Nil(suite.T(), err) - assert.Equal(suite.T(), int64(4), res2.Value()) - - // only source exists, only source elements gets popped, creates a list at nonExistingKey - res3, err := client.BLMove(key1, nonExistentKey, api.Right, api.Left, float64(0.1)) - assert.Equal(suite.T(), "four", res3.Value()) - assert.Nil(suite.T(), err) - - res4, err := client.LRange(key1, int64(0), int64(-1)) - assert.Nil(suite.T(), err) - assert.Equal( - suite.T(), - []api.Result[string]{ - api.CreateStringResult("one"), - api.CreateStringResult("two"), - api.CreateStringResult("three"), - }, - res4, - ) - - // source and destination are the same, performing list rotation, "one" gets popped and added back - res5, err := client.BLMove(key1, key1, api.Left, api.Left, float64(0.1)) - assert.Equal(suite.T(), "one", res5.Value()) - assert.Nil(suite.T(), err) - - res6, err := client.LRange(key1, int64(0), int64(-1)) - assert.Nil(suite.T(), err) - assert.Equal( - suite.T(), - []api.Result[string]{ - api.CreateStringResult("one"), - api.CreateStringResult("two"), - api.CreateStringResult("three"), - }, - res6, - ) - // normal use case, "three" gets popped and added to the left of destination - res7, err := client.LPush(key2, []string{"six", "five", "four"}) - assert.Nil(suite.T(), err) - assert.Equal(suite.T(), int64(3), res7.Value()) - - res8, err := client.BLMove(key1, key2, api.Right, api.Left, float64(0.1)) - assert.Equal(suite.T(), "three", res8.Value()) - assert.Nil(suite.T(), err) - - res9, err := client.LRange(key1, int64(0), int64(-1)) - assert.Nil(suite.T(), err) - assert.Equal( - suite.T(), - []api.Result[string]{ - api.CreateStringResult("one"), - api.CreateStringResult("two"), - }, - res9, - ) - res10, err := client.LRange(key2, int64(0), int64(-1)) - assert.Nil(suite.T(), err) - assert.Equal( - suite.T(), - []api.Result[string]{ - api.CreateStringResult("three"), - api.CreateStringResult("four"), - api.CreateStringResult("five"), - api.CreateStringResult("six"), - }, - res10, - ) - - // source exists but is not a list type key - suite.verifyOK(client.Set(nonListKey, "value")) - - res11, err := client.BLMove(nonListKey, key1, api.Left, api.Left, float64(0.1)) - assert.Equal(suite.T(), api.CreateNilStringResult(), res11) - assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) - - // destination exists but is not a list type key - suite.verifyOK(client.Set(nonListKey, "value")) - - res12, err := client.BLMove(key1, nonListKey, api.Left, api.Left, float64(0.1)) - assert.Equal(suite.T(), api.CreateNilStringResult(), res12) - assert.NotNil(suite.T(), err) - assert.IsType(suite.T(), &api.RequestError{}, err) - }) -} - -func (suite *GlideTestSuite) TestDel_MultipleKeys() { - suite.runWithDefaultClients(func(client api.BaseClient) { - key1 := "testKey1_" + uuid.New().String() - key2 := "testKey2_" + uuid.New().String() - key3 := "testKey3_" + uuid.New().String() - - suite.verifyOK(client.Set(key1, initialValue)) - suite.verifyOK(client.Set(key2, initialValue)) - suite.verifyOK(client.Set(key3, initialValue)) - - deletedCount, err := client.Del([]string{key1, key2, key3}) - - assert.Nil(suite.T(), err) - assert.Equal(suite.T(), int64(3), deletedCount.Value()) - - result1, err1 := client.Get(key1) - result2, err2 := client.Get(key2) - result3, err3 := client.Get(key3) - - assert.Nil(suite.T(), err1) - assert.True(suite.T(), result1.IsNil()) - - assert.Nil(suite.T(), err2) - assert.True(suite.T(), result2.IsNil()) - - assert.Nil(suite.T(), err3) - assert.True(suite.T(), result3.IsNil()) - }) -} - func (suite *GlideTestSuite) TestExists() { suite.runWithDefaultClients(func(client api.BaseClient) { key := uuid.New().String() @@ -3245,13 +3114,14 @@ func (suite *GlideTestSuite) TestPTTL_WithExpiredKey() { func (suite *GlideTestSuite) TestType() { suite.runWithDefaultClients(func(client api.BaseClient) { // Test 1: Check if the value is string + keyName := "{keyName}" + uuid.NewString() suite.verifyOK(client.Set(keyName, initialValue)) result, err := client.Type(keyName) assert.Nil(suite.T(), err) assert.IsType(suite.T(), result, api.CreateStringResult("string"), "Value is string") //Test 2: Check if the value is list - key1 := "{key}-1" + uuid.NewString() + key1 := "{keylist}-1" + uuid.NewString() resultLPush, err := client.LPush(key1, []string{"one", "two", "three"}) assert.Equal(suite.T(), int64(3), resultLPush.Value()) assert.Nil(suite.T(), err) @@ -3260,14 +3130,17 @@ func (suite *GlideTestSuite) TestType() { assert.IsType(suite.T(), resultType, api.CreateStringResult("list"), "Value is list") }) + } func (suite *GlideTestSuite) TestTouch() { suite.runWithDefaultClients(func(client api.BaseClient) { // Test 1: Check if an touch valid key + keyName := "{keyName}" + uuid.NewString() + keyName1 := "{keyName1}" + uuid.NewString() suite.verifyOK(client.Set(keyName, initialValue)) - suite.verifyOK(client.Set("anotherKey", "anotherValue")) - result, err := client.Touch([]string{keyName, "anotherKey"}) + suite.verifyOK(client.Set(keyName1, "anotherValue")) + result, err := client.Touch([]string{keyName, keyName1}) assert.Nil(suite.T(), err) assert.Equal(suite.T(), int64(2), result.Value(), "The touch should be 2") @@ -3277,14 +3150,18 @@ func (suite *GlideTestSuite) TestTouch() { assert.Equal(suite.T(), int64(0), resultInvalidKey.Value(), "The touch should be 0") }) + } func (suite *GlideTestSuite) TestUnlink() { suite.runWithDefaultClients(func(client api.BaseClient) { + // Test 1: Check if an unlink valid key + keyName := "{keyName}" + uuid.NewString() + keyName1 := "{keyName1}" + uuid.NewString() suite.verifyOK(client.Set(keyName, initialValue)) - suite.verifyOK(client.Set("anotherKey", "anotherValue")) - resultValidKey, err := client.Unlink([]string{keyName, "anotherKey"}) + suite.verifyOK(client.Set(keyName1, "anotherValue")) + resultValidKey, err := client.Unlink([]string{keyName, keyName1}) assert.Nil(suite.T(), err) assert.Equal(suite.T(), int64(2), resultValidKey.Value(), "The unlink should be 2") @@ -3292,6 +3169,6 @@ func (suite *GlideTestSuite) TestUnlink() { resultInvalidKey, err := client.Unlink([]string{"invalidKey2", "invalidKey3"}) assert.Nil(suite.T(), err) assert.Equal(suite.T(), int64(0), resultInvalidKey.Value(), "The unlink should be 0") - }) + } From e408c613792c83827fe1a96628431d393ce88370 Mon Sep 17 00:00:00 2001 From: EdricCua Date: Tue, 26 Nov 2024 09:54:10 +0000 Subject: [PATCH 03/12] Bring back the TestDel_MultipleKeys and TestBlMove Signed-off-by: EdricCua --- go/integTest/shared_commands_test.go | 131 +++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) diff --git a/go/integTest/shared_commands_test.go b/go/integTest/shared_commands_test.go index a481f8e4c9..4c89d0d426 100644 --- a/go/integTest/shared_commands_test.go +++ b/go/integTest/shared_commands_test.go @@ -3111,6 +3111,137 @@ func (suite *GlideTestSuite) TestPTTL_WithExpiredKey() { }) } +func (suite *GlideTestSuite) TestBLMove() { + if suite.serverVersion < "6.2.0" { + suite.T().Skip("This feature is added in version 6.2.0") + } + suite.runWithDefaultClients(func(client api.BaseClient) { + key1 := "{key}-1" + uuid.NewString() + key2 := "{key}-2" + uuid.NewString() + nonExistentKey := "{key}-3" + uuid.NewString() + nonListKey := "{key}-4" + uuid.NewString() + + res1, err := client.BLMove(key1, key2, api.Left, api.Right, float64(0.1)) + assert.Equal(suite.T(), api.CreateNilStringResult(), res1) + assert.Nil(suite.T(), err) + + res2, err := client.LPush(key1, []string{"four", "three", "two", "one"}) + assert.Nil(suite.T(), err) + assert.Equal(suite.T(), int64(4), res2.Value()) + + // only source exists, only source elements gets popped, creates a list at nonExistingKey + res3, err := client.BLMove(key1, nonExistentKey, api.Right, api.Left, float64(0.1)) + assert.Equal(suite.T(), "four", res3.Value()) + assert.Nil(suite.T(), err) + + res4, err := client.LRange(key1, int64(0), int64(-1)) + assert.Nil(suite.T(), err) + assert.Equal( + suite.T(), + []api.Result[string]{ + api.CreateStringResult("one"), + api.CreateStringResult("two"), + api.CreateStringResult("three"), + }, + res4, + ) + + // source and destination are the same, performing list rotation, "one" gets popped and added back + res5, err := client.BLMove(key1, key1, api.Left, api.Left, float64(0.1)) + assert.Equal(suite.T(), "one", res5.Value()) + assert.Nil(suite.T(), err) + + res6, err := client.LRange(key1, int64(0), int64(-1)) + assert.Nil(suite.T(), err) + assert.Equal( + suite.T(), + []api.Result[string]{ + api.CreateStringResult("one"), + api.CreateStringResult("two"), + api.CreateStringResult("three"), + }, + res6, + ) + // normal use case, "three" gets popped and added to the left of destination + res7, err := client.LPush(key2, []string{"six", "five", "four"}) + assert.Nil(suite.T(), err) + assert.Equal(suite.T(), int64(3), res7.Value()) + + res8, err := client.BLMove(key1, key2, api.Right, api.Left, float64(0.1)) + assert.Equal(suite.T(), "three", res8.Value()) + assert.Nil(suite.T(), err) + + res9, err := client.LRange(key1, int64(0), int64(-1)) + assert.Nil(suite.T(), err) + assert.Equal( + suite.T(), + []api.Result[string]{ + api.CreateStringResult("one"), + api.CreateStringResult("two"), + }, + res9, + ) + res10, err := client.LRange(key2, int64(0), int64(-1)) + assert.Nil(suite.T(), err) + assert.Equal( + suite.T(), + []api.Result[string]{ + api.CreateStringResult("three"), + api.CreateStringResult("four"), + api.CreateStringResult("five"), + api.CreateStringResult("six"), + }, + res10, + ) + + // source exists but is not a list type key + suite.verifyOK(client.Set(nonListKey, "value")) + + res11, err := client.BLMove(nonListKey, key1, api.Left, api.Left, float64(0.1)) + assert.Equal(suite.T(), api.CreateNilStringResult(), res11) + assert.NotNil(suite.T(), err) + assert.IsType(suite.T(), &api.RequestError{}, err) + + // destination exists but is not a list type key + suite.verifyOK(client.Set(nonListKey, "value")) + + res12, err := client.BLMove(key1, nonListKey, api.Left, api.Left, float64(0.1)) + assert.Equal(suite.T(), api.CreateNilStringResult(), res12) + assert.NotNil(suite.T(), err) + assert.IsType(suite.T(), &api.RequestError{}, err) + }) +} + +func (suite *GlideTestSuite) TestDel_MultipleKeys() { + suite.runWithDefaultClients(func(client api.BaseClient) { + key1 := "testKey1_" + uuid.New().String() + key2 := "testKey2_" + uuid.New().String() + key3 := "testKey3_" + uuid.New().String() + + suite.verifyOK(client.Set(key1, initialValue)) + suite.verifyOK(client.Set(key2, initialValue)) + suite.verifyOK(client.Set(key3, initialValue)) + + deletedCount, err := client.Del([]string{key1, key2, key3}) + + assert.Nil(suite.T(), err) + assert.Equal(suite.T(), int64(3), deletedCount.Value()) + + result1, err1 := client.Get(key1) + result2, err2 := client.Get(key2) + result3, err3 := client.Get(key3) + + assert.Nil(suite.T(), err1) + assert.True(suite.T(), result1.IsNil()) + + assert.Nil(suite.T(), err2) + assert.True(suite.T(), result2.IsNil()) + + assert.Nil(suite.T(), err3) + assert.True(suite.T(), result3.IsNil()) + }) +} + func (suite *GlideTestSuite) TestType() { suite.runWithDefaultClients(func(client api.BaseClient) { // Test 1: Check if the value is string From 7ecc5898e6e32af2cabf882e2ed705b3de9f43ee Mon Sep 17 00:00:00 2001 From: EdricCua Date: Wed, 27 Nov 2024 09:44:48 +0000 Subject: [PATCH 04/12] Touch, Type, Unlink corrected doc comment Signed-off-by: EdricCua --- go/api/generic_commands.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/go/api/generic_commands.go b/go/api/generic_commands.go index 0585e4cebe..167df8da15 100644 --- a/go/api/generic_commands.go +++ b/go/api/generic_commands.go @@ -331,7 +331,7 @@ type GenericBaseCommands interface { // if err != nil { // // handle error // } - // fmt.Println(result) // Output: int + // fmt.Println(result.Value()) // Output: int // // [valkey.io]: Https://valkey.io/commands/unlink/ Unlink(keys []string) (Result[int64], error) @@ -352,7 +352,7 @@ type GenericBaseCommands interface { // if err != nil { // // handle error // } - // fmt.Println(result) // Output: int + // fmt.Println(result.Value()) // Output: int // // [valkey.io]: Https://valkey.io/commands/touch/ Touch(keys []string) (Result[int64], error) @@ -374,7 +374,7 @@ type GenericBaseCommands interface { // if err != nil { // // handle error // } - // fmt.Println(result) // Output: string + // fmt.Println(result.Value()) // Output: string // // [valkey.io]: Https://valkey.io/commands/type/ Type(key string) (Result[string], error) From f83e00cfda7756d97a0d20b80f594871315b9e47 Mon Sep 17 00:00:00 2001 From: EdricCua Date: Thu, 28 Nov 2024 06:39:15 +0000 Subject: [PATCH 05/12] Notice change adjustment based on #2587 for Touch, Unlink, Type. Signed-off-by: EdricCua --- go/api/generic_commands.go | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/go/api/generic_commands.go b/go/api/generic_commands.go index 167df8da15..b5ba6b7fd6 100644 --- a/go/api/generic_commands.go +++ b/go/api/generic_commands.go @@ -318,7 +318,12 @@ type GenericBaseCommands interface { // This command, similar to Del However, this command does not block the server // // Note: - // When in cluster mode, the command may route to multiple nodes when keys map to different hash slots. + // In cluster mode, if keys in keys map to different hash slots, the command + // will be split across these slots and executed separately for each. This means the command + // is atomic only at the slot level. If one or more slot-specific requests fail, the entire + // call will return the first encountered error, even though some requests may have succeeded + // while others did not. If this behavior impacts your application logic, consider splitting + // the request into sub-requests per slot to ensure atomicity. // // Parameters: // keys - One or more keys to unlink. @@ -339,7 +344,12 @@ type GenericBaseCommands interface { // Alters the last access time of a key(s). A key is ignored if it does not exist. // // Note: - // When in cluster mode, the command may route to multiple nodes when `keys` map to different hash slots. + // In cluster mode, if keys in keys map to different hash slots, the command + // will be split across these slots and executed separately for each. This means the command + // is atomic only at the slot level. If one or more slot-specific requests fail, the entire + // call will return the first encountered error, even though some requests may have succeeded + // while others did not. If this behavior impacts your application logic, consider splitting + // the request into sub-requests per slot to ensure atomicity. // // Parameters: // The keys to update last access time. @@ -360,9 +370,6 @@ type GenericBaseCommands interface { // Type returns the string representation of the type of the value stored at key. // The different types that can be returned are: string, list, set, zset, hash and stream. // - // Note: - // When in cluster mode, the command may route to multiple nodes when `keys` map to different hash slots. - // // Parameters: // keys - string // From 0a1b42a6c7c52e127b14175fd1222f572181b92b Mon Sep 17 00:00:00 2001 From: EdricCua Date: Mon, 9 Dec 2024 11:52:59 +0000 Subject: [PATCH 06/12] Remove empty line Signed-off-by: EdricCua --- go/integTest/shared_commands_test.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/go/integTest/shared_commands_test.go b/go/integTest/shared_commands_test.go index 4c89d0d426..a414f1f8ab 100644 --- a/go/integTest/shared_commands_test.go +++ b/go/integTest/shared_commands_test.go @@ -3259,9 +3259,7 @@ func (suite *GlideTestSuite) TestType() { resultType, err := client.Type(key1) assert.Nil(suite.T(), err) assert.IsType(suite.T(), resultType, api.CreateStringResult("list"), "Value is list") - }) - } func (suite *GlideTestSuite) TestTouch() { @@ -3279,14 +3277,11 @@ func (suite *GlideTestSuite) TestTouch() { resultInvalidKey, err := client.Touch([]string{"invalidKey", "invalidKey1"}) assert.Nil(suite.T(), err) assert.Equal(suite.T(), int64(0), resultInvalidKey.Value(), "The touch should be 0") - }) - } func (suite *GlideTestSuite) TestUnlink() { suite.runWithDefaultClients(func(client api.BaseClient) { - // Test 1: Check if an unlink valid key keyName := "{keyName}" + uuid.NewString() keyName1 := "{keyName1}" + uuid.NewString() @@ -3301,5 +3296,4 @@ func (suite *GlideTestSuite) TestUnlink() { assert.Nil(suite.T(), err) assert.Equal(suite.T(), int64(0), resultInvalidKey.Value(), "The unlink should be 0") }) - } From 6fc4ab5c670dcbdcacce6e1d07297e23ca9759d3 Mon Sep 17 00:00:00 2001 From: EdricCua Date: Mon, 9 Dec 2024 11:59:08 +0000 Subject: [PATCH 07/12] Corrected keys into key in comment Signed-off-by: EdricCua --- go/api/generic_commands.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go/api/generic_commands.go b/go/api/generic_commands.go index b5ba6b7fd6..54c2208f63 100644 --- a/go/api/generic_commands.go +++ b/go/api/generic_commands.go @@ -371,7 +371,7 @@ type GenericBaseCommands interface { // The different types that can be returned are: string, list, set, zset, hash and stream. // // Parameters: - // keys - string + // key - string // // Return value: // If the key exists, the type of the stored value is returned. Otherwise, a none" string is returned. From 7aeb919948b8421f96819e2ede6a7c11fa1f05bc Mon Sep 17 00:00:00 2001 From: EdricCua Date: Mon, 16 Dec 2024 03:21:04 +0000 Subject: [PATCH 08/12] Fix test file formatting Signed-off-by: EdricCua --- go/integTest/shared_commands_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/go/integTest/shared_commands_test.go b/go/integTest/shared_commands_test.go index a414f1f8ab..6ad2f4fb85 100644 --- a/go/integTest/shared_commands_test.go +++ b/go/integTest/shared_commands_test.go @@ -3251,7 +3251,7 @@ func (suite *GlideTestSuite) TestType() { assert.Nil(suite.T(), err) assert.IsType(suite.T(), result, api.CreateStringResult("string"), "Value is string") - //Test 2: Check if the value is list + // Test 2: Check if the value is list key1 := "{keylist}-1" + uuid.NewString() resultLPush, err := client.LPush(key1, []string{"one", "two", "three"}) assert.Equal(suite.T(), int64(3), resultLPush.Value()) @@ -3273,7 +3273,7 @@ func (suite *GlideTestSuite) TestTouch() { assert.Nil(suite.T(), err) assert.Equal(suite.T(), int64(2), result.Value(), "The touch should be 2") - // Test 1: Check if an touch invalid key + // Test 2: Check if an touch invalid key resultInvalidKey, err := client.Touch([]string{"invalidKey", "invalidKey1"}) assert.Nil(suite.T(), err) assert.Equal(suite.T(), int64(0), resultInvalidKey.Value(), "The touch should be 0") From a292bd05def3eacb181456d9af5d81431b320a64 Mon Sep 17 00:00:00 2001 From: EdricCua Date: Mon, 16 Dec 2024 11:04:22 +0000 Subject: [PATCH 09/12] Fix formatting Signed-off-by: EdricCua --- go/integTest/shared_commands_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/go/integTest/shared_commands_test.go b/go/integTest/shared_commands_test.go index 46e4c86133..176c288b24 100644 --- a/go/integTest/shared_commands_test.go +++ b/go/integTest/shared_commands_test.go @@ -3458,7 +3458,7 @@ func (suite *GlideTestSuite) TestType() { assert.Nil(suite.T(), err) assert.IsType(suite.T(), result, api.CreateStringResult("string"), "Value is string") - // Test 2: Check if the value is list + //Test 2: Check if the value is list key1 := "{keylist}-1" + uuid.NewString() resultLPush, err := client.LPush(key1, []string{"one", "two", "three"}) assert.Equal(suite.T(), int64(3), resultLPush.Value()) @@ -3480,7 +3480,7 @@ func (suite *GlideTestSuite) TestTouch() { assert.Nil(suite.T(), err) assert.Equal(suite.T(), int64(2), result.Value(), "The touch should be 2") - // Test 2: Check if an touch invalid key + // Test 1: Check if an touch invalid key resultInvalidKey, err := client.Touch([]string{"invalidKey", "invalidKey1"}) assert.Nil(suite.T(), err) assert.Equal(suite.T(), int64(0), resultInvalidKey.Value(), "The touch should be 0") From d52a7a99486fc40bbead4ff1a531d3a901a68c4a Mon Sep 17 00:00:00 2001 From: EdricCua Date: Mon, 16 Dec 2024 11:08:55 +0000 Subject: [PATCH 10/12] Fix test name Signed-off-by: EdricCua --- go/integTest/shared_commands_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go/integTest/shared_commands_test.go b/go/integTest/shared_commands_test.go index 176c288b24..451b6f9440 100644 --- a/go/integTest/shared_commands_test.go +++ b/go/integTest/shared_commands_test.go @@ -3480,7 +3480,7 @@ func (suite *GlideTestSuite) TestTouch() { assert.Nil(suite.T(), err) assert.Equal(suite.T(), int64(2), result.Value(), "The touch should be 2") - // Test 1: Check if an touch invalid key + // Test 2: Check if an touch invalid key resultInvalidKey, err := client.Touch([]string{"invalidKey", "invalidKey1"}) assert.Nil(suite.T(), err) assert.Equal(suite.T(), int64(0), resultInvalidKey.Value(), "The touch should be 0") From 4ed9040f49388d299acea1945785697e949f3392 Mon Sep 17 00:00:00 2001 From: EdricCua Date: Mon, 16 Dec 2024 17:58:40 +0000 Subject: [PATCH 11/12] Fix formatting Signed-off-by: EdricCua --- go/integTest/shared_commands_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go/integTest/shared_commands_test.go b/go/integTest/shared_commands_test.go index 451b6f9440..46e4c86133 100644 --- a/go/integTest/shared_commands_test.go +++ b/go/integTest/shared_commands_test.go @@ -3458,7 +3458,7 @@ func (suite *GlideTestSuite) TestType() { assert.Nil(suite.T(), err) assert.IsType(suite.T(), result, api.CreateStringResult("string"), "Value is string") - //Test 2: Check if the value is list + // Test 2: Check if the value is list key1 := "{keylist}-1" + uuid.NewString() resultLPush, err := client.LPush(key1, []string{"one", "two", "three"}) assert.Equal(suite.T(), int64(3), resultLPush.Value()) From de57a793fa15a516a89adeb7c1c95f450d8c6636 Mon Sep 17 00:00:00 2001 From: EdricCua Date: Tue, 17 Dec 2024 06:22:20 +0000 Subject: [PATCH 12/12] Fix documentation output Signed-off-by: EdricCua --- go/api/generic_commands.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/go/api/generic_commands.go b/go/api/generic_commands.go index 54c2208f63..5978ce0c25 100644 --- a/go/api/generic_commands.go +++ b/go/api/generic_commands.go @@ -336,7 +336,7 @@ type GenericBaseCommands interface { // if err != nil { // // handle error // } - // fmt.Println(result.Value()) // Output: int + // fmt.Println(result.Value()) // Output: 3 // // [valkey.io]: Https://valkey.io/commands/unlink/ Unlink(keys []string) (Result[int64], error) @@ -362,7 +362,7 @@ type GenericBaseCommands interface { // if err != nil { // // handle error // } - // fmt.Println(result.Value()) // Output: int + // fmt.Println(result.Value()) // Output: 3 // // [valkey.io]: Https://valkey.io/commands/touch/ Touch(keys []string) (Result[int64], error)