"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.paginate = void 0; const content = `--[[ Paginate a set or hash Input: KEYS[1] key pointing to the set or hash to be paginated. ARGV[1] page start offset ARGV[2] page end offset (-1 for all the elements) ARGV[3] cursor ARGV[4] offset ARGV[5] max iterations ARGV[6] fetch jobs? Output: [cursor, offset, items, numItems] ]] local rcall = redis.call -- Includes --[[ Function to achieve pagination for a set or hash. This function simulates pagination in the most efficient way possible for a set using sscan or hscan. The main limitation is that sets are not order preserving, so the pagination is not stable. This means that if the set is modified between pages, the same element may appear in different pages. ]] -- Maximum number of elements to be returned by sscan per iteration. local maxCount = 100 -- Finds the cursor, and returns the first elements available for the requested page. local function findPage(key, command, pageStart, pageSize, cursor, offset, maxIterations, fetchJobs) local items = {} local jobs = {} local iterations = 0 repeat -- Iterate over the set using sscan/hscan. local result = rcall(command, key, cursor, "COUNT", maxCount) cursor = result[1] local members = result[2] local step = 1 if command == "HSCAN" then step = 2 end if #members == 0 then -- If the result is empty, we can return the result. return cursor, offset, items, jobs end local chunkStart = offset local chunkEnd = offset + #members / step local pageEnd = pageStart + pageSize if chunkEnd < pageStart then -- If the chunk is before the page, we can skip it. offset = chunkEnd elseif chunkStart > pageEnd then -- If the chunk is after the page, we can return the result. return cursor, offset, items, jobs else -- If the chunk is overlapping the page, we need to add the elements to the result. for i = 1, #members, step do if offset >= pageEnd then return cursor, offset, items, jobs end if offset >= pageStart then local index = #items + 1 if fetchJobs ~= nil then jobs[#jobs+1] = rcall("HGETALL", members[i]) end if step == 2 then items[index] = {members[i], members[i + 1]} else items[index] = members[i] end end offset = offset + 1 end end iterations = iterations + 1 until cursor == "0" or iterations >= maxIterations return cursor, offset, items, jobs end local key = KEYS[1] local scanCommand = "SSCAN" local countCommand = "SCARD" local type = rcall("TYPE", key)["ok"] if type == "none" then return {0, 0, {}, 0} elseif type == "hash" then scanCommand = "HSCAN" countCommand = "HLEN" elseif type ~= "set" then return redis.error_reply("Pagination is only supported for sets and hashes.") end local numItems = rcall(countCommand, key) local startOffset = tonumber(ARGV[1]) local endOffset = tonumber(ARGV[2]) if endOffset == -1 then endOffset = numItems end local pageSize = (endOffset - startOffset) + 1 local cursor, offset, items, jobs = findPage(key, scanCommand, startOffset, pageSize, ARGV[3], tonumber(ARGV[4]), tonumber(ARGV[5]), ARGV[6]) return {cursor, offset, items, numItems, jobs} `; exports.paginate = { name: 'paginate', content, keys: 1, }; //# sourceMappingURL=paginate-1.js.map