|
|
@@ -0,0 +1,178 @@
|
|
|
+// Author: simon (ynwdlxm@163.com)
|
|
|
+// Date: 2025/9/16 16:56
|
|
|
+// Desc:
|
|
|
+
|
|
|
+package database
|
|
|
+
|
|
|
+import (
|
|
|
+ "github.com/runningwater/go-redis/interface/resp"
|
|
|
+ "github.com/runningwater/go-redis/lib/wildcard"
|
|
|
+ "github.com/runningwater/go-redis/resp/reply"
|
|
|
+)
|
|
|
+
|
|
|
+// 语法:
|
|
|
+//
|
|
|
+// DEL key [key ...]
|
|
|
+//
|
|
|
+// 返回:
|
|
|
+//
|
|
|
+// Integer reply: the number of keys that were removed.
|
|
|
+func execDel(db *DB, args [][]byte) resp.Reply {
|
|
|
+ keys := make([]string, len(args))
|
|
|
+ for i, v := range args {
|
|
|
+ keys[i] = string(v)
|
|
|
+ }
|
|
|
+ return reply.NewIntReply(int64(db.Removes(keys...)))
|
|
|
+}
|
|
|
+
|
|
|
+// 语法:
|
|
|
+//
|
|
|
+// EXISTS key [key ...]
|
|
|
+//
|
|
|
+// 返回:
|
|
|
+//
|
|
|
+// Integer reply: the number of keys that exists.
|
|
|
+func execExists(db *DB, args [][]byte) resp.Reply {
|
|
|
+ result := int64(0)
|
|
|
+ for _, key := range args {
|
|
|
+ if _, exists := db.GetEntity(string(key)); exists {
|
|
|
+ result++
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return reply.NewIntReply(result)
|
|
|
+}
|
|
|
+
|
|
|
+// 语法:
|
|
|
+//
|
|
|
+// FLUSHDB [ASYNC | SYNC]
|
|
|
+//
|
|
|
+// 返回:
|
|
|
+//
|
|
|
+// Simple string reply: OK.
|
|
|
+func execFlushDb(db *DB, args [][]byte) resp.Reply {
|
|
|
+ db.Flush()
|
|
|
+ return reply.NewOkReply()
|
|
|
+}
|
|
|
+
|
|
|
+// 语法:
|
|
|
+//
|
|
|
+// KEYS pattern
|
|
|
+//
|
|
|
+// Supported glob-style patterns:
|
|
|
+//
|
|
|
+// h?llo matches hello, hallo and hxllo
|
|
|
+// h*llo matches hllo and heeeello
|
|
|
+// h[ae]llo matches hello and hallo, but not hillo
|
|
|
+// h[^e]llo matches hallo, hbllo, ... but not hello
|
|
|
+// h[a-b]llo matches hallo and hbllo
|
|
|
+//
|
|
|
+// Use \ to escape special characters if you want to match them verbatim.
|
|
|
+//
|
|
|
+// 返回:
|
|
|
+//
|
|
|
+// Array reply: a list of keys matching pattern.
|
|
|
+func execKeys(db *DB, args [][]byte) resp.Reply {
|
|
|
+ pattern := string(args[0])
|
|
|
+ compilePattern := wildcard.CompilePattern(pattern)
|
|
|
+
|
|
|
+ result := make([][]byte, 0)
|
|
|
+ db.data.ForEach(func(key string, value any) bool {
|
|
|
+ if compilePattern.IsMatch(key) {
|
|
|
+ result = append(result, []byte(key))
|
|
|
+ }
|
|
|
+ return true
|
|
|
+ })
|
|
|
+ return reply.NewMultiBulkReply(result)
|
|
|
+}
|
|
|
+
|
|
|
+// 语法:
|
|
|
+//
|
|
|
+// TYPE key
|
|
|
+//
|
|
|
+// 返回:
|
|
|
+//
|
|
|
+// Returns the string representation of the type of the value stored at key.
|
|
|
+// The different types that can be returned are: string, list, set, zset, hash, stream, and vectorset.
|
|
|
+func execType(db *DB, args [][]byte) resp.Reply {
|
|
|
+ key := string(args[0])
|
|
|
+ entity, exists := db.GetEntity(key)
|
|
|
+ if !exists {
|
|
|
+ return reply.NewStatusReply("none")
|
|
|
+ }
|
|
|
+
|
|
|
+ switch entity.Data.(type) {
|
|
|
+ case []byte:
|
|
|
+ return reply.NewStatusReply("string")
|
|
|
+ // : TODO 类型判断: 只实现了 string 类型, 其他类型未实现
|
|
|
+ default:
|
|
|
+ return reply.NewUnknownErrReply("don't know the type")
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 语法:
|
|
|
+//
|
|
|
+// RENAME key newkey
|
|
|
+//
|
|
|
+// 返回:
|
|
|
+//
|
|
|
+// returns an error when key does not exist.
|
|
|
+// If newkey already exists it is overwritten,
|
|
|
+// when this happens RENAME executes an implicit DEL operation,
|
|
|
+// so if the deleted key contains a very big value it may cause
|
|
|
+// high latency even if RENAME itself is usually a constant-time operation.
|
|
|
+func execRename(db *DB, args [][]byte) resp.Reply {
|
|
|
+ src := string(args[0])
|
|
|
+ dest := string(args[1])
|
|
|
+ entity, exists := db.GetEntity(src)
|
|
|
+ if !exists {
|
|
|
+ return reply.NewErrReply("no such key")
|
|
|
+ }
|
|
|
+ db.PutEntity(dest, entity)
|
|
|
+ db.Remove(src)
|
|
|
+ return reply.NewOkReply()
|
|
|
+}
|
|
|
+
|
|
|
+// 语法:
|
|
|
+//
|
|
|
+// RENAMENX key newkey
|
|
|
+//
|
|
|
+// 返回:
|
|
|
+//
|
|
|
+// Integer reply: 1 if key was renamed to newkey.
|
|
|
+// Integer reply: 0 if newkey already exists.
|
|
|
+func execRenamenx(db *DB, args [][]byte) resp.Reply {
|
|
|
+ src := string(args[0])
|
|
|
+ dest := string(args[1])
|
|
|
+
|
|
|
+ _, ok := db.GetEntity(dest)
|
|
|
+ if ok {
|
|
|
+ return reply.NewIntReply(0)
|
|
|
+ }
|
|
|
+
|
|
|
+ entity, exists := db.GetEntity(src)
|
|
|
+ if !exists {
|
|
|
+ return reply.NewErrReply("no such key")
|
|
|
+ }
|
|
|
+ db.PutEntity(dest, entity)
|
|
|
+ db.Remove(src)
|
|
|
+ return reply.NewIntReply(1)
|
|
|
+}
|
|
|
+
|
|
|
+// init 将键相关命令注册到命令表中
|
|
|
+// 此函数在包初始化期间自动调用
|
|
|
+func init() {
|
|
|
+ // 注册 DEL 命令,至少需要 2 个参数(命令名称 + 至少 1 个键)
|
|
|
+ RegisterCommand("DEL", execDel, -2)
|
|
|
+ // 注册 EXISTS 命令,至少需要 2 个参数(命令名称 + 至少 1 个键)
|
|
|
+ RegisterCommand("EXISTS", execExists, -2)
|
|
|
+ // 注册 FLUSHDB 命令,至少需要 1 个参数(命令名称)
|
|
|
+ RegisterCommand("FLUSHDB", execFlushDb, -1)
|
|
|
+ // 注册 RENAME 命令,需要 2 个参数(命令名称 + 源键 + 目标键)
|
|
|
+ RegisterCommand("KEYS", execKeys, 2)
|
|
|
+ // 注册 TYPE 命令,需要 2 个参数(命令名称 + 键)
|
|
|
+ RegisterCommand("TYPE", execType, 2)
|
|
|
+ // 注册 TYPE 命令,需要 3 个参数(命令名称 + 键)
|
|
|
+ RegisterCommand("RENAME", execRename, 3)
|
|
|
+ // 注册 RENAMENX 命令,需要 3 个参数(命令名称 + 源键 + 目标键)
|
|
|
+ RegisterCommand("RENAMENX", execRenamenx, 3)
|
|
|
+}
|