From f7a933a60ab17a622c2fbb3730ec2c647e5eaac8 Mon Sep 17 00:00:00 2001 From: Jaremy Creechley Date: Wed, 20 Sep 2023 17:49:57 -0700 Subject: [PATCH] openArray --- datastore/backend.nim | 10 ++++++++++ datastore/sql/sqliteds.nim | 22 +++++++++++----------- datastore/sql/sqliteutils.nim | 2 +- datastore/threads/databuffer.nim | 7 +++++++ datastore/threads/threadresult.nim | 3 +++ tests/datastore/testdatabuffer.nim | 10 ++++++++++ 6 files changed, 42 insertions(+), 12 deletions(-) create mode 100644 datastore/backend.nim diff --git a/datastore/backend.nim b/datastore/backend.nim new file mode 100644 index 0000000..9559f50 --- /dev/null +++ b/datastore/backend.nim @@ -0,0 +1,10 @@ +import pkg/questionable/results +import pkg/upraises + +import ./threads/databuffer +import ./threads/threadresult +import ./threads/semaphore +import ./types + +export databuffer, threadresult, semaphore, types +export upraises, results diff --git a/datastore/sql/sqliteds.nim b/datastore/sql/sqliteds.nim index 4241292..136ac71 100644 --- a/datastore/sql/sqliteds.nim +++ b/datastore/sql/sqliteds.nim @@ -7,10 +7,10 @@ import pkg/sqlite3_abi from pkg/stew/results as stewResults import isErr import pkg/upraises -import ../datastore +import ../backend import ./sqlitedsdb -export datastore, sqlitedsdb +export backend, sqlitedsdb push: {.upraises: [].} @@ -26,7 +26,7 @@ proc readOnly*(self: SQLiteDatastore): bool = self.db.readOnly proc timestamp*(t = epochTime()): int64 = (t * 1_000_000).int64 -proc has*(self: SQLiteDatastore, key: Key): ?!bool = +proc has*(self: SQLiteDatastore, key: DbKey): ?!bool = var exists = false @@ -38,10 +38,10 @@ proc has*(self: SQLiteDatastore, key: Key): ?!bool = return success exists -proc delete*(self: SQLiteDatastore, key: Key): ?!void = - return self.db.deleteStmt.exec((key.id)) +proc delete*(self: SQLiteDatastore, key: DbKey): ?!void = + return self.db.deleteStmt.exec((key.data)) -proc delete*(self: SQLiteDatastore, keys: seq[Key]): ?!void = +proc delete*(self: SQLiteDatastore, keys: seq[DbKey]): ?!void = if err =? self.db.beginStmt.exec().errorOption: return failure(err) @@ -57,7 +57,7 @@ proc delete*(self: SQLiteDatastore, keys: seq[Key]): ?!void = return success() -proc get*(self: SQLiteDatastore, key: Key): ?!seq[byte] = +proc get*(self: SQLiteDatastore, key: DbKey): ?!seq[byte] = # see comment in ./filesystem_datastore re: finer control of memory # allocation in `proc get`, could apply here as well if bytes were read # incrementally with `sqlite3_blob_read` @@ -73,11 +73,11 @@ proc get*(self: SQLiteDatastore, key: Key): ?!seq[byte] = if bytes.len <= 0: return failure( - newException(DatastoreKeyNotFound, "Key doesn't exist")) + newException(DatastoreKeyNotFound, "DbKey doesn't exist")) return success bytes -proc put*(self: SQLiteDatastore, key: Key, data: seq[byte]): ?!void = +proc put*(self: SQLiteDatastore, key: DbKey, data: seq[byte]): ?!void = return self.db.putStmt.exec((key.id, data, timestamp())) proc put*(self: SQLiteDatastore, batch: seq[BatchEntry]): ?!void = @@ -169,7 +169,7 @@ iterator query*(self: SQLiteDatastore, case v of SQLITE_ROW: let - key = Key.init( + key = DbKey.init( $sqlite3_column_text_not_null(s, QueryStmtIdCol)) .expect("should not fail") @@ -208,7 +208,7 @@ iterator query*(self: SQLiteDatastore, return success (key.some, data) of SQLITE_DONE: iter.finished = true - return success (Key.none, EmptyBytes) + return success (DbKey.none, EmptyBytes) else: iter.finished = true return failure newException(DatastoreError, $sqlite3_errstr(v)) diff --git a/datastore/sql/sqliteutils.nim b/datastore/sql/sqliteutils.nim index 4d2254a..54b2090 100644 --- a/datastore/sql/sqliteutils.nim +++ b/datastore/sql/sqliteutils.nim @@ -61,7 +61,7 @@ proc bindParam( sqlite3_bind_int64(s, n.cint, val.int64) elif val is float32 | float64: sqlite3_bind_double(s, n.cint, val.float64) - elif val is string: + elif val is string|openArray[char]: # `-1` implies string length is num bytes up to first null-terminator; # `SQLITE_TRANSIENT` "indicate[s] that the object is to be copied prior # to the return from sqlite3_bind_*(). The object and pointer to it must diff --git a/datastore/threads/databuffer.nim b/datastore/threads/databuffer.nim index 66bb7e6..130490e 100644 --- a/datastore/threads/databuffer.nim +++ b/datastore/threads/databuffer.nim @@ -90,3 +90,10 @@ converter toBuffer*(err: ref CatchableError): DataBuffer = ## return DataBuffer.new(err.msg) + +template toOpenArray*[T: byte | char](data: DataBuffer, t: typedesc[T]): openArray[T] = + ## get openArray from DataBuffer as char + ## + ## this is explicit since sqlite treats string differently from openArray[byte] + let bf = cast[ptr UncheckedArray[T]](data[].buf) + bf.toOpenArray(0, data[].size-1) diff --git a/datastore/threads/threadresult.nim b/datastore/threads/threadresult.nim index 746e45e..15a442a 100644 --- a/datastore/threads/threadresult.nim +++ b/datastore/threads/threadresult.nim @@ -37,6 +37,9 @@ proc toDb*(value: sink seq[byte]): DbValue {.inline, raises: [].} = proc toValue*(value: DbValue): seq[byte] {.inline, raises: [].} = value.data.toSeq() +template toOpenArray*(x: DbKey): openArray[char] = + x.data[].buf.toOpenArray(0, x[].size-1) + converter toThreadErr*(e: ref CatchableError): ThreadResErr {.inline, raises: [].} = if e of DatastoreKeyNotFound: (ErrorEnum.DatastoreKeyNotFoundErr, DataBuffer.new(e.msg)) elif e of QueryEndedError: (ErrorEnum.QueryEndedErr, DataBuffer.new(e.msg)) diff --git a/tests/datastore/testdatabuffer.nim b/tests/datastore/testdatabuffer.nim index 7fc3ceb..4969f9c 100644 --- a/tests/datastore/testdatabuffer.nim +++ b/tests/datastore/testdatabuffer.nim @@ -103,5 +103,15 @@ suite "Share buffer test": test "seq conversion": check a.toSeq() == "/a/b".toBytes + test "basic openArray test": + proc letters(val: openArray[char]): int = + val.len() + proc bytes(val: openArray[byte]): int = + val.len() + + check a.toOpenArray(char).letters() == a.len() + check a.toOpenArray(byte).bytes() == a.len() + # check a.toOpenArray(char).bytes() == a.len() + test "basic thread test": runBasicTest()