Skip to content

Commit 0651d7b

Browse files
authored
GO: Implement Copy Command (valkey-io#2980)
* Implement Copy Command Signed-off-by: EdricCua <[email protected]>
1 parent 46d3d26 commit 0651d7b

File tree

4 files changed

+163
-0
lines changed

4 files changed

+163
-0
lines changed

go/api/base_client.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3492,3 +3492,82 @@ func (client *baseClient) XClaimJustIdWithOptions(
34923492
}
34933493
return handleStringArrayResponse(result)
34943494
}
3495+
3496+
// Copies the value stored at the source to the destination key if the
3497+
// destination key does not yet exist.
3498+
//
3499+
// Note:
3500+
//
3501+
// When in cluster mode, both source and destination must map to the same hash slot.
3502+
//
3503+
// Parameters:
3504+
//
3505+
// source - The key to the source value.
3506+
// destination - The key where the value should be copied to.
3507+
//
3508+
// Return value:
3509+
//
3510+
// `true` if source was copied, `false` if source was not copied.
3511+
//
3512+
// Example:
3513+
//
3514+
// result, err := client.Copy("source, destination")
3515+
// if err != nil {
3516+
// // handle error
3517+
// }
3518+
// fmt.Println(result) // Output: true
3519+
//
3520+
// [valkey.io]: https://valkey.io/commands/copy/
3521+
func (client *baseClient) Copy(source string, destination string) (bool, error) {
3522+
result, err := client.executeCommand(C.Copy, []string{source, destination})
3523+
if err != nil {
3524+
return defaultBoolResponse, err
3525+
}
3526+
return handleBoolResponse(result)
3527+
}
3528+
3529+
// Copies the value stored at the source to the destination key. When
3530+
// replace is true, removes the destination key first if it already
3531+
// exists, otherwise performs no action.
3532+
//
3533+
// Note:
3534+
//
3535+
// When in cluster mode, both source and destination must map to the same hash slot.
3536+
//
3537+
// Parameters:
3538+
//
3539+
// source - The key to the source value.
3540+
// destination - The key where the value should be copied to.
3541+
// copyOptions - Set copy options with replace and DB destination-db
3542+
//
3543+
// Return value:
3544+
//
3545+
// `true` if source was copied, `false` if source was not copied.
3546+
//
3547+
// Example:
3548+
//
3549+
// copyOptions := api.NewCopyOptionsBuilder().SetDBDestination(2).SetReplace()
3550+
// result, err := client.CopyWithOptions(source, destination",copyOptions)
3551+
// if err != nil {
3552+
// // handle error
3553+
// }
3554+
// fmt.Println(result) // Output: true
3555+
//
3556+
// [valkey.io]: https://valkey.io/commands/copy/
3557+
func (client *baseClient) CopyWithOptions(
3558+
source string,
3559+
destination string,
3560+
options *CopyOptions,
3561+
) (bool, error) {
3562+
optionArgs, err := options.toArgs()
3563+
if err != nil {
3564+
return defaultBoolResponse, err
3565+
}
3566+
result, err := client.executeCommand(C.Copy, append([]string{
3567+
source, destination,
3568+
}, optionArgs...))
3569+
if err != nil {
3570+
return defaultBoolResponse, err
3571+
}
3572+
return handleBoolResponse(result)
3573+
}

go/api/command_options.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,3 +355,41 @@ func (opts *RestoreOptions) toArgs() ([]string, error) {
355355
}
356356
return args, err
357357
}
358+
359+
// Optional arguments to Copy(source string, destination string, option *CopyOptions)
360+
//
361+
// [valkey.io]: https://valkey.io/commands/Copy/
362+
type CopyOptions struct {
363+
// The REPLACE option removes the destination key before copying the value to it.
364+
replace bool
365+
// Option allows specifying an alternative logical database index for the destination key
366+
dbDestination int64
367+
}
368+
369+
func NewCopyOptionsBuilder() *CopyOptions {
370+
return &CopyOptions{replace: false}
371+
}
372+
373+
// Custom setter methods to removes the destination key before copying the value to it.
374+
func (restoreOption *CopyOptions) SetReplace() *CopyOptions {
375+
restoreOption.replace = true
376+
return restoreOption
377+
}
378+
379+
// Custom setter methods to allows specifying an alternative logical database index for the destination key.
380+
func (copyOption *CopyOptions) SetDBDestination(destinationDB int64) *CopyOptions {
381+
copyOption.dbDestination = destinationDB
382+
return copyOption
383+
}
384+
385+
func (opts *CopyOptions) toArgs() ([]string, error) {
386+
args := []string{}
387+
var err error
388+
if opts.replace {
389+
args = append(args, string("REPLACE"))
390+
}
391+
if opts.dbDestination >= 0 {
392+
args = append(args, "DB", utils.IntToString(opts.dbDestination))
393+
}
394+
return args, err
395+
}

go/api/generic_base_commands.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -705,4 +705,8 @@ type GenericBaseCommands interface {
705705
SortReadOnlyWithOptions(key string, sortOptions *options.SortOptions) ([]Result[string], error)
706706

707707
Wait(numberOfReplicas int64, timeout int64) (int64, error)
708+
709+
Copy(source string, destination string) (bool, error)
710+
711+
CopyWithOptions(source string, destination string, option *CopyOptions) (bool, error)
708712
}

go/integTest/shared_commands_test.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7210,3 +7210,45 @@ func (suite *GlideTestSuite) TestXClaimFailure() {
72107210
assert.IsType(suite.T(), &api.RequestError{}, err)
72117211
})
72127212
}
7213+
7214+
func (suite *GlideTestSuite) TestCopy() {
7215+
suite.runWithDefaultClients(func(client api.BaseClient) {
7216+
key := "{key}" + uuid.New().String()
7217+
key2 := "{key}" + uuid.New().String()
7218+
value := "hello"
7219+
t := suite.T()
7220+
suite.verifyOK(client.Set(key, value))
7221+
7222+
// Test 1: Check the copy command
7223+
resultCopy, err := client.Copy(key, key2)
7224+
assert.Nil(t, err)
7225+
assert.True(t, resultCopy)
7226+
7227+
// Test 2: Check if the value stored at the source is same with destination key.
7228+
resultGet, err := client.Get(key2)
7229+
assert.Nil(t, err)
7230+
assert.Equal(t, value, resultGet.Value())
7231+
})
7232+
}
7233+
7234+
func (suite *GlideTestSuite) TestCopyWithOptions() {
7235+
suite.runWithDefaultClients(func(client api.BaseClient) {
7236+
key := "{key}" + uuid.New().String()
7237+
key2 := "{key}" + uuid.New().String()
7238+
value := "hello"
7239+
t := suite.T()
7240+
suite.verifyOK(client.Set(key, value))
7241+
suite.verifyOK(client.Set(key2, "World"))
7242+
7243+
// Test 1: Check the copy command with options
7244+
optsCopy := api.NewCopyOptionsBuilder().SetReplace()
7245+
resultCopy, err := client.CopyWithOptions(key, key2, optsCopy)
7246+
assert.Nil(t, err)
7247+
assert.True(t, resultCopy)
7248+
7249+
// Test 2: Check if the value stored at the source is same with destination key.
7250+
resultGet, err := client.Get(key2)
7251+
assert.Nil(t, err)
7252+
assert.Equal(t, value, resultGet.Value())
7253+
})
7254+
}

0 commit comments

Comments
 (0)