diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c8bdf0ac..de0cbe65 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -23,7 +23,7 @@ jobs: os: windows, shell: msys2 } - nim: [1.6.18] + nim: [1.6.18, 2.0.14] name: ${{ matrix.platform.icon }} ${{ matrix.platform.label }} - Nim v${{ matrix.nim }} runs-on: ${{ matrix.platform.os }}-latest steps: diff --git a/.gitignore b/.gitignore index 5494ef99..9c524e96 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ nimcache TODO nimble.develop nimble.paths +nimbledeps diff --git a/config.nims b/config.nims index ed3a5315..d36ad3f9 100644 --- a/config.nims +++ b/config.nims @@ -14,3 +14,7 @@ when (NimMajor, NimMinor) > (1, 2): when withDir(thisDir(), system.fileExists("nimble.paths")): include "nimble.paths" # end Nimble config + +when (NimMajor, NimMinor) >= (2, 0): + --mm:refc + diff --git a/datastore.nimble b/datastore.nimble index 09c35d81..e00c130e 100644 --- a/datastore.nimble +++ b/datastore.nimble @@ -1,7 +1,7 @@ mode = ScriptMode.Verbose packageName = "datastore" -version = "0.1.1" +version = "0.2.0" author = "Status Research & Development GmbH" description = "Simple, unified API for multiple data stores" license = "Apache License 2.0 or MIT" @@ -10,10 +10,10 @@ requires "nim >= 1.2.0", "asynctest >= 0.5.2 & < 0.6.0", "chronos >= 4.0.3 & < 5.0.0", "questionable >= 0.10.15 & < 0.11.0", - "sqlite3_abi", - "leveldbstatic >= 0.1.6", - "stew", - "unittest2" + "sqlite3_abi == 3.47.0.0", + "leveldbstatic#0bd875d2b76c5b02c771fc1de136826dae6802c6", + "stew >= 0.2.0", + "unittest2 >= 0.2.3" task coverage, "generates code coverage report": var (output, exitCode) = gorgeEx("which lcov") diff --git a/datastore/datastore.nim b/datastore/datastore.nim index 47f339b1..b038165e 100644 --- a/datastore/datastore.nim +++ b/datastore/datastore.nim @@ -16,22 +16,22 @@ type Modify* = Function[?seq[byte], Future[?seq[byte]]] ModifyGet* = Function[?seq[byte], Future[(?seq[byte], seq[byte])]] -method has*(self: Datastore, key: Key): Future[?!bool] {.base, locks: "unknown".} = +method has*(self: Datastore, key: Key): Future[?!bool] {.base, gcsafe, locks: "unknown".} = raiseAssert("Not implemented!") -method delete*(self: Datastore, key: Key): Future[?!void] {.base, locks: "unknown".} = +method delete*(self: Datastore, key: Key): Future[?!void] {.base, gcsafe, locks: "unknown".} = raiseAssert("Not implemented!") -method delete*(self: Datastore, keys: seq[Key]): Future[?!void] {.base, locks: "unknown".} = +method delete*(self: Datastore, keys: seq[Key]): Future[?!void] {.base, gcsafe, locks: "unknown".} = raiseAssert("Not implemented!") -method get*(self: Datastore, key: Key): Future[?!seq[byte]] {.base, locks: "unknown".} = +method get*(self: Datastore, key: Key): Future[?!seq[byte]] {.base, gcsafe, locks: "unknown".} = raiseAssert("Not implemented!") -method put*(self: Datastore, key: Key, data: seq[byte]): Future[?!void] {.base, locks: "unknown".} = +method put*(self: Datastore, key: Key, data: seq[byte]): Future[?!void] {.base, gcsafe, locks: "unknown".} = raiseAssert("Not implemented!") -method put*(self: Datastore, batch: seq[BatchEntry]): Future[?!void] {.base, locks: "unknown".} = +method put*(self: Datastore, batch: seq[BatchEntry]): Future[?!void] {.base, gcsafe, locks: "unknown".} = raiseAssert("Not implemented!") method close*(self: Datastore): Future[?!void] {.base, async, locks: "unknown".} = @@ -46,7 +46,7 @@ method query*( proc contains*(self: Datastore, key: Key): Future[bool] {.async.} = return (await self.has(key)) |? false -method modify*(self: Datastore, key: Key, fn: Modify): Future[?!void] {.base, locks: "unknown".} = +method modify*(self: Datastore, key: Key, fn: Modify): Future[?!void] {.base, gcsafe, locks: "unknown".} = ## Concurrently safe way of modifying the value associated with the `key`. ## ## Same as `modifyGet`, but this takes `fn` that doesn't produce any auxillary value. @@ -54,7 +54,7 @@ method modify*(self: Datastore, key: Key, fn: Modify): Future[?!void] {.base, lo raiseAssert("Not implemented!") -method modifyGet*(self: Datastore, key: Key, fn: ModifyGet): Future[?!seq[byte]] {.base, locks: "unknown".} = +method modifyGet*(self: Datastore, key: Key, fn: ModifyGet): Future[?!seq[byte]] {.base, gcsafe, locks: "unknown".} = ## Concurrently safe way of updating value associated with the `key`. Returns auxillary value on ## successful update. ## diff --git a/datastore/leveldb/leveldbds.nim b/datastore/leveldb/leveldbds.nim index 30e30f67..afa07ae4 100644 --- a/datastore/leveldb/leveldbds.nim +++ b/datastore/leveldb/leveldbds.nim @@ -79,7 +79,7 @@ proc getQueryString(query: Query): string = result = $(query.key) let toTrim = ["/*", "\\*"] for trim in toTrim: - if result.endswith(trim): + if result.endsWith(trim): result = result[0 ..< ^(trim.len)] method query*( diff --git a/datastore/mountedds.nim b/datastore/mountedds.nim index d1c51cd8..5be85110 100644 --- a/datastore/mountedds.nim +++ b/datastore/mountedds.nim @@ -20,7 +20,7 @@ type MountedDatastore* = ref object of Datastore stores*: Table[Key, MountedStore] -method mount*(self: MountedDatastore, key: Key, store: Datastore): ?!void {.base.} = +method mount*(self: MountedDatastore, key: Key, store: Datastore): ?!void {.base, gcsafe.} = ## Mount a store on a namespace - namespaces are only `/` ## diff --git a/datastore/sql/sqliteutils.nim b/datastore/sql/sqliteutils.nim index c86f7071..2103e53b 100644 --- a/datastore/sql/sqliteutils.nim +++ b/datastore/sql/sqliteutils.nim @@ -128,7 +128,11 @@ template dispose*(db: SQLite) = template dispose*(sqliteStmt: SQLiteStmt) = doAssert SQLITE_OK == sqlite3_finalize(RawStmtPtr(sqliteStmt)) - sqliteStmt = nil + # nil literals can no longer be directly assigned to variables or fields of distinct pointer types. + # They must be converted instead. + # See https://nim-lang.org/blog/2022/12/21/version-20-rc.html#:~:text=nil%20literals%20can%20no%20longer%20be%20directly%20assigned%20to%20variables%20or%20fields%20of%20distinct%20pointer%20types.%20They%20must%20be%20converted%20instead. + # SQLiteStmt(nil) is generating a SIGSEGV, so we need to cast it + sqliteStmt = cast[typeof sqliteStmt](nil) proc release*[T](x: var AutoDisposed[T]): T = result = x.val @@ -237,7 +241,10 @@ proc query*[P]( case v of SQLITE_ROW: - onData(s) + try: + onData(s) + except Exception as err: + return failure("sqliteutils.query (stmt) exception: " & $err.msg) res = success true of SQLITE_DONE: break @@ -256,11 +263,14 @@ proc query*( query: string, onData: DataProc): ?!bool = - var - s = ? NoParamsStmt.prepare(env, query) - res = s.query((), onData) + var s = ? NoParamsStmt.prepare(env, query) - # NB: dispose of the prepared query statement and free associated memory - s.dispose + try: + var res = s.query((), onData) + return res + except Exception as err: + return failure("sqliteutils.query (env) exception: " & $err.msg) + finally: + # NB: dispose of the prepared query statement and free associated memory + s.dispose - res diff --git a/tests/datastore/leveldb/testleveldbds.nim b/tests/datastore/leveldb/testleveldbds.nim index 19a7c8e0..49c175d5 100644 --- a/tests/datastore/leveldb/testleveldbds.nim +++ b/tests/datastore/leveldb/testleveldbds.nim @@ -25,7 +25,7 @@ suite "Test Basic LevelDbDatastore": otherBytes = "some other bytes".toBytes setupAll: - createdir(tempDir) + createDir(tempDir) teardownAll: (await ds.close()).tryGet() @@ -40,7 +40,7 @@ suite "Test LevelDB Query": var ds: LevelDbDatastore setup: - createdir(tempDir) + createDir(tempDir) ds = LevelDbDatastore.new(tempDir).tryGet() teardown: @@ -57,7 +57,7 @@ suite "Test LevelDB Typed Query": var ds: LevelDbDatastore setup: - createdir(tempDir) + createDir(tempDir) ds = LevelDbDatastore.new(tempDir).tryGet() teardown: @@ -87,7 +87,7 @@ suite "LevelDB Query: keys should disregard trailing wildcards": val3 = "value for 3".toBytes setup: - createdir(tempDir) + createDir(tempDir) ds = LevelDbDatastore.new(tempDir).tryGet() (await ds.put(key1, val1)).tryGet (await ds.put(key2, val2)).tryGet