sekejap 0.16.5 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +172 -61
- package/index.d.ts +195 -137
- package/index.js +817 -298
- package/native/darwin-arm64/lib/libsekejap.dylib +0 -0
- package/native/darwin-x64/lib/libsekejap.dylib +0 -0
- package/native/linux-arm64/lib/libsekejap.so +0 -0
- package/native/linux-x64/lib/libsekejap.so +0 -0
- package/native/win32-x64/lib/sekejap.dll +0 -0
- package/package.json +10 -35
- package/sekejap.darwin-arm64.node +0 -0
- package/sekejap.darwin-x64.node +0 -0
- package/sekejap.linux-arm64-gnu.node +0 -0
- package/sekejap.linux-x64-gnu.node +0 -0
- package/sekejap.win32-x64-msvc.node +0 -0
package/README.md
CHANGED
|
@@ -1,14 +1,37 @@
|
|
|
1
|
-
# sekejap
|
|
2
|
-
|
|
3
|
-
Embedded **graph-first, multi-model database** for Node.js
|
|
4
|
-
spatial in one native library. No server, no external process
|
|
5
|
-
in-process
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
- **
|
|
9
|
-
- **
|
|
10
|
-
- **
|
|
11
|
-
|
|
1
|
+
# sekejap (Node.js)
|
|
2
|
+
|
|
3
|
+
Embedded **graph-first, multi-model database** for Node.js: SQL + graph + vector
|
|
4
|
+
+ spatial in one native library. No server, no external process — the whole
|
|
5
|
+
engine runs in-process, in Rust, and this package talks to it over the C ABI
|
|
6
|
+
(`docs/dist/C_ABI.md`), not napi-rs.
|
|
7
|
+
|
|
8
|
+
- **PostgreSQL-like SQL** — `CREATE TABLE`, `INSERT`, `SELECT … WHERE`, `$n` parameters.
|
|
9
|
+
- **Graph** — `link`/`unlink`/`neighbours`, and `GRAPH_TABLE` in SQL for deeper walks.
|
|
10
|
+
- **Prepared statements and paged scans** — compile once, run many; walk a
|
|
11
|
+
collection or a SELECT's answer a page at a time.
|
|
12
|
+
- **Transactions** — many writes under one commit barrier.
|
|
13
|
+
- **Documents already parsed** — every call returns a JS value, not a JSON
|
|
14
|
+
string to `JSON.parse` yourself.
|
|
15
|
+
|
|
16
|
+
## Choosing the FFI route
|
|
17
|
+
|
|
18
|
+
This wrapper binds `libsekejap` through [koffi](https://koffi.dev), not
|
|
19
|
+
through a compiled napi-rs addon (e1's approach, and what this package used
|
|
20
|
+
before). Two reasons:
|
|
21
|
+
|
|
22
|
+
1. **No native build for this package.** koffi ships its own prebuilt N-API
|
|
23
|
+
glue for the platforms it supports; this file does one `koffi.load()` of
|
|
24
|
+
the sekejap shared library at `require()` time. There is no `cargo build`,
|
|
25
|
+
no `node-gyp`, and no per-Node-ABI addon to rebuild — the wrapper itself
|
|
26
|
+
is pure JS, and only `libsekejap.{dylib,so,dll}` is platform-specific.
|
|
27
|
+
2. **`node-ffi-napi`/`ref-napi` are gone.** They were the other candidate
|
|
28
|
+
considered, but `node-ffi-napi` is unpublished from the npm registry
|
|
29
|
+
(`npm view node-ffi-napi` → 404) and its `ref-napi` dependency compiles a
|
|
30
|
+
native addon of its own — the opposite of what "no native build" needs.
|
|
31
|
+
koffi is the smaller, actively maintained port: one dependency, prebuilt,
|
|
32
|
+
with disposable types (`koffi.disposable`) that map directly onto this
|
|
33
|
+
ABI's "every returned `char*` is freed once with `sekejap_string_free`"
|
|
34
|
+
rule (see `index.js` §2-3).
|
|
12
35
|
|
|
13
36
|
## Install
|
|
14
37
|
|
|
@@ -16,71 +39,159 @@ in-process on a Rust core.
|
|
|
16
39
|
npm install sekejap
|
|
17
40
|
```
|
|
18
41
|
|
|
19
|
-
|
|
42
|
+
The published package bundles a `native/<platform>-<arch>/lib/libsekejap.*`
|
|
43
|
+
per supported platform (assembled by the `publish-node` CI job from the same
|
|
44
|
+
`build-native-libs` artifacts every other wrapper links). Locally, or against
|
|
45
|
+
a library you built yourself, point at it explicitly:
|
|
46
|
+
|
|
47
|
+
```sh
|
|
48
|
+
export SEKEJAP_LIB_PATH=/path/to/libsekejap.dylib # exact file, or:
|
|
49
|
+
export SEKEJAP_LIB_DIR=/path/to/dir/holding/it # a directory, or:
|
|
50
|
+
export DYLD_LIBRARY_PATH=/path/to/dir # (Linux: LD_LIBRARY_PATH)
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Resolution order: `SEKEJAP_LIB_PATH` → `SEKEJAP_LIB_DIR` →
|
|
54
|
+
`native/<platform>-<arch>/` inside the package → the bare library name,
|
|
55
|
+
which the OS loader then searches its own path for.
|
|
20
56
|
|
|
21
57
|
## Quick start
|
|
22
58
|
|
|
23
59
|
```js
|
|
24
|
-
const { Db
|
|
60
|
+
const { Db } = require('sekejap');
|
|
25
61
|
|
|
26
|
-
const db = Db.open('/tmp/notes');
|
|
62
|
+
const db = Db.open('/tmp/notes'); // open (or create) a database directory
|
|
27
63
|
|
|
28
|
-
|
|
29
|
-
db.execute(
|
|
30
|
-
db.execute("INSERT INTO note (_key, title, pinned) VALUES ('n1', 'Buy milk', 1)");
|
|
64
|
+
db.execute('CREATE TABLE note (title TEXT, pinned BOOL)');
|
|
65
|
+
db.execute("INSERT INTO note (_key, title, pinned) VALUES ('n1', 'Buy milk', true)");
|
|
31
66
|
|
|
32
|
-
//
|
|
33
|
-
|
|
67
|
+
// The document API — no SQL. `_key` in the value is optional; it is set
|
|
68
|
+
// from the `key` argument when absent.
|
|
69
|
+
db.put('note', 'n2', { title: 'Call Sam', pinned: false });
|
|
34
70
|
|
|
35
|
-
|
|
36
|
-
const notes = JSON.parse(db.query('SELECT * FROM note'));
|
|
37
|
-
console.log(notes);
|
|
38
|
-
// [ { _key: 'n1', title: 'Buy milk', pinned: 1, ... }, { _key: 'n2', ... } ]
|
|
71
|
+
console.log(db.get('note', 'n1')); // { _key: 'n1', title: 'Buy milk', pinned: true }
|
|
39
72
|
|
|
40
|
-
|
|
41
|
-
const pinned =
|
|
73
|
+
db.execute('CREATE INDEX note_pinned ON note USING btree (pinned)');
|
|
74
|
+
const pinned = db.query('SELECT title FROM note WHERE pinned = $1', [true]);
|
|
42
75
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
console.log(JSON.parse(db.queryPrepared(byPin, JSON.stringify([p]))));
|
|
47
|
-
}
|
|
76
|
+
const stmt = db.prepare('SELECT title FROM note WHERE pinned = $1');
|
|
77
|
+
for (const want of [true, false]) console.log(stmt.query([want]));
|
|
78
|
+
stmt.close();
|
|
48
79
|
|
|
49
|
-
|
|
50
|
-
db.
|
|
51
|
-
console.log('nodes:', db.nodeCount(), 'edges:', db.edgeCount());
|
|
80
|
+
db.link('note', 'n1', 'related', 'note', 'n2');
|
|
81
|
+
console.log(db.neighbours('note', 'n1', 'related', 'outgoing', 10));
|
|
52
82
|
|
|
53
|
-
|
|
54
|
-
|
|
83
|
+
const tx = db.transaction();
|
|
84
|
+
tx.put('note', 'n3', { title: 'Committed together', pinned: false });
|
|
85
|
+
tx.commit(); // or tx.rollback()
|
|
86
|
+
|
|
87
|
+
console.log('rows:', db.countRows('note'));
|
|
88
|
+
db.close();
|
|
55
89
|
```
|
|
56
90
|
|
|
57
|
-
|
|
91
|
+
More: `examples/tour.js`.
|
|
92
|
+
|
|
93
|
+
## API mapping (C function → wrapper call)
|
|
58
94
|
|
|
59
|
-
|
|
|
95
|
+
| C function | wrapper call |
|
|
60
96
|
|---|---|
|
|
61
|
-
| `Db.open(path)` |
|
|
62
|
-
| `
|
|
63
|
-
| `
|
|
64
|
-
| `
|
|
65
|
-
| `
|
|
66
|
-
| `
|
|
67
|
-
| `
|
|
68
|
-
| `
|
|
69
|
-
| `
|
|
70
|
-
| `
|
|
71
|
-
|
|
72
|
-
`
|
|
73
|
-
`
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
97
|
+
| `sekejap_open` | `Db.open(path)` |
|
|
98
|
+
| `sekejap_open_with_config` | `Db.openWithConfig(path, config)` |
|
|
99
|
+
| `sekejap_open_service` | `Db.openService(path)` |
|
|
100
|
+
| `sekejap_close` | `db.close()` |
|
|
101
|
+
| `sekejap_version` | `version()` (module function) |
|
|
102
|
+
| `sekejap_format_version` | `formatVersion()` (module function) |
|
|
103
|
+
| `sekejap_last_error` / `sekejap_last_error_code` | folded into every thrown `SekejapError` (`.message`, `.code`, `.status`) |
|
|
104
|
+
| `sekejap_string_free` | never called by user code — wired as a `koffi.disposable` type, freed automatically after every C→JS string conversion |
|
|
105
|
+
| `sekejap_put` | `db.put(collection, key, doc)` |
|
|
106
|
+
| `sekejap_put_many` | `db.putMany(collection, rows)` |
|
|
107
|
+
| `sekejap_get` | `db.get(collection, key)` → object or `null` |
|
|
108
|
+
| `sekejap_exists` | `db.exists(collection, key)` → boolean |
|
|
109
|
+
| `sekejap_delete` | `db.delete(collection, key)` → boolean |
|
|
110
|
+
| `sekejap_scan_open` / `_next` / `_close` | `db.scan(collection, pageRows)` → `Scan` (`for...of`, `.rows()`, `.next()`, `.close()`) |
|
|
111
|
+
| `sekejap_execute` | `db.execute(sql, params)` |
|
|
112
|
+
| `sekejap_query` | `db.query(sql, params)` |
|
|
113
|
+
| `sekejap_explain` | `db.explain(sql, params)` |
|
|
114
|
+
| `sekejap_prepare` | `db.prepare(sql)` → `Statement` |
|
|
115
|
+
| `sekejap_stmt_query` | `stmt.query(params)` |
|
|
116
|
+
| `sekejap_stmt_execute` | `stmt.execute(params)` |
|
|
117
|
+
| `sekejap_stmt_rebindable` | `stmt.rebindable()` → boolean or `null` (unbound) |
|
|
118
|
+
| `sekejap_stmt_free` | `stmt.close()` |
|
|
119
|
+
| `sekejap_query_open` / `_next` / `_close` | `db.stream(sql, params, pageRows)` → `Scan` |
|
|
120
|
+
| `sekejap_link` | `db.link(fromCollection, fromKey, edgeType, toCollection, toKey)` |
|
|
121
|
+
| `sekejap_link_with` | `db.linkWith(..., properties)` |
|
|
122
|
+
| `sekejap_unlink` | `db.unlink(...)` → boolean |
|
|
123
|
+
| `sekejap_neighbours` | `db.neighbours(collection, key, edgeType, direction, limit)` |
|
|
124
|
+
| `sekejap_create_collection` | `db.createCollection(name, fields)` → boolean |
|
|
125
|
+
| `sekejap_drop_collection` | `db.dropCollection(name)` → boolean |
|
|
126
|
+
| `sekejap_collections` | `db.collections()` |
|
|
127
|
+
| `sekejap_describe` | `db.describe(collection)` → object or `null` |
|
|
128
|
+
| `sekejap_count_rows` | `db.countRows(collection)` |
|
|
129
|
+
| `sekejap_scan_count_rows` | `db.scanCountRows(collection)` |
|
|
130
|
+
| `sekejap_scan_count_edges` | `db.scanCountEdges()` |
|
|
131
|
+
| `sekejap_tx_begin` | `db.transaction()` → `Tx` |
|
|
132
|
+
| `sekejap_tx_put` / `_delete` / `_link` / `_execute` | `tx.put` / `tx.delete` / `tx.link` / `tx.execute` |
|
|
133
|
+
| `sekejap_tx_commit` / `_rollback` | `tx.commit()` / `tx.rollback()` |
|
|
134
|
+
| `sekejap_checkpoint` | `db.checkpoint()` → boolean (folded/deferred) |
|
|
135
|
+
| `sekejap_publish` | `db.publish()` |
|
|
136
|
+
| `sekejap_storage` | `db.storage()` |
|
|
137
|
+
| `sekejap_statement_timeout_ms` | `db.statementTimeoutMs(ms)` |
|
|
138
|
+
| `sekejap_cancel` / `_clear_interrupt` | `db.cancel()` / `db.clearInterrupt()` |
|
|
139
|
+
| `sekejap_subscribe` / `_next_change` / `_unsubscribe` | `db.subscribe()` / `db.nextChange(id, timeoutMs)` / `db.unsubscribe(id)` |
|
|
140
|
+
| `sekejap_open_memory`, `_trim_memory`, `_compact`, `_show` | `Db.openMemory()`, `db.trimMemory()`, `db.compact()`, `db.show()` — all always throw `SekejapError` with `.code === 'Refused'`, by name |
|
|
141
|
+
|
|
142
|
+
## What was removed from e1's wrapper
|
|
143
|
+
|
|
144
|
+
e1's `dist/bindings/wrappers/node/` was a napi-rs addon (`src/lib.rs`,
|
|
145
|
+
`Cargo.toml`/`Cargo.lock`, `build.rs`) compiled against the OLD `CoreDB`
|
|
146
|
+
(slug-addressed rows, `nodeCount`/`edgeCount`, a single-string `Db.open`) and
|
|
147
|
+
a prebuilt `sekejap.darwin-arm64.node` binary, plus a TypeScript ORM layer
|
|
148
|
+
(`orm/`, and its build output `dist/`) and Next.js/Express example apps built
|
|
149
|
+
on that ORM. All of it is gone:
|
|
150
|
+
|
|
151
|
+
- **The napi-rs Rust glue crate** (`src/`, `Cargo.toml`, `Cargo.lock`,
|
|
152
|
+
`build.rs`) — this wrapper is pure JS over koffi now; there is nothing to
|
|
153
|
+
compile, so no Rust crate belongs here at all. This is also why `build-node`
|
|
154
|
+
no longer runs `cargo`/`napi build`.
|
|
155
|
+
- **The committed `.node` binary and `node_modules/`** — a native binary and
|
|
156
|
+
~2,000 files of transitively-vendored TypeScript/React tooling had no
|
|
157
|
+
business in version control; `npm install` fetches the one runtime
|
|
158
|
+
dependency (`koffi`) and `.gitignore` keeps `node_modules/` out from here on.
|
|
159
|
+
- **`orm/` and its `dist/` build output** — a hand-rolled query builder /
|
|
160
|
+
React-hooks layer over the old slug API. It does not carry over: this
|
|
161
|
+
wrapper's job is the one-to-one C ABI mirror above, and a higher-level ORM
|
|
162
|
+
over the 0.17 shape is a separate, later decision, not part of re-opening
|
|
163
|
+
the publish channel.
|
|
164
|
+
- **`examples/nextjs/`, `examples/express-server.js`** — both were demos of
|
|
165
|
+
the ORM layer, not of the C ABI surface. `examples/tour.js` stays,
|
|
166
|
+
rewritten against the 0.17 API (`db.query()`/`db.get()` already return
|
|
167
|
+
parsed values, not JSON strings; `_key` is implicit rather than a declared
|
|
168
|
+
`TEXT PRIMARY KEY` column — see `lang/src/compile/ddl.rs`: names starting
|
|
169
|
+
with `_` are reserved in `CREATE TABLE`).
|
|
170
|
+
- **`test.cjs`, `test_prepared.cjs`, `bench.cjs`** — kept as a single
|
|
171
|
+
`test.cjs` (every leg of the common wrapper checklist: open, create,
|
|
172
|
+
put/get, a parameterized query, scan, prepare+rebind, link+neighbours,
|
|
173
|
+
tx commit/rollback, count_rows, an error path, close) and a rewritten
|
|
174
|
+
`bench.cjs` (same shape, `Db.get` instead of a SQL SELECT by `_key`,
|
|
175
|
+
because `_key` equality now needs a named index like every other Tier-1
|
|
176
|
+
predicate — QL_CONTRACT §6 — and the point of this bench is the FFI/JSON
|
|
177
|
+
round trip, not the planner).
|
|
178
|
+
|
|
179
|
+
## Gaps in the C ABI found
|
|
180
|
+
|
|
181
|
+
None. Every one of the 59 functions in `dist/ffi/include/sekejap.h` is bound
|
|
182
|
+
and reachable from JS (the four "refused by name" calls are bound too, so
|
|
183
|
+
the refusal surfaces as a named `SekejapError`, never `TypeError: ... is not
|
|
184
|
+
a function`).
|
|
185
|
+
|
|
186
|
+
## Tests
|
|
83
187
|
|
|
84
|
-
|
|
188
|
+
```sh
|
|
189
|
+
export SEKEJAP_LIB_DIR=/path/to/libsekejap # or SEKEJAP_LIB_PATH
|
|
190
|
+
npm install
|
|
191
|
+
npm test
|
|
192
|
+
npm run bench # optional
|
|
193
|
+
node examples/tour.js
|
|
194
|
+
```
|
|
85
195
|
|
|
86
|
-
|
|
196
|
+
`test.cjs` runs against the real library — no mocks — and prints one `ok -`
|
|
197
|
+
line per leg.
|
package/index.d.ts
CHANGED
|
@@ -1,138 +1,196 @@
|
|
|
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
|
-
* JSON object). Returns how many were removed.
|
|
91
|
-
*/
|
|
92
|
-
unlinkWhere(from: string, to: string, edgeType: string, propsJson: string): number
|
|
93
|
-
/**
|
|
94
|
-
* Update attributes on matching edges: `propsJson` selects, `setsJson`
|
|
95
|
-
* assigns. Returns how many were updated.
|
|
96
|
-
*/
|
|
97
|
-
updateEdge(from: string, to: string, edgeType: string, propsJson: string, setsJson: string): number
|
|
98
|
-
/**
|
|
99
|
-
* Edges leaving a node, as a JSON-array string of
|
|
100
|
-
* `{from, to, type, meta}` objects.
|
|
101
|
-
*/
|
|
102
|
-
edgesFrom(slug: string): string
|
|
103
|
-
/** Edges arriving at a node, same shape as `edgesFrom`. */
|
|
104
|
-
edgesTo(slug: string): string
|
|
105
|
-
/** Edges from one collection to another, same shape as `edgesFrom`. */
|
|
106
|
-
edgesBetween(fromCollection: string, toCollection: string): string
|
|
107
|
-
/** All collection names. */
|
|
108
|
-
collectionNames(): Array<string>
|
|
109
|
-
/** Every node slug. */
|
|
110
|
-
allSlugs(): Array<string>
|
|
111
|
-
/** DDL string for a collection schema, or null. */
|
|
112
|
-
schemaDdl(collection: string): string | null
|
|
113
|
-
/**
|
|
114
|
-
* Ranked text search over a BM25-indexed field: JSON-array string of
|
|
115
|
-
* `[slug, score]` pairs, best first.
|
|
116
|
-
*/
|
|
117
|
-
bm25Search(field: string, query: string, topK: number): string
|
|
118
|
-
/**
|
|
119
|
-
* The query plan for a statement, as a JSON-array string (one step per
|
|
120
|
-
* element). `analyze = true` also executes it and adds per-step timings.
|
|
121
|
-
*/
|
|
122
|
-
explain(sql: string, analyze?: boolean | undefined | null): string
|
|
123
|
-
/** Run a SHOW statement (`SHOW TABLES`, `SHOW EDGES`, …); JSON-array string. */
|
|
124
|
-
show(sql: string): string
|
|
125
|
-
/** Shrink resident memory to the live working set (never drops indexes). */
|
|
126
|
-
trimMemory(): void
|
|
127
|
-
/** Per-structure resident-memory estimate, as a JSON object string. */
|
|
128
|
-
memoryReport(): string
|
|
129
|
-
/** Override HNSW search breadth (`efSearch`); null restores the default. */
|
|
130
|
-
setHnswEfSearch(ef?: number | undefined | null): void
|
|
131
|
-
/**
|
|
132
|
-
* Close the database and release its lock. Further calls error (or no-op
|
|
133
|
-
* for count/list getters). Safe to call twice.
|
|
134
|
-
*/
|
|
135
|
-
close(): void
|
|
1
|
+
// TypeScript definitions for the sekejap Node.js wrapper (over libsekejap's C ABI).
|
|
2
|
+
// See docs/dist/C_ABI.md for the contract this file mirrors.
|
|
3
|
+
|
|
4
|
+
export type SekejapStatusName =
|
|
5
|
+
| 'Ok'
|
|
6
|
+
| 'Refused'
|
|
7
|
+
| 'Corrupt'
|
|
8
|
+
| 'Unsupported'
|
|
9
|
+
| 'Io'
|
|
10
|
+
| 'Invalid'
|
|
11
|
+
| 'Busy'
|
|
12
|
+
| 'UnknownRow'
|
|
13
|
+
| 'Unknown';
|
|
14
|
+
|
|
15
|
+
export const SekejapStatus: {
|
|
16
|
+
readonly Ok: 0;
|
|
17
|
+
readonly Refused: 1;
|
|
18
|
+
readonly Corrupt: 2;
|
|
19
|
+
readonly Unsupported: 3;
|
|
20
|
+
readonly Io: 4;
|
|
21
|
+
readonly Invalid: 5;
|
|
22
|
+
readonly Busy: 6;
|
|
23
|
+
readonly UnknownRow: 7;
|
|
24
|
+
readonly Unknown: 8;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const SekejapDirection: {
|
|
28
|
+
readonly Outgoing: 0;
|
|
29
|
+
readonly Incoming: 1;
|
|
30
|
+
readonly Both: 2;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export type Direction = 'outgoing' | 'incoming' | 'both' | 0 | 1 | 2;
|
|
34
|
+
|
|
35
|
+
export class SekejapError extends Error {
|
|
36
|
+
code: SekejapStatusName;
|
|
37
|
+
status: number;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export type JsonValue =
|
|
41
|
+
| null
|
|
42
|
+
| boolean
|
|
43
|
+
| number
|
|
44
|
+
| string
|
|
45
|
+
| JsonValue[]
|
|
46
|
+
| { [key: string]: JsonValue };
|
|
47
|
+
|
|
48
|
+
export type Document = { _key?: string; [field: string]: JsonValue | undefined };
|
|
49
|
+
|
|
50
|
+
export type FieldKind = 'text' | 'int' | 'real' | 'bool' | 'json' | 'geo' | 'point' | 'vector';
|
|
51
|
+
|
|
52
|
+
export interface FieldDecl {
|
|
53
|
+
name: string;
|
|
54
|
+
kind: FieldKind;
|
|
55
|
+
dimension?: number;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface IndexDecl {
|
|
59
|
+
name: string;
|
|
60
|
+
field: string;
|
|
61
|
+
family: 'scalar' | 'text' | 'exact_vector' | 'quantized_vector' | 'spatial_point' | 'spatial_geometry';
|
|
62
|
+
unique: boolean;
|
|
63
|
+
ready: boolean;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface CollectionDescriptor {
|
|
67
|
+
name: string;
|
|
68
|
+
timestamps: boolean;
|
|
69
|
+
rows: number | null;
|
|
70
|
+
fields: Array<FieldDecl & { declared: string | null; primary_key: boolean }>;
|
|
71
|
+
indexes: IndexDecl[];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface Neighbour {
|
|
75
|
+
collection: string;
|
|
76
|
+
key: string;
|
|
77
|
+
document: Document;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface StoreConfig {
|
|
81
|
+
budgetBytes?: number;
|
|
82
|
+
io?: 'buffered' | 'direct';
|
|
83
|
+
sync?: 'full' | 'normal' | 'off';
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export interface Storage {
|
|
87
|
+
dataBytes: number;
|
|
88
|
+
walBytes: number;
|
|
89
|
+
totalBytes: number;
|
|
136
90
|
}
|
|
137
|
-
|
|
138
|
-
export
|
|
91
|
+
|
|
92
|
+
export interface ChangeEvent {
|
|
93
|
+
sequence: number;
|
|
94
|
+
collections: string[];
|
|
95
|
+
edge_types: string[];
|
|
96
|
+
keys: Array<{ collection: string; key: string; kind: 'put' | 'delete' }>;
|
|
97
|
+
keys_total: number;
|
|
98
|
+
keys_truncated: boolean;
|
|
99
|
+
unnamed_writes: number;
|
|
100
|
+
rows_affected: number;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export class Scan {
|
|
104
|
+
next(): JsonValue[] | null;
|
|
105
|
+
close(): void;
|
|
106
|
+
rows(): Generator<JsonValue, void, void>;
|
|
107
|
+
[Symbol.iterator](): Generator<JsonValue[], void, void>;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export class Statement {
|
|
111
|
+
query(params?: JsonValue): Document[];
|
|
112
|
+
execute(params?: JsonValue): number;
|
|
113
|
+
rebindable(): boolean | null;
|
|
114
|
+
close(): void;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export class Tx {
|
|
118
|
+
put(collection: string, key: string, doc: Document): void;
|
|
119
|
+
delete(collection: string, key: string): boolean;
|
|
120
|
+
link(fromCollection: string, fromKey: string, edgeType: string, toCollection: string, toKey: string): void;
|
|
121
|
+
execute(sql: string, params?: JsonValue): number;
|
|
122
|
+
commit(): void;
|
|
123
|
+
rollback(): void;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export class Db {
|
|
127
|
+
static open(path: string): Db;
|
|
128
|
+
static openWithConfig(path: string, config?: StoreConfig): Db;
|
|
129
|
+
static openService(path: string): Db;
|
|
130
|
+
/** REFUSED by name: sekejap has no in-memory store. Always throws. */
|
|
131
|
+
static openMemory(): never;
|
|
132
|
+
|
|
133
|
+
close(): void;
|
|
134
|
+
|
|
135
|
+
put(collection: string, key: string, doc: Document): void;
|
|
136
|
+
putMany(collection: string, rows: Array<{ key: string; doc: Document }>): number;
|
|
137
|
+
get(collection: string, key: string): Document | null;
|
|
138
|
+
exists(collection: string, key: string): boolean;
|
|
139
|
+
delete(collection: string, key: string): boolean;
|
|
140
|
+
scan(collection: string, pageRows?: number): Scan;
|
|
141
|
+
|
|
142
|
+
execute(sql: string, params?: JsonValue): number;
|
|
143
|
+
query(sql: string, params?: JsonValue): Document[];
|
|
144
|
+
explain(sql: string, params?: JsonValue): string;
|
|
145
|
+
prepare(sql: string): Statement;
|
|
146
|
+
stream(sql: string, params?: JsonValue, pageRows?: number): Scan;
|
|
147
|
+
|
|
148
|
+
link(fromCollection: string, fromKey: string, edgeType: string, toCollection: string, toKey: string): void;
|
|
149
|
+
linkWith(
|
|
150
|
+
fromCollection: string,
|
|
151
|
+
fromKey: string,
|
|
152
|
+
edgeType: string,
|
|
153
|
+
toCollection: string,
|
|
154
|
+
toKey: string,
|
|
155
|
+
properties: JsonValue
|
|
156
|
+
): void;
|
|
157
|
+
unlink(fromCollection: string, fromKey: string, edgeType: string, toCollection: string, toKey: string): boolean;
|
|
158
|
+
neighbours(
|
|
159
|
+
collection: string,
|
|
160
|
+
key: string,
|
|
161
|
+
edgeType?: string | null,
|
|
162
|
+
direction?: Direction,
|
|
163
|
+
limit?: number
|
|
164
|
+
): Neighbour[];
|
|
165
|
+
|
|
166
|
+
createCollection(name: string, fields: FieldDecl[]): boolean;
|
|
167
|
+
dropCollection(name: string): boolean;
|
|
168
|
+
collections(): string[];
|
|
169
|
+
describe(collection: string): CollectionDescriptor | null;
|
|
170
|
+
countRows(collection: string): number;
|
|
171
|
+
scanCountRows(collection: string): number;
|
|
172
|
+
scanCountEdges(): number;
|
|
173
|
+
|
|
174
|
+
transaction(): Tx;
|
|
175
|
+
|
|
176
|
+
checkpoint(): boolean;
|
|
177
|
+
publish(): void;
|
|
178
|
+
storage(): Storage;
|
|
179
|
+
|
|
180
|
+
statementTimeoutMs(milliseconds: number): void;
|
|
181
|
+
cancel(): void;
|
|
182
|
+
clearInterrupt(): boolean;
|
|
183
|
+
subscribe(): number;
|
|
184
|
+
nextChange(subscriptionId: number, timeoutMs?: number): ChangeEvent | null;
|
|
185
|
+
unsubscribe(subscriptionId: number): boolean;
|
|
186
|
+
|
|
187
|
+
/** REFUSED: no proportional-to-rows memory to trim. Always throws. */
|
|
188
|
+
trimMemory(): never;
|
|
189
|
+
/** REFUSED: no payload-rewriting compaction. Always throws; use checkpoint(). */
|
|
190
|
+
compact(): never;
|
|
191
|
+
/** REFUSED: SHOW has no Tier-1 spelling. Always throws; use collections()/describe(). */
|
|
192
|
+
show(statement?: string | null): never;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export function version(): string;
|
|
196
|
+
export function formatVersion(): number;
|