@velarscript-labs/sqlite 0.2.1 → 0.3.1
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/CHANGELOG.md +28 -0
- package/README.md +44 -12
- package/dist/index.js +1936 -0
- package/dist/index.js.map +1 -0
- package/dist/index.veli.json +7206 -0
- package/dist/velar-library.json +28 -0
- package/package.json +12 -5
- package/src/index.vel +161 -67
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"formatVersion": 1,
|
|
3
|
+
"kind": "velar-library-artifact",
|
|
4
|
+
"abiVersion": 1,
|
|
5
|
+
"package": {
|
|
6
|
+
"name": "@velarscript-labs/sqlite",
|
|
7
|
+
"version": "0.3.1"
|
|
8
|
+
},
|
|
9
|
+
"target": "node",
|
|
10
|
+
"compilerVersion": "0.14.2",
|
|
11
|
+
"sourceEntry": "src/index.vel",
|
|
12
|
+
"sources": [
|
|
13
|
+
{
|
|
14
|
+
"path": "src/index.vel",
|
|
15
|
+
"sha256": "2a561a3d17d372c8f0e95e416bc1e0b829b45e807b3454292c2191beb24a5d18"
|
|
16
|
+
}
|
|
17
|
+
],
|
|
18
|
+
"entry": {
|
|
19
|
+
"javascript": "index.js",
|
|
20
|
+
"sourceMap": "index.js.map",
|
|
21
|
+
"interface": "index.veli.json",
|
|
22
|
+
"sha256": {
|
|
23
|
+
"javascript": "bf5a8456e0778533840efb831a60b93ee23b3f0963735fccd29a89978a61358d",
|
|
24
|
+
"sourceMap": "6b8fe8ab61326511de62813d3e33a16aacf9f53ec46b16e20eb1cf68e05e2391",
|
|
25
|
+
"interface": "c340ec9d62adc30409be6de430791696e15cddb9e2b89da8b5d55cf444fc87b2"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
package/package.json
CHANGED
|
@@ -1,21 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@velarscript-labs/sqlite",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.3.1",
|
|
4
|
+
"description": "Injection-resistant bounded SQLite capability for VelarScript Node applications.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"files": [
|
|
8
8
|
"src/index.vel",
|
|
9
|
+
"dist",
|
|
9
10
|
"README.md",
|
|
10
11
|
"CHANGELOG.md",
|
|
11
12
|
"LICENSE"
|
|
12
13
|
],
|
|
13
14
|
"scripts": {
|
|
15
|
+
"build": "velar build-library",
|
|
14
16
|
"check": "velar format --check && velar check",
|
|
15
17
|
"test": "velar test"
|
|
16
18
|
},
|
|
17
19
|
"engines": {
|
|
18
|
-
"node": ">=24"
|
|
20
|
+
"node": ">=24.12"
|
|
19
21
|
},
|
|
20
22
|
"repository": {
|
|
21
23
|
"type": "git",
|
|
@@ -25,12 +27,17 @@
|
|
|
25
27
|
"publishConfig": {
|
|
26
28
|
"access": "public"
|
|
27
29
|
},
|
|
30
|
+
"exports": {
|
|
31
|
+
".": "./dist/index.js"
|
|
32
|
+
},
|
|
28
33
|
"velar": {
|
|
29
34
|
"entry": "src/index.vel",
|
|
35
|
+
"artifacts": { "node": "dist/velar-library.json" },
|
|
30
36
|
"targets": ["node"],
|
|
31
|
-
"requires": {"capabilities": ["node"], "language": ">=0.
|
|
37
|
+
"requires": {"capabilities": ["node"], "language": ">=0.14 <0.15"}
|
|
32
38
|
},
|
|
33
39
|
"dependencies": {
|
|
34
|
-
"@velarscript-labs/database": "0.
|
|
40
|
+
"@velarscript-labs/database": "0.3.1",
|
|
41
|
+
"sqlite3-parser": "0.7.1"
|
|
35
42
|
}
|
|
36
43
|
}
|
package/src/index.vel
CHANGED
|
@@ -1,12 +1,23 @@
|
|
|
1
1
|
/// Per-connection bounds. Every operation is serialized through one Worker;
|
|
2
2
|
/// queueCapacity bounds admitted operations waiting for that connection.
|
|
3
|
-
import {DatabaseExecutor} from "@velarscript-labs/database"
|
|
3
|
+
import {DatabaseExecutor, DatabaseStatement, trustedSql} from "@velarscript-labs/database"
|
|
4
|
+
|
|
5
|
+
export enum SqliteJournalMode:
|
|
6
|
+
delete
|
|
7
|
+
truncate
|
|
8
|
+
persist
|
|
9
|
+
memory
|
|
10
|
+
wal
|
|
11
|
+
off
|
|
4
12
|
|
|
5
13
|
export type SqliteOptions:
|
|
6
14
|
busyTimeoutMilliseconds: number?
|
|
7
15
|
queueCapacity: number?
|
|
8
16
|
maxRows: number?
|
|
9
17
|
maxResultBytes: number?
|
|
18
|
+
statementCacheCapacity: number?
|
|
19
|
+
journalMode: SqliteJournalMode?
|
|
20
|
+
readOnly: bool?
|
|
10
21
|
|
|
11
22
|
extern js()`
|
|
12
23
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
@@ -51,21 +62,31 @@ extern js()`
|
|
|
51
62
|
|
|
52
63
|
function checkedOptions(value) {
|
|
53
64
|
if (value === null || typeof value !== "object" || Array.isArray(value)) throw new TypeError("SQLite options must be a record");
|
|
54
|
-
const allowed = new Set(["busyTimeoutMilliseconds", "queueCapacity", "maxRows", "maxResultBytes"]);
|
|
65
|
+
const allowed = new Set(["busyTimeoutMilliseconds", "queueCapacity", "maxRows", "maxResultBytes", "statementCacheCapacity", "journalMode", "readOnly"]);
|
|
55
66
|
for (const key of Object.keys(value)) if (!allowed.has(key)) throw new TypeError("Unknown SQLite option " + key);
|
|
67
|
+
const journalModes = new Set(["delete", "truncate", "persist", "memory", "wal", "off"]);
|
|
68
|
+
const journalMode = value.journalMode == null ? null : value.journalMode;
|
|
69
|
+
if (journalMode !== null && (typeof journalMode !== "string" || !journalModes.has(journalMode))) throw new TypeError("SQLite journalMode must name a supported mode");
|
|
70
|
+
if (value.readOnly != null && typeof value.readOnly !== "boolean") throw new TypeError("SQLite readOnly must be bool");
|
|
71
|
+
if (value.readOnly === true && journalMode !== null) throw new TypeError("SQLite readOnly connections cannot change journalMode");
|
|
56
72
|
return {
|
|
57
73
|
busyTimeoutMilliseconds: integer(value.busyTimeoutMilliseconds, 2000, 1, 60000, "SQLite busy timeout"),
|
|
58
74
|
queueCapacity: integer(value.queueCapacity, 64, 1, 1024, "SQLite queue capacity"),
|
|
59
75
|
maxRows: integer(value.maxRows, 10000, 1, 1000000, "SQLite row limit"),
|
|
60
76
|
maxResultBytes: integer(value.maxResultBytes, 64 * 1024 * 1024, 1, 128 * 1024 * 1024, "SQLite result byte limit"),
|
|
77
|
+
statementCacheCapacity: integer(value.statementCacheCapacity, 128, 1, 1024, "SQLite statement cache capacity"),
|
|
78
|
+
journalMode,
|
|
79
|
+
readOnly: value.readOnly === true,
|
|
61
80
|
};
|
|
62
81
|
}
|
|
63
82
|
|
|
64
83
|
function workerMain() {
|
|
65
84
|
const { Buffer } = require("node:buffer");
|
|
66
85
|
const { parentPort, workerData } = require("node:worker_threads");
|
|
67
|
-
const { DatabaseSync } = require("node:sqlite");
|
|
86
|
+
const { DatabaseSync, constants } = require("node:sqlite");
|
|
87
|
+
const { parseStmt } = require("sqlite3-parser");
|
|
68
88
|
let database = null;
|
|
89
|
+
let statements = null;
|
|
69
90
|
let closed = false;
|
|
70
91
|
|
|
71
92
|
function failure(message, code, operation, retryable = false) {
|
|
@@ -89,13 +110,6 @@ extern js()`
|
|
|
89
110
|
};
|
|
90
111
|
}
|
|
91
112
|
|
|
92
|
-
function sqlText(value, operation) {
|
|
93
|
-
if (typeof value !== "string" || value.length === 0 || value.length > 1024 * 1024 || value.includes("\0")) {
|
|
94
|
-
throw failure("SQLite SQL must be non-empty text no longer than 1 MiB", "SQLITE_INPUT", operation);
|
|
95
|
-
}
|
|
96
|
-
return value;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
113
|
function parameter(value, budget) {
|
|
100
114
|
if (value === null) return null;
|
|
101
115
|
if (typeof value === "boolean") return value ? 1 : 0;
|
|
@@ -124,6 +138,29 @@ extern js()`
|
|
|
124
138
|
return output;
|
|
125
139
|
}
|
|
126
140
|
|
|
141
|
+
function statementParts(rawFragments, rawParameters, operation) {
|
|
142
|
+
if (!Array.isArray(rawFragments) || rawFragments.length !== rawParameters.length + 1 || rawFragments.length > 1000) {
|
|
143
|
+
throw failure("SQLite statements require exactly one more SQL fragment than bound parameters", "SQLITE_INPUT", operation);
|
|
144
|
+
}
|
|
145
|
+
let sourceBytes = 0;
|
|
146
|
+
const fragments = rawFragments.map(fragment => {
|
|
147
|
+
if (typeof fragment !== "string" || fragment.includes("\0") || fragment.includes("?")) {
|
|
148
|
+
throw failure("SQLite SQL fragments must be text without NUL or raw parameter placeholders", "SQLITE_INPUT", operation);
|
|
149
|
+
}
|
|
150
|
+
sourceBytes += Buffer.byteLength(fragment, "utf8");
|
|
151
|
+
return fragment;
|
|
152
|
+
});
|
|
153
|
+
if (sourceBytes === 0 || sourceBytes > 1024 * 1024) throw failure("SQLite SQL must be non-empty text no longer than 1 MiB", "SQLITE_INPUT", operation);
|
|
154
|
+
const bound = parameters(rawParameters);
|
|
155
|
+
const source = fragments.join("?");
|
|
156
|
+
const parsed = parseStmt(source);
|
|
157
|
+
if (parsed.status !== "ok") {
|
|
158
|
+
const message = parsed.errors.length === 0 ? "invalid statement" : parsed.errors[0].message;
|
|
159
|
+
throw failure("SQLite requires exactly one valid statement: " + message, "SQLITE_INPUT", operation);
|
|
160
|
+
}
|
|
161
|
+
return { fragments, bound };
|
|
162
|
+
}
|
|
163
|
+
|
|
127
164
|
function count(value, label) {
|
|
128
165
|
const number = typeof value === "bigint" ? Number(value) : value;
|
|
129
166
|
if (!Number.isSafeInteger(number) || number < 0) throw failure(label + " is outside VelarScript's safe integer range", "SQLITE_INTEGER_RANGE", "result");
|
|
@@ -165,30 +202,24 @@ extern js()`
|
|
|
165
202
|
return output;
|
|
166
203
|
}
|
|
167
204
|
|
|
168
|
-
function statement(sql, operation) {
|
|
169
|
-
const prepared = database.prepare(sqlText(sql, operation));
|
|
170
|
-
if (typeof prepared.setReadBigInts === "function") prepared.setReadBigInts(true);
|
|
171
|
-
return prepared;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
205
|
function execute(message) {
|
|
175
|
-
const
|
|
176
|
-
const result =
|
|
206
|
+
const statement = statementParts(message.fragments, message.params, "execute");
|
|
207
|
+
const result = statements.run(statement.fragments, ...statement.bound);
|
|
177
208
|
return count(result.changes, "SQLite affected row count");
|
|
178
209
|
}
|
|
179
210
|
|
|
180
211
|
function one(message) {
|
|
181
|
-
const
|
|
182
|
-
const row =
|
|
212
|
+
const statement = statementParts(message.fragments, message.params, "one");
|
|
213
|
+
const row = statements.get(statement.fragments, ...statement.bound);
|
|
183
214
|
if (row === undefined) return null;
|
|
184
215
|
return resultRow(row, { value: 0 });
|
|
185
216
|
}
|
|
186
217
|
|
|
187
218
|
function all(message) {
|
|
188
|
-
const
|
|
219
|
+
const statement = statementParts(message.fragments, message.params, "all");
|
|
189
220
|
const rows = [];
|
|
190
221
|
const budget = { value: 0 };
|
|
191
|
-
for (const row of
|
|
222
|
+
for (const row of statements.iterate(statement.fragments, ...statement.bound)) {
|
|
192
223
|
if (rows.length >= workerData.maxRows) throw failure("SQLite result exceeds the connection row limit", "SQLITE_ROW_LIMIT", "all");
|
|
193
224
|
rows.push(resultRow(row, budget));
|
|
194
225
|
}
|
|
@@ -227,8 +258,39 @@ extern js()`
|
|
|
227
258
|
}
|
|
228
259
|
|
|
229
260
|
try {
|
|
230
|
-
database = new DatabaseSync(workerData.path, {
|
|
231
|
-
|
|
261
|
+
database = new DatabaseSync(workerData.path, {
|
|
262
|
+
timeout: workerData.busyTimeoutMilliseconds,
|
|
263
|
+
readOnly: workerData.readOnly,
|
|
264
|
+
enableForeignKeyConstraints: true,
|
|
265
|
+
enableDoubleQuotedStringLiterals: false,
|
|
266
|
+
allowExtension: false,
|
|
267
|
+
readBigInts: true,
|
|
268
|
+
allowBareNamedParameters: false,
|
|
269
|
+
allowUnknownNamedParameters: false,
|
|
270
|
+
defensive: true,
|
|
271
|
+
limits: {
|
|
272
|
+
length: workerData.maxResultBytes,
|
|
273
|
+
sqlLength: 1024 * 1024,
|
|
274
|
+
column: 2000,
|
|
275
|
+
exprDepth: 1000,
|
|
276
|
+
compoundSelect: 500,
|
|
277
|
+
vdbeOp: 250000,
|
|
278
|
+
functionArg: 1000,
|
|
279
|
+
attach: 0,
|
|
280
|
+
likePatternLength: 50000,
|
|
281
|
+
variableNumber: 999,
|
|
282
|
+
triggerDepth: 100,
|
|
283
|
+
},
|
|
284
|
+
});
|
|
285
|
+
database.enableDefensive(true);
|
|
286
|
+
database.enableLoadExtension(false);
|
|
287
|
+
database.setAuthorizer((actionCode, arg1, arg2) => {
|
|
288
|
+
if (actionCode === constants.SQLITE_ATTACH || actionCode === constants.SQLITE_DETACH) return constants.SQLITE_DENY;
|
|
289
|
+
if (actionCode === constants.SQLITE_FUNCTION && typeof arg2 === "string" && arg2.toLowerCase() === "load_extension") return constants.SQLITE_DENY;
|
|
290
|
+
return constants.SQLITE_OK;
|
|
291
|
+
});
|
|
292
|
+
statements = database.createTagStore(workerData.statementCacheCapacity);
|
|
293
|
+
if (workerData.journalMode !== null) database.exec("PRAGMA journal_mode = " + workerData.journalMode.toUpperCase());
|
|
232
294
|
parentPort.postMessage({ kind: "ready" });
|
|
233
295
|
} catch (error) {
|
|
234
296
|
parentPort.postMessage({ kind: "ready", error: errorData(error, "open") });
|
|
@@ -261,13 +323,13 @@ extern js()`
|
|
|
261
323
|
state.pending.clear();
|
|
262
324
|
}
|
|
263
325
|
|
|
264
|
-
function request(state, operation,
|
|
326
|
+
function request(state, operation, fragments = [""], params = []) {
|
|
265
327
|
if (state.closed) return Promise.reject(new NativeSqliteError("SQLite connection is closed", "SQLITE_CLOSED", operation));
|
|
266
328
|
const id = state.nextId++;
|
|
267
329
|
return new Promise((resolve, reject) => {
|
|
268
330
|
state.pending.set(id, { resolve, reject });
|
|
269
331
|
try {
|
|
270
|
-
state.worker.postMessage({ id, operation,
|
|
332
|
+
state.worker.postMessage({ id, operation, fragments, params });
|
|
271
333
|
} catch (error) {
|
|
272
334
|
state.pending.delete(id);
|
|
273
335
|
reject(error);
|
|
@@ -287,11 +349,11 @@ extern js()`
|
|
|
287
349
|
return state;
|
|
288
350
|
}
|
|
289
351
|
|
|
290
|
-
function transactionRequest(transaction, operation,
|
|
352
|
+
function transactionRequest(transaction, operation, fragments = [""], params = []) {
|
|
291
353
|
const state = transactionStateOf(transaction);
|
|
292
354
|
if (state.busy) return Promise.reject(new NativeSqliteConcurrencyError("SQLite transaction operations must be awaited one at a time"));
|
|
293
355
|
state.busy = true;
|
|
294
|
-
return request(state.connection, operation,
|
|
356
|
+
return request(state.connection, operation, fragments, params).finally(() => { state.busy = false; });
|
|
295
357
|
}
|
|
296
358
|
|
|
297
359
|
function enqueue(state, operation) {
|
|
@@ -310,9 +372,9 @@ extern js()`
|
|
|
310
372
|
transactionStates.set(this, state);
|
|
311
373
|
}
|
|
312
374
|
|
|
313
|
-
execute(
|
|
314
|
-
one(
|
|
315
|
-
all(
|
|
375
|
+
execute(fragments, params = []) { return transactionRequest(this, "execute", fragments, params); }
|
|
376
|
+
one(fragments, params = []) { return transactionRequest(this, "one", fragments, params); }
|
|
377
|
+
all(fragments, params = []) { return transactionRequest(this, "all", fragments, params); }
|
|
316
378
|
}
|
|
317
379
|
|
|
318
380
|
export class NativeSqliteConnection {
|
|
@@ -321,19 +383,19 @@ extern js()`
|
|
|
321
383
|
connectionStates.set(this, state);
|
|
322
384
|
}
|
|
323
385
|
|
|
324
|
-
execute(
|
|
386
|
+
execute(fragments, params = []) {
|
|
325
387
|
const state = stateOf(this);
|
|
326
|
-
return enqueue(state, () => request(state, "execute",
|
|
388
|
+
return enqueue(state, () => request(state, "execute", fragments, params));
|
|
327
389
|
}
|
|
328
390
|
|
|
329
|
-
one(
|
|
391
|
+
one(fragments, params = []) {
|
|
330
392
|
const state = stateOf(this);
|
|
331
|
-
return enqueue(state, () => request(state, "one",
|
|
393
|
+
return enqueue(state, () => request(state, "one", fragments, params));
|
|
332
394
|
}
|
|
333
395
|
|
|
334
|
-
all(
|
|
396
|
+
all(fragments, params = []) {
|
|
335
397
|
const state = stateOf(this);
|
|
336
|
-
return enqueue(state, () => request(state, "all",
|
|
398
|
+
return enqueue(state, () => request(state, "all", fragments, params));
|
|
337
399
|
}
|
|
338
400
|
|
|
339
401
|
transaction(operation) {
|
|
@@ -448,14 +510,14 @@ extern js()`
|
|
|
448
510
|
const message: string
|
|
449
511
|
|
|
450
512
|
export class NativeSqliteTransaction:
|
|
451
|
-
async def execute(
|
|
452
|
-
async def one(
|
|
453
|
-
async def all(
|
|
513
|
+
async def execute(fragments: readonly List<string>, params: readonly List<unknown> = []) -> number
|
|
514
|
+
async def one(fragments: readonly List<string>, params: readonly List<unknown> = []) -> unknown
|
|
515
|
+
async def all(fragments: readonly List<string>, params: readonly List<unknown> = []) -> List<unknown>
|
|
454
516
|
|
|
455
517
|
export class NativeSqliteConnection:
|
|
456
|
-
async def execute(
|
|
457
|
-
async def one(
|
|
458
|
-
async def all(
|
|
518
|
+
async def execute(fragments: readonly List<string>, params: readonly List<unknown> = []) -> number
|
|
519
|
+
async def one(fragments: readonly List<string>, params: readonly List<unknown> = []) -> unknown
|
|
520
|
+
async def all(fragments: readonly List<string>, params: readonly List<unknown> = []) -> List<unknown>
|
|
459
521
|
async def transaction(operation: (NativeSqliteTransaction) -> Promise<null>) -> null
|
|
460
522
|
async def close() -> null
|
|
461
523
|
|
|
@@ -491,13 +553,36 @@ def sqliteFailure(error: NativeSqliteError) -> SqliteError:
|
|
|
491
553
|
return SqliteError(error.message, error.sqliteCode, error.operation, error.retryable)
|
|
492
554
|
return SqliteError(error.message)
|
|
493
555
|
|
|
556
|
+
/// Produces a SQLite literal only for grammar positions where bound parameters
|
|
557
|
+
/// are not legal, such as schema defaults and PRAGMA assignments. Ordinary
|
|
558
|
+
/// query values must still use sqlParameter/sqlTuple/sqlRows.
|
|
559
|
+
export def sqliteLiteral(value: unknown) -> DatabaseStatement:
|
|
560
|
+
if value == null:
|
|
561
|
+
return trustedSql("NULL")
|
|
562
|
+
if value is bool:
|
|
563
|
+
return trustedSql(value ? "1" : "0")
|
|
564
|
+
if value is string:
|
|
565
|
+
return trustedSql("'" + value.replaceAll("'", "''") + "'")
|
|
566
|
+
if value is number:
|
|
567
|
+
assert value.isFinite() else "SQLite numeric literals must be finite"
|
|
568
|
+
assert not value.isInteger() or (value >= -9007199254740991 and value <= 9007199254740991) else "SQLite integer literals must be safe integers"
|
|
569
|
+
return trustedSql(str(value))
|
|
570
|
+
throw Error("SQLite literals support only null, bool, string, and finite number")
|
|
571
|
+
|
|
572
|
+
/// Quotes one SQLite identifier as a single name. Qualified names must compose
|
|
573
|
+
/// separately quoted identifiers around trusted punctuation.
|
|
574
|
+
export def sqliteIdentifier(value: string) -> DatabaseStatement:
|
|
575
|
+
assert not value.isBlank() and value.size <= 255 and not value.has(Text.fromCodePoint(0)) else "SQLite identifiers must be non-blank text with no NUL and no longer than 255 characters"
|
|
576
|
+
return trustedSql(`"` + value.replaceAll(`"`, `""`) + `"`)
|
|
577
|
+
|
|
494
578
|
export class SqliteTransaction:
|
|
495
579
|
constructor(private const native: NativeSqliteTransaction):
|
|
496
580
|
pass
|
|
497
581
|
|
|
498
|
-
async def execute(
|
|
582
|
+
async def execute(statement: DatabaseStatement) -> number:
|
|
583
|
+
const data = statement.data()
|
|
499
584
|
try:
|
|
500
|
-
return await self.native.execute(
|
|
585
|
+
return await self.native.execute(data.fragments, data.parameters)
|
|
501
586
|
catch error:
|
|
502
587
|
if error is NativeSqliteError:
|
|
503
588
|
throw sqliteFailure(error)
|
|
@@ -505,20 +590,22 @@ export class SqliteTransaction:
|
|
|
505
590
|
|
|
506
591
|
/// Projects this transaction into the engine-neutral functional operation layer.
|
|
507
592
|
def executor() -> DatabaseExecutor:
|
|
508
|
-
async def executeStatement(
|
|
509
|
-
return await self.execute(
|
|
593
|
+
async def executeStatement(statement: DatabaseStatement) -> number:
|
|
594
|
+
return await self.execute(statement)
|
|
510
595
|
|
|
511
|
-
async def oneRow(
|
|
596
|
+
async def oneRow(statement: DatabaseStatement) -> unknown:
|
|
597
|
+
const data = statement.data()
|
|
512
598
|
try:
|
|
513
|
-
return await self.native.one(
|
|
599
|
+
return await self.native.one(data.fragments, data.parameters)
|
|
514
600
|
catch error:
|
|
515
601
|
if error is NativeSqliteError:
|
|
516
602
|
throw sqliteFailure(error)
|
|
517
603
|
throw SqliteError(error.message)
|
|
518
604
|
|
|
519
|
-
async def allRows(
|
|
605
|
+
async def allRows(statement: DatabaseStatement) -> List<unknown>:
|
|
606
|
+
const data = statement.data()
|
|
520
607
|
try:
|
|
521
|
-
return await self.native.all(
|
|
608
|
+
return await self.native.all(data.fragments, data.parameters)
|
|
522
609
|
catch error:
|
|
523
610
|
if error is NativeSqliteError:
|
|
524
611
|
throw sqliteFailure(error)
|
|
@@ -526,9 +613,10 @@ export class SqliteTransaction:
|
|
|
526
613
|
|
|
527
614
|
return {execute: executeStatement, one: oneRow, all: allRows}
|
|
528
615
|
|
|
529
|
-
async def one<T>(
|
|
616
|
+
async def one<T>(statement: DatabaseStatement, RowType: Type<T>) -> T?:
|
|
617
|
+
const data = statement.data()
|
|
530
618
|
try:
|
|
531
|
-
const row = await self.native.one(
|
|
619
|
+
const row = await self.native.one(data.fragments, data.parameters)
|
|
532
620
|
if row == null:
|
|
533
621
|
return null
|
|
534
622
|
return RowType.parse(row)
|
|
@@ -537,9 +625,10 @@ export class SqliteTransaction:
|
|
|
537
625
|
throw sqliteFailure(error)
|
|
538
626
|
throw SqliteError(error.message)
|
|
539
627
|
|
|
540
|
-
async def all<T>(
|
|
628
|
+
async def all<T>(statement: DatabaseStatement, RowType: Type<T>) -> List<T>:
|
|
629
|
+
const data = statement.data()
|
|
541
630
|
try:
|
|
542
|
-
const rows = await self.native.all(
|
|
631
|
+
const rows = await self.native.all(data.fragments, data.parameters)
|
|
543
632
|
return rows.map(row => RowType.parse(row))
|
|
544
633
|
catch error:
|
|
545
634
|
if error is NativeSqliteError:
|
|
@@ -550,9 +639,10 @@ export class SqliteConnection:
|
|
|
550
639
|
constructor(private const native: NativeSqliteConnection):
|
|
551
640
|
pass
|
|
552
641
|
|
|
553
|
-
async def execute(
|
|
642
|
+
async def execute(statement: DatabaseStatement) -> number:
|
|
643
|
+
const data = statement.data()
|
|
554
644
|
try:
|
|
555
|
-
return await self.native.execute(
|
|
645
|
+
return await self.native.execute(data.fragments, data.parameters)
|
|
556
646
|
catch error:
|
|
557
647
|
if error is NativeSqliteError:
|
|
558
648
|
throw sqliteFailure(error)
|
|
@@ -560,20 +650,22 @@ export class SqliteConnection:
|
|
|
560
650
|
|
|
561
651
|
/// Projects this connection into the engine-neutral functional operation layer.
|
|
562
652
|
def executor() -> DatabaseExecutor:
|
|
563
|
-
async def executeStatement(
|
|
564
|
-
return await self.execute(
|
|
653
|
+
async def executeStatement(statement: DatabaseStatement) -> number:
|
|
654
|
+
return await self.execute(statement)
|
|
565
655
|
|
|
566
|
-
async def oneRow(
|
|
656
|
+
async def oneRow(statement: DatabaseStatement) -> unknown:
|
|
657
|
+
const data = statement.data()
|
|
567
658
|
try:
|
|
568
|
-
return await self.native.one(
|
|
659
|
+
return await self.native.one(data.fragments, data.parameters)
|
|
569
660
|
catch error:
|
|
570
661
|
if error is NativeSqliteError:
|
|
571
662
|
throw sqliteFailure(error)
|
|
572
663
|
throw SqliteError(error.message)
|
|
573
664
|
|
|
574
|
-
async def allRows(
|
|
665
|
+
async def allRows(statement: DatabaseStatement) -> List<unknown>:
|
|
666
|
+
const data = statement.data()
|
|
575
667
|
try:
|
|
576
|
-
return await self.native.all(
|
|
668
|
+
return await self.native.all(data.fragments, data.parameters)
|
|
577
669
|
catch error:
|
|
578
670
|
if error is NativeSqliteError:
|
|
579
671
|
throw sqliteFailure(error)
|
|
@@ -581,9 +673,10 @@ export class SqliteConnection:
|
|
|
581
673
|
|
|
582
674
|
return {execute: executeStatement, one: oneRow, all: allRows}
|
|
583
675
|
|
|
584
|
-
async def one<T>(
|
|
676
|
+
async def one<T>(statement: DatabaseStatement, RowType: Type<T>) -> T?:
|
|
677
|
+
const data = statement.data()
|
|
585
678
|
try:
|
|
586
|
-
const row = await self.native.one(
|
|
679
|
+
const row = await self.native.one(data.fragments, data.parameters)
|
|
587
680
|
if row == null:
|
|
588
681
|
return null
|
|
589
682
|
return RowType.parse(row)
|
|
@@ -592,9 +685,10 @@ export class SqliteConnection:
|
|
|
592
685
|
throw sqliteFailure(error)
|
|
593
686
|
throw SqliteError(error.message)
|
|
594
687
|
|
|
595
|
-
async def all<T>(
|
|
688
|
+
async def all<T>(statement: DatabaseStatement, RowType: Type<T>) -> List<T>:
|
|
689
|
+
const data = statement.data()
|
|
596
690
|
try:
|
|
597
|
-
const rows = await self.native.all(
|
|
691
|
+
const rows = await self.native.all(data.fragments, data.parameters)
|
|
598
692
|
return rows.map(row => RowType.parse(row))
|
|
599
693
|
catch error:
|
|
600
694
|
if error is NativeSqliteError:
|