mirror of
https://github.com/logos-storage/nim-datastore.git
synced 2026-01-03 14:13:09 +00:00
add memory (test) ds
This commit is contained in:
parent
e89b383304
commit
344b50c703
96
datastore/memoryds.nim
Normal file
96
datastore/memoryds.nim
Normal file
@ -0,0 +1,96 @@
|
||||
import std/tables
|
||||
|
||||
import pkg/chronos
|
||||
import pkg/questionable
|
||||
import pkg/questionable/results
|
||||
import pkg/upraises
|
||||
|
||||
import ./key
|
||||
import ./query
|
||||
import ./datastore
|
||||
|
||||
export key, query
|
||||
|
||||
push: {.upraises: [].}
|
||||
|
||||
type
|
||||
MemoryStore* = object
|
||||
store*: Datastore
|
||||
key*: Key
|
||||
|
||||
MemoryDatastore* = ref object of Datastore
|
||||
stores*: Table[Key, MemoryStore]
|
||||
|
||||
method has*(
|
||||
self: MemoryDatastore,
|
||||
key: Key): Future[?!bool] {.async.} =
|
||||
|
||||
without mounted =? self.dispatch(key):
|
||||
return failure "No mounted datastore found"
|
||||
|
||||
return (await mounted.store.store.has(mounted.relative))
|
||||
|
||||
method delete*(
|
||||
self: MemoryDatastore,
|
||||
key: Key): Future[?!void] {.async.} =
|
||||
|
||||
without mounted =? self.dispatch(key), error:
|
||||
return failure(error)
|
||||
|
||||
return (await mounted.store.store.delete(mounted.relative))
|
||||
|
||||
method delete*(
|
||||
self: MemoryDatastore,
|
||||
keys: seq[Key]): Future[?!void] {.async.} =
|
||||
|
||||
for key in keys:
|
||||
if err =? (await self.delete(key)).errorOption:
|
||||
return failure err
|
||||
|
||||
return success()
|
||||
|
||||
method get*(
|
||||
self: MemoryDatastore,
|
||||
key: Key): Future[?!seq[byte]] {.async.} =
|
||||
|
||||
without mounted =? self.dispatch(key), error:
|
||||
return failure(error)
|
||||
|
||||
return await mounted.store.store.get(mounted.relative)
|
||||
|
||||
method put*(
|
||||
self: MemoryDatastore,
|
||||
key: Key,
|
||||
data: seq[byte]): Future[?!void] {.async.} =
|
||||
|
||||
without mounted =? self.dispatch(key), error:
|
||||
return failure(error)
|
||||
|
||||
return (await mounted.store.store.put(mounted.relative, data))
|
||||
|
||||
method put*(
|
||||
self: MemoryDatastore,
|
||||
batch: seq[BatchEntry]): Future[?!void] {.async.} =
|
||||
|
||||
for entry in batch:
|
||||
if err =? (await self.put(entry.key, entry.data)).errorOption:
|
||||
return failure err
|
||||
|
||||
return success()
|
||||
|
||||
method close*(self: MemoryDatastore): Future[?!void] {.async.} =
|
||||
for s in self.stores.values:
|
||||
discard await s.store.close()
|
||||
|
||||
# TODO: how to handle failed close?
|
||||
return success()
|
||||
|
||||
func new*(
|
||||
T: type MemoryDatastore,
|
||||
stores: Table[Key, Datastore] = initTable[Key, Datastore]()): ?!T =
|
||||
|
||||
var self = T()
|
||||
for (k, v) in stores.pairs:
|
||||
self.stores[?k.path] = MemoryStore(store: v, key: k)
|
||||
|
||||
success self
|
||||
138
tests/datastore/testmemoryds.nim
Normal file
138
tests/datastore/testmemoryds.nim
Normal file
@ -0,0 +1,138 @@
|
||||
import std/options
|
||||
import std/sequtils
|
||||
import std/os
|
||||
from std/algorithm import sort, reversed
|
||||
|
||||
import pkg/asynctest/unittest2
|
||||
import pkg/chronos
|
||||
import pkg/stew/results
|
||||
import pkg/stew/byteutils
|
||||
|
||||
import pkg/datastore/fsds
|
||||
|
||||
import ./dscommontests
|
||||
import ./querycommontests
|
||||
|
||||
suite "Test Basic MemoryDatastore":
|
||||
let
|
||||
path = currentSourcePath() # get this file's name
|
||||
basePath = "tests_data"
|
||||
basePathAbs = path.parentDir / basePath
|
||||
key = Key.init("/a/b").tryGet()
|
||||
bytes = "some bytes".toBytes
|
||||
otherBytes = "some other bytes".toBytes
|
||||
|
||||
var
|
||||
fsStore: MemoryDatastore
|
||||
|
||||
setupAll:
|
||||
removeDir(basePathAbs)
|
||||
require(not dirExists(basePathAbs))
|
||||
createDir(basePathAbs)
|
||||
|
||||
fsStore = MemoryDatastore.new(root = basePathAbs, depth = 3).tryGet()
|
||||
|
||||
teardownAll:
|
||||
removeDir(basePathAbs)
|
||||
require(not dirExists(basePathAbs))
|
||||
|
||||
basicStoreTests(fsStore, key, bytes, otherBytes)
|
||||
|
||||
suite "Test Misc MemoryDatastore":
|
||||
let
|
||||
path = currentSourcePath() # get this file's name
|
||||
basePath = "tests_data"
|
||||
basePathAbs = path.parentDir / basePath
|
||||
bytes = "some bytes".toBytes
|
||||
|
||||
setup:
|
||||
removeDir(basePathAbs)
|
||||
require(not dirExists(basePathAbs))
|
||||
createDir(basePathAbs)
|
||||
|
||||
teardown:
|
||||
removeDir(basePathAbs)
|
||||
require(not dirExists(basePathAbs))
|
||||
|
||||
test "Test validDepth()":
|
||||
let
|
||||
fs = MemoryDatastore.new(root = "/", depth = 3).tryGet()
|
||||
invalid = Key.init("/a/b/c/d").tryGet()
|
||||
valid = Key.init("/a/b/c").tryGet()
|
||||
|
||||
check:
|
||||
not fs.validDepth(invalid)
|
||||
fs.validDepth(valid)
|
||||
|
||||
test "Test invalid key (path) depth":
|
||||
let
|
||||
fs = MemoryDatastore.new(root = basePathAbs, depth = 3).tryGet()
|
||||
key = Key.init("/a/b/c/d").tryGet()
|
||||
|
||||
check:
|
||||
(await fs.put(key, bytes)).isErr
|
||||
(await fs.get(key)).isErr
|
||||
(await fs.delete(key)).isErr
|
||||
(await fs.has(key)).isErr
|
||||
|
||||
test "Test valid key (path) depth":
|
||||
let
|
||||
fs = MemoryDatastore.new(root = basePathAbs, depth = 3).tryGet()
|
||||
key = Key.init("/a/b/c").tryGet()
|
||||
|
||||
check:
|
||||
(await fs.put(key, bytes)).isOk
|
||||
(await fs.get(key)).isOk
|
||||
(await fs.delete(key)).isOk
|
||||
(await fs.has(key)).isOk
|
||||
|
||||
test "Test key cannot write outside of root":
|
||||
let
|
||||
fs = MemoryDatastore.new(root = basePathAbs, depth = 3).tryGet()
|
||||
key = Key.init("/a/../../c").tryGet()
|
||||
|
||||
check:
|
||||
(await fs.put(key, bytes)).isErr
|
||||
(await fs.get(key)).isErr
|
||||
(await fs.delete(key)).isErr
|
||||
(await fs.has(key)).isErr
|
||||
|
||||
test "Test key cannot convert to invalid path":
|
||||
let
|
||||
fs = MemoryDatastore.new(root = basePathAbs).tryGet()
|
||||
|
||||
for c in invalidFilenameChars:
|
||||
if c == ':': continue
|
||||
if c == '/': continue
|
||||
|
||||
let
|
||||
key = Key.init("/" & c).tryGet()
|
||||
|
||||
check:
|
||||
(await fs.put(key, bytes)).isErr
|
||||
(await fs.get(key)).isErr
|
||||
(await fs.delete(key)).isErr
|
||||
(await fs.has(key)).isErr
|
||||
|
||||
suite "Test Query":
|
||||
let
|
||||
path = currentSourcePath() # get this file's name
|
||||
basePath = "tests_data"
|
||||
basePathAbs = path.parentDir / basePath
|
||||
|
||||
var
|
||||
ds: MemoryDatastore
|
||||
|
||||
setup:
|
||||
removeDir(basePathAbs)
|
||||
require(not dirExists(basePathAbs))
|
||||
createDir(basePathAbs)
|
||||
|
||||
ds = MemoryDatastore.new(root = basePathAbs, depth = 5).tryGet()
|
||||
|
||||
teardown:
|
||||
|
||||
removeDir(basePathAbs)
|
||||
require(not dirExists(basePathAbs))
|
||||
|
||||
queryTests(ds, false)
|
||||
Loading…
x
Reference in New Issue
Block a user