@plurnk/plurnk-execs-sqlite 1.3.12 → 1.5.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 +23 -11
- package/dist/Sqlite.d.ts +1 -1
- package/dist/Sqlite.d.ts.map +1 -1
- package/dist/Sqlite.js +47 -17
- package/dist/Sqlite.js.map +1 -1
- package/docs/sqlite.md +13 -3
- package/package.json +9 -7
package/README.md
CHANGED
|
@@ -2,30 +2,31 @@
|
|
|
2
2
|
|
|
3
3
|
SQLite runtime executor for [plurnk-service](https://github.com/plurnk/plurnk-service)'s `exec` scheme. Runs the `sqlite` runtime tag **in-process** via Node's builtin `node:sqlite` — no subprocess.
|
|
4
4
|
|
|
5
|
-
A `@plurnk/plurnk-execs-*` sibling built on the [plurnk-execs](https://github.com/plurnk/plurnk-execs) framework.
|
|
5
|
+
A `@plurnk/plurnk-execs-*` sibling built on the [plurnk-execs](https://github.com/plurnk/plurnk-service/tree/main/plurnk-execs) framework.
|
|
6
6
|
|
|
7
7
|
## Runtime tag
|
|
8
8
|
|
|
9
|
-
| Tag
|
|
10
|
-
|
|
11
|
-
| `sqlite` | 🗃
|
|
9
|
+
| Tag | Glyph | Engine |
|
|
10
|
+
| -------- | ----- | ------------------------------------------- |
|
|
11
|
+
| `sqlite` | 🗃 | `node:sqlite` in the supported Node runtime |
|
|
12
12
|
|
|
13
13
|
## Database target
|
|
14
14
|
|
|
15
15
|
The EXEC target slot is the database file; with no target it defaults to an ephemeral in-memory db:
|
|
16
16
|
|
|
17
|
-
```
|
|
18
|
-
<<EXEC[sqlite]:SELECT * FROM users:EXEC
|
|
19
|
-
<<EXEC[sqlite](./app.db):SELECT * FROM users:EXEC
|
|
17
|
+
```plurnk
|
|
18
|
+
<<EXEC[sqlite]:SELECT * FROM users:EXEC
|
|
19
|
+
<<EXEC[sqlite](./app.db):SELECT * FROM users:EXEC
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
With no target, a fresh `:memory:` database exists for that operation only.
|
|
23
|
+
State does not persist across EXECs. Pass a file path for persistence.
|
|
23
24
|
|
|
24
25
|
### Transient tabular calculations
|
|
25
26
|
|
|
26
27
|
With no target, `:memory:` is a scratch calculator over ad-hoc tables — build one inline with `VALUES` and aggregate, no schema or file needed:
|
|
27
28
|
|
|
28
|
-
```
|
|
29
|
+
```plurnk
|
|
29
30
|
<<EXEC[sqlite]:WITH t(item,qty,price) AS (VALUES ('a',3,2),('b',1,5)) SELECT sum(qty*price) AS total, sum(qty*price)*1.0/sum(qty) AS avg_price FROM t:EXEC
|
|
30
31
|
```
|
|
31
32
|
|
|
@@ -38,11 +39,22 @@ Writes to the `results` channel as `application/json`, ready for the jsonpath bo
|
|
|
38
39
|
- **Row-returning statements** (SELECT, RETURNING, PRAGMA) → an array of row objects.
|
|
39
40
|
- **Mutations** (INSERT/UPDATE/DELETE/DDL) → `{ changes, lastInsertRowid }`.
|
|
40
41
|
|
|
41
|
-
The query/mutation split is decided by the prepared statement's `columns()`,
|
|
42
|
+
The query/mutation split is decided by the prepared statement's `columns()`,
|
|
43
|
+
never by parsing the SQL. One statement per EXEC. Errors return RFC 9457
|
|
44
|
+
Problems in the terminal operation result.
|
|
45
|
+
|
|
46
|
+
## Configuration
|
|
47
|
+
|
|
48
|
+
The framework's `PLURNK_EXECS_ERROR_DETAIL_LIMIT` bounds SQLite diagnostics and
|
|
49
|
+
rejected SQL tails included in Problem facts.
|
|
42
50
|
|
|
43
51
|
## Availability & proposal gating
|
|
44
52
|
|
|
45
|
-
`probe()`
|
|
53
|
+
`probe()` reports available because `node:sqlite` is part of the supported Node
|
|
54
|
+
>=26 runtime. `effect(target)` marks `:memory:` and no target as `pure`, while a
|
|
55
|
+
file-backed database is `host`. The former bypasses the proposal gate and the
|
|
56
|
+
latter requires it; both produce their result through the background stream
|
|
57
|
+
path ({§executor-effect}). Classification uses only the target, never the SQL.
|
|
46
58
|
|
|
47
59
|
## Tests
|
|
48
60
|
|
package/dist/Sqlite.d.ts
CHANGED
|
@@ -4,6 +4,6 @@ export default class Sqlite extends BaseExecutor {
|
|
|
4
4
|
get channels(): Readonly<Record<string, ChannelDecl>>;
|
|
5
5
|
probe(): Promise<RuntimeAvailability>;
|
|
6
6
|
effect(target: string | null): Effect;
|
|
7
|
-
run({ command, cwd, target, signal, write, setState
|
|
7
|
+
run({ command, cwd, target, signal, write, setState }: ExecArgs): Promise<ExecResult>;
|
|
8
8
|
}
|
|
9
9
|
//# sourceMappingURL=Sqlite.d.ts.map
|
package/dist/Sqlite.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Sqlite.d.ts","sourceRoot":"","sources":["../src/Sqlite.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,
|
|
1
|
+
{"version":3,"file":"Sqlite.d.ts","sourceRoot":"","sources":["../src/Sqlite.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAA0C,MAAM,sBAAsB,CAAC;AAC5F,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAkC3G,MAAM,CAAC,OAAO,OAAO,MAAO,SAAQ,YAAY;IAC5C,IAAI,QAAQ,IAAI,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAEpD;IAGc,KAAK,IAAI,OAAO,CAAC,mBAAmB,CAAC,CAEnD;IAIQ,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAE7C;IAEK,GAAG,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,CAAC,CAiH1F;CACJ"}
|
package/dist/Sqlite.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { isAbsolute, resolve } from "node:path";
|
|
2
2
|
import { DatabaseSync } from "node:sqlite";
|
|
3
|
-
import { BaseExecutor } from "@plurnk/plurnk-execs";
|
|
3
|
+
import { BaseExecutor, ErrorDetail, renderJsonResult, Results } from "@plurnk/plurnk-execs";
|
|
4
4
|
const MEMORY = ":memory:";
|
|
5
5
|
// Resolve the EXEC (target) slot to a db path: a relative target resolves
|
|
6
|
-
// against cwd (
|
|
6
|
+
// against cwd ({§executor-sinks}); null — or an explicit
|
|
7
7
|
// `:memory:` — means no file target → an ephemeral in-memory db.
|
|
8
8
|
const dbPath = (cwd, target) => {
|
|
9
9
|
if (target === null || target === MEMORY)
|
|
@@ -28,13 +28,11 @@ const stripComments = (sql) => sql.replace(/--[^\n]*/g, "").replace(/\/\*[\s\S]*
|
|
|
28
28
|
// objects; mutations write `{ changes, lastInsertRowid }`. The query/mutation
|
|
29
29
|
// split is decided by `columns()` — never by parsing the SQL.
|
|
30
30
|
//
|
|
31
|
-
// NOTE: `effect()` (per-runtime proposal gating; :memory:→pure, file→host) is
|
|
32
|
-
// pending the contract addition in plurnk-service#182 and lands when that does.
|
|
33
31
|
export default class Sqlite extends BaseExecutor {
|
|
34
32
|
get channels() {
|
|
35
33
|
return { results: { mimetype: "application/json" } };
|
|
36
34
|
}
|
|
37
|
-
// Always available
|
|
35
|
+
// Always available in the package's supported Node >=26 runtime.
|
|
38
36
|
async probe() {
|
|
39
37
|
return { available: true, detail: "node:sqlite" };
|
|
40
38
|
}
|
|
@@ -43,49 +41,81 @@ export default class Sqlite extends BaseExecutor {
|
|
|
43
41
|
effect(target) {
|
|
44
42
|
return target === null || target === MEMORY ? "pure" : "host";
|
|
45
43
|
}
|
|
46
|
-
async run({ command, cwd, target, signal, write, setState
|
|
44
|
+
async run({ command, cwd, target, signal, write, setState }) {
|
|
47
45
|
// node:sqlite is fully synchronous — no await point to interrupt mid-query —
|
|
48
|
-
// so the only place to honor an abort is before the work starts
|
|
46
|
+
// so the only place to honor an abort is before the work starts
|
|
47
|
+
// ({§executor-cancellation}).
|
|
49
48
|
// Matters for a file-backed (host) statement: a cancel/KILL that lands first
|
|
50
49
|
// must not still mutate the db.
|
|
51
50
|
if (signal.aborted) {
|
|
52
51
|
setState("results", "errored");
|
|
53
|
-
return
|
|
52
|
+
return Results.failure("executor:sqlite", "cancelled", 499, "SQLite execution was cancelled.", {}, {
|
|
53
|
+
stage: "execution",
|
|
54
|
+
retryable: false,
|
|
55
|
+
});
|
|
54
56
|
}
|
|
55
57
|
const path = dbPath(cwd, target);
|
|
56
58
|
const sql = command.trim();
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
+
const errorPreview = ErrorDetail.configuredLimit();
|
|
60
|
+
const fail = (kind, message, status = 500, extensions = {}) => {
|
|
59
61
|
setState("results", "errored");
|
|
60
|
-
return
|
|
62
|
+
return Results.failure("executor:sqlite", kind, status, message, {}, {
|
|
63
|
+
database: path,
|
|
64
|
+
...extensions,
|
|
65
|
+
});
|
|
61
66
|
};
|
|
67
|
+
if (errorPreview === null) {
|
|
68
|
+
setState("results", "errored");
|
|
69
|
+
return ErrorDetail.invalidConfiguration("executor:sqlite");
|
|
70
|
+
}
|
|
62
71
|
let db;
|
|
63
72
|
try {
|
|
64
73
|
db = new DatabaseSync(path);
|
|
65
74
|
}
|
|
66
75
|
catch (err) {
|
|
67
|
-
return fail("
|
|
76
|
+
return fail("sqlite-open-failed", `SQLite could not open '${path}': ${ErrorDetail.preview(err, errorPreview)}`, 500, {
|
|
77
|
+
stage: "open",
|
|
78
|
+
recovery: "Use an accessible SQLite database target.",
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
let stmt;
|
|
82
|
+
try {
|
|
83
|
+
stmt = db.prepare(sql);
|
|
84
|
+
}
|
|
85
|
+
catch (err) {
|
|
86
|
+
db.close();
|
|
87
|
+
return fail("sqlite-invalid-statement", `SQLite could not prepare the statement: ${ErrorDetail.preview(err, errorPreview)}`, 400, {
|
|
88
|
+
stage: "prepare",
|
|
89
|
+
recovery: "Correct the SQL statement.",
|
|
90
|
+
retryable: false,
|
|
91
|
+
});
|
|
68
92
|
}
|
|
69
93
|
try {
|
|
70
|
-
const stmt = db.prepare(sql);
|
|
71
94
|
// One statement per op is the contract (the results channel is one JSON
|
|
72
95
|
// doc) — but SQLite's prepare compiles only the FIRST statement and
|
|
73
96
|
// silently ignores the rest, so a sqlite3-CLI-style script would
|
|
74
|
-
// partially execute under a 200
|
|
97
|
+
// partially execute under a 200. sourceSQL is the compiled
|
|
75
98
|
// statement's own text: any real SQL left after it is a dropped tail —
|
|
76
99
|
// fail-hard, never truncate silently. Trailing whitespace/comments pass.
|
|
77
100
|
const tail = stripComments(sql.slice(stmt.sourceSQL.length)).trim();
|
|
78
101
|
if (tail !== "") {
|
|
79
|
-
return fail("
|
|
102
|
+
return fail("sqlite-multi-statement", "SQLite execution accepts exactly one statement, but the command contains a second statement.", 400, {
|
|
103
|
+
stage: "prepare",
|
|
104
|
+
rejectedTail: ErrorDetail.preview(tail, errorPreview),
|
|
105
|
+
recovery: "Run each SQL statement in a separate operation.",
|
|
106
|
+
retryable: false,
|
|
107
|
+
});
|
|
80
108
|
}
|
|
81
109
|
// Non-empty columns ⇒ a row-returning statement; empty ⇒ a mutation.
|
|
82
110
|
const output = stmt.columns().length > 0 ? stmt.all() : stmt.run();
|
|
83
|
-
write("results",
|
|
111
|
+
write("results", renderJsonResult(output, jsonReplacer));
|
|
84
112
|
setState("results", "closed");
|
|
85
113
|
return { status: 200 };
|
|
86
114
|
}
|
|
87
115
|
catch (err) {
|
|
88
|
-
return fail("
|
|
116
|
+
return fail("sqlite-error", `SQLite could not execute the statement: ${ErrorDetail.preview(err, errorPreview)}`, 500, {
|
|
117
|
+
stage: "execution",
|
|
118
|
+
});
|
|
89
119
|
}
|
|
90
120
|
finally {
|
|
91
121
|
db.close();
|
package/dist/Sqlite.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Sqlite.js","sourceRoot":"","sources":["../src/Sqlite.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,EAAE,YAAY,
|
|
1
|
+
{"version":3,"file":"Sqlite.js","sourceRoot":"","sources":["../src/Sqlite.ts"],"names":[],"mappings":"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"}
|
package/docs/sqlite.md
CHANGED
|
@@ -2,11 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
Runs **one SQL statement** in-process via `node:sqlite` and writes the result to the `results` channel as `application/json` — ready for a jsonpath body-matcher.
|
|
4
4
|
|
|
5
|
-
One statement per
|
|
5
|
+
One statement per operation is enforced. A multi-statement script fails with
|
|
6
|
+
`sqlite_multi_statement` (400) and names the rejected tail; partial execution
|
|
7
|
+
never passes as success. Trailing semicolons and comments are allowed.
|
|
8
|
+
Dot-commands such as `.tables` and `.schema` belong to the sqlite3 shell rather
|
|
9
|
+
than SQL. Use their SQL equivalents, such as querying `sqlite_master`.
|
|
6
10
|
|
|
7
11
|
## Database target
|
|
8
12
|
|
|
9
|
-
`EXEC[sqlite](./app.db):…` runs against the file `./app.db` (created if absent)
|
|
13
|
+
`EXEC[sqlite](./app.db):…` runs against the file `./app.db` (created if absent),
|
|
14
|
+
a persistent host-mutating database that requires proposal review. With no
|
|
15
|
+
target, it runs against a fresh `:memory:` database that is gone when the
|
|
16
|
+
operation finishes and bypasses proposal review. A directory is not a database
|
|
17
|
+
target; core routes it as a working directory, leaving SQLite in memory.
|
|
10
18
|
|
|
11
19
|
## Query vs mutation
|
|
12
20
|
|
|
@@ -15,4 +23,6 @@ The result shape is decided by the statement's columns, never by parsing the SQL
|
|
|
15
23
|
- **Row-returning** (SELECT, RETURNING, PRAGMA) → an array of row objects.
|
|
16
24
|
- **Mutation** (INSERT / UPDATE / DELETE / CREATE) → `{ changes, lastInsertRowid }`.
|
|
17
25
|
|
|
18
|
-
Large integers come back stringified (JSON
|
|
26
|
+
Large integers come back stringified (JSON cannot hold a bigint). Failures close
|
|
27
|
+
`results` as `errored` with an RFC 9457 Problem: invalid authored SQL is 400, a
|
|
28
|
+
missing database target is 404, and runtime/open failures are 500.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plurnk/plurnk-execs-sqlite",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "SQLite runtime executor for plurnk-service's exec scheme — runs the sqlite runtime tag in-process via node:sqlite, results as application/json.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"plurnk",
|
|
@@ -10,13 +10,14 @@
|
|
|
10
10
|
"sqlite",
|
|
11
11
|
"sql"
|
|
12
12
|
],
|
|
13
|
-
"homepage": "https://github.com/plurnk/plurnk-execs-sqlite#readme",
|
|
13
|
+
"homepage": "https://github.com/plurnk/plurnk-service/tree/main/plurnk-execs-sqlite#readme",
|
|
14
14
|
"bugs": {
|
|
15
|
-
"url": "https://
|
|
15
|
+
"url": "https://repo.possumtech.com/plurnk/plurnk-service/issues"
|
|
16
16
|
},
|
|
17
17
|
"repository": {
|
|
18
18
|
"type": "git",
|
|
19
|
-
"url": "git+https://github.com/plurnk/plurnk-
|
|
19
|
+
"url": "git+https://github.com/plurnk/plurnk-service.git",
|
|
20
|
+
"directory": "plurnk-execs-sqlite"
|
|
20
21
|
},
|
|
21
22
|
"engines": {
|
|
22
23
|
"node": ">=26"
|
|
@@ -52,14 +53,15 @@
|
|
|
52
53
|
],
|
|
53
54
|
"scripts": {
|
|
54
55
|
"test:lint": "tsc --noEmit",
|
|
55
|
-
"test:unit": "node --conditions=plurnk-dev --test \"src/**/*.test.ts\"",
|
|
56
|
+
"test:unit": "node --conditions=plurnk-dev --env-file-if-exists=../plurnk-execs/.env.defaults --test \"src/**/*.test.ts\"",
|
|
56
57
|
"test": "npm run test:lint && npm run test:unit",
|
|
58
|
+
"build:clean": "rm -rf dist",
|
|
57
59
|
"build:dist": "tsc -p tsconfig.build.json",
|
|
58
|
-
"build": "npm run build:dist",
|
|
60
|
+
"build": "npm run build:clean && npm run build:dist",
|
|
59
61
|
"prepack": "npm run build",
|
|
60
62
|
"prepublishOnly": "npm audit --audit-level=moderate && npm test"
|
|
61
63
|
},
|
|
62
64
|
"peerDependencies": {
|
|
63
|
-
"@plurnk/plurnk-execs": "^1.
|
|
65
|
+
"@plurnk/plurnk-execs": "^1.5.0"
|
|
64
66
|
}
|
|
65
67
|
}
|