@javalabs/prisma-client 1.0.4 → 1.0.8
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/dist/scripts/data-migration/batch-migrator.d.ts +14 -19
- package/dist/scripts/data-migration/batch-migrator.js +98 -297
- package/dist/scripts/data-migration/batch-migrator.js.map +1 -1
- package/dist/scripts/data-migration/data-transformer.d.ts +16 -7
- package/dist/scripts/data-migration/data-transformer.js +169 -133
- package/dist/scripts/data-migration/data-transformer.js.map +1 -1
- package/dist/scripts/data-migration/db-connector.d.ts +6 -1
- package/dist/scripts/data-migration/db-connector.js +44 -8
- package/dist/scripts/data-migration/db-connector.js.map +1 -1
- package/dist/scripts/data-migration/dependency-resolver.d.ts +10 -10
- package/dist/scripts/data-migration/dependency-resolver.js +92 -211
- package/dist/scripts/data-migration/dependency-resolver.js.map +1 -1
- package/dist/scripts/data-migration/foreign-key-manager.d.ts +6 -5
- package/dist/scripts/data-migration/foreign-key-manager.js +108 -18
- package/dist/scripts/data-migration/foreign-key-manager.js.map +1 -1
- package/dist/scripts/data-migration/migration-config.json +63 -0
- package/dist/scripts/data-migration/migration-tool.d.ts +25 -6
- package/dist/scripts/data-migration/migration-tool.js +78 -38
- package/dist/scripts/data-migration/migration-tool.js.map +1 -1
- package/dist/scripts/data-migration/multi-source-migrator.d.ts +17 -0
- package/dist/scripts/data-migration/multi-source-migrator.js +130 -0
- package/dist/scripts/data-migration/multi-source-migrator.js.map +1 -0
- package/dist/scripts/data-migration/schema-utils.d.ts +3 -3
- package/dist/scripts/data-migration/schema-utils.js +62 -19
- package/dist/scripts/data-migration/schema-utils.js.map +1 -1
- package/dist/scripts/data-migration/tenant-migrator.js +9 -2
- package/dist/scripts/data-migration/tenant-migrator.js.map +1 -1
- package/dist/scripts/data-migration/typecast-manager.d.ts +7 -3
- package/dist/scripts/data-migration/typecast-manager.js +169 -25
- package/dist/scripts/data-migration/typecast-manager.js.map +1 -1
- package/dist/scripts/data-migration/types.d.ts +68 -2
- package/dist/scripts/database-initializer.d.ts +5 -0
- package/dist/scripts/database-initializer.js +45 -0
- package/dist/scripts/database-initializer.js.map +1 -0
- package/dist/scripts/fix-table-indexes.d.ts +26 -0
- package/dist/scripts/fix-table-indexes.js +460 -0
- package/dist/scripts/fix-table-indexes.js.map +1 -0
- package/dist/scripts/multi-db-migration.d.ts +1 -0
- package/dist/scripts/multi-db-migration.js +55 -0
- package/dist/scripts/multi-db-migration.js.map +1 -0
- package/dist/scripts/post-migration-validator.d.ts +18 -5
- package/dist/scripts/post-migration-validator.js +61 -39
- package/dist/scripts/post-migration-validator.js.map +1 -1
- package/dist/scripts/run-migration.js +83 -96
- package/dist/scripts/run-migration.js.map +1 -1
- package/dist/scripts/sequence-synchronizer.d.ts +8 -0
- package/dist/scripts/sequence-synchronizer.js +88 -0
- package/dist/scripts/sequence-synchronizer.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/migration-config.json +40 -72
- package/{migration-config-public.json → migration-config.json.bk} +14 -14
- package/package.json +10 -3
- package/prisma/migrations/{20250422001248_add_bank_account_id → 0_init}/migration.sql +269 -47
- package/prisma/migrations/20250505171324_add_bank_owner_name_in_manual_transfer/migration.sql +2 -0
- package/prisma/migrations/20250505173850_add_method_name_in_manual_transfer/migration.sql +2 -0
- package/prisma/migrations/migration_lock.toml +2 -2
- package/prisma/schema.prisma +214 -77
- package/src/scripts/data-migration/batch-migrator.ts +192 -513
- package/src/scripts/data-migration/data-transformer.ts +252 -203
- package/src/scripts/data-migration/db-connector.ts +66 -13
- package/src/scripts/data-migration/dependency-resolver.ts +121 -266
- package/src/scripts/data-migration/foreign-key-manager.ts +214 -32
- package/src/scripts/data-migration/migration-config.json +63 -0
- package/src/scripts/data-migration/migration-tool.ts +377 -225
- package/src/scripts/data-migration/schema-utils.ts +94 -32
- package/src/scripts/data-migration/tenant-migrator.ts +12 -5
- package/src/scripts/data-migration/typecast-manager.ts +186 -31
- package/src/scripts/data-migration/types.ts +78 -5
- package/src/scripts/database-initializer.ts +49 -0
- package/src/scripts/fix-table-indexes.ts +602 -0
- package/src/scripts/post-migration-validator.ts +206 -107
- package/src/scripts/run-migration.ts +140 -124
- package/src/scripts/sequence-synchronizer.ts +127 -0
- package/prisma/migrations/20250422001957_add_bank_account_id_relations/migration.sql +0 -14
- package/src/scripts/dumps/source_dump_20250413_112626.sql +0 -1527
|
@@ -5,12 +5,37 @@ import { promisify } from "util";
|
|
|
5
5
|
import { SchemaDiscrepancyFixer } from "./fix-schema-discrepancies";
|
|
6
6
|
import { EnumSynchronizer } from "./sync-enum-types";
|
|
7
7
|
import { PrismaClient } from "@prisma/client";
|
|
8
|
+
import { MigrationConfig } from "./data-migration/types";
|
|
9
|
+
import * as fs from "fs";
|
|
10
|
+
import * as path from "path";
|
|
11
|
+
import { DatabaseInitializer } from "./database-initializer";
|
|
12
|
+
import { SequenceSynchronizer } from "./sequence-synchronizer";
|
|
8
13
|
|
|
9
14
|
dotenv.config();
|
|
10
15
|
|
|
11
16
|
const execAsync = promisify(exec);
|
|
12
17
|
const program = new Command();
|
|
13
18
|
|
|
19
|
+
// Función para cargar la configuración de migración
|
|
20
|
+
async function loadMigrationConfig(
|
|
21
|
+
configPath?: string
|
|
22
|
+
): Promise<MigrationConfig> {
|
|
23
|
+
const defaultPath = path.join(
|
|
24
|
+
__dirname,
|
|
25
|
+
"data-migration",
|
|
26
|
+
"migration-config.json"
|
|
27
|
+
);
|
|
28
|
+
const filePath = configPath || defaultPath;
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
const configContent = await fs.promises.readFile(filePath, "utf8");
|
|
32
|
+
return JSON.parse(configContent);
|
|
33
|
+
} catch (error) {
|
|
34
|
+
console.error(`Error loading migration config from ${filePath}:`, error);
|
|
35
|
+
throw error;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
14
39
|
// Añadir esta función después de las importaciones
|
|
15
40
|
async function testDatabaseConnection(
|
|
16
41
|
url: string,
|
|
@@ -36,85 +61,6 @@ async function testDatabaseConnection(
|
|
|
36
61
|
}
|
|
37
62
|
|
|
38
63
|
// Modificar la acción del comando migrate para incluir la prueba de conexión
|
|
39
|
-
async function initializeDatabase(options: any) {
|
|
40
|
-
try {
|
|
41
|
-
const { Pool } = await import("pg");
|
|
42
|
-
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
|
|
43
|
-
|
|
44
|
-
// Check if database is already initialized
|
|
45
|
-
const tablesExist = await checkIfTablesExist(pool);
|
|
46
|
-
|
|
47
|
-
if (!tablesExist) {
|
|
48
|
-
// Only create tables if they don't exist
|
|
49
|
-
console.log("Database empty, creating initial schema...");
|
|
50
|
-
await execAsync("npx prisma db push --skip-generate");
|
|
51
|
-
} else {
|
|
52
|
-
console.log("Database schema already exists, skipping schema creation");
|
|
53
|
-
// Create baseline if it doesn't exist
|
|
54
|
-
await execAsync(
|
|
55
|
-
"npx prisma migrate reset --force --skip-generate --skip-seed"
|
|
56
|
-
);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
if (!options.skipEnumSync) {
|
|
60
|
-
console.log("Synchronizing enum types...");
|
|
61
|
-
const enumSynchronizer = new EnumSynchronizer(
|
|
62
|
-
process.env.SOURCE_DATABASE_URL,
|
|
63
|
-
process.env.DATABASE_URL
|
|
64
|
-
);
|
|
65
|
-
await enumSynchronizer.synchronizeEnums();
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// Proceed with data migration if not skipped
|
|
69
|
-
if (!options.skipDataMigration) {
|
|
70
|
-
console.log("Starting data migration...");
|
|
71
|
-
const { DataMigrationTool } = await import(
|
|
72
|
-
"./data-migration/migration-tool"
|
|
73
|
-
);
|
|
74
|
-
const migrationTool = new DataMigrationTool({
|
|
75
|
-
sourcePool: new Pool({
|
|
76
|
-
connectionString: process.env.SOURCE_DATABASE_URL,
|
|
77
|
-
}),
|
|
78
|
-
targetPool: pool,
|
|
79
|
-
sourcePrisma: new PrismaClient({
|
|
80
|
-
datasources: { db: { url: process.env.SOURCE_DATABASE_URL } },
|
|
81
|
-
}),
|
|
82
|
-
targetPrisma: new PrismaClient({
|
|
83
|
-
datasources: { db: { url: process.env.DATABASE_URL } },
|
|
84
|
-
}),
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
await migrationTool.migrateData({
|
|
88
|
-
publicOnly: options.mode === "public-only",
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
await pool.end();
|
|
93
|
-
return true;
|
|
94
|
-
} catch (error) {
|
|
95
|
-
console.error("Error initializing database:", error);
|
|
96
|
-
return false;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// Helper function to check if tables exist
|
|
101
|
-
async function checkIfTablesExist(pool: any): Promise<boolean> {
|
|
102
|
-
try {
|
|
103
|
-
const result = await pool.query(`
|
|
104
|
-
SELECT COUNT(*)
|
|
105
|
-
FROM information_schema.tables
|
|
106
|
-
WHERE table_schema = 'public'
|
|
107
|
-
AND table_type = 'BASE TABLE'
|
|
108
|
-
`);
|
|
109
|
-
|
|
110
|
-
return parseInt(result.rows[0].count) > 0;
|
|
111
|
-
} catch (error) {
|
|
112
|
-
console.error("Error checking tables:", error);
|
|
113
|
-
return false;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// Modify the existing action handler
|
|
118
64
|
program
|
|
119
65
|
.command("migrate")
|
|
120
66
|
.description("Run the data migration process")
|
|
@@ -134,6 +80,9 @@ program
|
|
|
134
80
|
.option("--auto-fix-schema", "Automatically fix schema discrepancies", false)
|
|
135
81
|
.option("--force", "Force migration even if validation fails", false)
|
|
136
82
|
.option("-y, --yes", "Automatically answer yes to all prompts", false)
|
|
83
|
+
.option("--config-path <path>", "Path to migration config file")
|
|
84
|
+
.option("--skip-initialization", "Skip database initialization step", false)
|
|
85
|
+
.option("--skip-sequence-sync", "Skip sequence synchronization step", false)
|
|
137
86
|
.action(async (options) => {
|
|
138
87
|
// Set environment variables for the migration
|
|
139
88
|
if (options.source) {
|
|
@@ -182,12 +131,16 @@ program
|
|
|
182
131
|
}
|
|
183
132
|
|
|
184
133
|
try {
|
|
185
|
-
// Initialize database if
|
|
186
|
-
|
|
134
|
+
// Step 0: Initialize database if needed
|
|
135
|
+
if (!options.skipInitialization) {
|
|
136
|
+
console.log("Step 0: Checking database initialization...");
|
|
137
|
+
const initializer = new DatabaseInitializer(process.env.DATABASE_URL);
|
|
138
|
+
await initializer.initialize();
|
|
139
|
+
}
|
|
187
140
|
|
|
188
|
-
// Step
|
|
141
|
+
// Step 1: Pre-migration validation
|
|
189
142
|
if (!options.skipValidation) {
|
|
190
|
-
console.log("Step
|
|
143
|
+
console.log("Step 1: Running pre-migration validation...");
|
|
191
144
|
const { PreMigrationValidator } = await import(
|
|
192
145
|
"./pre-migration-validator"
|
|
193
146
|
);
|
|
@@ -198,9 +151,7 @@ program
|
|
|
198
151
|
console.log(
|
|
199
152
|
`Pre-migration validation found ${validationResult.issueCount} issues.`
|
|
200
153
|
);
|
|
201
|
-
console.log(
|
|
202
|
-
`Check the full report at: ${validationResult.reportPath}`
|
|
203
|
-
);
|
|
154
|
+
console.log(JSON.stringify(validationResult, null, 2));
|
|
204
155
|
|
|
205
156
|
// Si la opción --yes o --force está activada, continuar automáticamente
|
|
206
157
|
if (options.yes) {
|
|
@@ -245,14 +196,32 @@ program
|
|
|
245
196
|
}
|
|
246
197
|
}
|
|
247
198
|
|
|
248
|
-
// Step
|
|
199
|
+
// Step 2: Migrate schema structure
|
|
249
200
|
if (!options.skipSchemaMigration) {
|
|
250
|
-
console.log("Step
|
|
201
|
+
console.log("Step 2: Migrating schema structure...");
|
|
251
202
|
if (options.mode === "multi-tenant") {
|
|
252
203
|
await execAsync("node dist/scripts/migrate-schema-structure.js");
|
|
253
204
|
} else {
|
|
254
205
|
const { Pool } = await import("pg");
|
|
255
206
|
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
|
|
207
|
+
|
|
208
|
+
// Helper function to check if tables exist
|
|
209
|
+
async function checkIfTablesExist(pool: any): Promise<boolean> {
|
|
210
|
+
try {
|
|
211
|
+
const result = await pool.query(`
|
|
212
|
+
SELECT COUNT(*)
|
|
213
|
+
FROM information_schema.tables
|
|
214
|
+
WHERE table_schema = 'public'
|
|
215
|
+
AND table_type = 'BASE TABLE'
|
|
216
|
+
`);
|
|
217
|
+
|
|
218
|
+
return parseInt(result.rows[0].count) > 0;
|
|
219
|
+
} catch (error) {
|
|
220
|
+
console.error("Error checking tables:", error);
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
256
225
|
const tablesExist = await checkIfTablesExist(pool);
|
|
257
226
|
if (!tablesExist) {
|
|
258
227
|
await execAsync("npx prisma migrate deploy");
|
|
@@ -260,31 +229,49 @@ program
|
|
|
260
229
|
}
|
|
261
230
|
}
|
|
262
231
|
|
|
263
|
-
// Step
|
|
232
|
+
// Step 3: Synchronize and fix enum types
|
|
264
233
|
if (!options.skipEnumSync) {
|
|
265
|
-
console.log("Step
|
|
234
|
+
console.log("Step 3: Synchronizing and fixing enum types...");
|
|
235
|
+
// Sync enum types
|
|
266
236
|
const { EnumSynchronizer } = await import("./sync-enum-types");
|
|
267
237
|
const synchronizer = new EnumSynchronizer();
|
|
268
238
|
await synchronizer.synchronizeEnums();
|
|
269
239
|
console.log("Enum types synchronized successfully!");
|
|
270
240
|
|
|
271
|
-
|
|
241
|
+
// Sync enum values
|
|
242
|
+
console.log("Step 3.1: Synchronizing enum values...");
|
|
272
243
|
const { EnumValueSynchronizer } = await import("./sync-enum-values");
|
|
273
244
|
const valueSynchronizer = new EnumValueSynchronizer();
|
|
274
245
|
await valueSynchronizer.synchronizeEnumValues();
|
|
275
246
|
console.log("Enum values synchronized successfully!");
|
|
247
|
+
|
|
248
|
+
// Fix enum values
|
|
249
|
+
console.log("Step 3.2: Fixing enum values...");
|
|
250
|
+
const { EnumFixer } = await import("./fix-enum-values");
|
|
251
|
+
const enumFixer = new EnumFixer(process.env.DATABASE_URL);
|
|
252
|
+
await enumFixer.fixEnumValues();
|
|
253
|
+
console.log("Enum values fixed successfully!");
|
|
276
254
|
}
|
|
277
255
|
|
|
278
|
-
// Step
|
|
279
|
-
|
|
256
|
+
// Step 4: Fix data types
|
|
257
|
+
console.log("Step 4: Fixing data type issues...");
|
|
258
|
+
const { DataTypeFixer } = await import("./fix-data-types");
|
|
259
|
+
const fixer = new DataTypeFixer();
|
|
260
|
+
await fixer.fixDataTypes();
|
|
261
|
+
console.log("Data type fixing completed successfully!");
|
|
262
|
+
|
|
263
|
+
// Step 5: Migrate data with transformation
|
|
280
264
|
if (!options.skipDataMigration) {
|
|
281
|
-
console.log("Step
|
|
265
|
+
console.log("Step 5: Migrating data with transformation...");
|
|
282
266
|
const { DataMigrationTool } = await import(
|
|
283
267
|
"./data-migration/migration-tool"
|
|
284
268
|
);
|
|
285
269
|
const { PrismaClient } = await import("@prisma/client");
|
|
286
270
|
const { Pool } = await import("pg");
|
|
287
271
|
|
|
272
|
+
// Cargar la configuración de migración
|
|
273
|
+
const migrationConfig = await loadMigrationConfig(options.configPath);
|
|
274
|
+
|
|
288
275
|
// Create connections with increased pool size and timeout
|
|
289
276
|
const connections = {
|
|
290
277
|
sourcePool: new Pool({
|
|
@@ -313,20 +300,44 @@ program
|
|
|
313
300
|
"SET session_replication_role = 'replica';"
|
|
314
301
|
);
|
|
315
302
|
|
|
316
|
-
|
|
317
|
-
|
|
303
|
+
// Si es public-only, modificar la configuración para solo incluir tablas públicas
|
|
318
304
|
if (options.mode === "public-only") {
|
|
319
|
-
|
|
320
|
-
|
|
305
|
+
migrationConfig.tables = Object.entries(migrationConfig.tables)
|
|
306
|
+
.filter(([_, config]) => config.type === "public")
|
|
307
|
+
.reduce(
|
|
308
|
+
(acc, [key, value]) => ({
|
|
309
|
+
...acc,
|
|
310
|
+
[key]: value,
|
|
311
|
+
}),
|
|
312
|
+
{}
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
const migrationTool = new DataMigrationTool(
|
|
317
|
+
connections,
|
|
318
|
+
{
|
|
319
|
+
...migrationConfig,
|
|
320
|
+
tables: Object.entries(migrationConfig.tables).reduce(
|
|
321
|
+
(acc, [key, value]) => ({
|
|
322
|
+
...acc,
|
|
323
|
+
[key]: {
|
|
324
|
+
...value,
|
|
325
|
+
sourceTable: value.sourceTable || key,
|
|
326
|
+
targetTable: value.targetTable || key,
|
|
327
|
+
},
|
|
328
|
+
}),
|
|
329
|
+
{}
|
|
330
|
+
),
|
|
331
|
+
},
|
|
332
|
+
{
|
|
333
|
+
publicOnly: options.mode === "public-only",
|
|
321
334
|
targetSchema: "public",
|
|
322
335
|
sourceSchema: "public",
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
});
|
|
329
|
-
}
|
|
336
|
+
multiTenant: options.mode !== "public-only",
|
|
337
|
+
}
|
|
338
|
+
);
|
|
339
|
+
|
|
340
|
+
await migrationTool.migrate();
|
|
330
341
|
} finally {
|
|
331
342
|
// Re-enable foreign key constraints
|
|
332
343
|
await connections.targetPool.query(
|
|
@@ -341,20 +352,6 @@ program
|
|
|
341
352
|
}
|
|
342
353
|
}
|
|
343
354
|
|
|
344
|
-
// Step 4: Fix enum values if needed
|
|
345
|
-
console.log("Step 4: Fixing enum values...");
|
|
346
|
-
const { EnumFixer } = await import("./fix-enum-values");
|
|
347
|
-
const enumFixer = new EnumFixer(process.env.DATABASE_URL);
|
|
348
|
-
await enumFixer.fixEnumValues();
|
|
349
|
-
console.log("Enum values fixed successfully!");
|
|
350
|
-
|
|
351
|
-
// Step 5: Fix data types if needed
|
|
352
|
-
console.log("Step 5: Fixing data type issues...");
|
|
353
|
-
const { DataTypeFixer } = await import("./fix-data-types");
|
|
354
|
-
const fixer = new DataTypeFixer();
|
|
355
|
-
await fixer.fixDataTypes();
|
|
356
|
-
console.log("Data type fixing completed successfully!");
|
|
357
|
-
|
|
358
355
|
// Step 6: Post-migration validation
|
|
359
356
|
if (!options.skipValidation) {
|
|
360
357
|
console.log("Step 6: Running post-migration validation...");
|
|
@@ -362,7 +359,9 @@ program
|
|
|
362
359
|
"./post-migration-validator"
|
|
363
360
|
);
|
|
364
361
|
const validator = new PostMigrationValidator();
|
|
365
|
-
const result = await validator.validate(
|
|
362
|
+
const result = await validator.validate({
|
|
363
|
+
publicOnly: options.mode === "public-only",
|
|
364
|
+
});
|
|
366
365
|
|
|
367
366
|
if (result.success) {
|
|
368
367
|
console.log("Post-migration validation successful!");
|
|
@@ -370,13 +369,30 @@ program
|
|
|
370
369
|
console.log(
|
|
371
370
|
`Post-migration validation found ${result.issueCount} issues.`
|
|
372
371
|
);
|
|
373
|
-
console.log(
|
|
372
|
+
console.log(JSON.stringify(result, null, 2));
|
|
373
|
+
|
|
374
|
+
if (!options.force) {
|
|
375
|
+
console.error(
|
|
376
|
+
"Migration validation failed. Use --force to continue anyway."
|
|
377
|
+
);
|
|
378
|
+
process.exit(1);
|
|
379
|
+
}
|
|
374
380
|
console.log(
|
|
375
|
-
"
|
|
381
|
+
"Continuing with migration despite validation issues (--force flag provided)"
|
|
376
382
|
);
|
|
377
383
|
}
|
|
378
384
|
}
|
|
379
385
|
|
|
386
|
+
// Step 7: Synchronize sequences (final step)
|
|
387
|
+
if (!options.skipSequenceSync) {
|
|
388
|
+
console.log("Step 7: Synchronizing database sequences...");
|
|
389
|
+
const sequenceSynchronizer = new SequenceSynchronizer(
|
|
390
|
+
process.env.DATABASE_URL
|
|
391
|
+
);
|
|
392
|
+
await sequenceSynchronizer.synchronizeSequences();
|
|
393
|
+
console.log("Database sequences synchronized successfully!");
|
|
394
|
+
}
|
|
395
|
+
|
|
380
396
|
console.log("Migration process completed successfully!");
|
|
381
397
|
} catch (error) {
|
|
382
398
|
console.error("Error running migration:", error);
|
|
@@ -537,7 +553,7 @@ program
|
|
|
537
553
|
console.log(
|
|
538
554
|
`Pre-migration validation found ${result.issueCount} issues.`
|
|
539
555
|
);
|
|
540
|
-
console.log(
|
|
556
|
+
console.log(JSON.stringify(result, null, 2));
|
|
541
557
|
|
|
542
558
|
// Si la opción --yes está activada, continuar automáticamente
|
|
543
559
|
if (options.yes) {
|
|
@@ -643,7 +659,7 @@ program
|
|
|
643
659
|
console.log(
|
|
644
660
|
`Post-migration validation found ${result.issueCount} issues.`
|
|
645
661
|
);
|
|
646
|
-
console.log(
|
|
662
|
+
console.log(JSON.stringify(result, null, 2));
|
|
647
663
|
}
|
|
648
664
|
} catch (error) {
|
|
649
665
|
console.error("Error during post-migration validation:", error);
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { Logger } from "@nestjs/common";
|
|
2
|
+
import { Pool } from "pg";
|
|
3
|
+
|
|
4
|
+
export class SequenceSynchronizer {
|
|
5
|
+
private readonly logger = new Logger("SequenceSynchronizer");
|
|
6
|
+
private readonly pool: Pool;
|
|
7
|
+
|
|
8
|
+
constructor(databaseUrl: string) {
|
|
9
|
+
this.pool = new Pool({
|
|
10
|
+
connectionString: databaseUrl,
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async synchronizeSequences(): Promise<void> {
|
|
15
|
+
try {
|
|
16
|
+
this.logger.log("Iniciando sincronización de secuencias");
|
|
17
|
+
|
|
18
|
+
// Obtener todas las tablas en la base de datos
|
|
19
|
+
const tables = await this.getTables();
|
|
20
|
+
this.logger.log(`Encontradas ${tables.length} tablas para procesar`);
|
|
21
|
+
|
|
22
|
+
// Procesar cada tabla
|
|
23
|
+
for (const table of tables) {
|
|
24
|
+
await this.synchronizeTableSequences(table);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
this.logger.log("Sincronización de secuencias completada con éxito");
|
|
28
|
+
} catch (error) {
|
|
29
|
+
this.logger.error(
|
|
30
|
+
`Error durante la sincronización de secuencias: ${error.message}`,
|
|
31
|
+
error.stack
|
|
32
|
+
);
|
|
33
|
+
throw error;
|
|
34
|
+
} finally {
|
|
35
|
+
await this.pool.end();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
private async getTables(): Promise<string[]> {
|
|
40
|
+
const query = `
|
|
41
|
+
SELECT table_name
|
|
42
|
+
FROM information_schema.tables
|
|
43
|
+
WHERE table_schema = 'public'
|
|
44
|
+
AND table_type = 'BASE TABLE'
|
|
45
|
+
`;
|
|
46
|
+
|
|
47
|
+
const result = await this.pool.query(query);
|
|
48
|
+
return result.rows.map((row) => row.table_name);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
private async synchronizeTableSequences(tableName: string): Promise<void> {
|
|
52
|
+
try {
|
|
53
|
+
// Verificar si la tabla tiene una columna id
|
|
54
|
+
const columns = await this.pool.query(
|
|
55
|
+
`
|
|
56
|
+
SELECT column_name
|
|
57
|
+
FROM information_schema.columns
|
|
58
|
+
WHERE table_name = $1
|
|
59
|
+
AND column_name = 'id'
|
|
60
|
+
`,
|
|
61
|
+
[tableName]
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
if (columns.rows.length === 0) {
|
|
65
|
+
this.logger.debug(
|
|
66
|
+
`La tabla ${tableName} no tiene columna id, omitiendo`
|
|
67
|
+
);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Verificar si existe una secuencia para esta tabla
|
|
72
|
+
const sequenceName = `${tableName}_id_seq`;
|
|
73
|
+
const sequences = await this.pool.query(
|
|
74
|
+
`
|
|
75
|
+
SELECT sequence_name
|
|
76
|
+
FROM information_schema.sequences
|
|
77
|
+
WHERE sequence_name = $1
|
|
78
|
+
`,
|
|
79
|
+
[sequenceName]
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
if (sequences.rows.length === 0) {
|
|
83
|
+
this.logger.debug(
|
|
84
|
+
`No se encontró secuencia para la tabla ${tableName}, omitiendo`
|
|
85
|
+
);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Obtener el máximo ID actual de la tabla
|
|
90
|
+
const maxResult = await this.pool.query(`
|
|
91
|
+
SELECT COALESCE(MAX(id), 0) as max_id FROM "${tableName}"
|
|
92
|
+
`);
|
|
93
|
+
const maxId = maxResult.rows[0].max_id;
|
|
94
|
+
|
|
95
|
+
// Obtener el valor actual de la secuencia
|
|
96
|
+
const currValResult = await this.pool.query(`
|
|
97
|
+
SELECT last_value FROM "${sequenceName}"
|
|
98
|
+
`);
|
|
99
|
+
const currVal = currValResult.rows[0].last_value;
|
|
100
|
+
|
|
101
|
+
this.logger.log(
|
|
102
|
+
`Tabla ${tableName}: ID Máximo = ${maxId}, Valor Actual de Secuencia = ${currVal}`
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
// Actualizar la secuencia solo si es necesario
|
|
106
|
+
if (currVal <= maxId) {
|
|
107
|
+
await this.pool.query(
|
|
108
|
+
`
|
|
109
|
+
SELECT setval($1, $2, true)
|
|
110
|
+
`,
|
|
111
|
+
[sequenceName, maxId]
|
|
112
|
+
);
|
|
113
|
+
this.logger.log(
|
|
114
|
+
`Actualizada secuencia para tabla ${tableName} a ${maxId}`
|
|
115
|
+
);
|
|
116
|
+
} else {
|
|
117
|
+
this.logger.log(
|
|
118
|
+
`La secuencia para la tabla ${tableName} ya está adelantada al ID máximo, no se requiere actualización`
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
} catch (error) {
|
|
122
|
+
this.logger.error(
|
|
123
|
+
`Error sincronizando secuencias para tabla ${tableName}: ${error.message}`
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
Warnings:
|
|
3
|
-
|
|
4
|
-
- You are about to drop the column `usersUser_id` on the `manual_payments` table. All the data in the column will be lost.
|
|
5
|
-
|
|
6
|
-
*/
|
|
7
|
-
-- DropForeignKey
|
|
8
|
-
ALTER TABLE "manual_payments" DROP CONSTRAINT "manual_payments_usersUser_id_fkey";
|
|
9
|
-
|
|
10
|
-
-- AlterTable
|
|
11
|
-
ALTER TABLE "manual_payments" DROP COLUMN "usersUser_id";
|
|
12
|
-
|
|
13
|
-
-- AddForeignKey
|
|
14
|
-
ALTER TABLE "manual_payments" ADD CONSTRAINT "manual_payments_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("user_id") ON DELETE RESTRICT ON UPDATE CASCADE;
|