mirror of
https://github.com/logos-storage/nim-datastore.git
synced 2026-01-02 21:53:05 +00:00
323 lines
6.3 KiB
Nim
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
|