mirror of https://github.com/status-im/nim-eth.git
kvstore: return bool from del, add clear (#574)
This allows making decisions based on whether an element was present during the `del`
This commit is contained in:
parent
40ec601d07
commit
8f0ae55353
|
@ -31,7 +31,8 @@ type
|
||||||
PutProc = proc (db: RootRef, key, val: openArray[byte]): KvResult[void] {.nimcall, gcsafe, raises: [Defect].}
|
PutProc = proc (db: RootRef, key, val: openArray[byte]): KvResult[void] {.nimcall, gcsafe, raises: [Defect].}
|
||||||
GetProc = proc (db: RootRef, key: openArray[byte], onData: DataProc): KvResult[bool] {.nimcall, gcsafe, raises: [Defect].}
|
GetProc = proc (db: RootRef, key: openArray[byte], onData: DataProc): KvResult[bool] {.nimcall, gcsafe, raises: [Defect].}
|
||||||
FindProc = proc (db: RootRef, prefix: openArray[byte], onFind: KeyValueProc): KvResult[int] {.nimcall, gcsafe, raises: [Defect].}
|
FindProc = proc (db: RootRef, prefix: openArray[byte], onFind: KeyValueProc): KvResult[int] {.nimcall, gcsafe, raises: [Defect].}
|
||||||
DelProc = proc (db: RootRef, key: openArray[byte]): KvResult[void] {.nimcall, gcsafe, raises: [Defect].}
|
DelProc = proc (db: RootRef, key: openArray[byte]): KvResult[bool] {.nimcall, gcsafe, raises: [Defect].}
|
||||||
|
ClearProc = proc (db: RootRef): KvResult[bool] {.nimcall, gcsafe, raises: [Defect].}
|
||||||
ContainsProc = proc (db: RootRef, key: openArray[byte]): KvResult[bool] {.nimcall, gcsafe, raises: [Defect].}
|
ContainsProc = proc (db: RootRef, key: openArray[byte]): KvResult[bool] {.nimcall, gcsafe, raises: [Defect].}
|
||||||
CloseProc = proc (db: RootRef): KvResult[void] {.nimcall, gcsafe, raises: [Defect].}
|
CloseProc = proc (db: RootRef): KvResult[void] {.nimcall, gcsafe, raises: [Defect].}
|
||||||
|
|
||||||
|
@ -42,6 +43,7 @@ type
|
||||||
getProc: GetProc
|
getProc: GetProc
|
||||||
findProc: FindProc
|
findProc: FindProc
|
||||||
delProc: DelProc
|
delProc: DelProc
|
||||||
|
clearProc: ClearProc
|
||||||
containsProc: ContainsProc
|
containsProc: ContainsProc
|
||||||
closeProc: CloseProc
|
closeProc: CloseProc
|
||||||
|
|
||||||
|
@ -68,11 +70,18 @@ template find*(
|
||||||
let db = dbParam
|
let db = dbParam
|
||||||
db.findProc(db.obj, prefix, onFind)
|
db.findProc(db.obj, prefix, onFind)
|
||||||
|
|
||||||
template del*(dbParam: KvStoreRef, key: openArray[byte]): KvResult[void] =
|
template del*(dbParam: KvStoreRef, key: openArray[byte]): KvResult[bool] =
|
||||||
## Remove value at ``key`` from store - do nothing if the value is not present
|
## Remove value at ``key`` from store - do nothing if the value is not present
|
||||||
|
## Returns true iff value was found and deleted
|
||||||
let db = dbParam
|
let db = dbParam
|
||||||
db.delProc(db.obj, key)
|
db.delProc(db.obj, key)
|
||||||
|
|
||||||
|
template clear*(dbParam: KvStoreRef): KvResult[bool] =
|
||||||
|
## Remove all values from store
|
||||||
|
## Returns true iff a value was found and deleted
|
||||||
|
let db = dbParam
|
||||||
|
db.clearProc(db.obj)
|
||||||
|
|
||||||
template contains*(dbParam: KvStoreRef, key: openArray[byte]): KvResult[bool] =
|
template contains*(dbParam: KvStoreRef, key: openArray[byte]): KvResult[bool] =
|
||||||
## Return true iff ``key`` has a value in store
|
## Return true iff ``key`` has a value in store
|
||||||
let db = dbParam
|
let db = dbParam
|
||||||
|
@ -95,10 +104,14 @@ proc findImpl[T](db: RootRef, key: openArray[byte], onFind: KeyValueProc): KvRes
|
||||||
mixin get
|
mixin get
|
||||||
find(T(db), key, onFind)
|
find(T(db), key, onFind)
|
||||||
|
|
||||||
proc delImpl[T](db: RootRef, key: openArray[byte]): KvResult[void] {.gcsafe.} =
|
proc delImpl[T](db: RootRef, key: openArray[byte]): KvResult[bool] {.gcsafe.} =
|
||||||
mixin del
|
mixin del
|
||||||
del(T(db), key)
|
del(T(db), key)
|
||||||
|
|
||||||
|
proc clearImpl[T](db: RootRef): KvResult[bool] {.gcsafe.} =
|
||||||
|
mixin clear
|
||||||
|
clear(T(db))
|
||||||
|
|
||||||
proc containsImpl[T](db: RootRef, key: openArray[byte]): KvResult[bool] {.gcsafe.} =
|
proc containsImpl[T](db: RootRef, key: openArray[byte]): KvResult[bool] {.gcsafe.} =
|
||||||
mixin contains
|
mixin contains
|
||||||
contains(T(db), key)
|
contains(T(db), key)
|
||||||
|
@ -108,7 +121,7 @@ proc closeImpl[T](db: RootRef): KvResult[void] {.gcsafe.} =
|
||||||
close(T(db))
|
close(T(db))
|
||||||
|
|
||||||
func kvStore*[T: RootRef](x: T): KvStoreRef =
|
func kvStore*[T: RootRef](x: T): KvStoreRef =
|
||||||
mixin del, get, put, contains, close
|
mixin del, clear, get, put, contains, close
|
||||||
|
|
||||||
KvStoreRef(
|
KvStoreRef(
|
||||||
obj: x,
|
obj: x,
|
||||||
|
@ -116,6 +129,7 @@ func kvStore*[T: RootRef](x: T): KvStoreRef =
|
||||||
getProc: getImpl[T],
|
getProc: getImpl[T],
|
||||||
findProc: findImpl[T],
|
findProc: findImpl[T],
|
||||||
delProc: delImpl[T],
|
delProc: delImpl[T],
|
||||||
|
clearProc: clearImpl[T],
|
||||||
containsProc: containsImpl[T],
|
containsProc: containsImpl[T],
|
||||||
closeProc: closeImpl[T]
|
closeProc: closeImpl[T]
|
||||||
)
|
)
|
||||||
|
@ -139,9 +153,19 @@ proc find*(
|
||||||
|
|
||||||
ok(total)
|
ok(total)
|
||||||
|
|
||||||
proc del*(db: MemStoreRef, key: openArray[byte]): KvResult[void] =
|
proc del*(db: MemStoreRef, key: openArray[byte]): KvResult[bool] =
|
||||||
|
if @key in db.records:
|
||||||
db.records.del(@key)
|
db.records.del(@key)
|
||||||
ok()
|
ok(true)
|
||||||
|
else:
|
||||||
|
ok(false)
|
||||||
|
|
||||||
|
proc clear*(db: MemStoreRef): KvResult[bool] =
|
||||||
|
if db.records.len > 0:
|
||||||
|
db.records.clear()
|
||||||
|
ok(true)
|
||||||
|
else:
|
||||||
|
ok(false)
|
||||||
|
|
||||||
proc contains*(db: MemStoreRef, key: openArray[byte]): KvResult[bool] =
|
proc contains*(db: MemStoreRef, key: openArray[byte]): KvResult[bool] =
|
||||||
ok(db.records.contains(@key))
|
ok(db.records.contains(@key))
|
||||||
|
|
|
@ -38,7 +38,8 @@ type
|
||||||
# A Keyspace is a single key-value table - it is generally efficient to
|
# A Keyspace is a single key-value table - it is generally efficient to
|
||||||
# create separate keyspaces for each type of data stored
|
# create separate keyspaces for each type of data stored
|
||||||
open: bool
|
open: bool
|
||||||
getStmt, putStmt, delStmt, containsStmt,
|
env: Sqlite
|
||||||
|
getStmt, putStmt, delStmt, clearStmt, containsStmt,
|
||||||
findStmt0, findStmt1, findStmt2: RawStmtPtr
|
findStmt0, findStmt1, findStmt2: RawStmtPtr
|
||||||
|
|
||||||
SqKeyspaceRef* = ref SqKeyspace
|
SqKeyspaceRef* = ref SqKeyspace
|
||||||
|
@ -433,17 +434,17 @@ proc contains*(db: SqKeyspaceRef, key: openArray[byte]): KvResult[bool] =
|
||||||
|
|
||||||
res
|
res
|
||||||
|
|
||||||
proc del*(db: SqKeyspaceRef, key: openArray[byte]): KvResult[void] =
|
proc del*(db: SqKeyspaceRef, key: openArray[byte]): KvResult[bool] =
|
||||||
if not db.open: return err("sqlite: database closed")
|
if not db.open: return err("sqlite: database closed")
|
||||||
let delStmt = db.delStmt
|
let delStmt = db.delStmt
|
||||||
if delStmt == nil: return ok() # no such table
|
if delStmt == nil: return ok(false) # no such table
|
||||||
checkErr bindParam(delStmt, 1, key)
|
checkErr bindParam(delStmt, 1, key)
|
||||||
|
|
||||||
let res =
|
let res =
|
||||||
if (let v = sqlite3_step(delStmt); v != SQLITE_DONE):
|
if (let v = sqlite3_step(delStmt); v != SQLITE_DONE):
|
||||||
err($sqlite3_errstr(v))
|
err($sqlite3_errstr(v))
|
||||||
else:
|
else:
|
||||||
ok()
|
ok(sqlite3_changes(db.env) > 0)
|
||||||
|
|
||||||
# release implict transaction
|
# release implict transaction
|
||||||
discard sqlite3_reset(delStmt) # same return information as step
|
discard sqlite3_reset(delStmt) # same return information as step
|
||||||
|
@ -451,11 +452,28 @@ proc del*(db: SqKeyspaceRef, key: openArray[byte]): KvResult[void] =
|
||||||
|
|
||||||
res
|
res
|
||||||
|
|
||||||
|
proc clear*(db: SqKeyspaceRef): KvResult[bool] =
|
||||||
|
if not db.open: return err("sqlite: database closed")
|
||||||
|
let clearStmt = db.clearStmt
|
||||||
|
if clearStmt == nil: return ok(false) # no such table
|
||||||
|
|
||||||
|
let res =
|
||||||
|
if (let v = sqlite3_step(clearStmt); v != SQLITE_DONE):
|
||||||
|
err($sqlite3_errstr(v))
|
||||||
|
else:
|
||||||
|
ok(sqlite3_changes(db.env) > 0)
|
||||||
|
|
||||||
|
# release implicit transaction
|
||||||
|
discard sqlite3_reset(clearStmt) # same return information as step
|
||||||
|
|
||||||
|
res
|
||||||
|
|
||||||
proc close*(db: var SqKeyspace) =
|
proc close*(db: var SqKeyspace) =
|
||||||
# Calling with null stmt is harmless
|
# Calling with null stmt is harmless
|
||||||
discard sqlite3_finalize(db.putStmt)
|
discard sqlite3_finalize(db.putStmt)
|
||||||
discard sqlite3_finalize(db.getStmt)
|
discard sqlite3_finalize(db.getStmt)
|
||||||
discard sqlite3_finalize(db.delStmt)
|
discard sqlite3_finalize(db.delStmt)
|
||||||
|
discard sqlite3_finalize(db.clearStmt)
|
||||||
discard sqlite3_finalize(db.containsStmt)
|
discard sqlite3_finalize(db.containsStmt)
|
||||||
discard sqlite3_finalize(db.findStmt0)
|
discard sqlite3_finalize(db.findStmt0)
|
||||||
discard sqlite3_finalize(db.findStmt1)
|
discard sqlite3_finalize(db.findStmt1)
|
||||||
|
@ -604,7 +622,7 @@ proc openKvStore*(
|
||||||
if withoutRowid: createSql & " WITHOUT ROWID;" else: createSql & ";"
|
if withoutRowid: createSql & " WITHOUT ROWID;" else: createSql & ";"
|
||||||
true
|
true
|
||||||
var
|
var
|
||||||
tmp: SqKeyspace
|
tmp = SqKeyspace(env: db.env)
|
||||||
defer:
|
defer:
|
||||||
# We'll "move" ownership to the return value, effectively disabling "close"
|
# We'll "move" ownership to the return value, effectively disabling "close"
|
||||||
close(tmp)
|
close(tmp)
|
||||||
|
@ -615,6 +633,7 @@ proc openKvStore*(
|
||||||
tmp.putStmt =
|
tmp.putStmt =
|
||||||
prepare(db.env, "INSERT OR REPLACE INTO '" & name & "'(key, value) VALUES (?, ?);")
|
prepare(db.env, "INSERT OR REPLACE INTO '" & name & "'(key, value) VALUES (?, ?);")
|
||||||
tmp.delStmt = prepare(db.env, "DELETE FROM '" & name & "' WHERE key = ?;")
|
tmp.delStmt = prepare(db.env, "DELETE FROM '" & name & "' WHERE key = ?;")
|
||||||
|
tmp.clearStmt = prepare(db.env, "DELETE FROM '" & name & "';")
|
||||||
tmp.containsStmt = prepare(db.env, "SELECT 1 FROM '" & name & "' WHERE key = ?;")
|
tmp.containsStmt = prepare(db.env, "SELECT 1 FROM '" & name & "' WHERE key = ?;")
|
||||||
tmp.findStmt0 = prepare(db.env, "SELECT key, value FROM '" & name & "';")
|
tmp.findStmt0 = prepare(db.env, "SELECT key, value FROM '" & name & "';")
|
||||||
tmp.findStmt1 = prepare(db.env, "SELECT key, value FROM '" & name & "' WHERE key >= ?;")
|
tmp.findStmt1 = prepare(db.env, "SELECT key, value FROM '" & name & "' WHERE key >= ?;")
|
||||||
|
|
|
@ -16,8 +16,7 @@ proc testKvStore*(db: KvStoreRef, supportsFind: bool) =
|
||||||
|
|
||||||
not db.get(key, proc(data: openArray[byte]) = discard)[]
|
not db.get(key, proc(data: openArray[byte]) = discard)[]
|
||||||
not db.contains(key)[]
|
not db.contains(key)[]
|
||||||
|
not db.del(key)[] # does nothing
|
||||||
db.del(key)[] # does nothing
|
|
||||||
|
|
||||||
db.put(key, value)[]
|
db.put(key, value)[]
|
||||||
|
|
||||||
|
@ -39,12 +38,19 @@ proc testKvStore*(db: KvStoreRef, supportsFind: bool) =
|
||||||
db.get(key, grab)[]
|
db.get(key, grab)[]
|
||||||
v == value2
|
v == value2
|
||||||
|
|
||||||
db.del(key)[]
|
|
||||||
check:
|
check:
|
||||||
|
db.del(key)[]
|
||||||
not db.get(key, proc(data: openArray[byte]) = discard)[]
|
not db.get(key, proc(data: openArray[byte]) = discard)[]
|
||||||
not db.contains(key)[]
|
not db.contains(key)[]
|
||||||
|
|
||||||
db.del(key)[] # does nothing
|
not db.del(key)[] # does nothing
|
||||||
|
|
||||||
|
db.put(key, value2)[] # overwrite old value
|
||||||
|
check:
|
||||||
|
db.contains(key)[]
|
||||||
|
db.clear()[]
|
||||||
|
not db.contains(key)[]
|
||||||
|
not db.clear()[]
|
||||||
|
|
||||||
if supportsFind:
|
if supportsFind:
|
||||||
check:
|
check:
|
||||||
|
|
Loading…
Reference in New Issue