@zmdb/sqlite 1.0.0-beta.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/LICENSE +674 -0
- package/README.md +108 -0
- package/dist/dialect.d.ts +2 -0
- package/dist/dialect.d.ts.map +1 -0
- package/dist/dialect.js +93 -0
- package/dist/dialect.js.map +1 -0
- package/dist/driver.d.ts +21 -0
- package/dist/driver.d.ts.map +1 -0
- package/dist/driver.js +133 -0
- package/dist/driver.js.map +1 -0
- package/dist/embedded.d.ts +3 -0
- package/dist/embedded.d.ts.map +1 -0
- package/dist/embedded.js +2 -0
- package/dist/embedded.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/introspector.d.ts +5 -0
- package/dist/introspector.d.ts.map +1 -0
- package/dist/introspector.js +392 -0
- package/dist/introspector.js.map +1 -0
- package/dist/migrations.d.ts +3 -0
- package/dist/migrations.d.ts.map +1 -0
- package/dist/migrations.js +349 -0
- package/dist/migrations.js.map +1 -0
- package/dist/node.d.ts +2 -0
- package/dist/node.d.ts.map +1 -0
- package/dist/node.js +2 -0
- package/dist/node.js.map +1 -0
- package/package.json +61 -0
- package/src/dialect.ts +95 -0
- package/src/driver.ts +158 -0
- package/src/embedded.ts +2 -0
- package/src/index.ts +14 -0
- package/src/introspector.ts +513 -0
- package/src/migrations.ts +500 -0
- package/src/node.ts +1 -0
package/README.md
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# @zmdb/sqlite
|
|
2
|
+
|
|
3
|
+
The SQLite vertical owns the immutable `sqlite` dialect, its migration hooks and catalog introspector, and the `sqliteDriver` adapter. The shared query compiler comes from `@zmdb/sql`; repository and
|
|
4
|
+
driver contracts come from `@zmdb/orm`. `sqliteVertical` pairs this dialect with its driver factory.
|
|
5
|
+
|
|
6
|
+
## Install
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
yarn add @zmdb/sqlite@1.0.0-beta.1 @zmdb/sql@1.0.0-beta.1 @zmdb/migrations@1.0.0-beta.1
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
For the TypeScript snippets, install the declaration inputs used by the packed consumer:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
yarn add --dev typescript@7.0.2 @types/node@26.4.1
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Use Node.js 26+ and ESM. Keep the required `@zmdb/sql` and `@zmdb/orm` peers aligned with this package's version; npm resolves those peers. An application already using `zmdb` adds its selected
|
|
19
|
+
database package and client rather than replacing the product facade.
|
|
20
|
+
|
|
21
|
+
The only runtime dependency is `@zmdb/migrations`; `@zmdb/sql` and `@zmdb/orm` are required same-version peers. No third-party database client is installed.
|
|
22
|
+
|
|
23
|
+
## Configure
|
|
24
|
+
|
|
25
|
+
The snippets below are successive steps in one module.
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
import { DatabaseSync } from 'node:sqlite';
|
|
29
|
+
import { sqlite, sqliteDriver } from '@zmdb/sqlite';
|
|
30
|
+
|
|
31
|
+
const client = new DatabaseSync(':memory:');
|
|
32
|
+
const driver = sqliteDriver(client);
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The application owns the client and closes it with `client.close()` in a `finally` block after its work. Hosted services that accept this client's protocol are connection recipes, not additional
|
|
36
|
+
official database packages or automatically qualified server variants.
|
|
37
|
+
|
|
38
|
+
## Compile
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
import { createQueryCompiler } from '@zmdb/sql';
|
|
42
|
+
|
|
43
|
+
const compiler = createQueryCompiler(sqlite);
|
|
44
|
+
const query = compiler.selectFrom('users').where('id', '=', 7).compile();
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Compilation is pure: the result carries SQL text and a separate parameter array. It does not create the `users` table or open a connection.
|
|
48
|
+
|
|
49
|
+
## Migrate
|
|
50
|
+
|
|
51
|
+
Use `sqlite.migrations.emitUp(operation)` to obtain this database's DDL and `sqlite.migrations.connection(driver)` to create its migration connection. Pass reviewed migration records to `up` and
|
|
52
|
+
`down` from `@zmdb/migrations`; transactional behavior follows the capability table below. The [complete installed workflow](../../fixtures/consumer-database-publication/runtime.mjs) creates a fresh
|
|
53
|
+
table, applies and rolls back its migration, and closes the supplied client.
|
|
54
|
+
|
|
55
|
+
## Introspect
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
const snapshot = await sqlite.introspector.snapshot(driver);
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
The snapshot comes from the selected database's real catalog through the same driver. `sqliteIntrospector` is also exported directly. Introspection and generated DDL use this vertical's semantics.
|
|
62
|
+
|
|
63
|
+
## Execute
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
const rows = await driver.execute(query);
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Run this after migrating or otherwise creating the table. Use `driver.transaction(async transaction => ...)` for a pinned transactional driver; the application decides whether to retry. Query values
|
|
70
|
+
travel as parameters, not SQL string interpolation.
|
|
71
|
+
|
|
72
|
+
## Capabilities
|
|
73
|
+
|
|
74
|
+
These entries describe `sqlite.capabilities`; a true entry can still require the client support described below.
|
|
75
|
+
|
|
76
|
+
| Capability | Advertised support |
|
|
77
|
+
| ------------------------------------- | ------------------ |
|
|
78
|
+
| INSERT/upsert/UPDATE/DELETE returning | yes |
|
|
79
|
+
| Transactional DDL | yes |
|
|
80
|
+
| Schemas | no |
|
|
81
|
+
| Sequences | no |
|
|
82
|
+
| Generated columns | yes |
|
|
83
|
+
| Partial indexes | yes |
|
|
84
|
+
| Foreign keys | yes |
|
|
85
|
+
| Row-level security | no |
|
|
86
|
+
| Streaming | yes |
|
|
87
|
+
| Server-side cancellation | no |
|
|
88
|
+
|
|
89
|
+
## Refusals and ownership
|
|
90
|
+
|
|
91
|
+
Schemas, standalone sequences and row-level security are unsupported. SQLite table changes that need a rebuild must use the migration planner; the adapter does not pretend an unsupported `ALTER TABLE`
|
|
92
|
+
is available. Streaming iterates the supplied statement; cancellation of an executing query is not advertised.
|
|
93
|
+
|
|
94
|
+
SQLite owns its dialect, migration hooks and introspector. The root, `/node` and `/embedded` entries import no Node built-in or database client; the application supplies the binding. `/embedded`
|
|
95
|
+
exposes the SQLite embedded migration runner.
|
|
96
|
+
|
|
97
|
+
## Testing evidence
|
|
98
|
+
|
|
99
|
+
The [database publication qualification](../../fixtures/consumer-database-publication) builds real npm archives and installs this selected package in an independent consumer. Its public workflow
|
|
100
|
+
covers strict declarations, package/client ownership, parameterized CRUD, transaction rollback, migration application/rollback and catalog introspection. The
|
|
101
|
+
[SQLite consumer](../../fixtures/database-sqlite) adds the database-specific capability and refusal checks.
|
|
102
|
+
|
|
103
|
+
Issue [#676](https://github.com/ambasta/zmdb/issues/676) records the completed installed workflows. Those observations are scoped to their recorded clients and servers; they do not certify every
|
|
104
|
+
compatible hosted service. Qualification reports identify their source, archive and server inputs. See the [SQLite guide](../../docs-site/content/dialect-sqlite.md) for the detailed contract.
|
|
105
|
+
|
|
106
|
+
## License
|
|
107
|
+
|
|
108
|
+
GNU General Public License v3.0 or later (GPL-3.0-or-later) — see [LICENSE](./LICENSE).
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dialect.d.ts","sourceRoot":"","sources":["../src/dialect.ts"],"names":[],"mappings":"AAgDA,eAAO,MAAM,MAAM,0CA8CjB,CAAC"}
|
package/dist/dialect.js
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { defineSqlDialect } from '@zmdb/sql';
|
|
2
|
+
import { sqliteIntrospector } from './introspector.js';
|
|
3
|
+
import { sqliteMigrations } from './migrations.js';
|
|
4
|
+
const TYPES = Object.freeze({
|
|
5
|
+
serial: 'INTEGER',
|
|
6
|
+
integer: 'INTEGER',
|
|
7
|
+
bigint: 'INTEGER',
|
|
8
|
+
numeric: 'NUMERIC',
|
|
9
|
+
text: 'TEXT',
|
|
10
|
+
varchar: 'TEXT',
|
|
11
|
+
boolean: 'INTEGER',
|
|
12
|
+
timestamp: 'TEXT',
|
|
13
|
+
json: 'TEXT',
|
|
14
|
+
jsonEnum: 'TEXT',
|
|
15
|
+
});
|
|
16
|
+
const OPERATOR_TOKEN = /^(?!.*--)[A-Za-z@<>=!~*&|?-]{1,4}$/;
|
|
17
|
+
function acceptsOperator(operator) {
|
|
18
|
+
if (operator === '#>' || operator === '#>>')
|
|
19
|
+
return false;
|
|
20
|
+
if (!OPERATOR_TOKEN.test(operator))
|
|
21
|
+
return false;
|
|
22
|
+
return !operator.includes('?');
|
|
23
|
+
}
|
|
24
|
+
function paginate({ limit, offset }) {
|
|
25
|
+
let text = '';
|
|
26
|
+
if (limit !== undefined)
|
|
27
|
+
text += ` LIMIT ${String(limit)}`;
|
|
28
|
+
else if (offset !== undefined)
|
|
29
|
+
text += ' LIMIT -1';
|
|
30
|
+
if (offset !== undefined)
|
|
31
|
+
text += ` OFFSET ${String(offset)}`;
|
|
32
|
+
return text;
|
|
33
|
+
}
|
|
34
|
+
const suffixReturning = Object.freeze({
|
|
35
|
+
insert: 'suffix',
|
|
36
|
+
upsert: 'suffix',
|
|
37
|
+
update: 'suffix',
|
|
38
|
+
delete: 'suffix',
|
|
39
|
+
});
|
|
40
|
+
const returningCapabilities = Object.freeze({
|
|
41
|
+
insert: true,
|
|
42
|
+
upsert: true,
|
|
43
|
+
update: true,
|
|
44
|
+
delete: true,
|
|
45
|
+
});
|
|
46
|
+
export const sqlite = defineSqlDialect({
|
|
47
|
+
name: 'sqlite',
|
|
48
|
+
family: 'sqlite',
|
|
49
|
+
telemetrySystem: 'sqlite',
|
|
50
|
+
traits: {
|
|
51
|
+
placeholder: 'positional',
|
|
52
|
+
quote: Object.freeze(['"', '"']),
|
|
53
|
+
paginate,
|
|
54
|
+
paginationRequiresOrder: false,
|
|
55
|
+
rowValueIn: true,
|
|
56
|
+
returning: suffixReturning,
|
|
57
|
+
upsert: 'onConflict',
|
|
58
|
+
fts: 'companionTable',
|
|
59
|
+
concat: 'operator',
|
|
60
|
+
booleanNot: 'not',
|
|
61
|
+
types: TYPES,
|
|
62
|
+
paramLimit: 30_000,
|
|
63
|
+
retryableCodes: Object.freeze([]),
|
|
64
|
+
acceptsOperator,
|
|
65
|
+
functions: false,
|
|
66
|
+
procedures: false,
|
|
67
|
+
tableFunctions: false,
|
|
68
|
+
vectorDistance: false,
|
|
69
|
+
spatialPredicates: false,
|
|
70
|
+
},
|
|
71
|
+
capabilities: {
|
|
72
|
+
returning: returningCapabilities,
|
|
73
|
+
transactionalDdl: true,
|
|
74
|
+
schemas: false,
|
|
75
|
+
sequences: false,
|
|
76
|
+
generatedColumns: true,
|
|
77
|
+
partialIndexes: true,
|
|
78
|
+
foreignKeys: true,
|
|
79
|
+
rowLevelSecurity: false,
|
|
80
|
+
streaming: true,
|
|
81
|
+
cancellation: false,
|
|
82
|
+
},
|
|
83
|
+
migrations: sqliteMigrations,
|
|
84
|
+
introspector: sqliteIntrospector,
|
|
85
|
+
outbox: Object.freeze({
|
|
86
|
+
createTable: 'CREATE TABLE',
|
|
87
|
+
pendingIndex: 'filtered',
|
|
88
|
+
epochLiteral: "'1970-01-01T00:00:00.000Z'",
|
|
89
|
+
createdAtDefault: "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))",
|
|
90
|
+
boundedTextType: () => 'TEXT',
|
|
91
|
+
}),
|
|
92
|
+
});
|
|
93
|
+
//# sourceMappingURL=dialect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dialect.js","sourceRoot":"","sources":["../src/dialect.ts"],"names":[],"mappings":"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"}
|
package/dist/driver.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type TransactionalDriver } from '@zmdb/orm';
|
|
2
|
+
export interface SqliteStatement {
|
|
3
|
+
/** Returns rows for a row-returning statement such as SELECT, PRAGMA or RETURNING. */
|
|
4
|
+
all(...params: unknown[]): unknown[];
|
|
5
|
+
/** Describes result columns without executing the statement (`node:sqlite` provides this). */
|
|
6
|
+
columns?(): readonly unknown[];
|
|
7
|
+
/** Executes a non-returning statement. */
|
|
8
|
+
run(...params: unknown[]): unknown;
|
|
9
|
+
/** Steps a row-returning statement without materialising the result. */
|
|
10
|
+
iterate(...params: unknown[]): Iterable<Record<string, unknown>>;
|
|
11
|
+
}
|
|
12
|
+
export interface SqliteDatabase {
|
|
13
|
+
exec(sql: string): unknown;
|
|
14
|
+
prepare(sql: string): SqliteStatement;
|
|
15
|
+
}
|
|
16
|
+
export interface SqliteOptions {
|
|
17
|
+
maxCacheSize?: number;
|
|
18
|
+
}
|
|
19
|
+
/** Wrap a node:sqlite DatabaseSync as a zmdb Driver. Zero external deps. */
|
|
20
|
+
export declare function sqliteDriver(db: SqliteDatabase, opts?: SqliteOptions): TransactionalDriver<'sqlite'>;
|
|
21
|
+
//# sourceMappingURL=driver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"driver.d.ts","sourceRoot":"","sources":["../src/driver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAO1E,MAAM,WAAW,eAAe;IAC9B,sFAAsF;IACtF,GAAG,CAAC,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,EAAE,CAAC;IACrC,8FAA8F;IAC9F,OAAO,CAAC,IAAI,SAAS,OAAO,EAAE,CAAC;IAC/B,0CAA0C;IAC1C,GAAG,CAAC,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;IACnC,wEAAwE;IACxE,OAAO,CAAC,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAClE;AACD,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAC3B,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,CAAC;CACvC;AAED,MAAM,WAAW,aAAa;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AA+BD,4EAA4E;AAC5E,wBAAgB,YAAY,CAAC,EAAE,EAAE,cAAc,EAAE,IAAI,CAAC,EAAE,aAAa,GAAG,mBAAmB,CAAC,QAAQ,CAAC,CAqGpG"}
|
package/dist/driver.js
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import {} from '@zmdb/orm';
|
|
2
|
+
import { sqlite } from './dialect.js';
|
|
3
|
+
/**
|
|
4
|
+
* The app→db crossing for SQLite (plan D3).
|
|
5
|
+
*
|
|
6
|
+
* `node:sqlite` binds `null`, a boolean, a number, a bigint, a string and a `Uint8Array`, and
|
|
7
|
+
* throws "Provided value cannot be bound to SQLite parameter N" for anything else. A `Date`
|
|
8
|
+
* is exactly that anything else, and it is also the app type of every `timestamp` column —
|
|
9
|
+
* so before this, a `timestamp` could not be written through this driver at all: passing a
|
|
10
|
+
* `Date` threw here and passing a string was the wrong type one layer up.
|
|
11
|
+
*
|
|
12
|
+
* ISO-8601 is not an arbitrary choice of encoding. It is what the DDL emitter declares the
|
|
13
|
+
* column as (`TEXT`), what the wire layer carries, and — being fixed-width and
|
|
14
|
+
* zero-padded — the one text form whose lexicographic order is its chronological order, so
|
|
15
|
+
* `WHERE at > ?` and `ORDER BY at` mean what they say. UTC for the same reason: an offset
|
|
16
|
+
* would break that ordering.
|
|
17
|
+
*
|
|
18
|
+
* Applied to every parameter rather than per column, because the driver has no schema and
|
|
19
|
+
* needs none: there is one right answer for a `Date` here regardless of which column it
|
|
20
|
+
* was bound for.
|
|
21
|
+
*/
|
|
22
|
+
function bindable(value) {
|
|
23
|
+
return value instanceof Date ? value.toISOString() : value;
|
|
24
|
+
}
|
|
25
|
+
/** Wrap a node:sqlite DatabaseSync as a zmdb Driver. Zero external deps. */
|
|
26
|
+
export function sqliteDriver(db, opts) {
|
|
27
|
+
db.exec('PRAGMA foreign_keys = ON');
|
|
28
|
+
const maxCacheSize = opts?.maxCacheSize ?? 1000;
|
|
29
|
+
const cache = new Map();
|
|
30
|
+
const statementFor = (text) => {
|
|
31
|
+
let entry = maxCacheSize > 0 ? cache.get(text) : undefined;
|
|
32
|
+
if (entry !== undefined && entry.activeIterators === 0) {
|
|
33
|
+
cache.delete(text);
|
|
34
|
+
cache.set(text, entry);
|
|
35
|
+
return entry;
|
|
36
|
+
}
|
|
37
|
+
const stmt = db.prepare(text);
|
|
38
|
+
const columns = stmt.columns?.();
|
|
39
|
+
entry = {
|
|
40
|
+
stmt,
|
|
41
|
+
isRead: columns === undefined ? /^\s*(?:SELECT|PRAGMA)\b/i.test(text) || /RETURNING/i.test(text) : columns.length > 0,
|
|
42
|
+
activeIterators: 0,
|
|
43
|
+
};
|
|
44
|
+
if (maxCacheSize <= 0)
|
|
45
|
+
return entry;
|
|
46
|
+
if (cache.size >= maxCacheSize) {
|
|
47
|
+
const evictable = [...cache].find(([, candidate]) => candidate.activeIterators === 0);
|
|
48
|
+
if (evictable !== undefined)
|
|
49
|
+
cache.delete(evictable[0]);
|
|
50
|
+
}
|
|
51
|
+
if (cache.size < maxCacheSize)
|
|
52
|
+
cache.set(text, entry);
|
|
53
|
+
return entry;
|
|
54
|
+
};
|
|
55
|
+
const driver = {
|
|
56
|
+
dialect: sqlite,
|
|
57
|
+
async execute(q, executeOpts) {
|
|
58
|
+
const signal = executeOpts?.signal;
|
|
59
|
+
signal?.throwIfAborted();
|
|
60
|
+
const entry = statementFor(q.text);
|
|
61
|
+
const parameters = q.parameters.map(bindable);
|
|
62
|
+
if (entry.isRead) {
|
|
63
|
+
// boundary: rows leave the database untyped. `all()` is declared
|
|
64
|
+
// `unknown[]` (the widest shape every @types/node version agrees on);
|
|
65
|
+
// node:sqlite always yields plain row objects for a row-returning
|
|
66
|
+
// statement, and callers re-type them at the repository's row boundary.
|
|
67
|
+
const rows = entry.stmt.all(...parameters);
|
|
68
|
+
signal?.throwIfAborted();
|
|
69
|
+
return rows;
|
|
70
|
+
}
|
|
71
|
+
if (parameters.length === 0)
|
|
72
|
+
db.exec(q.text);
|
|
73
|
+
else
|
|
74
|
+
entry.stmt.run(...parameters);
|
|
75
|
+
signal?.throwIfAborted();
|
|
76
|
+
return [];
|
|
77
|
+
},
|
|
78
|
+
stream(q, executeOpts) {
|
|
79
|
+
const signal = executeOpts?.signal;
|
|
80
|
+
return {
|
|
81
|
+
async *[Symbol.asyncIterator]() {
|
|
82
|
+
signal?.throwIfAborted();
|
|
83
|
+
const entry = statementFor(q.text);
|
|
84
|
+
if (!entry.isRead)
|
|
85
|
+
throw new Error('sqliteDriver.stream requires a row-returning statement');
|
|
86
|
+
const parameters = q.parameters.map(bindable);
|
|
87
|
+
entry.activeIterators++;
|
|
88
|
+
let completed = false;
|
|
89
|
+
let iterator;
|
|
90
|
+
try {
|
|
91
|
+
iterator = entry.stmt.iterate(...parameters)[Symbol.iterator]();
|
|
92
|
+
for (;;) {
|
|
93
|
+
// node:sqlite has no sqlite3_interrupt binding. JavaScript regains
|
|
94
|
+
// control only between native steps, so abort can stop further
|
|
95
|
+
// rows but cannot interrupt one slow step already in SQLite.
|
|
96
|
+
signal?.throwIfAborted();
|
|
97
|
+
const next = iterator.next();
|
|
98
|
+
signal?.throwIfAborted();
|
|
99
|
+
if (next.done) {
|
|
100
|
+
completed = true;
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
yield next.value;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
finally {
|
|
107
|
+
try {
|
|
108
|
+
if (!completed && iterator?.return !== undefined)
|
|
109
|
+
iterator.return();
|
|
110
|
+
}
|
|
111
|
+
finally {
|
|
112
|
+
entry.activeIterators--;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
},
|
|
118
|
+
async transaction(run) {
|
|
119
|
+
db.exec('BEGIN');
|
|
120
|
+
try {
|
|
121
|
+
const result = await run(driver);
|
|
122
|
+
db.exec('COMMIT');
|
|
123
|
+
return result;
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
db.exec('ROLLBACK');
|
|
127
|
+
throw error;
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
return driver;
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=driver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"driver.js","sourceRoot":"","sources":["../src/driver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embedded.d.ts","sourceRoot":"","sources":["../src/embedded.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAChF,YAAY,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAC"}
|
package/dist/embedded.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embedded.js","sourceRoot":"","sources":["../src/embedded.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { sqlite } from './dialect.js';
|
|
2
|
+
export { sqliteDriver, type SqliteDatabase, type SqliteOptions, type SqliteStatement } from './driver.js';
|
|
3
|
+
export { sqliteIntrospector } from './introspector.js';
|
|
4
|
+
export { sqliteMigrations } from './migrations.js';
|
|
5
|
+
import { type DatabaseVertical } from '@zmdb/orm';
|
|
6
|
+
import { type SqliteDatabase, type SqliteOptions } from './driver.js';
|
|
7
|
+
export declare const sqliteVertical: DatabaseVertical<'sqlite', SqliteDatabase, SqliteOptions>;
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,YAAY,EAAE,KAAK,cAAc,EAAE,KAAK,aAAa,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAC1G,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEnD,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAGlD,OAAO,EAAgB,KAAK,cAAc,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAEpF,eAAO,MAAM,cAAc,EAAE,gBAAgB,CAAC,QAAQ,EAAE,cAAc,EAAE,aAAa,CAGnF,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { sqlite } from './dialect.js';
|
|
2
|
+
export { sqliteDriver } from './driver.js';
|
|
3
|
+
export { sqliteIntrospector } from './introspector.js';
|
|
4
|
+
export { sqliteMigrations } from './migrations.js';
|
|
5
|
+
import {} from '@zmdb/orm';
|
|
6
|
+
import { sqlite } from './dialect.js';
|
|
7
|
+
import { sqliteDriver } from './driver.js';
|
|
8
|
+
export const sqliteVertical = Object.freeze({
|
|
9
|
+
dialect: sqlite,
|
|
10
|
+
driver: sqliteDriver,
|
|
11
|
+
});
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,YAAY,EAAiE,MAAM,aAAa,CAAC;AAC1G,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEnD,OAAO,EAAyB,MAAM,WAAW,CAAC;AAElD,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,YAAY,EAA2C,MAAM,aAAa,CAAC;AAEpF,MAAM,CAAC,MAAM,cAAc,GAA8D,MAAM,CAAC,MAAM,CAAC;IACrG,OAAO,EAAE,MAAM;IACf,MAAM,EAAE,YAAY;CACrB,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"introspector.d.ts","sourceRoot":"","sources":["../src/introspector.ts"],"names":[],"mappings":"AACA,OAAO,EAsBL,KAAK,YAAY,EAElB,MAAM,qCAAqC,CAAC;AA+b7C,QAAA,MAAM,YAAY,EAAG,QAAiB,CAAC;AAoCvC,eAAO,MAAM,kBAAkB,EAAE,YAAY,CAAC,OAAO,YAAY,CAIhE,CAAC"}
|