mirror of https://github.com/status-im/nim-eth.git
Add support for array[N, byte] in SQLite queries
This commit is contained in:
parent
49c40c9b95
commit
482ea988c0
|
@ -3,7 +3,7 @@
|
|||
{.push raises: [Defect].}
|
||||
|
||||
import
|
||||
os, strformat,
|
||||
std/[os, strformat],
|
||||
sqlite3_abi,
|
||||
./kvstore
|
||||
|
||||
|
@ -74,12 +74,22 @@ proc bindParam(s: RawStmtPtr, n: int, val: auto): cint =
|
|||
sqlite3_bind_blob(s, n.cint, unsafeAddr val[0], val.len.cint, nil)
|
||||
else:
|
||||
sqlite3_bind_blob(s, n.cint, nil, 0.cint, nil)
|
||||
elif val is array:
|
||||
when val.items.typeof is byte:
|
||||
# Prior to Nim 1.4 and view types array[N, byte] in tuples
|
||||
# don't match with openarray[byte]
|
||||
if val.len > 0:
|
||||
sqlite3_bind_blob(s, n.cint, unsafeAddr val[0], val.len.cint, nil)
|
||||
else:
|
||||
sqlite3_bind_blob(s, n.cint, nil, 0.cint, nil)
|
||||
else:
|
||||
{.fatal: "Please add support for the '" & $typeof(val) & "' type".}
|
||||
elif val is int32:
|
||||
sqlite3_bind_int(s, n.cint, val)
|
||||
elif val is int64:
|
||||
sqlite3_bind_int64(s, n.cint, val)
|
||||
else:
|
||||
{.fatal: "Please add support for the '" & $(T) & "' type".}
|
||||
{.fatal: "Please add support for the '" & $typeof(val) & "' type".}
|
||||
|
||||
template bindParams(s: RawStmtPtr, params: auto) =
|
||||
when params is tuple:
|
||||
|
@ -125,6 +135,20 @@ template readResult(s: RawStmtPtr, column: cint, T: type): auto =
|
|||
res.setLen(len)
|
||||
copyMem(addr res[0], sqlite3_column_blob(s, column), len)
|
||||
res
|
||||
elif T is array:
|
||||
# array[N, byte]. "genericParams(T)[1]" requires 1.4 to handle nnkTypeOfExpr
|
||||
when typeof(block: (var a: T; a[0])) is byte:
|
||||
var res: T
|
||||
let colLen = sqlite3_column_bytes(s, column)
|
||||
|
||||
# truncate if the type is too small
|
||||
# TODO: warning/error? We assume that users always properly dimension buffers
|
||||
let copyLen = min(colLen, res.len)
|
||||
if copyLen > 0:
|
||||
copyMem(addr res[0], sqlite3_column_blob(s, column), copyLen)
|
||||
res
|
||||
else:
|
||||
{.fatal: "Please add support for the '" & $(T) & "' type".}
|
||||
else:
|
||||
{.fatal: "Please add support for the '" & $(T) & "' type".}
|
||||
|
||||
|
@ -445,4 +469,3 @@ when defined(metrics):
|
|||
timestamp: timestamp,
|
||||
),
|
||||
]
|
||||
|
||||
|
|
|
@ -95,3 +95,84 @@ procSuite "SqStoreRef":
|
|||
@[byte 5]
|
||||
]
|
||||
|
||||
test "Tuple with byte arrays support":
|
||||
# openarray[byte] requires either Nim 1.4
|
||||
# or hardcoding the seq[byte] and array[N, byte] paths
|
||||
let db = SqStoreRef.init("", "test", inMemory = true)[]
|
||||
defer: db.close()
|
||||
|
||||
let createTableRes = db.exec """
|
||||
CREATE TABLE IF NOT EXISTS attestations(
|
||||
validator_id INTEGER NOT NULL,
|
||||
source_epoch INTEGER NOT NULL,
|
||||
target_epoch INTEGER NOT NULL,
|
||||
attestation_root BLOB NOT NULL UNIQUE,
|
||||
UNIQUE (validator_id, target_epoch)
|
||||
);
|
||||
"""
|
||||
check createTableRes.isOk
|
||||
|
||||
let insertStmt = db.prepareStmt("""
|
||||
INSERT INTO attestations(
|
||||
validator_id,
|
||||
source_epoch,
|
||||
target_epoch,
|
||||
attestation_root)
|
||||
VALUES
|
||||
(?,?,?,?);
|
||||
""", (int32, int64, int64, array[32, byte]), void).get()
|
||||
|
||||
var hash: array[32, byte]
|
||||
hash[1] = byte 1
|
||||
hash[2] = byte 2
|
||||
let insertRes = insertStmt.exec(
|
||||
(123'i32, 2'i64, 4'i64, hash)
|
||||
)
|
||||
|
||||
check: insertRes.isOk
|
||||
|
||||
let countStmt = db.prepareStmt(
|
||||
"SELECT COUNT(*) FROM attestations;",
|
||||
NoParams, int64).get
|
||||
|
||||
var totalRecords = 0
|
||||
echo "About to call total attestations"
|
||||
let countRes = countStmt.exec do (res: int64):
|
||||
totalRecords = int res
|
||||
|
||||
check:
|
||||
countRes.isOk and countRes.get == true
|
||||
totalRecords == 1
|
||||
|
||||
let selectRangeStmt = db.prepareStmt("""
|
||||
SELECT
|
||||
source_epoch,
|
||||
target_epoch,
|
||||
attestation_root
|
||||
FROM
|
||||
attestations
|
||||
WHERE
|
||||
validator_id = ?
|
||||
AND
|
||||
? < source_epoch AND target_epoch < ?
|
||||
LIMIT 1
|
||||
""", (int32, int64, int64), (int64, int64, array[32, byte])).get()
|
||||
|
||||
block:
|
||||
var digest: array[32, byte]
|
||||
var source, target: int64
|
||||
let selectRangeRes = selectRangeStmt.exec(
|
||||
(123'i32, 1'i64, 5'i64)
|
||||
) do (res: tuple[source, target: int64, hash: array[32, byte]]) {.gcsafe.}:
|
||||
source = res.source
|
||||
target = res.target
|
||||
digest = res.hash
|
||||
|
||||
if selectRangeRes.isErr:
|
||||
echo selectRangeRes.error
|
||||
|
||||
check:
|
||||
selectRangeRes.isOk and selectRangeRes.get == true
|
||||
source == 2
|
||||
target == 4
|
||||
digest == hash
|
||||
|
|
Loading…
Reference in New Issue