diff options
| author | alex <[email protected]> | 2026-07-12 13:48:32 +0200 |
|---|---|---|
| committer | alex <[email protected]> | 2026-07-12 13:48:32 +0200 |
| commit | 89b3019a3ab77a3e72720342fc0e5bea996fa4f2 (patch) | |
| tree | ed9482c87ff2eaa52ba8359654e0e923a4732e30 /pkg/commands | |
| parent | 80100f574d8cf6c231217678356324d8ffa7140f (diff) | |
| download | redis-clone-89b3019a3ab77a3e72720342fc0e5bea996fa4f2.tar.xz redis-clone-89b3019a3ab77a3e72720342fc0e5bea996fa4f2.zip | |
refactored all functions to use the command registry
Diffstat (limited to 'pkg/commands')
| -rw-r--r-- | pkg/commands/command-registry.go | 73 | ||||
| -rw-r--r-- | pkg/commands/dbsize.go | 15 | ||||
| -rw-r--r-- | pkg/commands/expire.go | 26 | ||||
| -rw-r--r-- | pkg/commands/flushall.go | 14 | ||||
| -rw-r--r-- | pkg/commands/hget.go | 25 | ||||
| -rw-r--r-- | pkg/commands/hgetall.go | 20 | ||||
| -rw-r--r-- | pkg/commands/hkeys.go | 24 | ||||
| -rw-r--r-- | pkg/commands/hset.go | 32 | ||||
| -rw-r--r-- | pkg/commands/hvalues.go | 24 | ||||
| -rw-r--r-- | pkg/commands/keys.go | 41 | ||||
| -rw-r--r-- | pkg/commands/lrem.go | 75 | ||||
| -rw-r--r-- | pkg/commands/ping.go | 16 | ||||
| -rw-r--r-- | pkg/commands/type.go | 24 |
13 files changed, 408 insertions, 1 deletions
diff --git a/pkg/commands/command-registry.go b/pkg/commands/command-registry.go index baf7133..068fe7c 100644 --- a/pkg/commands/command-registry.go +++ b/pkg/commands/command-registry.go @@ -4,6 +4,13 @@ import ( "errors" "redisClone/pkg/core" ) + +var dbInstance core.RedisDB + +func SetDB(db core.RedisDB) { + dbInstance = db +} + func SingleKey(args []string) []string { return []string{args[1]} } @@ -16,6 +23,10 @@ func NoKeys(args []string) []string { return nil } +func RenameKeys(args []string) []string { + return []string{args[1], args[2]} +} + type CommandDef struct{ MinArgs int ExtractKeys func(args []string)[]string @@ -72,7 +83,7 @@ var Registry = map[string]CommandDef{ }, "RENAME": { MinArgs: 3, - ExtractKeys: SingleKey, + ExtractKeys: RenameKeys, Execute: Rename, }, "RPUSH": { @@ -100,4 +111,64 @@ var Registry = map[string]CommandDef{ ExtractKeys: SingleKey, Execute: Lrange, }, + "FLUSHALL": { + MinArgs: 1, + ExtractKeys: NoKeys, + Execute: Flushall, + }, + "EXPIRE": { + MinArgs: 3, + ExtractKeys: SingleKey, + Execute: Expire, + }, + "HSET": { + MinArgs: 4, + ExtractKeys: SingleKey, + Execute: Hset, + }, + "HGET": { + MinArgs: 3, + ExtractKeys: SingleKey, + Execute: Hget, + }, + "HGETALL": { + MinArgs: 2, + ExtractKeys: SingleKey, + Execute: Hgetall, + }, + "HKEYS": { + MinArgs: 2, + ExtractKeys: SingleKey, + Execute: Hkeys, + }, + "HVALUES": { + MinArgs: 2, + ExtractKeys: SingleKey, + Execute: Hvalues, + }, + "TYPE": { + MinArgs: 2, + ExtractKeys: SingleKey, + Execute: Type, + }, + "DBSIZE": { + MinArgs: 1, + ExtractKeys: NoKeys, + Execute: Dbsize, + }, + "KEYS": { + MinArgs: 2, + ExtractKeys: NoKeys, + Execute: Keys, + }, + "LREM": { + MinArgs: 4, + ExtractKeys: SingleKey, + Execute: Lrem, + }, + "PING": { + MinArgs: 1, + ExtractKeys: NoKeys, + Execute: Ping, + }, }
\ No newline at end of file diff --git a/pkg/commands/dbsize.go b/pkg/commands/dbsize.go new file mode 100644 index 0000000..dbe39a4 --- /dev/null +++ b/pkg/commands/dbsize.go @@ -0,0 +1,15 @@ +package commands + +import ( + "redisClone/pkg/core" +) + +func Dbsize(args []string, getShard func(k string) *core.Shard) interface{} { + return dbInstance.ExecuteReadAll(func(shards []*core.Shard) interface{} { + count := 0 + for _, shard := range shards { + count += len(shard.Data) + } + return count + }) +} diff --git a/pkg/commands/expire.go b/pkg/commands/expire.go new file mode 100644 index 0000000..4337e83 --- /dev/null +++ b/pkg/commands/expire.go @@ -0,0 +1,26 @@ +package commands + +import ( + "errors" + "redisClone/pkg/core" + "strconv" + "time" +) + +func Expire(args []string, getShard func(k string) *core.Shard) interface{} { + key := args[1] + seconds, err := strconv.Atoi(args[2]) + if err != nil { + return errors.New("value is not an integer") + } + + s := getShard(key) + item, exists := s.Data[key] + if !exists { + return 0 + } + expiry := time.Now().Add(time.Duration(seconds) * time.Second) + item.ExpiresAt = &expiry + s.Data[key] = item + return 1 +} diff --git a/pkg/commands/flushall.go b/pkg/commands/flushall.go new file mode 100644 index 0000000..9f1316a --- /dev/null +++ b/pkg/commands/flushall.go @@ -0,0 +1,14 @@ +package commands + +import ( + "redisClone/pkg/core" +) + +func Flushall(args []string, getShard func(k string) *core.Shard) interface{} { + return dbInstance.ExecuteAll(func(shards []*core.Shard) interface{} { + for _, shard := range shards { + shard.Data = make(map[string]core.Item) + } + return core.SimpleString("OK") + }) +} diff --git a/pkg/commands/hget.go b/pkg/commands/hget.go new file mode 100644 index 0000000..7d16808 --- /dev/null +++ b/pkg/commands/hget.go @@ -0,0 +1,25 @@ +package commands + +import ( + "errors" + "redisClone/pkg/core" +) + +func Hget(args []string, getShard func(k string) *core.Shard) interface{} { + key := args[1] + field := args[2] + s := getShard(key) + item, exists := s.Data[key] + if !exists { + return nil + } + hash, ok := item.Value.(map[string]string) + if !ok { + return errors.New("WRONGTYPE Operation against a key holding the wrong kind of value") + } + val, found := hash[field] + if !found { + return nil + } + return val +} diff --git a/pkg/commands/hgetall.go b/pkg/commands/hgetall.go new file mode 100644 index 0000000..02b3e3f --- /dev/null +++ b/pkg/commands/hgetall.go @@ -0,0 +1,20 @@ +package commands + +import ( + "errors" + "redisClone/pkg/core" +) + +func Hgetall(args []string, getShard func(k string) *core.Shard) interface{} { + key := args[1] + s := getShard(key) + item, exists := s.Data[key] + if !exists { + return nil + } + hash, ok := item.Value.(map[string]string) + if !ok { + return errors.New("WRONGTYPE Operation against a key holding the wrong kind of value") + } + return hash +} diff --git a/pkg/commands/hkeys.go b/pkg/commands/hkeys.go new file mode 100644 index 0000000..09a5d97 --- /dev/null +++ b/pkg/commands/hkeys.go @@ -0,0 +1,24 @@ +package commands + +import ( + "errors" + "redisClone/pkg/core" +) + +func Hkeys(args []string, getShard func(k string) *core.Shard) interface{} { + key := args[1] + s := getShard(key) + item, exists := s.Data[key] + if !exists { + return nil + } + hash, ok := item.Value.(map[string]string) + if !ok { + return errors.New("WRONGTYPE Operation against a key holding the wrong kind of value") + } + keys := make([]string, 0, len(hash)) + for k := range hash { + keys = append(keys, k) + } + return keys +} diff --git a/pkg/commands/hset.go b/pkg/commands/hset.go new file mode 100644 index 0000000..33f992f --- /dev/null +++ b/pkg/commands/hset.go @@ -0,0 +1,32 @@ +package commands + +import ( + "errors" + "redisClone/pkg/core" +) + +func Hset(args []string, getShard func(k string) *core.Shard) interface{} { + if (len(args)-2)%2 != 0 { + return errors.New("wrong number of arguments for 'HSET'") + } + key := args[1] + s := getShard(key) + item, exists := s.Data[key] + var hash map[string]string + if exists { + var ok bool + hash, ok = item.Value.(map[string]string) + if !ok { + return errors.New("WRONGTYPE Operation against a key holding the wrong kind of value") + } + } else { + hash = make(map[string]string) + } + count := 0 + for i := 2; i < len(args); i += 2 { + hash[args[i]] = args[i+1] + count++ + } + s.Data[key] = core.Item{Value: hash} + return count +} diff --git a/pkg/commands/hvalues.go b/pkg/commands/hvalues.go new file mode 100644 index 0000000..1034fbd --- /dev/null +++ b/pkg/commands/hvalues.go @@ -0,0 +1,24 @@ +package commands + +import ( + "errors" + "redisClone/pkg/core" +) + +func Hvalues(args []string, getShard func(k string) *core.Shard) interface{} { + key := args[1] + s := getShard(key) + item, exists := s.Data[key] + if !exists { + return nil + } + hash, ok := item.Value.(map[string]string) + if !ok { + return errors.New("WRONGTYPE Operation against a key holding the wrong kind of value") + } + values := make([]string, 0, len(hash)) + for _, v := range hash { + values = append(values, v) + } + return values +} diff --git a/pkg/commands/keys.go b/pkg/commands/keys.go new file mode 100644 index 0000000..b233964 --- /dev/null +++ b/pkg/commands/keys.go @@ -0,0 +1,41 @@ +package commands + +import ( + "errors" + "path/filepath" + "redisClone/pkg/core" + "sort" + "strconv" +) + +func Keys(args []string, getShard func(k string) *core.Shard) interface{} { + pattern := args[1] + limit := -1 + if len(args) == 3 { + val, err := strconv.Atoi(args[2]) + if err != nil { + return errors.New("value is not an integer") + } + limit = val + } + + return dbInstance.ExecuteReadAll(func(shards []*core.Shard) interface{} { + var matches []string + for _, shard := range shards { + for key := range shard.Data { + matched, err := filepath.Match(pattern, key) + if err != nil { + return errors.New("illegal glob pattern") + } + if matched { + matches = append(matches, key) + } + } + } + sort.Strings(matches) + if limit != -1 && len(matches) > limit { + matches = matches[:limit] + } + return matches + }) +} diff --git a/pkg/commands/lrem.go b/pkg/commands/lrem.go new file mode 100644 index 0000000..38be270 --- /dev/null +++ b/pkg/commands/lrem.go @@ -0,0 +1,75 @@ +package commands + +import ( + "errors" + "redisClone/pkg/core" + "strconv" +) + +func Lrem(args []string, getShard func(k string) *core.Shard) interface{} { + key := args[1] + count, err := strconv.Atoi(args[2]) + toBeRemoved := args[3] + if err != nil { + return errors.New("value is not an integer") + } + + s := getShard(key) + item, exists := s.Data[key] + if !exists { + return 0 + } + list, ok := item.Value.([]string) + if !ok { + return errors.New("WRONGTYPE Operation against a key holding the wrong kind of value") + } + + counter := 0 + absCount := count + if count < 0 { + absCount = -count + } + + var newList []string + if count == 0 { + newList = []string{} + for _, value := range list { + if value == toBeRemoved { + counter++ + } else { + newList = append(newList, value) + } + } + } else if count > 0 { + newList = []string{} + for _, value := range list { + if value == toBeRemoved && counter < absCount { + counter++ + } else { + newList = append(newList, value) + } + } + } else { // count < 0 + reversedNewList := []string{} + for i := len(list) - 1; i >= 0; i-- { + value := list[i] + if value == toBeRemoved && counter < absCount { + counter++ + } else { + reversedNewList = append(reversedNewList, value) + } + } + newList = make([]string, len(reversedNewList)) + for i, v := range reversedNewList { + newList[len(reversedNewList)-1-i] = v + } + } + + if len(newList) == 0 { + delete(s.Data, key) + } else { + item.Value = newList + s.Data[key] = item + } + return counter +} diff --git a/pkg/commands/ping.go b/pkg/commands/ping.go new file mode 100644 index 0000000..b56cd20 --- /dev/null +++ b/pkg/commands/ping.go @@ -0,0 +1,16 @@ +package commands + +import ( + "errors" + "redisClone/pkg/core" +) + +func Ping(args []string, getShard func(k string) *core.Shard) interface{} { + if len(args) == 1 { + return core.SimpleString("PONG") + } + if len(args) == 2 { + return args[1] + } + return errors.New("wrong number of arguments for 'PING' command") +} diff --git a/pkg/commands/type.go b/pkg/commands/type.go new file mode 100644 index 0000000..2a7ef95 --- /dev/null +++ b/pkg/commands/type.go @@ -0,0 +1,24 @@ +package commands + +import ( + "redisClone/pkg/core" +) + +func Type(args []string, getShard func(k string) *core.Shard) interface{} { + key := args[1] + s := getShard(key) + item, exists := s.Data[key] + if !exists { + return core.SimpleString("none") + } + switch item.Value.(type) { + case string: + return core.SimpleString("string") + case []string: + return core.SimpleString("list") + case map[string]string: + return core.SimpleString("hash") + default: + return core.SimpleString("unknown") + } +} |
