From f0f314dbea95c9a43d6abd9b4bf30b0bea7e7a2d Mon Sep 17 00:00:00 2001 From: Harmen Date: Wed, 24 Sep 2025 10:02:03 +0200 Subject: [PATCH 1/2] un-implent "SCAN COUNT" so cursors work as they should --- cmd_generic.go | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/cmd_generic.go b/cmd_generic.go index 2f55d5f..ea46203 100644 --- a/cmd_generic.go +++ b/cmd_generic.go @@ -649,7 +649,8 @@ func (m *Miniredis) cmdScan(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. + // We return _all_ (matched) keys every time, so that cursors work. + // We ignore "COUNT", which is allowed according to the Redis docs. var keys []string if opts.withType { @@ -670,24 +671,27 @@ func (m *Miniredis) cmdScan(c *server.Peer, cmd string, args []string) { keys, _ = matchKeys(keys, opts.match) } - low := opts.cursor - high := low + opts.count - // validate high is correct - if high > len(keys) || high == 0 { - high = len(keys) - } - if opts.cursor > high { - // invalid cursor - c.WriteLen(2) - c.WriteBulk("0") // no next cursor - c.WriteLen(0) // no elements - return - } - cursorValue := low + opts.count - if cursorValue >= len(keys) { - cursorValue = 0 // no next cursor - } - keys = keys[low:high] + cursorValue := 0 // we don't use cursors + /* + low := opts.cursor + high := low + opts.count + // validate high is correct + if high > len(keys) || high == 0 { + high = len(keys) + } + if opts.cursor > high { + // invalid cursor + c.WriteLen(2) + c.WriteBulk("0") // no next cursor + c.WriteLen(0) // no elements + return + } + cursorValue := low + opts.count + if cursorValue >= len(keys) { + cursorValue = 0 // no next cursor + } + keys = keys[low:high] + */ c.WriteLen(2) c.WriteBulk(fmt.Sprintf("%d", cursorValue)) From a4ae737f4b69e00d5d85689f30b29d6e05b85455 Mon Sep 17 00:00:00 2001 From: Harmen Date: Wed, 24 Sep 2025 10:17:09 +0200 Subject: [PATCH 2/2] fix tests --- cmd_generic.go | 28 +++++++--------------------- cmd_generic_test.go | 18 +++++++++++------- 2 files changed, 18 insertions(+), 28 deletions(-) diff --git a/cmd_generic.go b/cmd_generic.go index ea46203..d030888 100644 --- a/cmd_generic.go +++ b/cmd_generic.go @@ -671,28 +671,14 @@ func (m *Miniredis) cmdScan(c *server.Peer, cmd string, args []string) { keys, _ = matchKeys(keys, opts.match) } + // we only ever return all at once, so no non-zero cursor can every be valid + if opts.cursor != 0 { + c.WriteLen(2) + c.WriteBulk("0") // no next cursor + c.WriteLen(0) // no elements + return + } cursorValue := 0 // we don't use cursors - /* - low := opts.cursor - high := low + opts.count - // validate high is correct - if high > len(keys) || high == 0 { - high = len(keys) - } - if opts.cursor > high { - // invalid cursor - c.WriteLen(2) - c.WriteBulk("0") // no next cursor - c.WriteLen(0) // no elements - return - } - cursorValue := low + opts.count - if cursorValue >= len(keys) { - cursorValue = 0 // no next cursor - } - keys = keys[low:high] - */ - c.WriteLen(2) c.WriteBulk(fmt.Sprintf("%d", cursorValue)) c.WriteLen(len(keys)) diff --git a/cmd_generic_test.go b/cmd_generic_test.go index 3994bac..f2faf62 100644 --- a/cmd_generic_test.go +++ b/cmd_generic_test.go @@ -758,14 +758,22 @@ func TestScan(t *testing.T) { s.Set("v8", "value") s.Set("v9", "value") + // count is ignored mustDo(t, c, "SCAN", "0", "COUNT", "3", proto.Array( - proto.String("3"), + proto.String("0"), proto.Array( proto.String("key"), proto.String("v1"), proto.String("v2"), + proto.String("v3"), + proto.String("v4"), + proto.String("v5"), + proto.String("v6"), + proto.String("v7"), + proto.String("v8"), + proto.String("v9"), ), ), ) @@ -773,12 +781,8 @@ func TestScan(t *testing.T) { mustDo(t, c, "SCAN", "3", "COUNT", "3", proto.Array( - proto.String("6"), - proto.Array( - proto.String("v3"), - proto.String("v4"), - proto.String("v5"), - ), + proto.String("0"), + proto.Array(), ), ) })