Skip to content

Commit

Permalink
Merge pull request #103 from alicebob/keys
Browse files Browse the repository at this point in the history
allow newlines in keys
  • Loading branch information
alicebob authored Aug 27, 2019
2 parents 0195e13 + 3d33259 commit ce66b76
Show file tree
Hide file tree
Showing 9 changed files with 57 additions and 30 deletions.
4 changes: 2 additions & 2 deletions cmd_generic.go
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ func (m *Miniredis) cmdKeys(c *server.Peer, cmd string, args []string) {
withTx(m, c, func(c *server.Peer, ctx *connCtx) {
db := m.db(ctx.selectedDB)

keys := matchKeys(db.allKeys(), key)
keys, _ := matchKeys(db.allKeys(), key)
c.WriteLen(len(keys))
for _, s := range keys {
c.WriteBulk(s)
Expand Down Expand Up @@ -507,7 +507,7 @@ func (m *Miniredis) cmdScan(c *server.Peer, cmd string, args []string) {

keys := db.allKeys()
if withMatch {
keys = matchKeys(keys, match)
keys, _ = matchKeys(keys, match)
}

c.WriteLen(2)
Expand Down
2 changes: 1 addition & 1 deletion cmd_hash.go
Original file line number Diff line number Diff line change
Expand Up @@ -598,7 +598,7 @@ func (m *Miniredis) cmdHscan(c *server.Peer, cmd string, args []string) {

members := db.hashFields(key)
if withMatch {
members = matchKeys(members, match)
members, _ = matchKeys(members, match)
}

c.WriteLen(2)
Expand Down
2 changes: 1 addition & 1 deletion cmd_set.go
Original file line number Diff line number Diff line change
Expand Up @@ -661,7 +661,7 @@ func (m *Miniredis) cmdSscan(c *server.Peer, cmd string, args []string) {

members := db.setMembers(key)
if withMatch {
members = matchKeys(members, match)
members, _ = matchKeys(members, match)
}

c.WriteLen(2)
Expand Down
5 changes: 2 additions & 3 deletions cmd_sorted_set.go
Original file line number Diff line number Diff line change
Expand Up @@ -1360,8 +1360,7 @@ func (m *Miniredis) cmdZscan(c *server.Peer, cmd string, args []string) {

withTx(m, c, func(c *server.Peer, ctx *connCtx) {
db := m.db(ctx.selectedDB)
// We return _all_ (matched) keys every time.

// Paging is not implementend, all results are returned for cursor 0.
if cursor != 0 {
// Invalid cursor.
c.WriteLen(2)
Expand All @@ -1376,7 +1375,7 @@ func (m *Miniredis) cmdZscan(c *server.Peer, cmd string, args []string) {

members := db.ssetMembers(key)
if withMatch {
members = matchKeys(members, match)
members, _ = matchKeys(members, match)
}

c.WriteLen(2)
Expand Down
14 changes: 12 additions & 2 deletions integration/sorted_set_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,17 @@ func TestSortedSet(t *testing.T) {
succ("DEL", "z2"),
succ("EXISTS", "z2"),
)

testCommands(t,
succ("ZADD", "z", 0, "new\nline\n"),
succ("ZADD", "z", 0, "line"),
succ("ZADD", "z", 0, "another\nnew\nline\n"),
succ("ZSCAN", "z", 0, "MATCH", "*"),
succ("ZRANGEBYLEX", "z", "[a", "[z"),
succ("ZRANGE", "z", 0, -1, "WITHSCORES"),
)
}

func TestSortedSetAdd(t *testing.T) {
testCommands(t,
succ("ZADD", "z",
Expand Down Expand Up @@ -484,8 +494,8 @@ func TestSortedSetRangeByLex(t *testing.T) {
fail("ZRANGEBYLEX", "key", "!a", "[b"),
fail("ZRANGEBYLEX", "key", "[a", "!b"),
fail("ZRANGEBYLEX", "key", "[a", "b]"),
fail("ZRANGEBYLEX", "key", "[a", ""),
fail("ZRANGEBYLEX", "key", "", "[b"),
failWith("not valid string range item", "ZRANGEBYLEX", "key", "[a", ""),
failWith("not valid string range item", "ZRANGEBYLEX", "key", "", "[b"),
fail("ZRANGEBYLEX", "key", "[a", "[b", "LIMIT"),
fail("ZRANGEBYLEX", "key", "[a", "[b", "LIMIT", 1),
fail("ZRANGEBYLEX", "key", "[a", "[b", "LIMIT", "a", 1),
Expand Down
2 changes: 1 addition & 1 deletion integration/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func fail(cmd string, args ...interface{}) command {
}
}

// expect an error, with `sub` in both errors
// expect an error, with both errors containing `sub`
func failWith(sub string, cmd string, args ...interface{}) command {
return command{
cmd: cmd,
Expand Down
20 changes: 19 additions & 1 deletion keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
// The general strategy is to sandwich all non-meta characters between \Q...\E.
func patternRE(k string) *regexp.Regexp {
re := bytes.Buffer{}
re.WriteString(`^\Q`)
re.WriteString(`(?s)^\Q`)
for i := 0; i < len(k); i++ {
p := k[i]
switch p {
Expand Down Expand Up @@ -63,3 +63,21 @@ func patternRE(k string) *regexp.Regexp {
re.WriteString(`\E$`)
return regexp.MustCompile(re.String())
}

// matchKeys filters only matching keys.
// The returned boolean is whether the match pattern was valid
func matchKeys(keys []string, match string) ([]string, bool) {
re := patternRE(match)
if re == nil {
// Special case: the given pattern won't match anything or is invalid.
return nil, false
}
var res []string
for _, k := range keys {
if !re.MatchString(k) {
continue
}
res = append(res, k)
}
return res, true
}
19 changes: 19 additions & 0 deletions keys_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,22 @@ func TestKeysSel(t *testing.T) {
test2(`[]ap`) // empty char class
test2(`ap\`) // trailing \
}

func TestMatchKeys(t *testing.T) {
t.Run("simple", func(t *testing.T) {
m, ok := matchKeys([]string{"a", "b", "c"}, "*")
equals(t, true, ok)
equals(t, []string{"a", "b", "c"}, m)
})

t.Run("newlines", func(t *testing.T) {
m, ok := matchKeys([]string{"a", "b\nb", "c"}, "*")
equals(t, true, ok)
equals(t, []string{"a", "b\nb", "c"}, m)
})

t.Run("invalid", func(t *testing.T) {
_, ok := matchKeys([]string{"a", "b", "c"}, "[")
equals(t, false, ok)
})
}
19 changes: 0 additions & 19 deletions redis.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,22 +188,3 @@ func redisRange(l, start, end int, stringSymantics bool) (int, int) {
}
return start, end
}

// matchKeys filters only matching keys.
// Will return an empty list on invalid match expression.
func matchKeys(keys []string, match string) []string {
re := patternRE(match)
if re == nil {
// Special case, the given pattern won't match anything / is
// invalid.
return nil
}
res := []string{}
for _, k := range keys {
if !re.MatchString(k) {
continue
}
res = append(res, k)
}
return res
}

0 comments on commit ce66b76

Please sign in to comment.