@javalabs/prisma-client 1.0.4 → 1.0.6

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 (58) hide show
  1. package/dist/scripts/data-migration/batch-migrator.d.ts +14 -19
  2. package/dist/scripts/data-migration/batch-migrator.js +98 -297
  3. package/dist/scripts/data-migration/batch-migrator.js.map +1 -1
  4. package/dist/scripts/data-migration/data-transformer.d.ts +16 -7
  5. package/dist/scripts/data-migration/data-transformer.js +169 -133
  6. package/dist/scripts/data-migration/data-transformer.js.map +1 -1
  7. package/dist/scripts/data-migration/db-connector.d.ts +6 -1
  8. package/dist/scripts/data-migration/db-connector.js +44 -8
  9. package/dist/scripts/data-migration/db-connector.js.map +1 -1
  10. package/dist/scripts/data-migration/dependency-resolver.d.ts +10 -10
  11. package/dist/scripts/data-migration/dependency-resolver.js +92 -211
  12. package/dist/scripts/data-migration/dependency-resolver.js.map +1 -1
  13. package/dist/scripts/data-migration/foreign-key-manager.d.ts +6 -5
  14. package/dist/scripts/data-migration/foreign-key-manager.js +108 -18
  15. package/dist/scripts/data-migration/foreign-key-manager.js.map +1 -1
  16. package/dist/scripts/data-migration/migration-config.json +63 -0
  17. package/dist/scripts/data-migration/migration-tool.d.ts +25 -6
  18. package/dist/scripts/data-migration/migration-tool.js +78 -38
  19. package/dist/scripts/data-migration/migration-tool.js.map +1 -1
  20. package/dist/scripts/data-migration/multi-source-migrator.d.ts +17 -0
  21. package/dist/scripts/data-migration/multi-source-migrator.js +130 -0
  22. package/dist/scripts/data-migration/multi-source-migrator.js.map +1 -0
  23. package/dist/scripts/data-migration/schema-utils.d.ts +3 -3
  24. package/dist/scripts/data-migration/schema-utils.js +62 -19
  25. package/dist/scripts/data-migration/schema-utils.js.map +1 -1
  26. package/dist/scripts/data-migration/tenant-migrator.js +9 -2
  27. package/dist/scripts/data-migration/tenant-migrator.js.map +1 -1
  28. package/dist/scripts/data-migration/typecast-manager.d.ts +7 -3
  29. package/dist/scripts/data-migration/typecast-manager.js +169 -25
  30. package/dist/scripts/data-migration/typecast-manager.js.map +1 -1
  31. package/dist/scripts/data-migration/types.d.ts +68 -2
  32. package/dist/scripts/fix-table-indexes.d.ts +26 -0
  33. package/dist/scripts/fix-table-indexes.js +460 -0
  34. package/dist/scripts/fix-table-indexes.js.map +1 -0
  35. package/dist/scripts/multi-db-migration.d.ts +1 -0
  36. package/dist/scripts/multi-db-migration.js +55 -0
  37. package/dist/scripts/multi-db-migration.js.map +1 -0
  38. package/dist/scripts/run-migration.js +41 -75
  39. package/dist/scripts/run-migration.js.map +1 -1
  40. package/dist/tsconfig.tsbuildinfo +1 -1
  41. package/migration-config.json +40 -72
  42. package/{migration-config-public.json → migration-config.json.bk} +14 -14
  43. package/package.json +6 -3
  44. package/src/scripts/data-migration/batch-migrator.ts +192 -513
  45. package/src/scripts/data-migration/data-transformer.ts +252 -203
  46. package/src/scripts/data-migration/db-connector.ts +66 -13
  47. package/src/scripts/data-migration/dependency-resolver.ts +121 -266
  48. package/src/scripts/data-migration/foreign-key-manager.ts +214 -32
  49. package/src/scripts/data-migration/migration-config.json +63 -0
  50. package/src/scripts/data-migration/migration-tool.ts +377 -225
  51. package/src/scripts/data-migration/schema-utils.ts +94 -32
  52. package/src/scripts/data-migration/tenant-migrator.ts +12 -5
  53. package/src/scripts/data-migration/typecast-manager.ts +186 -31
  54. package/src/scripts/data-migration/types.ts +78 -5
  55. package/src/scripts/dumps/source_dump_20250428_145606.sql +323 -0
  56. package/src/scripts/fix-table-indexes.ts +602 -0
  57. package/src/scripts/post-migration-validator.ts +206 -107
  58. package/src/scripts/run-migration.ts +87 -101
@@ -4,6 +4,7 @@ import { DatabaseConnections } from "./types";
4
4
 
5
5
  export class ForeignKeyManager {
6
6
  private readonly logger = new Logger("ForeignKeyManager");
7
+ private readonly dependencyCache: Map<string, any[]> = new Map();
7
8
 
8
9
  constructor(private readonly connections: DatabaseConnections) {}
9
10
 
@@ -13,7 +14,15 @@ export class ForeignKeyManager {
13
14
  ): Promise<
14
15
  Array<{ column: string; foreignTable: string; foreignColumn: string }>
15
16
  > {
17
+ const cacheKey = `${schemaName}.${tableName}`;
18
+ if (this.dependencyCache.has(cacheKey)) {
19
+ return this.dependencyCache.get(cacheKey);
20
+ }
21
+
16
22
  try {
23
+ this.logger.log(
24
+ `Obteniendo dependencias de llaves foráneas para ${schemaName}.${tableName}`
25
+ );
17
26
  const query = `
18
27
  SELECT
19
28
  kcu.column_name,
@@ -37,14 +46,29 @@ export class ForeignKeyManager {
37
46
  schemaName,
38
47
  tableName,
39
48
  ]);
40
- return rows.map((row) => ({
49
+
50
+ const dependencies = rows.map((row) => ({
41
51
  column: row.column_name,
42
52
  foreignTable: row.foreign_table_name,
43
53
  foreignColumn: row.foreign_column_name,
44
54
  }));
55
+
56
+ this.logger.log(
57
+ `Encontradas ${
58
+ dependencies.length
59
+ } dependencias para ${schemaName}.${tableName}:
60
+ ${dependencies
61
+ .map(
62
+ (d) => `\n - ${d.column} -> ${d.foreignTable}.${d.foreignColumn}`
63
+ )
64
+ .join("")}`
65
+ );
66
+
67
+ this.dependencyCache.set(cacheKey, dependencies);
68
+ return dependencies;
45
69
  } catch (error) {
46
70
  this.logger.error(
47
- `Error getting foreign key dependencies for ${tableName}: ${error.message}`
71
+ `Error obteniendo dependencias de ${schemaName}.${tableName}: ${error.message}`
48
72
  );
49
73
  return [];
50
74
  }
@@ -52,44 +76,202 @@ export class ForeignKeyManager {
52
76
 
53
77
  async checkForeignKeyDependencies(
54
78
  prisma: PrismaClient,
55
- schemaName: string,
56
- row: any,
57
- dependencies: Array<{
58
- column: string;
59
- foreignTable: string;
60
- foreignColumn: string;
61
- }>
79
+ tenantId: string,
80
+ record: any,
81
+ dependencies: any[]
62
82
  ): Promise<string[]> {
63
83
  const missingDependencies: string[] = [];
84
+ const recordId = record.id || "unknown";
85
+
86
+ this.logger.debug(
87
+ `Verificando dependencias para registro ${recordId} en tenant ${tenantId}`
88
+ );
64
89
 
65
90
  for (const dep of dependencies) {
66
- if (row[dep.column] !== null) {
67
- const query = `
68
- SELECT 1 FROM "${schemaName}"."${dep.foreignTable}"
69
- WHERE "${dep.foreignColumn}" = $1
70
- LIMIT 1
71
- `;
72
-
73
- try {
74
- const result = await prisma.$queryRawUnsafe(query, row[dep.column]);
75
- if (!result || (Array.isArray(result) && result.length === 0)) {
76
- missingDependencies.push(
77
- `${dep.foreignTable}.${dep.foreignColumn}=${row[dep.column]}`
78
- );
79
- }
80
- } catch (error) {
81
- this.logger.error(
82
- `Error checking dependency ${dep.foreignTable}.${dep.foreignColumn}: ${error.message}`
91
+ const { table, column, references } = dep;
92
+ const foreignKeyValue = record[column];
93
+
94
+ if (foreignKeyValue === null) {
95
+ this.logger.debug(
96
+ `Dependencia ${table}.${references} es nula para registro ${recordId}, continuando`
97
+ );
98
+ continue;
99
+ }
100
+
101
+ // Verificar en origen
102
+ const sourceExists = await this.checkSourceDependency(
103
+ table,
104
+ references,
105
+ foreignKeyValue
106
+ );
107
+
108
+ if (!sourceExists) {
109
+ this.logger.debug(
110
+ `Registro ${recordId}: Dependencia ${table}.${references}=${foreignKeyValue} no existe en origen, ignorando`
111
+ );
112
+ continue;
113
+ }
114
+
115
+ // Verificar en destino
116
+ const exists = await this.checkDependencyExists(
117
+ prisma,
118
+ tenantId,
119
+ table,
120
+ references,
121
+ foreignKeyValue
122
+ );
123
+
124
+ if (!exists) {
125
+ const depString = `${table}.${references}=${foreignKeyValue}`;
126
+ this.logger.debug(
127
+ `Registro ${recordId}: Dependencia ${depString} existe en origen pero falta en destino`
128
+ );
129
+ missingDependencies.push(depString);
130
+ } else {
131
+ this.logger.debug(
132
+ `Registro ${recordId}: Dependencia ${table}.${references}=${foreignKeyValue} verificada OK`
133
+ );
134
+ }
135
+ }
136
+
137
+ if (missingDependencies.length > 0) {
138
+ this.logger.debug(
139
+ `Registro ${recordId}: Faltan ${
140
+ missingDependencies.length
141
+ } dependencias:
142
+ ${missingDependencies.map((dep) => `\n - ${dep}`).join("")}`
143
+ );
144
+ } else {
145
+ this.logger.debug(`Registro ${recordId}: Todas las dependencias OK`);
146
+ }
147
+
148
+ return missingDependencies;
149
+ }
150
+
151
+ private async checkSourceDependency(
152
+ table: string,
153
+ column: string,
154
+ value: any
155
+ ): Promise<boolean> {
156
+ try {
157
+ const result = await this.connections.sourcePool.query(
158
+ `SELECT 1 FROM "${table}" WHERE "${column}" = $1 LIMIT 1`,
159
+ [value]
160
+ );
161
+ const exists = result.rows.length > 0;
162
+ this.logger.debug(
163
+ `Verificación en origen ${table}.${column}=${value}: ${
164
+ exists ? "EXISTE" : "NO EXISTE"
165
+ }`
166
+ );
167
+ return exists;
168
+ } catch (error) {
169
+ this.logger.error(
170
+ `Error verificando en origen ${table}.${column}=${value}: ${error.message}`
171
+ );
172
+ return false;
173
+ }
174
+ }
175
+
176
+ private async checkDependencyExists(
177
+ prisma: PrismaClient,
178
+ tenantId: string,
179
+ table: string,
180
+ column: string,
181
+ value: any
182
+ ): Promise<boolean> {
183
+ try {
184
+ const result = await prisma.$queryRawUnsafe(
185
+ `SELECT 1 FROM "${tenantId}"."${table}" WHERE "${column}" = $1 LIMIT 1`,
186
+ value
187
+ );
188
+ const exists = Array.isArray(result) && result.length > 0;
189
+ this.logger.debug(
190
+ `Verificación en destino ${tenantId}.${table}.${column}=${value}: ${
191
+ exists ? "EXISTE" : "NO EXISTE"
192
+ }`
193
+ );
194
+ return exists;
195
+ } catch (error) {
196
+ this.logger.error(
197
+ `Error verificando en destino ${tenantId}.${table}.${column}=${value}: ${error.message}`
198
+ );
199
+ return false;
200
+ }
201
+ }
202
+
203
+ async verifyDependencies(
204
+ tableName: string,
205
+ record: any,
206
+ tenantId: string
207
+ ): Promise<boolean> {
208
+ try {
209
+ const dependencies = await this.getForeignKeyDependencies(
210
+ tableName,
211
+ tableName
212
+ );
213
+
214
+ for (const dep of dependencies) {
215
+ const { foreignTable, foreignColumn } = dep;
216
+
217
+ // Verificar si la tabla existe antes de hacer la consulta
218
+ const tableExists = await this.checkTableExists(foreignTable);
219
+ if (!tableExists) {
220
+ this.logger.warn(
221
+ `Table ${foreignTable} does not exist, skipping dependency check`
83
222
  );
84
- missingDependencies.push(
85
- `${dep.foreignTable}.${dep.foreignColumn}=${
86
- row[dep.column]
87
- } (error)`
223
+ continue;
224
+ }
225
+
226
+ // Verificar el valor de la dependencia
227
+ const foreignKeyValue = record[foreignColumn];
228
+ if (foreignKeyValue) {
229
+ const exists = await this.checkDependencyExists(
230
+ this.connections.targetPrisma,
231
+ tenantId,
232
+ foreignTable,
233
+ foreignColumn,
234
+ foreignKeyValue
88
235
  );
236
+
237
+ if (!exists) {
238
+ this.logger.warn(
239
+ `Valor ${foreignKeyValue} no existe en ${foreignTable}.${foreignColumn}`
240
+ );
241
+ return false;
242
+ }
89
243
  }
90
244
  }
245
+
246
+ return true;
247
+ } catch (error) {
248
+ this.logger.error(`Error verifying dependencies: ${error.message}`);
249
+ return false;
91
250
  }
251
+ }
92
252
 
93
- return missingDependencies;
253
+ private async checkTableExists(tableName: string): Promise<boolean> {
254
+ try {
255
+ const result = await this.connections.sourcePool.query(
256
+ `SELECT EXISTS (
257
+ SELECT FROM information_schema.tables
258
+ WHERE table_schema = 'public'
259
+ AND table_name = $1
260
+ )`,
261
+ [tableName]
262
+ );
263
+ const exists = result.rows[0].exists;
264
+ this.logger.debug(
265
+ `Verificación de existencia de tabla ${tableName}: ${
266
+ exists ? "EXISTE" : "NO EXISTE"
267
+ }`
268
+ );
269
+ return exists;
270
+ } catch (error) {
271
+ this.logger.error(
272
+ `Error verificando existencia de tabla ${tableName}: ${error.message}`
273
+ );
274
+ return false;
275
+ }
94
276
  }
95
- }
277
+ }
@@ -0,0 +1,63 @@
1
+ {
2
+ "commonSchema": "public",
3
+ "tenantInfo": {
4
+ "sourceTable": "users",
5
+ "tenantIdColumn": "user_id",
6
+ "providerIdColumn": "provider_id"
7
+ },
8
+ "migrationPriorities": {
9
+ "high": ["countries", "providers", "users", "api_keys"],
10
+ "medium": ["transactions", "charges", "balances"],
11
+ "low": ["invoices", "api_request_logs"]
12
+ },
13
+ "tables": {
14
+ "countries": {
15
+ "type": "public",
16
+ "idField": "id"
17
+ },
18
+ "providers": {
19
+ "type": "public",
20
+ "idField": "provider_id",
21
+ "dependencies": ["countries"]
22
+ },
23
+ "users": {
24
+ "type": "public",
25
+ "idField": "user_id",
26
+ "dependencies": ["providers"]
27
+ },
28
+ "api_keys": {
29
+ "type": "public",
30
+ "idField": "id",
31
+ "dependencies": ["users"]
32
+ },
33
+ "transactions": {
34
+ "type": "filteredPublic",
35
+ "idField": "id",
36
+ "filterColumn": "provider_id",
37
+ "dependencies": ["users", "providers"]
38
+ },
39
+ "charges": {
40
+ "type": "filteredPublic",
41
+ "idField": "id",
42
+ "filterColumn": "provider_id",
43
+ "dependencies": ["transactions"]
44
+ },
45
+ "invoices": {
46
+ "type": "filteredPublic",
47
+ "idField": "id",
48
+ "filterColumn": "provider_id",
49
+ "dependencies": ["transactions", "charges"]
50
+ },
51
+ "balances": {
52
+ "type": "filteredPublic",
53
+ "idField": "id",
54
+ "filterColumn": "provider_id",
55
+ "dependencies": ["users"]
56
+ },
57
+ "api_request_logs": {
58
+ "type": "filteredPublic",
59
+ "idField": "id",
60
+ "dependencies": ["api_keys"]
61
+ }
62
+ }
63
+ }