aboutsummaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/commands/command-registry.go73
-rw-r--r--pkg/commands/dbsize.go15
-rw-r--r--pkg/commands/expire.go26
-rw-r--r--pkg/commands/flushall.go14
-rw-r--r--pkg/commands/hget.go25
-rw-r--r--pkg/commands/hgetall.go20
-rw-r--r--pkg/commands/hkeys.go24
-rw-r--r--pkg/commands/hset.go32
-rw-r--r--pkg/commands/hvalues.go24
-rw-r--r--pkg/commands/keys.go41
-rw-r--r--pkg/commands/lrem.go75
-rw-r--r--pkg/commands/ping.go16
-rw-r--r--pkg/commands/type.go24
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")
+ }
+}