@remix-run/data-table 0.2.1 → 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.
- package/README.md +251 -123
- package/dist/cli.d.ts +54 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +53 -0
- package/dist/index.d.ts +5 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -7
- package/dist/lib/column.d.ts +1 -1
- package/dist/lib/column.d.ts.map +1 -1
- package/dist/lib/column.js +10 -1
- package/dist/lib/database/execution-context.d.ts +5 -5
- package/dist/lib/database/execution-context.d.ts.map +1 -1
- package/dist/lib/database/execution-context.js +1 -0
- package/dist/lib/database/helpers.js +6 -6
- package/dist/lib/database/query-execution.d.ts.map +1 -1
- package/dist/lib/database/query-execution.js +17 -17
- package/dist/lib/database/relations.js +5 -5
- package/dist/lib/database/write-lifecycle.d.ts +2 -2
- package/dist/lib/database/write-lifecycle.d.ts.map +1 -1
- package/dist/lib/database/write-lifecycle.js +5 -5
- package/dist/lib/database.d.ts +74 -59
- package/dist/lib/database.d.ts.map +1 -1
- package/dist/lib/database.js +176 -83
- package/dist/lib/driver.d.ts +287 -0
- package/dist/lib/driver.d.ts.map +1 -0
- package/dist/lib/errors.d.ts +2 -2
- package/dist/lib/errors.d.ts.map +1 -1
- package/dist/lib/errors.js +4 -4
- package/dist/lib/migrations/directive.d.ts +12 -0
- package/dist/lib/migrations/directive.d.ts.map +1 -0
- package/dist/lib/migrations/directive.js +28 -0
- package/dist/lib/migrations/directory-name.d.ts +12 -0
- package/dist/lib/migrations/directory-name.d.ts.map +1 -0
- package/dist/lib/migrations/directory-name.js +18 -0
- package/dist/lib/migrations/journal-store.d.ts +7 -7
- package/dist/lib/migrations/journal-store.d.ts.map +1 -1
- package/dist/lib/migrations/journal-store.js +37 -28
- package/dist/lib/migrations/registry.d.ts +1 -1
- package/dist/lib/migrations/registry.js +1 -1
- package/dist/lib/migrations/runner.d.ts +12 -19
- package/dist/lib/migrations/runner.d.ts.map +1 -1
- package/dist/lib/migrations/runner.js +170 -175
- package/dist/lib/migrations-node.d.ts +26 -5
- package/dist/lib/migrations-node.d.ts.map +1 -1
- package/dist/lib/migrations-node.js +73 -41
- package/dist/lib/migrations.d.ts +63 -209
- package/dist/lib/migrations.d.ts.map +1 -1
- package/dist/lib/migrations.js +1 -38
- package/dist/lib/operators.d.ts +1 -1
- package/dist/lib/operators.js +1 -1
- package/dist/lib/query.d.ts +34 -1
- package/dist/lib/query.d.ts.map +1 -1
- package/dist/lib/query.js +32 -4
- package/dist/lib/sql-helpers.d.ts +1 -7
- package/dist/lib/sql-helpers.d.ts.map +1 -1
- package/dist/lib/sql-helpers.js +0 -16
- package/dist/lib/sql.d.ts +1 -1
- package/dist/lib/sql.js +1 -1
- package/dist/lib/table.d.ts +1 -1
- package/dist/lib/table.d.ts.map +1 -1
- package/dist/lib/table.js +5 -5
- package/dist/migrations/node.d.ts +1 -1
- package/dist/migrations/node.d.ts.map +1 -1
- package/dist/migrations/node.js +1 -1
- package/dist/migrations.d.ts +2 -6
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +2 -5
- package/dist/operators.js +1 -1
- package/dist/sql-helpers.d.ts +1 -1
- package/dist/sql-helpers.d.ts.map +1 -1
- package/dist/sql-helpers.js +1 -1
- package/package.json +13 -9
- package/src/cli.ts +120 -0
- package/src/index.ts +20 -54
- package/src/lib/column.ts +14 -2
- package/src/lib/database/execution-context.ts +10 -6
- package/src/lib/database/helpers.ts +1 -1
- package/src/lib/database/query-execution.ts +15 -11
- package/src/lib/database/write-lifecycle.ts +4 -4
- package/src/lib/database.ts +223 -96
- package/src/lib/driver.ts +333 -0
- package/src/lib/errors.ts +4 -4
- package/src/lib/migrations/directive.ts +38 -0
- package/src/lib/migrations/directory-name.ts +23 -0
- package/src/lib/migrations/journal-store.ts +42 -28
- package/src/lib/migrations/registry.ts +1 -1
- package/src/lib/migrations/runner.ts +224 -205
- package/src/lib/migrations-node.ts +80 -38
- package/src/lib/migrations.ts +62 -228
- package/src/lib/operators.ts +1 -1
- package/src/lib/query.ts +34 -1
- package/src/lib/sql-helpers.ts +1 -22
- package/src/lib/sql.ts +1 -1
- package/src/lib/table.ts +1 -1
- package/src/migrations/node.ts +1 -1
- package/src/migrations.ts +5 -16
- package/src/sql-helpers.ts +0 -1
- package/dist/lib/adapter.d.ts +0 -550
- package/dist/lib/adapter.d.ts.map +0 -1
- package/dist/lib/migrations/filename.d.ts +0 -12
- package/dist/lib/migrations/filename.d.ts.map +0 -1
- package/dist/lib/migrations/filename.js +0 -20
- package/dist/lib/migrations/helpers.d.ts +0 -11
- package/dist/lib/migrations/helpers.d.ts.map +0 -1
- package/dist/lib/migrations/helpers.js +0 -77
- package/dist/lib/migrations/schema-api.d.ts +0 -7
- package/dist/lib/migrations/schema-api.d.ts.map +0 -1
- package/dist/lib/migrations/schema-api.js +0 -326
- package/src/lib/adapter.ts +0 -653
- package/src/lib/migrations/filename.ts +0 -25
- package/src/lib/migrations/helpers.ts +0 -108
- package/src/lib/migrations/schema-api.ts +0 -417
- /package/dist/lib/{adapter.js → driver.js} +0 -0
|
@@ -1,21 +1,27 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { Database } from '../database.ts'
|
|
3
|
-
import type { DatabaseAdapter, TransactionToken } from '../adapter.ts'
|
|
4
|
-
import type { SqlStatement } from '../sql.ts'
|
|
1
|
+
import type { DatabaseDriver, TransactionToken } from '../driver.ts'
|
|
5
2
|
import type {
|
|
6
|
-
|
|
3
|
+
MigrationOperationOptions,
|
|
7
4
|
MigrateResult,
|
|
8
|
-
MigrationContext,
|
|
9
5
|
MigrationDescriptor,
|
|
10
6
|
MigrationDirection,
|
|
11
7
|
MigrationJournalRow,
|
|
12
8
|
MigrationRegistry,
|
|
13
|
-
MigrationRunner,
|
|
14
|
-
MigrationRunnerOptions,
|
|
15
9
|
MigrationStatus,
|
|
16
10
|
MigrationStatusEntry,
|
|
11
|
+
MigrationTransactionMode,
|
|
17
12
|
} from '../migrations.ts'
|
|
18
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
|
+
|
|
24
|
+
import { parseTransactionDirective } from './directive.ts'
|
|
19
25
|
import {
|
|
20
26
|
deleteJournalRow,
|
|
21
27
|
ensureMigrationJournal,
|
|
@@ -23,17 +29,18 @@ import {
|
|
|
23
29
|
hasMigrationJournal,
|
|
24
30
|
insertJournalRow,
|
|
25
31
|
loadJournalRows,
|
|
26
|
-
|
|
32
|
+
computeChecksum,
|
|
27
33
|
} from './journal-store.ts'
|
|
28
34
|
import { resolveMigrations } from './registry.ts'
|
|
29
|
-
|
|
35
|
+
|
|
36
|
+
type MigrationRunnerContext = DatabaseDriver
|
|
30
37
|
|
|
31
38
|
type RunMigrationsInput = {
|
|
32
|
-
|
|
39
|
+
driver: MigrationRunnerContext
|
|
33
40
|
migrations: MigrationDescriptor[]
|
|
34
41
|
journalTable: string
|
|
35
42
|
direction: MigrationDirection
|
|
36
|
-
options:
|
|
43
|
+
options: MigrationOperationOptions
|
|
37
44
|
}
|
|
38
45
|
|
|
39
46
|
function assertStepOption(step: number | undefined): void {
|
|
@@ -46,38 +53,65 @@ function assertStepOption(step: number | undefined): void {
|
|
|
46
53
|
}
|
|
47
54
|
}
|
|
48
55
|
|
|
49
|
-
function
|
|
56
|
+
function assertMigrationOperationOptions(options: MigrationOperationOptions): void {
|
|
50
57
|
if (options.to !== undefined && options.step !== undefined) {
|
|
51
58
|
throw new Error('Cannot combine "to" and "step" migration options in the same run')
|
|
52
59
|
}
|
|
53
60
|
}
|
|
54
61
|
|
|
55
|
-
function
|
|
62
|
+
function resolveTargetOption(
|
|
63
|
+
migrations: MigrationDescriptor[],
|
|
64
|
+
to: string | undefined,
|
|
65
|
+
): string | undefined {
|
|
56
66
|
if (!to) {
|
|
57
|
-
return
|
|
67
|
+
return undefined
|
|
58
68
|
}
|
|
59
69
|
|
|
60
|
-
|
|
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
|
+
)
|
|
61
75
|
|
|
62
|
-
if (
|
|
76
|
+
if (matches.length === 0) {
|
|
63
77
|
throw new Error('Unknown migration target: ' + to)
|
|
64
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
|
|
65
90
|
}
|
|
66
91
|
|
|
67
|
-
function
|
|
92
|
+
async function assertMigrationIntegrity(
|
|
68
93
|
migrations: MigrationDescriptor[],
|
|
69
94
|
journal: MigrationJournalRow[],
|
|
70
|
-
|
|
95
|
+
direction: MigrationDirection,
|
|
96
|
+
): Promise<void> {
|
|
71
97
|
let migrationMap = new Map(migrations.map((migration) => [migration.id, migration]))
|
|
72
98
|
|
|
73
99
|
for (let row of journal) {
|
|
74
100
|
let migration = migrationMap.get(row.id)
|
|
75
101
|
|
|
76
102
|
if (!migration) {
|
|
77
|
-
|
|
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
|
+
)
|
|
78
112
|
}
|
|
79
113
|
|
|
80
|
-
let expected =
|
|
114
|
+
let expected = await computeChecksum(migration)
|
|
81
115
|
|
|
82
116
|
if (expected !== row.checksum) {
|
|
83
117
|
throw new Error(
|
|
@@ -93,244 +127,208 @@ function assertNoMigrationDrift(
|
|
|
93
127
|
}
|
|
94
128
|
}
|
|
95
129
|
|
|
96
|
-
function
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
throw error
|
|
130
|
+
function resolveTransactionMode(migration: MigrationDescriptor): MigrationTransactionMode {
|
|
131
|
+
if (migration.transaction) {
|
|
132
|
+
return migration.transaction
|
|
100
133
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
},
|
|
107
|
-
async hasTable(table) {
|
|
108
|
-
return adapter.hasTable(table)
|
|
109
|
-
},
|
|
110
|
-
async hasColumn(table, column) {
|
|
111
|
-
return adapter.hasColumn(table, column)
|
|
112
|
-
},
|
|
113
|
-
execute: throwDryRunError,
|
|
114
|
-
migrate: throwDryRunError,
|
|
115
|
-
beginTransaction: throwDryRunError,
|
|
116
|
-
commitTransaction: throwDryRunError,
|
|
117
|
-
rollbackTransaction: throwDryRunError,
|
|
118
|
-
createSavepoint: throwDryRunError,
|
|
119
|
-
rollbackToSavepoint: throwDryRunError,
|
|
120
|
-
releaseSavepoint: throwDryRunError,
|
|
134
|
+
|
|
135
|
+
let directive = parseTransactionDirective(migration.up)
|
|
136
|
+
|
|
137
|
+
if (directive) {
|
|
138
|
+
return directive
|
|
121
139
|
}
|
|
122
140
|
|
|
123
|
-
return
|
|
141
|
+
return 'auto'
|
|
124
142
|
}
|
|
125
143
|
|
|
126
144
|
async function runMigrations(input: RunMigrationsInput): Promise<MigrateResult> {
|
|
127
|
-
|
|
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
|
|
128
162
|
let migrations = input.migrations
|
|
129
163
|
let journalTable = input.journalTable
|
|
130
164
|
let dryRun = Boolean(input.options.dryRun)
|
|
131
|
-
let target = input.options.to
|
|
132
165
|
let step = input.options.step
|
|
133
166
|
|
|
134
|
-
|
|
167
|
+
assertMigrationOperationOptions(input.options)
|
|
135
168
|
assertStepOption(step)
|
|
136
|
-
assertTargetOption(migrations, target)
|
|
137
169
|
|
|
138
|
-
let
|
|
170
|
+
let target = resolveTargetOption(migrations, input.options.to)
|
|
139
171
|
|
|
140
|
-
|
|
172
|
+
let sql: string[] = []
|
|
141
173
|
|
|
142
|
-
|
|
143
|
-
let journal: MigrationJournalRow[] = []
|
|
174
|
+
let journal: MigrationJournalRow[] = []
|
|
144
175
|
|
|
145
|
-
|
|
146
|
-
|
|
176
|
+
if (dryRun) {
|
|
177
|
+
let canReadJournal = await hasMigrationJournal(driver, journalTable)
|
|
147
178
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
}
|
|
151
|
-
} else {
|
|
152
|
-
await ensureMigrationJournal(adapter, journalTable)
|
|
153
|
-
journal = await loadJournalRows(adapter, journalTable)
|
|
179
|
+
if (canReadJournal) {
|
|
180
|
+
journal = await loadJournalRows(driver, journalTable)
|
|
154
181
|
}
|
|
182
|
+
} else {
|
|
183
|
+
await ensureMigrationJournal(driver, journalTable)
|
|
184
|
+
journal = await loadJournalRows(driver, journalTable)
|
|
185
|
+
}
|
|
155
186
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
if (input.direction === 'up') {
|
|
161
|
-
for (let migration of migrations) {
|
|
162
|
-
if (!appliedMap.has(migration.id)) {
|
|
163
|
-
toRun.push(migration)
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
if (target) {
|
|
168
|
-
toRun = toRun.filter((migration) => migration.id <= target)
|
|
169
|
-
}
|
|
187
|
+
let appliedMap = new Map(journal.map((row) => [row.id, row]))
|
|
188
|
+
await assertMigrationIntegrity(migrations, journal, input.direction)
|
|
189
|
+
let toRun: MigrationDescriptor[] = []
|
|
170
190
|
|
|
171
|
-
|
|
172
|
-
|
|
191
|
+
if (input.direction === 'up') {
|
|
192
|
+
for (let migration of migrations) {
|
|
193
|
+
if (!appliedMap.has(migration.id)) {
|
|
194
|
+
toRun.push(migration)
|
|
173
195
|
}
|
|
174
|
-
}
|
|
175
|
-
let appliedMigrations = migrations
|
|
176
|
-
.filter((migration) => appliedMap.has(migration.id))
|
|
177
|
-
.reverse()
|
|
196
|
+
}
|
|
178
197
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
198
|
+
if (target) {
|
|
199
|
+
toRun = toRun.filter((migration) => migration.id <= target)
|
|
200
|
+
}
|
|
182
201
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
202
|
+
if (step !== undefined) {
|
|
203
|
+
toRun = toRun.slice(0, step)
|
|
204
|
+
}
|
|
205
|
+
} else {
|
|
206
|
+
toRun = migrations.filter((migration) => appliedMap.has(migration.id)).reverse()
|
|
186
207
|
|
|
187
|
-
|
|
208
|
+
if (target) {
|
|
209
|
+
toRun = toRun.filter((migration) => migration.id >= target)
|
|
188
210
|
}
|
|
189
211
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
212
|
+
if (step !== undefined) {
|
|
213
|
+
toRun = toRun.slice(0, step)
|
|
214
|
+
}
|
|
193
215
|
|
|
194
216
|
for (let migration of toRun) {
|
|
195
|
-
if (
|
|
196
|
-
migration.
|
|
197
|
-
!adapter.capabilities.transactionalDdl
|
|
198
|
-
) {
|
|
199
|
-
throw new Error(
|
|
200
|
-
'Migration "' +
|
|
201
|
-
migration.id +
|
|
202
|
-
'" requires transactional DDL, but adapter does not support it',
|
|
203
|
-
)
|
|
217
|
+
if (migration.down === undefined) {
|
|
218
|
+
throw new Error('Migration "' + migration.id + '" has no down script')
|
|
204
219
|
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
205
222
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
adapter.capabilities.transactionalDdl
|
|
210
|
-
let token: TransactionToken | undefined
|
|
223
|
+
let applied: MigrationStatusEntry[] = []
|
|
224
|
+
let reverted: MigrationStatusEntry[] = []
|
|
225
|
+
let batch = getBatch(journal)
|
|
211
226
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
227
|
+
for (let migration of toRun) {
|
|
228
|
+
let script = (input.direction === 'up' ? migration.up : migration.down) as string
|
|
229
|
+
let mode = resolveTransactionMode(migration)
|
|
215
230
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
let schema = createMigrationSchema(
|
|
223
|
-
db,
|
|
224
|
-
async (operation) => {
|
|
225
|
-
let compiled = adapter.compileSql(operation)
|
|
226
|
-
sql.push(...compiled)
|
|
227
|
-
|
|
228
|
-
if (!dryRun) {
|
|
229
|
-
await adapter.migrate({ operation, transaction: token })
|
|
230
|
-
}
|
|
231
|
-
},
|
|
232
|
-
{ transaction: token },
|
|
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',
|
|
233
236
|
)
|
|
234
|
-
|
|
235
|
-
db,
|
|
236
|
-
schema,
|
|
237
|
-
}
|
|
237
|
+
}
|
|
238
238
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
await migration.migration.up(context)
|
|
242
|
-
|
|
243
|
-
if (!dryRun) {
|
|
244
|
-
await insertJournalRow(
|
|
245
|
-
adapter,
|
|
246
|
-
journalTable,
|
|
247
|
-
{
|
|
248
|
-
id: migration.id,
|
|
249
|
-
name: migration.name,
|
|
250
|
-
checksum: normalizeChecksum(migration),
|
|
251
|
-
batch,
|
|
252
|
-
},
|
|
253
|
-
token,
|
|
254
|
-
)
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
applied.push({
|
|
258
|
-
id: migration.id,
|
|
259
|
-
name: migration.name,
|
|
260
|
-
status: 'applied',
|
|
261
|
-
})
|
|
262
|
-
} else {
|
|
263
|
-
await migration.migration.down(context)
|
|
239
|
+
let shouldUseTransaction = !dryRun && mode !== 'none' && driver.capabilities.transactionalDdl
|
|
240
|
+
let token: TransactionToken | undefined
|
|
264
241
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
242
|
+
if (shouldUseTransaction) {
|
|
243
|
+
token = await driver.beginTransaction()
|
|
244
|
+
}
|
|
268
245
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
246
|
+
sql.push(script)
|
|
247
|
+
|
|
248
|
+
try {
|
|
249
|
+
if (!dryRun) {
|
|
250
|
+
if (script.trim().length > 0) {
|
|
251
|
+
await driver.executeScript(script, token)
|
|
274
252
|
}
|
|
253
|
+
}
|
|
275
254
|
|
|
276
|
-
|
|
277
|
-
|
|
255
|
+
if (input.direction === 'up') {
|
|
256
|
+
if (!dryRun) {
|
|
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
|
+
)
|
|
278
268
|
}
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
269
|
+
|
|
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)
|
|
282
278
|
}
|
|
283
279
|
|
|
284
|
-
|
|
280
|
+
reverted.push({
|
|
281
|
+
id: migration.id,
|
|
282
|
+
name: migration.name,
|
|
283
|
+
status: 'pending',
|
|
284
|
+
})
|
|
285
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
|
+
})
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
throw error
|
|
286
298
|
}
|
|
287
299
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
reverted,
|
|
291
|
-
sql,
|
|
300
|
+
if (token) {
|
|
301
|
+
await driver.commitTransaction(token)
|
|
292
302
|
}
|
|
293
|
-
}
|
|
294
|
-
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
return {
|
|
306
|
+
applied,
|
|
307
|
+
reverted,
|
|
308
|
+
sql,
|
|
295
309
|
}
|
|
296
310
|
}
|
|
297
311
|
|
|
298
|
-
/**
|
|
299
|
-
* Creates a migration runner for applying/reverting migrations against an adapter.
|
|
300
|
-
* @param adapter Database adapter used to compile and execute migration operations.
|
|
301
|
-
* @param migrations Migration descriptors or registry.
|
|
302
|
-
* @param options Optional runner configuration.
|
|
303
|
-
* @returns A migration runner instance.
|
|
304
|
-
* @example
|
|
305
|
-
* ```ts
|
|
306
|
-
* import { createMigrationRunner } from 'remix/data-table/migrations'
|
|
307
|
-
*
|
|
308
|
-
* let runner = createMigrationRunner(adapter, migrations, {
|
|
309
|
-
* journalTable: 'app_migrations',
|
|
310
|
-
* })
|
|
311
|
-
* await runner.up()
|
|
312
|
-
* ```
|
|
313
|
-
*/
|
|
314
312
|
export function createMigrationRunner(
|
|
315
|
-
|
|
313
|
+
driver: DatabaseDriver,
|
|
316
314
|
migrations: MigrationDescriptor[] | MigrationRegistry,
|
|
317
315
|
options: MigrationRunnerOptions = {},
|
|
318
316
|
): MigrationRunner {
|
|
319
317
|
let journalTable = options.journalTable ?? 'data_table_migrations'
|
|
320
318
|
|
|
321
319
|
return {
|
|
322
|
-
async up(runOptions:
|
|
320
|
+
async up(runOptions: MigrationOperationOptions = {}): Promise<MigrateResult> {
|
|
323
321
|
return runMigrations({
|
|
324
|
-
|
|
322
|
+
driver,
|
|
325
323
|
migrations: resolveMigrations(migrations),
|
|
326
324
|
journalTable,
|
|
327
325
|
direction: 'up',
|
|
328
326
|
options: runOptions,
|
|
329
327
|
})
|
|
330
328
|
},
|
|
331
|
-
async down(runOptions:
|
|
329
|
+
async down(runOptions: MigrationOperationOptions = {}): Promise<MigrateResult> {
|
|
332
330
|
return runMigrations({
|
|
333
|
-
|
|
331
|
+
driver,
|
|
334
332
|
migrations: resolveMigrations(migrations),
|
|
335
333
|
journalTable,
|
|
336
334
|
direction: 'down',
|
|
@@ -338,26 +336,30 @@ export function createMigrationRunner(
|
|
|
338
336
|
})
|
|
339
337
|
},
|
|
340
338
|
async status(): Promise<MigrationStatusEntry[]> {
|
|
341
|
-
await
|
|
342
|
-
|
|
343
|
-
|
|
339
|
+
let journal = (await hasMigrationJournal(driver, journalTable))
|
|
340
|
+
? await loadJournalRows(driver, journalTable)
|
|
341
|
+
: []
|
|
344
342
|
let journalMap = new Map(journal.map((row) => [row.id, row]))
|
|
345
343
|
let sortedMigrations = resolveMigrations(migrations)
|
|
344
|
+
let migrationIds = new Set(sortedMigrations.map((migration) => migration.id))
|
|
346
345
|
|
|
347
|
-
|
|
346
|
+
let statuses: MigrationStatusEntry[] = []
|
|
347
|
+
|
|
348
|
+
for (let migration of sortedMigrations) {
|
|
348
349
|
let journalRow = journalMap.get(migration.id)
|
|
349
350
|
|
|
350
351
|
if (!journalRow) {
|
|
351
|
-
|
|
352
|
+
statuses.push({
|
|
352
353
|
id: migration.id,
|
|
353
354
|
name: migration.name,
|
|
354
355
|
status: 'pending' as MigrationStatus,
|
|
355
|
-
}
|
|
356
|
+
})
|
|
357
|
+
continue
|
|
356
358
|
}
|
|
357
359
|
|
|
358
|
-
let checksum =
|
|
360
|
+
let checksum = await computeChecksum(migration)
|
|
359
361
|
|
|
360
|
-
|
|
362
|
+
statuses.push({
|
|
361
363
|
id: migration.id,
|
|
362
364
|
name: migration.name,
|
|
363
365
|
status:
|
|
@@ -367,8 +369,25 @@ export function createMigrationRunner(
|
|
|
367
369
|
appliedAt: journalRow.appliedAt,
|
|
368
370
|
batch: journalRow.batch,
|
|
369
371
|
checksum: journalRow.checksum,
|
|
372
|
+
})
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
for (let journalRow of journal) {
|
|
376
|
+
if (migrationIds.has(journalRow.id)) {
|
|
377
|
+
continue
|
|
370
378
|
}
|
|
371
|
-
|
|
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))
|
|
372
391
|
},
|
|
373
392
|
}
|
|
374
393
|
}
|