mirror of https://github.com/status-im/nim-eth.git
sqlite3: support option type
.. and any integer when writing but don't support int32 on reads - internally sqlite will truncate on overflow which isn't nice.
This commit is contained in:
parent
2a292cfb62
commit
68e6aadc29
|
@ -93,10 +93,13 @@ proc bindParam(s: RawStmtPtr, n: int, val: auto): cint =
|
||||||
sqlite3_bind_blob(s, n.cint, nil, 0.cint, nil)
|
sqlite3_bind_blob(s, n.cint, nil, 0.cint, nil)
|
||||||
else:
|
else:
|
||||||
{.fatal: "Please add support for the '" & $typeof(val) & "' type".}
|
{.fatal: "Please add support for the '" & $typeof(val) & "' type".}
|
||||||
elif val is int32:
|
elif val is SomeInteger:
|
||||||
sqlite3_bind_int(s, n.cint, val)
|
sqlite3_bind_int64(s, n.cint, val.clong)
|
||||||
elif val is int64:
|
elif val is Option:
|
||||||
sqlite3_bind_int64(s, n.cint, val)
|
if val.isNone():
|
||||||
|
sqlite3_bind_null(s, n.cint)
|
||||||
|
else:
|
||||||
|
bindParam(s, n, val.get())
|
||||||
else:
|
else:
|
||||||
{.fatal: "Please add support for the '" & $typeof(val) & "' type".}
|
{.fatal: "Please add support for the '" & $typeof(val) & "' type".}
|
||||||
|
|
||||||
|
@ -125,13 +128,15 @@ proc exec*[P](s: SqliteStmt[P, void], params: P): KvResult[void] =
|
||||||
|
|
||||||
res
|
res
|
||||||
|
|
||||||
template readResult(s: RawStmtPtr, column: cint, T: type): auto =
|
template readSimpleResult(s: RawStmtPtr, column: cint, T: type): auto =
|
||||||
when T is int32:
|
when T is int64:
|
||||||
sqlite3_column_int(s, column)
|
|
||||||
elif T is int64:
|
|
||||||
sqlite3_column_int64(s, column)
|
sqlite3_column_int64(s, column)
|
||||||
elif T is int:
|
elif T is SomeInteger:
|
||||||
{.fatal: "Please use specify either int32 or int64 precisely".}
|
# sqlite integers are "up to" 8 bytes in size, so rather than silently
|
||||||
|
# truncate them, we support only 64-bit integers when reading and let the
|
||||||
|
# calling code deal with it - careful though, anything that is not an
|
||||||
|
# integer (ie TEXT) is returned as 0
|
||||||
|
{.fatal: "Use int64 for reading integers".}
|
||||||
elif T is openArray[byte]:
|
elif T is openArray[byte]:
|
||||||
let
|
let
|
||||||
p = cast[ptr UncheckedArray[byte]](sqlite3_column_blob(s, column))
|
p = cast[ptr UncheckedArray[byte]](sqlite3_column_blob(s, column))
|
||||||
|
@ -161,6 +166,15 @@ template readResult(s: RawStmtPtr, column: cint, T: type): auto =
|
||||||
else:
|
else:
|
||||||
{.fatal: "Please add support for the '" & $(T) & "' type".}
|
{.fatal: "Please add support for the '" & $(T) & "' type".}
|
||||||
|
|
||||||
|
template readResult(s: RawStmtPtr, column: cint, T: type): auto =
|
||||||
|
when T is Option:
|
||||||
|
if sqlite3_column_type(s, column) == SQLITE_NULL:
|
||||||
|
none(typeof(default(T).get()))
|
||||||
|
else:
|
||||||
|
some(readSimpleResult(s, column, typeof(default(T).get())))
|
||||||
|
else:
|
||||||
|
readSimpleResult(s, column, T)
|
||||||
|
|
||||||
template readResult(s: RawStmtPtr, T: type): auto =
|
template readResult(s: RawStmtPtr, T: type): auto =
|
||||||
when T is tuple:
|
when T is tuple:
|
||||||
var res: T
|
var res: T
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{.used.}
|
{.used.}
|
||||||
|
|
||||||
import
|
import
|
||||||
std/os,
|
std/[os, options],
|
||||||
testutils/unittests,
|
testutils/unittests,
|
||||||
../../eth/db/[kvstore, kvstore_sqlite3],
|
../../eth/db/[kvstore, kvstore_sqlite3],
|
||||||
./test_kvstore
|
./test_kvstore
|
||||||
|
@ -45,7 +45,6 @@ procSuite "SqStoreRef":
|
||||||
NoParams, int64).get
|
NoParams, int64).get
|
||||||
|
|
||||||
var totalRecords = 0
|
var totalRecords = 0
|
||||||
echo "About to call total records"
|
|
||||||
let countRes = countStmt.exec do (res: int64):
|
let countRes = countStmt.exec do (res: int64):
|
||||||
totalRecords = int res
|
totalRecords = int res
|
||||||
|
|
||||||
|
@ -138,7 +137,6 @@ procSuite "SqStoreRef":
|
||||||
NoParams, int64).get
|
NoParams, int64).get
|
||||||
|
|
||||||
var totalRecords = 0
|
var totalRecords = 0
|
||||||
echo "About to call total attestations"
|
|
||||||
let countRes = countStmt.exec do (res: int64):
|
let countRes = countStmt.exec do (res: int64):
|
||||||
totalRecords = int res
|
totalRecords = int res
|
||||||
|
|
||||||
|
@ -178,3 +176,43 @@ procSuite "SqStoreRef":
|
||||||
source == 2
|
source == 2
|
||||||
target == 4
|
target == 4
|
||||||
digest == hash
|
digest == hash
|
||||||
|
|
||||||
|
test "null values":
|
||||||
|
#
|
||||||
|
let db = SqStoreRef.init("", "test", inMemory = true)[]
|
||||||
|
defer: db.close()
|
||||||
|
|
||||||
|
let createTableRes = db.exec """
|
||||||
|
CREATE TABLE IF NOT EXISTS testnull(
|
||||||
|
a INTEGER PRIMARY KEY,
|
||||||
|
b INTEGER NULL,
|
||||||
|
c INTEGER NULL
|
||||||
|
);
|
||||||
|
"""
|
||||||
|
check createTableRes.isOk
|
||||||
|
|
||||||
|
type
|
||||||
|
ABC = (int64, Option[int64], Option[int64])
|
||||||
|
let insertStmt = db.prepareStmt("""
|
||||||
|
INSERT INTO testnull(a, b, c) VALUES (?,?,?);
|
||||||
|
""", ABC, void).get()
|
||||||
|
|
||||||
|
const val = (42'i64, none(int64), some(44'i64))
|
||||||
|
check:
|
||||||
|
insertStmt.exec(val).isOk()
|
||||||
|
|
||||||
|
let selectStmt = db.prepareStmt("""
|
||||||
|
SELECT a, b, c FROM testnull
|
||||||
|
""", NoParams, ABC).get()
|
||||||
|
|
||||||
|
block:
|
||||||
|
var abc: ABC
|
||||||
|
let selectRes = selectStmt.exec do (res: ABC):
|
||||||
|
abc = res
|
||||||
|
|
||||||
|
if selectRes.isErr:
|
||||||
|
echo selectRes.error
|
||||||
|
|
||||||
|
check:
|
||||||
|
selectRes.isOk and selectRes.get == true
|
||||||
|
abc == val
|
||||||
|
|
Loading…
Reference in New Issue