Adds support for skips and limits to queryIter

This commit is contained in:
Ben 2024-05-14 09:48:46 +02:00
parent e6ba737764
commit 9dc532b856
No known key found for this signature in database
GPG Key ID: 541B9D8C9F1426A1
2 changed files with 60 additions and 9 deletions

View File

@ -426,25 +426,37 @@ proc getIterValue(iterPtr: ptr leveldb_iterator_t): string =
str = leveldb_iter_value(iterPtr, addr len)
return newString(str, len)
proc queryIter*(self: LevelDb, prefix: string = "", keysOnly: bool = false): LevelDbQueryIter =
var iterPtr = leveldb_create_iterator(self.db, self.readOptions)
proc seekToQueryStart(iterPtr: ptr leveldb_iterator_t, prefix: string, skip: int) =
if prefix.len > 0:
leveldb_iter_seek(iterPtr, prefix, prefix.len.csize_t)
else:
leveldb_iter_seek_to_first(iterPtr)
for i in 0..<skip:
leveldb_iter_next(iterPtr)
var iter = LevelDbQueryIter()
proc closeIter(iter: LevelDbQueryIter, iterPtr: ptr leveldb_iterator_t) =
iter.finished = true
leveldb_iter_destroy(iterPtr)
proc queryIter*(self: LevelDb, prefix: string = "", keysOnly: bool = false, skip: int = 0, limit: int = 0): LevelDbQueryIter =
var iterPtr = leveldb_create_iterator(self.db, self.readOptions)
seekToQueryStart(iterPtr, prefix, skip)
var
iter = LevelDbQueryIter()
remaining = limit
let emptyResponse = ("", "")
proc getNext(): (string, string) {.gcsafe, closure.} =
if iter.finished:
return emptyResponse
if leveldb_iter_valid(iterPtr) == levelDbFalse:
iter.finished = true
leveldb_iter_destroy(iterPtr)
if leveldb_iter_valid(iterPtr) == levelDbFalse or (limit > 0 and remaining == 0):
iter.closeIter(iterPtr)
return emptyResponse
if limit > 0:
dec remaining
let
keyStr = getIterKey(iterPtr)
@ -460,8 +472,7 @@ proc queryIter*(self: LevelDb, prefix: string = "", keysOnly: bool = false): Lev
if keyStr.startsWith(prefix):
return (keyStr, valueStr)
else:
iter.finished = true
leveldb_iter_destroy(iterPtr)
iter.closeIter(iterPtr)
return emptyResponse
else:
return (keyStr, valueStr)

View File

@ -241,6 +241,28 @@ suite "leveldb queryIter":
iter.next() == empty
iter.finished
test "skip":
let iter = db.queryIter(skip = 1)
check:
not iter.finished
iter.next() == (k2, v2)
not iter.finished
iter.next() == (k3, v3)
not iter.finished
iter.next() == empty
iter.finished
test "limit":
let iter = db.queryIter(limit = 2)
check:
not iter.finished
iter.next() == (k1, v1)
not iter.finished
iter.next() == (k2, v2)
not iter.finished
iter.next() == empty
iter.finished
test "iterates only keys":
let iter = db.queryIter(keysOnly = true)
check:
@ -265,6 +287,24 @@ suite "leveldb queryIter":
iter.next() == empty
iter.finished
test "iterates only 'k', skip":
let iter = db.queryIter(prefix = "k", skip = 1)
check:
not iter.finished
iter.next() == (k2, v2)
not iter.finished
iter.next() == empty
iter.finished
test "iterate only 'k', limit":
let iter = db.queryIter(prefix = "k", limit = 1)
check:
not iter.finished
iter.next() == (k1, v1)
not iter.finished
iter.next() == empty
iter.finished
test "iterates only 'k', only keys":
let iter = db.queryIter(prefix = "k", keysOnly = true)
check: