@remix-run/data-table 0.2.1 → 0.3.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 +76 -74
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/lib/adapter.d.ts +10 -271
- package/dist/lib/adapter.d.ts.map +1 -1
- package/dist/lib/column.d.ts.map +1 -1
- package/dist/lib/column.js +10 -1
- 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 +1 -1
- package/dist/lib/migrations/journal-store.d.ts.map +1 -1
- package/dist/lib/migrations/journal-store.js +18 -18
- package/dist/lib/migrations/registry.d.ts +1 -1
- package/dist/lib/migrations/registry.js +1 -1
- package/dist/lib/migrations/runner.d.ts +2 -2
- package/dist/lib/migrations/runner.d.ts.map +1 -1
- package/dist/lib/migrations/runner.js +44 -71
- package/dist/lib/migrations-node.d.ts +7 -4
- package/dist/lib/migrations-node.d.ts.map +1 -1
- package/dist/lib/migrations-node.js +52 -41
- package/dist/lib/migrations.d.ts +19 -200
- package/dist/lib/migrations.d.ts.map +1 -1
- package/dist/lib/migrations.js +1 -38
- package/dist/lib/query.d.ts +33 -0
- package/dist/lib/query.d.ts.map +1 -1
- package/dist/lib/query.js +28 -0
- 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/migrations.d.ts +2 -5
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +1 -3
- 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 +2 -2
- package/src/index.ts +1 -34
- package/src/lib/adapter.ts +10 -330
- package/src/lib/column.ts +14 -2
- package/src/lib/migrations/directive.ts +38 -0
- package/src/lib/migrations/directory-name.ts +23 -0
- package/src/lib/migrations/journal-store.ts +22 -18
- package/src/lib/migrations/registry.ts +1 -1
- package/src/lib/migrations/runner.ts +51 -85
- package/src/lib/migrations-node.ts +58 -38
- package/src/lib/migrations.ts +19 -224
- package/src/lib/query.ts +33 -0
- package/src/lib/sql-helpers.ts +1 -22
- package/src/migrations.ts +3 -13
- package/src/sql-helpers.ts +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/migrations/filename.ts +0 -25
- package/src/lib/migrations/helpers.ts +0 -108
- package/src/lib/migrations/schema-api.ts +0 -417
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const directivePattern = /^\s*--\s*data-table\/transaction\s*:\s*(auto|required|none)\s*$/i;
|
|
2
|
+
/**
|
|
3
|
+
* Parses an optional `-- data-table/transaction: auto|required|none` directive
|
|
4
|
+
* from any single-line SQL comment in the script.
|
|
5
|
+
*
|
|
6
|
+
* Returns `undefined` when no directive is present.
|
|
7
|
+
* @param sql SQL script contents.
|
|
8
|
+
* @returns The declared transaction mode, or `undefined` when not declared.
|
|
9
|
+
* @throws when more than one directive is present or the value is invalid.
|
|
10
|
+
*/
|
|
11
|
+
export function parseTransactionDirective(sql) {
|
|
12
|
+
let match;
|
|
13
|
+
for (let line of sql.split(/\r?\n/)) {
|
|
14
|
+
let trimmed = line.trim();
|
|
15
|
+
if (!trimmed.startsWith('--')) {
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
let result = directivePattern.exec(trimmed);
|
|
19
|
+
if (!result) {
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
if (match !== undefined) {
|
|
23
|
+
throw new Error('Migration script declares more than one transaction directive');
|
|
24
|
+
}
|
|
25
|
+
match = result[1].toLowerCase();
|
|
26
|
+
}
|
|
27
|
+
return match;
|
|
28
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parses a migration directory name into `{ id, name }`.
|
|
3
|
+
*
|
|
4
|
+
* Expected format: `YYYYMMDDHHmmss_name`.
|
|
5
|
+
* @param name Migration directory basename.
|
|
6
|
+
* @returns Parsed migration id and name.
|
|
7
|
+
*/
|
|
8
|
+
export declare function parseMigrationDirectoryName(name: string): {
|
|
9
|
+
id: string;
|
|
10
|
+
name: string;
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=directory-name.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"directory-name.d.ts","sourceRoot":"","sources":["../../../src/lib/migrations/directory-name.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAatF"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const migrationDirectoryPattern = /^(\d{14})_(.+)$/;
|
|
2
|
+
/**
|
|
3
|
+
* Parses a migration directory name into `{ id, name }`.
|
|
4
|
+
*
|
|
5
|
+
* Expected format: `YYYYMMDDHHmmss_name`.
|
|
6
|
+
* @param name Migration directory basename.
|
|
7
|
+
* @returns Parsed migration id and name.
|
|
8
|
+
*/
|
|
9
|
+
export function parseMigrationDirectoryName(name) {
|
|
10
|
+
let match = name.match(migrationDirectoryPattern);
|
|
11
|
+
if (!match) {
|
|
12
|
+
throw new Error('Invalid migration directory name "' + name + '". Expected format YYYYMMDDHHmmss_name');
|
|
13
|
+
}
|
|
14
|
+
return {
|
|
15
|
+
id: match[1],
|
|
16
|
+
name: match[2],
|
|
17
|
+
};
|
|
18
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { DatabaseAdapter, TransactionToken } from '../adapter.ts';
|
|
2
2
|
import type { MigrationDescriptor, MigrationJournalRow } from '../migrations.ts';
|
|
3
|
-
export declare function
|
|
3
|
+
export declare function computeChecksum(migration: MigrationDescriptor): Promise<string>;
|
|
4
4
|
export declare function ensureMigrationJournal(adapter: DatabaseAdapter, tableName: string): Promise<void>;
|
|
5
5
|
export declare function hasMigrationJournal(adapter: DatabaseAdapter, tableName: string): Promise<boolean>;
|
|
6
6
|
export declare function loadJournalRows(adapter: DatabaseAdapter, tableName: string): Promise<MigrationJournalRow[]>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"journal-store.d.ts","sourceRoot":"","sources":["../../../src/lib/migrations/journal-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AAEtE,OAAO,KAAK,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AAEhF,
|
|
1
|
+
{"version":3,"file":"journal-store.d.ts","sourceRoot":"","sources":["../../../src/lib/migrations/journal-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AAEtE,OAAO,KAAK,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AAEhF,wBAAsB,eAAe,CAAC,SAAS,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAGrF;AAYD,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,eAAe,EACxB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAYf;AAED,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,eAAe,EACxB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,OAAO,CAAC,CAalB;AAED,wBAAsB,eAAe,CACnC,OAAO,EAAE,eAAe,EACxB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAmBhC;AAED,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,eAAe,EACxB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE;IACH,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;CACd,EACD,WAAW,CAAC,EAAE,gBAAgB,GAC7B,OAAO,CAAC,IAAI,CAAC,CAaf;AAED,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,eAAe,EACxB,SAAS,EAAE,MAAM,EACjB,EAAE,EAAE,MAAM,EACV,WAAW,CAAC,EAAE,gBAAgB,GAC7B,OAAO,CAAC,IAAI,CAAC,CAQf;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,mBAAmB,EAAE,GAAG,MAAM,CAO5D"}
|
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
import { rawSql } from "../sql.js";
|
|
2
|
-
export function
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
export async function computeChecksum(migration) {
|
|
3
|
+
let digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(migration.up));
|
|
4
|
+
return bytesToHex(new Uint8Array(digest));
|
|
5
|
+
}
|
|
6
|
+
function bytesToHex(bytes) {
|
|
7
|
+
let hex = '';
|
|
8
|
+
for (let byte of bytes) {
|
|
9
|
+
hex += byte.toString(16).padStart(2, '0');
|
|
5
10
|
}
|
|
6
|
-
return
|
|
11
|
+
return hex;
|
|
7
12
|
}
|
|
8
13
|
export async function ensureMigrationJournal(adapter, tableName) {
|
|
9
|
-
await adapter.
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
batch: { type: 'integer', nullable: false },
|
|
19
|
-
applied_at: { type: 'timestamp', nullable: false, default: { kind: 'now' } },
|
|
20
|
-
},
|
|
21
|
-
},
|
|
22
|
-
});
|
|
14
|
+
await adapter.executeScript('create table if not exists ' +
|
|
15
|
+
tableName +
|
|
16
|
+
' (' +
|
|
17
|
+
'id varchar(64) not null primary key, ' +
|
|
18
|
+
'name varchar(255) not null, ' +
|
|
19
|
+
'checksum varchar(128) not null, ' +
|
|
20
|
+
'batch integer not null, ' +
|
|
21
|
+
'applied_at timestamp not null default current_timestamp' +
|
|
22
|
+
')');
|
|
23
23
|
}
|
|
24
24
|
export async function hasMigrationJournal(adapter, tableName) {
|
|
25
25
|
try {
|
|
@@ -20,7 +20,7 @@ export declare function resolveMigrations(input: MigrationDescriptor[] | Migrati
|
|
|
20
20
|
* import { createMigrationRegistry } from 'remix/data-table/migrations'
|
|
21
21
|
*
|
|
22
22
|
* let registry = createMigrationRegistry()
|
|
23
|
-
* registry.register({ id, name,
|
|
23
|
+
* registry.register({ id, name, up, down })
|
|
24
24
|
* ```
|
|
25
25
|
*/
|
|
26
26
|
export declare function createMigrationRegistry(initial?: MigrationDescriptor[]): MigrationRegistry;
|
|
@@ -26,7 +26,7 @@ export function resolveMigrations(input) {
|
|
|
26
26
|
* import { createMigrationRegistry } from 'remix/data-table/migrations'
|
|
27
27
|
*
|
|
28
28
|
* let registry = createMigrationRegistry()
|
|
29
|
-
* registry.register({ id, name,
|
|
29
|
+
* registry.register({ id, name, up, down })
|
|
30
30
|
* ```
|
|
31
31
|
*/
|
|
32
32
|
export function createMigrationRegistry(initial = []) {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { DatabaseAdapter } from '../adapter.ts';
|
|
2
2
|
import type { MigrationDescriptor, MigrationRegistry, MigrationRunner, MigrationRunnerOptions } from '../migrations.ts';
|
|
3
3
|
/**
|
|
4
|
-
* Creates a migration runner for applying/reverting migrations against an adapter.
|
|
5
|
-
* @param adapter Database adapter used to
|
|
4
|
+
* Creates a migration runner for applying/reverting SQL migrations against an adapter.
|
|
5
|
+
* @param adapter Database adapter used to execute migration scripts.
|
|
6
6
|
* @param migrations Migration descriptors or registry.
|
|
7
7
|
* @param options Optional runner configuration.
|
|
8
8
|
* @returns A migration runner instance.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../../src/lib/migrations/runner.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../../src/lib/migrations/runner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAoB,MAAM,eAAe,CAAA;AACtE,OAAO,KAAK,EAGV,mBAAmB,EAGnB,iBAAiB,EACjB,eAAe,EACf,sBAAsB,EAIvB,MAAM,kBAAkB,CAAA;AAqPzB;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,eAAe,EACxB,UAAU,EAAE,mBAAmB,EAAE,GAAG,iBAAiB,EACrD,OAAO,GAAE,sBAA2B,GACnC,eAAe,CA6DjB"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { deleteJournalRow, ensureMigrationJournal, getBatch, hasMigrationJournal, insertJournalRow, loadJournalRows,
|
|
1
|
+
import { parseTransactionDirective } from "./directive.js";
|
|
2
|
+
import { deleteJournalRow, ensureMigrationJournal, getBatch, hasMigrationJournal, insertJournalRow, loadJournalRows, computeChecksum, } from "./journal-store.js";
|
|
3
3
|
import { resolveMigrations } from "./registry.js";
|
|
4
|
-
import { createMigrationSchema } from "./schema-api.js";
|
|
5
4
|
function assertStepOption(step) {
|
|
6
5
|
if (step === undefined) {
|
|
7
6
|
return;
|
|
@@ -24,14 +23,14 @@ function assertTargetOption(migrations, to) {
|
|
|
24
23
|
throw new Error('Unknown migration target: ' + to);
|
|
25
24
|
}
|
|
26
25
|
}
|
|
27
|
-
function assertNoMigrationDrift(migrations, journal) {
|
|
26
|
+
async function assertNoMigrationDrift(migrations, journal) {
|
|
28
27
|
let migrationMap = new Map(migrations.map((migration) => [migration.id, migration]));
|
|
29
28
|
for (let row of journal) {
|
|
30
29
|
let migration = migrationMap.get(row.id);
|
|
31
30
|
if (!migration) {
|
|
32
31
|
continue;
|
|
33
32
|
}
|
|
34
|
-
let expected =
|
|
33
|
+
let expected = await computeChecksum(migration);
|
|
35
34
|
if (expected !== row.checksum) {
|
|
36
35
|
throw new Error('Migration checksum drift detected for "' +
|
|
37
36
|
row.id +
|
|
@@ -43,33 +42,15 @@ function assertNoMigrationDrift(migrations, journal) {
|
|
|
43
42
|
}
|
|
44
43
|
}
|
|
45
44
|
}
|
|
46
|
-
function
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
return adapter.compileSql(operation);
|
|
56
|
-
},
|
|
57
|
-
async hasTable(table) {
|
|
58
|
-
return adapter.hasTable(table);
|
|
59
|
-
},
|
|
60
|
-
async hasColumn(table, column) {
|
|
61
|
-
return adapter.hasColumn(table, column);
|
|
62
|
-
},
|
|
63
|
-
execute: throwDryRunError,
|
|
64
|
-
migrate: throwDryRunError,
|
|
65
|
-
beginTransaction: throwDryRunError,
|
|
66
|
-
commitTransaction: throwDryRunError,
|
|
67
|
-
rollbackTransaction: throwDryRunError,
|
|
68
|
-
createSavepoint: throwDryRunError,
|
|
69
|
-
rollbackToSavepoint: throwDryRunError,
|
|
70
|
-
releaseSavepoint: throwDryRunError,
|
|
71
|
-
};
|
|
72
|
-
return createDatabase(dryRunAdapter);
|
|
45
|
+
function resolveTransactionMode(migration) {
|
|
46
|
+
if (migration.transaction) {
|
|
47
|
+
return migration.transaction;
|
|
48
|
+
}
|
|
49
|
+
let directive = parseTransactionDirective(migration.up);
|
|
50
|
+
if (directive) {
|
|
51
|
+
return directive;
|
|
52
|
+
}
|
|
53
|
+
return 'auto';
|
|
73
54
|
}
|
|
74
55
|
async function runMigrations(input) {
|
|
75
56
|
let adapter = input.adapter;
|
|
@@ -96,7 +77,7 @@ async function runMigrations(input) {
|
|
|
96
77
|
journal = await loadJournalRows(adapter, journalTable);
|
|
97
78
|
}
|
|
98
79
|
let appliedMap = new Map(journal.map((row) => [row.id, row]));
|
|
99
|
-
assertNoMigrationDrift(migrations, journal);
|
|
80
|
+
await assertNoMigrationDrift(migrations, journal);
|
|
100
81
|
let toRun = [];
|
|
101
82
|
if (input.direction === 'up') {
|
|
102
83
|
for (let migration of migrations) {
|
|
@@ -112,58 +93,48 @@ async function runMigrations(input) {
|
|
|
112
93
|
}
|
|
113
94
|
}
|
|
114
95
|
else {
|
|
115
|
-
|
|
116
|
-
.filter((migration) => appliedMap.has(migration.id))
|
|
117
|
-
.reverse();
|
|
96
|
+
toRun = migrations.filter((migration) => appliedMap.has(migration.id)).reverse();
|
|
118
97
|
if (target) {
|
|
119
|
-
|
|
98
|
+
toRun = toRun.filter((migration) => migration.id >= target);
|
|
120
99
|
}
|
|
121
100
|
if (step !== undefined) {
|
|
122
|
-
|
|
101
|
+
toRun = toRun.slice(0, step);
|
|
102
|
+
}
|
|
103
|
+
for (let migration of toRun) {
|
|
104
|
+
if (migration.down === undefined) {
|
|
105
|
+
throw new Error('Migration "' + migration.id + '" has no down script');
|
|
106
|
+
}
|
|
123
107
|
}
|
|
124
|
-
toRun = appliedMigrations;
|
|
125
108
|
}
|
|
126
109
|
let applied = [];
|
|
127
110
|
let reverted = [];
|
|
128
111
|
let batch = getBatch(journal);
|
|
129
112
|
for (let migration of toRun) {
|
|
130
|
-
|
|
131
|
-
|
|
113
|
+
let script = (input.direction === 'up' ? migration.up : migration.down);
|
|
114
|
+
let mode = resolveTransactionMode(migration);
|
|
115
|
+
if (mode === 'required' && !adapter.capabilities.transactionalDdl) {
|
|
132
116
|
throw new Error('Migration "' +
|
|
133
117
|
migration.id +
|
|
134
118
|
'" requires transactional DDL, but adapter does not support it');
|
|
135
119
|
}
|
|
136
|
-
let shouldUseTransaction = !dryRun &&
|
|
137
|
-
migration.migration.transaction !== 'none' &&
|
|
138
|
-
adapter.capabilities.transactionalDdl;
|
|
120
|
+
let shouldUseTransaction = !dryRun && mode !== 'none' && adapter.capabilities.transactionalDdl;
|
|
139
121
|
let token;
|
|
140
122
|
if (shouldUseTransaction) {
|
|
141
123
|
token = await adapter.beginTransaction();
|
|
142
124
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
: token
|
|
146
|
-
? createDatabaseWithTransaction(adapter, token)
|
|
147
|
-
: createDatabase(adapter);
|
|
148
|
-
let schema = createMigrationSchema(db, async (operation) => {
|
|
149
|
-
let compiled = adapter.compileSql(operation);
|
|
150
|
-
sql.push(...compiled);
|
|
125
|
+
sql.push(script);
|
|
126
|
+
try {
|
|
151
127
|
if (!dryRun) {
|
|
152
|
-
|
|
128
|
+
if (script.trim().length > 0) {
|
|
129
|
+
await adapter.executeScript(script, token);
|
|
130
|
+
}
|
|
153
131
|
}
|
|
154
|
-
}, { transaction: token });
|
|
155
|
-
let context = {
|
|
156
|
-
db,
|
|
157
|
-
schema,
|
|
158
|
-
};
|
|
159
|
-
try {
|
|
160
132
|
if (input.direction === 'up') {
|
|
161
|
-
await migration.migration.up(context);
|
|
162
133
|
if (!dryRun) {
|
|
163
134
|
await insertJournalRow(adapter, journalTable, {
|
|
164
135
|
id: migration.id,
|
|
165
136
|
name: migration.name,
|
|
166
|
-
checksum:
|
|
137
|
+
checksum: await computeChecksum(migration),
|
|
167
138
|
batch,
|
|
168
139
|
}, token);
|
|
169
140
|
}
|
|
@@ -174,7 +145,6 @@ async function runMigrations(input) {
|
|
|
174
145
|
});
|
|
175
146
|
}
|
|
176
147
|
else {
|
|
177
|
-
await migration.migration.down(context);
|
|
178
148
|
if (!dryRun) {
|
|
179
149
|
await deleteJournalRow(adapter, journalTable, migration.id, token);
|
|
180
150
|
}
|
|
@@ -206,8 +176,8 @@ async function runMigrations(input) {
|
|
|
206
176
|
}
|
|
207
177
|
}
|
|
208
178
|
/**
|
|
209
|
-
* Creates a migration runner for applying/reverting migrations against an adapter.
|
|
210
|
-
* @param adapter Database adapter used to
|
|
179
|
+
* Creates a migration runner for applying/reverting SQL migrations against an adapter.
|
|
180
|
+
* @param adapter Database adapter used to execute migration scripts.
|
|
211
181
|
* @param migrations Migration descriptors or registry.
|
|
212
182
|
* @param options Optional runner configuration.
|
|
213
183
|
* @returns A migration runner instance.
|
|
@@ -247,17 +217,19 @@ export function createMigrationRunner(adapter, migrations, options = {}) {
|
|
|
247
217
|
let journal = await loadJournalRows(adapter, journalTable);
|
|
248
218
|
let journalMap = new Map(journal.map((row) => [row.id, row]));
|
|
249
219
|
let sortedMigrations = resolveMigrations(migrations);
|
|
250
|
-
|
|
220
|
+
let statuses = [];
|
|
221
|
+
for (let migration of sortedMigrations) {
|
|
251
222
|
let journalRow = journalMap.get(migration.id);
|
|
252
223
|
if (!journalRow) {
|
|
253
|
-
|
|
224
|
+
statuses.push({
|
|
254
225
|
id: migration.id,
|
|
255
226
|
name: migration.name,
|
|
256
227
|
status: 'pending',
|
|
257
|
-
};
|
|
228
|
+
});
|
|
229
|
+
continue;
|
|
258
230
|
}
|
|
259
|
-
let checksum =
|
|
260
|
-
|
|
231
|
+
let checksum = await computeChecksum(migration);
|
|
232
|
+
statuses.push({
|
|
261
233
|
id: migration.id,
|
|
262
234
|
name: migration.name,
|
|
263
235
|
status: checksum === journalRow.checksum
|
|
@@ -266,8 +238,9 @@ export function createMigrationRunner(adapter, migrations, options = {}) {
|
|
|
266
238
|
appliedAt: journalRow.appliedAt,
|
|
267
239
|
batch: journalRow.batch,
|
|
268
240
|
checksum: journalRow.checksum,
|
|
269
|
-
};
|
|
270
|
-
}
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
return statuses;
|
|
271
244
|
},
|
|
272
245
|
};
|
|
273
246
|
}
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import type { MigrationDescriptor } from './migrations.ts';
|
|
2
2
|
/**
|
|
3
|
-
* Loads
|
|
3
|
+
* Loads SQL-file migrations from a directory on Node.js.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* Each migration is a directory named `YYYYMMDDHHmmss_<slug>` containing:
|
|
6
|
+
* - `up.sql` (required)
|
|
7
|
+
* - `down.sql` (optional; omit for irreversible migrations)
|
|
8
|
+
*
|
|
9
|
+
* `id` and `name` are inferred from the directory name.
|
|
10
|
+
* @param directory Absolute or relative directory containing migration directories.
|
|
8
11
|
* @returns A sorted list of loaded migration descriptors.
|
|
9
12
|
* @example
|
|
10
13
|
* ```ts
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrations-node.d.ts","sourceRoot":"","sources":["../../src/lib/migrations-node.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"migrations-node.d.ts","sourceRoot":"","sources":["../../src/lib/migrations-node.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AAG1D;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,EAAE,CAAC,CA0DtF"}
|
|
@@ -1,22 +1,15 @@
|
|
|
1
|
-
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
2
|
-
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
3
|
-
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
4
|
-
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
5
|
-
});
|
|
6
|
-
}
|
|
7
|
-
return path;
|
|
8
|
-
};
|
|
9
|
-
import { createHash } from 'node:crypto';
|
|
10
1
|
import { promises as fs } from 'node:fs';
|
|
11
2
|
import path from 'node:path';
|
|
12
|
-
import {
|
|
13
|
-
import { parseMigrationFilename } from "./migrations/filename.js";
|
|
3
|
+
import { parseMigrationDirectoryName } from "./migrations/directory-name.js";
|
|
14
4
|
/**
|
|
15
|
-
* Loads
|
|
5
|
+
* Loads SQL-file migrations from a directory on Node.js.
|
|
6
|
+
*
|
|
7
|
+
* Each migration is a directory named `YYYYMMDDHHmmss_<slug>` containing:
|
|
8
|
+
* - `up.sql` (required)
|
|
9
|
+
* - `down.sql` (optional; omit for irreversible migrations)
|
|
16
10
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* @param directory Absolute or relative directory containing migration files.
|
|
11
|
+
* `id` and `name` are inferred from the directory name.
|
|
12
|
+
* @param directory Absolute or relative directory containing migration directories.
|
|
20
13
|
* @returns A sorted list of loaded migration descriptors.
|
|
21
14
|
* @example
|
|
22
15
|
* ```ts
|
|
@@ -26,40 +19,58 @@ import { parseMigrationFilename } from "./migrations/filename.js";
|
|
|
26
19
|
* ```
|
|
27
20
|
*/
|
|
28
21
|
export async function loadMigrations(directory) {
|
|
29
|
-
let
|
|
30
|
-
|
|
22
|
+
let entries = await fs.readdir(directory, { withFileTypes: true });
|
|
23
|
+
let directories = entries
|
|
24
|
+
.filter((entry) => entry.isDirectory())
|
|
31
25
|
.map((entry) => entry.name)
|
|
32
26
|
.sort((left, right) => left.localeCompare(right));
|
|
33
|
-
let files = [];
|
|
34
|
-
for (let file of allFiles) {
|
|
35
|
-
if (!/\.(?:m?ts|m?js|cts|cjs)$/.test(file)) {
|
|
36
|
-
continue;
|
|
37
|
-
}
|
|
38
|
-
let parsed = parseMigrationFilename(file);
|
|
39
|
-
files.push({ file, id: parsed.id, name: parsed.name });
|
|
40
|
-
}
|
|
41
27
|
let migrations = [];
|
|
42
28
|
let seenIds = new Set();
|
|
43
|
-
for (let
|
|
44
|
-
|
|
45
|
-
|
|
29
|
+
for (let directoryName of directories) {
|
|
30
|
+
let parsed = parseMigrationDirectoryName(directoryName);
|
|
31
|
+
if (seenIds.has(parsed.id)) {
|
|
32
|
+
throw new Error('Duplicate migration id "' +
|
|
33
|
+
parsed.id +
|
|
34
|
+
'" inferred from directory "' +
|
|
35
|
+
directoryName +
|
|
36
|
+
'"');
|
|
46
37
|
}
|
|
47
|
-
seenIds.add(
|
|
48
|
-
let
|
|
49
|
-
let
|
|
50
|
-
let
|
|
51
|
-
let
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
38
|
+
seenIds.add(parsed.id);
|
|
39
|
+
let directoryPath = path.join(directory, directoryName);
|
|
40
|
+
let upPath = path.join(directoryPath, 'up.sql');
|
|
41
|
+
let downPath = path.join(directoryPath, 'down.sql');
|
|
42
|
+
let up;
|
|
43
|
+
try {
|
|
44
|
+
up = await fs.readFile(upPath, 'utf8');
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
if (isNodeFileNotFoundError(error)) {
|
|
48
|
+
throw new Error('Migration directory "' + directoryName + '" is missing up.sql');
|
|
49
|
+
}
|
|
50
|
+
throw error;
|
|
51
|
+
}
|
|
52
|
+
let down;
|
|
53
|
+
try {
|
|
54
|
+
down = await fs.readFile(downPath, 'utf8');
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
if (!isNodeFileNotFoundError(error)) {
|
|
58
|
+
throw error;
|
|
59
|
+
}
|
|
55
60
|
}
|
|
56
61
|
migrations.push({
|
|
57
|
-
id:
|
|
58
|
-
name:
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
+
id: parsed.id,
|
|
63
|
+
name: parsed.name,
|
|
64
|
+
up,
|
|
65
|
+
down,
|
|
66
|
+
path: directoryPath,
|
|
62
67
|
});
|
|
63
68
|
}
|
|
64
69
|
return migrations;
|
|
65
70
|
}
|
|
71
|
+
function isNodeFileNotFoundError(error) {
|
|
72
|
+
return (typeof error === 'object' &&
|
|
73
|
+
error !== null &&
|
|
74
|
+
'code' in error &&
|
|
75
|
+
error.code === 'ENOENT');
|
|
76
|
+
}
|