@zintrust/d1-migrator 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 (35) hide show
  1. package/README.md +871 -0
  2. package/dist/cli/DataMigrator.d.ts +104 -0
  3. package/dist/cli/DataMigrator.d.ts.map +1 -0
  4. package/dist/cli/DataMigrator.js +431 -0
  5. package/dist/cli/MigrateToD1Command.d.ts +52 -0
  6. package/dist/cli/MigrateToD1Command.d.ts.map +1 -0
  7. package/dist/cli/MigrateToD1Command.js +600 -0
  8. package/dist/cli/ProgressTracker.d.ts +32 -0
  9. package/dist/cli/ProgressTracker.d.ts.map +1 -0
  10. package/dist/cli/ProgressTracker.js +95 -0
  11. package/dist/cli/SchemaAnalyzer.d.ts +130 -0
  12. package/dist/cli/SchemaAnalyzer.d.ts.map +1 -0
  13. package/dist/cli/SchemaAnalyzer.js +660 -0
  14. package/dist/index.d.ts +46 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +32 -0
  17. package/dist/schema/SchemaBuilder.d.ts +51 -0
  18. package/dist/schema/SchemaBuilder.d.ts.map +1 -0
  19. package/dist/schema/SchemaBuilder.js +165 -0
  20. package/dist/schema/TypeConverter.d.ts +35 -0
  21. package/dist/schema/TypeConverter.d.ts.map +1 -0
  22. package/dist/schema/TypeConverter.js +187 -0
  23. package/dist/schema/Validator.d.ts +74 -0
  24. package/dist/schema/Validator.d.ts.map +1 -0
  25. package/dist/schema/Validator.js +225 -0
  26. package/dist/types.d.ts +145 -0
  27. package/dist/types.d.ts.map +1 -0
  28. package/dist/types.js +5 -0
  29. package/dist/utils/CheckpointManager.d.ts +48 -0
  30. package/dist/utils/CheckpointManager.d.ts.map +1 -0
  31. package/dist/utils/CheckpointManager.js +191 -0
  32. package/dist/utils/DataValidator.d.ts +46 -0
  33. package/dist/utils/DataValidator.d.ts.map +1 -0
  34. package/dist/utils/DataValidator.js +139 -0
  35. package/package.json +37 -0
@@ -0,0 +1,225 @@
1
+ /**
2
+ * Schema Validator
3
+ * Validates schemas and provides detailed error reporting
4
+ */
5
+ /**
6
+ * SchemaValidator - Sealed namespace for schema validation
7
+ * Provides comprehensive schema validation utilities
8
+ */
9
+ export const SchemaValidator = Object.freeze({
10
+ /**
11
+ * Validate complete schema
12
+ */
13
+ validateSchema(tables) {
14
+ const errors = [];
15
+ const warnings = [];
16
+ tables.forEach((table, index) => {
17
+ const tableValidation = SchemaValidator.validateTable(table);
18
+ errors.push(...tableValidation.errors.map((error) => `Table ${index + 1} (${table.name}): ${error}`));
19
+ warnings.push(...tableValidation.warnings.map((warning) => `Table ${index + 1} (${table.name}): ${warning}`));
20
+ });
21
+ // Check for duplicate table names
22
+ const tableNames = tables.map((t) => t.name.toLowerCase());
23
+ const duplicates = tableNames.filter((name, index) => tableNames.indexOf(name) !== index);
24
+ if (duplicates.length > 0) {
25
+ errors.push(`Duplicate table names: ${[...new Set(duplicates)].join(', ')}`);
26
+ }
27
+ return {
28
+ valid: errors.length === 0,
29
+ errors,
30
+ warnings,
31
+ };
32
+ },
33
+ /**
34
+ * Validate single table
35
+ */
36
+ validateTable(table) {
37
+ const errors = [];
38
+ const warnings = [];
39
+ // Validate table name
40
+ if (!table.name || table.name.trim() === '') {
41
+ errors.push('Table name is required');
42
+ }
43
+ else if (!/^\w*$/.test(table.name)) {
44
+ errors.push(`Invalid table name: ${table.name}. Must start with letter or underscore and contain only letters, numbers, and underscores`);
45
+ }
46
+ else if (table.name.length > 64) {
47
+ errors.push(`Table name too long: ${table.name}. Maximum 64 characters`);
48
+ }
49
+ // Validate columns
50
+ if (!table.columns || table.columns.length === 0) {
51
+ errors.push('Table must have at least one column');
52
+ }
53
+ else {
54
+ const columnNames = table.columns.map((c) => c.name.toLowerCase());
55
+ const duplicateColumns = columnNames.filter((name, index) => columnNames.indexOf(name) !== index);
56
+ if (duplicateColumns.length > 0) {
57
+ errors.push(`Duplicate column names: ${[...new Set(duplicateColumns)].join(', ')}`);
58
+ }
59
+ table.columns.forEach((column, colIndex) => {
60
+ const columnValidation = SchemaValidator.validateColumn(column);
61
+ errors.push(...columnValidation.errors.map((error) => `Column ${colIndex + 1} (${column.name}): ${error}`));
62
+ warnings.push(...columnValidation.warnings.map((warning) => `Column ${colIndex + 1} (${column.name}): ${warning}`));
63
+ });
64
+ }
65
+ // Validate primary key
66
+ if (table.primaryKey) {
67
+ const hasPrimaryKeyColumn = table.columns.some((column) => column.name === table.primaryKey);
68
+ if (!hasPrimaryKeyColumn) {
69
+ errors.push(`Primary key column '${table.primaryKey}' not found in table definition`);
70
+ }
71
+ }
72
+ return {
73
+ valid: errors.length === 0,
74
+ errors,
75
+ warnings,
76
+ };
77
+ },
78
+ /**
79
+ * Validate single column
80
+ */
81
+ validateColumn(column) {
82
+ const errors = [];
83
+ const warnings = [];
84
+ // Validate column name
85
+ if (!column.name || column.name.trim() === '') {
86
+ errors.push('Column name is required');
87
+ }
88
+ else if (!/^\w*$/.test(column.name)) {
89
+ errors.push(`Invalid column name: ${column.name}. Must start with letter or underscore and contain only letters, numbers, and underscores`);
90
+ }
91
+ else if (column.name.length > 64) {
92
+ errors.push(`Column name too long: ${column.name}. Maximum 64 characters`);
93
+ }
94
+ // Validate column type
95
+ if (!column.type || column.type.trim() === '') {
96
+ errors.push('Column type is required');
97
+ }
98
+ else {
99
+ const validTypes = [
100
+ 'integer',
101
+ 'text',
102
+ 'real',
103
+ 'numeric',
104
+ 'blob',
105
+ 'varchar',
106
+ 'char',
107
+ 'date',
108
+ 'datetime',
109
+ 'boolean',
110
+ ];
111
+ const normalizedType = column.type.toLowerCase();
112
+ if (!validTypes.includes(normalizedType)) {
113
+ warnings.push(`Potentially unsupported column type: ${column.type}. SQLite/D1 may not fully support this type`);
114
+ }
115
+ }
116
+ // Validate nullable
117
+ if (column.nullable !== undefined && typeof column.nullable !== 'boolean') {
118
+ errors.push('Nullable property must be a boolean');
119
+ }
120
+ return {
121
+ valid: errors.length === 0,
122
+ errors,
123
+ warnings,
124
+ };
125
+ },
126
+ /**
127
+ * Check for schema compatibility issues
128
+ */
129
+ checkCompatibility(issues) {
130
+ const blocking = [];
131
+ const warnings = [];
132
+ const { sourceDriver, tables } = issues;
133
+ tables.forEach((table) => {
134
+ table.columns.forEach((column) => {
135
+ const type = column.type.toLowerCase();
136
+ const compatibilityWarning = SchemaValidator.checkColumnTypeCompatibility(type, sourceDriver, table.name, column.name);
137
+ if (compatibilityWarning) {
138
+ warnings.push(compatibilityWarning);
139
+ }
140
+ });
141
+ });
142
+ return { blocking, warnings };
143
+ },
144
+ /**
145
+ * Check column type compatibility for specific driver
146
+ */
147
+ checkColumnTypeCompatibility(type, sourceDriver, tableName, columnName) {
148
+ switch (sourceDriver) {
149
+ case 'mysql':
150
+ return SchemaValidator.checkMySQLCompatibility(type, tableName, columnName);
151
+ case 'postgresql':
152
+ return SchemaValidator.checkPostgreSQLCompatibility(type, tableName, columnName);
153
+ case 'sqlserver':
154
+ return SchemaValidator.checkSQLServerCompatibility(type, tableName, columnName);
155
+ default:
156
+ return SchemaValidator.checkGeneralCompatibility(type, tableName, columnName);
157
+ }
158
+ },
159
+ /**
160
+ * Check MySQL-specific compatibility
161
+ */
162
+ checkMySQLCompatibility(type, tableName, columnName) {
163
+ if (type.includes('enum') || type.includes('set')) {
164
+ return `MySQL ENUM/SET types will be converted to TEXT in table: ${tableName}.${columnName}`;
165
+ }
166
+ if (type.includes('json')) {
167
+ return `MySQL JSON types will be converted to TEXT in table: ${tableName}.${columnName}`;
168
+ }
169
+ return null;
170
+ },
171
+ /**
172
+ * Check PostgreSQL-specific compatibility
173
+ */
174
+ checkPostgreSQLCompatibility(type, tableName, columnName) {
175
+ if (type.includes('uuid')) {
176
+ return `PostgreSQL UUID will be converted to TEXT in table: ${tableName}.${columnName}`;
177
+ }
178
+ if (type.includes('jsonb')) {
179
+ return `PostgreSQL JSONB will be converted to TEXT in table: ${tableName}.${columnName}`;
180
+ }
181
+ return null;
182
+ },
183
+ /**
184
+ * Check SQL Server-specific compatibility
185
+ */
186
+ checkSQLServerCompatibility(type, tableName, columnName) {
187
+ if (type.includes('uniqueidentifier')) {
188
+ return `SQL Server UNIQUEIDENTIFIER will be converted to TEXT in table: ${tableName}.${columnName}`;
189
+ }
190
+ if (type.includes('varbinary') || type.includes('image')) {
191
+ return `SQL Server binary types will be converted to BLOB in table: ${tableName}.${columnName}`;
192
+ }
193
+ return null;
194
+ },
195
+ /**
196
+ * Check general compatibility issues
197
+ */
198
+ checkGeneralCompatibility(type, tableName, columnName) {
199
+ if (type.includes('decimal') || type.includes('numeric')) {
200
+ return `Decimal/numeric types may lose precision when converted to REAL in table: ${tableName}.${columnName}`;
201
+ }
202
+ return null;
203
+ },
204
+ /**
205
+ * Generate validation report
206
+ */
207
+ generateReport(validation) {
208
+ let report = '# Schema Validation Report\n\n';
209
+ report += `## Status: ${validation.valid ? 'VALID' : 'INVALID'}\n\n`;
210
+ if (validation.errors.length > 0) {
211
+ report += `## Errors (${validation.errors.length})\n\n`;
212
+ validation.errors.forEach((error, index) => {
213
+ report += `${index + 1}. ${error}\n`;
214
+ });
215
+ report += '\n';
216
+ }
217
+ if (validation.warnings.length > 0) {
218
+ report += `## Warnings (${validation.warnings.length})\n\n`;
219
+ validation.warnings.forEach((warning, index) => {
220
+ report += `${index + 1}. ${warning}\n`;
221
+ });
222
+ }
223
+ return report;
224
+ },
225
+ });
@@ -0,0 +1,145 @@
1
+ /**
2
+ * D1 Migrator Types
3
+ * Type definitions for migration operations
4
+ */
5
+ export type SourceDatabaseDriver = 'mysql' | 'postgresql' | 'sqlite' | 'sqlserver';
6
+ export interface MigrationConfig {
7
+ sourceConnection: string;
8
+ sourceDriver: SourceDatabaseDriver;
9
+ targetDatabase: string;
10
+ targetType: 'd1' | 'd1-remote';
11
+ batchSize?: number;
12
+ checkpointInterval?: number;
13
+ dryRun?: boolean;
14
+ interactive?: boolean;
15
+ migrationId?: string;
16
+ }
17
+ export interface MigrationState {
18
+ id: string;
19
+ status: 'pending' | 'running' | 'paused' | 'completed' | 'failed';
20
+ startTime: Date;
21
+ lastCheckpoint?: Date;
22
+ totalTables: number;
23
+ completedTables: number;
24
+ totalRows: number;
25
+ completedRows: number;
26
+ errors: MigrationError[];
27
+ config: MigrationConfig;
28
+ }
29
+ export interface CheckpointData {
30
+ migrationId: string;
31
+ table: string;
32
+ lastProcessedId?: string | number;
33
+ processedRows: number;
34
+ totalRows: number;
35
+ checksum?: string;
36
+ timestamp: Date;
37
+ batchIndex: number;
38
+ }
39
+ export interface SchemaAnalysisResult {
40
+ tables: TableSchema[];
41
+ dependencies: TableDependency[];
42
+ conflicts: SchemaConflict[];
43
+ warnings: SchemaWarning[];
44
+ }
45
+ export interface DatabaseSchema {
46
+ tables: TableSchema[];
47
+ relationships: TableRelationship[];
48
+ constraints: TableConstraint[];
49
+ }
50
+ export interface TableRelationship {
51
+ sourceTable: string;
52
+ targetTable: string;
53
+ sourceColumn: string;
54
+ targetColumn: string;
55
+ type: 'one-to-one' | 'one-to-many' | 'many-to-many';
56
+ }
57
+ export interface TableConstraint {
58
+ table: string;
59
+ type: 'primary_key' | 'foreign_key' | 'unique' | 'check' | 'not_null';
60
+ columns: string[];
61
+ definition?: string;
62
+ }
63
+ export interface TableSchema {
64
+ primaryKey: string;
65
+ name: string;
66
+ columns: ColumnSchema[];
67
+ indexes: IndexSchema[];
68
+ foreignKeys: ForeignKeySchema[];
69
+ primaryKeys: string[];
70
+ rowCount?: number;
71
+ }
72
+ export interface ColumnSchema {
73
+ name: string;
74
+ type: string;
75
+ nullable: boolean;
76
+ defaultValue?: unknown;
77
+ autoIncrement?: boolean;
78
+ maxLength?: number;
79
+ precision?: number;
80
+ scale?: number;
81
+ }
82
+ export interface IndexSchema {
83
+ name: string;
84
+ columns: string[];
85
+ unique: boolean;
86
+ primary?: boolean;
87
+ }
88
+ export interface ForeignKeySchema {
89
+ name: string;
90
+ column: string;
91
+ referencedTable: string;
92
+ referencedColumn: string;
93
+ onDelete?: 'CASCADE' | 'SET NULL' | 'RESTRICT';
94
+ onUpdate?: 'CASCADE' | 'SET NULL' | 'RESTRICT';
95
+ }
96
+ export interface TableDependency {
97
+ table: string;
98
+ dependsOn: string[];
99
+ level: number;
100
+ }
101
+ export interface SchemaConflict {
102
+ type: 'unsupported_type' | 'size_limitation' | 'constraint_incompatible';
103
+ table: string;
104
+ column?: string;
105
+ description: string;
106
+ severity: 'error' | 'warning';
107
+ suggestion?: string;
108
+ }
109
+ export interface SchemaWarning {
110
+ type: 'data_loss_risk' | 'performance_impact' | 'manual_review';
111
+ table: string;
112
+ description: string;
113
+ suggestion?: string;
114
+ }
115
+ export interface MigrationProgress {
116
+ migrationId: string;
117
+ currentTable: string;
118
+ table: string;
119
+ status: 'pending' | 'processing' | 'completed' | 'failed';
120
+ processedRows: number;
121
+ totalTables: number;
122
+ totalRows: number;
123
+ percentage: number;
124
+ errors: Record<string, string>;
125
+ startTime?: Date;
126
+ endTime?: Date;
127
+ }
128
+ export interface MigrationError {
129
+ table?: string;
130
+ batch?: number;
131
+ error: string;
132
+ timestamp: Date;
133
+ retryCount: number;
134
+ resolved: boolean;
135
+ }
136
+ export interface DataValidationResult {
137
+ table: string;
138
+ sourceCount: number;
139
+ targetCount: number;
140
+ checksumMatch: boolean;
141
+ missingRows?: string[];
142
+ extraRows?: string[];
143
+ errors: string[];
144
+ }
145
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,5 @@
1
+ /**
2
+ * D1 Migrator Types
3
+ * Type definitions for migration operations
4
+ */
5
+ export {};
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Checkpoint Manager
3
+ * File-based persistent state tracking for resumable operations
4
+ */
5
+ import type { CheckpointData, MigrationError, MigrationState } from '../types';
6
+ /**
7
+ * CheckpointManager - Sealed namespace for migration state management
8
+ * Provides file-based persistent storage for migration progress
9
+ */
10
+ export declare const CheckpointManager: Readonly<{
11
+ /**
12
+ * Initialize migration directory
13
+ */
14
+ initDirectory(): Promise<void>;
15
+ /**
16
+ * Save migration state to file
17
+ */
18
+ saveState(state: MigrationState): Promise<void>;
19
+ /**
20
+ * Load migration state from file
21
+ */
22
+ loadState(migrationId: string): Promise<MigrationState | null>;
23
+ /**
24
+ * Save checkpoint data
25
+ */
26
+ saveCheckpoint(checkpoint: CheckpointData): Promise<void>;
27
+ /**
28
+ * Load checkpoint data
29
+ */
30
+ loadCheckpoint(migrationId: string, table: string): Promise<CheckpointData | null>;
31
+ /**
32
+ * Get all checkpoints for a migration
33
+ */
34
+ getAllCheckpoints(migrationId: string): Promise<CheckpointData[]>;
35
+ /**
36
+ * Clean up migration files
37
+ */
38
+ cleanup(migrationId: string): Promise<void>;
39
+ /**
40
+ * List all migrations
41
+ */
42
+ listMigrations(): Promise<string[]>;
43
+ /**
44
+ * Log migration error
45
+ */
46
+ logError(migrationId: string, errorData: MigrationError): Promise<void>;
47
+ }>;
48
+ //# sourceMappingURL=CheckpointManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CheckpointManager.d.ts","sourceRoot":"","sources":["../../src/utils/CheckpointManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAM/E;;;GAGG;AACH,eAAO,MAAM,iBAAiB;IAC5B;;OAEG;qBACoB,OAAO,CAAC,IAAI,CAAC;IASpC;;OAEG;qBACoB,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAerD;;OAEG;2BAC0B,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAoBpE;;OAEG;+BAC8B,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB/D;;OAEG;gCAC+B,MAAM,SAAS,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAcxF;;OAEG;mCACkC,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAuCvE;;OAEG;yBACwB,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAwBjD;;OAEG;sBACqB,OAAO,CAAC,MAAM,EAAE,CAAC;IAgBzC;;OAEG;0BACyB,MAAM,aAAa,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;EAuB7E,CAAC"}
@@ -0,0 +1,191 @@
1
+ /**
2
+ * Checkpoint Manager
3
+ * File-based persistent state tracking for resumable operations
4
+ */
5
+ import { ErrorFactory, Logger, NodeSingletons } from '@zintrust/core';
6
+ const MIGRATION_DIR = '.zintrust/migration';
7
+ const path = NodeSingletons.path;
8
+ const { fsPromises, mkdir, readFile, rm, writeFile } = NodeSingletons.fs;
9
+ /**
10
+ * CheckpointManager - Sealed namespace for migration state management
11
+ * Provides file-based persistent storage for migration progress
12
+ */
13
+ export const CheckpointManager = Object.freeze({
14
+ /**
15
+ * Initialize migration directory
16
+ */
17
+ async initDirectory() {
18
+ try {
19
+ await mkdir(MIGRATION_DIR, { recursive: true });
20
+ }
21
+ catch (initError) {
22
+ Logger.error('Failed to create migration directory:', initError);
23
+ throw ErrorFactory.createConfigError('Cannot create migration directory');
24
+ }
25
+ },
26
+ /**
27
+ * Save migration state to file
28
+ */
29
+ async saveState(state) {
30
+ await CheckpointManager.initDirectory();
31
+ const filePath = path.join(MIGRATION_DIR, `migration-${state.id}.json`);
32
+ const content = JSON.stringify(state, null, 2);
33
+ try {
34
+ await writeFile(filePath, content, 'utf-8');
35
+ Logger.info(`Migration state saved: ${filePath}`);
36
+ }
37
+ catch (writeError) {
38
+ Logger.error('Failed to save migration state:', writeError);
39
+ throw ErrorFactory.createConfigError('Cannot save migration state');
40
+ }
41
+ },
42
+ /**
43
+ * Load migration state from file
44
+ */
45
+ async loadState(migrationId) {
46
+ const filePath = NodeSingletons.path.join(MIGRATION_DIR, `migration-${migrationId}.json`);
47
+ try {
48
+ const content = await readFile(filePath, 'utf-8');
49
+ const state = JSON.parse(content);
50
+ // Convert date strings back to Date objects
51
+ state.startTime = new Date(state.startTime);
52
+ if (state.lastCheckpoint) {
53
+ state.lastCheckpoint = new Date(state.lastCheckpoint);
54
+ }
55
+ return state;
56
+ }
57
+ catch {
58
+ Logger.warn(`Migration state not found: ${filePath}`);
59
+ return null;
60
+ }
61
+ },
62
+ /**
63
+ * Save checkpoint data
64
+ */
65
+ async saveCheckpoint(checkpoint) {
66
+ await CheckpointManager.initDirectory();
67
+ const filePath = path.join(MIGRATION_DIR, `checkpoint-${checkpoint.migrationId}-${checkpoint.table}.json`);
68
+ const content = JSON.stringify(checkpoint, null, 2);
69
+ try {
70
+ await writeFile(filePath, content, 'utf-8');
71
+ Logger.debug(`Checkpoint saved: ${filePath}`);
72
+ }
73
+ catch (writeError) {
74
+ Logger.error('Failed to save checkpoint:', writeError);
75
+ throw ErrorFactory.createConfigError('Cannot save checkpoint');
76
+ }
77
+ },
78
+ /**
79
+ * Load checkpoint data
80
+ */
81
+ async loadCheckpoint(migrationId, table) {
82
+ const filePath = path.join(MIGRATION_DIR, `checkpoint-${migrationId}-${table}.json`);
83
+ try {
84
+ const content = await readFile(filePath, 'utf-8');
85
+ const checkpoint = JSON.parse(content);
86
+ checkpoint.timestamp = new Date(checkpoint.timestamp);
87
+ return checkpoint;
88
+ }
89
+ catch {
90
+ Logger.debug(`Checkpoint not found: ${filePath}`);
91
+ return null;
92
+ }
93
+ },
94
+ /**
95
+ * Get all checkpoints for a migration
96
+ */
97
+ async getAllCheckpoints(migrationId) {
98
+ await CheckpointManager.initDirectory();
99
+ try {
100
+ const files = await fsPromises.readdir(MIGRATION_DIR);
101
+ const checkpointFiles = files.filter((file) => file.startsWith(`checkpoint-${migrationId}-`) && file.endsWith('.json'));
102
+ const checkpoints = [];
103
+ // Process files in parallel for better performance
104
+ const checkpointPromises = checkpointFiles.map(async (file) => {
105
+ try {
106
+ const filePath = path.join(MIGRATION_DIR, file);
107
+ const content = await readFile(filePath, 'utf-8');
108
+ const checkpoint = JSON.parse(content);
109
+ checkpoint.timestamp = new Date(checkpoint.timestamp);
110
+ return checkpoint;
111
+ }
112
+ catch (parseError) {
113
+ Logger.warn(`Failed to load checkpoint file ${file}:`, parseError);
114
+ return null;
115
+ }
116
+ });
117
+ const results = await Promise.allSettled(checkpointPromises);
118
+ results.forEach((result) => {
119
+ if (result.status === 'fulfilled' && result.value !== null) {
120
+ checkpoints.push(result.value);
121
+ }
122
+ });
123
+ return checkpoints.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
124
+ }
125
+ catch (readError) {
126
+ Logger.error('Failed to list checkpoints:', readError);
127
+ return [];
128
+ }
129
+ },
130
+ /**
131
+ * Clean up migration files
132
+ */
133
+ async cleanup(migrationId) {
134
+ try {
135
+ const files = await fsPromises.readdir(MIGRATION_DIR);
136
+ const migrationFiles = files.filter((file) => file.includes(migrationId) && file.endsWith('.json'));
137
+ // Process cleanup in parallel
138
+ const cleanupPromises = migrationFiles.map(async (file) => {
139
+ try {
140
+ const filePath = path.join(MIGRATION_DIR, file);
141
+ await rm(filePath);
142
+ Logger.debug(`Cleaned up migration file: ${file}`);
143
+ }
144
+ catch (cleanupError) {
145
+ Logger.warn(`Failed to cleanup file ${file}:`, cleanupError);
146
+ }
147
+ });
148
+ await Promise.allSettled(cleanupPromises);
149
+ }
150
+ catch (readError) {
151
+ Logger.error('Failed to cleanup migration files:', readError);
152
+ }
153
+ },
154
+ /**
155
+ * List all migrations
156
+ */
157
+ async listMigrations() {
158
+ try {
159
+ const files = await fsPromises.readdir(MIGRATION_DIR);
160
+ const migrationFiles = files.filter((file) => file.startsWith('migration-') && file.endsWith('.json'));
161
+ return migrationFiles.map((file) => file.replace('migration-', '').replace('.json', ''));
162
+ }
163
+ catch (readError) {
164
+ Logger.error('Failed to list migrations:', readError);
165
+ return [];
166
+ }
167
+ },
168
+ /**
169
+ * Log migration error
170
+ */
171
+ async logError(migrationId, errorData) {
172
+ await CheckpointManager.initDirectory();
173
+ const filePath = path.join(MIGRATION_DIR, `errors-${migrationId}.json`);
174
+ try {
175
+ let errors = [];
176
+ try {
177
+ const content = await readFile(filePath, 'utf-8');
178
+ errors = JSON.parse(content);
179
+ }
180
+ catch {
181
+ // File doesn't exist, start with empty array
182
+ }
183
+ errors.push(errorData);
184
+ await writeFile(filePath, JSON.stringify(errors, null, 2), 'utf-8');
185
+ Logger.error(`Migration error logged: ${errorData.error}`);
186
+ }
187
+ catch (writeError) {
188
+ Logger.error('Failed to log migration error:', writeError);
189
+ }
190
+ },
191
+ });
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Data Validator
3
+ * Integrity checks and validation for migrated data
4
+ */
5
+ import type { DataValidationResult } from '../types';
6
+ /**
7
+ * DataValidator - Sealed namespace for data integrity validation
8
+ * Provides comprehensive validation of migrated data
9
+ */
10
+ export declare const DataValidator: Readonly<{
11
+ /**
12
+ * Validate data integrity between source and target
13
+ */
14
+ validateDataIntegrity(sourceCount: number, targetCount: number, tableName: string): Promise<boolean>;
15
+ /**
16
+ * Generate checksum for data validation
17
+ */
18
+ generateChecksum(data: unknown[]): Promise<string>;
19
+ /**
20
+ * Validate data checksums
21
+ */
22
+ validateChecksum(sourceData: unknown[], targetData: unknown[], tableName: string): Promise<boolean>;
23
+ /**
24
+ * Comprehensive data validation
25
+ */
26
+ validateTable(sourceData: unknown[], targetData: unknown[], tableName: string): Promise<DataValidationResult>;
27
+ /**
28
+ * Validate schema compatibility
29
+ */
30
+ validateSchemaCompatibility(sourceSchema: unknown, targetSchema: unknown, tableName: string): {
31
+ valid: boolean;
32
+ errors: string[];
33
+ };
34
+ /**
35
+ * Sanitize table name for D1 compatibility
36
+ */
37
+ sanitizeTableName(tableName: string): string;
38
+ /**
39
+ * Validate column type conversion
40
+ */
41
+ validateColumnType(sourceType: string, targetType: string, tableName: string, columnName: string): {
42
+ valid: boolean;
43
+ warning?: string;
44
+ };
45
+ }>;
46
+ //# sourceMappingURL=DataValidator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DataValidator.d.ts","sourceRoot":"","sources":["../../src/utils/DataValidator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAErD;;;GAGG;AACH,eAAO,MAAM,aAAa;IACxB;;OAEG;uCAEY,MAAM,eACN,MAAM,aACR,MAAM,GAChB,OAAO,CAAC,OAAO,CAAC;IAcnB;;OAEG;2BAC0B,OAAO,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IAMxD;;OAEG;iCAEW,OAAO,EAAE,cACT,OAAO,EAAE,aACV,MAAM,GAChB,OAAO,CAAC,OAAO,CAAC;IAiBnB;;OAEG;8BAEW,OAAO,EAAE,cACT,OAAO,EAAE,aACV,MAAM,GAChB,OAAO,CAAC,oBAAoB,CAAC;IAsChC;;OAEG;8CAEa,OAAO,gBACP,OAAO,aACV,MAAM,GAChB;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE;IAsBvC;;OAEG;iCAC0B,MAAM,GAAG,MAAM;IAe5C;;OAEG;mCAEW,MAAM,cACN,MAAM,aACP,MAAM,cACL,MAAM,GACjB;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE;EA2BvC,CAAC"}