@zintrust/d1-migrator 1.7.1 → 1.7.2
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
CHANGED
|
@@ -470,14 +470,17 @@ The interactive mode will:
|
|
|
470
470
|
|
|
471
471
|
The migrator automatically converts data types for D1 compatibility:
|
|
472
472
|
|
|
473
|
-
| Source Type | SQLite Type
|
|
474
|
-
| ------------------- |
|
|
475
|
-
|
|
|
476
|
-
|
|
|
477
|
-
|
|
|
478
|
-
|
|
|
479
|
-
|
|
|
480
|
-
|
|
|
473
|
+
| Source Type | SQLite Type | Notes |
|
|
474
|
+
| ------------------- | --------------------------------- | ------------------------------------------- |
|
|
475
|
+
| AUTO_INCREMENT PK | INTEGER PRIMARY KEY AUTOINCREMENT | Preserves SQLite rowid-backed id allocation |
|
|
476
|
+
| DATETIME, TIMESTAMP | TEXT (ISO 8601) | Converted to ISO 8601 strings |
|
|
477
|
+
| BIGINT | TEXT | Large integers stored as strings |
|
|
478
|
+
| DECIMAL, NUMERIC | TEXT | Precision preserved as strings |
|
|
479
|
+
| JSON | TEXT | JSON objects stored as strings |
|
|
480
|
+
| BLOB | BLOB | Binary data preserved |
|
|
481
|
+
| NULL | NULL | Null values preserved |
|
|
482
|
+
|
|
483
|
+
When the source schema marks a single-column primary key as auto-increment, the migrator preserves that contract on D1 by emitting `INTEGER PRIMARY KEY AUTOINCREMENT`. That keeps explicit imported ids valid during data copy and still allows later inserts that omit the id column to receive a database-generated numeric identifier.
|
|
481
484
|
|
|
482
485
|
### Manual Value Transformation
|
|
483
486
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DataMigrator.d.ts","sourceRoot":"","sources":["../../src/cli/DataMigrator.ts"],"names":[],"mappings":"AACA;;;GAGG;AAWH,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAEnE;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,eAAe,CAAC,cAAc,CAAC,CAAC;IACxC,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,eAAe,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,IAAI,GAAG,WAAW,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,eAAe,CAAC;CAC3B;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,KAAK,kBAAkB,GAAG;IACxB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,KAAK,eAAe,GAAG;IACrB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACzB,UAAU,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;CACxE,CAAC;AAEF,KAAK,0BAA0B,GAAG;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAsEF;;;GAGG;AACH,eAAO,MAAM,YAAY;IACvB;;OAEG;wBACuB,eAAe,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAmFtE;;OAEG;4BAC2B,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAoEzE;;OAEG;4BAC2B,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAyCzE;;OAEG;0CAEiB,gBAAgB,oBAChB,gBAAgB,UAC1B,eAAe,GACtB,OAAO,CAAC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"DataMigrator.d.ts","sourceRoot":"","sources":["../../src/cli/DataMigrator.ts"],"names":[],"mappings":"AACA;;;GAGG;AAWH,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAEnE;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,eAAe,CAAC,cAAc,CAAC,CAAC;IACxC,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,eAAe,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,IAAI,GAAG,WAAW,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,eAAe,CAAC;CAC3B;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,KAAK,kBAAkB,GAAG;IACxB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,KAAK,eAAe,GAAG;IACrB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACzB,UAAU,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;CACxE,CAAC;AAEF,KAAK,0BAA0B,GAAG;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAsEF;;;GAGG;AACH,eAAO,MAAM,YAAY;IACvB;;OAEG;wBACuB,eAAe,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAmFtE;;OAEG;4BAC2B,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAoEzE;;OAEG;4BAC2B,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAyCzE;;OAEG;0CAEiB,gBAAgB,oBAChB,gBAAgB,UAC1B,eAAe,GACtB,OAAO,CAAC,IAAI,CAAC;IAqChB;;OAEG;+BAC8B,gBAAgB,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,SAAS,EAAE,CAAA;KAAE,CAAC;IAiBpF;;OAEG;wBAEM,SAAS,oBACE,gBAAgB,oBAChB,gBAAgB,UAC1B,eAAe,GACtB,OAAO,CAAC;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IA4EtD;;OAEG;oCAEiB,gBAAgB,aACvB,MAAM,UACT,MAAM,aACH,MAAM,GAChB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IAkBrC;;OAEG;yBAEM,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,aACrB,MAAM,GAChB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IA4CrC;;OAEG;iCAEiB,gBAAgB,aACvB,MAAM,QACX,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAC9B,OAAO,CAAC,MAAM,CAAC;IAkClB;;OAEG;gCACyB,eAAe,CAAC,cAAc,CAAC,aAAa,MAAM,GAAG,MAAM;IAavF;;OAEG;wCAEM,MAAM,UACL,MAAM,gBACA,MAAM,gBACN,MAAM,GACnB,0BAA0B;IAS7B;;OAEG;gCACyB,MAAM,GAAG,iBAAiB;IAetD;;OAEG;6BAES,iBAAiB,WAClB,OAAO,CAAC,iBAAiB,CAAC,GAClC,iBAAiB;EAGpB,CAAC"}
|
package/dist/cli/DataMigrator.js
CHANGED
|
@@ -229,6 +229,7 @@ export const DataMigrator = Object.freeze({
|
|
|
229
229
|
connectionString: sourceConnection.connectionString,
|
|
230
230
|
});
|
|
231
231
|
const d1Schema = SchemaBuilder.buildD1Schema(sourceSchema.tables, config.sourceDriver);
|
|
232
|
+
SchemaBuilder.assertValidSchema(d1Schema);
|
|
232
233
|
for (const table of d1Schema) {
|
|
233
234
|
const createSQL = SchemaBuilder.generateCreateTableSQL(table).replace(/^CREATE TABLE\s+/i, 'CREATE TABLE IF NOT EXISTS ');
|
|
234
235
|
await targetConnection.adapter.query(createSQL, []);
|
|
@@ -27,7 +27,7 @@ export declare const SchemaBuilder: Readonly<{
|
|
|
27
27
|
/**
|
|
28
28
|
* Generate column definition
|
|
29
29
|
*/
|
|
30
|
-
generateColumnDefinition(column: ColumnSchema): string;
|
|
30
|
+
generateColumnDefinition(column: ColumnSchema, inlinePrimaryKey?: boolean): string;
|
|
31
31
|
/**
|
|
32
32
|
* Format default value for SQL
|
|
33
33
|
*/
|
|
@@ -47,5 +47,6 @@ export declare const SchemaBuilder: Readonly<{
|
|
|
47
47
|
valid: boolean;
|
|
48
48
|
errors: string[];
|
|
49
49
|
};
|
|
50
|
+
assertValidSchema(tables: TableSchema[]): void;
|
|
50
51
|
}>;
|
|
51
52
|
//# sourceMappingURL=SchemaBuilder.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SchemaBuilder.d.ts","sourceRoot":"","sources":["../../src/schema/SchemaBuilder.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"SchemaBuilder.d.ts","sourceRoot":"","sources":["../../src/schema/SchemaBuilder.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AA2B1D;;;GAGG;AACH,eAAO,MAAM,aAAa;IACxB;;OAEG;gCACyB,WAAW,EAAE,gBAAgB,MAAM,GAAG,WAAW,EAAE;IAM/E;;OAEG;8BACuB,WAAW,gBAAgB,MAAM,GAAG,WAAW;IA+BzE;;OAEG;gCACyB,YAAY,gBAAgB,MAAM,GAAG,YAAY;IAoB7E;;OAEG;kCAC2B,WAAW,GAAG,MAAM;IAwBlD;;OAEG;qCAC8B,YAAY,qBAAoB,OAAO,GAAW,MAAM;IAkBzF;;OAEG;8BACuB,OAAO,GAAG,MAAM;IAkB1C;;OAEG;4BACqB,WAAW,GAAG,MAAM,EAAE;IAqB9C;;OAEG;8BACuB,WAAW,EAAE,GAAG,MAAM;IAqBhD;;OAEG;2BACoB,WAAW,EAAE,GAAG;QACrC,KAAK,EAAE,OAAO,CAAC;QACf,MAAM,EAAE,MAAM,EAAE,CAAC;KAClB;8BA+CyB,WAAW,EAAE,GAAG,IAAI;EAU9C,CAAC"}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Schema Builder
|
|
3
3
|
* Builds D1/SQLite compatible schemas from source schemas
|
|
4
4
|
*/
|
|
5
|
-
import { Logger } from '@zintrust/core';
|
|
5
|
+
import { ErrorFactory, Logger } from '@zintrust/core';
|
|
6
6
|
import { DataValidator } from '../utils/DataValidator.js';
|
|
7
7
|
import { TypeConverter } from './TypeConverter.js';
|
|
8
8
|
const normalizeNullLikeDefaultValue = (value) => {
|
|
@@ -10,6 +10,20 @@ const normalizeNullLikeDefaultValue = (value) => {
|
|
|
10
10
|
return value;
|
|
11
11
|
return value.trim().toLowerCase() === 'null' ? null : value;
|
|
12
12
|
};
|
|
13
|
+
const getPrimaryKeyColumns = (table) => {
|
|
14
|
+
if (table.primaryKeys.length > 0) {
|
|
15
|
+
return table.primaryKeys;
|
|
16
|
+
}
|
|
17
|
+
return table.primaryKey ? [table.primaryKey] : [];
|
|
18
|
+
};
|
|
19
|
+
const getAutoIncrementPrimaryKeyColumn = (table) => {
|
|
20
|
+
const primaryKeyColumns = getPrimaryKeyColumns(table);
|
|
21
|
+
if (primaryKeyColumns.length !== 1) {
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
const primaryKeyName = primaryKeyColumns[0];
|
|
25
|
+
return table.columns.find((column) => column.name === primaryKeyName && column.autoIncrement);
|
|
26
|
+
};
|
|
13
27
|
/**
|
|
14
28
|
* SchemaBuilder - Sealed namespace for schema building
|
|
15
29
|
* Provides D1 schema generation from source schemas
|
|
@@ -27,9 +41,22 @@ export const SchemaBuilder = Object.freeze({
|
|
|
27
41
|
*/
|
|
28
42
|
buildD1Table(sourceTable, sourceDriver) {
|
|
29
43
|
const sanitizedTableName = DataValidator.sanitizeTableName(sourceTable.name);
|
|
44
|
+
const autoIncrementPrimaryKeyName = getAutoIncrementPrimaryKeyColumn(sourceTable)?.name;
|
|
30
45
|
const d1Table = {
|
|
31
46
|
name: sanitizedTableName,
|
|
32
|
-
columns: sourceTable.columns.map((column) =>
|
|
47
|
+
columns: sourceTable.columns.map((column) => {
|
|
48
|
+
const d1Column = SchemaBuilder.buildD1Column(column, sourceDriver);
|
|
49
|
+
if (column.name !== autoIncrementPrimaryKeyName) {
|
|
50
|
+
return d1Column;
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
...d1Column,
|
|
54
|
+
type: 'INTEGER',
|
|
55
|
+
nullable: false,
|
|
56
|
+
defaultValue: undefined,
|
|
57
|
+
autoIncrement: true,
|
|
58
|
+
};
|
|
59
|
+
}),
|
|
33
60
|
primaryKey: sourceTable.primaryKeys?.[0] || '',
|
|
34
61
|
indexes: sourceTable.indexes || [],
|
|
35
62
|
primaryKeys: sourceTable.primaryKeys || [],
|
|
@@ -53,6 +80,7 @@ export const SchemaBuilder = Object.freeze({
|
|
|
53
80
|
type: d1Type,
|
|
54
81
|
nullable: sourceColumn.nullable,
|
|
55
82
|
defaultValue: sourceColumn.defaultValue,
|
|
83
|
+
autoIncrement: sourceColumn.autoIncrement,
|
|
56
84
|
};
|
|
57
85
|
return d1Column;
|
|
58
86
|
},
|
|
@@ -61,9 +89,10 @@ export const SchemaBuilder = Object.freeze({
|
|
|
61
89
|
*/
|
|
62
90
|
generateCreateTableSQL(table) {
|
|
63
91
|
let sql = `CREATE TABLE \`${table.name}\` (\n`;
|
|
64
|
-
const
|
|
92
|
+
const autoIncrementPrimaryKeyColumn = getAutoIncrementPrimaryKeyColumn(table);
|
|
93
|
+
const columnDefinitions = table.columns.map((column) => SchemaBuilder.generateColumnDefinition(column, autoIncrementPrimaryKeyColumn?.name === column.name));
|
|
65
94
|
sql += columnDefinitions.join(',\n');
|
|
66
|
-
if (table.primaryKey) {
|
|
95
|
+
if (table.primaryKey && autoIncrementPrimaryKeyColumn === undefined) {
|
|
67
96
|
const keyList = table.primaryKey;
|
|
68
97
|
sql += `,\n PRIMARY KEY (${keyList})`;
|
|
69
98
|
}
|
|
@@ -73,7 +102,10 @@ export const SchemaBuilder = Object.freeze({
|
|
|
73
102
|
/**
|
|
74
103
|
* Generate column definition
|
|
75
104
|
*/
|
|
76
|
-
generateColumnDefinition(column) {
|
|
105
|
+
generateColumnDefinition(column, inlinePrimaryKey = false) {
|
|
106
|
+
if (inlinePrimaryKey) {
|
|
107
|
+
return ` \`${column.name}\` INTEGER PRIMARY KEY AUTOINCREMENT`;
|
|
108
|
+
}
|
|
77
109
|
let definition = ` \`${column.name}\` ${column.type}`;
|
|
78
110
|
if (!column.nullable) {
|
|
79
111
|
definition += ' NOT NULL';
|
|
@@ -162,10 +194,25 @@ export const SchemaBuilder = Object.freeze({
|
|
|
162
194
|
errors.push(`Primary key column '${table.primaryKey}' not found in table: ${table.name}`);
|
|
163
195
|
}
|
|
164
196
|
}
|
|
197
|
+
const autoIncrementPrimaryKeyColumn = getAutoIncrementPrimaryKeyColumn(table);
|
|
198
|
+
if (autoIncrementPrimaryKeyColumn) {
|
|
199
|
+
const createSql = SchemaBuilder.generateCreateTableSQL(table);
|
|
200
|
+
const expectedPrimaryKeyFragment = `\`${autoIncrementPrimaryKeyColumn.name}\` INTEGER PRIMARY KEY AUTOINCREMENT`;
|
|
201
|
+
if (!createSql.includes(expectedPrimaryKeyFragment)) {
|
|
202
|
+
errors.push(`Auto-increment primary key '${table.name}.${autoIncrementPrimaryKeyColumn.name}' must be emitted as INTEGER PRIMARY KEY AUTOINCREMENT for D1`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
165
205
|
});
|
|
166
206
|
return {
|
|
167
207
|
valid: errors.length === 0,
|
|
168
208
|
errors,
|
|
169
209
|
};
|
|
170
210
|
},
|
|
211
|
+
assertValidSchema(tables) {
|
|
212
|
+
const validation = SchemaBuilder.validateSchema(tables);
|
|
213
|
+
if (validation.valid) {
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
throw ErrorFactory.createValidationError(`Generated D1 schema is invalid: ${validation.errors.join('; ')}`);
|
|
217
|
+
},
|
|
171
218
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zintrust/d1-migrator",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.2",
|
|
4
4
|
"description": "Resumable database migration toolkit for moving data to Cloudflare D1 with ZinTrust.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
@@ -40,10 +40,10 @@
|
|
|
40
40
|
"prepublishOnly": "npm run build"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@zintrust/db-mysql": "1.
|
|
44
|
-
"@zintrust/db-postgres": "1.
|
|
45
|
-
"@zintrust/db-sqlite": "1.
|
|
46
|
-
"@zintrust/db-sqlserver": "1.
|
|
47
|
-
"@zintrust/db-d1": "1.
|
|
43
|
+
"@zintrust/db-mysql": "@zintrust/db-mysql^1.7.2",
|
|
44
|
+
"@zintrust/db-postgres": "@zintrust/db-postgres^1.7.2",
|
|
45
|
+
"@zintrust/db-sqlite": "@zintrust/db-sqlite^1.7.2",
|
|
46
|
+
"@zintrust/db-sqlserver": "@zintrust/db-sqlserver^1.7.0",
|
|
47
|
+
"@zintrust/db-d1": "@zintrust/db-d1^1.7.0"
|
|
48
48
|
}
|
|
49
|
-
}
|
|
49
|
+
}
|