firebird-wasm 0.1.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/LICENSE +201 -0
- package/README.md +120 -0
- package/dist/.tsbuildinfo.build +1 -0
- package/dist/browser/db-lock.d.ts +92 -0
- package/dist/browser/db-lock.d.ts.map +1 -0
- package/dist/browser/db-lock.js +163 -0
- package/dist/browser/db-lock.js.map +1 -0
- package/dist/browser/engine-transport.d.ts +94 -0
- package/dist/browser/engine-transport.d.ts.map +1 -0
- package/dist/browser/engine-transport.js +217 -0
- package/dist/browser/engine-transport.js.map +1 -0
- package/dist/browser/field-types.d.ts +19 -0
- package/dist/browser/field-types.d.ts.map +1 -0
- package/dist/browser/field-types.js +79 -0
- package/dist/browser/field-types.js.map +1 -0
- package/dist/browser/firebird-browser.d.ts +249 -0
- package/dist/browser/firebird-browser.d.ts.map +1 -0
- package/dist/browser/firebird-browser.js +401 -0
- package/dist/browser/firebird-browser.js.map +1 -0
- package/dist/browser/index.d.ts +31 -0
- package/dist/browser/index.d.ts.map +1 -0
- package/dist/browser/index.js +39 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/browser/indexeddb-vfs.d.ts +132 -0
- package/dist/browser/indexeddb-vfs.d.ts.map +1 -0
- package/dist/browser/indexeddb-vfs.js +285 -0
- package/dist/browser/indexeddb-vfs.js.map +1 -0
- package/dist/browser/params.d.ts +33 -0
- package/dist/browser/params.d.ts.map +1 -0
- package/dist/browser/params.js +92 -0
- package/dist/browser/params.js.map +1 -0
- package/dist/browser/sql-script.d.ts +27 -0
- package/dist/browser/sql-script.d.ts.map +1 -0
- package/dist/browser/sql-script.js +132 -0
- package/dist/browser/sql-script.js.map +1 -0
- package/dist/browser/worker-entry.d.ts +45 -0
- package/dist/browser/worker-entry.d.ts.map +1 -0
- package/dist/browser/worker-entry.js +79 -0
- package/dist/browser/worker-entry.js.map +1 -0
- package/dist/browser/worker-protocol.d.ts +37 -0
- package/dist/browser/worker-protocol.d.ts.map +1 -0
- package/dist/browser/worker-protocol.js +10 -0
- package/dist/browser/worker-protocol.js.map +1 -0
- package/dist/browser/worker-transport.d.ts +63 -0
- package/dist/browser/worker-transport.d.ts.map +1 -0
- package/dist/browser/worker-transport.js +133 -0
- package/dist/browser/worker-transport.js.map +1 -0
- package/dist/firebird.d.ts +73 -0
- package/dist/firebird.d.ts.map +1 -0
- package/dist/firebird.js +208 -0
- package/dist/firebird.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +88 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/dist/wasm/firebird-embedded.js +2 -0
- package/dist/wasm/firebird-embedded.wasm +0 -0
- package/dist/wasm-loader.d.ts +162 -0
- package/dist/wasm-loader.d.ts.map +1 -0
- package/dist/wasm-loader.js +103 -0
- package/dist/wasm-loader.js.map +1 -0
- package/package.json +86 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* sql-script.ts – split a SQL script into individual statements.
|
|
3
|
+
*
|
|
4
|
+
* The engine executes one statement at a time, so running a migration means
|
|
5
|
+
* splitting it first. Splitting on `;` alone is wrong in ways that corrupt
|
|
6
|
+
* data rather than merely failing: a semicolon inside a string literal, an
|
|
7
|
+
* identifier or a comment is not a terminator.
|
|
8
|
+
*
|
|
9
|
+
* Firebird adds `SET TERM`, which changes the terminator so that PSQL bodies —
|
|
10
|
+
* full of their own semicolons — can be written at all. A splitter that
|
|
11
|
+
* ignores it cuts every stored procedure and trigger in half, which is most of
|
|
12
|
+
* what a real migration contains.
|
|
13
|
+
*/
|
|
14
|
+
/** A statement and where it started, for error messages. */
|
|
15
|
+
export interface ScriptStatement {
|
|
16
|
+
sql: string;
|
|
17
|
+
/** 1-based line number of the statement's first character. */
|
|
18
|
+
line: number;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Split `script` into executable statements.
|
|
22
|
+
*
|
|
23
|
+
* Comments and empty statements are dropped; `SET TERM` directives are obeyed
|
|
24
|
+
* and not emitted, since they configure the splitter rather than the engine.
|
|
25
|
+
*/
|
|
26
|
+
export declare function splitStatements(script: string): ScriptStatement[];
|
|
27
|
+
//# sourceMappingURL=sql-script.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sql-script.d.ts","sourceRoot":"","sources":["../../src/browser/sql-script.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,4DAA4D;AAC5D,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,8DAA8D;IAC9D,IAAI,EAAE,MAAM,CAAC;CACd;AA+BD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,eAAe,EAAE,CA+FjE"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* sql-script.ts – split a SQL script into individual statements.
|
|
4
|
+
*
|
|
5
|
+
* The engine executes one statement at a time, so running a migration means
|
|
6
|
+
* splitting it first. Splitting on `;` alone is wrong in ways that corrupt
|
|
7
|
+
* data rather than merely failing: a semicolon inside a string literal, an
|
|
8
|
+
* identifier or a comment is not a terminator.
|
|
9
|
+
*
|
|
10
|
+
* Firebird adds `SET TERM`, which changes the terminator so that PSQL bodies —
|
|
11
|
+
* full of their own semicolons — can be written at all. A splitter that
|
|
12
|
+
* ignores it cuts every stored procedure and trigger in half, which is most of
|
|
13
|
+
* what a real migration contains.
|
|
14
|
+
*/
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.splitStatements = splitStatements;
|
|
17
|
+
const DEFAULT_TERMINATOR = ';';
|
|
18
|
+
/** Is `text` at `pos` the start of a `SET TERM <new> <old>` directive? */
|
|
19
|
+
function matchSetTerm(text, pos, terminator) {
|
|
20
|
+
const match = /^set\s+term\s+(\S+)/i.exec(text.slice(pos));
|
|
21
|
+
if (!match)
|
|
22
|
+
return null;
|
|
23
|
+
let newTerminator = match[1];
|
|
24
|
+
let end = pos + match[0].length;
|
|
25
|
+
// isql accepts "SET TERM ^;" — the old terminator glued to the new one.
|
|
26
|
+
if (newTerminator.length > terminator.length && newTerminator.endsWith(terminator)) {
|
|
27
|
+
newTerminator = newTerminator.slice(0, -terminator.length);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
// Otherwise the directive is itself closed by the current terminator.
|
|
31
|
+
const rest = text.slice(end);
|
|
32
|
+
const closing = rest.indexOf(terminator);
|
|
33
|
+
if (closing !== -1) {
|
|
34
|
+
end += closing + terminator.length;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return { newTerminator, end };
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Split `script` into executable statements.
|
|
41
|
+
*
|
|
42
|
+
* Comments and empty statements are dropped; `SET TERM` directives are obeyed
|
|
43
|
+
* and not emitted, since they configure the splitter rather than the engine.
|
|
44
|
+
*/
|
|
45
|
+
function splitStatements(script) {
|
|
46
|
+
const statements = [];
|
|
47
|
+
let terminator = DEFAULT_TERMINATOR;
|
|
48
|
+
let current = '';
|
|
49
|
+
let statementLine = 1;
|
|
50
|
+
let line = 1;
|
|
51
|
+
let i = 0;
|
|
52
|
+
const push = () => {
|
|
53
|
+
const sql = current.trim();
|
|
54
|
+
if (sql)
|
|
55
|
+
statements.push({ sql, line: statementLine });
|
|
56
|
+
current = '';
|
|
57
|
+
};
|
|
58
|
+
while (i < script.length) {
|
|
59
|
+
const ch = script[i];
|
|
60
|
+
const two = script.slice(i, i + 2);
|
|
61
|
+
// Line comment: to end of line, newline preserved so line numbers hold.
|
|
62
|
+
if (two === '--') {
|
|
63
|
+
const nl = script.indexOf('\n', i);
|
|
64
|
+
i = nl === -1 ? script.length : nl;
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
// Block comment.
|
|
68
|
+
if (two === '/*') {
|
|
69
|
+
const close = script.indexOf('*/', i + 2);
|
|
70
|
+
const end = close === -1 ? script.length : close + 2;
|
|
71
|
+
line += (script.slice(i, end).match(/\n/g) ?? []).length;
|
|
72
|
+
i = end;
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
// String literal or quoted identifier: copied verbatim, terminators inside
|
|
76
|
+
// are just characters.
|
|
77
|
+
if (ch === "'" || ch === '"') {
|
|
78
|
+
const quote = ch;
|
|
79
|
+
let j = i + 1;
|
|
80
|
+
current += quote;
|
|
81
|
+
while (j < script.length) {
|
|
82
|
+
if (script[j] === quote) {
|
|
83
|
+
// A doubled quote is an escaped quote, not the end.
|
|
84
|
+
if (script[j + 1] === quote) {
|
|
85
|
+
current += quote + quote;
|
|
86
|
+
j += 2;
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
current += quote;
|
|
90
|
+
j++;
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
if (script[j] === '\n')
|
|
94
|
+
line++;
|
|
95
|
+
current += script[j];
|
|
96
|
+
j++;
|
|
97
|
+
}
|
|
98
|
+
i = j;
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
// SET TERM, only at the start of a statement.
|
|
102
|
+
if ((ch === 's' || ch === 'S') && current.trim() === '') {
|
|
103
|
+
const directive = matchSetTerm(script, i, terminator);
|
|
104
|
+
if (directive) {
|
|
105
|
+
line += (script.slice(i, directive.end).match(/\n/g) ?? []).length;
|
|
106
|
+
terminator = directive.newTerminator;
|
|
107
|
+
i = directive.end;
|
|
108
|
+
current = '';
|
|
109
|
+
statementLine = line;
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// Statement terminator.
|
|
114
|
+
if (script.startsWith(terminator, i)) {
|
|
115
|
+
i += terminator.length;
|
|
116
|
+
push();
|
|
117
|
+
statementLine = line;
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
if (ch === '\n') {
|
|
121
|
+
line++;
|
|
122
|
+
if (current.trim() === '')
|
|
123
|
+
statementLine = line;
|
|
124
|
+
}
|
|
125
|
+
current += ch;
|
|
126
|
+
i++;
|
|
127
|
+
}
|
|
128
|
+
// Trailing statement without a terminator.
|
|
129
|
+
push();
|
|
130
|
+
return statements;
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=sql-script.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sql-script.js","sourceRoot":"","sources":["../../src/browser/sql-script.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* worker-entry.ts – the Worker side of the engine.
|
|
3
|
+
*
|
|
4
|
+
* Bundle this as the Worker script:
|
|
5
|
+
*
|
|
6
|
+
* ```ts
|
|
7
|
+
* // firebird-engine-worker.ts
|
|
8
|
+
* import 'firebird-wasm/browser/worker-entry';
|
|
9
|
+
* ```
|
|
10
|
+
*
|
|
11
|
+
* ```ts
|
|
12
|
+
* // application code
|
|
13
|
+
* const worker = new Worker('/firebird-engine-worker.js');
|
|
14
|
+
* const db = new FirebirdBrowser('mydb', { worker });
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* The Worker owns the WASM module and therefore Emscripten's filesystem, so it
|
|
18
|
+
* serves filesystem requests too — persistence copies the database between
|
|
19
|
+
* that filesystem and IndexedDB, and only this side can read it.
|
|
20
|
+
*
|
|
21
|
+
* The page must be cross-origin isolated (COOP/COEP): Emscripten's pthreads
|
|
22
|
+
* need SharedArrayBuffer, which browsers withhold otherwise.
|
|
23
|
+
*/
|
|
24
|
+
import type { EngineTransport } from './engine-transport';
|
|
25
|
+
import type { EngineRequest } from './worker-protocol';
|
|
26
|
+
/**
|
|
27
|
+
* The part of a Worker's global scope this file uses.
|
|
28
|
+
*
|
|
29
|
+
* Declared structurally rather than using `DedicatedWorkerGlobalScope`, which
|
|
30
|
+
* lives in TypeScript's `WebWorker` lib — and that cannot be combined with
|
|
31
|
+
* `DOM` in one compilation without duplicate-declaration errors. A library
|
|
32
|
+
* shipping both browser and worker code has to avoid the clash.
|
|
33
|
+
*/
|
|
34
|
+
export interface EngineWorkerScope {
|
|
35
|
+
postMessage(message: unknown, transfer?: Transferable[]): void;
|
|
36
|
+
addEventListener(type: 'message', listener: (event: MessageEvent<EngineRequest>) => void): void;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Wire a transport up to a Worker scope.
|
|
40
|
+
*
|
|
41
|
+
* Exported so a host application can build its own Worker entry point — for
|
|
42
|
+
* example to set `locateFile` before any message is handled.
|
|
43
|
+
*/
|
|
44
|
+
export declare function serveEngine(scope: EngineWorkerScope, transport: EngineTransport): void;
|
|
45
|
+
//# sourceMappingURL=worker-entry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-entry.d.ts","sourceRoot":"","sources":["../../src/browser/worker-entry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAGH,OAAO,KAAK,EAA0B,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAClF,OAAO,KAAK,EAAE,aAAa,EAAkB,MAAM,mBAAmB,CAAC;AAEvE;;;;;;;GAOG;AACH,MAAM,WAAW,iBAAiB;IAChC,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC;IAC/D,gBAAgB,CACd,IAAI,EAAE,SAAS,EACf,QAAQ,EAAE,CAAC,KAAK,EAAE,YAAY,CAAC,aAAa,CAAC,KAAK,IAAI,GACrD,IAAI,CAAC;CACT;AAOD;;;;;GAKG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,iBAAiB,EACxB,SAAS,EAAE,eAAe,GACzB,IAAI,CAiCN"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* worker-entry.ts – the Worker side of the engine.
|
|
4
|
+
*
|
|
5
|
+
* Bundle this as the Worker script:
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* // firebird-engine-worker.ts
|
|
9
|
+
* import 'firebird-wasm/browser/worker-entry';
|
|
10
|
+
* ```
|
|
11
|
+
*
|
|
12
|
+
* ```ts
|
|
13
|
+
* // application code
|
|
14
|
+
* const worker = new Worker('/firebird-engine-worker.js');
|
|
15
|
+
* const db = new FirebirdBrowser('mydb', { worker });
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* The Worker owns the WASM module and therefore Emscripten's filesystem, so it
|
|
19
|
+
* serves filesystem requests too — persistence copies the database between
|
|
20
|
+
* that filesystem and IndexedDB, and only this side can read it.
|
|
21
|
+
*
|
|
22
|
+
* The page must be cross-origin isolated (COOP/COEP): Emscripten's pthreads
|
|
23
|
+
* need SharedArrayBuffer, which browsers withhold otherwise.
|
|
24
|
+
*/
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.serveEngine = serveEngine;
|
|
27
|
+
const engine_transport_1 = require("./engine-transport");
|
|
28
|
+
/**
|
|
29
|
+
* Wire a transport up to a Worker scope.
|
|
30
|
+
*
|
|
31
|
+
* Exported so a host application can build its own Worker entry point — for
|
|
32
|
+
* example to set `locateFile` before any message is handled.
|
|
33
|
+
*/
|
|
34
|
+
function serveEngine(scope, transport) {
|
|
35
|
+
const reply = (response) => {
|
|
36
|
+
// Transfer the buffer for readFile rather than copying it: a database
|
|
37
|
+
// image is measured in megabytes and this runs on every persist.
|
|
38
|
+
const transfer = response.result instanceof Uint8Array ? [response.result.buffer] : [];
|
|
39
|
+
scope.postMessage(response, transfer);
|
|
40
|
+
};
|
|
41
|
+
scope.addEventListener('message', (event) => {
|
|
42
|
+
const { id, op, args } = event.data;
|
|
43
|
+
void (async () => {
|
|
44
|
+
try {
|
|
45
|
+
// The op names are exactly the transport's method names, so this is a
|
|
46
|
+
// direct dispatch rather than a switch that has to be kept in step.
|
|
47
|
+
const fn = transport[op];
|
|
48
|
+
if (typeof fn !== 'function') {
|
|
49
|
+
throw new Error(`unknown engine operation: ${op}`);
|
|
50
|
+
}
|
|
51
|
+
const result = (await fn.apply(transport, args)) ?? null;
|
|
52
|
+
reply({ id, ok: true, result: result });
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
reply({
|
|
56
|
+
id,
|
|
57
|
+
ok: false,
|
|
58
|
+
error: err instanceof Error ? err.message : String(err),
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
})();
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
// Auto-start when loaded as a Worker script.
|
|
65
|
+
if (typeof self !== 'undefined' && typeof self.postMessage === 'function') {
|
|
66
|
+
try {
|
|
67
|
+
serveEngine(self, new engine_transport_1.DirectTransport(self.FIREBIRD_WORKER_OPTIONS ?? {}));
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
// No request to answer yet, so report the bootstrap failure out of band;
|
|
71
|
+
// WorkerTransport treats id -1 as "this worker is unusable".
|
|
72
|
+
self.postMessage({
|
|
73
|
+
id: -1,
|
|
74
|
+
ok: false,
|
|
75
|
+
error: err instanceof Error ? err.message : String(err),
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=worker-entry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-entry.js","sourceRoot":"","sources":["../../src/browser/worker-entry.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;;AAiCH,kCAoCC;AAnED,yDAAqD;AAyBrD;;;;;GAKG;AACH,SAAgB,WAAW,CACzB,KAAwB,EACxB,SAA0B;IAE1B,MAAM,KAAK,GAAG,CAAC,QAAwB,EAAQ,EAAE;QAC/C,sEAAsE;QACtE,iEAAiE;QACjE,MAAM,QAAQ,GACZ,QAAQ,CAAC,MAAM,YAAY,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACxE,KAAK,CAAC,WAAW,CAAC,QAAQ,EAAE,QAA0B,CAAC,CAAC;IAC1D,CAAC,CAAC;IAEF,KAAK,CAAC,gBAAgB,CAAC,SAAS,EAAE,CAAC,KAAkC,EAAE,EAAE;QACvE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC;QAEpC,KAAK,CAAC,KAAK,IAAI,EAAE;YACf,IAAI,CAAC;gBACH,sEAAsE;gBACtE,oEAAoE;gBACpE,MAAM,EAAE,GAAI,SAA8E,CAAC,EAAE,CAAC,CAAC;gBAE/F,IAAI,OAAO,EAAE,KAAK,UAAU,EAAE,CAAC;oBAC7B,MAAM,IAAI,KAAK,CAAC,6BAA6B,EAAE,EAAE,CAAC,CAAC;gBACrD,CAAC;gBAED,MAAM,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC;gBACzD,KAAK,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAkC,EAAE,CAAC,CAAC;YACtE,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,KAAK,CAAC;oBACJ,EAAE;oBACF,EAAE,EAAE,KAAK;oBACT,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;iBACxD,CAAC,CAAC;YACL,CAAC;QACH,CAAC,CAAC,EAAE,CAAC;IACP,CAAC,CAAC,CAAC;AACL,CAAC;AAED,6CAA6C;AAC7C,IAAI,OAAO,IAAI,KAAK,WAAW,IAAI,OAAO,IAAI,CAAC,WAAW,KAAK,UAAU,EAAE,CAAC;IAC1E,IAAI,CAAC;QACH,WAAW,CAAC,IAAI,EAAE,IAAI,kCAAe,CAAC,IAAI,CAAC,uBAAuB,IAAI,EAAE,CAAC,CAAC,CAAC;IAC7E,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,yEAAyE;QACzE,6DAA6D;QAC7D,IAAI,CAAC,WAAW,CAAC;YACf,EAAE,EAAE,CAAC,CAAC;YACN,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;SACxD,CAAC,CAAC;IACL,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* worker-protocol.ts – the messages exchanged with the engine Worker.
|
|
3
|
+
*
|
|
4
|
+
* Shared by both ends so the request and response shapes cannot drift apart.
|
|
5
|
+
* Every request carries an `id`; the reply quotes it, which is what lets
|
|
6
|
+
* several calls be in flight at once.
|
|
7
|
+
*/
|
|
8
|
+
import type { Row, QueryResult } from '../types';
|
|
9
|
+
import type { EngineHandle } from './engine-transport';
|
|
10
|
+
/** Operations the Worker understands. One per EngineTransport method. */
|
|
11
|
+
export type EngineOp = 'init' | 'createDatabase' | 'attachDatabase' | 'detachDatabase' | 'execute' | 'query' | 'startTransaction' | 'commit' | 'rollback' | 'mkdir' | 'exists' | 'readFile' | 'writeFile';
|
|
12
|
+
/** A call from the main thread to the Worker. */
|
|
13
|
+
export interface EngineRequest {
|
|
14
|
+
id: number;
|
|
15
|
+
op: EngineOp;
|
|
16
|
+
args: unknown[];
|
|
17
|
+
}
|
|
18
|
+
/** The Worker's reply. Exactly one of `result` / `error` is meaningful. */
|
|
19
|
+
export interface EngineResponse {
|
|
20
|
+
id: number;
|
|
21
|
+
ok: boolean;
|
|
22
|
+
/** Present when `ok`. */
|
|
23
|
+
result?: EngineHandle | number | boolean | Uint8Array | QueryResult<Row> | null;
|
|
24
|
+
/**
|
|
25
|
+
* Present when not `ok`. A string rather than an Error because structured
|
|
26
|
+
* cloning drops the prototype and the stack is the Worker's, not the
|
|
27
|
+
* caller's — the message is the part worth keeping.
|
|
28
|
+
*/
|
|
29
|
+
error?: string;
|
|
30
|
+
}
|
|
31
|
+
/** Sent once when the Worker's own bootstrap fails, without a request to quote. */
|
|
32
|
+
export interface EngineFatal {
|
|
33
|
+
id: -1;
|
|
34
|
+
ok: false;
|
|
35
|
+
error: string;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=worker-protocol.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-protocol.d.ts","sourceRoot":"","sources":["../../src/browser/worker-protocol.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,0EAA0E;AAC1E,MAAM,MAAM,QAAQ,GAChB,MAAM,GACN,gBAAgB,GAChB,gBAAgB,GAChB,gBAAgB,GAChB,SAAS,GACT,OAAO,GACP,kBAAkB,GAClB,QAAQ,GACR,UAAU,GACV,OAAO,GACP,QAAQ,GACR,UAAU,GACV,WAAW,CAAC;AAEhB,iDAAiD;AACjD,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,QAAQ,CAAC;IACb,IAAI,EAAE,OAAO,EAAE,CAAC;CACjB;AAED,4EAA4E;AAC5E,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,OAAO,CAAC;IACZ,yBAAyB;IACzB,MAAM,CAAC,EAAE,YAAY,GAAG,MAAM,GAAG,OAAO,GAAG,UAAU,GAAG,WAAW,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;IAChF;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,mFAAmF;AACnF,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,CAAC,CAAC,CAAC;IACP,EAAE,EAAE,KAAK,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;CACf"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* worker-protocol.ts – the messages exchanged with the engine Worker.
|
|
4
|
+
*
|
|
5
|
+
* Shared by both ends so the request and response shapes cannot drift apart.
|
|
6
|
+
* Every request carries an `id`; the reply quotes it, which is what lets
|
|
7
|
+
* several calls be in flight at once.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
//# sourceMappingURL=worker-protocol.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-protocol.js","sourceRoot":"","sources":["../../src/browser/worker-protocol.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* worker-transport.ts – reaches the engine running in a Web Worker.
|
|
3
|
+
*
|
|
4
|
+
* Browsers have to use this. The build uses pthreads, Firebird blocks on
|
|
5
|
+
* mutexes while opening a database, and a browser main thread is not allowed
|
|
6
|
+
* to block, so calling the engine from a page deadlocks. Inside a Worker
|
|
7
|
+
* blocking is fine.
|
|
8
|
+
*
|
|
9
|
+
* The Worker also owns Emscripten's filesystem, which is why the filesystem
|
|
10
|
+
* operations are part of the transport rather than being done by the caller.
|
|
11
|
+
*/
|
|
12
|
+
import type { Row, QueryResult, QueryParams } from '../types';
|
|
13
|
+
import type { EngineHandle, EngineTransport } from './engine-transport';
|
|
14
|
+
/** Options accepted by {@link WorkerTransport}. */
|
|
15
|
+
export interface WorkerTransportOptions {
|
|
16
|
+
/**
|
|
17
|
+
* How long to wait for a single call before rejecting, in milliseconds.
|
|
18
|
+
*
|
|
19
|
+
* Creating a database is slow — the engine writes the whole system
|
|
20
|
+
* catalogue — so this is generous by default. Without a timeout a Worker
|
|
21
|
+
* that dies mid-call would leave the caller waiting forever.
|
|
22
|
+
*
|
|
23
|
+
* @default 120000
|
|
24
|
+
*/
|
|
25
|
+
timeoutMs?: number;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Forwards {@link EngineTransport} calls to a Worker over `postMessage`.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```ts
|
|
32
|
+
* const worker = new Worker('/firebird-engine-worker.js');
|
|
33
|
+
* const db = new FirebirdBrowser('mydb', { worker });
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export declare class WorkerTransport implements EngineTransport {
|
|
37
|
+
private readonly worker;
|
|
38
|
+
private readonly timeoutMs;
|
|
39
|
+
private readonly pending;
|
|
40
|
+
private nextId;
|
|
41
|
+
private failure;
|
|
42
|
+
constructor(worker: Worker, options?: WorkerTransportOptions);
|
|
43
|
+
private readonly onMessage;
|
|
44
|
+
private readonly onError;
|
|
45
|
+
/** Reject everything outstanding and refuse further calls. */
|
|
46
|
+
private fail;
|
|
47
|
+
private call;
|
|
48
|
+
init(): Promise<void>;
|
|
49
|
+
createDatabase(path: string): Promise<EngineHandle>;
|
|
50
|
+
attachDatabase(path: string): Promise<EngineHandle>;
|
|
51
|
+
detachDatabase(dbHandle: EngineHandle): Promise<void>;
|
|
52
|
+
execute(dbHandle: EngineHandle, txHandle: EngineHandle, sql: string, params?: QueryParams): Promise<number>;
|
|
53
|
+
query<T extends Row = Row>(dbHandle: EngineHandle, txHandle: EngineHandle, sql: string, params?: QueryParams): Promise<QueryResult<T>>;
|
|
54
|
+
startTransaction(dbHandle: EngineHandle): Promise<EngineHandle>;
|
|
55
|
+
commit(txHandle: EngineHandle): Promise<void>;
|
|
56
|
+
rollback(txHandle: EngineHandle): Promise<void>;
|
|
57
|
+
mkdir(path: string): Promise<void>;
|
|
58
|
+
exists(path: string): Promise<boolean>;
|
|
59
|
+
readFile(path: string): Promise<Uint8Array>;
|
|
60
|
+
writeFile(path: string, data: Uint8Array): Promise<void>;
|
|
61
|
+
dispose(): Promise<void>;
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=worker-transport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-transport.d.ts","sourceRoot":"","sources":["../../src/browser/worker-transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAGxE,mDAAmD;AACnD,MAAM,WAAW,sBAAsB;IACrC;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAUD;;;;;;;;GAQG;AACH,qBAAa,eAAgB,YAAW,eAAe;IACrD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA8B;IACtD,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,OAAO,CAAsB;gBAEzB,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,sBAA2B;IAQhE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAqBxB;IAEF,OAAO,CAAC,QAAQ,CAAC,OAAO,CAEtB;IAEF,8DAA8D;IAC9D,OAAO,CAAC,IAAI;IASZ,OAAO,CAAC,IAAI;IAwBZ,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAIrB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAInD,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAInD,cAAc,CAAC,QAAQ,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAIrD,OAAO,CACL,QAAQ,EAAE,YAAY,EACtB,QAAQ,EAAE,YAAY,EACtB,GAAG,EAAE,MAAM,EACX,MAAM,GAAE,WAAgB,GACvB,OAAO,CAAC,MAAM,CAAC;IAIlB,KAAK,CAAC,CAAC,SAAS,GAAG,GAAG,GAAG,EACvB,QAAQ,EAAE,YAAY,EACtB,QAAQ,EAAE,YAAY,EACtB,GAAG,EAAE,MAAM,EACX,MAAM,GAAE,WAAgB,GACvB,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IAI1B,gBAAgB,CAAC,QAAQ,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;IAI/D,MAAM,CAAC,QAAQ,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAI7C,QAAQ,CAAC,QAAQ,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAI/C,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAItC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAI3C,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlD,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAM/B"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* worker-transport.ts – reaches the engine running in a Web Worker.
|
|
4
|
+
*
|
|
5
|
+
* Browsers have to use this. The build uses pthreads, Firebird blocks on
|
|
6
|
+
* mutexes while opening a database, and a browser main thread is not allowed
|
|
7
|
+
* to block, so calling the engine from a page deadlocks. Inside a Worker
|
|
8
|
+
* blocking is fine.
|
|
9
|
+
*
|
|
10
|
+
* The Worker also owns Emscripten's filesystem, which is why the filesystem
|
|
11
|
+
* operations are part of the transport rather than being done by the caller.
|
|
12
|
+
*/
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.WorkerTransport = void 0;
|
|
15
|
+
const DEFAULT_TIMEOUT_MS = 120000;
|
|
16
|
+
/**
|
|
17
|
+
* Forwards {@link EngineTransport} calls to a Worker over `postMessage`.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* const worker = new Worker('/firebird-engine-worker.js');
|
|
22
|
+
* const db = new FirebirdBrowser('mydb', { worker });
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
class WorkerTransport {
|
|
26
|
+
constructor(worker, options = {}) {
|
|
27
|
+
this.pending = new Map();
|
|
28
|
+
this.nextId = 1;
|
|
29
|
+
this.failure = null;
|
|
30
|
+
this.onMessage = (event) => {
|
|
31
|
+
const data = event.data;
|
|
32
|
+
// id -1 is the Worker reporting that its own bootstrap failed; there is no
|
|
33
|
+
// request to answer, so fail everything outstanding and everything later.
|
|
34
|
+
if (data.id === -1) {
|
|
35
|
+
this.fail(new Error(data.error ?? 'engine worker failed to start'));
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const entry = this.pending.get(data.id);
|
|
39
|
+
if (!entry)
|
|
40
|
+
return; // already timed out, or a stray reply
|
|
41
|
+
this.pending.delete(data.id);
|
|
42
|
+
clearTimeout(entry.timer);
|
|
43
|
+
if (data.ok) {
|
|
44
|
+
entry.resolve(data.result);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
entry.reject(new Error(data.error ?? 'engine worker returned an error'));
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
this.onError = (event) => {
|
|
51
|
+
this.fail(new Error(`engine worker error: ${event.message}`));
|
|
52
|
+
};
|
|
53
|
+
this.worker = worker;
|
|
54
|
+
this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
55
|
+
this.worker.addEventListener('message', this.onMessage);
|
|
56
|
+
this.worker.addEventListener('error', this.onError);
|
|
57
|
+
}
|
|
58
|
+
/** Reject everything outstanding and refuse further calls. */
|
|
59
|
+
fail(error) {
|
|
60
|
+
this.failure = error;
|
|
61
|
+
for (const [, entry] of this.pending) {
|
|
62
|
+
clearTimeout(entry.timer);
|
|
63
|
+
entry.reject(error);
|
|
64
|
+
}
|
|
65
|
+
this.pending.clear();
|
|
66
|
+
}
|
|
67
|
+
call(op, ...args) {
|
|
68
|
+
if (this.failure) {
|
|
69
|
+
return Promise.reject(this.failure);
|
|
70
|
+
}
|
|
71
|
+
const id = this.nextId++;
|
|
72
|
+
const request = { id, op, args };
|
|
73
|
+
return new Promise((resolve, reject) => {
|
|
74
|
+
const timer = setTimeout(() => {
|
|
75
|
+
this.pending.delete(id);
|
|
76
|
+
reject(new Error(`engine worker timed out after ${this.timeoutMs}ms: ${op}`));
|
|
77
|
+
}, this.timeoutMs);
|
|
78
|
+
this.pending.set(id, {
|
|
79
|
+
resolve: resolve,
|
|
80
|
+
reject,
|
|
81
|
+
timer,
|
|
82
|
+
});
|
|
83
|
+
this.worker.postMessage(request);
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
init() {
|
|
87
|
+
return this.call('init');
|
|
88
|
+
}
|
|
89
|
+
createDatabase(path) {
|
|
90
|
+
return this.call('createDatabase', path);
|
|
91
|
+
}
|
|
92
|
+
attachDatabase(path) {
|
|
93
|
+
return this.call('attachDatabase', path);
|
|
94
|
+
}
|
|
95
|
+
detachDatabase(dbHandle) {
|
|
96
|
+
return this.call('detachDatabase', dbHandle);
|
|
97
|
+
}
|
|
98
|
+
execute(dbHandle, txHandle, sql, params = []) {
|
|
99
|
+
return this.call('execute', dbHandle, txHandle, sql, params);
|
|
100
|
+
}
|
|
101
|
+
query(dbHandle, txHandle, sql, params = []) {
|
|
102
|
+
return this.call('query', dbHandle, txHandle, sql, params);
|
|
103
|
+
}
|
|
104
|
+
startTransaction(dbHandle) {
|
|
105
|
+
return this.call('startTransaction', dbHandle);
|
|
106
|
+
}
|
|
107
|
+
commit(txHandle) {
|
|
108
|
+
return this.call('commit', txHandle);
|
|
109
|
+
}
|
|
110
|
+
rollback(txHandle) {
|
|
111
|
+
return this.call('rollback', txHandle);
|
|
112
|
+
}
|
|
113
|
+
mkdir(path) {
|
|
114
|
+
return this.call('mkdir', path);
|
|
115
|
+
}
|
|
116
|
+
exists(path) {
|
|
117
|
+
return this.call('exists', path);
|
|
118
|
+
}
|
|
119
|
+
readFile(path) {
|
|
120
|
+
return this.call('readFile', path);
|
|
121
|
+
}
|
|
122
|
+
writeFile(path, data) {
|
|
123
|
+
return this.call('writeFile', path, data);
|
|
124
|
+
}
|
|
125
|
+
async dispose() {
|
|
126
|
+
this.worker.removeEventListener('message', this.onMessage);
|
|
127
|
+
this.worker.removeEventListener('error', this.onError);
|
|
128
|
+
this.fail(new Error('engine worker disposed'));
|
|
129
|
+
this.worker.terminate();
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
exports.WorkerTransport = WorkerTransport;
|
|
133
|
+
//# sourceMappingURL=worker-transport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-transport.js","sourceRoot":"","sources":["../../src/browser/worker-transport.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { Attachment, Transaction } from 'node-firebird-driver';
|
|
2
|
+
import type { FirebirdLiteOptions, QueryResult, Row, QueryParams, TransactionOptions } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* FirebirdLite – a PGlite-style wrapper around Firebird Embedded.
|
|
5
|
+
*
|
|
6
|
+
* Provides a simple async API for running SQL against a Firebird database
|
|
7
|
+
* using the Firebird embedded engine (single-process mode).
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* const db = new FirebirdLite('/tmp/my-database.fdb');
|
|
12
|
+
* await db.exec('CREATE TABLE t (id INTEGER, name VARCHAR(100))');
|
|
13
|
+
* await db.query('INSERT INTO t VALUES (?, ?)', [1, 'hello']);
|
|
14
|
+
* const result = await db.query('SELECT * FROM t');
|
|
15
|
+
* // { rows: [ { ID: 1, NAME: 'hello' } ], fields: [...] }
|
|
16
|
+
* await db.close();
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export declare class FirebirdLite {
|
|
20
|
+
private readonly dbPath;
|
|
21
|
+
private readonly libraryPath;
|
|
22
|
+
private readonly connectOptions;
|
|
23
|
+
private client;
|
|
24
|
+
private attachment;
|
|
25
|
+
private closed;
|
|
26
|
+
constructor(dbPath: string, options?: FirebirdLiteOptions);
|
|
27
|
+
/**
|
|
28
|
+
* Lazily initialize the native client and open (or create) the database.
|
|
29
|
+
*/
|
|
30
|
+
private ensureReady;
|
|
31
|
+
/**
|
|
32
|
+
* Execute a DDL or DML statement that does not return rows.
|
|
33
|
+
*
|
|
34
|
+
* The statement is executed in its own auto-committed transaction.
|
|
35
|
+
*/
|
|
36
|
+
exec(sql: string): Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Execute a (parameterised) SQL statement and return the result rows.
|
|
39
|
+
*
|
|
40
|
+
* For SELECT queries the rows are returned as plain objects keyed by the
|
|
41
|
+
* (upper-cased) column name, mirroring the PGlite convention.
|
|
42
|
+
*/
|
|
43
|
+
query<T extends Row = Row>(sql: string, params?: QueryParams, options?: TransactionOptions): Promise<QueryResult<T>>;
|
|
44
|
+
/**
|
|
45
|
+
* Run a function inside an explicit transaction.
|
|
46
|
+
*
|
|
47
|
+
* The transaction is automatically committed on success or rolled back on
|
|
48
|
+
* error.
|
|
49
|
+
*/
|
|
50
|
+
transaction<T>(fn: (tx: FirebirdTransaction) => Promise<T>, options?: TransactionOptions): Promise<T>;
|
|
51
|
+
/**
|
|
52
|
+
* Close the database connection and release all resources.
|
|
53
|
+
*/
|
|
54
|
+
close(): Promise<void>;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* A handle to an active Firebird transaction, exposed to callers of
|
|
58
|
+
* `FirebirdLite.transaction()`.
|
|
59
|
+
*/
|
|
60
|
+
export declare class FirebirdTransaction {
|
|
61
|
+
private readonly attachment;
|
|
62
|
+
private readonly transaction;
|
|
63
|
+
constructor(attachment: Attachment, transaction: Transaction);
|
|
64
|
+
/**
|
|
65
|
+
* Execute a DDL or DML statement inside this transaction.
|
|
66
|
+
*/
|
|
67
|
+
exec(sql: string, params?: QueryParams): Promise<void>;
|
|
68
|
+
/**
|
|
69
|
+
* Execute a SELECT statement inside this transaction and return rows.
|
|
70
|
+
*/
|
|
71
|
+
query<T extends Row = Row>(sql: string, params?: QueryParams): Promise<QueryResult<T>>;
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=firebird.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"firebird.d.ts","sourceRoot":"","sources":["../src/firebird.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAEV,UAAU,EACV,WAAW,EAEZ,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EACV,mBAAmB,EACnB,WAAW,EACX,GAAG,EACH,WAAW,EACX,kBAAkB,EAEnB,MAAM,SAAS,CAAC;AAEjB;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAoE;IACnG,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,UAAU,CAA2B;IAC7C,OAAO,CAAC,MAAM,CAAS;gBAEX,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,mBAAwB;IAU7D;;OAEG;YACW,WAAW;IAgBzB;;;;OAIG;IACG,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAatC;;;;;OAKG;IACG,KAAK,CAAC,CAAC,SAAS,GAAG,GAAG,GAAG,EAC7B,GAAG,EAAE,MAAM,EACX,MAAM,GAAE,WAAgB,EACxB,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IAqC1B;;;;;OAKG;IACG,WAAW,CAAC,CAAC,EACjB,EAAE,EAAE,CAAC,EAAE,EAAE,mBAAmB,KAAK,OAAO,CAAC,CAAC,CAAC,EAC3C,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,CAAC,CAAC;IAkBb;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAa7B;AAED;;;GAGG;AACH,qBAAa,mBAAmB;IAE5B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,WAAW;gBADX,UAAU,EAAE,UAAU,EACtB,WAAW,EAAE,WAAW;IAG3C;;OAEG;IACG,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,GAAE,WAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAahE;;OAEG;IACG,KAAK,CAAC,CAAC,SAAS,GAAG,GAAG,GAAG,EAC7B,GAAG,EAAE,MAAM,EACX,MAAM,GAAE,WAAgB,GACvB,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;CAkB3B"}
|