@remix-run/data-table 0.3.0 → 0.4.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 (82) hide show
  1. package/README.md +205 -79
  2. package/dist/cli.d.ts +54 -0
  3. package/dist/cli.d.ts.map +1 -0
  4. package/dist/cli.js +53 -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 +151 -129
  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 +1 -1
  40. package/dist/lib/operators.js +1 -1
  41. package/dist/lib/query.d.ts +1 -1
  42. package/dist/lib/query.d.ts.map +1 -1
  43. package/dist/lib/query.js +4 -4
  44. package/dist/lib/sql-helpers.d.ts +1 -1
  45. package/dist/lib/sql-helpers.d.ts.map +1 -1
  46. package/dist/lib/sql.d.ts +1 -1
  47. package/dist/lib/sql.js +1 -1
  48. package/dist/lib/table.d.ts +1 -1
  49. package/dist/lib/table.d.ts.map +1 -1
  50. package/dist/lib/table.js +5 -5
  51. package/dist/migrations/node.d.ts +1 -1
  52. package/dist/migrations/node.d.ts.map +1 -1
  53. package/dist/migrations/node.js +1 -1
  54. package/dist/migrations.d.ts +1 -2
  55. package/dist/migrations.d.ts.map +1 -1
  56. package/dist/migrations.js +2 -3
  57. package/dist/operators.js +1 -1
  58. package/dist/sql-helpers.js +1 -1
  59. package/package.json +13 -9
  60. package/src/cli.ts +120 -0
  61. package/src/index.ts +19 -20
  62. package/src/lib/column.ts +1 -1
  63. package/src/lib/database/execution-context.ts +10 -6
  64. package/src/lib/database/helpers.ts +1 -1
  65. package/src/lib/database/query-execution.ts +15 -11
  66. package/src/lib/database/write-lifecycle.ts +4 -4
  67. package/src/lib/database.ts +223 -96
  68. package/src/lib/{adapter.ts → driver.ts} +48 -48
  69. package/src/lib/errors.ts +4 -4
  70. package/src/lib/migrations/journal-store.ts +21 -11
  71. package/src/lib/migrations/runner.ts +200 -147
  72. package/src/lib/migrations-node.ts +23 -1
  73. package/src/lib/migrations.ts +58 -19
  74. package/src/lib/operators.ts +1 -1
  75. package/src/lib/query.ts +1 -1
  76. package/src/lib/sql-helpers.ts +1 -1
  77. package/src/lib/sql.ts +1 -1
  78. package/src/lib/table.ts +1 -1
  79. package/src/migrations/node.ts +1 -1
  80. package/src/migrations.ts +3 -4
  81. package/dist/lib/adapter.d.ts.map +0 -1
  82. /package/dist/lib/{adapter.js → driver.js} +0 -0
@@ -1,18 +1,26 @@
1
- import type { DatabaseAdapter, TransactionToken } from '../adapter.ts'
1
+ import type { DatabaseDriver, TransactionToken } from '../driver.ts'
2
2
  import type {
3
- MigrateOptions,
3
+ MigrationOperationOptions,
4
4
  MigrateResult,
5
5
  MigrationDescriptor,
6
6
  MigrationDirection,
7
7
  MigrationJournalRow,
8
8
  MigrationRegistry,
9
- MigrationRunner,
10
- MigrationRunnerOptions,
11
9
  MigrationStatus,
12
10
  MigrationStatusEntry,
13
11
  MigrationTransactionMode,
14
12
  } from '../migrations.ts'
15
13
 
14
+ interface MigrationRunnerOptions {
15
+ journalTable?: string
16
+ }
17
+
18
+ interface MigrationRunner {
19
+ up(options?: MigrationOperationOptions): Promise<MigrateResult>
20
+ down(options?: MigrationOperationOptions): Promise<MigrateResult>
21
+ status(): Promise<MigrationStatusEntry[]>
22
+ }
23
+
16
24
  import { parseTransactionDirective } from './directive.ts'
17
25
  import {
18
26
  deleteJournalRow,
@@ -25,12 +33,14 @@ import {
25
33
  } from './journal-store.ts'
26
34
  import { resolveMigrations } from './registry.ts'
27
35
 
36
+ type MigrationRunnerContext = DatabaseDriver
37
+
28
38
  type RunMigrationsInput = {
29
- adapter: DatabaseAdapter
39
+ driver: MigrationRunnerContext
30
40
  migrations: MigrationDescriptor[]
31
41
  journalTable: string
32
42
  direction: MigrationDirection
33
- options: MigrateOptions
43
+ options: MigrationOperationOptions
34
44
  }
35
45
 
36
46
  function assertStepOption(step: number | undefined): void {
@@ -43,27 +53,46 @@ function assertStepOption(step: number | undefined): void {
43
53
  }
44
54
  }
45
55
 
46
- function assertMigrateOptions(options: MigrateOptions): void {
56
+ function assertMigrationOperationOptions(options: MigrationOperationOptions): void {
47
57
  if (options.to !== undefined && options.step !== undefined) {
48
58
  throw new Error('Cannot combine "to" and "step" migration options in the same run')
49
59
  }
50
60
  }
51
61
 
52
- function assertTargetOption(migrations: MigrationDescriptor[], to: string | undefined): void {
62
+ function resolveTargetOption(
63
+ migrations: MigrationDescriptor[],
64
+ to: string | undefined,
65
+ ): string | undefined {
53
66
  if (!to) {
54
- return
67
+ return undefined
55
68
  }
56
69
 
57
- let target = migrations.find((migration) => migration.id === to)
70
+ // Accept either a bare migration id or the full `id_name` directory form and
71
+ // normalize to the bare id so range filtering compares ids consistently.
72
+ let matches = migrations.filter(
73
+ (migration) => migration.id === to || migration.id + '_' + migration.name === to,
74
+ )
58
75
 
59
- if (!target) {
76
+ if (matches.length === 0) {
60
77
  throw new Error('Unknown migration target: ' + to)
61
78
  }
79
+
80
+ if (matches.length > 1) {
81
+ throw new Error(
82
+ 'Ambiguous migration target "' +
83
+ to +
84
+ '". Matches: ' +
85
+ matches.map((migration) => migration.id + '_' + migration.name).join(', '),
86
+ )
87
+ }
88
+
89
+ return matches[0].id
62
90
  }
63
91
 
64
- async function assertNoMigrationDrift(
92
+ async function assertMigrationIntegrity(
65
93
  migrations: MigrationDescriptor[],
66
94
  journal: MigrationJournalRow[],
95
+ direction: MigrationDirection,
67
96
  ): Promise<void> {
68
97
  let migrationMap = new Map(migrations.map((migration) => [migration.id, migration]))
69
98
 
@@ -71,7 +100,15 @@ async function assertNoMigrationDrift(
71
100
  let migration = migrationMap.get(row.id)
72
101
 
73
102
  if (!migration) {
74
- continue
103
+ // Rolling back must stay possible when journal rows have no matching
104
+ // migration files, so only forward runs hard-error on orphaned entries.
105
+ if (direction === 'down') {
106
+ continue
107
+ }
108
+
109
+ throw new Error(
110
+ 'Applied migration "' + row.id + '_' + row.name + '" is missing from current migrations',
111
+ )
75
112
  }
76
113
 
77
114
  let expected = await computeChecksum(migration)
@@ -105,193 +142,193 @@ function resolveTransactionMode(migration: MigrationDescriptor): MigrationTransa
105
142
  }
106
143
 
107
144
  async function runMigrations(input: RunMigrationsInput): Promise<MigrateResult> {
108
- let adapter = input.adapter
145
+ if (input.driver.capabilities.migrationLock && !input.driver.withMigrationLock) {
146
+ throw new Error(
147
+ 'Database driver reports migration lock support but does not implement withMigrationLock()',
148
+ )
149
+ }
150
+
151
+ if (input.driver.withMigrationLock) {
152
+ return input.driver.withMigrationLock(input.journalTable, (driver) =>
153
+ runMigrationsUnlocked({ ...input, driver }),
154
+ )
155
+ }
156
+
157
+ return runMigrationsUnlocked(input)
158
+ }
159
+
160
+ async function runMigrationsUnlocked(input: RunMigrationsInput): Promise<MigrateResult> {
161
+ let driver = input.driver
109
162
  let migrations = input.migrations
110
163
  let journalTable = input.journalTable
111
164
  let dryRun = Boolean(input.options.dryRun)
112
- let target = input.options.to
113
165
  let step = input.options.step
114
166
 
115
- assertMigrateOptions(input.options)
167
+ assertMigrationOperationOptions(input.options)
116
168
  assertStepOption(step)
117
- assertTargetOption(migrations, target)
169
+
170
+ let target = resolveTargetOption(migrations, input.options.to)
118
171
 
119
172
  let sql: string[] = []
120
173
 
121
- await adapter.acquireMigrationLock?.()
174
+ let journal: MigrationJournalRow[] = []
122
175
 
123
- try {
124
- let journal: MigrationJournalRow[] = []
176
+ if (dryRun) {
177
+ let canReadJournal = await hasMigrationJournal(driver, journalTable)
125
178
 
126
- if (dryRun) {
127
- let canReadJournal = await hasMigrationJournal(adapter, journalTable)
179
+ if (canReadJournal) {
180
+ journal = await loadJournalRows(driver, journalTable)
181
+ }
182
+ } else {
183
+ await ensureMigrationJournal(driver, journalTable)
184
+ journal = await loadJournalRows(driver, journalTable)
185
+ }
128
186
 
129
- if (canReadJournal) {
130
- journal = await loadJournalRows(adapter, journalTable)
187
+ let appliedMap = new Map(journal.map((row) => [row.id, row]))
188
+ await assertMigrationIntegrity(migrations, journal, input.direction)
189
+ let toRun: MigrationDescriptor[] = []
190
+
191
+ if (input.direction === 'up') {
192
+ for (let migration of migrations) {
193
+ if (!appliedMap.has(migration.id)) {
194
+ toRun.push(migration)
131
195
  }
132
- } else {
133
- await ensureMigrationJournal(adapter, journalTable)
134
- journal = await loadJournalRows(adapter, journalTable)
135
196
  }
136
197
 
137
- let appliedMap = new Map(journal.map((row) => [row.id, row]))
138
- await assertNoMigrationDrift(migrations, journal)
139
- let toRun: MigrationDescriptor[] = []
198
+ if (target) {
199
+ toRun = toRun.filter((migration) => migration.id <= target)
200
+ }
140
201
 
141
- if (input.direction === 'up') {
142
- for (let migration of migrations) {
143
- if (!appliedMap.has(migration.id)) {
144
- toRun.push(migration)
145
- }
146
- }
202
+ if (step !== undefined) {
203
+ toRun = toRun.slice(0, step)
204
+ }
205
+ } else {
206
+ toRun = migrations.filter((migration) => appliedMap.has(migration.id)).reverse()
147
207
 
148
- if (target) {
149
- toRun = toRun.filter((migration) => migration.id <= target)
150
- }
208
+ if (target) {
209
+ toRun = toRun.filter((migration) => migration.id >= target)
210
+ }
151
211
 
152
- if (step !== undefined) {
153
- toRun = toRun.slice(0, step)
154
- }
155
- } else {
156
- toRun = migrations.filter((migration) => appliedMap.has(migration.id)).reverse()
212
+ if (step !== undefined) {
213
+ toRun = toRun.slice(0, step)
214
+ }
157
215
 
158
- if (target) {
159
- toRun = toRun.filter((migration) => migration.id >= target)
216
+ for (let migration of toRun) {
217
+ if (migration.down === undefined) {
218
+ throw new Error('Migration "' + migration.id + '" has no down script')
160
219
  }
220
+ }
221
+ }
161
222
 
162
- if (step !== undefined) {
163
- toRun = toRun.slice(0, step)
164
- }
223
+ let applied: MigrationStatusEntry[] = []
224
+ let reverted: MigrationStatusEntry[] = []
225
+ let batch = getBatch(journal)
165
226
 
166
- for (let migration of toRun) {
167
- if (migration.down === undefined) {
168
- throw new Error('Migration "' + migration.id + '" has no down script')
169
- }
170
- }
227
+ for (let migration of toRun) {
228
+ let script = (input.direction === 'up' ? migration.up : migration.down) as string
229
+ let mode = resolveTransactionMode(migration)
230
+
231
+ if (mode === 'required' && !driver.capabilities.transactionalDdl) {
232
+ throw new Error(
233
+ 'Migration "' +
234
+ migration.id +
235
+ '" requires transactional DDL, but the database does not support it',
236
+ )
171
237
  }
172
238
 
173
- let applied: MigrationStatusEntry[] = []
174
- let reverted: MigrationStatusEntry[] = []
175
- let batch = getBatch(journal)
239
+ let shouldUseTransaction = !dryRun && mode !== 'none' && driver.capabilities.transactionalDdl
240
+ let token: TransactionToken | undefined
176
241
 
177
- for (let migration of toRun) {
178
- let script = (input.direction === 'up' ? migration.up : migration.down) as string
179
- let mode = resolveTransactionMode(migration)
180
-
181
- if (mode === 'required' && !adapter.capabilities.transactionalDdl) {
182
- throw new Error(
183
- 'Migration "' +
184
- migration.id +
185
- '" requires transactional DDL, but adapter does not support it',
186
- )
187
- }
242
+ if (shouldUseTransaction) {
243
+ token = await driver.beginTransaction()
244
+ }
188
245
 
189
- let shouldUseTransaction = !dryRun && mode !== 'none' && adapter.capabilities.transactionalDdl
190
- let token: TransactionToken | undefined
246
+ sql.push(script)
191
247
 
192
- if (shouldUseTransaction) {
193
- token = await adapter.beginTransaction()
248
+ try {
249
+ if (!dryRun) {
250
+ if (script.trim().length > 0) {
251
+ await driver.executeScript(script, token)
252
+ }
194
253
  }
195
254
 
196
- sql.push(script)
197
-
198
- try {
255
+ if (input.direction === 'up') {
199
256
  if (!dryRun) {
200
- if (script.trim().length > 0) {
201
- await adapter.executeScript(script, token)
202
- }
257
+ await insertJournalRow(
258
+ driver,
259
+ journalTable,
260
+ {
261
+ id: migration.id,
262
+ name: migration.name,
263
+ checksum: await computeChecksum(migration),
264
+ batch,
265
+ },
266
+ token,
267
+ )
203
268
  }
204
269
 
205
- if (input.direction === 'up') {
206
- if (!dryRun) {
207
- await insertJournalRow(
208
- adapter,
209
- journalTable,
210
- {
211
- id: migration.id,
212
- name: migration.name,
213
- checksum: await computeChecksum(migration),
214
- batch,
215
- },
216
- token,
217
- )
218
- }
219
-
220
- applied.push({
221
- id: migration.id,
222
- name: migration.name,
223
- status: 'applied',
224
- })
225
- } else {
226
- if (!dryRun) {
227
- await deleteJournalRow(adapter, journalTable, migration.id, token)
228
- }
229
-
230
- reverted.push({
231
- id: migration.id,
232
- name: migration.name,
233
- status: 'pending',
234
- })
270
+ applied.push({
271
+ id: migration.id,
272
+ name: migration.name,
273
+ status: 'applied',
274
+ })
275
+ } else {
276
+ if (!dryRun) {
277
+ await deleteJournalRow(driver, journalTable, migration.id, token)
235
278
  }
236
279
 
237
- if (token) {
238
- await adapter.commitTransaction(token)
239
- }
240
- } catch (error) {
241
- if (token) {
242
- await adapter.rollbackTransaction(token)
280
+ reverted.push({
281
+ id: migration.id,
282
+ name: migration.name,
283
+ status: 'pending',
284
+ })
285
+ }
286
+ } catch (error) {
287
+ if (token) {
288
+ try {
289
+ await driver.rollbackTransaction(token)
290
+ } catch (rollbackError) {
291
+ throw new AggregateError([error, rollbackError], 'Migration and rollback both failed', {
292
+ cause: error,
293
+ })
243
294
  }
244
-
245
- throw error
246
295
  }
296
+
297
+ throw error
247
298
  }
248
299
 
249
- return {
250
- applied,
251
- reverted,
252
- sql,
300
+ if (token) {
301
+ await driver.commitTransaction(token)
253
302
  }
254
- } finally {
255
- await adapter.releaseMigrationLock?.()
303
+ }
304
+
305
+ return {
306
+ applied,
307
+ reverted,
308
+ sql,
256
309
  }
257
310
  }
258
311
 
259
- /**
260
- * Creates a migration runner for applying/reverting SQL migrations against an adapter.
261
- * @param adapter Database adapter used to execute migration scripts.
262
- * @param migrations Migration descriptors or registry.
263
- * @param options Optional runner configuration.
264
- * @returns A migration runner instance.
265
- * @example
266
- * ```ts
267
- * import { createMigrationRunner } from 'remix/data-table/migrations'
268
- *
269
- * let runner = createMigrationRunner(adapter, migrations, {
270
- * journalTable: 'app_migrations',
271
- * })
272
- * await runner.up()
273
- * ```
274
- */
275
312
  export function createMigrationRunner(
276
- adapter: DatabaseAdapter,
313
+ driver: DatabaseDriver,
277
314
  migrations: MigrationDescriptor[] | MigrationRegistry,
278
315
  options: MigrationRunnerOptions = {},
279
316
  ): MigrationRunner {
280
317
  let journalTable = options.journalTable ?? 'data_table_migrations'
281
318
 
282
319
  return {
283
- async up(runOptions: MigrateOptions = {}): Promise<MigrateResult> {
320
+ async up(runOptions: MigrationOperationOptions = {}): Promise<MigrateResult> {
284
321
  return runMigrations({
285
- adapter,
322
+ driver,
286
323
  migrations: resolveMigrations(migrations),
287
324
  journalTable,
288
325
  direction: 'up',
289
326
  options: runOptions,
290
327
  })
291
328
  },
292
- async down(runOptions: MigrateOptions = {}): Promise<MigrateResult> {
329
+ async down(runOptions: MigrationOperationOptions = {}): Promise<MigrateResult> {
293
330
  return runMigrations({
294
- adapter,
331
+ driver,
295
332
  migrations: resolveMigrations(migrations),
296
333
  journalTable,
297
334
  direction: 'down',
@@ -299,11 +336,12 @@ export function createMigrationRunner(
299
336
  })
300
337
  },
301
338
  async status(): Promise<MigrationStatusEntry[]> {
302
- await ensureMigrationJournal(adapter, journalTable)
303
-
304
- let journal = await loadJournalRows(adapter, journalTable)
339
+ let journal = (await hasMigrationJournal(driver, journalTable))
340
+ ? await loadJournalRows(driver, journalTable)
341
+ : []
305
342
  let journalMap = new Map(journal.map((row) => [row.id, row]))
306
343
  let sortedMigrations = resolveMigrations(migrations)
344
+ let migrationIds = new Set(sortedMigrations.map((migration) => migration.id))
307
345
 
308
346
  let statuses: MigrationStatusEntry[] = []
309
347
 
@@ -334,7 +372,22 @@ export function createMigrationRunner(
334
372
  })
335
373
  }
336
374
 
337
- return statuses
375
+ for (let journalRow of journal) {
376
+ if (migrationIds.has(journalRow.id)) {
377
+ continue
378
+ }
379
+
380
+ statuses.push({
381
+ id: journalRow.id,
382
+ name: journalRow.name,
383
+ status: 'missing',
384
+ appliedAt: journalRow.appliedAt,
385
+ batch: journalRow.batch,
386
+ checksum: journalRow.checksum,
387
+ })
388
+ }
389
+
390
+ return statuses.sort((left, right) => left.id.localeCompare(right.id))
338
391
  },
339
392
  }
340
393
  }
@@ -1,7 +1,7 @@
1
1
  import { promises as fs } from 'node:fs'
2
2
  import path from 'node:path'
3
3
 
4
- import type { MigrationDescriptor } from './migrations.ts'
4
+ import type { MigrationDescriptor, Seed } from './migrations.ts'
5
5
  import { parseMigrationDirectoryName } from './migrations/directory-name.ts'
6
6
 
7
7
  /**
@@ -81,6 +81,28 @@ export async function loadMigrations(directory: string): Promise<MigrationDescri
81
81
  return migrations
82
82
  }
83
83
 
84
+ /**
85
+ * Loads a SQL seed file on Node.js.
86
+ *
87
+ * The file may contain multiple SQL statements. Seeds that must be safe to
88
+ * run against an already-seeded database should use idempotent statements
89
+ * (for example, `insert or ignore` on SQLite).
90
+ *
91
+ * @param filename Absolute or relative path to a SQL seed file.
92
+ * @returns A seed function that executes the file's SQL script.
93
+ * @example
94
+ * ```ts
95
+ * import { loadSeed } from 'remix/data-table/migrations/node'
96
+ *
97
+ * let seed = await loadSeed('./app/data/seed.sql')
98
+ * await db.reset({ migrations, seed })
99
+ * ```
100
+ */
101
+ export async function loadSeed(filename: string): Promise<Seed> {
102
+ let sql = await fs.readFile(filename, 'utf8')
103
+ return (db) => db.executeScript(sql)
104
+ }
105
+
84
106
  function isNodeFileNotFoundError(error: unknown): boolean {
85
107
  return (
86
108
  typeof error === 'object' &&
@@ -1,24 +1,26 @@
1
+ import type { Database } from './database.ts'
2
+
1
3
  /**
2
4
  * Controls how each migration is wrapped in transactions.
3
5
  *
4
- * - `auto` (default): wrap when the adapter supports transactional DDL.
5
- * - `required`: wrap; throws when the adapter does not support transactional DDL.
6
+ * - `auto` (default): wrap when the database supports transactional DDL.
7
+ * - `required`: wrap; throws when the database does not support transactional DDL.
6
8
  * - `none`: never wrap.
7
9
  */
8
10
  export type MigrationTransactionMode = 'auto' | 'required' | 'none'
9
11
 
10
12
  /**
11
- * Migration metadata + SQL consumed by the registry/runner.
13
+ * Migration metadata and SQL consumed by `Database.migrate()`.
12
14
  */
13
15
  export type MigrationDescriptor = {
14
16
  /** Migration id (typically a `YYYYMMDDHHmmss` timestamp). */
15
17
  id: string
16
18
  /** Human-readable migration slug. */
17
19
  name: string
18
- /** SQL executed for `runner.up(...)`. May contain multiple statements. */
20
+ /** SQL executed when applying the migration. May contain multiple statements. */
19
21
  up: string
20
22
  /**
21
- * SQL executed for `runner.down(...)`. May contain multiple statements.
23
+ * SQL executed when reverting the migration. May contain multiple statements.
22
24
  * Omit (or pass `undefined`) for irreversible migrations.
23
25
  */
24
26
  down?: string
@@ -29,7 +31,7 @@ export type MigrationDescriptor = {
29
31
  }
30
32
 
31
33
  /**
32
- * Direction used by migration runner operations.
34
+ * Direction used by `Database.migrate()`.
33
35
  */
34
36
  export type MigrationDirection = 'up' | 'down'
35
37
 
@@ -45,12 +47,17 @@ export type MigrationJournalRow = {
45
47
  }
46
48
 
47
49
  /**
48
- * Effective status for a known migration.
50
+ * Effective migration status.
51
+ *
52
+ * - `applied`: the current migration matches its journal entry.
53
+ * - `pending`: the current migration has not been applied.
54
+ * - `drifted`: the current migration differs from its journal entry.
55
+ * - `missing`: an applied journal entry has no migration in the current set.
49
56
  */
50
- export type MigrationStatus = 'applied' | 'pending' | 'drifted'
57
+ export type MigrationStatus = 'applied' | 'pending' | 'drifted' | 'missing'
51
58
 
52
59
  /**
53
- * Status row returned by `runner.status()` and `runner.up/down(...)`.
60
+ * Status entry returned by database migration operations.
54
61
  */
55
62
  export type MigrationStatusEntry = {
56
63
  id: string
@@ -62,10 +69,13 @@ export type MigrationStatusEntry = {
62
69
  }
63
70
 
64
71
  /**
65
- * Common options for `runner.up(...)` and `runner.down(...)`.
72
+ * Bounds and dry-run options for a migration operation.
66
73
  * `to` and `step` are mutually exclusive.
74
+ *
75
+ * `to` accepts a bare migration id (`20260301113000`) or the full `id_name`
76
+ * directory form (`20260301113000_add_user_status`).
67
77
  */
68
- export type MigrateOptions =
78
+ export type MigrationOperationOptions =
69
79
  | {
70
80
  to: string
71
81
  step?: never
@@ -83,7 +93,7 @@ export type MigrateOptions =
83
93
  }
84
94
 
85
95
  /**
86
- * Result shape returned by migration runner commands.
96
+ * Result returned by `Database.migrate()`.
87
97
  */
88
98
  export type MigrateResult = {
89
99
  applied: MigrationStatusEntry[]
@@ -103,9 +113,21 @@ export type MigrationRegistry = {
103
113
  }
104
114
 
105
115
  /**
106
- * Options for creating a migration runner.
116
+ * Migration collection accepted by `db.migrate(...)` and `db.migrationStatus(...)`.
117
+ */
118
+ export type Migrations = MigrationDescriptor[] | MigrationRegistry
119
+
120
+ /**
121
+ * Function that initializes application data in a database.
107
122
  */
108
- export type MigrationRunnerOptions = {
123
+ export type Seed = (db: Database) => void | Promise<void>
124
+
125
+ /**
126
+ * Options for applying or reverting migrations through `Database.migrate()`.
127
+ */
128
+ export type DatabaseMigrateOptions = MigrationOperationOptions & {
129
+ /** Migration direction. Defaults to `up`. */
130
+ direction?: MigrationDirection
109
131
  /**
110
132
  * Journal table used to record applied migrations.
111
133
  * Defaults to `data_table_migrations`.
@@ -114,10 +136,27 @@ export type MigrationRunnerOptions = {
114
136
  }
115
137
 
116
138
  /**
117
- * Migration runner API for applying, reverting, and inspecting migration state.
139
+ * Options for reading migration status through `Database.migrationStatus()`.
118
140
  */
119
- export type MigrationRunner = {
120
- up(options?: MigrateOptions): Promise<MigrateResult>
121
- down(options?: MigrateOptions): Promise<MigrateResult>
122
- status(): Promise<MigrationStatusEntry[]>
141
+ export interface DatabaseMigrationStatusOptions {
142
+ /**
143
+ * Journal table used to record applied migrations.
144
+ * Defaults to `data_table_migrations`.
145
+ */
146
+ journalTable?: string
147
+ }
148
+
149
+ /**
150
+ * Options for rebuilding a database through `Database.reset()`.
151
+ */
152
+ export interface DatabaseResetOptions {
153
+ /** Migrations to apply after wiping the database. */
154
+ migrations: Migrations
155
+ /** Function that initializes application data after migrations finish. */
156
+ seed?: Seed
157
+ /**
158
+ * Journal table used to record applied migrations.
159
+ * Defaults to `data_table_migrations`.
160
+ */
161
+ journalTable?: string
123
162
  }
@@ -22,7 +22,7 @@ type PredicateColumn<input extends string | ColumnReferenceLike> = NormalizeColu
22
22
  string
23
23
 
24
24
  /**
25
- * Normalized predicate representation consumed by adapters.
25
+ * Normalized predicate representation consumed by drivers.
26
26
  */
27
27
  export type Predicate<column extends string = string> =
28
28
  | {
package/src/lib/query.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { JoinClause, JoinType, SelectColumn } from './adapter.ts'
1
+ import type { JoinClause, JoinType, SelectColumn } from './driver.ts'
2
2
  import { DataTableQueryError, DataTableValidationError } from './errors.ts'
3
3
  import type {
4
4
  MergeColumnTypeMaps,
@@ -1,4 +1,4 @@
1
- import type { TableRef } from './adapter.ts'
1
+ import type { TableRef } from './driver.ts'
2
2
 
3
3
  /**
4
4
  * Function used to quote SQL identifiers for a dialect.