nim-datastore/tests/datastore/test_sqlite_datastore.nim
2022-06-22 13:16:43 -05:00

323 lines
6.3 KiB
Nim

import std/options
import std/os
import pkg/stew/results
import pkg/unittest2
import ../../datastore/sqlite_datastore
suite "SQLiteDatastore":
setup:
var
ds: SQLiteDatastore
# assumes tests/test_all is run from project root, e.g. with `nimble test`
let
basePath = "tests" / "test_data"
basePathAbs = getCurrentDir() / basePath
filename = "test_store" & dbExt
dbPathAbs = basePathAbs / filename
removeDir(basePathAbs)
require(not dirExists(basePathAbs))
discard dbPathAbs # suppresses "declared but not used" re: dbPathAbs
teardown:
if not ds.isNil: ds.close
removeDir(basePathAbs)
require(not dirExists(basePathAbs))
test "new":
var
dsRes = SQLiteDatastore.new(basePathAbs, filename, readOnly = true)
# for `readOnly = true` to succeed the database file must already exist
check: dsRes.isErr
dsRes = SQLiteDatastore.new(basePathAbs, filename)
assert dsRes.isOk
ds = dsRes.get
check:
dirExists(basePathAbs)
fileExists(dbPathAbs)
ds.close
removeDir(basePathAbs)
assert not dirExists(basePathAbs)
dsRes = SQLiteDatastore.new(basePath, filename)
assert dsRes.isOk
ds = dsRes.get
check:
dirExists(basePathAbs)
fileExists(dbPathAbs)
ds.close
# for `readOnly = true` to succeed the database file must already exist, so
# the existing file (per previous step) is not deleted prior to the next
# invocation of `SQLiteDatastore.new`
dsRes = SQLiteDatastore.new(basePath, filename, readOnly = true)
assert dsRes.isOk
ds = dsRes.get
check:
dirExists(basePathAbs)
fileExists(dbPathAbs)
ds.close
removeDir(basePathAbs)
assert not dirExists(basePathAbs)
dsRes = SQLiteDatastore.new(inMemory = true)
assert dsRes.isOk
ds = dsRes.get
check:
not dirExists(basePathAbs)
not fileExists(dbPathAbs)
ds.close
dsRes = SQLiteDatastore.new(readOnly = true, inMemory = true)
check: dsRes.isErr
test "accessors":
ds = SQLiteDatastore.new(basePath).get
check:
parentDir(ds.dbPath) == basePathAbs
not ds.env.isNil
test "helpers":
ds = SQLiteDatastore.new(basePath).get
ds.close
check:
ds.env.isNil
timestamp(10.123_456) == 10_123_456.int64
test "put":
let
key = Key.init("a:b/c/d:e").get
# for `readOnly = true` to succeed the database file must already exist
ds = SQLiteDatastore.new(basePathAbs, filename).get
ds.close
ds = SQLiteDatastore.new(basePathAbs, filename, readOnly = true).get
var
bytes: seq[byte]
timestamp = timestamp()
putRes = ds.put(key, bytes, timestamp)
check: putRes.isErr
ds.close
removeDir(basePathAbs)
assert not dirExists(basePathAbs)
ds = SQLiteDatastore.new(basePathAbs, filename).get
timestamp = timestamp()
putRes = ds.put(key, bytes, timestamp)
check: putRes.isOk
let
query = "SELECT * FROM " & tableTitle & ";"
var
qId: string
qData: seq[byte]
qTimestamp: int64
rowCount = 0
proc onData(s: RawStmtPtr) {.closure.} =
qId = idCol(s)
qData = dataCol(s)
qTimestamp = timestampCol(s)
inc rowCount
var
qRes = ds.env.query(query, onData)
assert qRes.isOk
check:
qRes.get
qId == key.id
qData == bytes
qTimestamp == timestamp
rowCount == 1
bytes = @[1.byte, 2.byte, 3.byte]
timestamp = timestamp()
putRes = ds.put(key, bytes, timestamp)
check: putRes.isOk
rowCount = 0
qRes = ds.env.query(query, onData)
assert qRes.isOk
check:
qRes.get
qId == key.id
qData == bytes
qTimestamp == timestamp
rowCount == 1
bytes = @[4.byte, 5.byte, 6.byte]
timestamp = timestamp()
putRes = ds.put(key, bytes, timestamp)
check: putRes.isOk
rowCount = 0
qRes = ds.env.query(query, onData)
assert qRes.isOk
check:
qRes.get
qId == key.id
qData == bytes
qTimestamp == timestamp
rowCount == 1
test "delete":
let
bytes = @[1.byte, 2.byte, 3.byte]
var
key = Key.init("a:b/c/d:e").get
# for `readOnly = true` to succeed the database file must already exist
ds = SQLiteDatastore.new(basePathAbs, filename).get
ds.close
ds = SQLiteDatastore.new(basePathAbs, filename, readOnly = true).get
var
delRes = ds.delete(key)
check: delRes.isErr
ds.close
removeDir(basePathAbs)
assert not dirExists(basePathAbs)
ds = SQLiteDatastore.new(basePathAbs, filename).get
let
putRes = ds.put(key, bytes)
assert putRes.isOk
let
query = "SELECT * FROM " & tableTitle & ";"
var
rowCount = 0
proc onData(s: RawStmtPtr) {.closure.} =
inc rowCount
var
qRes = ds.env.query(query, onData)
assert qRes.isOk
check: rowCount == 1
delRes = ds.delete(key)
check: delRes.isOk
rowCount = 0
qRes = ds.env.query(query, onData)
assert qRes.isOk
check:
delRes.isOk
rowCount == 0
key = Key.init("X/Y/Z").get
delRes = ds.delete(key)
check: delRes.isOk
test "contains":
let
bytes = @[1.byte, 2.byte, 3.byte]
var
key = Key.init("a:b/c/d:e").get
ds = SQLiteDatastore.new(basePathAbs, filename).get
let
putRes = ds.put(key, bytes)
assert putRes.isOk
var
containsRes = ds.contains(key)
assert containsRes.isOk
check: containsRes.get == true
key = Key.init("X/Y/Z").get
containsRes = ds.contains(key)
assert containsRes.isOk
check: containsRes.get == false
test "get":
ds = SQLiteDatastore.new(basePathAbs, filename).get
var
bytes: seq[byte]
key = Key.init("a:b/c/d:e").get
putRes = ds.put(key, bytes)
assert putRes.isOk
var
getRes = ds.get(key)
getOpt = getRes.get
check: getOpt.isSome and getOpt.get == bytes
bytes = @[1.byte, 2.byte, 3.byte]
putRes = ds.put(key, bytes)
assert putRes.isOk
getRes = ds.get(key)
getOpt = getRes.get
check: getOpt.isSome and getOpt.get == bytes
key = Key.init("X/Y/Z").get
assert not ds.contains(key).get
getRes = ds.get(key)
getOpt = getRes.get
check: getOpt.isNone
# test "query":
# check:
# true