mirror of
https://github.com/EchoVault/SugarDB.git
synced 2025-10-28 18:12:37 +08:00
@@ -562,3 +562,19 @@ func (server *EchoVault) RandomKey() (string, error) {
|
|||||||
}
|
}
|
||||||
return internal.ParseStringResponse(b)
|
return internal.ParseStringResponse(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetDel retrieves the value at the provided key and deletes that key.
|
||||||
|
//
|
||||||
|
// Parameters:
|
||||||
|
//
|
||||||
|
// `key` - string - the key whose value should be retrieved and then deleted.
|
||||||
|
//
|
||||||
|
// Returns: A string representing the value at the specified key. If the value does not exist, an empty
|
||||||
|
// string is returned.
|
||||||
|
func (server *EchoVault) GetDel(key string) (string, error) {
|
||||||
|
b, err := server.handleCommand(server.context, internal.EncodeCommand([]string{"GETDEL", key}), nil, false, true)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return internal.ParseStringResponse(b)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1342,3 +1342,61 @@ func TestEchoVault_RANDOMKEY(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEchoVault_GETDEL(t *testing.T) {
|
||||||
|
server := createEchoVault()
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
presetValue interface{}
|
||||||
|
key string
|
||||||
|
want string
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Return string from existing key",
|
||||||
|
presetValue: "value1",
|
||||||
|
key: "key1",
|
||||||
|
want: "value1",
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Return empty string if the key does not exist",
|
||||||
|
presetValue: nil,
|
||||||
|
key: "key2",
|
||||||
|
want: "",
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if tt.presetValue != nil {
|
||||||
|
err := presetValue(server, context.Background(), tt.key, tt.presetValue)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Check value received
|
||||||
|
got, err := server.GetDel(tt.key)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("GETDEL() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if got != tt.want {
|
||||||
|
t.Errorf("GETDEL() got = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
//Check key was deleted
|
||||||
|
if tt.presetValue != nil {
|
||||||
|
got, err := server.Get(tt.key)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("GETDEL() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if got != "" {
|
||||||
|
t.Errorf("GETDEL() got = %v, want empty string", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -655,9 +655,11 @@ func (server *EchoVault) randomKey(ctx context.Context) string {
|
|||||||
for key, _ := range server.store[database] {
|
for key, _ := range server.store[database] {
|
||||||
if i == randnum {
|
if i == randnum {
|
||||||
randkey = key
|
randkey = key
|
||||||
|
break
|
||||||
} else {
|
} else {
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return randkey
|
return randkey
|
||||||
|
|||||||
@@ -690,6 +690,28 @@ func handleRandomkey(params internal.HandlerFuncParams) ([]byte, error) {
|
|||||||
return []byte(fmt.Sprintf("+%v\r\n", key)), nil
|
return []byte(fmt.Sprintf("+%v\r\n", key)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func handleGetdel(params internal.HandlerFuncParams) ([]byte, error) {
|
||||||
|
keys, err := getDelKeyFunc(params.Command)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
key := keys.ReadKeys[0]
|
||||||
|
keyExists := params.KeysExist(params.Context, []string{key})[key]
|
||||||
|
|
||||||
|
if !keyExists {
|
||||||
|
return []byte("$-1\r\n"), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
value := params.GetValues(params.Context, []string{key})[key]
|
||||||
|
delkey := keys.WriteKeys[0]
|
||||||
|
err = params.DeleteKey(params.Context, delkey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return []byte(fmt.Sprintf("+%v\r\n", value)), nil
|
||||||
|
}
|
||||||
|
|
||||||
func Commands() []internal.Command {
|
func Commands() []internal.Command {
|
||||||
return []internal.Command{
|
return []internal.Command{
|
||||||
{
|
{
|
||||||
@@ -973,5 +995,14 @@ Delete all the keys in the currently selected database. This command is always s
|
|||||||
KeyExtractionFunc: randomKeyFunc,
|
KeyExtractionFunc: randomKeyFunc,
|
||||||
HandlerFunc: handleRandomkey,
|
HandlerFunc: handleRandomkey,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Command: "getdel",
|
||||||
|
Module: constants.GenericModule,
|
||||||
|
Categories: []string{constants.WriteCategory, constants.FastCategory},
|
||||||
|
Description: "(GETDEL key) Get the value of key and delete the key. This command is similar to [GET], but deletes key on success.",
|
||||||
|
Sync: true,
|
||||||
|
KeyExtractionFunc: getDelKeyFunc,
|
||||||
|
HandlerFunc: handleGetdel,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2797,4 +2797,137 @@ func Test_Generic(t *testing.T) {
|
|||||||
t.Errorf("expected a key containing substring '%s', got %s", expected, res.String())
|
t.Errorf("expected a key containing substring '%s', got %s", expected, res.String())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("Test_HandleGETDEL", 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
|
||||||
|
key string
|
||||||
|
value string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "1. String",
|
||||||
|
key: "GetDelKey1",
|
||||||
|
value: "value1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "2. Integer",
|
||||||
|
key: "GetDelKey2",
|
||||||
|
value: "10",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "3. Float",
|
||||||
|
key: "GetDelKey3",
|
||||||
|
value: "3.142",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
// Test successful GETDEL command
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
func(key, value string) {
|
||||||
|
// Preset the values
|
||||||
|
err = client.WriteArray([]resp.Value{resp.StringValue("SET"), resp.StringValue(key), resp.StringValue(value)})
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
res, _, err := client.ReadValue()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.EqualFold(res.String(), "ok") {
|
||||||
|
t.Errorf("expected preset response to be \"OK\", got %s", res.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify correct value returned
|
||||||
|
if err = client.WriteArray([]resp.Value{resp.StringValue("GETDEL"), resp.StringValue(key)}); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
res, _, err = client.ReadValue()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if res.String() != test.value {
|
||||||
|
t.Errorf("expected value %s, got %s", test.value, res.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify key was deleted
|
||||||
|
if err = client.WriteArray([]resp.Value{resp.StringValue("GET"), resp.StringValue(key)}); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
res, _, err = client.ReadValue()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
if !res.IsNull() {
|
||||||
|
t.Errorf("expected nil, got: %+v", res)
|
||||||
|
}
|
||||||
|
}(test.key, test.value)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test get non-existent key
|
||||||
|
if err = client.WriteArray([]resp.Value{resp.StringValue("GETDEL"), resp.StringValue("test4")}); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
res, _, err := client.ReadValue()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
if !res.IsNull() {
|
||||||
|
t.Errorf("expected nil, got: %+v", res)
|
||||||
|
}
|
||||||
|
|
||||||
|
errorTests := []struct {
|
||||||
|
name string
|
||||||
|
command []string
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "1. Return error when no GETDEL key is passed",
|
||||||
|
command: []string{"GETDEL"},
|
||||||
|
expected: constants.WrongArgsResponse,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "2. Return error when too many GETDEL keys are passed",
|
||||||
|
command: []string{"GETDEL", "GetKey1", "test"},
|
||||||
|
expected: constants.WrongArgsResponse,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range errorTests {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
command := make([]resp.Value, len(test.command))
|
||||||
|
for i, c := range test.command {
|
||||||
|
command[i] = resp.StringValue(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = client.WriteArray(command); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
res, _, err = client.ReadValue()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.Contains(res.Error().Error(), test.expected) {
|
||||||
|
t.Errorf("expected error '%s', got: %s", test.expected, err.Error())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -201,3 +201,14 @@ func randomKeyFunc(cmd []string) (internal.KeyExtractionFuncResult, error) {
|
|||||||
WriteKeys: make([]string, 0),
|
WriteKeys: make([]string, 0),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getDelKeyFunc(cmd []string) (internal.KeyExtractionFuncResult, error) {
|
||||||
|
if len(cmd) != 2 {
|
||||||
|
return internal.KeyExtractionFuncResult{}, errors.New(constants.WrongArgsResponse)
|
||||||
|
}
|
||||||
|
return internal.KeyExtractionFuncResult{
|
||||||
|
Channels: make([]string, 0),
|
||||||
|
ReadKeys: cmd[1:],
|
||||||
|
WriteKeys: cmd[1:],
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user