mirror of https://github.com/tidwall/tile38.git
Better KEYS tests
This commit is contained in:
parent
295a9c45a8
commit
5bcef43894
|
@ -1,8 +1,7 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/tidwall/resp"
|
||||
|
@ -10,86 +9,59 @@ import (
|
|||
"github.com/tidwall/tile38/internal/glob"
|
||||
)
|
||||
|
||||
func (s *Server) cmdKeys(msg *Message) (res resp.Value, err error) {
|
||||
// KEYS pattern
|
||||
func (s *Server) cmdKEYS(msg *Message) (resp.Value, error) {
|
||||
var start = time.Now()
|
||||
vs := msg.Args[1:]
|
||||
|
||||
var pattern string
|
||||
var ok bool
|
||||
if vs, pattern, ok = tokenval(vs); !ok || pattern == "" {
|
||||
return NOMessage, errInvalidNumberOfArguments
|
||||
}
|
||||
if len(vs) != 0 {
|
||||
return NOMessage, errInvalidNumberOfArguments
|
||||
}
|
||||
// >> Args
|
||||
|
||||
var wr = &bytes.Buffer{}
|
||||
var once bool
|
||||
if msg.OutputType == JSON {
|
||||
wr.WriteString(`{"ok":true,"keys":[`)
|
||||
args := msg.Args
|
||||
if len(args) != 2 {
|
||||
return retrerr(errInvalidNumberOfArguments)
|
||||
}
|
||||
var wild bool
|
||||
if strings.Contains(pattern, "*") {
|
||||
wild = true
|
||||
}
|
||||
var everything bool
|
||||
var greater bool
|
||||
var greaterPivot string
|
||||
var vals []resp.Value
|
||||
pattern := args[1]
|
||||
|
||||
iter := func(key string, col *collection.Collection) bool {
|
||||
var match bool
|
||||
// >> Operation
|
||||
|
||||
keys := []string{}
|
||||
g := glob.Parse(pattern, false)
|
||||
everything := g.Limits[0] == "" && g.Limits[1] == ""
|
||||
if everything {
|
||||
match = true
|
||||
} else if greater {
|
||||
if !strings.HasPrefix(key, greaterPivot) {
|
||||
return false
|
||||
}
|
||||
match = true
|
||||
} else {
|
||||
match, _ = glob.Match(pattern, key)
|
||||
}
|
||||
s.cols.Scan(
|
||||
func(key string, _ *collection.Collection) bool {
|
||||
match, _ := glob.Match(pattern, key)
|
||||
if match {
|
||||
if once {
|
||||
if msg.OutputType == JSON {
|
||||
wr.WriteByte(',')
|
||||
}
|
||||
} else {
|
||||
once = true
|
||||
}
|
||||
switch msg.OutputType {
|
||||
case JSON:
|
||||
wr.WriteString(jsonString(key))
|
||||
case RESP:
|
||||
vals = append(vals, resp.StringValue(key))
|
||||
}
|
||||
|
||||
// If no more than one match is expected, stop searching
|
||||
if !wild {
|
||||
return false
|
||||
}
|
||||
keys = append(keys, key)
|
||||
}
|
||||
return true
|
||||
},
|
||||
)
|
||||
} else {
|
||||
s.cols.Ascend(g.Limits[0],
|
||||
func(key string, _ *collection.Collection) bool {
|
||||
if key > g.Limits[1] {
|
||||
return false
|
||||
}
|
||||
match, _ := glob.Match(pattern, key)
|
||||
if match {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
return true
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// TODO: This can be further optimized by using glob.Parse and limits
|
||||
if pattern == "*" {
|
||||
everything = true
|
||||
s.cols.Scan(iter)
|
||||
} else if strings.HasSuffix(pattern, "*") {
|
||||
greaterPivot = pattern[:len(pattern)-1]
|
||||
if glob.IsGlob(greaterPivot) {
|
||||
s.cols.Scan(iter)
|
||||
} else {
|
||||
greater = true
|
||||
s.cols.Ascend(greaterPivot, iter)
|
||||
}
|
||||
} else {
|
||||
s.cols.Scan(iter)
|
||||
}
|
||||
// >> Response
|
||||
|
||||
if msg.OutputType == JSON {
|
||||
wr.WriteString(`],"elapsed":"` + time.Since(start).String() + "\"}")
|
||||
return resp.StringValue(wr.String()), nil
|
||||
data, _ := json.Marshal(keys)
|
||||
return resp.StringValue(`{"ok":true,"keys":` + string(data) +
|
||||
`,"elapsed":"` + time.Since(start).String() + `"}`), nil
|
||||
}
|
||||
|
||||
var vals []resp.Value
|
||||
for _, key := range keys {
|
||||
vals = append(vals, resp.StringValue(key))
|
||||
}
|
||||
return resp.ArrayValue(vals), nil
|
||||
}
|
||||
|
|
|
@ -636,7 +636,7 @@ func (s *Server) commandInScript(msg *Message) (
|
|||
case "type":
|
||||
res, err = s.cmdTYPE(msg)
|
||||
case "keys":
|
||||
res, err = s.cmdKeys(msg)
|
||||
res, err = s.cmdKEYS(msg)
|
||||
case "test":
|
||||
res, err = s.cmdTest(msg)
|
||||
case "server":
|
||||
|
|
|
@ -1110,7 +1110,7 @@ func (s *Server) command(msg *Message, client *Client) (
|
|||
case "type":
|
||||
res, err = s.cmdTYPE(msg)
|
||||
case "keys":
|
||||
res, err = s.cmdKeys(msg)
|
||||
res, err = s.cmdKEYS(msg)
|
||||
case "output":
|
||||
res, err = s.cmdOutput(msg)
|
||||
case "aof":
|
||||
|
|
|
@ -225,28 +225,30 @@ func keys_GET_test(mc *mockServer) error {
|
|||
)
|
||||
}
|
||||
func keys_KEYS_test(mc *mockServer) error {
|
||||
return mc.DoBatch([][]interface{}{
|
||||
{"SET", "mykey11", "myid4", "STRING", "value"}, {"OK"},
|
||||
{"SET", "mykey22", "myid2", "HASH", "9my5xp7"}, {"OK"},
|
||||
{"SET", "mykey22", "myid1", "OBJECT", `{"type":"Point","coordinates":[-130,38,10]}`}, {"OK"},
|
||||
{"SET", "mykey11", "myid3", "OBJECT", `{"type":"Point","coordinates":[-110,25,-8]}`}, {"OK"},
|
||||
{"SET", "mykey42", "myid2", "HASH", "9my5xp7"}, {"OK"},
|
||||
{"SET", "mykey31", "myid4", "STRING", "value"}, {"OK"},
|
||||
{"SET", "mykey310", "myid5", "STRING", "value"}, {"OK"},
|
||||
{"KEYS", "*"}, {"[mykey11 mykey22 mykey31 mykey310 mykey42]"},
|
||||
{"KEYS", "*key*"}, {"[mykey11 mykey22 mykey31 mykey310 mykey42]"},
|
||||
{"KEYS", "mykey*"}, {"[mykey11 mykey22 mykey31 mykey310 mykey42]"},
|
||||
{"KEYS", "mykey4*"}, {"[mykey42]"},
|
||||
{"KEYS", "mykey*1"}, {"[mykey11 mykey31]"},
|
||||
{"KEYS", "mykey*1*"}, {"[mykey11 mykey31 mykey310]"},
|
||||
{"KEYS", "mykey*10"}, {"[mykey310]"},
|
||||
{"KEYS", "mykey*2"}, {"[mykey22 mykey42]"},
|
||||
{"KEYS", "*2"}, {"[mykey22 mykey42]"},
|
||||
{"KEYS", "*1*"}, {"[mykey11 mykey31 mykey310]"},
|
||||
{"KEYS", "mykey"}, {"[]"},
|
||||
{"KEYS", "mykey31"}, {"[mykey31]"},
|
||||
{"KEYS", "mykey[^3]*"}, {"[mykey11 mykey22 mykey42]"},
|
||||
})
|
||||
return mc.DoBatch(
|
||||
Do("SET", "mykey11", "myid4", "STRING", "value").OK(),
|
||||
Do("SET", "mykey22", "myid2", "HASH", "9my5xp7").OK(),
|
||||
Do("SET", "mykey22", "myid1", "OBJECT", `{"type":"Point","coordinates":[-130,38,10]}`).OK(),
|
||||
Do("SET", "mykey11", "myid3", "OBJECT", `{"type":"Point","coordinates":[-110,25,-8]}`).OK(),
|
||||
Do("SET", "mykey42", "myid2", "HASH", "9my5xp7").OK(),
|
||||
Do("SET", "mykey31", "myid4", "STRING", "value").OK(),
|
||||
Do("SET", "mykey310", "myid5", "STRING", "value").OK(),
|
||||
Do("KEYS", "*").Str("[mykey11 mykey22 mykey31 mykey310 mykey42]"),
|
||||
Do("KEYS", "*key*").Str("[mykey11 mykey22 mykey31 mykey310 mykey42]"),
|
||||
Do("KEYS", "mykey*").Str("[mykey11 mykey22 mykey31 mykey310 mykey42]"),
|
||||
Do("KEYS", "mykey4*").Str("[mykey42]"),
|
||||
Do("KEYS", "mykey*1").Str("[mykey11 mykey31]"),
|
||||
Do("KEYS", "mykey*1*").Str("[mykey11 mykey31 mykey310]"),
|
||||
Do("KEYS", "mykey*10").Str("[mykey310]"),
|
||||
Do("KEYS", "mykey*2").Str("[mykey22 mykey42]"),
|
||||
Do("KEYS", "*2").Str("[mykey22 mykey42]"),
|
||||
Do("KEYS", "*1*").Str("[mykey11 mykey31 mykey310]"),
|
||||
Do("KEYS", "mykey").Str("[]"),
|
||||
Do("KEYS", "mykey31").Str("[mykey31]"),
|
||||
Do("KEYS", "mykey[^3]*").Str("[mykey11 mykey22 mykey42]"),
|
||||
Do("KEYS").Err("wrong number of arguments for 'keys' command"),
|
||||
Do("KEYS", "*").JSON().Str(`{"ok":true,"keys":["mykey11","mykey22","mykey31","mykey310","mykey42"]}`),
|
||||
)
|
||||
}
|
||||
func keys_PERSIST_test(mc *mockServer) error {
|
||||
return mc.DoBatch(
|
||||
|
@ -371,6 +373,8 @@ func keys_STATS_test(mc *mockServer) error {
|
|||
Do("DEL", "mykey", "myid2").Str("1"),
|
||||
Do("STATS", "mykey").Str("[nil]"),
|
||||
Do("STATS", "mykey", "mykey2").Str("[nil nil]"),
|
||||
Do("STATS", "mykey").Str("[nil]"),
|
||||
Do("STATS").Err(`wrong number of arguments for 'stats' command`),
|
||||
)
|
||||
}
|
||||
func keys_TTL_test(mc *mockServer) error {
|
||||
|
|
Loading…
Reference in New Issue