dbgate-sqlite-dumper 0.1.0 → 0.1.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 -674
- package/README.md +247 -230
- package/dist/better-sqlite3.cjs.map +1 -1
- package/dist/better-sqlite3.d.cts +1 -1
- package/dist/better-sqlite3.d.ts +1 -1
- package/dist/better-sqlite3.js.map +1 -1
- package/dist/d1.cjs +260 -0
- package/dist/d1.cjs.map +1 -0
- package/dist/d1.d.cts +101 -0
- package/dist/d1.d.ts +101 -0
- package/dist/d1.js +229 -0
- package/dist/d1.js.map +1 -0
- package/dist/errors-CplNzuYs.d.cts +20 -0
- package/dist/errors-CplNzuYs.d.ts +20 -0
- package/dist/index.cjs +405 -90
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +58 -24
- package/dist/index.d.ts +58 -24
- package/dist/index.js +400 -89
- package/dist/index.js.map +1 -1
- package/dist/{types-CTyJTzB6.d.cts → types-DziV5ysl.d.cts} +67 -2
- package/dist/{types-CTyJTzB6.d.ts → types-DziV5ysl.d.ts} +67 -2
- package/docs/architecture.md +180 -157
- package/docs/better-sqlite3-adapter.md +83 -83
- package/docs/d1-adapter.md +98 -0
- package/docs/dump-api.md +253 -253
- package/docs/known-limitations.md +100 -88
- package/docs/native-compatibility.md +124 -124
- package/docs/restore-api.md +234 -234
- package/docs/round-trip-testing.md +84 -84
- package/docs/supported-data-types.md +74 -74
- package/docs/supported-objects.md +85 -85
- package/package.json +96 -89
package/docs/dump-api.md
CHANGED
|
@@ -1,253 +1,253 @@
|
|
|
1
|
-
# Dump API
|
|
2
|
-
|
|
3
|
-
```ts
|
|
4
|
-
dumpSqlite(connection, options, output, onProgress?, signal?): Promise<DumpResult>
|
|
5
|
-
```
|
|
6
|
-
|
|
7
|
-
Runs a complete dump — acquire a handle, open a read snapshot, introspect, plan, render,
|
|
8
|
-
stream rows — writing plain SQL in the native `.dump` layout to `output`.
|
|
9
|
-
|
|
10
|
-
```ts
|
|
11
|
-
import { createWriteStream } from 'node:fs';
|
|
12
|
-
import { dumpSqlite } from 'dbgate-sqlite-dumper';
|
|
13
|
-
import { connectBetterSqlite3 } from 'dbgate-sqlite-dumper/better-sqlite3';
|
|
14
|
-
|
|
15
|
-
const { connection, close } = await connectBetterSqlite3('shop.db', { readonly: true });
|
|
16
|
-
try {
|
|
17
|
-
const result = await dumpSqlite(connection, {}, createWriteStream('shop.sql'));
|
|
18
|
-
console.log(`${result.rowsExported} rows in ${result.statementsWritten} statements`);
|
|
19
|
-
} finally {
|
|
20
|
-
await close();
|
|
21
|
-
}
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
## `output`
|
|
25
|
-
|
|
26
|
-
Any `Writable`. Never ended or closed by this package — the caller owns its lifecycle.
|
|
27
|
-
|
|
28
|
-
A dump is written incrementally, honouring backpressure, so a multi-gigabyte database
|
|
29
|
-
dumps in constant memory. `output` may receive `Buffer` chunks as well as text: a `TEXT`
|
|
30
|
-
value holding bytes that are not valid UTF-8 is written raw, exactly as the native `.dump`
|
|
31
|
-
writes it, and cannot be routed through a JavaScript string without corruption.
|
|
32
|
-
|
|
33
|
-
## `DumpSqliteOptions`
|
|
34
|
-
|
|
35
|
-
| Option | Default | Meaning |
|
|
36
|
-
| ------------- | ------------ | ----------------------------------------------- |
|
|
37
|
-
| `mode` | `'full'` | `'full'`, `'schema-only'`, `'data-only'`. |
|
|
38
|
-
| `schemaName` | `'main'` | `main`, `temp`, or an attached database's name. |
|
|
39
|
-
| `selection` | everything | Per-name object filters; see below. |
|
|
40
|
-
| `objectKinds` | all `true` | Which kinds participate at all. |
|
|
41
|
-
| `render` | see below | Output shape. |
|
|
42
|
-
| `dataExport` | see below | Row rendering and batching. |
|
|
43
|
-
| `consistency` | `'snapshot'` | How a consistent view is obtained. |
|
|
44
|
-
|
|
45
|
-
The dump itself never names the schema (`CREATE TABLE t`, not `CREATE TABLE aux.t`), so a
|
|
46
|
-
dump of an attached database restores into whatever database it is run against — like a
|
|
47
|
-
native `.dump`.
|
|
48
|
-
|
|
49
|
-
### `mode`
|
|
50
|
-
|
|
51
|
-
- **`'full'`** — schema and rows: the native `.dump`.
|
|
52
|
-
- **`'data-only'`** — `INSERT` statements only, no frame: the native `.dump --data-only`.
|
|
53
|
-
See [data-only dumps](#data-only-dumps).
|
|
54
|
-
- **`'schema-only'`** — every `CREATE`, no rows, no `AUTOINCREMENT` counters, no statistics.
|
|
55
|
-
Virtual tables are created with their own `CREATE VIRTUAL TABLE`, so their module sets up
|
|
56
|
-
its shadow tables, which are therefore left out.
|
|
57
|
-
|
|
58
|
-
### `selection`
|
|
59
|
-
|
|
60
|
-
Names are exact identifiers, never patterns, compared the way SQLite compares them (ASCII
|
|
61
|
-
letters case-insensitively, nothing else folded).
|
|
62
|
-
|
|
63
|
-
```ts
|
|
64
|
-
selection: {
|
|
65
|
-
tables: ['orders', 'order_lines'], // omit for all
|
|
66
|
-
excludeTables: ['orders_archive'], // applied after `tables`
|
|
67
|
-
views: [...], excludeViews: [...],
|
|
68
|
-
triggers: [...], excludeTriggers: [...],
|
|
69
|
-
excludeIndexes: [...], // indexes otherwise follow their table
|
|
70
|
-
|
|
71
|
-
// Structure dumped, rows skipped — for a large log or cache table you still
|
|
72
|
-
// want recreated.
|
|
73
|
-
dataExcludedTables: ['request_log'],
|
|
74
|
-
}
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
Selecting a virtual table selects its shadow tables (`docs` brings `docs_data`,
|
|
78
|
-
`docs_idx`, ...). A trigger whose table is not selected is dropped rather than orphaned,
|
|
79
|
-
and reported as `trigger-table-not-selected`. In a partial dump, the `sqlite_sequence` and
|
|
80
|
-
statistics rows are restricted to the selected tables, and only their counters are reset.
|
|
81
|
-
|
|
82
|
-
### `objectKinds`
|
|
83
|
-
|
|
84
|
-
```ts
|
|
85
|
-
objectKinds: {
|
|
86
|
-
includeTables: true,
|
|
87
|
-
includeViews: true,
|
|
88
|
-
includeIndexes: true,
|
|
89
|
-
includeTriggers: true,
|
|
90
|
-
includeVirtualTables: true, // and their shadow tables
|
|
91
|
-
includeSystemTables: true, // sqlite_sequence, sqlite_stat*; false = native --nosys
|
|
92
|
-
}
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
### `render` — output shape
|
|
96
|
-
|
|
97
|
-
| Option | Default | Meaning |
|
|
98
|
-
| -------------------------- | --------- | ------------------------------------------------------------------ |
|
|
99
|
-
| `includeSessionGuards` | `true` | `PRAGMA foreign_keys=OFF;` / `BEGIN TRANSACTION;` … `COMMIT;` |
|
|
100
|
-
| `includeHeaderComments` | `true` | The defensive-mode warning line, when there are virtual tables. |
|
|
101
|
-
| `addDropStatements` | `false` | `DROP … IF EXISTS` before each `CREATE`. |
|
|
102
|
-
| `includeDatabaseSettings` | `false` | `PRAGMA user_version` / `application_id` before `COMMIT`. |
|
|
103
|
-
| `legacySchemaTableName` | `false` | Write `sqlite_master` instead of `sqlite_schema` (targets < 3.33). |
|
|
104
|
-
| `unsupportedFeaturePolicy` | `'error'` | `'warn-omit'` skips an entry that cannot be rendered instead. |
|
|
105
|
-
|
|
106
|
-
Notes on the ones that carry weight:
|
|
107
|
-
|
|
108
|
-
- **`includeSessionGuards: false`** produces a `session-guards-disabled` warning. Without
|
|
109
|
-
`foreign_keys=OFF`, tables that reference each other may not restore in creation order;
|
|
110
|
-
without the transaction, every `INSERT` is its own transaction and its own disk sync.
|
|
111
|
-
- **`includeDatabaseSettings`** is off to match the native `.dump`, which does not carry
|
|
112
|
-
`user_version`. Applications often track their schema migrations there, so a non-zero
|
|
113
|
-
value that is not being dumped is reported as `user-version-not-dumped`.
|
|
114
|
-
|
|
115
|
-
### `dataExport` — row rendering
|
|
116
|
-
|
|
117
|
-
| Option | Default | Meaning |
|
|
118
|
-
| --------------------- | ------- | ----------------------------------------------------------------------- |
|
|
119
|
-
| `preserveRowids` | `false` | `INSERT INTO t(rowid,…)` for hidden rowids; native `--preserve-rowids`. |
|
|
120
|
-
| `rawNewlines` | `false` | Raw newlines in literals instead of `replace()`; native `--newlines`. |
|
|
121
|
-
| `extendedInsert` | `false` | Multi-row `INSERT … VALUES (…),(…)`. |
|
|
122
|
-
| `maxRowsPerStatement` | `500` | With `extendedInsert`. |
|
|
123
|
-
| `maxStatementBytes` | 1 MiB | With `extendedInsert`; a single larger row is still emitted alone. |
|
|
124
|
-
| `streamBatchSize` | — | Hint passed to `connection.stream()`. |
|
|
125
|
-
|
|
126
|
-
- **`preserveRowids`**: a table without an `INTEGER PRIMARY KEY` has a hidden rowid, and
|
|
127
|
-
without this option a restore renumbers its rows from 1. That matters when anything
|
|
128
|
-
refers to rowids — an external-content FTS index, an application storing them.
|
|
129
|
-
- **`extendedInsert`** makes the file smaller and the restore faster, at the cost of native
|
|
130
|
-
byte identity. One row per statement is not slow in SQLite — the whole restore is one
|
|
131
|
-
transaction — so the default follows the native layout.
|
|
132
|
-
|
|
133
|
-
Rows are read in the table's natural order, with no `ORDER BY`, exactly like the native
|
|
134
|
-
`.dump`: rowid order for an ordinary table, primary-key order for a `WITHOUT ROWID` one. Two
|
|
135
|
-
dumps of an unchanged database are identical.
|
|
136
|
-
|
|
137
|
-
### `consistency`
|
|
138
|
-
|
|
139
|
-
- **`'snapshot'`** (default) — the whole dump runs inside one read transaction (a
|
|
140
|
-
`SAVEPOINT`, so it nests inside a transaction the caller already has open, and reads
|
|
141
|
-
what that transaction sees). In WAL mode that is a true snapshot and writers carry on; in
|
|
142
|
-
rollback-journal mode it holds a `SHARED` lock that keeps writers out until the dump
|
|
143
|
-
ends. It is the same mechanism the native `.dump` uses.
|
|
144
|
-
- **`'none'`** — no transaction; only safe when nothing else writes to the database.
|
|
145
|
-
|
|
146
|
-
## Data-only dumps
|
|
147
|
-
|
|
148
|
-
`.dump --data-only` — and `mode: 'data-only'`, which reproduces it — has two quirks that
|
|
149
|
-
matter when loading the rows into an existing schema:
|
|
150
|
-
|
|
151
|
-
- it carries each virtual table's rows twice: through the table, and as its shadow tables'
|
|
152
|
-
rows, which collide with the target table's own shadow rows;
|
|
153
|
-
- it inserts into `sqlite_sequence` and `sqlite_stat*` without preparing them, leaving
|
|
154
|
-
duplicate counters, or failing where the target was never analyzed.
|
|
155
|
-
|
|
156
|
-
For loading rows into an existing schema, this option set avoids both:
|
|
157
|
-
|
|
158
|
-
```ts
|
|
159
|
-
await dumpSqlite(
|
|
160
|
-
connection,
|
|
161
|
-
{
|
|
162
|
-
mode: 'data-only',
|
|
163
|
-
objectKinds: { includeSystemTables: false },
|
|
164
|
-
selection: {
|
|
165
|
-
dataExcludedTables: ['docs_data', 'docs_idx', 'docs_content', 'docs_docsize', 'docs_config'],
|
|
166
|
-
},
|
|
167
|
-
},
|
|
168
|
-
output,
|
|
169
|
-
);
|
|
170
|
-
|
|
171
|
-
// …and restore with
|
|
172
|
-
await restoreSqlDump({
|
|
173
|
-
connection: target,
|
|
174
|
-
source,
|
|
175
|
-
options: { transaction: 'wrap', disableForeignKeys: true },
|
|
176
|
-
});
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
Create triggers after the load, or they fire for every restored row.
|
|
180
|
-
|
|
181
|
-
## `DumpResult`
|
|
182
|
-
|
|
183
|
-
```ts
|
|
184
|
-
{
|
|
185
|
-
bytesWritten: number;
|
|
186
|
-
rowsExported: number;
|
|
187
|
-
statementsWritten: number;
|
|
188
|
-
renderedDumpIds: readonly string[];
|
|
189
|
-
skippedDumpIds: readonly string[];
|
|
190
|
-
warnings: readonly SqliteDiagnostic[];
|
|
191
|
-
cancelled: boolean;
|
|
192
|
-
}
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
`cancelled` is `true` when the `AbortSignal` fired; the dump is truncated but nothing
|
|
196
|
-
throws, and the read transaction is ended cleanly.
|
|
197
|
-
|
|
198
|
-
## Progress
|
|
199
|
-
|
|
200
|
-
Phases, in order: `connecting`, `starting-snapshot`, `introspecting`, `detecting-version`,
|
|
201
|
-
`planning-archive`, `rendering-schema`, `exporting-data`, `finalizing`. Rendering events
|
|
202
|
-
carry `section`, `objectsProcessed`/`objectsTotal` and `objectName`; data events carry
|
|
203
|
-
`exportState` (`started`/`progress`/`finished`/`failed`/`cancelled`), `tableName`,
|
|
204
|
-
`rowsExported` and `bytesWritten`, every 1000 rows.
|
|
205
|
-
|
|
206
|
-
## Cancellation
|
|
207
|
-
|
|
208
|
-
```ts
|
|
209
|
-
const controller = new AbortController();
|
|
210
|
-
const result = await dumpSqlite(connection, {}, output, undefined, controller.signal);
|
|
211
|
-
if (result.cancelled) console.warn('dump truncated');
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
Cancellation takes effect between rows. Buffered output is deliberately **not** flushed: a
|
|
215
|
-
dump cut off at an arbitrary row should look truncated, not complete.
|
|
216
|
-
|
|
217
|
-
## Composing the stages
|
|
218
|
-
|
|
219
|
-
```ts
|
|
220
|
-
import {
|
|
221
|
-
introspectSqlite,
|
|
222
|
-
inspectDumpArchive,
|
|
223
|
-
renderPlainSql,
|
|
224
|
-
BufferDumpWriter,
|
|
225
|
-
} from 'dbgate-sqlite-dumper';
|
|
226
|
-
|
|
227
|
-
const { database, version } = await introspectSqlite(connection);
|
|
228
|
-
|
|
229
|
-
// Inspect the plan without rendering anything.
|
|
230
|
-
const archive = inspectDumpArchive(database, { mode: 'schema-only' });
|
|
231
|
-
for (const entry of archive.entries) {
|
|
232
|
-
console.log(entry.sequenceNumber, entry.section, entry.objectType, entry.name);
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
// Render schema only, into memory, with no database access.
|
|
236
|
-
const writer = new BufferDumpWriter();
|
|
237
|
-
await renderPlainSql({ database, archive, writer, mode: 'schema-only', sourceVersion: version });
|
|
238
|
-
console.log(writer.toString());
|
|
239
|
-
```
|
|
240
|
-
|
|
241
|
-
`exportTableDataAsInserts` streams one table's rows on its own:
|
|
242
|
-
|
|
243
|
-
```ts
|
|
244
|
-
import { exportTableDataAsInserts } from 'dbgate-sqlite-dumper';
|
|
245
|
-
|
|
246
|
-
await exportTableDataAsInserts({
|
|
247
|
-
connection,
|
|
248
|
-
schemaName: 'main',
|
|
249
|
-
table: database.tables.find(table => table.name === 'orders')!,
|
|
250
|
-
writer,
|
|
251
|
-
options: { extendedInsert: true },
|
|
252
|
-
});
|
|
253
|
-
```
|
|
1
|
+
# Dump API
|
|
2
|
+
|
|
3
|
+
```ts
|
|
4
|
+
dumpSqlite(connection, options, output, onProgress?, signal?): Promise<DumpResult>
|
|
5
|
+
```
|
|
6
|
+
|
|
7
|
+
Runs a complete dump — acquire a handle, open a read snapshot, introspect, plan, render,
|
|
8
|
+
stream rows — writing plain SQL in the native `.dump` layout to `output`.
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
import { createWriteStream } from 'node:fs';
|
|
12
|
+
import { dumpSqlite } from 'dbgate-sqlite-dumper';
|
|
13
|
+
import { connectBetterSqlite3 } from 'dbgate-sqlite-dumper/better-sqlite3';
|
|
14
|
+
|
|
15
|
+
const { connection, close } = await connectBetterSqlite3('shop.db', { readonly: true });
|
|
16
|
+
try {
|
|
17
|
+
const result = await dumpSqlite(connection, {}, createWriteStream('shop.sql'));
|
|
18
|
+
console.log(`${result.rowsExported} rows in ${result.statementsWritten} statements`);
|
|
19
|
+
} finally {
|
|
20
|
+
await close();
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## `output`
|
|
25
|
+
|
|
26
|
+
Any `Writable`. Never ended or closed by this package — the caller owns its lifecycle.
|
|
27
|
+
|
|
28
|
+
A dump is written incrementally, honouring backpressure, so a multi-gigabyte database
|
|
29
|
+
dumps in constant memory. `output` may receive `Buffer` chunks as well as text: a `TEXT`
|
|
30
|
+
value holding bytes that are not valid UTF-8 is written raw, exactly as the native `.dump`
|
|
31
|
+
writes it, and cannot be routed through a JavaScript string without corruption.
|
|
32
|
+
|
|
33
|
+
## `DumpSqliteOptions`
|
|
34
|
+
|
|
35
|
+
| Option | Default | Meaning |
|
|
36
|
+
| ------------- | ------------ | ----------------------------------------------- |
|
|
37
|
+
| `mode` | `'full'` | `'full'`, `'schema-only'`, `'data-only'`. |
|
|
38
|
+
| `schemaName` | `'main'` | `main`, `temp`, or an attached database's name. |
|
|
39
|
+
| `selection` | everything | Per-name object filters; see below. |
|
|
40
|
+
| `objectKinds` | all `true` | Which kinds participate at all. |
|
|
41
|
+
| `render` | see below | Output shape. |
|
|
42
|
+
| `dataExport` | see below | Row rendering and batching. |
|
|
43
|
+
| `consistency` | `'snapshot'` | How a consistent view is obtained. |
|
|
44
|
+
|
|
45
|
+
The dump itself never names the schema (`CREATE TABLE t`, not `CREATE TABLE aux.t`), so a
|
|
46
|
+
dump of an attached database restores into whatever database it is run against — like a
|
|
47
|
+
native `.dump`.
|
|
48
|
+
|
|
49
|
+
### `mode`
|
|
50
|
+
|
|
51
|
+
- **`'full'`** — schema and rows: the native `.dump`.
|
|
52
|
+
- **`'data-only'`** — `INSERT` statements only, no frame: the native `.dump --data-only`.
|
|
53
|
+
See [data-only dumps](#data-only-dumps).
|
|
54
|
+
- **`'schema-only'`** — every `CREATE`, no rows, no `AUTOINCREMENT` counters, no statistics.
|
|
55
|
+
Virtual tables are created with their own `CREATE VIRTUAL TABLE`, so their module sets up
|
|
56
|
+
its shadow tables, which are therefore left out.
|
|
57
|
+
|
|
58
|
+
### `selection`
|
|
59
|
+
|
|
60
|
+
Names are exact identifiers, never patterns, compared the way SQLite compares them (ASCII
|
|
61
|
+
letters case-insensitively, nothing else folded).
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
selection: {
|
|
65
|
+
tables: ['orders', 'order_lines'], // omit for all
|
|
66
|
+
excludeTables: ['orders_archive'], // applied after `tables`
|
|
67
|
+
views: [...], excludeViews: [...],
|
|
68
|
+
triggers: [...], excludeTriggers: [...],
|
|
69
|
+
excludeIndexes: [...], // indexes otherwise follow their table
|
|
70
|
+
|
|
71
|
+
// Structure dumped, rows skipped — for a large log or cache table you still
|
|
72
|
+
// want recreated.
|
|
73
|
+
dataExcludedTables: ['request_log'],
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Selecting a virtual table selects its shadow tables (`docs` brings `docs_data`,
|
|
78
|
+
`docs_idx`, ...). A trigger whose table is not selected is dropped rather than orphaned,
|
|
79
|
+
and reported as `trigger-table-not-selected`. In a partial dump, the `sqlite_sequence` and
|
|
80
|
+
statistics rows are restricted to the selected tables, and only their counters are reset.
|
|
81
|
+
|
|
82
|
+
### `objectKinds`
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
objectKinds: {
|
|
86
|
+
includeTables: true,
|
|
87
|
+
includeViews: true,
|
|
88
|
+
includeIndexes: true,
|
|
89
|
+
includeTriggers: true,
|
|
90
|
+
includeVirtualTables: true, // and their shadow tables
|
|
91
|
+
includeSystemTables: true, // sqlite_sequence, sqlite_stat*; false = native --nosys
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### `render` — output shape
|
|
96
|
+
|
|
97
|
+
| Option | Default | Meaning |
|
|
98
|
+
| -------------------------- | --------- | ------------------------------------------------------------------ |
|
|
99
|
+
| `includeSessionGuards` | `true` | `PRAGMA foreign_keys=OFF;` / `BEGIN TRANSACTION;` … `COMMIT;` |
|
|
100
|
+
| `includeHeaderComments` | `true` | The defensive-mode warning line, when there are virtual tables. |
|
|
101
|
+
| `addDropStatements` | `false` | `DROP … IF EXISTS` before each `CREATE`. |
|
|
102
|
+
| `includeDatabaseSettings` | `false` | `PRAGMA user_version` / `application_id` before `COMMIT`. |
|
|
103
|
+
| `legacySchemaTableName` | `false` | Write `sqlite_master` instead of `sqlite_schema` (targets < 3.33). |
|
|
104
|
+
| `unsupportedFeaturePolicy` | `'error'` | `'warn-omit'` skips an entry that cannot be rendered instead. |
|
|
105
|
+
|
|
106
|
+
Notes on the ones that carry weight:
|
|
107
|
+
|
|
108
|
+
- **`includeSessionGuards: false`** produces a `session-guards-disabled` warning. Without
|
|
109
|
+
`foreign_keys=OFF`, tables that reference each other may not restore in creation order;
|
|
110
|
+
without the transaction, every `INSERT` is its own transaction and its own disk sync.
|
|
111
|
+
- **`includeDatabaseSettings`** is off to match the native `.dump`, which does not carry
|
|
112
|
+
`user_version`. Applications often track their schema migrations there, so a non-zero
|
|
113
|
+
value that is not being dumped is reported as `user-version-not-dumped`.
|
|
114
|
+
|
|
115
|
+
### `dataExport` — row rendering
|
|
116
|
+
|
|
117
|
+
| Option | Default | Meaning |
|
|
118
|
+
| --------------------- | ------- | ----------------------------------------------------------------------- |
|
|
119
|
+
| `preserveRowids` | `false` | `INSERT INTO t(rowid,…)` for hidden rowids; native `--preserve-rowids`. |
|
|
120
|
+
| `rawNewlines` | `false` | Raw newlines in literals instead of `replace()`; native `--newlines`. |
|
|
121
|
+
| `extendedInsert` | `false` | Multi-row `INSERT … VALUES (…),(…)`. |
|
|
122
|
+
| `maxRowsPerStatement` | `500` | With `extendedInsert`. |
|
|
123
|
+
| `maxStatementBytes` | 1 MiB | With `extendedInsert`; a single larger row is still emitted alone. |
|
|
124
|
+
| `streamBatchSize` | — | Hint passed to `connection.stream()`. |
|
|
125
|
+
|
|
126
|
+
- **`preserveRowids`**: a table without an `INTEGER PRIMARY KEY` has a hidden rowid, and
|
|
127
|
+
without this option a restore renumbers its rows from 1. That matters when anything
|
|
128
|
+
refers to rowids — an external-content FTS index, an application storing them.
|
|
129
|
+
- **`extendedInsert`** makes the file smaller and the restore faster, at the cost of native
|
|
130
|
+
byte identity. One row per statement is not slow in SQLite — the whole restore is one
|
|
131
|
+
transaction — so the default follows the native layout.
|
|
132
|
+
|
|
133
|
+
Rows are read in the table's natural order, with no `ORDER BY`, exactly like the native
|
|
134
|
+
`.dump`: rowid order for an ordinary table, primary-key order for a `WITHOUT ROWID` one. Two
|
|
135
|
+
dumps of an unchanged database are identical.
|
|
136
|
+
|
|
137
|
+
### `consistency`
|
|
138
|
+
|
|
139
|
+
- **`'snapshot'`** (default) — the whole dump runs inside one read transaction (a
|
|
140
|
+
`SAVEPOINT`, so it nests inside a transaction the caller already has open, and reads
|
|
141
|
+
what that transaction sees). In WAL mode that is a true snapshot and writers carry on; in
|
|
142
|
+
rollback-journal mode it holds a `SHARED` lock that keeps writers out until the dump
|
|
143
|
+
ends. It is the same mechanism the native `.dump` uses.
|
|
144
|
+
- **`'none'`** — no transaction; only safe when nothing else writes to the database.
|
|
145
|
+
|
|
146
|
+
## Data-only dumps
|
|
147
|
+
|
|
148
|
+
`.dump --data-only` — and `mode: 'data-only'`, which reproduces it — has two quirks that
|
|
149
|
+
matter when loading the rows into an existing schema:
|
|
150
|
+
|
|
151
|
+
- it carries each virtual table's rows twice: through the table, and as its shadow tables'
|
|
152
|
+
rows, which collide with the target table's own shadow rows;
|
|
153
|
+
- it inserts into `sqlite_sequence` and `sqlite_stat*` without preparing them, leaving
|
|
154
|
+
duplicate counters, or failing where the target was never analyzed.
|
|
155
|
+
|
|
156
|
+
For loading rows into an existing schema, this option set avoids both:
|
|
157
|
+
|
|
158
|
+
```ts
|
|
159
|
+
await dumpSqlite(
|
|
160
|
+
connection,
|
|
161
|
+
{
|
|
162
|
+
mode: 'data-only',
|
|
163
|
+
objectKinds: { includeSystemTables: false },
|
|
164
|
+
selection: {
|
|
165
|
+
dataExcludedTables: ['docs_data', 'docs_idx', 'docs_content', 'docs_docsize', 'docs_config'],
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
output,
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
// …and restore with
|
|
172
|
+
await restoreSqlDump({
|
|
173
|
+
connection: target,
|
|
174
|
+
source,
|
|
175
|
+
options: { transaction: 'wrap', disableForeignKeys: true },
|
|
176
|
+
});
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Create triggers after the load, or they fire for every restored row.
|
|
180
|
+
|
|
181
|
+
## `DumpResult`
|
|
182
|
+
|
|
183
|
+
```ts
|
|
184
|
+
{
|
|
185
|
+
bytesWritten: number;
|
|
186
|
+
rowsExported: number;
|
|
187
|
+
statementsWritten: number;
|
|
188
|
+
renderedDumpIds: readonly string[];
|
|
189
|
+
skippedDumpIds: readonly string[];
|
|
190
|
+
warnings: readonly SqliteDiagnostic[];
|
|
191
|
+
cancelled: boolean;
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
`cancelled` is `true` when the `AbortSignal` fired; the dump is truncated but nothing
|
|
196
|
+
throws, and the read transaction is ended cleanly.
|
|
197
|
+
|
|
198
|
+
## Progress
|
|
199
|
+
|
|
200
|
+
Phases, in order: `connecting`, `starting-snapshot`, `introspecting`, `detecting-version`,
|
|
201
|
+
`planning-archive`, `rendering-schema`, `exporting-data`, `finalizing`. Rendering events
|
|
202
|
+
carry `section`, `objectsProcessed`/`objectsTotal` and `objectName`; data events carry
|
|
203
|
+
`exportState` (`started`/`progress`/`finished`/`failed`/`cancelled`), `tableName`,
|
|
204
|
+
`rowsExported` and `bytesWritten`, every 1000 rows.
|
|
205
|
+
|
|
206
|
+
## Cancellation
|
|
207
|
+
|
|
208
|
+
```ts
|
|
209
|
+
const controller = new AbortController();
|
|
210
|
+
const result = await dumpSqlite(connection, {}, output, undefined, controller.signal);
|
|
211
|
+
if (result.cancelled) console.warn('dump truncated');
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Cancellation takes effect between rows. Buffered output is deliberately **not** flushed: a
|
|
215
|
+
dump cut off at an arbitrary row should look truncated, not complete.
|
|
216
|
+
|
|
217
|
+
## Composing the stages
|
|
218
|
+
|
|
219
|
+
```ts
|
|
220
|
+
import {
|
|
221
|
+
introspectSqlite,
|
|
222
|
+
inspectDumpArchive,
|
|
223
|
+
renderPlainSql,
|
|
224
|
+
BufferDumpWriter,
|
|
225
|
+
} from 'dbgate-sqlite-dumper';
|
|
226
|
+
|
|
227
|
+
const { database, version } = await introspectSqlite(connection);
|
|
228
|
+
|
|
229
|
+
// Inspect the plan without rendering anything.
|
|
230
|
+
const archive = inspectDumpArchive(database, { mode: 'schema-only' });
|
|
231
|
+
for (const entry of archive.entries) {
|
|
232
|
+
console.log(entry.sequenceNumber, entry.section, entry.objectType, entry.name);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Render schema only, into memory, with no database access.
|
|
236
|
+
const writer = new BufferDumpWriter();
|
|
237
|
+
await renderPlainSql({ database, archive, writer, mode: 'schema-only', sourceVersion: version });
|
|
238
|
+
console.log(writer.toString());
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
`exportTableDataAsInserts` streams one table's rows on its own:
|
|
242
|
+
|
|
243
|
+
```ts
|
|
244
|
+
import { exportTableDataAsInserts } from 'dbgate-sqlite-dumper';
|
|
245
|
+
|
|
246
|
+
await exportTableDataAsInserts({
|
|
247
|
+
connection,
|
|
248
|
+
schemaName: 'main',
|
|
249
|
+
table: database.tables.find(table => table.name === 'orders')!,
|
|
250
|
+
writer,
|
|
251
|
+
options: { extendedInsert: true },
|
|
252
|
+
});
|
|
253
|
+
```
|