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
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"encoding/json"
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/tidwall/resp"
|
"github.com/tidwall/resp"
|
||||||
|
@ -10,86 +9,59 @@ import (
|
||||||
"github.com/tidwall/tile38/internal/glob"
|
"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()
|
var start = time.Now()
|
||||||
vs := msg.Args[1:]
|
|
||||||
|
|
||||||
var pattern string
|
// >> Args
|
||||||
var ok bool
|
|
||||||
if vs, pattern, ok = tokenval(vs); !ok || pattern == "" {
|
|
||||||
return NOMessage, errInvalidNumberOfArguments
|
|
||||||
}
|
|
||||||
if len(vs) != 0 {
|
|
||||||
return NOMessage, errInvalidNumberOfArguments
|
|
||||||
}
|
|
||||||
|
|
||||||
var wr = &bytes.Buffer{}
|
args := msg.Args
|
||||||
var once bool
|
if len(args) != 2 {
|
||||||
if msg.OutputType == JSON {
|
return retrerr(errInvalidNumberOfArguments)
|
||||||
wr.WriteString(`{"ok":true,"keys":[`)
|
|
||||||
}
|
}
|
||||||
var wild bool
|
pattern := args[1]
|
||||||
if strings.Contains(pattern, "*") {
|
|
||||||
wild = true
|
|
||||||
}
|
|
||||||
var everything bool
|
|
||||||
var greater bool
|
|
||||||
var greaterPivot string
|
|
||||||
var vals []resp.Value
|
|
||||||
|
|
||||||
iter := func(key string, col *collection.Collection) bool {
|
// >> Operation
|
||||||
var match bool
|
|
||||||
if everything {
|
keys := []string{}
|
||||||
match = true
|
g := glob.Parse(pattern, false)
|
||||||
} else if greater {
|
everything := g.Limits[0] == "" && g.Limits[1] == ""
|
||||||
if !strings.HasPrefix(key, greaterPivot) {
|
if everything {
|
||||||
return false
|
s.cols.Scan(
|
||||||
}
|
func(key string, _ *collection.Collection) bool {
|
||||||
match = true
|
match, _ := glob.Match(pattern, key)
|
||||||
} else {
|
if match {
|
||||||
match, _ = glob.Match(pattern, key)
|
keys = append(keys, key)
|
||||||
}
|
|
||||||
if match {
|
|
||||||
if once {
|
|
||||||
if msg.OutputType == JSON {
|
|
||||||
wr.WriteByte(',')
|
|
||||||
}
|
}
|
||||||
} else {
|
return true
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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 {
|
} else {
|
||||||
s.cols.Scan(iter)
|
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
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// >> Response
|
||||||
|
|
||||||
if msg.OutputType == JSON {
|
if msg.OutputType == JSON {
|
||||||
wr.WriteString(`],"elapsed":"` + time.Since(start).String() + "\"}")
|
data, _ := json.Marshal(keys)
|
||||||
return resp.StringValue(wr.String()), nil
|
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
|
return resp.ArrayValue(vals), nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -636,7 +636,7 @@ func (s *Server) commandInScript(msg *Message) (
|
||||||
case "type":
|
case "type":
|
||||||
res, err = s.cmdTYPE(msg)
|
res, err = s.cmdTYPE(msg)
|
||||||
case "keys":
|
case "keys":
|
||||||
res, err = s.cmdKeys(msg)
|
res, err = s.cmdKEYS(msg)
|
||||||
case "test":
|
case "test":
|
||||||
res, err = s.cmdTest(msg)
|
res, err = s.cmdTest(msg)
|
||||||
case "server":
|
case "server":
|
||||||
|
|
|
@ -1110,7 +1110,7 @@ func (s *Server) command(msg *Message, client *Client) (
|
||||||
case "type":
|
case "type":
|
||||||
res, err = s.cmdTYPE(msg)
|
res, err = s.cmdTYPE(msg)
|
||||||
case "keys":
|
case "keys":
|
||||||
res, err = s.cmdKeys(msg)
|
res, err = s.cmdKEYS(msg)
|
||||||
case "output":
|
case "output":
|
||||||
res, err = s.cmdOutput(msg)
|
res, err = s.cmdOutput(msg)
|
||||||
case "aof":
|
case "aof":
|
||||||
|
|
|
@ -225,28 +225,30 @@ func keys_GET_test(mc *mockServer) error {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
func keys_KEYS_test(mc *mockServer) error {
|
func keys_KEYS_test(mc *mockServer) error {
|
||||||
return mc.DoBatch([][]interface{}{
|
return mc.DoBatch(
|
||||||
{"SET", "mykey11", "myid4", "STRING", "value"}, {"OK"},
|
Do("SET", "mykey11", "myid4", "STRING", "value").OK(),
|
||||||
{"SET", "mykey22", "myid2", "HASH", "9my5xp7"}, {"OK"},
|
Do("SET", "mykey22", "myid2", "HASH", "9my5xp7").OK(),
|
||||||
{"SET", "mykey22", "myid1", "OBJECT", `{"type":"Point","coordinates":[-130,38,10]}`}, {"OK"},
|
Do("SET", "mykey22", "myid1", "OBJECT", `{"type":"Point","coordinates":[-130,38,10]}`).OK(),
|
||||||
{"SET", "mykey11", "myid3", "OBJECT", `{"type":"Point","coordinates":[-110,25,-8]}`}, {"OK"},
|
Do("SET", "mykey11", "myid3", "OBJECT", `{"type":"Point","coordinates":[-110,25,-8]}`).OK(),
|
||||||
{"SET", "mykey42", "myid2", "HASH", "9my5xp7"}, {"OK"},
|
Do("SET", "mykey42", "myid2", "HASH", "9my5xp7").OK(),
|
||||||
{"SET", "mykey31", "myid4", "STRING", "value"}, {"OK"},
|
Do("SET", "mykey31", "myid4", "STRING", "value").OK(),
|
||||||
{"SET", "mykey310", "myid5", "STRING", "value"}, {"OK"},
|
Do("SET", "mykey310", "myid5", "STRING", "value").OK(),
|
||||||
{"KEYS", "*"}, {"[mykey11 mykey22 mykey31 mykey310 mykey42]"},
|
Do("KEYS", "*").Str("[mykey11 mykey22 mykey31 mykey310 mykey42]"),
|
||||||
{"KEYS", "*key*"}, {"[mykey11 mykey22 mykey31 mykey310 mykey42]"},
|
Do("KEYS", "*key*").Str("[mykey11 mykey22 mykey31 mykey310 mykey42]"),
|
||||||
{"KEYS", "mykey*"}, {"[mykey11 mykey22 mykey31 mykey310 mykey42]"},
|
Do("KEYS", "mykey*").Str("[mykey11 mykey22 mykey31 mykey310 mykey42]"),
|
||||||
{"KEYS", "mykey4*"}, {"[mykey42]"},
|
Do("KEYS", "mykey4*").Str("[mykey42]"),
|
||||||
{"KEYS", "mykey*1"}, {"[mykey11 mykey31]"},
|
Do("KEYS", "mykey*1").Str("[mykey11 mykey31]"),
|
||||||
{"KEYS", "mykey*1*"}, {"[mykey11 mykey31 mykey310]"},
|
Do("KEYS", "mykey*1*").Str("[mykey11 mykey31 mykey310]"),
|
||||||
{"KEYS", "mykey*10"}, {"[mykey310]"},
|
Do("KEYS", "mykey*10").Str("[mykey310]"),
|
||||||
{"KEYS", "mykey*2"}, {"[mykey22 mykey42]"},
|
Do("KEYS", "mykey*2").Str("[mykey22 mykey42]"),
|
||||||
{"KEYS", "*2"}, {"[mykey22 mykey42]"},
|
Do("KEYS", "*2").Str("[mykey22 mykey42]"),
|
||||||
{"KEYS", "*1*"}, {"[mykey11 mykey31 mykey310]"},
|
Do("KEYS", "*1*").Str("[mykey11 mykey31 mykey310]"),
|
||||||
{"KEYS", "mykey"}, {"[]"},
|
Do("KEYS", "mykey").Str("[]"),
|
||||||
{"KEYS", "mykey31"}, {"[mykey31]"},
|
Do("KEYS", "mykey31").Str("[mykey31]"),
|
||||||
{"KEYS", "mykey[^3]*"}, {"[mykey11 mykey22 mykey42]"},
|
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 {
|
func keys_PERSIST_test(mc *mockServer) error {
|
||||||
return mc.DoBatch(
|
return mc.DoBatch(
|
||||||
|
@ -371,6 +373,8 @@ func keys_STATS_test(mc *mockServer) error {
|
||||||
Do("DEL", "mykey", "myid2").Str("1"),
|
Do("DEL", "mykey", "myid2").Str("1"),
|
||||||
Do("STATS", "mykey").Str("[nil]"),
|
Do("STATS", "mykey").Str("[nil]"),
|
||||||
Do("STATS", "mykey", "mykey2").Str("[nil 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 {
|
func keys_TTL_test(mc *mockServer) error {
|
||||||
|
|
Loading…
Reference in New Issue