// 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/utils" "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) } deleted := db.Removes(keys...) if deleted > 0 { db.addAof(utils.ToCmdLine2("DEL", args...)) } return reply.NewIntReply(int64(deleted)) } // 语法: // // 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() db.addAof(utils.ToCmdLine2("FLUSHDB", args...)) 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) db.addAof(utils.ToCmdLine2("RENAME", args...)) 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) db.addAof(utils.ToCmdLine2("RENAMENX", args...)) 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) }