refactoring to non-async

This commit is contained in:
Jaremy Creechley 2023-09-20 20:57:47 -07:00
parent 8800a2ccc0
commit 10d4031c5c
No known key found for this signature in database
GPG Key ID: 4E66FB67B21D3300
4 changed files with 53 additions and 72 deletions

View File

@ -33,6 +33,9 @@ type
proc `$`*(id: KeyId): string = $(id.data)
proc new*(tp: typedesc[KeyId], id: cstring): KeyId =
KeyId(data: DataBuffer.new(id.pointer, 0, id.len()-1))
proc toDb*(key: Key): DbKey {.inline, raises: [].} =
let id: string = key.id()
let db = DataBuffer.new(id.len()+1) # include room for null for cstring compat

View File

@ -103,9 +103,9 @@ proc close*(self: SQLiteDatastore): ?!void =
return success()
iterator query*(self: SQLiteDatastore,
query: DbQuery
): ?!DbQueryResponse {.closure.} =
proc query*(self: SQLiteDatastore,
query: DbQuery
): Result[iterator(): ?!DbQueryResponse {.closure.}, ref CatchableError] =
var
queryStr = if query.value:
@ -132,7 +132,7 @@ iterator query*(self: SQLiteDatastore,
var
v = sqlite3_bind_text(
s, 1.cint, (query.key.id & "*").cstring, -1.cint, SQLITE_TRANSIENT_GCSAFE)
s, 1.cint, ($query.key & "*").cstring, -1.cint, SQLITE_TRANSIENT_GCSAFE)
if not (v == SQLITE_OK):
return failure newException(DatastoreError, $sqlite3_errstr(v))
@ -149,78 +149,53 @@ iterator query*(self: SQLiteDatastore,
if not (v == SQLITE_OK):
return failure newException(DatastoreError, $sqlite3_errstr(v))
let lock = newAsyncLock()
proc next(): ?!QueryResponse =
defer:
if lock.locked:
lock.release()
let iter = iterator(): ?!DbQueryResponse {.closure.} =
if lock.locked:
return failure (ref DatastoreError)(msg: "Should always await query features")
if iter.finished:
return failure((ref QueryEndedError)(msg: "Calling next on a finished query!"))
await lock.acquire()
let
v = sqlite3_step(s)
case v
of SQLITE_ROW:
try:
let
key = DbKey.init(
$sqlite3_column_text_not_null(s, QueryStmtIdCol))
.expect("should not fail")
v = sqlite3_step(s)
blob: ?pointer =
if query.value:
sqlite3_column_blob(s, QueryStmtDataCol).some
else:
pointer.none
# detect out-of-memory error
# see the conversion table and final paragraph of:
# https://www.sqlite.org/c3ref/column_blob.html
# see also https://www.sqlite.org/rescode.html
# the "data" column can be NULL so in order to detect an out-of-memory
# error it is necessary to check that the result is a null pointer and
# that the result code is an error code
if blob.isSome and blob.get().isNil:
case v
of SQLITE_ROW:
let
v = sqlite3_errcode(sqlite3_db_handle(s))
key = KeyId.new(sqlite3_column_text_not_null(s, QueryStmtIdCol))
if not (v in [SQLITE_OK, SQLITE_ROW, SQLITE_DONE]):
iter.finished = true
return failure newException(DatastoreError, $sqlite3_errstr(v))
blob: ?pointer =
if query.value: sqlite3_column_blob(s, QueryStmtDataCol).some
else: pointer.none
let
dataLen = sqlite3_column_bytes(s, QueryStmtDataCol)
data = if blob.isSome:
@(
toOpenArray(cast[ptr UncheckedArray[byte]](blob.get),
0,
dataLen - 1))
else:
@[]
# detect out-of-memory error
# see the conversion table and final paragraph of:
# https://www.sqlite.org/c3ref/column_blob.html
# see also https://www.sqlite.org/rescode.html
return success (key.some, data)
of SQLITE_DONE:
iter.finished = true
return success (DbKey.none, EmptyBytes)
else:
iter.finished = true
return failure newException(DatastoreError, $sqlite3_errstr(v))
# the "data" column can be NULL so in order to detect an out-of-memory
# error it is necessary to check that the result is a null pointer and
# that the result code is an error code
if blob.isSome and blob.get().isNil:
let v = sqlite3_errcode(sqlite3_db_handle(s))
iter.dispose = proc(): ?!void =
discard sqlite3_reset(s)
discard sqlite3_clear_bindings(s)
s.dispose
return success()
if not (v in [SQLITE_OK, SQLITE_ROW, SQLITE_DONE]):
return failure newException(DatastoreError, $sqlite3_errstr(v))
let
dataLen = sqlite3_column_bytes(s, QueryStmtDataCol)
data =
if blob.isSome: DataBuffer.new(blob.get(), 0, dataLen - 1)
else: DataBuffer.new(0)
return success (key.some, data)
of SQLITE_DONE:
return success (KeyId.none, DataBuffer.new(0))
else:
return failure newException(DatastoreError, $sqlite3_errstr(v))
finally:
discard sqlite3_reset(s)
discard sqlite3_clear_bindings(s)
s.dispose()
return
iter.next = next
return success iter
proc new*(T: type SQLiteDatastore,
path: string,

View File

@ -68,6 +68,9 @@ proc new*[T: byte | char](tp: type DataBuffer, data: openArray[T], opts: set[Dat
copyMem(result[].buf, baseAddr data, data.len())
result[].size = data.len()
proc new*(tp: type DataBuffer, data: pointer, first, last: int): DataBuffer =
DataBuffer.new(toOpenArray(cast[ptr UncheckedArray[byte]](data), first, last))
proc clear*(db: DataBuffer) =
zeroMem(db[].buf, db[].cap)
db[].size = 0

View File

@ -38,8 +38,8 @@ converter toExc*(e: ThreadResErr): ref CatchableError =
of ErrorEnum.DatastoreErr: (ref DatastoreError)(msg: $e[1])
of ErrorEnum.CatchableErr: (ref CatchableError)(msg: $e[1])
converter toQueryResponse*(r: DbQueryResponse): QueryResponse =
if not r.key.data.isNil and r.key.data.len > 0 and key =? Key.init($r.key.data):
(key.some, @(r.val))
else:
(Key.none, EmptyBytes)
# converter toQueryResponse*(r: DbQueryResponse): QueryResponse =
# if not r.key.data.isNil and r.key.data.len > 0 and key =? Key.init($r.key.data):
# (key.some, @(r.val))
# else:
# (Key.none, EmptyBytes)