From 281c4f27a78bdbfee889624c6e2da534c997571d Mon Sep 17 00:00:00 2001 From: Kelvin Clement Mwinuka Date: Mon, 29 Apr 2024 15:20:10 +0800 Subject: [PATCH] Added godoc commends for embedded methods and types to extend commands. Moved constants to internal directory --- echovault/api_admin.go | 113 +++++++++++++++++---- echovault/echovault.go | 2 +- echovault/keyspace.go | 2 +- echovault/modules.go | 2 +- internal/config/config.go | 2 +- internal/config/default.go | 2 +- {constants => internal/constants}/const.go | 0 internal/modules/acl/acl.go | 2 +- internal/modules/acl/commands.go | 2 +- internal/modules/admin/commands.go | 2 +- internal/modules/connection/commands.go | 2 +- internal/modules/generic/commands.go | 2 +- internal/modules/generic/key_funcs.go | 2 +- internal/modules/hash/commands.go | 2 +- internal/modules/hash/key_funcs.go | 2 +- internal/modules/list/commands.go | 2 +- internal/modules/list/key_funcs.go | 2 +- internal/modules/pubsub/commands.go | 2 +- internal/modules/set/commands.go | 2 +- internal/modules/set/key_funcs.go | 2 +- internal/modules/sorted_set/commands.go | 2 +- internal/modules/sorted_set/key_funcs.go | 2 +- internal/modules/string/commands.go | 2 +- internal/modules/string/key_funcs.go | 2 +- internal/utils.go | 2 +- test/modules/acl/commands_test.go | 2 +- test/modules/admin/api_test.go | 24 ++--- test/modules/admin/commands_test.go | 2 +- test/modules/connection/commands_test.go | 2 +- test/modules/generic/commands_test.go | 2 +- test/modules/hash/commands_test.go | 2 +- test/modules/list/commands_test.go | 2 +- test/modules/pubsub/commands_test.go | 2 +- test/modules/set/commands_test.go | 2 +- test/modules/sorted_set/commands_test.go | 2 +- test/modules/string/commands_test.go | 2 +- types/types.go | 59 +++++++++-- 37 files changed, 187 insertions(+), 75 deletions(-) rename {constants => internal/constants}/const.go (100%) diff --git a/echovault/api_admin.go b/echovault/api_admin.go index 7c8c7bbe..2b815b9a 100644 --- a/echovault/api_admin.go +++ b/echovault/api_admin.go @@ -35,7 +35,28 @@ type CommandListOptions struct { MODULE string } -// TODO: Write godoc comment for CommandOptions type +// CommandOptions provides the specification of the command to be added to the EchoVault instance. +// +// Command is the keyword used to trigger this command (e.g. LPUSH, ZADD, ACL ...). +// +// Module is a string that classifies a group of commands. +// +// Categories is a string slice of all the categories that this command belongs to. +// +// Description is a string describing the command, can include an example of how to trigger the command. +// +// SubCommand is a slice of subcommands for this command. +// +// Sync is a boolean value that determines whether this command should be synced across a replication cluster. +// If subcommands are specified, each subcommand will override this value for its own execution. +// +// KeyExtractionFunc is a function that extracts the keys from the command if the command accesses any keys. +// the extracted keys are used by the ACL layer to determine whether a TCP client is authorized to execute this command. +// If subcommands are specified, this function is discarded and each subcommands must implement its own KeyExtractionFunc. +// +// HandlerFunc is the command handler. This function must return a valid RESP2 response as it the command will be +// available to RESP clients. If subcommands are specified, this function is discarded and each subcommand must implement +// its own HandlerFunc. type CommandOptions struct { Command string Module string @@ -43,19 +64,36 @@ type CommandOptions struct { Description string SubCommand []SubCommandOptions Sync bool - KeyExtractionFunc types.PluginKeyExtractionFunc - HandlerFunc types.PluginHandlerFunc + KeyExtractionFunc types.CommandKeyExtractionFunc + HandlerFunc types.CommandHandlerFunc } -// TODO: Write godoc comment for SubCommandOptions type +// SubCommandOptions provides the specification of a subcommand within CommandOptions. +// +// Command is the keyword used to trigger this subcommand (e.g. "CAT" for the subcommand "ACL CAT"). +// +// Module is a string that classifies a group of commands/subcommands. +// +// Categories is a string slice of all the categories that this subcommand belongs to. +// +// Description is a string describing the subcommand, can include an example of how to trigger the subcommand. +// +// Sync is a boolean value that determines whether this subcommand should be synced across a replication cluster. +// This value overrides the Sync value set by the parent command. It's possible to have some synced and un-synced +// subcommands with the same parent command regardless of the parent's Sync value. +// +// KeyExtractionFunc is a function that extracts the keys from the subcommand if it accesses any keys. +// +// HandlerFunc is the subcommand handler. This function must return a valid RESP2 response as it will be +// available to RESP clients. type SubCommandOptions struct { Command string Module string Categories []string Description string Sync bool - KeyExtractionFunc types.PluginKeyExtractionFunc - HandlerFunc types.PluginHandlerFunc + KeyExtractionFunc types.CommandKeyExtractionFunc + HandlerFunc types.CommandHandlerFunc } // CommandList returns the list of commands currently loaded in the EchoVault instance. @@ -123,7 +161,15 @@ func (server *EchoVault) RewriteAOF() (string, error) { return internal.ParseStringResponse(b) } -// TODO: Write godoc comment for AddCommand method +// AddCommand adds a new command to EchoVault. The added command can be executed using the ExecuteCommand method. +// +// Parameters: +// +// `command` - CommandOptions. +// +// Errors: +// +// "command already exists" - If a command with the same command name as the passed command already exists. func (server *EchoVault) AddCommand(command CommandOptions) error { // Check if command already exists for _, c := range server.commands { @@ -159,7 +205,7 @@ func (server *EchoVault) AddCommand(command CommandOptions) error { }, nil }), HandlerFunc: internal.HandlerFunc(func(params internal.HandlerFuncParams) ([]byte, error) { - return command.HandlerFunc(types.PluginHandlerFuncParams{ + return command.HandlerFunc(types.CommandHandlerFuncParams{ Context: params.Context, Command: params.Command, Connection: params.Connection, @@ -171,10 +217,6 @@ func (server *EchoVault) AddCommand(command CommandOptions) error { CreateKeyAndLock: params.CreateKeyAndLock, GetValue: params.GetValue, SetValue: params.SetValue, - GetExpiry: params.GetExpiry, - SetExpiry: params.SetExpiry, - RemoveExpiry: params.RemoveExpiry, - DeleteKey: params.DeleteKey, }) }), }) @@ -234,7 +276,7 @@ func (server *EchoVault) AddCommand(command CommandOptions) error { }, nil }), HandlerFunc: internal.HandlerFunc(func(params internal.HandlerFuncParams) ([]byte, error) { - return sc.HandlerFunc(types.PluginHandlerFuncParams{ + return sc.HandlerFunc(types.CommandHandlerFuncParams{ Context: params.Context, Command: params.Command, Connection: params.Connection, @@ -246,10 +288,6 @@ func (server *EchoVault) AddCommand(command CommandOptions) error { CreateKeyAndLock: params.CreateKeyAndLock, GetValue: params.GetValue, SetValue: params.SetValue, - GetExpiry: params.GetExpiry, - SetExpiry: params.SetExpiry, - RemoveExpiry: params.RemoveExpiry, - DeleteKey: params.DeleteKey, }) }), } @@ -260,12 +298,47 @@ func (server *EchoVault) AddCommand(command CommandOptions) error { return nil } -// TODO: Write godoc comment for ExecuteCommand method -func (server *EchoVault) ExecuteCommand(command []string) ([]byte, error) { +// ExecuteCommand executes the command passed to it. If 1 string is passed, EchoVault will try to +// execute the command. If 2 strings are passed, EchoVault will attempt to execute the subcommand of the command. +// If more than 2 strings are provided, all additional strings will be ignored. +// +// This method returns the raw RESP response from the command handler. You will have to parse the RESP response if +// you want to use the return value from the handler. +// +// This method does not work with handlers that manipulate the client connection directly (i.e SUBSCRIBE, PSUBSCRIBE). +// If you'd like to (p)subscribe or (p)unsubscribe, use the (P)SUBSCRIBE and (P)UNSUBSCRIBE methods instead. +// +// Parameters: +// +// `command` - ...string. +// +// Returns: []byte - Raw RESP response returned by the command handler. +// +// Errors: +// +// All errors from the command handler are forwarded to the caller. Other errors returned include: +// +// "command not supported" - If the command does not exist. +// +// "command not supported" - If the command exists but the subcommand does not exist for that command. +func (server *EchoVault) ExecuteCommand(command ...string) ([]byte, error) { return server.handleCommand(server.context, internal.EncodeCommand(command), nil, false, true) } -// TODO: Write godoc commend for RemoveCommand method +// RemoveCommand removes the specified command or subcommand from EchoVault. +// When commands are removed, they will no longer be available for both the embedded instance and for TCP clients. +// +// Note: If a command is removed, the API wrapper for the command will also be unusable. +// For example, calling RemoveCommand("LPUSH") will cause the LPUSH method to always return a +// "command LPUSH not supported" error so use this method with caution. +// +// If one string is passed, the command matching that string is removed along will all of its subcommand if it has any. +// If two strings are passed, only the subcommand of the specified command is removed. +// If more than 2 strings are passed, all additional strings are ignored. +// +// Parameters: +// +// `command` - ...string. func (server *EchoVault) RemoveCommand(command ...string) { switch len(command) { case 1: diff --git a/echovault/echovault.go b/echovault/echovault.go index 180ea7e2..97313198 100644 --- a/echovault/echovault.go +++ b/echovault/echovault.go @@ -20,11 +20,11 @@ import ( "crypto/x509" "errors" "fmt" - "github.com/echovault/echovault/constants" "github.com/echovault/echovault/internal" "github.com/echovault/echovault/internal/aof" "github.com/echovault/echovault/internal/clock" "github.com/echovault/echovault/internal/config" + "github.com/echovault/echovault/internal/constants" "github.com/echovault/echovault/internal/eviction" "github.com/echovault/echovault/internal/memberlist" "github.com/echovault/echovault/internal/modules/acl" diff --git a/echovault/keyspace.go b/echovault/keyspace.go index fcfdf9ce..3dbbb4d2 100644 --- a/echovault/keyspace.go +++ b/echovault/keyspace.go @@ -18,8 +18,8 @@ import ( "context" "errors" "fmt" - "github.com/echovault/echovault/constants" "github.com/echovault/echovault/internal" + "github.com/echovault/echovault/internal/constants" "log" "math/rand" "runtime" diff --git a/echovault/modules.go b/echovault/modules.go index 96b90b4b..a13aa412 100644 --- a/echovault/modules.go +++ b/echovault/modules.go @@ -18,8 +18,8 @@ import ( "context" "errors" "fmt" - "github.com/echovault/echovault/constants" "github.com/echovault/echovault/internal" + "github.com/echovault/echovault/internal/constants" "net" "strings" ) diff --git a/internal/config/config.go b/internal/config/config.go index 3f817baa..205b047a 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -19,8 +19,8 @@ import ( "errors" "flag" "fmt" - "github.com/echovault/echovault/constants" "github.com/echovault/echovault/internal" + "github.com/echovault/echovault/internal/constants" "log" "os" "path" diff --git a/internal/config/default.go b/internal/config/default.go index bfe4fd74..e50c2171 100644 --- a/internal/config/default.go +++ b/internal/config/default.go @@ -1,7 +1,7 @@ package config import ( - "github.com/echovault/echovault/constants" + "github.com/echovault/echovault/internal/constants" "time" ) diff --git a/constants/const.go b/internal/constants/const.go similarity index 100% rename from constants/const.go rename to internal/constants/const.go diff --git a/internal/modules/acl/acl.go b/internal/modules/acl/acl.go index e79ea58f..5dc7d644 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/constants" "github.com/echovault/echovault/internal" "github.com/echovault/echovault/internal/config" + "github.com/echovault/echovault/internal/constants" "github.com/gobwas/glob" "gopkg.in/yaml.v3" "log" diff --git a/internal/modules/acl/commands.go b/internal/modules/acl/commands.go index 258a7cd1..e155ed67 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/constants" "github.com/echovault/echovault/internal" + "github.com/echovault/echovault/internal/constants" "gopkg.in/yaml.v3" "log" "os" diff --git a/internal/modules/admin/commands.go b/internal/modules/admin/commands.go index e89f2cf4..18591ba2 100644 --- a/internal/modules/admin/commands.go +++ b/internal/modules/admin/commands.go @@ -17,8 +17,8 @@ package admin import ( "errors" "fmt" - "github.com/echovault/echovault/constants" "github.com/echovault/echovault/internal" + "github.com/echovault/echovault/internal/constants" "github.com/gobwas/glob" "slices" "strings" diff --git a/internal/modules/connection/commands.go b/internal/modules/connection/commands.go index 47c523d4..03312838 100644 --- a/internal/modules/connection/commands.go +++ b/internal/modules/connection/commands.go @@ -17,8 +17,8 @@ package connection import ( "errors" "fmt" - "github.com/echovault/echovault/constants" "github.com/echovault/echovault/internal" + "github.com/echovault/echovault/internal/constants" ) func handlePing(params internal.HandlerFuncParams) ([]byte, error) { diff --git a/internal/modules/generic/commands.go b/internal/modules/generic/commands.go index 5ac18637..9c1ae96a 100644 --- a/internal/modules/generic/commands.go +++ b/internal/modules/generic/commands.go @@ -17,8 +17,8 @@ package generic import ( "errors" "fmt" - "github.com/echovault/echovault/constants" "github.com/echovault/echovault/internal" + "github.com/echovault/echovault/internal/constants" "log" "strconv" "strings" diff --git a/internal/modules/generic/key_funcs.go b/internal/modules/generic/key_funcs.go index 6b9c2399..875c34a4 100644 --- a/internal/modules/generic/key_funcs.go +++ b/internal/modules/generic/key_funcs.go @@ -16,8 +16,8 @@ package generic import ( "errors" - "github.com/echovault/echovault/constants" "github.com/echovault/echovault/internal" + "github.com/echovault/echovault/internal/constants" ) func setKeyFunc(cmd []string) (internal.KeyExtractionFuncResult, error) { diff --git a/internal/modules/hash/commands.go b/internal/modules/hash/commands.go index 60fe7930..5924321b 100644 --- a/internal/modules/hash/commands.go +++ b/internal/modules/hash/commands.go @@ -17,8 +17,8 @@ package hash import ( "errors" "fmt" - "github.com/echovault/echovault/constants" "github.com/echovault/echovault/internal" + "github.com/echovault/echovault/internal/constants" "math/rand" "slices" "strconv" diff --git a/internal/modules/hash/key_funcs.go b/internal/modules/hash/key_funcs.go index ee96b6a4..e259c208 100644 --- a/internal/modules/hash/key_funcs.go +++ b/internal/modules/hash/key_funcs.go @@ -16,8 +16,8 @@ package hash import ( "errors" - "github.com/echovault/echovault/constants" "github.com/echovault/echovault/internal" + "github.com/echovault/echovault/internal/constants" ) func hsetKeyFunc(cmd []string) (internal.KeyExtractionFuncResult, error) { diff --git a/internal/modules/list/commands.go b/internal/modules/list/commands.go index 618086a8..33f3a6a3 100644 --- a/internal/modules/list/commands.go +++ b/internal/modules/list/commands.go @@ -17,8 +17,8 @@ package list import ( "errors" "fmt" - "github.com/echovault/echovault/constants" "github.com/echovault/echovault/internal" + "github.com/echovault/echovault/internal/constants" "math" "slices" "strings" diff --git a/internal/modules/list/key_funcs.go b/internal/modules/list/key_funcs.go index c0c8cd8a..7a855e3a 100644 --- a/internal/modules/list/key_funcs.go +++ b/internal/modules/list/key_funcs.go @@ -16,8 +16,8 @@ package list import ( "errors" - "github.com/echovault/echovault/constants" "github.com/echovault/echovault/internal" + "github.com/echovault/echovault/internal/constants" ) func lpushKeyFunc(cmd []string) (internal.KeyExtractionFuncResult, error) { diff --git a/internal/modules/pubsub/commands.go b/internal/modules/pubsub/commands.go index 6743d764..eb8e1b27 100644 --- a/internal/modules/pubsub/commands.go +++ b/internal/modules/pubsub/commands.go @@ -17,8 +17,8 @@ package pubsub import ( "errors" "fmt" - "github.com/echovault/echovault/constants" "github.com/echovault/echovault/internal" + "github.com/echovault/echovault/internal/constants" "strings" ) diff --git a/internal/modules/set/commands.go b/internal/modules/set/commands.go index 52591aea..ba19e1f8 100644 --- a/internal/modules/set/commands.go +++ b/internal/modules/set/commands.go @@ -17,8 +17,8 @@ package set import ( "errors" "fmt" - "github.com/echovault/echovault/constants" "github.com/echovault/echovault/internal" + "github.com/echovault/echovault/internal/constants" "slices" "strings" ) diff --git a/internal/modules/set/key_funcs.go b/internal/modules/set/key_funcs.go index ed08d3ea..391f8462 100644 --- a/internal/modules/set/key_funcs.go +++ b/internal/modules/set/key_funcs.go @@ -16,8 +16,8 @@ package set import ( "errors" - "github.com/echovault/echovault/constants" "github.com/echovault/echovault/internal" + "github.com/echovault/echovault/internal/constants" "slices" "strings" ) diff --git a/internal/modules/sorted_set/commands.go b/internal/modules/sorted_set/commands.go index e43a5b4c..9af3d076 100644 --- a/internal/modules/sorted_set/commands.go +++ b/internal/modules/sorted_set/commands.go @@ -18,8 +18,8 @@ import ( "cmp" "errors" "fmt" - "github.com/echovault/echovault/constants" "github.com/echovault/echovault/internal" + "github.com/echovault/echovault/internal/constants" "math" "slices" "strconv" diff --git a/internal/modules/sorted_set/key_funcs.go b/internal/modules/sorted_set/key_funcs.go index a434fd59..8c9a5cbf 100644 --- a/internal/modules/sorted_set/key_funcs.go +++ b/internal/modules/sorted_set/key_funcs.go @@ -16,8 +16,8 @@ package sorted_set import ( "errors" - "github.com/echovault/echovault/constants" "github.com/echovault/echovault/internal" + "github.com/echovault/echovault/internal/constants" "slices" "strings" ) diff --git a/internal/modules/string/commands.go b/internal/modules/string/commands.go index a70c36f8..b4662282 100644 --- a/internal/modules/string/commands.go +++ b/internal/modules/string/commands.go @@ -17,8 +17,8 @@ package str import ( "errors" "fmt" - "github.com/echovault/echovault/constants" "github.com/echovault/echovault/internal" + "github.com/echovault/echovault/internal/constants" ) func handleSetRange(params internal.HandlerFuncParams) ([]byte, error) { diff --git a/internal/modules/string/key_funcs.go b/internal/modules/string/key_funcs.go index a33c6657..960e784e 100644 --- a/internal/modules/string/key_funcs.go +++ b/internal/modules/string/key_funcs.go @@ -16,8 +16,8 @@ package str import ( "errors" - "github.com/echovault/echovault/constants" "github.com/echovault/echovault/internal" + "github.com/echovault/echovault/internal/constants" ) func setRangeKeyFunc(cmd []string) (internal.KeyExtractionFuncResult, error) { diff --git a/internal/utils.go b/internal/utils.go index 6eab940f..e7ef6081 100644 --- a/internal/utils.go +++ b/internal/utils.go @@ -20,7 +20,7 @@ import ( "cmp" "errors" "fmt" - "github.com/echovault/echovault/constants" + "github.com/echovault/echovault/internal/constants" "io" "log" "math/big" diff --git a/test/modules/acl/commands_test.go b/test/modules/acl/commands_test.go index 50e64710..bb0d9b82 100644 --- a/test/modules/acl/commands_test.go +++ b/test/modules/acl/commands_test.go @@ -17,9 +17,9 @@ package acl import ( "crypto/sha256" "fmt" - "github.com/echovault/echovault/constants" "github.com/echovault/echovault/echovault" "github.com/echovault/echovault/internal/config" + "github.com/echovault/echovault/internal/constants" "github.com/echovault/echovault/internal/modules/acl" "github.com/tidwall/resp" "net" diff --git a/test/modules/admin/api_test.go b/test/modules/admin/api_test.go index 73b527a3..1eabe9ad 100644 --- a/test/modules/admin/api_test.go +++ b/test/modules/admin/api_test.go @@ -18,9 +18,9 @@ import ( "bytes" "errors" "fmt" - "github.com/echovault/echovault/constants" "github.com/echovault/echovault/echovault" "github.com/echovault/echovault/internal/config" + "github.com/echovault/echovault/internal/constants" "github.com/echovault/echovault/types" "github.com/tidwall/resp" "strconv" @@ -64,16 +64,16 @@ Test command to handle successful addition of a single command without subcomman The value passed must be an integer.`, Categories: []string{}, Sync: false, - KeyExtractionFunc: func(cmd []string) (types.PluginKeyExtractionFuncResult, error) { + KeyExtractionFunc: func(cmd []string) (types.CommandKeyExtractionFuncResult, error) { if len(cmd) != 4 { - return types.PluginKeyExtractionFuncResult{}, errors.New(constants.WrongArgsResponse) + return types.CommandKeyExtractionFuncResult{}, errors.New(constants.WrongArgsResponse) } - return types.PluginKeyExtractionFuncResult{ + return types.CommandKeyExtractionFuncResult{ WriteKeys: cmd[1:2], ReadKeys: cmd[2:3], }, nil }, - HandlerFunc: func(params types.PluginHandlerFuncParams) ([]byte, error) { + HandlerFunc: func(params types.CommandHandlerFuncParams) ([]byte, error) { if len(params.Command) != 4 { return nil, errors.New(constants.WrongArgsResponse) } @@ -128,16 +128,16 @@ Test command to handle successful addition of a single command with subcommands. The value passed must be an integer.`, Categories: []string{}, Sync: false, - KeyExtractionFunc: func(cmd []string) (types.PluginKeyExtractionFuncResult, error) { + KeyExtractionFunc: func(cmd []string) (types.CommandKeyExtractionFuncResult, error) { if len(cmd) != 5 { - return types.PluginKeyExtractionFuncResult{}, errors.New(constants.WrongArgsResponse) + return types.CommandKeyExtractionFuncResult{}, errors.New(constants.WrongArgsResponse) } - return types.PluginKeyExtractionFuncResult{ + return types.CommandKeyExtractionFuncResult{ WriteKeys: cmd[2:3], ReadKeys: cmd[3:4], }, nil }, - HandlerFunc: func(params types.PluginHandlerFuncParams) ([]byte, error) { + HandlerFunc: func(params types.CommandHandlerFuncParams) ([]byte, error) { if len(params.Command) != 5 { return nil, errors.New(constants.WrongArgsResponse) } @@ -187,7 +187,7 @@ The value passed must be an integer.`, t.Errorf("AddCommand() error = %v, wantErr %v", err, tt.wantErr) } for _, scenario := range tt.scenarios { - b, err := server.ExecuteCommand(scenario.command) + b, err := server.ExecuteCommand(scenario.command...) if scenario.wantErr != nil { if scenario.wantErr.Error() != err.Error() { t.Errorf("AddCommand() error = %v, wantErr %v", err, scenario.wantErr) @@ -243,7 +243,7 @@ func TestEchoVault_ExecuteCommand(t *testing.T) { if tt.args.presetValue != nil { _, _ = server.LPush(tt.args.key, tt.args.presetValue...) } - b, err := server.ExecuteCommand(tt.args.command) + b, err := server.ExecuteCommand(tt.args.command...) if tt.wantErr != nil { if err.Error() != tt.wantErr.Error() { t.Errorf("ExecuteCommand() error = %v, wantErr %v", err, tt.wantErr) @@ -298,7 +298,7 @@ func TestEchoVault_RemoveCommand(t *testing.T) { server := createEchoVault() t.Run(tt.name, func(t *testing.T) { server.RemoveCommand(tt.args.removeCommand...) - _, err := server.ExecuteCommand(tt.args.executeCommand) + _, err := server.ExecuteCommand(tt.args.executeCommand...) if tt.wantErr != nil { if err.Error() != tt.wantErr.Error() { t.Errorf("RemoveCommand() error = %v, wantErr %v", err, tt.wantErr) diff --git a/test/modules/admin/commands_test.go b/test/modules/admin/commands_test.go index 2e577924..c4e932cc 100644 --- a/test/modules/admin/commands_test.go +++ b/test/modules/admin/commands_test.go @@ -18,10 +18,10 @@ import ( "bytes" "context" "fmt" - "github.com/echovault/echovault/constants" "github.com/echovault/echovault/echovault" "github.com/echovault/echovault/internal" "github.com/echovault/echovault/internal/config" + "github.com/echovault/echovault/internal/constants" "github.com/tidwall/resp" "net" "reflect" diff --git a/test/modules/connection/commands_test.go b/test/modules/connection/commands_test.go index 5d05d6b5..8d1e08fc 100644 --- a/test/modules/connection/commands_test.go +++ b/test/modules/connection/commands_test.go @@ -18,10 +18,10 @@ import ( "bytes" "context" "errors" - "github.com/echovault/echovault/constants" "github.com/echovault/echovault/echovault" "github.com/echovault/echovault/internal" "github.com/echovault/echovault/internal/config" + "github.com/echovault/echovault/internal/constants" "github.com/tidwall/resp" "net" "reflect" diff --git a/test/modules/generic/commands_test.go b/test/modules/generic/commands_test.go index 523d2e7a..d73df9c4 100644 --- a/test/modules/generic/commands_test.go +++ b/test/modules/generic/commands_test.go @@ -19,11 +19,11 @@ import ( "context" "errors" "fmt" - "github.com/echovault/echovault/constants" "github.com/echovault/echovault/echovault" "github.com/echovault/echovault/internal" "github.com/echovault/echovault/internal/clock" "github.com/echovault/echovault/internal/config" + "github.com/echovault/echovault/internal/constants" "github.com/tidwall/resp" "net" "reflect" diff --git a/test/modules/hash/commands_test.go b/test/modules/hash/commands_test.go index b85d467a..f2fe29a1 100644 --- a/test/modules/hash/commands_test.go +++ b/test/modules/hash/commands_test.go @@ -19,10 +19,10 @@ import ( "context" "errors" "fmt" - "github.com/echovault/echovault/constants" "github.com/echovault/echovault/echovault" "github.com/echovault/echovault/internal" "github.com/echovault/echovault/internal/config" + "github.com/echovault/echovault/internal/constants" "github.com/tidwall/resp" "net" "reflect" diff --git a/test/modules/list/commands_test.go b/test/modules/list/commands_test.go index 93862c70..f748cf4b 100644 --- a/test/modules/list/commands_test.go +++ b/test/modules/list/commands_test.go @@ -19,10 +19,10 @@ import ( "context" "errors" "fmt" - "github.com/echovault/echovault/constants" "github.com/echovault/echovault/echovault" "github.com/echovault/echovault/internal" "github.com/echovault/echovault/internal/config" + "github.com/echovault/echovault/internal/constants" "github.com/tidwall/resp" "net" "reflect" diff --git a/test/modules/pubsub/commands_test.go b/test/modules/pubsub/commands_test.go index e78530c7..72febf19 100644 --- a/test/modules/pubsub/commands_test.go +++ b/test/modules/pubsub/commands_test.go @@ -18,10 +18,10 @@ import ( "bytes" "context" "fmt" - "github.com/echovault/echovault/constants" "github.com/echovault/echovault/echovault" "github.com/echovault/echovault/internal" "github.com/echovault/echovault/internal/config" + "github.com/echovault/echovault/internal/constants" "github.com/echovault/echovault/internal/modules/pubsub" "github.com/tidwall/resp" "net" diff --git a/test/modules/set/commands_test.go b/test/modules/set/commands_test.go index 0b449d9d..b6305f89 100644 --- a/test/modules/set/commands_test.go +++ b/test/modules/set/commands_test.go @@ -19,10 +19,10 @@ import ( "context" "errors" "fmt" - "github.com/echovault/echovault/constants" "github.com/echovault/echovault/echovault" "github.com/echovault/echovault/internal" "github.com/echovault/echovault/internal/config" + "github.com/echovault/echovault/internal/constants" "github.com/echovault/echovault/internal/modules/set" "github.com/tidwall/resp" "net" diff --git a/test/modules/sorted_set/commands_test.go b/test/modules/sorted_set/commands_test.go index 5255b043..0ae5a4c8 100644 --- a/test/modules/sorted_set/commands_test.go +++ b/test/modules/sorted_set/commands_test.go @@ -19,10 +19,10 @@ import ( "context" "errors" "fmt" - "github.com/echovault/echovault/constants" "github.com/echovault/echovault/echovault" "github.com/echovault/echovault/internal" "github.com/echovault/echovault/internal/config" + "github.com/echovault/echovault/internal/constants" "github.com/echovault/echovault/internal/modules/sorted_set" "github.com/tidwall/resp" "math" diff --git a/test/modules/string/commands_test.go b/test/modules/string/commands_test.go index 45601791..b92aba0d 100644 --- a/test/modules/string/commands_test.go +++ b/test/modules/string/commands_test.go @@ -19,10 +19,10 @@ import ( "context" "errors" "fmt" - "github.com/echovault/echovault/constants" "github.com/echovault/echovault/echovault" "github.com/echovault/echovault/internal" "github.com/echovault/echovault/internal/config" + "github.com/echovault/echovault/internal/constants" "github.com/tidwall/resp" "net" "reflect" diff --git a/types/types.go b/types/types.go index 19f9d632..2e421b60 100644 --- a/types/types.go +++ b/types/types.go @@ -35,27 +35,66 @@ type EchoVault interface { DeleteKey(ctx context.Context, key string) error } -type PluginKeyExtractionFuncResult struct { +// CommandKeyExtractionFuncResult specifies the keys accessed by the associated command or subcommand. +// ReadKeys is a string slice containing the keys that the commands read from. +// WriteKeys is a string slice containing the keys that the command writes to. +// +// These keys will typically be extracted from the command slice, but they can also be hardcoded. +type CommandKeyExtractionFuncResult struct { ReadKeys []string WriteKeys []string } -type PluginKeyExtractionFunc func(cmd []string) (PluginKeyExtractionFuncResult, error) -type PluginHandlerFunc func(params PluginHandlerFuncParams) ([]byte, error) -type PluginHandlerFuncParams struct { +// CommandKeyExtractionFunc if the function that extracts the keys accessed by the command or subcommand. +type CommandKeyExtractionFunc func(cmd []string) (CommandKeyExtractionFuncResult, error) + +// CommandHandlerFunc is the handler function for the command or subcommand. +// +// This function must return a byte slice containing a valid RESP2 response, or an error. +type CommandHandlerFunc func(params CommandHandlerFuncParams) ([]byte, error) + +// CommandHandlerFuncParams contains the helper parameters passed to the command's handler by EchoVault. +// +// Command is the string slice command containing the command that triggered this handler. +// +// Connection is the TCP connection that triggered this command. In embedded mode, this will always be nil. +// Any TCP client that trigger the custom command will have its connection passed to the handler here. +// +// KeyExists returns true if the key passed to it exists in the store. +// +// CreateKeyAndLock creates the new key and immediately write locks it. If the key already exists, then +// it is simply write locked which makes this function safe to call even if the key already exists. Always call +// KeyUnlock when done after CreateKeyAndLock. +// +// KeyLock acquires a write lock for the specified key. If the lock is successfully acquired, the function will return +// (true, nil). Otherwise, it will return false and an error describing why the locking failed. Always call KeyUnlock +// when done after KeyLock. +// +// KeyUnlock releases the write lock for the specified key. Always call this after KeyLock otherwise the key will not be +// lockable by any future invocations of this command or other commands. +// +// KeyRLock acquires a read lock for the specified key. If the lock is successfully acquired, the function will return +// (true, nil). Otherwise, it will return false and an error describing why the locking failed. Always call KeyRUnlock +// when done after KeyRLock. +// +// KeyRUnlock releases the real lock for the specified key. Always call this after KeyRLock otherwise the key will not be +// write-lockable by any future invocations of this command or other commands. +// +// GetValue returns the value held at the specified key as an interface{}. Make sure to invoke KeyLock or KeyRLock on the +// key before GetValue to ensure thread safety. +// +// SetValue sets the value at the specified key. Make sure to invoke KeyLock on the key before +// SetValue to ensure thread safety. +type CommandHandlerFuncParams struct { Context context.Context Command []string Connection *net.Conn + KeyExists func(ctx context.Context, key string) bool + CreateKeyAndLock func(ctx context.Context, key string) (bool, error) 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 }