ledisdb/server/cmd_scan.go

252 lines
4.0 KiB
Go

package server
import (
"fmt"
"github.com/siddontang/go/hack"
"github.com/siddontang/go/num"
"github.com/siddontang/ledisdb/ledis"
"strconv"
"strings"
)
func parseScanArgs(args [][]byte) (cursor []byte, match string, count int, desc bool, err error) {
cursor = args[0]
args = args[1:]
count = 10
desc = false
for i := 0; i < len(args); {
switch strings.ToUpper(hack.String(args[i])) {
case "MATCH":
if i+1 >= len(args) {
err = ErrCmdParams
return
}
match = hack.String(args[i+1])
i++
case "COUNT":
if i+1 >= len(args) {
err = ErrCmdParams
return
}
count, err = strconv.Atoi(hack.String(args[i+1]))
if err != nil {
return
}
i++
case "ASC":
desc = false
case "DESC":
desc = true
default:
err = fmt.Errorf("invalid argument %s", args[i])
return
}
i++
}
return
}
// XSCAN type cursor [MATCH match] [COUNT count] [ASC|DESC]
func xscanCommand(c *client) error {
args := c.args
if len(args) < 2 {
return ErrCmdParams
}
var dataType ledis.DataType
switch strings.ToUpper(hack.String(args[0])) {
case "KV":
dataType = ledis.KV
case "HASH":
dataType = ledis.HASH
case "LIST":
dataType = ledis.LIST
case "SET":
dataType = ledis.SET
case "ZSET":
dataType = ledis.ZSET
default:
return fmt.Errorf("invalid key type %s", args[0])
}
cursor, match, count, desc, err := parseScanArgs(args[1:])
if err != nil {
return err
}
var ay [][]byte
if !desc {
ay, err = c.db.Scan(dataType, cursor, count, false, match)
} else {
ay, err = c.db.RevScan(dataType, cursor, count, false, match)
}
if err != nil {
return err
}
data := make([]interface{}, 2)
if len(ay) < count {
data[0] = []byte("")
} else {
data[0] = ay[len(ay)-1]
}
data[1] = ay
c.resp.writeArray(data)
return nil
}
// XHSCAN key cursor [MATCH match] [COUNT count] [ASC|DESC]
func xhscanCommand(c *client) error {
args := c.args
if len(args) < 2 {
return ErrCmdParams
}
key := args[0]
cursor, match, count, desc, err := parseScanArgs(args[1:])
if err != nil {
return err
}
var ay []ledis.FVPair
if !desc {
ay, err = c.db.HScan(key, cursor, count, false, match)
} else {
ay, err = c.db.HRevScan(key, cursor, count, false, match)
}
if err != nil {
return err
}
data := make([]interface{}, 2)
if len(ay) < count {
data[0] = []byte("")
} else {
data[0] = ay[len(ay)-1].Field
}
vv := make([][]byte, 0, len(ay)*2)
for _, v := range ay {
vv = append(vv, v.Field, v.Value)
}
data[1] = vv
c.resp.writeArray(data)
return nil
}
// XSSCAN key cursor [MATCH match] [COUNT count] [ASC|DESC]
func xsscanCommand(c *client) error {
args := c.args
if len(args) < 2 {
return ErrCmdParams
}
key := args[0]
cursor, match, count, desc, err := parseScanArgs(args[1:])
if err != nil {
return err
}
var ay [][]byte
if !desc {
ay, err = c.db.SScan(key, cursor, count, false, match)
} else {
ay, err = c.db.SRevScan(key, cursor, count, false, match)
}
if err != nil {
return err
}
data := make([]interface{}, 2)
if len(ay) < count {
data[0] = []byte("")
} else {
data[0] = ay[len(ay)-1]
}
data[1] = ay
c.resp.writeArray(data)
return nil
}
// XZSCAN key cursor [MATCH match] [COUNT count] [ASC|DESC]
func xzscanCommand(c *client) error {
args := c.args
if len(args) < 2 {
return ErrCmdParams
}
key := args[0]
cursor, match, count, desc, err := parseScanArgs(args[1:])
if err != nil {
return err
}
var ay []ledis.ScorePair
if !desc {
ay, err = c.db.ZScan(key, cursor, count, false, match)
} else {
ay, err = c.db.ZRevScan(key, cursor, count, false, match)
}
if err != nil {
return err
}
data := make([]interface{}, 2)
if len(ay) < count {
data[0] = []byte("")
} else {
data[0] = ay[len(ay)-1].Member
}
vv := make([][]byte, 0, len(ay)*2)
for _, v := range ay {
vv = append(vv, v.Member, num.FormatInt64ToSlice(v.Score))
}
data[1] = vv
c.resp.writeArray(data)
return nil
}
func init() {
register("xscan", xscanCommand)
register("xhscan", xhscanCommand)
register("xsscan", xsscanCommand)
register("xzscan", xzscanCommand)
}