@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
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
import type { AnyTable, OrderByClause } from './table.ts'
|
|
2
|
+
import type { Predicate } from './operators.ts'
|
|
3
|
+
import type { SqlStatement } from './sql.ts'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* SQL join kinds supported by database drivers.
|
|
7
|
+
*/
|
|
8
|
+
export type JoinType = 'inner' | 'left' | 'right'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Join configuration used in compiled select statements.
|
|
12
|
+
*/
|
|
13
|
+
export type JoinClause = {
|
|
14
|
+
type: JoinType
|
|
15
|
+
table: AnyTable
|
|
16
|
+
on: Predicate
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Selected output column with optional alias.
|
|
21
|
+
*/
|
|
22
|
+
export type SelectColumn = {
|
|
23
|
+
column: string
|
|
24
|
+
alias: string
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Returning selection for write statements.
|
|
29
|
+
*/
|
|
30
|
+
export type ReturningSelection = '*' | string[]
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Canonical select statement shape consumed by drivers.
|
|
34
|
+
*/
|
|
35
|
+
export type SelectOperation<table extends AnyTable = AnyTable> = {
|
|
36
|
+
kind: 'select'
|
|
37
|
+
table: table
|
|
38
|
+
select: '*' | SelectColumn[]
|
|
39
|
+
distinct: boolean
|
|
40
|
+
joins: JoinClause[]
|
|
41
|
+
where: Predicate[]
|
|
42
|
+
groupBy: string[]
|
|
43
|
+
having: Predicate[]
|
|
44
|
+
orderBy: OrderByClause[]
|
|
45
|
+
limit?: number
|
|
46
|
+
offset?: number
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Canonical count statement shape consumed by drivers.
|
|
51
|
+
*/
|
|
52
|
+
export type CountOperation<table extends AnyTable = AnyTable> = {
|
|
53
|
+
kind: 'count'
|
|
54
|
+
table: table
|
|
55
|
+
joins: JoinClause[]
|
|
56
|
+
where: Predicate[]
|
|
57
|
+
groupBy: string[]
|
|
58
|
+
having: Predicate[]
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Canonical exists statement shape consumed by drivers.
|
|
63
|
+
*/
|
|
64
|
+
export type ExistsOperation<table extends AnyTable = AnyTable> = {
|
|
65
|
+
kind: 'exists'
|
|
66
|
+
table: table
|
|
67
|
+
joins: JoinClause[]
|
|
68
|
+
where: Predicate[]
|
|
69
|
+
groupBy: string[]
|
|
70
|
+
having: Predicate[]
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Canonical insert statement shape consumed by drivers.
|
|
75
|
+
*/
|
|
76
|
+
export type InsertOperation<table extends AnyTable = AnyTable> = {
|
|
77
|
+
kind: 'insert'
|
|
78
|
+
table: table
|
|
79
|
+
values: Record<string, unknown>
|
|
80
|
+
returning?: ReturningSelection
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Canonical bulk-insert statement shape consumed by drivers.
|
|
85
|
+
*/
|
|
86
|
+
export type InsertManyOperation<table extends AnyTable = AnyTable> = {
|
|
87
|
+
kind: 'insertMany'
|
|
88
|
+
table: table
|
|
89
|
+
values: Record<string, unknown>[]
|
|
90
|
+
returning?: ReturningSelection
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Canonical update statement shape consumed by drivers.
|
|
95
|
+
*/
|
|
96
|
+
export type UpdateOperation<table extends AnyTable = AnyTable> = {
|
|
97
|
+
kind: 'update'
|
|
98
|
+
table: table
|
|
99
|
+
changes: Record<string, unknown>
|
|
100
|
+
where: Predicate[]
|
|
101
|
+
returning?: ReturningSelection
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Canonical delete statement shape consumed by drivers.
|
|
106
|
+
*/
|
|
107
|
+
export type DeleteOperation<table extends AnyTable = AnyTable> = {
|
|
108
|
+
kind: 'delete'
|
|
109
|
+
table: table
|
|
110
|
+
where: Predicate[]
|
|
111
|
+
returning?: ReturningSelection
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Canonical upsert statement shape consumed by drivers.
|
|
116
|
+
*/
|
|
117
|
+
export type UpsertOperation<table extends AnyTable = AnyTable> = {
|
|
118
|
+
kind: 'upsert'
|
|
119
|
+
table: table
|
|
120
|
+
values: Record<string, unknown>
|
|
121
|
+
conflictTarget?: string[]
|
|
122
|
+
update?: Record<string, unknown>
|
|
123
|
+
returning?: ReturningSelection
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Raw SQL statement execution descriptor.
|
|
128
|
+
*/
|
|
129
|
+
export type RawOperation = {
|
|
130
|
+
kind: 'raw'
|
|
131
|
+
sql: SqlStatement
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Union of all data-manipulation statement shapes.
|
|
136
|
+
*/
|
|
137
|
+
export type DataManipulationOperation =
|
|
138
|
+
| SelectOperation
|
|
139
|
+
| CountOperation
|
|
140
|
+
| ExistsOperation
|
|
141
|
+
| InsertOperation
|
|
142
|
+
| InsertManyOperation
|
|
143
|
+
| UpdateOperation
|
|
144
|
+
| DeleteOperation
|
|
145
|
+
| UpsertOperation
|
|
146
|
+
| RawOperation
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Qualified table reference.
|
|
150
|
+
*/
|
|
151
|
+
export type TableRef = {
|
|
152
|
+
name: string
|
|
153
|
+
schema?: string
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Referential actions supported by foreign key constraints.
|
|
158
|
+
*/
|
|
159
|
+
export type ForeignKeyAction = 'cascade' | 'restrict' | 'set null' | 'set default' | 'no action'
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Logical column type names used by schema definitions.
|
|
163
|
+
*/
|
|
164
|
+
export type ColumnTypeName =
|
|
165
|
+
| 'varchar'
|
|
166
|
+
| 'text'
|
|
167
|
+
| 'integer'
|
|
168
|
+
| 'bigint'
|
|
169
|
+
| 'decimal'
|
|
170
|
+
| 'boolean'
|
|
171
|
+
| 'uuid'
|
|
172
|
+
| 'date'
|
|
173
|
+
| 'time'
|
|
174
|
+
| 'timestamp'
|
|
175
|
+
| 'json'
|
|
176
|
+
| 'binary'
|
|
177
|
+
| 'enum'
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Default value definition for a column.
|
|
181
|
+
*/
|
|
182
|
+
export type ColumnDefault =
|
|
183
|
+
| { kind: 'literal'; value: unknown }
|
|
184
|
+
| { kind: 'now' }
|
|
185
|
+
| { kind: 'sql'; expression: string }
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Definition for a computed or generated column.
|
|
189
|
+
*/
|
|
190
|
+
export type ColumnComputed = {
|
|
191
|
+
expression: string
|
|
192
|
+
stored: boolean
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/** Options for configuring identity column generation. */
|
|
196
|
+
export type IdentityOptions = {
|
|
197
|
+
always?: boolean
|
|
198
|
+
start?: number
|
|
199
|
+
increment?: number
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/** Foreign-key reference metadata declared on a column. */
|
|
203
|
+
export type ColumnReference = {
|
|
204
|
+
table: TableRef
|
|
205
|
+
columns: string[]
|
|
206
|
+
name: string
|
|
207
|
+
onDelete?: ForeignKeyAction
|
|
208
|
+
onUpdate?: ForeignKeyAction
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Check constraint declared on a column definition.
|
|
213
|
+
*/
|
|
214
|
+
export type ColumnCheck = {
|
|
215
|
+
expression: string
|
|
216
|
+
name: string
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Normalized column definition used in schema operations.
|
|
221
|
+
*/
|
|
222
|
+
export type ColumnDefinition = {
|
|
223
|
+
type: ColumnTypeName
|
|
224
|
+
nullable?: boolean
|
|
225
|
+
primaryKey?: boolean
|
|
226
|
+
unique?: boolean | { name?: string }
|
|
227
|
+
default?: ColumnDefault
|
|
228
|
+
computed?: ColumnComputed
|
|
229
|
+
references?: ColumnReference
|
|
230
|
+
checks?: ColumnCheck[]
|
|
231
|
+
comment?: string
|
|
232
|
+
length?: number
|
|
233
|
+
precision?: number
|
|
234
|
+
scale?: number
|
|
235
|
+
unsigned?: boolean
|
|
236
|
+
withTimezone?: boolean
|
|
237
|
+
enumValues?: string[]
|
|
238
|
+
autoIncrement?: boolean
|
|
239
|
+
identity?: IdentityOptions
|
|
240
|
+
collate?: string
|
|
241
|
+
charset?: string
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Opaque transaction handle supplied by database drivers.
|
|
246
|
+
*/
|
|
247
|
+
export type TransactionToken = {
|
|
248
|
+
id: string
|
|
249
|
+
metadata?: Record<string, unknown>
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Transaction hints that database drivers may apply when supported by the dialect.
|
|
254
|
+
*/
|
|
255
|
+
export type TransactionOptions = {
|
|
256
|
+
isolationLevel?: 'read uncommitted' | 'read committed' | 'repeatable read' | 'serializable'
|
|
257
|
+
readOnly?: boolean
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Database driver execution request payload.
|
|
262
|
+
*/
|
|
263
|
+
export type DataManipulationRequest = {
|
|
264
|
+
operation: DataManipulationOperation
|
|
265
|
+
transaction?: TransactionToken
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Database data-manipulation result payload.
|
|
270
|
+
*/
|
|
271
|
+
export type DataManipulationResult = {
|
|
272
|
+
rows?: Record<string, unknown>[]
|
|
273
|
+
affectedRows?: number
|
|
274
|
+
insertId?: unknown
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Declares database feature support.
|
|
279
|
+
*/
|
|
280
|
+
export type DatabaseCapabilities = {
|
|
281
|
+
readonly returning: boolean
|
|
282
|
+
readonly savepoints: boolean
|
|
283
|
+
readonly upsert: boolean
|
|
284
|
+
readonly transactionalDdl: boolean
|
|
285
|
+
readonly migrationLock: boolean
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Low-level contract that connects a `Database` to a database engine.
|
|
290
|
+
*/
|
|
291
|
+
export interface DatabaseDriver<dialect extends string = string> {
|
|
292
|
+
/** Stable identifier for the SQL dialect. */
|
|
293
|
+
readonly dialect: dialect
|
|
294
|
+
/** Immutable feature flags used by shared query and migration behavior. */
|
|
295
|
+
readonly capabilities: DatabaseCapabilities
|
|
296
|
+
/** Executes a data-manipulation request. */
|
|
297
|
+
execute(request: DataManipulationRequest): Promise<DataManipulationResult>
|
|
298
|
+
/** Executes a raw SQL script that may contain multiple statements. */
|
|
299
|
+
executeScript(sql: string, transaction?: TransactionToken): Promise<void>
|
|
300
|
+
/** Starts a new database transaction. */
|
|
301
|
+
beginTransaction(options?: TransactionOptions): Promise<TransactionToken>
|
|
302
|
+
/** Commits an open transaction. */
|
|
303
|
+
commitTransaction(token: TransactionToken): Promise<void>
|
|
304
|
+
/** Rolls back an open transaction. */
|
|
305
|
+
rollbackTransaction(token: TransactionToken): Promise<void>
|
|
306
|
+
/** Checks whether a table exists. */
|
|
307
|
+
hasTable(table: TableRef, transaction?: TransactionToken): Promise<boolean>
|
|
308
|
+
/** Checks whether a column exists on a table. */
|
|
309
|
+
hasColumn(table: TableRef, column: string, transaction?: TransactionToken): Promise<boolean>
|
|
310
|
+
/** Creates a savepoint inside an open transaction. */
|
|
311
|
+
createSavepoint(token: TransactionToken, name: string): Promise<void>
|
|
312
|
+
/** Rolls back to a previously created savepoint. */
|
|
313
|
+
rollbackToSavepoint(token: TransactionToken, name: string): Promise<void>
|
|
314
|
+
/** Releases a previously created savepoint. */
|
|
315
|
+
releaseSavepoint(token: TransactionToken, name: string): Promise<void>
|
|
316
|
+
/** Destructively recreates the configured database. */
|
|
317
|
+
wipe(): Promise<void>
|
|
318
|
+
/** Releases connection handles owned by the driver. Must be safe to call repeatedly. */
|
|
319
|
+
close(): void | Promise<void>
|
|
320
|
+
/**
|
|
321
|
+
* Runs migration work while holding a driver-specific lock.
|
|
322
|
+
*
|
|
323
|
+
* The callback receives a driver bound to the connection that owns the lock. Drivers must
|
|
324
|
+
* release the lock when the callback rejects as well as when it resolves.
|
|
325
|
+
* @param name Logical migration lock name.
|
|
326
|
+
* @param run Migration work to run with the connection-bound driver.
|
|
327
|
+
* @returns The callback result.
|
|
328
|
+
*/
|
|
329
|
+
withMigrationLock?<result>(
|
|
330
|
+
name: string,
|
|
331
|
+
run: (driver: DatabaseDriver<dialect>) => Promise<result>,
|
|
332
|
+
): Promise<result>
|
|
333
|
+
}
|
package/src/lib/errors.ts
CHANGED
|
@@ -77,9 +77,9 @@ export class DataTableQueryError extends DataTableError {
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
/**
|
|
80
|
-
* Thrown when
|
|
80
|
+
* Thrown when database execution fails.
|
|
81
81
|
*/
|
|
82
|
-
export class
|
|
82
|
+
export class DataTableDatabaseError extends DataTableError {
|
|
83
83
|
constructor(
|
|
84
84
|
message: string,
|
|
85
85
|
options?: {
|
|
@@ -88,12 +88,12 @@ export class DataTableAdapterError extends DataTableError {
|
|
|
88
88
|
},
|
|
89
89
|
) {
|
|
90
90
|
super(message, {
|
|
91
|
-
code: '
|
|
91
|
+
code: 'DATA_TABLE_DATABASE_ERROR',
|
|
92
92
|
cause: options?.cause,
|
|
93
93
|
metadata: options?.metadata,
|
|
94
94
|
})
|
|
95
95
|
|
|
96
|
-
this.name = '
|
|
96
|
+
this.name = 'DataTableDatabaseError'
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
99
|
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { MigrationTransactionMode } from '../migrations.ts'
|
|
2
|
+
|
|
3
|
+
const directivePattern = /^\s*--\s*data-table\/transaction\s*:\s*(auto|required|none)\s*$/i
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Parses an optional `-- data-table/transaction: auto|required|none` directive
|
|
7
|
+
* from any single-line SQL comment in the script.
|
|
8
|
+
*
|
|
9
|
+
* Returns `undefined` when no directive is present.
|
|
10
|
+
* @param sql SQL script contents.
|
|
11
|
+
* @returns The declared transaction mode, or `undefined` when not declared.
|
|
12
|
+
* @throws when more than one directive is present or the value is invalid.
|
|
13
|
+
*/
|
|
14
|
+
export function parseTransactionDirective(sql: string): MigrationTransactionMode | undefined {
|
|
15
|
+
let match: MigrationTransactionMode | undefined
|
|
16
|
+
|
|
17
|
+
for (let line of sql.split(/\r?\n/)) {
|
|
18
|
+
let trimmed = line.trim()
|
|
19
|
+
|
|
20
|
+
if (!trimmed.startsWith('--')) {
|
|
21
|
+
continue
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
let result = directivePattern.exec(trimmed)
|
|
25
|
+
|
|
26
|
+
if (!result) {
|
|
27
|
+
continue
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (match !== undefined) {
|
|
31
|
+
throw new Error('Migration script declares more than one transaction directive')
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
match = result[1].toLowerCase() as MigrationTransactionMode
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return match
|
|
38
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const migrationDirectoryPattern = /^(\d{14})_(.+)$/
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Parses a migration directory name into `{ id, name }`.
|
|
5
|
+
*
|
|
6
|
+
* Expected format: `YYYYMMDDHHmmss_name`.
|
|
7
|
+
* @param name Migration directory basename.
|
|
8
|
+
* @returns Parsed migration id and name.
|
|
9
|
+
*/
|
|
10
|
+
export function parseMigrationDirectoryName(name: string): { id: string; name: string } {
|
|
11
|
+
let match = name.match(migrationDirectoryPattern)
|
|
12
|
+
|
|
13
|
+
if (!match) {
|
|
14
|
+
throw new Error(
|
|
15
|
+
'Invalid migration directory name "' + name + '". Expected format YYYYMMDDHHmmss_name',
|
|
16
|
+
)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
id: match[1],
|
|
21
|
+
name: match[2],
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -1,41 +1,45 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { DatabaseDriver, TransactionToken } from '../driver.ts'
|
|
2
2
|
import { rawSql } from '../sql.ts'
|
|
3
3
|
import type { MigrationDescriptor, MigrationJournalRow } from '../migrations.ts'
|
|
4
4
|
|
|
5
|
-
export function
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
export async function computeChecksum(migration: MigrationDescriptor): Promise<string> {
|
|
6
|
+
let digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(migration.up))
|
|
7
|
+
return bytesToHex(new Uint8Array(digest))
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function bytesToHex(bytes: Uint8Array): string {
|
|
11
|
+
let hex = ''
|
|
12
|
+
|
|
13
|
+
for (let byte of bytes) {
|
|
14
|
+
hex += byte.toString(16).padStart(2, '0')
|
|
8
15
|
}
|
|
9
16
|
|
|
10
|
-
return
|
|
17
|
+
return hex
|
|
11
18
|
}
|
|
12
19
|
|
|
13
20
|
export async function ensureMigrationJournal(
|
|
14
|
-
|
|
21
|
+
driver: DatabaseDriver,
|
|
15
22
|
tableName: string,
|
|
16
23
|
): Promise<void> {
|
|
17
|
-
await
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
},
|
|
29
|
-
},
|
|
30
|
-
})
|
|
24
|
+
await driver.executeScript(
|
|
25
|
+
'create table if not exists ' +
|
|
26
|
+
tableName +
|
|
27
|
+
' (' +
|
|
28
|
+
'id varchar(64) not null primary key, ' +
|
|
29
|
+
'name varchar(255) not null, ' +
|
|
30
|
+
'checksum varchar(128) not null, ' +
|
|
31
|
+
'batch integer not null, ' +
|
|
32
|
+
'applied_at timestamp not null default current_timestamp' +
|
|
33
|
+
')',
|
|
34
|
+
)
|
|
31
35
|
}
|
|
32
36
|
|
|
33
37
|
export async function hasMigrationJournal(
|
|
34
|
-
|
|
38
|
+
driver: DatabaseDriver,
|
|
35
39
|
tableName: string,
|
|
36
40
|
): Promise<boolean> {
|
|
37
41
|
try {
|
|
38
|
-
await
|
|
42
|
+
await driver.execute({
|
|
39
43
|
operation: {
|
|
40
44
|
kind: 'raw',
|
|
41
45
|
sql: rawSql('select 1 from ' + tableName + ' limit 1'),
|
|
@@ -44,15 +48,25 @@ export async function hasMigrationJournal(
|
|
|
44
48
|
|
|
45
49
|
return true
|
|
46
50
|
} catch {
|
|
51
|
+
// The probe fails both when the journal table is missing and when the
|
|
52
|
+
// database itself is unreachable. Only the former means "no journal yet";
|
|
53
|
+
// rethrow connection/auth failures via a table-independent query.
|
|
54
|
+
await driver.execute({
|
|
55
|
+
operation: {
|
|
56
|
+
kind: 'raw',
|
|
57
|
+
sql: rawSql('select 1'),
|
|
58
|
+
},
|
|
59
|
+
})
|
|
60
|
+
|
|
47
61
|
return false
|
|
48
62
|
}
|
|
49
63
|
}
|
|
50
64
|
|
|
51
65
|
export async function loadJournalRows(
|
|
52
|
-
|
|
66
|
+
driver: DatabaseDriver,
|
|
53
67
|
tableName: string,
|
|
54
68
|
): Promise<MigrationJournalRow[]> {
|
|
55
|
-
let result = await
|
|
69
|
+
let result = await driver.execute({
|
|
56
70
|
operation: {
|
|
57
71
|
kind: 'raw',
|
|
58
72
|
sql: rawSql(
|
|
@@ -73,7 +87,7 @@ export async function loadJournalRows(
|
|
|
73
87
|
}
|
|
74
88
|
|
|
75
89
|
export async function insertJournalRow(
|
|
76
|
-
|
|
90
|
+
driver: DatabaseDriver,
|
|
77
91
|
tableName: string,
|
|
78
92
|
row: {
|
|
79
93
|
id: string
|
|
@@ -83,7 +97,7 @@ export async function insertJournalRow(
|
|
|
83
97
|
},
|
|
84
98
|
transaction?: TransactionToken,
|
|
85
99
|
): Promise<void> {
|
|
86
|
-
await
|
|
100
|
+
await driver.execute({
|
|
87
101
|
operation: {
|
|
88
102
|
kind: 'raw',
|
|
89
103
|
sql: rawSql('insert into ' + tableName + ' (id, name, checksum, batch) values (?, ?, ?, ?)', [
|
|
@@ -98,12 +112,12 @@ export async function insertJournalRow(
|
|
|
98
112
|
}
|
|
99
113
|
|
|
100
114
|
export async function deleteJournalRow(
|
|
101
|
-
|
|
115
|
+
driver: DatabaseDriver,
|
|
102
116
|
tableName: string,
|
|
103
117
|
id: string,
|
|
104
118
|
transaction?: TransactionToken,
|
|
105
119
|
): Promise<void> {
|
|
106
|
-
await
|
|
120
|
+
await driver.execute({
|
|
107
121
|
operation: {
|
|
108
122
|
kind: 'raw',
|
|
109
123
|
sql: rawSql('delete from ' + tableName + ' where id = ?', [id]),
|
|
@@ -33,7 +33,7 @@ export function resolveMigrations(
|
|
|
33
33
|
* import { createMigrationRegistry } from 'remix/data-table/migrations'
|
|
34
34
|
*
|
|
35
35
|
* let registry = createMigrationRegistry()
|
|
36
|
-
* registry.register({ id, name,
|
|
36
|
+
* registry.register({ id, name, up, down })
|
|
37
37
|
* ```
|
|
38
38
|
*/
|
|
39
39
|
export function createMigrationRegistry(initial: MigrationDescriptor[] = []): MigrationRegistry {
|