Skip to content

Commit

Permalink
GO: Implement Copy Command (valkey-io#2980)
Browse files Browse the repository at this point in the history
* Implement Copy Command

Signed-off-by: EdricCua <[email protected]>
  • Loading branch information
EdricCua authored Jan 23, 2025
1 parent 46d3d26 commit 0651d7b
Show file tree
Hide file tree
Showing 4 changed files with 163 additions and 0 deletions.
79 changes: 79 additions & 0 deletions go/api/base_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -3492,3 +3492,82 @@ func (client *baseClient) XClaimJustIdWithOptions(
}
return handleStringArrayResponse(result)
}

// Copies the value stored at the source to the destination key if the
// destination key does not yet exist.
//
// Note:
//
// When in cluster mode, both source and destination must map to the same hash slot.
//
// Parameters:
//
// source - The key to the source value.
// destination - The key where the value should be copied to.
//
// Return value:
//
// `true` if source was copied, `false` if source was not copied.
//
// Example:
//
// result, err := client.Copy("source, destination")
// if err != nil {
// // handle error
// }
// fmt.Println(result) // Output: true
//
// [valkey.io]: https://valkey.io/commands/copy/
func (client *baseClient) Copy(source string, destination string) (bool, error) {
result, err := client.executeCommand(C.Copy, []string{source, destination})
if err != nil {
return defaultBoolResponse, err
}
return handleBoolResponse(result)
}

// Copies the value stored at the source to the destination key. When
// replace is true, removes the destination key first if it already
// exists, otherwise performs no action.
//
// Note:
//
// When in cluster mode, both source and destination must map to the same hash slot.
//
// Parameters:
//
// source - The key to the source value.
// destination - The key where the value should be copied to.
// copyOptions - Set copy options with replace and DB destination-db
//
// Return value:
//
// `true` if source was copied, `false` if source was not copied.
//
// Example:
//
// copyOptions := api.NewCopyOptionsBuilder().SetDBDestination(2).SetReplace()
// result, err := client.CopyWithOptions(source, destination",copyOptions)
// if err != nil {
// // handle error
// }
// fmt.Println(result) // Output: true
//
// [valkey.io]: https://valkey.io/commands/copy/
func (client *baseClient) CopyWithOptions(
source string,
destination string,
options *CopyOptions,
) (bool, error) {
optionArgs, err := options.toArgs()
if err != nil {
return defaultBoolResponse, err
}
result, err := client.executeCommand(C.Copy, append([]string{
source, destination,
}, optionArgs...))
if err != nil {
return defaultBoolResponse, err
}
return handleBoolResponse(result)
}
38 changes: 38 additions & 0 deletions go/api/command_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -355,3 +355,41 @@ func (opts *RestoreOptions) toArgs() ([]string, error) {
}
return args, err
}

// Optional arguments to Copy(source string, destination string, option *CopyOptions)
//
// [valkey.io]: https://valkey.io/commands/Copy/
type CopyOptions struct {
// The REPLACE option removes the destination key before copying the value to it.
replace bool
// Option allows specifying an alternative logical database index for the destination key
dbDestination int64
}

func NewCopyOptionsBuilder() *CopyOptions {
return &CopyOptions{replace: false}
}

// Custom setter methods to removes the destination key before copying the value to it.
func (restoreOption *CopyOptions) SetReplace() *CopyOptions {
restoreOption.replace = true
return restoreOption
}

// Custom setter methods to allows specifying an alternative logical database index for the destination key.
func (copyOption *CopyOptions) SetDBDestination(destinationDB int64) *CopyOptions {
copyOption.dbDestination = destinationDB
return copyOption
}

func (opts *CopyOptions) toArgs() ([]string, error) {
args := []string{}
var err error
if opts.replace {
args = append(args, string("REPLACE"))
}
if opts.dbDestination >= 0 {
args = append(args, "DB", utils.IntToString(opts.dbDestination))
}
return args, err
}
4 changes: 4 additions & 0 deletions go/api/generic_base_commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -705,4 +705,8 @@ type GenericBaseCommands interface {
SortReadOnlyWithOptions(key string, sortOptions *options.SortOptions) ([]Result[string], error)

Wait(numberOfReplicas int64, timeout int64) (int64, error)

Copy(source string, destination string) (bool, error)

CopyWithOptions(source string, destination string, option *CopyOptions) (bool, error)
}
42 changes: 42 additions & 0 deletions go/integTest/shared_commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7210,3 +7210,45 @@ func (suite *GlideTestSuite) TestXClaimFailure() {
assert.IsType(suite.T(), &api.RequestError{}, err)
})
}

func (suite *GlideTestSuite) TestCopy() {
suite.runWithDefaultClients(func(client api.BaseClient) {
key := "{key}" + uuid.New().String()
key2 := "{key}" + uuid.New().String()
value := "hello"
t := suite.T()
suite.verifyOK(client.Set(key, value))

// Test 1: Check the copy command
resultCopy, err := client.Copy(key, key2)
assert.Nil(t, err)
assert.True(t, resultCopy)

// Test 2: Check if the value stored at the source is same with destination key.
resultGet, err := client.Get(key2)
assert.Nil(t, err)
assert.Equal(t, value, resultGet.Value())
})
}

func (suite *GlideTestSuite) TestCopyWithOptions() {
suite.runWithDefaultClients(func(client api.BaseClient) {
key := "{key}" + uuid.New().String()
key2 := "{key}" + uuid.New().String()
value := "hello"
t := suite.T()
suite.verifyOK(client.Set(key, value))
suite.verifyOK(client.Set(key2, "World"))

// Test 1: Check the copy command with options
optsCopy := api.NewCopyOptionsBuilder().SetReplace()
resultCopy, err := client.CopyWithOptions(key, key2, optsCopy)
assert.Nil(t, err)
assert.True(t, resultCopy)

// Test 2: Check if the value stored at the source is same with destination key.
resultGet, err := client.Get(key2)
assert.Nil(t, err)
assert.Equal(t, value, resultGet.Value())
})
}

0 comments on commit 0651d7b

Please sign in to comment.