change to non-closure iterator

This commit is contained in:
Jaremy Creechley 2023-09-25 17:35:37 -07:00
parent 85352e8bc5
commit 0336b93360
No known key found for this signature in database
GPG Key ID: 4E66FB67B21D3300
3 changed files with 52 additions and 69 deletions

View File

@ -15,21 +15,21 @@ export backend, sqlitedsdb
push: {.upraises: [].}
type
SQLiteBackend* = object
db: SQLiteDsDb
SQLiteBackend*[K, V] = object
db: SQLiteDsDb[K, V]
proc path*(self: SQLiteBackend): string =
proc path*[K,V](self: SQLiteBackend[K,V]): string =
$self.db.dbPath
proc readOnly*(self: SQLiteBackend): bool = self.db.readOnly
proc readOnly*[K,V](self: SQLiteBackend[K,V]): bool = self.db.readOnly
proc timestamp*(t = epochTime()): int64 =
(t * 1_000_000).int64
proc has*(self: SQLiteBackend, key: DbKey): ?!bool =
proc has*[K,V](self: SQLiteBackend[K,V], key: DbKey): ?!bool =
var
exists = false
key = $key
key = key
proc onData(s: RawStmtPtr) =
exists = sqlite3_column_int64(s, ContainsStmtExistsCol.cint).bool
@ -39,15 +39,15 @@ proc has*(self: SQLiteBackend, key: DbKey): ?!bool =
return success exists
proc delete*(self: SQLiteBackend, key: DbKey): ?!void =
return self.db.deleteStmt.exec(($key))
proc delete*[K,V](self: SQLiteBackend[K,V], key: DbKey): ?!void =
return self.db.deleteStmt.exec((key))
proc delete*(self: SQLiteBackend, keys: openArray[DbKey]): ?!void =
proc delete*[K,V](self: SQLiteBackend[K,V], keys: openArray[DbKey]): ?!void =
if err =? self.db.beginStmt.exec().errorOption:
return failure(err)
for key in keys:
if err =? self.db.deleteStmt.exec(($key)).errorOption:
if err =? self.db.deleteStmt.exec((key)).errorOption:
if err =? self.db.rollbackStmt.exec().errorOption:
return failure err.msg
@ -58,7 +58,7 @@ proc delete*(self: SQLiteBackend, keys: openArray[DbKey]): ?!void =
return success()
proc get*(self: SQLiteBackend, key: DbKey): ?!seq[byte] =
proc get*[K,V](self: SQLiteBackend[K,V], key: KeyId): ?!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`
@ -69,7 +69,7 @@ proc get*(self: SQLiteBackend, key: DbKey): ?!seq[byte] =
proc onData(s: RawStmtPtr) =
bytes = dataCol(self.db.getDataCol)
if err =? self.db.getStmt.query(($key), onData).errorOption:
if err =? self.db.getStmt.query((key), onData).errorOption:
return failure(err)
if bytes.len <= 0:
@ -78,25 +78,15 @@ proc get*(self: SQLiteBackend, key: DbKey): ?!seq[byte] =
return success bytes
proc put*(self: SQLiteBackend, key: DbKey, data: DbVal): ?!void =
when DbVal is seq[byte]:
return self.db.putStmt.exec((key, data, timestamp()))
elif DbVal is DataBuffer:
return self.db.putBufferStmt.exec((key, data, timestamp()))
else:
{.error: "unknown type".}
proc put*[K,V](self: SQLiteBackend[K,V], key: KeyId, data: DataBuffer): ?!void =
return self.db.putStmt.exec((key, data, timestamp()))
proc put*(self: SQLiteBackend, batch: openArray[DbBatchEntry]): ?!void =
proc put*[K,V](self: SQLiteBackend[K,V], batch: openArray[DbBatchEntry]): ?!void =
if err =? self.db.beginStmt.exec().errorOption:
return failure err
for entry in batch:
when entry.key is string:
let putStmt = self.db.putStmt
elif entry.key is KeyId:
let putStmt = self.db.putBufferStmt
else:
{.error: "unhandled type".}
let putStmt = self.db.putStmt
if err =? putStmt.exec((entry.key, entry.data, timestamp())).errorOption:
if err =? self.db.rollbackStmt.exec().errorOption:
return failure err
@ -108,13 +98,13 @@ proc put*(self: SQLiteBackend, batch: openArray[DbBatchEntry]): ?!void =
return success()
proc close*(self: SQLiteBackend): ?!void =
proc close*[K,V](self: SQLiteBackend[K,V]): ?!void =
self.db.close()
return success()
proc query*(
self: SQLiteBackend,
proc query*[K,V](
self: SQLiteBackend[K,V],
query: DbQuery
): Result[DbQueryHandle[RawStmtPtr], ref CatchableError] =
@ -219,23 +209,23 @@ iterator iter*(handle: var DbQueryHandle[RawStmtPtr]): ?!DbQueryResponse =
handle.close()
proc contains*(self: SQLiteBackend, key: DbKey): bool =
proc contains*[K,V](self: SQLiteBackend[K,V], key: DbKey): bool =
return self.has(key).get()
proc new*(T: type SQLiteBackend,
proc newSQLiteBackend*[K,V](
path: string,
readOnly = false): ?!SQLiteBackend =
readOnly = false): ?!SQLiteBackend[K,V] =
let
flags =
if readOnly: SQLITE_OPEN_READONLY
else: SQLITE_OPEN_READWRITE or SQLITE_OPEN_CREATE
success SQLiteBackend(db: ? SQLiteDsDb.open(path, flags))
success SQLiteBackend[K,V](db: ? SQLiteDsDb[KeyId,DataBuffer].open(path, flags))
proc new*(T: type SQLiteBackend,
db: SQLiteDsDb): ?!T =
proc newSQLiteBackend*[K,V](
db: SQLiteDsDb[K,V]): ?!SQLiteBackend[K,V] =
success SQLiteBackend(db: db)
success SQLiteBackend[K,V](db: db)

View File

@ -17,26 +17,24 @@ type
# feels odd to use `void` for prepared statements corresponding to SELECT
# queries but it fits with the rest of the SQLite wrapper adapted from
# status-im/nwaku, at least in its current form in ./sqlite
ContainsStmt* = SQLiteStmt[(string), void]
DeleteStmt* = SQLiteStmt[(string), void]
GetStmt* = SQLiteStmt[(string), void]
PutStmt* = SQLiteStmt[(string, seq[byte], int64), void]
PutBufferStmt* = SQLiteStmt[(KeyId, DataBuffer, int64), void]
ContainsStmt*[K] = SQLiteStmt[(K), void]
DeleteStmt*[K] = SQLiteStmt[(K), void]
GetStmt*[K] = SQLiteStmt[(K), void]
PutStmt*[K, V] = SQLiteStmt[(K, V, int64), void]
QueryStmt* = SQLiteStmt[(string), void]
BeginStmt* = NoParamsStmt
EndStmt* = NoParamsStmt
RollbackStmt* = NoParamsStmt
SQLiteDsDb* = object
SQLiteDsDb*[K,V] = object
readOnly*: bool
dbPath*: DataBuffer
containsStmt*: ContainsStmt
deleteStmt*: DeleteStmt
containsStmt*: ContainsStmt[K]
deleteStmt*: DeleteStmt[K]
env*: SQLite
getDataCol*: (RawStmtPtr, int)
getStmt*: GetStmt
putStmt*: PutStmt
putBufferStmt*: PutBufferStmt
getStmt*: GetStmt[K]
putStmt*: PutStmt[K,V]
beginStmt*: BeginStmt
endStmt*: EndStmt
rollbackStmt*: RollbackStmt
@ -230,10 +228,10 @@ proc close*(self: SQLiteDsDb) =
self.env.dispose
proc open*(
T: type SQLiteDsDb,
proc open*[K,V](
T: type SQLiteDsDb[K,V],
path = Memory,
flags = SQLITE_OPEN_READONLY): ?!SQLiteDsDb =
flags = SQLITE_OPEN_READONLY): ?!SQLiteDsDb[K, V] =
# make it optional to enable WAL with it enabled being the default?
@ -266,11 +264,10 @@ proc open*(
checkExec(pragmaStmt)
var
containsStmt: ContainsStmt
deleteStmt: DeleteStmt
getStmt: GetStmt
putStmt: PutStmt
putBufferStmt: PutBufferStmt
containsStmt: ContainsStmt[K]
deleteStmt: DeleteStmt[K]
getStmt: GetStmt[K]
putStmt: PutStmt[K,V]
beginStmt: BeginStmt
endStmt: EndStmt
rollbackStmt: RollbackStmt
@ -278,13 +275,10 @@ proc open*(
if not readOnly:
checkExec(env.val, CreateStmtStr)
deleteStmt = ? DeleteStmt.prepare(
deleteStmt = ? DeleteStmt[K].prepare(
env.val, DeleteStmtStr, SQLITE_PREPARE_PERSISTENT)
putStmt = ? PutStmt.prepare(
env.val, PutStmtStr, SQLITE_PREPARE_PERSISTENT)
putBufferStmt = ? PutBufferStmt.prepare(
putStmt = ? PutStmt[K,V].prepare(
env.val, PutStmtStr, SQLITE_PREPARE_PERSISTENT)
beginStmt = ? BeginStmt.prepare(
@ -296,10 +290,10 @@ proc open*(
rollbackStmt = ? RollbackStmt.prepare(
env.val, RollbackTransactionStr, SQLITE_PREPARE_PERSISTENT)
containsStmt = ? ContainsStmt.prepare(
containsStmt = ? ContainsStmt[K].prepare(
env.val, ContainsStmtStr, SQLITE_PREPARE_PERSISTENT)
getStmt = ? GetStmt.prepare(
getStmt = ? GetStmt[K].prepare(
env.val, GetStmtStr, SQLITE_PREPARE_PERSISTENT)
# if a readOnly/existing database does not satisfy the expected schema
@ -309,7 +303,7 @@ proc open*(
let
getDataCol = (RawStmtPtr(getStmt), GetStmtDataCol)
success SQLiteDsDb(
success SQLiteDsDb[K,V](
readOnly: readOnly,
dbPath: DataBuffer.new path,
containsStmt: containsStmt,
@ -318,7 +312,6 @@ proc open*(
getStmt: getStmt,
getDataCol: getDataCol,
putStmt: putStmt,
putBufferStmt: putBufferStmt,
beginStmt: beginStmt,
endStmt: endStmt,
rollbackStmt: rollbackStmt)

View File

@ -60,14 +60,14 @@ proc testBasic[K, V, B](
check: not ds.has(k).tryGet
test "handle missing key":
let key = Key.init("/missing/key").tryGet().id()
let key = KeyId.new Key.init("/missing/key").tryGet().id()
expect(DatastoreKeyNotFound):
discard ds.get(key).tryGet() # non existing key
suite "Test Basic SQLiteDatastore":
let
ds = SQLiteBackend.new(Memory).tryGet()
ds = newSQLiteBackend[KeyId, DataBuffer](path=Memory).tryGet()
keyFull = Key.init("a:b/c/d:e").tryGet()
key = keyFull.id()
bytes = "some bytes".toBytes
@ -81,11 +81,11 @@ suite "Test Basic SQLiteDatastore":
suiteTeardown:
ds.close().tryGet()
testBasic(ds, key, bytes, otherBytes, batch)
# testBasic(ds, key, bytes, otherBytes, batch)
suite "Test DataBuffer SQLiteDatastore":
let
ds = SQLiteBackend.new(Memory).tryGet()
ds = newSQLiteBackend[KeyId, DataBuffer](Memory).tryGet()
keyFull = Key.init("a:b/c/d:e").tryGet()
key = KeyId.new keyFull.id()
bytes = DataBuffer.new "some bytes"
@ -103,7 +103,7 @@ suite "Test DataBuffer SQLiteDatastore":
suite "queryTests":
let
ds = SQLiteBackend.new(Memory).tryGet()
ds = newSQLiteBackend[KeyId, DataBuffer](Memory).tryGet()
var
key1: KeyId