all repos — litestore @ dfaa905915573ecfa609bb0aec9f783e46df7c85

A minimalist nosql document store.

litestore.nim

 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
import 
  sqlite3, 
  db_sqlite as db, 
  strutils, 
  os

{.compile: "vendor/sqlite/libsqlite3.c".}
{.passC: "-DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_PARENTHESIS".}


type 
  EDatastoreExists* = object of Exception
  EDatastoreDoesNotExist* = object of Exception
  EDatastoreUnavailable* = object of Exception
  Datastore* = object
    db: TDbConn
    path: string
    name: string
  QueryOptions* = object
    count*: bool
    limit*: int
    orderby*: seq[string]
    tags*: seq[string]
    search*: string
    select*: seq[string]
    raw*: bool

# TODO manage stores directory
let cwd = getCurrentDir()

const DOCUMENTS_TABLE = sql"""
CREATE TABLE documents (
key TEXT PRIMARY KEY,
bvalue BLOB,
tvalue TEXT,
mimetype TEXT,
created TEXT,
modified TEXT)
"""

const SEARCHINDEX_TABLE = sql"""
CREATE VIRTUAL TABLE searchindex USING fts4(
key TEXT REFERENCES documents (key) ON DELETE CASCADE,
content TEXT)
"""

const TAGS_TABLE = sql"""
CREATE TABLE tags (
tag TEXT,
key TEXT REFERENCES documents (key) ON DELETE CASCADE,
PRIMARY KEY (tag, key))
"""

# Manage Datastores

proc createDatastore*(name:string) = 
  if name.changeFileExt("ls").fileExists:
    raise newException(EDatastoreExists, "Datastore '$1' already exists." % name)
  let store = db.open(cwd.joinPath(name.changeFileExt("ls")), "", "", "")
  store.exec(DOCUMENTS_TABLE)
  store.exec(SEARCHINDEX_TABLE)
  store.exec(TAGS_TABLE)

proc deleteDatastore*(name:string) =
  try:
    cwd.joinPath(name.changeFileExt("ls")).removeFile
  except:
    raise newException(EDatastoreUnavailable, "Datastore '$1' cannot deleted." % name)

proc openDatastore(name:string): Datastore =
  if not name.fileExists:
    raise newException(EDatastoreDoesNotExist, "Datastore '$1' does not exists." % name)
  try:
    result.db = db.open(cwd.joinPath(name.changeFileExt("ls")), "", "", "")
    result.name = name
    result.path = cwd.joinPath(name)
  except:
    raise newException(EDatastoreUnavailable, "Datastore '$1' cannot be opened." % name)

proc closeDatastore(store:Datastore) = 
  try:
    db.close(store.db)
  except:
    raise newException(EDatastoreUnavailable, "Datastore '$1' cannot be closed." % store.name)

proc retrieveDatastores*(): seq[string] =
  result = newSeq[string](0)
  for f in walkFiles(cwd.joinPath("*.ls")):
    result.add f.extractFilename.changeFileExt("")

# TODO Implement
proc createDocument*(store: Datastore, value: string, content = "", mimetype = "text/plain") =
  discard

proc updateDocument*(store: Datastore, key: string, value: string, content = "", mimetype = "text/plain") =
  discard

proc deleteDocument*(store: Datastore, key: string) =
  discard

proc retrieveDocument*(store: Datastore, key: string, options: QueryOptions = QueryOptions()) =
  discard

proc retrieveDocuments*(store: Datastore, options: QueryOptions = QueryOptions()) =
  discard

proc createTag*(store: Datastore, tag, key: string) =
  discard

proc deleteTag*(store: Datastore, tag, key: string) =
  discard

proc retrieveTags*(store: Datastore, options: QueryOptions = QueryOptions()) =
  discard

# Test

var store = "test"
createDatastore(store)
echo retrieveDatastores()