From 778e9d4d2d6e65ee9df994e38afb2ead046e2b78 Mon Sep 17 00:00:00 2001 From: xgzlucario <912156837@qq.com> Date: Fri, 13 Dec 2024 21:40:21 +0800 Subject: [PATCH] feat: add type command --- command.go | 52 +++++++++++++++++++++++++++++++++++++++---------- command_test.go | 33 +++++++++++++++++++++++++++++++ const.go | 14 ------------- 3 files changed, 75 insertions(+), 24 deletions(-) diff --git a/command.go b/command.go index ec556af..266d7a2 100644 --- a/command.go +++ b/command.go @@ -18,7 +18,6 @@ import ( const ( KeepTtl = "KEEPTTL" Count = "COUNT" - Match = "MATCH" NX = "NX" EX = "EX" PX = "PX" @@ -45,6 +44,7 @@ var cmdTable = []*Command{ {"set", setCommand, 2, true}, {"get", getCommand, 1, false}, {"del", delCommand, 1, true}, + {"type", typeCommand, 1, false}, {"scan", scanCommand, 1, false}, {"incr", incrCommand, 1, true}, {"hset", hsetCommand, 3, true}, @@ -194,6 +194,29 @@ func delCommand(writer *resp.Writer, args []redcon.RESP) { writer.WriteInt(count) } +func typeCommand(writer *resp.Writer, args []redcon.RESP) { + key := b2s(args[0].Bytes()) + object, ttl := db.dict.Get(key) + if ttl == KeyNotExist { + writer.WriteString("none") + return + } + switch v := object.(type) { + case int, []byte: + writer.WriteString("string") + case *hash.ZipMap: + writer.WriteString("hash") + case *hash.ZipSet, *hash.Set: + writer.WriteString("set") + case *list.QuickList: + writer.WriteString("list") + case *zset.ZipZSet, *zset.ZSet: + writer.WriteString("zset") + default: + writer.WriteError(fmt.Sprintf("unknown type: %T", v)) + } +} + func scanCommand(writer *resp.Writer, args []redcon.RESP) { cursor := int(args[0].Int()) count := 10 @@ -304,11 +327,16 @@ func lpushCommand(writer *resp.Writer, args []redcon.RESP) { writer.WriteError(err.Error()) return } - keys := make([]string, 0, len(args)-1) - for _, arg := range args[1:] { - keys = append(keys, b2s(arg.Bytes())) + // fast push + if len(args[1:]) == 1 { + ls.LPush(b2s(args[1].Bytes())) + } else { + keys := make([]string, 0, len(args)-1) + for _, arg := range args[1:] { + keys = append(keys, b2s(arg.Bytes())) + } + ls.LPush(keys...) } - ls.LPush(keys...) writer.WriteInt(ls.Len()) } @@ -319,11 +347,16 @@ func rpushCommand(writer *resp.Writer, args []redcon.RESP) { writer.WriteError(err.Error()) return } - keys := make([]string, 0, len(args)-1) - for _, arg := range args[1:] { - keys = append(keys, b2s(arg.Bytes())) + // fast push + if len(args[1:]) == 1 { + ls.RPush(b2s(args[1].Bytes())) + } else { + keys := make([]string, 0, len(args)-1) + for _, arg := range args[1:] { + keys = append(keys, b2s(arg.Bytes())) + } + ls.RPush(keys...) } - ls.RPush(keys...) writer.WriteInt(ls.Len()) } @@ -599,7 +632,6 @@ func fetch[T any](key []byte, new func() T, setnx ...bool) (T, error) { if !ok { return v, errWrongType } - // conversion zipped structure if len(setnx) > 0 && setnx[0] { switch data := object.(type) { diff --git a/command_test.go b/command_test.go index 5f2d5cb..55ed2a1 100644 --- a/command_test.go +++ b/command_test.go @@ -94,6 +94,12 @@ func testCommand(t *testing.T, testType string, rdb *redis.Client, sleepFn func( ast.Equal(res, "") ast.Equal(err, redis.Nil) + _type, _ := rdb.Type(ctx, "foo").Result() + ast.Equal(_type, "string") + + _type, _ = rdb.Type(ctx, "not-exist").Result() + ast.Equal(_type, "none") + n, _ := rdb.Del(ctx, "foo", "none").Result() ast.Equal(n, int64(1)) // setex @@ -150,6 +156,9 @@ func testCommand(t *testing.T, testType string, rdb *redis.Client, sleepFn func( res, _ = rdb.Incr(ctx, "testInt").Result() ast.Equal(res, int64(2)) + _type, _ := rdb.Type(ctx, "testInt").Result() + ast.Equal(_type, "string") + // get int str, _ := rdb.Get(ctx, "testInt").Result() ast.Equal(str, "2") @@ -188,10 +197,16 @@ func testCommand(t *testing.T, testType string, rdb *redis.Client, sleepFn func( ast.Nil(err) } + _, err = rdb.HGet(ctx, "map", "not-exist").Result() + ast.Equal(err, redis.Nil) + // hgetall resm, _ := rdb.HGetAll(ctx, "map").Result() ast.Equal(len(resm), 100) + _type, _ := rdb.Type(ctx, "map").Result() + ast.Equal(_type, "hash") + // hdel res, _ = rdb.HDel(ctx, "map", keys[0:10]...).Result() ast.Equal(res, int64(10)) @@ -228,6 +243,9 @@ func testCommand(t *testing.T, testType string, rdb *redis.Client, sleepFn func( n, _ = rdb.RPush(ctx, "list", "4", "5", "6").Result() ast.Equal(n, int64(6)) + _type, _ := rdb.Type(ctx, "list").Result() + ast.Equal(_type, "list") + // list: [1,2,3,4,5,6] // lrange res, _ := rdb.LRange(ctx, "list", 0, -1).Result() @@ -261,6 +279,9 @@ func testCommand(t *testing.T, testType string, rdb *redis.Client, sleepFn func( val, _ = rdb.RPop(ctx, "list").Result() ast.Equal(val, "6") + n, _ = rdb.LPush(ctx, "list", "6").Result() + ast.Equal(n, int64(5)) + // pop nil { _, err := rdb.LPop(ctx, "list-empty").Result() @@ -301,6 +322,9 @@ func testCommand(t *testing.T, testType string, rdb *redis.Client, sleepFn func( mems, _ := rdb.SMembers(ctx, "set").Result() ast.ElementsMatch(mems, []string{"k1", "k2", "k3"}) + _type, _ := rdb.Type(ctx, "set").Result() + ast.Equal(_type, "set") + // spop for i := 0; i < 3; i++ { val, _ := rdb.SPop(ctx, "set").Result() @@ -324,6 +348,9 @@ func testCommand(t *testing.T, testType string, rdb *redis.Client, sleepFn func( _, err = rdb.SRem(ctx, "key", "1").Result() ast.Equal(err.Error(), errWrongType.Error()) + _, err = rdb.SMembers(ctx, "key").Result() + ast.Equal(err.Error(), errWrongType.Error()) + _, err = rdb.SPop(ctx, "key").Result() ast.Equal(err.Error(), errWrongType.Error()) }) @@ -338,6 +365,9 @@ func testCommand(t *testing.T, testType string, rdb *redis.Client, sleepFn func( redis.Z{Member: "user3", Score: 100}).Result() ast.Equal(n, int64(2)) + _type, _ := rdb.Type(ctx, "rank").Result() + ast.Equal(_type, "zset") + // zrank { res, _ := rdb.ZRank(ctx, "rank", "user1").Result() @@ -411,6 +441,9 @@ func testCommand(t *testing.T, testType string, rdb *redis.Client, sleepFn func( _, err = rdb.ZRank(ctx, "key", "member1").Result() ast.Equal(err.Error(), errWrongType.Error()) + _, err = rdb.ZRange(ctx, "key", 0, -1).Result() + ast.Equal(err.Error(), errWrongType.Error()) + _, err = rdb.ZRem(ctx, "key", "member1").Result() ast.Equal(err.Error(), errWrongType.Error()) diff --git a/const.go b/const.go index a3e8a10..ef844bb 100644 --- a/const.go +++ b/const.go @@ -2,10 +2,6 @@ package main import ( "github.com/redis/go-redis/v9" - "github.com/xgzlucario/rotom/internal/hash" - "github.com/xgzlucario/rotom/internal/iface" - "github.com/xgzlucario/rotom/internal/list" - "github.com/xgzlucario/rotom/internal/zset" ) type ObjectType byte @@ -32,13 +28,3 @@ const ( MB = 1024 * KB GB = 1024 * MB ) - -// type2c is objectType to new encoder. -var type2c = map[ObjectType]func() iface.Encoder{ - TypeMap: func() iface.Encoder { return hash.New() }, - TypeSet: func() iface.Encoder { return hash.NewSet() }, - TypeZipSet: func() iface.Encoder { return hash.NewZipSet() }, - TypeList: func() iface.Encoder { return list.New() }, - TypeZSet: func() iface.Encoder { return zset.New() }, - TypeZipZSet: func() iface.Encoder { return zset.NewZipZSet() }, -}