@remix-run/data-table-sqlite 0.4.1 → 0.5.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/README.md +6 -8
- package/dist/lib/adapter.d.ts +9 -8
- package/dist/lib/adapter.d.ts.map +1 -1
- package/dist/lib/adapter.js +15 -383
- package/package.json +5 -5
- package/src/lib/adapter.ts +17 -456
package/README.md
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
# data-table-sqlite
|
|
2
2
|
|
|
3
|
-
SQLite adapter for [`remix/data-table`](https://github.com/remix-run/remix/tree/main/packages/data-table).
|
|
4
|
-
Use this package when you want `data-table` APIs backed by a synchronous SQLite client.
|
|
3
|
+
SQLite adapter for [`remix/data-table`](https://github.com/remix-run/remix/tree/main/packages/data-table). Use this package when you want `data-table` APIs backed by a synchronous SQLite client.
|
|
5
4
|
|
|
6
5
|
## Features
|
|
7
6
|
|
|
8
7
|
- **Native Runtime SQLite Support**: Works with Node's `node:sqlite` `DatabaseSync`, Bun's `bun:sqlite` `Database`, and compatible synchronous SQLite clients
|
|
9
8
|
- **Full `data-table` API Support**: Queries, relations, writes, and transactions
|
|
10
9
|
- **Adapter-Owned Compiler**: SQL compilation lives in this adapter, with optional shared pure helpers from `data-table`
|
|
11
|
-
- **
|
|
10
|
+
- **Multi-Statement Migrations**: `executeScript()` runs `up.sql` / `down.sql` files via `Database.exec()`
|
|
12
11
|
- **SQLite Capabilities Enabled By Default**:
|
|
13
12
|
- `returning: true`
|
|
14
13
|
- `savepoints: true`
|
|
@@ -29,7 +28,7 @@ npm i remix
|
|
|
29
28
|
```ts
|
|
30
29
|
import { DatabaseSync } from 'node:sqlite'
|
|
31
30
|
import { createDatabase } from 'remix/data-table'
|
|
32
|
-
import { createSqliteDatabaseAdapter } from 'remix/data-table
|
|
31
|
+
import { createSqliteDatabaseAdapter } from 'remix/data-table/sqlite'
|
|
33
32
|
|
|
34
33
|
let sqlite = new DatabaseSync('app.db')
|
|
35
34
|
let db = createDatabase(createSqliteDatabaseAdapter(sqlite))
|
|
@@ -40,14 +39,13 @@ let db = createDatabase(createSqliteDatabaseAdapter(sqlite))
|
|
|
40
39
|
```ts
|
|
41
40
|
import { Database } from 'bun:sqlite'
|
|
42
41
|
import { createDatabase } from 'remix/data-table'
|
|
43
|
-
import { createSqliteDatabaseAdapter } from 'remix/data-table
|
|
42
|
+
import { createSqliteDatabaseAdapter } from 'remix/data-table/sqlite'
|
|
44
43
|
|
|
45
44
|
let sqlite = new Database('app.db')
|
|
46
45
|
let db = createDatabase(createSqliteDatabaseAdapter(sqlite))
|
|
47
46
|
```
|
|
48
47
|
|
|
49
|
-
This is a good fit for local development, embedded deployments, and single-node services.
|
|
50
|
-
Import any driver-specific types you need directly from your runtime's SQLite module.
|
|
48
|
+
This is a good fit for local development, embedded deployments, and single-node services. Import any driver-specific types you need directly from your runtime's SQLite module.
|
|
51
49
|
|
|
52
50
|
## Adapter Capabilities
|
|
53
51
|
|
|
@@ -66,7 +64,7 @@ Import any driver-specific types you need directly from your runtime's SQLite mo
|
|
|
66
64
|
```ts
|
|
67
65
|
import { DatabaseSync } from 'node:sqlite'
|
|
68
66
|
import { createDatabase } from 'remix/data-table'
|
|
69
|
-
import { createSqliteDatabaseAdapter } from 'remix/data-table
|
|
67
|
+
import { createSqliteDatabaseAdapter } from 'remix/data-table/sqlite'
|
|
70
68
|
|
|
71
69
|
let sqlite = new DatabaseSync(':memory:')
|
|
72
70
|
let db = createDatabase(createSqliteDatabaseAdapter(sqlite))
|
package/dist/lib/adapter.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DataManipulationRequest,
|
|
1
|
+
import type { DataManipulationRequest, DataManipulationResult, DataManipulationOperation, DatabaseAdapter, SqlStatement, TableRef, TransactionOptions, TransactionToken } from '@remix-run/data-table';
|
|
2
2
|
/**
|
|
3
3
|
* Synchronous SQLite database client accepted by the sqlite adapter.
|
|
4
4
|
*
|
|
@@ -48,11 +48,11 @@ export declare class SqliteDatabaseAdapter implements DatabaseAdapter {
|
|
|
48
48
|
};
|
|
49
49
|
constructor(database: SqliteDatabase);
|
|
50
50
|
/**
|
|
51
|
-
* Compiles a data
|
|
51
|
+
* Compiles a data-manipulation operation to sqlite SQL statements.
|
|
52
52
|
* @param operation Operation to compile.
|
|
53
53
|
* @returns Compiled SQL statements.
|
|
54
54
|
*/
|
|
55
|
-
compileSql(operation: DataManipulationOperation
|
|
55
|
+
compileSql(operation: DataManipulationOperation): SqlStatement[];
|
|
56
56
|
/**
|
|
57
57
|
* Executes a sqlite data-manipulation request.
|
|
58
58
|
* @param request Request to execute.
|
|
@@ -60,11 +60,12 @@ export declare class SqliteDatabaseAdapter implements DatabaseAdapter {
|
|
|
60
60
|
*/
|
|
61
61
|
execute(request: DataManipulationRequest): Promise<DataManipulationResult>;
|
|
62
62
|
/**
|
|
63
|
-
* Executes sqlite
|
|
64
|
-
* @param
|
|
65
|
-
* @
|
|
63
|
+
* Executes a multi-statement sqlite SQL script.
|
|
64
|
+
* @param sql SQL script to execute.
|
|
65
|
+
* @param transaction Optional transaction token (asserted when present).
|
|
66
|
+
* @returns A promise that resolves once execution completes.
|
|
66
67
|
*/
|
|
67
|
-
|
|
68
|
+
executeScript(sql: string, transaction?: TransactionToken): Promise<void>;
|
|
68
69
|
/**
|
|
69
70
|
* Checks whether a table exists in sqlite.
|
|
70
71
|
* @param table Table reference to inspect.
|
|
@@ -128,7 +129,7 @@ export declare class SqliteDatabaseAdapter implements DatabaseAdapter {
|
|
|
128
129
|
* ```ts
|
|
129
130
|
* import { DatabaseSync } from 'node:sqlite'
|
|
130
131
|
* import { createDatabase } from 'remix/data-table'
|
|
131
|
-
* import { createSqliteDatabaseAdapter } from 'remix/data-table
|
|
132
|
+
* import { createSqliteDatabaseAdapter } from 'remix/data-table/sqlite'
|
|
132
133
|
*
|
|
133
134
|
* let sqlite = new DatabaseSync('./data/app.db')
|
|
134
135
|
* let adapter = createSqliteDatabaseAdapter(sqlite)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../src/lib/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,uBAAuB,EACvB,
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../src/lib/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,uBAAuB,EACvB,sBAAsB,EACtB,yBAAyB,EACzB,eAAe,EACf,YAAY,EACZ,QAAQ,EACR,kBAAkB,EAClB,gBAAgB,EACjB,MAAM,uBAAuB,CAAA;AAK9B;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,CAAA;IACrC,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,GAAG,CAAC,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,EAAE,CAAA;IACpC,GAAG,CAAC,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAA;IAClC,GAAG,CAAC,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,eAAe,CAAA;IAC1C,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,OAAO,EAAE,CAAA;IACzB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,GAAG,MAAM,CAAA;IACxB,eAAe,EAAE,OAAO,CAAA;CACzB;AAED;;GAEG;AACH,qBAAa,qBAAsB,YAAW,eAAe;;IAC3D;;OAEG;IACH,OAAO,SAAW;IAElB;;OAEG;IACH,YAAY;;;;;;MAAA;IAMZ,YAAY,QAAQ,EAAE,cAAc,EASnC;IAED;;;;OAIG;IACH,UAAU,CAAC,SAAS,EAAE,yBAAyB,GAAG,YAAY,EAAE,CAG/D;IAED;;;;OAIG;IACG,OAAO,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAqC/E;IAED;;;;;OAKG;IACG,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAM9E;IAED;;;;;OAKG;IACG,QAAQ,CAAC,KAAK,EAAE,QAAQ,EAAE,WAAW,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC,CAahF;IAED;;;;;;OAMG;IACG,SAAS,CACb,KAAK,EAAE,QAAQ,EACf,MAAM,EAAE,MAAM,EACd,WAAW,CAAC,EAAE,gBAAgB,GAC7B,OAAO,CAAC,OAAO,CAAC,CAYlB;IAED;;;;OAIG;IACG,gBAAgB,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAY9E;IAED;;;;OAIG;IACG,iBAAiB,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAI9D;IAED;;;;OAIG;IACG,mBAAmB,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAIhE;IAED;;;;;OAKG;IACG,eAAe,CAAC,KAAK,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAG1E;IAED;;;;;OAKG;IACG,mBAAmB,CAAC,KAAK,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAG9E;IAED;;;;;OAKG;IACG,gBAAgB,CAAC,KAAK,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAG3E;CAOF;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,cAAc,GAAG,qBAAqB,CAE3F"}
|
package/dist/lib/adapter.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { getTablePrimaryKey } from '@remix-run/data-table';
|
|
2
|
-
import { isDataManipulationOperation as isDataManipulationOperationHelper, quoteLiteral as quoteLiteralHelper, quoteTableRef as quoteTableRefHelper, } from '@remix-run/data-table/sql-helpers';
|
|
3
2
|
import { compileSqliteOperation } from "./sql-compiler.js";
|
|
4
3
|
/**
|
|
5
4
|
* `DatabaseAdapter` implementation for synchronous SQLite clients.
|
|
@@ -27,16 +26,13 @@ export class SqliteDatabaseAdapter {
|
|
|
27
26
|
};
|
|
28
27
|
}
|
|
29
28
|
/**
|
|
30
|
-
* Compiles a data
|
|
29
|
+
* Compiles a data-manipulation operation to sqlite SQL statements.
|
|
31
30
|
* @param operation Operation to compile.
|
|
32
31
|
* @returns Compiled SQL statements.
|
|
33
32
|
*/
|
|
34
33
|
compileSql(operation) {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
return [{ text: compiled.text, values: compiled.values }];
|
|
38
|
-
}
|
|
39
|
-
return compileSqliteMigrationOperations(operation);
|
|
34
|
+
let compiled = compileSqliteOperation(operation);
|
|
35
|
+
return [{ text: compiled.text, values: compiled.values }];
|
|
40
36
|
}
|
|
41
37
|
/**
|
|
42
38
|
* Executes a sqlite data-manipulation request.
|
|
@@ -51,6 +47,9 @@ export class SqliteDatabaseAdapter {
|
|
|
51
47
|
rows: request.operation.returning ? [] : undefined,
|
|
52
48
|
};
|
|
53
49
|
}
|
|
50
|
+
if (request.transaction) {
|
|
51
|
+
this.#assertTransaction(request.transaction);
|
|
52
|
+
}
|
|
54
53
|
let statement = this.compileSql(request.operation)[0];
|
|
55
54
|
let prepared = this.#database.prepare(statement.text);
|
|
56
55
|
let values = normalizeStatementValues(statement.values);
|
|
@@ -72,19 +71,16 @@ export class SqliteDatabaseAdapter {
|
|
|
72
71
|
};
|
|
73
72
|
}
|
|
74
73
|
/**
|
|
75
|
-
* Executes sqlite
|
|
76
|
-
* @param
|
|
77
|
-
* @
|
|
74
|
+
* Executes a multi-statement sqlite SQL script.
|
|
75
|
+
* @param sql SQL script to execute.
|
|
76
|
+
* @param transaction Optional transaction token (asserted when present).
|
|
77
|
+
* @returns A promise that resolves once execution completes.
|
|
78
78
|
*/
|
|
79
|
-
async
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
let prepared = this.#database.prepare(statement.text);
|
|
83
|
-
prepared.run(...normalizeStatementValues(statement.values));
|
|
79
|
+
async executeScript(sql, transaction) {
|
|
80
|
+
if (transaction) {
|
|
81
|
+
this.#assertTransaction(transaction);
|
|
84
82
|
}
|
|
85
|
-
|
|
86
|
-
affectedOperations: statements.length,
|
|
87
|
-
};
|
|
83
|
+
this.#database.exec(sql);
|
|
88
84
|
}
|
|
89
85
|
/**
|
|
90
86
|
* Checks whether a table exists in sqlite.
|
|
@@ -198,7 +194,7 @@ export class SqliteDatabaseAdapter {
|
|
|
198
194
|
* ```ts
|
|
199
195
|
* import { DatabaseSync } from 'node:sqlite'
|
|
200
196
|
* import { createDatabase } from 'remix/data-table'
|
|
201
|
-
* import { createSqliteDatabaseAdapter } from 'remix/data-table
|
|
197
|
+
* import { createSqliteDatabaseAdapter } from 'remix/data-table/sqlite'
|
|
202
198
|
*
|
|
203
199
|
* let sqlite = new DatabaseSync('./data/app.db')
|
|
204
200
|
* let adapter = createSqliteDatabaseAdapter(sqlite)
|
|
@@ -296,12 +292,6 @@ function shouldReadStatement(operation, statement) {
|
|
|
296
292
|
function quoteIdentifier(value) {
|
|
297
293
|
return '"' + value.replace(/"/g, '""') + '"';
|
|
298
294
|
}
|
|
299
|
-
function quoteTableRef(table) {
|
|
300
|
-
return quoteTableRefHelper(table, quoteIdentifier);
|
|
301
|
-
}
|
|
302
|
-
function quoteLiteral(value) {
|
|
303
|
-
return quoteLiteralHelper(value, { booleansAsIntegers: true });
|
|
304
|
-
}
|
|
305
295
|
function isWriteOperationKind(kind) {
|
|
306
296
|
return (kind === 'insert' ||
|
|
307
297
|
kind === 'insertMany' ||
|
|
@@ -315,361 +305,3 @@ function isInsertOperationKind(kind) {
|
|
|
315
305
|
function isInsertOperation(operation) {
|
|
316
306
|
return (operation.kind === 'insert' || operation.kind === 'insertMany' || operation.kind === 'upsert');
|
|
317
307
|
}
|
|
318
|
-
function isDataManipulationOperation(operation) {
|
|
319
|
-
return isDataManipulationOperationHelper(operation);
|
|
320
|
-
}
|
|
321
|
-
function compileSqliteMigrationOperations(operation) {
|
|
322
|
-
if (operation.kind === 'raw') {
|
|
323
|
-
return [{ text: operation.sql.text, values: [...operation.sql.values] }];
|
|
324
|
-
}
|
|
325
|
-
if (operation.kind === 'createTable') {
|
|
326
|
-
let columns = Object.keys(operation.columns).map((columnName) => quoteIdentifier(columnName) + ' ' + compileSqliteColumn(operation.columns[columnName]));
|
|
327
|
-
let constraints = [];
|
|
328
|
-
if (operation.primaryKey) {
|
|
329
|
-
constraints.push('constraint ' +
|
|
330
|
-
quoteIdentifier(operation.primaryKey.name) +
|
|
331
|
-
' primary key (' +
|
|
332
|
-
operation.primaryKey.columns.map((column) => quoteIdentifier(column)).join(', ') +
|
|
333
|
-
')');
|
|
334
|
-
}
|
|
335
|
-
for (let unique of operation.uniques ?? []) {
|
|
336
|
-
constraints.push('constraint ' +
|
|
337
|
-
quoteIdentifier(unique.name) +
|
|
338
|
-
' ' +
|
|
339
|
-
'unique (' +
|
|
340
|
-
unique.columns.map((column) => quoteIdentifier(column)).join(', ') +
|
|
341
|
-
')');
|
|
342
|
-
}
|
|
343
|
-
for (let check of operation.checks ?? []) {
|
|
344
|
-
constraints.push('constraint ' + quoteIdentifier(check.name) + ' ' + 'check (' + check.expression + ')');
|
|
345
|
-
}
|
|
346
|
-
for (let foreignKey of operation.foreignKeys ?? []) {
|
|
347
|
-
let clause = 'constraint ' +
|
|
348
|
-
quoteIdentifier(foreignKey.name) +
|
|
349
|
-
' ' +
|
|
350
|
-
'foreign key (' +
|
|
351
|
-
foreignKey.columns.map((column) => quoteIdentifier(column)).join(', ') +
|
|
352
|
-
') references ' +
|
|
353
|
-
quoteTableRef(foreignKey.references.table) +
|
|
354
|
-
' (' +
|
|
355
|
-
foreignKey.references.columns.map((column) => quoteIdentifier(column)).join(', ') +
|
|
356
|
-
')';
|
|
357
|
-
if (foreignKey.onDelete) {
|
|
358
|
-
clause += ' on delete ' + foreignKey.onDelete;
|
|
359
|
-
}
|
|
360
|
-
if (foreignKey.onUpdate) {
|
|
361
|
-
clause += ' on update ' + foreignKey.onUpdate;
|
|
362
|
-
}
|
|
363
|
-
constraints.push(clause);
|
|
364
|
-
}
|
|
365
|
-
return [
|
|
366
|
-
{
|
|
367
|
-
text: 'create table ' +
|
|
368
|
-
(operation.ifNotExists ? 'if not exists ' : '') +
|
|
369
|
-
quoteTableRef(operation.table) +
|
|
370
|
-
' (' +
|
|
371
|
-
[...columns, ...constraints].join(', ') +
|
|
372
|
-
')',
|
|
373
|
-
values: [],
|
|
374
|
-
},
|
|
375
|
-
];
|
|
376
|
-
}
|
|
377
|
-
if (operation.kind === 'alterTable') {
|
|
378
|
-
let statements = [];
|
|
379
|
-
for (let change of operation.changes) {
|
|
380
|
-
let sql = 'alter table ' + quoteTableRef(operation.table) + ' ';
|
|
381
|
-
if (change.kind === 'addColumn') {
|
|
382
|
-
sql +=
|
|
383
|
-
'add column ' +
|
|
384
|
-
quoteIdentifier(change.column) +
|
|
385
|
-
' ' +
|
|
386
|
-
compileSqliteColumn(change.definition);
|
|
387
|
-
}
|
|
388
|
-
else if (change.kind === 'changeColumn') {
|
|
389
|
-
sql +=
|
|
390
|
-
'alter column ' +
|
|
391
|
-
quoteIdentifier(change.column) +
|
|
392
|
-
' type ' +
|
|
393
|
-
compileSqliteColumnType(change.definition);
|
|
394
|
-
}
|
|
395
|
-
else if (change.kind === 'renameColumn') {
|
|
396
|
-
sql += 'rename column ' + quoteIdentifier(change.from) + ' to ' + quoteIdentifier(change.to);
|
|
397
|
-
}
|
|
398
|
-
else if (change.kind === 'dropColumn') {
|
|
399
|
-
sql += 'drop column ' + quoteIdentifier(change.column);
|
|
400
|
-
}
|
|
401
|
-
else if (change.kind === 'addPrimaryKey') {
|
|
402
|
-
sql +=
|
|
403
|
-
'add primary key (' +
|
|
404
|
-
change.constraint.columns.map((column) => quoteIdentifier(column)).join(', ') +
|
|
405
|
-
')';
|
|
406
|
-
}
|
|
407
|
-
else if (change.kind === 'dropPrimaryKey') {
|
|
408
|
-
sql += 'drop primary key';
|
|
409
|
-
}
|
|
410
|
-
else if (change.kind === 'addUnique') {
|
|
411
|
-
sql +=
|
|
412
|
-
'add ' +
|
|
413
|
-
'constraint ' +
|
|
414
|
-
quoteIdentifier(change.constraint.name) +
|
|
415
|
-
' ' +
|
|
416
|
-
'unique (' +
|
|
417
|
-
change.constraint.columns.map((column) => quoteIdentifier(column)).join(', ') +
|
|
418
|
-
')';
|
|
419
|
-
}
|
|
420
|
-
else if (change.kind === 'dropUnique') {
|
|
421
|
-
sql += 'drop constraint ' + quoteIdentifier(change.name);
|
|
422
|
-
}
|
|
423
|
-
else if (change.kind === 'addForeignKey') {
|
|
424
|
-
sql +=
|
|
425
|
-
'add ' +
|
|
426
|
-
'constraint ' +
|
|
427
|
-
quoteIdentifier(change.constraint.name) +
|
|
428
|
-
' ' +
|
|
429
|
-
'foreign key (' +
|
|
430
|
-
change.constraint.columns.map((column) => quoteIdentifier(column)).join(', ') +
|
|
431
|
-
') references ' +
|
|
432
|
-
quoteTableRef(change.constraint.references.table) +
|
|
433
|
-
' (' +
|
|
434
|
-
change.constraint.references.columns.map((column) => quoteIdentifier(column)).join(', ') +
|
|
435
|
-
')';
|
|
436
|
-
}
|
|
437
|
-
else if (change.kind === 'dropForeignKey') {
|
|
438
|
-
sql += 'drop constraint ' + quoteIdentifier(change.name);
|
|
439
|
-
}
|
|
440
|
-
else if (change.kind === 'addCheck') {
|
|
441
|
-
sql +=
|
|
442
|
-
'add ' +
|
|
443
|
-
'constraint ' +
|
|
444
|
-
quoteIdentifier(change.constraint.name) +
|
|
445
|
-
' ' +
|
|
446
|
-
'check (' +
|
|
447
|
-
change.constraint.expression +
|
|
448
|
-
')';
|
|
449
|
-
}
|
|
450
|
-
else if (change.kind === 'dropCheck') {
|
|
451
|
-
sql += 'drop constraint ' + quoteIdentifier(change.name);
|
|
452
|
-
}
|
|
453
|
-
else if (change.kind === 'setTableComment') {
|
|
454
|
-
continue;
|
|
455
|
-
}
|
|
456
|
-
else {
|
|
457
|
-
continue;
|
|
458
|
-
}
|
|
459
|
-
statements.push({ text: sql, values: [] });
|
|
460
|
-
}
|
|
461
|
-
return statements;
|
|
462
|
-
}
|
|
463
|
-
if (operation.kind === 'renameTable') {
|
|
464
|
-
return [
|
|
465
|
-
{
|
|
466
|
-
text: 'alter table ' +
|
|
467
|
-
quoteTableRef(operation.from) +
|
|
468
|
-
' rename to ' +
|
|
469
|
-
quoteIdentifier(operation.to.name),
|
|
470
|
-
values: [],
|
|
471
|
-
},
|
|
472
|
-
];
|
|
473
|
-
}
|
|
474
|
-
if (operation.kind === 'dropTable') {
|
|
475
|
-
return [
|
|
476
|
-
{
|
|
477
|
-
text: 'drop table ' + (operation.ifExists ? 'if exists ' : '') + quoteTableRef(operation.table),
|
|
478
|
-
values: [],
|
|
479
|
-
},
|
|
480
|
-
];
|
|
481
|
-
}
|
|
482
|
-
if (operation.kind === 'createIndex') {
|
|
483
|
-
return [
|
|
484
|
-
{
|
|
485
|
-
text: 'create ' +
|
|
486
|
-
(operation.index.unique ? 'unique ' : '') +
|
|
487
|
-
'index ' +
|
|
488
|
-
(operation.ifNotExists ? 'if not exists ' : '') +
|
|
489
|
-
quoteIdentifier(operation.index.name) +
|
|
490
|
-
' on ' +
|
|
491
|
-
quoteTableRef(operation.index.table) +
|
|
492
|
-
' (' +
|
|
493
|
-
operation.index.columns.map((column) => quoteIdentifier(column)).join(', ') +
|
|
494
|
-
')' +
|
|
495
|
-
(operation.index.where ? ' where ' + operation.index.where : ''),
|
|
496
|
-
values: [],
|
|
497
|
-
},
|
|
498
|
-
];
|
|
499
|
-
}
|
|
500
|
-
if (operation.kind === 'dropIndex') {
|
|
501
|
-
return [
|
|
502
|
-
{
|
|
503
|
-
text: 'drop index ' +
|
|
504
|
-
(operation.ifExists ? 'if exists ' : '') +
|
|
505
|
-
quoteIdentifier(operation.name),
|
|
506
|
-
values: [],
|
|
507
|
-
},
|
|
508
|
-
];
|
|
509
|
-
}
|
|
510
|
-
if (operation.kind === 'renameIndex') {
|
|
511
|
-
return [
|
|
512
|
-
{
|
|
513
|
-
text: 'alter table ' +
|
|
514
|
-
quoteTableRef(operation.table) +
|
|
515
|
-
' rename index ' +
|
|
516
|
-
quoteIdentifier(operation.from) +
|
|
517
|
-
' to ' +
|
|
518
|
-
quoteIdentifier(operation.to),
|
|
519
|
-
values: [],
|
|
520
|
-
},
|
|
521
|
-
];
|
|
522
|
-
}
|
|
523
|
-
if (operation.kind === 'addForeignKey') {
|
|
524
|
-
return [
|
|
525
|
-
{
|
|
526
|
-
text: 'alter table ' +
|
|
527
|
-
quoteTableRef(operation.table) +
|
|
528
|
-
' add ' +
|
|
529
|
-
'constraint ' +
|
|
530
|
-
quoteIdentifier(operation.constraint.name) +
|
|
531
|
-
' ' +
|
|
532
|
-
'foreign key (' +
|
|
533
|
-
operation.constraint.columns.map((column) => quoteIdentifier(column)).join(', ') +
|
|
534
|
-
') references ' +
|
|
535
|
-
quoteTableRef(operation.constraint.references.table) +
|
|
536
|
-
' (' +
|
|
537
|
-
operation.constraint.references.columns
|
|
538
|
-
.map((column) => quoteIdentifier(column))
|
|
539
|
-
.join(', ') +
|
|
540
|
-
')' +
|
|
541
|
-
(operation.constraint.onDelete ? ' on delete ' + operation.constraint.onDelete : '') +
|
|
542
|
-
(operation.constraint.onUpdate ? ' on update ' + operation.constraint.onUpdate : ''),
|
|
543
|
-
values: [],
|
|
544
|
-
},
|
|
545
|
-
];
|
|
546
|
-
}
|
|
547
|
-
if (operation.kind === 'dropForeignKey') {
|
|
548
|
-
return [
|
|
549
|
-
{
|
|
550
|
-
text: 'alter table ' +
|
|
551
|
-
quoteTableRef(operation.table) +
|
|
552
|
-
' drop constraint ' +
|
|
553
|
-
quoteIdentifier(operation.name),
|
|
554
|
-
values: [],
|
|
555
|
-
},
|
|
556
|
-
];
|
|
557
|
-
}
|
|
558
|
-
if (operation.kind === 'addCheck') {
|
|
559
|
-
return [
|
|
560
|
-
{
|
|
561
|
-
text: 'alter table ' +
|
|
562
|
-
quoteTableRef(operation.table) +
|
|
563
|
-
' add ' +
|
|
564
|
-
'constraint ' +
|
|
565
|
-
quoteIdentifier(operation.constraint.name) +
|
|
566
|
-
' ' +
|
|
567
|
-
'check (' +
|
|
568
|
-
operation.constraint.expression +
|
|
569
|
-
')',
|
|
570
|
-
values: [],
|
|
571
|
-
},
|
|
572
|
-
];
|
|
573
|
-
}
|
|
574
|
-
if (operation.kind === 'dropCheck') {
|
|
575
|
-
return [
|
|
576
|
-
{
|
|
577
|
-
text: 'alter table ' +
|
|
578
|
-
quoteTableRef(operation.table) +
|
|
579
|
-
' drop constraint ' +
|
|
580
|
-
quoteIdentifier(operation.name),
|
|
581
|
-
values: [],
|
|
582
|
-
},
|
|
583
|
-
];
|
|
584
|
-
}
|
|
585
|
-
throw new Error('Unsupported data migration operation kind');
|
|
586
|
-
}
|
|
587
|
-
function compileSqliteColumn(definition) {
|
|
588
|
-
let parts = [compileSqliteColumnType(definition)];
|
|
589
|
-
if (definition.nullable === false) {
|
|
590
|
-
parts.push('not null');
|
|
591
|
-
}
|
|
592
|
-
if (definition.default) {
|
|
593
|
-
if (definition.default.kind === 'now') {
|
|
594
|
-
parts.push('default current_timestamp');
|
|
595
|
-
}
|
|
596
|
-
else if (definition.default.kind === 'sql') {
|
|
597
|
-
parts.push('default ' + definition.default.expression);
|
|
598
|
-
}
|
|
599
|
-
else {
|
|
600
|
-
parts.push('default ' + quoteLiteral(definition.default.value));
|
|
601
|
-
}
|
|
602
|
-
}
|
|
603
|
-
if (definition.primaryKey) {
|
|
604
|
-
parts.push('primary key');
|
|
605
|
-
}
|
|
606
|
-
if (definition.unique) {
|
|
607
|
-
parts.push('unique');
|
|
608
|
-
}
|
|
609
|
-
if (definition.computed) {
|
|
610
|
-
parts.push('generated always as (' + definition.computed.expression + ')');
|
|
611
|
-
parts.push(definition.computed.stored ? 'stored' : 'virtual');
|
|
612
|
-
}
|
|
613
|
-
if (definition.references) {
|
|
614
|
-
let clause = 'references ' +
|
|
615
|
-
quoteTableRef(definition.references.table) +
|
|
616
|
-
' (' +
|
|
617
|
-
definition.references.columns.map((column) => quoteIdentifier(column)).join(', ') +
|
|
618
|
-
')';
|
|
619
|
-
if (definition.references.onDelete) {
|
|
620
|
-
clause += ' on delete ' + definition.references.onDelete;
|
|
621
|
-
}
|
|
622
|
-
if (definition.references.onUpdate) {
|
|
623
|
-
clause += ' on update ' + definition.references.onUpdate;
|
|
624
|
-
}
|
|
625
|
-
parts.push(clause);
|
|
626
|
-
}
|
|
627
|
-
if (definition.checks && definition.checks.length > 0) {
|
|
628
|
-
for (let check of definition.checks) {
|
|
629
|
-
parts.push('check (' + check.expression + ')');
|
|
630
|
-
}
|
|
631
|
-
}
|
|
632
|
-
return parts.join(' ');
|
|
633
|
-
}
|
|
634
|
-
function compileSqliteColumnType(definition) {
|
|
635
|
-
if (definition.type === 'varchar') {
|
|
636
|
-
return 'text';
|
|
637
|
-
}
|
|
638
|
-
if (definition.type === 'text') {
|
|
639
|
-
return 'text';
|
|
640
|
-
}
|
|
641
|
-
if (definition.type === 'integer') {
|
|
642
|
-
return 'integer';
|
|
643
|
-
}
|
|
644
|
-
if (definition.type === 'bigint') {
|
|
645
|
-
return 'integer';
|
|
646
|
-
}
|
|
647
|
-
if (definition.type === 'decimal') {
|
|
648
|
-
return 'numeric';
|
|
649
|
-
}
|
|
650
|
-
if (definition.type === 'boolean') {
|
|
651
|
-
return 'integer';
|
|
652
|
-
}
|
|
653
|
-
if (definition.type === 'uuid') {
|
|
654
|
-
return 'text';
|
|
655
|
-
}
|
|
656
|
-
if (definition.type === 'date') {
|
|
657
|
-
return 'text';
|
|
658
|
-
}
|
|
659
|
-
if (definition.type === 'time') {
|
|
660
|
-
return 'text';
|
|
661
|
-
}
|
|
662
|
-
if (definition.type === 'timestamp') {
|
|
663
|
-
return 'text';
|
|
664
|
-
}
|
|
665
|
-
if (definition.type === 'json') {
|
|
666
|
-
return 'text';
|
|
667
|
-
}
|
|
668
|
-
if (definition.type === 'binary') {
|
|
669
|
-
return 'blob';
|
|
670
|
-
}
|
|
671
|
-
if (definition.type === 'enum') {
|
|
672
|
-
return 'text';
|
|
673
|
-
}
|
|
674
|
-
return 'text';
|
|
675
|
-
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remix-run/data-table-sqlite",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "SQLite adapter for remix/data-table",
|
|
5
5
|
"author": "Michael Jackson <mjijackson@gmail.com>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -29,12 +29,12 @@
|
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"@types/node": "^24.6.0",
|
|
31
31
|
"@typescript/native-preview": "7.0.0-dev.20251125.1",
|
|
32
|
-
"@remix-run/assert": "0.2.
|
|
33
|
-
"@remix-run/
|
|
34
|
-
"@remix-run/
|
|
32
|
+
"@remix-run/assert": "0.2.1",
|
|
33
|
+
"@remix-run/data-table": "0.3.0",
|
|
34
|
+
"@remix-run/test": "0.4.2"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@remix-run/data-table": "^0.
|
|
37
|
+
"@remix-run/data-table": "^0.3.0"
|
|
38
38
|
},
|
|
39
39
|
"keywords": [
|
|
40
40
|
"remix",
|
package/src/lib/adapter.ts
CHANGED
|
@@ -1,23 +1,14 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
DataManipulationRequest,
|
|
3
|
-
DataMigrationRequest,
|
|
4
|
-
DataMigrationResult,
|
|
5
|
-
DataMigrationOperation,
|
|
6
3
|
DataManipulationResult,
|
|
7
4
|
DataManipulationOperation,
|
|
8
5
|
DatabaseAdapter,
|
|
9
|
-
ColumnDefinition,
|
|
10
6
|
SqlStatement,
|
|
11
7
|
TableRef,
|
|
12
8
|
TransactionOptions,
|
|
13
9
|
TransactionToken,
|
|
14
10
|
} from '@remix-run/data-table'
|
|
15
11
|
import { getTablePrimaryKey } from '@remix-run/data-table'
|
|
16
|
-
import {
|
|
17
|
-
isDataManipulationOperation as isDataManipulationOperationHelper,
|
|
18
|
-
quoteLiteral as quoteLiteralHelper,
|
|
19
|
-
quoteTableRef as quoteTableRefHelper,
|
|
20
|
-
} from '@remix-run/data-table/sql-helpers'
|
|
21
12
|
|
|
22
13
|
import { compileSqliteOperation } from './sql-compiler.ts'
|
|
23
14
|
|
|
@@ -82,17 +73,13 @@ export class SqliteDatabaseAdapter implements DatabaseAdapter {
|
|
|
82
73
|
}
|
|
83
74
|
|
|
84
75
|
/**
|
|
85
|
-
* Compiles a data
|
|
76
|
+
* Compiles a data-manipulation operation to sqlite SQL statements.
|
|
86
77
|
* @param operation Operation to compile.
|
|
87
78
|
* @returns Compiled SQL statements.
|
|
88
79
|
*/
|
|
89
|
-
compileSql(operation: DataManipulationOperation
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
return [{ text: compiled.text, values: compiled.values }]
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
return compileSqliteMigrationOperations(operation)
|
|
80
|
+
compileSql(operation: DataManipulationOperation): SqlStatement[] {
|
|
81
|
+
let compiled = compileSqliteOperation(operation)
|
|
82
|
+
return [{ text: compiled.text, values: compiled.values }]
|
|
96
83
|
}
|
|
97
84
|
|
|
98
85
|
/**
|
|
@@ -109,6 +96,10 @@ export class SqliteDatabaseAdapter implements DatabaseAdapter {
|
|
|
109
96
|
}
|
|
110
97
|
}
|
|
111
98
|
|
|
99
|
+
if (request.transaction) {
|
|
100
|
+
this.#assertTransaction(request.transaction)
|
|
101
|
+
}
|
|
102
|
+
|
|
112
103
|
let statement = this.compileSql(request.operation)[0]
|
|
113
104
|
let prepared = this.#database.prepare(statement.text)
|
|
114
105
|
let values = normalizeStatementValues(statement.values)
|
|
@@ -136,21 +127,17 @@ export class SqliteDatabaseAdapter implements DatabaseAdapter {
|
|
|
136
127
|
}
|
|
137
128
|
|
|
138
129
|
/**
|
|
139
|
-
* Executes sqlite
|
|
140
|
-
* @param
|
|
141
|
-
* @
|
|
130
|
+
* Executes a multi-statement sqlite SQL script.
|
|
131
|
+
* @param sql SQL script to execute.
|
|
132
|
+
* @param transaction Optional transaction token (asserted when present).
|
|
133
|
+
* @returns A promise that resolves once execution completes.
|
|
142
134
|
*/
|
|
143
|
-
async
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
for (let statement of statements) {
|
|
147
|
-
let prepared = this.#database.prepare(statement.text)
|
|
148
|
-
prepared.run(...normalizeStatementValues(statement.values))
|
|
135
|
+
async executeScript(sql: string, transaction?: TransactionToken): Promise<void> {
|
|
136
|
+
if (transaction) {
|
|
137
|
+
this.#assertTransaction(transaction)
|
|
149
138
|
}
|
|
150
139
|
|
|
151
|
-
|
|
152
|
-
affectedOperations: statements.length,
|
|
153
|
-
}
|
|
140
|
+
this.#database.exec(sql)
|
|
154
141
|
}
|
|
155
142
|
|
|
156
143
|
/**
|
|
@@ -288,7 +275,7 @@ export class SqliteDatabaseAdapter implements DatabaseAdapter {
|
|
|
288
275
|
* ```ts
|
|
289
276
|
* import { DatabaseSync } from 'node:sqlite'
|
|
290
277
|
* import { createDatabase } from 'remix/data-table'
|
|
291
|
-
* import { createSqliteDatabaseAdapter } from 'remix/data-table
|
|
278
|
+
* import { createSqliteDatabaseAdapter } from 'remix/data-table/sqlite'
|
|
292
279
|
*
|
|
293
280
|
* let sqlite = new DatabaseSync('./data/app.db')
|
|
294
281
|
* let adapter = createSqliteDatabaseAdapter(sqlite)
|
|
@@ -429,14 +416,6 @@ function quoteIdentifier(value: string): string {
|
|
|
429
416
|
return '"' + value.replace(/"/g, '""') + '"'
|
|
430
417
|
}
|
|
431
418
|
|
|
432
|
-
function quoteTableRef(table: TableRef): string {
|
|
433
|
-
return quoteTableRefHelper(table, quoteIdentifier)
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
function quoteLiteral(value: unknown): string {
|
|
437
|
-
return quoteLiteralHelper(value, { booleansAsIntegers: true })
|
|
438
|
-
}
|
|
439
|
-
|
|
440
419
|
function isWriteOperationKind(kind: DataManipulationRequest['operation']['kind']): boolean {
|
|
441
420
|
return (
|
|
442
421
|
kind === 'insert' ||
|
|
@@ -461,421 +440,3 @@ function isInsertOperation(
|
|
|
461
440
|
operation.kind === 'insert' || operation.kind === 'insertMany' || operation.kind === 'upsert'
|
|
462
441
|
)
|
|
463
442
|
}
|
|
464
|
-
|
|
465
|
-
function isDataManipulationOperation(
|
|
466
|
-
operation: DataManipulationOperation | DataMigrationOperation,
|
|
467
|
-
): operation is DataManipulationOperation {
|
|
468
|
-
return isDataManipulationOperationHelper(operation)
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
function compileSqliteMigrationOperations(operation: DataMigrationOperation): SqlStatement[] {
|
|
472
|
-
if (operation.kind === 'raw') {
|
|
473
|
-
return [{ text: operation.sql.text, values: [...operation.sql.values] }]
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
if (operation.kind === 'createTable') {
|
|
477
|
-
let columns = Object.keys(operation.columns).map(
|
|
478
|
-
(columnName) =>
|
|
479
|
-
quoteIdentifier(columnName) + ' ' + compileSqliteColumn(operation.columns[columnName]),
|
|
480
|
-
)
|
|
481
|
-
let constraints: string[] = []
|
|
482
|
-
|
|
483
|
-
if (operation.primaryKey) {
|
|
484
|
-
constraints.push(
|
|
485
|
-
'constraint ' +
|
|
486
|
-
quoteIdentifier(operation.primaryKey.name) +
|
|
487
|
-
' primary key (' +
|
|
488
|
-
operation.primaryKey.columns.map((column) => quoteIdentifier(column)).join(', ') +
|
|
489
|
-
')',
|
|
490
|
-
)
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
for (let unique of operation.uniques ?? []) {
|
|
494
|
-
constraints.push(
|
|
495
|
-
'constraint ' +
|
|
496
|
-
quoteIdentifier(unique.name) +
|
|
497
|
-
' ' +
|
|
498
|
-
'unique (' +
|
|
499
|
-
unique.columns.map((column) => quoteIdentifier(column)).join(', ') +
|
|
500
|
-
')',
|
|
501
|
-
)
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
for (let check of operation.checks ?? []) {
|
|
505
|
-
constraints.push(
|
|
506
|
-
'constraint ' + quoteIdentifier(check.name) + ' ' + 'check (' + check.expression + ')',
|
|
507
|
-
)
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
for (let foreignKey of operation.foreignKeys ?? []) {
|
|
511
|
-
let clause =
|
|
512
|
-
'constraint ' +
|
|
513
|
-
quoteIdentifier(foreignKey.name) +
|
|
514
|
-
' ' +
|
|
515
|
-
'foreign key (' +
|
|
516
|
-
foreignKey.columns.map((column) => quoteIdentifier(column)).join(', ') +
|
|
517
|
-
') references ' +
|
|
518
|
-
quoteTableRef(foreignKey.references.table) +
|
|
519
|
-
' (' +
|
|
520
|
-
foreignKey.references.columns.map((column) => quoteIdentifier(column)).join(', ') +
|
|
521
|
-
')'
|
|
522
|
-
|
|
523
|
-
if (foreignKey.onDelete) {
|
|
524
|
-
clause += ' on delete ' + foreignKey.onDelete
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
if (foreignKey.onUpdate) {
|
|
528
|
-
clause += ' on update ' + foreignKey.onUpdate
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
constraints.push(clause)
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
return [
|
|
535
|
-
{
|
|
536
|
-
text:
|
|
537
|
-
'create table ' +
|
|
538
|
-
(operation.ifNotExists ? 'if not exists ' : '') +
|
|
539
|
-
quoteTableRef(operation.table) +
|
|
540
|
-
' (' +
|
|
541
|
-
[...columns, ...constraints].join(', ') +
|
|
542
|
-
')',
|
|
543
|
-
values: [],
|
|
544
|
-
},
|
|
545
|
-
]
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
if (operation.kind === 'alterTable') {
|
|
549
|
-
let statements: SqlStatement[] = []
|
|
550
|
-
|
|
551
|
-
for (let change of operation.changes) {
|
|
552
|
-
let sql = 'alter table ' + quoteTableRef(operation.table) + ' '
|
|
553
|
-
|
|
554
|
-
if (change.kind === 'addColumn') {
|
|
555
|
-
sql +=
|
|
556
|
-
'add column ' +
|
|
557
|
-
quoteIdentifier(change.column) +
|
|
558
|
-
' ' +
|
|
559
|
-
compileSqliteColumn(change.definition)
|
|
560
|
-
} else if (change.kind === 'changeColumn') {
|
|
561
|
-
sql +=
|
|
562
|
-
'alter column ' +
|
|
563
|
-
quoteIdentifier(change.column) +
|
|
564
|
-
' type ' +
|
|
565
|
-
compileSqliteColumnType(change.definition)
|
|
566
|
-
} else if (change.kind === 'renameColumn') {
|
|
567
|
-
sql += 'rename column ' + quoteIdentifier(change.from) + ' to ' + quoteIdentifier(change.to)
|
|
568
|
-
} else if (change.kind === 'dropColumn') {
|
|
569
|
-
sql += 'drop column ' + quoteIdentifier(change.column)
|
|
570
|
-
} else if (change.kind === 'addPrimaryKey') {
|
|
571
|
-
sql +=
|
|
572
|
-
'add primary key (' +
|
|
573
|
-
change.constraint.columns.map((column) => quoteIdentifier(column)).join(', ') +
|
|
574
|
-
')'
|
|
575
|
-
} else if (change.kind === 'dropPrimaryKey') {
|
|
576
|
-
sql += 'drop primary key'
|
|
577
|
-
} else if (change.kind === 'addUnique') {
|
|
578
|
-
sql +=
|
|
579
|
-
'add ' +
|
|
580
|
-
'constraint ' +
|
|
581
|
-
quoteIdentifier(change.constraint.name) +
|
|
582
|
-
' ' +
|
|
583
|
-
'unique (' +
|
|
584
|
-
change.constraint.columns.map((column) => quoteIdentifier(column)).join(', ') +
|
|
585
|
-
')'
|
|
586
|
-
} else if (change.kind === 'dropUnique') {
|
|
587
|
-
sql += 'drop constraint ' + quoteIdentifier(change.name)
|
|
588
|
-
} else if (change.kind === 'addForeignKey') {
|
|
589
|
-
sql +=
|
|
590
|
-
'add ' +
|
|
591
|
-
'constraint ' +
|
|
592
|
-
quoteIdentifier(change.constraint.name) +
|
|
593
|
-
' ' +
|
|
594
|
-
'foreign key (' +
|
|
595
|
-
change.constraint.columns.map((column) => quoteIdentifier(column)).join(', ') +
|
|
596
|
-
') references ' +
|
|
597
|
-
quoteTableRef(change.constraint.references.table) +
|
|
598
|
-
' (' +
|
|
599
|
-
change.constraint.references.columns.map((column) => quoteIdentifier(column)).join(', ') +
|
|
600
|
-
')'
|
|
601
|
-
} else if (change.kind === 'dropForeignKey') {
|
|
602
|
-
sql += 'drop constraint ' + quoteIdentifier(change.name)
|
|
603
|
-
} else if (change.kind === 'addCheck') {
|
|
604
|
-
sql +=
|
|
605
|
-
'add ' +
|
|
606
|
-
'constraint ' +
|
|
607
|
-
quoteIdentifier(change.constraint.name) +
|
|
608
|
-
' ' +
|
|
609
|
-
'check (' +
|
|
610
|
-
change.constraint.expression +
|
|
611
|
-
')'
|
|
612
|
-
} else if (change.kind === 'dropCheck') {
|
|
613
|
-
sql += 'drop constraint ' + quoteIdentifier(change.name)
|
|
614
|
-
} else if (change.kind === 'setTableComment') {
|
|
615
|
-
continue
|
|
616
|
-
} else {
|
|
617
|
-
continue
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
statements.push({ text: sql, values: [] })
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
return statements
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
if (operation.kind === 'renameTable') {
|
|
627
|
-
return [
|
|
628
|
-
{
|
|
629
|
-
text:
|
|
630
|
-
'alter table ' +
|
|
631
|
-
quoteTableRef(operation.from) +
|
|
632
|
-
' rename to ' +
|
|
633
|
-
quoteIdentifier(operation.to.name),
|
|
634
|
-
values: [],
|
|
635
|
-
},
|
|
636
|
-
]
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
if (operation.kind === 'dropTable') {
|
|
640
|
-
return [
|
|
641
|
-
{
|
|
642
|
-
text:
|
|
643
|
-
'drop table ' + (operation.ifExists ? 'if exists ' : '') + quoteTableRef(operation.table),
|
|
644
|
-
values: [],
|
|
645
|
-
},
|
|
646
|
-
]
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
if (operation.kind === 'createIndex') {
|
|
650
|
-
return [
|
|
651
|
-
{
|
|
652
|
-
text:
|
|
653
|
-
'create ' +
|
|
654
|
-
(operation.index.unique ? 'unique ' : '') +
|
|
655
|
-
'index ' +
|
|
656
|
-
(operation.ifNotExists ? 'if not exists ' : '') +
|
|
657
|
-
quoteIdentifier(operation.index.name) +
|
|
658
|
-
' on ' +
|
|
659
|
-
quoteTableRef(operation.index.table) +
|
|
660
|
-
' (' +
|
|
661
|
-
operation.index.columns.map((column) => quoteIdentifier(column)).join(', ') +
|
|
662
|
-
')' +
|
|
663
|
-
(operation.index.where ? ' where ' + operation.index.where : ''),
|
|
664
|
-
values: [],
|
|
665
|
-
},
|
|
666
|
-
]
|
|
667
|
-
}
|
|
668
|
-
|
|
669
|
-
if (operation.kind === 'dropIndex') {
|
|
670
|
-
return [
|
|
671
|
-
{
|
|
672
|
-
text:
|
|
673
|
-
'drop index ' +
|
|
674
|
-
(operation.ifExists ? 'if exists ' : '') +
|
|
675
|
-
quoteIdentifier(operation.name),
|
|
676
|
-
values: [],
|
|
677
|
-
},
|
|
678
|
-
]
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
if (operation.kind === 'renameIndex') {
|
|
682
|
-
return [
|
|
683
|
-
{
|
|
684
|
-
text:
|
|
685
|
-
'alter table ' +
|
|
686
|
-
quoteTableRef(operation.table) +
|
|
687
|
-
' rename index ' +
|
|
688
|
-
quoteIdentifier(operation.from) +
|
|
689
|
-
' to ' +
|
|
690
|
-
quoteIdentifier(operation.to),
|
|
691
|
-
values: [],
|
|
692
|
-
},
|
|
693
|
-
]
|
|
694
|
-
}
|
|
695
|
-
|
|
696
|
-
if (operation.kind === 'addForeignKey') {
|
|
697
|
-
return [
|
|
698
|
-
{
|
|
699
|
-
text:
|
|
700
|
-
'alter table ' +
|
|
701
|
-
quoteTableRef(operation.table) +
|
|
702
|
-
' add ' +
|
|
703
|
-
'constraint ' +
|
|
704
|
-
quoteIdentifier(operation.constraint.name) +
|
|
705
|
-
' ' +
|
|
706
|
-
'foreign key (' +
|
|
707
|
-
operation.constraint.columns.map((column) => quoteIdentifier(column)).join(', ') +
|
|
708
|
-
') references ' +
|
|
709
|
-
quoteTableRef(operation.constraint.references.table) +
|
|
710
|
-
' (' +
|
|
711
|
-
operation.constraint.references.columns
|
|
712
|
-
.map((column) => quoteIdentifier(column))
|
|
713
|
-
.join(', ') +
|
|
714
|
-
')' +
|
|
715
|
-
(operation.constraint.onDelete ? ' on delete ' + operation.constraint.onDelete : '') +
|
|
716
|
-
(operation.constraint.onUpdate ? ' on update ' + operation.constraint.onUpdate : ''),
|
|
717
|
-
values: [],
|
|
718
|
-
},
|
|
719
|
-
]
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
if (operation.kind === 'dropForeignKey') {
|
|
723
|
-
return [
|
|
724
|
-
{
|
|
725
|
-
text:
|
|
726
|
-
'alter table ' +
|
|
727
|
-
quoteTableRef(operation.table) +
|
|
728
|
-
' drop constraint ' +
|
|
729
|
-
quoteIdentifier(operation.name),
|
|
730
|
-
values: [],
|
|
731
|
-
},
|
|
732
|
-
]
|
|
733
|
-
}
|
|
734
|
-
|
|
735
|
-
if (operation.kind === 'addCheck') {
|
|
736
|
-
return [
|
|
737
|
-
{
|
|
738
|
-
text:
|
|
739
|
-
'alter table ' +
|
|
740
|
-
quoteTableRef(operation.table) +
|
|
741
|
-
' add ' +
|
|
742
|
-
'constraint ' +
|
|
743
|
-
quoteIdentifier(operation.constraint.name) +
|
|
744
|
-
' ' +
|
|
745
|
-
'check (' +
|
|
746
|
-
operation.constraint.expression +
|
|
747
|
-
')',
|
|
748
|
-
values: [],
|
|
749
|
-
},
|
|
750
|
-
]
|
|
751
|
-
}
|
|
752
|
-
|
|
753
|
-
if (operation.kind === 'dropCheck') {
|
|
754
|
-
return [
|
|
755
|
-
{
|
|
756
|
-
text:
|
|
757
|
-
'alter table ' +
|
|
758
|
-
quoteTableRef(operation.table) +
|
|
759
|
-
' drop constraint ' +
|
|
760
|
-
quoteIdentifier(operation.name),
|
|
761
|
-
values: [],
|
|
762
|
-
},
|
|
763
|
-
]
|
|
764
|
-
}
|
|
765
|
-
|
|
766
|
-
throw new Error('Unsupported data migration operation kind')
|
|
767
|
-
}
|
|
768
|
-
|
|
769
|
-
function compileSqliteColumn(definition: ColumnDefinition): string {
|
|
770
|
-
let parts = [compileSqliteColumnType(definition)]
|
|
771
|
-
|
|
772
|
-
if (definition.nullable === false) {
|
|
773
|
-
parts.push('not null')
|
|
774
|
-
}
|
|
775
|
-
|
|
776
|
-
if (definition.default) {
|
|
777
|
-
if (definition.default.kind === 'now') {
|
|
778
|
-
parts.push('default current_timestamp')
|
|
779
|
-
} else if (definition.default.kind === 'sql') {
|
|
780
|
-
parts.push('default ' + definition.default.expression)
|
|
781
|
-
} else {
|
|
782
|
-
parts.push('default ' + quoteLiteral(definition.default.value))
|
|
783
|
-
}
|
|
784
|
-
}
|
|
785
|
-
|
|
786
|
-
if (definition.primaryKey) {
|
|
787
|
-
parts.push('primary key')
|
|
788
|
-
}
|
|
789
|
-
|
|
790
|
-
if (definition.unique) {
|
|
791
|
-
parts.push('unique')
|
|
792
|
-
}
|
|
793
|
-
|
|
794
|
-
if (definition.computed) {
|
|
795
|
-
parts.push('generated always as (' + definition.computed.expression + ')')
|
|
796
|
-
parts.push(definition.computed.stored ? 'stored' : 'virtual')
|
|
797
|
-
}
|
|
798
|
-
|
|
799
|
-
if (definition.references) {
|
|
800
|
-
let clause =
|
|
801
|
-
'references ' +
|
|
802
|
-
quoteTableRef(definition.references.table) +
|
|
803
|
-
' (' +
|
|
804
|
-
definition.references.columns.map((column) => quoteIdentifier(column)).join(', ') +
|
|
805
|
-
')'
|
|
806
|
-
|
|
807
|
-
if (definition.references.onDelete) {
|
|
808
|
-
clause += ' on delete ' + definition.references.onDelete
|
|
809
|
-
}
|
|
810
|
-
|
|
811
|
-
if (definition.references.onUpdate) {
|
|
812
|
-
clause += ' on update ' + definition.references.onUpdate
|
|
813
|
-
}
|
|
814
|
-
|
|
815
|
-
parts.push(clause)
|
|
816
|
-
}
|
|
817
|
-
|
|
818
|
-
if (definition.checks && definition.checks.length > 0) {
|
|
819
|
-
for (let check of definition.checks) {
|
|
820
|
-
parts.push('check (' + check.expression + ')')
|
|
821
|
-
}
|
|
822
|
-
}
|
|
823
|
-
|
|
824
|
-
return parts.join(' ')
|
|
825
|
-
}
|
|
826
|
-
|
|
827
|
-
function compileSqliteColumnType(definition: ColumnDefinition): string {
|
|
828
|
-
if (definition.type === 'varchar') {
|
|
829
|
-
return 'text'
|
|
830
|
-
}
|
|
831
|
-
|
|
832
|
-
if (definition.type === 'text') {
|
|
833
|
-
return 'text'
|
|
834
|
-
}
|
|
835
|
-
|
|
836
|
-
if (definition.type === 'integer') {
|
|
837
|
-
return 'integer'
|
|
838
|
-
}
|
|
839
|
-
|
|
840
|
-
if (definition.type === 'bigint') {
|
|
841
|
-
return 'integer'
|
|
842
|
-
}
|
|
843
|
-
|
|
844
|
-
if (definition.type === 'decimal') {
|
|
845
|
-
return 'numeric'
|
|
846
|
-
}
|
|
847
|
-
|
|
848
|
-
if (definition.type === 'boolean') {
|
|
849
|
-
return 'integer'
|
|
850
|
-
}
|
|
851
|
-
|
|
852
|
-
if (definition.type === 'uuid') {
|
|
853
|
-
return 'text'
|
|
854
|
-
}
|
|
855
|
-
|
|
856
|
-
if (definition.type === 'date') {
|
|
857
|
-
return 'text'
|
|
858
|
-
}
|
|
859
|
-
|
|
860
|
-
if (definition.type === 'time') {
|
|
861
|
-
return 'text'
|
|
862
|
-
}
|
|
863
|
-
|
|
864
|
-
if (definition.type === 'timestamp') {
|
|
865
|
-
return 'text'
|
|
866
|
-
}
|
|
867
|
-
|
|
868
|
-
if (definition.type === 'json') {
|
|
869
|
-
return 'text'
|
|
870
|
-
}
|
|
871
|
-
|
|
872
|
-
if (definition.type === 'binary') {
|
|
873
|
-
return 'blob'
|
|
874
|
-
}
|
|
875
|
-
|
|
876
|
-
if (definition.type === 'enum') {
|
|
877
|
-
return 'text'
|
|
878
|
-
}
|
|
879
|
-
|
|
880
|
-
return 'text'
|
|
881
|
-
}
|