@remix-run/data-table-sqlite 0.4.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -8,7 +8,7 @@ Use this package when you want `data-table` APIs backed by a synchronous SQLite
8
8
  - **Native Runtime SQLite Support**: Works with Node's `node:sqlite` `DatabaseSync`, Bun's `bun:sqlite` `Database`, and compatible synchronous SQLite clients
9
9
  - **Full `data-table` API Support**: Queries, relations, writes, and transactions
10
10
  - **Adapter-Owned Compiler**: SQL compilation lives in this adapter, with optional shared pure helpers from `data-table`
11
- - **Migration DDL Support**: Compiles and executes `DataMigrationOperation` operations for `remix/data-table/migrations`
11
+ - **Multi-Statement Migrations**: `executeScript()` runs `up.sql` / `down.sql` files via `Database.exec()`
12
12
  - **SQLite Capabilities Enabled By Default**:
13
13
  - `returning: true`
14
14
  - `savepoints: true`
@@ -29,7 +29,7 @@ npm i remix
29
29
  ```ts
30
30
  import { DatabaseSync } from 'node:sqlite'
31
31
  import { createDatabase } from 'remix/data-table'
32
- import { createSqliteDatabaseAdapter } from 'remix/data-table-sqlite'
32
+ import { createSqliteDatabaseAdapter } from 'remix/data-table/sqlite'
33
33
 
34
34
  let sqlite = new DatabaseSync('app.db')
35
35
  let db = createDatabase(createSqliteDatabaseAdapter(sqlite))
@@ -40,7 +40,7 @@ let db = createDatabase(createSqliteDatabaseAdapter(sqlite))
40
40
  ```ts
41
41
  import { Database } from 'bun:sqlite'
42
42
  import { createDatabase } from 'remix/data-table'
43
- import { createSqliteDatabaseAdapter } from 'remix/data-table-sqlite'
43
+ import { createSqliteDatabaseAdapter } from 'remix/data-table/sqlite'
44
44
 
45
45
  let sqlite = new Database('app.db')
46
46
  let db = createDatabase(createSqliteDatabaseAdapter(sqlite))
@@ -66,7 +66,7 @@ Import any driver-specific types you need directly from your runtime's SQLite mo
66
66
  ```ts
67
67
  import { DatabaseSync } from 'node:sqlite'
68
68
  import { createDatabase } from 'remix/data-table'
69
- import { createSqliteDatabaseAdapter } from 'remix/data-table-sqlite'
69
+ import { createSqliteDatabaseAdapter } from 'remix/data-table/sqlite'
70
70
 
71
71
  let sqlite = new DatabaseSync(':memory:')
72
72
  let db = createDatabase(createSqliteDatabaseAdapter(sqlite))
@@ -1,4 +1,4 @@
1
- import type { DataManipulationRequest, DataMigrationRequest, DataMigrationResult, DataMigrationOperation, DataManipulationResult, DataManipulationOperation, DatabaseAdapter, SqlStatement, TableRef, TransactionOptions, TransactionToken } from '@remix-run/data-table';
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 or migration operation to sqlite SQL statements.
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 | DataMigrationOperation): SqlStatement[];
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 migration operations.
64
- * @param request Migration request to execute.
65
- * @returns Migration result.
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
- migrate(request: DataMigrationRequest): Promise<DataMigrationResult>;
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-sqlite'
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,oBAAoB,EACpB,mBAAmB,EACnB,sBAAsB,EACtB,sBAAsB,EACtB,yBAAyB,EACzB,eAAe,EAEf,YAAY,EACZ,QAAQ,EACR,kBAAkB,EAClB,gBAAgB,EACjB,MAAM,uBAAuB,CAAA;AAU9B;;;;;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,sBAAsB,GAAG,YAAY,EAAE,CAOxF;IAED;;;;OAIG;IACG,OAAO,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAiC/E;IAED;;;;OAIG;IACG,OAAO,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAWzE;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"}
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,CAiC/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"}
@@ -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 or migration operation to sqlite SQL statements.
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
- if (isDataManipulationOperation(operation)) {
36
- let compiled = compileSqliteOperation(operation);
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.
@@ -72,19 +68,16 @@ export class SqliteDatabaseAdapter {
72
68
  };
73
69
  }
74
70
  /**
75
- * Executes sqlite migration operations.
76
- * @param request Migration request to execute.
77
- * @returns Migration result.
71
+ * Executes a multi-statement sqlite SQL script.
72
+ * @param sql SQL script to execute.
73
+ * @param transaction Optional transaction token (asserted when present).
74
+ * @returns A promise that resolves once execution completes.
78
75
  */
79
- async migrate(request) {
80
- let statements = this.compileSql(request.operation);
81
- for (let statement of statements) {
82
- let prepared = this.#database.prepare(statement.text);
83
- prepared.run(...normalizeStatementValues(statement.values));
76
+ async executeScript(sql, transaction) {
77
+ if (transaction) {
78
+ this.#assertTransaction(transaction);
84
79
  }
85
- return {
86
- affectedOperations: statements.length,
87
- };
80
+ this.#database.exec(sql);
88
81
  }
89
82
  /**
90
83
  * Checks whether a table exists in sqlite.
@@ -198,7 +191,7 @@ export class SqliteDatabaseAdapter {
198
191
  * ```ts
199
192
  * import { DatabaseSync } from 'node:sqlite'
200
193
  * import { createDatabase } from 'remix/data-table'
201
- * import { createSqliteDatabaseAdapter } from 'remix/data-table-sqlite'
194
+ * import { createSqliteDatabaseAdapter } from 'remix/data-table/sqlite'
202
195
  *
203
196
  * let sqlite = new DatabaseSync('./data/app.db')
204
197
  * let adapter = createSqliteDatabaseAdapter(sqlite)
@@ -296,12 +289,6 @@ function shouldReadStatement(operation, statement) {
296
289
  function quoteIdentifier(value) {
297
290
  return '"' + value.replace(/"/g, '""') + '"';
298
291
  }
299
- function quoteTableRef(table) {
300
- return quoteTableRefHelper(table, quoteIdentifier);
301
- }
302
- function quoteLiteral(value) {
303
- return quoteLiteralHelper(value, { booleansAsIntegers: true });
304
- }
305
292
  function isWriteOperationKind(kind) {
306
293
  return (kind === 'insert' ||
307
294
  kind === 'insertMany' ||
@@ -315,361 +302,3 @@ function isInsertOperationKind(kind) {
315
302
  function isInsertOperation(operation) {
316
303
  return (operation.kind === 'insert' || operation.kind === 'insertMany' || operation.kind === 'upsert');
317
304
  }
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.4.1",
3
+ "version": "0.5.0",
4
4
  "description": "SQLite adapter for remix/data-table",
5
5
  "author": "Michael Jackson <mjijackson@gmail.com>",
6
6
  "license": "MIT",
@@ -30,11 +30,11 @@
30
30
  "@types/node": "^24.6.0",
31
31
  "@typescript/native-preview": "7.0.0-dev.20251125.1",
32
32
  "@remix-run/assert": "0.2.0",
33
- "@remix-run/test": "0.3.0",
34
- "@remix-run/data-table": "0.2.1"
33
+ "@remix-run/test": "0.4.0",
34
+ "@remix-run/data-table": "0.3.0"
35
35
  },
36
36
  "dependencies": {
37
- "@remix-run/data-table": "^0.2.1"
37
+ "@remix-run/data-table": "^0.3.0"
38
38
  },
39
39
  "keywords": [
40
40
  "remix",
@@ -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 or migration operation to sqlite SQL statements.
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 | DataMigrationOperation): SqlStatement[] {
90
- if (isDataManipulationOperation(operation)) {
91
- let compiled = compileSqliteOperation(operation)
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
  /**
@@ -136,21 +123,17 @@ export class SqliteDatabaseAdapter implements DatabaseAdapter {
136
123
  }
137
124
 
138
125
  /**
139
- * Executes sqlite migration operations.
140
- * @param request Migration request to execute.
141
- * @returns Migration result.
126
+ * Executes a multi-statement sqlite SQL script.
127
+ * @param sql SQL script to execute.
128
+ * @param transaction Optional transaction token (asserted when present).
129
+ * @returns A promise that resolves once execution completes.
142
130
  */
143
- async migrate(request: DataMigrationRequest): Promise<DataMigrationResult> {
144
- let statements = this.compileSql(request.operation)
145
-
146
- for (let statement of statements) {
147
- let prepared = this.#database.prepare(statement.text)
148
- prepared.run(...normalizeStatementValues(statement.values))
131
+ async executeScript(sql: string, transaction?: TransactionToken): Promise<void> {
132
+ if (transaction) {
133
+ this.#assertTransaction(transaction)
149
134
  }
150
135
 
151
- return {
152
- affectedOperations: statements.length,
153
- }
136
+ this.#database.exec(sql)
154
137
  }
155
138
 
156
139
  /**
@@ -288,7 +271,7 @@ export class SqliteDatabaseAdapter implements DatabaseAdapter {
288
271
  * ```ts
289
272
  * import { DatabaseSync } from 'node:sqlite'
290
273
  * import { createDatabase } from 'remix/data-table'
291
- * import { createSqliteDatabaseAdapter } from 'remix/data-table-sqlite'
274
+ * import { createSqliteDatabaseAdapter } from 'remix/data-table/sqlite'
292
275
  *
293
276
  * let sqlite = new DatabaseSync('./data/app.db')
294
277
  * let adapter = createSqliteDatabaseAdapter(sqlite)
@@ -429,14 +412,6 @@ function quoteIdentifier(value: string): string {
429
412
  return '"' + value.replace(/"/g, '""') + '"'
430
413
  }
431
414
 
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
415
  function isWriteOperationKind(kind: DataManipulationRequest['operation']['kind']): boolean {
441
416
  return (
442
417
  kind === 'insert' ||
@@ -461,421 +436,3 @@ function isInsertOperation(
461
436
  operation.kind === 'insert' || operation.kind === 'insertMany' || operation.kind === 'upsert'
462
437
  )
463
438
  }
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
- }