Absorbed by the Syndesizer
https://git.syndicate-lang.org/ehmry/syndicate_utils
This commit is contained in:
parent
023d50abbb
commit
32c2d251ab
|
@ -1 +0,0 @@
|
||||||
/nim.cfg
|
|
31
README.md
31
README.md
|
@ -1,32 +1,5 @@
|
||||||
# sqlite_actor
|
# sqlite_actor
|
||||||
|
|
||||||
Syndicate actor for accessing SQLite databases.
|
Absorbed by the Syndesizer
|
||||||
|
|
||||||
## Build
|
https://git.syndicate-lang.org/ehmry/syndicate_utils
|
||||||
|
|
||||||
Depends on the [SQLcipher](https://www.zetetic.net/sqlcipher/) library and pkg-config.
|
|
||||||
|
|
||||||
## Example configuration
|
|
||||||
```
|
|
||||||
? <example-dataspace ?ds> [
|
|
||||||
|
|
||||||
$ds <query example-row "SELECT id, name FROM stuff">
|
|
||||||
|
|
||||||
$ds ? <example-row ?id ?name> [
|
|
||||||
$log ! <log "-" { row: <example-row $id $name> }>
|
|
||||||
]
|
|
||||||
|
|
||||||
<require-service <daemon sqlite_actor>>
|
|
||||||
? <service-object <daemon sqlite_actor> ?cap> [
|
|
||||||
$cap {
|
|
||||||
dataspace: $ds
|
|
||||||
database: "/var/db/example.db"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
<daemon sqlite_actor {
|
|
||||||
argv: [ "/usr/local/bin/sqlite_actor" ]
|
|
||||||
protocol: application/syndicate
|
|
||||||
}>
|
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
include ../syndicate-nim/depends.tup
|
|
||||||
NIM_FLAGS += --path:$(TUP_CWD)/../syndicate-nim/src
|
|
||||||
NIM_GROUPS += $(TUP_CWD)/<lock>
|
|
|
@ -1 +0,0 @@
|
||||||
{"depends":[{"method":"fetchzip","packages":["hashlib"],"path":"/nix/store/v03nzlpdgbfxd2zhcnkfbkq01d5kqxcl-source","rev":"84e0247555e4488594975900401baaf5bbbfb53","sha256":"1pfczsv8kl36qpv543f93d2y2vgz2acckssfap7l51s2x62m6qwx","srcDir":"","url":"https://github.com/khchen/hashlib/archive/84e0247555e4488594975900401baaf5bbbfb53.tar.gz"},{"method":"fetchzip","packages":["nimcrypto"],"path":"/nix/store/zyr8zwh7vaiycn1s4r8cxwc71f2k5l0h-source","ref":"traditional-api","rev":"602c5d20c69c76137201b5d41f788f72afb95aa8","sha256":"1dmdmgb6b9m5f8dyxk781nnd61dsk3hdxqks7idk9ncnpj9fng65","srcDir":"","url":"https://github.com/cheatfate/nimcrypto/archive/602c5d20c69c76137201b5d41f788f72afb95aa8.tar.gz"},{"method":"fetchzip","packages":["npeg"],"path":"/nix/store/ffkxmjmigfs7zhhiiqm0iw2c34smyciy-source","ref":"1.2.1","rev":"26d62fdc40feb84c6533956dc11d5ee9ea9b6c09","sha256":"0xpzifjkfp49w76qmaylan8q181bs45anmp46l4bwr3lkrr7bpwh","srcDir":"src","url":"https://github.com/zevv/npeg/archive/26d62fdc40feb84c6533956dc11d5ee9ea9b6c09.tar.gz"},{"method":"fetchzip","packages":["preserves"],"path":"/nix/store/nrcpzf9hx70kry3gwhrdzcs3qicjncjh-source","ref":"20231021","rev":"edece399be70818208bf2263c30cb2bcf435bbff","sha256":"0xmw35wmw3a4lja9q4qvlvpxv3xk0hnkjg4fwfw6f3inh6zfiqki","srcDir":"src","url":"https://git.syndicate-lang.org/ehmry/preserves-nim/archive/edece399be70818208bf2263c30cb2bcf435bbff.tar.gz"},{"method":"fetchzip","packages":["syndicate"],"path":"/nix/store/1y3nnpp2mhxqmdb3xh4c4k5k5l9hhqk3-source","ref":"20231019","rev":"57b99b20e7db1b97b1cb9c6df574bd13983c26fc","sha256":"1kgb3a78igs37xkmv8cbaxa17qdjf2h43vdmpda517c9086ggsn5","srcDir":"src","url":"https://git.syndicate-lang.org/ehmry/syndicate-nim/archive/57b99b20e7db1b97b1cb9c6df574bd13983c26fc.tar.gz"}]}
|
|
|
@ -1,7 +0,0 @@
|
||||||
{ pkgs ? import <nixpkgs> { } }:
|
|
||||||
|
|
||||||
pkgs.nim2Packages.buildNimPackage {
|
|
||||||
name = "dummy";
|
|
||||||
propagatedNativeBuildInputs = [ pkgs.pkg-config ];
|
|
||||||
propagatedBuildInputs = [ pkgs.sqlcipher ];
|
|
||||||
}
|
|
6
sql.prs
6
sql.prs
|
@ -1,6 +0,0 @@
|
||||||
version 1 .
|
|
||||||
|
|
||||||
; When asserted the actor reponds with
|
|
||||||
; rows as records of the given label and
|
|
||||||
; row columns as record fields.
|
|
||||||
Query = <query @label any @statement string> .
|
|
|
@ -1,8 +0,0 @@
|
||||||
version = "20231021"
|
|
||||||
author = "Emery Hemingway"
|
|
||||||
description = "Syndicate Actor for accessing SQLite databases"
|
|
||||||
license = "Unlicense"
|
|
||||||
srcDir = "src"
|
|
||||||
bin = @["sqlite_actor"]
|
|
||||||
|
|
||||||
requires "nim >= 1.6.10", "syndicate >= 20230518"
|
|
|
@ -1,4 +0,0 @@
|
||||||
include_rules
|
|
||||||
: foreach ../*.prs |> !preserves_schema_nim |> {schema}
|
|
||||||
: sqlite_actor.nim | $(SYNDICATE_PROTOCOL) {schema} |> !nim_bin |> {bin}
|
|
||||||
: {bin} |> !assert_built |>
|
|
14
src/sql.nim
14
src/sql.nim
|
@ -1,14 +0,0 @@
|
||||||
|
|
||||||
import
|
|
||||||
preserves
|
|
||||||
|
|
||||||
type
|
|
||||||
Query* {.preservesRecord: "query".} = object
|
|
||||||
`label`*: Preserve[void]
|
|
||||||
`statement`*: string
|
|
||||||
|
|
||||||
proc `$`*(x: Query): string =
|
|
||||||
`$`(toPreserve(x))
|
|
||||||
|
|
||||||
proc encode*(x: Query): seq[byte] =
|
|
||||||
encode(toPreserve(x))
|
|
|
@ -1,112 +0,0 @@
|
||||||
# SPDX-FileCopyrightText: ☭ Emery Hemingway
|
|
||||||
# SPDX-License-Identifier: Unlicense
|
|
||||||
|
|
||||||
# Avoid Sqlite3 from the standard library because it is
|
|
||||||
# only held together by wishful thinking and dlload.
|
|
||||||
|
|
||||||
{.passC: staticExec("pkg-config --cflags sqlcipher").}
|
|
||||||
{.passL: staticExec("pkg-config --libs sqlcipher").}
|
|
||||||
|
|
||||||
{.pragma: sqlite3h, header: "sqlite3.h".}
|
|
||||||
|
|
||||||
var
|
|
||||||
SQLITE_VERSION_NUMBER {.importc, sqlite3h.}: cint
|
|
||||||
SQLITE_OK {.importc, sqlite3h.}: cint
|
|
||||||
SQLITE_ROW {.importc, sqlite3h.}: cint
|
|
||||||
SQLITE_DONE {.importc, sqlite3h.}: cint
|
|
||||||
SQLITE_OPEN_READONLY {.importc, sqlite3h.}: cint
|
|
||||||
|
|
||||||
const
|
|
||||||
SQLITE_INTEGER = 1
|
|
||||||
SQLITE_FLOAT = 2
|
|
||||||
SQLITE_TEXT = 3
|
|
||||||
SQLITE_BLOB = 4
|
|
||||||
# SQLITE_NULL = 5
|
|
||||||
|
|
||||||
type
|
|
||||||
Sqlite3 {.importc: "sqlite3", sqlite3h.} = distinct pointer
|
|
||||||
Stmt {.importc: "sqlite3_stmt", sqlite3h.} = distinct pointer
|
|
||||||
|
|
||||||
{.pragma: importSqlite3, importc: "sqlite3_$1", sqlite3h.}
|
|
||||||
|
|
||||||
proc libversion_number: cint {.importSqlite3.}
|
|
||||||
|
|
||||||
proc open_v2(filename: cstring; ppDb: ptr Sqlite3; flags: cint; zVfs: cstring): cint {.importSqlite3.}
|
|
||||||
proc close(ds: Sqlite3): int32 {.discardable, importSqlite3.}
|
|
||||||
|
|
||||||
proc errmsg(db: Sqlite3): cstring {.importSqlite3.}
|
|
||||||
|
|
||||||
proc prepare_v2(db: Sqlite3; zSql: cstring, nByte: cint; ppStmt: ptr Stmt; pzTail: ptr cstring): cint {.importSqlite3.}
|
|
||||||
|
|
||||||
proc step(para1: Stmt): cint {.importSqlite3.}
|
|
||||||
|
|
||||||
proc column_count(stmt: Stmt): int32 {.importSqlite3.}
|
|
||||||
proc column_blob(stmt: Stmt; col: cint): pointer {.importSqlite3.}
|
|
||||||
proc column_bytes(stmt: Stmt; col: cint): cint {.importSqlite3.}
|
|
||||||
proc column_double(stmt: Stmt; col: cint): float64 {.importSqlite3.}
|
|
||||||
proc column_int64(stmt: Stmt; col: cint): int64 {.importSqlite3.}
|
|
||||||
proc column_text(stmt: Stmt; col: cint): cstring {.importSqlite3.}
|
|
||||||
proc column_type(stmt: Stmt; col: cint): cint {.importSqlite3.}
|
|
||||||
proc finalize(stmt: Stmt): cint {.importSqlite3.}
|
|
||||||
|
|
||||||
doAssert libversion_number() == SQLITE_VERSION_NUMBER
|
|
||||||
|
|
||||||
import preserves, syndicate, syndicate/relays
|
|
||||||
import ./sql
|
|
||||||
|
|
||||||
proc logError(db: Sqlite3; context: string) =
|
|
||||||
writeLine(stderr, errmsg(db), ": ", context)
|
|
||||||
|
|
||||||
type
|
|
||||||
Value = Preserve[void]
|
|
||||||
Args {.preservesDictionary.} = object
|
|
||||||
database: string
|
|
||||||
dataspace: Cap
|
|
||||||
|
|
||||||
proc extractValue(stmt: Stmt; col: cint): Value =
|
|
||||||
case column_type(stmt, col)
|
|
||||||
of SQLITE_INTEGER:
|
|
||||||
result = toPreserve(column_int64(stmt, col))
|
|
||||||
of SQLITE_FLOAT:
|
|
||||||
result = toPreserve(column_double(stmt, col))
|
|
||||||
of SQLITE_TEXT:
|
|
||||||
result = Value(kind: pkString, string: newString(column_bytes(stmt, col)))
|
|
||||||
if result.string.len > 0:
|
|
||||||
copyMem(addr result.string[0], column_text(stmt, col), result.string.len)
|
|
||||||
of SQLITE_BLOB:
|
|
||||||
result = Value(kind: pkByteString, bytes: newSeq[byte](column_bytes(stmt, col)))
|
|
||||||
if result.bytes.len > 0:
|
|
||||||
copyMem(addr result.bytes[0], column_blob(stmt, col), result.bytes.len)
|
|
||||||
else:
|
|
||||||
result = initRecord[void]("null")
|
|
||||||
|
|
||||||
proc extractRecord(stmt: Stmt; label: Value, arity: cint): Value =
|
|
||||||
result = initRecord(label, arity)
|
|
||||||
for col in 0..<arity: result.record[col] = extractValue(stmt, col)
|
|
||||||
|
|
||||||
runActor("main") do (root: Cap; turn: var Turn):
|
|
||||||
connectStdio(turn, root)
|
|
||||||
during(turn, root, ?Args) do (path: string, ds: Cap):
|
|
||||||
var db: Sqlite3
|
|
||||||
if open_v2(path, addr db, SQLITE_OPEN_READONLY, nil) != SQLITE_OK:
|
|
||||||
logError(db, path)
|
|
||||||
else:
|
|
||||||
during(turn, ds, ?Query) do (label: Value, statement: string):
|
|
||||||
var stmt: Stmt
|
|
||||||
if prepare_v2(db, statement, statement.len.cint, addr stmt, nil) != SQLITE_OK:
|
|
||||||
logError(db, statement)
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
let arity = column_count(stmt)
|
|
||||||
var res = step(stmt)
|
|
||||||
while res == SQLITE_ROW:
|
|
||||||
var rec = extractRecord(stmt, label, arity)
|
|
||||||
discard publish(turn, ds, rec)
|
|
||||||
res = step(stmt)
|
|
||||||
assert res != 100
|
|
||||||
if res != SQLITE_DONE:
|
|
||||||
logError(db, statement)
|
|
||||||
finally:
|
|
||||||
if finalize(stmt) != SQLITE_OK: logError(db, statement)
|
|
||||||
do:
|
|
||||||
close(db)
|
|
Loading…
Reference in New Issue