stipsan / ioredis-mock

Emulates ioredis by performing all operations in-memory.
MIT License
333 stars 125 forks source link

Bug: while scanning, removing elements may hide other elements #1348

Open moritzraho opened 1 month ago

moritzraho commented 1 month ago

See https://github.com/stipsan/ioredis-mock/blob/main/src/commands-utils/scan-command.common.js#L55

The start cursor may not accurately point to the "end" index of the last iteration when elements were removed in between calls.

moritzraho commented 1 month ago

workaround patch (iterate from last element and adjust cursor if there are deleted elements)

diff --git a/node_modules/ioredis-mock/lib/index.js b/node_modules/ioredis-mock/lib/index.js
index a82c297..475598c 100644
--- a/node_modules/ioredis-mock/lib/index.js
+++ b/node_modules/ioredis-mock/lib/index.js
@@ -4260,13 +4276,14 @@ function scanHelper(allKeysOrEntries, size, cursorStart, ...args) {
   let cursor = parseInt(cursorStart, 10);
   if (Number.isNaN(cursor))
     throw new Error("Cursor must be integer");
-  let [count, matchPattern] = getCountAndMatch(args), nextCursor = cursor + count, keysOrEntries = allKeysOrEntries.slice(cursor, nextCursor);
+  const internalCursor = cursor === 0 ? allKeysOrEntries.length: Math.min(cursor, allKeysOrEntries.length)
+  let [count, matchPattern] = getCountAndMatch(args), nextCursor = Math.max(internalCursor - count, 0), keysOrEntries = allKeysOrEntries.slice(nextCursor, internalCursor);
   if (matchPattern) {
     let i = 0;
     for (; i < keysOrEntries.length; )
       matchPattern(keysOrEntries[i]) ? i += size : keysOrEntries.splice(i, size);
   }
-  return nextCursor >= allKeysOrEntries.length && (nextCursor = 0), [String(nextCursor), keysOrEntries];
+  return [String(nextCursor), keysOrEntries];
 }