Skip to content

Commit 3b45c8b

Browse files
authored
Merge pull request #107 from cankush625/ankushchavan/exists-command
feat(cmd): implement EXISTS command
2 parents 5d7a543 + 33ca13c commit 3b45c8b

7 files changed

Lines changed: 114 additions & 0 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,4 @@ See the [Usage Guide](./docs/usage.md) for installation, connecting, and a walkt
2626
| [KEYS](./docs/keys.md) | Find keys matching a pattern |
2727
| [CONFIG](./docs/config.md) | Read and modify server configuration |
2828
| [TYPE](./docs/type.md) | Return the type of the value stored at a key |
29+
| [EXISTS](./docs/exists.md) | Check if one or more keys exist |

cmd/exists.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package cmd
2+
3+
import (
4+
"HelixDB/common"
5+
)
6+
7+
// Exists returns the number of the given keys that exist in the store.
8+
// If the same key is provided multiple times it is counted multiple times.
9+
// Expired keys are treated as non-existent.
10+
func Exists(command common.Cmd) ([]byte, error) {
11+
if len(command.Args) < 1 {
12+
err := common.WrongNumberOfArgsError(command.Name)
13+
return common.RespError(err.Error()), err
14+
}
15+
count := 0
16+
for _, key := range command.Args {
17+
if _, err := GetValueFromMemory(key); err == nil {
18+
count++
19+
}
20+
}
21+
return common.RespInteger(count), nil
22+
}

cmd/exists_test.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package cmd
2+
3+
import (
4+
"HelixDB/common"
5+
"errors"
6+
"reflect"
7+
"testing"
8+
)
9+
10+
func TestExists(t *testing.T) {
11+
_, _ = Set(common.Cmd{Name: "SET", Args: []string{"ex_key1", "value1"}})
12+
_, _ = Set(common.Cmd{Name: "SET", Args: []string{"ex_key2", "value2"}})
13+
14+
tests := []struct {
15+
command common.Cmd
16+
want []byte
17+
wantErr error
18+
}{
19+
// Single existing key
20+
{common.Cmd{Name: "EXISTS", Args: []string{"ex_key1"}}, common.RespInteger(1), nil},
21+
// Single non-existent key
22+
{common.Cmd{Name: "EXISTS", Args: []string{"no_such_key"}}, common.RespInteger(0), nil},
23+
// Multiple keys, all exist
24+
{common.Cmd{Name: "EXISTS", Args: []string{"ex_key1", "ex_key2"}}, common.RespInteger(2), nil},
25+
// Multiple keys, some missing
26+
{common.Cmd{Name: "EXISTS", Args: []string{"ex_key1", "no_such_key"}}, common.RespInteger(1), nil},
27+
// Duplicate key counts multiple times
28+
{common.Cmd{Name: "EXISTS", Args: []string{"ex_key1", "ex_key1"}}, common.RespInteger(2), nil},
29+
// Wrong number of arguments
30+
{common.Cmd{Name: "EXISTS"}, common.RespError("wrong number of arguments for 'exists' command"), common.ErrWrongNumberOfArgs},
31+
}
32+
for _, test := range tests {
33+
if got, gotErr := Exists(test.command); !reflect.DeepEqual(got, test.want) || !errors.Is(gotErr, test.wantErr) {
34+
t.Errorf("Exists(%v) = %v, %v; want %v, %v", test.command, got, gotErr, test.want, test.wantErr)
35+
}
36+
}
37+
}

common/constants.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const Del = "DEL"
1414
const Keys = "KEYS"
1515
const Config = "CONFIG"
1616
const Type = "TYPE"
17+
const Exists = "EXISTS"
1718

1819
// Command Args
1920
// Expiration Args

docs/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@
1717
| [KEYS](./keys.md) | Find keys matching a pattern |
1818
| [CONFIG](./config.md) | Read and modify server configuration |
1919
| [TYPE](./type.md) | Return the type of the value stored at a key |
20+
| [EXISTS](./exists.md) | Check if one or more keys exist |

docs/exists.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# EXISTS
2+
3+
Returns the number of the given keys that exist in the store. Expired keys are treated as non-existent.
4+
5+
If the same key is provided multiple times it is counted multiple times.
6+
7+
## Syntax
8+
9+
```
10+
EXISTS key [key ...]
11+
```
12+
13+
## Arguments
14+
15+
| Argument | Type | Required | Description |
16+
|----------|--------|----------|------------------------------|
17+
| `key` | string | Yes | One or more keys to check. |
18+
19+
## Return value
20+
21+
The number of keys that exist. Ranges from `0` (none exist) to the total number of key arguments supplied.
22+
23+
## Errors
24+
25+
- `wrong number of arguments for 'exists' command` — when called with no arguments.
26+
27+
## Examples
28+
29+
```
30+
> SET a 1
31+
OK
32+
33+
> SET b 2
34+
OK
35+
36+
> EXISTS a
37+
1
38+
39+
> EXISTS a b
40+
2
41+
42+
> EXISTS a missing
43+
1
44+
45+
> EXISTS missing
46+
0
47+
48+
> EXISTS a a
49+
2
50+
```

exc/command_executor.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ func ExecuteCommand(command common.Cmd) ([]byte, error) {
3030
return cmd.ConfigCmd(command)
3131
case common.Type:
3232
return cmd.Type(command)
33+
case common.Exists:
34+
return cmd.Exists(command)
3335
}
3436
return []byte("-unsupported command\r\n"), UnsupportedCommand
3537
}

0 commit comments

Comments
 (0)