Skip to content

Commit

Permalink
feat: add scan command
Browse files Browse the repository at this point in the history
  • Loading branch information
xgzlucario committed Dec 2, 2024
1 parent ba6ee32 commit b80780b
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 16 deletions.
45 changes: 38 additions & 7 deletions command.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@ import (
"github.com/xgzlucario/rotom/internal/zset"
)

var (
WithScores = "WITHSCORES"
const (
KeepTtl = "KEEPTTL"
Count = "COUNT"
Match = "MATCH"
NX = "NX"
EX = "EX"
PX = "PX"
WithScores = "WITHSCORES"
)

type Command struct {
Expand All @@ -43,6 +45,7 @@ var cmdTable = []*Command{
{"set", setCommand, 2, true},
{"get", getCommand, 1, false},
{"del", delCommand, 1, true},
{"scan", scanCommand, 1, false},
{"incr", incrCommand, 1, true},
{"hset", hsetCommand, 3, true},
{"hget", hgetCommand, 2, false},
Expand Down Expand Up @@ -106,32 +109,27 @@ func setCommand(writer *resp.Writer, args []redcon.RESP) {

for len(extra) > 0 {
arg := b2s(extra[0].Bytes())

// EX
if equalFold(arg, EX) && len(extra) >= 2 {
n := extra[1].Int()
ttl = time.Now().Add(time.Duration(n) * time.Second).UnixNano()
extra = extra[2:]

// PX
} else if equalFold(arg, PX) && len(extra) >= 2 {
n := extra[1].Int()
ttl = time.Now().Add(time.Duration(n) * time.Millisecond).UnixNano()
extra = extra[2:]

// KEEPTTL
} else if equalFold(arg, KeepTtl) {
extra = extra[1:]
ttl = -1

// NX
} else if equalFold(arg, NX) {
if _, ttl := db.dict.Get(key); ttl != KeyNotExist {
writer.WriteNull()
return
}
extra = extra[1:]

} else {
writer.WriteError(errSyntax.Error())
return
Expand Down Expand Up @@ -196,6 +194,39 @@ func delCommand(writer *resp.Writer, args []redcon.RESP) {
writer.WriteInt(count)
}

func scanCommand(writer *resp.Writer, args []redcon.RESP) {
cursor := int(args[0].Int())
count := 10
extra := args[1:]

for len(extra) > 0 {
arg := b2s(extra[0].Bytes())
// COUNT
if equalFold(arg, Count) && len(extra) >= 2 {
count = int(extra[1].Int())
extra = extra[2:]
} else {
writer.WriteError(errSyntax.Error())
return
}
}

keys := make([]string, 0, count)
db.dict.data.All(func(key string, _ any) bool {
keys = append(keys, key)
return count > len(keys)
})

if len(keys) == db.dict.data.Len() {
cursor = 0
} else {
cursor = count
}
writer.WriteArray(2)
writer.WriteInt(cursor)
writer.WriteAny(keys)
}

func hsetCommand(writer *resp.Writer, args []redcon.RESP) {
key := args[0].Bytes()
args = args[1:]
Expand Down
31 changes: 23 additions & 8 deletions command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -422,14 +422,29 @@ func testCommand(t *testing.T, testType string, rdb *redis.Client, sleepFn func(
ast.Equal(err.Error(), errWrongType.Error())
})

//t.Run("flushdb", func(t *testing.T) {
// rdb.Set(ctx, "test-flush", "1", 0)
// res, _ := rdb.FlushDB(ctx).Result()
// ast.Equal(res, "OK")
//
// _, err := rdb.Get(ctx, "test-flush").Result()
// ast.Equal(err, redis.Nil)
//})
t.Run("flushdb", func(t *testing.T) {
rdb.Set(ctx, "test-flush", "1", 0)
res, _ := rdb.FlushDB(ctx).Result()
ast.Equal(res, "OK")

_, err := rdb.Get(ctx, "test-flush").Result()
ast.Equal(err, redis.Nil)
})

t.Run("scan", func(t *testing.T) {
for i := 0; i < 10; i++ {
rdb.Set(ctx, fmt.Sprintf("key-%d", i), 1, 0)
}
keys, cursor, err := rdb.Scan(ctx, 0, "", 5).Result()
ast.Equal(len(keys), 5)
ast.Equal(cursor, uint64(5))
ast.Nil(err)

keys, cursor, err = rdb.Scan(ctx, 0, "", 10).Result()
ast.Equal(len(keys), 10)
ast.Equal(cursor, uint64(0))
ast.Nil(err)
})

t.Run("pipline", func(t *testing.T) {
pip := rdb.Pipeline()
Expand Down
2 changes: 1 addition & 1 deletion config.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"port": 6379,
"port": 7799,
"appendonly": false,
"appendfilename": "appendonly.aof",
"save": false,
Expand Down

0 comments on commit b80780b

Please sign in to comment.