mirror of
https://github.com/EchoVault/SugarDB.git
synced 2025-10-17 05:20:47 +08:00
Implementation of Copy command (#141)
* Added COPY command - @zenc0derr --------- Co-authored-by: Tejesh Kumar S <zenc0derr> Co-authored-by: Kelvin Clement Mwinuka <kelvinmwinuka@hotmail.co.uk>
This commit is contained in:
@@ -595,6 +595,7 @@ func handleIncrByFloat(params internal.HandlerFuncParams) ([]byte, error) {
|
|||||||
response := fmt.Sprintf("$%d\r\n%g\r\n", len(fmt.Sprintf("%g", newValue)), newValue)
|
response := fmt.Sprintf("$%d\r\n%g\r\n", len(fmt.Sprintf("%g", newValue)), newValue)
|
||||||
return []byte(response), nil
|
return []byte(response), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleDecrBy(params internal.HandlerFuncParams) ([]byte, error) {
|
func handleDecrBy(params internal.HandlerFuncParams) ([]byte, error) {
|
||||||
// Extract key from command
|
// Extract key from command
|
||||||
keys, err := decrByKeyFunc(params.Command)
|
keys, err := decrByKeyFunc(params.Command)
|
||||||
@@ -870,6 +871,50 @@ func handleObjIdleTime(params internal.HandlerFuncParams) ([]byte, error) {
|
|||||||
return []byte(fmt.Sprintf("+%v\r\n", idletime)), nil
|
return []byte(fmt.Sprintf("+%v\r\n", idletime)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func handleCopy(params internal.HandlerFuncParams) ([]byte, error) {
|
||||||
|
keys, err := copyKeyFunc(params.Command)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
options, err := getCopyCommandOptions(params.Command[3:], CopyOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
sourceKey := keys.ReadKeys[0]
|
||||||
|
destinationKey := keys.WriteKeys[0]
|
||||||
|
sourceKeyExists := params.KeysExist(params.Context, []string{sourceKey})[sourceKey]
|
||||||
|
|
||||||
|
if !sourceKeyExists {
|
||||||
|
return []byte(":0\r\n"), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if !options.replace {
|
||||||
|
destinationKeyExists := params.KeysExist(params.Context, []string{destinationKey})[destinationKey]
|
||||||
|
|
||||||
|
if destinationKeyExists {
|
||||||
|
return []byte(":0\r\n"), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
value := params.GetValues(params.Context, []string{sourceKey})[sourceKey]
|
||||||
|
|
||||||
|
ctx := context.WithoutCancel(params.Context)
|
||||||
|
|
||||||
|
if options.database != "" {
|
||||||
|
database, _ := strconv.Atoi(options.database)
|
||||||
|
ctx = context.WithValue(ctx, "Database", database)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = params.SetValues(ctx, map[string]interface{}{
|
||||||
|
destinationKey: value,
|
||||||
|
}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return []byte(":1\r\n"), nil
|
||||||
|
}
|
||||||
|
|
||||||
func handleMove(params internal.HandlerFuncParams) ([]byte, error) {
|
func handleMove(params internal.HandlerFuncParams) ([]byte, error) {
|
||||||
keys, err := moveKeyFunc(params.Command)
|
keys, err := moveKeyFunc(params.Command)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1255,6 +1300,18 @@ The command is only available when the maxmemory-policy configuration directive
|
|||||||
KeyExtractionFunc: objIdleTimeKeyFunc,
|
KeyExtractionFunc: objIdleTimeKeyFunc,
|
||||||
HandlerFunc: handleObjIdleTime,
|
HandlerFunc: handleObjIdleTime,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Command: "copy",
|
||||||
|
Module: constants.GenericModule,
|
||||||
|
Categories: []string{constants.KeyspaceCategory, constants.WriteCategory, constants.SlowCategory},
|
||||||
|
Description: `(COPY source destination [DB destination-db] [REPLACE])
|
||||||
|
Copies the value stored at the source key to the destination key.
|
||||||
|
The command returns zero when the destination key already exists.
|
||||||
|
The REPLACE option removes the destination key before copying the value to it.`,
|
||||||
|
Sync: false,
|
||||||
|
KeyExtractionFunc: copyKeyFunc,
|
||||||
|
HandlerFunc: handleCopy,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Command: "move",
|
Command: "move",
|
||||||
Module: constants.GenericModule,
|
Module: constants.GenericModule,
|
||||||
|
@@ -3333,6 +3333,168 @@ func Test_Generic(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("Test_HandleCOPY", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
conn, err := internal.GetConnection("localhost", port)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
_ = conn.Close()
|
||||||
|
}()
|
||||||
|
client := resp.NewConn(conn)
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
sourceKeyPresetValue interface{}
|
||||||
|
sourcekey string
|
||||||
|
destKeyPresetValue interface{}
|
||||||
|
destinationKey string
|
||||||
|
database string
|
||||||
|
replace bool
|
||||||
|
expectedValue string
|
||||||
|
expectedResponse string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "1. Copy Value into non existing key",
|
||||||
|
sourceKeyPresetValue: "value1",
|
||||||
|
sourcekey: "skey1",
|
||||||
|
destKeyPresetValue: nil,
|
||||||
|
destinationKey: "dkey1",
|
||||||
|
database: "0",
|
||||||
|
replace: false,
|
||||||
|
expectedValue: "value1",
|
||||||
|
expectedResponse: "1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "2. Copy Value into existing key without replace option",
|
||||||
|
sourceKeyPresetValue: "value2",
|
||||||
|
sourcekey: "skey2",
|
||||||
|
destKeyPresetValue: "dValue2",
|
||||||
|
destinationKey: "dkey2",
|
||||||
|
database: "0",
|
||||||
|
replace: false,
|
||||||
|
expectedValue: "dValue2",
|
||||||
|
expectedResponse: "0",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "3. Copy Value into existing key with replace option",
|
||||||
|
sourceKeyPresetValue: "value3",
|
||||||
|
sourcekey: "skey3",
|
||||||
|
destKeyPresetValue: "dValue3",
|
||||||
|
destinationKey: "dkey3",
|
||||||
|
database: "0",
|
||||||
|
replace: true,
|
||||||
|
expectedValue: "value3",
|
||||||
|
expectedResponse: "1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "4. Copy Value into different database",
|
||||||
|
sourceKeyPresetValue: "value4",
|
||||||
|
sourcekey: "skey4",
|
||||||
|
destKeyPresetValue: nil,
|
||||||
|
destinationKey: "dkey4",
|
||||||
|
database: "1",
|
||||||
|
replace: true,
|
||||||
|
expectedValue: "value4",
|
||||||
|
expectedResponse: "1",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if tt.sourceKeyPresetValue != nil {
|
||||||
|
cmd := []resp.Value{resp.StringValue("Set"), resp.StringValue(tt.sourcekey), resp.StringValue(tt.sourceKeyPresetValue.(string))}
|
||||||
|
|
||||||
|
err := client.WriteArray(cmd)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rd, _, err := client.ReadValue()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.EqualFold(rd.String(), "ok") {
|
||||||
|
t.Errorf("expected preset response to be \"OK\", got %s", rd.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if tt.destKeyPresetValue != nil {
|
||||||
|
cmd := []resp.Value{resp.StringValue("Set"), resp.StringValue(tt.destinationKey), resp.StringValue(tt.destKeyPresetValue.(string))}
|
||||||
|
|
||||||
|
err := client.WriteArray(cmd)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rd, _, err := client.ReadValue()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.EqualFold(rd.String(), "ok") {
|
||||||
|
t.Errorf("expected preset response to be \"OK\", got %s", rd.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
command := []resp.Value{resp.StringValue("COPY"), resp.StringValue(tt.sourcekey), resp.StringValue(tt.destinationKey)}
|
||||||
|
|
||||||
|
if tt.database != "0" {
|
||||||
|
command = append(command, resp.StringValue("DB"), resp.StringValue(tt.database))
|
||||||
|
}
|
||||||
|
|
||||||
|
if tt.replace {
|
||||||
|
command = append(command, resp.StringValue("REPLACE"))
|
||||||
|
}
|
||||||
|
|
||||||
|
err := client.WriteArray(command)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rd, _, err := client.ReadValue()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
if !strings.EqualFold(rd.String(), tt.expectedResponse) {
|
||||||
|
t.Errorf("expected response to be %s, but got %s", tt.expectedResponse, rd.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
if tt.database != "0" {
|
||||||
|
selectCommand := []resp.Value{resp.StringValue("SELECT"), resp.StringValue(tt.database)}
|
||||||
|
|
||||||
|
err := client.WriteArray(selectCommand)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
_, _, err = client.ReadValue()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getCommand := []resp.Value{resp.StringValue("GET"), resp.StringValue(tt.destinationKey)}
|
||||||
|
|
||||||
|
err = client.WriteArray(getCommand)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rd, _, err = client.ReadValue()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
if !strings.EqualFold(rd.String(), tt.expectedValue) {
|
||||||
|
t.Errorf("expected value in destinaton key to be %s, but got %s", tt.expectedValue, rd.String())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("Test_HandleMOVE", func(t *testing.T) {
|
t.Run("Test_HandleMOVE", func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
@@ -3474,7 +3636,7 @@ func Test_Generic(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Certain commands will need to be tested in a server with an eviction policy.
|
// Certain commands will need to be tested in a server with an eviction policy.
|
||||||
// This is for testing against an LFU evictiona policy.
|
// This is for testing against an LFU eviction policy.
|
||||||
func Test_LFU_Generic(t *testing.T) {
|
func Test_LFU_Generic(t *testing.T) {
|
||||||
// mockClock := clock.NewClock()
|
// mockClock := clock.NewClock()
|
||||||
port, err := internal.GetFreePort()
|
port, err := internal.GetFreePort()
|
||||||
|
@@ -268,6 +268,18 @@ func objIdleTimeKeyFunc(cmd []string) (internal.KeyExtractionFuncResult, error)
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func copyKeyFunc(cmd []string) (internal.KeyExtractionFuncResult, error) {
|
||||||
|
if len(cmd) < 3 && len(cmd)>6{
|
||||||
|
return internal.KeyExtractionFuncResult{}, errors.New(constants.WrongArgsResponse)
|
||||||
|
}
|
||||||
|
|
||||||
|
return internal.KeyExtractionFuncResult{
|
||||||
|
Channels: make([]string, 0),
|
||||||
|
ReadKeys: cmd[1:2],
|
||||||
|
WriteKeys: cmd[2:3],
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func moveKeyFunc(cmd []string) (internal.KeyExtractionFuncResult, error) {
|
func moveKeyFunc(cmd []string) (internal.KeyExtractionFuncResult, error) {
|
||||||
if len(cmd) != 3 {
|
if len(cmd) != 3 {
|
||||||
return internal.KeyExtractionFuncResult{}, errors.New(constants.WrongArgsResponse)
|
return internal.KeyExtractionFuncResult{}, errors.New(constants.WrongArgsResponse)
|
||||||
|
@@ -29,6 +29,11 @@ type SetOptions struct {
|
|||||||
expireAt interface{} // Exact expireAt time un unix milliseconds
|
expireAt interface{} // Exact expireAt time un unix milliseconds
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CopyOptions struct {
|
||||||
|
database string
|
||||||
|
replace bool
|
||||||
|
}
|
||||||
|
|
||||||
func getSetCommandOptions(clock clock.Clock, cmd []string, options SetOptions) (SetOptions, error) {
|
func getSetCommandOptions(clock clock.Clock, cmd []string, options SetOptions) (SetOptions, error) {
|
||||||
if len(cmd) == 0 {
|
if len(cmd) == 0 {
|
||||||
return options, nil
|
return options, nil
|
||||||
@@ -116,3 +121,32 @@ func getSetCommandOptions(clock clock.Clock, cmd []string, options SetOptions) (
|
|||||||
return SetOptions{}, fmt.Errorf("unknown option %s for set command", strings.ToUpper(cmd[0]))
|
return SetOptions{}, fmt.Errorf("unknown option %s for set command", strings.ToUpper(cmd[0]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getCopyCommandOptions(cmd []string, options CopyOptions) (CopyOptions, error) {
|
||||||
|
if len(cmd) == 0 {
|
||||||
|
return options, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch strings.ToLower(cmd[0]){
|
||||||
|
case "replace":
|
||||||
|
options.replace = true
|
||||||
|
return getCopyCommandOptions(cmd[1:], options)
|
||||||
|
|
||||||
|
case "db":
|
||||||
|
if len(cmd) < 2 {
|
||||||
|
return CopyOptions{}, errors.New("syntax error")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := strconv.Atoi(cmd[1])
|
||||||
|
if err != nil {
|
||||||
|
return CopyOptions{}, errors.New("value is not an integer or out of range")
|
||||||
|
}
|
||||||
|
|
||||||
|
options.database = cmd [1]
|
||||||
|
return getCopyCommandOptions(cmd[2:], options)
|
||||||
|
|
||||||
|
|
||||||
|
default:
|
||||||
|
return CopyOptions{}, fmt.Errorf("unknown option %s for copy command", strings.ToUpper(cmd[0]))
|
||||||
|
}
|
||||||
|
}
|
@@ -137,6 +137,16 @@ type GetExOption interface {
|
|||||||
|
|
||||||
func (x GetExOpt) isGetExOpt() GetExOpt { return x }
|
func (x GetExOpt) isGetExOpt() GetExOpt { return x }
|
||||||
|
|
||||||
|
// COPYOptions is a struct wrapper for all optional parameters of the Copy command.
|
||||||
|
//
|
||||||
|
// `Database` - string - Logical database index
|
||||||
|
//
|
||||||
|
// `Replace` - bool - Whether to replace the destination key if it exists
|
||||||
|
type COPYOptions struct {
|
||||||
|
Database string
|
||||||
|
Replace bool
|
||||||
|
}
|
||||||
|
|
||||||
// Set creates or modifies the value at the given key.
|
// Set creates or modifies the value at the given key.
|
||||||
//
|
//
|
||||||
// Parameters:
|
// Parameters:
|
||||||
@@ -719,6 +729,33 @@ func (server *SugarDB) Type(key string) (string, error) {
|
|||||||
return internal.ParseStringResponse(b)
|
return internal.ParseStringResponse(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Copy copies a value of a source key to destination key.
|
||||||
|
//
|
||||||
|
// Parameters:
|
||||||
|
//
|
||||||
|
// `source` - string - the source key from which data is to be copied
|
||||||
|
//
|
||||||
|
// `destination` - string - the destination key where data should be copied
|
||||||
|
//
|
||||||
|
// Returns: 1 if the copy is successful. 0 if the copy is unsuccessful
|
||||||
|
func (server *SugarDB) Copy(sourceKey, destinationKey string, options COPYOptions) (int, error) {
|
||||||
|
cmd := []string{"COPY", sourceKey, destinationKey}
|
||||||
|
|
||||||
|
if options.Database != "" {
|
||||||
|
cmd = append(cmd, "db", options.Database)
|
||||||
|
}
|
||||||
|
|
||||||
|
if options.Replace {
|
||||||
|
cmd = append(cmd, "replace")
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := server.handleCommand(server.context, internal.EncodeCommand(cmd), nil, false, true)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return internal.ParseIntegerResponse(b)
|
||||||
|
}
|
||||||
|
|
||||||
// Move key from currently selected database to specified destination database and return 1.
|
// Move key from currently selected database to specified destination database and return 1.
|
||||||
// When key already exists in the destination database, or it does not exist in the source database, it does nothing and returns 0.
|
// When key already exists in the destination database, or it does not exist in the source database, it does nothing and returns 0.
|
||||||
//
|
//
|
||||||
|
@@ -1826,6 +1826,111 @@ func TestSugarDB_TYPE(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSugarDB_COPY(t *testing.T) {
|
||||||
|
server := createSugarDB()
|
||||||
|
|
||||||
|
CopyOptions := func(DB string, R bool) COPYOptions {
|
||||||
|
return COPYOptions{
|
||||||
|
Database: DB,
|
||||||
|
Replace: R,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
sourceKeyPresetValue interface{}
|
||||||
|
sourcekey string
|
||||||
|
destKeyPresetValue interface{}
|
||||||
|
destinationKey string
|
||||||
|
options COPYOptions
|
||||||
|
expectedValue string
|
||||||
|
want int
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Copy Value into non existing key",
|
||||||
|
sourceKeyPresetValue: "value1",
|
||||||
|
sourcekey: "skey1",
|
||||||
|
destKeyPresetValue: nil,
|
||||||
|
destinationKey: "dkey1",
|
||||||
|
options: CopyOptions("0", false),
|
||||||
|
expectedValue: "value1",
|
||||||
|
want: 1,
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Copy Value into existing key without replace option",
|
||||||
|
sourceKeyPresetValue: "value2",
|
||||||
|
sourcekey: "skey2",
|
||||||
|
destKeyPresetValue: "dValue2",
|
||||||
|
destinationKey: "dkey2",
|
||||||
|
options: CopyOptions("0", false),
|
||||||
|
expectedValue: "dValue2",
|
||||||
|
want: 0,
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Copy Value into existing key with replace option",
|
||||||
|
sourceKeyPresetValue: "value3",
|
||||||
|
sourcekey: "skey3",
|
||||||
|
destKeyPresetValue: "dValue3",
|
||||||
|
destinationKey: "dkey3",
|
||||||
|
options: CopyOptions("0", true),
|
||||||
|
expectedValue: "value3",
|
||||||
|
want: 1,
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Copy Value into different database",
|
||||||
|
sourceKeyPresetValue: "value4",
|
||||||
|
sourcekey: "skey4",
|
||||||
|
destKeyPresetValue: nil,
|
||||||
|
destinationKey: "dkey4",
|
||||||
|
options: CopyOptions("1", false),
|
||||||
|
expectedValue: "value4",
|
||||||
|
want: 1,
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if tt.sourceKeyPresetValue != nil {
|
||||||
|
err := presetValue(server, context.Background(), tt.sourcekey, tt.sourceKeyPresetValue)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if tt.destKeyPresetValue != nil {
|
||||||
|
err := presetValue(server, context.Background(), tt.destinationKey, tt.destKeyPresetValue)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
got, err := server.Copy(tt.sourcekey, tt.destinationKey, tt.options)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("COPY() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if got != tt.want {
|
||||||
|
t.Errorf("COPY() got = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
|
||||||
|
val, err := getValue(server, context.Background(), tt.destinationKey, tt.options.Database)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if val != tt.expectedValue {
|
||||||
|
t.Errorf("COPY() value in destionation key: %v, should be: %v", val, tt.expectedValue)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestSugarDB_MOVE(t *testing.T) {
|
func TestSugarDB_MOVE(t *testing.T) {
|
||||||
server := createSugarDB()
|
server := createSugarDB()
|
||||||
|
|
||||||
@@ -1867,7 +1972,6 @@ func TestSugarDB_MOVE(t *testing.T) {
|
|||||||
if got != tt.want {
|
if got != tt.want {
|
||||||
t.Errorf("MOVE() got %v, want %v", got, tt.want)
|
t.Errorf("MOVE() got %v, want %v", got, tt.want)
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,6 +2,8 @@ package sugardb
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/echovault/sugardb/internal"
|
"github.com/echovault/sugardb/internal"
|
||||||
"github.com/echovault/sugardb/internal/config"
|
"github.com/echovault/sugardb/internal/config"
|
||||||
"github.com/echovault/sugardb/internal/constants"
|
"github.com/echovault/sugardb/internal/constants"
|
||||||
@@ -37,3 +39,13 @@ func presetKeyData(server *SugarDB, ctx context.Context, key string, data intern
|
|||||||
_ = server.setValues(ctx, map[string]interface{}{key: data.Value})
|
_ = server.setValues(ctx, map[string]interface{}{key: data.Value})
|
||||||
server.setExpiry(ctx, key, data.ExpireAt, false)
|
server.setExpiry(ctx, key, data.ExpireAt, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getValue (server *SugarDB, ctx context.Context, key string, database string) (interface{}, error) {
|
||||||
|
db, err := strconv.Atoi(database)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ctx = context.WithValue(ctx, "Database", db)
|
||||||
|
|
||||||
|
return server.getValues(ctx, []string{key})[key], err
|
||||||
|
}
|
Reference in New Issue
Block a user