From fbf4782b7c0573411134778bc18b6589d655a08e Mon Sep 17 00:00:00 2001 From: Kelvin Clement Mwinuka Date: Wed, 24 Apr 2024 16:34:59 +0800 Subject: [PATCH 1/6] Instead of passing in EchoVault instance to commands handler, we now pass a struct of params containing all the variables and functions used within the handler function. This removes the modules' dependency on the echovault package. Moved string command and api tests to test/modules/string --- internal/raft/fsm.go | 53 +++++++------- pkg/echovault/modules.go | 19 ++++- pkg/modules/string/commands.go | 58 ++++++++------- pkg/types/types.go | 26 ++++++- .../modules/string}/api_string_test.go | 53 ++++++++++---- {pkg => test}/modules/string/commands_test.go | 72 +++++++++++++++++-- 6 files changed, 205 insertions(+), 76 deletions(-) rename {pkg/echovault => test/modules/string}/api_string_test.go (87%) rename {pkg => test}/modules/string/commands_test.go (87%) diff --git a/internal/raft/fsm.go b/internal/raft/fsm.go index 1979e7eb..7619deea 100644 --- a/internal/raft/fsm.go +++ b/internal/raft/fsm.go @@ -86,33 +86,34 @@ func (fsm *FSM) Apply(log *raft.Log) interface{} { } case "command": + // TODO: Re-Implement Command handling with dependency injection // Handle command - command, err := fsm.options.GetCommand(request.CMD[0]) - if err != nil { - return internal.ApplyResponse{ - Error: err, - Response: nil, - } - } - - handler := command.HandlerFunc - - subCommand, ok := internal.GetSubCommand(command, request.CMD).(types.SubCommand) - if ok { - handler = subCommand.HandlerFunc - } - - if res, err := handler(ctx, request.CMD, fsm.options.EchoVault, nil); err != nil { - return internal.ApplyResponse{ - Error: err, - Response: nil, - } - } else { - return internal.ApplyResponse{ - Error: nil, - Response: res, - } - } + // command, err := fsm.options.GetCommand(request.CMD[0]) + // if err != nil { + // return internal.ApplyResponse{ + // Error: err, + // Response: nil, + // } + // } + // + // handler := command.HandlerFunc + // + // subCommand, ok := internal.GetSubCommand(command, request.CMD).(types.SubCommand) + // if ok { + // handler = subCommand.HandlerFunc + // } + // + // if res, err := handler(ctx, request.CMD, fsm.options.EchoVault, nil); err != nil { + // return internal.ApplyResponse{ + // Error: err, + // Response: nil, + // } + // } else { + // return internal.ApplyResponse{ + // Error: nil, + // Response: res, + // } + // } } } diff --git a/pkg/echovault/modules.go b/pkg/echovault/modules.go index 2baeb0a9..0f02e3ea 100644 --- a/pkg/echovault/modules.go +++ b/pkg/echovault/modules.go @@ -46,6 +46,23 @@ func (server *EchoVault) getCommand(cmd string) (types.Command, error) { return types.Command{}, fmt.Errorf("command %s not supported", cmd) } +func (server *EchoVault) getHandlerFuncParams(ctx context.Context, cmd []string, conn *net.Conn) types.HandlerFuncParams { + return types.HandlerFuncParams{ + // TODO: Add all the required methods here + Context: ctx, + Command: cmd, + Connection: conn, + KeyExists: server.KeyExists, + CreateKeyAndLock: server.CreateKeyAndLock, + KeyLock: server.KeyLock, + KeyRLock: server.KeyRLock, + KeyUnlock: server.KeyUnlock, + KeyRUnlock: server.KeyRUnlock, + GetValue: server.GetValue, + SetValue: server.SetValue, + } +} + func (server *EchoVault) handleCommand(ctx context.Context, message []byte, conn *net.Conn, replay bool, embedded bool) ([]byte, error) { cmd, err := internal.Decode(message) if err != nil { @@ -85,7 +102,7 @@ func (server *EchoVault) handleCommand(ctx context.Context, message []byte, conn } if !server.isInCluster() || !synchronize { - res, err := handler(ctx, cmd, server, conn) + res, err := handler(server.getHandlerFuncParams(ctx, cmd, conn)) if err != nil { return nil, err } diff --git a/pkg/modules/string/commands.go b/pkg/modules/string/commands.go index b1586a88..346d5c6e 100644 --- a/pkg/modules/string/commands.go +++ b/pkg/modules/string/commands.go @@ -15,47 +15,45 @@ package str import ( - "context" "errors" "fmt" "github.com/echovault/echovault/internal" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/types" - "net" ) -func handleSetRange(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := setRangeKeyFunc(cmd) +func handleSetRange(params types.HandlerFuncParams) ([]byte, error) { + keys, err := setRangeKeyFunc(params.Command) if err != nil { return nil, err } key := keys.WriteKeys[0] - offset, ok := internal.AdaptType(cmd[2]).(int) + offset, ok := internal.AdaptType(params.Command[2]).(int) if !ok { return nil, errors.New("offset must be an integer") } - newStr := cmd[3] + newStr := params.Command[3] - if !server.KeyExists(ctx, key) { - if _, err = server.CreateKeyAndLock(ctx, key); err != nil { + if !params.KeyExists(params.Context, key) { + if _, err = params.CreateKeyAndLock(params.Context, key); err != nil { return nil, err } - if err = server.SetValue(ctx, key, newStr); err != nil { + if err = params.SetValue(params.Context, key, newStr); err != nil { return nil, err } - server.KeyUnlock(ctx, key) + params.KeyUnlock(params.Context, key) return []byte(fmt.Sprintf(":%d\r\n", len(newStr))), nil } - if _, err := server.KeyLock(ctx, key); err != nil { + if _, err := params.KeyLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) - str, ok := server.GetValue(ctx, key).(string) + str, ok := params.GetValue(params.Context, key).(string) if !ok { return nil, fmt.Errorf("value at key %s is not a string", key) } @@ -63,7 +61,7 @@ func handleSetRange(ctx context.Context, cmd []string, server types.EchoVault, _ // If the offset >= length of the string, append the new string to the old one. if offset >= len(str) { newStr = str + newStr - if err = server.SetValue(ctx, key, newStr); err != nil { + if err = params.SetValue(params.Context, key, newStr); err != nil { return nil, err } return []byte(fmt.Sprintf(":%d\r\n", len(newStr))), nil @@ -72,7 +70,7 @@ func handleSetRange(ctx context.Context, cmd []string, server types.EchoVault, _ // If the offset is < 0, prepend the new string to the old one. if offset < 0 { newStr = newStr + str - if err = server.SetValue(ctx, key, newStr); err != nil { + if err = params.SetValue(params.Context, key, newStr); err != nil { return nil, err } return []byte(fmt.Sprintf(":%d\r\n", len(newStr))), nil @@ -92,31 +90,31 @@ func handleSetRange(ctx context.Context, cmd []string, server types.EchoVault, _ break } - if err = server.SetValue(ctx, key, string(strRunes)); err != nil { + if err = params.SetValue(params.Context, key, string(strRunes)); err != nil { return nil, err } return []byte(fmt.Sprintf(":%d\r\n", len(strRunes))), nil } -func handleStrLen(ctx context.Context, cmd []string, server types.EchoVault, conn *net.Conn) ([]byte, error) { - keys, err := strLenKeyFunc(cmd) +func handleStrLen(params types.HandlerFuncParams) ([]byte, error) { + keys, err := strLenKeyFunc(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte(":0\r\n"), nil } - if _, err := server.KeyRLock(ctx, key); err != nil { + if _, err := params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - value, ok := server.GetValue(ctx, key).(string) + value, ok := params.GetValue(params.Context, key).(string) if !ok { return nil, fmt.Errorf("value at key %s is not a string", key) @@ -125,32 +123,32 @@ func handleStrLen(ctx context.Context, cmd []string, server types.EchoVault, con return []byte(fmt.Sprintf(":%d\r\n", len(value))), nil } -func handleSubStr(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := subStrKeyFunc(cmd) +func handleSubStr(params types.HandlerFuncParams) ([]byte, error) { + keys, err := subStrKeyFunc(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] - start, startOk := internal.AdaptType(cmd[2]).(int) - end, endOk := internal.AdaptType(cmd[3]).(int) + start, startOk := internal.AdaptType(params.Command[2]).(int) + end, endOk := internal.AdaptType(params.Command[3]).(int) reversed := false if !startOk || !endOk { return nil, errors.New("start and end indices must be integers") } - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return nil, fmt.Errorf("key %s does not exist", key) } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - value, ok := server.GetValue(ctx, key).(string) + value, ok := params.GetValue(params.Context, key).(string) if !ok { return nil, fmt.Errorf("value at key %s is not a string", key) } diff --git a/pkg/types/types.go b/pkg/types/types.go index 8a53730c..8e867dfa 100644 --- a/pkg/types/types.go +++ b/pkg/types/types.go @@ -50,7 +50,31 @@ type AccessKeys struct { } type KeyExtractionFunc func(cmd []string) (AccessKeys, error) -type HandlerFunc func(ctx context.Context, cmd []string, echovault EchoVault, conn *net.Conn) ([]byte, error) +type HandlerFuncParams struct { + Context context.Context + Command []string + Connection *net.Conn + KeyLock func(ctx context.Context, key string) (bool, error) + KeyUnlock func(ctx context.Context, key string) + KeyRLock func(ctx context.Context, key string) (bool, error) + KeyRUnlock func(ctx context.Context, key string) + KeyExists func(ctx context.Context, key string) bool + CreateKeyAndLock func(ctx context.Context, key string) (bool, error) + GetValue func(ctx context.Context, key string) interface{} + SetValue func(ctx context.Context, key string, value interface{}) error + GetExpiry func(ctx context.Context, key string) time.Time + SetExpiry func(ctx context.Context, key string, expire time.Time, touch bool) + RemoveExpiry func(key string) + DeleteKey func(ctx context.Context, key string) error + GetClock func() clock.Clock + GetAllCommands func() []Command + GetACL func() interface{} + GetPubSub func() interface{} + TakeSnapshot func() error + RewriteAOF func() error + GetLatestSnapshotTime func() int64 +} +type HandlerFunc func(params HandlerFuncParams) ([]byte, error) type SubCommand struct { Command string diff --git a/pkg/echovault/api_string_test.go b/test/modules/string/api_string_test.go similarity index 87% rename from pkg/echovault/api_string_test.go rename to test/modules/string/api_string_test.go index 499f1dbb..9526bce0 100644 --- a/pkg/echovault/api_string_test.go +++ b/test/modules/string/api_string_test.go @@ -12,19 +12,32 @@ // See the License for the specific language governing permissions and // limitations under the License. -package echovault +package str import ( + "context" "github.com/echovault/echovault/internal/config" - "github.com/echovault/echovault/pkg/commands" "github.com/echovault/echovault/pkg/constants" + "github.com/echovault/echovault/pkg/echovault" + str "github.com/echovault/echovault/pkg/modules/string" "testing" ) +func presetValue(server *echovault.EchoVault, ctx context.Context, key string, value interface{}) error { + if _, err := server.CreateKeyAndLock(ctx, key); err != nil { + return err + } + if err := server.SetValue(ctx, key, value); err != nil { + return err + } + server.KeyUnlock(ctx, key) + return nil +} + func TestEchoVault_SUBSTR(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ + server, _ := echovault.NewEchoVault( + echovault.WithCommands(str.Commands()), + echovault.WithConfig(config.Config{ DataDir: "", EvictionPolicy: constants.NoEviction, }), @@ -168,7 +181,11 @@ func TestEchoVault_SUBSTR(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.presetValue != nil { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := tt.substrFunc(tt.key, tt.start, tt.end) if (err != nil) != tt.wantErr { @@ -183,9 +200,9 @@ func TestEchoVault_SUBSTR(t *testing.T) { } func TestEchoVault_SETRANGE(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ + server, _ := echovault.NewEchoVault( + echovault.WithCommands(str.Commands()), + echovault.WithConfig(config.Config{ DataDir: "", EvictionPolicy: constants.NoEviction, }), @@ -258,7 +275,11 @@ func TestEchoVault_SETRANGE(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.presetValue != nil { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.SETRANGE(tt.key, tt.offset, tt.new) if (err != nil) != tt.wantErr { @@ -273,9 +294,9 @@ func TestEchoVault_SETRANGE(t *testing.T) { } func TestEchoVault_STRLEN(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ + server, _ := echovault.NewEchoVault( + echovault.WithCommands(str.Commands()), + echovault.WithConfig(config.Config{ DataDir: "", EvictionPolicy: constants.NoEviction, }), @@ -306,7 +327,11 @@ func TestEchoVault_STRLEN(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.presetValue != nil { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.STRLEN(tt.key) if (err != nil) != tt.wantErr { diff --git a/pkg/modules/string/commands_test.go b/test/modules/string/commands_test.go similarity index 87% rename from pkg/modules/string/commands_test.go rename to test/modules/string/commands_test.go index 1851c352..22ce5179 100644 --- a/pkg/modules/string/commands_test.go +++ b/test/modules/string/commands_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package str +package str_test import ( "bytes" @@ -23,8 +23,11 @@ import ( "github.com/echovault/echovault/internal/config" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/echovault" + str "github.com/echovault/echovault/pkg/modules/string" + "github.com/echovault/echovault/pkg/types" "github.com/tidwall/resp" "strconv" + "strings" "testing" ) @@ -32,6 +35,7 @@ var mockServer *echovault.EchoVault func init() { mockServer, _ = echovault.NewEchoVault( + echovault.WithCommands(str.Commands()), echovault.WithConfig(config.Config{ DataDir: "", EvictionPolicy: constants.NoEviction, @@ -39,6 +43,15 @@ func init() { ) } +func getHandler(command string) types.HandlerFunc { + for _, c := range mockServer.GetAllCommands() { + if strings.EqualFold(command, c.Command) { + return c.HandlerFunc + } + } + return nil +} + func Test_HandleSetRange(t *testing.T) { tests := []struct { name string @@ -157,7 +170,24 @@ func Test_HandleSetRange(t *testing.T) { mockServer.KeyUnlock(ctx, test.key) } - res, err := handleSetRange(ctx, test.command, mockServer, nil) + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(types.HandlerFuncParams{ + Context: ctx, + Command: test.command, + Connection: nil, + KeyExists: mockServer.KeyExists, + CreateKeyAndLock: mockServer.CreateKeyAndLock, + KeyLock: mockServer.KeyLock, + KeyUnlock: mockServer.KeyUnlock, + GetValue: mockServer.GetValue, + SetValue: mockServer.SetValue, + }) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -254,7 +284,24 @@ func Test_HandleStrLen(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleStrLen(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(types.HandlerFuncParams{ + Context: ctx, + Command: test.command, + Connection: nil, + KeyExists: mockServer.KeyExists, + KeyRLock: mockServer.KeyRLock, + KeyRUnlock: mockServer.KeyRUnlock, + GetValue: mockServer.GetValue, + SetValue: mockServer.SetValue, + }) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -382,7 +429,24 @@ func Test_HandleSubStr(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleSubStr(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(types.HandlerFuncParams{ + Context: ctx, + Command: test.command, + Connection: nil, + KeyExists: mockServer.KeyExists, + KeyRLock: mockServer.KeyRLock, + KeyRUnlock: mockServer.KeyRUnlock, + GetValue: mockServer.GetValue, + SetValue: mockServer.SetValue, + }) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) From 3e04b7a822d10c060392dac8e71ada5d23004276 Mon Sep 17 00:00:00 2001 From: Kelvin Clement Mwinuka Date: Wed, 24 Apr 2024 21:36:59 +0800 Subject: [PATCH 2/6] Moved tests for module commands and apis into 'test' folder --- Makefile | 2 +- coverage/coverage.out | 3138 ----------------- internal/raft/fsm.go | 55 +- internal/raft/raft.go | 2 + pkg/echovault/echovault.go | 1 + pkg/echovault/modules.go | 8 +- pkg/modules/acl/commands.go | 76 +- pkg/modules/admin/commands.go | 54 +- pkg/modules/connection/commands.go | 10 +- pkg/modules/generic/commands.go | 212 +- pkg/modules/generic/utils.go | 76 +- pkg/modules/hash/commands.go | 192 +- pkg/modules/list/commands.go | 202 +- pkg/modules/pubsub/commands.go | 52 +- pkg/modules/set/commands.go | 294 +- pkg/modules/sorted_set/commands.go | 520 ++- .../modules/acl}/api_acl_test.go | 2 +- {pkg => test}/modules/acl/commands_test.go | 3 +- .../modules/admin}/api_admin_test.go | 2 +- {pkg => test}/modules/admin/commands_test.go | 46 +- .../connection}/api_connection_test.go | 2 +- .../modules/connection/commands_test.go | 36 +- .../modules/generic}/api_generic_test.go | 207 +- .../modules/generic/commands_test.go | 146 +- .../modules/hash}/api_hash_test.go | 182 +- {pkg => test}/modules/hash/commands_test.go | 153 +- .../modules/list}/api_list_test.go | 166 +- {pkg => test}/modules/list/commands_test.go | 216 +- .../modules/pubsub}/api_pubsub_test.go | 2 +- {pkg => test}/modules/pubsub/commands_test.go | 97 +- .../modules/set}/api_set_test.go | 250 +- .../modules/set/commands_test.go | 193 +- .../sorted_set}/api_sorted_set_test.go | 498 ++- .../modules/sorted_set/commands_test.go | 272 +- test/modules/string/api_string_test.go | 35 +- test/modules/string/commands_test.go | 69 +- 36 files changed, 2559 insertions(+), 4912 deletions(-) rename {pkg/echovault => test/modules/acl}/api_acl_test.go (97%) rename {pkg => test}/modules/acl/commands_test.go (99%) rename {pkg/echovault => test/modules/admin}/api_admin_test.go (97%) rename {pkg => test}/modules/admin/commands_test.go (51%) rename {pkg/echovault => test/modules/connection}/api_connection_test.go (96%) rename {pkg => test}/modules/connection/commands_test.go (68%) rename {pkg/echovault => test/modules/generic}/api_generic_test.go (85%) rename {pkg => test}/modules/generic/commands_test.go (92%) rename {pkg/echovault => test/modules/hash}/api_hash_test.go (87%) rename {pkg => test}/modules/hash/commands_test.go (92%) rename {pkg/echovault => test/modules/list}/api_list_test.go (91%) rename {pkg => test}/modules/list/commands_test.go (90%) rename {pkg/echovault => test/modules/pubsub}/api_pubsub_test.go (97%) rename {pkg => test}/modules/pubsub/commands_test.go (85%) rename {pkg/echovault => test/modules/set}/api_set_test.go (90%) rename pkg/modules/set/commant_test.go => test/modules/set/commands_test.go (93%) rename {pkg/echovault => test/modules/sorted_set}/api_sorted_set_test.go (91%) rename {pkg => test}/modules/sorted_set/commands_test.go (96%) diff --git a/Makefile b/Makefile index 61b39bc0..7b76abbd 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ build: run: make build && docker-compose up --build -test: +test-normal: go clean -testcache && go test ./... -coverprofile coverage/coverage.out test-race: diff --git a/coverage/coverage.out b/coverage/coverage.out index ec87e687..5f02b111 100644 --- a/coverage/coverage.out +++ b/coverage/coverage.out @@ -1,3139 +1 @@ mode: set -github.com/echovault/echovault/pkg/modules/acl/commands.go:34.108,35.34 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:35.34,37.3 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:38.2,39.9 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:39.9,41.3 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:42.2,42.67 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:42.67,44.3 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:45.2,45.42 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:48.106,49.19 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:49.19,51.3 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:53.2,54.9 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:54.9,56.3 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:58.2,60.30 3 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:60.30,61.27 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:61.27,64.9 3 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:68.2,68.16 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:68.16,70.3 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:73.2,77.18 3 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:77.18,79.3 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:79.8,81.3 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:82.2,82.21 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:82.21,84.3 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:85.2,85.17 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:85.17,87.3 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:89.2,90.29 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:90.29,92.3 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:95.2,96.51 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:96.51,97.22 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:97.22,99.12 2 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:101.3,101.49 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:103.2,103.51 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:103.51,104.22 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:104.22,106.12 2 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:108.3,108.49 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:112.2,113.48 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:113.48,114.21 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:114.21,116.12 2 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:118.3,118.47 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:120.2,120.48 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:120.48,121.21 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:121.21,123.12 2 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:125.3,125.47 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:129.2,130.79 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:130.79,131.37 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:131.37,133.4 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:135.2,136.30 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:136.30,137.10 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:138.100,140.53 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:141.53,143.52 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:144.52,146.52 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:151.2,153.54 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:153.54,155.3 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:156.2,156.54 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:156.54,158.3 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:160.2,162.25 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:165.102,166.18 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:166.18,168.3 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:170.2,174.35 3 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:174.35,175.36 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:175.36,176.48 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:176.48,178.5 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:179.4,179.12 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:181.3,181.50 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:181.50,182.51 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:182.51,185.5 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:189.2,189.19 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:189.19,192.34 3 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:192.34,195.4 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:196.3,197.28 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:197.28,199.24 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:199.24,201.5 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:203.3,203.26 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:206.2,206.19 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:206.19,208.46 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:208.46,209.43 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:209.43,211.38 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:211.38,213.30 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:213.30,215.7 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:217.5,217.28 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:222.2,222.74 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:225.102,227.9 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:227.9,229.3 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:230.2,231.33 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:231.33,233.3 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:234.2,235.25 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:238.106,240.9 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:240.9,242.3 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:243.2,243.45 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:243.45,245.3 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:246.2,246.42 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:249.108,250.18 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:250.18,252.3 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:253.2,254.9 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:254.9,256.3 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:257.2,257.53 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:257.53,259.3 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:260.2,260.42 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:263.106,265.9 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:265.9,267.3 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:268.2,269.74 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:272.103,273.18 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:273.18,275.3 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:276.2,277.9 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:277.9,279.3 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:280.2,282.33 3 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:282.33,285.19 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:285.19,287.4 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:287.9,289.4 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:291.3,291.22 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:291.22,293.4 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:295.3,295.18 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:295.18,297.4 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:299.3,299.43 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:299.43,300.61 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:300.61,302.5 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:303.4,303.58 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:303.58,305.5 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:308.3,308.52 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:308.52,309.23 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:309.23,311.13 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:313.4,313.39 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:316.3,316.52 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:316.52,317.23 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:317.23,319.13 2 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:321.4,321.39 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:324.3,324.49 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:324.49,325.22 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:325.22,327.13 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:329.4,329.37 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:332.3,332.49 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:332.49,333.22 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:333.22,335.13 2 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:337.4,337.37 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:340.3,340.45 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:340.45,341.52 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:341.52,343.13 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:345.4,345.41 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:348.3,348.45 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:348.45,349.52 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:349.52,351.5 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:354.3,354.55 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:354.55,356.4 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:358.3,358.55 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:358.55,360.4 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:361.3,361.54 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:364.2,365.25 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:368.103,369.19 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:369.19,371.3 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:373.2,374.9 2 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:374.9,376.3 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:378.2,382.16 4 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:382.16,384.3 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:386.2,386.15 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:386.15,387.35 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:387.35,389.4 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:392.2,396.20 3 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:396.20,397.59 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:397.59,399.4 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:402.2,402.37 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:402.37,403.59 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:403.59,405.4 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:409.2,409.29 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:409.29,413.31 3 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:413.31,414.35 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:414.35,417.43 2 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:417.43,419.6 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:419.11,422.6 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:423.5,423.10 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:427.3,427.17 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:427.17,429.4 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:432.2,432.42 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:435.103,436.18 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:436.18,438.3 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:440.2,441.9 2 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:441.9,443.3 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:445.2,449.16 4 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:449.16,451.3 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:453.2,453.15 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:453.15,454.35 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:454.35,456.4 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:459.2,461.20 2 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:461.20,464.17 2 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:464.17,466.4 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:467.3,468.17 2 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:468.17,470.4 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:473.2,473.37 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:473.37,476.17 2 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:476.17,478.4 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:479.3,480.17 2 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:480.17,482.4 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:485.2,486.16 2 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:486.16,488.3 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:490.2,490.42 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:493.33,501.68 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:501.68,507.5 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:516.68,522.5 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:531.70,537.7 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:546.70,552.7 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:561.70,567.7 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:576.70,582.7 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:591.70,597.7 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:606.70,612.7 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:621.70,627.7 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:639.70,645.7 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:654.70,660.7 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:30.105,32.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:32.16,34.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:36.2,38.33 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:38.33,41.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:43.2,43.52 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:43.52,45.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:46.2,48.63 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:48.63,50.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:52.2,52.57 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:55.107,57.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:57.16,59.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:61.2,64.9 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:64.9,66.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:68.2,68.33 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:68.33,70.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:72.2,72.52 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:72.52,74.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:75.2,78.9 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:78.9,80.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:82.2,82.40 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:82.40,84.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:86.2,86.57 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:89.107,91.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:91.16,93.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:95.2,99.24 4 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:99.24,101.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:103.2,103.33 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:103.33,105.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:107.2,107.52 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:107.52,109.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:110.2,113.9 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:113.9,115.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:118.2,118.40 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:118.40,120.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:123.2,123.51 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:123.51,125.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:127.2,130.15 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:130.15,132.43 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:132.43,135.4 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:136.3,136.20 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:140.2,140.18 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:140.18,142.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:147.2,151.17 4 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:151.17,153.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:155.2,155.13 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:155.13,158.18 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:158.18,160.4 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:160.9,162.4 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:165.2,165.19 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:168.105,170.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:170.16,172.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:174.2,177.9 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:177.9,179.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:181.2,181.33 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:181.33,183.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:185.2,185.51 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:185.51,187.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:188.2,191.9 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:191.9,193.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:195.2,195.40 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:195.40,197.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:199.2,200.55 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:200.55,202.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:204.2,204.42 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:207.106,209.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:209.16,211.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:213.2,217.24 4 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:217.24,219.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:221.2,221.30 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:221.30,223.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:225.2,225.33 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:225.33,227.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:229.2,229.51 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:229.51,231.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:232.2,235.9 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:235.9,237.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:239.2,239.40 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:239.40,241.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:243.2,243.34 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:243.34,244.64 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:244.64,246.4 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:247.3,247.43 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:250.2,250.66 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:250.66,252.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:253.2,253.42 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:256.105,258.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:258.16,260.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:262.2,266.9 4 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:266.9,268.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:270.2,272.33 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:272.33,274.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:276.2,276.51 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:276.51,278.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:279.2,282.9 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:282.9,284.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:286.2,286.9 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:287.10,287.10 0 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:289.17,291.34 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:291.34,292.26 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:292.26,293.10 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:295.4,295.43 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:295.43,298.5 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:300.17,302.39 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:302.39,303.26 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:303.26,304.10 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:306.4,306.43 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:306.43,309.5 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:313.2,313.61 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:313.61,315.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:317.2,317.55 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:317.55,319.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:321.2,321.42 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:324.106,326.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:326.16,328.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:330.2,334.116 4 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:334.116,336.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:338.2,338.75 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:338.75,340.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:342.2,342.54 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:342.54,344.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:345.2,348.16 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:348.16,350.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:351.2,356.33 4 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:356.33,358.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:360.2,360.19 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:361.14,363.24 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:363.24,365.4 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:365.9,365.32 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:365.32,367.4 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:368.15,370.24 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:370.24,372.4 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:372.9,372.32 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:372.32,374.4 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:377.2,377.16 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:377.16,379.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:381.2,381.42 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:384.106,386.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:386.16,388.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:390.2,392.31 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:392.31,394.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:396.2,398.33 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:398.33,399.34 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:400.17,401.61 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:402.11,403.62 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:403.62,405.5 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:406.4,406.68 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:406.68,408.5 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:410.8,411.52 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:411.52,413.4 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:415.2,420.9 4 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:420.9,422.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:424.2,424.73 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:424.73,426.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:427.2,427.42 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:430.106,432.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:432.16,434.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:436.2,440.31 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:440.31,442.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:444.2,444.33 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:444.33,445.34 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:446.17,447.61 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:448.11,449.62 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:449.62,451.5 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:452.4,453.68 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:453.68,455.5 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:457.8,458.52 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:458.52,460.4 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:461.3,461.35 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:464.2,468.9 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:468.9,470.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:472.2,472.73 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:472.73,474.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:475.2,475.42 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:478.104,480.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:480.16,482.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:484.2,486.33 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:486.33,488.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:490.2,490.51 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:490.51,492.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:493.2,496.9 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:496.9,498.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:500.2,500.33 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:501.10,502.60 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:502.60,504.4 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:505.3,505.54 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:506.14,507.70 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:507.70,509.4 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:510.3,510.64 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:514.33,634.2 1 0 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:23.59,24.18 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:24.18,26.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:27.2,31.8 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:34.57,35.19 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:35.19,37.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:38.2,42.8 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:45.58,46.19 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:46.19,48.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:49.2,53.8 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:56.60,57.19 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:57.19,59.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:60.2,64.8 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:67.60,68.19 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:68.19,70.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:71.2,75.8 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:78.58,79.19 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:79.19,81.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:82.2,86.8 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:89.59,90.19 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:90.19,92.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:93.2,97.8 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:100.58,101.19 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:101.19,103.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:104.2,108.8 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:111.59,112.18 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:112.18,114.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:115.2,119.8 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:122.59,123.19 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:123.19,125.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:126.2,130.8 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:36.104,38.16 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:38.16,40.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:42.2,48.16 6 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:48.16,50.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:54.2,54.16 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:54.16,55.34 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:55.34,57.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:57.9,59.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:62.2,62.44 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:62.44,64.34 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:64.34,66.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:67.3,67.36 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:68.8,68.51 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:68.51,70.33 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:70.33,72.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:73.3,73.45 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:74.8,76.34 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:76.34,79.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:79.9,82.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:84.2,84.16 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:84.16,86.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:87.2,89.76 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:89.76,91.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:94.2,94.28 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:94.28,96.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:98.2,98.17 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:101.105,103.16 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:103.16,105.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:107.2,110.15 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:110.15,111.29 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:111.29,112.16 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:112.16,118.5 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:123.2,123.30 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:123.30,124.15 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:124.15,129.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:134.2,134.28 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:134.28,135.31 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:135.31,136.52 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:136.52,138.5 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:139.4,140.12 2 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:142.3,142.60 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:142.60,144.4 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:145.3,145.55 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:149.2,149.28 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:149.28,150.58 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:150.58,152.4 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:155.2,155.42 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:158.104,160.16 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:160.16,162.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:163.2,165.33 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:165.33,167.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:169.2,170.16 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:170.16,172.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:173.2,177.51 3 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:180.105,182.16 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:182.16,184.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:186.2,189.36 3 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:189.36,190.31 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:190.31,192.12 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:194.3,194.33 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:194.33,196.18 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:196.18,198.5 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:199.4,200.12 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:202.3,202.19 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:204.2,204.15 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:204.15,205.34 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:205.34,206.14 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:206.14,209.5 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:213.2,213.28 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:213.28,215.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:217.2,219.30 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:219.30,220.24 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:220.24,222.12 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:224.3,224.96 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:227.2,227.19 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:230.104,232.16 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:232.16,234.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:235.2,236.37 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:236.37,238.17 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:238.17,240.12 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:242.3,242.13 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:244.2,244.51 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:247.108,249.16 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:249.16,251.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:253.2,255.33 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:255.33,257.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:259.2,259.51 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:259.51,261.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:262.2,265.31 3 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:265.31,267.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:269.2,271.30 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:274.111,276.16 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:276.16,278.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:280.2,282.33 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:282.33,284.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:286.2,286.52 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:286.52,288.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:289.2,293.31 3 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:293.31,295.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:297.2,298.46 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:298.46,300.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:302.2,302.47 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:305.104,307.16 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:307.16,309.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:311.2,315.33 3 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:315.33,317.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:319.2,319.52 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:319.52,321.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:322.2,326.31 3 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:326.31,328.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:330.2,331.39 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:331.39,333.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:335.2,335.12 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:335.12,337.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:339.2,339.47 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:342.107,344.16 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:344.16,346.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:348.2,352.16 3 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:352.16,354.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:355.2,356.42 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:356.42,358.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:360.2,360.33 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:360.33,362.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:364.2,364.51 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:364.51,366.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:367.2,369.19 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:369.19,372.3 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:374.2,376.33 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:377.12,378.39 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:378.39,380.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:381.3,381.46 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:382.12,383.39 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:383.39,385.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:386.3,386.46 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:387.12,388.39 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:388.39,390.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:391.3,391.39 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:391.39,393.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:394.3,394.46 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:395.12,396.39 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:396.39,397.40 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:397.40,399.5 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:400.4,400.47 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:402.3,402.46 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:403.10,404.71 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:407.2,407.30 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:410.109,412.16 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:412.16,414.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:416.2,420.16 3 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:420.16,422.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:423.2,424.44 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:424.44,426.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:428.2,428.33 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:428.33,430.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:432.2,432.51 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:432.51,434.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:435.2,437.19 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:437.19,440.3 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:442.2,444.33 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:445.12,446.39 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:446.39,448.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:449.3,449.46 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:450.12,451.39 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:451.39,453.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:454.3,454.46 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:455.12,456.39 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:456.39,458.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:459.3,459.39 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:459.39,461.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:462.3,462.46 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:463.12,464.39 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:464.39,465.40 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:465.40,467.5 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:468.4,468.47 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:470.3,470.46 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:471.10,472.71 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:475.2,475.30 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:478.33,647.2 1 0 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:23.57,24.34 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:24.34,26.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:27.2,31.8 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:34.58,35.25 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:35.25,37.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:38.2,39.30 2 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:39.30,40.15 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:40.15,42.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:44.2,48.8 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:51.57,52.19 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:52.19,54.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:55.2,59.8 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:62.58,63.18 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:63.18,65.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:66.2,70.8 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:73.57,74.18 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:74.18,76.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:77.2,81.8 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:84.61,85.19 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:85.19,87.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:88.2,92.8 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:95.64,96.19 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:96.19,98.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:99.2,103.8 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:106.57,107.19 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:107.19,109.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:110.2,114.8 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:117.60,118.34 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:118.34,120.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:121.2,125.8 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:128.62,129.34 1 0 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:129.34,131.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:132.2,136.8 1 0 -github.com/echovault/echovault/pkg/modules/generic/utils.go:32.96,33.19 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:33.19,35.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:36.2,36.33 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:37.13,39.53 2 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:41.12,42.26 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:42.26,44.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:45.3,46.53 2 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:48.12,49.26 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:49.26,51.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:52.3,53.53 2 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:55.12,56.19 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:56.19,58.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:59.3,59.29 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:59.29,61.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:62.3,64.17 3 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:64.17,66.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:67.3,68.53 2 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:70.12,71.19 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:71.19,73.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:74.3,74.29 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:74.29,76.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:77.3,79.17 3 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:79.17,81.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:82.3,83.53 2 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:85.14,86.19 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:86.19,88.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:89.3,89.29 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:89.29,91.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:92.3,94.17 3 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:94.17,96.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:97.3,98.53 2 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:100.14,101.19 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:101.19,103.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:104.3,104.29 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:104.29,106.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:107.3,109.17 3 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:109.17,111.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:112.3,113.53 2 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:115.10,116.95 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:31.105,33.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:33.16,35.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:37.2,40.25 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:40.25,42.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:44.2,44.38 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:44.38,46.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:48.2,48.33 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:48.33,50.17 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:50.17,52.4 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:53.3,54.59 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:54.59,56.4 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:57.3,57.59 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:60.2,60.51 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:60.51,62.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:63.2,66.9 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:66.9,68.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:70.2,71.36 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:71.36,72.42 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:72.42,73.26 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:73.26,76.5 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:77.4,77.12 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:79.3,80.13 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:82.2,82.55 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:82.55,84.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:86.2,86.51 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:89.105,91.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:91.16,93.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:95.2,98.33 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:98.33,100.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:102.2,102.52 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:102.52,104.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:105.2,108.9 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:108.9,110.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:112.2,115.31 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:115.31,117.19 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:117.19,119.12 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:121.3,121.34 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:121.34,123.12 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:125.3,125.31 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:125.31,127.12 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:129.3,129.35 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:129.35,132.12 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:134.3,134.32 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:137.2,137.25 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:140.108,142.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:142.16,144.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:146.2,149.33 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:149.33,151.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:153.2,153.52 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:153.52,155.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:156.2,159.9 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:159.9,161.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:163.2,166.31 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:166.31,168.19 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:168.19,170.12 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:172.3,172.34 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:172.34,174.12 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:176.3,176.35 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:176.35,179.12 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:181.3,181.31 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:181.31,183.12 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:185.3,185.18 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:188.2,188.25 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:191.106,193.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:193.16,195.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:197.2,199.33 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:199.33,201.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:203.2,203.52 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:203.52,205.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:206.2,209.9 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:209.9,211.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:213.2,214.27 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:214.27,215.32 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:215.32,217.12 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:219.3,219.33 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:219.33,222.12 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:224.3,224.29 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:224.29,226.4 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:229.2,229.25 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:232.111,234.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:234.16,236.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:238.2,241.19 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:241.19,243.17 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:243.17,245.4 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:246.3,246.13 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:246.13,248.4 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:249.3,249.12 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:252.2,253.19 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:253.19,254.46 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:254.46,256.4 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:256.9,258.4 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:261.2,261.33 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:261.33,263.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:265.2,265.52 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:265.52,267.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:268.2,271.9 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:271.9,273.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:276.2,276.24 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:276.24,278.17 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:278.17,280.4 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:281.3,281.34 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:281.34,283.18 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:283.18,284.36 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:284.36,286.14 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:288.5,288.37 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:288.37,291.14 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:293.5,293.33 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:293.33,295.14 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:299.3,299.26 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:303.2,304.29 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:304.29,306.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:309.2,311.46 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:311.46,315.16 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:315.16,316.59 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:316.59,318.5 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:322.2,323.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:323.16,325.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:326.2,326.38 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:326.38,328.17 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:328.17,329.41 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:329.41,331.13 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:333.4,333.42 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:333.42,336.13 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:338.4,338.38 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:338.38,340.13 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:345.2,345.25 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:348.105,350.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:350.16,352.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:354.2,356.33 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:356.33,358.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:360.2,360.52 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:360.52,362.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:363.2,366.9 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:366.9,368.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:370.2,370.55 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:373.106,375.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:375.16,377.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:379.2,381.33 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:381.33,383.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:385.2,385.52 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:385.52,387.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:388.2,391.9 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:391.9,393.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:395.2,396.29 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:396.29,398.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:400.2,400.25 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:403.108,405.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:405.16,407.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:409.2,415.47 5 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:415.47,417.17 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:417.17,419.4 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:420.3,420.21 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:421.8,423.17 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:423.17,425.4 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:426.3,426.19 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:429.2,429.33 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:429.33,430.62 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:430.62,432.4 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:433.3,435.48 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:435.48,437.57 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:437.57,439.5 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:440.4,440.96 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:441.9,443.57 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:443.57,445.5 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:446.4,446.60 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:450.2,450.52 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:450.52,452.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:453.2,456.9 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:456.9,458.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:460.2,460.24 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:460.24,462.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:464.2,464.28 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:465.10,466.69 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:467.11,469.48 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:469.48,471.4 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:471.9,473.4 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:474.15,476.48 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:476.48,478.4 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:478.9,480.4 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:483.2,483.55 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:483.55,485.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:487.2,487.40 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:487.40,489.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:491.2,492.47 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:495.108,497.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:497.16,499.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:501.2,503.33 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:503.33,505.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:507.2,507.52 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:507.52,509.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:510.2,513.9 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:513.9,515.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:517.2,518.33 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:518.33,520.34 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:520.34,522.4 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:523.3,523.35 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:523.35,526.4 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:527.3,527.31 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:527.31,529.4 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:532.2,532.25 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:535.108,537.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:537.16,539.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:541.2,544.33 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:544.33,546.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:548.2,548.52 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:548.52,550.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:551.2,554.9 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:554.9,556.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:558.2,558.24 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:558.24,560.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:562.2,562.30 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:565.105,567.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:567.16,569.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:571.2,574.33 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:574.33,576.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:578.2,578.51 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:578.51,580.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:581.2,584.9 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:584.9,586.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:588.2,590.31 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:590.31,591.25 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:591.25,594.4 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:597.2,597.55 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:597.55,599.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:601.2,601.51 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:604.33,725.2 1 0 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:23.58,24.18 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:24.18,26.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:27.2,31.8 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:34.60,35.18 1 0 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:35.18,37.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:38.2,42.8 1 0 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:45.58,46.18 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:46.18,48.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:49.2,53.8 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:56.61,57.18 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:57.18,59.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:60.2,64.8 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:67.59,68.19 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:68.19,70.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:71.2,75.8 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:78.64,79.34 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:79.34,81.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:82.2,82.19 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:82.19,88.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:89.2,93.8 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:96.58,97.19 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:97.19,99.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:100.2,104.8 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:107.59,108.19 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:108.19,110.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:111.2,115.8 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:118.61,119.19 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:119.19,121.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:122.2,126.8 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:129.61,130.19 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:130.19,132.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:133.2,137.8 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:140.61,141.19 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:141.19,143.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:144.2,148.8 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:151.58,152.18 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:152.18,154.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:155.2,159.8 1 1 -github.com/echovault/echovault/pkg/modules/connection/commands.go:26.108,27.18 1 1 -github.com/echovault/echovault/pkg/modules/connection/commands.go:28.10,29.54 1 1 -github.com/echovault/echovault/pkg/modules/connection/commands.go:30.9,31.34 1 1 -github.com/echovault/echovault/pkg/modules/connection/commands.go:32.9,33.72 1 1 -github.com/echovault/echovault/pkg/modules/connection/commands.go:37.33,45.68 1 0 -github.com/echovault/echovault/pkg/modules/connection/commands.go:45.68,51.5 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:125.72,127.23 2 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:127.23,129.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:130.2,131.16 2 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:131.16,133.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:134.2,134.45 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:138.56,140.16 2 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:140.16,142.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:143.2,143.45 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:154.65,157.18 2 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:157.18,159.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:159.8,161.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:163.2,163.21 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:163.21,165.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:167.2,167.17 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:167.17,169.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:171.2,171.21 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:171.21,173.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:175.2,175.20 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:175.20,177.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:179.2,179.20 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:179.20,181.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:183.2,183.24 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:183.24,185.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:187.2,187.50 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:187.50,189.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:191.2,191.53 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:191.53,193.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:195.2,195.49 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:195.49,197.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:199.2,199.52 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:199.52,201.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:203.2,203.50 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:203.50,205.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:207.2,207.50 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:207.50,209.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:211.2,211.47 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:211.47,213.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:215.2,215.47 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:215.47,217.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:219.2,219.48 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:219.48,221.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:223.2,223.43 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:223.43,225.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:227.2,227.44 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:227.44,229.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:231.2,231.47 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:231.47,233.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:235.2,235.47 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:235.47,237.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:239.2,240.16 2 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:240.16,242.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:244.2,244.40 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:291.84,293.16 2 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:293.16,295.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:297.2,299.16 3 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:299.16,301.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:303.2,306.35 3 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:306.35,312.35 4 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:312.35,314.4 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:317.2,317.20 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:327.75,330.16 3 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:330.16,332.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:333.2,333.40 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:337.55,339.16 2 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:339.16,341.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:342.2,342.45 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:353.75,355.9 2 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:356.21,357.29 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:358.23,359.31 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:360.10,361.31 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:364.2,365.16 2 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:365.16,367.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:369.2,369.40 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:375.53,377.16 2 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:377.16,379.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:380.2,380.40 1 0 -github.com/echovault/echovault/pkg/echovault/api_admin.go:39.85,42.9 2 0 -github.com/echovault/echovault/pkg/echovault/api_admin.go:43.28,44.71 1 0 -github.com/echovault/echovault/pkg/echovault/api_admin.go:45.29,46.73 1 0 -github.com/echovault/echovault/pkg/echovault/api_admin.go:47.28,48.71 1 0 -github.com/echovault/echovault/pkg/echovault/api_admin.go:51.2,52.16 2 0 -github.com/echovault/echovault/pkg/echovault/api_admin.go:52.16,54.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_admin.go:56.2,56.45 1 0 -github.com/echovault/echovault/pkg/echovault/api_admin.go:62.55,64.16 2 0 -github.com/echovault/echovault/pkg/echovault/api_admin.go:64.16,66.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_admin.go:67.2,67.41 1 0 -github.com/echovault/echovault/pkg/echovault/api_admin.go:71.49,73.16 2 0 -github.com/echovault/echovault/pkg/echovault/api_admin.go:73.16,75.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_admin.go:76.2,76.40 1 0 -github.com/echovault/echovault/pkg/echovault/api_admin.go:80.50,82.16 2 0 -github.com/echovault/echovault/pkg/echovault/api_admin.go:82.16,84.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_admin.go:85.2,85.41 1 0 -github.com/echovault/echovault/pkg/echovault/api_admin.go:89.55,91.16 2 0 -github.com/echovault/echovault/pkg/echovault/api_admin.go:91.16,93.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_admin.go:94.2,94.40 1 0 -github.com/echovault/echovault/pkg/echovault/api_generic.go:87.85,90.9 2 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:91.18,92.26 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:93.18,94.26 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:97.2,97.9 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:98.23,99.65 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:100.23,101.65 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:102.25,103.69 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:104.25,105.69 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:108.2,108.17 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:108.17,110.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:112.2,113.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:113.16,115.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:117.2,117.40 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:132.74,135.28 2 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:135.28,137.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:139.2,140.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:140.16,142.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_generic.go:144.2,144.40 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:155.58,157.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:157.16,159.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_generic.go:160.2,160.40 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:171.65,173.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:173.16,175.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_generic.go:176.2,176.45 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:186.59,188.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:188.16,190.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_generic.go:191.2,191.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:202.60,204.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:204.16,206.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_generic.go:207.2,207.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:217.62,219.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:219.16,221.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_generic.go:222.2,222.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:232.63,234.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:234.16,236.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_generic.go:237.2,237.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:247.55,249.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:249.16,251.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_generic.go:252.2,252.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:262.56,264.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:264.16,266.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_generic.go:267.2,267.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:282.94,285.9 2 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:286.18,287.26 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:288.18,289.26 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:290.18,291.26 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:292.18,293.26 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:296.2,297.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:297.16,299.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_generic.go:301.2,301.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:316.101,319.9 2 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:320.18,321.26 1 0 -github.com/echovault/echovault/pkg/echovault/api_generic.go:322.18,323.26 1 0 -github.com/echovault/echovault/pkg/echovault/api_generic.go:324.18,325.26 1 0 -github.com/echovault/echovault/pkg/echovault/api_generic.go:326.18,327.26 1 0 -github.com/echovault/echovault/pkg/echovault/api_generic.go:330.2,331.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:331.16,333.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_generic.go:335.2,335.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:350.102,353.9 2 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:354.18,355.26 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:356.18,357.26 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:358.18,359.26 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:360.18,361.26 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:364.2,365.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:365.16,367.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_generic.go:369.2,369.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:384.109,387.9 2 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:388.18,389.26 1 0 -github.com/echovault/echovault/pkg/echovault/api_generic.go:390.18,391.26 1 0 -github.com/echovault/echovault/pkg/echovault/api_generic.go:392.18,393.26 1 0 -github.com/echovault/echovault/pkg/echovault/api_generic.go:394.18,395.26 1 0 -github.com/echovault/echovault/pkg/echovault/api_generic.go:398.2,399.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:399.16,401.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_generic.go:403.2,403.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:46.91,49.36 2 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:49.36,51.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:53.2,54.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:54.16,56.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:58.2,58.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:76.93,79.36 2 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:79.36,81.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:83.2,84.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:84.16,86.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_hash.go:88.2,88.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:105.79,109.16 3 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:109.16,111.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:113.2,113.46 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:127.62,129.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:129.16,131.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:132.2,132.45 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:148.94,151.24 2 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:151.24,153.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:153.8,155.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:157.2,157.24 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:157.24,159.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:161.2,162.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:162.16,164.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:166.2,166.45 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:180.56,182.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:182.16,184.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:185.2,185.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:199.62,201.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:201.16,203.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:204.2,204.45 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:223.85,225.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:225.16,227.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:228.2,228.39 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:232.94,234.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:234.16,236.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_hash.go:237.2,237.39 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:252.64,254.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:254.16,256.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:257.2,257.45 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:273.67,275.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:275.16,277.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:278.2,278.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:294.74,297.16 3 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:297.16,299.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:300.2,300.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:34.56,37.16 3 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:37.16,39.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:40.2,40.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:63.79,65.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:65.16,67.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:68.2,68.45 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:86.73,88.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:88.16,90.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:91.2,91.40 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:111.84,113.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:113.16,115.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:116.2,116.40 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:121.80,123.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:123.16,125.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:126.2,126.40 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:144.84,146.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:146.16,148.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:149.2,149.40 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:173.96,175.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:175.16,177.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:178.2,178.40 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:192.59,194.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:194.16,196.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:197.2,197.40 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:211.59,213.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:213.16,215.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:216.2,216.40 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:233.78,236.16 3 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:236.16,238.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_list.go:239.2,239.40 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:255.79,258.16 3 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:258.16,260.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:261.2,261.40 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:278.78,281.16 3 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:281.16,283.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_list.go:284.2,284.40 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:300.79,303.16 3 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:303.16,305.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:306.2,306.40 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:49.86,51.24 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:51.24,53.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:56.2,58.36 3 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:58.36,64.3 2 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:67.2,68.12 2 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:68.12,70.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:72.2,72.25 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:72.25,77.33 4 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:77.33,79.4 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:81.3,81.13 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:92.70,93.24 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:93.24,95.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:97.2,97.36 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:97.36,99.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:101.2,102.115 2 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:115.87,117.24 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:117.24,119.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:122.2,124.36 3 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:124.36,130.3 2 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:133.2,134.12 2 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:134.12,136.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:138.2,138.25 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:138.25,143.33 4 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:143.33,145.4 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:147.3,147.13 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:158.71,159.24 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:159.24,161.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:163.2,163.36 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:163.36,165.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:167.2,168.115 2 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:181.75,183.16 2 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:183.16,185.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:186.2,186.40 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:196.76,198.19 2 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:198.19,200.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:201.2,202.16 2 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:202.16,204.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:205.2,205.45 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:211.55,213.16 2 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:213.16,215.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:216.2,216.41 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:226.84,230.16 3 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:230.16,232.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:234.2,236.16 3 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:236.16,238.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:240.2,243.28 3 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:243.28,246.3 2 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:248.2,248.20 1 0 -github.com/echovault/echovault/pkg/echovault/api_set.go:36.75,39.16 3 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:39.16,41.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:42.2,42.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:56.57,58.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:58.16,60.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:61.2,61.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:78.66,81.16 3 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:81.16,83.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:84.2,84.45 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:89.86,92.16 3 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:92.16,94.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:95.2,95.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:112.67,115.16 3 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:115.16,117.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:118.2,118.45 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:136.77,138.15 2 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:138.15,140.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:141.2,142.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:142.16,144.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:145.2,145.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:150.87,153.16 3 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:153.16,155.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:156.2,156.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:172.70,174.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:174.16,176.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:177.2,177.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:191.65,193.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:193.16,195.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:196.2,196.45 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:213.84,216.16 3 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:216.16,218.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:219.2,219.46 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:241.82,243.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:243.16,245.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:246.2,246.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:262.73,264.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:264.16,266.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:267.2,267.45 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:284.79,286.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:286.16,288.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:289.2,289.45 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:305.75,308.16 3 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:308.16,310.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:311.2,311.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:326.67,329.16 3 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:329.16,331.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:332.2,332.45 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:337.87,340.16 3 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:340.16,342.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:343.2,343.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:102.87,104.28 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:104.28,105.17 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:105.17,107.18 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:107.18,109.5 1 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:110.4,111.12 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:113.3,113.23 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:115.2,115.20 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:118.85,120.28 2 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:120.28,122.17 2 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:122.17,124.4 1 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:125.3,126.17 2 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:126.17,128.18 2 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:128.18,130.5 1 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:131.4,131.24 1 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:134.2,134.20 1 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:158.105,161.9 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:162.18,163.26 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:164.18,165.26 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:168.2,168.9 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:169.18,170.26 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:171.18,172.26 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:175.2,175.16 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:175.16,177.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:179.2,179.18 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:179.18,181.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:183.2,183.37 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:183.37,185.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:187.2,188.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:188.16,190.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:192.2,192.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:206.57,208.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:208.16,210.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:211.2,211.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:229.76,237.16 3 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:237.16,239.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:240.2,240.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:258.93,260.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:260.16,262.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:263.2,264.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:264.16,266.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:268.2,269.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:269.16,271.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:273.2,273.45 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:290.86,293.16 3 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:293.16,295.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:296.2,296.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:313.99,316.30 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:316.30,318.45 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:318.45,320.4 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:323.2,323.29 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:323.29,325.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:327.2,327.24 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:327.24,329.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:331.2,332.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:332.16,334.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:336.2,337.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:337.16,339.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:341.2,341.53 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:360.114,363.30 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:363.30,365.42 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:365.42,367.4 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:370.2,370.29 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:370.29,372.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:374.2,374.24 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:374.24,376.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:378.2,379.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:379.16,381.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:383.2,383.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:400.99,403.30 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:403.30,405.42 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:405.42,407.4 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:410.2,410.29 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:410.29,412.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:414.2,414.24 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:414.24,416.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:418.2,419.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:419.16,421.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:423.2,424.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:424.16,426.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:428.2,428.53 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:447.114,450.30 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:450.30,452.42 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:452.42,454.4 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:457.2,457.29 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:457.29,459.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:461.2,461.24 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:461.24,463.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:465.2,466.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:466.16,468.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:470.2,470.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:489.97,492.16 3 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:492.16,494.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:495.2,496.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:496.16,498.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:499.2,499.15 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:516.89,519.9 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:520.19,521.27 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:522.19,523.27 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:524.10,525.27 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:528.2,528.9 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:529.26,530.76 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:531.10,532.59 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:535.2,536.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:536.16,538.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:540.2,540.51 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:558.88,560.33 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:560.33,562.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:564.2,565.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:565.16,567.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:569.2,570.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:570.16,572.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:574.2,575.24 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:575.24,576.14 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:576.14,578.12 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:580.3,581.17 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:581.17,583.4 1 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:584.3,584.20 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:587.2,587.20 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:607.71,610.16 3 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:610.16,612.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:613.2,613.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:632.78,634.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:634.16,636.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:637.2,637.51 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:656.78,658.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:658.16,660.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:661.2,661.51 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:685.98,687.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:687.16,689.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:690.2,690.16 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:690.16,692.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:694.2,695.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:695.16,697.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:699.2,699.51 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:720.101,722.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:722.16,724.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:726.2,727.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:727.16,729.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:731.2,733.19 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:733.19,735.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:737.2,738.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:738.16,740.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:742.2,744.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:744.16,746.17 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:746.17,748.4 1 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:749.3,749.13 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:752.2,752.17 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:757.104,759.16 2 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:759.16,761.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:763.2,764.16 2 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:764.16,766.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:768.2,770.46 2 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:787.81,790.16 3 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:790.16,792.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:794.2,795.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:795.16,797.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:799.2,799.11 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:799.11,801.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:803.2,804.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:804.16,806.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:808.2,808.19 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:824.75,826.33 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:826.33,828.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:829.2,830.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:830.16,832.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:833.2,833.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:851.94,860.16 3 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:860.16,862.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:864.2,864.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:884.109,887.9 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:888.23,889.31 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:890.21,891.29 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:892.10,893.31 1 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:896.2,896.24 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:896.24,898.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:900.2,900.47 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:900.47,902.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:904.2,905.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:905.16,907.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:909.2,910.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:910.16,912.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:914.2,914.53 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:936.120,939.9 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:940.23,941.31 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:942.21,943.29 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:944.10,945.31 1 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:948.2,948.47 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:948.47,950.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:952.2,953.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:953.16,955.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:957.2,957.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_string.go:30.84,32.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_string.go:32.16,34.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_string.go:35.2,35.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_string.go:45.58,47.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_string.go:47.16,49.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_string.go:50.2,50.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_string.go:63.77,65.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_string.go:65.16,67.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_string.go:68.2,68.40 1 1 -github.com/echovault/echovault/pkg/echovault/api_string.go:72.79,74.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_string.go:74.16,76.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_string.go:77.2,77.40 1 1 -github.com/echovault/echovault/pkg/echovault/cluster.go:25.45,27.2 1 1 -github.com/echovault/echovault/pkg/echovault/cluster.go:29.84,40.16 4 0 -github.com/echovault/echovault/pkg/echovault/cluster.go:40.16,42.3 1 0 -github.com/echovault/echovault/pkg/echovault/cluster.go:44.2,46.43 2 0 -github.com/echovault/echovault/pkg/echovault/cluster.go:46.43,48.3 1 0 -github.com/echovault/echovault/pkg/echovault/cluster.go:50.2,52.9 2 0 -github.com/echovault/echovault/pkg/echovault/cluster.go:52.9,54.3 1 0 -github.com/echovault/echovault/pkg/echovault/cluster.go:56.2,56.20 1 0 -github.com/echovault/echovault/pkg/echovault/cluster.go:56.20,58.3 1 0 -github.com/echovault/echovault/pkg/echovault/cluster.go:60.2,60.12 1 0 -github.com/echovault/echovault/pkg/echovault/cluster.go:63.94,75.16 5 0 -github.com/echovault/echovault/pkg/echovault/cluster.go:75.16,77.3 1 0 -github.com/echovault/echovault/pkg/echovault/cluster.go:79.2,81.43 2 0 -github.com/echovault/echovault/pkg/echovault/cluster.go:81.43,83.3 1 0 -github.com/echovault/echovault/pkg/echovault/cluster.go:85.2,87.9 2 0 -github.com/echovault/echovault/pkg/echovault/cluster.go:87.9,89.3 1 0 -github.com/echovault/echovault/pkg/echovault/cluster.go:91.2,91.20 1 0 -github.com/echovault/echovault/pkg/echovault/cluster.go:91.20,93.3 1 0 -github.com/echovault/echovault/pkg/echovault/cluster.go:95.2,95.24 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:99.66,100.36 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:100.36,102.3 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:108.66,109.36 1 1 -github.com/echovault/echovault/pkg/echovault/echovault.go:109.36,111.3 1 1 -github.com/echovault/echovault/pkg/echovault/echovault.go:117.72,118.36 1 1 -github.com/echovault/echovault/pkg/echovault/echovault.go:118.36,120.3 1 1 -github.com/echovault/echovault/pkg/echovault/echovault.go:125.78,136.33 2 1 -github.com/echovault/echovault/pkg/echovault/echovault.go:136.33,138.3 1 1 -github.com/echovault/echovault/pkg/echovault/echovault.go:140.2,151.29 4 1 -github.com/echovault/echovault/pkg/echovault/echovault.go:151.29,160.49 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:160.49,162.44 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:162.44,163.46 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:163.46,165.7 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:167.5,167.17 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:170.3,178.5 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:179.8,190.65 1 1 -github.com/echovault/echovault/pkg/echovault/echovault.go:190.65,192.44 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:192.44,193.46 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:193.46,195.7 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:197.5,197.17 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:199.72,201.67 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:201.67,203.6 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:204.5,204.68 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:204.68,206.6 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:207.5,208.34 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:212.3,218.60 1 1 -github.com/echovault/echovault/pkg/echovault/echovault.go:218.60,220.44 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:220.44,221.46 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:221.46,223.7 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:225.5,225.17 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:227.68,229.67 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:229.67,231.6 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:232.5,232.69 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:232.69,234.6 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:235.5,236.34 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:238.51,240.19 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:240.19,242.6 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:248.2,248.61 1 1 -github.com/echovault/echovault/pkg/echovault/echovault.go:248.61,249.13 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:249.13,250.8 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:250.8,252.83 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:252.83,254.6 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:259.2,259.69 1 1 -github.com/echovault/echovault/pkg/echovault/echovault.go:259.69,261.3 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:263.2,263.29 1 1 -github.com/echovault/echovault/pkg/echovault/echovault.go:263.29,267.36 3 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:267.36,269.4 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:272.2,272.30 1 1 -github.com/echovault/echovault/pkg/echovault/echovault.go:272.30,275.34 2 1 -github.com/echovault/echovault/pkg/echovault/echovault.go:275.34,277.18 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:277.18,279.5 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:283.3,283.71 1 1 -github.com/echovault/echovault/pkg/echovault/echovault.go:283.71,285.18 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:285.18,287.5 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:291.2,291.23 1 1 -github.com/echovault/echovault/pkg/echovault/echovault.go:294.37,303.16 4 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:303.16,305.3 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:307.2,307.15 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:307.15,310.3 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:312.2,312.27 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:312.27,314.15 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:314.15,316.4 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:316.9,318.4 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:320.3,321.49 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:321.49,323.18 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:323.18,325.5 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:326.4,326.42 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:329.3,332.16 3 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:332.16,334.37 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:334.37,336.19 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:336.19,338.6 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:339.5,340.19 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:340.19,342.6 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:343.5,343.61 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:343.61,345.6 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:349.3,353.5 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:357.2,357.6 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:357.6,359.17 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:359.17,361.12 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:364.3,364.35 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:368.58,370.23 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:370.23,372.3 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:374.2,380.6 4 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:380.6,383.43 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:383.43,386.9 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:389.3,389.17 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:389.17,391.9 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:394.3,396.43 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:396.43,397.9 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:400.3,400.17 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:400.17,401.87 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:401.87,403.5 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:404.4,404.12 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:407.3,410.20 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:410.20,411.12 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:414.3,414.28 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:414.28,416.12 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:420.3,421.7 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:421.7,423.41 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:423.41,425.19 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:425.19,427.6 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:428.5,428.10 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:430.4,431.21 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:431.21,432.10 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:434.4,434.27 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:438.2,438.37 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:438.37,440.3 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:448.34,450.2 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:453.47,454.38 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:454.38,456.3 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:458.2,458.12 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:458.12,459.27 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:459.27,461.53 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:461.53,463.5 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:464.4,464.10 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:467.3,467.62 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:467.62,469.4 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:472.2,472.12 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:476.49,478.2 1 1 -github.com/echovault/echovault/pkg/echovault/echovault.go:480.42,482.2 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:484.43,486.2 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:488.56,490.2 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:493.56,495.2 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:497.44,499.2 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:501.45,503.2 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:506.45,507.40 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:507.40,509.3 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:510.2,510.12 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:510.12,511.55 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:511.55,513.4 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:515.2,515.12 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:520.37,521.26 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:521.26,524.3 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:527.45,544.2 2 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:37.81,40.34 2 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:40.34,43.3 2 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:45.2,45.6 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:45.6,46.10 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:47.11,48.35 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:48.35,50.5 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:51.4,52.10 2 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:52.10,54.5 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:55.21,56.36 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:65.67,66.39 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:66.39,68.3 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:76.82,79.34 2 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:79.34,82.3 2 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:84.2,84.6 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:84.6,85.10 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:86.11,87.35 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:87.35,89.5 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:90.4,91.10 2 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:91.10,93.5 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:94.21,95.36 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:104.68,105.39 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:105.39,107.3 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:115.74,117.9 2 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:117.9,119.3 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:121.2,121.82 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:121.82,122.28 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:122.28,125.18 2 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:125.18,127.5 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:128.9,128.64 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:128.64,131.18 2 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:131.18,133.5 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:134.9,134.65 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:134.65,139.4 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:141.3,141.15 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:144.2,144.13 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:152.90,153.115 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:153.115,155.3 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:157.2,160.33 3 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:160.33,171.3 5 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:173.2,173.33 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:178.80,179.58 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:179.58,181.3 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:182.2,182.32 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:189.93,190.115 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:190.115,192.3 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:194.2,200.16 3 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:200.16,202.3 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:204.2,204.27 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:204.27,206.3 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:208.2,208.12 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:213.79,214.58 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:214.58,216.3 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:217.2,217.35 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:226.101,234.55 3 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:234.55,236.3 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:237.2,240.11 2 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:240.11,242.17 2 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:242.17,244.4 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:250.51,259.97 4 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:259.97,261.3 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:269.60,271.6 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:271.6,272.83 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:272.83,274.9 2 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:277.2,278.33 2 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:278.33,280.3 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:281.2,282.13 2 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:289.75,290.52 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:290.52,292.3 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:295.2,302.9 4 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:303.108,304.36 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:305.108,306.36 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:309.2,311.12 2 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:316.82,318.83 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:318.83,320.3 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:322.2,322.34 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:322.34,324.3 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:325.2,325.55 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:326.28,329.36 3 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:330.28,333.36 3 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:334.29,337.50 3 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:337.50,339.4 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:340.29,343.50 3 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:343.50,345.4 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:347.2,347.54 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:347.54,349.3 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:350.2,350.12 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:354.71,356.34 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:356.34,358.3 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:361.2,364.50 3 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:364.50,366.3 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:368.2,370.50 3 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:370.50,372.3 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:376.2,376.9 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:377.125,382.7 3 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:382.7,384.40 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:384.40,386.5 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:388.4,389.29 2 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:389.29,391.54 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:391.54,393.6 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:394.10,394.65 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:394.65,396.63 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:396.63,398.6 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:402.4,405.52 3 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:405.52,407.5 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:409.125,414.7 3 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:414.7,416.40 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:416.40,418.5 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:420.4,421.29 2 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:421.29,423.54 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:423.54,425.6 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:426.10,426.65 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:426.65,429.63 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:429.63,431.6 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:435.4,438.52 3 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:438.52,440.5 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:442.105,445.7 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:445.7,447.33 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:447.33,450.5 2 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:452.4,453.40 2 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:453.40,454.17 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:454.17,455.31 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:455.31,457.56 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:457.56,459.8 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:460.12,460.67 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:460.67,461.65 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:461.65,463.8 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:466.6,469.54 3 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:469.54,471.7 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:473.5,473.10 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:476.106,479.7 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:479.7,486.29 5 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:486.29,488.54 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:488.54,490.6 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:491.10,491.65 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:491.65,492.63 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:492.63,494.6 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:498.4,501.52 3 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:501.52,503.5 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:505.10,506.13 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:515.77,517.57 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:517.57,519.3 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:521.2,526.50 3 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:526.50,528.3 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:529.2,536.33 6 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:536.33,537.7 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:537.7,541.35 3 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:541.35,543.10 2 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:547.2,550.25 2 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:550.25,551.52 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:551.52,552.12 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:556.3,556.57 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:556.57,558.12 2 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:562.3,564.28 3 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:564.28,565.51 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:565.51,567.5 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:568.9,568.64 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:568.64,569.60 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:569.60,571.5 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:576.2,576.21 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:576.21,579.3 2 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:581.2,584.58 2 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:584.58,588.3 2 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:590.2,590.12 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:593.68,597.2 3 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:599.74,604.2 4 1 -github.com/echovault/echovault/pkg/echovault/modules.go:28.59,30.2 1 0 -github.com/echovault/echovault/pkg/echovault/modules.go:32.47,34.2 1 0 -github.com/echovault/echovault/pkg/echovault/modules.go:36.50,38.2 1 0 -github.com/echovault/echovault/pkg/echovault/modules.go:40.72,41.42 1 1 -github.com/echovault/echovault/pkg/echovault/modules.go:41.42,42.46 1 1 -github.com/echovault/echovault/pkg/echovault/modules.go:42.46,44.4 1 1 -github.com/echovault/echovault/pkg/echovault/modules.go:46.2,46.69 1 0 -github.com/echovault/echovault/pkg/echovault/modules.go:49.137,51.16 2 1 -github.com/echovault/echovault/pkg/echovault/modules.go:51.16,53.3 1 0 -github.com/echovault/echovault/pkg/echovault/modules.go:55.2,56.16 2 1 -github.com/echovault/echovault/pkg/echovault/modules.go:56.16,58.3 1 0 -github.com/echovault/echovault/pkg/echovault/modules.go:60.2,64.8 4 1 -github.com/echovault/echovault/pkg/echovault/modules.go:64.8,67.3 2 0 -github.com/echovault/echovault/pkg/echovault/modules.go:69.2,69.51 1 1 -github.com/echovault/echovault/pkg/echovault/modules.go:69.51,72.87 1 0 -github.com/echovault/echovault/pkg/echovault/modules.go:72.87,74.4 1 0 -github.com/echovault/echovault/pkg/echovault/modules.go:78.2,78.50 1 1 -github.com/echovault/echovault/pkg/echovault/modules.go:78.50,79.7 1 1 -github.com/echovault/echovault/pkg/echovault/modules.go:79.7,80.42 1 1 -github.com/echovault/echovault/pkg/echovault/modules.go:80.42,82.10 2 1 -github.com/echovault/echovault/pkg/echovault/modules.go:87.2,87.43 1 1 -github.com/echovault/echovault/pkg/echovault/modules.go:87.43,89.17 2 1 -github.com/echovault/echovault/pkg/echovault/modules.go:89.17,91.4 1 1 -github.com/echovault/echovault/pkg/echovault/modules.go:93.3,93.62 1 1 -github.com/echovault/echovault/pkg/echovault/modules.go:93.62,95.4 1 1 -github.com/echovault/echovault/pkg/echovault/modules.go:97.3,99.18 2 1 -github.com/echovault/echovault/pkg/echovault/modules.go:103.2,103.32 1 0 -github.com/echovault/echovault/pkg/echovault/modules.go:103.32,106.17 3 0 -github.com/echovault/echovault/pkg/echovault/modules.go:106.17,108.4 1 0 -github.com/echovault/echovault/pkg/echovault/modules.go:109.3,109.18 1 0 -github.com/echovault/echovault/pkg/echovault/modules.go:113.2,113.34 1 0 -github.com/echovault/echovault/pkg/echovault/modules.go:113.34,116.3 2 0 -github.com/echovault/echovault/pkg/echovault/modules.go:118.2,118.72 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:29.111,35.29 4 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:35.29,36.54 1 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:36.54,42.42 4 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:42.42,44.5 1 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:46.4,49.12 3 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:52.3,52.36 1 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:52.36,59.43 5 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:59.43,61.5 1 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:63.4,65.21 2 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:69.2,71.25 2 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:74.109,78.35 3 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:78.35,79.65 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:79.65,80.41 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:80.41,82.5 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:83.4,83.12 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:85.3,85.13 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:88.2,88.51 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:91.110,92.18 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:93.9,98.36 4 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:98.36,99.66 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:99.66,100.52 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:100.52,104.6 3 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:105.5,105.13 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:107.4,108.14 2 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:110.3,111.26 2 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:113.9,117.45 3 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:117.45,119.4 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:120.3,120.42 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:120.42,124.37 3 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:124.37,125.67 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:125.67,126.53 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:126.53,127.59 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:127.59,131.8 3 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:133.6,133.14 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:135.5,135.54 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:135.54,138.6 2 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:140.9,140.50 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:140.50,144.37 3 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:144.37,145.67 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:145.67,146.53 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:146.53,148.24 2 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:148.24,151.8 2 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:153.6,153.14 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:155.5,155.33 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:155.33,158.6 2 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:160.9,160.49 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:160.49,164.37 3 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:164.37,165.67 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:165.67,166.53 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:166.53,167.55 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:167.55,171.8 3 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:173.6,173.14 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:175.5,175.50 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:175.50,178.6 2 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:180.9,182.4 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:183.3,184.26 2 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:185.10,186.54 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:190.103,192.2 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:194.33,202.68 1 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:202.68,208.5 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:217.68,223.5 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:231.70,237.7 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:246.70,252.7 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:262.70,268.7 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:279.68,285.5 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:286.113,287.49 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:287.49,289.6 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:290.5,290.45 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:299.68,305.5 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:306.113,308.18 2 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:308.18,310.6 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:311.5,311.53 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:320.68,326.5 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:327.113,328.47 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:328.47,330.6 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:331.5,331.45 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:28.113,30.9 2 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:30.9,32.3 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:34.2,36.24 2 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:36.24,38.3 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:40.2,43.17 3 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:46.115,48.9 2 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:48.9,50.3 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:52.2,56.66 3 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:59.108,61.9 2 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:61.9,63.3 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:64.2,64.19 1 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:64.19,66.3 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:67.2,68.42 2 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:71.113,72.18 1 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:72.18,74.3 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:76.2,77.9 2 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:77.9,79.3 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:81.2,82.19 2 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:82.19,84.3 1 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:86.2,86.38 1 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:89.109,91.9 2 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:91.9,93.3 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:94.2,95.49 2 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:98.112,100.9 2 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:100.9,102.3 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:103.2,103.36 1 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:106.33,114.68 1 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:114.68,116.21 1 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:116.21,118.6 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:119.5,123.11 1 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:133.68,135.21 1 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:135.21,137.6 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:138.5,142.11 1 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:152.68,154.22 1 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:154.22,156.6 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:157.5,161.11 1 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:173.68,180.5 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:191.68,197.5 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:206.68,212.5 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:213.101,215.5 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:225.70,231.7 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:240.70,246.7 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:256.70,262.7 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:30.105,32.16 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:32.16,34.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:36.2,40.33 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:40.33,42.70 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:42.70,44.4 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:45.3,45.55 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:45.55,47.4 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:48.3,49.59 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:52.2,52.51 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:52.51,54.3 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:55.2,58.9 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:58.9,60.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:62.2,64.51 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:67.106,69.16 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:69.16,71.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:73.2,75.33 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:75.33,77.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:79.2,79.52 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:79.52,81.3 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:82.2,85.9 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:85.9,87.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:89.2,91.57 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:94.106,96.16 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:96.16,98.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:101.2,101.46 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:101.46,103.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:104.2,104.65 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:104.65,106.3 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:107.2,109.9 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:109.9,111.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:113.2,114.15 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:114.15,115.34 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:115.34,116.14 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:116.14,118.5 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:122.2,122.40 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:122.40,123.34 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:123.34,124.12 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:126.3,126.53 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:126.53,127.12 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:129.3,129.20 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:132.2,133.30 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:133.30,135.10 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:135.10,136.12 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:138.3,138.27 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:141.2,145.26 4 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:145.26,147.24 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:147.24,149.4 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:152.2,152.25 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:155.111,157.16 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:157.16,159.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:161.2,164.46 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:164.46,166.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:167.2,167.66 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:167.66,169.3 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:170.2,172.9 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:172.9,174.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:176.2,177.15 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:177.15,178.34 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:178.34,179.14 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:179.14,181.5 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:185.2,185.40 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:185.40,186.34 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:186.34,187.12 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:189.3,189.53 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:189.53,190.12 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:192.3,192.20 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:195.2,196.40 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:196.40,198.10 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:198.10,199.12 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:201.3,201.27 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:204.2,209.40 4 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:209.40,210.60 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:210.60,212.4 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:213.3,213.64 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:213.64,215.4 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:216.3,217.26 2 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:220.2,220.68 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:220.68,222.3 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:223.2,223.63 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:223.63,225.3 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:226.2,228.25 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:231.107,233.16 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:233.16,235.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:237.2,238.15 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:238.15,239.34 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:239.34,240.14 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:240.14,242.5 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:246.2,246.36 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:246.36,247.34 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:247.34,250.4 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:251.3,251.53 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:251.53,253.4 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:254.3,254.20 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:257.2,259.28 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:259.28,261.10 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:261.10,264.4 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:265.3,265.27 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:268.2,268.20 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:268.20,270.3 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:272.2,276.26 4 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:276.26,278.24 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:278.24,280.4 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:283.2,283.25 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:286.111,288.16 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:288.16,290.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:293.2,294.56 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:294.56,296.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:297.2,297.35 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:297.35,299.3 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:300.2,300.20 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:300.20,302.27 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:302.27,304.4 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:306.3,306.60 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:306.60,308.4 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:308.9,310.4 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:313.2,314.15 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:314.15,315.34 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:315.34,316.14 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:316.14,318.5 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:322.2,322.36 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:322.36,323.34 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:323.34,326.4 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:327.3,327.53 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:327.53,329.4 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:330.3,330.20 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:333.2,335.28 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:335.28,337.10 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:337.10,340.4 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:341.3,341.27 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:344.2,344.20 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:344.20,346.3 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:348.2,350.69 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:353.112,355.16 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:355.16,357.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:359.2,360.15 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:360.15,361.34 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:361.34,362.14 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:362.14,364.5 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:368.2,368.36 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:368.36,369.34 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:369.34,372.4 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:373.3,373.53 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:373.53,375.4 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:376.3,376.20 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:379.2,381.28 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:381.28,383.10 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:383.10,386.4 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:387.3,387.27 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:390.2,393.40 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:393.40,394.60 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:394.60,396.4 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:397.8,398.69 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:398.69,400.4 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:403.2,403.68 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:403.68,405.3 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:406.2,408.69 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:411.110,413.16 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:413.16,415.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:417.2,419.33 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:419.33,421.3 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:423.2,423.52 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:423.52,425.3 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:426.2,429.9 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:429.9,431.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:433.2,433.27 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:433.27,435.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:437.2,437.30 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:440.109,442.16 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:442.16,444.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:446.2,448.33 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:448.33,450.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:452.2,452.52 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:452.52,454.3 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:455.2,458.9 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:458.9,460.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:462.2,465.26 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:465.26,467.24 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:467.24,469.4 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:472.2,472.25 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:475.111,477.16 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:477.16,479.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:481.2,484.33 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:484.33,486.29 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:486.29,488.27 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:488.27,490.5 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:492.3,492.26 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:495.2,495.52 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:495.52,497.3 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:498.2,501.9 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:501.9,503.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:505.2,506.36 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:506.36,507.31 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:507.31,509.4 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:509.9,511.4 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:513.2,515.25 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:518.106,520.16 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:520.16,522.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:524.2,527.36 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:527.36,529.3 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:531.2,531.54 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:531.54,533.3 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:534.2,537.9 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:537.9,539.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:541.2,543.41 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:543.41,545.69 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:545.69,547.4 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:548.3,550.74 3 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:550.74,552.4 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:553.8,555.61 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:555.61,557.4 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:558.3,560.10 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:560.10,562.4 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:563.3,563.22 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:566.2,568.49 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:571.105,573.16 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:573.16,575.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:577.2,580.19 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:580.19,582.10 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:582.10,584.4 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:585.3,585.12 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:588.2,588.33 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:588.33,590.3 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:592.2,592.51 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:592.51,594.3 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:595.2,598.9 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:598.9,600.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:602.2,605.28 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:605.28,607.26 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:607.26,609.4 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:612.2,612.25 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:615.112,617.16 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:617.16,619.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:621.2,624.19 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:624.19,626.10 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:626.10,628.4 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:629.3,629.12 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:632.2,632.33 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:632.33,634.3 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:636.2,636.51 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:636.51,638.3 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:639.2,642.9 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:642.9,644.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:646.2,649.28 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:649.28,651.26 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:651.26,653.4 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:656.2,656.25 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:659.105,661.16 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:661.16,663.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:665.2,668.33 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:668.33,670.3 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:672.2,672.51 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:672.51,674.3 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:675.2,678.9 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:678.9,680.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:682.2,684.51 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:687.107,689.16 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:689.16,691.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:693.2,694.15 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:694.15,695.34 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:695.34,696.14 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:696.14,698.5 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:702.2,702.36 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:702.36,703.34 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:703.34,704.12 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:706.3,706.53 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:706.53,708.4 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:709.3,709.20 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:712.2,714.33 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:714.33,715.14 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:715.14,716.12 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:718.3,719.10 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:719.10,721.4 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:722.3,722.27 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:725.2,728.35 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:728.35,730.33 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:730.33,732.4 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:735.2,735.25 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:738.112,740.16 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:740.16,742.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:744.2,745.15 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:745.15,746.34 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:746.34,747.14 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:747.14,749.5 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:753.2,753.36 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:753.36,754.34 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:754.34,755.12 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:757.3,757.53 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:757.53,759.4 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:760.3,760.20 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:763.2,765.33 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:765.33,766.14 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:766.14,767.12 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:769.3,770.10 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:770.10,772.4 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:773.3,773.27 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:776.2,780.40 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:780.40,781.60 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:781.60,783.4 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:784.8,785.69 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:785.69,787.4 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:789.2,791.64 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:791.64,793.3 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:794.2,794.65 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:797.33,948.2 1 0 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:25.58,26.18 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:26.18,28.3 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:29.2,33.8 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:36.59,37.19 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:37.19,39.3 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:40.2,44.8 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:47.59,48.18 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:48.18,50.3 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:51.2,55.8 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:58.64,59.18 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:59.18,61.3 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:62.2,66.8 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:69.60,70.18 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:70.18,72.3 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:73.2,77.8 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:80.64,81.18 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:81.18,83.3 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:85.2,85.56 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:85.56,87.3 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:89.2,89.20 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:89.20,95.3 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:97.2,101.8 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:104.65,105.18 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:105.18,107.3 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:108.2,112.8 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:115.63,116.19 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:116.19,118.3 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:119.2,123.8 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:126.62,127.19 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:127.19,129.3 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:130.2,134.8 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:137.64,138.18 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:138.18,140.3 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:141.2,145.8 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:148.59,149.19 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:149.19,151.3 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:152.2,156.8 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:159.58,160.34 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:160.34,162.3 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:163.2,167.8 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:170.65,171.34 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:171.34,173.3 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:174.2,178.8 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:181.58,182.18 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:182.18,184.3 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:185.2,189.8 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:192.60,193.18 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:193.18,195.3 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:196.2,200.8 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:203.65,204.18 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:204.18,206.3 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:207.2,211.8 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:33.105,35.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:35.16,37.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:39.2,48.32 7 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:48.32,49.29 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:49.29,50.9 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:52.3,52.44 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:53.15,54.74 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:54.74,56.5 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:57.16,58.25 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:59.12,60.25 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:64.2,64.66 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:64.66,66.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:68.2,70.52 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:70.52,71.15 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:71.15,72.12 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:74.3,75.23 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:76.11,77.64 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:78.15,80.49 2 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:80.49,86.5 2 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:87.4,87.49 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:87.49,93.5 2 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:94.16,99.6 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:100.12,105.6 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:110.2,110.27 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:110.27,112.34 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:112.34,113.70 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:113.70,116.61 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:116.61,118.6 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:119.5,119.13 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:121.4,121.70 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:121.70,125.36 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:125.36,127.6 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:128.5,128.13 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:130.4,130.39 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:130.39,132.13 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:134.4,134.41 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:134.41,137.25 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:137.25,139.6 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:140.5,140.13 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:142.4,142.55 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:146.2,146.32 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:146.32,149.17 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:149.17,151.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:152.3,154.10 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:154.10,156.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:157.3,158.17 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:158.17,160.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:162.3,162.18 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:162.18,165.4 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:167.3,167.52 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:171.2,171.60 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:171.60,173.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:174.2,177.54 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:177.54,179.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:181.2,181.63 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:184.106,186.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:186.16,188.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:189.2,191.33 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:191.33,193.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:195.2,195.52 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:195.52,197.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:198.2,201.9 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:201.9,203.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:205.2,205.63 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:208.107,210.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:210.16,212.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:214.2,217.43 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:218.10,219.60 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:220.14,221.40 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:221.40,223.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:223.9,225.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:226.15,228.32 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:229.11,231.32 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:234.2,235.43 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:236.10,237.60 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:238.14,239.40 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:239.40,241.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:241.9,243.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:244.15,246.32 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:247.11,249.32 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:252.2,252.33 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:252.33,254.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:256.2,256.52 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:256.52,258.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:259.2,262.9 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:262.9,264.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:266.2,267.33 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:267.33,268.47 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:268.47,270.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:273.2,273.58 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:276.110,278.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:278.16,280.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:282.2,286.33 4 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:286.33,288.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:290.2,290.52 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:290.52,292.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:293.2,296.9 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:296.9,298.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:300.2,303.38 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:303.38,304.45 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:304.45,306.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:309.2,311.28 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:311.28,313.81 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:313.81,315.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:318.2,318.51 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:321.106,323.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:323.16,325.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:327.2,327.63 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:327.63,329.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:330.2,330.49 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:330.49,332.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:334.2,335.15 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:335.15,336.34 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:336.34,337.14 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:337.14,339.5 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:344.2,344.46 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:344.46,347.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:348.2,348.65 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:348.65,350.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:351.2,353.9 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:353.9,355.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:358.2,360.42 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:360.42,361.47 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:361.47,362.12 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:364.3,365.17 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:365.17,367.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:368.3,370.10 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:370.10,372.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:373.3,373.27 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:376.2,381.34 4 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:381.34,382.20 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:382.20,384.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:384.9,386.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:389.2,391.25 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:394.111,396.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:396.16,398.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:400.2,403.15 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:403.15,404.34 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:404.34,405.14 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:405.14,407.5 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:412.2,412.46 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:412.46,415.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:416.2,416.65 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:416.65,418.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:419.2,421.9 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:421.9,423.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:425.2,427.42 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:427.42,428.46 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:428.46,429.67 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:429.67,431.5 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:432.4,433.11 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:433.11,435.5 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:436.4,436.28 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:440.2,442.40 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:442.40,443.60 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:443.60,445.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:446.8,447.69 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:447.69,449.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:451.2,453.63 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:453.63,455.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:457.2,457.64 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:460.108,462.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:462.16,464.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:466.2,470.43 4 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:471.10,472.55 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:473.14,474.57 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:474.57,476.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:476.9,476.64 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:476.64,478.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:478.9,480.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:481.15,483.34 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:484.11,486.34 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:489.2,489.33 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:489.33,492.61 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:492.61,494.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:495.3,499.17 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:499.17,501.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:502.3,503.99 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:506.2,506.51 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:506.51,508.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:509.2,511.9 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:511.9,513.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:514.2,520.23 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:520.23,522.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:523.2,524.74 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:527.107,529.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:529.16,531.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:533.2,534.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:534.16,536.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:538.2,539.15 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:539.15,540.34 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:540.34,541.14 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:541.14,543.5 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:547.2,549.33 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:549.33,550.38 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:550.38,553.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:554.3,554.57 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:554.57,556.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:557.3,559.10 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:559.10,561.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:562.3,565.5 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:568.2,572.33 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:572.33,573.40 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:573.40,574.18 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:574.18,576.5 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:576.10,578.5 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:582.2,584.25 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:587.112,589.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:589.16,591.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:593.2,596.51 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:596.51,598.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:600.2,601.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:601.16,603.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:605.2,606.15 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:606.15,607.34 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:607.34,608.14 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:608.14,610.5 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:614.2,616.33 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:616.33,617.38 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:617.38,619.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:620.3,620.57 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:620.57,622.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:623.3,625.10 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:625.10,627.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:628.3,631.5 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:634.2,636.71 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:636.71,637.60 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:637.60,639.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:640.8,640.40 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:640.40,641.69 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:641.69,643.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:645.2,647.68 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:647.68,649.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:651.2,651.69 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:654.106,656.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:656.16,658.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:660.2,665.56 4 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:665.56,667.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:668.2,668.20 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:668.20,669.19 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:669.19,671.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:672.3,672.29 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:672.29,674.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:675.3,676.17 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:676.17,678.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:679.3,679.13 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:679.13,681.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:682.3,683.25 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:687.2,687.57 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:687.57,689.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:690.2,690.21 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:690.21,691.20 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:691.20,693.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:694.3,695.53 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:695.53,697.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:700.2,700.43 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:700.43,701.47 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:701.47,702.67 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:702.67,703.13 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:705.4,706.35 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:706.35,708.13 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:710.4,711.18 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:711.18,714.5 2 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:715.4,719.38 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:719.38,721.5 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:723.4,725.27 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:729.2,729.30 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:732.105,734.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:734.16,736.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:738.2,742.42 4 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:742.42,744.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:746.2,746.19 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:746.19,748.17 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:748.17,750.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:751.3,751.12 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:751.12,753.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:756.2,756.33 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:756.33,758.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:760.2,760.51 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:760.51,762.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:763.2,766.9 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:766.9,768.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:770.2,771.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:771.16,773.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:775.2,776.36 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:776.36,778.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:780.2,782.25 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:785.108,787.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:787.16,789.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:791.2,793.33 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:793.33,795.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:797.2,797.52 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:797.52,799.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:800.2,803.9 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:803.9,805.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:807.2,813.36 4 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:813.36,815.21 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:815.21,817.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:817.9,819.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:822.2,824.25 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:827.112,829.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:829.16,831.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:833.2,836.19 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:836.19,838.17 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:838.17,840.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:841.3,841.13 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:841.13,843.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:846.2,847.19 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:847.19,848.46 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:848.46,850.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:850.9,852.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:855.2,855.33 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:855.33,857.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:859.2,859.52 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:859.52,861.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:862.2,865.9 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:865.9,867.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:869.2,872.28 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:872.28,873.17 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:873.17,875.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:875.9,877.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:880.2,882.25 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:885.106,887.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:887.16,889.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:891.2,895.62 4 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:895.62,897.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:899.2,899.33 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:899.33,901.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:903.2,903.52 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:903.52,905.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:906.2,909.9 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:909.9,911.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:913.2,914.65 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:914.65,915.44 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:915.44,917.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:918.3,918.39 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:921.2,921.36 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:921.36,922.51 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:922.51,923.18 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:923.18,926.5 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:926.10,928.5 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:932.2,932.31 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:935.105,937.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:937.16,939.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:941.2,943.33 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:943.33,945.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:947.2,947.51 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:947.51,949.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:950.2,953.9 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:953.9,955.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:957.2,958.28 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:958.28,959.38 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:959.38,961.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:964.2,964.58 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:967.107,969.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:969.16,971.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:973.2,975.33 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:975.33,977.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:978.2,978.52 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:978.52,980.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:981.2,983.9 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:983.9,985.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:986.2,987.20 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:987.20,989.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:991.2,993.69 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:996.117,998.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:998.16,1000.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1002.2,1007.16 4 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1007.16,1009.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1011.2,1012.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1012.16,1014.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1016.2,1016.33 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1016.33,1018.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1020.2,1020.51 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1020.51,1022.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1023.2,1026.9 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1026.9,1028.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1030.2,1030.33 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1030.33,1031.83 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1031.83,1034.4 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1037.2,1037.58 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1040.116,1042.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1042.16,1044.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1046.2,1049.16 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1049.16,1051.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1053.2,1054.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1054.16,1056.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1058.2,1058.33 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1058.33,1060.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1062.2,1062.51 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1062.51,1064.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1065.2,1068.9 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1068.9,1070.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1072.2,1072.15 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1072.15,1074.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1075.2,1075.14 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1075.14,1077.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1079.2,1079.88 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1079.88,1081.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1083.2,1084.65 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1084.65,1086.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1088.2,1090.18 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1090.18,1091.34 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1091.34,1094.4 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1095.8,1096.34 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1096.34,1099.4 2 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1102.2,1102.58 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1105.115,1107.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1107.16,1109.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1111.2,1115.33 4 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1115.33,1117.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1119.2,1119.51 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1119.51,1121.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1122.2,1125.9 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1125.9,1127.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1129.2,1132.38 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1132.38,1133.45 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1133.45,1135.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1138.2,1141.28 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1141.28,1143.81 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1143.81,1146.4 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1149.2,1149.58 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1152.107,1154.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1154.16,1156.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1158.2,1167.65 9 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1167.65,1169.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1171.2,1171.62 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1171.62,1173.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1175.2,1175.54 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1175.54,1177.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1177.5,1179.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1179.8,1182.17 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1182.17,1184.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1185.3,1186.17 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1186.17,1188.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1191.2,1191.54 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1191.54,1193.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1193.5,1194.61 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1194.61,1196.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1197.3,1197.50 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1197.50,1199.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1200.3,1201.17 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1201.17,1203.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1204.3,1204.17 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1204.17,1206.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1207.3,1208.17 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1208.17,1210.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1213.2,1213.33 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1213.33,1215.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1217.2,1217.52 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1217.52,1219.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1220.2,1223.9 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1223.9,1225.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1227.2,1227.32 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1227.32,1229.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1230.2,1230.15 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1230.15,1232.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1234.2,1235.42 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1235.42,1236.66 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1236.66,1238.15 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1238.15,1240.5 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1241.4,1241.40 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1244.2,1244.40 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1244.40,1246.39 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1246.39,1247.46 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1247.46,1249.5 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1251.3,1251.66 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1251.66,1252.15 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1252.15,1254.5 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1255.4,1255.64 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1259.2,1261.35 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1261.35,1262.24 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1262.24,1263.9 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1265.3,1265.43 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1265.43,1266.107 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1266.107,1268.5 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1269.4,1269.12 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1271.3,1272.90 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1272.90,1274.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1277.2,1279.34 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1279.34,1280.17 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1280.17,1282.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1282.9,1284.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1287.2,1289.25 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1292.112,1294.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1294.16,1296.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1298.2,1308.62 10 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1308.62,1310.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1312.2,1312.54 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1312.54,1314.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1314.5,1316.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1316.8,1319.17 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1319.17,1321.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1322.3,1323.17 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1323.17,1325.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1328.2,1328.54 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1328.54,1330.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1330.5,1331.61 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1331.61,1333.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1334.3,1334.50 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1334.50,1336.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1337.3,1338.17 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1338.17,1340.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1341.3,1341.17 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1341.17,1343.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1344.3,1345.17 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1345.17,1347.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1350.2,1350.36 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1350.36,1352.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1354.2,1354.55 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1354.55,1356.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1357.2,1360.9 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1360.9,1362.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1364.2,1364.32 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1364.32,1366.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1367.2,1367.15 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1367.15,1369.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1371.2,1372.42 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1372.42,1373.66 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1373.66,1375.15 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1375.15,1377.5 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1378.4,1378.40 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1381.2,1381.40 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1381.40,1383.39 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1383.39,1384.46 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1384.46,1386.5 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1388.3,1388.66 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1388.66,1389.15 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1389.15,1391.5 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1392.4,1392.64 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1396.2,1398.35 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1398.35,1399.24 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1399.24,1400.9 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1402.3,1402.43 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1402.43,1403.107 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1403.107,1405.5 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1406.4,1406.12 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1408.3,1409.90 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1409.90,1411.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1414.2,1416.40 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1416.40,1417.60 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1417.60,1419.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1420.8,1421.69 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1421.69,1423.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1425.2,1427.71 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1427.71,1429.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1431.2,1431.72 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1434.107,1435.46 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1435.46,1437.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1439.2,1440.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1440.16,1442.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1444.2,1445.15 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1445.15,1446.34 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1446.34,1447.14 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1447.14,1449.5 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1453.2,1455.33 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1455.33,1456.37 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1456.37,1457.58 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1457.58,1459.5 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1460.4,1462.11 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1462.11,1464.5 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1465.4,1468.6 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1472.2,1475.35 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1475.35,1476.17 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1476.17,1478.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1478.9,1480.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1483.2,1485.25 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1488.112,1490.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1490.16,1492.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1494.2,1497.51 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1497.51,1499.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1501.2,1502.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1502.16,1504.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1506.2,1507.15 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1507.15,1508.34 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1508.34,1509.14 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1509.14,1511.5 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1515.2,1517.33 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1517.33,1518.37 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1518.37,1519.58 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1519.58,1521.5 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1522.4,1524.11 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1524.11,1526.5 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1527.4,1530.6 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1534.2,1536.40 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1536.40,1537.60 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1537.60,1539.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1540.8,1541.69 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1541.69,1543.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1545.2,1547.64 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1547.64,1549.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1551.2,1551.65 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1554.33,1826.2 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:25.58,26.18 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:26.18,28.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:29.2,33.8 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:36.59,37.19 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:37.19,39.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:40.2,44.8 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:47.60,48.19 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:48.19,50.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:51.2,55.8 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:58.59,59.18 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:59.18,61.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:63.2,63.63 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:63.63,65.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:67.2,67.27 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:67.27,73.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:75.2,79.8 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:82.64,83.18 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:83.18,85.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:86.2,90.8 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:93.61,94.19 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:94.19,96.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:97.2,101.8 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:104.60,105.18 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:105.18,107.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:108.2,108.58 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:108.58,111.39 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:111.39,113.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:114.3,114.15 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:116.2,116.18 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:116.18,122.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:123.2,123.17 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:123.17,129.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:130.2,130.68 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:133.65,134.18 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:134.18,136.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:137.2,137.58 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:137.58,140.39 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:140.39,142.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:143.3,143.15 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:145.2,145.18 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:145.18,151.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:152.2,152.17 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:152.17,158.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:159.2,159.68 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:162.59,163.18 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:163.18,165.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:166.2,166.54 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:166.54,168.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:169.2,169.18 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:169.18,175.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:176.2,176.17 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:176.17,182.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:183.2,183.68 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:186.61,187.18 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:187.18,189.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:190.2,194.8 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:197.58,198.34 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:198.34,200.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:201.2,205.8 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:208.65,209.34 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:209.34,211.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:212.2,216.8 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:219.59,220.34 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:220.34,222.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:223.2,227.8 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:230.58,231.18 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:231.18,233.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:234.2,238.8 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:241.62,242.18 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:242.18,244.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:245.2,249.8 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:252.60,253.19 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:253.19,255.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:256.2,260.8 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:263.68,264.19 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:264.19,266.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:267.2,271.8 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:274.69,275.19 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:275.19,277.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:278.2,282.8 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:285.70,286.19 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:286.19,288.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:289.2,293.8 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:296.63,297.19 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:297.19,299.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:300.2,304.8 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:307.61,308.35 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:308.35,310.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:311.2,315.8 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:318.65,319.35 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:319.35,321.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:322.2,326.8 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:329.60,330.18 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:330.18,332.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:333.2,333.58 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:333.58,336.39 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:336.39,338.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:339.3,339.15 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:341.2,341.18 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:341.18,347.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:348.2,348.17 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:348.17,354.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:355.2,355.68 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:358.65,359.18 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:359.18,361.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:362.2,362.58 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:362.58,365.39 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:365.39,367.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:368.3,368.15 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:370.2,370.18 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:370.18,376.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:377.2,377.17 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:377.17,383.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:384.2,384.68 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:24.97,26.60 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:26.60,28.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:29.2,29.24 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:29.24,30.48 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:30.48,31.85 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:31.85,32.10 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:34.4,35.18 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:35.18,37.5 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:38.4,38.32 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:42.2,43.62 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:43.62,45.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:46.2,46.26 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:46.26,47.94 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:47.94,49.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:50.3,50.53 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:53.2,54.63 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:54.63,56.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:57.2,57.27 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:57.27,59.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:62.2,63.85 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:63.85,64.26 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:64.26,65.12 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:67.3,67.31 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:67.31,69.12 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:71.3,71.41 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:71.41,73.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:76.2,77.30 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:77.30,79.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:79.8,81.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:83.2,83.55 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:83.55,85.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:85.8,85.31 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:85.31,86.34 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:86.34,88.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:91.2,91.50 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:27.109,29.16 2 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:29.16,31.3 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:33.2,36.9 3 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:36.9,38.3 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:40.2,42.33 2 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:42.33,43.61 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:43.61,45.4 1 0 -github.com/echovault/echovault/pkg/modules/string/commands.go:46.3,46.58 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:46.58,48.4 1 0 -github.com/echovault/echovault/pkg/modules/string/commands.go:49.3,50.58 2 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:53.2,53.52 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:53.52,55.3 1 0 -github.com/echovault/echovault/pkg/modules/string/commands.go:56.2,59.9 3 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:59.9,61.3 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:64.2,64.24 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:64.24,66.58 2 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:66.58,68.4 1 0 -github.com/echovault/echovault/pkg/modules/string/commands.go:69.3,69.58 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:73.2,73.16 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:73.16,75.58 2 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:75.58,77.4 1 0 -github.com/echovault/echovault/pkg/modules/string/commands.go:78.3,78.58 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:81.2,83.35 2 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:83.35,85.24 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:85.24,88.12 3 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:91.3,92.8 2 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:95.2,95.67 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:95.67,97.3 1 0 -github.com/echovault/echovault/pkg/modules/string/commands.go:99.2,99.59 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:102.110,104.16 2 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:104.16,106.3 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:108.2,110.33 2 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:110.33,112.3 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:114.2,114.53 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:114.53,116.3 1 0 -github.com/echovault/echovault/pkg/modules/string/commands.go:117.2,121.9 3 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:121.9,123.3 1 0 -github.com/echovault/echovault/pkg/modules/string/commands.go:125.2,125.56 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:128.107,130.16 2 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:130.16,132.3 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:134.2,140.24 5 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:140.24,142.3 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:144.2,144.33 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:144.33,146.3 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:148.2,148.52 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:148.52,150.3 1 0 -github.com/echovault/echovault/pkg/modules/string/commands.go:151.2,154.9 3 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:154.9,156.3 1 0 -github.com/echovault/echovault/pkg/modules/string/commands.go:158.2,158.15 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:158.15,160.3 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:161.2,161.13 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:161.13,163.3 1 0 -github.com/echovault/echovault/pkg/modules/string/commands.go:165.2,165.30 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:165.30,167.3 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:169.2,169.22 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:169.22,171.3 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:173.2,173.17 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:173.17,176.3 2 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:178.2,180.14 2 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:180.14,182.38 2 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:182.38,184.4 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:185.3,185.12 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:188.2,188.65 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:191.33,231.2 1 0 -github.com/echovault/echovault/pkg/modules/string/key_funcs.go:23.62,24.19 1 1 -github.com/echovault/echovault/pkg/modules/string/key_funcs.go:24.19,26.3 1 1 -github.com/echovault/echovault/pkg/modules/string/key_funcs.go:27.2,31.8 1 1 -github.com/echovault/echovault/pkg/modules/string/key_funcs.go:34.60,35.19 1 1 -github.com/echovault/echovault/pkg/modules/string/key_funcs.go:35.19,37.3 1 1 -github.com/echovault/echovault/pkg/modules/string/key_funcs.go:38.2,42.8 1 1 -github.com/echovault/echovault/pkg/modules/string/key_funcs.go:45.60,46.19 1 1 -github.com/echovault/echovault/pkg/modules/string/key_funcs.go:46.19,48.3 1 1 -github.com/echovault/echovault/pkg/modules/string/key_funcs.go:49.2,53.8 1 1 diff --git a/internal/raft/fsm.go b/internal/raft/fsm.go index 7619deea..2de04d81 100644 --- a/internal/raft/fsm.go +++ b/internal/raft/fsm.go @@ -24,6 +24,7 @@ import ( "github.com/hashicorp/raft" "io" "log" + "net" "strings" ) @@ -36,6 +37,7 @@ type FSMOpts struct { StartSnapshot func() FinishSnapshot func() SetLatestSnapshotTime func(msec int64) + GetHandlerFuncParams func(ctx context.Context, cmd []string, conn *net.Conn) types.HandlerFuncParams } type FSM struct { @@ -86,34 +88,33 @@ func (fsm *FSM) Apply(log *raft.Log) interface{} { } case "command": - // TODO: Re-Implement Command handling with dependency injection // Handle command - // command, err := fsm.options.GetCommand(request.CMD[0]) - // if err != nil { - // return internal.ApplyResponse{ - // Error: err, - // Response: nil, - // } - // } - // - // handler := command.HandlerFunc - // - // subCommand, ok := internal.GetSubCommand(command, request.CMD).(types.SubCommand) - // if ok { - // handler = subCommand.HandlerFunc - // } - // - // if res, err := handler(ctx, request.CMD, fsm.options.EchoVault, nil); err != nil { - // return internal.ApplyResponse{ - // Error: err, - // Response: nil, - // } - // } else { - // return internal.ApplyResponse{ - // Error: nil, - // Response: res, - // } - // } + command, err := fsm.options.GetCommand(request.CMD[0]) + if err != nil { + return internal.ApplyResponse{ + Error: err, + Response: nil, + } + } + + handler := command.HandlerFunc + + subCommand, ok := internal.GetSubCommand(command, request.CMD).(types.SubCommand) + if ok { + handler = subCommand.HandlerFunc + } + + if res, err := handler(fsm.options.GetHandlerFuncParams(ctx, request.CMD, nil)); err != nil { + return internal.ApplyResponse{ + Error: err, + Response: nil, + } + } else { + return internal.ApplyResponse{ + Error: nil, + Response: res, + } + } } } diff --git a/internal/raft/raft.go b/internal/raft/raft.go index 3a113545..a6abbc6a 100644 --- a/internal/raft/raft.go +++ b/internal/raft/raft.go @@ -41,6 +41,7 @@ type Opts struct { StartSnapshot func() FinishSnapshot func() SetLatestSnapshotTime func(msec int64) + GetHandlerFuncParams func(ctx context.Context, cmd []string, conn *net.Conn) types.HandlerFuncParams } type Raft struct { @@ -120,6 +121,7 @@ func (r *Raft) RaftInit(ctx context.Context) { StartSnapshot: r.options.StartSnapshot, FinishSnapshot: r.options.FinishSnapshot, SetLatestSnapshotTime: r.options.SetLatestSnapshotTime, + GetHandlerFuncParams: r.options.GetHandlerFuncParams, }), logStore, stableStore, diff --git a/pkg/echovault/echovault.go b/pkg/echovault/echovault.go index b56b7425..70e69bf1 100644 --- a/pkg/echovault/echovault.go +++ b/pkg/echovault/echovault.go @@ -157,6 +157,7 @@ func NewEchoVault(options ...func(echovault *EchoVault)) (*EchoVault, error) { StartSnapshot: echovault.startSnapshot, FinishSnapshot: echovault.finishSnapshot, SetLatestSnapshotTime: echovault.setLatestSnapshot, + GetHandlerFuncParams: echovault.getHandlerFuncParams, GetState: func() map[string]internal.KeyData { state := make(map[string]internal.KeyData) for k, v := range echovault.getState() { diff --git a/pkg/echovault/modules.go b/pkg/echovault/modules.go index 0f02e3ea..9f8e44ff 100644 --- a/pkg/echovault/modules.go +++ b/pkg/echovault/modules.go @@ -48,7 +48,6 @@ func (server *EchoVault) getCommand(cmd string) (types.Command, error) { func (server *EchoVault) getHandlerFuncParams(ctx context.Context, cmd []string, conn *net.Conn) types.HandlerFuncParams { return types.HandlerFuncParams{ - // TODO: Add all the required methods here Context: ctx, Command: cmd, Connection: conn, @@ -60,6 +59,13 @@ func (server *EchoVault) getHandlerFuncParams(ctx context.Context, cmd []string, KeyRUnlock: server.KeyRUnlock, GetValue: server.GetValue, SetValue: server.SetValue, + GetClock: server.GetClock, + GetExpiry: server.GetExpiry, + SetExpiry: server.SetExpiry, + DeleteKey: server.DeleteKey, + GetPubSub: server.GetPubSub, + GetACL: server.GetACL, + GetAllCommands: server.GetAllCommands, } } diff --git a/pkg/modules/acl/commands.go b/pkg/modules/acl/commands.go index 2392cb83..68e05ba0 100644 --- a/pkg/modules/acl/commands.go +++ b/pkg/modules/acl/commands.go @@ -15,7 +15,6 @@ package acl import ( - "context" "encoding/json" "errors" "fmt" @@ -24,33 +23,32 @@ import ( "github.com/echovault/echovault/pkg/types" "gopkg.in/yaml.v3" "log" - "net" "os" "path" "slices" "strings" ) -func handleAuth(ctx context.Context, cmd []string, server types.EchoVault, conn *net.Conn) ([]byte, error) { - if len(cmd) < 2 || len(cmd) > 3 { +func handleAuth(params types.HandlerFuncParams) ([]byte, error) { + if len(params.Command) < 2 || len(params.Command) > 3 { return nil, errors.New(constants.WrongArgsResponse) } - acl, ok := server.GetACL().(*internal_acl.ACL) + acl, ok := params.GetACL().(*internal_acl.ACL) if !ok { return nil, errors.New("could not load ACL") } - if err := acl.AuthenticateConnection(ctx, conn, cmd); err != nil { + if err := acl.AuthenticateConnection(params.Context, params.Connection, params.Command); err != nil { return nil, err } return []byte(constants.OkResponse), nil } -func handleGetUser(_ context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - if len(cmd) != 3 { +func handleGetUser(params types.HandlerFuncParams) ([]byte, error) { + if len(params.Command) != 3 { return nil, errors.New(constants.WrongArgsResponse) } - acl, ok := server.GetACL().(*internal_acl.ACL) + acl, ok := params.GetACL().(*internal_acl.ACL) if !ok { return nil, errors.New("could not load ACL") } @@ -58,7 +56,7 @@ func handleGetUser(_ context.Context, cmd []string, server types.EchoVault, _ *n var user *internal_acl.User userFound := false for _, u := range acl.Users { - if u.Username == cmd[2] { + if u.Username == params.Command[2] { user = u userFound = true break @@ -162,14 +160,14 @@ func handleGetUser(_ context.Context, cmd []string, server types.EchoVault, _ *n return []byte(res), nil } -func handleCat(_ context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - if len(cmd) > 3 { +func handleCat(params types.HandlerFuncParams) ([]byte, error) { + if len(params.Command) > 3 { return nil, errors.New(constants.WrongArgsResponse) } categories := make(map[string][]string) - commands := server.GetAllCommands() + commands := params.GetAllCommands() for _, command := range commands { if len(command.SubCommands) == 0 { @@ -186,7 +184,7 @@ func handleCat(_ context.Context, cmd []string, server types.EchoVault, _ *net.C } } - if len(cmd) == 2 { + if len(params.Command) == 2 { var cats []string length := 0 for key, _ := range categories { @@ -203,10 +201,10 @@ func handleCat(_ context.Context, cmd []string, server types.EchoVault, _ *net.C return []byte(res), nil } - if len(cmd) == 3 { + if len(params.Command) == 3 { var res string for category, commands := range categories { - if strings.EqualFold(category, cmd[2]) { + if strings.EqualFold(category, params.Command[2]) { res = fmt.Sprintf("*%d", len(commands)) for i, command := range commands { res = fmt.Sprintf("%s\r\n+%s", res, command) @@ -219,11 +217,11 @@ func handleCat(_ context.Context, cmd []string, server types.EchoVault, _ *net.C } } - return nil, fmt.Errorf("category %s not found", strings.ToUpper(cmd[2])) + return nil, fmt.Errorf("category %s not found", strings.ToUpper(params.Command[2])) } -func handleUsers(_ context.Context, _ []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - acl, ok := server.GetACL().(*internal_acl.ACL) +func handleUsers(params types.HandlerFuncParams) ([]byte, error) { + acl, ok := params.GetACL().(*internal_acl.ACL) if !ok { return nil, errors.New("could not load ACL") } @@ -235,45 +233,45 @@ func handleUsers(_ context.Context, _ []string, server types.EchoVault, _ *net.C return []byte(res), nil } -func handleSetUser(_ context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - acl, ok := server.GetACL().(*internal_acl.ACL) +func handleSetUser(params types.HandlerFuncParams) ([]byte, error) { + acl, ok := params.GetACL().(*internal_acl.ACL) if !ok { return nil, errors.New("could not load ACL") } - if err := acl.SetUser(cmd[2:]); err != nil { + if err := acl.SetUser(params.Command[2:]); err != nil { return nil, err } return []byte(constants.OkResponse), nil } -func handleDelUser(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - if len(cmd) < 3 { +func handleDelUser(params types.HandlerFuncParams) ([]byte, error) { + if len(params.Command) < 3 { return nil, errors.New(constants.WrongArgsResponse) } - acl, ok := server.GetACL().(*internal_acl.ACL) + acl, ok := params.GetACL().(*internal_acl.ACL) if !ok { return nil, errors.New("could not load ACL") } - if err := acl.DeleteUser(ctx, cmd[2:]); err != nil { + if err := acl.DeleteUser(params.Context, params.Command[2:]); err != nil { return nil, err } return []byte(constants.OkResponse), nil } -func handleWhoAmI(_ context.Context, _ []string, server types.EchoVault, conn *net.Conn) ([]byte, error) { - acl, ok := server.GetACL().(*internal_acl.ACL) +func handleWhoAmI(params types.HandlerFuncParams) ([]byte, error) { + acl, ok := params.GetACL().(*internal_acl.ACL) if !ok { return nil, errors.New("could not load ACL") } - connectionInfo := acl.Connections[conn] + connectionInfo := acl.Connections[params.Connection] return []byte(fmt.Sprintf("+%s\r\n", connectionInfo.User.Username)), nil } -func handleList(_ context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - if len(cmd) > 2 { +func handleList(params types.HandlerFuncParams) ([]byte, error) { + if len(params.Command) > 2 { return nil, errors.New(constants.WrongArgsResponse) } - acl, ok := server.GetACL().(*internal_acl.ACL) + acl, ok := params.GetACL().(*internal_acl.ACL) if !ok { return nil, errors.New("could not load ACL") } @@ -365,12 +363,12 @@ func handleList(_ context.Context, cmd []string, server types.EchoVault, _ *net. return []byte(res), nil } -func handleLoad(_ context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - if len(cmd) != 3 { +func handleLoad(params types.HandlerFuncParams) ([]byte, error) { + if len(params.Command) != 3 { return nil, errors.New(constants.WrongArgsResponse) } - acl, ok := server.GetACL().(*internal_acl.ACL) + acl, ok := params.GetACL().(*internal_acl.ACL) if !ok { return nil, errors.New("could not load ACL") } @@ -414,7 +412,7 @@ func handleLoad(_ context.Context, cmd []string, server types.EchoVault, _ *net. if u.Username == user.Username { userFound = true // If we have a user with the current username and are in merge mode, merge the two users. - if strings.EqualFold(cmd[2], "merge") { + if strings.EqualFold(params.Command[2], "merge") { u.Merge(user) } else { // If we have a user with the current username and are in replace mode, merge the two users. @@ -432,12 +430,12 @@ func handleLoad(_ context.Context, cmd []string, server types.EchoVault, _ *net. return []byte(constants.OkResponse), nil } -func handleSave(_ context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - if len(cmd) > 2 { +func handleSave(params types.HandlerFuncParams) ([]byte, error) { + if len(params.Command) > 2 { return nil, errors.New(constants.WrongArgsResponse) } - acl, ok := server.GetACL().(*internal_acl.ACL) + acl, ok := params.GetACL().(*internal_acl.ACL) if !ok { return nil, errors.New("could not load ACL") } diff --git a/pkg/modules/admin/commands.go b/pkg/modules/admin/commands.go index b1edf83e..0ea5f150 100644 --- a/pkg/modules/admin/commands.go +++ b/pkg/modules/admin/commands.go @@ -15,19 +15,17 @@ package admin import ( - "context" "errors" "fmt" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/types" "github.com/gobwas/glob" - "net" "slices" "strings" ) -func handleGetAllCommands(_ context.Context, _ []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - commands := server.GetAllCommands() +func handleGetAllCommands(params types.HandlerFuncParams) ([]byte, error) { + commands := params.GetAllCommands() res := "" commandCount := 0 @@ -71,10 +69,10 @@ func handleGetAllCommands(_ context.Context, _ []string, server types.EchoVault, return []byte(res), nil } -func handleCommandCount(_ context.Context, _ []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { +func handleCommandCount(params types.HandlerFuncParams) ([]byte, error) { var count int - commands := server.GetAllCommands() + commands := params.GetAllCommands() for _, command := range commands { if command.SubCommands != nil && len(command.SubCommands) > 0 { for _, _ = range command.SubCommands { @@ -88,13 +86,13 @@ func handleCommandCount(_ context.Context, _ []string, server types.EchoVault, _ return []byte(fmt.Sprintf(":%d\r\n", count)), nil } -func handleCommandList(_ context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - switch len(cmd) { +func handleCommandList(params types.HandlerFuncParams) ([]byte, error) { + switch len(params.Command) { case 2: // Command is COMMAND LIST var count int var res string - commands := server.GetAllCommands() + commands := params.GetAllCommands() for _, command := range commands { if command.SubCommands != nil && len(command.SubCommands) > 0 { for _, subcommand := range command.SubCommands { @@ -114,13 +112,13 @@ func handleCommandList(_ context.Context, cmd []string, server types.EchoVault, var count int var res string // Command has filter - if !strings.EqualFold("FILTERBY", cmd[2]) { - return nil, fmt.Errorf("expected FILTERBY, got %s", strings.ToUpper(cmd[2])) + if !strings.EqualFold("FILTERBY", params.Command[2]) { + return nil, fmt.Errorf("expected FILTERBY, got %s", strings.ToUpper(params.Command[2])) } - if strings.EqualFold("ACLCAT", cmd[3]) { + if strings.EqualFold("ACLCAT", params.Command[3]) { // ACL Category filter - commands := server.GetAllCommands() - category := strings.ToLower(cmd[4]) + commands := params.GetAllCommands() + category := strings.ToLower(params.Command[4]) for _, command := range commands { if command.SubCommands != nil && len(command.SubCommands) > 0 { for _, subcommand := range command.SubCommands { @@ -137,10 +135,10 @@ func handleCommandList(_ context.Context, cmd []string, server types.EchoVault, count += 1 } } - } else if strings.EqualFold("PATTERN", cmd[3]) { + } else if strings.EqualFold("PATTERN", params.Command[3]) { // Pattern filter - commands := server.GetAllCommands() - g := glob.MustCompile(cmd[4]) + commands := params.GetAllCommands() + g := glob.MustCompile(params.Command[4]) for _, command := range commands { if command.SubCommands != nil && len(command.SubCommands) > 0 { for _, subcommand := range command.SubCommands { @@ -157,10 +155,10 @@ func handleCommandList(_ context.Context, cmd []string, server types.EchoVault, count += 1 } } - } else if strings.EqualFold("MODULE", cmd[3]) { + } else if strings.EqualFold("MODULE", params.Command[3]) { // Module filter - commands := server.GetAllCommands() - module := strings.ToLower(cmd[4]) + commands := params.GetAllCommands() + module := strings.ToLower(params.Command[4]) for _, command := range commands { if command.SubCommands != nil && len(command.SubCommands) > 0 { for _, subcommand := range command.SubCommands { @@ -178,7 +176,7 @@ func handleCommandList(_ context.Context, cmd []string, server types.EchoVault, } } } else { - return nil, fmt.Errorf("expected filter to be ACLCAT or PATTERN, got %s", strings.ToUpper(cmd[3])) + return nil, fmt.Errorf("expected filter to be ACLCAT or PATTERN, got %s", strings.ToUpper(params.Command[3])) } res = fmt.Sprintf("*%d\r\n%s", count, res) return []byte(res), nil @@ -187,7 +185,7 @@ func handleCommandList(_ context.Context, cmd []string, server types.EchoVault, } } -func handleCommandDocs(_ context.Context, _ []string, _ types.EchoVault, _ *net.Conn) ([]byte, error) { +func handleCommandDocs(params types.HandlerFuncParams) ([]byte, error) { return []byte("*0\r\n"), nil } @@ -283,8 +281,8 @@ Allows for filtering by ACL category or glob pattern.`, WriteKeys: make([]string, 0), }, nil }, - HandlerFunc: func(ctx context.Context, cmd []string, server types.EchoVault, conn *net.Conn) ([]byte, error) { - if err := server.TakeSnapshot(); err != nil { + HandlerFunc: func(params types.HandlerFuncParams) ([]byte, error) { + if err := params.TakeSnapshot(); err != nil { return nil, err } return []byte(constants.OkResponse), nil @@ -303,8 +301,8 @@ Allows for filtering by ACL category or glob pattern.`, WriteKeys: make([]string, 0), }, nil }, - HandlerFunc: func(ctx context.Context, cmd []string, server types.EchoVault, conn *net.Conn) ([]byte, error) { - msec := server.GetLatestSnapshotTime() + HandlerFunc: func(params types.HandlerFuncParams) ([]byte, error) { + msec := params.GetLatestSnapshotTime() if msec == 0 { return nil, errors.New("no snapshot") } @@ -324,8 +322,8 @@ Allows for filtering by ACL category or glob pattern.`, WriteKeys: make([]string, 0), }, nil }, - HandlerFunc: func(ctx context.Context, cmd []string, server types.EchoVault, conn *net.Conn) ([]byte, error) { - if err := server.RewriteAOF(); err != nil { + HandlerFunc: func(params types.HandlerFuncParams) ([]byte, error) { + if err := params.RewriteAOF(); err != nil { return nil, err } return []byte(constants.OkResponse), nil diff --git a/pkg/modules/connection/commands.go b/pkg/modules/connection/commands.go index f9eac58b..1cfb8870 100644 --- a/pkg/modules/connection/commands.go +++ b/pkg/modules/connection/commands.go @@ -15,29 +15,27 @@ package connection import ( - "context" "errors" "fmt" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/types" - "net" ) -func handlePing(ctx context.Context, cmd []string, server types.EchoVault, conn *net.Conn) ([]byte, error) { - switch len(cmd) { +func handlePing(params types.HandlerFuncParams) ([]byte, error) { + switch len(params.Command) { default: return nil, errors.New(constants.WrongArgsResponse) case 1: return []byte("+PONG\r\n"), nil case 2: - return []byte(fmt.Sprintf("$%d\r\n%s\r\n", len(cmd[1]), cmd[1])), nil + return []byte(fmt.Sprintf("$%d\r\n%s\r\n", len(params.Command[1]), params.Command[1])), nil } } func Commands() []types.Command { return []types.Command{ { - Command: "connection", + Command: "ping", Module: constants.ConnectionModule, Categories: []string{constants.FastCategory, constants.ConnectionCategory}, Description: "(PING [value]) Ping the echovault. If a value is provided, the value will be echoed.", diff --git a/pkg/modules/generic/commands.go b/pkg/modules/generic/commands.go index a9e454d7..6db861e1 100644 --- a/pkg/modules/generic/commands.go +++ b/pkg/modules/generic/commands.go @@ -15,14 +15,12 @@ package generic import ( - "context" "errors" "fmt" "github.com/echovault/echovault/internal" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/types" "log" - "net" "strconv" "strings" "time" @@ -33,73 +31,73 @@ type KeyObject struct { locked bool } -func handleSet(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := setKeyFunc(cmd) +func handleSet(params types.HandlerFuncParams) ([]byte, error) { + keys, err := setKeyFunc(params.Command) if err != nil { return nil, err } key := keys.WriteKeys[0] - value := cmd[2] + value := params.Command[2] res := []byte(constants.OkResponse) - clock := server.GetClock() + clock := params.GetClock() - params, err := getSetCommandParams(clock, cmd[3:], SetParams{}) + options, err := getSetCommandOptions(clock, params.Command[3:], SetOptions{}) if err != nil { return nil, err } // If GET is provided, the response should be the current stored value. // If there's no current value, then the response should be nil. - if params.get { - if !server.KeyExists(ctx, key) { + if options.get { + if !params.KeyExists(params.Context, key) { res = []byte("$-1\r\n") } else { - res = []byte(fmt.Sprintf("+%v\r\n", server.GetValue(ctx, key))) + res = []byte(fmt.Sprintf("+%v\r\n", params.GetValue(params.Context, key))) } } - if "xx" == strings.ToLower(params.exists) { + if "xx" == strings.ToLower(options.exists) { // If XX is specified, make sure the key exists. - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return nil, fmt.Errorf("key %s does not exist", key) } - _, err = server.KeyLock(ctx, key) - } else if "nx" == strings.ToLower(params.exists) { + _, err = params.KeyLock(params.Context, key) + } else if "nx" == strings.ToLower(options.exists) { // If NX is specified, make sure that the key does not currently exist. - if server.KeyExists(ctx, key) { + if params.KeyExists(params.Context, key) { return nil, fmt.Errorf("key %s already exists", key) } - _, err = server.CreateKeyAndLock(ctx, key) + _, err = params.CreateKeyAndLock(params.Context, key) } else { // Neither XX not NX are specified, lock or create the lock - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { // Key does not exist, create it - _, err = server.CreateKeyAndLock(ctx, key) + _, err = params.CreateKeyAndLock(params.Context, key) } else { // Key exists, acquire the lock - _, err = server.KeyLock(ctx, key) + _, err = params.KeyLock(params.Context, key) } } if err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) - if err = server.SetValue(ctx, key, internal.AdaptType(value)); err != nil { + if err = params.SetValue(params.Context, key, internal.AdaptType(value)); err != nil { return nil, err } // If expiresAt is set, set the key's expiry time as well - if params.expireAt != nil { - server.SetExpiry(ctx, key, params.expireAt.(time.Time), false) + if options.expireAt != nil { + params.SetExpiry(params.Context, key, options.expireAt.(time.Time), false) } return res, nil } -func handleMSet(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - _, err := msetKeyFunc(cmd) +func handleMSet(params types.HandlerFuncParams) ([]byte, error) { + _, err := msetKeyFunc(params.Command) if err != nil { return nil, err } @@ -110,7 +108,7 @@ func handleMSet(ctx context.Context, cmd []string, server types.EchoVault, _ *ne defer func() { for k, v := range entries { if v.locked { - server.KeyUnlock(ctx, k) + params.KeyUnlock(params.Context, k) entries[k] = KeyObject{ value: v.value, locked: false, @@ -120,10 +118,10 @@ func handleMSet(ctx context.Context, cmd []string, server types.EchoVault, _ *ne }() // Extract all the key/value pairs - for i, key := range cmd[1:] { + for i, key := range params.Command[1:] { if i%2 == 0 { entries[key] = KeyObject{ - value: internal.AdaptType(cmd[1:][i+1]), + value: internal.AdaptType(params.Command[1:][i+1]), locked: false, } } @@ -132,14 +130,14 @@ func handleMSet(ctx context.Context, cmd []string, server types.EchoVault, _ *ne // Acquire all the locks for each key first // If any key cannot be acquired, abandon transaction and release all currently held keys for k, v := range entries { - if server.KeyExists(ctx, k) { - if _, err := server.KeyLock(ctx, k); err != nil { + if params.KeyExists(params.Context, k) { + if _, err := params.KeyLock(params.Context, k); err != nil { return nil, err } entries[k] = KeyObject{value: v.value, locked: true} continue } - if _, err := server.CreateKeyAndLock(ctx, k); err != nil { + if _, err := params.CreateKeyAndLock(params.Context, k); err != nil { return nil, err } entries[k] = KeyObject{value: v.value, locked: true} @@ -147,7 +145,7 @@ func handleMSet(ctx context.Context, cmd []string, server types.EchoVault, _ *ne // Set all the values for k, v := range entries { - if err := server.SetValue(ctx, k, v.value); err != nil { + if err := params.SetValue(params.Context, k, v.value); err != nil { return nil, err } } @@ -155,30 +153,30 @@ func handleMSet(ctx context.Context, cmd []string, server types.EchoVault, _ *ne return []byte(constants.OkResponse), nil } -func handleGet(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := getKeyFunc(cmd) +func handleGet(params types.HandlerFuncParams) ([]byte, error) { + keys, err := getKeyFunc(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte("$-1\r\n"), nil } - _, err = server.KeyRLock(ctx, key) + _, err = params.KeyRLock(params.Context, key) if err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - value := server.GetValue(ctx, key) + value := params.GetValue(params.Context, key) return []byte(fmt.Sprintf("+%v\r\n", value)), nil } -func handleMGet(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := mgetKeyFunc(cmd) +func handleMGet(params types.HandlerFuncParams) ([]byte, error) { + keys, err := mgetKeyFunc(params.Command) if err != nil { return nil, err } @@ -191,8 +189,8 @@ func handleMGet(ctx context.Context, cmd []string, server types.EchoVault, _ *ne // Skip if we have already locked this key continue } - if server.KeyExists(ctx, key) { - _, err = server.KeyRLock(ctx, key) + if params.KeyExists(params.Context, key) { + _, err = params.KeyRLock(params.Context, key) if err != nil { return nil, fmt.Errorf("could not obtain lock for %s key", key) } @@ -204,19 +202,19 @@ func handleMGet(ctx context.Context, cmd []string, server types.EchoVault, _ *ne defer func() { for key, locked := range locks { if locked { - server.KeyRUnlock(ctx, key) + params.KeyRUnlock(params.Context, key) locks[key] = false } } }() for key, _ := range locks { - values[key] = fmt.Sprintf("%v", server.GetValue(ctx, key)) + values[key] = fmt.Sprintf("%v", params.GetValue(params.Context, key)) } - bytes := []byte(fmt.Sprintf("*%d\r\n", len(cmd[1:]))) + bytes := []byte(fmt.Sprintf("*%d\r\n", len(params.Command[1:]))) - for _, key := range cmd[1:] { + for _, key := range params.Command[1:] { if values[key] == "" { bytes = append(bytes, []byte("$-1\r\n")...) continue @@ -227,14 +225,14 @@ func handleMGet(ctx context.Context, cmd []string, server types.EchoVault, _ *ne return bytes, nil } -func handleDel(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := delKeyFunc(cmd) +func handleDel(params types.HandlerFuncParams) ([]byte, error) { + keys, err := delKeyFunc(params.Command) if err != nil { return nil, err } count := 0 for _, key := range keys.WriteKeys { - err = server.DeleteKey(ctx, key) + err = params.DeleteKey(params.Context, key) if err != nil { log.Printf("could not delete key %s due to error: %+v\n", key, err) continue @@ -244,91 +242,91 @@ func handleDel(ctx context.Context, cmd []string, server types.EchoVault, _ *net return []byte(fmt.Sprintf(":%d\r\n", count)), nil } -func handlePersist(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := persistKeyFunc(cmd) +func handlePersist(params types.HandlerFuncParams) ([]byte, error) { + keys, err := persistKeyFunc(params.Command) if err != nil { return nil, err } key := keys.WriteKeys[0] - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte(":0\r\n"), nil } - if _, err = server.KeyLock(ctx, key); err != nil { + if _, err = params.KeyLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) - expireAt := server.GetExpiry(ctx, key) + expireAt := params.GetExpiry(params.Context, key) if expireAt == (time.Time{}) { return []byte(":0\r\n"), nil } - server.SetExpiry(ctx, key, time.Time{}, false) + params.SetExpiry(params.Context, key, time.Time{}, false) return []byte(":1\r\n"), nil } -func handleExpireTime(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := expireTimeKeyFunc(cmd) +func handleExpireTime(params types.HandlerFuncParams) ([]byte, error) { + keys, err := expireTimeKeyFunc(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte(":-2\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - expireAt := server.GetExpiry(ctx, key) + expireAt := params.GetExpiry(params.Context, key) if expireAt == (time.Time{}) { return []byte(":-1\r\n"), nil } t := expireAt.Unix() - if strings.ToLower(cmd[0]) == "pexpiretime" { + if strings.ToLower(params.Command[0]) == "pexpiretime" { t = expireAt.UnixMilli() } return []byte(fmt.Sprintf(":%d\r\n", t)), nil } -func handleTTL(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := ttlKeyFunc(cmd) +func handleTTL(params types.HandlerFuncParams) ([]byte, error) { + keys, err := ttlKeyFunc(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] - clock := server.GetClock() + clock := params.GetClock() - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte(":-2\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - expireAt := server.GetExpiry(ctx, key) + expireAt := params.GetExpiry(params.Context, key) if expireAt == (time.Time{}) { return []byte(":-1\r\n"), nil } t := expireAt.Unix() - clock.Now().Unix() - if strings.ToLower(cmd[0]) == "pttl" { + if strings.ToLower(params.Command[0]) == "pttl" { t = expireAt.UnixMilli() - clock.Now().UnixMilli() } @@ -339,8 +337,8 @@ func handleTTL(ctx context.Context, cmd []string, server types.EchoVault, _ *net return []byte(fmt.Sprintf(":%d\r\n", t)), nil } -func handleExpire(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := expireKeyFunc(cmd) +func handleExpire(params types.HandlerFuncParams) ([]byte, error) { + keys, err := expireKeyFunc(params.Command) if err != nil { return nil, err } @@ -348,42 +346,42 @@ func handleExpire(ctx context.Context, cmd []string, server types.EchoVault, _ * key := keys.WriteKeys[0] // Extract time - n, err := strconv.ParseInt(cmd[2], 10, 64) + n, err := strconv.ParseInt(params.Command[2], 10, 64) if err != nil { return nil, errors.New("expire time must be integer") } - expireAt := server.GetClock().Now().Add(time.Duration(n) * time.Second) - if strings.ToLower(cmd[0]) == "pexpire" { - expireAt = server.GetClock().Now().Add(time.Duration(n) * time.Millisecond) + expireAt := params.GetClock().Now().Add(time.Duration(n) * time.Second) + if strings.ToLower(params.Command[0]) == "pexpire" { + expireAt = params.GetClock().Now().Add(time.Duration(n) * time.Millisecond) } - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte(":0\r\n"), nil } - if _, err = server.KeyLock(ctx, key); err != nil { + if _, err = params.KeyLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) - if len(cmd) == 3 { - server.SetExpiry(ctx, key, expireAt, true) + if len(params.Command) == 3 { + params.SetExpiry(params.Context, key, expireAt, true) return []byte(":1\r\n"), nil } - currentExpireAt := server.GetExpiry(ctx, key) + currentExpireAt := params.GetExpiry(params.Context, key) - switch strings.ToLower(cmd[3]) { + switch strings.ToLower(params.Command[3]) { case "nx": if currentExpireAt != (time.Time{}) { return []byte(":0\r\n"), nil } - server.SetExpiry(ctx, key, expireAt, false) + params.SetExpiry(params.Context, key, expireAt, false) case "xx": if currentExpireAt == (time.Time{}) { return []byte(":0\r\n"), nil } - server.SetExpiry(ctx, key, expireAt, false) + params.SetExpiry(params.Context, key, expireAt, false) case "gt": if currentExpireAt == (time.Time{}) { return []byte(":0\r\n"), nil @@ -391,24 +389,24 @@ func handleExpire(ctx context.Context, cmd []string, server types.EchoVault, _ * if expireAt.Before(currentExpireAt) { return []byte(":0\r\n"), nil } - server.SetExpiry(ctx, key, expireAt, false) + params.SetExpiry(params.Context, key, expireAt, false) case "lt": if currentExpireAt != (time.Time{}) { if currentExpireAt.Before(expireAt) { return []byte(":0\r\n"), nil } - server.SetExpiry(ctx, key, expireAt, false) + params.SetExpiry(params.Context, key, expireAt, false) } - server.SetExpiry(ctx, key, expireAt, false) + params.SetExpiry(params.Context, key, expireAt, false) default: - return nil, fmt.Errorf("unknown option %s", strings.ToUpper(cmd[3])) + return nil, fmt.Errorf("unknown option %s", strings.ToUpper(params.Command[3])) } return []byte(":1\r\n"), nil } -func handleExpireAt(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := expireKeyFunc(cmd) +func handleExpireAt(params types.HandlerFuncParams) ([]byte, error) { + keys, err := expireKeyFunc(params.Command) if err != nil { return nil, err } @@ -416,42 +414,42 @@ func handleExpireAt(ctx context.Context, cmd []string, server types.EchoVault, _ key := keys.WriteKeys[0] // Extract time - n, err := strconv.ParseInt(cmd[2], 10, 64) + n, err := strconv.ParseInt(params.Command[2], 10, 64) if err != nil { return nil, errors.New("expire time must be integer") } expireAt := time.Unix(n, 0) - if strings.ToLower(cmd[0]) == "pexpireat" { + if strings.ToLower(params.Command[0]) == "pexpireat" { expireAt = time.UnixMilli(n) } - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte(":0\r\n"), nil } - if _, err = server.KeyLock(ctx, key); err != nil { + if _, err = params.KeyLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) - if len(cmd) == 3 { - server.SetExpiry(ctx, key, expireAt, true) + if len(params.Command) == 3 { + params.SetExpiry(params.Context, key, expireAt, true) return []byte(":1\r\n"), nil } - currentExpireAt := server.GetExpiry(ctx, key) + currentExpireAt := params.GetExpiry(params.Context, key) - switch strings.ToLower(cmd[3]) { + switch strings.ToLower(params.Command[3]) { case "nx": if currentExpireAt != (time.Time{}) { return []byte(":0\r\n"), nil } - server.SetExpiry(ctx, key, expireAt, false) + params.SetExpiry(params.Context, key, expireAt, false) case "xx": if currentExpireAt == (time.Time{}) { return []byte(":0\r\n"), nil } - server.SetExpiry(ctx, key, expireAt, false) + params.SetExpiry(params.Context, key, expireAt, false) case "gt": if currentExpireAt == (time.Time{}) { return []byte(":0\r\n"), nil @@ -459,17 +457,17 @@ func handleExpireAt(ctx context.Context, cmd []string, server types.EchoVault, _ if expireAt.Before(currentExpireAt) { return []byte(":0\r\n"), nil } - server.SetExpiry(ctx, key, expireAt, false) + params.SetExpiry(params.Context, key, expireAt, false) case "lt": if currentExpireAt != (time.Time{}) { if currentExpireAt.Before(expireAt) { return []byte(":0\r\n"), nil } - server.SetExpiry(ctx, key, expireAt, false) + params.SetExpiry(params.Context, key, expireAt, false) } - server.SetExpiry(ctx, key, expireAt, false) + params.SetExpiry(params.Context, key, expireAt, false) default: - return nil, fmt.Errorf("unknown option %s", strings.ToUpper(cmd[3])) + return nil, fmt.Errorf("unknown option %s", strings.ToUpper(params.Command[3])) } return []byte(":1\r\n"), nil diff --git a/pkg/modules/generic/utils.go b/pkg/modules/generic/utils.go index 17a3f5db..3e5b215f 100644 --- a/pkg/modules/generic/utils.go +++ b/pkg/modules/generic/utils.go @@ -23,96 +23,96 @@ import ( "time" ) -type SetParams struct { +type SetOptions struct { exists string get bool expireAt interface{} // Exact expireAt time un unix milliseconds } -func getSetCommandParams(clock clock.Clock, cmd []string, params SetParams) (SetParams, error) { +func getSetCommandOptions(clock clock.Clock, cmd []string, options SetOptions) (SetOptions, error) { if len(cmd) == 0 { - return params, nil + return options, nil } switch strings.ToLower(cmd[0]) { case "get": - params.get = true - return getSetCommandParams(clock, cmd[1:], params) + options.get = true + return getSetCommandOptions(clock, cmd[1:], options) case "nx": - if params.exists != "" { - return SetParams{}, fmt.Errorf("cannot specify NX when %s is already specified", strings.ToUpper(params.exists)) + if options.exists != "" { + return SetOptions{}, fmt.Errorf("cannot specify NX when %s is already specified", strings.ToUpper(options.exists)) } - params.exists = "NX" - return getSetCommandParams(clock, cmd[1:], params) + options.exists = "NX" + return getSetCommandOptions(clock, cmd[1:], options) case "xx": - if params.exists != "" { - return SetParams{}, fmt.Errorf("cannot specify XX when %s is already specified", strings.ToUpper(params.exists)) + if options.exists != "" { + return SetOptions{}, fmt.Errorf("cannot specify XX when %s is already specified", strings.ToUpper(options.exists)) } - params.exists = "XX" - return getSetCommandParams(clock, cmd[1:], params) + options.exists = "XX" + return getSetCommandOptions(clock, cmd[1:], options) case "ex": if len(cmd) < 2 { - return SetParams{}, errors.New("seconds value required after EX") + return SetOptions{}, errors.New("seconds value required after EX") } - if params.expireAt != nil { - return SetParams{}, errors.New("cannot specify EX when expiry time is already set") + if options.expireAt != nil { + return SetOptions{}, errors.New("cannot specify EX when expiry time is already set") } secondsStr := cmd[1] seconds, err := strconv.ParseInt(secondsStr, 10, 64) if err != nil { - return SetParams{}, errors.New("seconds value should be an integer") + return SetOptions{}, errors.New("seconds value should be an integer") } - params.expireAt = clock.Now().Add(time.Duration(seconds) * time.Second) - return getSetCommandParams(clock, cmd[2:], params) + options.expireAt = clock.Now().Add(time.Duration(seconds) * time.Second) + return getSetCommandOptions(clock, cmd[2:], options) case "px": if len(cmd) < 2 { - return SetParams{}, errors.New("milliseconds value required after PX") + return SetOptions{}, errors.New("milliseconds value required after PX") } - if params.expireAt != nil { - return SetParams{}, errors.New("cannot specify PX when expiry time is already set") + if options.expireAt != nil { + return SetOptions{}, errors.New("cannot specify PX when expiry time is already set") } millisecondsStr := cmd[1] milliseconds, err := strconv.ParseInt(millisecondsStr, 10, 64) if err != nil { - return SetParams{}, errors.New("milliseconds value should be an integer") + return SetOptions{}, errors.New("milliseconds value should be an integer") } - params.expireAt = clock.Now().Add(time.Duration(milliseconds) * time.Millisecond) - return getSetCommandParams(clock, cmd[2:], params) + options.expireAt = clock.Now().Add(time.Duration(milliseconds) * time.Millisecond) + return getSetCommandOptions(clock, cmd[2:], options) case "exat": if len(cmd) < 2 { - return SetParams{}, errors.New("seconds value required after EXAT") + return SetOptions{}, errors.New("seconds value required after EXAT") } - if params.expireAt != nil { - return SetParams{}, errors.New("cannot specify EXAT when expiry time is already set") + if options.expireAt != nil { + return SetOptions{}, errors.New("cannot specify EXAT when expiry time is already set") } secondsStr := cmd[1] seconds, err := strconv.ParseInt(secondsStr, 10, 64) if err != nil { - return SetParams{}, errors.New("seconds value should be an integer") + return SetOptions{}, errors.New("seconds value should be an integer") } - params.expireAt = time.Unix(seconds, 0) - return getSetCommandParams(clock, cmd[2:], params) + options.expireAt = time.Unix(seconds, 0) + return getSetCommandOptions(clock, cmd[2:], options) case "pxat": if len(cmd) < 2 { - return SetParams{}, errors.New("milliseconds value required after PXAT") + return SetOptions{}, errors.New("milliseconds value required after PXAT") } - if params.expireAt != nil { - return SetParams{}, errors.New("cannot specify PXAT when expiry time is already set") + if options.expireAt != nil { + return SetOptions{}, errors.New("cannot specify PXAT when expiry time is already set") } millisecondsStr := cmd[1] milliseconds, err := strconv.ParseInt(millisecondsStr, 10, 64) if err != nil { - return SetParams{}, errors.New("milliseconds value should be an integer") + return SetOptions{}, errors.New("milliseconds value should be an integer") } - params.expireAt = time.UnixMilli(milliseconds) - return getSetCommandParams(clock, cmd[2:], params) + options.expireAt = time.UnixMilli(milliseconds) + return getSetCommandOptions(clock, cmd[2:], options) default: - return SetParams{}, 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])) } } diff --git a/pkg/modules/hash/commands.go b/pkg/modules/hash/commands.go index 3399db31..c8b74b3f 100644 --- a/pkg/modules/hash/commands.go +++ b/pkg/modules/hash/commands.go @@ -15,21 +15,19 @@ package hash import ( - "context" "errors" "fmt" "github.com/echovault/echovault/internal" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/types" "math/rand" - "net" "slices" "strconv" "strings" ) -func handleHSET(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := hsetKeyFunc(cmd) +func handleHSET(params types.HandlerFuncParams) ([]byte, error) { + keys, err := hsetKeyFunc(params.Command) if err != nil { return nil, err } @@ -37,39 +35,39 @@ func handleHSET(ctx context.Context, cmd []string, server types.EchoVault, _ *ne key := keys.WriteKeys[0] entries := make(map[string]interface{}) - if len(cmd[2:])%2 != 0 { + if len(params.Command[2:])%2 != 0 { return nil, errors.New("each field must have a corresponding value") } - for i := 2; i <= len(cmd)-2; i += 2 { - entries[cmd[i]] = internal.AdaptType(cmd[i+1]) + for i := 2; i <= len(params.Command)-2; i += 2 { + entries[params.Command[i]] = internal.AdaptType(params.Command[i+1]) } - if !server.KeyExists(ctx, key) { - _, err = server.CreateKeyAndLock(ctx, key) + if !params.KeyExists(params.Context, key) { + _, err = params.CreateKeyAndLock(params.Context, key) if err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) - if err = server.SetValue(ctx, key, entries); err != nil { + defer params.KeyUnlock(params.Context, key) + if err = params.SetValue(params.Context, key, entries); err != nil { return nil, err } return []byte(fmt.Sprintf(":%d\r\n", len(entries))), nil } - if _, err = server.KeyLock(ctx, key); err != nil { + if _, err = params.KeyLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) - hash, ok := server.GetValue(ctx, key).(map[string]interface{}) + hash, ok := params.GetValue(params.Context, key).(map[string]interface{}) if !ok { return nil, fmt.Errorf("value at %s is not a hash", key) } count := 0 for field, value := range entries { - if strings.EqualFold(cmd[0], "hsetnx") { + if strings.EqualFold(params.Command[0], "hsetnx") { if hash[field] == nil { hash[field] = value count += 1 @@ -79,32 +77,32 @@ func handleHSET(ctx context.Context, cmd []string, server types.EchoVault, _ *ne hash[field] = value count += 1 } - if err = server.SetValue(ctx, key, hash); err != nil { + if err = params.SetValue(params.Context, key, hash); err != nil { return nil, err } return []byte(fmt.Sprintf(":%d\r\n", count)), nil } -func handleHGET(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := hgetKeyFunc(cmd) +func handleHGET(params types.HandlerFuncParams) ([]byte, error) { + keys, err := hgetKeyFunc(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] - fields := cmd[2:] + fields := params.Command[2:] - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte("$-1\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - hash, ok := server.GetValue(ctx, key).(map[string]interface{}) + hash, ok := params.GetValue(params.Context, key).(map[string]interface{}) if !ok { return nil, fmt.Errorf("value at %s is not a hash", key) } @@ -137,25 +135,25 @@ func handleHGET(ctx context.Context, cmd []string, server types.EchoVault, _ *ne return []byte(res), nil } -func handleHSTRLEN(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := hstrlenKeyFunc(cmd) +func handleHSTRLEN(params types.HandlerFuncParams) ([]byte, error) { + keys, err := hstrlenKeyFunc(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] - fields := cmd[2:] + fields := params.Command[2:] - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte("$-1\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - hash, ok := server.GetValue(ctx, key).(map[string]interface{}) + hash, ok := params.GetValue(params.Context, key).(map[string]interface{}) if !ok { return nil, fmt.Errorf("value at %s is not a hash", key) } @@ -188,24 +186,24 @@ func handleHSTRLEN(ctx context.Context, cmd []string, server types.EchoVault, _ return []byte(res), nil } -func handleHVALS(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := hvalsKeyFunc(cmd) +func handleHVALS(params types.HandlerFuncParams) ([]byte, error) { + keys, err := hvalsKeyFunc(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte("*0\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - hash, ok := server.GetValue(ctx, key).(map[string]interface{}) + hash, ok := params.GetValue(params.Context, key).(map[string]interface{}) if !ok { return nil, fmt.Errorf("value at %s is not a hash", key) } @@ -229,8 +227,8 @@ func handleHVALS(ctx context.Context, cmd []string, server types.EchoVault, _ *n return []byte(res), nil } -func handleHRANDFIELD(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := hrandfieldKeyFunc(cmd) +func handleHRANDFIELD(params types.HandlerFuncParams) ([]byte, error) { + keys, err := hrandfieldKeyFunc(params.Command) if err != nil { return nil, err } @@ -238,8 +236,8 @@ func handleHRANDFIELD(ctx context.Context, cmd []string, server types.EchoVault, key := keys.ReadKeys[0] count := 1 - if len(cmd) >= 3 { - c, err := strconv.Atoi(cmd[2]) + if len(params.Command) >= 3 { + c, err := strconv.Atoi(params.Command[2]) if err != nil { return nil, errors.New("count must be an integer") } @@ -250,24 +248,24 @@ func handleHRANDFIELD(ctx context.Context, cmd []string, server types.EchoVault, } withvalues := false - if len(cmd) == 4 { - if strings.EqualFold(cmd[3], "withvalues") { + if len(params.Command) == 4 { + if strings.EqualFold(params.Command[3], "withvalues") { withvalues = true } else { return nil, errors.New("result modifier must be withvalues") } } - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte("*0\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - hash, ok := server.GetValue(ctx, key).(map[string]interface{}) + hash, ok := params.GetValue(params.Context, key).(map[string]interface{}) if !ok { return nil, fmt.Errorf("value at %s is not a hash", key) } @@ -345,24 +343,24 @@ func handleHRANDFIELD(ctx context.Context, cmd []string, server types.EchoVault, return []byte(res), nil } -func handleHLEN(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := hlenKeyFunc(cmd) +func handleHLEN(params types.HandlerFuncParams) ([]byte, error) { + keys, err := hlenKeyFunc(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte(":0\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - hash, ok := server.GetValue(ctx, key).(map[string]interface{}) + hash, ok := params.GetValue(params.Context, key).(map[string]interface{}) if !ok { return nil, fmt.Errorf("value at %s is not a hash", key) } @@ -370,24 +368,24 @@ func handleHLEN(ctx context.Context, cmd []string, server types.EchoVault, _ *ne return []byte(fmt.Sprintf(":%d\r\n", len(hash))), nil } -func handleHKEYS(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := hkeysKeyFunc(cmd) +func handleHKEYS(params types.HandlerFuncParams) ([]byte, error) { + keys, err := hkeysKeyFunc(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte("*0\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - hash, ok := server.GetValue(ctx, key).(map[string]interface{}) + hash, ok := params.GetValue(params.Context, key).(map[string]interface{}) if !ok { return nil, fmt.Errorf("value at %s is not a hash", key) } @@ -400,59 +398,59 @@ func handleHKEYS(ctx context.Context, cmd []string, server types.EchoVault, _ *n return []byte(res), nil } -func handleHINCRBY(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := hincrbyKeyFunc(cmd) +func handleHINCRBY(params types.HandlerFuncParams) ([]byte, error) { + keys, err := hincrbyKeyFunc(params.Command) if err != nil { return nil, err } key := keys.WriteKeys[0] - field := cmd[2] + field := params.Command[2] var intIncrement int var floatIncrement float64 - if strings.EqualFold(cmd[0], "hincrbyfloat") { - f, err := strconv.ParseFloat(cmd[3], 64) + if strings.EqualFold(params.Command[0], "hincrbyfloat") { + f, err := strconv.ParseFloat(params.Command[3], 64) if err != nil { return nil, errors.New("increment must be a float") } floatIncrement = f } else { - i, err := strconv.Atoi(cmd[3]) + i, err := strconv.Atoi(params.Command[3]) if err != nil { return nil, errors.New("increment must be an integer") } intIncrement = i } - if !server.KeyExists(ctx, key) { - if _, err := server.CreateKeyAndLock(ctx, key); err != nil { + if !params.KeyExists(params.Context, key) { + if _, err := params.CreateKeyAndLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) hash := make(map[string]interface{}) - if strings.EqualFold(cmd[0], "hincrbyfloat") { + if strings.EqualFold(params.Command[0], "hincrbyfloat") { hash[field] = floatIncrement - if err = server.SetValue(ctx, key, hash); err != nil { + if err = params.SetValue(params.Context, key, hash); err != nil { return nil, err } return []byte(fmt.Sprintf("+%s\r\n", strconv.FormatFloat(floatIncrement, 'f', -1, 64))), nil } else { hash[field] = intIncrement - if err = server.SetValue(ctx, key, hash); err != nil { + if err = params.SetValue(params.Context, key, hash); err != nil { return nil, err } return []byte(fmt.Sprintf(":%d\r\n", intIncrement)), nil } } - if _, err := server.KeyLock(ctx, key); err != nil { + if _, err := params.KeyLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) - hash, ok := server.GetValue(ctx, key).(map[string]interface{}) + hash, ok := params.GetValue(params.Context, key).(map[string]interface{}) if !ok { return nil, fmt.Errorf("value at %s is not a hash", key) } @@ -466,21 +464,21 @@ func handleHINCRBY(ctx context.Context, cmd []string, server types.EchoVault, _ return nil, fmt.Errorf("value at field %s is not a number", field) case int: i, _ := hash[field].(int) - if strings.EqualFold(cmd[0], "hincrbyfloat") { + if strings.EqualFold(params.Command[0], "hincrbyfloat") { hash[field] = float64(i) + floatIncrement } else { hash[field] = i + intIncrement } case float64: f, _ := hash[field].(float64) - if strings.EqualFold(cmd[0], "hincrbyfloat") { + if strings.EqualFold(params.Command[0], "hincrbyfloat") { hash[field] = f + floatIncrement } else { hash[field] = f + float64(intIncrement) } } - if err = server.SetValue(ctx, key, hash); err != nil { + if err = params.SetValue(params.Context, key, hash); err != nil { return nil, err } @@ -492,24 +490,24 @@ func handleHINCRBY(ctx context.Context, cmd []string, server types.EchoVault, _ return []byte(fmt.Sprintf(":%d\r\n", i)), nil } -func handleHGETALL(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := hgetallKeyFunc(cmd) +func handleHGETALL(params types.HandlerFuncParams) ([]byte, error) { + keys, err := hgetallKeyFunc(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte("*0\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - hash, ok := server.GetValue(ctx, key).(map[string]interface{}) + hash, ok := params.GetValue(params.Context, key).(map[string]interface{}) if !ok { return nil, fmt.Errorf("value at %s is not a hash", key) } @@ -532,25 +530,25 @@ func handleHGETALL(ctx context.Context, cmd []string, server types.EchoVault, _ return []byte(res), nil } -func handleHEXISTS(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := hexistsKeyFunc(cmd) +func handleHEXISTS(params types.HandlerFuncParams) ([]byte, error) { + keys, err := hexistsKeyFunc(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] - field := cmd[2] + field := params.Command[2] - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte(":0\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - hash, ok := server.GetValue(ctx, key).(map[string]interface{}) + hash, ok := params.GetValue(params.Context, key).(map[string]interface{}) if !ok { return nil, fmt.Errorf("value at %s is not a hash", key) } @@ -562,25 +560,25 @@ func handleHEXISTS(ctx context.Context, cmd []string, server types.EchoVault, _ return []byte(":0\r\n"), nil } -func handleHDEL(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := hdelKeyFunc(cmd) +func handleHDEL(params types.HandlerFuncParams) ([]byte, error) { + keys, err := hdelKeyFunc(params.Command) if err != nil { return nil, err } key := keys.WriteKeys[0] - fields := cmd[2:] + fields := params.Command[2:] - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte(":0\r\n"), nil } - if _, err = server.KeyLock(ctx, key); err != nil { + if _, err = params.KeyLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) - hash, ok := server.GetValue(ctx, key).(map[string]interface{}) + hash, ok := params.GetValue(params.Context, key).(map[string]interface{}) if !ok { return nil, fmt.Errorf("value at %s is not a hash", key) } @@ -594,7 +592,7 @@ func handleHDEL(ctx context.Context, cmd []string, server types.EchoVault, _ *ne } } - if err = server.SetValue(ctx, key, hash); err != nil { + if err = params.SetValue(params.Context, key, hash); err != nil { return nil, err } diff --git a/pkg/modules/list/commands.go b/pkg/modules/list/commands.go index 145dc1c9..0d3bf1e8 100644 --- a/pkg/modules/list/commands.go +++ b/pkg/modules/list/commands.go @@ -15,65 +15,63 @@ package list import ( - "context" "errors" "fmt" "github.com/echovault/echovault/internal" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/types" "math" - "net" "slices" "strings" ) -func handleLLen(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := llenKeyFunc(cmd) +func handleLLen(params types.HandlerFuncParams) ([]byte, error) { + keys, err := llenKeyFunc(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { // If key does not exist, return 0 return []byte(":0\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - if list, ok := server.GetValue(ctx, key).([]interface{}); ok { + if list, ok := params.GetValue(params.Context, key).([]interface{}); ok { return []byte(fmt.Sprintf(":%d\r\n", len(list))), nil } return nil, errors.New("LLEN command on non-list item") } -func handleLIndex(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := lindexKeyFunc(cmd) +func handleLIndex(params types.HandlerFuncParams) ([]byte, error) { + keys, err := lindexKeyFunc(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] - index, ok := internal.AdaptType(cmd[2]).(int) + index, ok := internal.AdaptType(params.Command[2]).(int) if !ok { return nil, errors.New("index must be an integer") } - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return nil, errors.New("LINDEX command on non-list item") } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - list, ok := server.GetValue(ctx, key).([]interface{}) - server.KeyRUnlock(ctx, key) + list, ok := params.GetValue(params.Context, key).([]interface{}) + params.KeyRUnlock(params.Context, key) if !ok { return nil, errors.New("LINDEX command on non-list item") @@ -86,30 +84,30 @@ func handleLIndex(ctx context.Context, cmd []string, server types.EchoVault, _ * return []byte(fmt.Sprintf("+%s\r\n", list[index])), nil } -func handleLRange(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := lrangeKeyFunc(cmd) +func handleLRange(params types.HandlerFuncParams) ([]byte, error) { + keys, err := lrangeKeyFunc(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] - start, startOk := internal.AdaptType(cmd[2]).(int) - end, endOk := internal.AdaptType(cmd[3]).(int) + start, startOk := internal.AdaptType(params.Command[2]).(int) + end, endOk := internal.AdaptType(params.Command[3]).(int) if !startOk || !endOk { return nil, errors.New("start and end indices must be integers") } - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return nil, errors.New("LRANGE command on non-list item") } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - list, ok := server.GetValue(ctx, key).([]interface{}) + list, ok := params.GetValue(params.Context, key).([]interface{}) if !ok { return nil, errors.New("LRANGE command on non-list item") } @@ -165,29 +163,29 @@ func handleLRange(ctx context.Context, cmd []string, server types.EchoVault, _ * return bytes, nil } -func handleLSet(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := lsetKeyFunc(cmd) +func handleLSet(params types.HandlerFuncParams) ([]byte, error) { + keys, err := lsetKeyFunc(params.Command) if err != nil { return nil, err } key := keys.WriteKeys[0] - index, ok := internal.AdaptType(cmd[2]).(int) + index, ok := internal.AdaptType(params.Command[2]).(int) if !ok { return nil, errors.New("index must be an integer") } - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return nil, errors.New("LSET command on non-list item") } - if _, err = server.KeyLock(ctx, key); err != nil { + if _, err = params.KeyLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) - list, ok := server.GetValue(ctx, key).([]interface{}) + list, ok := params.GetValue(params.Context, key).([]interface{}) if !ok { return nil, errors.New("LSET command on non-list item") } @@ -196,23 +194,23 @@ func handleLSet(ctx context.Context, cmd []string, server types.EchoVault, _ *ne return nil, errors.New("index must be within list range") } - list[index] = internal.AdaptType(cmd[3]) - if err = server.SetValue(ctx, key, list); err != nil { + list[index] = internal.AdaptType(params.Command[3]) + if err = params.SetValue(params.Context, key, list); err != nil { return nil, err } return []byte(constants.OkResponse), nil } -func handleLTrim(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := ltrimKeyFunc(cmd) +func handleLTrim(params types.HandlerFuncParams) ([]byte, error) { + keys, err := ltrimKeyFunc(params.Command) if err != nil { return nil, err } key := keys.WriteKeys[0] - start, startOk := internal.AdaptType(cmd[2]).(int) - end, endOk := internal.AdaptType(cmd[3]).(int) + start, startOk := internal.AdaptType(params.Command[2]).(int) + end, endOk := internal.AdaptType(params.Command[3]).(int) if !startOk || !endOk { return nil, errors.New("start and end indices must be integers") @@ -222,16 +220,16 @@ func handleLTrim(ctx context.Context, cmd []string, server types.EchoVault, _ *n return nil, errors.New("end index must be greater than start index or -1") } - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return nil, errors.New("LTRIM command on non-list item") } - if _, err = server.KeyLock(ctx, key); err != nil { + if _, err = params.KeyLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) - list, ok := server.GetValue(ctx, key).([]interface{}) + list, ok := params.GetValue(params.Context, key).([]interface{}) if !ok { return nil, errors.New("LTRIM command on non-list item") } @@ -241,44 +239,44 @@ func handleLTrim(ctx context.Context, cmd []string, server types.EchoVault, _ *n } if end == -1 || end > len(list) { - if err = server.SetValue(ctx, key, list[start:]); err != nil { + if err = params.SetValue(params.Context, key, list[start:]); err != nil { return nil, err } return []byte(constants.OkResponse), nil } - if err = server.SetValue(ctx, key, list[start:end]); err != nil { + if err = params.SetValue(params.Context, key, list[start:end]); err != nil { return nil, err } return []byte(constants.OkResponse), nil } -func handleLRem(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := lremKeyFunc(cmd) +func handleLRem(params types.HandlerFuncParams) ([]byte, error) { + keys, err := lremKeyFunc(params.Command) if err != nil { return nil, err } key := keys.WriteKeys[0] - value := cmd[3] + value := params.Command[3] - count, ok := internal.AdaptType(cmd[2]).(int) + count, ok := internal.AdaptType(params.Command[2]).(int) if !ok { return nil, errors.New("count must be an integer") } absoluteCount := internal.AbsInt(count) - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return nil, errors.New("LREM command on non-list item") } - if _, err = server.KeyLock(ctx, key); err != nil { + if _, err = params.KeyLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) - list, ok := server.GetValue(ctx, key).([]interface{}) + list, ok := params.GetValue(params.Context, key).([]interface{}) if !ok { return nil, errors.New("LREM command on non-list item") } @@ -314,44 +312,44 @@ func handleLRem(ctx context.Context, cmd []string, server types.EchoVault, _ *ne return elem == nil }) - if err = server.SetValue(ctx, key, list); err != nil { + if err = params.SetValue(params.Context, key, list); err != nil { return nil, err } return []byte(constants.OkResponse), nil } -func handleLMove(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := lmoveKeyFunc(cmd) +func handleLMove(params types.HandlerFuncParams) ([]byte, error) { + keys, err := lmoveKeyFunc(params.Command) if err != nil { return nil, err } source, destination := keys.WriteKeys[0], keys.WriteKeys[1] - whereFrom := strings.ToLower(cmd[3]) - whereTo := strings.ToLower(cmd[4]) + whereFrom := strings.ToLower(params.Command[3]) + whereTo := strings.ToLower(params.Command[4]) if !slices.Contains([]string{"left", "right"}, whereFrom) || !slices.Contains([]string{"left", "right"}, whereTo) { return nil, errors.New("wherefrom and whereto arguments must be either LEFT or RIGHT") } - if !server.KeyExists(ctx, source) || !server.KeyExists(ctx, destination) { + if !params.KeyExists(params.Context, source) || !params.KeyExists(params.Context, destination) { return nil, errors.New("both source and destination must be lists") } - if _, err = server.KeyLock(ctx, source); err != nil { + if _, err = params.KeyLock(params.Context, source); err != nil { return nil, err } - defer server.KeyUnlock(ctx, source) + defer params.KeyUnlock(params.Context, source) - _, err = server.KeyLock(ctx, destination) + _, err = params.KeyLock(params.Context, destination) if err != nil { return nil, err } - defer server.KeyUnlock(ctx, destination) + defer params.KeyUnlock(params.Context, destination) - sourceList, sourceOk := server.GetValue(ctx, source).([]interface{}) - destinationList, destinationOk := server.GetValue(ctx, destination).([]interface{}) + sourceList, sourceOk := params.GetValue(params.Context, source).([]interface{}) + destinationList, destinationOk := params.GetValue(params.Context, destination).([]interface{}) if !sourceOk || !destinationOk { return nil, errors.New("both source and destination must be lists") @@ -359,18 +357,18 @@ func handleLMove(ctx context.Context, cmd []string, server types.EchoVault, _ *n switch whereFrom { case "left": - err = server.SetValue(ctx, source, append([]interface{}{}, sourceList[1:]...)) + err = params.SetValue(params.Context, source, append([]interface{}{}, sourceList[1:]...)) if whereTo == "left" { - err = server.SetValue(ctx, destination, append(sourceList[0:1], destinationList...)) + err = params.SetValue(params.Context, destination, append(sourceList[0:1], destinationList...)) } else if whereTo == "right" { - err = server.SetValue(ctx, destination, append(destinationList, sourceList[0])) + err = params.SetValue(params.Context, destination, append(destinationList, sourceList[0])) } case "right": - err = server.SetValue(ctx, source, append([]interface{}{}, sourceList[:len(sourceList)-1]...)) + err = params.SetValue(params.Context, source, append([]interface{}{}, sourceList[:len(sourceList)-1]...)) if whereTo == "left" { - err = server.SetValue(ctx, destination, append(sourceList[len(sourceList)-1:], destinationList...)) + err = params.SetValue(params.Context, destination, append(sourceList[len(sourceList)-1:], destinationList...)) } else if whereTo == "right" { - err = server.SetValue(ctx, destination, append(destinationList, sourceList[len(sourceList)-1])) + err = params.SetValue(params.Context, destination, append(destinationList, sourceList[len(sourceList)-1])) } } @@ -381,54 +379,54 @@ func handleLMove(ctx context.Context, cmd []string, server types.EchoVault, _ *n return []byte(constants.OkResponse), nil } -func handleLPush(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := lpushKeyFunc(cmd) +func handleLPush(params types.HandlerFuncParams) ([]byte, error) { + keys, err := lpushKeyFunc(params.Command) if err != nil { return nil, err } var newElems []interface{} - for _, elem := range cmd[2:] { + for _, elem := range params.Command[2:] { newElems = append(newElems, internal.AdaptType(elem)) } key := keys.WriteKeys[0] - if !server.KeyExists(ctx, key) { - switch strings.ToLower(cmd[0]) { + if !params.KeyExists(params.Context, key) { + switch strings.ToLower(params.Command[0]) { case "lpushx": return nil, errors.New("LPUSHX command on non-list item") default: - if _, err = server.CreateKeyAndLock(ctx, key); err != nil { + if _, err = params.CreateKeyAndLock(params.Context, key); err != nil { return nil, err } - if err = server.SetValue(ctx, key, []interface{}{}); err != nil { + if err = params.SetValue(params.Context, key, []interface{}{}); err != nil { return nil, err } } } else { - if _, err = server.KeyLock(ctx, key); err != nil { + if _, err = params.KeyLock(params.Context, key); err != nil { return nil, err } } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) - currentList := server.GetValue(ctx, key) + currentList := params.GetValue(params.Context, key) l, ok := currentList.([]interface{}) if !ok { return nil, errors.New("LPUSH command on non-list item") } - if err = server.SetValue(ctx, key, append(newElems, l...)); err != nil { + if err = params.SetValue(params.Context, key, append(newElems, l...)); err != nil { return nil, err } return []byte(constants.OkResponse), nil } -func handleRPush(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := rpushKeyFunc(cmd) +func handleRPush(params types.HandlerFuncParams) ([]byte, error) { + keys, err := rpushKeyFunc(params.Command) if err != nil { return nil, err } @@ -437,31 +435,31 @@ func handleRPush(ctx context.Context, cmd []string, server types.EchoVault, _ *n var newElems []interface{} - for _, elem := range cmd[2:] { + for _, elem := range params.Command[2:] { newElems = append(newElems, internal.AdaptType(elem)) } - if !server.KeyExists(ctx, key) { - switch strings.ToLower(cmd[0]) { + if !params.KeyExists(params.Context, key) { + switch strings.ToLower(params.Command[0]) { case "rpushx": return nil, errors.New("RPUSHX command on non-list item") default: - if _, err = server.CreateKeyAndLock(ctx, key); err != nil { + if _, err = params.CreateKeyAndLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) - if err = server.SetValue(ctx, key, []interface{}{}); err != nil { + defer params.KeyUnlock(params.Context, key) + if err = params.SetValue(params.Context, key, []interface{}{}); err != nil { return nil, err } } } else { - if _, err = server.KeyLock(ctx, key); err != nil { + if _, err = params.KeyLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) } - currentList := server.GetValue(ctx, key) + currentList := params.GetValue(params.Context, key) l, ok := currentList.([]interface{}) @@ -469,42 +467,42 @@ func handleRPush(ctx context.Context, cmd []string, server types.EchoVault, _ *n return nil, errors.New("RPUSH command on non-list item") } - if err = server.SetValue(ctx, key, append(l, newElems...)); err != nil { + if err = params.SetValue(params.Context, key, append(l, newElems...)); err != nil { return nil, err } return []byte(constants.OkResponse), nil } -func handlePop(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := popKeyFunc(cmd) +func handlePop(params types.HandlerFuncParams) ([]byte, error) { + keys, err := popKeyFunc(params.Command) if err != nil { return nil, err } key := keys.WriteKeys[0] - if !server.KeyExists(ctx, key) { - return nil, fmt.Errorf("%s command on non-list item", strings.ToUpper(cmd[0])) + if !params.KeyExists(params.Context, key) { + return nil, fmt.Errorf("%s command on non-list item", strings.ToUpper(params.Command[0])) } - if _, err = server.KeyLock(ctx, key); err != nil { + if _, err = params.KeyLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) - list, ok := server.GetValue(ctx, key).([]interface{}) + list, ok := params.GetValue(params.Context, key).([]interface{}) if !ok { - return nil, fmt.Errorf("%s command on non-list item", strings.ToUpper(cmd[0])) + return nil, fmt.Errorf("%s command on non-list item", strings.ToUpper(params.Command[0])) } - switch strings.ToLower(cmd[0]) { + switch strings.ToLower(params.Command[0]) { default: - if err = server.SetValue(ctx, key, list[1:]); err != nil { + if err = params.SetValue(params.Context, key, list[1:]); err != nil { return nil, err } return []byte(fmt.Sprintf("+%v\r\n", list[0])), nil case "rpop": - if err = server.SetValue(ctx, key, list[:len(list)-1]); err != nil { + if err = params.SetValue(params.Context, key, list[:len(list)-1]); err != nil { return nil, err } return []byte(fmt.Sprintf("+%v\r\n", list[len(list)-1])), nil diff --git a/pkg/modules/pubsub/commands.go b/pkg/modules/pubsub/commands.go index 6fe9fab9..e8c0f79e 100644 --- a/pkg/modules/pubsub/commands.go +++ b/pkg/modules/pubsub/commands.go @@ -15,79 +15,77 @@ package pubsub import ( - "context" "errors" "fmt" internal_pubsub "github.com/echovault/echovault/internal/pubsub" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/types" - "net" "strings" ) -func handleSubscribe(ctx context.Context, cmd []string, server types.EchoVault, conn *net.Conn) ([]byte, error) { - pubsub, ok := server.GetPubSub().(*internal_pubsub.PubSub) +func handleSubscribe(params types.HandlerFuncParams) ([]byte, error) { + pubsub, ok := params.GetPubSub().(*internal_pubsub.PubSub) if !ok { return nil, errors.New("could not load pubsub module") } - channels := cmd[1:] + channels := params.Command[1:] if len(channels) == 0 { return nil, errors.New(constants.WrongArgsResponse) } - withPattern := strings.EqualFold(cmd[0], "psubscribe") - pubsub.Subscribe(ctx, conn, channels, withPattern) + withPattern := strings.EqualFold(params.Command[0], "psubscribe") + pubsub.Subscribe(params.Context, params.Connection, channels, withPattern) return nil, nil } -func handleUnsubscribe(ctx context.Context, cmd []string, server types.EchoVault, conn *net.Conn) ([]byte, error) { - pubsub, ok := server.GetPubSub().(*internal_pubsub.PubSub) +func handleUnsubscribe(params types.HandlerFuncParams) ([]byte, error) { + pubsub, ok := params.GetPubSub().(*internal_pubsub.PubSub) if !ok { return nil, errors.New("could not load pubsub module") } - channels := cmd[1:] + channels := params.Command[1:] - withPattern := strings.EqualFold(cmd[0], "punsubscribe") + withPattern := strings.EqualFold(params.Command[0], "punsubscribe") - return pubsub.Unsubscribe(ctx, conn, channels, withPattern), nil + return pubsub.Unsubscribe(params.Context, params.Connection, channels, withPattern), nil } -func handlePublish(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - pubsub, ok := server.GetPubSub().(*internal_pubsub.PubSub) +func handlePublish(params types.HandlerFuncParams) ([]byte, error) { + pubsub, ok := params.GetPubSub().(*internal_pubsub.PubSub) if !ok { return nil, errors.New("could not load pubsub module") } - if len(cmd) != 3 { + if len(params.Command) != 3 { return nil, errors.New(constants.WrongArgsResponse) } - pubsub.Publish(ctx, cmd[2], cmd[1]) + pubsub.Publish(params.Context, params.Command[2], params.Command[1]) return []byte(constants.OkResponse), nil } -func handlePubSubChannels(_ context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - if len(cmd) > 3 { +func handlePubSubChannels(params types.HandlerFuncParams) ([]byte, error) { + if len(params.Command) > 3 { return nil, errors.New(constants.WrongArgsResponse) } - pubsub, ok := server.GetPubSub().(*internal_pubsub.PubSub) + pubsub, ok := params.GetPubSub().(*internal_pubsub.PubSub) if !ok { return nil, errors.New("could not load pubsub module") } pattern := "" - if len(cmd) == 3 { - pattern = cmd[2] + if len(params.Command) == 3 { + pattern = params.Command[2] } return pubsub.Channels(pattern), nil } -func handlePubSubNumPat(_ context.Context, _ []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - pubsub, ok := server.GetPubSub().(*internal_pubsub.PubSub) +func handlePubSubNumPat(params types.HandlerFuncParams) ([]byte, error) { + pubsub, ok := params.GetPubSub().(*internal_pubsub.PubSub) if !ok { return nil, errors.New("could not load pubsub module") } @@ -95,12 +93,12 @@ func handlePubSubNumPat(_ context.Context, _ []string, server types.EchoVault, _ return []byte(fmt.Sprintf(":%d\r\n", num)), nil } -func handlePubSubNumSubs(_ context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - pubsub, ok := server.GetPubSub().(*internal_pubsub.PubSub) +func handlePubSubNumSubs(params types.HandlerFuncParams) ([]byte, error) { + pubsub, ok := params.GetPubSub().(*internal_pubsub.PubSub) if !ok { return nil, errors.New("could not load pubsub module") } - return pubsub.NumSub(cmd[2:]), nil + return pubsub.NumSub(params.Command[2:]), nil } func Commands() []types.Command { @@ -210,7 +208,7 @@ it's currently subscribe to.`, WriteKeys: make([]string, 0), }, nil }, - HandlerFunc: func(_ context.Context, _ []string, _ types.EchoVault, _ *net.Conn) ([]byte, error) { + HandlerFunc: func(_ types.HandlerFuncParams) ([]byte, error) { return nil, errors.New("provide CHANNELS, NUMPAT, or NUMSUB subcommand") }, SubCommands: []types.SubCommand{ diff --git a/pkg/modules/set/commands.go b/pkg/modules/set/commands.go index f258283e..f7f4c729 100644 --- a/pkg/modules/set/commands.go +++ b/pkg/modules/set/commands.go @@ -15,20 +15,18 @@ package set import ( - "context" "errors" "fmt" "github.com/echovault/echovault/internal" internal_set "github.com/echovault/echovault/internal/set" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/types" - "net" "slices" "strings" ) -func handleSADD(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := saddKeyFunc(cmd) +func handleSADD(params types.HandlerFuncParams) ([]byte, error) { + keys, err := saddKeyFunc(params.Command) if err != nil { return nil, err } @@ -37,51 +35,51 @@ func handleSADD(ctx context.Context, cmd []string, server types.EchoVault, _ *ne var set *internal_set.Set - if !server.KeyExists(ctx, key) { - set = internal_set.NewSet(cmd[2:]) - if ok, err := server.CreateKeyAndLock(ctx, key); !ok && err != nil { + if !params.KeyExists(params.Context, key) { + set = internal_set.NewSet(params.Command[2:]) + if ok, err := params.CreateKeyAndLock(params.Context, key); !ok && err != nil { return nil, err } - if err = server.SetValue(ctx, key, set); err != nil { + if err = params.SetValue(params.Context, key, set); err != nil { return nil, err } - server.KeyUnlock(ctx, key) - return []byte(fmt.Sprintf(":%d\r\n", len(cmd[2:]))), nil + params.KeyUnlock(params.Context, key) + return []byte(fmt.Sprintf(":%d\r\n", len(params.Command[2:]))), nil } - if _, err = server.KeyLock(ctx, key); err != nil { + if _, err = params.KeyLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) - set, ok := server.GetValue(ctx, key).(*internal_set.Set) + set, ok := params.GetValue(params.Context, key).(*internal_set.Set) if !ok { return nil, fmt.Errorf("value at key %s is not a set", key) } - count := set.Add(cmd[2:]) + count := set.Add(params.Command[2:]) return []byte(fmt.Sprintf(":%d\r\n", count)), nil } -func handleSCARD(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := scardKeyFunc(cmd) +func handleSCARD(params types.HandlerFuncParams) ([]byte, error) { + keys, err := scardKeyFunc(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte(fmt.Sprintf(":0\r\n")), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - set, ok := server.GetValue(ctx, key).(*internal_set.Set) + set, ok := params.GetValue(params.Context, key).(*internal_set.Set) if !ok { return nil, fmt.Errorf("value at key %s is not a set", key) } @@ -91,21 +89,21 @@ func handleSCARD(ctx context.Context, cmd []string, server types.EchoVault, _ *n return []byte(fmt.Sprintf(":%d\r\n", cardinality)), nil } -func handleSDIFF(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := sdiffKeyFunc(cmd) +func handleSDIFF(params types.HandlerFuncParams) ([]byte, error) { + keys, err := sdiffKeyFunc(params.Command) if err != nil { return nil, err } // Extract base set first - if !server.KeyExists(ctx, keys.ReadKeys[0]) { + if !params.KeyExists(params.Context, keys.ReadKeys[0]) { return nil, fmt.Errorf("key for base set \"%s\" does not exist", keys.ReadKeys[0]) } - if _, err = server.KeyRLock(ctx, keys.ReadKeys[0]); err != nil { + if _, err = params.KeyRLock(params.Context, keys.ReadKeys[0]); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, keys.ReadKeys[0]) - baseSet, ok := server.GetValue(ctx, keys.ReadKeys[0]).(*internal_set.Set) + defer params.KeyRUnlock(params.Context, keys.ReadKeys[0]) + baseSet, ok := params.GetValue(params.Context, keys.ReadKeys[0]).(*internal_set.Set) if !ok { return nil, fmt.Errorf("value at key %s is not a set", keys.ReadKeys[0]) } @@ -114,24 +112,24 @@ func handleSDIFF(ctx context.Context, cmd []string, server types.EchoVault, _ *n defer func() { for key, locked := range locks { if locked { - server.KeyRUnlock(ctx, key) + params.KeyRUnlock(params.Context, key) } } }() for _, key := range keys.ReadKeys[1:] { - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { continue } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { continue } locks[key] = true } var sets []*internal_set.Set - for _, key := range cmd[2:] { - set, ok := server.GetValue(ctx, key).(*internal_set.Set) + for _, key := range params.Command[2:] { + set, ok := params.GetValue(params.Context, key).(*internal_set.Set) if !ok { continue } @@ -152,8 +150,8 @@ func handleSDIFF(ctx context.Context, cmd []string, server types.EchoVault, _ *n return []byte(res), nil } -func handleSDIFFSTORE(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := sdiffstoreKeyFunc(cmd) +func handleSDIFFSTORE(params types.HandlerFuncParams) ([]byte, error) { + keys, err := sdiffstoreKeyFunc(params.Command) if err != nil { return nil, err } @@ -161,14 +159,14 @@ func handleSDIFFSTORE(ctx context.Context, cmd []string, server types.EchoVault, destination := keys.WriteKeys[0] // Extract base set first - if !server.KeyExists(ctx, keys.ReadKeys[0]) { + if !params.KeyExists(params.Context, keys.ReadKeys[0]) { return nil, fmt.Errorf("key for base set \"%s\" does not exist", keys.ReadKeys[0]) } - if _, err := server.KeyRLock(ctx, keys.ReadKeys[0]); err != nil { + if _, err := params.KeyRLock(params.Context, keys.ReadKeys[0]); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, keys.ReadKeys[0]) - baseSet, ok := server.GetValue(ctx, keys.ReadKeys[0]).(*internal_set.Set) + defer params.KeyRUnlock(params.Context, keys.ReadKeys[0]) + baseSet, ok := params.GetValue(params.Context, keys.ReadKeys[0]).(*internal_set.Set) if !ok { return nil, fmt.Errorf("value at key %s is not a set", keys.ReadKeys[0]) } @@ -177,16 +175,16 @@ func handleSDIFFSTORE(ctx context.Context, cmd []string, server types.EchoVault, defer func() { for key, locked := range locks { if locked { - server.KeyRUnlock(ctx, key) + params.KeyRUnlock(params.Context, key) } } }() for _, key := range keys.ReadKeys[1:] { - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { continue } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { continue } locks[key] = true @@ -194,7 +192,7 @@ func handleSDIFFSTORE(ctx context.Context, cmd []string, server types.EchoVault, var sets []*internal_set.Set for _, key := range keys.ReadKeys[1:] { - set, ok := server.GetValue(ctx, key).(*internal_set.Set) + set, ok := params.GetValue(params.Context, key).(*internal_set.Set) if !ok { continue } @@ -206,30 +204,30 @@ func handleSDIFFSTORE(ctx context.Context, cmd []string, server types.EchoVault, res := fmt.Sprintf(":%d\r\n", len(elems)) - if server.KeyExists(ctx, destination) { - if _, err = server.KeyLock(ctx, destination); err != nil { + if params.KeyExists(params.Context, destination) { + if _, err = params.KeyLock(params.Context, destination); err != nil { return nil, err } - if err = server.SetValue(ctx, destination, diff); err != nil { + if err = params.SetValue(params.Context, destination, diff); err != nil { return nil, err } - server.KeyUnlock(ctx, destination) + params.KeyUnlock(params.Context, destination) return []byte(res), nil } - if _, err = server.CreateKeyAndLock(ctx, destination); err != nil { + if _, err = params.CreateKeyAndLock(params.Context, destination); err != nil { return nil, err } - if err = server.SetValue(ctx, destination, diff); err != nil { + if err = params.SetValue(params.Context, destination, diff); err != nil { return nil, err } - server.KeyUnlock(ctx, destination) + params.KeyUnlock(params.Context, destination) return []byte(res), nil } -func handleSINTER(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := sinterKeyFunc(cmd) +func handleSINTER(params types.HandlerFuncParams) ([]byte, error) { + keys, err := sinterKeyFunc(params.Command) if err != nil { return nil, err } @@ -238,17 +236,17 @@ func handleSINTER(ctx context.Context, cmd []string, server types.EchoVault, _ * defer func() { for key, locked := range locks { if locked { - server.KeyRUnlock(ctx, key) + params.KeyRUnlock(params.Context, key) } } }() for _, key := range keys.ReadKeys { - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { // If key does not exist, then there is no intersection return []byte("*0\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } locks[key] = true @@ -257,7 +255,7 @@ func handleSINTER(ctx context.Context, cmd []string, server types.EchoVault, _ * var sets []*internal_set.Set for key, _ := range locks { - set, ok := server.GetValue(ctx, key).(*internal_set.Set) + set, ok := params.GetValue(params.Context, key).(*internal_set.Set) if !ok { // If the value at the key is not a set, return error return nil, fmt.Errorf("value at key %s is not a set", key) @@ -283,15 +281,15 @@ func handleSINTER(ctx context.Context, cmd []string, server types.EchoVault, _ * return []byte(res), nil } -func handleSINTERCARD(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := sintercardKeyFunc(cmd) +func handleSINTERCARD(params types.HandlerFuncParams) ([]byte, error) { + keys, err := sintercardKeyFunc(params.Command) if err != nil { return nil, err } // Extract the limit from the command var limit int - limitIdx := slices.IndexFunc(cmd, func(s string) bool { + limitIdx := slices.IndexFunc(params.Command, func(s string) bool { return strings.EqualFold(s, "limit") }) if limitIdx >= 0 && limitIdx < 2 { @@ -299,11 +297,11 @@ func handleSINTERCARD(ctx context.Context, cmd []string, server types.EchoVault, } if limitIdx != -1 { limitIdx += 1 - if limitIdx >= len(cmd) { + if limitIdx >= len(params.Command) { return nil, errors.New("provide limit after LIMIT keyword") } - if l, ok := internal.AdaptType(cmd[limitIdx]).(int); !ok { + if l, ok := internal.AdaptType(params.Command[limitIdx]).(int); !ok { return nil, errors.New("limit must be an integer") } else { limit = l @@ -314,17 +312,17 @@ func handleSINTERCARD(ctx context.Context, cmd []string, server types.EchoVault, defer func() { for key, locked := range locks { if locked { - server.KeyRUnlock(ctx, key) + params.KeyRUnlock(params.Context, key) } } }() for _, key := range keys.ReadKeys { - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { // If key does not exist, then there is no intersection return []byte(":0\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } locks[key] = true @@ -333,7 +331,7 @@ func handleSINTERCARD(ctx context.Context, cmd []string, server types.EchoVault, var sets []*internal_set.Set for key, _ := range locks { - set, ok := server.GetValue(ctx, key).(*internal_set.Set) + set, ok := params.GetValue(params.Context, key).(*internal_set.Set) if !ok { // If the value at the key is not a set, return error return nil, fmt.Errorf("value at key %s is not a set", key) @@ -350,8 +348,8 @@ func handleSINTERCARD(ctx context.Context, cmd []string, server types.EchoVault, return []byte(fmt.Sprintf(":%d\r\n", intersect.Cardinality())), nil } -func handleSINTERSTORE(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := sinterstoreKeyFunc(cmd) +func handleSINTERSTORE(params types.HandlerFuncParams) ([]byte, error) { + keys, err := sinterstoreKeyFunc(params.Command) if err != nil { return nil, err } @@ -360,17 +358,17 @@ func handleSINTERSTORE(ctx context.Context, cmd []string, server types.EchoVault defer func() { for key, locked := range locks { if locked { - server.KeyRUnlock(ctx, key) + params.KeyRUnlock(params.Context, key) } } }() for _, key := range keys.ReadKeys { - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { // If key does not exist, then there is no intersection return []byte(":0\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } locks[key] = true @@ -379,7 +377,7 @@ func handleSINTERSTORE(ctx context.Context, cmd []string, server types.EchoVault var sets []*internal_set.Set for key, _ := range locks { - set, ok := server.GetValue(ctx, key).(*internal_set.Set) + set, ok := params.GetValue(params.Context, key).(*internal_set.Set) if !ok { // If the value at the key is not a set, return error return nil, fmt.Errorf("value at key %s is not a set", key) @@ -390,71 +388,71 @@ func handleSINTERSTORE(ctx context.Context, cmd []string, server types.EchoVault intersect, _ := internal_set.Intersection(0, sets...) destination := keys.WriteKeys[0] - if server.KeyExists(ctx, destination) { - if _, err = server.KeyLock(ctx, destination); err != nil { + if params.KeyExists(params.Context, destination) { + if _, err = params.KeyLock(params.Context, destination); err != nil { return nil, err } } else { - if _, err = server.CreateKeyAndLock(ctx, destination); err != nil { + if _, err = params.CreateKeyAndLock(params.Context, destination); err != nil { return nil, err } } - if err = server.SetValue(ctx, destination, intersect); err != nil { + if err = params.SetValue(params.Context, destination, intersect); err != nil { return nil, err } - server.KeyUnlock(ctx, destination) + params.KeyUnlock(params.Context, destination) return []byte(fmt.Sprintf(":%d\r\n", intersect.Cardinality())), nil } -func handleSISMEMBER(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := sismemberKeyFunc(cmd) +func handleSISMEMBER(params types.HandlerFuncParams) ([]byte, error) { + keys, err := sismemberKeyFunc(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte(":0\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - set, ok := server.GetValue(ctx, key).(*internal_set.Set) + set, ok := params.GetValue(params.Context, key).(*internal_set.Set) if !ok { return nil, fmt.Errorf("value at key %s is not a set", key) } - if !set.Contains(cmd[2]) { + if !set.Contains(params.Command[2]) { return []byte(":0\r\n"), nil } return []byte(":1\r\n"), nil } -func handleSMEMBERS(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := smembersKeyFunc(cmd) +func handleSMEMBERS(params types.HandlerFuncParams) ([]byte, error) { + keys, err := smembersKeyFunc(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte("*0\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - set, ok := server.GetValue(ctx, key).(*internal_set.Set) + set, ok := params.GetValue(params.Context, key).(*internal_set.Set) if !ok { return nil, fmt.Errorf("value at key %s is not a set", key) } @@ -472,16 +470,16 @@ func handleSMEMBERS(ctx context.Context, cmd []string, server types.EchoVault, _ return []byte(res), nil } -func handleSMISMEMBER(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := smismemberKeyFunc(cmd) +func handleSMISMEMBER(params types.HandlerFuncParams) ([]byte, error) { + keys, err := smismemberKeyFunc(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] - members := cmd[2:] + members := params.Command[2:] - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { res := fmt.Sprintf("*%d", len(members)) for i, _ := range members { res = fmt.Sprintf("%s\r\n:0", res) @@ -492,12 +490,12 @@ func handleSMISMEMBER(ctx context.Context, cmd []string, server types.EchoVault, return []byte(res), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - set, ok := server.GetValue(ctx, key).(*internal_set.Set) + set, ok := params.GetValue(params.Context, key).(*internal_set.Set) if !ok { return nil, fmt.Errorf("value at key %s is not a set", key) } @@ -515,48 +513,48 @@ func handleSMISMEMBER(ctx context.Context, cmd []string, server types.EchoVault, return []byte(res), nil } -func handleSMOVE(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := smoveKeyFunc(cmd) +func handleSMOVE(params types.HandlerFuncParams) ([]byte, error) { + keys, err := smoveKeyFunc(params.Command) if err != nil { return nil, err } source, destination := keys.WriteKeys[0], keys.WriteKeys[1] - member := cmd[3] + member := params.Command[3] - if !server.KeyExists(ctx, source) { + if !params.KeyExists(params.Context, source) { return []byte(":0\r\n"), nil } - if _, err = server.KeyLock(ctx, source); err != nil { + if _, err = params.KeyLock(params.Context, source); err != nil { return nil, err } - defer server.KeyUnlock(ctx, source) + defer params.KeyUnlock(params.Context, source) - sourceSet, ok := server.GetValue(ctx, source).(*internal_set.Set) + sourceSet, ok := params.GetValue(params.Context, source).(*internal_set.Set) if !ok { return nil, errors.New("source is not a set") } var destinationSet *internal_set.Set - if !server.KeyExists(ctx, destination) { + if !params.KeyExists(params.Context, destination) { // Destination key does not exist - if _, err = server.CreateKeyAndLock(ctx, destination); err != nil { + if _, err = params.CreateKeyAndLock(params.Context, destination); err != nil { return nil, err } - defer server.KeyUnlock(ctx, destination) + defer params.KeyUnlock(params.Context, destination) destinationSet = internal_set.NewSet([]string{}) - if err = server.SetValue(ctx, destination, destinationSet); err != nil { + if err = params.SetValue(params.Context, destination, destinationSet); err != nil { return nil, err } } else { // Destination key exists - if _, err := server.KeyLock(ctx, destination); err != nil { + if _, err := params.KeyLock(params.Context, destination); err != nil { return nil, err } - defer server.KeyUnlock(ctx, destination) - ds, ok := server.GetValue(ctx, destination).(*internal_set.Set) + defer params.KeyUnlock(params.Context, destination) + ds, ok := params.GetValue(params.Context, destination).(*internal_set.Set) if !ok { return nil, errors.New("destination is not a set") } @@ -568,8 +566,8 @@ func handleSMOVE(ctx context.Context, cmd []string, server types.EchoVault, _ *n return []byte(fmt.Sprintf(":%d\r\n", res)), nil } -func handleSPOP(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := spopKeyFunc(cmd) +func handleSPOP(params types.HandlerFuncParams) ([]byte, error) { + keys, err := spopKeyFunc(params.Command) if err != nil { return nil, err } @@ -577,24 +575,24 @@ func handleSPOP(ctx context.Context, cmd []string, server types.EchoVault, _ *ne key := keys.WriteKeys[0] count := 1 - if len(cmd) == 3 { - c, ok := internal.AdaptType(cmd[2]).(int) + if len(params.Command) == 3 { + c, ok := internal.AdaptType(params.Command[2]).(int) if !ok { return nil, errors.New("count must be an integer") } count = c } - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte("*-1\r\n"), nil } - if _, err = server.KeyLock(ctx, key); err != nil { + if _, err = params.KeyLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) - set, ok := server.GetValue(ctx, key).(*internal_set.Set) + set, ok := params.GetValue(params.Context, key).(*internal_set.Set) if !ok { return nil, fmt.Errorf("value at %s is not a set", key) } @@ -612,8 +610,8 @@ func handleSPOP(ctx context.Context, cmd []string, server types.EchoVault, _ *ne return []byte(res), nil } -func handleSRANDMEMBER(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := srandmemberKeyFunc(cmd) +func handleSRANDMEMBER(params types.HandlerFuncParams) ([]byte, error) { + keys, err := srandmemberKeyFunc(params.Command) if err != nil { return nil, err } @@ -621,24 +619,24 @@ func handleSRANDMEMBER(ctx context.Context, cmd []string, server types.EchoVault key := keys.ReadKeys[0] count := 1 - if len(cmd) == 3 { - c, ok := internal.AdaptType(cmd[2]).(int) + if len(params.Command) == 3 { + c, ok := internal.AdaptType(params.Command[2]).(int) if !ok { return nil, errors.New("count must be an integer") } count = c } - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte("*-1\r\n"), nil } - if _, err = server.KeyLock(ctx, key); err != nil { + if _, err = params.KeyLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) - set, ok := server.GetValue(ctx, key).(*internal_set.Set) + set, ok := params.GetValue(params.Context, key).(*internal_set.Set) if !ok { return nil, fmt.Errorf("value at %s is not a set", key) } @@ -656,25 +654,25 @@ func handleSRANDMEMBER(ctx context.Context, cmd []string, server types.EchoVault return []byte(res), nil } -func handleSREM(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := sremKeyFunc(cmd) +func handleSREM(params types.HandlerFuncParams) ([]byte, error) { + keys, err := sremKeyFunc(params.Command) if err != nil { return nil, err } key := keys.WriteKeys[0] - members := cmd[2:] + members := params.Command[2:] - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte(":0\r\n"), nil } - if _, err = server.KeyLock(ctx, key); err != nil { + if _, err = params.KeyLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) - set, ok := server.GetValue(ctx, key).(*internal_set.Set) + set, ok := params.GetValue(params.Context, key).(*internal_set.Set) if !ok { return nil, fmt.Errorf("value at key %s is not a set", key) } @@ -684,8 +682,8 @@ func handleSREM(ctx context.Context, cmd []string, server types.EchoVault, _ *ne return []byte(fmt.Sprintf(":%d\r\n", count)), nil } -func handleSUNION(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := sunionKeyFunc(cmd) +func handleSUNION(params types.HandlerFuncParams) ([]byte, error) { + keys, err := sunionKeyFunc(params.Command) if err != nil { return nil, err } @@ -694,16 +692,16 @@ func handleSUNION(ctx context.Context, cmd []string, server types.EchoVault, _ * defer func() { for key, locked := range locks { if locked { - server.KeyRUnlock(ctx, key) + params.KeyRUnlock(params.Context, key) } } }() for _, key := range keys.ReadKeys { - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { continue } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } locks[key] = true @@ -715,7 +713,7 @@ func handleSUNION(ctx context.Context, cmd []string, server types.EchoVault, _ * if !locked { continue } - set, ok := server.GetValue(ctx, key).(*internal_set.Set) + set, ok := params.GetValue(params.Context, key).(*internal_set.Set) if !ok { return nil, fmt.Errorf("value at key %s is not a set", key) } @@ -735,8 +733,8 @@ func handleSUNION(ctx context.Context, cmd []string, server types.EchoVault, _ * return []byte(res), nil } -func handleSUNIONSTORE(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := sunionstoreKeyFunc(cmd) +func handleSUNIONSTORE(params types.HandlerFuncParams) ([]byte, error) { + keys, err := sunionstoreKeyFunc(params.Command) if err != nil { return nil, err } @@ -745,16 +743,16 @@ func handleSUNIONSTORE(ctx context.Context, cmd []string, server types.EchoVault defer func() { for key, locked := range locks { if locked { - server.KeyRUnlock(ctx, key) + params.KeyRUnlock(params.Context, key) } } }() for _, key := range keys.ReadKeys { - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { continue } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } locks[key] = true @@ -766,7 +764,7 @@ func handleSUNIONSTORE(ctx context.Context, cmd []string, server types.EchoVault if !locked { continue } - set, ok := server.GetValue(ctx, key).(*internal_set.Set) + set, ok := params.GetValue(params.Context, key).(*internal_set.Set) if !ok { return nil, fmt.Errorf("value at key %s is not a set", key) } @@ -777,18 +775,18 @@ func handleSUNIONSTORE(ctx context.Context, cmd []string, server types.EchoVault destination := keys.WriteKeys[0] - if server.KeyExists(ctx, destination) { - if _, err = server.KeyLock(ctx, destination); err != nil { + if params.KeyExists(params.Context, destination) { + if _, err = params.KeyLock(params.Context, destination); err != nil { return nil, err } } else { - if _, err = server.CreateKeyAndLock(ctx, destination); err != nil { + if _, err = params.CreateKeyAndLock(params.Context, destination); err != nil { return nil, err } } - defer server.KeyUnlock(ctx, destination) + defer params.KeyUnlock(params.Context, destination) - if err = server.SetValue(ctx, destination, union); err != nil { + if err = params.SetValue(params.Context, destination, union); err != nil { return nil, err } return []byte(fmt.Sprintf(":%d\r\n", union.Cardinality())), nil diff --git a/pkg/modules/sorted_set/commands.go b/pkg/modules/sorted_set/commands.go index 325844c4..d892fe43 100644 --- a/pkg/modules/sorted_set/commands.go +++ b/pkg/modules/sorted_set/commands.go @@ -16,7 +16,6 @@ package sorted_set import ( "cmp" - "context" "errors" "fmt" "github.com/echovault/echovault/internal" @@ -24,14 +23,13 @@ import ( "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/types" "math" - "net" "slices" "strconv" "strings" ) -func handleZADD(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := zaddKeyFunc(cmd) +func handleZADD(params types.HandlerFuncParams) ([]byte, error) { + keys, err := zaddKeyFunc(params.Command) if err != nil { return nil, err } @@ -45,13 +43,13 @@ func handleZADD(ctx context.Context, cmd []string, server types.EchoVault, _ *ne // Find the first valid score and this will be the start of the score/member pairs var membersStartIndex int - for i := 0; i < len(cmd); i++ { + for i := 0; i < len(params.Command); i++ { if membersStartIndex != 0 { break } - switch internal.AdaptType(cmd[i]).(type) { + switch internal.AdaptType(params.Command[i]).(type) { case string: - if slices.Contains([]string{"-inf", "+inf"}, strings.ToLower(cmd[i])) { + if slices.Contains([]string{"-inf", "+inf"}, strings.ToLower(params.Command[i])) { membersStartIndex = i } case float64: @@ -61,17 +59,17 @@ func handleZADD(ctx context.Context, cmd []string, server types.EchoVault, _ *ne } } - if membersStartIndex < 2 || len(cmd[membersStartIndex:])%2 != 0 { + if membersStartIndex < 2 || len(params.Command[membersStartIndex:])%2 != 0 { return nil, errors.New("score/member pairs must be float/string") } var members []sorted_set.MemberParam - for i := 0; i < len(cmd[membersStartIndex:]); i++ { + for i := 0; i < len(params.Command[membersStartIndex:]); i++ { if i%2 != 0 { continue } - score := internal.AdaptType(cmd[membersStartIndex:][i]) + score := internal.AdaptType(params.Command[membersStartIndex:][i]) switch score.(type) { default: return nil, errors.New("invalid score in score/member list") @@ -80,27 +78,27 @@ func handleZADD(ctx context.Context, cmd []string, server types.EchoVault, _ *ne if strings.ToLower(score.(string)) == "-inf" { s = math.Inf(-1) members = append(members, sorted_set.MemberParam{ - Value: sorted_set.Value(cmd[membersStartIndex:][i+1]), + Value: sorted_set.Value(params.Command[membersStartIndex:][i+1]), Score: sorted_set.Score(s), }) } if strings.ToLower(score.(string)) == "+inf" { s = math.Inf(1) members = append(members, sorted_set.MemberParam{ - Value: sorted_set.Value(cmd[membersStartIndex:][i+1]), + Value: sorted_set.Value(params.Command[membersStartIndex:][i+1]), Score: sorted_set.Score(s), }) } case float64: s, _ := score.(float64) members = append(members, sorted_set.MemberParam{ - Value: sorted_set.Value(cmd[membersStartIndex:][i+1]), + Value: sorted_set.Value(params.Command[membersStartIndex:][i+1]), Score: sorted_set.Score(s), }) case int: s, _ := score.(int) members = append(members, sorted_set.MemberParam{ - Value: sorted_set.Value(cmd[membersStartIndex:][i+1]), + Value: sorted_set.Value(params.Command[membersStartIndex:][i+1]), Score: sorted_set.Score(s), }) } @@ -108,7 +106,7 @@ func handleZADD(ctx context.Context, cmd []string, server types.EchoVault, _ *ne // Parse options using membersStartIndex as the upper limit if membersStartIndex > 2 { - options := cmd[2:membersStartIndex] + options := params.Command[2:membersStartIndex] for _, option := range options { if slices.Contains([]string{"xx", "nx"}, strings.ToLower(option)) { updatePolicy = option @@ -143,14 +141,14 @@ func handleZADD(ctx context.Context, cmd []string, server types.EchoVault, _ *ne } } - if server.KeyExists(ctx, key) { + if params.KeyExists(params.Context, key) { // Key exists - _, err = server.KeyLock(ctx, key) + _, err = params.KeyLock(params.Context, key) if err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) - set, ok := server.GetValue(ctx, key).(*sorted_set.SortedSet) + defer params.KeyUnlock(params.Context, key) + set, ok := params.GetValue(params.Context, key).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", key) } @@ -168,36 +166,36 @@ func handleZADD(ctx context.Context, cmd []string, server types.EchoVault, _ *ne } // Key does not exist - if _, err = server.CreateKeyAndLock(ctx, key); err != nil { + if _, err = params.CreateKeyAndLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) set := sorted_set.NewSortedSet(members) - if err = server.SetValue(ctx, key, set); err != nil { + if err = params.SetValue(params.Context, key, set); err != nil { return nil, err } return []byte(fmt.Sprintf(":%d\r\n", set.Cardinality())), nil } -func handleZCARD(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := zcardKeyFunc(cmd) +func handleZCARD(params types.HandlerFuncParams) ([]byte, error) { + keys, err := zcardKeyFunc(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte(":0\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - set, ok := server.GetValue(ctx, key).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, key).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", key) } @@ -205,8 +203,8 @@ func handleZCARD(ctx context.Context, cmd []string, server types.EchoVault, _ *n return []byte(fmt.Sprintf(":%d\r\n", set.Cardinality())), nil } -func handleZCOUNT(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := zcountKeyFunc(cmd) +func handleZCOUNT(params types.HandlerFuncParams) ([]byte, error) { + keys, err := zcountKeyFunc(params.Command) if err != nil { return nil, err } @@ -214,51 +212,51 @@ func handleZCOUNT(ctx context.Context, cmd []string, server types.EchoVault, _ * key := keys.ReadKeys[0] minimum := sorted_set.Score(math.Inf(-1)) - switch internal.AdaptType(cmd[2]).(type) { + switch internal.AdaptType(params.Command[2]).(type) { default: return nil, errors.New("min constraint must be a double") case string: - if strings.ToLower(cmd[2]) == "+inf" { + if strings.ToLower(params.Command[2]) == "+inf" { minimum = sorted_set.Score(math.Inf(1)) } else { return nil, errors.New("min constraint must be a double") } case float64: - s, _ := internal.AdaptType(cmd[2]).(float64) + s, _ := internal.AdaptType(params.Command[2]).(float64) minimum = sorted_set.Score(s) case int: - s, _ := internal.AdaptType(cmd[2]).(int) + s, _ := internal.AdaptType(params.Command[2]).(int) minimum = sorted_set.Score(s) } maximum := sorted_set.Score(math.Inf(1)) - switch internal.AdaptType(cmd[3]).(type) { + switch internal.AdaptType(params.Command[3]).(type) { default: return nil, errors.New("max constraint must be a double") case string: - if strings.ToLower(cmd[3]) == "-inf" { + if strings.ToLower(params.Command[3]) == "-inf" { maximum = sorted_set.Score(math.Inf(-1)) } else { return nil, errors.New("max constraint must be a double") } case float64: - s, _ := internal.AdaptType(cmd[3]).(float64) + s, _ := internal.AdaptType(params.Command[3]).(float64) maximum = sorted_set.Score(s) case int: - s, _ := internal.AdaptType(cmd[3]).(int) + s, _ := internal.AdaptType(params.Command[3]).(int) maximum = sorted_set.Score(s) } - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte(":0\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - set, ok := server.GetValue(ctx, key).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, key).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", key) } @@ -273,26 +271,26 @@ func handleZCOUNT(ctx context.Context, cmd []string, server types.EchoVault, _ * return []byte(fmt.Sprintf(":%d\r\n", len(members))), nil } -func handleZLEXCOUNT(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := zlexcountKeyFunc(cmd) +func handleZLEXCOUNT(params types.HandlerFuncParams) ([]byte, error) { + keys, err := zlexcountKeyFunc(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] - minimum := cmd[2] - maximum := cmd[3] + minimum := params.Command[2] + maximum := params.Command[3] - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte(":0\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - set, ok := server.GetValue(ctx, key).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, key).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", key) } @@ -318,13 +316,13 @@ func handleZLEXCOUNT(ctx context.Context, cmd []string, server types.EchoVault, return []byte(fmt.Sprintf(":%d\r\n", count)), nil } -func handleZDIFF(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := zdiffKeyFunc(cmd) +func handleZDIFF(params types.HandlerFuncParams) ([]byte, error) { + keys, err := zdiffKeyFunc(params.Command) if err != nil { return nil, err } - withscoresIndex := slices.IndexFunc(cmd, func(s string) bool { + withscoresIndex := slices.IndexFunc(params.Command, func(s string) bool { return strings.EqualFold(s, "withscores") }) if withscoresIndex > -1 && withscoresIndex < 2 { @@ -335,21 +333,21 @@ func handleZDIFF(ctx context.Context, cmd []string, server types.EchoVault, _ *n defer func() { for key, locked := range locks { if locked { - server.KeyRUnlock(ctx, key) + params.KeyRUnlock(params.Context, key) } } }() // Extract base set - if !server.KeyExists(ctx, keys.ReadKeys[0]) { + if !params.KeyExists(params.Context, keys.ReadKeys[0]) { // If base set does not exist, return an empty array return []byte("*0\r\n"), nil } - if _, err = server.KeyRLock(ctx, keys.ReadKeys[0]); err != nil { + if _, err = params.KeyRLock(params.Context, keys.ReadKeys[0]); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, keys.ReadKeys[0]) - baseSortedSet, ok := server.GetValue(ctx, keys.ReadKeys[0]).(*sorted_set.SortedSet) + defer params.KeyRUnlock(params.Context, keys.ReadKeys[0]) + baseSortedSet, ok := params.GetValue(params.Context, keys.ReadKeys[0]).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", keys.ReadKeys[0]) } @@ -358,15 +356,15 @@ func handleZDIFF(ctx context.Context, cmd []string, server types.EchoVault, _ *n var sets []*sorted_set.SortedSet for i := 1; i < len(keys.ReadKeys); i++ { - if !server.KeyExists(ctx, keys.ReadKeys[i]) { + if !params.KeyExists(params.Context, keys.ReadKeys[i]) { continue } - locked, err := server.KeyRLock(ctx, keys.ReadKeys[i]) + locked, err := params.KeyRLock(params.Context, keys.ReadKeys[i]) if err != nil { return nil, err } locks[keys.ReadKeys[i]] = locked - set, ok := server.GetValue(ctx, keys.ReadKeys[i]).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, keys.ReadKeys[i]).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", keys.ReadKeys[i]) } @@ -391,8 +389,8 @@ func handleZDIFF(ctx context.Context, cmd []string, server types.EchoVault, _ *n return []byte(res), nil } -func handleZDIFFSTORE(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := zdiffstoreKeyFunc(cmd) +func handleZDIFFSTORE(params types.HandlerFuncParams) ([]byte, error) { + keys, err := zdiffstoreKeyFunc(params.Command) if err != nil { return nil, err } @@ -403,21 +401,21 @@ func handleZDIFFSTORE(ctx context.Context, cmd []string, server types.EchoVault, defer func() { for key, locked := range locks { if locked { - server.KeyRUnlock(ctx, key) + params.KeyRUnlock(params.Context, key) } } }() // Extract base set - if !server.KeyExists(ctx, keys.ReadKeys[0]) { + if !params.KeyExists(params.Context, keys.ReadKeys[0]) { // If base set does not exist, return 0 return []byte(":0\r\n"), nil } - if _, err = server.KeyRLock(ctx, keys.ReadKeys[0]); err != nil { + if _, err = params.KeyRLock(params.Context, keys.ReadKeys[0]); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, keys.ReadKeys[0]) - baseSortedSet, ok := server.GetValue(ctx, keys.ReadKeys[0]).(*sorted_set.SortedSet) + defer params.KeyRUnlock(params.Context, keys.ReadKeys[0]) + baseSortedSet, ok := params.GetValue(params.Context, keys.ReadKeys[0]).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", keys.ReadKeys[0]) } @@ -425,11 +423,11 @@ func handleZDIFFSTORE(ctx context.Context, cmd []string, server types.EchoVault, var sets []*sorted_set.SortedSet for i := 1; i < len(keys.ReadKeys); i++ { - if server.KeyExists(ctx, keys.ReadKeys[i]) { - if _, err = server.KeyRLock(ctx, keys.ReadKeys[i]); err != nil { + if params.KeyExists(params.Context, keys.ReadKeys[i]) { + if _, err = params.KeyRLock(params.Context, keys.ReadKeys[i]); err != nil { return nil, err } - set, ok := server.GetValue(ctx, keys.ReadKeys[i]).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, keys.ReadKeys[i]).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", keys.ReadKeys[i]) } @@ -439,75 +437,75 @@ func handleZDIFFSTORE(ctx context.Context, cmd []string, server types.EchoVault, diff := baseSortedSet.Subtract(sets) - if server.KeyExists(ctx, destination) { - if _, err = server.KeyLock(ctx, destination); err != nil { + if params.KeyExists(params.Context, destination) { + if _, err = params.KeyLock(params.Context, destination); err != nil { return nil, err } } else { - if _, err = server.CreateKeyAndLock(ctx, destination); err != nil { + if _, err = params.CreateKeyAndLock(params.Context, destination); err != nil { return nil, err } } - defer server.KeyUnlock(ctx, destination) + defer params.KeyUnlock(params.Context, destination) - if err = server.SetValue(ctx, destination, diff); err != nil { + if err = params.SetValue(params.Context, destination, diff); err != nil { return nil, err } return []byte(fmt.Sprintf(":%d\r\n", diff.Cardinality())), nil } -func handleZINCRBY(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := zincrbyKeyFunc(cmd) +func handleZINCRBY(params types.HandlerFuncParams) ([]byte, error) { + keys, err := zincrbyKeyFunc(params.Command) if err != nil { return nil, err } key := keys.WriteKeys[0] - member := sorted_set.Value(cmd[3]) + member := sorted_set.Value(params.Command[3]) var increment sorted_set.Score - switch internal.AdaptType(cmd[2]).(type) { + switch internal.AdaptType(params.Command[2]).(type) { default: return nil, errors.New("increment must be a double") case string: - if strings.EqualFold("-inf", strings.ToLower(cmd[2])) { + if strings.EqualFold("-inf", strings.ToLower(params.Command[2])) { increment = sorted_set.Score(math.Inf(-1)) - } else if strings.EqualFold("+inf", strings.ToLower(cmd[2])) { + } else if strings.EqualFold("+inf", strings.ToLower(params.Command[2])) { increment = sorted_set.Score(math.Inf(1)) } else { return nil, errors.New("increment must be a double") } case float64: - s, _ := internal.AdaptType(cmd[2]).(float64) + s, _ := internal.AdaptType(params.Command[2]).(float64) increment = sorted_set.Score(s) case int: - s, _ := internal.AdaptType(cmd[2]).(int) + s, _ := internal.AdaptType(params.Command[2]).(int) increment = sorted_set.Score(s) } - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { // If the key does not exist, create a new sorted set at the key with // the member and increment as the first value - if _, err = server.CreateKeyAndLock(ctx, key); err != nil { + if _, err = params.CreateKeyAndLock(params.Context, key); err != nil { return nil, err } - if err = server.SetValue( - ctx, + if err = params.SetValue( + params.Context, key, sorted_set.NewSortedSet([]sorted_set.MemberParam{{Value: member, Score: increment}}), ); err != nil { return nil, err } - server.KeyUnlock(ctx, key) + params.KeyUnlock(params.Context, key) return []byte(fmt.Sprintf("+%s\r\n", strconv.FormatFloat(float64(increment), 'f', -1, 64))), nil } - if _, err = server.KeyLock(ctx, key); err != nil { + if _, err = params.KeyLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) - set, ok := server.GetValue(ctx, key).(*sorted_set.SortedSet) + defer params.KeyUnlock(params.Context, key) + set, ok := params.GetValue(params.Context, key).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", key) } @@ -524,13 +522,13 @@ func handleZINCRBY(ctx context.Context, cmd []string, server types.EchoVault, _ strconv.FormatFloat(float64(set.Get(member).Score), 'f', -1, 64))), nil } -func handleZINTER(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - _, err := zinterKeyFunc(cmd) +func handleZINTER(params types.HandlerFuncParams) ([]byte, error) { + _, err := zinterKeyFunc(params.Command) if err != nil { return nil, err } - keys, weights, aggregate, withscores, err := extractKeysWeightsAggregateWithScores(cmd) + keys, weights, aggregate, withscores, err := extractKeysWeightsAggregateWithScores(params.Command) if err != nil { return nil, err } @@ -539,7 +537,7 @@ func handleZINTER(ctx context.Context, cmd []string, server types.EchoVault, _ * defer func() { for key, locked := range locks { if locked { - server.KeyRUnlock(ctx, key) + params.KeyRUnlock(params.Context, key) } } }() @@ -547,15 +545,15 @@ func handleZINTER(ctx context.Context, cmd []string, server types.EchoVault, _ * var setParams []sorted_set.SortedSetParam for i := 0; i < len(keys); i++ { - if !server.KeyExists(ctx, keys[i]) { + if !params.KeyExists(params.Context, keys[i]) { // If any of the keys is non-existent, return an empty array as there's no intersect return []byte("*0\r\n"), nil } - if _, err = server.KeyRLock(ctx, keys[i]); err != nil { + if _, err = params.KeyRLock(params.Context, keys[i]); err != nil { return nil, err } locks[keys[i]] = true - set, ok := server.GetValue(ctx, keys[i]).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, keys[i]).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", keys[i]) } @@ -584,8 +582,8 @@ func handleZINTER(ctx context.Context, cmd []string, server types.EchoVault, _ * return []byte(res), nil } -func handleZINTERSTORE(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - k, err := zinterstoreKeyFunc(cmd) +func handleZINTERSTORE(params types.HandlerFuncParams) ([]byte, error) { + k, err := zinterstoreKeyFunc(params.Command) if err != nil { return nil, err } @@ -593,7 +591,7 @@ func handleZINTERSTORE(ctx context.Context, cmd []string, server types.EchoVault destination := k.WriteKeys[0] // Remove the destination keys from the command before parsing it - cmd = slices.DeleteFunc(cmd, func(s string) bool { + cmd := slices.DeleteFunc(params.Command, func(s string) bool { return s == destination }) @@ -606,7 +604,7 @@ func handleZINTERSTORE(ctx context.Context, cmd []string, server types.EchoVault defer func() { for key, locked := range locks { if locked { - server.KeyRUnlock(ctx, key) + params.KeyRUnlock(params.Context, key) } } }() @@ -614,14 +612,14 @@ func handleZINTERSTORE(ctx context.Context, cmd []string, server types.EchoVault var setParams []sorted_set.SortedSetParam for i := 0; i < len(keys); i++ { - if !server.KeyExists(ctx, keys[i]) { + if !params.KeyExists(params.Context, keys[i]) { return []byte(":0\r\n"), nil } - if _, err = server.KeyRLock(ctx, keys[i]); err != nil { + if _, err = params.KeyRLock(params.Context, keys[i]); err != nil { return nil, err } locks[keys[i]] = true - set, ok := server.GetValue(ctx, keys[i]).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, keys[i]).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", keys[i]) } @@ -633,26 +631,26 @@ func handleZINTERSTORE(ctx context.Context, cmd []string, server types.EchoVault intersect := sorted_set.Intersect(aggregate, setParams...) - if server.KeyExists(ctx, destination) && intersect.Cardinality() > 0 { - if _, err = server.KeyLock(ctx, destination); err != nil { + if params.KeyExists(params.Context, destination) && intersect.Cardinality() > 0 { + if _, err = params.KeyLock(params.Context, destination); err != nil { return nil, err } } else if intersect.Cardinality() > 0 { - if _, err = server.CreateKeyAndLock(ctx, destination); err != nil { + if _, err = params.CreateKeyAndLock(params.Context, destination); err != nil { return nil, err } } - defer server.KeyUnlock(ctx, destination) + defer params.KeyUnlock(params.Context, destination) - if err = server.SetValue(ctx, destination, intersect); err != nil { + if err = params.SetValue(params.Context, destination, intersect); err != nil { return nil, err } return []byte(fmt.Sprintf(":%d\r\n", intersect.Cardinality())), nil } -func handleZMPOP(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := zmpopKeyFunc(cmd) +func handleZMPOP(params types.HandlerFuncParams) ([]byte, error) { + keys, err := zmpopKeyFunc(params.Command) if err != nil { return nil, err } @@ -662,17 +660,17 @@ func handleZMPOP(ctx context.Context, cmd []string, server types.EchoVault, _ *n modifierIdx := -1 // Parse COUNT from command - countIdx := slices.IndexFunc(cmd, func(s string) bool { + countIdx := slices.IndexFunc(params.Command, func(s string) bool { return strings.ToLower(s) == "count" }) if countIdx != -1 { if countIdx < 2 { return nil, errors.New(constants.WrongArgsResponse) } - if countIdx == len(cmd)-1 { + if countIdx == len(params.Command)-1 { return nil, errors.New("count must be a positive integer") } - c, err := strconv.Atoi(cmd[countIdx+1]) + c, err := strconv.Atoi(params.Command[countIdx+1]) if err != nil { return nil, err } @@ -684,35 +682,35 @@ func handleZMPOP(ctx context.Context, cmd []string, server types.EchoVault, _ *n } // Parse MIN/MAX from the command - policyIdx := slices.IndexFunc(cmd, func(s string) bool { + policyIdx := slices.IndexFunc(params.Command, func(s string) bool { return slices.Contains([]string{"min", "max"}, strings.ToLower(s)) }) if policyIdx != -1 { if policyIdx < 2 { return nil, errors.New(constants.WrongArgsResponse) } - policy = strings.ToLower(cmd[policyIdx]) + policy = strings.ToLower(params.Command[policyIdx]) if modifierIdx == -1 || (policyIdx < modifierIdx) { modifierIdx = policyIdx } } for i := 0; i < len(keys.WriteKeys); i++ { - if server.KeyExists(ctx, keys.WriteKeys[i]) { - if _, err = server.KeyLock(ctx, keys.WriteKeys[i]); err != nil { + if params.KeyExists(params.Context, keys.WriteKeys[i]) { + if _, err = params.KeyLock(params.Context, keys.WriteKeys[i]); err != nil { continue } - v, ok := server.GetValue(ctx, keys.WriteKeys[i]).(*sorted_set.SortedSet) + v, ok := params.GetValue(params.Context, keys.WriteKeys[i]).(*sorted_set.SortedSet) if !ok || v.Cardinality() == 0 { - server.KeyUnlock(ctx, keys.WriteKeys[i]) + params.KeyUnlock(params.Context, keys.WriteKeys[i]) continue } popped, err := v.Pop(count, policy) if err != nil { - server.KeyUnlock(ctx, keys.WriteKeys[i]) + params.KeyUnlock(params.Context, keys.WriteKeys[i]) return nil, err } - server.KeyUnlock(ctx, keys.WriteKeys[i]) + params.KeyUnlock(params.Context, keys.WriteKeys[i]) res := fmt.Sprintf("*%d", popped.Cardinality()) @@ -729,8 +727,8 @@ func handleZMPOP(ctx context.Context, cmd []string, server types.EchoVault, _ *n return []byte("*0\r\n"), nil } -func handleZPOP(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := zpopKeyFunc(cmd) +func handleZPOP(params types.HandlerFuncParams) ([]byte, error) { + keys, err := zpopKeyFunc(params.Command) if err != nil { return nil, err } @@ -739,12 +737,12 @@ func handleZPOP(ctx context.Context, cmd []string, server types.EchoVault, _ *ne count := 1 policy := "min" - if strings.EqualFold(cmd[0], "zpopmax") { + if strings.EqualFold(params.Command[0], "zpopmax") { policy = "max" } - if len(cmd) == 3 { - c, err := strconv.Atoi(cmd[2]) + if len(params.Command) == 3 { + c, err := strconv.Atoi(params.Command[2]) if err != nil { return nil, err } @@ -753,16 +751,16 @@ func handleZPOP(ctx context.Context, cmd []string, server types.EchoVault, _ *ne } } - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte("*0\r\n"), nil } - if _, err = server.KeyLock(ctx, key); err != nil { + if _, err = params.KeyLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) - set, ok := server.GetValue(ctx, key).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, key).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at key %s is not a sorted set", key) } @@ -782,29 +780,29 @@ func handleZPOP(ctx context.Context, cmd []string, server types.EchoVault, _ *ne return []byte(res), nil } -func handleZMSCORE(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := zmscoreKeyFunc(cmd) +func handleZMSCORE(params types.HandlerFuncParams) ([]byte, error) { + keys, err := zmscoreKeyFunc(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte("*0\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - set, ok := server.GetValue(ctx, key).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, key).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", key) } - members := cmd[2:] + members := params.Command[2:] res := fmt.Sprintf("*%d", len(members)) @@ -824,8 +822,8 @@ func handleZMSCORE(ctx context.Context, cmd []string, server types.EchoVault, _ return []byte(res), nil } -func handleZRANDMEMBER(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := zrandmemberKeyFunc(cmd) +func handleZRANDMEMBER(params types.HandlerFuncParams) ([]byte, error) { + keys, err := zrandmemberKeyFunc(params.Command) if err != nil { return nil, err } @@ -833,8 +831,8 @@ func handleZRANDMEMBER(ctx context.Context, cmd []string, server types.EchoVault key := keys.ReadKeys[0] count := 1 - if len(cmd) >= 3 { - c, err := strconv.Atoi(cmd[2]) + if len(params.Command) >= 3 { + c, err := strconv.Atoi(params.Command[2]) if err != nil { return nil, errors.New("count must be an integer") } @@ -844,24 +842,24 @@ func handleZRANDMEMBER(ctx context.Context, cmd []string, server types.EchoVault } withscores := false - if len(cmd) == 4 { - if strings.EqualFold(cmd[3], "withscores") { + if len(params.Command) == 4 { + if strings.EqualFold(params.Command[3], "withscores") { withscores = true } else { return nil, errors.New("last option must be WITHSCORES") } } - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte("$-1\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - set, ok := server.GetValue(ctx, key).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, key).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", key) } @@ -882,37 +880,37 @@ func handleZRANDMEMBER(ctx context.Context, cmd []string, server types.EchoVault return []byte(res), nil } -func handleZRANK(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := zrankKeyFunc(cmd) +func handleZRANK(params types.HandlerFuncParams) ([]byte, error) { + keys, err := zrankKeyFunc(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] - member := cmd[2] + member := params.Command[2] withscores := false - if len(cmd) == 4 && strings.EqualFold(cmd[3], "withscores") { + if len(params.Command) == 4 && strings.EqualFold(params.Command[3], "withscores") { withscores = true } - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte("$-1\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - set, ok := server.GetValue(ctx, key).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, key).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", key) } members := set.GetAll() slices.SortFunc(members, func(a, b sorted_set.MemberParam) int { - if strings.EqualFold(cmd[0], "zrevrank") { + if strings.EqualFold(params.Command[0], "zrevrank") { return cmp.Compare(b.Score, a.Score) } return cmp.Compare(a.Score, b.Score) @@ -932,30 +930,30 @@ func handleZRANK(ctx context.Context, cmd []string, server types.EchoVault, _ *n return []byte("$-1\r\n"), nil } -func handleZREM(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := zremKeyFunc(cmd) +func handleZREM(params types.HandlerFuncParams) ([]byte, error) { + keys, err := zremKeyFunc(params.Command) if err != nil { return nil, err } key := keys.WriteKeys[0] - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte(":0\r\n"), nil } - if _, err = server.KeyLock(ctx, key); err != nil { + if _, err = params.KeyLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) - set, ok := server.GetValue(ctx, key).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, key).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", key) } deletedCount := 0 - for _, m := range cmd[2:] { + for _, m := range params.Command[2:] { if set.Remove(sorted_set.Value(m)) { deletedCount += 1 } @@ -964,26 +962,26 @@ func handleZREM(ctx context.Context, cmd []string, server types.EchoVault, _ *ne return []byte(fmt.Sprintf(":%d\r\n", deletedCount)), nil } -func handleZSCORE(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := zscoreKeyFunc(cmd) +func handleZSCORE(params types.HandlerFuncParams) ([]byte, error) { + keys, err := zscoreKeyFunc(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte("$-1\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) - set, ok := server.GetValue(ctx, key).(*sorted_set.SortedSet) + defer params.KeyRUnlock(params.Context, key) + set, ok := params.GetValue(params.Context, key).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", key) } - member := set.Get(sorted_set.Value(cmd[2])) + member := set.Get(sorted_set.Value(params.Command[2])) if !member.Exists { return []byte("$-1\r\n"), nil } @@ -993,8 +991,8 @@ func handleZSCORE(ctx context.Context, cmd []string, server types.EchoVault, _ * return []byte(fmt.Sprintf("$%d\r\n%s\r\n", len(score), score)), nil } -func handleZREMRANGEBYSCORE(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := zremrangebyscoreKeyFunc(cmd) +func handleZREMRANGEBYSCORE(params types.HandlerFuncParams) ([]byte, error) { + keys, err := zremrangebyscoreKeyFunc(params.Command) if err != nil { return nil, err } @@ -1003,26 +1001,26 @@ func handleZREMRANGEBYSCORE(ctx context.Context, cmd []string, server types.Echo deletedCount := 0 - minimum, err := strconv.ParseFloat(cmd[2], 64) + minimum, err := strconv.ParseFloat(params.Command[2], 64) if err != nil { return nil, err } - maximum, err := strconv.ParseFloat(cmd[3], 64) + maximum, err := strconv.ParseFloat(params.Command[3], 64) if err != nil { return nil, err } - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte(":0\r\n"), nil } - if _, err = server.KeyLock(ctx, key); err != nil { + if _, err = params.KeyLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) - set, ok := server.GetValue(ctx, key).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, key).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", key) } @@ -1037,34 +1035,34 @@ func handleZREMRANGEBYSCORE(ctx context.Context, cmd []string, server types.Echo return []byte(fmt.Sprintf(":%d\r\n", deletedCount)), nil } -func handleZREMRANGEBYRANK(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := zremrangebyrankKeyFunc(cmd) +func handleZREMRANGEBYRANK(params types.HandlerFuncParams) ([]byte, error) { + keys, err := zremrangebyrankKeyFunc(params.Command) if err != nil { return nil, err } key := keys.WriteKeys[0] - start, err := strconv.Atoi(cmd[2]) + start, err := strconv.Atoi(params.Command[2]) if err != nil { return nil, err } - stop, err := strconv.Atoi(cmd[3]) + stop, err := strconv.Atoi(params.Command[3]) if err != nil { return nil, err } - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte(":0\r\n"), nil } - if _, err = server.KeyLock(ctx, key); err != nil { + if _, err = params.KeyLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) - set, ok := server.GetValue(ctx, key).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, key).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", key) } @@ -1102,26 +1100,26 @@ func handleZREMRANGEBYRANK(ctx context.Context, cmd []string, server types.EchoV return []byte(fmt.Sprintf(":%d\r\n", deletedCount)), nil } -func handleZREMRANGEBYLEX(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := zremrangebylexKeyFunc(cmd) +func handleZREMRANGEBYLEX(params types.HandlerFuncParams) ([]byte, error) { + keys, err := zremrangebylexKeyFunc(params.Command) if err != nil { return nil, err } key := keys.WriteKeys[0] - minimum := cmd[2] - maximum := cmd[3] + minimum := params.Command[2] + maximum := params.Command[3] - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte(":0\r\n"), nil } - if _, err = server.KeyLock(ctx, key); err != nil { + if _, err = params.KeyLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) - set, ok := server.GetValue(ctx, key).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, key).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", key) } @@ -1149,77 +1147,77 @@ func handleZREMRANGEBYLEX(ctx context.Context, cmd []string, server types.EchoVa return []byte(fmt.Sprintf(":%d\r\n", deletedCount)), nil } -func handleZRANGE(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := zrangeKeyCount(cmd) +func handleZRANGE(params types.HandlerFuncParams) ([]byte, error) { + keys, err := zrangeKeyCount(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] policy := "byscore" - scoreStart := math.Inf(-1) // Lower bound if policy is "byscore" - scoreStop := math.Inf(1) // Upper bound if policy is "byscore" - lexStart := cmd[2] // Lower bound if policy is "bylex" - lexStop := cmd[3] // Upper bound if policy is "bylex" + scoreStart := math.Inf(-1) // Lower bound if policy is "byscore" + scoreStop := math.Inf(1) // Upper bound if policy is "byscore" + lexStart := params.Command[2] // Lower bound if policy is "bylex" + lexStop := params.Command[3] // Upper bound if policy is "bylex" offset := 0 count := -1 - withscores := slices.ContainsFunc(cmd[4:], func(s string) bool { + withscores := slices.ContainsFunc(params.Command[4:], func(s string) bool { return strings.EqualFold(s, "withscores") }) - reverse := slices.ContainsFunc(cmd[4:], func(s string) bool { + reverse := slices.ContainsFunc(params.Command[4:], func(s string) bool { return strings.EqualFold(s, "rev") }) - if slices.ContainsFunc(cmd[4:], func(s string) bool { + if slices.ContainsFunc(params.Command[4:], func(s string) bool { return strings.EqualFold(s, "bylex") }) { policy = "bylex" } else { // policy is "byscore" make sure start and stop are valid float values - scoreStart, err = strconv.ParseFloat(cmd[2], 64) + scoreStart, err = strconv.ParseFloat(params.Command[2], 64) if err != nil { return nil, err } - scoreStop, err = strconv.ParseFloat(cmd[3], 64) + scoreStop, err = strconv.ParseFloat(params.Command[3], 64) if err != nil { return nil, err } } - if slices.ContainsFunc(cmd[4:], func(s string) bool { + if slices.ContainsFunc(params.Command[4:], func(s string) bool { return strings.EqualFold(s, "limit") }) { - limitIdx := slices.IndexFunc(cmd[4:], func(s string) bool { + limitIdx := slices.IndexFunc(params.Command[4:], func(s string) bool { return strings.EqualFold(s, "limit") }) - if limitIdx != -1 && limitIdx > len(cmd[4:])-3 { + if limitIdx != -1 && limitIdx > len(params.Command[4:])-3 { return nil, errors.New("limit should contain offset and count as integers") } - offset, err = strconv.Atoi(cmd[4:][limitIdx+1]) + offset, err = strconv.Atoi(params.Command[4:][limitIdx+1]) if err != nil { return nil, errors.New("limit offset must be integer") } if offset < 0 { return nil, errors.New("limit offset must be >= 0") } - count, err = strconv.Atoi(cmd[4:][limitIdx+2]) + count, err = strconv.Atoi(params.Command[4:][limitIdx+2]) if err != nil { return nil, errors.New("limit count must be integer") } } - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte("*0\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - set, ok := server.GetValue(ctx, key).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, key).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", key) } @@ -1289,8 +1287,8 @@ func handleZRANGE(ctx context.Context, cmd []string, server types.EchoVault, _ * return []byte(res), nil } -func handleZRANGESTORE(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := zrangeStoreKeyFunc(cmd) +func handleZRANGESTORE(params types.HandlerFuncParams) ([]byte, error) { + keys, err := zrangeStoreKeyFunc(params.Command) if err != nil { return nil, err } @@ -1298,65 +1296,65 @@ func handleZRANGESTORE(ctx context.Context, cmd []string, server types.EchoVault destination := keys.WriteKeys[0] source := keys.ReadKeys[0] policy := "byscore" - scoreStart := math.Inf(-1) // Lower bound if policy is "byscore" - scoreStop := math.Inf(1) // Upper bound if policy is "byfloat" - lexStart := cmd[3] // Lower bound if policy is "bylex" - lexStop := cmd[4] // Upper bound if policy is "bylex" + scoreStart := math.Inf(-1) // Lower bound if policy is "byscore" + scoreStop := math.Inf(1) // Upper bound if policy is "byfloat" + lexStart := params.Command[3] // Lower bound if policy is "bylex" + lexStop := params.Command[4] // Upper bound if policy is "bylex" offset := 0 count := -1 - reverse := slices.ContainsFunc(cmd[5:], func(s string) bool { + reverse := slices.ContainsFunc(params.Command[5:], func(s string) bool { return strings.EqualFold(s, "rev") }) - if slices.ContainsFunc(cmd[5:], func(s string) bool { + if slices.ContainsFunc(params.Command[5:], func(s string) bool { return strings.EqualFold(s, "bylex") }) { policy = "bylex" } else { // policy is "byscore" make sure start and stop are valid float values - scoreStart, err = strconv.ParseFloat(cmd[3], 64) + scoreStart, err = strconv.ParseFloat(params.Command[3], 64) if err != nil { return nil, err } - scoreStop, err = strconv.ParseFloat(cmd[4], 64) + scoreStop, err = strconv.ParseFloat(params.Command[4], 64) if err != nil { return nil, err } } - if slices.ContainsFunc(cmd[5:], func(s string) bool { + if slices.ContainsFunc(params.Command[5:], func(s string) bool { return strings.EqualFold(s, "limit") }) { - limitIdx := slices.IndexFunc(cmd[5:], func(s string) bool { + limitIdx := slices.IndexFunc(params.Command[5:], func(s string) bool { return strings.EqualFold(s, "limit") }) - if limitIdx != -1 && limitIdx > len(cmd[5:])-3 { + if limitIdx != -1 && limitIdx > len(params.Command[5:])-3 { return nil, errors.New("limit should contain offset and count as integers") } - offset, err = strconv.Atoi(cmd[5:][limitIdx+1]) + offset, err = strconv.Atoi(params.Command[5:][limitIdx+1]) if err != nil { return nil, errors.New("limit offset must be integer") } if offset < 0 { return nil, errors.New("limit offset must be >= 0") } - count, err = strconv.Atoi(cmd[5:][limitIdx+2]) + count, err = strconv.Atoi(params.Command[5:][limitIdx+2]) if err != nil { return nil, errors.New("limit count must be integer") } } - if !server.KeyExists(ctx, source) { + if !params.KeyExists(params.Context, source) { return []byte("*0\r\n"), nil } - if _, err = server.KeyRLock(ctx, source); err != nil { + if _, err = params.KeyRLock(params.Context, source); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, source) + defer params.KeyRUnlock(params.Context, source) - set, ok := server.GetValue(ctx, source).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, source).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", source) } @@ -1413,30 +1411,30 @@ func handleZRANGESTORE(ctx context.Context, cmd []string, server types.EchoVault newSortedSet := sorted_set.NewSortedSet(resultMembers) - if server.KeyExists(ctx, destination) { - if _, err = server.KeyLock(ctx, destination); err != nil { + if params.KeyExists(params.Context, destination) { + if _, err = params.KeyLock(params.Context, destination); err != nil { return nil, err } } else { - if _, err = server.CreateKeyAndLock(ctx, destination); err != nil { + if _, err = params.CreateKeyAndLock(params.Context, destination); err != nil { return nil, err } } - defer server.KeyUnlock(ctx, destination) + defer params.KeyUnlock(params.Context, destination) - if err = server.SetValue(ctx, destination, newSortedSet); err != nil { + if err = params.SetValue(params.Context, destination, newSortedSet); err != nil { return nil, err } return []byte(fmt.Sprintf(":%d\r\n", newSortedSet.Cardinality())), nil } -func handleZUNION(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - if _, err := zunionKeyFunc(cmd); err != nil { +func handleZUNION(params types.HandlerFuncParams) ([]byte, error) { + if _, err := zunionKeyFunc(params.Command); err != nil { return nil, err } - keys, weights, aggregate, withscores, err := extractKeysWeightsAggregateWithScores(cmd) + keys, weights, aggregate, withscores, err := extractKeysWeightsAggregateWithScores(params.Command) if err != nil { return nil, err } @@ -1445,7 +1443,7 @@ func handleZUNION(ctx context.Context, cmd []string, server types.EchoVault, _ * defer func() { for key, locked := range locks { if locked { - server.KeyRUnlock(ctx, key) + params.KeyRUnlock(params.Context, key) } } }() @@ -1453,12 +1451,12 @@ func handleZUNION(ctx context.Context, cmd []string, server types.EchoVault, _ * var setParams []sorted_set.SortedSetParam for i := 0; i < len(keys); i++ { - if server.KeyExists(ctx, keys[i]) { - if _, err = server.KeyRLock(ctx, keys[i]); err != nil { + if params.KeyExists(params.Context, keys[i]) { + if _, err = params.KeyRLock(params.Context, keys[i]); err != nil { return nil, err } locks[keys[i]] = true - set, ok := server.GetValue(ctx, keys[i]).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, keys[i]).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", keys[i]) } @@ -1485,8 +1483,8 @@ func handleZUNION(ctx context.Context, cmd []string, server types.EchoVault, _ * return []byte(res), nil } -func handleZUNIONSTORE(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - k, err := zunionstoreKeyFunc(cmd) +func handleZUNIONSTORE(params types.HandlerFuncParams) ([]byte, error) { + k, err := zunionstoreKeyFunc(params.Command) if err != nil { return nil, err } @@ -1494,11 +1492,11 @@ func handleZUNIONSTORE(ctx context.Context, cmd []string, server types.EchoVault destination := k.WriteKeys[0] // Remove destination key from list of keys - cmd = slices.DeleteFunc(cmd, func(s string) bool { + params.Command = slices.DeleteFunc(params.Command, func(s string) bool { return s == destination }) - keys, weights, aggregate, _, err := extractKeysWeightsAggregateWithScores(cmd) + keys, weights, aggregate, _, err := extractKeysWeightsAggregateWithScores(params.Command) if err != nil { return nil, err } @@ -1507,7 +1505,7 @@ func handleZUNIONSTORE(ctx context.Context, cmd []string, server types.EchoVault defer func() { for key, locked := range locks { if locked { - server.KeyRUnlock(ctx, key) + params.KeyRUnlock(params.Context, key) } } }() @@ -1515,12 +1513,12 @@ func handleZUNIONSTORE(ctx context.Context, cmd []string, server types.EchoVault var setParams []sorted_set.SortedSetParam for i := 0; i < len(keys); i++ { - if server.KeyExists(ctx, keys[i]) { - if _, err = server.KeyRLock(ctx, keys[i]); err != nil { + if params.KeyExists(params.Context, keys[i]) { + if _, err = params.KeyRLock(params.Context, keys[i]); err != nil { return nil, err } locks[keys[i]] = true - set, ok := server.GetValue(ctx, keys[i]).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, keys[i]).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", keys[i]) } @@ -1533,18 +1531,18 @@ func handleZUNIONSTORE(ctx context.Context, cmd []string, server types.EchoVault union := sorted_set.Union(aggregate, setParams...) - if server.KeyExists(ctx, destination) { - if _, err = server.KeyLock(ctx, destination); err != nil { + if params.KeyExists(params.Context, destination) { + if _, err = params.KeyLock(params.Context, destination); err != nil { return nil, err } } else { - if _, err = server.CreateKeyAndLock(ctx, destination); err != nil { + if _, err = params.CreateKeyAndLock(params.Context, destination); err != nil { return nil, err } } - defer server.KeyUnlock(ctx, destination) + defer params.KeyUnlock(params.Context, destination) - if err = server.SetValue(ctx, destination, union); err != nil { + if err = params.SetValue(params.Context, destination, union); err != nil { return nil, err } diff --git a/pkg/echovault/api_acl_test.go b/test/modules/acl/api_acl_test.go similarity index 97% rename from pkg/echovault/api_acl_test.go rename to test/modules/acl/api_acl_test.go index f6598c81..96769fed 100644 --- a/pkg/echovault/api_acl_test.go +++ b/test/modules/acl/api_acl_test.go @@ -12,4 +12,4 @@ // See the License for the specific language governing permissions and // limitations under the License. -package echovault +package acl diff --git a/pkg/modules/acl/commands_test.go b/test/modules/acl/commands_test.go similarity index 99% rename from pkg/modules/acl/commands_test.go rename to test/modules/acl/commands_test.go index da8b5577..5c9a81d9 100644 --- a/pkg/modules/acl/commands_test.go +++ b/test/modules/acl/commands_test.go @@ -21,6 +21,7 @@ import ( "github.com/echovault/echovault/internal/config" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/echovault" + acl2 "github.com/echovault/echovault/pkg/modules/acl" "github.com/tidwall/resp" "net" "slices" @@ -60,8 +61,8 @@ func setUpServer(bindAddr string, port uint16, requirePass bool, aclConfig strin } mockServer, _ := echovault.NewEchoVault( + echovault.WithCommands(acl2.Commands()), echovault.WithConfig(conf), - echovault.WithCommands(Commands()), ) // Add the initial test users to the ACL module diff --git a/pkg/echovault/api_admin_test.go b/test/modules/admin/api_admin_test.go similarity index 97% rename from pkg/echovault/api_admin_test.go rename to test/modules/admin/api_admin_test.go index afd234ac..d643816b 100644 --- a/pkg/echovault/api_admin_test.go +++ b/test/modules/admin/api_admin_test.go @@ -12,4 +12,4 @@ // See the License for the specific language governing permissions and // limitations under the License. -package echovault +package admin diff --git a/pkg/modules/admin/commands_test.go b/test/modules/admin/commands_test.go similarity index 51% rename from pkg/modules/admin/commands_test.go rename to test/modules/admin/commands_test.go index cd558ee2..6e1ac3cb 100644 --- a/pkg/modules/admin/commands_test.go +++ b/test/modules/admin/commands_test.go @@ -21,20 +21,58 @@ import ( "github.com/echovault/echovault/internal/config" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/echovault" + "github.com/echovault/echovault/pkg/modules/admin" + "github.com/echovault/echovault/pkg/types" "github.com/tidwall/resp" + "net" + "strings" "testing" ) -func Test_CommandsHandler(t *testing.T) { - mockServer, _ := echovault.NewEchoVault( +var mockServer *echovault.EchoVault + +func init() { + mockServer, _ = echovault.NewEchoVault( + echovault.WithCommands(admin.Commands()), echovault.WithConfig(config.Config{ DataDir: "", EvictionPolicy: constants.NoEviction, }), - echovault.WithCommands(Commands()), ) +} - res, err := handleGetAllCommands(context.Background(), []string{"commands"}, mockServer, nil) +func getHandler(commands ...string) types.HandlerFunc { + if len(commands) == 0 { + return nil + } + for _, c := range mockServer.GetAllCommands() { + if strings.EqualFold(commands[0], c.Command) && len(commands) == 1 { + // Get command handler + return c.HandlerFunc + } + if strings.EqualFold(commands[0], c.Command) { + // Get sub-command handler + for _, sc := range c.SubCommands { + if strings.EqualFold(commands[1], sc.Command) { + return sc.HandlerFunc + } + } + } + } + return nil +} + +func getHandlerFuncParams(ctx context.Context, cmd []string, conn *net.Conn) types.HandlerFuncParams { + return types.HandlerFuncParams{ + Context: ctx, + Command: cmd, + Connection: conn, + GetAllCommands: mockServer.GetAllCommands, + } +} + +func Test_CommandsHandler(t *testing.T) { + res, err := getHandler("COMMANDS")(getHandlerFuncParams(context.Background(), []string{"commands"}, nil)) if err != nil { t.Error(err) } diff --git a/pkg/echovault/api_connection_test.go b/test/modules/connection/api_connection_test.go similarity index 96% rename from pkg/echovault/api_connection_test.go rename to test/modules/connection/api_connection_test.go index afd234ac..dacccb84 100644 --- a/pkg/echovault/api_connection_test.go +++ b/test/modules/connection/api_connection_test.go @@ -12,4 +12,4 @@ // See the License for the specific language governing permissions and // limitations under the License. -package echovault +package connection diff --git a/pkg/modules/connection/commands_test.go b/test/modules/connection/commands_test.go similarity index 68% rename from pkg/modules/connection/commands_test.go rename to test/modules/connection/commands_test.go index 3d96fa55..675a4e2d 100644 --- a/pkg/modules/connection/commands_test.go +++ b/test/modules/connection/commands_test.go @@ -21,7 +21,11 @@ import ( "github.com/echovault/echovault/internal/config" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/echovault" + "github.com/echovault/echovault/pkg/modules/connection" + "github.com/echovault/echovault/pkg/types" "github.com/tidwall/resp" + "net" + "strings" "testing" ) @@ -29,6 +33,7 @@ var mockServer *echovault.EchoVault func init() { mockServer, _ = echovault.NewEchoVault( + echovault.WithCommands(connection.Commands()), echovault.WithConfig(config.Config{ DataDir: "", EvictionPolicy: constants.NoEviction, @@ -36,6 +41,35 @@ func init() { ) } +func getHandler(commands ...string) types.HandlerFunc { + if len(commands) == 0 { + return nil + } + for _, c := range mockServer.GetAllCommands() { + if strings.EqualFold(commands[0], c.Command) && len(commands) == 1 { + // Get command handler + return c.HandlerFunc + } + if strings.EqualFold(commands[0], c.Command) { + // Get sub-command handler + for _, sc := range c.SubCommands { + if strings.EqualFold(commands[1], sc.Command) { + return sc.HandlerFunc + } + } + } + } + return nil +} + +func getHandlerFuncParams(ctx context.Context, cmd []string, conn *net.Conn) types.HandlerFuncParams { + return types.HandlerFuncParams{ + Context: ctx, + Command: cmd, + Connection: conn, + } +} + func Test_HandlePing(t *testing.T) { ctx := context.Background() @@ -62,7 +96,7 @@ func Test_HandlePing(t *testing.T) { } for _, test := range tests { - res, err := handlePing(ctx, test.command, mockServer, nil) + res, err := getHandler("PING")(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedErr != nil && err != nil { if err.Error() != test.expectedErr.Error() { t.Errorf("expected error %s, got: %s", test.expectedErr.Error(), err.Error()) diff --git a/pkg/echovault/api_generic_test.go b/test/modules/generic/api_generic_test.go similarity index 85% rename from pkg/echovault/api_generic_test.go rename to test/modules/generic/api_generic_test.go index 9ec5b451..d0f6cdcd 100644 --- a/pkg/echovault/api_generic_test.go +++ b/test/modules/generic/api_generic_test.go @@ -12,14 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -package echovault +package generic import ( + "context" "github.com/echovault/echovault/internal" "github.com/echovault/echovault/internal/clock" "github.com/echovault/echovault/internal/config" - "github.com/echovault/echovault/pkg/commands" - "github.com/echovault/echovault/pkg/constants" + "github.com/echovault/echovault/pkg/echovault" + "github.com/echovault/echovault/pkg/modules/generic" "reflect" "slices" "strings" @@ -27,13 +28,36 @@ import ( "time" ) -func TestEchoVault_DEL(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - EvictionPolicy: constants.NoEviction, +func createEchoVault() *echovault.EchoVault { + ev, _ := echovault.NewEchoVault( + echovault.WithCommands(generic.Commands()), + echovault.WithConfig(config.Config{ + DataDir: "", }), ) + return ev +} + +func presetValue(server *echovault.EchoVault, ctx context.Context, key string, value interface{}) error { + if _, err := server.CreateKeyAndLock(ctx, key); err != nil { + return err + } + if err := server.SetValue(ctx, key, value); err != nil { + return err + } + server.KeyUnlock(ctx, key) + return nil +} + +func presetKeyData(server *echovault.EchoVault, ctx context.Context, key string, data internal.KeyData) { + _, _ = server.CreateKeyAndLock(ctx, key) + defer server.KeyUnlock(ctx, key) + _ = server.SetValue(ctx, key, data.Value) + server.SetExpiry(ctx, key, data.ExpireAt, false) +} + +func TestEchoVault_DEL(t *testing.T) { + server := createEchoVault() tests := []struct { name string @@ -59,7 +83,7 @@ func TestEchoVault_DEL(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.presetValues != nil { for k, d := range tt.presetValues { - presetKeyData(server, k, d) + presetKeyData(server, context.Background(), k, d) } } got, err := server.DEL(tt.keys...) @@ -77,12 +101,7 @@ func TestEchoVault_DEL(t *testing.T) { func TestEchoVault_EXPIRE(t *testing.T) { mockClock := clock.NewClock() - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -90,8 +109,8 @@ func TestEchoVault_EXPIRE(t *testing.T) { cmd string key string time int - expireOpts EXPIREOptions - pexpireOpts PEXPIREOptions + expireOpts echovault.EXPIREOptions + pexpireOpts echovault.PEXPIREOptions want int wantErr bool }{ @@ -100,7 +119,7 @@ func TestEchoVault_EXPIRE(t *testing.T) { cmd: "EXPIRE", key: "key1", time: 100, - expireOpts: EXPIREOptions{}, + expireOpts: echovault.EXPIREOptions{}, presetValues: map[string]internal.KeyData{ "key1": {Value: "value1", ExpireAt: time.Time{}}, }, @@ -112,7 +131,7 @@ func TestEchoVault_EXPIRE(t *testing.T) { cmd: "PEXPIRE", key: "key2", time: 1000, - pexpireOpts: PEXPIREOptions{}, + pexpireOpts: echovault.PEXPIREOptions{}, presetValues: map[string]internal.KeyData{ "key2": {Value: "value2", ExpireAt: time.Time{}}, }, @@ -124,7 +143,7 @@ func TestEchoVault_EXPIRE(t *testing.T) { cmd: "EXPIRE", key: "key3", time: 1000, - expireOpts: EXPIREOptions{NX: true}, + expireOpts: echovault.EXPIREOptions{NX: true}, presetValues: map[string]internal.KeyData{ "key3": {Value: "value3", ExpireAt: time.Time{}}, }, @@ -136,7 +155,7 @@ func TestEchoVault_EXPIRE(t *testing.T) { cmd: "EXPIRE", key: "key4", time: 1000, - expireOpts: EXPIREOptions{NX: true}, + expireOpts: echovault.EXPIREOptions{NX: true}, presetValues: map[string]internal.KeyData{ "key4": {Value: "value4", ExpireAt: mockClock.Now().Add(1000 * time.Second)}, }, @@ -148,7 +167,7 @@ func TestEchoVault_EXPIRE(t *testing.T) { cmd: "EXPIRE", key: "key5", time: 1000, - expireOpts: EXPIREOptions{XX: true}, + expireOpts: echovault.EXPIREOptions{XX: true}, presetValues: map[string]internal.KeyData{ "key5": {Value: "value5", ExpireAt: mockClock.Now().Add(30 * time.Second)}, }, @@ -159,7 +178,7 @@ func TestEchoVault_EXPIRE(t *testing.T) { name: "Return 0 when key does not have an expiry and the XX flag is provided", cmd: "EXPIRE", time: 1000, - expireOpts: EXPIREOptions{XX: true}, + expireOpts: echovault.EXPIREOptions{XX: true}, key: "key6", presetValues: map[string]internal.KeyData{ "key6": {Value: "value6", ExpireAt: time.Time{}}, @@ -172,7 +191,7 @@ func TestEchoVault_EXPIRE(t *testing.T) { cmd: "EXPIRE", key: "key7", time: 100000, - expireOpts: EXPIREOptions{GT: true}, + expireOpts: echovault.EXPIREOptions{GT: true}, presetValues: map[string]internal.KeyData{ "key7": {Value: "value7", ExpireAt: mockClock.Now().Add(30 * time.Second)}, }, @@ -184,7 +203,7 @@ func TestEchoVault_EXPIRE(t *testing.T) { cmd: "EXPIRE", key: "key8", time: 1000, - expireOpts: EXPIREOptions{GT: true}, + expireOpts: echovault.EXPIREOptions{GT: true}, presetValues: map[string]internal.KeyData{ "key8": {Value: "value8", ExpireAt: mockClock.Now().Add(3000 * time.Second)}, }, @@ -196,7 +215,7 @@ func TestEchoVault_EXPIRE(t *testing.T) { cmd: "EXPIRE", key: "key9", time: 1000, - expireOpts: EXPIREOptions{GT: true}, + expireOpts: echovault.EXPIREOptions{GT: true}, presetValues: map[string]internal.KeyData{ "key9": {Value: "value9", ExpireAt: time.Time{}}, }, @@ -208,7 +227,7 @@ func TestEchoVault_EXPIRE(t *testing.T) { cmd: "EXPIRE", key: "key10", time: 1000, - expireOpts: EXPIREOptions{LT: true}, + expireOpts: echovault.EXPIREOptions{LT: true}, presetValues: map[string]internal.KeyData{ "key10": {Value: "value10", ExpireAt: mockClock.Now().Add(3000 * time.Second)}, }, @@ -220,7 +239,7 @@ func TestEchoVault_EXPIRE(t *testing.T) { cmd: "EXPIRE", key: "key11", time: 50000, - expireOpts: EXPIREOptions{LT: true}, + expireOpts: echovault.EXPIREOptions{LT: true}, presetValues: map[string]internal.KeyData{ "key11": {Value: "value11", ExpireAt: mockClock.Now().Add(30 * time.Second)}, }, @@ -232,7 +251,7 @@ func TestEchoVault_EXPIRE(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.presetValues != nil { for k, d := range tt.presetValues { - presetKeyData(server, k, d) + presetKeyData(server, context.Background(), k, d) } } var got int @@ -256,12 +275,7 @@ func TestEchoVault_EXPIRE(t *testing.T) { func TestEchoVault_EXPIREAT(t *testing.T) { mockClock := clock.NewClock() - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -269,8 +283,8 @@ func TestEchoVault_EXPIREAT(t *testing.T) { cmd string key string time int - expireAtOpts EXPIREATOptions - pexpireAtOpts PEXPIREATOptions + expireAtOpts echovault.EXPIREATOptions + pexpireAtOpts echovault.PEXPIREATOptions want int wantErr bool }{ @@ -278,7 +292,7 @@ func TestEchoVault_EXPIREAT(t *testing.T) { name: "Set new expire by unix seconds", cmd: "EXPIREAT", key: "key1", - expireAtOpts: EXPIREATOptions{}, + expireAtOpts: echovault.EXPIREATOptions{}, time: int(mockClock.Now().Add(1000 * time.Second).Unix()), presetValues: map[string]internal.KeyData{ "key1": {Value: "value1", ExpireAt: time.Time{}}, @@ -290,7 +304,7 @@ func TestEchoVault_EXPIREAT(t *testing.T) { name: "Set new expire by milliseconds", cmd: "PEXPIREAT", key: "key2", - pexpireAtOpts: PEXPIREATOptions{}, + pexpireAtOpts: echovault.PEXPIREATOptions{}, time: int(mockClock.Now().Add(1000 * time.Second).UnixMilli()), presetValues: map[string]internal.KeyData{ "key2": {Value: "value2", ExpireAt: time.Time{}}, @@ -303,7 +317,7 @@ func TestEchoVault_EXPIREAT(t *testing.T) { cmd: "EXPIREAT", key: "key3", time: int(mockClock.Now().Add(1000 * time.Second).Unix()), - expireAtOpts: EXPIREATOptions{NX: true}, + expireAtOpts: echovault.EXPIREATOptions{NX: true}, presetValues: map[string]internal.KeyData{ "key3": {Value: "value3", ExpireAt: time.Time{}}, }, @@ -314,7 +328,7 @@ func TestEchoVault_EXPIREAT(t *testing.T) { name: "Return 0, when NX flag is provided and key already has an expiry time", cmd: "EXPIREAT", time: int(mockClock.Now().Add(1000 * time.Second).Unix()), - expireAtOpts: EXPIREATOptions{NX: true}, + expireAtOpts: echovault.EXPIREATOptions{NX: true}, key: "key4", presetValues: map[string]internal.KeyData{ "key4": {Value: "value4", ExpireAt: mockClock.Now().Add(1000 * time.Second)}, @@ -327,7 +341,7 @@ func TestEchoVault_EXPIREAT(t *testing.T) { cmd: "EXPIREAT", time: int(mockClock.Now().Add(1000 * time.Second).Unix()), key: "key5", - expireAtOpts: EXPIREATOptions{XX: true}, + expireAtOpts: echovault.EXPIREATOptions{XX: true}, presetValues: map[string]internal.KeyData{ "key5": {Value: "value5", ExpireAt: mockClock.Now().Add(30 * time.Second)}, }, @@ -339,7 +353,7 @@ func TestEchoVault_EXPIREAT(t *testing.T) { cmd: "EXPIREAT", key: "key6", time: int(mockClock.Now().Add(1000 * time.Second).Unix()), - expireAtOpts: EXPIREATOptions{XX: true}, + expireAtOpts: echovault.EXPIREATOptions{XX: true}, presetValues: map[string]internal.KeyData{ "key6": {Value: "value6", ExpireAt: time.Time{}}, }, @@ -351,7 +365,7 @@ func TestEchoVault_EXPIREAT(t *testing.T) { cmd: "EXPIREAT", key: "key7", time: int(mockClock.Now().Add(1000 * time.Second).Unix()), - expireAtOpts: EXPIREATOptions{GT: true}, + expireAtOpts: echovault.EXPIREATOptions{GT: true}, presetValues: map[string]internal.KeyData{ "key7": {Value: "value7", ExpireAt: mockClock.Now().Add(30 * time.Second)}, }, @@ -363,7 +377,7 @@ func TestEchoVault_EXPIREAT(t *testing.T) { cmd: "EXPIREAT", key: "key8", time: int(mockClock.Now().Add(1000 * time.Second).Unix()), - expireAtOpts: EXPIREATOptions{GT: true}, + expireAtOpts: echovault.EXPIREATOptions{GT: true}, presetValues: map[string]internal.KeyData{ "key8": {Value: "value8", ExpireAt: mockClock.Now().Add(3000 * time.Second)}, }, @@ -375,7 +389,7 @@ func TestEchoVault_EXPIREAT(t *testing.T) { cmd: "EXPIREAT", key: "key9", time: int(mockClock.Now().Add(1000 * time.Second).Unix()), - expireAtOpts: EXPIREATOptions{GT: true}, + expireAtOpts: echovault.EXPIREATOptions{GT: true}, presetValues: map[string]internal.KeyData{ "key9": {Value: "value9", ExpireAt: time.Time{}}, }, @@ -386,7 +400,7 @@ func TestEchoVault_EXPIREAT(t *testing.T) { cmd: "EXPIREAT", key: "key10", time: int(mockClock.Now().Add(1000 * time.Second).Unix()), - expireAtOpts: EXPIREATOptions{LT: true}, + expireAtOpts: echovault.EXPIREATOptions{LT: true}, presetValues: map[string]internal.KeyData{ "key10": {Value: "value10", ExpireAt: mockClock.Now().Add(3000 * time.Second)}, }, @@ -398,7 +412,7 @@ func TestEchoVault_EXPIREAT(t *testing.T) { cmd: "EXPIREAT", key: "key11", time: int(mockClock.Now().Add(3000 * time.Second).Unix()), - expireAtOpts: EXPIREATOptions{LT: true}, + expireAtOpts: echovault.EXPIREATOptions{LT: true}, presetValues: map[string]internal.KeyData{ "key11": {Value: "value11", ExpireAt: mockClock.Now().Add(1000 * time.Second)}, }, @@ -410,7 +424,7 @@ func TestEchoVault_EXPIREAT(t *testing.T) { cmd: "EXPIREAT", key: "key12", time: int(mockClock.Now().Add(1000 * time.Second).Unix()), - expireAtOpts: EXPIREATOptions{LT: true}, + expireAtOpts: echovault.EXPIREATOptions{LT: true}, presetValues: map[string]internal.KeyData{ "key12": {Value: "value12", ExpireAt: time.Time{}}, }, @@ -422,7 +436,7 @@ func TestEchoVault_EXPIREAT(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.presetValues != nil { for k, d := range tt.presetValues { - presetKeyData(server, k, d) + presetKeyData(server, context.Background(), k, d) } } var got int @@ -446,12 +460,7 @@ func TestEchoVault_EXPIREAT(t *testing.T) { func TestEchoVault_EXPIRETIME(t *testing.T) { mockClock := clock.NewClock() - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -503,7 +512,7 @@ func TestEchoVault_EXPIRETIME(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.presetValues != nil { for k, d := range tt.presetValues { - presetKeyData(server, k, d) + presetKeyData(server, context.Background(), k, d) } } got, err := tt.expiretimeFunc(tt.key) @@ -519,12 +528,7 @@ func TestEchoVault_EXPIRETIME(t *testing.T) { } func TestEchoVault_GET(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -551,7 +555,11 @@ func TestEchoVault_GET(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.presetValue != nil { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.GET(tt.key) if (err != nil) != tt.wantErr { @@ -566,12 +574,7 @@ func TestEchoVault_GET(t *testing.T) { } func TestEchoVault_MGET(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -599,7 +602,11 @@ func TestEchoVault_MGET(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.presetValues != nil { for k, v := range tt.presetValues { - presetValue(server, k, v) + err := presetValue(server, context.Background(), k, v) + if err != nil { + t.Error(err) + return + } } } got, err := server.MGET(tt.keys...) @@ -625,19 +632,14 @@ func TestEchoVault_MGET(t *testing.T) { func TestEchoVault_SET(t *testing.T) { mockClock := clock.NewClock() - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string presetValues map[string]internal.KeyData key string value string - options SETOptions + options echovault.SETOptions want string wantErr bool }{ @@ -646,7 +648,7 @@ func TestEchoVault_SET(t *testing.T) { presetValues: nil, key: "key1", value: "value1", - options: SETOptions{}, + options: echovault.SETOptions{}, want: "OK", wantErr: false, }, @@ -655,7 +657,7 @@ func TestEchoVault_SET(t *testing.T) { presetValues: nil, key: "key2", value: "value2", - options: SETOptions{NX: true}, + options: echovault.SETOptions{NX: true}, want: "OK", wantErr: false, }, @@ -669,7 +671,7 @@ func TestEchoVault_SET(t *testing.T) { }, key: "key3", value: "value3", - options: SETOptions{NX: true}, + options: echovault.SETOptions{NX: true}, want: "", wantErr: true, }, @@ -683,7 +685,7 @@ func TestEchoVault_SET(t *testing.T) { }, key: "key4", value: "value4", - options: SETOptions{XX: true}, + options: echovault.SETOptions{XX: true}, want: "OK", wantErr: false, }, @@ -692,7 +694,7 @@ func TestEchoVault_SET(t *testing.T) { presetValues: nil, key: "key5", value: "value5", - options: SETOptions{XX: true}, + options: echovault.SETOptions{XX: true}, want: "", wantErr: true, }, @@ -701,7 +703,7 @@ func TestEchoVault_SET(t *testing.T) { presetValues: nil, key: "key6", value: "value6", - options: SETOptions{EX: 100}, + options: echovault.SETOptions{EX: 100}, want: "OK", wantErr: false, }, @@ -710,7 +712,7 @@ func TestEchoVault_SET(t *testing.T) { presetValues: nil, key: "key7", value: "value7", - options: SETOptions{PX: 4096}, + options: echovault.SETOptions{PX: 4096}, want: "OK", wantErr: false, }, @@ -719,7 +721,7 @@ func TestEchoVault_SET(t *testing.T) { presetValues: nil, key: "key8", value: "value8", - options: SETOptions{EXAT: int(mockClock.Now().Add(200 * time.Second).Unix())}, + options: echovault.SETOptions{EXAT: int(mockClock.Now().Add(200 * time.Second).Unix())}, want: "OK", wantErr: false, }, @@ -727,7 +729,7 @@ func TestEchoVault_SET(t *testing.T) { name: "Set exact expiry time in milliseconds from unix epoch", key: "key9", value: "value9", - options: SETOptions{PXAT: int(mockClock.Now().Add(4096 * time.Millisecond).UnixMilli())}, + options: echovault.SETOptions{PXAT: int(mockClock.Now().Add(4096 * time.Millisecond).UnixMilli())}, presetValues: nil, want: "OK", wantErr: false, @@ -742,7 +744,7 @@ func TestEchoVault_SET(t *testing.T) { }, key: "key10", value: "value10", - options: SETOptions{GET: true, EX: 1000}, + options: echovault.SETOptions{GET: true, EX: 1000}, want: "previous-value", wantErr: false, }, @@ -751,7 +753,7 @@ func TestEchoVault_SET(t *testing.T) { presetValues: nil, key: "key11", value: "value11", - options: SETOptions{GET: true, EX: 1000}, + options: echovault.SETOptions{GET: true, EX: 1000}, want: "", wantErr: false, }, @@ -760,7 +762,7 @@ func TestEchoVault_SET(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.presetValues != nil { for k, d := range tt.presetValues { - presetKeyData(server, k, d) + presetKeyData(server, context.Background(), k, d) } } got, err := server.SET(tt.key, tt.value, tt.options) @@ -776,12 +778,7 @@ func TestEchoVault_SET(t *testing.T) { } func TestEchoVault_MSET(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -813,12 +810,7 @@ func TestEchoVault_MSET(t *testing.T) { func TestEchoVault_PERSIST(t *testing.T) { mockClock := clock.NewClock() - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -857,7 +849,7 @@ func TestEchoVault_PERSIST(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.presetValues != nil { for k, d := range tt.presetValues { - presetKeyData(server, k, d) + presetKeyData(server, context.Background(), k, d) } } got, err := server.PERSIST(tt.key) @@ -875,12 +867,7 @@ func TestEchoVault_PERSIST(t *testing.T) { func TestEchoVault_TTL(t *testing.T) { mockClock := clock.NewClock() - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -933,7 +920,7 @@ func TestEchoVault_TTL(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.presetValues != nil { for k, d := range tt.presetValues { - presetKeyData(server, k, d) + presetKeyData(server, context.Background(), k, d) } } got, err := tt.ttlFunc(tt.key) diff --git a/pkg/modules/generic/commands_test.go b/test/modules/generic/commands_test.go similarity index 92% rename from pkg/modules/generic/commands_test.go rename to test/modules/generic/commands_test.go index fd64081a..95f012f2 100644 --- a/pkg/modules/generic/commands_test.go +++ b/test/modules/generic/commands_test.go @@ -23,7 +23,11 @@ import ( "github.com/echovault/echovault/internal/config" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/echovault" + "github.com/echovault/echovault/pkg/modules/generic" + "github.com/echovault/echovault/pkg/types" "github.com/tidwall/resp" + "net" + "strings" "testing" "time" ) @@ -41,6 +45,7 @@ func init() { mockClock = clock.NewClock() mockServer, _ = echovault.NewEchoVault( + echovault.WithCommands(generic.Commands()), echovault.WithConfig(config.Config{ DataDir: "", EvictionPolicy: constants.NoEviction, @@ -48,6 +53,47 @@ func init() { ) } +func getHandler(commands ...string) types.HandlerFunc { + if len(commands) == 0 { + return nil + } + for _, c := range mockServer.GetAllCommands() { + if strings.EqualFold(commands[0], c.Command) && len(commands) == 1 { + // Get command handler + return c.HandlerFunc + } + if strings.EqualFold(commands[0], c.Command) { + // Get sub-command handler + for _, sc := range c.SubCommands { + if strings.EqualFold(commands[1], sc.Command) { + return sc.HandlerFunc + } + } + } + } + return nil +} + +func getHandlerFuncParams(ctx context.Context, cmd []string, conn *net.Conn) types.HandlerFuncParams { + return types.HandlerFuncParams{ + Context: ctx, + Command: cmd, + Connection: conn, + KeyExists: mockServer.KeyExists, + CreateKeyAndLock: mockServer.CreateKeyAndLock, + KeyLock: mockServer.KeyLock, + KeyRLock: mockServer.KeyRLock, + KeyUnlock: mockServer.KeyUnlock, + KeyRUnlock: mockServer.KeyRUnlock, + GetValue: mockServer.GetValue, + SetValue: mockServer.SetValue, + GetClock: mockServer.GetClock, + GetExpiry: mockServer.GetExpiry, + SetExpiry: mockServer.SetExpiry, + DeleteKey: mockServer.DeleteKey, + } +} + func Test_HandleSET(t *testing.T) { tests := []struct { name string @@ -372,7 +418,13 @@ func Test_HandleSET(t *testing.T) { } } - res, err := handleSet(ctx, test.command, mockServer, nil) + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedErr != nil { if err == nil { t.Errorf("expected error \"%s\", got nil", test.expectedErr.Error()) @@ -454,7 +506,14 @@ func Test_HandleMSET(t *testing.T) { for i, test := range tests { t.Run(test.name, func(t *testing.T) { ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("MSET, %d", i)) - res, err := handleMSet(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedErr != nil { if err.Error() != test.expectedErr.Error() { t.Errorf("expected error %s, got %s", test.expectedErr.Error(), err.Error()) @@ -547,7 +606,14 @@ func Test_HandleGET(t *testing.T) { } mockServer.KeyUnlock(ctx, key) - res, err := handleGet(ctx, []string{"GET", key}, mockServer, nil) + handler := getHandler("GET") + if handler == nil { + t.Error("no handler found for command GET") + return + } + + res, err := handler(getHandlerFuncParams(ctx, []string{"GET", key}, nil)) + if err != nil { t.Error(err) } @@ -559,7 +625,7 @@ func Test_HandleGET(t *testing.T) { } // Test get non-existent key - res, err := handleGet(context.Background(), []string{"GET", "test4"}, mockServer, nil) + res, err := getHandler("GET")(getHandlerFuncParams(context.Background(), []string{"GET", "test4"}, nil)) if err != nil { t.Error(err) } @@ -585,7 +651,12 @@ func Test_HandleGET(t *testing.T) { } for _, test := range errorTests { t.Run(test.name, func(t *testing.T) { - res, err = handleGet(context.Background(), test.command, mockServer, nil) + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + res, err = handler(getHandlerFuncParams(context.Background(), test.command, nil)) if res != nil { t.Errorf("expected nil response, got: %+v", res) } @@ -631,21 +702,28 @@ func Test_HandleMGET(t *testing.T) { }, } - for _, test := range tests { + for i, test := range tests { t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("MGET, %d", i)) // Set up the values for i, key := range test.presetKeys { - _, err := mockServer.CreateKeyAndLock(context.Background(), key) + _, err := mockServer.CreateKeyAndLock(ctx, key) if err != nil { t.Error(err) } - if err = mockServer.SetValue(context.Background(), key, test.presetValues[i]); err != nil { + if err = mockServer.SetValue(ctx, key, test.presetValues[i]); err != nil { t.Error(err) } - mockServer.KeyUnlock(context.Background(), key) + mockServer.KeyUnlock(ctx, key) } // Test the command and its results - res, err := handleMGet(context.Background(), test.command, mockServer, nil) + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { // If we expect and error, branch out and check error if err.Error() != test.expectedError.Error() { @@ -734,7 +812,13 @@ func Test_HandleDEL(t *testing.T) { } } - res, err := handleDel(ctx, test.command, mockServer, nil) + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedErr != nil { if err == nil { t.Errorf("exected error \"%s\", got nil", test.expectedErr.Error()) @@ -844,7 +928,13 @@ func Test_HandlePERSIST(t *testing.T) { } } - res, err := handlePersist(ctx, test.command, mockServer, nil) + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err == nil { @@ -965,7 +1055,13 @@ func Test_HandleEXPIRETIME(t *testing.T) { } } - res, err := handleExpireTime(ctx, test.command, mockServer, nil) + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err == nil { @@ -1067,7 +1163,13 @@ func Test_HandleTTL(t *testing.T) { } } - res, err := handleTTL(ctx, test.command, mockServer, nil) + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err == nil { @@ -1300,7 +1402,13 @@ func Test_HandleEXPIRE(t *testing.T) { } } - res, err := handleExpire(ctx, test.command, mockServer, nil) + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err == nil { @@ -1576,7 +1684,13 @@ func Test_HandleEXPIREAT(t *testing.T) { } } - res, err := handleExpireAt(ctx, test.command, mockServer, nil) + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err == nil { diff --git a/pkg/echovault/api_hash_test.go b/test/modules/hash/api_hash_test.go similarity index 87% rename from pkg/echovault/api_hash_test.go rename to test/modules/hash/api_hash_test.go index 0aaf7d9b..9ee30f13 100644 --- a/pkg/echovault/api_hash_test.go +++ b/test/modules/hash/api_hash_test.go @@ -12,25 +12,41 @@ // See the License for the specific language governing permissions and // limitations under the License. -package echovault +package hash import ( + "context" "github.com/echovault/echovault/internal/config" - "github.com/echovault/echovault/pkg/commands" - "github.com/echovault/echovault/pkg/constants" + "github.com/echovault/echovault/pkg/echovault" + "github.com/echovault/echovault/pkg/modules/hash" "reflect" "slices" "testing" ) -func TestEchoVault_HDEL(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, +func createEchoVault() *echovault.EchoVault { + ev, _ := echovault.NewEchoVault( + echovault.WithCommands(hash.Commands()), + echovault.WithConfig(config.Config{ + DataDir: "", }), ) + return ev +} + +func presetValue(server *echovault.EchoVault, ctx context.Context, key string, value interface{}) error { + if _, err := server.CreateKeyAndLock(ctx, key); err != nil { + return err + } + if err := server.SetValue(ctx, key, value); err != nil { + return err + } + server.KeyUnlock(ctx, key) + return nil +} + +func TestEchoVault_HDEL(t *testing.T) { + server := createEchoVault() tests := []struct { name string @@ -76,7 +92,11 @@ func TestEchoVault_HDEL(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.presetValue != nil { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.HDEL(tt.key, tt.fields...) if (err != nil) != tt.wantErr { @@ -91,13 +111,7 @@ func TestEchoVault_HDEL(t *testing.T) { } func TestEchoVault_HEXISTS(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -135,7 +149,11 @@ func TestEchoVault_HEXISTS(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.presetValue != nil { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.HEXISTS(tt.key, tt.field) if (err != nil) != tt.wantErr { @@ -150,13 +168,7 @@ func TestEchoVault_HEXISTS(t *testing.T) { } func TestEchoVault_HGETALL(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -190,7 +202,11 @@ func TestEchoVault_HGETALL(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.presetValue != nil { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.HGETALL(tt.key) if (err != nil) != tt.wantErr { @@ -212,13 +228,7 @@ func TestEchoVault_HGETALL(t *testing.T) { } func TestEchoVault_HINCRBY(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() const ( HINCRBY = "HINCRBY" @@ -300,7 +310,11 @@ func TestEchoVault_HINCRBY(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.presetValue != nil { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } var got float64 var err error @@ -326,13 +340,7 @@ func TestEchoVault_HINCRBY(t *testing.T) { } func TestEchoVault_HKEYS(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -366,7 +374,11 @@ func TestEchoVault_HKEYS(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.presetValue != nil { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.HKEYS(tt.key) if (err != nil) != tt.wantErr { @@ -386,13 +398,7 @@ func TestEchoVault_HKEYS(t *testing.T) { } func TestEchoVault_HLEN(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -426,7 +432,11 @@ func TestEchoVault_HLEN(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.presetValue != nil { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.HLEN(tt.key) if (err != nil) != tt.wantErr { @@ -441,19 +451,13 @@ func TestEchoVault_HLEN(t *testing.T) { } func TestEchoVault_HRANDFIELD(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string presetValue interface{} key string - options HRANDFIELDOptions + options echovault.HRANDFIELDOptions wantCount int want []string wantErr bool @@ -462,7 +466,7 @@ func TestEchoVault_HRANDFIELD(t *testing.T) { name: "Get a random field", presetValue: map[string]interface{}{"field1": "value1", "field2": 123456789, "field3": 3.142}, key: "key1", - options: HRANDFIELDOptions{Count: 1}, + options: echovault.HRANDFIELDOptions{Count: 1}, wantCount: 1, want: []string{"field1", "field2", "field3"}, wantErr: false, @@ -471,7 +475,7 @@ func TestEchoVault_HRANDFIELD(t *testing.T) { name: "Get a random field with a value", presetValue: map[string]interface{}{"field1": "value1", "field2": 123456789, "field3": 3.142}, key: "key2", - options: HRANDFIELDOptions{WithValues: true, Count: 1}, + options: echovault.HRANDFIELDOptions{WithValues: true, Count: 1}, wantCount: 2, want: []string{"field1", "value1", "field2", "123456789", "field3", "3.142"}, wantErr: false, @@ -486,7 +490,7 @@ func TestEchoVault_HRANDFIELD(t *testing.T) { "field5": "value5", }, key: "key3", - options: HRANDFIELDOptions{Count: 3}, + options: echovault.HRANDFIELDOptions{Count: 3}, wantCount: 3, want: []string{"field1", "field2", "field3", "field4", "field5"}, wantErr: false, @@ -501,7 +505,7 @@ func TestEchoVault_HRANDFIELD(t *testing.T) { "field5": "value5", }, key: "key4", - options: HRANDFIELDOptions{WithValues: true, Count: 3}, + options: echovault.HRANDFIELDOptions{WithValues: true, Count: 3}, wantCount: 6, want: []string{ "field1", "value1", "field2", "123456789", "field3", @@ -519,7 +523,7 @@ func TestEchoVault_HRANDFIELD(t *testing.T) { "field5": "value5", }, key: "key5", - options: HRANDFIELDOptions{Count: 5}, + options: echovault.HRANDFIELDOptions{Count: 5}, wantCount: 5, want: []string{"field1", "field2", "field3", "field4", "field5"}, wantErr: false, @@ -534,7 +538,7 @@ func TestEchoVault_HRANDFIELD(t *testing.T) { "field5": "value5", }, key: "key5", - options: HRANDFIELDOptions{WithValues: true, Count: 5}, + options: echovault.HRANDFIELDOptions{WithValues: true, Count: 5}, wantCount: 10, want: []string{ "field1", "value1", "field2", "123456789", "field3", @@ -546,7 +550,7 @@ func TestEchoVault_HRANDFIELD(t *testing.T) { name: "Trying to get random field on a non hash map returns error", presetValue: "Default value", key: "key12", - options: HRANDFIELDOptions{}, + options: echovault.HRANDFIELDOptions{}, wantCount: 0, want: nil, wantErr: true, @@ -555,7 +559,11 @@ func TestEchoVault_HRANDFIELD(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.presetValue != nil { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.HRANDFIELD(tt.key, tt.options) if (err != nil) != tt.wantErr { @@ -575,13 +583,7 @@ func TestEchoVault_HRANDFIELD(t *testing.T) { } func TestEchoVault_HSET(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -650,7 +652,11 @@ func TestEchoVault_HSET(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.presetValue != nil { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := tt.hsetFunc(tt.key, tt.fieldValuePairs) if (err != nil) != tt.wantErr { @@ -665,13 +671,7 @@ func TestEchoVault_HSET(t *testing.T) { } func TestEchoVault_HSTRLEN(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -719,7 +719,11 @@ func TestEchoVault_HSTRLEN(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.presetValue != nil { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.HSTRLEN(tt.key, tt.fields...) if (err != nil) != tt.wantErr { @@ -734,13 +738,7 @@ func TestEchoVault_HSTRLEN(t *testing.T) { } func TestEchoVault_HVALS(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -774,7 +772,11 @@ func TestEchoVault_HVALS(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.presetValue != nil { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.HVALS(tt.key) if (err != nil) != tt.wantErr { diff --git a/pkg/modules/hash/commands_test.go b/test/modules/hash/commands_test.go similarity index 92% rename from pkg/modules/hash/commands_test.go rename to test/modules/hash/commands_test.go index 1b9e2ac4..ba7c7fa8 100644 --- a/pkg/modules/hash/commands_test.go +++ b/test/modules/hash/commands_test.go @@ -22,8 +22,12 @@ import ( "github.com/echovault/echovault/internal/config" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/echovault" + "github.com/echovault/echovault/pkg/modules/hash" + "github.com/echovault/echovault/pkg/types" "github.com/tidwall/resp" + "net" "slices" + "strings" "testing" ) @@ -31,6 +35,7 @@ var mockServer *echovault.EchoVault func init() { mockServer, _ = echovault.NewEchoVault( + echovault.WithCommands(hash.Commands()), echovault.WithConfig(config.Config{ DataDir: "", EvictionPolicy: constants.NoEviction, @@ -38,6 +43,43 @@ func init() { ) } +func getHandler(commands ...string) types.HandlerFunc { + if len(commands) == 0 { + return nil + } + for _, c := range mockServer.GetAllCommands() { + if strings.EqualFold(commands[0], c.Command) && len(commands) == 1 { + // Get command handler + return c.HandlerFunc + } + if strings.EqualFold(commands[0], c.Command) { + // Get sub-command handler + for _, sc := range c.SubCommands { + if strings.EqualFold(commands[1], sc.Command) { + return sc.HandlerFunc + } + } + } + } + return nil +} + +func getHandlerFuncParams(ctx context.Context, cmd []string, conn *net.Conn) types.HandlerFuncParams { + return types.HandlerFuncParams{ + Context: ctx, + Command: cmd, + Connection: conn, + KeyExists: mockServer.KeyExists, + CreateKeyAndLock: mockServer.CreateKeyAndLock, + KeyLock: mockServer.KeyLock, + KeyRLock: mockServer.KeyRLock, + KeyUnlock: mockServer.KeyUnlock, + KeyRUnlock: mockServer.KeyRUnlock, + GetValue: mockServer.GetValue, + SetValue: mockServer.SetValue, + } +} + func Test_HandleHSET(t *testing.T) { // Tests for both HSET and HSETNX tests := []struct { @@ -144,7 +186,14 @@ func Test_HandleHSET(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleHSET(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -163,11 +212,11 @@ func Test_HandleHSET(t *testing.T) { if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { t.Error(err) } - hash, ok := mockServer.GetValue(ctx, test.key).(map[string]interface{}) + h, ok := mockServer.GetValue(ctx, test.key).(map[string]interface{}) if !ok { t.Errorf("value at key \"%s\" is not a hash map", test.key) } - for field, value := range hash { + for field, value := range h { if value != test.expectedValue[field] { t.Errorf("expected value \"%+v\" for field \"%+v\", got \"%+v\"", test.expectedValue[field], field, value) } @@ -303,7 +352,14 @@ func Test_HandleHINCRBY(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleHINCRBY(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -331,11 +387,11 @@ func Test_HandleHINCRBY(t *testing.T) { if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { t.Error(err) } - hash, ok := mockServer.GetValue(ctx, test.key).(map[string]interface{}) + h, ok := mockServer.GetValue(ctx, test.key).(map[string]interface{}) if !ok { t.Errorf("value at key \"%s\" is not a hash map", test.key) } - for field, value := range hash { + for field, value := range h { if value != test.expectedValue[field] { t.Errorf("expected value \"%+v\" for field \"%+v\", got \"%+v\"", test.expectedValue[field], field, value) } @@ -410,7 +466,14 @@ func Test_HandleHGET(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleHGET(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -519,7 +582,14 @@ func Test_HandleHSTRLEN(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleHSTRLEN(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -623,7 +693,14 @@ func Test_HandleHVALS(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleHVALS(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -831,7 +908,14 @@ func Test_HandleHRANDFIELD(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleHRANDFIELD(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -954,7 +1038,14 @@ func Test_HandleHLEN(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleHLEN(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -1053,7 +1144,14 @@ func Test_HandleHKeys(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleHKEYS(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -1159,7 +1257,14 @@ func Test_HandleHGETALL(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleHGETALL(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -1276,7 +1381,14 @@ func Test_HandleHEXISTS(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleHEXISTS(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -1375,7 +1487,14 @@ func Test_HandleHDEL(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleHDEL(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -1396,8 +1515,8 @@ func Test_HandleHDEL(t *testing.T) { if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { t.Error(err) } - if hash, ok := mockServer.GetValue(ctx, test.key).(map[string]interface{}); ok { - for field, value := range hash { + if h, ok := mockServer.GetValue(ctx, test.key).(map[string]interface{}); ok { + for field, value := range h { if value != test.expectedValue[field] { t.Errorf("expected value \"%+v\", got \"%+v\"", test.expectedValue[field], value) } diff --git a/pkg/echovault/api_list_test.go b/test/modules/list/api_list_test.go similarity index 91% rename from pkg/echovault/api_list_test.go rename to test/modules/list/api_list_test.go index 22ec6fc0..40181099 100644 --- a/pkg/echovault/api_list_test.go +++ b/test/modules/list/api_list_test.go @@ -12,24 +12,40 @@ // See the License for the specific language governing permissions and // limitations under the License. -package echovault +package list import ( + "context" "github.com/echovault/echovault/internal/config" - "github.com/echovault/echovault/pkg/commands" - "github.com/echovault/echovault/pkg/constants" + "github.com/echovault/echovault/pkg/echovault" + "github.com/echovault/echovault/pkg/modules/list" "reflect" "testing" ) -func TestEchoVault_LLEN(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, +func createEchoVault() *echovault.EchoVault { + ev, _ := echovault.NewEchoVault( + echovault.WithCommands(list.Commands()), + echovault.WithConfig(config.Config{ + DataDir: "", }), ) + return ev +} + +func presetValue(server *echovault.EchoVault, ctx context.Context, key string, value interface{}) error { + if _, err := server.CreateKeyAndLock(ctx, key); err != nil { + return err + } + if err := server.SetValue(ctx, key, value); err != nil { + return err + } + server.KeyUnlock(ctx, key) + return nil +} + +func TestEchoVault_LLEN(t *testing.T) { + server := createEchoVault() tests := []struct { preset bool @@ -67,7 +83,11 @@ func TestEchoVault_LLEN(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.preset { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.LLEN(tt.key) if (err != nil) != tt.wantErr { @@ -82,13 +102,7 @@ func TestEchoVault_LLEN(t *testing.T) { } func TestEchoVault_LINDEX(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { preset bool @@ -156,7 +170,11 @@ func TestEchoVault_LINDEX(t *testing.T) { } for _, tt := range tests { if tt.preset { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } t.Run(tt.name, func(t *testing.T) { got, err := server.LINDEX(tt.key, tt.index) @@ -172,13 +190,7 @@ func TestEchoVault_LINDEX(t *testing.T) { } func TestEchoVault_LMOVE(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -328,7 +340,11 @@ func TestEchoVault_LMOVE(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.preset { for k, v := range tt.presetValue { - presetValue(server, k, v) + err := presetValue(server, context.Background(), k, v) + if err != nil { + t.Error(err) + return + } } } got, err := server.LMOVE(tt.source, tt.destination, tt.whereFrom, tt.whereTo) @@ -344,13 +360,7 @@ func TestEchoVault_LMOVE(t *testing.T) { } func TestEchoVault_POP(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -401,7 +411,11 @@ func TestEchoVault_POP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.preset { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := tt.popFunc(tt.key) if (err != nil) != tt.wantErr { @@ -416,13 +430,7 @@ func TestEchoVault_POP(t *testing.T) { } func TestEchoVault_LPUSH(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -478,7 +486,11 @@ func TestEchoVault_LPUSH(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.preset { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := tt.lpushFunc(tt.key, tt.values...) if (err != nil) != tt.wantErr { @@ -493,13 +505,7 @@ func TestEchoVault_LPUSH(t *testing.T) { } func TestEchoVault_RPUSH(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -535,7 +541,11 @@ func TestEchoVault_RPUSH(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.preset { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := tt.rpushFunc(tt.key, tt.values...) if (err != nil) != tt.wantErr { @@ -550,13 +560,7 @@ func TestEchoVault_RPUSH(t *testing.T) { } func TestEchoVault_LRANGE(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -656,7 +660,11 @@ func TestEchoVault_LRANGE(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.preset { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.LRANGE(tt.key, tt.start, tt.end) if (err != nil) != tt.wantErr { @@ -671,13 +679,7 @@ func TestEchoVault_LRANGE(t *testing.T) { } func TestEchoVault_LREM(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -722,7 +724,11 @@ func TestEchoVault_LREM(t *testing.T) { } for _, tt := range tests { if tt.preset { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } t.Run(tt.name, func(t *testing.T) { got, err := server.LREM(tt.key, tt.count, tt.value) @@ -738,13 +744,7 @@ func TestEchoVault_LREM(t *testing.T) { } func TestEchoVault_LSET(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -830,7 +830,11 @@ func TestEchoVault_LSET(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.preset { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.LSET(tt.key, tt.index, tt.value) if (err != nil) != tt.wantErr { @@ -845,13 +849,7 @@ func TestEchoVault_LSET(t *testing.T) { } func TestEchoVault_LTRIM(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -940,7 +938,11 @@ func TestEchoVault_LTRIM(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.preset { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.LTRIM(tt.key, tt.start, tt.end) if (err != nil) != tt.wantErr { diff --git a/pkg/modules/list/commands_test.go b/test/modules/list/commands_test.go similarity index 90% rename from pkg/modules/list/commands_test.go rename to test/modules/list/commands_test.go index 94ecab10..1074d1b0 100644 --- a/pkg/modules/list/commands_test.go +++ b/test/modules/list/commands_test.go @@ -22,7 +22,11 @@ import ( "github.com/echovault/echovault/internal/config" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/echovault" + "github.com/echovault/echovault/pkg/modules/list" + "github.com/echovault/echovault/pkg/types" "github.com/tidwall/resp" + "net" + "strings" "testing" ) @@ -30,6 +34,7 @@ var mockServer *echovault.EchoVault func init() { mockServer, _ = echovault.NewEchoVault( + echovault.WithCommands(list.Commands()), echovault.WithConfig(config.Config{ DataDir: "", EvictionPolicy: constants.NoEviction, @@ -37,6 +42,43 @@ func init() { ) } +func getHandler(commands ...string) types.HandlerFunc { + if len(commands) == 0 { + return nil + } + for _, c := range mockServer.GetAllCommands() { + if strings.EqualFold(commands[0], c.Command) && len(commands) == 1 { + // Get command handler + return c.HandlerFunc + } + if strings.EqualFold(commands[0], c.Command) { + // Get sub-command handler + for _, sc := range c.SubCommands { + if strings.EqualFold(commands[1], sc.Command) { + return sc.HandlerFunc + } + } + } + } + return nil +} + +func getHandlerFuncParams(ctx context.Context, cmd []string, conn *net.Conn) types.HandlerFuncParams { + return types.HandlerFuncParams{ + Context: ctx, + Command: cmd, + Connection: conn, + KeyExists: mockServer.KeyExists, + CreateKeyAndLock: mockServer.CreateKeyAndLock, + KeyLock: mockServer.KeyLock, + KeyRLock: mockServer.KeyRLock, + KeyUnlock: mockServer.KeyUnlock, + KeyRUnlock: mockServer.KeyRUnlock, + GetValue: mockServer.GetValue, + SetValue: mockServer.SetValue, + } +} + func Test_HandleLLEN(t *testing.T) { tests := []struct { name string @@ -113,7 +155,14 @@ func Test_HandleLLEN(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleLLen(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -258,7 +307,14 @@ func Test_HandleLINDEX(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleLIndex(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -426,7 +482,14 @@ func Test_HandleLRANGE(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleLRange(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -577,7 +640,14 @@ func Test_HandleLSET(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleLSet(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -595,16 +665,16 @@ func Test_HandleLSET(t *testing.T) { if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { t.Error(err) } - list, ok := mockServer.GetValue(ctx, test.key).([]interface{}) + l, ok := mockServer.GetValue(ctx, test.key).([]interface{}) if !ok { t.Error("expected value to be list, got another type") } - if len(list) != len(test.expectedValue) { - t.Errorf("expected list length to be %d, got %d", len(test.expectedValue), len(list)) + if len(l) != len(test.expectedValue) { + t.Errorf("expected list length to be %d, got %d", len(test.expectedValue), len(l)) } - for i := 0; i < len(list); i++ { - if list[i] != test.expectedValue[i] { - t.Errorf("expected element at index %d to be %+v, got %+v", i, test.expectedValue[i], list[i]) + for i := 0; i < len(l); i++ { + if l[i] != test.expectedValue[i] { + t.Errorf("expected element at index %d to be %+v, got %+v", i, test.expectedValue[i], l[i]) } } mockServer.KeyRUnlock(ctx, test.key) @@ -751,7 +821,14 @@ func Test_HandleLTRIM(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleLTrim(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -769,16 +846,16 @@ func Test_HandleLTRIM(t *testing.T) { if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { t.Error(err) } - list, ok := mockServer.GetValue(ctx, test.key).([]interface{}) + l, ok := mockServer.GetValue(ctx, test.key).([]interface{}) if !ok { t.Error("expected value to be list, got another type") } - if len(list) != len(test.expectedValue) { - t.Errorf("expected list length to be %d, got %d", len(test.expectedValue), len(list)) + if len(l) != len(test.expectedValue) { + t.Errorf("expected list length to be %d, got %d", len(test.expectedValue), len(l)) } - for i := 0; i < len(list); i++ { - if list[i] != test.expectedValue[i] { - t.Errorf("expected element at index %d to be %+v, got %+v", i, test.expectedValue[i], list[i]) + for i := 0; i < len(l); i++ { + if l[i] != test.expectedValue[i] { + t.Errorf("expected element at index %d to be %+v, got %+v", i, test.expectedValue[i], l[i]) } } mockServer.KeyRUnlock(ctx, test.key) @@ -882,7 +959,14 @@ func Test_HandleLREM(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleLRem(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -900,16 +984,16 @@ func Test_HandleLREM(t *testing.T) { if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { t.Error(err) } - list, ok := mockServer.GetValue(ctx, test.key).([]interface{}) + l, ok := mockServer.GetValue(ctx, test.key).([]interface{}) if !ok { t.Error("expected value to be list, got another type") } - if len(list) != len(test.expectedValue) { - t.Errorf("expected list length to be %d, got %d", len(test.expectedValue), len(list)) + if len(l) != len(test.expectedValue) { + t.Errorf("expected list length to be %d, got %d", len(test.expectedValue), len(l)) } - for i := 0; i < len(list); i++ { - if list[i] != test.expectedValue[i] { - t.Errorf("expected element at index %d to be %+v, got %+v", i, test.expectedValue[i], list[i]) + for i := 0; i < len(l); i++ { + if l[i] != test.expectedValue[i] { + t.Errorf("expected element at index %d to be %+v, got %+v", i, test.expectedValue[i], l[i]) } } mockServer.KeyRUnlock(ctx, test.key) @@ -1096,7 +1180,14 @@ func Test_HandleLMOVE(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleLMove(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -1115,7 +1206,7 @@ func Test_HandleLMOVE(t *testing.T) { if _, err = mockServer.KeyRLock(ctx, key); err != nil { t.Error(err) } - list, ok := mockServer.GetValue(ctx, key).([]interface{}) + l, ok := mockServer.GetValue(ctx, key).([]interface{}) if !ok { t.Error("expected value to be list, got another type") } @@ -1123,12 +1214,12 @@ func Test_HandleLMOVE(t *testing.T) { if !ok { t.Error("expected test value to be list, got another type") } - if len(list) != len(expectedList) { - t.Errorf("expected list length to be %d, got %d", len(expectedList), len(list)) + if len(l) != len(expectedList) { + t.Errorf("expected list length to be %d, got %d", len(expectedList), len(l)) } - for i := 0; i < len(list); i++ { - if list[i] != expectedList[i] { - t.Errorf("expected element at index %d to be %+v, got %+v", i, expectedList[i], list[i]) + for i := 0; i < len(l); i++ { + if l[i] != expectedList[i] { + t.Errorf("expected element at index %d to be %+v, got %+v", i, expectedList[i], l[i]) } } mockServer.KeyRUnlock(ctx, key) @@ -1213,7 +1304,14 @@ func Test_HandleLPUSH(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleLPush(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -1231,16 +1329,16 @@ func Test_HandleLPUSH(t *testing.T) { if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { t.Error(err) } - list, ok := mockServer.GetValue(ctx, test.key).([]interface{}) + l, ok := mockServer.GetValue(ctx, test.key).([]interface{}) if !ok { t.Error("expected value to be list, got another type") } - if len(list) != len(test.expectedValue) { - t.Errorf("expected list length to be %d, got %d", len(test.expectedValue), len(list)) + if len(l) != len(test.expectedValue) { + t.Errorf("expected list length to be %d, got %d", len(test.expectedValue), len(l)) } - for i := 0; i < len(list); i++ { - if list[i] != test.expectedValue[i] { - t.Errorf("expected element at index %d to be %+v, got %+v", i, test.expectedValue[i], list[i]) + for i := 0; i < len(l); i++ { + if l[i] != test.expectedValue[i] { + t.Errorf("expected element at index %d to be %+v, got %+v", i, test.expectedValue[i], l[i]) } } mockServer.KeyRUnlock(ctx, test.key) @@ -1324,7 +1422,14 @@ func Test_HandleRPUSH(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleRPush(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -1342,16 +1447,16 @@ func Test_HandleRPUSH(t *testing.T) { if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { t.Error(err) } - list, ok := mockServer.GetValue(ctx, test.key).([]interface{}) + l, ok := mockServer.GetValue(ctx, test.key).([]interface{}) if !ok { t.Error("expected value to be list, got another type") } - if len(list) != len(test.expectedValue) { - t.Errorf("expected list length to be %d, got %d", len(test.expectedValue), len(list)) + if len(l) != len(test.expectedValue) { + t.Errorf("expected list length to be %d, got %d", len(test.expectedValue), len(l)) } - for i := 0; i < len(list); i++ { - if list[i] != test.expectedValue[i] { - t.Errorf("expected element at index %d to be %+v, got %+v", i, test.expectedValue[i], list[i]) + for i := 0; i < len(l); i++ { + if l[i] != test.expectedValue[i] { + t.Errorf("expected element at index %d to be %+v, got %+v", i, test.expectedValue[i], l[i]) } } mockServer.KeyRUnlock(ctx, test.key) @@ -1445,7 +1550,14 @@ func Test_HandlePOP(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handlePop(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -1463,16 +1575,16 @@ func Test_HandlePOP(t *testing.T) { if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { t.Error(err) } - list, ok := mockServer.GetValue(ctx, test.key).([]interface{}) + l, ok := mockServer.GetValue(ctx, test.key).([]interface{}) if !ok { t.Error("expected value to be list, got another type") } - if len(list) != len(test.expectedValue) { - t.Errorf("expected list length to be %d, got %d", len(test.expectedValue), len(list)) + if len(l) != len(test.expectedValue) { + t.Errorf("expected list length to be %d, got %d", len(test.expectedValue), len(l)) } - for i := 0; i < len(list); i++ { - if list[i] != test.expectedValue[i] { - t.Errorf("expected element at index %d to be %+v, got %+v", i, test.expectedValue[i], list[i]) + for i := 0; i < len(l); i++ { + if l[i] != test.expectedValue[i] { + t.Errorf("expected element at index %d to be %+v, got %+v", i, test.expectedValue[i], l[i]) } } mockServer.KeyRUnlock(ctx, test.key) diff --git a/pkg/echovault/api_pubsub_test.go b/test/modules/pubsub/api_pubsub_test.go similarity index 97% rename from pkg/echovault/api_pubsub_test.go rename to test/modules/pubsub/api_pubsub_test.go index afd234ac..5a6d9c1c 100644 --- a/pkg/echovault/api_pubsub_test.go +++ b/test/modules/pubsub/api_pubsub_test.go @@ -12,4 +12,4 @@ // See the License for the specific language governing permissions and // limitations under the License. -package echovault +package pubsub diff --git a/pkg/modules/pubsub/commands_test.go b/test/modules/pubsub/commands_test.go similarity index 85% rename from pkg/modules/pubsub/commands_test.go rename to test/modules/pubsub/commands_test.go index 03ca8a73..07ea3b25 100644 --- a/pkg/modules/pubsub/commands_test.go +++ b/test/modules/pubsub/commands_test.go @@ -22,9 +22,12 @@ import ( internal_pubsub "github.com/echovault/echovault/internal/pubsub" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/echovault" + ps "github.com/echovault/echovault/pkg/modules/pubsub" + "github.com/echovault/echovault/pkg/types" "github.com/tidwall/resp" "net" "slices" + "strings" "sync" "testing" "time" @@ -51,7 +54,7 @@ func init() { func setUpServer(bindAddr string, port uint16) *echovault.EchoVault { server, _ := echovault.NewEchoVault( - echovault.WithCommands(Commands()), + echovault.WithCommands(ps.Commands()), echovault.WithConfig(config.Config{ BindAddr: bindAddr, Port: port, @@ -62,6 +65,36 @@ func setUpServer(bindAddr string, port uint16) *echovault.EchoVault { return server } +func getHandler(commands ...string) types.HandlerFunc { + if len(commands) == 0 { + return nil + } + for _, c := range mockServer.GetAllCommands() { + if strings.EqualFold(commands[0], c.Command) && len(commands) == 1 { + // Get command handler + return c.HandlerFunc + } + if strings.EqualFold(commands[0], c.Command) { + // Get sub-command handler + for _, sc := range c.SubCommands { + if strings.EqualFold(commands[1], sc.Command) { + return sc.HandlerFunc + } + } + } + } + return nil +} + +func getHandlerFuncParams(ctx context.Context, cmd []string, conn *net.Conn, mockServer *echovault.EchoVault) types.HandlerFuncParams { + return types.HandlerFuncParams{ + Context: ctx, + Command: cmd, + Connection: conn, + GetPubSub: mockServer.GetPubSub, + } +} + func Test_HandleSubscribe(t *testing.T) { ctx := context.WithValue(context.Background(), "test_name", "SUBSCRIBE/PSUBSCRIBE") @@ -86,7 +119,8 @@ func Test_HandleSubscribe(t *testing.T) { // Test subscribe to channels channels := []string{"sub_channel1", "sub_channel2", "sub_channel3"} for _, conn := range connections { - if _, err := handleSubscribe(ctx, append([]string{"SUBSCRIBE"}, channels...), mockServer, conn); err != nil { + _, err := getHandler("SUBSCRIBE")(getHandlerFuncParams(ctx, append([]string{"SUBSCRIBE"}, channels...), conn, mockServer)) + if err != nil { t.Error(err) } } @@ -116,7 +150,8 @@ func Test_HandleSubscribe(t *testing.T) { // Test subscribe to patterns patterns := []string{"psub_channel*"} for _, conn := range connections { - if _, err := handleSubscribe(ctx, append([]string{"PSUBSCRIBE"}, patterns...), mockServer, conn); err != nil { + _, err := getHandler("PSUBSCRIBE")(getHandlerFuncParams(ctx, append([]string{"PSUBSCRIBE"}, patterns...), conn, mockServer)) + if err != nil { t.Error(err) } } @@ -263,24 +298,24 @@ func Test_HandleUnsubscribe(t *testing.T) { // Subscribe all the connections to the channels and patterns for _, conn := range append(test.otherConnections, test.targetConn) { - _, err := handleSubscribe(ctx, append([]string{"SUBSCRIBE"}, test.subChannels...), mockServer, conn) + _, err := getHandler("SUBSCRIBE")(getHandlerFuncParams(ctx, append([]string{"SUBSCRIBE"}, test.subChannels...), conn, mockServer)) if err != nil { t.Error(err) } - _, err = handleSubscribe(ctx, append([]string{"PSUBSCRIBE"}, test.subPatterns...), mockServer, conn) + _, err = getHandler("PSUBSCRIBE")(getHandlerFuncParams(ctx, append([]string{"PSUBSCRIBE"}, test.subPatterns...), conn, mockServer)) if err != nil { t.Error(err) } } // Unsubscribe the target connection from the unsub channels and patterns - res, err := handleUnsubscribe(ctx, append([]string{"UNSUBSCRIBE"}, test.unSubChannels...), mockServer, test.targetConn) + res, err := getHandler("UNSUBSCRIBE")(getHandlerFuncParams(ctx, append([]string{"UNSUBSCRIBE"}, test.unSubChannels...), test.targetConn, mockServer)) if err != nil { t.Error(err) } verifyResponse(res, test.expectedResponses["channel"]) - res, err = handleUnsubscribe(ctx, append([]string{"PUNSUBSCRIBE"}, test.unSubPatterns...), mockServer, test.targetConn) + res, err = getHandler("PUNSUBSCRIBE")(getHandlerFuncParams(ctx, append([]string{"PUNSUBSCRIBE"}, test.unSubPatterns...), test.targetConn, mockServer)) if err != nil { t.Error(err) } @@ -347,7 +382,7 @@ func Test_HandlePublish(t *testing.T) { subscribe := func(ctx context.Context, channels []string, patterns []string, c *net.Conn, r *resp.Conn) { // Subscribe to channels go func() { - _, _ = handleSubscribe(ctx, append([]string{"SUBSCRIBE"}, channels...), mockServer, c) + _, _ = getHandler("SUBSCRIBE")(getHandlerFuncParams(ctx, append([]string{"SUBSCRIBE"}, channels...), c, mockServer)) }() // Verify all the responses for each channel subscription for i := 0; i < len(channels); i++ { @@ -355,7 +390,7 @@ func Test_HandlePublish(t *testing.T) { } // Subscribe to all the patterns go func() { - _, _ = handleSubscribe(ctx, append([]string{"PSUBSCRIBE"}, patterns...), mockServer, c) + _, _ = getHandler("PSUBSCRIBE")(getHandlerFuncParams(ctx, append([]string{"PSUBSCRIBE"}, patterns...), c, mockServer)) }() // Verify all the responses for each pattern subscription for i := 0; i < len(patterns); i++ { @@ -518,7 +553,7 @@ func Test_HandlePubSubChannels(t *testing.T) { // Subscribe connections to channels go func() { - _, err := handleSubscribe(ctx, append([]string{"SUBSCRIBE"}, channels...), mockServer, &wConn1) + _, err := getHandler("SUBSCRIBE")(getHandlerFuncParams(ctx, append([]string{"SUBSCRIBE"}, channels...), &wConn1, mockServer)) if err != nil { t.Error(err) } @@ -535,7 +570,7 @@ func Test_HandlePubSubChannels(t *testing.T) { } } go func() { - _, err := handleSubscribe(ctx, append([]string{"PSUBSCRIBE"}, patterns...), mockServer, &wConn2) + _, err := getHandler("PSUBSCRIBE")(getHandlerFuncParams(ctx, append([]string{"PSUBSCRIBE"}, patterns...), &wConn2, mockServer)) if err != nil { t.Error(err) } @@ -571,7 +606,7 @@ func Test_HandlePubSubChannels(t *testing.T) { } // Check if all subscriptions are returned - res, err := handlePubSubChannels(ctx, []string{"PUBSUB", "CHANNELS"}, mockServer, nil) + res, err := getHandler("PUBSUB", "CHANNELS")(getHandlerFuncParams(ctx, []string{"PUBSUB", "CHANNELS"}, nil, mockServer)) if err != nil { t.Error(err) } @@ -579,45 +614,45 @@ func Test_HandlePubSubChannels(t *testing.T) { // Unsubscribe from one pattern and one channel before checking against a new slice of // expected channels/patterns in the response of the "PUBSUB CHANNELS" command - _, err = handleUnsubscribe( + _, err = getHandler("UNSUBSCRIBE")(getHandlerFuncParams( ctx, append([]string{"UNSUBSCRIBE"}, []string{"channel_2", "channel_3"}...), - mockServer, &wConn1, - ) + mockServer, + )) if err != nil { t.Error(err) } - _, err = handleUnsubscribe( + _, err = getHandler("UNSUBSCRIBE")(getHandlerFuncParams( ctx, append([]string{"UNSUBSCRIBE"}, "channel_[456]"), - mockServer, &wConn2, - ) + mockServer, + )) if err != nil { t.Error(err) } // Return all the remaining channels - res, err = handlePubSubChannels(ctx, []string{"PUBSUB", "CHANNELS"}, mockServer, nil) + res, err = getHandler("PUBSUB", "CHANNELS")(getHandlerFuncParams(ctx, []string{"PUBSUB", "CHANNELS"}, nil, mockServer)) if err != nil { t.Error(err) } verifyExpectedResponse(res, []string{"channel_1", "channel_[123]"}) // Return only one of the remaining channels when passed a pattern that matches it - res, err = handlePubSubChannels(ctx, []string{"PUBSUB", "CHANNELS", "channel_[189]"}, mockServer, nil) + res, err = getHandler("PUBSUB", "CHANNELS")(getHandlerFuncParams(ctx, []string{"PUBSUB", "CHANNELS", "channel_[189]"}, nil, mockServer)) if err != nil { t.Error(err) } verifyExpectedResponse(res, []string{"channel_1"}) // Return both remaining channels when passed a pattern that matches them - res, err = handlePubSubChannels(ctx, []string{"PUBSUB", "CHANNELS", "channel_[123]"}, mockServer, nil) + res, err = getHandler("PUBSUB", "CHANNELS")(getHandlerFuncParams(ctx, []string{"PUBSUB", "CHANNELS", "channel_[123]"}, nil, mockServer)) if err != nil { t.Error(err) } verifyExpectedResponse(res, []string{"channel_1", "channel_[123]"}) // Return none channels when passed a pattern that does not match either channel - res, err = handlePubSubChannels(ctx, []string{"PUBSUB", "CHANNELS", "channel_[456]"}, mockServer, nil) + res, err = getHandler("PUBSUB", "CHANNELS")(getHandlerFuncParams(ctx, []string{"PUBSUB", "CHANNELS", "channel_[456]"}, nil, mockServer)) if err != nil { t.Error(err) } @@ -655,7 +690,8 @@ func Test_HandleNumPat(t *testing.T) { r *resp.Conn }{w: &w, r: resp.NewConn(r)} go func() { - if _, err := handleSubscribe(ctx, append([]string{"PSUBSCRIBE"}, patterns...), mockServer, &w); err != nil { + _, err := getHandler("PSUBSCRIBE")(getHandlerFuncParams(ctx, append([]string{"PSUBSCRIBE"}, patterns...), &w, mockServer)) + if err != nil { t.Error(err) } }() @@ -685,7 +721,7 @@ func Test_HandleNumPat(t *testing.T) { } // Check that we receive all the patterns with NUMPAT commands - res, err := handlePubSubNumPat(ctx, []string{"PUBSUB", "NUMPAT"}, mockServer, nil) + res, err := getHandler("PUBSUB", "NUMPAT")(getHandlerFuncParams(ctx, []string{"PUBSUB", "NUMPAT"}, nil, mockServer)) if err != nil { t.Error(err) } @@ -693,12 +729,12 @@ func Test_HandleNumPat(t *testing.T) { // Unsubscribe from a channel and check if the number of active channels is updated for _, conn := range connections { - _, err = handleUnsubscribe(ctx, []string{"PUNSUBSCRIBE", patterns[0]}, mockServer, conn.w) + _, err = getHandler("PUNSUBSCRIBE")(getHandlerFuncParams(ctx, []string{"PUNSUBSCRIBE", patterns[0]}, conn.w, mockServer)) if err != nil { t.Error(err) } } - res, err = handlePubSubNumPat(ctx, []string{"PUBSUB", "NUMPAT"}, mockServer, nil) + res, err = getHandler("PUBSUB", "NUMPAT")(getHandlerFuncParams(ctx, []string{"PUBSUB", "NUMPAT"}, nil, mockServer)) if err != nil { t.Error(err) } @@ -706,12 +742,12 @@ func Test_HandleNumPat(t *testing.T) { // Unsubscribe from all the channels and check if we get a 0 response for _, conn := range connections { - _, err = handleUnsubscribe(ctx, []string{"PUNSUBSCRIBE"}, mockServer, conn.w) + _, err = getHandler("PUNSUBSCRIBE")(getHandlerFuncParams(ctx, []string{"PUNSUBSCRIBE"}, conn.w, mockServer)) if err != nil { t.Error(err) } } - res, err = handlePubSubNumPat(ctx, []string{"PUBSUB", "NUMPAT"}, mockServer, nil) + res, err = getHandler("PUBSUB", "NUMPAT")(getHandlerFuncParams(ctx, []string{"PUBSUB", "NUMPAT"}, nil, mockServer)) if err != nil { t.Error(err) } @@ -748,7 +784,8 @@ func Test_HandleNumSub(t *testing.T) { r *resp.Conn }{w: &w, r: resp.NewConn(r)} go func() { - if _, err := handleSubscribe(ctx, append([]string{"SUBSCRIBE"}, channels...), mockServer, &w); err != nil { + _, err := getHandler("SUBSCRIBE")(getHandlerFuncParams(ctx, append([]string{"SUBSCRIBE"}, channels...), &w, mockServer)) + if err != nil { t.Error(err) } }() @@ -793,7 +830,7 @@ func Test_HandleNumSub(t *testing.T) { for i, test := range tests { ctx = context.WithValue(ctx, "test_index", i) - res, err := handlePubSubNumSubs(ctx, test.cmd, mockServer, nil) + res, err := getHandler("PUBSUB", "NUMSUB")(getHandlerFuncParams(ctx, test.cmd, nil, mockServer)) if err != nil { t.Error(err) } diff --git a/pkg/echovault/api_set_test.go b/test/modules/set/api_set_test.go similarity index 90% rename from pkg/echovault/api_set_test.go rename to test/modules/set/api_set_test.go index 36f25a18..491eb8b9 100644 --- a/pkg/echovault/api_set_test.go +++ b/test/modules/set/api_set_test.go @@ -12,26 +12,42 @@ // See the License for the specific language governing permissions and // limitations under the License. -package echovault +package set import ( + "context" "github.com/echovault/echovault/internal/config" "github.com/echovault/echovault/internal/set" - "github.com/echovault/echovault/pkg/commands" - "github.com/echovault/echovault/pkg/constants" + "github.com/echovault/echovault/pkg/echovault" + s "github.com/echovault/echovault/pkg/modules/set" "reflect" "slices" "testing" ) -func TestEchoVault_SADD(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, +func createEchoVault() *echovault.EchoVault { + ev, _ := echovault.NewEchoVault( + echovault.WithCommands(s.Commands()), + echovault.WithConfig(config.Config{ + DataDir: "", }), ) + return ev +} + +func presetValue(server *echovault.EchoVault, ctx context.Context, key string, value interface{}) error { + if _, err := server.CreateKeyAndLock(ctx, key); err != nil { + return err + } + if err := server.SetValue(ctx, key, value); err != nil { + return err + } + server.KeyUnlock(ctx, key) + return nil +} + +func TestEchoVault_SADD(t *testing.T) { + server := createEchoVault() tests := []struct { name string @@ -69,7 +85,11 @@ func TestEchoVault_SADD(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.presetValue != nil { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.SADD(tt.key, tt.members...) if (err != nil) != tt.wantErr { @@ -84,13 +104,7 @@ func TestEchoVault_SADD(t *testing.T) { } func TestEchoVault_SCARD(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -124,7 +138,11 @@ func TestEchoVault_SCARD(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.presetValue != nil { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.SCARD(tt.key) if (err != nil) != tt.wantErr { @@ -139,13 +157,7 @@ func TestEchoVault_SCARD(t *testing.T) { } func TestEchoVault_SDIFF(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -212,7 +224,11 @@ func TestEchoVault_SDIFF(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.presetValues != nil { for k, v := range tt.presetValues { - presetValue(server, k, v) + err := presetValue(server, context.Background(), k, v) + if err != nil { + t.Error(err) + return + } } } got, err := server.SDIFF(tt.keys...) @@ -233,13 +249,7 @@ func TestEchoVault_SDIFF(t *testing.T) { } func TestEchoVault_SDIFFSTORE(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -312,7 +322,11 @@ func TestEchoVault_SDIFFSTORE(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.presetValues != nil { for k, v := range tt.presetValues { - presetValue(server, k, v) + err := presetValue(server, context.Background(), k, v) + if err != nil { + t.Error(err) + return + } } } got, err := server.SDIFFSTORE(tt.destination, tt.keys...) @@ -328,13 +342,7 @@ func TestEchoVault_SDIFFSTORE(t *testing.T) { } func TestEchoVault_SINTER(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -401,7 +409,11 @@ func TestEchoVault_SINTER(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.presetValues != nil { for k, v := range tt.presetValues { - presetValue(server, k, v) + err := presetValue(server, context.Background(), k, v) + if err != nil { + t.Error(err) + return + } } } got, err := server.SINTER(tt.keys...) @@ -422,13 +434,7 @@ func TestEchoVault_SINTER(t *testing.T) { } func TestEchoVault_SINTERCARD(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -512,7 +518,11 @@ func TestEchoVault_SINTERCARD(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.presetValues != nil { for k, v := range tt.presetValues { - presetValue(server, k, v) + err := presetValue(server, context.Background(), k, v) + if err != nil { + t.Error(err) + return + } } } got, err := server.SINTERCARD(tt.keys, tt.limit) @@ -528,13 +538,7 @@ func TestEchoVault_SINTERCARD(t *testing.T) { } func TestEchoVault_SINTERSTORE(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -607,7 +611,11 @@ func TestEchoVault_SINTERSTORE(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.presetValues != nil { for k, v := range tt.presetValues { - presetValue(server, k, v) + err := presetValue(server, context.Background(), k, v) + if err != nil { + t.Error(err) + return + } } } got, err := server.SINTERSTORE(tt.destination, tt.keys...) @@ -623,13 +631,7 @@ func TestEchoVault_SINTERSTORE(t *testing.T) { } func TestEchoVault_SISMEMBER(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -667,7 +669,11 @@ func TestEchoVault_SISMEMBER(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.presetValue != nil { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.SISMEMBER(tt.key, tt.member) if (err != nil) != tt.wantErr { @@ -682,13 +688,7 @@ func TestEchoVault_SISMEMBER(t *testing.T) { } func TestEchoVault_SMEMBERS(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -722,7 +722,11 @@ func TestEchoVault_SMEMBERS(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.presetValue != nil { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.SMEMBERS(tt.key) if (err != nil) != tt.wantErr { @@ -742,13 +746,7 @@ func TestEchoVault_SMEMBERS(t *testing.T) { } func TestEchoVault_SMISMEMBER(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -805,7 +803,11 @@ func TestEchoVault_SMISMEMBER(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.presetValue != nil { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.SMISMEMBER(tt.key, tt.members...) if (err != nil) != tt.wantErr { @@ -820,13 +822,7 @@ func TestEchoVault_SMISMEMBER(t *testing.T) { } func TestEchoVault_SMOVE(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -890,7 +886,11 @@ func TestEchoVault_SMOVE(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.presetValues != nil { for k, v := range tt.presetValues { - presetValue(server, k, v) + err := presetValue(server, context.Background(), k, v) + if err != nil { + t.Error(err) + return + } } } got, err := server.SMOVE(tt.source, tt.destination, tt.member) @@ -906,13 +906,7 @@ func TestEchoVault_SMOVE(t *testing.T) { } func TestEchoVault_SPOP(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -942,7 +936,11 @@ func TestEchoVault_SPOP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.presetValue != nil { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.SPOP(tt.key, tt.count) if (err != nil) != tt.wantErr { @@ -959,13 +957,7 @@ func TestEchoVault_SPOP(t *testing.T) { } func TestEchoVault_SRANDMEMBER(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -1007,7 +999,11 @@ func TestEchoVault_SRANDMEMBER(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.presetValue != nil { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.SRANDMEMBER(tt.key, tt.count) if (err != nil) != tt.wantErr { @@ -1028,13 +1024,7 @@ func TestEchoVault_SRANDMEMBER(t *testing.T) { } func TestEchoVault_SREM(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -1072,7 +1062,11 @@ func TestEchoVault_SREM(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.presetValue != nil { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.SREM(tt.key, tt.members...) if (err != nil) != tt.wantErr { @@ -1087,13 +1081,7 @@ func TestEchoVault_SREM(t *testing.T) { } func TestEchoVault_SUNION(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -1153,7 +1141,11 @@ func TestEchoVault_SUNION(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.presetValues != nil { for k, v := range tt.presetValues { - presetValue(server, k, v) + err := presetValue(server, context.Background(), k, v) + if err != nil { + t.Error(err) + return + } } } got, err := server.SUNION(tt.keys...) @@ -1174,13 +1166,7 @@ func TestEchoVault_SUNION(t *testing.T) { } func TestEchoVault_SUNIONSTORE(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -1230,7 +1216,11 @@ func TestEchoVault_SUNIONSTORE(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.presetValues != nil { for k, v := range tt.presetValues { - presetValue(server, k, v) + err := presetValue(server, context.Background(), k, v) + if err != nil { + t.Error(err) + return + } } } got, err := server.SUNIONSTORE(tt.destination, tt.keys...) diff --git a/pkg/modules/set/commant_test.go b/test/modules/set/commands_test.go similarity index 93% rename from pkg/modules/set/commant_test.go rename to test/modules/set/commands_test.go index fdd35d54..aa716b9f 100644 --- a/pkg/modules/set/commant_test.go +++ b/test/modules/set/commands_test.go @@ -23,8 +23,12 @@ import ( "github.com/echovault/echovault/internal/set" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/echovault" + s "github.com/echovault/echovault/pkg/modules/set" + "github.com/echovault/echovault/pkg/types" "github.com/tidwall/resp" + "net" "slices" + "strings" "testing" ) @@ -32,6 +36,7 @@ var mockServer *echovault.EchoVault func init() { mockServer, _ = echovault.NewEchoVault( + echovault.WithCommands(s.Commands()), echovault.WithConfig(config.Config{ DataDir: "", EvictionPolicy: constants.NoEviction, @@ -39,6 +44,43 @@ func init() { ) } +func getHandler(commands ...string) types.HandlerFunc { + if len(commands) == 0 { + return nil + } + for _, c := range mockServer.GetAllCommands() { + if strings.EqualFold(commands[0], c.Command) && len(commands) == 1 { + // Get command handler + return c.HandlerFunc + } + if strings.EqualFold(commands[0], c.Command) { + // Get sub-command handler + for _, sc := range c.SubCommands { + if strings.EqualFold(commands[1], sc.Command) { + return sc.HandlerFunc + } + } + } + } + return nil +} + +func getHandlerFuncParams(ctx context.Context, cmd []string, conn *net.Conn) types.HandlerFuncParams { + return types.HandlerFuncParams{ + Context: ctx, + Command: cmd, + Connection: conn, + KeyExists: mockServer.KeyExists, + CreateKeyAndLock: mockServer.CreateKeyAndLock, + KeyLock: mockServer.KeyLock, + KeyRLock: mockServer.KeyRLock, + KeyUnlock: mockServer.KeyUnlock, + KeyRUnlock: mockServer.KeyRUnlock, + GetValue: mockServer.GetValue, + SetValue: mockServer.SetValue, + } +} + func Test_HandleSADD(t *testing.T) { tests := []struct { name string @@ -103,7 +145,15 @@ func Test_HandleSADD(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleSADD(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -214,7 +264,15 @@ func Test_HandleSCARD(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleSCARD(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -327,7 +385,15 @@ func Test_HandleSDIFF(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleSDIFF(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -454,7 +520,15 @@ func Test_HandleSDIFFSTORE(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleSDIFFSTORE(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -582,7 +656,15 @@ func Test_HandleSINTER(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleSINTER(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -709,7 +791,15 @@ func Test_HandleSINTERCARD(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleSINTERCARD(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -834,7 +924,13 @@ func Test_HandleSINTERSTORE(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleSINTERSTORE(ctx, test.command, mockServer, nil) + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -939,7 +1035,14 @@ func Test_HandleSISMEMBER(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleSISMEMBER(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -1027,7 +1130,14 @@ func Test_HandleSMEMBERS(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleSMEMBERS(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -1118,7 +1228,14 @@ func Test_HandleSMISMEMBER(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleSMISMEMBER(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -1160,7 +1277,7 @@ func Test_HandleSMOVE(t *testing.T) { "SmoveSource1": set.NewSet([]string{"one", "two", "three", "four"}), "SmoveDestination1": set.NewSet([]string{"five", "six", "seven", "eight"}), }, - command: []string{"MOVE", "SmoveSource1", "SmoveDestination1", "four"}, + command: []string{"SMOVE", "SmoveSource1", "SmoveDestination1", "four"}, expectedValues: map[string]interface{}{ "SmoveSource1": set.NewSet([]string{"one", "two", "three"}), "SmoveDestination1": set.NewSet([]string{"four", "five", "six", "seven", "eight"}), @@ -1242,7 +1359,14 @@ func Test_HandleSMOVE(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleSMOVE(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -1350,7 +1474,14 @@ func Test_HandleSPOP(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleSPOP(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -1473,7 +1604,14 @@ func Test_HandleSRANDMEMBER(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleSRANDMEMBER(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -1588,7 +1726,14 @@ func Test_HandleSREM(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleSREM(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -1708,7 +1853,14 @@ func Test_HandleSUNION(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleSUNION(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -1811,7 +1963,14 @@ func Test_HandleSUNIONSTORE(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleSUNIONSTORE(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) diff --git a/pkg/echovault/api_sorted_set_test.go b/test/modules/sorted_set/api_sorted_set_test.go similarity index 91% rename from pkg/echovault/api_sorted_set_test.go rename to test/modules/sorted_set/api_sorted_set_test.go index 69598773..9c674d61 100644 --- a/pkg/echovault/api_sorted_set_test.go +++ b/test/modules/sorted_set/api_sorted_set_test.go @@ -12,28 +12,44 @@ // See the License for the specific language governing permissions and // limitations under the License. -package echovault +package sorted_set import ( + "context" "github.com/echovault/echovault/internal" "github.com/echovault/echovault/internal/config" "github.com/echovault/echovault/internal/sorted_set" - "github.com/echovault/echovault/pkg/commands" - "github.com/echovault/echovault/pkg/constants" + "github.com/echovault/echovault/pkg/echovault" + ss "github.com/echovault/echovault/pkg/modules/sorted_set" "math" "reflect" "strconv" "testing" ) -func TestEchoVault_ZADD(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, +func createEchoVault() *echovault.EchoVault { + ev, _ := echovault.NewEchoVault( + echovault.WithCommands(ss.Commands()), + echovault.WithConfig(config.Config{ + DataDir: "", }), ) + return ev +} + +func presetValue(server *echovault.EchoVault, ctx context.Context, key string, value interface{}) error { + if _, err := server.CreateKeyAndLock(ctx, key); err != nil { + return err + } + if err := server.SetValue(ctx, key, value); err != nil { + return err + } + server.KeyUnlock(ctx, key) + return nil +} + +func TestEchoVault_ZADD(t *testing.T) { + server := createEchoVault() tests := []struct { name string @@ -41,7 +57,7 @@ func TestEchoVault_ZADD(t *testing.T) { presetValue *sorted_set.SortedSet key string entries map[string]float64 - options ZADDOptions + options echovault.ZADDOptions want int wantErr bool }{ @@ -57,7 +73,7 @@ func TestEchoVault_ZADD(t *testing.T) { "member4": math.Inf(-1), "member5": math.Inf(1), }, - options: ZADDOptions{}, + options: echovault.ZADDOptions{}, want: 5, wantErr: false, }, @@ -75,7 +91,7 @@ func TestEchoVault_ZADD(t *testing.T) { "member4": 67.77, "member5": 10, }, - options: ZADDOptions{NX: true}, + options: echovault.ZADDOptions{NX: true}, want: 2, wantErr: false, }, @@ -93,7 +109,7 @@ func TestEchoVault_ZADD(t *testing.T) { "member2": 67.77, "member3": 10, }, - options: ZADDOptions{NX: true}, + options: echovault.ZADDOptions{NX: true}, want: 0, wantErr: false, }, @@ -112,7 +128,7 @@ func TestEchoVault_ZADD(t *testing.T) { "member3": 15, "member4": 99.75, }, - options: ZADDOptions{XX: true, CH: true}, + options: echovault.ZADDOptions{XX: true, CH: true}, want: 3, wantErr: false, }, @@ -130,7 +146,7 @@ func TestEchoVault_ZADD(t *testing.T) { "member5": 100.5, "member6": 15, }, - options: ZADDOptions{XX: true}, + options: echovault.ZADDOptions{XX: true}, want: 0, wantErr: false, }, @@ -150,7 +166,7 @@ func TestEchoVault_ZADD(t *testing.T) { "member4": 100.5, "member5": 15, }, - options: ZADDOptions{XX: true, CH: true, GT: true}, + options: echovault.ZADDOptions{XX: true, CH: true, GT: true}, want: 1, wantErr: false, }, @@ -170,7 +186,7 @@ func TestEchoVault_ZADD(t *testing.T) { "member4": 100.5, "member5": 15, }, - options: ZADDOptions{XX: true, LT: true}, + options: echovault.ZADDOptions{XX: true, LT: true}, want: 0, wantErr: false, }, @@ -188,7 +204,7 @@ func TestEchoVault_ZADD(t *testing.T) { "member4": 100.5, "member5": 15, }, - options: ZADDOptions{XX: true, LT: true, CH: true}, + options: echovault.ZADDOptions{XX: true, LT: true, CH: true}, want: 1, wantErr: false, }, @@ -204,7 +220,7 @@ func TestEchoVault_ZADD(t *testing.T) { entries: map[string]float64{ "member3": 5.5, }, - options: ZADDOptions{INCR: true}, + options: echovault.ZADDOptions{INCR: true}, want: 0, wantErr: false, }, @@ -217,7 +233,7 @@ func TestEchoVault_ZADD(t *testing.T) { "member1": 3.5, "member5": 15, }, - options: ZADDOptions{NX: true, LT: true, CH: true}, + options: echovault.ZADDOptions{NX: true, LT: true, CH: true}, want: 0, wantErr: true, }, @@ -230,7 +246,7 @@ func TestEchoVault_ZADD(t *testing.T) { "member1": 10.5, "member2": 12.5, }, - options: ZADDOptions{INCR: true}, + options: echovault.ZADDOptions{INCR: true}, want: 0, wantErr: true, }, @@ -238,7 +254,11 @@ func TestEchoVault_ZADD(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.preset { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.ZADD(tt.key, tt.entries, tt.options) if (err != nil) != tt.wantErr { @@ -253,13 +273,7 @@ func TestEchoVault_ZADD(t *testing.T) { } func TestEchoVault_ZCARD(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -301,7 +315,11 @@ func TestEchoVault_ZCARD(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.preset { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.ZCARD(tt.key) if (err != nil) != tt.wantErr { @@ -316,13 +334,7 @@ func TestEchoVault_ZCARD(t *testing.T) { } func TestEchoVault_ZCOUNT(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -402,7 +414,11 @@ func TestEchoVault_ZCOUNT(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.preset { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.ZCOUNT(tt.key, tt.min, tt.max) if (err != nil) != tt.wantErr { @@ -417,13 +433,7 @@ func TestEchoVault_ZCOUNT(t *testing.T) { } func TestEchoVault_ZDIFF(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -553,7 +563,11 @@ func TestEchoVault_ZDIFF(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.preset { for k, v := range tt.presetValues { - presetValue(server, k, v) + err := presetValue(server, context.Background(), k, v) + if err != nil { + t.Error(err) + return + } } } got, err := server.ZDIFF(tt.withscores, tt.keys...) @@ -569,13 +583,7 @@ func TestEchoVault_ZDIFF(t *testing.T) { } func TestEchoVault_ZDIFFSTORE(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -674,7 +682,11 @@ func TestEchoVault_ZDIFFSTORE(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.preset { for k, v := range tt.presetValues { - presetValue(server, k, v) + err := presetValue(server, context.Background(), k, v) + if err != nil { + t.Error(err) + return + } } } got, err := server.ZDIFFSTORE(tt.destination, tt.keys...) @@ -690,13 +702,7 @@ func TestEchoVault_ZDIFFSTORE(t *testing.T) { } func TestEchoVault_ZINCRBY(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -825,7 +831,11 @@ func TestEchoVault_ZINCRBY(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.preset { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.ZINCRBY(tt.key, tt.increment, tt.member) if (err != nil) != tt.wantErr { @@ -840,20 +850,14 @@ func TestEchoVault_ZINCRBY(t *testing.T) { } func TestEchoVault_ZINTER(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string preset bool presetValues map[string]interface{} keys []string - options ZINTEROptions + options echovault.ZINTEROptions want map[string]float64 wantErr bool }{ @@ -873,7 +877,7 @@ func TestEchoVault_ZINTER(t *testing.T) { }), }, keys: []string{"key1", "key2"}, - options: ZINTEROptions{}, + options: echovault.ZINTEROptions{}, want: map[string]float64{"three": 0, "four": 0, "five": 0}, wantErr: false, }, @@ -901,7 +905,7 @@ func TestEchoVault_ZINTER(t *testing.T) { }), }, keys: []string{"key3", "key4", "key5"}, - options: ZINTEROptions{WithScores: true}, + options: echovault.ZINTEROptions{WithScores: true}, want: map[string]float64{"one": 3, "eight": 24}, wantErr: false, }, @@ -929,7 +933,7 @@ func TestEchoVault_ZINTER(t *testing.T) { }), }, keys: []string{"key6", "key7", "key8"}, - options: ZINTEROptions{Aggregate: "MIN", WithScores: true}, + options: echovault.ZINTEROptions{Aggregate: "MIN", WithScores: true}, want: map[string]float64{"one": 1, "eight": 8}, wantErr: false, }, @@ -956,7 +960,7 @@ func TestEchoVault_ZINTER(t *testing.T) { }), }, keys: []string{"key9", "key10", "key11"}, - options: ZINTEROptions{WithScores: true, Aggregate: "MAX"}, + options: echovault.ZINTEROptions{WithScores: true, Aggregate: "MAX"}, want: map[string]float64{"one": 1000, "eight": 800}, wantErr: false, }, @@ -984,7 +988,7 @@ func TestEchoVault_ZINTER(t *testing.T) { }), }, keys: []string{"key12", "key13", "key14"}, - options: ZINTEROptions{WithScores: true, Aggregate: "SUM", Weights: []float64{1, 5, 3}}, + options: echovault.ZINTEROptions{WithScores: true, Aggregate: "SUM", Weights: []float64{1, 5, 3}}, want: map[string]float64{"one": 3105, "eight": 2808}, wantErr: false, }, @@ -1012,7 +1016,7 @@ func TestEchoVault_ZINTER(t *testing.T) { }), }, keys: []string{"key15", "key16", "key17"}, - options: ZINTEROptions{WithScores: true, Aggregate: "MAX", Weights: []float64{1, 5, 3}}, + options: echovault.ZINTEROptions{WithScores: true, Aggregate: "MAX", Weights: []float64{1, 5, 3}}, want: map[string]float64{"one": 3000, "eight": 2400}, wantErr: false, }, @@ -1040,7 +1044,7 @@ func TestEchoVault_ZINTER(t *testing.T) { }), }, keys: []string{"key18", "key19", "key20"}, - options: ZINTEROptions{WithScores: true, Aggregate: "MIN", Weights: []float64{1, 5, 3}}, + options: echovault.ZINTEROptions{WithScores: true, Aggregate: "MIN", Weights: []float64{1, 5, 3}}, want: map[string]float64{"one": 5, "eight": 8}, wantErr: false, }, @@ -1057,7 +1061,7 @@ func TestEchoVault_ZINTER(t *testing.T) { "key22": sorted_set.NewSortedSet([]sorted_set.MemberParam{{Value: "one", Score: 1}}), }, keys: []string{"key21", "key22"}, - options: ZINTEROptions{Weights: []float64{1, 2, 3}}, + options: echovault.ZINTEROptions{Weights: []float64{1, 2, 3}}, want: nil, wantErr: true, }, @@ -1077,7 +1081,7 @@ func TestEchoVault_ZINTER(t *testing.T) { "key25": sorted_set.NewSortedSet([]sorted_set.MemberParam{{Value: "one", Score: 1}}), }, keys: []string{"key23", "key24", "key25"}, - options: ZINTEROptions{Weights: []float64{5, 4}}, + options: echovault.ZINTEROptions{Weights: []float64{5, 4}}, want: nil, wantErr: true, }, @@ -1090,7 +1094,7 @@ func TestEchoVault_ZINTER(t *testing.T) { "key28": sorted_set.NewSortedSet([]sorted_set.MemberParam{{Value: "one", Score: 1}}), }, keys: []string{}, - options: ZINTEROptions{}, + options: echovault.ZINTEROptions{}, want: nil, wantErr: true, }, @@ -1108,7 +1112,7 @@ func TestEchoVault_ZINTER(t *testing.T) { "key31": sorted_set.NewSortedSet([]sorted_set.MemberParam{{Value: "one", Score: 1}}), }, keys: []string{"key29", "key30", "key31"}, - options: ZINTEROptions{}, + options: echovault.ZINTEROptions{}, want: nil, wantErr: true, }, @@ -1128,7 +1132,7 @@ func TestEchoVault_ZINTER(t *testing.T) { }), }, keys: []string{"non-existent", "key32", "key33"}, - options: ZINTEROptions{}, + options: echovault.ZINTEROptions{}, want: map[string]float64{}, wantErr: false, }, @@ -1137,7 +1141,11 @@ func TestEchoVault_ZINTER(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.preset { for k, v := range tt.presetValues { - presetValue(server, k, v) + err := presetValue(server, context.Background(), k, v) + if err != nil { + t.Error(err) + return + } } } got, err := server.ZINTER(tt.keys, tt.options) @@ -1153,13 +1161,7 @@ func TestEchoVault_ZINTER(t *testing.T) { } func TestEchoVault_ZINTERSTORE(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -1167,7 +1169,7 @@ func TestEchoVault_ZINTERSTORE(t *testing.T) { presetValues map[string]interface{} destination string keys []string - options ZINTERSTOREOptions + options echovault.ZINTERSTOREOptions want int wantErr bool }{ @@ -1188,7 +1190,7 @@ func TestEchoVault_ZINTERSTORE(t *testing.T) { }, destination: "destination1", keys: []string{"key1", "key2"}, - options: ZINTERSTOREOptions{}, + options: echovault.ZINTERSTOREOptions{}, want: 3, wantErr: false, }, @@ -1217,7 +1219,7 @@ func TestEchoVault_ZINTERSTORE(t *testing.T) { }, destination: "destination2", keys: []string{"key3", "key4", "key5"}, - options: ZINTERSTOREOptions{WithScores: true}, + options: echovault.ZINTERSTOREOptions{WithScores: true}, want: 2, wantErr: false, }, @@ -1246,7 +1248,7 @@ func TestEchoVault_ZINTERSTORE(t *testing.T) { }, destination: "destination3", keys: []string{"key6", "key7", "key8"}, - options: ZINTERSTOREOptions{WithScores: true, Aggregate: "MIN"}, + options: echovault.ZINTERSTOREOptions{WithScores: true, Aggregate: "MIN"}, want: 2, wantErr: false, }, @@ -1275,7 +1277,7 @@ func TestEchoVault_ZINTERSTORE(t *testing.T) { }, destination: "destination4", keys: []string{"key9", "key10", "key11"}, - options: ZINTERSTOREOptions{WithScores: true, Aggregate: "MAX"}, + options: echovault.ZINTERSTOREOptions{WithScores: true, Aggregate: "MAX"}, want: 2, wantErr: false, }, @@ -1304,7 +1306,7 @@ func TestEchoVault_ZINTERSTORE(t *testing.T) { }, destination: "destination5", keys: []string{"key12", "key13", "key14"}, - options: ZINTERSTOREOptions{WithScores: true, Aggregate: "SUM", Weights: []float64{1, 5, 3}}, + options: echovault.ZINTERSTOREOptions{WithScores: true, Aggregate: "SUM", Weights: []float64{1, 5, 3}}, want: 2, wantErr: false, }, @@ -1333,7 +1335,7 @@ func TestEchoVault_ZINTERSTORE(t *testing.T) { }, destination: "destination6", keys: []string{"key15", "key16", "key17"}, - options: ZINTERSTOREOptions{WithScores: true, Aggregate: "MAX", Weights: []float64{1, 5, 3}}, + options: echovault.ZINTERSTOREOptions{WithScores: true, Aggregate: "MAX", Weights: []float64{1, 5, 3}}, want: 2, wantErr: false, }, @@ -1362,7 +1364,7 @@ func TestEchoVault_ZINTERSTORE(t *testing.T) { }, destination: "destination7", keys: []string{"key18", "key19", "key20"}, - options: ZINTERSTOREOptions{WithScores: true, Aggregate: "MIN", Weights: []float64{1, 5, 3}}, + options: echovault.ZINTERSTOREOptions{WithScores: true, Aggregate: "MIN", Weights: []float64{1, 5, 3}}, want: 2, wantErr: false, }, @@ -1380,7 +1382,7 @@ func TestEchoVault_ZINTERSTORE(t *testing.T) { }, destination: "destination8", keys: []string{"key21", "key22"}, - options: ZINTERSTOREOptions{Weights: []float64{1, 2, 3}}, + options: echovault.ZINTERSTOREOptions{Weights: []float64{1, 2, 3}}, want: 0, wantErr: true, }, @@ -1401,7 +1403,7 @@ func TestEchoVault_ZINTERSTORE(t *testing.T) { }, destination: "destination9", keys: []string{"key23", "key24"}, - options: ZINTERSTOREOptions{Weights: []float64{5}}, + options: echovault.ZINTERSTOREOptions{Weights: []float64{5}}, want: 0, wantErr: true, }, @@ -1415,7 +1417,7 @@ func TestEchoVault_ZINTERSTORE(t *testing.T) { }, destination: "destination10", keys: []string{}, - options: ZINTERSTOREOptions{Weights: []float64{5, 4}}, + options: echovault.ZINTERSTOREOptions{Weights: []float64{5, 4}}, want: 0, wantErr: true, }, @@ -1434,7 +1436,7 @@ func TestEchoVault_ZINTERSTORE(t *testing.T) { }, destination: "destination11", keys: []string{"key29", "key30", "key31"}, - options: ZINTERSTOREOptions{}, + options: echovault.ZINTERSTOREOptions{}, want: 0, wantErr: true, }, @@ -1455,7 +1457,7 @@ func TestEchoVault_ZINTERSTORE(t *testing.T) { }, destination: "destination12", keys: []string{"non-existent", "key32", "key33"}, - options: ZINTERSTOREOptions{}, + options: echovault.ZINTERSTOREOptions{}, want: 0, wantErr: false, }, @@ -1464,7 +1466,11 @@ func TestEchoVault_ZINTERSTORE(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.preset { for k, v := range tt.presetValues { - presetValue(server, k, v) + err := presetValue(server, context.Background(), k, v) + if err != nil { + t.Error(err) + return + } } } got, err := server.ZINTERSTORE(tt.destination, tt.keys, tt.options) @@ -1480,13 +1486,7 @@ func TestEchoVault_ZINTERSTORE(t *testing.T) { } func TestEchoVault_ZLEXCOUNT(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -1558,7 +1558,11 @@ func TestEchoVault_ZLEXCOUNT(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.preset { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.ZLEXCOUNT(tt.key, tt.min, tt.max) if (err != nil) != tt.wantErr { @@ -1573,20 +1577,14 @@ func TestEchoVault_ZLEXCOUNT(t *testing.T) { } func TestEchoVault_ZMPOP(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string preset bool presetValues map[string]interface{} keys []string - options ZMPOPOptions + options echovault.ZMPOPOptions want [][]string wantErr bool }{ @@ -1601,7 +1599,7 @@ func TestEchoVault_ZMPOP(t *testing.T) { }), }, keys: []string{"key1"}, - options: ZMPOPOptions{}, + options: echovault.ZMPOPOptions{}, want: [][]string{ {"one", "1"}, }, @@ -1618,7 +1616,7 @@ func TestEchoVault_ZMPOP(t *testing.T) { }), }, keys: []string{"key2"}, - options: ZMPOPOptions{Min: true}, + options: echovault.ZMPOPOptions{Min: true}, want: [][]string{ {"one", "1"}, }, @@ -1635,7 +1633,7 @@ func TestEchoVault_ZMPOP(t *testing.T) { }), }, keys: []string{"key3"}, - options: ZMPOPOptions{Max: true}, + options: echovault.ZMPOPOptions{Max: true}, want: [][]string{ {"five", "5"}, }, @@ -1652,7 +1650,7 @@ func TestEchoVault_ZMPOP(t *testing.T) { }), }, keys: []string{"key4"}, - options: ZMPOPOptions{Min: true, Count: 5}, + options: echovault.ZMPOPOptions{Min: true, Count: 5}, want: [][]string{ {"one", "1"}, {"two", "2"}, {"three", "3"}, {"four", "4"}, {"five", "5"}, @@ -1670,7 +1668,7 @@ func TestEchoVault_ZMPOP(t *testing.T) { }), }, keys: []string{"key5"}, - options: ZMPOPOptions{Max: true, Count: 5}, + options: echovault.ZMPOPOptions{Max: true, Count: 5}, want: [][]string{{"two", "2"}, {"three", "3"}, {"four", "4"}, {"five", "5"}, {"six", "6"}}, wantErr: false, }, @@ -1686,7 +1684,7 @@ func TestEchoVault_ZMPOP(t *testing.T) { }), }, keys: []string{"key6", "key7"}, - options: ZMPOPOptions{Max: true, Count: 5}, + options: echovault.ZMPOPOptions{Max: true, Count: 5}, want: [][]string{{"two", "2"}, {"three", "3"}, {"four", "4"}, {"five", "5"}, {"six", "6"}}, wantErr: false, }, @@ -1704,7 +1702,7 @@ func TestEchoVault_ZMPOP(t *testing.T) { }), }, keys: []string{"key8", "key9", "key10", "key11"}, - options: ZMPOPOptions{Min: true, Count: 5}, + options: echovault.ZMPOPOptions{Min: true, Count: 5}, want: [][]string{{"one", "1"}, {"two", "2"}, {"three", "3"}, {"four", "4"}, {"five", "5"}}, wantErr: false, }, @@ -1713,7 +1711,11 @@ func TestEchoVault_ZMPOP(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.preset { for k, v := range tt.presetValues { - presetValue(server, k, v) + err := presetValue(server, context.Background(), k, v) + if err != nil { + t.Error(err) + return + } } } got, err := server.ZMPOP(tt.keys, tt.options) @@ -1729,13 +1731,7 @@ func TestEchoVault_ZMPOP(t *testing.T) { } func TestEchoVault_ZMSCORE(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -1782,7 +1778,11 @@ func TestEchoVault_ZMSCORE(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.preset { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.ZMSCORE(tt.key, tt.members...) if (err != nil) != tt.wantErr { @@ -1810,13 +1810,7 @@ func TestEchoVault_ZMSCORE(t *testing.T) { } func TestEchoVault_ZPOP(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -1903,7 +1897,11 @@ func TestEchoVault_ZPOP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.preset { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := tt.popFunc(tt.key, tt.count) if (err != nil) != tt.wantErr { @@ -1918,13 +1916,7 @@ func TestEchoVault_ZPOP(t *testing.T) { } func TestEchoVault_ZRANDMEMBER(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -1979,7 +1971,11 @@ func TestEchoVault_ZRANDMEMBER(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.preset { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.ZRANDMEMBER(tt.key, tt.count, tt.withscores) if (err != nil) != tt.wantErr { @@ -1994,13 +1990,7 @@ func TestEchoVault_ZRANDMEMBER(t *testing.T) { } func TestEchoVault_ZRANGE(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -2009,7 +1999,7 @@ func TestEchoVault_ZRANGE(t *testing.T) { key string start string stop string - options ZRANGEOptions + options echovault.ZRANGEOptions want map[string]float64 wantErr bool }{ @@ -2025,7 +2015,7 @@ func TestEchoVault_ZRANGE(t *testing.T) { key: "key1", start: "3", stop: "7", - options: ZRANGEOptions{ByScore: true}, + options: echovault.ZRANGEOptions{ByScore: true}, want: map[string]float64{"three": 0, "four": 0, "five": 0, "six": 0, "seven": 0}, wantErr: false, }, @@ -2041,7 +2031,7 @@ func TestEchoVault_ZRANGE(t *testing.T) { key: "key2", start: "3", stop: "7", - options: ZRANGEOptions{ByScore: true, WithScores: true}, + options: echovault.ZRANGEOptions{ByScore: true, WithScores: true}, want: map[string]float64{"three": 3, "four": 4, "five": 5, "six": 6, "seven": 7}, wantErr: false, }, @@ -2059,7 +2049,7 @@ func TestEchoVault_ZRANGE(t *testing.T) { key: "key3", start: "3", stop: "7", - options: ZRANGEOptions{WithScores: true, ByScore: true, Offset: 2, Count: 4}, + options: echovault.ZRANGEOptions{WithScores: true, ByScore: true, Offset: 2, Count: 4}, want: map[string]float64{"three": 3, "four": 4, "five": 5}, wantErr: false, }, @@ -2075,7 +2065,7 @@ func TestEchoVault_ZRANGE(t *testing.T) { key: "key4", start: "c", stop: "g", - options: ZRANGEOptions{ByLex: true}, + options: echovault.ZRANGEOptions{ByLex: true}, want: map[string]float64{"c": 0, "d": 0, "e": 0, "f": 0, "g": 0}, wantErr: false, }, @@ -2091,7 +2081,7 @@ func TestEchoVault_ZRANGE(t *testing.T) { key: "key5", start: "a", stop: "f", - options: ZRANGEOptions{ByLex: true, WithScores: true}, + options: echovault.ZRANGEOptions{ByLex: true, WithScores: true}, want: map[string]float64{"a": 1, "b": 1, "c": 1, "d": 1, "e": 1, "f": 1}, wantErr: false, }, @@ -2109,7 +2099,7 @@ func TestEchoVault_ZRANGE(t *testing.T) { key: "key6", start: "a", stop: "h", - options: ZRANGEOptions{WithScores: true, ByLex: true, Offset: 2, Count: 4}, + options: echovault.ZRANGEOptions{WithScores: true, ByLex: true, Offset: 2, Count: 4}, want: map[string]float64{"c": 1, "d": 1, "e": 1}, wantErr: false, }, @@ -2125,7 +2115,7 @@ func TestEchoVault_ZRANGE(t *testing.T) { key: "key7", start: "a", stop: "h", - options: ZRANGEOptions{WithScores: true, ByLex: true, Offset: 2, Count: 4}, + options: echovault.ZRANGEOptions{WithScores: true, ByLex: true, Offset: 2, Count: 4}, want: map[string]float64{}, wantErr: false, }, @@ -2136,7 +2126,7 @@ func TestEchoVault_ZRANGE(t *testing.T) { key: "key10", start: "a", stop: "h", - options: ZRANGEOptions{WithScores: true, ByLex: true, Offset: 2, Count: 4}, + options: echovault.ZRANGEOptions{WithScores: true, ByLex: true, Offset: 2, Count: 4}, want: nil, wantErr: true, }, @@ -2144,7 +2134,11 @@ func TestEchoVault_ZRANGE(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.preset { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.ZRANGE(tt.key, tt.start, tt.stop, tt.options) if (err != nil) != tt.wantErr { @@ -2159,13 +2153,7 @@ func TestEchoVault_ZRANGE(t *testing.T) { } func TestEchoVault_ZRANGESTORE(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -2175,7 +2163,7 @@ func TestEchoVault_ZRANGESTORE(t *testing.T) { source string start string stop string - options ZRANGESTOREOptions + options echovault.ZRANGESTOREOptions want int wantErr bool }{ @@ -2194,7 +2182,7 @@ func TestEchoVault_ZRANGESTORE(t *testing.T) { source: "key1", start: "3", stop: "7", - options: ZRANGESTOREOptions{ByScore: true}, + options: echovault.ZRANGESTOREOptions{ByScore: true}, want: 5, wantErr: false, }, @@ -2213,7 +2201,7 @@ func TestEchoVault_ZRANGESTORE(t *testing.T) { source: "key2", start: "3", stop: "7", - options: ZRANGESTOREOptions{WithScores: true, ByScore: true}, + options: echovault.ZRANGESTOREOptions{WithScores: true, ByScore: true}, want: 5, wantErr: false, }, @@ -2234,7 +2222,7 @@ func TestEchoVault_ZRANGESTORE(t *testing.T) { source: "key3", start: "3", stop: "7", - options: ZRANGESTOREOptions{ByScore: true, WithScores: true, Offset: 2, Count: 4}, + options: echovault.ZRANGESTOREOptions{ByScore: true, WithScores: true, Offset: 2, Count: 4}, want: 3, wantErr: false, }, @@ -2253,7 +2241,7 @@ func TestEchoVault_ZRANGESTORE(t *testing.T) { source: "key4", start: "c", stop: "g", - options: ZRANGESTOREOptions{ByLex: true}, + options: echovault.ZRANGESTOREOptions{ByLex: true}, want: 5, wantErr: false, }, @@ -2272,7 +2260,7 @@ func TestEchoVault_ZRANGESTORE(t *testing.T) { source: "key5", start: "a", stop: "f", - options: ZRANGESTOREOptions{ByLex: true, WithScores: true}, + options: echovault.ZRANGESTOREOptions{ByLex: true, WithScores: true}, want: 6, wantErr: false, }, @@ -2293,7 +2281,7 @@ func TestEchoVault_ZRANGESTORE(t *testing.T) { source: "key6", start: "a", stop: "h", - options: ZRANGESTOREOptions{WithScores: true, ByLex: true, Offset: 2, Count: 4}, + options: echovault.ZRANGESTOREOptions{WithScores: true, ByLex: true, Offset: 2, Count: 4}, want: 3, wantErr: false, }, @@ -2315,7 +2303,7 @@ func TestEchoVault_ZRANGESTORE(t *testing.T) { source: "key7", start: "a", stop: "h", - options: ZRANGESTOREOptions{WithScores: true, ByLex: true, Offset: 2, Count: 4}, + options: echovault.ZRANGESTOREOptions{WithScores: true, ByLex: true, Offset: 2, Count: 4}, want: 3, wantErr: false, }, @@ -2334,7 +2322,7 @@ func TestEchoVault_ZRANGESTORE(t *testing.T) { source: "key8", start: "a", stop: "h", - options: ZRANGESTOREOptions{WithScores: true, ByLex: true, Offset: 2, Count: 4}, + options: echovault.ZRANGESTOREOptions{WithScores: true, ByLex: true, Offset: 2, Count: 4}, want: 0, wantErr: false, }, @@ -2348,7 +2336,7 @@ func TestEchoVault_ZRANGESTORE(t *testing.T) { source: "key9", start: "a", stop: "h", - options: ZRANGESTOREOptions{WithScores: true, ByLex: true, Offset: 2, Count: 4}, + options: echovault.ZRANGESTOREOptions{WithScores: true, ByLex: true, Offset: 2, Count: 4}, want: 0, wantErr: true, }, @@ -2357,7 +2345,11 @@ func TestEchoVault_ZRANGESTORE(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.preset { for k, v := range tt.presetValues { - presetValue(server, k, v) + err := presetValue(server, context.Background(), k, v) + if err != nil { + t.Error(err) + return + } } } got, err := server.ZRANGESTORE(tt.destination, tt.source, tt.start, tt.stop, tt.options) @@ -2373,13 +2365,7 @@ func TestEchoVault_ZRANGESTORE(t *testing.T) { } func TestEchoVault_ZRANK(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -2457,7 +2443,11 @@ func TestEchoVault_ZRANK(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.preset { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.ZRANK(tt.key, tt.member, tt.withscores) if (err != nil) != tt.wantErr { @@ -2472,13 +2462,7 @@ func TestEchoVault_ZRANK(t *testing.T) { } func TestEchoVault_ZREM(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -2528,7 +2512,11 @@ func TestEchoVault_ZREM(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.preset { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.ZREM(tt.key, tt.members...) if (err != nil) != tt.wantErr { @@ -2543,13 +2531,7 @@ func TestEchoVault_ZREM(t *testing.T) { } func TestEchoVault_ZREMRANGEBYSCORE(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -2600,7 +2582,11 @@ func TestEchoVault_ZREMRANGEBYSCORE(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.preset { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.ZREMRANGEBYSCORE(tt.key, tt.min, tt.max) if (err != nil) != tt.wantErr { @@ -2615,13 +2601,7 @@ func TestEchoVault_ZREMRANGEBYSCORE(t *testing.T) { } func TestEchoVault_ZSCORE(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -2680,7 +2660,11 @@ func TestEchoVault_ZSCORE(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.preset { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.ZSCORE(tt.key, tt.member) if (err != nil) != tt.wantErr { @@ -2695,20 +2679,14 @@ func TestEchoVault_ZSCORE(t *testing.T) { } func TestEchoVault_ZUNION(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string preset bool presetValues map[string]interface{} keys []string - options ZUNIONOptions + options echovault.ZUNIONOptions want map[string]float64 wantErr bool }{ @@ -2728,7 +2706,7 @@ func TestEchoVault_ZUNION(t *testing.T) { }), }, keys: []string{"key1", "key2"}, - options: ZUNIONOptions{}, + options: echovault.ZUNIONOptions{}, want: map[string]float64{ "one": 0, "two": 0, "three": 0, "four": 0, "five": 0, "six": 0, "seven": 0, "eight": 0, @@ -2759,7 +2737,7 @@ func TestEchoVault_ZUNION(t *testing.T) { }), }, keys: []string{"key3", "key4", "key5"}, - options: ZUNIONOptions{WithScores: true}, + options: echovault.ZUNIONOptions{WithScores: true}, want: map[string]float64{ "one": 3, "two": 4, "three": 3, "four": 4, "five": 5, "six": 6, "seven": 7, "eight": 24, "nine": 9, "ten": 10, "eleven": 11, "twelve": 24, "thirty-six": 72, @@ -2790,7 +2768,7 @@ func TestEchoVault_ZUNION(t *testing.T) { }), }, keys: []string{"key6", "key7", "key8"}, - options: ZUNIONOptions{WithScores: true, Aggregate: "MIN"}, + options: echovault.ZUNIONOptions{WithScores: true, Aggregate: "MIN"}, want: map[string]float64{ "one": 1, "two": 2, "three": 3, "four": 4, "five": 5, "six": 6, "seven": 7, "eight": 8, "nine": 9, "ten": 10, "eleven": 11, "twelve": 12, "thirty-six": 36, @@ -2821,7 +2799,7 @@ func TestEchoVault_ZUNION(t *testing.T) { }), }, keys: []string{"key9", "key10", "key11"}, - options: ZUNIONOptions{WithScores: true, Aggregate: "MAX"}, + options: echovault.ZUNIONOptions{WithScores: true, Aggregate: "MAX"}, want: map[string]float64{ "one": 1000, "two": 2, "three": 3, "four": 4, "five": 5, "six": 6, "seven": 7, "eight": 800, "nine": 9, "ten": 10, "eleven": 11, "twelve": 12, "thirty-six": 72, @@ -2852,7 +2830,7 @@ func TestEchoVault_ZUNION(t *testing.T) { }), }, keys: []string{"key12", "key13", "key14"}, - options: ZUNIONOptions{WithScores: true, Aggregate: "SUM", Weights: []float64{1, 2, 3}}, + options: echovault.ZUNIONOptions{WithScores: true, Aggregate: "SUM", Weights: []float64{1, 2, 3}}, want: map[string]float64{ "one": 3102, "two": 6, "three": 3, "four": 4, "five": 5, "six": 6, "seven": 7, "eight": 2568, "nine": 27, "ten": 30, "eleven": 22, "twelve": 60, "thirty-six": 72, @@ -2883,7 +2861,7 @@ func TestEchoVault_ZUNION(t *testing.T) { }), }, keys: []string{"key15", "key16", "key17"}, - options: ZUNIONOptions{WithScores: true, Aggregate: "MAX", Weights: []float64{1, 2, 3}}, + options: echovault.ZUNIONOptions{WithScores: true, Aggregate: "MAX", Weights: []float64{1, 2, 3}}, want: map[string]float64{ "one": 3000, "two": 4, "three": 3, "four": 4, "five": 5, "six": 6, "seven": 7, "eight": 2400, "nine": 27, "ten": 30, "eleven": 22, "twelve": 36, "thirty-six": 72, @@ -2914,7 +2892,7 @@ func TestEchoVault_ZUNION(t *testing.T) { }), }, keys: []string{"key18", "key19", "key20"}, - options: ZUNIONOptions{WithScores: true, Aggregate: "MIN", Weights: []float64{1, 2, 3}}, + options: echovault.ZUNIONOptions{WithScores: true, Aggregate: "MIN", Weights: []float64{1, 2, 3}}, want: map[string]float64{ "one": 2, "two": 2, "three": 3, "four": 4, "five": 5, "six": 6, "seven": 7, "eight": 8, "nine": 27, "ten": 30, "eleven": 22, "twelve": 24, "thirty-six": 72, @@ -2934,7 +2912,7 @@ func TestEchoVault_ZUNION(t *testing.T) { "key22": sorted_set.NewSortedSet([]sorted_set.MemberParam{{Value: "one", Score: 1}}), }, keys: []string{"key21", "key22"}, - options: ZUNIONOptions{Weights: []float64{1, 2, 3}}, + options: echovault.ZUNIONOptions{Weights: []float64{1, 2, 3}}, want: nil, wantErr: true, }, @@ -2954,7 +2932,7 @@ func TestEchoVault_ZUNION(t *testing.T) { "key25": sorted_set.NewSortedSet([]sorted_set.MemberParam{{Value: "one", Score: 1}}), }, keys: []string{"key23", "key24", "key25"}, - options: ZUNIONOptions{Weights: []float64{5, 4}}, + options: echovault.ZUNIONOptions{Weights: []float64{5, 4}}, want: nil, wantErr: true, }, @@ -2967,7 +2945,7 @@ func TestEchoVault_ZUNION(t *testing.T) { "key28": sorted_set.NewSortedSet([]sorted_set.MemberParam{{Value: "one", Score: 1}}), }, keys: []string{}, - options: ZUNIONOptions{Weights: []float64{5, 4}}, + options: echovault.ZUNIONOptions{Weights: []float64{5, 4}}, want: nil, wantErr: true, }, @@ -2985,7 +2963,7 @@ func TestEchoVault_ZUNION(t *testing.T) { "key31": sorted_set.NewSortedSet([]sorted_set.MemberParam{{Value: "one", Score: 1}}), }, keys: []string{"key29", "key30", "key31"}, - options: ZUNIONOptions{}, + options: echovault.ZUNIONOptions{}, want: nil, wantErr: true, }, @@ -3005,7 +2983,7 @@ func TestEchoVault_ZUNION(t *testing.T) { }), }, keys: []string{"non-existent", "key32", "key33"}, - options: ZUNIONOptions{}, + options: echovault.ZUNIONOptions{}, want: map[string]float64{ "one": 0, "two": 0, "thirty-six": 0, "twelve": 0, "eleven": 0, "seven": 0, "eight": 0, "nine": 0, "ten": 0, @@ -3017,7 +2995,11 @@ func TestEchoVault_ZUNION(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.preset { for k, v := range tt.presetValues { - presetValue(server, k, v) + err := presetValue(server, context.Background(), k, v) + if err != nil { + t.Error(err) + return + } } } got, err := server.ZUNION(tt.keys, tt.options) @@ -3033,13 +3015,7 @@ func TestEchoVault_ZUNION(t *testing.T) { } func TestEchoVault_ZUNIONSTORE(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -3047,7 +3023,7 @@ func TestEchoVault_ZUNIONSTORE(t *testing.T) { presetValues map[string]interface{} destination string keys []string - options ZUNIONSTOREOptions + options echovault.ZUNIONSTOREOptions want int wantErr bool }{ @@ -3068,7 +3044,7 @@ func TestEchoVault_ZUNIONSTORE(t *testing.T) { }, destination: "destination1", keys: []string{"key1", "key2"}, - options: ZUNIONSTOREOptions{}, + options: echovault.ZUNIONSTOREOptions{}, want: 8, wantErr: false, }, @@ -3097,7 +3073,7 @@ func TestEchoVault_ZUNIONSTORE(t *testing.T) { }, destination: "destination2", keys: []string{"key3", "key4", "key5"}, - options: ZUNIONSTOREOptions{WithScores: true}, + options: echovault.ZUNIONSTOREOptions{WithScores: true}, want: 13, wantErr: false, }, @@ -3126,7 +3102,7 @@ func TestEchoVault_ZUNIONSTORE(t *testing.T) { }, destination: "destination3", keys: []string{"key6", "key7", "key8"}, - options: ZUNIONSTOREOptions{WithScores: true, Aggregate: "MIN"}, + options: echovault.ZUNIONSTOREOptions{WithScores: true, Aggregate: "MIN"}, want: 13, wantErr: false, }, @@ -3155,7 +3131,7 @@ func TestEchoVault_ZUNIONSTORE(t *testing.T) { }, destination: "destination4", keys: []string{"key9", "key10", "key11"}, - options: ZUNIONSTOREOptions{WithScores: true, Aggregate: "MAX"}, + options: echovault.ZUNIONSTOREOptions{WithScores: true, Aggregate: "MAX"}, want: 13, wantErr: false, }, @@ -3184,7 +3160,7 @@ func TestEchoVault_ZUNIONSTORE(t *testing.T) { }, destination: "destination5", keys: []string{"key12", "key13", "key14"}, - options: ZUNIONSTOREOptions{WithScores: true, Aggregate: "SUM", Weights: []float64{1, 2, 3}}, + options: echovault.ZUNIONSTOREOptions{WithScores: true, Aggregate: "SUM", Weights: []float64{1, 2, 3}}, want: 13, wantErr: false, }, @@ -3213,7 +3189,7 @@ func TestEchoVault_ZUNIONSTORE(t *testing.T) { }, destination: "destination6", keys: []string{"key15", "key16", "key17"}, - options: ZUNIONSTOREOptions{WithScores: true, Aggregate: "MAX", Weights: []float64{1, 2, 3}}, + options: echovault.ZUNIONSTOREOptions{WithScores: true, Aggregate: "MAX", Weights: []float64{1, 2, 3}}, want: 13, wantErr: false, }, @@ -3242,7 +3218,7 @@ func TestEchoVault_ZUNIONSTORE(t *testing.T) { }, destination: "destination7", keys: []string{"destination7", "key18", "key19", "key20"}, - options: ZUNIONSTOREOptions{WithScores: true, Aggregate: "MIN", Weights: []float64{1, 2, 3}}, + options: echovault.ZUNIONSTOREOptions{WithScores: true, Aggregate: "MIN", Weights: []float64{1, 2, 3}}, want: 13, wantErr: false, }, @@ -3260,7 +3236,7 @@ func TestEchoVault_ZUNIONSTORE(t *testing.T) { }, destination: "destination8", keys: []string{"key21", "key22"}, - options: ZUNIONSTOREOptions{Weights: []float64{1, 2, 3}}, + options: echovault.ZUNIONSTOREOptions{Weights: []float64{1, 2, 3}}, want: 0, wantErr: true, }, @@ -3281,7 +3257,7 @@ func TestEchoVault_ZUNIONSTORE(t *testing.T) { }, destination: "destination9", keys: []string{"key23", "key24", "key25"}, - options: ZUNIONSTOREOptions{Weights: []float64{5, 4}}, + options: echovault.ZUNIONSTOREOptions{Weights: []float64{5, 4}}, want: 0, wantErr: true, }, @@ -3300,7 +3276,7 @@ func TestEchoVault_ZUNIONSTORE(t *testing.T) { }, destination: "destination11", keys: []string{"key29", "key30", "key31"}, - options: ZUNIONSTOREOptions{}, + options: echovault.ZUNIONSTOREOptions{}, want: 0, wantErr: true, }, @@ -3329,7 +3305,11 @@ func TestEchoVault_ZUNIONSTORE(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.preset { for k, v := range tt.presetValues { - presetValue(server, k, v) + err := presetValue(server, context.Background(), k, v) + if err != nil { + t.Error(err) + return + } } } got, err := server.ZUNIONSTORE(tt.destination, tt.keys, tt.options) diff --git a/pkg/modules/sorted_set/commands_test.go b/test/modules/sorted_set/commands_test.go similarity index 96% rename from pkg/modules/sorted_set/commands_test.go rename to test/modules/sorted_set/commands_test.go index bf8ed36c..0810b450 100644 --- a/pkg/modules/sorted_set/commands_test.go +++ b/test/modules/sorted_set/commands_test.go @@ -23,10 +23,14 @@ import ( "github.com/echovault/echovault/internal/sorted_set" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/echovault" + ss "github.com/echovault/echovault/pkg/modules/sorted_set" + "github.com/echovault/echovault/pkg/types" "github.com/tidwall/resp" "math" + "net" "slices" "strconv" + "strings" "testing" ) @@ -34,6 +38,7 @@ var mockServer *echovault.EchoVault func init() { mockServer, _ = echovault.NewEchoVault( + echovault.WithCommands(ss.Commands()), echovault.WithConfig(config.Config{ DataDir: "", EvictionPolicy: constants.NoEviction, @@ -41,6 +46,43 @@ func init() { ) } +func getHandler(commands ...string) types.HandlerFunc { + if len(commands) == 0 { + return nil + } + for _, c := range mockServer.GetAllCommands() { + if strings.EqualFold(commands[0], c.Command) && len(commands) == 1 { + // Get command handler + return c.HandlerFunc + } + if strings.EqualFold(commands[0], c.Command) { + // Get sub-command handler + for _, sc := range c.SubCommands { + if strings.EqualFold(commands[1], sc.Command) { + return sc.HandlerFunc + } + } + } + } + return nil +} + +func getHandlerFuncParams(ctx context.Context, cmd []string, conn *net.Conn) types.HandlerFuncParams { + return types.HandlerFuncParams{ + Context: ctx, + Command: cmd, + Connection: conn, + KeyExists: mockServer.KeyExists, + CreateKeyAndLock: mockServer.CreateKeyAndLock, + KeyLock: mockServer.KeyLock, + KeyRLock: mockServer.KeyRLock, + KeyUnlock: mockServer.KeyUnlock, + KeyRUnlock: mockServer.KeyRUnlock, + GetValue: mockServer.GetValue, + SetValue: mockServer.SetValue, + } +} + func Test_HandleZADD(t *testing.T) { tests := []struct { name string @@ -273,7 +315,15 @@ func Test_HandleZADD(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleZADD(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -390,7 +440,15 @@ func Test_HandleZCARD(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleZCARD(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -542,7 +600,15 @@ func Test_HandleZCOUNT(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleZCOUNT(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -666,7 +732,15 @@ func Test_HandleZLEXCOUNT(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleZLEXCOUNT(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -830,7 +904,15 @@ func Test_HandleZDIFF(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleZDIFF(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -1016,7 +1098,15 @@ func Test_HandleZDIFFSTORE(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleZDIFFSTORE(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -1246,7 +1336,15 @@ func Test_HandleZINCRBY(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleZINCRBY(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -1482,7 +1580,15 @@ func Test_HandleZMPOP(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleZMPOP(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -1665,7 +1771,15 @@ func Test_HandleZPOP(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleZPOP(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -1775,7 +1889,15 @@ func Test_HandleZMSCORE(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleZMSCORE(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -1886,7 +2008,15 @@ func Test_HandleZSCORE(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleZSCORE(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -2012,7 +2142,15 @@ func Test_HandleZRANDMEMBER(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleZRANDMEMBER(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -2181,7 +2319,15 @@ func Test_HandleZRANK(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleZRANK(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -2289,7 +2435,15 @@ func Test_HandleZREM(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleZREM(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -2405,7 +2559,15 @@ func Test_HandleZREMRANGEBYSCORE(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleZREMRANGEBYSCORE(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -2578,7 +2740,15 @@ func Test_HandleZREMRANGEBYRANK(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleZREMRANGEBYRANK(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -2720,7 +2890,15 @@ func Test_HandleZREMRANGEBYLEX(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleZREMRANGEBYLEX(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -2990,7 +3168,15 @@ func Test_HandleZRANGE(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleZRANGE(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -3297,7 +3483,15 @@ func Test_HandleZRANGESTORE(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleZRANGESTORE(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -3629,7 +3823,15 @@ func Test_HandleZINTER(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleZINTER(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -3992,7 +4194,15 @@ func Test_HandleZINTERSTORE(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleZINTERSTORE(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -4351,7 +4561,15 @@ func Test_HandleZUNION(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleZUNION(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -4753,7 +4971,15 @@ func Test_HandleZUNIONSTORE(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleZUNIONSTORE(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) diff --git a/test/modules/string/api_string_test.go b/test/modules/string/api_string_test.go index 9526bce0..36197c94 100644 --- a/test/modules/string/api_string_test.go +++ b/test/modules/string/api_string_test.go @@ -17,12 +17,21 @@ package str import ( "context" "github.com/echovault/echovault/internal/config" - "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/echovault" str "github.com/echovault/echovault/pkg/modules/string" "testing" ) +func createEchoVault() *echovault.EchoVault { + ev, _ := echovault.NewEchoVault( + echovault.WithCommands(str.Commands()), + echovault.WithConfig(config.Config{ + DataDir: "", + }), + ) + return ev +} + func presetValue(server *echovault.EchoVault, ctx context.Context, key string, value interface{}) error { if _, err := server.CreateKeyAndLock(ctx, key); err != nil { return err @@ -35,13 +44,7 @@ func presetValue(server *echovault.EchoVault, ctx context.Context, key string, v } func TestEchoVault_SUBSTR(t *testing.T) { - server, _ := echovault.NewEchoVault( - echovault.WithCommands(str.Commands()), - echovault.WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -200,13 +203,7 @@ func TestEchoVault_SUBSTR(t *testing.T) { } func TestEchoVault_SETRANGE(t *testing.T) { - server, _ := echovault.NewEchoVault( - echovault.WithCommands(str.Commands()), - echovault.WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -294,13 +291,7 @@ func TestEchoVault_SETRANGE(t *testing.T) { } func TestEchoVault_STRLEN(t *testing.T) { - server, _ := echovault.NewEchoVault( - echovault.WithCommands(str.Commands()), - echovault.WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string diff --git a/test/modules/string/commands_test.go b/test/modules/string/commands_test.go index 22ce5179..9497e45c 100644 --- a/test/modules/string/commands_test.go +++ b/test/modules/string/commands_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package str_test +package str import ( "bytes" @@ -26,6 +26,7 @@ import ( str "github.com/echovault/echovault/pkg/modules/string" "github.com/echovault/echovault/pkg/types" "github.com/tidwall/resp" + "net" "strconv" "strings" "testing" @@ -43,15 +44,43 @@ func init() { ) } -func getHandler(command string) types.HandlerFunc { +func getHandler(commands ...string) types.HandlerFunc { + if len(commands) == 0 { + return nil + } for _, c := range mockServer.GetAllCommands() { - if strings.EqualFold(command, c.Command) { + if strings.EqualFold(commands[0], c.Command) && len(commands) == 1 { + // Get command handler return c.HandlerFunc } + if strings.EqualFold(commands[0], c.Command) { + // Get sub-command handler + for _, sc := range c.SubCommands { + if strings.EqualFold(commands[1], sc.Command) { + return sc.HandlerFunc + } + } + } } return nil } +func getHandlerFuncParams(ctx context.Context, cmd []string, conn *net.Conn) types.HandlerFuncParams { + return types.HandlerFuncParams{ + Context: ctx, + Command: cmd, + Connection: conn, + KeyExists: mockServer.KeyExists, + CreateKeyAndLock: mockServer.CreateKeyAndLock, + KeyLock: mockServer.KeyLock, + KeyRLock: mockServer.KeyRLock, + KeyUnlock: mockServer.KeyUnlock, + KeyRUnlock: mockServer.KeyRUnlock, + GetValue: mockServer.GetValue, + SetValue: mockServer.SetValue, + } +} + func Test_HandleSetRange(t *testing.T) { tests := []struct { name string @@ -176,17 +205,7 @@ func Test_HandleSetRange(t *testing.T) { return } - res, err := handler(types.HandlerFuncParams{ - Context: ctx, - Command: test.command, - Connection: nil, - KeyExists: mockServer.KeyExists, - CreateKeyAndLock: mockServer.CreateKeyAndLock, - KeyLock: mockServer.KeyLock, - KeyUnlock: mockServer.KeyUnlock, - GetValue: mockServer.GetValue, - SetValue: mockServer.SetValue, - }) + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { @@ -291,16 +310,7 @@ func Test_HandleStrLen(t *testing.T) { return } - res, err := handler(types.HandlerFuncParams{ - Context: ctx, - Command: test.command, - Connection: nil, - KeyExists: mockServer.KeyExists, - KeyRLock: mockServer.KeyRLock, - KeyRUnlock: mockServer.KeyRUnlock, - GetValue: mockServer.GetValue, - SetValue: mockServer.SetValue, - }) + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { @@ -436,16 +446,7 @@ func Test_HandleSubStr(t *testing.T) { return } - res, err := handler(types.HandlerFuncParams{ - Context: ctx, - Command: test.command, - Connection: nil, - KeyExists: mockServer.KeyExists, - KeyRLock: mockServer.KeyRLock, - KeyRUnlock: mockServer.KeyRUnlock, - GetValue: mockServer.GetValue, - SetValue: mockServer.SetValue, - }) + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { From b6ddb43a4945629daaa6d0283d5cef231439fe01 Mon Sep 17 00:00:00 2001 From: Kelvin Clement Mwinuka Date: Wed, 24 Apr 2024 22:37:16 +0800 Subject: [PATCH 3/6] Removed duplicate imports for set, sorted_set, pubsub and acl modules. Moved /modules from /pkg to /internal. Delted commands package: Commands will now be automatically loaded when an EchoVault instance is initialised. --- Makefile | 2 +- cmd/main.go | 2 - internal/{ => modules}/acl/acl.go | 0 {pkg => internal}/modules/acl/commands.go | 23 +- internal/{ => modules}/acl/user.go | 0 {pkg => internal}/modules/admin/commands.go | 0 .../modules/connection/commands.go | 0 {pkg => internal}/modules/generic/commands.go | 0 .../modules/generic/key_funcs.go | 0 {pkg => internal}/modules/generic/utils.go | 0 {pkg => internal}/modules/hash/commands.go | 0 {pkg => internal}/modules/hash/key_funcs.go | 0 {pkg => internal}/modules/list/commands.go | 0 {pkg => internal}/modules/list/key_funcs.go | 0 internal/{ => modules}/pubsub/channel.go | 0 {pkg => internal}/modules/pubsub/commands.go | 13 +- internal/{ => modules}/pubsub/pubsub.go | 0 {pkg => internal}/modules/set/commands.go | 71 ++- {pkg => internal}/modules/set/key_funcs.go | 0 internal/{ => modules}/set/set.go | 0 .../modules/sorted_set/commands.go | 175 +++--- .../modules/sorted_set/key_funcs.go | 0 .../{ => modules}/sorted_set/sorted_set.go | 0 {pkg => internal}/modules/sorted_set/utils.go | 77 +++ {pkg => internal}/modules/string/commands.go | 0 {pkg => internal}/modules/string/key_funcs.go | 0 internal/sorted_set/utils.go | 98 ---- pkg/commands/commands.go | 31 - pkg/echovault/echovault.go | 27 +- pkg/echovault/keyspace.go | 13 - test/modules/acl/commands_test.go | 258 ++++----- test/modules/admin/commands_test.go | 2 - test/modules/connection/commands_test.go | 2 - test/modules/generic/api_generic_test.go | 2 - test/modules/generic/commands_test.go | 2 - test/modules/hash/api_hash_test.go | 2 - test/modules/hash/commands_test.go | 2 - test/modules/list/api_list_test.go | 2 - test/modules/list/commands_test.go | 2 - test/modules/pubsub/commands_test.go | 20 +- test/modules/set/api_set_test.go | 4 +- test/modules/set/commands_test.go | 4 +- .../modules/sorted_set/api_sorted_set_test.go | 538 +++++++++--------- test/modules/sorted_set/commands_test.go | 4 +- test/modules/string/api_string_test.go | 2 - test/modules/string/commands_test.go | 2 - 46 files changed, 645 insertions(+), 735 deletions(-) rename internal/{ => modules}/acl/acl.go (100%) rename {pkg => internal}/modules/acl/commands.go (96%) rename internal/{ => modules}/acl/user.go (100%) rename {pkg => internal}/modules/admin/commands.go (100%) rename {pkg => internal}/modules/connection/commands.go (100%) rename {pkg => internal}/modules/generic/commands.go (100%) rename {pkg => internal}/modules/generic/key_funcs.go (100%) rename {pkg => internal}/modules/generic/utils.go (100%) rename {pkg => internal}/modules/hash/commands.go (100%) rename {pkg => internal}/modules/hash/key_funcs.go (100%) rename {pkg => internal}/modules/list/commands.go (100%) rename {pkg => internal}/modules/list/key_funcs.go (100%) rename internal/{ => modules}/pubsub/channel.go (100%) rename {pkg => internal}/modules/pubsub/commands.go (95%) rename internal/{ => modules}/pubsub/pubsub.go (100%) rename {pkg => internal}/modules/set/commands.go (92%) rename {pkg => internal}/modules/set/key_funcs.go (100%) rename internal/{ => modules}/set/set.go (100%) rename {pkg => internal}/modules/sorted_set/commands.go (91%) rename {pkg => internal}/modules/sorted_set/key_funcs.go (100%) rename internal/{ => modules}/sorted_set/sorted_set.go (100%) rename {pkg => internal}/modules/sorted_set/utils.go (62%) rename {pkg => internal}/modules/string/commands.go (100%) rename {pkg => internal}/modules/string/key_funcs.go (100%) delete mode 100644 internal/sorted_set/utils.go delete mode 100644 pkg/commands/commands.go diff --git a/Makefile b/Makefile index 7b76abbd..5bd7f5d8 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ build: run: make build && docker-compose up --build -test-normal: +test-unit: go clean -testcache && go test ./... -coverprofile coverage/coverage.out test-race: diff --git a/cmd/main.go b/cmd/main.go index 7719d87a..d0ce2c0b 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -18,7 +18,6 @@ import ( "context" "github.com/echovault/echovault/internal" "github.com/echovault/echovault/internal/config" - "github.com/echovault/echovault/pkg/commands" "github.com/echovault/echovault/pkg/echovault" "log" "os" @@ -49,7 +48,6 @@ func main() { server, err := echovault.NewEchoVault( echovault.WithContext(ctx), echovault.WithConfig(conf), - echovault.WithCommands(commands.All()), ) if err != nil { diff --git a/internal/acl/acl.go b/internal/modules/acl/acl.go similarity index 100% rename from internal/acl/acl.go rename to internal/modules/acl/acl.go diff --git a/pkg/modules/acl/commands.go b/internal/modules/acl/commands.go similarity index 96% rename from pkg/modules/acl/commands.go rename to internal/modules/acl/commands.go index 68e05ba0..1f86baee 100644 --- a/pkg/modules/acl/commands.go +++ b/internal/modules/acl/commands.go @@ -18,7 +18,6 @@ import ( "encoding/json" "errors" "fmt" - internal_acl "github.com/echovault/echovault/internal/acl" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/types" "gopkg.in/yaml.v3" @@ -33,7 +32,7 @@ func handleAuth(params types.HandlerFuncParams) ([]byte, error) { if len(params.Command) < 2 || len(params.Command) > 3 { return nil, errors.New(constants.WrongArgsResponse) } - acl, ok := params.GetACL().(*internal_acl.ACL) + acl, ok := params.GetACL().(*ACL) if !ok { return nil, errors.New("could not load ACL") } @@ -48,12 +47,12 @@ func handleGetUser(params types.HandlerFuncParams) ([]byte, error) { return nil, errors.New(constants.WrongArgsResponse) } - acl, ok := params.GetACL().(*internal_acl.ACL) + acl, ok := params.GetACL().(*ACL) if !ok { return nil, errors.New("could not load ACL") } - var user *internal_acl.User + var user *User userFound := false for _, u := range acl.Users { if u.Username == params.Command[2] { @@ -221,7 +220,7 @@ func handleCat(params types.HandlerFuncParams) ([]byte, error) { } func handleUsers(params types.HandlerFuncParams) ([]byte, error) { - acl, ok := params.GetACL().(*internal_acl.ACL) + acl, ok := params.GetACL().(*ACL) if !ok { return nil, errors.New("could not load ACL") } @@ -234,7 +233,7 @@ func handleUsers(params types.HandlerFuncParams) ([]byte, error) { } func handleSetUser(params types.HandlerFuncParams) ([]byte, error) { - acl, ok := params.GetACL().(*internal_acl.ACL) + acl, ok := params.GetACL().(*ACL) if !ok { return nil, errors.New("could not load ACL") } @@ -248,7 +247,7 @@ func handleDelUser(params types.HandlerFuncParams) ([]byte, error) { if len(params.Command) < 3 { return nil, errors.New(constants.WrongArgsResponse) } - acl, ok := params.GetACL().(*internal_acl.ACL) + acl, ok := params.GetACL().(*ACL) if !ok { return nil, errors.New("could not load ACL") } @@ -259,7 +258,7 @@ func handleDelUser(params types.HandlerFuncParams) ([]byte, error) { } func handleWhoAmI(params types.HandlerFuncParams) ([]byte, error) { - acl, ok := params.GetACL().(*internal_acl.ACL) + acl, ok := params.GetACL().(*ACL) if !ok { return nil, errors.New("could not load ACL") } @@ -271,7 +270,7 @@ func handleList(params types.HandlerFuncParams) ([]byte, error) { if len(params.Command) > 2 { return nil, errors.New(constants.WrongArgsResponse) } - acl, ok := params.GetACL().(*internal_acl.ACL) + acl, ok := params.GetACL().(*ACL) if !ok { return nil, errors.New("could not load ACL") } @@ -368,7 +367,7 @@ func handleLoad(params types.HandlerFuncParams) ([]byte, error) { return nil, errors.New(constants.WrongArgsResponse) } - acl, ok := params.GetACL().(*internal_acl.ACL) + acl, ok := params.GetACL().(*ACL) if !ok { return nil, errors.New("could not load ACL") } @@ -389,7 +388,7 @@ func handleLoad(params types.HandlerFuncParams) ([]byte, error) { ext := path.Ext(f.Name()) - var users []*internal_acl.User + var users []*User if ext == ".json" { if err := json.NewDecoder(f).Decode(&users); err != nil { @@ -435,7 +434,7 @@ func handleSave(params types.HandlerFuncParams) ([]byte, error) { return nil, errors.New(constants.WrongArgsResponse) } - acl, ok := params.GetACL().(*internal_acl.ACL) + acl, ok := params.GetACL().(*ACL) if !ok { return nil, errors.New("could not load ACL") } diff --git a/internal/acl/user.go b/internal/modules/acl/user.go similarity index 100% rename from internal/acl/user.go rename to internal/modules/acl/user.go diff --git a/pkg/modules/admin/commands.go b/internal/modules/admin/commands.go similarity index 100% rename from pkg/modules/admin/commands.go rename to internal/modules/admin/commands.go diff --git a/pkg/modules/connection/commands.go b/internal/modules/connection/commands.go similarity index 100% rename from pkg/modules/connection/commands.go rename to internal/modules/connection/commands.go diff --git a/pkg/modules/generic/commands.go b/internal/modules/generic/commands.go similarity index 100% rename from pkg/modules/generic/commands.go rename to internal/modules/generic/commands.go diff --git a/pkg/modules/generic/key_funcs.go b/internal/modules/generic/key_funcs.go similarity index 100% rename from pkg/modules/generic/key_funcs.go rename to internal/modules/generic/key_funcs.go diff --git a/pkg/modules/generic/utils.go b/internal/modules/generic/utils.go similarity index 100% rename from pkg/modules/generic/utils.go rename to internal/modules/generic/utils.go diff --git a/pkg/modules/hash/commands.go b/internal/modules/hash/commands.go similarity index 100% rename from pkg/modules/hash/commands.go rename to internal/modules/hash/commands.go diff --git a/pkg/modules/hash/key_funcs.go b/internal/modules/hash/key_funcs.go similarity index 100% rename from pkg/modules/hash/key_funcs.go rename to internal/modules/hash/key_funcs.go diff --git a/pkg/modules/list/commands.go b/internal/modules/list/commands.go similarity index 100% rename from pkg/modules/list/commands.go rename to internal/modules/list/commands.go diff --git a/pkg/modules/list/key_funcs.go b/internal/modules/list/key_funcs.go similarity index 100% rename from pkg/modules/list/key_funcs.go rename to internal/modules/list/key_funcs.go diff --git a/internal/pubsub/channel.go b/internal/modules/pubsub/channel.go similarity index 100% rename from internal/pubsub/channel.go rename to internal/modules/pubsub/channel.go diff --git a/pkg/modules/pubsub/commands.go b/internal/modules/pubsub/commands.go similarity index 95% rename from pkg/modules/pubsub/commands.go rename to internal/modules/pubsub/commands.go index e8c0f79e..0d876b34 100644 --- a/pkg/modules/pubsub/commands.go +++ b/internal/modules/pubsub/commands.go @@ -17,14 +17,13 @@ package pubsub import ( "errors" "fmt" - internal_pubsub "github.com/echovault/echovault/internal/pubsub" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/types" "strings" ) func handleSubscribe(params types.HandlerFuncParams) ([]byte, error) { - pubsub, ok := params.GetPubSub().(*internal_pubsub.PubSub) + pubsub, ok := params.GetPubSub().(*PubSub) if !ok { return nil, errors.New("could not load pubsub module") } @@ -42,7 +41,7 @@ func handleSubscribe(params types.HandlerFuncParams) ([]byte, error) { } func handleUnsubscribe(params types.HandlerFuncParams) ([]byte, error) { - pubsub, ok := params.GetPubSub().(*internal_pubsub.PubSub) + pubsub, ok := params.GetPubSub().(*PubSub) if !ok { return nil, errors.New("could not load pubsub module") } @@ -55,7 +54,7 @@ func handleUnsubscribe(params types.HandlerFuncParams) ([]byte, error) { } func handlePublish(params types.HandlerFuncParams) ([]byte, error) { - pubsub, ok := params.GetPubSub().(*internal_pubsub.PubSub) + pubsub, ok := params.GetPubSub().(*PubSub) if !ok { return nil, errors.New("could not load pubsub module") } @@ -71,7 +70,7 @@ func handlePubSubChannels(params types.HandlerFuncParams) ([]byte, error) { return nil, errors.New(constants.WrongArgsResponse) } - pubsub, ok := params.GetPubSub().(*internal_pubsub.PubSub) + pubsub, ok := params.GetPubSub().(*PubSub) if !ok { return nil, errors.New("could not load pubsub module") } @@ -85,7 +84,7 @@ func handlePubSubChannels(params types.HandlerFuncParams) ([]byte, error) { } func handlePubSubNumPat(params types.HandlerFuncParams) ([]byte, error) { - pubsub, ok := params.GetPubSub().(*internal_pubsub.PubSub) + pubsub, ok := params.GetPubSub().(*PubSub) if !ok { return nil, errors.New("could not load pubsub module") } @@ -94,7 +93,7 @@ func handlePubSubNumPat(params types.HandlerFuncParams) ([]byte, error) { } func handlePubSubNumSubs(params types.HandlerFuncParams) ([]byte, error) { - pubsub, ok := params.GetPubSub().(*internal_pubsub.PubSub) + pubsub, ok := params.GetPubSub().(*PubSub) if !ok { return nil, errors.New("could not load pubsub module") } diff --git a/internal/pubsub/pubsub.go b/internal/modules/pubsub/pubsub.go similarity index 100% rename from internal/pubsub/pubsub.go rename to internal/modules/pubsub/pubsub.go diff --git a/pkg/modules/set/commands.go b/internal/modules/set/commands.go similarity index 92% rename from pkg/modules/set/commands.go rename to internal/modules/set/commands.go index f7f4c729..88abedf0 100644 --- a/pkg/modules/set/commands.go +++ b/internal/modules/set/commands.go @@ -18,7 +18,6 @@ import ( "errors" "fmt" "github.com/echovault/echovault/internal" - internal_set "github.com/echovault/echovault/internal/set" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/types" "slices" @@ -33,10 +32,10 @@ func handleSADD(params types.HandlerFuncParams) ([]byte, error) { key := keys.WriteKeys[0] - var set *internal_set.Set + var set *Set if !params.KeyExists(params.Context, key) { - set = internal_set.NewSet(params.Command[2:]) + set = NewSet(params.Command[2:]) if ok, err := params.CreateKeyAndLock(params.Context, key); !ok && err != nil { return nil, err } @@ -52,7 +51,7 @@ func handleSADD(params types.HandlerFuncParams) ([]byte, error) { } defer params.KeyUnlock(params.Context, key) - set, ok := params.GetValue(params.Context, key).(*internal_set.Set) + set, ok := params.GetValue(params.Context, key).(*Set) if !ok { return nil, fmt.Errorf("value at key %s is not a set", key) } @@ -79,7 +78,7 @@ func handleSCARD(params types.HandlerFuncParams) ([]byte, error) { } defer params.KeyRUnlock(params.Context, key) - set, ok := params.GetValue(params.Context, key).(*internal_set.Set) + set, ok := params.GetValue(params.Context, key).(*Set) if !ok { return nil, fmt.Errorf("value at key %s is not a set", key) } @@ -103,7 +102,7 @@ func handleSDIFF(params types.HandlerFuncParams) ([]byte, error) { return nil, err } defer params.KeyRUnlock(params.Context, keys.ReadKeys[0]) - baseSet, ok := params.GetValue(params.Context, keys.ReadKeys[0]).(*internal_set.Set) + baseSet, ok := params.GetValue(params.Context, keys.ReadKeys[0]).(*Set) if !ok { return nil, fmt.Errorf("value at key %s is not a set", keys.ReadKeys[0]) } @@ -127,9 +126,9 @@ func handleSDIFF(params types.HandlerFuncParams) ([]byte, error) { locks[key] = true } - var sets []*internal_set.Set + var sets []*Set for _, key := range params.Command[2:] { - set, ok := params.GetValue(params.Context, key).(*internal_set.Set) + set, ok := params.GetValue(params.Context, key).(*Set) if !ok { continue } @@ -166,7 +165,7 @@ func handleSDIFFSTORE(params types.HandlerFuncParams) ([]byte, error) { return nil, err } defer params.KeyRUnlock(params.Context, keys.ReadKeys[0]) - baseSet, ok := params.GetValue(params.Context, keys.ReadKeys[0]).(*internal_set.Set) + baseSet, ok := params.GetValue(params.Context, keys.ReadKeys[0]).(*Set) if !ok { return nil, fmt.Errorf("value at key %s is not a set", keys.ReadKeys[0]) } @@ -190,9 +189,9 @@ func handleSDIFFSTORE(params types.HandlerFuncParams) ([]byte, error) { locks[key] = true } - var sets []*internal_set.Set + var sets []*Set for _, key := range keys.ReadKeys[1:] { - set, ok := params.GetValue(params.Context, key).(*internal_set.Set) + set, ok := params.GetValue(params.Context, key).(*Set) if !ok { continue } @@ -252,10 +251,10 @@ func handleSINTER(params types.HandlerFuncParams) ([]byte, error) { locks[key] = true } - var sets []*internal_set.Set + var sets []*Set for key, _ := range locks { - set, ok := params.GetValue(params.Context, key).(*internal_set.Set) + set, ok := params.GetValue(params.Context, key).(*Set) if !ok { // If the value at the key is not a set, return error return nil, fmt.Errorf("value at key %s is not a set", key) @@ -267,7 +266,7 @@ func handleSINTER(params types.HandlerFuncParams) ([]byte, error) { return nil, fmt.Errorf("not enough sets in the keys provided") } - intersect, _ := internal_set.Intersection(0, sets...) + intersect, _ := Intersection(0, sets...) elems := intersect.GetAll() res := fmt.Sprintf("*%d", len(elems)) @@ -328,10 +327,10 @@ func handleSINTERCARD(params types.HandlerFuncParams) ([]byte, error) { locks[key] = true } - var sets []*internal_set.Set + var sets []*Set for key, _ := range locks { - set, ok := params.GetValue(params.Context, key).(*internal_set.Set) + set, ok := params.GetValue(params.Context, key).(*Set) if !ok { // If the value at the key is not a set, return error return nil, fmt.Errorf("value at key %s is not a set", key) @@ -343,7 +342,7 @@ func handleSINTERCARD(params types.HandlerFuncParams) ([]byte, error) { return nil, fmt.Errorf("not enough sets in the keys provided") } - intersect, _ := internal_set.Intersection(limit, sets...) + intersect, _ := Intersection(limit, sets...) return []byte(fmt.Sprintf(":%d\r\n", intersect.Cardinality())), nil } @@ -374,10 +373,10 @@ func handleSINTERSTORE(params types.HandlerFuncParams) ([]byte, error) { locks[key] = true } - var sets []*internal_set.Set + var sets []*Set for key, _ := range locks { - set, ok := params.GetValue(params.Context, key).(*internal_set.Set) + set, ok := params.GetValue(params.Context, key).(*Set) if !ok { // If the value at the key is not a set, return error return nil, fmt.Errorf("value at key %s is not a set", key) @@ -385,7 +384,7 @@ func handleSINTERSTORE(params types.HandlerFuncParams) ([]byte, error) { sets = append(sets, set) } - intersect, _ := internal_set.Intersection(0, sets...) + intersect, _ := Intersection(0, sets...) destination := keys.WriteKeys[0] if params.KeyExists(params.Context, destination) { @@ -423,7 +422,7 @@ func handleSISMEMBER(params types.HandlerFuncParams) ([]byte, error) { } defer params.KeyRUnlock(params.Context, key) - set, ok := params.GetValue(params.Context, key).(*internal_set.Set) + set, ok := params.GetValue(params.Context, key).(*Set) if !ok { return nil, fmt.Errorf("value at key %s is not a set", key) } @@ -452,7 +451,7 @@ func handleSMEMBERS(params types.HandlerFuncParams) ([]byte, error) { } defer params.KeyRUnlock(params.Context, key) - set, ok := params.GetValue(params.Context, key).(*internal_set.Set) + set, ok := params.GetValue(params.Context, key).(*Set) if !ok { return nil, fmt.Errorf("value at key %s is not a set", key) } @@ -495,7 +494,7 @@ func handleSMISMEMBER(params types.HandlerFuncParams) ([]byte, error) { } defer params.KeyRUnlock(params.Context, key) - set, ok := params.GetValue(params.Context, key).(*internal_set.Set) + set, ok := params.GetValue(params.Context, key).(*Set) if !ok { return nil, fmt.Errorf("value at key %s is not a set", key) } @@ -531,12 +530,12 @@ func handleSMOVE(params types.HandlerFuncParams) ([]byte, error) { } defer params.KeyUnlock(params.Context, source) - sourceSet, ok := params.GetValue(params.Context, source).(*internal_set.Set) + sourceSet, ok := params.GetValue(params.Context, source).(*Set) if !ok { return nil, errors.New("source is not a set") } - var destinationSet *internal_set.Set + var destinationSet *Set if !params.KeyExists(params.Context, destination) { // Destination key does not exist @@ -544,7 +543,7 @@ func handleSMOVE(params types.HandlerFuncParams) ([]byte, error) { return nil, err } defer params.KeyUnlock(params.Context, destination) - destinationSet = internal_set.NewSet([]string{}) + destinationSet = NewSet([]string{}) if err = params.SetValue(params.Context, destination, destinationSet); err != nil { return nil, err } @@ -554,7 +553,7 @@ func handleSMOVE(params types.HandlerFuncParams) ([]byte, error) { return nil, err } defer params.KeyUnlock(params.Context, destination) - ds, ok := params.GetValue(params.Context, destination).(*internal_set.Set) + ds, ok := params.GetValue(params.Context, destination).(*Set) if !ok { return nil, errors.New("destination is not a set") } @@ -592,7 +591,7 @@ func handleSPOP(params types.HandlerFuncParams) ([]byte, error) { } defer params.KeyUnlock(params.Context, key) - set, ok := params.GetValue(params.Context, key).(*internal_set.Set) + set, ok := params.GetValue(params.Context, key).(*Set) if !ok { return nil, fmt.Errorf("value at %s is not a set", key) } @@ -636,7 +635,7 @@ func handleSRANDMEMBER(params types.HandlerFuncParams) ([]byte, error) { } defer params.KeyUnlock(params.Context, key) - set, ok := params.GetValue(params.Context, key).(*internal_set.Set) + set, ok := params.GetValue(params.Context, key).(*Set) if !ok { return nil, fmt.Errorf("value at %s is not a set", key) } @@ -672,7 +671,7 @@ func handleSREM(params types.HandlerFuncParams) ([]byte, error) { } defer params.KeyUnlock(params.Context, key) - set, ok := params.GetValue(params.Context, key).(*internal_set.Set) + set, ok := params.GetValue(params.Context, key).(*Set) if !ok { return nil, fmt.Errorf("value at key %s is not a set", key) } @@ -707,20 +706,20 @@ func handleSUNION(params types.HandlerFuncParams) ([]byte, error) { locks[key] = true } - var sets []*internal_set.Set + var sets []*Set for key, locked := range locks { if !locked { continue } - set, ok := params.GetValue(params.Context, key).(*internal_set.Set) + set, ok := params.GetValue(params.Context, key).(*Set) if !ok { return nil, fmt.Errorf("value at key %s is not a set", key) } sets = append(sets, set) } - union := internal_set.Union(sets...) + union := Union(sets...) res := fmt.Sprintf("*%d", union.Cardinality()) for i, e := range union.GetAll() { @@ -758,20 +757,20 @@ func handleSUNIONSTORE(params types.HandlerFuncParams) ([]byte, error) { locks[key] = true } - var sets []*internal_set.Set + var sets []*Set for key, locked := range locks { if !locked { continue } - set, ok := params.GetValue(params.Context, key).(*internal_set.Set) + set, ok := params.GetValue(params.Context, key).(*Set) if !ok { return nil, fmt.Errorf("value at key %s is not a set", key) } sets = append(sets, set) } - union := internal_set.Union(sets...) + union := Union(sets...) destination := keys.WriteKeys[0] diff --git a/pkg/modules/set/key_funcs.go b/internal/modules/set/key_funcs.go similarity index 100% rename from pkg/modules/set/key_funcs.go rename to internal/modules/set/key_funcs.go diff --git a/internal/set/set.go b/internal/modules/set/set.go similarity index 100% rename from internal/set/set.go rename to internal/modules/set/set.go diff --git a/pkg/modules/sorted_set/commands.go b/internal/modules/sorted_set/commands.go similarity index 91% rename from pkg/modules/sorted_set/commands.go rename to internal/modules/sorted_set/commands.go index d892fe43..27a86562 100644 --- a/pkg/modules/sorted_set/commands.go +++ b/internal/modules/sorted_set/commands.go @@ -19,7 +19,6 @@ import ( "errors" "fmt" "github.com/echovault/echovault/internal" - "github.com/echovault/echovault/internal/sorted_set" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/types" "math" @@ -63,7 +62,7 @@ func handleZADD(params types.HandlerFuncParams) ([]byte, error) { return nil, errors.New("score/member pairs must be float/string") } - var members []sorted_set.MemberParam + var members []MemberParam for i := 0; i < len(params.Command[membersStartIndex:]); i++ { if i%2 != 0 { @@ -77,29 +76,29 @@ func handleZADD(params types.HandlerFuncParams) ([]byte, error) { var s float64 if strings.ToLower(score.(string)) == "-inf" { s = math.Inf(-1) - members = append(members, sorted_set.MemberParam{ - Value: sorted_set.Value(params.Command[membersStartIndex:][i+1]), - Score: sorted_set.Score(s), + members = append(members, MemberParam{ + Value: Value(params.Command[membersStartIndex:][i+1]), + Score: Score(s), }) } if strings.ToLower(score.(string)) == "+inf" { s = math.Inf(1) - members = append(members, sorted_set.MemberParam{ - Value: sorted_set.Value(params.Command[membersStartIndex:][i+1]), - Score: sorted_set.Score(s), + members = append(members, MemberParam{ + Value: Value(params.Command[membersStartIndex:][i+1]), + Score: Score(s), }) } case float64: s, _ := score.(float64) - members = append(members, sorted_set.MemberParam{ - Value: sorted_set.Value(params.Command[membersStartIndex:][i+1]), - Score: sorted_set.Score(s), + members = append(members, MemberParam{ + Value: Value(params.Command[membersStartIndex:][i+1]), + Score: Score(s), }) case int: s, _ := score.(int) - members = append(members, sorted_set.MemberParam{ - Value: sorted_set.Value(params.Command[membersStartIndex:][i+1]), - Score: sorted_set.Score(s), + members = append(members, MemberParam{ + Value: Value(params.Command[membersStartIndex:][i+1]), + Score: Score(s), }) } } @@ -148,7 +147,7 @@ func handleZADD(params types.HandlerFuncParams) ([]byte, error) { return nil, err } defer params.KeyUnlock(params.Context, key) - set, ok := params.GetValue(params.Context, key).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, key).(*SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", key) } @@ -171,7 +170,7 @@ func handleZADD(params types.HandlerFuncParams) ([]byte, error) { } defer params.KeyUnlock(params.Context, key) - set := sorted_set.NewSortedSet(members) + set := NewSortedSet(members) if err = params.SetValue(params.Context, key, set); err != nil { return nil, err } @@ -195,7 +194,7 @@ func handleZCARD(params types.HandlerFuncParams) ([]byte, error) { } defer params.KeyRUnlock(params.Context, key) - set, ok := params.GetValue(params.Context, key).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, key).(*SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", key) } @@ -211,40 +210,40 @@ func handleZCOUNT(params types.HandlerFuncParams) ([]byte, error) { key := keys.ReadKeys[0] - minimum := sorted_set.Score(math.Inf(-1)) + minimum := Score(math.Inf(-1)) switch internal.AdaptType(params.Command[2]).(type) { default: return nil, errors.New("min constraint must be a double") case string: if strings.ToLower(params.Command[2]) == "+inf" { - minimum = sorted_set.Score(math.Inf(1)) + minimum = Score(math.Inf(1)) } else { return nil, errors.New("min constraint must be a double") } case float64: s, _ := internal.AdaptType(params.Command[2]).(float64) - minimum = sorted_set.Score(s) + minimum = Score(s) case int: s, _ := internal.AdaptType(params.Command[2]).(int) - minimum = sorted_set.Score(s) + minimum = Score(s) } - maximum := sorted_set.Score(math.Inf(1)) + maximum := Score(math.Inf(1)) switch internal.AdaptType(params.Command[3]).(type) { default: return nil, errors.New("max constraint must be a double") case string: if strings.ToLower(params.Command[3]) == "-inf" { - maximum = sorted_set.Score(math.Inf(-1)) + maximum = Score(math.Inf(-1)) } else { return nil, errors.New("max constraint must be a double") } case float64: s, _ := internal.AdaptType(params.Command[3]).(float64) - maximum = sorted_set.Score(s) + maximum = Score(s) case int: s, _ := internal.AdaptType(params.Command[3]).(int) - maximum = sorted_set.Score(s) + maximum = Score(s) } if !params.KeyExists(params.Context, key) { @@ -256,12 +255,12 @@ func handleZCOUNT(params types.HandlerFuncParams) ([]byte, error) { } defer params.KeyRUnlock(params.Context, key) - set, ok := params.GetValue(params.Context, key).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, key).(*SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", key) } - var members []sorted_set.MemberParam + var members []MemberParam for _, m := range set.GetAll() { if m.Score >= minimum && m.Score <= maximum { members = append(members, m) @@ -290,7 +289,7 @@ func handleZLEXCOUNT(params types.HandlerFuncParams) ([]byte, error) { } defer params.KeyRUnlock(params.Context, key) - set, ok := params.GetValue(params.Context, key).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, key).(*SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", key) } @@ -347,13 +346,13 @@ func handleZDIFF(params types.HandlerFuncParams) ([]byte, error) { return nil, err } defer params.KeyRUnlock(params.Context, keys.ReadKeys[0]) - baseSortedSet, ok := params.GetValue(params.Context, keys.ReadKeys[0]).(*sorted_set.SortedSet) + baseSortedSet, ok := params.GetValue(params.Context, keys.ReadKeys[0]).(*SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", keys.ReadKeys[0]) } // Extract the remaining sets - var sets []*sorted_set.SortedSet + var sets []*SortedSet for i := 1; i < len(keys.ReadKeys); i++ { if !params.KeyExists(params.Context, keys.ReadKeys[i]) { @@ -364,7 +363,7 @@ func handleZDIFF(params types.HandlerFuncParams) ([]byte, error) { return nil, err } locks[keys.ReadKeys[i]] = locked - set, ok := params.GetValue(params.Context, keys.ReadKeys[i]).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, keys.ReadKeys[i]).(*SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", keys.ReadKeys[i]) } @@ -415,19 +414,19 @@ func handleZDIFFSTORE(params types.HandlerFuncParams) ([]byte, error) { return nil, err } defer params.KeyRUnlock(params.Context, keys.ReadKeys[0]) - baseSortedSet, ok := params.GetValue(params.Context, keys.ReadKeys[0]).(*sorted_set.SortedSet) + baseSortedSet, ok := params.GetValue(params.Context, keys.ReadKeys[0]).(*SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", keys.ReadKeys[0]) } - var sets []*sorted_set.SortedSet + var sets []*SortedSet for i := 1; i < len(keys.ReadKeys); i++ { if params.KeyExists(params.Context, keys.ReadKeys[i]) { if _, err = params.KeyRLock(params.Context, keys.ReadKeys[i]); err != nil { return nil, err } - set, ok := params.GetValue(params.Context, keys.ReadKeys[i]).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, keys.ReadKeys[i]).(*SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", keys.ReadKeys[i]) } @@ -462,26 +461,26 @@ func handleZINCRBY(params types.HandlerFuncParams) ([]byte, error) { } key := keys.WriteKeys[0] - member := sorted_set.Value(params.Command[3]) - var increment sorted_set.Score + member := Value(params.Command[3]) + var increment Score switch internal.AdaptType(params.Command[2]).(type) { default: return nil, errors.New("increment must be a double") case string: if strings.EqualFold("-inf", strings.ToLower(params.Command[2])) { - increment = sorted_set.Score(math.Inf(-1)) + increment = Score(math.Inf(-1)) } else if strings.EqualFold("+inf", strings.ToLower(params.Command[2])) { - increment = sorted_set.Score(math.Inf(1)) + increment = Score(math.Inf(1)) } else { return nil, errors.New("increment must be a double") } case float64: s, _ := internal.AdaptType(params.Command[2]).(float64) - increment = sorted_set.Score(s) + increment = Score(s) case int: s, _ := internal.AdaptType(params.Command[2]).(int) - increment = sorted_set.Score(s) + increment = Score(s) } if !params.KeyExists(params.Context, key) { @@ -493,7 +492,7 @@ func handleZINCRBY(params types.HandlerFuncParams) ([]byte, error) { if err = params.SetValue( params.Context, key, - sorted_set.NewSortedSet([]sorted_set.MemberParam{{Value: member, Score: increment}}), + NewSortedSet([]MemberParam{{Value: member, Score: increment}}), ); err != nil { return nil, err } @@ -505,12 +504,12 @@ func handleZINCRBY(params types.HandlerFuncParams) ([]byte, error) { return nil, err } defer params.KeyUnlock(params.Context, key) - set, ok := params.GetValue(params.Context, key).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, key).(*SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", key) } if _, err = set.AddOrUpdate( - []sorted_set.MemberParam{ + []MemberParam{ {Value: member, Score: increment}}, "xx", nil, @@ -542,7 +541,7 @@ func handleZINTER(params types.HandlerFuncParams) ([]byte, error) { } }() - var setParams []sorted_set.SortedSetParam + var setParams []SortedSetParam for i := 0; i < len(keys); i++ { if !params.KeyExists(params.Context, keys[i]) { @@ -553,17 +552,17 @@ func handleZINTER(params types.HandlerFuncParams) ([]byte, error) { return nil, err } locks[keys[i]] = true - set, ok := params.GetValue(params.Context, keys[i]).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, keys[i]).(*SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", keys[i]) } - setParams = append(setParams, sorted_set.SortedSetParam{ + setParams = append(setParams, SortedSetParam{ Set: set, Weight: weights[i], }) } - intersect := sorted_set.Intersect(aggregate, setParams...) + intersect := Intersect(aggregate, setParams...) res := fmt.Sprintf("*%d", intersect.Cardinality()) @@ -609,7 +608,7 @@ func handleZINTERSTORE(params types.HandlerFuncParams) ([]byte, error) { } }() - var setParams []sorted_set.SortedSetParam + var setParams []SortedSetParam for i := 0; i < len(keys); i++ { if !params.KeyExists(params.Context, keys[i]) { @@ -619,17 +618,17 @@ func handleZINTERSTORE(params types.HandlerFuncParams) ([]byte, error) { return nil, err } locks[keys[i]] = true - set, ok := params.GetValue(params.Context, keys[i]).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, keys[i]).(*SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", keys[i]) } - setParams = append(setParams, sorted_set.SortedSetParam{ + setParams = append(setParams, SortedSetParam{ Set: set, Weight: weights[i], }) } - intersect := sorted_set.Intersect(aggregate, setParams...) + intersect := Intersect(aggregate, setParams...) if params.KeyExists(params.Context, destination) && intersect.Cardinality() > 0 { if _, err = params.KeyLock(params.Context, destination); err != nil { @@ -700,7 +699,7 @@ func handleZMPOP(params types.HandlerFuncParams) ([]byte, error) { if _, err = params.KeyLock(params.Context, keys.WriteKeys[i]); err != nil { continue } - v, ok := params.GetValue(params.Context, keys.WriteKeys[i]).(*sorted_set.SortedSet) + v, ok := params.GetValue(params.Context, keys.WriteKeys[i]).(*SortedSet) if !ok || v.Cardinality() == 0 { params.KeyUnlock(params.Context, keys.WriteKeys[i]) continue @@ -760,7 +759,7 @@ func handleZPOP(params types.HandlerFuncParams) ([]byte, error) { } defer params.KeyUnlock(params.Context, key) - set, ok := params.GetValue(params.Context, key).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, key).(*SortedSet) if !ok { return nil, fmt.Errorf("value at key %s is not a sorted set", key) } @@ -797,7 +796,7 @@ func handleZMSCORE(params types.HandlerFuncParams) ([]byte, error) { } defer params.KeyRUnlock(params.Context, key) - set, ok := params.GetValue(params.Context, key).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, key).(*SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", key) } @@ -806,10 +805,10 @@ func handleZMSCORE(params types.HandlerFuncParams) ([]byte, error) { res := fmt.Sprintf("*%d", len(members)) - var member sorted_set.MemberObject + var member MemberObject for i := 0; i < len(members); i++ { - member = set.Get(sorted_set.Value(members[i])) + member = set.Get(Value(members[i])) if !member.Exists { res = fmt.Sprintf("%s\r\n$-1", res) } else { @@ -859,7 +858,7 @@ func handleZRANDMEMBER(params types.HandlerFuncParams) ([]byte, error) { } defer params.KeyRUnlock(params.Context, key) - set, ok := params.GetValue(params.Context, key).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, key).(*SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", key) } @@ -903,13 +902,13 @@ func handleZRANK(params types.HandlerFuncParams) ([]byte, error) { } defer params.KeyRUnlock(params.Context, key) - set, ok := params.GetValue(params.Context, key).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, key).(*SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", key) } members := set.GetAll() - slices.SortFunc(members, func(a, b sorted_set.MemberParam) int { + slices.SortFunc(members, func(a, b MemberParam) int { if strings.EqualFold(params.Command[0], "zrevrank") { return cmp.Compare(b.Score, a.Score) } @@ -917,7 +916,7 @@ func handleZRANK(params types.HandlerFuncParams) ([]byte, error) { }) for i := 0; i < len(members); i++ { - if members[i].Value == sorted_set.Value(member) { + if members[i].Value == Value(member) { if withscores { score := strconv.FormatFloat(float64(members[i].Score), 'f', -1, 64) return []byte(fmt.Sprintf("*2\r\n:%d\r\n$%d\r\n%s\r\n", i, len(score), score)), nil @@ -947,14 +946,14 @@ func handleZREM(params types.HandlerFuncParams) ([]byte, error) { } defer params.KeyUnlock(params.Context, key) - set, ok := params.GetValue(params.Context, key).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, key).(*SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", key) } deletedCount := 0 for _, m := range params.Command[2:] { - if set.Remove(sorted_set.Value(m)) { + if set.Remove(Value(m)) { deletedCount += 1 } } @@ -977,11 +976,11 @@ func handleZSCORE(params types.HandlerFuncParams) ([]byte, error) { return nil, err } defer params.KeyRUnlock(params.Context, key) - set, ok := params.GetValue(params.Context, key).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, key).(*SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", key) } - member := set.Get(sorted_set.Value(params.Command[2])) + member := set.Get(Value(params.Command[2])) if !member.Exists { return []byte("$-1\r\n"), nil } @@ -1020,13 +1019,13 @@ func handleZREMRANGEBYSCORE(params types.HandlerFuncParams) ([]byte, error) { } defer params.KeyUnlock(params.Context, key) - set, ok := params.GetValue(params.Context, key).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, key).(*SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", key) } for _, m := range set.GetAll() { - if m.Score >= sorted_set.Score(minimum) && m.Score <= sorted_set.Score(maximum) { + if m.Score >= Score(minimum) && m.Score <= Score(maximum) { set.Remove(m.Value) deletedCount += 1 } @@ -1062,7 +1061,7 @@ func handleZREMRANGEBYRANK(params types.HandlerFuncParams) ([]byte, error) { } defer params.KeyUnlock(params.Context, key) - set, ok := params.GetValue(params.Context, key).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, key).(*SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", key) } @@ -1079,7 +1078,7 @@ func handleZREMRANGEBYRANK(params types.HandlerFuncParams) ([]byte, error) { } members := set.GetAll() - slices.SortFunc(members, func(a, b sorted_set.MemberParam) int { + slices.SortFunc(members, func(a, b MemberParam) int { return cmp.Compare(a.Score, b.Score) }) @@ -1119,7 +1118,7 @@ func handleZREMRANGEBYLEX(params types.HandlerFuncParams) ([]byte, error) { } defer params.KeyUnlock(params.Context, key) - set, ok := params.GetValue(params.Context, key).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, key).(*SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", key) } @@ -1217,7 +1216,7 @@ func handleZRANGE(params types.HandlerFuncParams) ([]byte, error) { } defer params.KeyRUnlock(params.Context, key) - set, ok := params.GetValue(params.Context, key).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, key).(*SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", key) } @@ -1231,7 +1230,7 @@ func handleZRANGE(params types.HandlerFuncParams) ([]byte, error) { members := set.GetAll() if strings.EqualFold(policy, "byscore") { - slices.SortFunc(members, func(a, b sorted_set.MemberParam) int { + slices.SortFunc(members, func(a, b MemberParam) int { // Do a score sort if reverse { return cmp.Compare(b.Score, a.Score) @@ -1246,7 +1245,7 @@ func handleZRANGE(params types.HandlerFuncParams) ([]byte, error) { return []byte("*0\r\n"), nil } } - slices.SortFunc(members, func(a, b sorted_set.MemberParam) int { + slices.SortFunc(members, func(a, b MemberParam) int { if reverse { return internal.CompareLex(string(b.Value), string(a.Value)) } @@ -1254,14 +1253,14 @@ func handleZRANGE(params types.HandlerFuncParams) ([]byte, error) { }) } - var resultMembers []sorted_set.MemberParam + var resultMembers []MemberParam for i := offset; i <= count; i++ { if i >= len(members) { break } if strings.EqualFold(policy, "byscore") { - if members[i].Score >= sorted_set.Score(scoreStart) && members[i].Score <= sorted_set.Score(scoreStop) { + if members[i].Score >= Score(scoreStart) && members[i].Score <= Score(scoreStop) { resultMembers = append(resultMembers, members[i]) } continue @@ -1354,7 +1353,7 @@ func handleZRANGESTORE(params types.HandlerFuncParams) ([]byte, error) { } defer params.KeyRUnlock(params.Context, source) - set, ok := params.GetValue(params.Context, source).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, source).(*SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", source) } @@ -1368,7 +1367,7 @@ func handleZRANGESTORE(params types.HandlerFuncParams) ([]byte, error) { members := set.GetAll() if strings.EqualFold(policy, "byscore") { - slices.SortFunc(members, func(a, b sorted_set.MemberParam) int { + slices.SortFunc(members, func(a, b MemberParam) int { // Do a score sort if reverse { return cmp.Compare(b.Score, a.Score) @@ -1383,7 +1382,7 @@ func handleZRANGESTORE(params types.HandlerFuncParams) ([]byte, error) { return []byte(":0\r\n"), nil } } - slices.SortFunc(members, func(a, b sorted_set.MemberParam) int { + slices.SortFunc(members, func(a, b MemberParam) int { if reverse { return internal.CompareLex(string(b.Value), string(a.Value)) } @@ -1391,14 +1390,14 @@ func handleZRANGESTORE(params types.HandlerFuncParams) ([]byte, error) { }) } - var resultMembers []sorted_set.MemberParam + var resultMembers []MemberParam for i := offset; i <= count; i++ { if i >= len(members) { break } if strings.EqualFold(policy, "byscore") { - if members[i].Score >= sorted_set.Score(scoreStart) && members[i].Score <= sorted_set.Score(scoreStop) { + if members[i].Score >= Score(scoreStart) && members[i].Score <= Score(scoreStop) { resultMembers = append(resultMembers, members[i]) } continue @@ -1409,7 +1408,7 @@ func handleZRANGESTORE(params types.HandlerFuncParams) ([]byte, error) { } } - newSortedSet := sorted_set.NewSortedSet(resultMembers) + newSortedSet := NewSortedSet(resultMembers) if params.KeyExists(params.Context, destination) { if _, err = params.KeyLock(params.Context, destination); err != nil { @@ -1448,7 +1447,7 @@ func handleZUNION(params types.HandlerFuncParams) ([]byte, error) { } }() - var setParams []sorted_set.SortedSetParam + var setParams []SortedSetParam for i := 0; i < len(keys); i++ { if params.KeyExists(params.Context, keys[i]) { @@ -1456,18 +1455,18 @@ func handleZUNION(params types.HandlerFuncParams) ([]byte, error) { return nil, err } locks[keys[i]] = true - set, ok := params.GetValue(params.Context, keys[i]).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, keys[i]).(*SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", keys[i]) } - setParams = append(setParams, sorted_set.SortedSetParam{ + setParams = append(setParams, SortedSetParam{ Set: set, Weight: weights[i], }) } } - union := sorted_set.Union(aggregate, setParams...) + union := Union(aggregate, setParams...) res := fmt.Sprintf("*%d", union.Cardinality()) for _, m := range union.GetAll() { @@ -1510,7 +1509,7 @@ func handleZUNIONSTORE(params types.HandlerFuncParams) ([]byte, error) { } }() - var setParams []sorted_set.SortedSetParam + var setParams []SortedSetParam for i := 0; i < len(keys); i++ { if params.KeyExists(params.Context, keys[i]) { @@ -1518,18 +1517,18 @@ func handleZUNIONSTORE(params types.HandlerFuncParams) ([]byte, error) { return nil, err } locks[keys[i]] = true - set, ok := params.GetValue(params.Context, keys[i]).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, keys[i]).(*SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", keys[i]) } - setParams = append(setParams, sorted_set.SortedSetParam{ + setParams = append(setParams, SortedSetParam{ Set: set, Weight: weights[i], }) } } - union := sorted_set.Union(aggregate, setParams...) + union := Union(aggregate, setParams...) if params.KeyExists(params.Context, destination) { if _, err = params.KeyLock(params.Context, destination); err != nil { diff --git a/pkg/modules/sorted_set/key_funcs.go b/internal/modules/sorted_set/key_funcs.go similarity index 100% rename from pkg/modules/sorted_set/key_funcs.go rename to internal/modules/sorted_set/key_funcs.go diff --git a/internal/sorted_set/sorted_set.go b/internal/modules/sorted_set/sorted_set.go similarity index 100% rename from internal/sorted_set/sorted_set.go rename to internal/modules/sorted_set/sorted_set.go diff --git a/pkg/modules/sorted_set/utils.go b/internal/modules/sorted_set/utils.go similarity index 62% rename from pkg/modules/sorted_set/utils.go rename to internal/modules/sorted_set/utils.go index bde1a246..11638e26 100644 --- a/pkg/modules/sorted_set/utils.go +++ b/internal/modules/sorted_set/utils.go @@ -90,3 +90,80 @@ func extractKeysWeightsAggregateWithScores(cmd []string) ([]string, []int, strin return keys, weights, aggregate, withscores, nil } + +func validateUpdatePolicy(updatePolicy interface{}) (string, error) { + if updatePolicy == nil { + return "", nil + } + err := errors.New("update policy must be a string of Value NX or XX") + policy, ok := updatePolicy.(string) + if !ok { + return "", err + } + if !slices.Contains([]string{"nx", "xx"}, strings.ToLower(policy)) { + return "", err + } + return policy, nil +} + +func validateComparison(comparison interface{}) (string, error) { + if comparison == nil { + return "", nil + } + err := errors.New("comparison condition must be a string of Value LT or GT") + comp, ok := comparison.(string) + if !ok { + return "", err + } + if !slices.Contains([]string{"lt", "gt"}, strings.ToLower(comp)) { + return "", err + } + return comp, nil +} + +func validateChanged(changed interface{}) (string, error) { + if changed == nil { + return "", nil + } + err := errors.New("changed condition should be a string of Value CH") + ch, ok := changed.(string) + if !ok { + return "", err + } + if !strings.EqualFold(ch, "ch") { + return "", err + } + return ch, nil +} + +func validateIncr(incr interface{}) (string, error) { + if incr == nil { + return "", nil + } + err := errors.New("incr condition should be a string of Value INCR") + i, ok := incr.(string) + if !ok { + return "", err + } + if !strings.EqualFold(i, "incr") { + return "", err + } + return i, nil +} + +func compareScores(old Score, new Score, comp string) Score { + switch strings.ToLower(comp) { + default: + return new + case "lt": + if new < old { + return new + } + return old + case "gt": + if new > old { + return new + } + return old + } +} diff --git a/pkg/modules/string/commands.go b/internal/modules/string/commands.go similarity index 100% rename from pkg/modules/string/commands.go rename to internal/modules/string/commands.go diff --git a/pkg/modules/string/key_funcs.go b/internal/modules/string/key_funcs.go similarity index 100% rename from pkg/modules/string/key_funcs.go rename to internal/modules/string/key_funcs.go diff --git a/internal/sorted_set/utils.go b/internal/sorted_set/utils.go deleted file mode 100644 index 73a531cf..00000000 --- a/internal/sorted_set/utils.go +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2024 Kelvin Clement Mwinuka -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package sorted_set - -import ( - "errors" - "slices" - "strings" -) - -func validateUpdatePolicy(updatePolicy interface{}) (string, error) { - if updatePolicy == nil { - return "", nil - } - err := errors.New("update policy must be a string of Value NX or XX") - policy, ok := updatePolicy.(string) - if !ok { - return "", err - } - if !slices.Contains([]string{"nx", "xx"}, strings.ToLower(policy)) { - return "", err - } - return policy, nil -} - -func validateComparison(comparison interface{}) (string, error) { - if comparison == nil { - return "", nil - } - err := errors.New("comparison condition must be a string of Value LT or GT") - comp, ok := comparison.(string) - if !ok { - return "", err - } - if !slices.Contains([]string{"lt", "gt"}, strings.ToLower(comp)) { - return "", err - } - return comp, nil -} - -func validateChanged(changed interface{}) (string, error) { - if changed == nil { - return "", nil - } - err := errors.New("changed condition should be a string of Value CH") - ch, ok := changed.(string) - if !ok { - return "", err - } - if !strings.EqualFold(ch, "ch") { - return "", err - } - return ch, nil -} - -func validateIncr(incr interface{}) (string, error) { - if incr == nil { - return "", nil - } - err := errors.New("incr condition should be a string of Value INCR") - i, ok := incr.(string) - if !ok { - return "", err - } - if !strings.EqualFold(i, "incr") { - return "", err - } - return i, nil -} - -func compareScores(old Score, new Score, comp string) Score { - switch strings.ToLower(comp) { - default: - return new - case "lt": - if new < old { - return new - } - return old - case "gt": - if new > old { - return new - } - return old - } -} diff --git a/pkg/commands/commands.go b/pkg/commands/commands.go deleted file mode 100644 index 4cc7643e..00000000 --- a/pkg/commands/commands.go +++ /dev/null @@ -1,31 +0,0 @@ -package commands - -import ( - "github.com/echovault/echovault/pkg/modules/acl" - "github.com/echovault/echovault/pkg/modules/admin" - "github.com/echovault/echovault/pkg/modules/connection" - "github.com/echovault/echovault/pkg/modules/generic" - "github.com/echovault/echovault/pkg/modules/hash" - "github.com/echovault/echovault/pkg/modules/list" - "github.com/echovault/echovault/pkg/modules/pubsub" - "github.com/echovault/echovault/pkg/modules/set" - "github.com/echovault/echovault/pkg/modules/sorted_set" - str "github.com/echovault/echovault/pkg/modules/string" - "github.com/echovault/echovault/pkg/types" -) - -// All returns all the commands currently available on EchoVault -func All() []types.Command { - var commands []types.Command - commands = append(commands, acl.Commands()...) - commands = append(commands, admin.Commands()...) - commands = append(commands, generic.Commands()...) - commands = append(commands, hash.Commands()...) - commands = append(commands, list.Commands()...) - commands = append(commands, connection.Commands()...) - commands = append(commands, pubsub.Commands()...) - commands = append(commands, set.Commands()...) - commands = append(commands, sorted_set.Commands()...) - commands = append(commands, str.Commands()...) - return commands -} diff --git a/pkg/echovault/echovault.go b/pkg/echovault/echovault.go index 70e69bf1..18911fca 100644 --- a/pkg/echovault/echovault.go +++ b/pkg/echovault/echovault.go @@ -21,13 +21,21 @@ import ( "errors" "fmt" "github.com/echovault/echovault/internal" - "github.com/echovault/echovault/internal/acl" "github.com/echovault/echovault/internal/aof" "github.com/echovault/echovault/internal/clock" "github.com/echovault/echovault/internal/config" "github.com/echovault/echovault/internal/eviction" "github.com/echovault/echovault/internal/memberlist" - "github.com/echovault/echovault/internal/pubsub" + "github.com/echovault/echovault/internal/modules/acl" + "github.com/echovault/echovault/internal/modules/admin" + "github.com/echovault/echovault/internal/modules/connection" + "github.com/echovault/echovault/internal/modules/generic" + "github.com/echovault/echovault/internal/modules/hash" + "github.com/echovault/echovault/internal/modules/list" + "github.com/echovault/echovault/internal/modules/pubsub" + "github.com/echovault/echovault/internal/modules/set" + "github.com/echovault/echovault/internal/modules/sorted_set" + str "github.com/echovault/echovault/internal/modules/string" "github.com/echovault/echovault/internal/raft" "github.com/echovault/echovault/internal/snapshot" "github.com/echovault/echovault/pkg/constants" @@ -126,11 +134,24 @@ func NewEchoVault(options ...func(echovault *EchoVault)) (*EchoVault, error) { echovault := &EchoVault{ clock: clock.NewClock(), context: context.Background(), - commands: make([]types.Command, 0), config: config.DefaultConfig(), store: make(map[string]internal.KeyData), keyLocks: make(map[string]*sync.RWMutex), keyCreationLock: &sync.Mutex{}, + commands: func() []types.Command { + var commands []types.Command + commands = append(commands, acl.Commands()...) + commands = append(commands, admin.Commands()...) + commands = append(commands, generic.Commands()...) + commands = append(commands, hash.Commands()...) + commands = append(commands, list.Commands()...) + commands = append(commands, connection.Commands()...) + commands = append(commands, pubsub.Commands()...) + commands = append(commands, set.Commands()...) + commands = append(commands, sorted_set.Commands()...) + commands = append(commands, str.Commands()...) + return commands + }(), } for _, option := range options { diff --git a/pkg/echovault/keyspace.go b/pkg/echovault/keyspace.go index a6ae9ba7..a751dbad 100644 --- a/pkg/echovault/keyspace.go +++ b/pkg/echovault/keyspace.go @@ -589,16 +589,3 @@ func (server *EchoVault) evictKeysWithExpiredTTL(ctx context.Context) error { return nil } - -func presetValue(server *EchoVault, key string, value interface{}) { - _, _ = server.CreateKeyAndLock(server.context, key) - _ = server.SetValue(server.context, key, value) - server.KeyUnlock(server.context, key) -} - -func presetKeyData(server *EchoVault, key string, data internal.KeyData) { - _, _ = server.CreateKeyAndLock(server.context, key) - defer server.KeyUnlock(server.context, key) - _ = server.SetValue(server.context, key, data.Value) - server.SetExpiry(server.context, key, data.ExpireAt, false) -} diff --git a/test/modules/acl/commands_test.go b/test/modules/acl/commands_test.go index 5c9a81d9..09303a0a 100644 --- a/test/modules/acl/commands_test.go +++ b/test/modules/acl/commands_test.go @@ -17,11 +17,10 @@ package acl import ( "crypto/sha256" "fmt" - internal_acl "github.com/echovault/echovault/internal/acl" "github.com/echovault/echovault/internal/config" + "github.com/echovault/echovault/internal/modules/acl" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/echovault" - acl2 "github.com/echovault/echovault/pkg/modules/acl" "github.com/tidwall/resp" "net" "slices" @@ -61,44 +60,43 @@ func setUpServer(bindAddr string, port uint16, requirePass bool, aclConfig strin } mockServer, _ := echovault.NewEchoVault( - echovault.WithCommands(acl2.Commands()), echovault.WithConfig(conf), ) // Add the initial test users to the ACL module - acl := mockServer.GetACL().(*internal_acl.ACL) - acl.AddUsers(generateInitialTestUsers()) + a := mockServer.GetACL().(*acl.ACL) + a.AddUsers(generateInitialTestUsers()) return mockServer } -func generateInitialTestUsers() []*internal_acl.User { +func generateInitialTestUsers() []*acl.User { // User with both hash password and plaintext password - withPasswordUser := internal_acl.CreateUser("with_password_user") + withPasswordUser := acl.CreateUser("with_password_user") h := sha256.New() h.Write([]byte("password3")) - withPasswordUser.Passwords = []internal_acl.Password{ - {PasswordType: internal_acl.PasswordPlainText, PasswordValue: "password2"}, - {PasswordType: internal_acl.PasswordSHA256, PasswordValue: string(h.Sum(nil))}, + withPasswordUser.Passwords = []acl.Password{ + {PasswordType: acl.PasswordPlainText, PasswordValue: "password2"}, + {PasswordType: acl.PasswordSHA256, PasswordValue: string(h.Sum(nil))}, } withPasswordUser.IncludedCategories = []string{"*"} withPasswordUser.IncludedCommands = []string{"*"} // User with NoPassword option - noPasswordUser := internal_acl.CreateUser("no_password_user") - noPasswordUser.Passwords = []internal_acl.Password{ - {PasswordType: internal_acl.PasswordPlainText, PasswordValue: "password4"}, + noPasswordUser := acl.CreateUser("no_password_user") + noPasswordUser.Passwords = []acl.Password{ + {PasswordType: acl.PasswordPlainText, PasswordValue: "password4"}, } noPasswordUser.NoPassword = true // Disabled user - disabledUser := internal_acl.CreateUser("disabled_user") - disabledUser.Passwords = []internal_acl.Password{ - {PasswordType: internal_acl.PasswordPlainText, PasswordValue: "password5"}, + disabledUser := acl.CreateUser("disabled_user") + disabledUser.Passwords = []acl.Password{ + {PasswordType: acl.PasswordPlainText, PasswordValue: "password5"}, } disabledUser.Enabled = false - return []*internal_acl.User{ + return []*acl.User{ withPasswordUser, noPasswordUser, disabledUser, @@ -129,7 +127,7 @@ func compareSlices[T comparable](res, expected []T) error { } // compareUsers compares 2 users and checks if all their fields are equal -func compareUsers(user1, user2 *internal_acl.User) error { +func compareUsers(user1, user2 *acl.User) error { // Compare flags if user1.Username != user2.Username { return fmt.Errorf("mismatched usernames \"%s\", and \"%s\"", user1.Username, user2.Username) @@ -146,14 +144,14 @@ func compareUsers(user1, user2 *internal_acl.User) error { // Compare passwords for _, password1 := range user1.Passwords { - if !slices.ContainsFunc(user2.Passwords, func(password2 internal_acl.Password) bool { + if !slices.ContainsFunc(user2.Passwords, func(password2 acl.Password) bool { return password1.PasswordType == password2.PasswordType && password1.PasswordValue == password2.PasswordValue }) { return fmt.Errorf("found password %+v in user1 that was not found in user2", password1) } } for _, password2 := range user2.Passwords { - if !slices.ContainsFunc(user1.Passwords, func(password1 internal_acl.Password) bool { + if !slices.ContainsFunc(user1.Passwords, func(password1 acl.Password) bool { return password1.PasswordType == password2.PasswordType && password1.PasswordValue == password2.PasswordValue }) { return fmt.Errorf("found password %+v in user2 that was not found in user1", password2) @@ -392,14 +390,6 @@ func Test_HandleCat(t *testing.T) { t.Errorf("could not find expected command \"%s\" in the response array for category", expected) } } - // Check if all the elements in the response array are in the expected array - for _, value := range resArr { - if !slices.ContainsFunc(test.wantRes, func(expected string) bool { - return value.String() == expected - }) { - t.Errorf("could not find response command \"%s\" in the expected array", value.String()) - } - } } } @@ -469,7 +459,7 @@ func Test_HandleSetUser(t *testing.T) { }() wg.Wait() - acl, ok := mockServer.GetACL().(*internal_acl.ACL) + a, ok := mockServer.GetACL().(*acl.ACL) if !ok { t.Error("error loading ACL module") } @@ -487,11 +477,11 @@ func Test_HandleSetUser(t *testing.T) { r := resp.NewConn(conn) tests := []struct { - presetUser *internal_acl.User + presetUser *acl.User cmd []resp.Value wantRes string wantErr string - wantUser *internal_acl.User + wantUser *acl.User }{ { // 1. Create new enabled user @@ -504,8 +494,8 @@ func Test_HandleSetUser(t *testing.T) { }, wantRes: "OK", wantErr: "", - wantUser: func() *internal_acl.User { - user := internal_acl.CreateUser("set_user_1") + wantUser: func() *acl.User { + user := acl.CreateUser("set_user_1") user.Enabled = true user.Normalise() return user @@ -522,8 +512,8 @@ func Test_HandleSetUser(t *testing.T) { }, wantRes: "OK", wantErr: "", - wantUser: func() *internal_acl.User { - user := internal_acl.CreateUser("set_user_2") + wantUser: func() *acl.User { + user := acl.CreateUser("set_user_2") user.Enabled = false user.Normalise() return user @@ -544,14 +534,14 @@ func Test_HandleSetUser(t *testing.T) { }, wantRes: "OK", wantErr: "", - wantUser: func() *internal_acl.User { - user := internal_acl.CreateUser("set_user_3") + wantUser: func() *acl.User { + user := acl.CreateUser("set_user_3") user.Enabled = true - user.Passwords = []internal_acl.Password{ - {PasswordType: internal_acl.PasswordPlainText, PasswordValue: "set_user_3_plaintext_password_1"}, - {PasswordType: internal_acl.PasswordPlainText, PasswordValue: "set_user_3_plaintext_password_2"}, - {PasswordType: internal_acl.PasswordSHA256, PasswordValue: generateSHA256Password("set_user_3_hash_password_1")}, - {PasswordType: internal_acl.PasswordSHA256, PasswordValue: generateSHA256Password("set_user_3_hash_password_2")}, + user.Passwords = []acl.Password{ + {PasswordType: acl.PasswordPlainText, PasswordValue: "set_user_3_plaintext_password_1"}, + {PasswordType: acl.PasswordPlainText, PasswordValue: "set_user_3_plaintext_password_2"}, + {PasswordType: acl.PasswordSHA256, PasswordValue: generateSHA256Password("set_user_3_hash_password_1")}, + {PasswordType: acl.PasswordSHA256, PasswordValue: generateSHA256Password("set_user_3_hash_password_2")}, } user.Normalise() return user @@ -559,14 +549,14 @@ func Test_HandleSetUser(t *testing.T) { }, { // 4. Remove plaintext and SHA256 password from existing user - presetUser: func() *internal_acl.User { - user := internal_acl.CreateUser("set_user_4") + presetUser: func() *acl.User { + user := acl.CreateUser("set_user_4") user.Enabled = true - user.Passwords = []internal_acl.Password{ - {PasswordType: internal_acl.PasswordPlainText, PasswordValue: "set_user_3_plaintext_password_1"}, - {PasswordType: internal_acl.PasswordPlainText, PasswordValue: "set_user_3_plaintext_password_2"}, - {PasswordType: internal_acl.PasswordSHA256, PasswordValue: generateSHA256Password("set_user_3_hash_password_1")}, - {PasswordType: internal_acl.PasswordSHA256, PasswordValue: generateSHA256Password("set_user_3_hash_password_2")}, + user.Passwords = []acl.Password{ + {PasswordType: acl.PasswordPlainText, PasswordValue: "set_user_3_plaintext_password_1"}, + {PasswordType: acl.PasswordPlainText, PasswordValue: "set_user_3_plaintext_password_2"}, + {PasswordType: acl.PasswordSHA256, PasswordValue: generateSHA256Password("set_user_3_hash_password_1")}, + {PasswordType: acl.PasswordSHA256, PasswordValue: generateSHA256Password("set_user_3_hash_password_2")}, } user.Normalise() return user @@ -581,12 +571,12 @@ func Test_HandleSetUser(t *testing.T) { }, wantRes: "OK", wantErr: "", - wantUser: func() *internal_acl.User { - user := internal_acl.CreateUser("set_user_4") + wantUser: func() *acl.User { + user := acl.CreateUser("set_user_4") user.Enabled = true - user.Passwords = []internal_acl.Password{ - {PasswordType: internal_acl.PasswordPlainText, PasswordValue: "set_user_3_plaintext_password_1"}, - {PasswordType: internal_acl.PasswordSHA256, PasswordValue: generateSHA256Password("set_user_3_hash_password_1")}, + user.Passwords = []acl.Password{ + {PasswordType: acl.PasswordPlainText, PasswordValue: "set_user_3_plaintext_password_1"}, + {PasswordType: acl.PasswordSHA256, PasswordValue: generateSHA256Password("set_user_3_hash_password_1")}, } user.Normalise() return user @@ -604,8 +594,8 @@ func Test_HandleSetUser(t *testing.T) { }, wantRes: "OK", wantErr: "", - wantUser: func() *internal_acl.User { - user := internal_acl.CreateUser("set_user_5") + wantUser: func() *acl.User { + user := acl.CreateUser("set_user_5") user.Enabled = true user.ExcludedCommands = []string{"*"} user.ExcludedCategories = []string{"*"} @@ -625,8 +615,8 @@ func Test_HandleSetUser(t *testing.T) { }, wantRes: "OK", wantErr: "", - wantUser: func() *internal_acl.User { - user := internal_acl.CreateUser("set_user_6") + wantUser: func() *acl.User { + user := acl.CreateUser("set_user_6") user.Enabled = true user.IncludedCategories = []string{"*"} user.ExcludedCategories = []string{} @@ -646,8 +636,8 @@ func Test_HandleSetUser(t *testing.T) { }, wantRes: "OK", wantErr: "", - wantUser: func() *internal_acl.User { - user := internal_acl.CreateUser("set_user_7") + wantUser: func() *acl.User { + user := acl.CreateUser("set_user_7") user.Enabled = true user.IncludedCategories = []string{"*"} user.ExcludedCategories = []string{} @@ -672,8 +662,8 @@ func Test_HandleSetUser(t *testing.T) { }, wantRes: "OK", wantErr: "", - wantUser: func() *internal_acl.User { - user := internal_acl.CreateUser("set_user_8") + wantUser: func() *acl.User { + user := acl.CreateUser("set_user_8") user.Enabled = true user.IncludedCategories = []string{constants.WriteCategory, constants.ReadCategory, constants.PubSubCategory} user.ExcludedCategories = []string{constants.AdminCategory, constants.ConnectionCategory, constants.DangerousCategory} @@ -693,8 +683,8 @@ func Test_HandleSetUser(t *testing.T) { }, wantRes: "OK", wantErr: "", - wantUser: func() *internal_acl.User { - user := internal_acl.CreateUser("set_user_9") + wantUser: func() *acl.User { + user := acl.CreateUser("set_user_9") user.Enabled = true user.NoKeys = true user.IncludedReadKeys = []string{} @@ -723,8 +713,8 @@ func Test_HandleSetUser(t *testing.T) { }, wantRes: "OK", wantErr: "", - wantUser: func() *internal_acl.User { - user := internal_acl.CreateUser("set_user_10") + wantUser: func() *acl.User { + user := acl.CreateUser("set_user_10") user.Enabled = true user.NoKeys = false user.IncludedReadKeys = []string{"key1", "key2", "key3", "key4", "key5", "key6"} @@ -745,8 +735,8 @@ func Test_HandleSetUser(t *testing.T) { }, wantRes: "OK", wantErr: "", - wantUser: func() *internal_acl.User { - user := internal_acl.CreateUser("set_user_11") + wantUser: func() *acl.User { + user := acl.CreateUser("set_user_11") user.Enabled = true user.IncludedPubSubChannels = []string{"*"} user.ExcludedPubSubChannels = []string{} @@ -766,8 +756,8 @@ func Test_HandleSetUser(t *testing.T) { }, wantRes: "OK", wantErr: "", - wantUser: func() *internal_acl.User { - user := internal_acl.CreateUser("set_user_12") + wantUser: func() *acl.User { + user := acl.CreateUser("set_user_12") user.Enabled = true user.IncludedPubSubChannels = []string{"*"} user.ExcludedPubSubChannels = []string{} @@ -790,8 +780,8 @@ func Test_HandleSetUser(t *testing.T) { }, wantRes: "OK", wantErr: "", - wantUser: func() *internal_acl.User { - user := internal_acl.CreateUser("set_user_13") + wantUser: func() *acl.User { + user := acl.CreateUser("set_user_13") user.Enabled = true user.IncludedPubSubChannels = []string{"channel1", "channel2"} user.ExcludedPubSubChannels = []string{"channel3", "channel4"} @@ -811,8 +801,8 @@ func Test_HandleSetUser(t *testing.T) { }, wantRes: "OK", wantErr: "", - wantUser: func() *internal_acl.User { - user := internal_acl.CreateUser("set_user_14") + wantUser: func() *acl.User { + user := acl.CreateUser("set_user_14") user.Enabled = true user.IncludedCommands = []string{"*"} user.ExcludedCommands = []string{} @@ -837,8 +827,8 @@ func Test_HandleSetUser(t *testing.T) { }, wantRes: "OK", wantErr: "", - wantUser: func() *internal_acl.User { - user := internal_acl.CreateUser("set_user_15") + wantUser: func() *acl.User { + user := acl.CreateUser("set_user_15") user.Enabled = true user.IncludedCommands = []string{"acl|getuser", "acl|setuser", "acl|deluser"} user.ExcludedCommands = []string{"rewriteaof", "save", "publish"} @@ -861,24 +851,24 @@ func Test_HandleSetUser(t *testing.T) { }, wantRes: "OK", wantErr: "", - wantUser: func() *internal_acl.User { - user := internal_acl.CreateUser("set_user_16") + wantUser: func() *acl.User { + user := acl.CreateUser("set_user_16") user.Enabled = true user.NoPassword = true - user.Passwords = []internal_acl.Password{} + user.Passwords = []acl.Password{} user.Normalise() return user }(), }, { // 17. Delete all existing users passwords using 'nopass' - presetUser: func() *internal_acl.User { - user := internal_acl.CreateUser("set_user_17") + presetUser: func() *acl.User { + user := acl.CreateUser("set_user_17") user.Enabled = true user.NoPassword = true - user.Passwords = []internal_acl.Password{ - {PasswordType: internal_acl.PasswordPlainText, PasswordValue: "password1"}, - {PasswordType: internal_acl.PasswordSHA256, PasswordValue: generateSHA256Password("password2")}, + user.Passwords = []acl.Password{ + {PasswordType: acl.PasswordPlainText, PasswordValue: "password1"}, + {PasswordType: acl.PasswordSHA256, PasswordValue: generateSHA256Password("password2")}, } user.Normalise() return user @@ -892,24 +882,24 @@ func Test_HandleSetUser(t *testing.T) { }, wantRes: "OK", wantErr: "", - wantUser: func() *internal_acl.User { - user := internal_acl.CreateUser("set_user_17") + wantUser: func() *acl.User { + user := acl.CreateUser("set_user_17") user.Enabled = true user.NoPassword = true - user.Passwords = []internal_acl.Password{} + user.Passwords = []acl.Password{} user.Normalise() return user }(), }, { // 18. Clear all of an existing user's passwords using 'resetpass' - presetUser: func() *internal_acl.User { - user := internal_acl.CreateUser("set_user_18") + presetUser: func() *acl.User { + user := acl.CreateUser("set_user_18") user.Enabled = true user.NoPassword = true - user.Passwords = []internal_acl.Password{ - {PasswordType: internal_acl.PasswordPlainText, PasswordValue: "password1"}, - {PasswordType: internal_acl.PasswordSHA256, PasswordValue: generateSHA256Password("password2")}, + user.Passwords = []acl.Password{ + {PasswordType: acl.PasswordPlainText, PasswordValue: "password1"}, + {PasswordType: acl.PasswordSHA256, PasswordValue: generateSHA256Password("password2")}, } user.Normalise() return user @@ -923,19 +913,19 @@ func Test_HandleSetUser(t *testing.T) { }, wantRes: "OK", wantErr: "", - wantUser: func() *internal_acl.User { - user := internal_acl.CreateUser("set_user_18") + wantUser: func() *acl.User { + user := acl.CreateUser("set_user_18") user.Enabled = true user.NoPassword = true - user.Passwords = []internal_acl.Password{} + user.Passwords = []acl.Password{} user.Normalise() return user }(), }, { // 19. Clear all of an existing user's command privileges using 'nocommands' - presetUser: func() *internal_acl.User { - user := internal_acl.CreateUser("set_user_19") + presetUser: func() *acl.User { + user := acl.CreateUser("set_user_19") user.Enabled = true user.IncludedCommands = []string{"acl|getuser", "acl|setuser", "acl|deluser"} user.ExcludedCommands = []string{"rewriteaof", "save"} @@ -951,8 +941,8 @@ func Test_HandleSetUser(t *testing.T) { }, wantRes: "OK", wantErr: "", - wantUser: func() *internal_acl.User { - user := internal_acl.CreateUser("set_user_19") + wantUser: func() *acl.User { + user := acl.CreateUser("set_user_19") user.Enabled = true user.IncludedCommands = []string{} user.ExcludedCommands = []string{"*"} @@ -964,8 +954,8 @@ func Test_HandleSetUser(t *testing.T) { }, { // 20. Clear all of an existing user's allowed keys using 'resetkeys' - presetUser: func() *internal_acl.User { - user := internal_acl.CreateUser("set_user_20") + presetUser: func() *acl.User { + user := acl.CreateUser("set_user_20") user.Enabled = true user.IncludedWriteKeys = []string{"key1", "key2", "key3", "key4", "key5", "key6"} user.IncludedReadKeys = []string{"key1", "key2", "key3", "key7", "key8", "key9"} @@ -981,8 +971,8 @@ func Test_HandleSetUser(t *testing.T) { }, wantRes: "OK", wantErr: "", - wantUser: func() *internal_acl.User { - user := internal_acl.CreateUser("set_user_20") + wantUser: func() *acl.User { + user := acl.CreateUser("set_user_20") user.Enabled = true user.NoKeys = true user.IncludedReadKeys = []string{} @@ -993,8 +983,8 @@ func Test_HandleSetUser(t *testing.T) { }, { // 21. Allow user to access all channels using 'resetchannels' - presetUser: func() *internal_acl.User { - user := internal_acl.CreateUser("set_user_21") + presetUser: func() *acl.User { + user := acl.CreateUser("set_user_21") user.IncludedPubSubChannels = []string{"channel1", "channel2"} user.ExcludedPubSubChannels = []string{"channel3", "channel4"} user.Normalise() @@ -1008,8 +998,8 @@ func Test_HandleSetUser(t *testing.T) { }, wantRes: "OK", wantErr: "", - wantUser: func() *internal_acl.User { - user := internal_acl.CreateUser("set_user_21") + wantUser: func() *acl.User { + user := acl.CreateUser("set_user_21") user.IncludedPubSubChannels = []string{} user.ExcludedPubSubChannels = []string{"*"} user.Normalise() @@ -1020,7 +1010,7 @@ func Test_HandleSetUser(t *testing.T) { for i, test := range tests { if test.presetUser != nil { - acl.AddUsers([]*internal_acl.User{test.presetUser}) + a.AddUsers([]*acl.User{test.presetUser}) } if err = r.WriteArray(test.cmd); err != nil { t.Error(err) @@ -1042,13 +1032,13 @@ func Test_HandleSetUser(t *testing.T) { continue } expectedUser := test.wantUser - currUserIdx := slices.IndexFunc(acl.Users, func(user *internal_acl.User) bool { + currUserIdx := slices.IndexFunc(a.Users, func(user *acl.User) bool { return user.Username == expectedUser.Username }) if currUserIdx == -1 { t.Errorf("expected to find user with username \"%s\" but could not find them.", expectedUser.Username) } - if err = compareUsers(expectedUser, acl.Users[currUserIdx]); err != nil { + if err = compareUsers(expectedUser, a.Users[currUserIdx]); err != nil { t.Errorf("test idx: %d, %+v", i, err) } } @@ -1065,7 +1055,7 @@ func Test_HandleGetUser(t *testing.T) { }() wg.Wait() - acl, _ := mockServer.GetACL().(*internal_acl.ACL) + a, _ := mockServer.GetACL().(*acl.ACL) conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", bindAddr, port)) if err != nil { @@ -1080,20 +1070,20 @@ func Test_HandleGetUser(t *testing.T) { r := resp.NewConn(conn) tests := []struct { - presetUser *internal_acl.User + presetUser *acl.User cmd []resp.Value wantRes []resp.Value wantErr string }{ { // 1. Get the user and all their details - presetUser: &internal_acl.User{ + presetUser: &acl.User{ Username: "get_user_1", Enabled: true, NoPassword: false, NoKeys: false, - Passwords: []internal_acl.Password{ - {PasswordType: internal_acl.PasswordPlainText, PasswordValue: "get_user_password_1"}, - {PasswordType: internal_acl.PasswordSHA256, PasswordValue: generateSHA256Password("get_user_password_2")}, + Passwords: []acl.Password{ + {PasswordType: acl.PasswordPlainText, PasswordValue: "get_user_password_1"}, + {PasswordType: acl.PasswordSHA256, PasswordValue: generateSHA256Password("get_user_password_2")}, }, IncludedCategories: []string{constants.WriteCategory, constants.ReadCategory, constants.PubSubCategory}, ExcludedCategories: []string{constants.AdminCategory, constants.ConnectionCategory, constants.DangerousCategory}, @@ -1165,7 +1155,7 @@ func Test_HandleGetUser(t *testing.T) { for _, test := range tests { if test.presetUser != nil { - acl.AddUsers([]*internal_acl.User{test.presetUser}) + a.AddUsers([]*acl.User{test.presetUser}) } if err = r.WriteArray(test.cmd); err != nil { t.Error(err) @@ -1218,7 +1208,7 @@ func Test_HandleDelUser(t *testing.T) { }() wg.Wait() - acl, _ := mockServer.GetACL().(*internal_acl.ACL) + a, _ := mockServer.GetACL().(*acl.ACL) conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", bindAddr, port)) if err != nil { @@ -1233,14 +1223,14 @@ func Test_HandleDelUser(t *testing.T) { r := resp.NewConn(conn) tests := []struct { - presetUser *internal_acl.User + presetUser *acl.User cmd []resp.Value wantRes string wantErr string }{ { // 1. Delete existing user while skipping default user and non-existent user - presetUser: internal_acl.CreateUser("user_to_delete"), + presetUser: acl.CreateUser("user_to_delete"), cmd: []resp.Value{ resp.StringValue("ACL"), resp.StringValue("DELUSER"), @@ -1262,7 +1252,7 @@ func Test_HandleDelUser(t *testing.T) { for _, test := range tests { if test.presetUser != nil { - acl.AddUsers([]*internal_acl.User{test.presetUser}) + a.AddUsers([]*acl.User{test.presetUser}) } if err = r.WriteArray(test.cmd); err != nil { t.Error(err) @@ -1278,13 +1268,13 @@ func Test_HandleDelUser(t *testing.T) { continue } // Check that default user still exists in the list of users - if !slices.ContainsFunc(acl.Users, func(user *internal_acl.User) bool { + if !slices.ContainsFunc(a.Users, func(user *acl.User) bool { return user.Username == "default" }) { t.Error("could not find user with username \"default\" in the ACL after deleting user") } // Check that the deleted user is no longer in the list - if slices.ContainsFunc(acl.Users, func(user *internal_acl.User) bool { + if slices.ContainsFunc(a.Users, func(user *acl.User) bool { return user.Username == "user_to_delete" }) { t.Error("deleted user found in the ACL") @@ -1368,7 +1358,7 @@ func Test_HandleList(t *testing.T) { }() wg.Wait() - acl, _ := mockServer.GetACL().(*internal_acl.ACL) + a, _ := mockServer.GetACL().(*acl.ACL) conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", bindAddr, port)) if err != nil { @@ -1383,21 +1373,21 @@ func Test_HandleList(t *testing.T) { r := resp.NewConn(conn) tests := []struct { - presetUsers []*internal_acl.User + presetUsers []*acl.User cmd []resp.Value wantRes []string wantErr string }{ { // 1. Get the user and all their details - presetUsers: []*internal_acl.User{ + presetUsers: []*acl.User{ { Username: "list_user_1", Enabled: true, NoPassword: false, NoKeys: false, - Passwords: []internal_acl.Password{ - {PasswordType: internal_acl.PasswordPlainText, PasswordValue: "list_user_password_1"}, - {PasswordType: internal_acl.PasswordSHA256, PasswordValue: generateSHA256Password("list_user_password_2")}, + Passwords: []acl.Password{ + {PasswordType: acl.PasswordPlainText, PasswordValue: "list_user_password_1"}, + {PasswordType: acl.PasswordSHA256, PasswordValue: generateSHA256Password("list_user_password_2")}, }, IncludedCategories: []string{constants.WriteCategory, constants.ReadCategory, constants.PubSubCategory}, ExcludedCategories: []string{constants.AdminCategory, constants.ConnectionCategory, constants.DangerousCategory}, @@ -1413,7 +1403,7 @@ func Test_HandleList(t *testing.T) { Enabled: true, NoPassword: true, NoKeys: true, - Passwords: []internal_acl.Password{}, + Passwords: []acl.Password{}, IncludedCategories: []string{constants.WriteCategory, constants.ReadCategory, constants.PubSubCategory}, ExcludedCategories: []string{constants.AdminCategory, constants.ConnectionCategory, constants.DangerousCategory}, IncludedCommands: []string{"acl|setuser", "acl|getuser", "acl|deluser"}, @@ -1428,9 +1418,9 @@ func Test_HandleList(t *testing.T) { Enabled: true, NoPassword: false, NoKeys: false, - Passwords: []internal_acl.Password{ - {PasswordType: internal_acl.PasswordPlainText, PasswordValue: "list_user_password_3"}, - {PasswordType: internal_acl.PasswordSHA256, PasswordValue: generateSHA256Password("list_user_password_4")}, + Passwords: []acl.Password{ + {PasswordType: acl.PasswordPlainText, PasswordValue: "list_user_password_3"}, + {PasswordType: acl.PasswordSHA256, PasswordValue: generateSHA256Password("list_user_password_4")}, }, IncludedCategories: []string{constants.WriteCategory, constants.ReadCategory, constants.PubSubCategory}, ExcludedCategories: []string{constants.AdminCategory, constants.ConnectionCategory, constants.DangerousCategory}, @@ -1457,7 +1447,7 @@ func Test_HandleList(t *testing.T) { } for _, test := range tests { - acl.AddUsers(test.presetUsers) + a.AddUsers(test.presetUsers) if err = r.WriteArray(test.cmd); err != nil { t.Error(err) diff --git a/test/modules/admin/commands_test.go b/test/modules/admin/commands_test.go index 6e1ac3cb..0f8b908f 100644 --- a/test/modules/admin/commands_test.go +++ b/test/modules/admin/commands_test.go @@ -21,7 +21,6 @@ import ( "github.com/echovault/echovault/internal/config" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/echovault" - "github.com/echovault/echovault/pkg/modules/admin" "github.com/echovault/echovault/pkg/types" "github.com/tidwall/resp" "net" @@ -33,7 +32,6 @@ var mockServer *echovault.EchoVault func init() { mockServer, _ = echovault.NewEchoVault( - echovault.WithCommands(admin.Commands()), echovault.WithConfig(config.Config{ DataDir: "", EvictionPolicy: constants.NoEviction, diff --git a/test/modules/connection/commands_test.go b/test/modules/connection/commands_test.go index 675a4e2d..633e884e 100644 --- a/test/modules/connection/commands_test.go +++ b/test/modules/connection/commands_test.go @@ -21,7 +21,6 @@ import ( "github.com/echovault/echovault/internal/config" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/echovault" - "github.com/echovault/echovault/pkg/modules/connection" "github.com/echovault/echovault/pkg/types" "github.com/tidwall/resp" "net" @@ -33,7 +32,6 @@ var mockServer *echovault.EchoVault func init() { mockServer, _ = echovault.NewEchoVault( - echovault.WithCommands(connection.Commands()), echovault.WithConfig(config.Config{ DataDir: "", EvictionPolicy: constants.NoEviction, diff --git a/test/modules/generic/api_generic_test.go b/test/modules/generic/api_generic_test.go index d0f6cdcd..b18281b9 100644 --- a/test/modules/generic/api_generic_test.go +++ b/test/modules/generic/api_generic_test.go @@ -20,7 +20,6 @@ import ( "github.com/echovault/echovault/internal/clock" "github.com/echovault/echovault/internal/config" "github.com/echovault/echovault/pkg/echovault" - "github.com/echovault/echovault/pkg/modules/generic" "reflect" "slices" "strings" @@ -30,7 +29,6 @@ import ( func createEchoVault() *echovault.EchoVault { ev, _ := echovault.NewEchoVault( - echovault.WithCommands(generic.Commands()), echovault.WithConfig(config.Config{ DataDir: "", }), diff --git a/test/modules/generic/commands_test.go b/test/modules/generic/commands_test.go index 95f012f2..e89d2283 100644 --- a/test/modules/generic/commands_test.go +++ b/test/modules/generic/commands_test.go @@ -23,7 +23,6 @@ import ( "github.com/echovault/echovault/internal/config" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/echovault" - "github.com/echovault/echovault/pkg/modules/generic" "github.com/echovault/echovault/pkg/types" "github.com/tidwall/resp" "net" @@ -45,7 +44,6 @@ func init() { mockClock = clock.NewClock() mockServer, _ = echovault.NewEchoVault( - echovault.WithCommands(generic.Commands()), echovault.WithConfig(config.Config{ DataDir: "", EvictionPolicy: constants.NoEviction, diff --git a/test/modules/hash/api_hash_test.go b/test/modules/hash/api_hash_test.go index 9ee30f13..6ef4db5e 100644 --- a/test/modules/hash/api_hash_test.go +++ b/test/modules/hash/api_hash_test.go @@ -18,7 +18,6 @@ import ( "context" "github.com/echovault/echovault/internal/config" "github.com/echovault/echovault/pkg/echovault" - "github.com/echovault/echovault/pkg/modules/hash" "reflect" "slices" "testing" @@ -26,7 +25,6 @@ import ( func createEchoVault() *echovault.EchoVault { ev, _ := echovault.NewEchoVault( - echovault.WithCommands(hash.Commands()), echovault.WithConfig(config.Config{ DataDir: "", }), diff --git a/test/modules/hash/commands_test.go b/test/modules/hash/commands_test.go index ba7c7fa8..ec890a25 100644 --- a/test/modules/hash/commands_test.go +++ b/test/modules/hash/commands_test.go @@ -22,7 +22,6 @@ import ( "github.com/echovault/echovault/internal/config" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/echovault" - "github.com/echovault/echovault/pkg/modules/hash" "github.com/echovault/echovault/pkg/types" "github.com/tidwall/resp" "net" @@ -35,7 +34,6 @@ var mockServer *echovault.EchoVault func init() { mockServer, _ = echovault.NewEchoVault( - echovault.WithCommands(hash.Commands()), echovault.WithConfig(config.Config{ DataDir: "", EvictionPolicy: constants.NoEviction, diff --git a/test/modules/list/api_list_test.go b/test/modules/list/api_list_test.go index 40181099..44e85526 100644 --- a/test/modules/list/api_list_test.go +++ b/test/modules/list/api_list_test.go @@ -18,14 +18,12 @@ import ( "context" "github.com/echovault/echovault/internal/config" "github.com/echovault/echovault/pkg/echovault" - "github.com/echovault/echovault/pkg/modules/list" "reflect" "testing" ) func createEchoVault() *echovault.EchoVault { ev, _ := echovault.NewEchoVault( - echovault.WithCommands(list.Commands()), echovault.WithConfig(config.Config{ DataDir: "", }), diff --git a/test/modules/list/commands_test.go b/test/modules/list/commands_test.go index 1074d1b0..ff40a593 100644 --- a/test/modules/list/commands_test.go +++ b/test/modules/list/commands_test.go @@ -22,7 +22,6 @@ import ( "github.com/echovault/echovault/internal/config" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/echovault" - "github.com/echovault/echovault/pkg/modules/list" "github.com/echovault/echovault/pkg/types" "github.com/tidwall/resp" "net" @@ -34,7 +33,6 @@ var mockServer *echovault.EchoVault func init() { mockServer, _ = echovault.NewEchoVault( - echovault.WithCommands(list.Commands()), echovault.WithConfig(config.Config{ DataDir: "", EvictionPolicy: constants.NoEviction, diff --git a/test/modules/pubsub/commands_test.go b/test/modules/pubsub/commands_test.go index 07ea3b25..a8874ed8 100644 --- a/test/modules/pubsub/commands_test.go +++ b/test/modules/pubsub/commands_test.go @@ -19,10 +19,9 @@ import ( "context" "fmt" "github.com/echovault/echovault/internal/config" - internal_pubsub "github.com/echovault/echovault/internal/pubsub" + "github.com/echovault/echovault/internal/modules/pubsub" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/echovault" - ps "github.com/echovault/echovault/pkg/modules/pubsub" "github.com/echovault/echovault/pkg/types" "github.com/tidwall/resp" "net" @@ -33,7 +32,7 @@ import ( "time" ) -var pubsub *internal_pubsub.PubSub +var ps *pubsub.PubSub var mockServer *echovault.EchoVault var bindAddr = "localhost" @@ -41,7 +40,7 @@ var port uint16 = 7490 func init() { mockServer = setUpServer(bindAddr, port) - pubsub = mockServer.GetPubSub().(*internal_pubsub.PubSub) + ps = mockServer.GetPubSub().(*pubsub.PubSub) wg := sync.WaitGroup{} wg.Add(1) @@ -54,7 +53,6 @@ func init() { func setUpServer(bindAddr string, port uint16) *echovault.EchoVault { server, _ := echovault.NewEchoVault( - echovault.WithCommands(ps.Commands()), echovault.WithConfig(config.Config{ BindAddr: bindAddr, Port: port, @@ -126,12 +124,12 @@ func Test_HandleSubscribe(t *testing.T) { } for _, channel := range channels { // Check if the channel exists in the pubsub module - if !slices.ContainsFunc(pubsub.GetAllChannels(), func(c *internal_pubsub.Channel) bool { + if !slices.ContainsFunc(ps.GetAllChannels(), func(c *pubsub.Channel) bool { return c.Name() == channel }) { t.Errorf("expected pubsub to contain channel \"%s\" but it was not found", channel) } - for _, c := range pubsub.GetAllChannels() { + for _, c := range ps.GetAllChannels() { if c.Name() == channel { // Check if channel has nil pattern if c.Pattern() != nil { @@ -157,12 +155,12 @@ func Test_HandleSubscribe(t *testing.T) { } for _, pattern := range patterns { // Check if pattern channel exists in pubsub module - if !slices.ContainsFunc(pubsub.GetAllChannels(), func(c *internal_pubsub.Channel) bool { + if !slices.ContainsFunc(ps.GetAllChannels(), func(c *pubsub.Channel) bool { return c.Name() == pattern }) { t.Errorf("expected pubsub to contain pattern channel \"%s\" but it was not found", pattern) } - for _, c := range pubsub.GetAllChannels() { + for _, c := range ps.GetAllChannels() { if c.Name() == pattern { // Check if channel has non-nil pattern if c.Pattern() == nil { @@ -322,7 +320,7 @@ func Test_HandleUnsubscribe(t *testing.T) { verifyResponse(res, test.expectedResponses["pattern"]) for _, channel := range append(test.unSubChannels, test.unSubPatterns...) { - for _, pubsubChannel := range pubsub.GetAllChannels() { + for _, pubsubChannel := range ps.GetAllChannels() { if pubsubChannel.Name() == channel { // Assert that target connection is no longer in the unsub channels and patterns if _, ok := pubsubChannel.Subscribers()[test.targetConn]; ok { @@ -339,7 +337,7 @@ func Test_HandleUnsubscribe(t *testing.T) { // Assert that the target connection is still in the remain channels and patterns for _, channel := range append(test.remainChannels, test.remainPatterns...) { - for _, pubsubChannel := range pubsub.GetAllChannels() { + for _, pubsubChannel := range ps.GetAllChannels() { if pubsubChannel.Name() == channel { if _, ok := pubsubChannel.Subscribers()[test.targetConn]; !ok { t.Errorf("could not find expected target connection in channel \"%s\"", channel) diff --git a/test/modules/set/api_set_test.go b/test/modules/set/api_set_test.go index 491eb8b9..6c085b8a 100644 --- a/test/modules/set/api_set_test.go +++ b/test/modules/set/api_set_test.go @@ -17,9 +17,8 @@ package set import ( "context" "github.com/echovault/echovault/internal/config" - "github.com/echovault/echovault/internal/set" + "github.com/echovault/echovault/internal/modules/set" "github.com/echovault/echovault/pkg/echovault" - s "github.com/echovault/echovault/pkg/modules/set" "reflect" "slices" "testing" @@ -27,7 +26,6 @@ import ( func createEchoVault() *echovault.EchoVault { ev, _ := echovault.NewEchoVault( - echovault.WithCommands(s.Commands()), echovault.WithConfig(config.Config{ DataDir: "", }), diff --git a/test/modules/set/commands_test.go b/test/modules/set/commands_test.go index aa716b9f..abb14ecf 100644 --- a/test/modules/set/commands_test.go +++ b/test/modules/set/commands_test.go @@ -20,10 +20,9 @@ import ( "errors" "fmt" "github.com/echovault/echovault/internal/config" - "github.com/echovault/echovault/internal/set" + "github.com/echovault/echovault/internal/modules/set" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/echovault" - s "github.com/echovault/echovault/pkg/modules/set" "github.com/echovault/echovault/pkg/types" "github.com/tidwall/resp" "net" @@ -36,7 +35,6 @@ var mockServer *echovault.EchoVault func init() { mockServer, _ = echovault.NewEchoVault( - echovault.WithCommands(s.Commands()), echovault.WithConfig(config.Config{ DataDir: "", EvictionPolicy: constants.NoEviction, diff --git a/test/modules/sorted_set/api_sorted_set_test.go b/test/modules/sorted_set/api_sorted_set_test.go index 9c674d61..8dcd57f5 100644 --- a/test/modules/sorted_set/api_sorted_set_test.go +++ b/test/modules/sorted_set/api_sorted_set_test.go @@ -18,9 +18,8 @@ import ( "context" "github.com/echovault/echovault/internal" "github.com/echovault/echovault/internal/config" - "github.com/echovault/echovault/internal/sorted_set" + ss "github.com/echovault/echovault/internal/modules/sorted_set" "github.com/echovault/echovault/pkg/echovault" - ss "github.com/echovault/echovault/pkg/modules/sorted_set" "math" "reflect" "strconv" @@ -29,7 +28,6 @@ import ( func createEchoVault() *echovault.EchoVault { ev, _ := echovault.NewEchoVault( - echovault.WithCommands(ss.Commands()), echovault.WithConfig(config.Config{ DataDir: "", }), @@ -54,7 +52,7 @@ func TestEchoVault_ZADD(t *testing.T) { tests := []struct { name string preset bool - presetValue *sorted_set.SortedSet + presetValue *ss.SortedSet key string entries map[string]float64 options echovault.ZADDOptions @@ -80,10 +78,10 @@ func TestEchoVault_ZADD(t *testing.T) { { name: "Only add the elements that do not currently exist in the sorted set when NX flag is provided", preset: true, - presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ - {Value: "member1", Score: sorted_set.Score(5.5)}, - {Value: "member2", Score: sorted_set.Score(67.77)}, - {Value: "member3", Score: sorted_set.Score(10)}, + presetValue: ss.NewSortedSet([]ss.MemberParam{ + {Value: "member1", Score: ss.Score(5.5)}, + {Value: "member2", Score: ss.Score(67.77)}, + {Value: "member3", Score: ss.Score(10)}, }), key: "key2", entries: map[string]float64{ @@ -98,10 +96,10 @@ func TestEchoVault_ZADD(t *testing.T) { { name: "Do not add any elements when providing existing members with NX flag", preset: true, - presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ - {Value: "member1", Score: sorted_set.Score(5.5)}, - {Value: "member2", Score: sorted_set.Score(67.77)}, - {Value: "member3", Score: sorted_set.Score(10)}, + presetValue: ss.NewSortedSet([]ss.MemberParam{ + {Value: "member1", Score: ss.Score(5.5)}, + {Value: "member2", Score: ss.Score(67.77)}, + {Value: "member3", Score: ss.Score(10)}, }), key: "key3", entries: map[string]float64{ @@ -116,10 +114,10 @@ func TestEchoVault_ZADD(t *testing.T) { { name: "Successfully add elements to an existing set when XX flag is provided with existing elements", preset: true, - presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ - {Value: "member1", Score: sorted_set.Score(5.5)}, - {Value: "member2", Score: sorted_set.Score(67.77)}, - {Value: "member3", Score: sorted_set.Score(10)}, + presetValue: ss.NewSortedSet([]ss.MemberParam{ + {Value: "member1", Score: ss.Score(5.5)}, + {Value: "member2", Score: ss.Score(67.77)}, + {Value: "member3", Score: ss.Score(10)}, }), key: "key4", entries: map[string]float64{ @@ -135,10 +133,10 @@ func TestEchoVault_ZADD(t *testing.T) { { name: "Fail to add element when providing XX flag with elements that do not exist in the sorted set", preset: true, - presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ - {Value: "member1", Score: sorted_set.Score(5.5)}, - {Value: "member2", Score: sorted_set.Score(67.77)}, - {Value: "member3", Score: sorted_set.Score(10)}, + presetValue: ss.NewSortedSet([]ss.MemberParam{ + {Value: "member1", Score: ss.Score(5.5)}, + {Value: "member2", Score: ss.Score(67.77)}, + {Value: "member3", Score: ss.Score(10)}, }), key: "key5", entries: map[string]float64{ @@ -155,10 +153,10 @@ func TestEchoVault_ZADD(t *testing.T) { // Return only the new elements added by default name: "Only update the elements where provided score is greater than current score if GT flag", preset: true, - presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ - {Value: "member1", Score: sorted_set.Score(5.5)}, - {Value: "member2", Score: sorted_set.Score(67.77)}, - {Value: "member3", Score: sorted_set.Score(10)}, + presetValue: ss.NewSortedSet([]ss.MemberParam{ + {Value: "member1", Score: ss.Score(5.5)}, + {Value: "member2", Score: ss.Score(67.77)}, + {Value: "member3", Score: ss.Score(10)}, }), key: "key6", entries: map[string]float64{ @@ -175,10 +173,10 @@ func TestEchoVault_ZADD(t *testing.T) { // Return only the new elements added by default. name: "Only update the elements where provided score is less than current score if LT flag is provided", preset: true, - presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ - {Value: "member1", Score: sorted_set.Score(5.5)}, - {Value: "member2", Score: sorted_set.Score(67.77)}, - {Value: "member3", Score: sorted_set.Score(10)}, + presetValue: ss.NewSortedSet([]ss.MemberParam{ + {Value: "member1", Score: ss.Score(5.5)}, + {Value: "member2", Score: ss.Score(67.77)}, + {Value: "member3", Score: ss.Score(10)}, }), key: "key7", entries: map[string]float64{ @@ -193,10 +191,10 @@ func TestEchoVault_ZADD(t *testing.T) { { name: "Return all the elements that were updated AND added when CH flag is provided", preset: true, - presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ - {Value: "member1", Score: sorted_set.Score(5.5)}, - {Value: "member2", Score: sorted_set.Score(67.77)}, - {Value: "member3", Score: sorted_set.Score(10)}, + presetValue: ss.NewSortedSet([]ss.MemberParam{ + {Value: "member1", Score: ss.Score(5.5)}, + {Value: "member2", Score: ss.Score(67.77)}, + {Value: "member3", Score: ss.Score(10)}, }), key: "key8", entries: map[string]float64{ @@ -211,10 +209,10 @@ func TestEchoVault_ZADD(t *testing.T) { { name: "Increment the member by score", preset: true, - presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ - {Value: "member1", Score: sorted_set.Score(5.5)}, - {Value: "member2", Score: sorted_set.Score(67.77)}, - {Value: "member3", Score: sorted_set.Score(10)}, + presetValue: ss.NewSortedSet([]ss.MemberParam{ + {Value: "member1", Score: ss.Score(5.5)}, + {Value: "member2", Score: ss.Score(67.77)}, + {Value: "member3", Score: ss.Score(10)}, }), key: "key9", entries: map[string]float64{ @@ -286,10 +284,10 @@ func TestEchoVault_ZCARD(t *testing.T) { { name: "Get cardinality of valid sorted set", preset: true, - presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ - {Value: "member1", Score: sorted_set.Score(5.5)}, - {Value: "member2", Score: sorted_set.Score(67.77)}, - {Value: "member3", Score: sorted_set.Score(10)}, + presetValue: ss.NewSortedSet([]ss.MemberParam{ + {Value: "member1", Score: ss.Score(5.5)}, + {Value: "member2", Score: ss.Score(67.77)}, + {Value: "member3", Score: ss.Score(10)}, }), key: "key1", want: 3, @@ -349,14 +347,14 @@ func TestEchoVault_ZCOUNT(t *testing.T) { { name: "Get entire count using infinity boundaries", preset: true, - presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ - {Value: "member1", Score: sorted_set.Score(5.5)}, - {Value: "member2", Score: sorted_set.Score(67.77)}, - {Value: "member3", Score: sorted_set.Score(10)}, - {Value: "member4", Score: sorted_set.Score(1083.13)}, - {Value: "member5", Score: sorted_set.Score(11)}, - {Value: "member6", Score: sorted_set.Score(math.Inf(-1))}, - {Value: "member7", Score: sorted_set.Score(math.Inf(1))}, + presetValue: ss.NewSortedSet([]ss.MemberParam{ + {Value: "member1", Score: ss.Score(5.5)}, + {Value: "member2", Score: ss.Score(67.77)}, + {Value: "member3", Score: ss.Score(10)}, + {Value: "member4", Score: ss.Score(1083.13)}, + {Value: "member5", Score: ss.Score(11)}, + {Value: "member6", Score: ss.Score(math.Inf(-1))}, + {Value: "member7", Score: ss.Score(math.Inf(1))}, }), key: "key1", min: math.Inf(-1), @@ -367,14 +365,14 @@ func TestEchoVault_ZCOUNT(t *testing.T) { { name: "Get count of sub-set from -inf to limit", preset: true, - presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ - {Value: "member1", Score: sorted_set.Score(5.5)}, - {Value: "member2", Score: sorted_set.Score(67.77)}, - {Value: "member3", Score: sorted_set.Score(10)}, - {Value: "member4", Score: sorted_set.Score(1083.13)}, - {Value: "member5", Score: sorted_set.Score(11)}, - {Value: "member6", Score: sorted_set.Score(math.Inf(-1))}, - {Value: "member7", Score: sorted_set.Score(math.Inf(1))}, + presetValue: ss.NewSortedSet([]ss.MemberParam{ + {Value: "member1", Score: ss.Score(5.5)}, + {Value: "member2", Score: ss.Score(67.77)}, + {Value: "member3", Score: ss.Score(10)}, + {Value: "member4", Score: ss.Score(1083.13)}, + {Value: "member5", Score: ss.Score(11)}, + {Value: "member6", Score: ss.Score(math.Inf(-1))}, + {Value: "member7", Score: ss.Score(math.Inf(1))}, }), key: "key2", min: math.Inf(-1), @@ -385,14 +383,14 @@ func TestEchoVault_ZCOUNT(t *testing.T) { { name: "Get count of sub-set from bottom boundary to +inf limit", preset: true, - presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ - {Value: "member1", Score: sorted_set.Score(5.5)}, - {Value: "member2", Score: sorted_set.Score(67.77)}, - {Value: "member3", Score: sorted_set.Score(10)}, - {Value: "member4", Score: sorted_set.Score(1083.13)}, - {Value: "member5", Score: sorted_set.Score(11)}, - {Value: "member6", Score: sorted_set.Score(math.Inf(-1))}, - {Value: "member7", Score: sorted_set.Score(math.Inf(1))}, + presetValue: ss.NewSortedSet([]ss.MemberParam{ + {Value: "member1", Score: ss.Score(5.5)}, + {Value: "member2", Score: ss.Score(67.77)}, + {Value: "member3", Score: ss.Score(10)}, + {Value: "member4", Score: ss.Score(1083.13)}, + {Value: "member5", Score: ss.Score(11)}, + {Value: "member6", Score: ss.Score(math.Inf(-1))}, + {Value: "member7", Score: ss.Score(math.Inf(1))}, }), key: "key3", min: 1000, @@ -448,13 +446,13 @@ func TestEchoVault_ZDIFF(t *testing.T) { name: "Get the difference between 2 sorted sets without scores", preset: true, presetValues: map[string]interface{}{ - "key1": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key1": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, }), - "key2": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key2": ss.NewSortedSet([]ss.MemberParam{ {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, @@ -472,13 +470,13 @@ func TestEchoVault_ZDIFF(t *testing.T) { name: "Get the difference between 2 sorted sets with scores", preset: true, presetValues: map[string]interface{}{ - "key3": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key3": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, }), - "key4": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key4": ss.NewSortedSet([]ss.MemberParam{ {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, @@ -496,18 +494,18 @@ func TestEchoVault_ZDIFF(t *testing.T) { name: "Get the difference between 3 sets with scores", preset: true, presetValues: map[string]interface{}{ - "key5": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key5": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, }), - "key6": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key6": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "thirty-six", Score: 36}, {Value: "twelve", Score: 12}, {Value: "eleven", Score: 11}, }), - "key7": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key7": ss.NewSortedSet([]ss.MemberParam{ {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, {Value: "nine", Score: 9}, {Value: "ten", Score: 10}, {Value: "twelve", Score: 12}, @@ -522,7 +520,7 @@ func TestEchoVault_ZDIFF(t *testing.T) { name: "Return sorted set if only one key exists and is a sorted set", preset: true, presetValues: map[string]interface{}{ - "key8": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key8": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, @@ -542,12 +540,12 @@ func TestEchoVault_ZDIFF(t *testing.T) { preset: true, presetValues: map[string]interface{}{ "key9": "Default value", - "key10": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key10": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "thirty-six", Score: 36}, {Value: "twelve", Score: 12}, {Value: "eleven", Score: 11}, }), - "key11": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key11": ss.NewSortedSet([]ss.MemberParam{ {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, {Value: "nine", Score: 9}, {Value: "ten", Score: 10}, {Value: "twelve", Score: 12}, @@ -598,12 +596,12 @@ func TestEchoVault_ZDIFFSTORE(t *testing.T) { name: "Get the difference between 2 sorted sets", preset: true, presetValues: map[string]interface{}{ - "key1": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key1": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, }), - "key2": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key2": ss.NewSortedSet([]ss.MemberParam{ {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, @@ -618,18 +616,18 @@ func TestEchoVault_ZDIFFSTORE(t *testing.T) { name: "Get the difference between 3 sorted sets", preset: true, presetValues: map[string]interface{}{ - "key3": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key3": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, }), - "key4": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key4": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "thirty-six", Score: 36}, {Value: "twelve", Score: 12}, {Value: "eleven", Score: 11}, }), - "key5": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key5": ss.NewSortedSet([]ss.MemberParam{ {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, {Value: "nine", Score: 9}, {Value: "ten", Score: 10}, {Value: "twelve", Score: 12}, @@ -644,7 +642,7 @@ func TestEchoVault_ZDIFFSTORE(t *testing.T) { name: "Return base sorted set element if base set is the only existing key provided and is a valid sorted set", preset: true, presetValues: map[string]interface{}{ - "key6": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key6": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, @@ -661,12 +659,12 @@ func TestEchoVault_ZDIFFSTORE(t *testing.T) { preset: true, presetValues: map[string]interface{}{ "key7": "Default value", - "key8": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key8": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "thirty-six", Score: 36}, {Value: "twelve", Score: 12}, {Value: "eleven", Score: 11}, }), - "key9": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key9": ss.NewSortedSet([]ss.MemberParam{ {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, {Value: "nine", Score: 9}, {Value: "ten", Score: 10}, {Value: "twelve", Score: 12}, @@ -717,7 +715,7 @@ func TestEchoVault_ZINCRBY(t *testing.T) { { name: "Successfully increment by int. Return the new score", preset: true, - presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ + presetValue: ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, @@ -731,7 +729,7 @@ func TestEchoVault_ZINCRBY(t *testing.T) { { name: "Successfully increment by float. Return new score", preset: true, - presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ + presetValue: ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, @@ -754,7 +752,7 @@ func TestEchoVault_ZINCRBY(t *testing.T) { { // 4. name: "Increment score to +inf", preset: true, - presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ + presetValue: ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, @@ -768,7 +766,7 @@ func TestEchoVault_ZINCRBY(t *testing.T) { { name: "Increment score to -inf", preset: true, - presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ + presetValue: ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, @@ -782,7 +780,7 @@ func TestEchoVault_ZINCRBY(t *testing.T) { { name: "Incrementing score by negative increment should lower the score", preset: true, - presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ + presetValue: ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, @@ -806,8 +804,8 @@ func TestEchoVault_ZINCRBY(t *testing.T) { { name: "Return error when trying to increment a member that already has score -inf", preset: true, - presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ - {Value: "one", Score: sorted_set.Score(math.Inf(-1))}, + presetValue: ss.NewSortedSet([]ss.MemberParam{ + {Value: "one", Score: ss.Score(math.Inf(-1))}, }), key: "key8", increment: 2.5, @@ -818,8 +816,8 @@ func TestEchoVault_ZINCRBY(t *testing.T) { { name: "Return error when trying to increment a member that already has score +inf", preset: true, - presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ - {Value: "one", Score: sorted_set.Score(math.Inf(1))}, + presetValue: ss.NewSortedSet([]ss.MemberParam{ + {Value: "one", Score: ss.Score(math.Inf(1))}, }), key: "key9", increment: 2.5, @@ -865,12 +863,12 @@ func TestEchoVault_ZINTER(t *testing.T) { name: "Get the intersection between 2 sorted sets", preset: true, presetValues: map[string]interface{}{ - "key1": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key1": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, }), - "key2": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key2": ss.NewSortedSet([]ss.MemberParam{ {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, @@ -887,18 +885,18 @@ func TestEchoVault_ZINTER(t *testing.T) { name: "Get the intersection between 3 sorted sets with scores", preset: true, presetValues: map[string]interface{}{ - "key3": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key3": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, }), - "key4": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key4": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "thirty-six", Score: 36}, {Value: "twelve", Score: 12}, {Value: "eleven", Score: 11}, {Value: "eight", Score: 8}, }), - "key5": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key5": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "eight", Score: 8}, {Value: "nine", Score: 9}, {Value: "ten", Score: 10}, {Value: "twelve", Score: 12}, @@ -915,18 +913,18 @@ func TestEchoVault_ZINTER(t *testing.T) { name: "Get the intersection between 3 sorted sets with scores", preset: true, presetValues: map[string]interface{}{ - "key6": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key6": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 100}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, }), - "key7": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key7": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "thirty-six", Score: 36}, {Value: "twelve", Score: 12}, {Value: "eleven", Score: 11}, {Value: "eight", Score: 80}, }), - "key8": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key8": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1000}, {Value: "eight", Score: 800}, {Value: "nine", Score: 9}, {Value: "ten", Score: 10}, {Value: "twelve", Score: 12}, @@ -942,18 +940,18 @@ func TestEchoVault_ZINTER(t *testing.T) { // Use MAX aggregate. preset: true, presetValues: map[string]interface{}{ - "key9": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key9": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 100}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, }), - "key10": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key10": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "thirty-six", Score: 36}, {Value: "twelve", Score: 12}, {Value: "eleven", Score: 11}, {Value: "eight", Score: 80}, }), - "key11": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key11": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1000}, {Value: "eight", Score: 800}, {Value: "nine", Score: 9}, {Value: "ten", Score: 10}, {Value: "twelve", Score: 12}, @@ -970,18 +968,18 @@ func TestEchoVault_ZINTER(t *testing.T) { name: "Get the intersection between 3 sorted sets with scores", preset: true, presetValues: map[string]interface{}{ - "key12": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key12": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 100}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, }), - "key13": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key13": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "thirty-six", Score: 36}, {Value: "twelve", Score: 12}, {Value: "eleven", Score: 11}, {Value: "eight", Score: 80}, }), - "key14": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key14": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1000}, {Value: "eight", Score: 800}, {Value: "nine", Score: 9}, {Value: "ten", Score: 10}, {Value: "twelve", Score: 12}, @@ -998,18 +996,18 @@ func TestEchoVault_ZINTER(t *testing.T) { name: "Get the intersection between 3 sorted sets with scores", preset: true, presetValues: map[string]interface{}{ - "key15": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key15": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 100}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, }), - "key16": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key16": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "thirty-six", Score: 36}, {Value: "twelve", Score: 12}, {Value: "eleven", Score: 11}, {Value: "eight", Score: 80}, }), - "key17": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key17": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1000}, {Value: "eight", Score: 800}, {Value: "nine", Score: 9}, {Value: "ten", Score: 10}, {Value: "twelve", Score: 12}, @@ -1026,18 +1024,18 @@ func TestEchoVault_ZINTER(t *testing.T) { name: "Get the intersection between 3 sorted sets with scores", preset: true, presetValues: map[string]interface{}{ - "key18": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key18": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 100}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, }), - "key19": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key19": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "thirty-six", Score: 36}, {Value: "twelve", Score: 12}, {Value: "eleven", Score: 11}, {Value: "eight", Score: 80}, }), - "key20": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key20": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1000}, {Value: "eight", Score: 800}, {Value: "nine", Score: 9}, {Value: "ten", Score: 10}, {Value: "twelve", Score: 12}, @@ -1052,13 +1050,13 @@ func TestEchoVault_ZINTER(t *testing.T) { name: "Throw an error if there are more weights than keys", preset: true, presetValues: map[string]interface{}{ - "key21": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key21": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, }), - "key22": sorted_set.NewSortedSet([]sorted_set.MemberParam{{Value: "one", Score: 1}}), + "key22": ss.NewSortedSet([]ss.MemberParam{{Value: "one", Score: 1}}), }, keys: []string{"key21", "key22"}, options: echovault.ZINTEROptions{Weights: []float64{1, 2, 3}}, @@ -1069,16 +1067,16 @@ func TestEchoVault_ZINTER(t *testing.T) { name: "Throw an error if there are fewer weights than keys", preset: true, presetValues: map[string]interface{}{ - "key23": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key23": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, }), - "key24": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key24": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, }), - "key25": sorted_set.NewSortedSet([]sorted_set.MemberParam{{Value: "one", Score: 1}}), + "key25": ss.NewSortedSet([]ss.MemberParam{{Value: "one", Score: 1}}), }, keys: []string{"key23", "key24", "key25"}, options: echovault.ZINTEROptions{Weights: []float64{5, 4}}, @@ -1089,9 +1087,9 @@ func TestEchoVault_ZINTER(t *testing.T) { name: "Throw an error if there are no keys provided", preset: true, presetValues: map[string]interface{}{ - "key26": sorted_set.NewSortedSet([]sorted_set.MemberParam{{Value: "one", Score: 1}}), - "key27": sorted_set.NewSortedSet([]sorted_set.MemberParam{{Value: "one", Score: 1}}), - "key28": sorted_set.NewSortedSet([]sorted_set.MemberParam{{Value: "one", Score: 1}}), + "key26": ss.NewSortedSet([]ss.MemberParam{{Value: "one", Score: 1}}), + "key27": ss.NewSortedSet([]ss.MemberParam{{Value: "one", Score: 1}}), + "key28": ss.NewSortedSet([]ss.MemberParam{{Value: "one", Score: 1}}), }, keys: []string{}, options: echovault.ZINTEROptions{}, @@ -1102,14 +1100,14 @@ func TestEchoVault_ZINTER(t *testing.T) { name: "Throw an error if any of the provided keys are not sorted sets", preset: true, presetValues: map[string]interface{}{ - "key29": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key29": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, }), "key30": "Default value", - "key31": sorted_set.NewSortedSet([]sorted_set.MemberParam{{Value: "one", Score: 1}}), + "key31": ss.NewSortedSet([]ss.MemberParam{{Value: "one", Score: 1}}), }, keys: []string{"key29", "key30", "key31"}, options: echovault.ZINTEROptions{}, @@ -1120,12 +1118,12 @@ func TestEchoVault_ZINTER(t *testing.T) { name: "If any of the keys does not exist, return an empty array", preset: true, presetValues: map[string]interface{}{ - "key32": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key32": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "thirty-six", Score: 36}, {Value: "twelve", Score: 12}, {Value: "eleven", Score: 11}, }), - "key33": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key33": ss.NewSortedSet([]ss.MemberParam{ {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, {Value: "nine", Score: 9}, {Value: "ten", Score: 10}, {Value: "twelve", Score: 12}, @@ -1177,12 +1175,12 @@ func TestEchoVault_ZINTERSTORE(t *testing.T) { name: "Get the intersection between 2 sorted sets", preset: true, presetValues: map[string]interface{}{ - "key1": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key1": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, }), - "key2": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key2": ss.NewSortedSet([]ss.MemberParam{ {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, @@ -1200,18 +1198,18 @@ func TestEchoVault_ZINTERSTORE(t *testing.T) { name: "Get the intersection between 3 sorted sets with scores", preset: true, presetValues: map[string]interface{}{ - "key3": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key3": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, }), - "key4": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key4": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "thirty-six", Score: 36}, {Value: "twelve", Score: 12}, {Value: "eleven", Score: 11}, {Value: "eight", Score: 8}, }), - "key5": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key5": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "eight", Score: 8}, {Value: "nine", Score: 9}, {Value: "ten", Score: 10}, {Value: "twelve", Score: 12}, @@ -1229,18 +1227,18 @@ func TestEchoVault_ZINTERSTORE(t *testing.T) { name: "Get the intersection between 3 sorted sets with scores", preset: true, presetValues: map[string]interface{}{ - "key6": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key6": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 100}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, }), - "key7": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key7": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "thirty-six", Score: 36}, {Value: "twelve", Score: 12}, {Value: "eleven", Score: 11}, {Value: "eight", Score: 80}, }), - "key8": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key8": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1000}, {Value: "eight", Score: 800}, {Value: "nine", Score: 9}, {Value: "ten", Score: 10}, {Value: "twelve", Score: 12}, @@ -1258,18 +1256,18 @@ func TestEchoVault_ZINTERSTORE(t *testing.T) { name: "Get the intersection between 3 sorted sets with scores", preset: true, presetValues: map[string]interface{}{ - "key9": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key9": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 100}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, }), - "key10": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key10": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "thirty-six", Score: 36}, {Value: "twelve", Score: 12}, {Value: "eleven", Score: 11}, {Value: "eight", Score: 80}, }), - "key11": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key11": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1000}, {Value: "eight", Score: 800}, {Value: "nine", Score: 9}, {Value: "ten", Score: 10}, {Value: "twelve", Score: 12}, @@ -1287,18 +1285,18 @@ func TestEchoVault_ZINTERSTORE(t *testing.T) { name: "Get the intersection between 3 sorted sets with scores", preset: true, presetValues: map[string]interface{}{ - "key12": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key12": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 100}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, }), - "key13": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key13": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "thirty-six", Score: 36}, {Value: "twelve", Score: 12}, {Value: "eleven", Score: 11}, {Value: "eight", Score: 80}, }), - "key14": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key14": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1000}, {Value: "eight", Score: 800}, {Value: "nine", Score: 9}, {Value: "ten", Score: 10}, {Value: "twelve", Score: 12}, @@ -1316,18 +1314,18 @@ func TestEchoVault_ZINTERSTORE(t *testing.T) { name: "Get the intersection between 3 sorted sets with scores", preset: true, presetValues: map[string]interface{}{ - "key15": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key15": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 100}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, }), - "key16": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key16": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "thirty-six", Score: 36}, {Value: "twelve", Score: 12}, {Value: "eleven", Score: 11}, {Value: "eight", Score: 80}, }), - "key17": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key17": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1000}, {Value: "eight", Score: 800}, {Value: "nine", Score: 9}, {Value: "ten", Score: 10}, {Value: "twelve", Score: 12}, @@ -1345,18 +1343,18 @@ func TestEchoVault_ZINTERSTORE(t *testing.T) { name: "Get the intersection between 3 sorted sets with scores", preset: true, presetValues: map[string]interface{}{ - "key18": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key18": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 100}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, }), - "key19": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key19": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "thirty-six", Score: 36}, {Value: "twelve", Score: 12}, {Value: "eleven", Score: 11}, {Value: "eight", Score: 80}, }), - "key20": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key20": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1000}, {Value: "eight", Score: 800}, {Value: "nine", Score: 9}, {Value: "ten", Score: 10}, {Value: "twelve", Score: 12}, @@ -1372,13 +1370,13 @@ func TestEchoVault_ZINTERSTORE(t *testing.T) { name: "Throw an error if there are more weights than keys", preset: true, presetValues: map[string]interface{}{ - "key21": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key21": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, }), - "key22": sorted_set.NewSortedSet([]sorted_set.MemberParam{{Value: "one", Score: 1}}), + "key22": ss.NewSortedSet([]ss.MemberParam{{Value: "one", Score: 1}}), }, destination: "destination8", keys: []string{"key21", "key22"}, @@ -1390,16 +1388,16 @@ func TestEchoVault_ZINTERSTORE(t *testing.T) { name: "Throw an error if there are fewer weights than keys", preset: true, presetValues: map[string]interface{}{ - "key23": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key23": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, }), - "key24": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key24": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, }), - "key25": sorted_set.NewSortedSet([]sorted_set.MemberParam{{Value: "one", Score: 1}}), + "key25": ss.NewSortedSet([]ss.MemberParam{{Value: "one", Score: 1}}), }, destination: "destination9", keys: []string{"key23", "key24"}, @@ -1411,9 +1409,9 @@ func TestEchoVault_ZINTERSTORE(t *testing.T) { name: "Throw an error if there are no keys provided", preset: true, presetValues: map[string]interface{}{ - "key26": sorted_set.NewSortedSet([]sorted_set.MemberParam{{Value: "one", Score: 1}}), - "key27": sorted_set.NewSortedSet([]sorted_set.MemberParam{{Value: "one", Score: 1}}), - "key28": sorted_set.NewSortedSet([]sorted_set.MemberParam{{Value: "one", Score: 1}}), + "key26": ss.NewSortedSet([]ss.MemberParam{{Value: "one", Score: 1}}), + "key27": ss.NewSortedSet([]ss.MemberParam{{Value: "one", Score: 1}}), + "key28": ss.NewSortedSet([]ss.MemberParam{{Value: "one", Score: 1}}), }, destination: "destination10", keys: []string{}, @@ -1425,14 +1423,14 @@ func TestEchoVault_ZINTERSTORE(t *testing.T) { name: "Throw an error if any of the provided keys are not sorted sets", preset: true, presetValues: map[string]interface{}{ - "key29": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key29": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, }), "key30": "Default value", - "key31": sorted_set.NewSortedSet([]sorted_set.MemberParam{{Value: "one", Score: 1}}), + "key31": ss.NewSortedSet([]ss.MemberParam{{Value: "one", Score: 1}}), }, destination: "destination11", keys: []string{"key29", "key30", "key31"}, @@ -1444,12 +1442,12 @@ func TestEchoVault_ZINTERSTORE(t *testing.T) { name: "If any of the keys does not exist, return an empty array", preset: true, presetValues: map[string]interface{}{ - "key32": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key32": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "thirty-six", Score: 36}, {Value: "twelve", Score: 12}, {Value: "eleven", Score: 11}, }), - "key33": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key33": ss.NewSortedSet([]ss.MemberParam{ {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, {Value: "nine", Score: 9}, {Value: "ten", Score: 10}, {Value: "twelve", Score: 12}, @@ -1501,14 +1499,14 @@ func TestEchoVault_ZLEXCOUNT(t *testing.T) { { name: "Get entire count using infinity boundaries", preset: true, - presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ - {Value: "e", Score: sorted_set.Score(1)}, - {Value: "f", Score: sorted_set.Score(1)}, - {Value: "g", Score: sorted_set.Score(1)}, - {Value: "h", Score: sorted_set.Score(1)}, - {Value: "i", Score: sorted_set.Score(1)}, - {Value: "j", Score: sorted_set.Score(1)}, - {Value: "k", Score: sorted_set.Score(1)}, + presetValue: ss.NewSortedSet([]ss.MemberParam{ + {Value: "e", Score: ss.Score(1)}, + {Value: "f", Score: ss.Score(1)}, + {Value: "g", Score: ss.Score(1)}, + {Value: "h", Score: ss.Score(1)}, + {Value: "i", Score: ss.Score(1)}, + {Value: "j", Score: ss.Score(1)}, + {Value: "k", Score: ss.Score(1)}, }), key: "key1", min: "f", @@ -1519,14 +1517,14 @@ func TestEchoVault_ZLEXCOUNT(t *testing.T) { { name: "Return 0 when the members do not have the same score", preset: true, - presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ - {Value: "a", Score: sorted_set.Score(5.5)}, - {Value: "b", Score: sorted_set.Score(67.77)}, - {Value: "c", Score: sorted_set.Score(10)}, - {Value: "d", Score: sorted_set.Score(1083.13)}, - {Value: "e", Score: sorted_set.Score(11)}, - {Value: "f", Score: sorted_set.Score(math.Inf(-1))}, - {Value: "g", Score: sorted_set.Score(math.Inf(1))}, + presetValue: ss.NewSortedSet([]ss.MemberParam{ + {Value: "a", Score: ss.Score(5.5)}, + {Value: "b", Score: ss.Score(67.77)}, + {Value: "c", Score: ss.Score(10)}, + {Value: "d", Score: ss.Score(1083.13)}, + {Value: "e", Score: ss.Score(11)}, + {Value: "f", Score: ss.Score(math.Inf(-1))}, + {Value: "g", Score: ss.Score(math.Inf(1))}, }), key: "key2", min: "a", @@ -1592,7 +1590,7 @@ func TestEchoVault_ZMPOP(t *testing.T) { name: "Successfully pop one min element by default", preset: true, presetValues: map[string]interface{}{ - "key1": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key1": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, @@ -1609,7 +1607,7 @@ func TestEchoVault_ZMPOP(t *testing.T) { name: "Successfully pop one min element by specifying MIN", preset: true, presetValues: map[string]interface{}{ - "key2": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key2": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, @@ -1626,7 +1624,7 @@ func TestEchoVault_ZMPOP(t *testing.T) { name: "Successfully pop one max element by specifying MAX modifier", preset: true, presetValues: map[string]interface{}{ - "key3": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key3": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, @@ -1643,7 +1641,7 @@ func TestEchoVault_ZMPOP(t *testing.T) { name: "Successfully pop multiple min elements", preset: true, presetValues: map[string]interface{}{ - "key4": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key4": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, @@ -1661,7 +1659,7 @@ func TestEchoVault_ZMPOP(t *testing.T) { name: "Successfully pop multiple max elements", preset: true, presetValues: map[string]interface{}{ - "key5": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key5": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, @@ -1676,8 +1674,8 @@ func TestEchoVault_ZMPOP(t *testing.T) { name: "Successfully pop elements from the first set which is non-empty", preset: true, presetValues: map[string]interface{}{ - "key6": sorted_set.NewSortedSet([]sorted_set.MemberParam{}), - "key7": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key6": ss.NewSortedSet([]ss.MemberParam{}), + "key7": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, @@ -1694,8 +1692,8 @@ func TestEchoVault_ZMPOP(t *testing.T) { presetValues: map[string]interface{}{ "key8": "Default value", "key9": 56, - "key10": sorted_set.NewSortedSet([]sorted_set.MemberParam{}), - "key11": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key10": ss.NewSortedSet([]ss.MemberParam{}), + "key11": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, @@ -1746,7 +1744,7 @@ func TestEchoVault_ZMSCORE(t *testing.T) { // Return nil for elements that do not exist in the sorted set. name: "Return multiple scores from the sorted set", preset: true, - presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ + presetValue: ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1.1}, {Value: "two", Score: 245}, {Value: "three", Score: 3}, {Value: "four", Score: 4.055}, {Value: "five", Score: 5}, @@ -1825,7 +1823,7 @@ func TestEchoVault_ZPOP(t *testing.T) { { name: "Successfully pop one min element", preset: true, - presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ + presetValue: ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, @@ -1841,7 +1839,7 @@ func TestEchoVault_ZPOP(t *testing.T) { { name: "Successfully pop one max element", preset: true, - presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ + presetValue: ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, @@ -1855,7 +1853,7 @@ func TestEchoVault_ZPOP(t *testing.T) { { name: "Successfully pop multiple min elements", preset: true, - presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ + presetValue: ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, @@ -1872,7 +1870,7 @@ func TestEchoVault_ZPOP(t *testing.T) { { name: "Successfully pop multiple max elements", preset: true, - presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ + presetValue: ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, @@ -1933,7 +1931,7 @@ func TestEchoVault_ZRANDMEMBER(t *testing.T) { name: "Return multiple random elements without removing them", preset: true, key: "key1", - presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ + presetValue: ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, }), @@ -1948,7 +1946,7 @@ func TestEchoVault_ZRANDMEMBER(t *testing.T) { name: "Return multiple random elements and their scores without removing them", preset: true, key: "key2", - presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ + presetValue: ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, }), @@ -2006,7 +2004,7 @@ func TestEchoVault_ZRANGE(t *testing.T) { { name: "Get elements withing score range without score", preset: true, - presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ + presetValue: ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, @@ -2022,7 +2020,7 @@ func TestEchoVault_ZRANGE(t *testing.T) { { name: "Get elements within score range with score", preset: true, - presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ + presetValue: ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, @@ -2040,7 +2038,7 @@ func TestEchoVault_ZRANGE(t *testing.T) { // Offset and limit are in where we start and stop counting in the original sorted set (NOT THE RESULT). name: "Get elements within score range with offset and limit", preset: true, - presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ + presetValue: ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, @@ -2056,7 +2054,7 @@ func TestEchoVault_ZRANGE(t *testing.T) { { name: "Get elements within lex range without score", preset: true, - presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ + presetValue: ss.NewSortedSet([]ss.MemberParam{ {Value: "a", Score: 1}, {Value: "e", Score: 1}, {Value: "b", Score: 1}, {Value: "f", Score: 1}, {Value: "c", Score: 1}, {Value: "g", Score: 1}, @@ -2072,7 +2070,7 @@ func TestEchoVault_ZRANGE(t *testing.T) { { name: "Get elements within lex range with score", preset: true, - presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ + presetValue: ss.NewSortedSet([]ss.MemberParam{ {Value: "a", Score: 1}, {Value: "e", Score: 1}, {Value: "b", Score: 1}, {Value: "f", Score: 1}, {Value: "c", Score: 1}, {Value: "g", Score: 1}, @@ -2090,7 +2088,7 @@ func TestEchoVault_ZRANGE(t *testing.T) { // Offset and limit are in where we start and stop counting in the original sorted set (NOT THE RESULT). name: "Get elements within lex range with offset and limit", preset: true, - presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ + presetValue: ss.NewSortedSet([]ss.MemberParam{ {Value: "a", Score: 1}, {Value: "b", Score: 1}, {Value: "c", Score: 1}, {Value: "d", Score: 1}, {Value: "e", Score: 1}, {Value: "f", Score: 1}, @@ -2106,7 +2104,7 @@ func TestEchoVault_ZRANGE(t *testing.T) { { name: "Return an empty map when we use BYLEX while elements have different scores", preset: true, - presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ + presetValue: ss.NewSortedSet([]ss.MemberParam{ {Value: "a", Score: 1}, {Value: "b", Score: 5}, {Value: "c", Score: 2}, {Value: "d", Score: 6}, {Value: "e", Score: 3}, {Value: "f", Score: 7}, @@ -2171,7 +2169,7 @@ func TestEchoVault_ZRANGESTORE(t *testing.T) { name: "Get elements within score range without score", preset: true, presetValues: map[string]interface{}{ - "key1": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key1": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, @@ -2190,7 +2188,7 @@ func TestEchoVault_ZRANGESTORE(t *testing.T) { name: "Get elements within score range with score", preset: true, presetValues: map[string]interface{}{ - "key2": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key2": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, @@ -2211,7 +2209,7 @@ func TestEchoVault_ZRANGESTORE(t *testing.T) { name: "Get elements within score range with offset and limit", preset: true, presetValues: map[string]interface{}{ - "key3": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key3": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, @@ -2230,7 +2228,7 @@ func TestEchoVault_ZRANGESTORE(t *testing.T) { name: "Get elements within lex range without score", preset: true, presetValues: map[string]interface{}{ - "key4": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key4": ss.NewSortedSet([]ss.MemberParam{ {Value: "a", Score: 1}, {Value: "e", Score: 1}, {Value: "b", Score: 1}, {Value: "f", Score: 1}, {Value: "c", Score: 1}, {Value: "g", Score: 1}, @@ -2249,7 +2247,7 @@ func TestEchoVault_ZRANGESTORE(t *testing.T) { name: "Get elements within lex range with score", preset: true, presetValues: map[string]interface{}{ - "key5": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key5": ss.NewSortedSet([]ss.MemberParam{ {Value: "a", Score: 1}, {Value: "e", Score: 1}, {Value: "b", Score: 1}, {Value: "f", Score: 1}, {Value: "c", Score: 1}, {Value: "g", Score: 1}, @@ -2270,7 +2268,7 @@ func TestEchoVault_ZRANGESTORE(t *testing.T) { name: "Get elements within lex range with offset and limit", preset: true, presetValues: map[string]interface{}{ - "key6": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key6": ss.NewSortedSet([]ss.MemberParam{ {Value: "a", Score: 1}, {Value: "b", Score: 1}, {Value: "c", Score: 1}, {Value: "d", Score: 1}, {Value: "e", Score: 1}, {Value: "f", Score: 1}, @@ -2292,7 +2290,7 @@ func TestEchoVault_ZRANGESTORE(t *testing.T) { name: "Get elements within lex range with offset and limit + reverse the results", preset: true, presetValues: map[string]interface{}{ - "key7": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key7": ss.NewSortedSet([]ss.MemberParam{ {Value: "a", Score: 1}, {Value: "b", Score: 1}, {Value: "c", Score: 1}, {Value: "d", Score: 1}, {Value: "e", Score: 1}, {Value: "f", Score: 1}, @@ -2311,7 +2309,7 @@ func TestEchoVault_ZRANGESTORE(t *testing.T) { name: "Return an empty slice when we use BYLEX while elements have different scores", preset: true, presetValues: map[string]interface{}{ - "key8": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key8": ss.NewSortedSet([]ss.MemberParam{ {Value: "a", Score: 1}, {Value: "b", Score: 5}, {Value: "c", Score: 2}, {Value: "d", Score: 6}, {Value: "e", Score: 3}, {Value: "f", Score: 7}, @@ -2380,7 +2378,7 @@ func TestEchoVault_ZRANK(t *testing.T) { { name: "Return element's rank from a sorted set", preset: true, - presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ + presetValue: ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, @@ -2394,7 +2392,7 @@ func TestEchoVault_ZRANK(t *testing.T) { { name: "Return element's rank from a sorted set with its score", preset: true, - presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ + presetValue: ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 100.1}, {Value: "two", Score: 245}, {Value: "three", Score: 305.43}, {Value: "four", Score: 411.055}, {Value: "five", Score: 500}, @@ -2418,7 +2416,7 @@ func TestEchoVault_ZRANK(t *testing.T) { { name: "If key exists and is a sorted set, but the member does not exist, return nil", preset: true, - presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ + presetValue: ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1.1}, {Value: "two", Score: 245}, {Value: "three", Score: 3}, {Value: "four", Score: 4.055}, {Value: "five", Score: 5}, @@ -2478,7 +2476,7 @@ func TestEchoVault_ZREM(t *testing.T) { // Return deleted count. name: "Successfully remove multiple elements from sorted set, skipping non-existent members", preset: true, - presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ + presetValue: ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, @@ -2546,7 +2544,7 @@ func TestEchoVault_ZREMRANGEBYSCORE(t *testing.T) { { name: "Successfully remove multiple elements with scores inside the provided range", preset: true, - presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ + presetValue: ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, @@ -2615,7 +2613,7 @@ func TestEchoVault_ZSCORE(t *testing.T) { { name: "Return score from a sorted set", preset: true, - presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ + presetValue: ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1.1}, {Value: "two", Score: 245}, {Value: "three", Score: 3}, {Value: "four", Score: 4.055}, {Value: "five", Score: 5}, @@ -2637,7 +2635,7 @@ func TestEchoVault_ZSCORE(t *testing.T) { { name: "If key exists and is a sorted set, but the member does not exist, return nil", preset: true, - presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ + presetValue: ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1.1}, {Value: "two", Score: 245}, {Value: "three", Score: 3}, {Value: "four", Score: 4.055}, {Value: "five", Score: 5}, @@ -2694,12 +2692,12 @@ func TestEchoVault_ZUNION(t *testing.T) { name: "Get the union between 2 sorted sets", preset: true, presetValues: map[string]interface{}{ - "key1": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key1": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, }), - "key2": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key2": ss.NewSortedSet([]ss.MemberParam{ {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, @@ -2719,18 +2717,18 @@ func TestEchoVault_ZUNION(t *testing.T) { name: "Get the union between 3 sorted sets with scores", preset: true, presetValues: map[string]interface{}{ - "key3": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key3": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, }), - "key4": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key4": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "thirty-six", Score: 36}, {Value: "twelve", Score: 12}, {Value: "eleven", Score: 11}, {Value: "eight", Score: 8}, }), - "key5": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key5": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "eight", Score: 8}, {Value: "nine", Score: 9}, {Value: "ten", Score: 10}, {Value: "twelve", Score: 12}, {Value: "thirty-six", Score: 36}, @@ -2750,18 +2748,18 @@ func TestEchoVault_ZUNION(t *testing.T) { name: "Get the union between 3 sorted sets with scores", preset: true, presetValues: map[string]interface{}{ - "key6": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key6": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 100}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, }), - "key7": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key7": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "thirty-six", Score: 36}, {Value: "twelve", Score: 12}, {Value: "eleven", Score: 11}, {Value: "eight", Score: 80}, }), - "key8": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key8": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1000}, {Value: "eight", Score: 800}, {Value: "nine", Score: 9}, {Value: "ten", Score: 10}, {Value: "twelve", Score: 12}, {Value: "thirty-six", Score: 72}, @@ -2781,18 +2779,18 @@ func TestEchoVault_ZUNION(t *testing.T) { name: "Get the union between 3 sorted sets with scores", preset: true, presetValues: map[string]interface{}{ - "key9": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key9": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 100}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, }), - "key10": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key10": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "thirty-six", Score: 36}, {Value: "twelve", Score: 12}, {Value: "eleven", Score: 11}, {Value: "eight", Score: 80}, }), - "key11": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key11": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1000}, {Value: "eight", Score: 800}, {Value: "nine", Score: 9}, {Value: "ten", Score: 10}, {Value: "twelve", Score: 12}, {Value: "thirty-six", Score: 72}, @@ -2812,18 +2810,18 @@ func TestEchoVault_ZUNION(t *testing.T) { name: "Get the union between 3 sorted sets with scores", preset: true, presetValues: map[string]interface{}{ - "key12": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key12": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 100}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, }), - "key13": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key13": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "thirty-six", Score: 36}, {Value: "twelve", Score: 12}, {Value: "eleven", Score: 11}, {Value: "eight", Score: 80}, }), - "key14": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key14": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1000}, {Value: "eight", Score: 800}, {Value: "nine", Score: 9}, {Value: "ten", Score: 10}, {Value: "twelve", Score: 12}, @@ -2843,18 +2841,18 @@ func TestEchoVault_ZUNION(t *testing.T) { name: "Get the union between 3 sorted sets with scores", preset: true, presetValues: map[string]interface{}{ - "key15": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key15": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 100}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, }), - "key16": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key16": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "thirty-six", Score: 36}, {Value: "twelve", Score: 12}, {Value: "eleven", Score: 11}, {Value: "eight", Score: 80}, }), - "key17": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key17": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1000}, {Value: "eight", Score: 800}, {Value: "nine", Score: 9}, {Value: "ten", Score: 10}, {Value: "twelve", Score: 12}, @@ -2874,18 +2872,18 @@ func TestEchoVault_ZUNION(t *testing.T) { name: "Get the union between 3 sorted sets with scores", preset: true, presetValues: map[string]interface{}{ - "key18": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key18": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 100}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, }), - "key19": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key19": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "thirty-six", Score: 36}, {Value: "twelve", Score: 12}, {Value: "eleven", Score: 11}, {Value: "eight", Score: 80}, }), - "key20": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key20": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1000}, {Value: "eight", Score: 800}, {Value: "nine", Score: 9}, {Value: "ten", Score: 10}, {Value: "twelve", Score: 12}, @@ -2903,13 +2901,13 @@ func TestEchoVault_ZUNION(t *testing.T) { name: "Throw an error if there are more weights than keys", preset: true, presetValues: map[string]interface{}{ - "key21": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key21": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, }), - "key22": sorted_set.NewSortedSet([]sorted_set.MemberParam{{Value: "one", Score: 1}}), + "key22": ss.NewSortedSet([]ss.MemberParam{{Value: "one", Score: 1}}), }, keys: []string{"key21", "key22"}, options: echovault.ZUNIONOptions{Weights: []float64{1, 2, 3}}, @@ -2920,16 +2918,16 @@ func TestEchoVault_ZUNION(t *testing.T) { name: "Throw an error if there are fewer weights than keys", preset: true, presetValues: map[string]interface{}{ - "key23": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key23": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, }), - "key24": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key24": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, }), - "key25": sorted_set.NewSortedSet([]sorted_set.MemberParam{{Value: "one", Score: 1}}), + "key25": ss.NewSortedSet([]ss.MemberParam{{Value: "one", Score: 1}}), }, keys: []string{"key23", "key24", "key25"}, options: echovault.ZUNIONOptions{Weights: []float64{5, 4}}, @@ -2940,9 +2938,9 @@ func TestEchoVault_ZUNION(t *testing.T) { name: "Throw an error if there are no keys provided", preset: true, presetValues: map[string]interface{}{ - "key26": sorted_set.NewSortedSet([]sorted_set.MemberParam{{Value: "one", Score: 1}}), - "key27": sorted_set.NewSortedSet([]sorted_set.MemberParam{{Value: "one", Score: 1}}), - "key28": sorted_set.NewSortedSet([]sorted_set.MemberParam{{Value: "one", Score: 1}}), + "key26": ss.NewSortedSet([]ss.MemberParam{{Value: "one", Score: 1}}), + "key27": ss.NewSortedSet([]ss.MemberParam{{Value: "one", Score: 1}}), + "key28": ss.NewSortedSet([]ss.MemberParam{{Value: "one", Score: 1}}), }, keys: []string{}, options: echovault.ZUNIONOptions{Weights: []float64{5, 4}}, @@ -2953,14 +2951,14 @@ func TestEchoVault_ZUNION(t *testing.T) { name: "Throw an error if any of the provided keys are not sorted sets", preset: true, presetValues: map[string]interface{}{ - "key29": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key29": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, }), "key30": "Default value", - "key31": sorted_set.NewSortedSet([]sorted_set.MemberParam{{Value: "one", Score: 1}}), + "key31": ss.NewSortedSet([]ss.MemberParam{{Value: "one", Score: 1}}), }, keys: []string{"key29", "key30", "key31"}, options: echovault.ZUNIONOptions{}, @@ -2971,12 +2969,12 @@ func TestEchoVault_ZUNION(t *testing.T) { name: "If any of the keys does not exist, skip it", preset: true, presetValues: map[string]interface{}{ - "key32": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key32": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "thirty-six", Score: 36}, {Value: "twelve", Score: 12}, {Value: "eleven", Score: 11}, }), - "key33": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key33": ss.NewSortedSet([]ss.MemberParam{ {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, {Value: "nine", Score: 9}, {Value: "ten", Score: 10}, {Value: "twelve", Score: 12}, @@ -3031,12 +3029,12 @@ func TestEchoVault_ZUNIONSTORE(t *testing.T) { name: "Get the union between 2 sorted sets", preset: true, presetValues: map[string]interface{}{ - "key1": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key1": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, }), - "key2": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key2": ss.NewSortedSet([]ss.MemberParam{ {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, @@ -3054,18 +3052,18 @@ func TestEchoVault_ZUNIONSTORE(t *testing.T) { name: "Get the union between 3 sorted sets with scores", preset: true, presetValues: map[string]interface{}{ - "key3": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key3": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, }), - "key4": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key4": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "thirty-six", Score: 36}, {Value: "twelve", Score: 12}, {Value: "eleven", Score: 11}, {Value: "eight", Score: 8}, }), - "key5": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key5": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "eight", Score: 8}, {Value: "nine", Score: 9}, {Value: "ten", Score: 10}, {Value: "twelve", Score: 12}, {Value: "thirty-six", Score: 36}, @@ -3083,18 +3081,18 @@ func TestEchoVault_ZUNIONSTORE(t *testing.T) { name: "Get the union between 3 sorted sets with scores", preset: true, presetValues: map[string]interface{}{ - "key6": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key6": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 100}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, }), - "key7": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key7": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "thirty-six", Score: 36}, {Value: "twelve", Score: 12}, {Value: "eleven", Score: 11}, {Value: "eight", Score: 80}, }), - "key8": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key8": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1000}, {Value: "eight", Score: 800}, {Value: "nine", Score: 9}, {Value: "ten", Score: 10}, {Value: "twelve", Score: 12}, {Value: "thirty-six", Score: 72}, @@ -3112,18 +3110,18 @@ func TestEchoVault_ZUNIONSTORE(t *testing.T) { name: "Get the union between 3 sorted sets with scores", preset: true, presetValues: map[string]interface{}{ - "key9": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key9": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 100}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, }), - "key10": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key10": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "thirty-six", Score: 36}, {Value: "twelve", Score: 12}, {Value: "eleven", Score: 11}, {Value: "eight", Score: 80}, }), - "key11": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key11": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1000}, {Value: "eight", Score: 800}, {Value: "nine", Score: 9}, {Value: "ten", Score: 10}, {Value: "twelve", Score: 12}, {Value: "thirty-six", Score: 72}, @@ -3141,18 +3139,18 @@ func TestEchoVault_ZUNIONSTORE(t *testing.T) { name: "Get the union between 3 sorted sets with scores", preset: true, presetValues: map[string]interface{}{ - "key12": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key12": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 100}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, }), - "key13": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key13": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "thirty-six", Score: 36}, {Value: "twelve", Score: 12}, {Value: "eleven", Score: 11}, {Value: "eight", Score: 80}, }), - "key14": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key14": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1000}, {Value: "eight", Score: 800}, {Value: "nine", Score: 9}, {Value: "ten", Score: 10}, {Value: "twelve", Score: 12}, @@ -3170,18 +3168,18 @@ func TestEchoVault_ZUNIONSTORE(t *testing.T) { name: "Get the union between 3 sorted sets with scores", preset: true, presetValues: map[string]interface{}{ - "key15": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key15": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 100}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, }), - "key16": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key16": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "thirty-six", Score: 36}, {Value: "twelve", Score: 12}, {Value: "eleven", Score: 11}, {Value: "eight", Score: 80}, }), - "key17": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key17": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1000}, {Value: "eight", Score: 800}, {Value: "nine", Score: 9}, {Value: "ten", Score: 10}, {Value: "twelve", Score: 12}, @@ -3199,18 +3197,18 @@ func TestEchoVault_ZUNIONSTORE(t *testing.T) { name: "Get the union between 3 sorted sets with scores", preset: true, presetValues: map[string]interface{}{ - "key18": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key18": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 100}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, }), - "key19": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key19": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "thirty-six", Score: 36}, {Value: "twelve", Score: 12}, {Value: "eleven", Score: 11}, {Value: "eight", Score: 80}, }), - "key20": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key20": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1000}, {Value: "eight", Score: 800}, {Value: "nine", Score: 9}, {Value: "ten", Score: 10}, {Value: "twelve", Score: 12}, @@ -3226,13 +3224,13 @@ func TestEchoVault_ZUNIONSTORE(t *testing.T) { name: "Throw an error if there are more weights than keys", preset: true, presetValues: map[string]interface{}{ - "key21": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key21": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, }), - "key22": sorted_set.NewSortedSet([]sorted_set.MemberParam{{Value: "one", Score: 1}}), + "key22": ss.NewSortedSet([]ss.MemberParam{{Value: "one", Score: 1}}), }, destination: "destination8", keys: []string{"key21", "key22"}, @@ -3244,16 +3242,16 @@ func TestEchoVault_ZUNIONSTORE(t *testing.T) { name: "Throw an error if there are fewer weights than keys", preset: true, presetValues: map[string]interface{}{ - "key23": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key23": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, }), - "key24": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key24": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, }), - "key25": sorted_set.NewSortedSet([]sorted_set.MemberParam{{Value: "one", Score: 1}}), + "key25": ss.NewSortedSet([]ss.MemberParam{{Value: "one", Score: 1}}), }, destination: "destination9", keys: []string{"key23", "key24", "key25"}, @@ -3265,14 +3263,14 @@ func TestEchoVault_ZUNIONSTORE(t *testing.T) { name: "Throw an error if any of the provided keys are not sorted sets", preset: true, presetValues: map[string]interface{}{ - "key29": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key29": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "three", Score: 3}, {Value: "four", Score: 4}, {Value: "five", Score: 5}, {Value: "six", Score: 6}, {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, }), "key30": "Default value", - "key31": sorted_set.NewSortedSet([]sorted_set.MemberParam{{Value: "one", Score: 1}}), + "key31": ss.NewSortedSet([]ss.MemberParam{{Value: "one", Score: 1}}), }, destination: "destination11", keys: []string{"key29", "key30", "key31"}, @@ -3284,12 +3282,12 @@ func TestEchoVault_ZUNIONSTORE(t *testing.T) { name: "If any of the keys does not exist, skip it", preset: true, presetValues: map[string]interface{}{ - "key32": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key32": ss.NewSortedSet([]ss.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, {Value: "thirty-six", Score: 36}, {Value: "twelve", Score: 12}, {Value: "eleven", Score: 11}, }), - "key33": sorted_set.NewSortedSet([]sorted_set.MemberParam{ + "key33": ss.NewSortedSet([]ss.MemberParam{ {Value: "seven", Score: 7}, {Value: "eight", Score: 8}, {Value: "nine", Score: 9}, {Value: "ten", Score: 10}, {Value: "twelve", Score: 12}, diff --git a/test/modules/sorted_set/commands_test.go b/test/modules/sorted_set/commands_test.go index 0810b450..bfc31df2 100644 --- a/test/modules/sorted_set/commands_test.go +++ b/test/modules/sorted_set/commands_test.go @@ -20,10 +20,9 @@ import ( "errors" "fmt" "github.com/echovault/echovault/internal/config" - "github.com/echovault/echovault/internal/sorted_set" + "github.com/echovault/echovault/internal/modules/sorted_set" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/echovault" - ss "github.com/echovault/echovault/pkg/modules/sorted_set" "github.com/echovault/echovault/pkg/types" "github.com/tidwall/resp" "math" @@ -38,7 +37,6 @@ var mockServer *echovault.EchoVault func init() { mockServer, _ = echovault.NewEchoVault( - echovault.WithCommands(ss.Commands()), echovault.WithConfig(config.Config{ DataDir: "", EvictionPolicy: constants.NoEviction, diff --git a/test/modules/string/api_string_test.go b/test/modules/string/api_string_test.go index 36197c94..6bb96f47 100644 --- a/test/modules/string/api_string_test.go +++ b/test/modules/string/api_string_test.go @@ -18,13 +18,11 @@ import ( "context" "github.com/echovault/echovault/internal/config" "github.com/echovault/echovault/pkg/echovault" - str "github.com/echovault/echovault/pkg/modules/string" "testing" ) func createEchoVault() *echovault.EchoVault { ev, _ := echovault.NewEchoVault( - echovault.WithCommands(str.Commands()), echovault.WithConfig(config.Config{ DataDir: "", }), diff --git a/test/modules/string/commands_test.go b/test/modules/string/commands_test.go index 9497e45c..296501d0 100644 --- a/test/modules/string/commands_test.go +++ b/test/modules/string/commands_test.go @@ -23,7 +23,6 @@ import ( "github.com/echovault/echovault/internal/config" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/echovault" - str "github.com/echovault/echovault/pkg/modules/string" "github.com/echovault/echovault/pkg/types" "github.com/tidwall/resp" "net" @@ -36,7 +35,6 @@ var mockServer *echovault.EchoVault func init() { mockServer, _ = echovault.NewEchoVault( - echovault.WithCommands(str.Commands()), echovault.WithConfig(config.Config{ DataDir: "", EvictionPolicy: constants.NoEviction, From 6bf638e6226b69015e05d364fe45978c2c13d0b5 Mon Sep 17 00:00:00 2001 From: Kelvin Clement Mwinuka Date: Wed, 24 Apr 2024 22:42:01 +0800 Subject: [PATCH 4/6] Renamed all api test files to api_test.go --- test/modules/acl/{api_acl_test.go => api_test.go} | 0 test/modules/admin/{api_admin_test.go => api_test.go} | 0 test/modules/connection/{api_connection_test.go => api_test.go} | 0 test/modules/generic/{api_generic_test.go => api_test.go} | 0 test/modules/hash/{api_hash_test.go => api_test.go} | 0 test/modules/list/{api_list_test.go => api_test.go} | 0 test/modules/pubsub/{api_pubsub_test.go => api_test.go} | 0 test/modules/set/{api_set_test.go => api_test.go} | 0 test/modules/sorted_set/{api_sorted_set_test.go => api_test.go} | 0 test/modules/string/{api_string_test.go => api_test.go} | 0 10 files changed, 0 insertions(+), 0 deletions(-) rename test/modules/acl/{api_acl_test.go => api_test.go} (100%) rename test/modules/admin/{api_admin_test.go => api_test.go} (100%) rename test/modules/connection/{api_connection_test.go => api_test.go} (100%) rename test/modules/generic/{api_generic_test.go => api_test.go} (100%) rename test/modules/hash/{api_hash_test.go => api_test.go} (100%) rename test/modules/list/{api_list_test.go => api_test.go} (100%) rename test/modules/pubsub/{api_pubsub_test.go => api_test.go} (100%) rename test/modules/set/{api_set_test.go => api_test.go} (100%) rename test/modules/sorted_set/{api_sorted_set_test.go => api_test.go} (100%) rename test/modules/string/{api_string_test.go => api_test.go} (100%) diff --git a/test/modules/acl/api_acl_test.go b/test/modules/acl/api_test.go similarity index 100% rename from test/modules/acl/api_acl_test.go rename to test/modules/acl/api_test.go diff --git a/test/modules/admin/api_admin_test.go b/test/modules/admin/api_test.go similarity index 100% rename from test/modules/admin/api_admin_test.go rename to test/modules/admin/api_test.go diff --git a/test/modules/connection/api_connection_test.go b/test/modules/connection/api_test.go similarity index 100% rename from test/modules/connection/api_connection_test.go rename to test/modules/connection/api_test.go diff --git a/test/modules/generic/api_generic_test.go b/test/modules/generic/api_test.go similarity index 100% rename from test/modules/generic/api_generic_test.go rename to test/modules/generic/api_test.go diff --git a/test/modules/hash/api_hash_test.go b/test/modules/hash/api_test.go similarity index 100% rename from test/modules/hash/api_hash_test.go rename to test/modules/hash/api_test.go diff --git a/test/modules/list/api_list_test.go b/test/modules/list/api_test.go similarity index 100% rename from test/modules/list/api_list_test.go rename to test/modules/list/api_test.go diff --git a/test/modules/pubsub/api_pubsub_test.go b/test/modules/pubsub/api_test.go similarity index 100% rename from test/modules/pubsub/api_pubsub_test.go rename to test/modules/pubsub/api_test.go diff --git a/test/modules/set/api_set_test.go b/test/modules/set/api_test.go similarity index 100% rename from test/modules/set/api_set_test.go rename to test/modules/set/api_test.go diff --git a/test/modules/sorted_set/api_sorted_set_test.go b/test/modules/sorted_set/api_test.go similarity index 100% rename from test/modules/sorted_set/api_sorted_set_test.go rename to test/modules/sorted_set/api_test.go diff --git a/test/modules/string/api_string_test.go b/test/modules/string/api_test.go similarity index 100% rename from test/modules/string/api_string_test.go rename to test/modules/string/api_test.go From 44e4f06670231f25ace955344cf68fe6c6f4d63e Mon Sep 17 00:00:00 2001 From: Kelvin Clement Mwinuka Date: Thu, 25 Apr 2024 21:02:12 +0800 Subject: [PATCH 5/6] Deleted ACL type from pkg types --- pkg/types/types.go | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/pkg/types/types.go b/pkg/types/types.go index 8e867dfa..3aeefc6f 100644 --- a/pkg/types/types.go +++ b/pkg/types/types.go @@ -81,7 +81,7 @@ type SubCommand struct { Module string Categories []string Description string - Sync bool // Specifies if sub-command should be synced across cluster + Sync bool // Specifies if sub-command should be synced across replication cluster KeyExtractionFunc HandlerFunc } @@ -92,14 +92,7 @@ type Command struct { Categories []string Description string SubCommands []SubCommand - Sync bool // Specifies if command should be synced across cluster + Sync bool // Specifies if command should be synced across replication cluster KeyExtractionFunc HandlerFunc } - -type ACL interface { - RegisterConnection(conn *net.Conn) - AuthorizeConnection(conn *net.Conn, cmd []string, command Command, subCommand SubCommand) error -} - -type PubSub interface{} From 6ad3b7baab62f3d042cb575ea18793bfb21625ca Mon Sep 17 00:00:00 2001 From: Kelvin Clement Mwinuka Date: Fri, 26 Apr 2024 02:33:35 +0800 Subject: [PATCH 6/6] Exported EchoVault interface now onlu contains the keyspace methods. All other methods are private. Private methods are accessed using the reflect package in the test folder --- internal/modules/acl/acl.go | 6 +- internal/modules/acl/commands.go | 72 +++++----- internal/modules/admin/commands.go | 54 ++++---- internal/modules/connection/commands.go | 12 +- internal/modules/generic/commands.go | 25 ++-- internal/modules/generic/key_funcs.go | 62 ++++----- internal/modules/hash/commands.go | 27 ++-- internal/modules/hash/key_funcs.go | 76 +++++----- internal/modules/list/commands.go | 25 ++-- internal/modules/list/key_funcs.go | 62 ++++----- internal/modules/pubsub/commands.go | 64 ++++----- internal/modules/set/commands.go | 37 +++-- internal/modules/set/key_funcs.go | 100 +++++++------- internal/modules/sorted_set/commands.go | 51 ++++--- internal/modules/sorted_set/key_funcs.go | 168 +++++++++++------------ internal/modules/string/commands.go | 11 +- internal/modules/string/key_funcs.go | 20 +-- internal/raft/fsm.go | 6 +- internal/raft/raft.go | 4 +- internal/types.go | 63 ++++++++- internal/utils.go | 5 +- pkg/echovault/echovault.go | 60 ++++---- pkg/echovault/keyspace.go | 4 +- pkg/echovault/modules.go | 62 ++++----- pkg/types/types.go | 65 +-------- test/modules/acl/commands_test.go | 25 ++-- test/modules/admin/commands_test.go | 22 ++- test/modules/connection/commands_test.go | 18 ++- test/modules/generic/commands_test.go | 22 ++- test/modules/hash/commands_test.go | 18 ++- test/modules/list/commands_test.go | 18 ++- test/modules/pubsub/commands_test.go | 26 +++- test/modules/set/commands_test.go | 18 ++- test/modules/sorted_set/commands_test.go | 18 ++- test/modules/string/commands_test.go | 17 ++- 35 files changed, 709 insertions(+), 634 deletions(-) diff --git a/internal/modules/acl/acl.go b/internal/modules/acl/acl.go index 94adf91f..f2e158ed 100644 --- a/internal/modules/acl/acl.go +++ b/internal/modules/acl/acl.go @@ -20,9 +20,9 @@ import ( "encoding/json" "errors" "fmt" + "github.com/echovault/echovault/internal" "github.com/echovault/echovault/internal/config" "github.com/echovault/echovault/pkg/constants" - "github.com/echovault/echovault/pkg/types" "github.com/gobwas/glob" "gopkg.in/yaml.v3" "log" @@ -286,7 +286,7 @@ func (acl *ACL) AuthenticateConnection(_ context.Context, conn *net.Conn, cmd [] return errors.New("could not authenticate user") } -func (acl *ACL) AuthorizeConnection(conn *net.Conn, cmd []string, command types.Command, subCommand types.SubCommand) error { +func (acl *ACL) AuthorizeConnection(conn *net.Conn, cmd []string, command internal.Command, subCommand internal.SubCommand) error { acl.RLockUsers() defer acl.RUnlockUsers() @@ -303,7 +303,7 @@ func (acl *ACL) AuthorizeConnection(conn *net.Conn, cmd []string, command types. readKeys := keys.ReadKeys writeKeys := keys.WriteKeys - if !reflect.DeepEqual(subCommand, types.SubCommand{}) { + if !reflect.DeepEqual(subCommand, internal.SubCommand{}) { comm = fmt.Sprintf("%s|%s", comm, subCommand.Command) categories = append(categories, subCommand.Categories...) keys, err = subCommand.KeyExtractionFunc(cmd) diff --git a/internal/modules/acl/commands.go b/internal/modules/acl/commands.go index 1f86baee..64cb5c3a 100644 --- a/internal/modules/acl/commands.go +++ b/internal/modules/acl/commands.go @@ -18,8 +18,8 @@ import ( "encoding/json" "errors" "fmt" + "github.com/echovault/echovault/internal" "github.com/echovault/echovault/pkg/constants" - "github.com/echovault/echovault/pkg/types" "gopkg.in/yaml.v3" "log" "os" @@ -28,7 +28,7 @@ import ( "strings" ) -func handleAuth(params types.HandlerFuncParams) ([]byte, error) { +func handleAuth(params internal.HandlerFuncParams) ([]byte, error) { if len(params.Command) < 2 || len(params.Command) > 3 { return nil, errors.New(constants.WrongArgsResponse) } @@ -42,7 +42,7 @@ func handleAuth(params types.HandlerFuncParams) ([]byte, error) { return []byte(constants.OkResponse), nil } -func handleGetUser(params types.HandlerFuncParams) ([]byte, error) { +func handleGetUser(params internal.HandlerFuncParams) ([]byte, error) { if len(params.Command) != 3 { return nil, errors.New(constants.WrongArgsResponse) } @@ -159,7 +159,7 @@ func handleGetUser(params types.HandlerFuncParams) ([]byte, error) { return []byte(res), nil } -func handleCat(params types.HandlerFuncParams) ([]byte, error) { +func handleCat(params internal.HandlerFuncParams) ([]byte, error) { if len(params.Command) > 3 { return nil, errors.New(constants.WrongArgsResponse) } @@ -219,7 +219,7 @@ func handleCat(params types.HandlerFuncParams) ([]byte, error) { return nil, fmt.Errorf("category %s not found", strings.ToUpper(params.Command[2])) } -func handleUsers(params types.HandlerFuncParams) ([]byte, error) { +func handleUsers(params internal.HandlerFuncParams) ([]byte, error) { acl, ok := params.GetACL().(*ACL) if !ok { return nil, errors.New("could not load ACL") @@ -232,7 +232,7 @@ func handleUsers(params types.HandlerFuncParams) ([]byte, error) { return []byte(res), nil } -func handleSetUser(params types.HandlerFuncParams) ([]byte, error) { +func handleSetUser(params internal.HandlerFuncParams) ([]byte, error) { acl, ok := params.GetACL().(*ACL) if !ok { return nil, errors.New("could not load ACL") @@ -243,7 +243,7 @@ func handleSetUser(params types.HandlerFuncParams) ([]byte, error) { return []byte(constants.OkResponse), nil } -func handleDelUser(params types.HandlerFuncParams) ([]byte, error) { +func handleDelUser(params internal.HandlerFuncParams) ([]byte, error) { if len(params.Command) < 3 { return nil, errors.New(constants.WrongArgsResponse) } @@ -257,7 +257,7 @@ func handleDelUser(params types.HandlerFuncParams) ([]byte, error) { return []byte(constants.OkResponse), nil } -func handleWhoAmI(params types.HandlerFuncParams) ([]byte, error) { +func handleWhoAmI(params internal.HandlerFuncParams) ([]byte, error) { acl, ok := params.GetACL().(*ACL) if !ok { return nil, errors.New("could not load ACL") @@ -266,7 +266,7 @@ func handleWhoAmI(params types.HandlerFuncParams) ([]byte, error) { return []byte(fmt.Sprintf("+%s\r\n", connectionInfo.User.Username)), nil } -func handleList(params types.HandlerFuncParams) ([]byte, error) { +func handleList(params internal.HandlerFuncParams) ([]byte, error) { if len(params.Command) > 2 { return nil, errors.New(constants.WrongArgsResponse) } @@ -362,7 +362,7 @@ func handleList(params types.HandlerFuncParams) ([]byte, error) { return []byte(res), nil } -func handleLoad(params types.HandlerFuncParams) ([]byte, error) { +func handleLoad(params internal.HandlerFuncParams) ([]byte, error) { if len(params.Command) != 3 { return nil, errors.New(constants.WrongArgsResponse) } @@ -429,7 +429,7 @@ func handleLoad(params types.HandlerFuncParams) ([]byte, error) { return []byte(constants.OkResponse), nil } -func handleSave(params types.HandlerFuncParams) ([]byte, error) { +func handleSave(params internal.HandlerFuncParams) ([]byte, error) { if len(params.Command) > 2 { return nil, errors.New(constants.WrongArgsResponse) } @@ -487,16 +487,16 @@ func handleSave(params types.HandlerFuncParams) ([]byte, error) { return []byte(constants.OkResponse), nil } -func Commands() []types.Command { - return []types.Command{ +func Commands() []internal.Command { + return []internal.Command{ { Command: "auth", Module: constants.ACLModule, Categories: []string{constants.ConnectionCategory, constants.SlowCategory}, Description: "(AUTH [username] password) Authenticates the connection", Sync: false, - KeyExtractionFunc: func(cmd []string) (types.AccessKeys, error) { - return types.AccessKeys{ + KeyExtractionFunc: func(cmd []string) (internal.AccessKeys, error) { + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: make([]string, 0), @@ -510,14 +510,14 @@ func Commands() []types.Command { Categories: []string{}, Description: "Access-Control-List commands", Sync: false, - KeyExtractionFunc: func(cmd []string) (types.AccessKeys, error) { - return types.AccessKeys{ + KeyExtractionFunc: func(cmd []string) (internal.AccessKeys, error) { + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: make([]string, 0), }, nil }, - SubCommands: []types.SubCommand{ + SubCommands: []internal.SubCommand{ { Command: "cat", Module: constants.ACLModule, @@ -525,8 +525,8 @@ func Commands() []types.Command { Description: `(ACL CAT [category]) List all the categories. If the optional category is provided, list all the commands in the category`, Sync: false, - KeyExtractionFunc: func(cmd []string) (types.AccessKeys, error) { - return types.AccessKeys{ + KeyExtractionFunc: func(cmd []string) (internal.AccessKeys, error) { + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: make([]string, 0), @@ -540,8 +540,8 @@ If the optional category is provided, list all the commands in the category`, Categories: []string{constants.AdminCategory, constants.SlowCategory, constants.DangerousCategory}, Description: "(ACL USERS) List all usernames of the configured ACL users", Sync: false, - KeyExtractionFunc: func(cmd []string) (types.AccessKeys, error) { - return types.AccessKeys{ + KeyExtractionFunc: func(cmd []string) (internal.AccessKeys, error) { + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: make([]string, 0), @@ -555,8 +555,8 @@ If the optional category is provided, list all the commands in the category`, Categories: []string{constants.AdminCategory, constants.SlowCategory, constants.DangerousCategory}, Description: "(ACL SETUSER) Configure a new or existing user", Sync: true, - KeyExtractionFunc: func(cmd []string) (types.AccessKeys, error) { - return types.AccessKeys{ + KeyExtractionFunc: func(cmd []string) (internal.AccessKeys, error) { + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: make([]string, 0), @@ -570,8 +570,8 @@ If the optional category is provided, list all the commands in the category`, Categories: []string{constants.AdminCategory, constants.SlowCategory, constants.DangerousCategory}, Description: "(ACL GETUSER username) List the ACL rules of a user", Sync: false, - KeyExtractionFunc: func(cmd []string) (types.AccessKeys, error) { - return types.AccessKeys{ + KeyExtractionFunc: func(cmd []string) (internal.AccessKeys, error) { + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: make([]string, 0), @@ -585,8 +585,8 @@ If the optional category is provided, list all the commands in the category`, Categories: []string{constants.AdminCategory, constants.SlowCategory, constants.DangerousCategory}, Description: "(ACL DELUSER username [username ...]) Deletes users and terminates their connections. Cannot delete default user", Sync: true, - KeyExtractionFunc: func(cmd []string) (types.AccessKeys, error) { - return types.AccessKeys{ + KeyExtractionFunc: func(cmd []string) (internal.AccessKeys, error) { + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: make([]string, 0), @@ -600,8 +600,8 @@ If the optional category is provided, list all the commands in the category`, Categories: []string{constants.FastCategory}, Description: "(ACL WHOAMI) Returns the authenticated user of the current connection", Sync: true, - KeyExtractionFunc: func(cmd []string) (types.AccessKeys, error) { - return types.AccessKeys{ + KeyExtractionFunc: func(cmd []string) (internal.AccessKeys, error) { + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: make([]string, 0), @@ -615,8 +615,8 @@ If the optional category is provided, list all the commands in the category`, Categories: []string{constants.AdminCategory, constants.SlowCategory, constants.DangerousCategory}, Description: "(ACL LIST) Dumps effective acl rules in acl config file format", Sync: true, - KeyExtractionFunc: func(cmd []string) (types.AccessKeys, error) { - return types.AccessKeys{ + KeyExtractionFunc: func(cmd []string) (internal.AccessKeys, error) { + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: make([]string, 0), @@ -633,8 +633,8 @@ If the optional category is provided, list all the commands in the category`, When 'MERGE' is passed, users from config file who share a username with users in memory will be merged. When 'REPLACE' is passed, users from config file who share a username with users in memory will replace the user in memory.`, Sync: true, - KeyExtractionFunc: func(cmd []string) (types.AccessKeys, error) { - return types.AccessKeys{ + KeyExtractionFunc: func(cmd []string) (internal.AccessKeys, error) { + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: make([]string, 0), @@ -648,8 +648,8 @@ When 'REPLACE' is passed, users from config file who share a username with users Categories: []string{constants.AdminCategory, constants.SlowCategory, constants.DangerousCategory}, Description: "(ACL SAVE) Saves the effective ACL rules the configured ACL config file", Sync: true, - KeyExtractionFunc: func(cmd []string) (types.AccessKeys, error) { - return types.AccessKeys{ + KeyExtractionFunc: func(cmd []string) (internal.AccessKeys, error) { + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: make([]string, 0), diff --git a/internal/modules/admin/commands.go b/internal/modules/admin/commands.go index 0ea5f150..26b87dc3 100644 --- a/internal/modules/admin/commands.go +++ b/internal/modules/admin/commands.go @@ -17,14 +17,14 @@ package admin import ( "errors" "fmt" + "github.com/echovault/echovault/internal" "github.com/echovault/echovault/pkg/constants" - "github.com/echovault/echovault/pkg/types" "github.com/gobwas/glob" "slices" "strings" ) -func handleGetAllCommands(params types.HandlerFuncParams) ([]byte, error) { +func handleGetAllCommands(params internal.HandlerFuncParams) ([]byte, error) { commands := params.GetAllCommands() res := "" @@ -69,7 +69,7 @@ func handleGetAllCommands(params types.HandlerFuncParams) ([]byte, error) { return []byte(res), nil } -func handleCommandCount(params types.HandlerFuncParams) ([]byte, error) { +func handleCommandCount(params internal.HandlerFuncParams) ([]byte, error) { var count int commands := params.GetAllCommands() @@ -86,7 +86,7 @@ func handleCommandCount(params types.HandlerFuncParams) ([]byte, error) { return []byte(fmt.Sprintf(":%d\r\n", count)), nil } -func handleCommandList(params types.HandlerFuncParams) ([]byte, error) { +func handleCommandList(params internal.HandlerFuncParams) ([]byte, error) { switch len(params.Command) { case 2: // Command is COMMAND LIST @@ -185,20 +185,20 @@ func handleCommandList(params types.HandlerFuncParams) ([]byte, error) { } } -func handleCommandDocs(params types.HandlerFuncParams) ([]byte, error) { +func handleCommandDocs(params internal.HandlerFuncParams) ([]byte, error) { return []byte("*0\r\n"), nil } -func Commands() []types.Command { - return []types.Command{ +func Commands() []internal.Command { + return []internal.Command{ { Command: "commands", Module: constants.AdminModule, Categories: []string{constants.AdminCategory, constants.SlowCategory}, Description: "Get a list of all the commands in available on the echovault with categories and descriptions", Sync: false, - KeyExtractionFunc: func(cmd []string) (types.AccessKeys, error) { - return types.AccessKeys{ + KeyExtractionFunc: func(cmd []string) (internal.AccessKeys, error) { + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: make([]string, 0), @@ -212,22 +212,22 @@ func Commands() []types.Command { Categories: []string{}, Description: "Commands pertaining to echovault commands", Sync: false, - KeyExtractionFunc: func(cmd []string) (types.AccessKeys, error) { - return types.AccessKeys{ + KeyExtractionFunc: func(cmd []string) (internal.AccessKeys, error) { + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: make([]string, 0), }, nil }, - SubCommands: []types.SubCommand{ + SubCommands: []internal.SubCommand{ { Command: "docs", Module: constants.AdminModule, Categories: []string{constants.SlowCategory, constants.ConnectionCategory}, Description: "Get command documentation", Sync: false, - KeyExtractionFunc: func(cmd []string) (types.AccessKeys, error) { - return types.AccessKeys{ + KeyExtractionFunc: func(cmd []string) (internal.AccessKeys, error) { + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: make([]string, 0), @@ -241,8 +241,8 @@ func Commands() []types.Command { Categories: []string{constants.SlowCategory}, Description: "Get the dumber of commands in the echovault", Sync: false, - KeyExtractionFunc: func(cmd []string) (types.AccessKeys, error) { - return types.AccessKeys{ + KeyExtractionFunc: func(cmd []string) (internal.AccessKeys, error) { + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: make([]string, 0), @@ -257,8 +257,8 @@ func Commands() []types.Command { Description: `(COMMAND LIST [FILTERBY ]) Get the list of command names. Allows for filtering by ACL category or glob pattern.`, Sync: false, - KeyExtractionFunc: func(cmd []string) (types.AccessKeys, error) { - return types.AccessKeys{ + KeyExtractionFunc: func(cmd []string) (internal.AccessKeys, error) { + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: make([]string, 0), @@ -274,14 +274,14 @@ Allows for filtering by ACL category or glob pattern.`, Categories: []string{constants.AdminCategory, constants.SlowCategory, constants.DangerousCategory}, Description: "(SAVE) Trigger a snapshot save", Sync: true, - KeyExtractionFunc: func(cmd []string) (types.AccessKeys, error) { - return types.AccessKeys{ + KeyExtractionFunc: func(cmd []string) (internal.AccessKeys, error) { + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: make([]string, 0), }, nil }, - HandlerFunc: func(params types.HandlerFuncParams) ([]byte, error) { + HandlerFunc: func(params internal.HandlerFuncParams) ([]byte, error) { if err := params.TakeSnapshot(); err != nil { return nil, err } @@ -294,14 +294,14 @@ Allows for filtering by ACL category or glob pattern.`, Categories: []string{constants.AdminCategory, constants.FastCategory, constants.DangerousCategory}, Description: "(LASTSAVE) Get unix timestamp for the latest snapshot in milliseconds.", Sync: false, - KeyExtractionFunc: func(cmd []string) (types.AccessKeys, error) { - return types.AccessKeys{ + KeyExtractionFunc: func(cmd []string) (internal.AccessKeys, error) { + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: make([]string, 0), }, nil }, - HandlerFunc: func(params types.HandlerFuncParams) ([]byte, error) { + HandlerFunc: func(params internal.HandlerFuncParams) ([]byte, error) { msec := params.GetLatestSnapshotTime() if msec == 0 { return nil, errors.New("no snapshot") @@ -315,14 +315,14 @@ Allows for filtering by ACL category or glob pattern.`, Categories: []string{constants.AdminCategory, constants.SlowCategory, constants.DangerousCategory}, Description: "(REWRITEAOF) Trigger re-writing of append process", Sync: false, - KeyExtractionFunc: func(cmd []string) (types.AccessKeys, error) { - return types.AccessKeys{ + KeyExtractionFunc: func(cmd []string) (internal.AccessKeys, error) { + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: make([]string, 0), }, nil }, - HandlerFunc: func(params types.HandlerFuncParams) ([]byte, error) { + HandlerFunc: func(params internal.HandlerFuncParams) ([]byte, error) { if err := params.RewriteAOF(); err != nil { return nil, err } diff --git a/internal/modules/connection/commands.go b/internal/modules/connection/commands.go index 1cfb8870..d3ddf334 100644 --- a/internal/modules/connection/commands.go +++ b/internal/modules/connection/commands.go @@ -17,11 +17,11 @@ package connection import ( "errors" "fmt" + "github.com/echovault/echovault/internal" "github.com/echovault/echovault/pkg/constants" - "github.com/echovault/echovault/pkg/types" ) -func handlePing(params types.HandlerFuncParams) ([]byte, error) { +func handlePing(params internal.HandlerFuncParams) ([]byte, error) { switch len(params.Command) { default: return nil, errors.New(constants.WrongArgsResponse) @@ -32,16 +32,16 @@ func handlePing(params types.HandlerFuncParams) ([]byte, error) { } } -func Commands() []types.Command { - return []types.Command{ +func Commands() []internal.Command { + return []internal.Command{ { Command: "ping", Module: constants.ConnectionModule, Categories: []string{constants.FastCategory, constants.ConnectionCategory}, Description: "(PING [value]) Ping the echovault. If a value is provided, the value will be echoed.", Sync: false, - KeyExtractionFunc: func(cmd []string) (types.AccessKeys, error) { - return types.AccessKeys{ + KeyExtractionFunc: func(cmd []string) (internal.AccessKeys, error) { + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: make([]string, 0), diff --git a/internal/modules/generic/commands.go b/internal/modules/generic/commands.go index 6db861e1..49c0bbb4 100644 --- a/internal/modules/generic/commands.go +++ b/internal/modules/generic/commands.go @@ -19,7 +19,6 @@ import ( "fmt" "github.com/echovault/echovault/internal" "github.com/echovault/echovault/pkg/constants" - "github.com/echovault/echovault/pkg/types" "log" "strconv" "strings" @@ -31,7 +30,7 @@ type KeyObject struct { locked bool } -func handleSet(params types.HandlerFuncParams) ([]byte, error) { +func handleSet(params internal.HandlerFuncParams) ([]byte, error) { keys, err := setKeyFunc(params.Command) if err != nil { return nil, err @@ -96,7 +95,7 @@ func handleSet(params types.HandlerFuncParams) ([]byte, error) { return res, nil } -func handleMSet(params types.HandlerFuncParams) ([]byte, error) { +func handleMSet(params internal.HandlerFuncParams) ([]byte, error) { _, err := msetKeyFunc(params.Command) if err != nil { return nil, err @@ -153,7 +152,7 @@ func handleMSet(params types.HandlerFuncParams) ([]byte, error) { return []byte(constants.OkResponse), nil } -func handleGet(params types.HandlerFuncParams) ([]byte, error) { +func handleGet(params internal.HandlerFuncParams) ([]byte, error) { keys, err := getKeyFunc(params.Command) if err != nil { return nil, err @@ -175,7 +174,7 @@ func handleGet(params types.HandlerFuncParams) ([]byte, error) { return []byte(fmt.Sprintf("+%v\r\n", value)), nil } -func handleMGet(params types.HandlerFuncParams) ([]byte, error) { +func handleMGet(params internal.HandlerFuncParams) ([]byte, error) { keys, err := mgetKeyFunc(params.Command) if err != nil { return nil, err @@ -225,7 +224,7 @@ func handleMGet(params types.HandlerFuncParams) ([]byte, error) { return bytes, nil } -func handleDel(params types.HandlerFuncParams) ([]byte, error) { +func handleDel(params internal.HandlerFuncParams) ([]byte, error) { keys, err := delKeyFunc(params.Command) if err != nil { return nil, err @@ -242,7 +241,7 @@ func handleDel(params types.HandlerFuncParams) ([]byte, error) { return []byte(fmt.Sprintf(":%d\r\n", count)), nil } -func handlePersist(params types.HandlerFuncParams) ([]byte, error) { +func handlePersist(params internal.HandlerFuncParams) ([]byte, error) { keys, err := persistKeyFunc(params.Command) if err != nil { return nil, err @@ -269,7 +268,7 @@ func handlePersist(params types.HandlerFuncParams) ([]byte, error) { return []byte(":1\r\n"), nil } -func handleExpireTime(params types.HandlerFuncParams) ([]byte, error) { +func handleExpireTime(params internal.HandlerFuncParams) ([]byte, error) { keys, err := expireTimeKeyFunc(params.Command) if err != nil { return nil, err @@ -300,7 +299,7 @@ func handleExpireTime(params types.HandlerFuncParams) ([]byte, error) { return []byte(fmt.Sprintf(":%d\r\n", t)), nil } -func handleTTL(params types.HandlerFuncParams) ([]byte, error) { +func handleTTL(params internal.HandlerFuncParams) ([]byte, error) { keys, err := ttlKeyFunc(params.Command) if err != nil { return nil, err @@ -337,7 +336,7 @@ func handleTTL(params types.HandlerFuncParams) ([]byte, error) { return []byte(fmt.Sprintf(":%d\r\n", t)), nil } -func handleExpire(params types.HandlerFuncParams) ([]byte, error) { +func handleExpire(params internal.HandlerFuncParams) ([]byte, error) { keys, err := expireKeyFunc(params.Command) if err != nil { return nil, err @@ -405,7 +404,7 @@ func handleExpire(params types.HandlerFuncParams) ([]byte, error) { return []byte(":1\r\n"), nil } -func handleExpireAt(params types.HandlerFuncParams) ([]byte, error) { +func handleExpireAt(params internal.HandlerFuncParams) ([]byte, error) { keys, err := expireKeyFunc(params.Command) if err != nil { return nil, err @@ -473,8 +472,8 @@ func handleExpireAt(params types.HandlerFuncParams) ([]byte, error) { return []byte(":1\r\n"), nil } -func Commands() []types.Command { - return []types.Command{ +func Commands() []internal.Command { + return []internal.Command{ { Command: "set", Module: constants.GenericModule, diff --git a/internal/modules/generic/key_funcs.go b/internal/modules/generic/key_funcs.go index 5584af57..e9a42d95 100644 --- a/internal/modules/generic/key_funcs.go +++ b/internal/modules/generic/key_funcs.go @@ -16,24 +16,24 @@ package generic import ( "errors" + "github.com/echovault/echovault/internal" "github.com/echovault/echovault/pkg/constants" - "github.com/echovault/echovault/pkg/types" ) -func setKeyFunc(cmd []string) (types.AccessKeys, error) { +func setKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) < 3 || len(cmd) > 7 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: cmd[1:2], }, nil } -func msetKeyFunc(cmd []string) (types.AccessKeys, error) { +func msetKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd[1:])%2 != 0 { - return types.AccessKeys{}, errors.New("each key must be paired with a value") + return internal.AccessKeys{}, errors.New("each key must be paired with a value") } var keys []string for i, key := range cmd[1:] { @@ -41,95 +41,95 @@ func msetKeyFunc(cmd []string) (types.AccessKeys, error) { keys = append(keys, key) } } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: keys, }, nil } -func getKeyFunc(cmd []string) (types.AccessKeys, error) { +func getKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) != 2 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[1:], WriteKeys: make([]string, 0), }, nil } -func mgetKeyFunc(cmd []string) (types.AccessKeys, error) { +func mgetKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) < 2 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[1:], WriteKeys: make([]string, 0), }, nil } -func delKeyFunc(cmd []string) (types.AccessKeys, error) { +func delKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) < 2 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: cmd[1:], }, nil } -func persistKeyFunc(cmd []string) (types.AccessKeys, error) { +func persistKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) != 2 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: cmd[1:], }, nil } -func expireTimeKeyFunc(cmd []string) (types.AccessKeys, error) { +func expireTimeKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) != 2 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[1:], WriteKeys: make([]string, 0), }, nil } -func ttlKeyFunc(cmd []string) (types.AccessKeys, error) { +func ttlKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) != 2 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[1:], WriteKeys: make([]string, 0), }, nil } -func expireKeyFunc(cmd []string) (types.AccessKeys, error) { +func expireKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) < 3 || len(cmd) > 4 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: cmd[1:2], }, nil } -func expireAtKeyFunc(cmd []string) (types.AccessKeys, error) { +func expireAtKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) < 3 || len(cmd) > 4 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: cmd[1:2], diff --git a/internal/modules/hash/commands.go b/internal/modules/hash/commands.go index c8b74b3f..5a679d2e 100644 --- a/internal/modules/hash/commands.go +++ b/internal/modules/hash/commands.go @@ -19,14 +19,13 @@ import ( "fmt" "github.com/echovault/echovault/internal" "github.com/echovault/echovault/pkg/constants" - "github.com/echovault/echovault/pkg/types" "math/rand" "slices" "strconv" "strings" ) -func handleHSET(params types.HandlerFuncParams) ([]byte, error) { +func handleHSET(params internal.HandlerFuncParams) ([]byte, error) { keys, err := hsetKeyFunc(params.Command) if err != nil { return nil, err @@ -84,7 +83,7 @@ func handleHSET(params types.HandlerFuncParams) ([]byte, error) { return []byte(fmt.Sprintf(":%d\r\n", count)), nil } -func handleHGET(params types.HandlerFuncParams) ([]byte, error) { +func handleHGET(params internal.HandlerFuncParams) ([]byte, error) { keys, err := hgetKeyFunc(params.Command) if err != nil { return nil, err @@ -135,7 +134,7 @@ func handleHGET(params types.HandlerFuncParams) ([]byte, error) { return []byte(res), nil } -func handleHSTRLEN(params types.HandlerFuncParams) ([]byte, error) { +func handleHSTRLEN(params internal.HandlerFuncParams) ([]byte, error) { keys, err := hstrlenKeyFunc(params.Command) if err != nil { return nil, err @@ -186,7 +185,7 @@ func handleHSTRLEN(params types.HandlerFuncParams) ([]byte, error) { return []byte(res), nil } -func handleHVALS(params types.HandlerFuncParams) ([]byte, error) { +func handleHVALS(params internal.HandlerFuncParams) ([]byte, error) { keys, err := hvalsKeyFunc(params.Command) if err != nil { return nil, err @@ -227,7 +226,7 @@ func handleHVALS(params types.HandlerFuncParams) ([]byte, error) { return []byte(res), nil } -func handleHRANDFIELD(params types.HandlerFuncParams) ([]byte, error) { +func handleHRANDFIELD(params internal.HandlerFuncParams) ([]byte, error) { keys, err := hrandfieldKeyFunc(params.Command) if err != nil { return nil, err @@ -343,7 +342,7 @@ func handleHRANDFIELD(params types.HandlerFuncParams) ([]byte, error) { return []byte(res), nil } -func handleHLEN(params types.HandlerFuncParams) ([]byte, error) { +func handleHLEN(params internal.HandlerFuncParams) ([]byte, error) { keys, err := hlenKeyFunc(params.Command) if err != nil { return nil, err @@ -368,7 +367,7 @@ func handleHLEN(params types.HandlerFuncParams) ([]byte, error) { return []byte(fmt.Sprintf(":%d\r\n", len(hash))), nil } -func handleHKEYS(params types.HandlerFuncParams) ([]byte, error) { +func handleHKEYS(params internal.HandlerFuncParams) ([]byte, error) { keys, err := hkeysKeyFunc(params.Command) if err != nil { return nil, err @@ -398,7 +397,7 @@ func handleHKEYS(params types.HandlerFuncParams) ([]byte, error) { return []byte(res), nil } -func handleHINCRBY(params types.HandlerFuncParams) ([]byte, error) { +func handleHINCRBY(params internal.HandlerFuncParams) ([]byte, error) { keys, err := hincrbyKeyFunc(params.Command) if err != nil { return nil, err @@ -490,7 +489,7 @@ func handleHINCRBY(params types.HandlerFuncParams) ([]byte, error) { return []byte(fmt.Sprintf(":%d\r\n", i)), nil } -func handleHGETALL(params types.HandlerFuncParams) ([]byte, error) { +func handleHGETALL(params internal.HandlerFuncParams) ([]byte, error) { keys, err := hgetallKeyFunc(params.Command) if err != nil { return nil, err @@ -530,7 +529,7 @@ func handleHGETALL(params types.HandlerFuncParams) ([]byte, error) { return []byte(res), nil } -func handleHEXISTS(params types.HandlerFuncParams) ([]byte, error) { +func handleHEXISTS(params internal.HandlerFuncParams) ([]byte, error) { keys, err := hexistsKeyFunc(params.Command) if err != nil { return nil, err @@ -560,7 +559,7 @@ func handleHEXISTS(params types.HandlerFuncParams) ([]byte, error) { return []byte(":0\r\n"), nil } -func handleHDEL(params types.HandlerFuncParams) ([]byte, error) { +func handleHDEL(params internal.HandlerFuncParams) ([]byte, error) { keys, err := hdelKeyFunc(params.Command) if err != nil { return nil, err @@ -599,8 +598,8 @@ func handleHDEL(params types.HandlerFuncParams) ([]byte, error) { return []byte(fmt.Sprintf(":%d\r\n", count)), nil } -func Commands() []types.Command { - return []types.Command{ +func Commands() []internal.Command { + return []internal.Command{ { Command: "hset", Module: constants.HashModule, diff --git a/internal/modules/hash/key_funcs.go b/internal/modules/hash/key_funcs.go index 3e2f72db..847ea9cd 100644 --- a/internal/modules/hash/key_funcs.go +++ b/internal/modules/hash/key_funcs.go @@ -16,143 +16,143 @@ package hash import ( "errors" + "github.com/echovault/echovault/internal" "github.com/echovault/echovault/pkg/constants" - "github.com/echovault/echovault/pkg/types" ) -func hsetKeyFunc(cmd []string) (types.AccessKeys, error) { +func hsetKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) < 4 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: cmd[1:2], }, nil } -func hsetnxKeyFunc(cmd []string) (types.AccessKeys, error) { +func hsetnxKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) < 4 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: cmd[1:2], }, nil } -func hgetKeyFunc(cmd []string) (types.AccessKeys, error) { +func hgetKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) < 3 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[1:2], WriteKeys: make([]string, 0), }, nil } -func hstrlenKeyFunc(cmd []string) (types.AccessKeys, error) { +func hstrlenKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) < 3 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[1:2], WriteKeys: make([]string, 0), }, nil } -func hvalsKeyFunc(cmd []string) (types.AccessKeys, error) { +func hvalsKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) != 2 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[1:], WriteKeys: make([]string, 0), }, nil } -func hrandfieldKeyFunc(cmd []string) (types.AccessKeys, error) { +func hrandfieldKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) < 2 || len(cmd) > 4 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } if len(cmd) == 2 { - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[1:], WriteKeys: make([]string, 0), }, nil } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[1:2], WriteKeys: make([]string, 0), }, nil } -func hlenKeyFunc(cmd []string) (types.AccessKeys, error) { +func hlenKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) != 2 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[1:], WriteKeys: make([]string, 0), }, nil } -func hkeysKeyFunc(cmd []string) (types.AccessKeys, error) { +func hkeysKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) != 2 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[1:], WriteKeys: make([]string, 0), }, nil } -func hincrbyKeyFunc(cmd []string) (types.AccessKeys, error) { +func hincrbyKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) != 4 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: cmd[1:2], }, nil } -func hgetallKeyFunc(cmd []string) (types.AccessKeys, error) { +func hgetallKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) != 2 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[1:], WriteKeys: make([]string, 0), }, nil } -func hexistsKeyFunc(cmd []string) (types.AccessKeys, error) { +func hexistsKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) != 3 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[1:2], WriteKeys: make([]string, 0), }, nil } -func hdelKeyFunc(cmd []string) (types.AccessKeys, error) { +func hdelKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) < 3 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: cmd[1:2], diff --git a/internal/modules/list/commands.go b/internal/modules/list/commands.go index 0d3bf1e8..448f3415 100644 --- a/internal/modules/list/commands.go +++ b/internal/modules/list/commands.go @@ -19,13 +19,12 @@ import ( "fmt" "github.com/echovault/echovault/internal" "github.com/echovault/echovault/pkg/constants" - "github.com/echovault/echovault/pkg/types" "math" "slices" "strings" ) -func handleLLen(params types.HandlerFuncParams) ([]byte, error) { +func handleLLen(params internal.HandlerFuncParams) ([]byte, error) { keys, err := llenKeyFunc(params.Command) if err != nil { return nil, err @@ -50,7 +49,7 @@ func handleLLen(params types.HandlerFuncParams) ([]byte, error) { return nil, errors.New("LLEN command on non-list item") } -func handleLIndex(params types.HandlerFuncParams) ([]byte, error) { +func handleLIndex(params internal.HandlerFuncParams) ([]byte, error) { keys, err := lindexKeyFunc(params.Command) if err != nil { return nil, err @@ -84,7 +83,7 @@ func handleLIndex(params types.HandlerFuncParams) ([]byte, error) { return []byte(fmt.Sprintf("+%s\r\n", list[index])), nil } -func handleLRange(params types.HandlerFuncParams) ([]byte, error) { +func handleLRange(params internal.HandlerFuncParams) ([]byte, error) { keys, err := lrangeKeyFunc(params.Command) if err != nil { return nil, err @@ -163,7 +162,7 @@ func handleLRange(params types.HandlerFuncParams) ([]byte, error) { return bytes, nil } -func handleLSet(params types.HandlerFuncParams) ([]byte, error) { +func handleLSet(params internal.HandlerFuncParams) ([]byte, error) { keys, err := lsetKeyFunc(params.Command) if err != nil { return nil, err @@ -202,7 +201,7 @@ func handleLSet(params types.HandlerFuncParams) ([]byte, error) { return []byte(constants.OkResponse), nil } -func handleLTrim(params types.HandlerFuncParams) ([]byte, error) { +func handleLTrim(params internal.HandlerFuncParams) ([]byte, error) { keys, err := ltrimKeyFunc(params.Command) if err != nil { return nil, err @@ -251,7 +250,7 @@ func handleLTrim(params types.HandlerFuncParams) ([]byte, error) { return []byte(constants.OkResponse), nil } -func handleLRem(params types.HandlerFuncParams) ([]byte, error) { +func handleLRem(params internal.HandlerFuncParams) ([]byte, error) { keys, err := lremKeyFunc(params.Command) if err != nil { return nil, err @@ -319,7 +318,7 @@ func handleLRem(params types.HandlerFuncParams) ([]byte, error) { return []byte(constants.OkResponse), nil } -func handleLMove(params types.HandlerFuncParams) ([]byte, error) { +func handleLMove(params internal.HandlerFuncParams) ([]byte, error) { keys, err := lmoveKeyFunc(params.Command) if err != nil { return nil, err @@ -379,7 +378,7 @@ func handleLMove(params types.HandlerFuncParams) ([]byte, error) { return []byte(constants.OkResponse), nil } -func handleLPush(params types.HandlerFuncParams) ([]byte, error) { +func handleLPush(params internal.HandlerFuncParams) ([]byte, error) { keys, err := lpushKeyFunc(params.Command) if err != nil { return nil, err @@ -425,7 +424,7 @@ func handleLPush(params types.HandlerFuncParams) ([]byte, error) { return []byte(constants.OkResponse), nil } -func handleRPush(params types.HandlerFuncParams) ([]byte, error) { +func handleRPush(params internal.HandlerFuncParams) ([]byte, error) { keys, err := rpushKeyFunc(params.Command) if err != nil { return nil, err @@ -473,7 +472,7 @@ func handleRPush(params types.HandlerFuncParams) ([]byte, error) { return []byte(constants.OkResponse), nil } -func handlePop(params types.HandlerFuncParams) ([]byte, error) { +func handlePop(params internal.HandlerFuncParams) ([]byte, error) { keys, err := popKeyFunc(params.Command) if err != nil { return nil, err @@ -509,8 +508,8 @@ func handlePop(params types.HandlerFuncParams) ([]byte, error) { } } -func Commands() []types.Command { - return []types.Command{ +func Commands() []internal.Command { + return []internal.Command{ { Command: "lpush", Module: constants.ListModule, diff --git a/internal/modules/list/key_funcs.go b/internal/modules/list/key_funcs.go index 3bd55262..2025d039 100644 --- a/internal/modules/list/key_funcs.go +++ b/internal/modules/list/key_funcs.go @@ -16,114 +16,114 @@ package list import ( "errors" + "github.com/echovault/echovault/internal" "github.com/echovault/echovault/pkg/constants" - "github.com/echovault/echovault/pkg/types" ) -func lpushKeyFunc(cmd []string) (types.AccessKeys, error) { +func lpushKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) < 3 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: cmd[1:2], }, nil } -func popKeyFunc(cmd []string) (types.AccessKeys, error) { +func popKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) != 2 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: cmd[1:], }, nil } -func llenKeyFunc(cmd []string) (types.AccessKeys, error) { +func llenKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) != 2 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[1:], WriteKeys: make([]string, 0), }, nil } -func lrangeKeyFunc(cmd []string) (types.AccessKeys, error) { +func lrangeKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) != 4 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[1:2], WriteKeys: make([]string, 0), }, nil } -func lindexKeyFunc(cmd []string) (types.AccessKeys, error) { +func lindexKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) != 3 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[1:2], WriteKeys: make([]string, 0), }, nil } -func lsetKeyFunc(cmd []string) (types.AccessKeys, error) { +func lsetKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) != 4 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: cmd[1:2], }, nil } -func ltrimKeyFunc(cmd []string) (types.AccessKeys, error) { +func ltrimKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) != 4 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: cmd[1:2], }, nil } -func lremKeyFunc(cmd []string) (types.AccessKeys, error) { +func lremKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) != 4 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: cmd[1:2], }, nil } -func rpushKeyFunc(cmd []string) (types.AccessKeys, error) { +func rpushKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) < 3 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: cmd[1:2], }, nil } -func lmoveKeyFunc(cmd []string) (types.AccessKeys, error) { +func lmoveKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) != 5 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: cmd[1:3], diff --git a/internal/modules/pubsub/commands.go b/internal/modules/pubsub/commands.go index 0d876b34..81a60a3b 100644 --- a/internal/modules/pubsub/commands.go +++ b/internal/modules/pubsub/commands.go @@ -17,12 +17,12 @@ package pubsub import ( "errors" "fmt" + "github.com/echovault/echovault/internal" "github.com/echovault/echovault/pkg/constants" - "github.com/echovault/echovault/pkg/types" "strings" ) -func handleSubscribe(params types.HandlerFuncParams) ([]byte, error) { +func handleSubscribe(params internal.HandlerFuncParams) ([]byte, error) { pubsub, ok := params.GetPubSub().(*PubSub) if !ok { return nil, errors.New("could not load pubsub module") @@ -40,7 +40,7 @@ func handleSubscribe(params types.HandlerFuncParams) ([]byte, error) { return nil, nil } -func handleUnsubscribe(params types.HandlerFuncParams) ([]byte, error) { +func handleUnsubscribe(params internal.HandlerFuncParams) ([]byte, error) { pubsub, ok := params.GetPubSub().(*PubSub) if !ok { return nil, errors.New("could not load pubsub module") @@ -53,7 +53,7 @@ func handleUnsubscribe(params types.HandlerFuncParams) ([]byte, error) { return pubsub.Unsubscribe(params.Context, params.Connection, channels, withPattern), nil } -func handlePublish(params types.HandlerFuncParams) ([]byte, error) { +func handlePublish(params internal.HandlerFuncParams) ([]byte, error) { pubsub, ok := params.GetPubSub().(*PubSub) if !ok { return nil, errors.New("could not load pubsub module") @@ -65,7 +65,7 @@ func handlePublish(params types.HandlerFuncParams) ([]byte, error) { return []byte(constants.OkResponse), nil } -func handlePubSubChannels(params types.HandlerFuncParams) ([]byte, error) { +func handlePubSubChannels(params internal.HandlerFuncParams) ([]byte, error) { if len(params.Command) > 3 { return nil, errors.New(constants.WrongArgsResponse) } @@ -83,7 +83,7 @@ func handlePubSubChannels(params types.HandlerFuncParams) ([]byte, error) { return pubsub.Channels(pattern), nil } -func handlePubSubNumPat(params types.HandlerFuncParams) ([]byte, error) { +func handlePubSubNumPat(params internal.HandlerFuncParams) ([]byte, error) { pubsub, ok := params.GetPubSub().(*PubSub) if !ok { return nil, errors.New("could not load pubsub module") @@ -92,7 +92,7 @@ func handlePubSubNumPat(params types.HandlerFuncParams) ([]byte, error) { return []byte(fmt.Sprintf(":%d\r\n", num)), nil } -func handlePubSubNumSubs(params types.HandlerFuncParams) ([]byte, error) { +func handlePubSubNumSubs(params internal.HandlerFuncParams) ([]byte, error) { pubsub, ok := params.GetPubSub().(*PubSub) if !ok { return nil, errors.New("could not load pubsub module") @@ -100,20 +100,20 @@ func handlePubSubNumSubs(params types.HandlerFuncParams) ([]byte, error) { return pubsub.NumSub(params.Command[2:]), nil } -func Commands() []types.Command { - return []types.Command{ +func Commands() []internal.Command { + return []internal.Command{ { Command: "subscribe", Module: constants.PubSubModule, Categories: []string{constants.PubSubCategory, constants.ConnectionCategory, constants.SlowCategory}, Description: "(SUBSCRIBE channel [channel ...]) Subscribe to one or more channels.", Sync: false, - KeyExtractionFunc: func(cmd []string) (types.AccessKeys, error) { + KeyExtractionFunc: func(cmd []string) (internal.AccessKeys, error) { // Treat the channels as keys if len(cmd) < 2 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: cmd[1:], ReadKeys: make([]string, 0), WriteKeys: make([]string, 0), @@ -127,12 +127,12 @@ func Commands() []types.Command { Categories: []string{constants.PubSubCategory, constants.ConnectionCategory, constants.SlowCategory}, Description: "(PSUBSCRIBE pattern [pattern ...]) Subscribe to one or more glob patterns.", Sync: false, - KeyExtractionFunc: func(cmd []string) (types.AccessKeys, error) { + KeyExtractionFunc: func(cmd []string) (internal.AccessKeys, error) { // Treat the patterns as keys if len(cmd) < 2 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: cmd[1:], ReadKeys: make([]string, 0), WriteKeys: make([]string, 0), @@ -146,12 +146,12 @@ func Commands() []types.Command { Categories: []string{constants.PubSubCategory, constants.FastCategory}, Description: "(PUBLISH channel message) Publish a message to the specified channel.", Sync: true, - KeyExtractionFunc: func(cmd []string) (types.AccessKeys, error) { + KeyExtractionFunc: func(cmd []string) (internal.AccessKeys, error) { // Treat the channel as a key if len(cmd) != 3 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: cmd[1:2], ReadKeys: make([]string, 0), WriteKeys: make([]string, 0), @@ -167,9 +167,9 @@ func Commands() []types.Command { If the channel list is not provided, then the connection will be unsubscribed from all the channels that it's currently subscribe to.`, Sync: false, - KeyExtractionFunc: func(cmd []string) (types.AccessKeys, error) { + KeyExtractionFunc: func(cmd []string) (internal.AccessKeys, error) { // Treat the channels as keys - return types.AccessKeys{ + return internal.AccessKeys{ Channels: cmd[1:], ReadKeys: make([]string, 0), WriteKeys: make([]string, 0), @@ -185,8 +185,8 @@ it's currently subscribe to.`, If the pattern list is not provided, then the connection will be unsubscribed from all the patterns that it's currently subscribe to.`, Sync: false, - KeyExtractionFunc: func(cmd []string) (types.AccessKeys, error) { - return types.AccessKeys{ + KeyExtractionFunc: func(cmd []string) (internal.AccessKeys, error) { + return internal.AccessKeys{ Channels: cmd[1:], ReadKeys: make([]string, 0), WriteKeys: make([]string, 0), @@ -200,17 +200,17 @@ it's currently subscribe to.`, Categories: []string{}, Description: "", Sync: false, - KeyExtractionFunc: func(cmd []string) (types.AccessKeys, error) { - return types.AccessKeys{ + KeyExtractionFunc: func(cmd []string) (internal.AccessKeys, error) { + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: make([]string, 0), }, nil }, - HandlerFunc: func(_ types.HandlerFuncParams) ([]byte, error) { + HandlerFunc: func(_ internal.HandlerFuncParams) ([]byte, error) { return nil, errors.New("provide CHANNELS, NUMPAT, or NUMSUB subcommand") }, - SubCommands: []types.SubCommand{ + SubCommands: []internal.SubCommand{ { Command: "channels", Module: constants.PubSubModule, @@ -219,8 +219,8 @@ it's currently subscribe to.`, match the given pattern. If no pattern is provided, all active channels are returned. Active channels are channels with 1 or more subscribers.`, Sync: false, - KeyExtractionFunc: func(cmd []string) (types.AccessKeys, error) { - return types.AccessKeys{ + KeyExtractionFunc: func(cmd []string) (internal.AccessKeys, error) { + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: make([]string, 0), @@ -234,8 +234,8 @@ channels with 1 or more subscribers.`, Categories: []string{constants.PubSubCategory, constants.SlowCategory}, Description: `(PUBSUB NUMPAT) Return the number of patterns that are currently subscribed to by clients.`, Sync: false, - KeyExtractionFunc: func(cmd []string) (types.AccessKeys, error) { - return types.AccessKeys{ + KeyExtractionFunc: func(cmd []string) (internal.AccessKeys, error) { + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: make([]string, 0), @@ -250,8 +250,8 @@ channels with 1 or more subscribers.`, Description: `(PUBSUB NUMSUB [channel [channel ...]]) Return an array of arrays containing the provided channel name and how many clients are currently subscribed to the channel.`, Sync: false, - KeyExtractionFunc: func(cmd []string) (types.AccessKeys, error) { - return types.AccessKeys{ + KeyExtractionFunc: func(cmd []string) (internal.AccessKeys, error) { + return internal.AccessKeys{ Channels: cmd[2:], ReadKeys: make([]string, 0), WriteKeys: make([]string, 0), diff --git a/internal/modules/set/commands.go b/internal/modules/set/commands.go index 88abedf0..fd77af8d 100644 --- a/internal/modules/set/commands.go +++ b/internal/modules/set/commands.go @@ -19,12 +19,11 @@ import ( "fmt" "github.com/echovault/echovault/internal" "github.com/echovault/echovault/pkg/constants" - "github.com/echovault/echovault/pkg/types" "slices" "strings" ) -func handleSADD(params types.HandlerFuncParams) ([]byte, error) { +func handleSADD(params internal.HandlerFuncParams) ([]byte, error) { keys, err := saddKeyFunc(params.Command) if err != nil { return nil, err @@ -61,7 +60,7 @@ func handleSADD(params types.HandlerFuncParams) ([]byte, error) { return []byte(fmt.Sprintf(":%d\r\n", count)), nil } -func handleSCARD(params types.HandlerFuncParams) ([]byte, error) { +func handleSCARD(params internal.HandlerFuncParams) ([]byte, error) { keys, err := scardKeyFunc(params.Command) if err != nil { return nil, err @@ -88,7 +87,7 @@ func handleSCARD(params types.HandlerFuncParams) ([]byte, error) { return []byte(fmt.Sprintf(":%d\r\n", cardinality)), nil } -func handleSDIFF(params types.HandlerFuncParams) ([]byte, error) { +func handleSDIFF(params internal.HandlerFuncParams) ([]byte, error) { keys, err := sdiffKeyFunc(params.Command) if err != nil { return nil, err @@ -149,7 +148,7 @@ func handleSDIFF(params types.HandlerFuncParams) ([]byte, error) { return []byte(res), nil } -func handleSDIFFSTORE(params types.HandlerFuncParams) ([]byte, error) { +func handleSDIFFSTORE(params internal.HandlerFuncParams) ([]byte, error) { keys, err := sdiffstoreKeyFunc(params.Command) if err != nil { return nil, err @@ -225,7 +224,7 @@ func handleSDIFFSTORE(params types.HandlerFuncParams) ([]byte, error) { return []byte(res), nil } -func handleSINTER(params types.HandlerFuncParams) ([]byte, error) { +func handleSINTER(params internal.HandlerFuncParams) ([]byte, error) { keys, err := sinterKeyFunc(params.Command) if err != nil { return nil, err @@ -280,7 +279,7 @@ func handleSINTER(params types.HandlerFuncParams) ([]byte, error) { return []byte(res), nil } -func handleSINTERCARD(params types.HandlerFuncParams) ([]byte, error) { +func handleSINTERCARD(params internal.HandlerFuncParams) ([]byte, error) { keys, err := sintercardKeyFunc(params.Command) if err != nil { return nil, err @@ -347,7 +346,7 @@ func handleSINTERCARD(params types.HandlerFuncParams) ([]byte, error) { return []byte(fmt.Sprintf(":%d\r\n", intersect.Cardinality())), nil } -func handleSINTERSTORE(params types.HandlerFuncParams) ([]byte, error) { +func handleSINTERSTORE(params internal.HandlerFuncParams) ([]byte, error) { keys, err := sinterstoreKeyFunc(params.Command) if err != nil { return nil, err @@ -405,7 +404,7 @@ func handleSINTERSTORE(params types.HandlerFuncParams) ([]byte, error) { return []byte(fmt.Sprintf(":%d\r\n", intersect.Cardinality())), nil } -func handleSISMEMBER(params types.HandlerFuncParams) ([]byte, error) { +func handleSISMEMBER(params internal.HandlerFuncParams) ([]byte, error) { keys, err := sismemberKeyFunc(params.Command) if err != nil { return nil, err @@ -434,7 +433,7 @@ func handleSISMEMBER(params types.HandlerFuncParams) ([]byte, error) { return []byte(":1\r\n"), nil } -func handleSMEMBERS(params types.HandlerFuncParams) ([]byte, error) { +func handleSMEMBERS(params internal.HandlerFuncParams) ([]byte, error) { keys, err := smembersKeyFunc(params.Command) if err != nil { return nil, err @@ -469,7 +468,7 @@ func handleSMEMBERS(params types.HandlerFuncParams) ([]byte, error) { return []byte(res), nil } -func handleSMISMEMBER(params types.HandlerFuncParams) ([]byte, error) { +func handleSMISMEMBER(params internal.HandlerFuncParams) ([]byte, error) { keys, err := smismemberKeyFunc(params.Command) if err != nil { return nil, err @@ -512,7 +511,7 @@ func handleSMISMEMBER(params types.HandlerFuncParams) ([]byte, error) { return []byte(res), nil } -func handleSMOVE(params types.HandlerFuncParams) ([]byte, error) { +func handleSMOVE(params internal.HandlerFuncParams) ([]byte, error) { keys, err := smoveKeyFunc(params.Command) if err != nil { return nil, err @@ -565,7 +564,7 @@ func handleSMOVE(params types.HandlerFuncParams) ([]byte, error) { return []byte(fmt.Sprintf(":%d\r\n", res)), nil } -func handleSPOP(params types.HandlerFuncParams) ([]byte, error) { +func handleSPOP(params internal.HandlerFuncParams) ([]byte, error) { keys, err := spopKeyFunc(params.Command) if err != nil { return nil, err @@ -609,7 +608,7 @@ func handleSPOP(params types.HandlerFuncParams) ([]byte, error) { return []byte(res), nil } -func handleSRANDMEMBER(params types.HandlerFuncParams) ([]byte, error) { +func handleSRANDMEMBER(params internal.HandlerFuncParams) ([]byte, error) { keys, err := srandmemberKeyFunc(params.Command) if err != nil { return nil, err @@ -653,7 +652,7 @@ func handleSRANDMEMBER(params types.HandlerFuncParams) ([]byte, error) { return []byte(res), nil } -func handleSREM(params types.HandlerFuncParams) ([]byte, error) { +func handleSREM(params internal.HandlerFuncParams) ([]byte, error) { keys, err := sremKeyFunc(params.Command) if err != nil { return nil, err @@ -681,7 +680,7 @@ func handleSREM(params types.HandlerFuncParams) ([]byte, error) { return []byte(fmt.Sprintf(":%d\r\n", count)), nil } -func handleSUNION(params types.HandlerFuncParams) ([]byte, error) { +func handleSUNION(params internal.HandlerFuncParams) ([]byte, error) { keys, err := sunionKeyFunc(params.Command) if err != nil { return nil, err @@ -732,7 +731,7 @@ func handleSUNION(params types.HandlerFuncParams) ([]byte, error) { return []byte(res), nil } -func handleSUNIONSTORE(params types.HandlerFuncParams) ([]byte, error) { +func handleSUNIONSTORE(params internal.HandlerFuncParams) ([]byte, error) { keys, err := sunionstoreKeyFunc(params.Command) if err != nil { return nil, err @@ -791,8 +790,8 @@ func handleSUNIONSTORE(params types.HandlerFuncParams) ([]byte, error) { return []byte(fmt.Sprintf(":%d\r\n", union.Cardinality())), nil } -func Commands() []types.Command { - return []types.Command{ +func Commands() []internal.Command { + return []internal.Command{ { Command: "sadd", Module: constants.SetModule, diff --git a/internal/modules/set/key_funcs.go b/internal/modules/set/key_funcs.go index 36910de7..3e703c48 100644 --- a/internal/modules/set/key_funcs.go +++ b/internal/modules/set/key_funcs.go @@ -16,70 +16,70 @@ package set import ( "errors" + "github.com/echovault/echovault/internal" "github.com/echovault/echovault/pkg/constants" - "github.com/echovault/echovault/pkg/types" "slices" "strings" ) -func saddKeyFunc(cmd []string) (types.AccessKeys, error) { +func saddKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) < 3 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: cmd[1:2], }, nil } -func scardKeyFunc(cmd []string) (types.AccessKeys, error) { +func scardKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) != 2 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[1:2], WriteKeys: make([]string, 0), }, nil } -func sdiffKeyFunc(cmd []string) (types.AccessKeys, error) { +func sdiffKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) < 2 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[1:], WriteKeys: make([]string, 0), }, nil } -func sdiffstoreKeyFunc(cmd []string) (types.AccessKeys, error) { +func sdiffstoreKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) < 3 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[2:], WriteKeys: cmd[1:2], }, nil } -func sinterKeyFunc(cmd []string) (types.AccessKeys, error) { +func sinterKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) < 2 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[1:], WriteKeys: make([]string, 0), }, nil } -func sintercardKeyFunc(cmd []string) (types.AccessKeys, error) { +func sintercardKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) < 2 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } limitIdx := slices.IndexFunc(cmd, func(s string) bool { @@ -87,124 +87,124 @@ func sintercardKeyFunc(cmd []string) (types.AccessKeys, error) { }) if limitIdx == -1 { - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[1:], WriteKeys: make([]string, 0), }, nil } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[1:limitIdx], WriteKeys: make([]string, 0), }, nil } -func sinterstoreKeyFunc(cmd []string) (types.AccessKeys, error) { +func sinterstoreKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) < 3 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[2:], WriteKeys: cmd[1:2], }, nil } -func sismemberKeyFunc(cmd []string) (types.AccessKeys, error) { +func sismemberKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) != 3 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[1:], WriteKeys: make([]string, 0), }, nil } -func smembersKeyFunc(cmd []string) (types.AccessKeys, error) { +func smembersKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) != 2 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[1:], WriteKeys: make([]string, 0), }, nil } -func smismemberKeyFunc(cmd []string) (types.AccessKeys, error) { +func smismemberKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) < 3 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[1:2], WriteKeys: make([]string, 0), }, nil } -func smoveKeyFunc(cmd []string) (types.AccessKeys, error) { +func smoveKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) != 4 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: cmd[1:3], }, nil } -func spopKeyFunc(cmd []string) (types.AccessKeys, error) { +func spopKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) < 2 || len(cmd) > 3 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: cmd[1:2], }, nil } -func srandmemberKeyFunc(cmd []string) (types.AccessKeys, error) { +func srandmemberKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) < 2 || len(cmd) > 3 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[1:2], WriteKeys: make([]string, 0), }, nil } -func sremKeyFunc(cmd []string) (types.AccessKeys, error) { +func sremKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) < 3 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: cmd[1:2], }, nil } -func sunionKeyFunc(cmd []string) (types.AccessKeys, error) { +func sunionKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) < 2 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[1:], WriteKeys: make([]string, 0), }, nil } -func sunionstoreKeyFunc(cmd []string) (types.AccessKeys, error) { +func sunionstoreKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) < 3 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[2:], WriteKeys: cmd[1:2], diff --git a/internal/modules/sorted_set/commands.go b/internal/modules/sorted_set/commands.go index 27a86562..5e3fd6e2 100644 --- a/internal/modules/sorted_set/commands.go +++ b/internal/modules/sorted_set/commands.go @@ -20,14 +20,13 @@ import ( "fmt" "github.com/echovault/echovault/internal" "github.com/echovault/echovault/pkg/constants" - "github.com/echovault/echovault/pkg/types" "math" "slices" "strconv" "strings" ) -func handleZADD(params types.HandlerFuncParams) ([]byte, error) { +func handleZADD(params internal.HandlerFuncParams) ([]byte, error) { keys, err := zaddKeyFunc(params.Command) if err != nil { return nil, err @@ -178,7 +177,7 @@ func handleZADD(params types.HandlerFuncParams) ([]byte, error) { return []byte(fmt.Sprintf(":%d\r\n", set.Cardinality())), nil } -func handleZCARD(params types.HandlerFuncParams) ([]byte, error) { +func handleZCARD(params internal.HandlerFuncParams) ([]byte, error) { keys, err := zcardKeyFunc(params.Command) if err != nil { return nil, err @@ -202,7 +201,7 @@ func handleZCARD(params types.HandlerFuncParams) ([]byte, error) { return []byte(fmt.Sprintf(":%d\r\n", set.Cardinality())), nil } -func handleZCOUNT(params types.HandlerFuncParams) ([]byte, error) { +func handleZCOUNT(params internal.HandlerFuncParams) ([]byte, error) { keys, err := zcountKeyFunc(params.Command) if err != nil { return nil, err @@ -270,7 +269,7 @@ func handleZCOUNT(params types.HandlerFuncParams) ([]byte, error) { return []byte(fmt.Sprintf(":%d\r\n", len(members))), nil } -func handleZLEXCOUNT(params types.HandlerFuncParams) ([]byte, error) { +func handleZLEXCOUNT(params internal.HandlerFuncParams) ([]byte, error) { keys, err := zlexcountKeyFunc(params.Command) if err != nil { return nil, err @@ -315,7 +314,7 @@ func handleZLEXCOUNT(params types.HandlerFuncParams) ([]byte, error) { return []byte(fmt.Sprintf(":%d\r\n", count)), nil } -func handleZDIFF(params types.HandlerFuncParams) ([]byte, error) { +func handleZDIFF(params internal.HandlerFuncParams) ([]byte, error) { keys, err := zdiffKeyFunc(params.Command) if err != nil { return nil, err @@ -388,7 +387,7 @@ func handleZDIFF(params types.HandlerFuncParams) ([]byte, error) { return []byte(res), nil } -func handleZDIFFSTORE(params types.HandlerFuncParams) ([]byte, error) { +func handleZDIFFSTORE(params internal.HandlerFuncParams) ([]byte, error) { keys, err := zdiffstoreKeyFunc(params.Command) if err != nil { return nil, err @@ -454,7 +453,7 @@ func handleZDIFFSTORE(params types.HandlerFuncParams) ([]byte, error) { return []byte(fmt.Sprintf(":%d\r\n", diff.Cardinality())), nil } -func handleZINCRBY(params types.HandlerFuncParams) ([]byte, error) { +func handleZINCRBY(params internal.HandlerFuncParams) ([]byte, error) { keys, err := zincrbyKeyFunc(params.Command) if err != nil { return nil, err @@ -521,7 +520,7 @@ func handleZINCRBY(params types.HandlerFuncParams) ([]byte, error) { strconv.FormatFloat(float64(set.Get(member).Score), 'f', -1, 64))), nil } -func handleZINTER(params types.HandlerFuncParams) ([]byte, error) { +func handleZINTER(params internal.HandlerFuncParams) ([]byte, error) { _, err := zinterKeyFunc(params.Command) if err != nil { return nil, err @@ -581,7 +580,7 @@ func handleZINTER(params types.HandlerFuncParams) ([]byte, error) { return []byte(res), nil } -func handleZINTERSTORE(params types.HandlerFuncParams) ([]byte, error) { +func handleZINTERSTORE(params internal.HandlerFuncParams) ([]byte, error) { k, err := zinterstoreKeyFunc(params.Command) if err != nil { return nil, err @@ -648,7 +647,7 @@ func handleZINTERSTORE(params types.HandlerFuncParams) ([]byte, error) { return []byte(fmt.Sprintf(":%d\r\n", intersect.Cardinality())), nil } -func handleZMPOP(params types.HandlerFuncParams) ([]byte, error) { +func handleZMPOP(params internal.HandlerFuncParams) ([]byte, error) { keys, err := zmpopKeyFunc(params.Command) if err != nil { return nil, err @@ -726,7 +725,7 @@ func handleZMPOP(params types.HandlerFuncParams) ([]byte, error) { return []byte("*0\r\n"), nil } -func handleZPOP(params types.HandlerFuncParams) ([]byte, error) { +func handleZPOP(params internal.HandlerFuncParams) ([]byte, error) { keys, err := zpopKeyFunc(params.Command) if err != nil { return nil, err @@ -779,7 +778,7 @@ func handleZPOP(params types.HandlerFuncParams) ([]byte, error) { return []byte(res), nil } -func handleZMSCORE(params types.HandlerFuncParams) ([]byte, error) { +func handleZMSCORE(params internal.HandlerFuncParams) ([]byte, error) { keys, err := zmscoreKeyFunc(params.Command) if err != nil { return nil, err @@ -821,7 +820,7 @@ func handleZMSCORE(params types.HandlerFuncParams) ([]byte, error) { return []byte(res), nil } -func handleZRANDMEMBER(params types.HandlerFuncParams) ([]byte, error) { +func handleZRANDMEMBER(params internal.HandlerFuncParams) ([]byte, error) { keys, err := zrandmemberKeyFunc(params.Command) if err != nil { return nil, err @@ -879,7 +878,7 @@ func handleZRANDMEMBER(params types.HandlerFuncParams) ([]byte, error) { return []byte(res), nil } -func handleZRANK(params types.HandlerFuncParams) ([]byte, error) { +func handleZRANK(params internal.HandlerFuncParams) ([]byte, error) { keys, err := zrankKeyFunc(params.Command) if err != nil { return nil, err @@ -929,7 +928,7 @@ func handleZRANK(params types.HandlerFuncParams) ([]byte, error) { return []byte("$-1\r\n"), nil } -func handleZREM(params types.HandlerFuncParams) ([]byte, error) { +func handleZREM(params internal.HandlerFuncParams) ([]byte, error) { keys, err := zremKeyFunc(params.Command) if err != nil { return nil, err @@ -961,7 +960,7 @@ func handleZREM(params types.HandlerFuncParams) ([]byte, error) { return []byte(fmt.Sprintf(":%d\r\n", deletedCount)), nil } -func handleZSCORE(params types.HandlerFuncParams) ([]byte, error) { +func handleZSCORE(params internal.HandlerFuncParams) ([]byte, error) { keys, err := zscoreKeyFunc(params.Command) if err != nil { return nil, err @@ -990,7 +989,7 @@ func handleZSCORE(params types.HandlerFuncParams) ([]byte, error) { return []byte(fmt.Sprintf("$%d\r\n%s\r\n", len(score), score)), nil } -func handleZREMRANGEBYSCORE(params types.HandlerFuncParams) ([]byte, error) { +func handleZREMRANGEBYSCORE(params internal.HandlerFuncParams) ([]byte, error) { keys, err := zremrangebyscoreKeyFunc(params.Command) if err != nil { return nil, err @@ -1034,7 +1033,7 @@ func handleZREMRANGEBYSCORE(params types.HandlerFuncParams) ([]byte, error) { return []byte(fmt.Sprintf(":%d\r\n", deletedCount)), nil } -func handleZREMRANGEBYRANK(params types.HandlerFuncParams) ([]byte, error) { +func handleZREMRANGEBYRANK(params internal.HandlerFuncParams) ([]byte, error) { keys, err := zremrangebyrankKeyFunc(params.Command) if err != nil { return nil, err @@ -1099,7 +1098,7 @@ func handleZREMRANGEBYRANK(params types.HandlerFuncParams) ([]byte, error) { return []byte(fmt.Sprintf(":%d\r\n", deletedCount)), nil } -func handleZREMRANGEBYLEX(params types.HandlerFuncParams) ([]byte, error) { +func handleZREMRANGEBYLEX(params internal.HandlerFuncParams) ([]byte, error) { keys, err := zremrangebylexKeyFunc(params.Command) if err != nil { return nil, err @@ -1146,7 +1145,7 @@ func handleZREMRANGEBYLEX(params types.HandlerFuncParams) ([]byte, error) { return []byte(fmt.Sprintf(":%d\r\n", deletedCount)), nil } -func handleZRANGE(params types.HandlerFuncParams) ([]byte, error) { +func handleZRANGE(params internal.HandlerFuncParams) ([]byte, error) { keys, err := zrangeKeyCount(params.Command) if err != nil { return nil, err @@ -1286,7 +1285,7 @@ func handleZRANGE(params types.HandlerFuncParams) ([]byte, error) { return []byte(res), nil } -func handleZRANGESTORE(params types.HandlerFuncParams) ([]byte, error) { +func handleZRANGESTORE(params internal.HandlerFuncParams) ([]byte, error) { keys, err := zrangeStoreKeyFunc(params.Command) if err != nil { return nil, err @@ -1428,7 +1427,7 @@ func handleZRANGESTORE(params types.HandlerFuncParams) ([]byte, error) { return []byte(fmt.Sprintf(":%d\r\n", newSortedSet.Cardinality())), nil } -func handleZUNION(params types.HandlerFuncParams) ([]byte, error) { +func handleZUNION(params internal.HandlerFuncParams) ([]byte, error) { if _, err := zunionKeyFunc(params.Command); err != nil { return nil, err } @@ -1482,7 +1481,7 @@ func handleZUNION(params types.HandlerFuncParams) ([]byte, error) { return []byte(res), nil } -func handleZUNIONSTORE(params types.HandlerFuncParams) ([]byte, error) { +func handleZUNIONSTORE(params internal.HandlerFuncParams) ([]byte, error) { k, err := zunionstoreKeyFunc(params.Command) if err != nil { return nil, err @@ -1548,8 +1547,8 @@ func handleZUNIONSTORE(params types.HandlerFuncParams) ([]byte, error) { return []byte(fmt.Sprintf(":%d\r\n", union.Cardinality())), nil } -func Commands() []types.Command { - return []types.Command{ +func Commands() []internal.Command { + return []internal.Command{ { Command: "zadd", Module: constants.SortedSetModule, diff --git a/internal/modules/sorted_set/key_funcs.go b/internal/modules/sorted_set/key_funcs.go index 0a655834..42e8988e 100644 --- a/internal/modules/sorted_set/key_funcs.go +++ b/internal/modules/sorted_set/key_funcs.go @@ -16,48 +16,48 @@ package sorted_set import ( "errors" + "github.com/echovault/echovault/internal" "github.com/echovault/echovault/pkg/constants" - "github.com/echovault/echovault/pkg/types" "slices" "strings" ) -func zaddKeyFunc(cmd []string) (types.AccessKeys, error) { +func zaddKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) < 4 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: cmd[1:2], }, nil } -func zcardKeyFunc(cmd []string) (types.AccessKeys, error) { +func zcardKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) != 2 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[1:], WriteKeys: make([]string, 0), }, nil } -func zcountKeyFunc(cmd []string) (types.AccessKeys, error) { +func zcountKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) != 4 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[1:2], WriteKeys: make([]string, 0), }, nil } -func zdiffKeyFunc(cmd []string) (types.AccessKeys, error) { +func zdiffKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) < 2 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } withscoresIndex := slices.IndexFunc(cmd, func(s string) bool { @@ -65,45 +65,45 @@ func zdiffKeyFunc(cmd []string) (types.AccessKeys, error) { }) if withscoresIndex == -1 { - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[1:], WriteKeys: make([]string, 0), }, nil } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[1:withscoresIndex], WriteKeys: make([]string, 0), }, nil } -func zdiffstoreKeyFunc(cmd []string) (types.AccessKeys, error) { +func zdiffstoreKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) < 3 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[2:], WriteKeys: cmd[1:2], }, nil } -func zincrbyKeyFunc(cmd []string) (types.AccessKeys, error) { +func zincrbyKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) != 4 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: cmd[1:2], }, nil } -func zinterKeyFunc(cmd []string) (types.AccessKeys, error) { +func zinterKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) < 2 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } endIdx := slices.IndexFunc(cmd[1:], func(s string) bool { if strings.EqualFold(s, "WEIGHTS") || @@ -114,25 +114,25 @@ func zinterKeyFunc(cmd []string) (types.AccessKeys, error) { return false }) if endIdx == -1 { - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[1:], WriteKeys: make([]string, 0), }, nil } if endIdx >= 1 { - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[1:endIdx], WriteKeys: make([]string, 0), }, nil } - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } -func zinterstoreKeyFunc(cmd []string) (types.AccessKeys, error) { +func zinterstoreKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) < 3 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } endIdx := slices.IndexFunc(cmd[1:], func(s string) bool { if strings.EqualFold(s, "WEIGHTS") || @@ -143,192 +143,192 @@ func zinterstoreKeyFunc(cmd []string) (types.AccessKeys, error) { return false }) if endIdx == -1 { - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[2:], WriteKeys: cmd[1:2], }, nil } if endIdx >= 3 { - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[2:endIdx], WriteKeys: cmd[1:2], }, nil } - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } -func zmpopKeyFunc(cmd []string) (types.AccessKeys, error) { +func zmpopKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) < 2 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } endIdx := slices.IndexFunc(cmd, func(s string) bool { return slices.Contains([]string{"MIN", "MAX", "COUNT"}, strings.ToUpper(s)) }) if endIdx == -1 { - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: cmd[1:], }, nil } if endIdx >= 2 { - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: cmd[1:endIdx], }, nil } - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } -func zmscoreKeyFunc(cmd []string) (types.AccessKeys, error) { +func zmscoreKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) < 3 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[1:2], WriteKeys: make([]string, 0), }, nil } -func zpopKeyFunc(cmd []string) (types.AccessKeys, error) { +func zpopKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) < 2 || len(cmd) > 3 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: cmd[1:2], }, nil } -func zrandmemberKeyFunc(cmd []string) (types.AccessKeys, error) { +func zrandmemberKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) < 2 || len(cmd) > 4 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[1:2], WriteKeys: make([]string, 0), }, nil } -func zrankKeyFunc(cmd []string) (types.AccessKeys, error) { +func zrankKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) < 3 || len(cmd) > 4 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[1:2], WriteKeys: make([]string, 0), }, nil } -func zremKeyFunc(cmd []string) (types.AccessKeys, error) { +func zremKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) < 3 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: cmd[1:2], }, nil } -func zrevrankKeyFunc(cmd []string) (types.AccessKeys, error) { +func zrevrankKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) < 3 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[1:2], WriteKeys: make([]string, 0), }, nil } -func zscoreKeyFunc(cmd []string) (types.AccessKeys, error) { +func zscoreKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) != 3 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[1:2], WriteKeys: make([]string, 0), }, nil } -func zremrangebylexKeyFunc(cmd []string) (types.AccessKeys, error) { +func zremrangebylexKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) != 4 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: cmd[1:2], }, nil } -func zremrangebyrankKeyFunc(cmd []string) (types.AccessKeys, error) { +func zremrangebyrankKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) != 4 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: cmd[1:2], }, nil } -func zremrangebyscoreKeyFunc(cmd []string) (types.AccessKeys, error) { +func zremrangebyscoreKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) != 4 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: cmd[1:2], }, nil } -func zlexcountKeyFunc(cmd []string) (types.AccessKeys, error) { +func zlexcountKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) != 4 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[1:2], WriteKeys: make([]string, 0), }, nil } -func zrangeKeyCount(cmd []string) (types.AccessKeys, error) { +func zrangeKeyCount(cmd []string) (internal.AccessKeys, error) { if len(cmd) < 4 || len(cmd) > 10 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[1:2], WriteKeys: make([]string, 0), }, nil } -func zrangeStoreKeyFunc(cmd []string) (types.AccessKeys, error) { +func zrangeStoreKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) < 5 || len(cmd) > 11 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[2:3], WriteKeys: cmd[1:2], }, nil } -func zunionKeyFunc(cmd []string) (types.AccessKeys, error) { +func zunionKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) < 2 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } endIdx := slices.IndexFunc(cmd[1:], func(s string) bool { if strings.EqualFold(s, "WEIGHTS") || @@ -339,25 +339,25 @@ func zunionKeyFunc(cmd []string) (types.AccessKeys, error) { return false }) if endIdx == -1 { - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[1:], WriteKeys: make([]string, 0), }, nil } if endIdx >= 1 { - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[1:endIdx], WriteKeys: cmd[1:endIdx], }, nil } - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } -func zunionstoreKeyFunc(cmd []string) (types.AccessKeys, error) { +func zunionstoreKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) < 3 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } endIdx := slices.IndexFunc(cmd[1:], func(s string) bool { if strings.EqualFold(s, "WEIGHTS") || @@ -368,18 +368,18 @@ func zunionstoreKeyFunc(cmd []string) (types.AccessKeys, error) { return false }) if endIdx == -1 { - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[2:], WriteKeys: cmd[1:2], }, nil } if endIdx >= 1 { - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[2:endIdx], WriteKeys: cmd[1:2], }, nil } - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } diff --git a/internal/modules/string/commands.go b/internal/modules/string/commands.go index 346d5c6e..ce3ce904 100644 --- a/internal/modules/string/commands.go +++ b/internal/modules/string/commands.go @@ -19,10 +19,9 @@ import ( "fmt" "github.com/echovault/echovault/internal" "github.com/echovault/echovault/pkg/constants" - "github.com/echovault/echovault/pkg/types" ) -func handleSetRange(params types.HandlerFuncParams) ([]byte, error) { +func handleSetRange(params internal.HandlerFuncParams) ([]byte, error) { keys, err := setRangeKeyFunc(params.Command) if err != nil { return nil, err @@ -97,7 +96,7 @@ func handleSetRange(params types.HandlerFuncParams) ([]byte, error) { return []byte(fmt.Sprintf(":%d\r\n", len(strRunes))), nil } -func handleStrLen(params types.HandlerFuncParams) ([]byte, error) { +func handleStrLen(params internal.HandlerFuncParams) ([]byte, error) { keys, err := strLenKeyFunc(params.Command) if err != nil { return nil, err @@ -123,7 +122,7 @@ func handleStrLen(params types.HandlerFuncParams) ([]byte, error) { return []byte(fmt.Sprintf(":%d\r\n", len(value))), nil } -func handleSubStr(params types.HandlerFuncParams) ([]byte, error) { +func handleSubStr(params internal.HandlerFuncParams) ([]byte, error) { keys, err := subStrKeyFunc(params.Command) if err != nil { return nil, err @@ -186,8 +185,8 @@ func handleSubStr(params types.HandlerFuncParams) ([]byte, error) { return []byte(fmt.Sprintf("$%d\r\n%s\r\n", len(str), str)), nil } -func Commands() []types.Command { - return []types.Command{ +func Commands() []internal.Command { + return []internal.Command{ { Command: "setrange", Module: constants.StringModule, diff --git a/internal/modules/string/key_funcs.go b/internal/modules/string/key_funcs.go index 92e57364..95ee5b5f 100644 --- a/internal/modules/string/key_funcs.go +++ b/internal/modules/string/key_funcs.go @@ -16,37 +16,37 @@ package str import ( "errors" + "github.com/echovault/echovault/internal" "github.com/echovault/echovault/pkg/constants" - "github.com/echovault/echovault/pkg/types" ) -func setRangeKeyFunc(cmd []string) (types.AccessKeys, error) { +func setRangeKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) != 4 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: make([]string, 0), WriteKeys: cmd[1:2], }, nil } -func strLenKeyFunc(cmd []string) (types.AccessKeys, error) { +func strLenKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) != 2 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[1:2], WriteKeys: make([]string, 0), }, nil } -func subStrKeyFunc(cmd []string) (types.AccessKeys, error) { +func subStrKeyFunc(cmd []string) (internal.AccessKeys, error) { if len(cmd) != 4 { - return types.AccessKeys{}, errors.New(constants.WrongArgsResponse) + return internal.AccessKeys{}, errors.New(constants.WrongArgsResponse) } - return types.AccessKeys{ + return internal.AccessKeys{ Channels: make([]string, 0), ReadKeys: cmd[1:2], WriteKeys: make([]string, 0), diff --git a/internal/raft/fsm.go b/internal/raft/fsm.go index 2de04d81..8f7aa2e9 100644 --- a/internal/raft/fsm.go +++ b/internal/raft/fsm.go @@ -32,12 +32,12 @@ type FSMOpts struct { Config config.Config EchoVault types.EchoVault GetState func() map[string]internal.KeyData - GetCommand func(command string) (types.Command, error) + GetCommand func(command string) (internal.Command, error) DeleteKey func(ctx context.Context, key string) error StartSnapshot func() FinishSnapshot func() SetLatestSnapshotTime func(msec int64) - GetHandlerFuncParams func(ctx context.Context, cmd []string, conn *net.Conn) types.HandlerFuncParams + GetHandlerFuncParams func(ctx context.Context, cmd []string, conn *net.Conn) internal.HandlerFuncParams } type FSM struct { @@ -99,7 +99,7 @@ func (fsm *FSM) Apply(log *raft.Log) interface{} { handler := command.HandlerFunc - subCommand, ok := internal.GetSubCommand(command, request.CMD).(types.SubCommand) + subCommand, ok := internal.GetSubCommand(command, request.CMD).(internal.SubCommand) if ok { handler = subCommand.HandlerFunc } diff --git a/internal/raft/raft.go b/internal/raft/raft.go index a6abbc6a..f74532ac 100644 --- a/internal/raft/raft.go +++ b/internal/raft/raft.go @@ -36,12 +36,12 @@ type Opts struct { Config config.Config EchoVault types.EchoVault GetState func() map[string]internal.KeyData - GetCommand func(command string) (types.Command, error) + GetCommand func(command string) (internal.Command, error) DeleteKey func(ctx context.Context, key string) error StartSnapshot func() FinishSnapshot func() SetLatestSnapshotTime func(msec int64) - GetHandlerFuncParams func(ctx context.Context, cmd []string, conn *net.Conn) types.HandlerFuncParams + GetHandlerFuncParams func(ctx context.Context, cmd []string, conn *net.Conn) internal.HandlerFuncParams } type Raft struct { diff --git a/internal/types.go b/internal/types.go index 277af0de..56990e28 100644 --- a/internal/types.go +++ b/internal/types.go @@ -14,7 +14,12 @@ package internal -import "time" +import ( + "context" + "github.com/echovault/echovault/internal/clock" + "net" + "time" +) type KeyData struct { Value interface{} @@ -41,3 +46,59 @@ type SnapshotObject struct { State map[string]KeyData LatestSnapshotMilliseconds int64 } + +type AccessKeys struct { + Channels []string + ReadKeys []string + WriteKeys []string +} + +type KeyExtractionFunc func(cmd []string) (AccessKeys, error) + +type HandlerFuncParams struct { + Context context.Context + Command []string + Connection *net.Conn + KeyLock func(ctx context.Context, key string) (bool, error) + KeyUnlock func(ctx context.Context, key string) + KeyRLock func(ctx context.Context, key string) (bool, error) + KeyRUnlock func(ctx context.Context, key string) + KeyExists func(ctx context.Context, key string) bool + CreateKeyAndLock func(ctx context.Context, key string) (bool, error) + GetValue func(ctx context.Context, key string) interface{} + SetValue func(ctx context.Context, key string, value interface{}) error + GetExpiry func(ctx context.Context, key string) time.Time + SetExpiry func(ctx context.Context, key string, expire time.Time, touch bool) + RemoveExpiry func(ctx context.Context, key string) + DeleteKey func(ctx context.Context, key string) error + GetClock func() clock.Clock + GetAllCommands func() []Command + GetACL func() interface{} + GetPubSub func() interface{} + TakeSnapshot func() error + RewriteAOF func() error + GetLatestSnapshotTime func() int64 +} + +type HandlerFunc func(params HandlerFuncParams) ([]byte, error) + +type Command struct { + Command string + Module string + Categories []string + Description string + SubCommands []SubCommand + Sync bool // Specifies if command should be synced across replication cluster + KeyExtractionFunc + HandlerFunc +} + +type SubCommand struct { + Command string + Module string + Categories []string + Description string + Sync bool // Specifies if sub-command should be synced across replication cluster + KeyExtractionFunc + HandlerFunc +} diff --git a/internal/utils.go b/internal/utils.go index 6f417c23..f27b0155 100644 --- a/internal/utils.go +++ b/internal/utils.go @@ -21,7 +21,6 @@ import ( "errors" "fmt" "github.com/echovault/echovault/pkg/constants" - "github.com/echovault/echovault/pkg/types" "io" "log" "math/big" @@ -129,7 +128,7 @@ func GetIPAddress() (string, error) { return localAddr, nil } -func GetSubCommand(command types.Command, cmd []string) interface{} { +func GetSubCommand(command Command, cmd []string) interface{} { if len(command.SubCommands) == 0 || len(cmd) < 2 { return nil } @@ -141,7 +140,7 @@ func GetSubCommand(command types.Command, cmd []string) interface{} { return nil } -func IsWriteCommand(command types.Command, subCommand types.SubCommand) bool { +func IsWriteCommand(command Command, subCommand SubCommand) bool { return slices.Contains(append(command.Categories, subCommand.Categories...), constants.WriteCategory) } diff --git a/pkg/echovault/echovault.go b/pkg/echovault/echovault.go index 18911fca..b5b1ba34 100644 --- a/pkg/echovault/echovault.go +++ b/pkg/echovault/echovault.go @@ -39,7 +39,6 @@ import ( "github.com/echovault/echovault/internal/raft" "github.com/echovault/echovault/internal/snapshot" "github.com/echovault/echovault/pkg/constants" - "github.com/echovault/echovault/pkg/types" "io" "log" "net" @@ -51,7 +50,8 @@ import ( type EchoVault struct { // clock is an implementation of a time interface that allows mocking of time functions during testing. - clock clock.Clock + clock clock.Clock + getClock func() clock.Clock // config holds the echovault configuration variables. config config.Config @@ -82,7 +82,8 @@ type EchoVault struct { } // Holds the list of all commands supported by the echovault. - commands []types.Command + commands []internal.Command + getCommands func() []internal.Command raft *raft.Raft // The raft replication layer for the echovault. memberList *memberlist.MemberList // The memberlist layer for the echovault. @@ -90,7 +91,10 @@ type EchoVault struct { context context.Context acl *acl.ACL - pubSub *pubsub.PubSub + getACL func() interface{} + + pubSub *pubsub.PubSub + getPubSub func() interface{} snapshotInProgress atomic.Bool // Atomic boolean that's true when actively taking a snapshot. rewriteAOFInProgress atomic.Bool // Atomic boolean that's true when actively rewriting AOF file is in progress. @@ -119,15 +123,6 @@ func WithConfig(config config.Config) func(echovault *EchoVault) { } } -// WithCommands is an options for the NewEchoVault function that allows you to pass a -// list of commands that should be supported by your EchoVault instance. -// If you don't pass this option, EchoVault will start with no commands loaded. -func WithCommands(commands []types.Command) func(echovault *EchoVault) { - return func(echovault *EchoVault) { - echovault.commands = commands - } -} - // NewEchoVault creates a new EchoVault instance. // This functions accepts the WithContext, WithConfig and WithCommands options. func NewEchoVault(options ...func(echovault *EchoVault)) (*EchoVault, error) { @@ -138,8 +133,8 @@ func NewEchoVault(options ...func(echovault *EchoVault)) (*EchoVault, error) { store: make(map[string]internal.KeyData), keyLocks: make(map[string]*sync.RWMutex), keyCreationLock: &sync.Mutex{}, - commands: func() []types.Command { - var commands []types.Command + commands: func() []internal.Command { + var commands []internal.Command commands = append(commands, acl.Commands()...) commands = append(commands, admin.Commands()...) commands = append(commands, generic.Commands()...) @@ -163,11 +158,27 @@ func NewEchoVault(options ...func(echovault *EchoVault)) (*EchoVault, error) { internal.ContextServerID(echovault.config.ServerID), ) + // Function for server commands retrieval + echovault.getCommands = func() []internal.Command { + return echovault.commands + } + + // Function for clock retrieval + echovault.getClock = func() clock.Clock { + return echovault.clock + } + // Set up ACL module echovault.acl = acl.NewACL(echovault.config) + echovault.getACL = func() interface{} { + return echovault.acl + } // Set up Pub/Sub module echovault.pubSub = pubsub.NewPubSub() + echovault.getPubSub = func() interface{} { + return echovault.pubSub + } if echovault.isInCluster() { echovault.raft = raft.NewRaft(raft.Opts{ @@ -208,7 +219,7 @@ func NewEchoVault(options ...func(echovault *EchoVault)) (*EchoVault, error) { snapshot.WithStartSnapshotFunc(echovault.startSnapshot), snapshot.WithFinishSnapshotFunc(echovault.finishSnapshot), snapshot.WithSetLatestSnapshotTimeFunc(echovault.setLatestSnapshot), - snapshot.WithGetLatestSnapshotTimeFunc(echovault.GetLatestSnapshotTime), + snapshot.WithGetLatestSnapshotTimeFunc(echovault.getLatestSnapshotTime), snapshot.WithGetStateFunc(func() map[string]internal.KeyData { state := make(map[string]internal.KeyData) for k, v := range echovault.getState() { @@ -471,8 +482,8 @@ func (server *EchoVault) Start() { server.startTCP() } -// TakeSnapshot triggers a snapshot when called. -func (server *EchoVault) TakeSnapshot() error { +// takeSnapshot triggers a snapshot when called. +func (server *EchoVault) takeSnapshot() error { if server.snapshotInProgress.Load() { return errors.New("snapshot already in progress") } @@ -494,11 +505,6 @@ func (server *EchoVault) TakeSnapshot() error { return nil } -// GetClock returns the server's clock implementation -func (server *EchoVault) GetClock() clock.Clock { - return server.clock -} - func (server *EchoVault) startSnapshot() { server.snapshotInProgress.Store(true) } @@ -511,8 +517,8 @@ func (server *EchoVault) setLatestSnapshot(msec int64) { server.latestSnapshotMilliseconds.Store(msec) } -// GetLatestSnapshotTime returns the latest snapshot time in unix epoch milliseconds. -func (server *EchoVault) GetLatestSnapshotTime() int64 { +// getLatestSnapshotTime returns the latest snapshot time in unix epoch milliseconds. +func (server *EchoVault) getLatestSnapshotTime() int64 { return server.latestSnapshotMilliseconds.Load() } @@ -524,8 +530,8 @@ func (server *EchoVault) finishRewriteAOF() { server.rewriteAOFInProgress.Store(false) } -// RewriteAOF triggers an AOF compaction when running in standalone mode. -func (server *EchoVault) RewriteAOF() error { +// rewriteAOF triggers an AOF compaction when running in standalone mode. +func (server *EchoVault) rewriteAOF() error { if server.rewriteAOFInProgress.Load() { return errors.New("aof rewrite in progress") } diff --git a/pkg/echovault/keyspace.go b/pkg/echovault/keyspace.go index a751dbad..1ba9d542 100644 --- a/pkg/echovault/keyspace.go +++ b/pkg/echovault/keyspace.go @@ -247,7 +247,7 @@ func (server *EchoVault) SetExpiry(ctx context.Context, key string, expireAt tim // RemoveExpiry is called by commands that remove key expiry (e.g. PERSIST). // The key must be locked prior ro calling this function. -func (server *EchoVault) RemoveExpiry(key string) { +func (server *EchoVault) RemoveExpiry(_ context.Context, key string) { // Reset expiry time server.store[key] = internal.KeyData{ Value: server.store[key].Value, @@ -292,7 +292,7 @@ func (server *EchoVault) DeleteKey(ctx context.Context, key string) error { } // Remove key expiry. - server.RemoveExpiry(key) + server.RemoveExpiry(ctx, key) // Delete the key from keyLocks and store. delete(server.keyLocks, key) diff --git a/pkg/echovault/modules.go b/pkg/echovault/modules.go index 9f8e44ff..f228b371 100644 --- a/pkg/echovault/modules.go +++ b/pkg/echovault/modules.go @@ -20,52 +20,42 @@ import ( "fmt" "github.com/echovault/echovault/internal" "github.com/echovault/echovault/pkg/constants" - "github.com/echovault/echovault/pkg/types" "net" "strings" ) -func (server *EchoVault) GetAllCommands() []types.Command { - return server.commands -} - -func (server *EchoVault) GetACL() interface{} { - return server.acl -} - -func (server *EchoVault) GetPubSub() interface{} { - return server.pubSub -} - -func (server *EchoVault) getCommand(cmd string) (types.Command, error) { +func (server *EchoVault) getCommand(cmd string) (internal.Command, error) { for _, command := range server.commands { if strings.EqualFold(command.Command, cmd) { return command, nil } } - return types.Command{}, fmt.Errorf("command %s not supported", cmd) + return internal.Command{}, fmt.Errorf("command %s not supported", cmd) } -func (server *EchoVault) getHandlerFuncParams(ctx context.Context, cmd []string, conn *net.Conn) types.HandlerFuncParams { - return types.HandlerFuncParams{ - Context: ctx, - Command: cmd, - Connection: conn, - KeyExists: server.KeyExists, - CreateKeyAndLock: server.CreateKeyAndLock, - KeyLock: server.KeyLock, - KeyRLock: server.KeyRLock, - KeyUnlock: server.KeyUnlock, - KeyRUnlock: server.KeyRUnlock, - GetValue: server.GetValue, - SetValue: server.SetValue, - GetClock: server.GetClock, - GetExpiry: server.GetExpiry, - SetExpiry: server.SetExpiry, - DeleteKey: server.DeleteKey, - GetPubSub: server.GetPubSub, - GetACL: server.GetACL, - GetAllCommands: server.GetAllCommands, +func (server *EchoVault) getHandlerFuncParams(ctx context.Context, cmd []string, conn *net.Conn) internal.HandlerFuncParams { + return internal.HandlerFuncParams{ + Context: ctx, + Command: cmd, + Connection: conn, + KeyExists: server.KeyExists, + CreateKeyAndLock: server.CreateKeyAndLock, + KeyLock: server.KeyLock, + KeyRLock: server.KeyRLock, + KeyUnlock: server.KeyUnlock, + KeyRUnlock: server.KeyRUnlock, + GetValue: server.GetValue, + SetValue: server.SetValue, + GetExpiry: server.GetExpiry, + SetExpiry: server.SetExpiry, + DeleteKey: server.DeleteKey, + TakeSnapshot: server.takeSnapshot, + GetLatestSnapshotTime: server.getLatestSnapshotTime, + RewriteAOF: server.rewriteAOF, + GetClock: server.getClock, + GetPubSub: server.getPubSub, + GetACL: server.getACL, + GetAllCommands: server.getCommands, } } @@ -83,7 +73,7 @@ func (server *EchoVault) handleCommand(ctx context.Context, message []byte, conn synchronize := command.Sync handler := command.HandlerFunc - subCommand, ok := internal.GetSubCommand(command, cmd).(types.SubCommand) + subCommand, ok := internal.GetSubCommand(command, cmd).(internal.SubCommand) if ok { synchronize = subCommand.Sync handler = subCommand.HandlerFunc diff --git a/pkg/types/types.go b/pkg/types/types.go index 3aeefc6f..2b4f46cc 100644 --- a/pkg/types/types.go +++ b/pkg/types/types.go @@ -16,8 +16,6 @@ package types import ( "context" - "github.com/echovault/echovault/internal/clock" - "net" "time" ) @@ -32,67 +30,6 @@ type EchoVault interface { SetValue(ctx context.Context, key string, value interface{}) error GetExpiry(ctx context.Context, key string) time.Time SetExpiry(ctx context.Context, key string, expire time.Time, touch bool) - RemoveExpiry(key string) + RemoveExpiry(ctx context.Context, key string) DeleteKey(ctx context.Context, key string) error - GetClock() clock.Clock - GetAllCommands() []Command - GetACL() interface{} - GetPubSub() interface{} - TakeSnapshot() error - RewriteAOF() error - GetLatestSnapshotTime() int64 -} - -type AccessKeys struct { - Channels []string - ReadKeys []string - WriteKeys []string -} -type KeyExtractionFunc func(cmd []string) (AccessKeys, error) - -type HandlerFuncParams struct { - Context context.Context - Command []string - Connection *net.Conn - KeyLock func(ctx context.Context, key string) (bool, error) - KeyUnlock func(ctx context.Context, key string) - KeyRLock func(ctx context.Context, key string) (bool, error) - KeyRUnlock func(ctx context.Context, key string) - KeyExists func(ctx context.Context, key string) bool - CreateKeyAndLock func(ctx context.Context, key string) (bool, error) - GetValue func(ctx context.Context, key string) interface{} - SetValue func(ctx context.Context, key string, value interface{}) error - GetExpiry func(ctx context.Context, key string) time.Time - SetExpiry func(ctx context.Context, key string, expire time.Time, touch bool) - RemoveExpiry func(key string) - DeleteKey func(ctx context.Context, key string) error - GetClock func() clock.Clock - GetAllCommands func() []Command - GetACL func() interface{} - GetPubSub func() interface{} - TakeSnapshot func() error - RewriteAOF func() error - GetLatestSnapshotTime func() int64 -} -type HandlerFunc func(params HandlerFuncParams) ([]byte, error) - -type SubCommand struct { - Command string - Module string - Categories []string - Description string - Sync bool // Specifies if sub-command should be synced across replication cluster - KeyExtractionFunc - HandlerFunc -} - -type Command struct { - Command string - Module string - Categories []string - Description string - SubCommands []SubCommand - Sync bool // Specifies if command should be synced across replication cluster - KeyExtractionFunc - HandlerFunc } diff --git a/test/modules/acl/commands_test.go b/test/modules/acl/commands_test.go index 09303a0a..bbc2b3ed 100644 --- a/test/modules/acl/commands_test.go +++ b/test/modules/acl/commands_test.go @@ -23,10 +23,12 @@ import ( "github.com/echovault/echovault/pkg/echovault" "github.com/tidwall/resp" "net" + "reflect" "slices" "strings" "sync" "testing" + "unsafe" ) var bindAddr string @@ -64,12 +66,22 @@ func setUpServer(bindAddr string, port uint16, requirePass bool, aclConfig strin ) // Add the initial test users to the ACL module - a := mockServer.GetACL().(*acl.ACL) + a := getACL(mockServer) a.AddUsers(generateInitialTestUsers()) return mockServer } +func getUnexportedField(field reflect.Value) interface{} { + return reflect.NewAt(field.Type(), unsafe.Pointer(field.UnsafeAddr())).Elem().Interface() +} + +func getACL(mockServer *echovault.EchoVault) *acl.ACL { + method := getUnexportedField(reflect.ValueOf(mockServer).Elem().FieldByName("getACL")) + f := method.(func() interface{}) + return f().(*acl.ACL) +} + func generateInitialTestUsers() []*acl.User { // User with both hash password and plaintext password withPasswordUser := acl.CreateUser("with_password_user") @@ -459,10 +471,7 @@ func Test_HandleSetUser(t *testing.T) { }() wg.Wait() - a, ok := mockServer.GetACL().(*acl.ACL) - if !ok { - t.Error("error loading ACL module") - } + a := getACL(mockServer) conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", bindAddr, port)) if err != nil { @@ -1055,7 +1064,7 @@ func Test_HandleGetUser(t *testing.T) { }() wg.Wait() - a, _ := mockServer.GetACL().(*acl.ACL) + a := getACL(mockServer) conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", bindAddr, port)) if err != nil { @@ -1208,7 +1217,7 @@ func Test_HandleDelUser(t *testing.T) { }() wg.Wait() - a, _ := mockServer.GetACL().(*acl.ACL) + a := getACL(mockServer) conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", bindAddr, port)) if err != nil { @@ -1358,7 +1367,7 @@ func Test_HandleList(t *testing.T) { }() wg.Wait() - a, _ := mockServer.GetACL().(*acl.ACL) + a := getACL(mockServer) conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", bindAddr, port)) if err != nil { diff --git a/test/modules/admin/commands_test.go b/test/modules/admin/commands_test.go index 0f8b908f..fd6ea317 100644 --- a/test/modules/admin/commands_test.go +++ b/test/modules/admin/commands_test.go @@ -18,14 +18,16 @@ import ( "bytes" "context" "fmt" + "github.com/echovault/echovault/internal" "github.com/echovault/echovault/internal/config" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/echovault" - "github.com/echovault/echovault/pkg/types" "github.com/tidwall/resp" "net" + "reflect" "strings" "testing" + "unsafe" ) var mockServer *echovault.EchoVault @@ -39,11 +41,17 @@ func init() { ) } -func getHandler(commands ...string) types.HandlerFunc { +func getUnexportedField(field reflect.Value) interface{} { + return reflect.NewAt(field.Type(), unsafe.Pointer(field.UnsafeAddr())).Elem().Interface() +} + +func getHandler(commands ...string) internal.HandlerFunc { if len(commands) == 0 { return nil } - for _, c := range mockServer.GetAllCommands() { + getCommands := + getUnexportedField(reflect.ValueOf(mockServer).Elem().FieldByName("getCommands")).(func() []internal.Command) + for _, c := range getCommands() { if strings.EqualFold(commands[0], c.Command) && len(commands) == 1 { // Get command handler return c.HandlerFunc @@ -60,12 +68,14 @@ func getHandler(commands ...string) types.HandlerFunc { return nil } -func getHandlerFuncParams(ctx context.Context, cmd []string, conn *net.Conn) types.HandlerFuncParams { - return types.HandlerFuncParams{ +func getHandlerFuncParams(ctx context.Context, cmd []string, conn *net.Conn) internal.HandlerFuncParams { + getCommands := + getUnexportedField(reflect.ValueOf(mockServer).Elem().FieldByName("getCommands")).(func() []internal.Command) + return internal.HandlerFuncParams{ Context: ctx, Command: cmd, Connection: conn, - GetAllCommands: mockServer.GetAllCommands, + GetAllCommands: getCommands, } } diff --git a/test/modules/connection/commands_test.go b/test/modules/connection/commands_test.go index 633e884e..6e3a05b6 100644 --- a/test/modules/connection/commands_test.go +++ b/test/modules/connection/commands_test.go @@ -18,14 +18,16 @@ import ( "bytes" "context" "errors" + "github.com/echovault/echovault/internal" "github.com/echovault/echovault/internal/config" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/echovault" - "github.com/echovault/echovault/pkg/types" "github.com/tidwall/resp" "net" + "reflect" "strings" "testing" + "unsafe" ) var mockServer *echovault.EchoVault @@ -39,11 +41,17 @@ func init() { ) } -func getHandler(commands ...string) types.HandlerFunc { +func getUnexportedField(field reflect.Value) interface{} { + return reflect.NewAt(field.Type(), unsafe.Pointer(field.UnsafeAddr())).Elem().Interface() +} + +func getHandler(commands ...string) internal.HandlerFunc { if len(commands) == 0 { return nil } - for _, c := range mockServer.GetAllCommands() { + getCommands := + getUnexportedField(reflect.ValueOf(mockServer).Elem().FieldByName("getCommands")).(func() []internal.Command) + for _, c := range getCommands() { if strings.EqualFold(commands[0], c.Command) && len(commands) == 1 { // Get command handler return c.HandlerFunc @@ -60,8 +68,8 @@ func getHandler(commands ...string) types.HandlerFunc { return nil } -func getHandlerFuncParams(ctx context.Context, cmd []string, conn *net.Conn) types.HandlerFuncParams { - return types.HandlerFuncParams{ +func getHandlerFuncParams(ctx context.Context, cmd []string, conn *net.Conn) internal.HandlerFuncParams { + return internal.HandlerFuncParams{ Context: ctx, Command: cmd, Connection: conn, diff --git a/test/modules/generic/commands_test.go b/test/modules/generic/commands_test.go index e89d2283..9598de09 100644 --- a/test/modules/generic/commands_test.go +++ b/test/modules/generic/commands_test.go @@ -19,16 +19,18 @@ import ( "context" "errors" "fmt" + "github.com/echovault/echovault/internal" "github.com/echovault/echovault/internal/clock" "github.com/echovault/echovault/internal/config" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/echovault" - "github.com/echovault/echovault/pkg/types" "github.com/tidwall/resp" "net" + "reflect" "strings" "testing" "time" + "unsafe" ) var mockServer *echovault.EchoVault @@ -51,11 +53,17 @@ func init() { ) } -func getHandler(commands ...string) types.HandlerFunc { +func getUnexportedField(field reflect.Value) interface{} { + return reflect.NewAt(field.Type(), unsafe.Pointer(field.UnsafeAddr())).Elem().Interface() +} + +func getHandler(commands ...string) internal.HandlerFunc { if len(commands) == 0 { return nil } - for _, c := range mockServer.GetAllCommands() { + getCommands := + getUnexportedField(reflect.ValueOf(mockServer).Elem().FieldByName("getCommands")).(func() []internal.Command) + for _, c := range getCommands() { if strings.EqualFold(commands[0], c.Command) && len(commands) == 1 { // Get command handler return c.HandlerFunc @@ -72,8 +80,10 @@ func getHandler(commands ...string) types.HandlerFunc { return nil } -func getHandlerFuncParams(ctx context.Context, cmd []string, conn *net.Conn) types.HandlerFuncParams { - return types.HandlerFuncParams{ +func getHandlerFuncParams(ctx context.Context, cmd []string, conn *net.Conn) internal.HandlerFuncParams { + getClock := + getUnexportedField(reflect.ValueOf(mockServer).Elem().FieldByName("getClock")).(func() clock.Clock) + return internal.HandlerFuncParams{ Context: ctx, Command: cmd, Connection: conn, @@ -85,10 +95,10 @@ func getHandlerFuncParams(ctx context.Context, cmd []string, conn *net.Conn) typ KeyRUnlock: mockServer.KeyRUnlock, GetValue: mockServer.GetValue, SetValue: mockServer.SetValue, - GetClock: mockServer.GetClock, GetExpiry: mockServer.GetExpiry, SetExpiry: mockServer.SetExpiry, DeleteKey: mockServer.DeleteKey, + GetClock: getClock, } } diff --git a/test/modules/hash/commands_test.go b/test/modules/hash/commands_test.go index ec890a25..27a05897 100644 --- a/test/modules/hash/commands_test.go +++ b/test/modules/hash/commands_test.go @@ -19,15 +19,17 @@ import ( "context" "errors" "fmt" + "github.com/echovault/echovault/internal" "github.com/echovault/echovault/internal/config" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/echovault" - "github.com/echovault/echovault/pkg/types" "github.com/tidwall/resp" "net" + "reflect" "slices" "strings" "testing" + "unsafe" ) var mockServer *echovault.EchoVault @@ -41,11 +43,17 @@ func init() { ) } -func getHandler(commands ...string) types.HandlerFunc { +func getUnexportedField(field reflect.Value) interface{} { + return reflect.NewAt(field.Type(), unsafe.Pointer(field.UnsafeAddr())).Elem().Interface() +} + +func getHandler(commands ...string) internal.HandlerFunc { if len(commands) == 0 { return nil } - for _, c := range mockServer.GetAllCommands() { + getCommands := + getUnexportedField(reflect.ValueOf(mockServer).Elem().FieldByName("getCommands")).(func() []internal.Command) + for _, c := range getCommands() { if strings.EqualFold(commands[0], c.Command) && len(commands) == 1 { // Get command handler return c.HandlerFunc @@ -62,8 +70,8 @@ func getHandler(commands ...string) types.HandlerFunc { return nil } -func getHandlerFuncParams(ctx context.Context, cmd []string, conn *net.Conn) types.HandlerFuncParams { - return types.HandlerFuncParams{ +func getHandlerFuncParams(ctx context.Context, cmd []string, conn *net.Conn) internal.HandlerFuncParams { + return internal.HandlerFuncParams{ Context: ctx, Command: cmd, Connection: conn, diff --git a/test/modules/list/commands_test.go b/test/modules/list/commands_test.go index ff40a593..a2272d28 100644 --- a/test/modules/list/commands_test.go +++ b/test/modules/list/commands_test.go @@ -19,14 +19,16 @@ import ( "context" "errors" "fmt" + "github.com/echovault/echovault/internal" "github.com/echovault/echovault/internal/config" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/echovault" - "github.com/echovault/echovault/pkg/types" "github.com/tidwall/resp" "net" + "reflect" "strings" "testing" + "unsafe" ) var mockServer *echovault.EchoVault @@ -40,11 +42,17 @@ func init() { ) } -func getHandler(commands ...string) types.HandlerFunc { +func getUnexportedField(field reflect.Value) interface{} { + return reflect.NewAt(field.Type(), unsafe.Pointer(field.UnsafeAddr())).Elem().Interface() +} + +func getHandler(commands ...string) internal.HandlerFunc { if len(commands) == 0 { return nil } - for _, c := range mockServer.GetAllCommands() { + getCommands := + getUnexportedField(reflect.ValueOf(mockServer).Elem().FieldByName("getCommands")).(func() []internal.Command) + for _, c := range getCommands() { if strings.EqualFold(commands[0], c.Command) && len(commands) == 1 { // Get command handler return c.HandlerFunc @@ -61,8 +69,8 @@ func getHandler(commands ...string) types.HandlerFunc { return nil } -func getHandlerFuncParams(ctx context.Context, cmd []string, conn *net.Conn) types.HandlerFuncParams { - return types.HandlerFuncParams{ +func getHandlerFuncParams(ctx context.Context, cmd []string, conn *net.Conn) internal.HandlerFuncParams { + return internal.HandlerFuncParams{ Context: ctx, Command: cmd, Connection: conn, diff --git a/test/modules/pubsub/commands_test.go b/test/modules/pubsub/commands_test.go index a8874ed8..4774c8c0 100644 --- a/test/modules/pubsub/commands_test.go +++ b/test/modules/pubsub/commands_test.go @@ -18,18 +18,20 @@ import ( "bytes" "context" "fmt" + "github.com/echovault/echovault/internal" "github.com/echovault/echovault/internal/config" "github.com/echovault/echovault/internal/modules/pubsub" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/echovault" - "github.com/echovault/echovault/pkg/types" "github.com/tidwall/resp" "net" + "reflect" "slices" "strings" "sync" "testing" "time" + "unsafe" ) var ps *pubsub.PubSub @@ -40,7 +42,9 @@ var port uint16 = 7490 func init() { mockServer = setUpServer(bindAddr, port) - ps = mockServer.GetPubSub().(*pubsub.PubSub) + + getPubSub := getUnexportedField(reflect.ValueOf(mockServer).Elem().FieldByName("getPubSub")).(func() interface{}) + ps = getPubSub().(*pubsub.PubSub) wg := sync.WaitGroup{} wg.Add(1) @@ -63,11 +67,17 @@ func setUpServer(bindAddr string, port uint16) *echovault.EchoVault { return server } -func getHandler(commands ...string) types.HandlerFunc { +func getUnexportedField(field reflect.Value) interface{} { + return reflect.NewAt(field.Type(), unsafe.Pointer(field.UnsafeAddr())).Elem().Interface() +} + +func getHandler(commands ...string) internal.HandlerFunc { if len(commands) == 0 { return nil } - for _, c := range mockServer.GetAllCommands() { + getCommands := + getUnexportedField(reflect.ValueOf(mockServer).Elem().FieldByName("getCommands")).(func() []internal.Command) + for _, c := range getCommands() { if strings.EqualFold(commands[0], c.Command) && len(commands) == 1 { // Get command handler return c.HandlerFunc @@ -84,12 +94,14 @@ func getHandler(commands ...string) types.HandlerFunc { return nil } -func getHandlerFuncParams(ctx context.Context, cmd []string, conn *net.Conn, mockServer *echovault.EchoVault) types.HandlerFuncParams { - return types.HandlerFuncParams{ +func getHandlerFuncParams(ctx context.Context, cmd []string, conn *net.Conn, mockServer *echovault.EchoVault) internal.HandlerFuncParams { + getPubSub := + getUnexportedField(reflect.ValueOf(mockServer).Elem().FieldByName("getPubSub")).(func() interface{}) + return internal.HandlerFuncParams{ Context: ctx, Command: cmd, Connection: conn, - GetPubSub: mockServer.GetPubSub, + GetPubSub: getPubSub, } } diff --git a/test/modules/set/commands_test.go b/test/modules/set/commands_test.go index abb14ecf..5a107ab5 100644 --- a/test/modules/set/commands_test.go +++ b/test/modules/set/commands_test.go @@ -19,16 +19,18 @@ import ( "context" "errors" "fmt" + "github.com/echovault/echovault/internal" "github.com/echovault/echovault/internal/config" "github.com/echovault/echovault/internal/modules/set" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/echovault" - "github.com/echovault/echovault/pkg/types" "github.com/tidwall/resp" "net" + "reflect" "slices" "strings" "testing" + "unsafe" ) var mockServer *echovault.EchoVault @@ -42,11 +44,17 @@ func init() { ) } -func getHandler(commands ...string) types.HandlerFunc { +func getUnexportedField(field reflect.Value) interface{} { + return reflect.NewAt(field.Type(), unsafe.Pointer(field.UnsafeAddr())).Elem().Interface() +} + +func getHandler(commands ...string) internal.HandlerFunc { if len(commands) == 0 { return nil } - for _, c := range mockServer.GetAllCommands() { + getCommands := + getUnexportedField(reflect.ValueOf(mockServer).Elem().FieldByName("getCommands")).(func() []internal.Command) + for _, c := range getCommands() { if strings.EqualFold(commands[0], c.Command) && len(commands) == 1 { // Get command handler return c.HandlerFunc @@ -63,8 +71,8 @@ func getHandler(commands ...string) types.HandlerFunc { return nil } -func getHandlerFuncParams(ctx context.Context, cmd []string, conn *net.Conn) types.HandlerFuncParams { - return types.HandlerFuncParams{ +func getHandlerFuncParams(ctx context.Context, cmd []string, conn *net.Conn) internal.HandlerFuncParams { + return internal.HandlerFuncParams{ Context: ctx, Command: cmd, Connection: conn, diff --git a/test/modules/sorted_set/commands_test.go b/test/modules/sorted_set/commands_test.go index bfc31df2..bdf233ed 100644 --- a/test/modules/sorted_set/commands_test.go +++ b/test/modules/sorted_set/commands_test.go @@ -19,18 +19,20 @@ import ( "context" "errors" "fmt" + "github.com/echovault/echovault/internal" "github.com/echovault/echovault/internal/config" "github.com/echovault/echovault/internal/modules/sorted_set" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/echovault" - "github.com/echovault/echovault/pkg/types" "github.com/tidwall/resp" "math" "net" + "reflect" "slices" "strconv" "strings" "testing" + "unsafe" ) var mockServer *echovault.EchoVault @@ -44,11 +46,17 @@ func init() { ) } -func getHandler(commands ...string) types.HandlerFunc { +func getUnexportedField(field reflect.Value) interface{} { + return reflect.NewAt(field.Type(), unsafe.Pointer(field.UnsafeAddr())).Elem().Interface() +} + +func getHandler(commands ...string) internal.HandlerFunc { if len(commands) == 0 { return nil } - for _, c := range mockServer.GetAllCommands() { + getCommands := + getUnexportedField(reflect.ValueOf(mockServer).Elem().FieldByName("getCommands")).(func() []internal.Command) + for _, c := range getCommands() { if strings.EqualFold(commands[0], c.Command) && len(commands) == 1 { // Get command handler return c.HandlerFunc @@ -65,8 +73,8 @@ func getHandler(commands ...string) types.HandlerFunc { return nil } -func getHandlerFuncParams(ctx context.Context, cmd []string, conn *net.Conn) types.HandlerFuncParams { - return types.HandlerFuncParams{ +func getHandlerFuncParams(ctx context.Context, cmd []string, conn *net.Conn) internal.HandlerFuncParams { + return internal.HandlerFuncParams{ Context: ctx, Command: cmd, Connection: conn, diff --git a/test/modules/string/commands_test.go b/test/modules/string/commands_test.go index 296501d0..5eac8292 100644 --- a/test/modules/string/commands_test.go +++ b/test/modules/string/commands_test.go @@ -23,12 +23,13 @@ import ( "github.com/echovault/echovault/internal/config" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/echovault" - "github.com/echovault/echovault/pkg/types" "github.com/tidwall/resp" "net" + "reflect" "strconv" "strings" "testing" + "unsafe" ) var mockServer *echovault.EchoVault @@ -42,11 +43,17 @@ func init() { ) } -func getHandler(commands ...string) types.HandlerFunc { +func getUnexportedField(field reflect.Value) interface{} { + return reflect.NewAt(field.Type(), unsafe.Pointer(field.UnsafeAddr())).Elem().Interface() +} + +func getHandler(commands ...string) internal.HandlerFunc { if len(commands) == 0 { return nil } - for _, c := range mockServer.GetAllCommands() { + getCommands := + getUnexportedField(reflect.ValueOf(mockServer).Elem().FieldByName("getCommands")).(func() []internal.Command) + for _, c := range getCommands() { if strings.EqualFold(commands[0], c.Command) && len(commands) == 1 { // Get command handler return c.HandlerFunc @@ -63,8 +70,8 @@ func getHandler(commands ...string) types.HandlerFunc { return nil } -func getHandlerFuncParams(ctx context.Context, cmd []string, conn *net.Conn) types.HandlerFuncParams { - return types.HandlerFuncParams{ +func getHandlerFuncParams(ctx context.Context, cmd []string, conn *net.Conn) internal.HandlerFuncParams { + return internal.HandlerFuncParams{ Context: ctx, Command: cmd, Connection: conn,