Compare commits

..

No commits in common. "master" and "0.1.0" have entirely different histories.

11 changed files with 129 additions and 494 deletions

View File

@ -8,15 +8,14 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest, macOS-latest, windows-latest]
nim: [stable, 1.6.18, 2.0.12]
nim: [stable, 1.6.18]
steps:
- uses: actions/checkout@v2
with:
submodules: true
- uses: jiro4989/setup-nim-action@v2
- uses: iffy/install-nim@v4
with:
nim-version: ${{matrix.nim}}
repo-token: ${{ secrets.GITHUB_TOKEN }}
version: ${{ matrix.nim }}
- name: Build
run: nimble install -y
- name: Test

3
.gitignore vendored
View File

@ -8,5 +8,4 @@ leveldbtool
*.html
*.css
build
nimbledeps
*.exe

View File

@ -6,8 +6,6 @@ Original nim LevelDB wrapper: [HERE](https://github.com/zielmicha/leveldb.nim)
Replacing of system library dependency with self-contained C/CPP interoperability by (Codex.Storage)[https://codex.storage]
## Usage
Create a database:
```Nim
import leveldbstatic
@ -51,25 +49,3 @@ Iterate over subset of database content:
db.close()
```
## Compiling with optimizations
CMake is used during compilation to determine which of the following optimization options are enabled. You can set the following nim compiler flags to 0 or 1 to override them:
- fdatasync from <unistd.h> `--passC:-DHAVE_FDATASYNC=1`
- F_FULLSYNC from <fcntl.h> `--passC:-DHAVE_FULLFSYNC=1`
- O_CLOEXEC from <fcntl.h> `--passC:-DHAVE_O_CLOEXEC=1`
- crc32c from <crc32c/crc32c.h> `--passC:-DHAVE_CRC32C=1`
- snappy from <snappy.h> `--passC:-DHAVE_SNAPPY=1`
- zstd from <zstd.h> `--passC:-DHAVE_ZSTD=1`
## Updating
When you want to update this library to a new version of LevelDB, follow these steps:
- Update LevelDB submodule to new version.
- Run 'build.sh'.
- Run 'nimble build' and 'nimble test'.
- Make sure everything's working.
- Increment version of this library in 'leveldbstatic.nimble'.
- Commit the changes.
- Tag the commit with the new version number.
- Push.

View File

@ -21,7 +21,7 @@ rm -Rf "${sourceDir}/benchmarks"
rm "${sourceDir}/util/testutil.cc"
# Prelude:
cat "${root}/leveldbstatic/prelude.nim" > "${output}"
cat "${root}/leveldb/prelude.nim" > "${output}"
echo >> "${output}"
# assemble files to be compiled:
@ -47,8 +47,10 @@ toast \
--includeDirs="${sourceDir}/helpers/memenv" \
--includeDirs="${sourceDir}/port" \
--includeDirs="${sourceDir}/include" \
--includeDirs="${buildDir}/include" \
"${sourceDir}/include/leveldb/c.h" >> "${output}"
sed -i 's/\bpassC\b/passc/g' "${output}"
sed -i 's/{\.compile\:\ \"\./{\.compile\:\ root\ \&\ \"/g' "${output}"
sed -i 's/{\.passc\:\ \"-I\./{\.passc\:\ \"-I\"\ \&\ root\ \&\ \"/g' "${output}"

View File

View File

@ -0,0 +1,38 @@
// Copyright 2017 The LevelDB Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors.
#ifndef STORAGE_LEVELDB_PORT_PORT_CONFIG_H_
#define STORAGE_LEVELDB_PORT_PORT_CONFIG_H_
// Define to 1 if you have a definition for fdatasync() in <unistd.h>.
#if !defined(HAVE_FDATASYNC)
#define HAVE_FDATASYNC 1
#endif // !defined(HAVE_FDATASYNC)
// Define to 1 if you have a definition for F_FULLFSYNC in <fcntl.h>.
#if !defined(HAVE_FULLFSYNC)
#define HAVE_FULLFSYNC 0
#endif // !defined(HAVE_FULLFSYNC)
// Define to 1 if you have a definition for O_CLOEXEC in <fcntl.h>.
#if !defined(HAVE_O_CLOEXEC)
#define HAVE_O_CLOEXEC 1
#endif // !defined(HAVE_O_CLOEXEC)
// Define to 1 if you have Google CRC32C.
#if !defined(HAVE_CRC32C)
#define HAVE_CRC32C 0
#endif // !defined(HAVE_CRC32C)
// Define to 1 if you have Google Snappy.
#if !defined(HAVE_SNAPPY)
#define HAVE_SNAPPY 0
#endif // !defined(HAVE_SNAPPY)
// Define to 1 if you have Zstd.
#if !defined(HAVE_Zstd)
#define HAVE_ZSTD 0
#endif // !defined(HAVE_ZSTD)
#endif // STORAGE_LEVELDB_PORT_PORT_CONFIG_H_

View File

@ -76,13 +76,6 @@ type
LevelDbException* = object of CatchableError
IterNext* = proc(): (string, string) {.gcsafe, closure, raises: [LevelDbException].}
IterDispose* = proc() {.gcsafe, closure, raises: [].}
LevelDbQueryIter* = ref object
finished*: bool
next*: IterNext
dispose*: IterDispose
const
version* = block:
const configFile = "leveldbstatic.nimble"
@ -413,81 +406,6 @@ iterator iterRange*(self: LevelDb, start, limit: string): (string, string) =
break
yield (key, value)
proc getIterKey(iterPtr: ptr leveldb_iterator_t): string =
var len: csize_t
var str: cstring
str = leveldb_iter_key(iterPtr, addr len)
return newString(str, len)
proc getIterValue(iterPtr: ptr leveldb_iterator_t): string =
var len: csize_t
var str: cstring
str = leveldb_iter_value(iterPtr, addr len)
return newString(str, len)
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)
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 or (limit > 0 and remaining == 0):
iter.closeIter(iterPtr)
return emptyResponse
if limit > 0:
dec remaining
let
keyStr = getIterKey(iterPtr)
valueStr = if keysOnly: "" else: getIterValue(iterPtr)
var err: cstring = nil
leveldb_iter_get_error(iterPtr, addr err)
checkError(err)
leveldb_iter_next(iterPtr)
if prefix.len > 0:
if keyStr.startsWith(prefix):
return (keyStr, valueStr)
else:
iter.closeIter(iterPtr)
return emptyResponse
else:
return (keyStr, valueStr)
proc dispose() {.gcsafe, closure.} =
if not iter.finished:
iter.closeIter(iterPtr)
iter.finished = false
iter.next = getNext
iter.dispose = dispose
return iter
proc removeDb*(name: string) =
## Remove the database `name`.
var err: cstring = nil

View File

@ -1,6 +1,6 @@
# Package
version = "0.2.1"
version = "0.1.0"
author = "leveldbstatic authors"
description = "Statically linked LevelDB wrapper for Nim"
license = "MIT"

View File

@ -1,46 +1,8 @@
import os
const
root = currentSourcePath.parentDir.parentDir
envWindows = root/"vendor"/"util"/"env_windows.cc"
envPosix = root/"vendor"/"util"/"env_posix.cc"
LevelDbCMakeFlags {.strdefine.} =
when defined(macosx):
"-DCMAKE_BUILD_TYPE=Release -DLEVELDB_BUILD_BENCHMARKS=OFF"
elif defined(windows):
"-G\"MSYS Makefiles\" -DCMAKE_BUILD_TYPE=Release -DLEVELDB_BUILD_BENCHMARKS=OFF"
else:
"-DCMAKE_BUILD_TYPE=Release -DLEVELDB_BUILD_BENCHMARKS=OFF"
LevelDbCMakeCommonFlags = " -DCMAKE_POLICY_VERSION_MINIMUM=3.31"
LevelDbDir {.strdefine.} = $(root/"vendor")
buildDir = $(root/"build")
proc buildLevelDb() =
if fileExists(buildDir/"Makefile"):
echo "LevelDB already build. Delete '" & buildDir & "' to force rebuild."
return
echo "Initializing submodule..."
discard gorge "git submodule deinit -f \"" & root & "\""
discard gorge "git submodule update --init --recursive --checkout \"" & root & "\""
echo "\nClean dir: \"" & buildDir & "\""
discard gorge "rm -rf " & buildDir
discard gorge "mkdir -p " & buildDir
let cmd = "cmake -S \"" & LevelDbDir & "\" -B \"" & buildDir & "\" " & LevelDbCMakeFlags & LevelDbCMakeCommonFlags
echo "\nBuilding LevelDB: " & cmd
let (output, exitCode) = gorgeEx cmd
if exitCode != 0:
discard gorge "rm -rf " & buildDir
echo output
raise (ref Defect)(msg: "Failed to build LevelDB")
static:
buildLevelDb()
const root = currentSourcePath.parentDir.parentDir
const envWindows = root/"vendor"/"util"/"env_windows.cc"
const envPosix = root/"vendor"/"util"/"env_posix.cc"
when defined(windows):
{.compile: envWindows.}
@ -51,3 +13,13 @@ when defined(windows):
when defined(posix):
{.compile: envPosix.}
{.passc: "-DLEVELDB_PLATFORM_POSIX".}
{.passc: "-DHAVE_FDATASYNC=0".}
{.passc: "-DHAVE_FULLFSYNC=0".}
{.passc: "-DHAVE_O_CLOEXEC=0".}
{.passc: "-DHAVE_CRC32C=0".}
{.passc: "-DHAVE_SNAPPY=0".}
{.passc: "-DHAVE_ZSTD=0".}
{.passc: "-DHAVE_Zstd=0".}

View File

@ -1,46 +1,8 @@
import os
const
root = currentSourcePath.parentDir.parentDir
envWindows = root/"vendor"/"util"/"env_windows.cc"
envPosix = root/"vendor"/"util"/"env_posix.cc"
LevelDbCMakeFlags {.strdefine.} =
when defined(macosx):
"-DCMAKE_BUILD_TYPE=Release -DLEVELDB_BUILD_BENCHMARKS=OFF"
elif defined(windows):
"-G\"MSYS Makefiles\" -DCMAKE_BUILD_TYPE=Release -DLEVELDB_BUILD_BENCHMARKS=OFF"
else:
"-DCMAKE_BUILD_TYPE=Release -DLEVELDB_BUILD_BENCHMARKS=OFF"
LevelDbCMakeCommonFlags = " -DCMAKE_POLICY_VERSION_MINIMUM=3.31"
LevelDbDir {.strdefine.} = $(root/"vendor")
buildDir = $(root/"build")
proc buildLevelDb() =
if fileExists(buildDir/"Makefile"):
echo "LevelDB already build. Delete '" & buildDir & "' to force rebuild."
return
echo "Initializing submodule..."
discard gorge "git submodule deinit -f \"" & root & "\""
discard gorge "git submodule update --init --recursive --checkout \"" & root & "\""
echo "\nClean dir: \"" & buildDir & "\""
discard gorge "rm -rf " & buildDir
discard gorge "mkdir -p " & buildDir
let cmd = "cmake -S \"" & LevelDbDir & "\" -B \"" & buildDir & "\" " & LevelDbCMakeFlags & LevelDbCMakeCommonFlags
echo "\nBuilding LevelDB: " & cmd
let (output, exitCode) = gorgeEx cmd
if exitCode != 0:
discard gorge "rm -rf " & buildDir
echo output
raise (ref Defect)(msg: "Failed to build LevelDB")
static:
buildLevelDb()
const root = currentSourcePath.parentDir.parentDir
const envWindows = root/"vendor"/"util"/"env_windows.cc"
const envPosix = root/"vendor"/"util"/"env_posix.cc"
when defined(windows):
{.compile: envWindows.}
@ -52,9 +14,19 @@ when defined(posix):
{.compile: envPosix.}
{.passc: "-DLEVELDB_PLATFORM_POSIX".}
# Generated @ 2024-12-09T16:35:09+01:00
{.passc: "-DHAVE_FDATASYNC=0".}
{.passc: "-DHAVE_FULLFSYNC=0".}
{.passc: "-DHAVE_O_CLOEXEC=0".}
{.passc: "-DHAVE_CRC32C=0".}
{.passc: "-DHAVE_SNAPPY=0".}
{.passc: "-DHAVE_ZSTD=0".}
{.passc: "-DHAVE_Zstd=0".}
# Generated @ 2024-05-13T12:00:58+02:00
# Command line:
# /home/arnaud/.nimble/pkgs2/nimterop-0.6.13-a93246b2ad5531db11e51de7b2d188c42d95576a/nimterop/toast --compile=./vendor/util/bloom.cc --compile=./vendor/util/arena.cc --compile=./vendor/util/env.cc --compile=./vendor/util/filter_policy.cc --compile=./vendor/util/histogram.cc --compile=./vendor/util/hash.cc --compile=./vendor/util/comparator.cc --compile=./vendor/util/options.cc --compile=./vendor/util/logging.cc --compile=./vendor/util/status.cc --compile=./vendor/util/coding.cc --compile=./vendor/util/cache.cc --compile=./vendor/util/crc32c.cc --compile=./vendor/table/table.cc --compile=./vendor/table/format.cc --compile=./vendor/table/table_builder.cc --compile=./vendor/table/block_builder.cc --compile=./vendor/table/merger.cc --compile=./vendor/table/block.cc --compile=./vendor/table/filter_block.cc --compile=./vendor/table/iterator.cc --compile=./vendor/table/two_level_iterator.cc --compile=./vendor/helpers/memenv/memenv.cc --compile=./vendor/db/filename.cc --compile=./vendor/db/dbformat.cc --compile=./vendor/db/c.cc --compile=./vendor/db/memtable.cc --compile=./vendor/db/version_set.cc --compile=./vendor/db/repair.cc --compile=./vendor/db/builder.cc --compile=./vendor/db/write_batch.cc --compile=./vendor/db/version_edit.cc --compile=./vendor/db/dumpfile.cc --compile=./vendor/db/db_impl.cc --compile=./vendor/db/log_reader.cc --compile=./vendor/db/table_cache.cc --compile=./vendor/db/db_iter.cc --compile=./vendor/db/log_writer.cc --pnim --preprocess --noHeader --includeDirs=./vendor --includeDirs=./vendor/helpers --includeDirs=./vendor/helpers/memenv --includeDirs=./vendor/port --includeDirs=./vendor/include ./vendor/include/leveldb/c.h
# /home/ben/.nimble/pkgs/nimterop-0.6.13/nimterop/toast --compile=./vendor/db/log_writer.cc --compile=./vendor/db/db_impl.cc --compile=./vendor/db/db_iter.cc --compile=./vendor/db/dumpfile.cc --compile=./vendor/db/c.cc --compile=./vendor/db/builder.cc --compile=./vendor/db/filename.cc --compile=./vendor/db/write_batch.cc --compile=./vendor/db/table_cache.cc --compile=./vendor/db/version_edit.cc --compile=./vendor/db/dbformat.cc --compile=./vendor/db/log_reader.cc --compile=./vendor/db/memtable.cc --compile=./vendor/db/version_set.cc --compile=./vendor/db/repair.cc --compile=./vendor/table/block.cc --compile=./vendor/table/two_level_iterator.cc --compile=./vendor/table/table_builder.cc --compile=./vendor/table/iterator.cc --compile=./vendor/table/block_builder.cc --compile=./vendor/table/merger.cc --compile=./vendor/table/format.cc --compile=./vendor/table/filter_block.cc --compile=./vendor/table/table.cc --compile=./vendor/util/hash.cc --compile=./vendor/util/arena.cc --compile=./vendor/util/options.cc --compile=./vendor/util/histogram.cc --compile=./vendor/util/crc32c.cc --compile=./vendor/util/env.cc --compile=./vendor/util/filter_policy.cc --compile=./vendor/util/bloom.cc --compile=./vendor/util/logging.cc --compile=./vendor/util/coding.cc --compile=./vendor/util/status.cc --compile=./vendor/util/cache.cc --compile=./vendor/util/comparator.cc --compile=./vendor/helpers/memenv/memenv.cc --pnim --preprocess --noHeader --includeDirs=./vendor --includeDirs=./vendor/helpers --includeDirs=./vendor/helpers/memenv --includeDirs=./vendor/port --includeDirs=./vendor/include --includeDirs=./build/include ./vendor/include/leveldb/c.h
{.push hint[ConvFromXtoItselfNotNeeded]: off.}
import macros
@ -107,44 +79,45 @@ macro defineEnum(typ: untyped): untyped =
{.passc: "-I" & root & "/vendor/helpers/memenv".}
{.passc: "-I" & root & "/vendor/port".}
{.passc: "-I" & root & "/vendor/include".}
{.compile: root & "/vendor/util/bloom.cc".}
{.compile: root & "/vendor/util/arena.cc".}
{.compile: root & "/vendor/util/env.cc".}
{.compile: root & "/vendor/util/filter_policy.cc".}
{.compile: root & "/vendor/util/histogram.cc".}
{.compile: root & "/vendor/util/hash.cc".}
{.compile: root & "/vendor/util/comparator.cc".}
{.compile: root & "/vendor/util/options.cc".}
{.compile: root & "/vendor/util/logging.cc".}
{.compile: root & "/vendor/util/status.cc".}
{.compile: root & "/vendor/util/coding.cc".}
{.compile: root & "/vendor/util/cache.cc".}
{.compile: root & "/vendor/util/crc32c.cc".}
{.compile: root & "/vendor/table/table.cc".}
{.compile: root & "/vendor/table/format.cc".}
{.compile: root & "/vendor/table/table_builder.cc".}
{.compile: root & "/vendor/table/block_builder.cc".}
{.compile: root & "/vendor/table/merger.cc".}
{.compile: root & "/vendor/table/block.cc".}
{.compile: root & "/vendor/table/filter_block.cc".}
{.compile: root & "/vendor/table/iterator.cc".}
{.compile: root & "/vendor/table/two_level_iterator.cc".}
{.compile: root & "/vendor/helpers/memenv/memenv.cc".}
{.compile: root & "/vendor/db/filename.cc".}
{.compile: root & "/vendor/db/dbformat.cc".}
{.passc: "-I" & root & "/build/include".}
{.compile: root & "/vendor/db/log_writer.cc".}
{.compile: root & "/vendor/db/db_impl.cc".}
{.compile: root & "/vendor/db/db_iter.cc".}
{.compile: root & "/vendor/db/dumpfile.cc".}
{.compile: root & "/vendor/db/c.cc".}
{.compile: root & "/vendor/db/builder.cc".}
{.compile: root & "/vendor/db/filename.cc".}
{.compile: root & "/vendor/db/write_batch.cc".}
{.compile: root & "/vendor/db/table_cache.cc".}
{.compile: root & "/vendor/db/version_edit.cc".}
{.compile: root & "/vendor/db/dbformat.cc".}
{.compile: root & "/vendor/db/log_reader.cc".}
{.compile: root & "/vendor/db/memtable.cc".}
{.compile: root & "/vendor/db/version_set.cc".}
{.compile: root & "/vendor/db/repair.cc".}
{.compile: root & "/vendor/db/builder.cc".}
{.compile: root & "/vendor/db/write_batch.cc".}
{.compile: root & "/vendor/db/version_edit.cc".}
{.compile: root & "/vendor/db/dumpfile.cc".}
{.compile: root & "/vendor/db/db_impl.cc".}
{.compile: root & "/vendor/db/log_reader.cc".}
{.compile: root & "/vendor/db/table_cache.cc".}
{.compile: root & "/vendor/db/db_iter.cc".}
{.compile: root & "/vendor/db/log_writer.cc".}
{.compile: root & "/vendor/table/block.cc".}
{.compile: root & "/vendor/table/two_level_iterator.cc".}
{.compile: root & "/vendor/table/table_builder.cc".}
{.compile: root & "/vendor/table/iterator.cc".}
{.compile: root & "/vendor/table/block_builder.cc".}
{.compile: root & "/vendor/table/merger.cc".}
{.compile: root & "/vendor/table/format.cc".}
{.compile: root & "/vendor/table/filter_block.cc".}
{.compile: root & "/vendor/table/table.cc".}
{.compile: root & "/vendor/util/hash.cc".}
{.compile: root & "/vendor/util/arena.cc".}
{.compile: root & "/vendor/util/options.cc".}
{.compile: root & "/vendor/util/histogram.cc".}
{.compile: root & "/vendor/util/crc32c.cc".}
{.compile: root & "/vendor/util/env.cc".}
{.compile: root & "/vendor/util/filter_policy.cc".}
{.compile: root & "/vendor/util/bloom.cc".}
{.compile: root & "/vendor/util/logging.cc".}
{.compile: root & "/vendor/util/coding.cc".}
{.compile: root & "/vendor/util/status.cc".}
{.compile: root & "/vendor/util/cache.cc".}
{.compile: root & "/vendor/util/comparator.cc".}
{.compile: root & "/vendor/helpers/memenv/memenv.cc".}
defineEnum(Enum_ch1)
const
leveldb_no_compression* = (0).cint

View File

@ -21,10 +21,7 @@ proc execNimble(args: varargs[string]): tuple[output: string, exitCode: int] =
quotedArgs.insert("-y")
quotedArgs.insert("--nimbleDir:" & tmpNimbleDir)
quotedArgs.insert("nimble")
quotedArgs = quotedArgs.map(
proc(x: string): string =
"\"" & x & "\""
)
quotedArgs = quotedArgs.map(proc (x: string): string = "\"" & x & "\"")
let cmd = quotedArgs.join(" ")
result = execCmdEx(cmd)
@ -36,10 +33,7 @@ proc execTool(args: varargs[string]): tuple[output: string, exitCode: int] =
quotedArgs.insert(tmpDbDir)
quotedArgs.insert("--database")
quotedArgs.insert(findExe(tmpNimbleDir / "bin" / "leveldbtool"))
quotedArgs = quotedArgs.map(
proc(x: string): string =
"\"" & x & "\""
)
quotedArgs = quotedArgs.map(proc (x: string): string = "\"" & x & "\"")
if not dirExists(tmpDbDir):
createDir(tmpDbDir)
@ -50,6 +44,7 @@ proc execTool(args: varargs[string]): tuple[output: string, exitCode: int] =
checkpoint(result.output)
suite "leveldb":
setup:
let env = leveldb_create_default_env()
let dbName = $(leveldb_env_get_test_directory(env))
@ -102,27 +97,33 @@ suite "leveldb":
test "iter reverse":
initData(db)
check(toSeq(db.iter(reverse = true)) == @[("bb", "3"), ("ba", "2"), ("aa", "1")])
check(toSeq(db.iter(reverse = true)) ==
@[("bb", "3"), ("ba", "2"), ("aa", "1")])
test "iter seek":
initData(db)
check(toSeq(db.iter(seek = "ab")) == @[("ba", "2"), ("bb", "3")])
check(toSeq(db.iter(seek = "ab")) ==
@[("ba", "2"), ("bb", "3")])
test "iter seek reverse":
initData(db)
check(toSeq(db.iter(seek = "ab", reverse = true)) == @[("ba", "2"), ("aa", "1")])
check(toSeq(db.iter(seek = "ab", reverse = true)) ==
@[("ba", "2"), ("aa", "1")])
test "iter prefix":
initData(db)
check(toSeq(db.iterPrefix(prefix = "b")) == @[("ba", "2"), ("bb", "3")])
check(toSeq(db.iterPrefix(prefix = "b")) ==
@[("ba", "2"), ("bb", "3")])
test "iter range":
initData(db)
check(toSeq(db.iterRange(start = "a", limit = "ba")) == @[("aa", "1"), ("ba", "2")])
check(toSeq(db.iterRange(start = "a", limit = "ba")) ==
@[("aa", "1"), ("ba", "2")])
test "iter range reverse":
initData(db)
check(toSeq(db.iterRange(start = "bb", limit = "b")) == @[("bb", "3"), ("ba", "2")])
check(toSeq(db.iterRange(start = "bb", limit = "b")) ==
@[("bb", "3"), ("ba", "2")])
test "iter with 0x00":
db.put("\0z1", "\0ff")
@ -200,265 +201,21 @@ suite "leveldb":
test "no compress":
db.close()
let nc = leveldb.open(dbName, compressionType = ctNoCompression)
defer:
nc.close()
defer: nc.close()
nc.put("a", "1")
check(toSeq(nc.iter()) == @[("a", "1")])
suite "leveldb queryIter":
setup:
let env = leveldb_create_default_env()
let dbName = $(leveldb_env_get_test_directory(env))
let db = leveldb.open(dbName)
let
k1 = "k1"
k2 = "k2"
k3 = "l3"
v1 = "v1"
v2 = "v2"
v3 = "v3"
empty = ("", "")
db.put(k1, v1)
db.put(k2, v2)
db.put(k3, v3)
teardown:
db.close()
removeDb(dbName)
test "iterates all keys and values":
let iter = db.queryIter()
check:
not iter.finished
iter.next() == (k1, v1)
not iter.finished
iter.next() == (k2, v2)
not iter.finished
iter.next() == (k3, v3)
not iter.finished
iter.next() == empty
iter.finished
test "iterate until disposed":
let iter = db.queryIter()
check:
not iter.finished
iter.next() == (k1, v1)
not iter.finished
iter.next() == (k2, v2)
not iter.finished
iter.dispose()
check:
iter.finished
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:
not iter.finished
iter.next() == (k1, "")
not iter.finished
iter.next() == (k2, "")
not iter.finished
iter.next() == (k3, "")
not iter.finished
iter.next() == empty
iter.finished
test "iterates only 'k', both keys and values":
let iter = db.queryIter(prefix = "k")
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 '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:
not iter.finished
iter.next() == (k1, "")
not iter.finished
iter.next() == (k2, "")
not iter.finished
iter.next() == empty
iter.finished
test "concurrent iterators - 1":
let
iter1 = db.queryIter()
iter2 = db.queryIter()
check:
# 1, then 2
not iter1.finished
iter1.next() == (k1, v1)
not iter2.finished
iter2.next() == (k1, v1)
# 1, 1, then 2, 2
not iter1.finished
iter1.next() == (k2, v2)
not iter1.finished
iter1.next() == (k3, v3)
not iter2.finished
iter2.next() == (k2, v2)
not iter2.finished
iter2.next() == (k3, v3)
# finish 1, then finish 2
not iter1.finished
iter1.next() == empty
not iter2.finished
iter2.next() == empty
iter1.finished
iter2.finished
test "concurrent iterators - 2":
let
iter1 = db.queryIter()
iter2 = db.queryIter()
check:
# 1, then 2
not iter1.finished
iter1.next() == (k1, v1)
not iter2.finished
iter2.next() == (k1, v1)
# finish 1
not iter1.finished
iter1.next() == (k2, v2)
not iter1.finished
iter1.next() == (k3, v3)
not iter1.finished
iter1.next() == empty
iter1.finished
# finish 2
not iter2.finished
iter2.next() == (k2, v2)
not iter2.finished
iter2.next() == (k3, v3)
not iter2.finished
iter2.next() == empty
iter2.finished
test "concurrent iterators - dispose":
let
iter1 = db.queryIter()
iter2 = db.queryIter()
check:
# 1, then 2
not iter1.finished
iter1.next() == (k1, v1)
not iter2.finished
iter2.next() == (k1, v1)
# dispose 1
iter1.dispose()
check:
iter1.finished
iter1.next() == empty
iter1.finished
# finish 2
not iter2.finished
iter2.next() == (k2, v2)
not iter2.finished
iter2.next() == (k3, v3)
not iter2.finished
iter2.next() == empty
iter2.finished
test "modify while iterating":
let iter = db.queryIter()
check:
not iter.finished
iter.next() == (k1, v1)
not iter.finished
iter.next() == (k2, v2)
# insert
let
k4 = "k4"
v4 = "v4"
db.put(k4, v4)
check:
not iter.finished
iter.next() == (k3, v3)
not iter.finished
iter.next() == empty
iter.finished
suite "package":
setup:
removeDir(tmpDir)
test "import as package":
let (output, exitCode) = execNimble("install")
check exitCode == QuitSuccess
check output.contains("leveldbstatic installed successfully.") or
output.contains("LevelDB already build")
check output.contains("leveldbstatic installed successfully.")
cd "tests" / "packagetest":
cd "tests"/"packagetest":
var (output, exitCode) = execNimble("build")
check exitCode == QuitSuccess
check output.contains("Building")
@ -469,6 +226,7 @@ suite "package":
check output.contains("leveldb works.")
suite "tool":
setup:
removeDir(tmpDir)