From 7b69ea2bdb522346356e7afcc79f7274d4a425c0 Mon Sep 17 00:00:00 2001 From: Vaibhav Yadav Date: Sun, 22 Jun 2025 12:19:10 +0530 Subject: [PATCH 1/2] Add support for COMMAND GETKEYSANDFLAGS (#642) --- internal/cmd/cmd_decr.go | 7 +++- internal/cmd/cmd_decrby.go | 7 +++- internal/cmd/cmd_del.go | 7 +++- internal/cmd/cmd_echo.go | 1 + internal/cmd/cmd_exists.go | 7 +++- internal/cmd/cmd_expire.go | 7 +++- internal/cmd/cmd_expireat.go | 7 +++- internal/cmd/cmd_expiretime.go | 7 +++- internal/cmd/cmd_flushdb.go | 1 + internal/cmd/cmd_get.go | 3 ++ internal/cmd/cmd_getdel.go | 7 +++- internal/cmd/cmd_getex.go | 7 +++- internal/cmd/cmd_getset.go | 7 +++- internal/cmd/cmd_hget.go | 3 ++ internal/cmd/cmd_hgetall.go | 3 ++ internal/cmd/cmd_hset.go | 7 +++- internal/cmd/cmd_incr.go | 7 +++- internal/cmd/cmd_incrby.go | 7 +++- internal/cmd/cmd_keys.go | 1 + internal/cmd/cmd_ping.go | 1 + internal/cmd/cmd_set.go | 8 +++- internal/cmd/cmd_ttl.go | 7 +++- internal/cmd/cmd_type.go | 7 +++- internal/cmd/cmd_unwatch.go | 1 + internal/cmd/cmd_zadd.go | 7 +++- internal/cmd/cmd_zcard.go | 3 ++ internal/cmd/cmd_zcount.go | 3 ++ internal/cmd/cmd_zpopmax.go | 7 +++- internal/cmd/cmd_zpopmin.go | 7 +++- internal/cmd/cmd_zrange.go | 3 ++ internal/cmd/cmd_zrank.go | 3 ++ internal/cmd/cmd_zrem.go | 7 +++- internal/cmd/cmds.go | 4 ++ internal/constants.go | 68 ++++++++++++++++++++++++++++++++++ internal/eval/store_eval.go | 58 +++++++++++++++++++++++++++++ 35 files changed, 257 insertions(+), 40 deletions(-) create mode 100644 internal/constants.go diff --git a/internal/cmd/cmd_decr.go b/internal/cmd/cmd_decr.go index a517a7cc6..6a60ebf3e 100644 --- a/internal/cmd/cmd_decr.go +++ b/internal/cmd/cmd_decr.go @@ -4,6 +4,7 @@ package cmd import ( + flg "github.com/dicedb/dice/internal" "github.com/dicedb/dice/internal/errors" "github.com/dicedb/dice/internal/shardmanager" dstore "github.com/dicedb/dice/internal/store" @@ -32,8 +33,10 @@ OK localhost:7379> DECR k2 ERR wrongtype operation against a key holding the wrong kind of value `, - Eval: evalDECR, - Execute: executeDECR, + Eval: evalDECR, + Execute: executeDECR, + Arity: 2, + KeySpecs: flg.KeySpecs{BeginIndex: 1, Flags: flg.RM | flg.ACCESS | flg.UPDATE}, } func init() { diff --git a/internal/cmd/cmd_decrby.go b/internal/cmd/cmd_decrby.go index bc72c60a8..ce11cfd24 100644 --- a/internal/cmd/cmd_decrby.go +++ b/internal/cmd/cmd_decrby.go @@ -6,6 +6,7 @@ package cmd import ( "strconv" + flg "github.com/dicedb/dice/internal" "github.com/dicedb/dice/internal/errors" "github.com/dicedb/dice/internal/shardmanager" dstore "github.com/dicedb/dice/internal/store" @@ -32,8 +33,10 @@ OK -50 localhost:7379> GET k2 OK "-50" `, - Eval: evalDECRBY, - Execute: executeDECRBY, + Eval: evalDECRBY, + Execute: executeDECRBY, + Arity: 3, + KeySpecs: flg.KeySpecs{BeginIndex: 1, Flags: flg.RM | flg.ACCESS | flg.UPDATE}, } func init() { diff --git a/internal/cmd/cmd_del.go b/internal/cmd/cmd_del.go index daef4837d..361bff2d2 100644 --- a/internal/cmd/cmd_del.go +++ b/internal/cmd/cmd_del.go @@ -4,6 +4,7 @@ package cmd import ( + flg "github.com/dicedb/dice/internal" "github.com/dicedb/dice/internal/errors" "github.com/dicedb/dice/internal/shardmanager" dstore "github.com/dicedb/dice/internal/store" @@ -24,8 +25,10 @@ localhost:7379> SET k2 v2 OK localhost:7379> DEL k1 k2 k3 OK 2`, - Eval: evalDEL, - Execute: executeDEL, + Eval: evalDEL, + Execute: executeDEL, + Arity: -2, + KeySpecs: flg.KeySpecs{BeginIndex: 1, Flags: flg.RM | flg.DELETE}, } func init() { diff --git a/internal/cmd/cmd_echo.go b/internal/cmd/cmd_echo.go index 0e3d1360d..e98115626 100644 --- a/internal/cmd/cmd_echo.go +++ b/internal/cmd/cmd_echo.go @@ -20,6 +20,7 @@ localhost:7379> ECHO dicedb OK dicedb`, Eval: evalECHO, Execute: executeECHO, + Arity: 1, } func init() { diff --git a/internal/cmd/cmd_exists.go b/internal/cmd/cmd_exists.go index 15a5643cc..12224683d 100644 --- a/internal/cmd/cmd_exists.go +++ b/internal/cmd/cmd_exists.go @@ -4,6 +4,7 @@ package cmd import ( + flg "github.com/dicedb/dice/internal" "github.com/dicedb/dice/internal/errors" "github.com/dicedb/dice/internal/shard" "github.com/dicedb/dice/internal/shardmanager" @@ -24,8 +25,10 @@ OK localhost:7379> EXISTS k1 k2 k3 OK 2 `, - Eval: evalEXISTS, - Execute: executeEXISTS, + Eval: evalEXISTS, + Execute: executeEXISTS, + Arity: -2, + KeySpecs: flg.KeySpecs{BeginIndex: 1, Flags: flg.RO}, } func init() { diff --git a/internal/cmd/cmd_expire.go b/internal/cmd/cmd_expire.go index 0b26a3357..8b6e254a1 100644 --- a/internal/cmd/cmd_expire.go +++ b/internal/cmd/cmd_expire.go @@ -7,6 +7,7 @@ import ( "strconv" "time" + flg "github.com/dicedb/dice/internal" "github.com/dicedb/dice/internal/errors" "github.com/dicedb/dice/internal/shardmanager" dstore "github.com/dicedb/dice/internal/store" @@ -43,8 +44,10 @@ OK true localhost:7379> EXPIRE k2 20 NX OK false `, - Eval: evalEXPIRE, - Execute: executeEXPIRE, + Eval: evalEXPIRE, + Execute: executeEXPIRE, + Arity: -3, + KeySpecs: flg.KeySpecs{BeginIndex: 1, Step: 1, Flags: flg.RW | flg.UPDATE}, } func init() { diff --git a/internal/cmd/cmd_expireat.go b/internal/cmd/cmd_expireat.go index a62440d26..44ac03de5 100644 --- a/internal/cmd/cmd_expireat.go +++ b/internal/cmd/cmd_expireat.go @@ -7,6 +7,7 @@ import ( "strconv" "time" + flg "github.com/dicedb/dice/internal" "github.com/dicedb/dice/internal/errors" "github.com/dicedb/dice/internal/shardmanager" dstore "github.com/dicedb/dice/internal/store" @@ -40,8 +41,10 @@ OK false localhost:7379> EXPIREAT k1 1740829942 XX OK false `, - Eval: evalEXPIREAT, - Execute: executeEXPIREAT, + Eval: evalEXPIREAT, + Execute: executeEXPIREAT, + Arity: -3, + KeySpecs: flg.KeySpecs{BeginIndex: 1, Flags: flg.RW | flg.UPDATE}, } func init() { diff --git a/internal/cmd/cmd_expiretime.go b/internal/cmd/cmd_expiretime.go index 5922ab8f6..b9b7f8aa5 100644 --- a/internal/cmd/cmd_expiretime.go +++ b/internal/cmd/cmd_expiretime.go @@ -4,6 +4,7 @@ package cmd import ( + flg "github.com/dicedb/dice/internal" "github.com/dicedb/dice/internal/errors" "github.com/dicedb/dice/internal/shardmanager" dstore "github.com/dicedb/dice/internal/store" @@ -28,8 +29,10 @@ OK true localhost:7379> EXPIRETIME k1 OK 1744451192 `, - Eval: evalEXPIRETIME, - Execute: executeEXPIRETIME, + Eval: evalEXPIRETIME, + Execute: executeEXPIRETIME, + Arity: 2, + KeySpecs: flg.KeySpecs{BeginIndex: 1, Flags: flg.RO | flg.ACCESS}, } func init() { diff --git a/internal/cmd/cmd_flushdb.go b/internal/cmd/cmd_flushdb.go index e189775cb..78a020b0b 100644 --- a/internal/cmd/cmd_flushdb.go +++ b/internal/cmd/cmd_flushdb.go @@ -31,6 +31,7 @@ OK "" `, Eval: evalFLUSHDB, Execute: executeFLUSHDB, + Arity: -1, } func init() { diff --git a/internal/cmd/cmd_get.go b/internal/cmd/cmd_get.go index bf5af8a3b..7adc84848 100644 --- a/internal/cmd/cmd_get.go +++ b/internal/cmd/cmd_get.go @@ -6,6 +6,7 @@ package cmd import ( "fmt" + flg "github.com/dicedb/dice/internal" "github.com/dicedb/dice/internal/errors" "github.com/dicedb/dice/internal/object" "github.com/dicedb/dice/internal/shardmanager" @@ -33,6 +34,8 @@ OK "" Eval: evalGET, Execute: executeGET, IsWatchable: true, + Arity: 2, + KeySpecs: flg.KeySpecs{BeginIndex: 1, Flags: flg.RO | flg.ACCESS}, } func init() { diff --git a/internal/cmd/cmd_getdel.go b/internal/cmd/cmd_getdel.go index 7cf1bc564..e245ce1bd 100644 --- a/internal/cmd/cmd_getdel.go +++ b/internal/cmd/cmd_getdel.go @@ -4,6 +4,7 @@ package cmd import ( + flg "github.com/dicedb/dice/internal" "github.com/dicedb/dice/internal/errors" "github.com/dicedb/dice/internal/object" "github.com/dicedb/dice/internal/shardmanager" @@ -28,8 +29,10 @@ OK "v" localhost:7379> GET k OK "" `, - Eval: evalGETDEL, - Execute: executeGETDEL, + Eval: evalGETDEL, + Execute: executeGETDEL, + Arity: 2, + KeySpecs: flg.KeySpecs{BeginIndex: 1, Flags: flg.RW | flg.ACCESS | flg.DELETE}, } func init() { diff --git a/internal/cmd/cmd_getex.go b/internal/cmd/cmd_getex.go index 7b6b4f16e..480034ee2 100644 --- a/internal/cmd/cmd_getex.go +++ b/internal/cmd/cmd_getex.go @@ -8,6 +8,7 @@ import ( "strings" "time" + flg "github.com/dicedb/dice/internal" "github.com/dicedb/dice/internal/errors" "github.com/dicedb/dice/internal/object" "github.com/dicedb/dice/internal/shardmanager" @@ -52,8 +53,10 @@ OK "v" localhost:7379> EXPIRETIME k OK -1 `, - Eval: evalGETEX, - Execute: executeGETEX, + Eval: evalGETEX, + Execute: executeGETEX, + Arity: -2, + KeySpecs: flg.KeySpecs{BeginIndex: 1, Flags: flg.RW | flg.ACCESS | flg.UPDATE}, } func init() { diff --git a/internal/cmd/cmd_getset.go b/internal/cmd/cmd_getset.go index 612b7728e..a14eb5576 100644 --- a/internal/cmd/cmd_getset.go +++ b/internal/cmd/cmd_getset.go @@ -4,6 +4,7 @@ package cmd import ( + flg "github.com/dicedb/dice/internal" "github.com/dicedb/dice/internal/errors" "github.com/dicedb/dice/internal/object" "github.com/dicedb/dice/internal/shardmanager" @@ -28,8 +29,10 @@ OK "v1" localhost:7379> GET k1 OK "v2" `, - Eval: evalGETSET, - Execute: executeGETSET, + Eval: evalGETSET, + Execute: executeGETSET, + Arity: 3, + KeySpecs: flg.KeySpecs{BeginIndex: 1, Flags: flg.RW | flg.ACCESS | flg.UPDATE}, } func init() { diff --git a/internal/cmd/cmd_hget.go b/internal/cmd/cmd_hget.go index 6ea4a4bec..722191cf6 100644 --- a/internal/cmd/cmd_hget.go +++ b/internal/cmd/cmd_hget.go @@ -4,6 +4,7 @@ package cmd import ( + flg "github.com/dicedb/dice/internal" "github.com/dicedb/dice/internal/errors" "github.com/dicedb/dice/internal/shardmanager" dstore "github.com/dicedb/dice/internal/store" @@ -32,6 +33,8 @@ OK "" Eval: evalHGET, Execute: executeHGET, IsWatchable: true, + Arity: 3, + KeySpecs: flg.KeySpecs{BeginIndex: 1, Flags: flg.RO | flg.ACCESS}, } func init() { diff --git a/internal/cmd/cmd_hgetall.go b/internal/cmd/cmd_hgetall.go index 1b8b11924..f734883a4 100644 --- a/internal/cmd/cmd_hgetall.go +++ b/internal/cmd/cmd_hgetall.go @@ -4,6 +4,7 @@ package cmd import ( + flg "github.com/dicedb/dice/internal" "github.com/dicedb/dice/internal/errors" "github.com/dicedb/dice/internal/object" "github.com/dicedb/dice/internal/shardmanager" @@ -34,6 +35,8 @@ OK Eval: evalHGETALL, Execute: executeHGETALL, IsWatchable: true, + Arity: 2, + KeySpecs: flg.KeySpecs{BeginIndex: 1, Flags: flg.RO | flg.ACCESS}, } func init() { diff --git a/internal/cmd/cmd_hset.go b/internal/cmd/cmd_hset.go index ad7b13ee1..1d69c3255 100644 --- a/internal/cmd/cmd_hset.go +++ b/internal/cmd/cmd_hset.go @@ -4,6 +4,7 @@ package cmd import ( + flg "github.com/dicedb/dice/internal" "github.com/dicedb/dice/internal/errors" "github.com/dicedb/dice/internal/object" "github.com/dicedb/dice/internal/shardmanager" @@ -28,8 +29,10 @@ OK 1 localhost:7379> HSET k1 f1 v1 f2 v2 f3 v3 OK 2 `, - Eval: evalHSET, - Execute: executeHSET, + Eval: evalHSET, + Execute: executeHSET, + Arity: -4, + KeySpecs: flg.KeySpecs{BeginIndex: 1, Flags: flg.RW | flg.UPDATE}, } func init() { diff --git a/internal/cmd/cmd_incr.go b/internal/cmd/cmd_incr.go index 32a066d2e..02cfb637f 100644 --- a/internal/cmd/cmd_incr.go +++ b/internal/cmd/cmd_incr.go @@ -4,6 +4,7 @@ package cmd import ( + flg "github.com/dicedb/dice/internal" "github.com/dicedb/dice/internal/errors" "github.com/dicedb/dice/internal/shardmanager" dstore "github.com/dicedb/dice/internal/store" @@ -30,8 +31,10 @@ OK 1 localhost:7379> GET k2 OK "1" `, - Eval: evalINCR, - Execute: executeINCR, + Eval: evalINCR, + Execute: executeINCR, + Arity: 2, + KeySpecs: flg.KeySpecs{BeginIndex: 1, Flags: flg.ACCESS | flg.RW | flg.UPDATE}, } func init() { diff --git a/internal/cmd/cmd_incrby.go b/internal/cmd/cmd_incrby.go index dc1db750e..9287bc79f 100644 --- a/internal/cmd/cmd_incrby.go +++ b/internal/cmd/cmd_incrby.go @@ -6,6 +6,7 @@ package cmd import ( "strconv" + flg "github.com/dicedb/dice/internal" "github.com/dicedb/dice/internal/errors" "github.com/dicedb/dice/internal/object" "github.com/dicedb/dice/internal/shardmanager" @@ -33,8 +34,10 @@ OK 50 localhost:7379> GET k2 OK "50" `, - Eval: evalINCRBY, - Execute: executeINCRBY, + Eval: evalINCRBY, + Execute: executeINCRBY, + Arity: 2, + KeySpecs: flg.KeySpecs{BeginIndex: 1, Flags: flg.UPDATE | flg.ACCESS | flg.RW}, } func init() { diff --git a/internal/cmd/cmd_keys.go b/internal/cmd/cmd_keys.go index b597f0008..3bc083e10 100644 --- a/internal/cmd/cmd_keys.go +++ b/internal/cmd/cmd_keys.go @@ -45,6 +45,7 @@ OK `, Eval: evalKEYS, Execute: executeKEYS, + Arity: 2, } func init() { diff --git a/internal/cmd/cmd_ping.go b/internal/cmd/cmd_ping.go index 8e88ed369..639ea6de3 100644 --- a/internal/cmd/cmd_ping.go +++ b/internal/cmd/cmd_ping.go @@ -25,6 +25,7 @@ OK "PONG dicedb" `, Eval: evalPING, Execute: executePING, + Arity: -1, } func init() { diff --git a/internal/cmd/cmd_set.go b/internal/cmd/cmd_set.go index 0e00b298a..bb37072d7 100644 --- a/internal/cmd/cmd_set.go +++ b/internal/cmd/cmd_set.go @@ -8,6 +8,7 @@ import ( "strings" "time" + flg "github.com/dicedb/dice/internal" "github.com/dicedb/dice/internal/errors" "github.com/dicedb/dice/internal/object" "github.com/dicedb/dice/internal/shardmanager" @@ -59,8 +60,11 @@ OK localhost:7379> SET k 43 KEEPTTL OK `, - Eval: evalSET, - Execute: executeSET, + Eval: evalSET, + Execute: executeSET, + Arity: -3, + KeySpecs: flg.KeySpecs{BeginIndex: 1, Flags: flg.RW | flg.ACCESS | flg.UPDATE | flg.VARIABLEFLAGS}, + GetFlags: flg.SetGetKeys, } func init() { diff --git a/internal/cmd/cmd_ttl.go b/internal/cmd/cmd_ttl.go index a52a8a3a0..5c7e38979 100644 --- a/internal/cmd/cmd_ttl.go +++ b/internal/cmd/cmd_ttl.go @@ -6,6 +6,7 @@ package cmd import ( "time" + flg "github.com/dicedb/dice/internal" "github.com/dicedb/dice/internal/errors" "github.com/dicedb/dice/internal/shardmanager" dstore "github.com/dicedb/dice/internal/store" @@ -34,8 +35,10 @@ OK 8 localhost:7379> TTL kn OK -2 `, - Eval: evalTTL, - Execute: executeTTL, + Eval: evalTTL, + Execute: executeTTL, + Arity: 2, + KeySpecs: flg.KeySpecs{BeginIndex: 1, Flags: flg.RO | flg.ACCESS}, } func init() { diff --git a/internal/cmd/cmd_type.go b/internal/cmd/cmd_type.go index ea1f6e1a7..1d9530c63 100644 --- a/internal/cmd/cmd_type.go +++ b/internal/cmd/cmd_type.go @@ -4,6 +4,7 @@ package cmd import ( + flg "github.com/dicedb/dice/internal" "github.com/dicedb/dice/internal/errors" "github.com/dicedb/dice/internal/shardmanager" dstore "github.com/dicedb/dice/internal/store" @@ -30,8 +31,10 @@ OK int localhost:7379> TYPE kn OK none `, - Eval: evalTYPE, - Execute: executeTYPE, + Eval: evalTYPE, + Execute: executeTYPE, + Arity: 1, + KeySpecs: flg.KeySpecs{BeginIndex: 1, Flags: flg.RO}, } func init() { diff --git a/internal/cmd/cmd_unwatch.go b/internal/cmd/cmd_unwatch.go index 121fb62bb..933496f8d 100644 --- a/internal/cmd/cmd_unwatch.go +++ b/internal/cmd/cmd_unwatch.go @@ -27,6 +27,7 @@ OK `, Eval: evalUNWATCH, Execute: executeUNWATCH, + Arity: 1, } func init() { diff --git a/internal/cmd/cmd_zadd.go b/internal/cmd/cmd_zadd.go index 1abbfd62a..502ea3ea0 100644 --- a/internal/cmd/cmd_zadd.go +++ b/internal/cmd/cmd_zadd.go @@ -6,6 +6,7 @@ package cmd import ( "strconv" + flg "github.com/dicedb/dice/internal" "github.com/dicedb/dice/internal/errors" "github.com/dicedb/dice/internal/object" "github.com/dicedb/dice/internal/shardmanager" @@ -46,8 +47,10 @@ OK 0 localhost:7379> ZADD users CH 11 u1 OK 1 `, - Eval: evalZADD, - Execute: executeZADD, + Eval: evalZADD, + Execute: executeZADD, + Arity: -4, + KeySpecs: flg.KeySpecs{BeginIndex: 1, Flags: flg.RW | flg.UPDATE}, } func init() { diff --git a/internal/cmd/cmd_zcard.go b/internal/cmd/cmd_zcard.go index 306001353..8803573d4 100644 --- a/internal/cmd/cmd_zcard.go +++ b/internal/cmd/cmd_zcard.go @@ -4,6 +4,7 @@ package cmd import ( + flg "github.com/dicedb/dice/internal" "github.com/dicedb/dice/internal/errors" "github.com/dicedb/dice/internal/object" "github.com/dicedb/dice/internal/shardmanager" @@ -32,6 +33,8 @@ OK 0 Eval: evalZCARD, Execute: executeZCARD, IsWatchable: true, + Arity: 2, + KeySpecs: flg.KeySpecs{BeginIndex: 1, Flags: flg.RO}, } func init() { diff --git a/internal/cmd/cmd_zcount.go b/internal/cmd/cmd_zcount.go index ead560d7d..14f5b0d7f 100644 --- a/internal/cmd/cmd_zcount.go +++ b/internal/cmd/cmd_zcount.go @@ -7,6 +7,7 @@ import ( "math" "strconv" + flg "github.com/dicedb/dice/internal" "github.com/dicedb/dice/internal/errors" "github.com/dicedb/dice/internal/object" "github.com/dicedb/dice/internal/shardmanager" @@ -48,6 +49,8 @@ OK 1 Eval: evalZCOUNT, Execute: executeZCOUNT, IsWatchable: true, + Arity: 4, + KeySpecs: flg.KeySpecs{BeginIndex: 1, Flags: flg.RO | flg.ACCESS}, } func init() { diff --git a/internal/cmd/cmd_zpopmax.go b/internal/cmd/cmd_zpopmax.go index 1a9851429..7f14520a9 100644 --- a/internal/cmd/cmd_zpopmax.go +++ b/internal/cmd/cmd_zpopmax.go @@ -6,6 +6,7 @@ package cmd import ( "strconv" + flg "github.com/dicedb/dice/internal" "github.com/dicedb/dice/internal/errors" "github.com/dicedb/dice/internal/object" "github.com/dicedb/dice/internal/shardmanager" @@ -39,8 +40,10 @@ OK 2) 20, bob 1) 10, alice `, - Eval: evalZPOPMAX, - Execute: executeZPOPMAX, + Eval: evalZPOPMAX, + Execute: executeZPOPMAX, + Arity: -2, + KeySpecs: flg.KeySpecs{BeginIndex: 1, Flags: flg.RW | flg.ACCESS | flg.DELETE}, } func init() { diff --git a/internal/cmd/cmd_zpopmin.go b/internal/cmd/cmd_zpopmin.go index bfebe80f2..dcd0390d1 100644 --- a/internal/cmd/cmd_zpopmin.go +++ b/internal/cmd/cmd_zpopmin.go @@ -6,6 +6,7 @@ package cmd import ( "strconv" + flg "github.com/dicedb/dice/internal" "github.com/dicedb/dice/internal/errors" "github.com/dicedb/dice/internal/object" "github.com/dicedb/dice/internal/shardmanager" @@ -39,8 +40,10 @@ OK 1) 20, bob 2) 30, charlie `, - Eval: evalZPOPMIN, - Execute: executeZPOPMIN, + Eval: evalZPOPMIN, + Execute: executeZPOPMIN, + Arity: -2, + KeySpecs: flg.KeySpecs{BeginIndex: 1, Flags: flg.RW | flg.ACCESS | flg.DELETE}, } func init() { diff --git a/internal/cmd/cmd_zrange.go b/internal/cmd/cmd_zrange.go index 67b2e6e9a..c459644d9 100644 --- a/internal/cmd/cmd_zrange.go +++ b/internal/cmd/cmd_zrange.go @@ -7,6 +7,7 @@ import ( "strconv" "strings" + flg "github.com/dicedb/dice/internal" "github.com/dicedb/dice/internal/errors" "github.com/dicedb/dice/internal/object" "github.com/dicedb/dice/internal/shardmanager" @@ -54,6 +55,8 @@ OK Eval: evalZRANGE, Execute: executeZRANGE, IsWatchable: true, + Arity: -4, + KeySpecs: flg.KeySpecs{BeginIndex: 1, Flags: flg.RO | flg.ACCESS}, } func init() { diff --git a/internal/cmd/cmd_zrank.go b/internal/cmd/cmd_zrank.go index d11b30c59..bd72815b7 100644 --- a/internal/cmd/cmd_zrank.go +++ b/internal/cmd/cmd_zrank.go @@ -4,6 +4,7 @@ package cmd import ( + flg "github.com/dicedb/dice/internal" "github.com/dicedb/dice/internal/errors" "github.com/dicedb/dice/internal/object" "github.com/dicedb/dice/internal/shardmanager" @@ -41,6 +42,8 @@ OK 0) 0, daniel Eval: evalZRANK, Execute: executeZRANK, IsWatchable: true, + Arity: -3, + KeySpecs: flg.KeySpecs{BeginIndex: 1, Flags: flg.RO | flg.ACCESS}, } func init() { diff --git a/internal/cmd/cmd_zrem.go b/internal/cmd/cmd_zrem.go index 65c983bc7..71ce83c3c 100644 --- a/internal/cmd/cmd_zrem.go +++ b/internal/cmd/cmd_zrem.go @@ -4,6 +4,7 @@ package cmd import ( + flg "github.com/dicedb/dice/internal" "github.com/dicedb/dice/internal/errors" "github.com/dicedb/dice/internal/object" "github.com/dicedb/dice/internal/shardmanager" @@ -35,8 +36,10 @@ localhost:7379> ZRANGE users 0 60 BYSCORE OK 1) 30, charlie `, - Eval: evalZREM, - Execute: executeZREM, + Eval: evalZREM, + Execute: executeZREM, + Arity: -3, + KeySpecs: flg.KeySpecs{BeginIndex: 1, Flags: flg.RW | flg.DELETE}, } func init() { diff --git a/internal/cmd/cmds.go b/internal/cmd/cmds.go index d5c297a60..1bf1302c4 100644 --- a/internal/cmd/cmds.go +++ b/internal/cmd/cmds.go @@ -10,6 +10,7 @@ import ( "time" "github.com/dgryski/go-farm" + flg "github.com/dicedb/dice/internal" "github.com/dicedb/dice/internal/errors" "github.com/dicedb/dice/internal/object" "github.com/dicedb/dice/internal/shardmanager" @@ -81,6 +82,9 @@ type CommandMeta struct { IsWatchable bool Eval func(c *Cmd, s *store.Store) (*CmdRes, error) Execute func(c *Cmd, sm *shardmanager.ShardManager) (*CmdRes, error) + KeySpecs flg.KeySpecs + Arity int + GetFlags func(args []string, ks *flg.KeySpecs) } type CmdRegistry struct { diff --git a/internal/constants.go b/internal/constants.go new file mode 100644 index 000000000..30a55ec89 --- /dev/null +++ b/internal/constants.go @@ -0,0 +1,68 @@ +package cmd + +type KeySpecs struct { + BeginIndex int + Step int + LastKey int + Flags uint64 +} + +var ( + // Flags + RO uint64 = (1 << 0) + RW uint64 = (1 << 1) + OW uint64 = (1 << 2) + RM uint64 = (1 << 3) + ACCESS uint64 = (1 << 4) + UPDATE uint64 = (1 << 5) + INSERT uint64 = (1 << 6) + DELETE uint64 = (1 << 7) + NOTKEY uint64 = (1 << 8) + INCOMPLETE uint64 = (1 << 9) + VARIABLEFLAGS uint64 = (1 << 10) +) + +func GetFlagsNameMap() map[uint64]string { + return map[uint64]string{ + RO: "RO", + RW: "RW", + OW: "OW", + RM: "RM", + ACCESS: "access", + UPDATE: "update", + INSERT: "insert", + DELETE: "delete", + NOTKEY: "not_key", + INCOMPLETE: "incomplete", + VARIABLEFLAGS: "variable_flags", + } +} + +func GetFlags() []uint64 { + return []uint64{ + RO, + RW, + OW, + RM, + ACCESS, + UPDATE, + INSERT, + DELETE, + NOTKEY, + INCOMPLETE, + VARIABLEFLAGS, + } +} + +func SetGetKeys(args []string, ks *KeySpecs) { + for i := 2; i < len(args); i++ { + if (len(args[i]) == 3) && + (args[i][0] == 'g' || args[i][0] == 'G') && + (args[i][1] == 'e' || args[i][1] == 'E') && + (args[i][2] == 't' || args[i][2] == 'T') { + ks.Flags = RW | ACCESS | UPDATE + return + } + } + ks.Flags = OW | UPDATE +} diff --git a/internal/eval/store_eval.go b/internal/eval/store_eval.go index 2d3f17e20..e47da48f0 100644 --- a/internal/eval/store_eval.go +++ b/internal/eval/store_eval.go @@ -20,6 +20,7 @@ import ( "github.com/axiomhq/hyperloglog" "github.com/bytedance/sonic" + flg "github.com/dicedb/dice/internal" "github.com/dicedb/dice/internal/cmd" diceerrors "github.com/dicedb/dice/internal/errors" "github.com/dicedb/dice/internal/eval/geo" @@ -5729,6 +5730,8 @@ func evalCommand(args []string, store *dstore.Store) *EvalResponse { return evalCommandInfo(args[1:]) case Docs: return evalCommandDocs(args[1:]) + case GetKeysandFlags: + return evalCommandKeyandFlags(args[1:]) default: return makeEvalError(diceerrors.ErrGeneral(fmt.Sprintf("unknown subcommand '%s'. Try COMMAND HELP.", subcommand))) } @@ -5886,6 +5889,61 @@ func evalCommandDocs(args []string) *EvalResponse { return makeEvalResult(result) } +func evalCommandKeyandFlags(args []string) *EvalResponse { + if len(args) == 0 { + return makeEvalError(diceerrors.ErrWrongArgumentCount("COMMAND|GETKEYSANDFLAGS")) + } + + diceCmd, ok := cmd.CommandRegistry.CommandMetas[strings.ToUpper(args[0])] + if !ok { + return makeEvalError(diceerrors.ErrGeneral("invalid command specified")) + } + + keySpecs := diceCmd.KeySpecs + if keySpecs.BeginIndex == 0 { + return makeEvalError(diceerrors.ErrGeneral("the command has no key arguments")) + } + + arity := diceCmd.Arity + if (arity < 0 && len(args) < arity) || + (arity >= 0 && len(args) != arity) { + return makeEvalError(diceerrors.ErrGeneral("invalid number of arguments specified for command")) + } + + if (flg.VARIABLEFLAGS)&(keySpecs.Flags) != 0 { + diceCmd.GetFlags(args, &keySpecs) + } + + // Output like + // [ + // [1, ["RW", "access", "update"]] + // ] + keysAndFlags := []interface{}{} + flagNames := make([]string, 0) + step := max(keySpecs.Step, 1) + + lastIdx := keySpecs.BeginIndex + if keySpecs.LastKey != 0 { + lastIdx = len(args) + keySpecs.LastKey + } + + flags := flg.GetFlags() + flagNameMap := flg.GetFlagsNameMap() + + for _, v := range flags { + if fname, ok := flagNameMap[v]; ok && (v&keySpecs.Flags) != 0 { + flagNames = append(flagNames, fname) + } + } + + for i := keySpecs.BeginIndex; i <= lastIdx; i += step { + r := []interface{}{i, flagNames} + keysAndFlags = append(keysAndFlags, r) + } + + return makeEvalResult(keysAndFlags) +} + func evalJSONARRINDEX(args []string, store *dstore.Store) *EvalResponse { if len(args) < 3 || len(args) > 5 { return makeEvalError(diceerrors.ErrWrongArgumentCount("JSON.ARRINDEX")) From 14d173887b9604282fc0e776049232fe509c5971 Mon Sep 17 00:00:00 2001 From: Vaibhav Yadav Date: Sun, 22 Jun 2025 12:27:10 +0530 Subject: [PATCH 2/2] Added test for COMMAND GETKEYSANDFLAGS (#642) --- internal/eval/eval_test.go | 59 +++++++++++++ tests0/command_getkeysandflags_test.go | 109 +++++++++++++++++++++++++ 2 files changed, 168 insertions(+) create mode 100644 tests0/command_getkeysandflags_test.go diff --git a/internal/eval/eval_test.go b/internal/eval/eval_test.go index 7b5b8d091..20fa572ff 100644 --- a/internal/eval/eval_test.go +++ b/internal/eval/eval_test.go @@ -5486,6 +5486,65 @@ func testEvalCOMMAND(t *testing.T, store *dstore.Store) { Error: diceerrors.ErrGeneral("unknown subcommand 'UNKNOWN'. Try COMMAND HELP."), }, }, + "command getKeysAndFlags (set)": { + input: []string{"GETKEYSANDFLAGS", "SET", "1", "2"}, + migratedOutput: EvalResponse{ + Result: []interface{}{ + []interface{}{ + 1, + []interface{}{ + "OW", + "update", + }, + }, + }, + Error: nil, + }, + }, + "command getKeysAndFlags (set with get as arg)": { + input: []string{"GETKEYSANDFLAGS", "SET", "1", "3", "GET"}, + migratedOutput: EvalResponse{ + Result: []interface{}{ + []interface{}{ + 1, + []interface{}{ + "RW", + "access", + "update", + }, + }, + }, + Error: nil, + }, + }, + "command getKeysAndFlags (No Args)": { + input: []string{"GETKEYSANDFLAGS"}, + migratedOutput: EvalResponse{ + Result: nil, + Error: diceerrors.ErrWrongArgumentCount("COMMAND|GETKEYSANDFLAGS"), + }, + }, + "command getKeysAndFlags (Invalid Command)": { + input: []string{"GETKEYSANDFLAGS", "GETA", "1"}, + migratedOutput: EvalResponse{ + Result: nil, + Error: diceerrors.ErrGeneral("invalid command specified"), + }, + }, + "command getKeysAndFlags (Command having no keys)": { + input: []string{"GETKEYSANDFLAGS", "PING"}, + migratedOutput: EvalResponse{ + Result: nil, + Error: diceerrors.ErrGeneral("the command has no key arguments"), + }, + }, + "command getKeysAndFlags (providing invalid number of args)": { + input: []string{"GETKEYSANDFLAGS", "SET", "1"}, + migratedOutput: EvalResponse{ + Result: nil, + Error: diceerrors.ErrGeneral("invalid number of arguments specified for command"), + }, + }, } runMigratedEvalTests(t, tests, evalCommand, store) diff --git a/tests0/command_getkeysandflags_test.go b/tests0/command_getkeysandflags_test.go new file mode 100644 index 000000000..236cfb80d --- /dev/null +++ b/tests0/command_getkeysandflags_test.go @@ -0,0 +1,109 @@ +package ironhawk + +import ( + "testing" + + "gotest.tools/v3/assert" +) + +var getKeysAndFlagsTestCases = []struct { + name string + inCmd string + expected interface{} +}{ + { + name: "Set command", + inCmd: "set 1 2", + expected: []interface{}{ + []interface{}{ + 1, + []interface{}{ + "OW", + "update", + }, + }, + }, + }, + { + name: "Get Command in Set", + inCmd: "set 1 2 get", + expected: []interface{}{ + []interface{}{ + 1, + []interface{}{ + "RW", + "access", + "update", + }, + }, + }, + }, + { + name: "DEL Command", + inCmd: "DEL 1 2", + expected: []interface{}{ + []interface{}{ + 1, + []interface{}{ + "RM", + "delete", + }, + }, + []interface{}{ + 2, + []interface{}{ + "RM", + "delete", + }, + }, + }, + }, + { + name: "DEL Command", + inCmd: "DEL 1 2", + expected: []interface{}{ + []interface{}{ + 1, + []interface{}{ + "RM", + "delete", + }, + }, + []interface{}{ + 2, + []interface{}{ + "RM", + "delete", + }, + }, + }, + }, + { + name: "PING Command", + inCmd: "PING", + expected: "ERR the command has no key arguments", + }, +} + +func TestCommandGetKeysAndFlags(t *testing.T) { + conn := getLocalConnection() + defer conn.Close() + for _, tc := range getKeysAndFlagsTestCases { + t.Run(tc.name, func(t *testing.T) { + result := conn.FireString("COMMAND GETKEYSANDFLAGS " + tc.inCmd) + assert.Equal(t, tc.expected, result) + }) + } +} + +func BenchmarkGetKeysAndFlagsMatch(b *testing.B) { + conn := getLocalConnection() + defer conn.Close() + + b.ResetTimer() + for i := 0; i < b.N; i++ { + for _, tc := range getKeysAndFlagsTestCases { + conn.FireString("COMMAND GETKEYS " + tc.inCmd) + } + } +}