@remix-run/data-table 0.3.0 → 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.
Files changed (83) hide show
  1. package/README.md +217 -78
  2. package/dist/cli.d.ts +76 -0
  3. package/dist/cli.d.ts.map +1 -0
  4. package/dist/cli.js +78 -0
  5. package/dist/index.d.ts +5 -4
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +7 -7
  8. package/dist/lib/column.d.ts +1 -1
  9. package/dist/lib/column.d.ts.map +1 -1
  10. package/dist/lib/database/execution-context.d.ts +5 -5
  11. package/dist/lib/database/execution-context.d.ts.map +1 -1
  12. package/dist/lib/database/execution-context.js +1 -0
  13. package/dist/lib/database/helpers.js +6 -6
  14. package/dist/lib/database/query-execution.d.ts.map +1 -1
  15. package/dist/lib/database/query-execution.js +17 -17
  16. package/dist/lib/database/relations.js +5 -5
  17. package/dist/lib/database/write-lifecycle.d.ts +2 -2
  18. package/dist/lib/database/write-lifecycle.d.ts.map +1 -1
  19. package/dist/lib/database/write-lifecycle.js +5 -5
  20. package/dist/lib/database.d.ts +74 -59
  21. package/dist/lib/database.d.ts.map +1 -1
  22. package/dist/lib/database.js +176 -83
  23. package/dist/lib/{adapter.d.ts → driver.d.ts} +46 -48
  24. package/dist/lib/driver.d.ts.map +1 -0
  25. package/dist/lib/errors.d.ts +2 -2
  26. package/dist/lib/errors.d.ts.map +1 -1
  27. package/dist/lib/errors.js +4 -4
  28. package/dist/lib/migrations/journal-store.d.ts +6 -6
  29. package/dist/lib/migrations/journal-store.d.ts.map +1 -1
  30. package/dist/lib/migrations/journal-store.js +20 -11
  31. package/dist/lib/migrations/runner.d.ts +12 -19
  32. package/dist/lib/migrations/runner.d.ts.map +1 -1
  33. package/dist/lib/migrations/runner.js +152 -130
  34. package/dist/lib/migrations-node.d.ts +19 -1
  35. package/dist/lib/migrations-node.d.ts.map +1 -1
  36. package/dist/lib/migrations-node.js +22 -1
  37. package/dist/lib/migrations.d.ts +55 -20
  38. package/dist/lib/migrations.d.ts.map +1 -1
  39. package/dist/lib/operators.d.ts +8 -7
  40. package/dist/lib/operators.d.ts.map +1 -1
  41. package/dist/lib/operators.js +15 -11
  42. package/dist/lib/query.d.ts +1 -1
  43. package/dist/lib/query.d.ts.map +1 -1
  44. package/dist/lib/query.js +4 -4
  45. package/dist/lib/sql-helpers.d.ts +1 -1
  46. package/dist/lib/sql-helpers.d.ts.map +1 -1
  47. package/dist/lib/sql.d.ts +1 -1
  48. package/dist/lib/sql.js +1 -1
  49. package/dist/lib/table.d.ts +1 -1
  50. package/dist/lib/table.d.ts.map +1 -1
  51. package/dist/lib/table.js +5 -5
  52. package/dist/migrations/node.d.ts +1 -1
  53. package/dist/migrations/node.d.ts.map +1 -1
  54. package/dist/migrations/node.js +1 -1
  55. package/dist/migrations.d.ts +1 -2
  56. package/dist/migrations.d.ts.map +1 -1
  57. package/dist/migrations.js +2 -3
  58. package/dist/operators.js +1 -1
  59. package/dist/sql-helpers.js +1 -1
  60. package/package.json +13 -9
  61. package/src/cli.ts +179 -0
  62. package/src/index.ts +19 -20
  63. package/src/lib/column.ts +1 -1
  64. package/src/lib/database/execution-context.ts +10 -6
  65. package/src/lib/database/helpers.ts +1 -1
  66. package/src/lib/database/query-execution.ts +15 -11
  67. package/src/lib/database/write-lifecycle.ts +4 -4
  68. package/src/lib/database.ts +223 -96
  69. package/src/lib/{adapter.ts → driver.ts} +48 -48
  70. package/src/lib/errors.ts +4 -4
  71. package/src/lib/migrations/journal-store.ts +21 -11
  72. package/src/lib/migrations/runner.ts +201 -148
  73. package/src/lib/migrations-node.ts +23 -1
  74. package/src/lib/migrations.ts +58 -19
  75. package/src/lib/operators.ts +24 -11
  76. package/src/lib/query.ts +1 -1
  77. package/src/lib/sql-helpers.ts +1 -1
  78. package/src/lib/sql.ts +1 -1
  79. package/src/lib/table.ts +1 -1
  80. package/src/migrations/node.ts +1 -1
  81. package/src/migrations.ts +3 -4
  82. package/dist/lib/adapter.d.ts.map +0 -1
  83. /package/dist/lib/{adapter.js → driver.js} +0 -0
package/src/cli.ts ADDED
@@ -0,0 +1,179 @@
1
+ import type { Database } from './lib/database.ts'
2
+ import type { Migrations, Seed } from './lib/migrations.ts'
3
+
4
+ interface DatabaseCommandOptions {
5
+ /** Database instance used by the command. */
6
+ db: Database
7
+ }
8
+
9
+ type RollbackBoundOptions =
10
+ | {
11
+ /**
12
+ * Reverts back through this migration, inclusive. Accepts a bare
13
+ * migration id or the full `id_name` directory form.
14
+ */
15
+ to: string
16
+ step?: never
17
+ }
18
+ | {
19
+ to?: never
20
+ /** Reverts this many migrations. Defaults to `1`. */
21
+ step?: number
22
+ }
23
+
24
+ type RollbackCommandOptions = DatabaseCommandOptions &
25
+ RollbackBoundOptions & {
26
+ /** Reverts applied migrations, newest first. */
27
+ command: 'rollback'
28
+ /** Migrations to revert. */
29
+ migrations: Migrations
30
+ /** Reports what would be reverted without running it. */
31
+ dryRun?: boolean
32
+ /** Migration journal table. */
33
+ journalTable?: string
34
+ }
35
+
36
+ /** Structured invocation options accepted by {@link runRemixDb}. */
37
+ export type RunRemixDbOptions =
38
+ | (DatabaseCommandOptions & {
39
+ /** Applies pending migrations. */
40
+ command: 'migrate'
41
+ /** Migrations to apply. */
42
+ migrations: Migrations
43
+ /**
44
+ * Stops after applying this migration. Accepts a bare migration id or
45
+ * the full `id_name` directory form.
46
+ */
47
+ to?: string
48
+ /** Migration journal table. */
49
+ journalTable?: string
50
+ })
51
+ | RollbackCommandOptions
52
+ | (DatabaseCommandOptions & {
53
+ /** Wipes, migrates, and optionally seeds the database. */
54
+ command: 'reset'
55
+ /** Migrations to apply after wiping the database. */
56
+ migrations: Migrations
57
+ /** Initializes database data after migrations finish. */
58
+ seed?: Seed
59
+ /** Migration journal table. */
60
+ journalTable?: string
61
+ })
62
+ | (DatabaseCommandOptions & {
63
+ /** Runs the application's seed function. */
64
+ command: 'seed'
65
+ /** Initializes application database data. */
66
+ seed: Seed
67
+ })
68
+ | (DatabaseCommandOptions & {
69
+ /** Reports the status of known migrations. */
70
+ command: 'status'
71
+ /** Migrations to inspect. */
72
+ migrations: Migrations
73
+ /** Migration journal table. */
74
+ journalTable?: string
75
+ })
76
+ | (DatabaseCommandOptions & {
77
+ /** Destructively recreates the configured database. */
78
+ command: 'wipe'
79
+ })
80
+
81
+ /**
82
+ * Runs a data-table database command from structured invocation options.
83
+ *
84
+ * @param options Database command and application database values.
85
+ * @returns The exit code the host CLI should use. Always resolves `0`;
86
+ * command failures throw.
87
+ */
88
+ export async function runRemixDb(options: RunRemixDbOptions): Promise<number> {
89
+ if (options.command === 'migrate') {
90
+ let migrateOptions =
91
+ options.to === undefined
92
+ ? { journalTable: options.journalTable }
93
+ : { to: options.to, journalTable: options.journalTable }
94
+ let result = await options.db.migrate(options.migrations, migrateOptions)
95
+
96
+ if (result.applied.length === 0) {
97
+ console.log('no pending migrations')
98
+ }
99
+
100
+ for (let entry of result.applied) {
101
+ console.log('applied ' + entry.id + '_' + entry.name)
102
+ }
103
+
104
+ return 0
105
+ }
106
+
107
+ if (options.command === 'rollback') {
108
+ if (options.to !== undefined && options.step !== undefined) {
109
+ throw new Error('Cannot combine "to" and "step" migration options in the same run')
110
+ }
111
+
112
+ let result =
113
+ options.to === undefined
114
+ ? await options.db.migrate(options.migrations, {
115
+ direction: 'down',
116
+ step: options.step ?? 1,
117
+ dryRun: options.dryRun,
118
+ journalTable: options.journalTable,
119
+ })
120
+ : await options.db.migrate(options.migrations, {
121
+ direction: 'down',
122
+ to: options.to,
123
+ dryRun: options.dryRun,
124
+ journalTable: options.journalTable,
125
+ })
126
+
127
+ if (result.reverted.length === 0) {
128
+ console.log('no migrations to revert')
129
+ }
130
+
131
+ for (let entry of result.reverted) {
132
+ console.log((options.dryRun ? 'would revert ' : 'reverted ') + entry.id + '_' + entry.name)
133
+ }
134
+
135
+ return 0
136
+ }
137
+
138
+ if (options.command === 'reset') {
139
+ await options.db.reset({
140
+ migrations: options.migrations,
141
+ seed: options.seed,
142
+ journalTable: options.journalTable,
143
+ })
144
+
145
+ console.log('database reset')
146
+
147
+ return 0
148
+ }
149
+
150
+ if (options.command === 'seed') {
151
+ await options.seed(options.db)
152
+
153
+ console.log('database seeded')
154
+
155
+ return 0
156
+ }
157
+
158
+ if (options.command === 'status') {
159
+ let entries = await options.db.migrationStatus(options.migrations, {
160
+ journalTable: options.journalTable,
161
+ })
162
+
163
+ for (let entry of entries) {
164
+ console.log(entry.id + ' ' + entry.name + ' ' + entry.status)
165
+ }
166
+
167
+ return 0
168
+ }
169
+
170
+ if (options.command === 'wipe') {
171
+ await options.db.wipe()
172
+ return 0
173
+ }
174
+
175
+ // Guard against unchecked command strings from plain-JS callers so an
176
+ // unknown command can never fall through to a destructive operation.
177
+ let command = (options as { command: string }).command
178
+ throw new Error('Unknown database command: ' + command)
179
+ }
package/src/index.ts CHANGED
@@ -1,37 +1,23 @@
1
1
  export type {
2
- AdapterCapabilityOverrides,
3
- AdapterCapabilities,
2
+ DatabaseCapabilities,
3
+ DatabaseDriver,
4
+ DataManipulationOperation,
4
5
  DataManipulationRequest,
5
6
  ColumnCheck,
6
7
  ColumnComputed,
7
8
  ColumnDefault,
8
9
  ColumnDefinition,
9
10
  ColumnTypeName,
10
- CountOperation,
11
11
  DataManipulationResult,
12
- DataManipulationOperation,
13
- DeleteOperation,
14
- DatabaseAdapter,
15
- ExistsOperation,
16
12
  ForeignKeyAction,
17
13
  IdentityOptions,
18
- InsertManyOperation,
19
- InsertOperation,
20
- JoinClause,
21
- JoinType,
22
- RawOperation,
23
- ReturningSelection,
24
- SelectColumn,
25
- SelectOperation,
26
14
  TableRef,
27
15
  TransactionOptions,
28
16
  TransactionToken,
29
- UpdateOperation,
30
- UpsertOperation,
31
- } from './lib/adapter.ts'
17
+ } from './lib/driver.ts'
32
18
 
33
19
  export {
34
- DataTableAdapterError,
20
+ DataTableDatabaseError,
35
21
  DataTableConstraintError,
36
22
  DataTableError,
37
23
  DataTableQueryError,
@@ -145,6 +131,7 @@ export type {
145
131
  CreateResultOptions,
146
132
  CreateRowOptions,
147
133
  DeleteManyOptions,
134
+ DatabaseOptions,
148
135
  FindManyOptions,
149
136
  FindOneOptions,
150
137
  OrderByInput,
@@ -160,6 +147,18 @@ export type {
160
147
  WriteRowResult,
161
148
  WriteRowsResult,
162
149
  } from './lib/database.ts'
163
- export { createDatabase, Database } from './lib/database.ts'
150
+ export { Database } from './lib/database.ts'
151
+ export type {
152
+ DatabaseMigrateOptions,
153
+ DatabaseMigrationStatusOptions,
154
+ DatabaseResetOptions,
155
+ MigrateResult,
156
+ MigrationDescriptor,
157
+ MigrationRegistry,
158
+ Migrations,
159
+ MigrationStatus,
160
+ MigrationStatusEntry,
161
+ Seed,
162
+ } from './lib/migrations.ts'
164
163
  export type { AnyQuery } from './lib/query.ts'
165
164
  export { Query, query } from './lib/query.ts'
package/src/lib/column.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { ColumnDefinition, ForeignKeyAction, IdentityOptions, TableRef } from './adapter.ts'
1
+ import type { ColumnDefinition, ForeignKeyAction, IdentityOptions, TableRef } from './driver.ts'
2
2
 
3
3
  function toTableRef(name: string): TableRef {
4
4
  let segments = name.split('.')
@@ -1,15 +1,19 @@
1
1
  import type {
2
+ DatabaseCapabilities,
2
3
  DataManipulationOperation,
3
4
  DataManipulationResult,
4
- DatabaseAdapter,
5
- } from '../adapter.ts'
6
- import type { Database } from '../database.ts'
5
+ TransactionOptions,
6
+ } from '../driver.ts'
7
7
 
8
8
  export const executeOperation = Symbol('executeOperation')
9
+ export const runInTransaction = Symbol('runInTransaction')
9
10
 
10
- export type QueryExecutionContext = {
11
- adapter: DatabaseAdapter
11
+ export type QueryExecutionContext<dialect extends string = string> = {
12
+ capabilities: DatabaseCapabilities
12
13
  now(): unknown
13
- transaction<result>(callback: (database: Database) => Promise<result>): Promise<result>
14
14
  [executeOperation](operation: DataManipulationOperation): Promise<DataManipulationResult>
15
+ [runInTransaction]<result>(
16
+ callback: (database: QueryExecutionContext<dialect>) => Promise<result>,
17
+ options?: TransactionOptions,
18
+ ): Promise<result>
15
19
  }
@@ -80,7 +80,7 @@ export function resolveCreateRowWhere<table extends AnyTable>(
80
80
  throw new DataTableQueryError(
81
81
  'create({ returnRow: true }) requires primary key values for table "' +
82
82
  getTableName(table) +
83
- '" when adapter does not support RETURNING',
83
+ '" when the database does not support RETURNING',
84
84
  )
85
85
  }
86
86
 
@@ -9,7 +9,7 @@ import type {
9
9
  SelectOperation,
10
10
  UpdateOperation,
11
11
  UpsertOperation,
12
- } from '../adapter.ts'
12
+ } from '../driver.ts'
13
13
  import { DataTableQueryError } from '../errors.ts'
14
14
  import type { ReturningInput, WriteResult, WriteRowResult, WriteRowsResult } from '../database.ts'
15
15
  import { normalizeWhereInput } from '../operators.ts'
@@ -18,7 +18,11 @@ import { cloneQueryState, querySnapshot } from '../query.ts'
18
18
  import type { AnyTable } from '../table.ts'
19
19
  import { getPrimaryKeyObject, getTableName } from '../table.ts'
20
20
 
21
- import { executeOperation, type QueryExecutionContext } from './execution-context.ts'
21
+ import {
22
+ executeOperation,
23
+ runInTransaction,
24
+ type QueryExecutionContext,
25
+ } from './execution-context.ts'
22
26
  import {
23
27
  buildPrimaryKeyPredicate,
24
28
  hasScopedWriteModifiers,
@@ -244,7 +248,7 @@ async function executeInsert(
244
248
  )
245
249
  let returning = options?.returning
246
250
 
247
- assertReturningCapability(database.adapter, 'insert', returning)
251
+ assertReturningCapability(database.capabilities, 'insert', returning)
248
252
 
249
253
  if (returning) {
250
254
  let operation: InsertOperation<AnyTable> = {
@@ -314,7 +318,7 @@ async function executeInsertMany(
314
318
  }
315
319
 
316
320
  let returning = options?.returning
317
- assertReturningCapability(database.adapter, 'insertMany', returning)
321
+ assertReturningCapability(database.capabilities, 'insertMany', returning)
318
322
 
319
323
  if (returning) {
320
324
  let operation: InsertManyOperation<AnyTable> = {
@@ -371,7 +375,7 @@ async function executeUpdate(
371
375
  options?: { returning?: ReturningInput<Record<string, unknown>>; touch?: boolean },
372
376
  ): Promise<WriteResult | WriteRowsResult<Record<string, unknown>>> {
373
377
  let returning = options?.returning
374
- assertReturningCapability(database.adapter, 'update', returning)
378
+ assertReturningCapability(database.capabilities, 'update', returning)
375
379
  let preparedChanges = prepareUpdateValues(
376
380
  table,
377
381
  changes as never,
@@ -386,7 +390,7 @@ async function executeUpdate(
386
390
  let result: DataManipulationResult
387
391
 
388
392
  if (hasScopedWriteModifiers(state)) {
389
- result = await database.transaction(async (tx) => {
393
+ result = await database[runInTransaction](async (tx) => {
390
394
  let primaryKeys = await loadPrimaryKeyRowsForScope(tx, table, state)
391
395
  let primaryKeyPredicate = buildPrimaryKeyPredicate(table, primaryKeys)
392
396
 
@@ -448,7 +452,7 @@ async function executeDelete(
448
452
  options?: { returning?: ReturningInput<Record<string, unknown>> },
449
453
  ): Promise<WriteResult | WriteRowsResult<Record<string, unknown>>> {
450
454
  let returning = options?.returning
451
- assertReturningCapability(database.adapter, 'delete', returning)
455
+ assertReturningCapability(database.capabilities, 'delete', returning)
452
456
  let tableName = getTableName(table)
453
457
  let deleteContext = {
454
458
  tableName,
@@ -462,7 +466,7 @@ async function executeDelete(
462
466
  let result: DataManipulationResult
463
467
 
464
468
  if (hasScopedWriteModifiers(state)) {
465
- result = await database.transaction(async (tx) => {
469
+ result = await database[runInTransaction](async (tx) => {
466
470
  let primaryKeys = await loadPrimaryKeyRowsForScope(tx, table, state)
467
471
  let primaryKeyPredicate = buildPrimaryKeyPredicate(table, primaryKeys)
468
472
 
@@ -527,8 +531,8 @@ async function executeUpsert(
527
531
  update?: Record<string, unknown>
528
532
  },
529
533
  ): Promise<WriteResult | WriteRowResult<Record<string, unknown>>> {
530
- if (!database.adapter.capabilities.upsert) {
531
- throw new DataTableQueryError('Adapter does not support upsert')
534
+ if (!database.capabilities.upsert) {
535
+ throw new DataTableQueryError('Database does not support upsert')
532
536
  }
533
537
 
534
538
  let preparedValues = prepareInsertValues(
@@ -547,7 +551,7 @@ async function executeUpsert(
547
551
  )
548
552
  : undefined
549
553
  let returning = options?.returning
550
- assertReturningCapability(database.adapter, 'upsert', returning)
554
+ assertReturningCapability(database.capabilities, 'upsert', returning)
551
555
 
552
556
  if (returning) {
553
557
  let operation: UpsertOperation<AnyTable> = {
@@ -1,4 +1,4 @@
1
- import type { DatabaseAdapter, ReturningSelection } from '../adapter.ts'
1
+ import type { DatabaseCapabilities, ReturningSelection } from '../driver.ts'
2
2
  import { DataTableQueryError, DataTableValidationError } from '../errors.ts'
3
3
  import type { ReturningInput } from '../database.ts'
4
4
  import type {
@@ -249,12 +249,12 @@ export function runAfterDeleteHook<table extends AnyTable>(
249
249
  }
250
250
 
251
251
  export function assertReturningCapability<row extends Record<string, unknown>>(
252
- adapter: DatabaseAdapter,
252
+ capabilities: DatabaseCapabilities,
253
253
  operation: 'insert' | 'insertMany' | 'update' | 'delete' | 'upsert',
254
254
  returning: ReturningInput<row> | undefined,
255
255
  ): void {
256
- if (returning && !adapter.capabilities.returning) {
257
- throw new DataTableQueryError(operation + '() returning is not supported by this adapter')
256
+ if (returning && !capabilities.returning) {
257
+ throw new DataTableQueryError(operation + '() returning is not supported by this database')
258
258
  }
259
259
  }
260
260