@javalabs/prisma-client 1.0.27 → 1.0.29
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/.github/CODEOWNERS +1 -1
- package/README.md +269 -269
- package/migration-config.json +63 -63
- package/migration-config.json.bk +95 -95
- package/migrations/add_reserved_amount.sql +7 -7
- package/package.json +44 -44
- package/prisma/migrations/add_uuid_to_transactions.sql +13 -13
- package/prisma/schema.prisma +609 -601
- package/src/index.ts +23 -23
- package/src/prisma-factory.service.ts +40 -40
- package/src/prisma.module.ts +9 -9
- package/src/prisma.service.ts +16 -16
- package/src/scripts/add-uuid-to-table.ts +138 -138
- package/src/scripts/create-tenant-schemas.ts +145 -145
- package/src/scripts/data-migration/batch-migrator.ts +248 -248
- package/src/scripts/data-migration/data-transformer.ts +426 -426
- package/src/scripts/data-migration/db-connector.ts +120 -120
- package/src/scripts/data-migration/dependency-resolver.ts +174 -174
- package/src/scripts/data-migration/entity-discovery.ts +196 -196
- package/src/scripts/data-migration/foreign-key-manager.ts +277 -277
- package/src/scripts/data-migration/migration-config.json +63 -63
- package/src/scripts/data-migration/migration-tool.ts +509 -509
- package/src/scripts/data-migration/schema-utils.ts +248 -248
- package/src/scripts/data-migration/tenant-migrator.ts +201 -201
- package/src/scripts/data-migration/typecast-manager.ts +193 -193
- package/src/scripts/data-migration/types.ts +113 -113
- package/src/scripts/database-initializer.ts +49 -49
- package/src/scripts/drop-database.ts +104 -104
- package/src/scripts/dump-source-db.sh +61 -61
- package/src/scripts/encrypt-user-passwords.ts +36 -36
- package/src/scripts/error-handler.ts +117 -117
- package/src/scripts/fix-data-types.ts +241 -241
- package/src/scripts/fix-enum-values.ts +357 -357
- package/src/scripts/fix-schema-discrepancies.ts +317 -317
- package/src/scripts/fix-table-indexes.ts +601 -601
- package/src/scripts/migrate-schema-structure.ts +90 -90
- package/src/scripts/migrate-uuid.ts +76 -76
- package/src/scripts/post-migration-validator.ts +526 -526
- package/src/scripts/pre-migration-validator.ts +610 -610
- package/src/scripts/reset-database.ts +263 -263
- package/src/scripts/retry-failed-migrations.ts +416 -416
- package/src/scripts/run-migration.ts +707 -707
- package/src/scripts/schema-sync.ts +128 -128
- package/src/scripts/sequence-sync-cli.ts +416 -416
- package/src/scripts/sequence-synchronizer.ts +127 -127
- package/src/scripts/sync-enum-types.ts +170 -170
- package/src/scripts/sync-enum-values.ts +563 -563
- package/src/scripts/truncate-database.ts +123 -123
- package/src/scripts/verify-migration-setup.ts +135 -135
- package/tsconfig.json +17 -17
|
@@ -1,242 +1,242 @@
|
|
|
1
|
-
import { PrismaClient } from "@prisma/client";
|
|
2
|
-
import * as dotenv from "dotenv";
|
|
3
|
-
import { Logger } from "@nestjs/common";
|
|
4
|
-
import * as pg from "pg";
|
|
5
|
-
|
|
6
|
-
dotenv.config();
|
|
7
|
-
|
|
8
|
-
export class DataTypeFixer {
|
|
9
|
-
private readonly logger = new Logger("DataTypeFixer");
|
|
10
|
-
private readonly sourcePool: pg.Pool;
|
|
11
|
-
private readonly targetPool: pg.Pool;
|
|
12
|
-
|
|
13
|
-
constructor() {
|
|
14
|
-
// Source database connection
|
|
15
|
-
this.sourcePool = new pg.Pool({
|
|
16
|
-
connectionString: process.env.SOURCE_DATABASE_URL,
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
// Target database connection
|
|
20
|
-
this.targetPool = new pg.Pool({
|
|
21
|
-
connectionString: process.env.DATABASE_URL,
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
async fixDataTypes() {
|
|
26
|
-
try {
|
|
27
|
-
this.logger.log("Starting data type fixing process");
|
|
28
|
-
|
|
29
|
-
// Get all schemas (tenants) from the target database
|
|
30
|
-
const schemasQuery = `
|
|
31
|
-
SELECT schema_name
|
|
32
|
-
FROM information_schema.schemata
|
|
33
|
-
WHERE schema_name NOT IN ('public', 'information_schema', 'pg_catalog', 'pg_toast')
|
|
34
|
-
AND schema_name NOT LIKE 'pg_%';
|
|
35
|
-
`;
|
|
36
|
-
|
|
37
|
-
const schemasResult = await this.targetPool.query(schemasQuery);
|
|
38
|
-
const schemas = schemasResult.rows.map(row => row.schema_name);
|
|
39
|
-
|
|
40
|
-
this.logger.log(`Found ${schemas.length} schemas to process`);
|
|
41
|
-
|
|
42
|
-
// Process each schema
|
|
43
|
-
for (const schema of schemas) {
|
|
44
|
-
await this.fixNumericFieldsForSchema(schema);
|
|
45
|
-
await this.fixEnumFieldsForSchema(schema);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
this.logger.log("Data type fixing completed successfully");
|
|
49
|
-
} catch (error) {
|
|
50
|
-
this.logger.error(
|
|
51
|
-
`Error during data type fixing: ${error.message}`,
|
|
52
|
-
error.stack
|
|
53
|
-
);
|
|
54
|
-
} finally {
|
|
55
|
-
await this.cleanup();
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
private async fixNumericFieldsForSchema(schema: string) {
|
|
60
|
-
this.logger.log(`Processing numeric fields for schema: ${schema}`);
|
|
61
|
-
|
|
62
|
-
try {
|
|
63
|
-
// Get all tables with numeric columns in this schema
|
|
64
|
-
const numericColumnsQuery = `
|
|
65
|
-
SELECT
|
|
66
|
-
table_name,
|
|
67
|
-
column_name
|
|
68
|
-
FROM
|
|
69
|
-
information_schema.columns
|
|
70
|
-
WHERE
|
|
71
|
-
table_schema = $1
|
|
72
|
-
AND data_type = 'numeric'
|
|
73
|
-
`;
|
|
74
|
-
|
|
75
|
-
const numericColumnsResult = await this.targetPool.query(numericColumnsQuery, [schema]);
|
|
76
|
-
|
|
77
|
-
// Process each table with numeric columns
|
|
78
|
-
for (const row of numericColumnsResult.rows) {
|
|
79
|
-
const tableName = row.table_name;
|
|
80
|
-
const columnName = row.column_name;
|
|
81
|
-
|
|
82
|
-
this.logger.log(`Fixing numeric column ${columnName} in table ${schema}.${tableName}`);
|
|
83
|
-
|
|
84
|
-
// Update the column to cast text values to numeric
|
|
85
|
-
const updateQuery = `
|
|
86
|
-
UPDATE "${schema}"."${tableName}"
|
|
87
|
-
SET "${columnName}" = CASE
|
|
88
|
-
WHEN "${columnName}" IS NULL THEN NULL
|
|
89
|
-
WHEN "${columnName}" = '' THEN NULL
|
|
90
|
-
ELSE CAST("${columnName}" AS NUMERIC)
|
|
91
|
-
END
|
|
92
|
-
WHERE "${columnName}" IS NOT NULL
|
|
93
|
-
AND "${columnName}" != ''
|
|
94
|
-
AND "${columnName}" ~ '^[0-9]+(\.[0-9]+)?$';
|
|
95
|
-
`;
|
|
96
|
-
|
|
97
|
-
try {
|
|
98
|
-
await this.targetPool.query(updateQuery);
|
|
99
|
-
this.logger.log(`Successfully fixed numeric column ${columnName} in table ${schema}.${tableName}`);
|
|
100
|
-
} catch (updateError) {
|
|
101
|
-
this.logger.error(
|
|
102
|
-
`Error fixing numeric column ${columnName} in table ${schema}.${tableName}: ${updateError.message}`
|
|
103
|
-
);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
this.logger.log(`Completed processing numeric fields for schema: ${schema}`);
|
|
108
|
-
} catch (error) {
|
|
109
|
-
this.logger.error(
|
|
110
|
-
`Error processing numeric fields for schema ${schema}: ${error.message}`,
|
|
111
|
-
error.stack
|
|
112
|
-
);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
private async fixEnumFieldsForSchema(schema: string) {
|
|
117
|
-
this.logger.log(`Processing enum fields for schema: ${schema}`);
|
|
118
|
-
|
|
119
|
-
try {
|
|
120
|
-
// Get all tables with enum columns in this schema
|
|
121
|
-
const enumColumnsQuery = `
|
|
122
|
-
SELECT
|
|
123
|
-
c.table_name,
|
|
124
|
-
c.column_name,
|
|
125
|
-
c.udt_name
|
|
126
|
-
FROM
|
|
127
|
-
information_schema.columns c
|
|
128
|
-
WHERE
|
|
129
|
-
c.table_schema = $1
|
|
130
|
-
AND c.data_type = 'USER-DEFINED'
|
|
131
|
-
AND c.udt_name LIKE 'enum_%'
|
|
132
|
-
`;
|
|
133
|
-
|
|
134
|
-
const enumColumnsResult = await this.targetPool.query(enumColumnsQuery, [schema]);
|
|
135
|
-
|
|
136
|
-
// Process each table with enum columns
|
|
137
|
-
for (const row of enumColumnsResult.rows) {
|
|
138
|
-
const tableName = row.table_name;
|
|
139
|
-
const columnName = row.column_name;
|
|
140
|
-
const enumTypeName = row.udt_name;
|
|
141
|
-
|
|
142
|
-
this.logger.log(`Fixing enum column ${columnName} (${enumTypeName}) in table ${schema}.${tableName}`);
|
|
143
|
-
|
|
144
|
-
// Get the valid enum values
|
|
145
|
-
const enumValuesQuery = `
|
|
146
|
-
SELECT e.enumlabel
|
|
147
|
-
FROM pg_enum e
|
|
148
|
-
JOIN pg_type t ON e.enumtypid = t.oid
|
|
149
|
-
WHERE t.typname = $1
|
|
150
|
-
ORDER BY e.enumsortorder
|
|
151
|
-
`;
|
|
152
|
-
|
|
153
|
-
const enumValuesResult = await this.targetPool.query(enumValuesQuery, [enumTypeName]);
|
|
154
|
-
const validEnumValues = enumValuesResult.rows.map(r => r.enumlabel);
|
|
155
|
-
|
|
156
|
-
if (validEnumValues.length === 0) {
|
|
157
|
-
this.logger.warn(`No enum values found for type ${enumTypeName}. Skipping.`);
|
|
158
|
-
continue;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
this.logger.log(`Valid values for ${enumTypeName}: ${validEnumValues.join(', ')}`);
|
|
162
|
-
|
|
163
|
-
// Get current values in the column
|
|
164
|
-
const currentValuesQuery = `
|
|
165
|
-
SELECT DISTINCT "${columnName}"
|
|
166
|
-
FROM "${schema}"."${tableName}"
|
|
167
|
-
WHERE "${columnName}" IS NOT NULL
|
|
168
|
-
`;
|
|
169
|
-
|
|
170
|
-
const currentValuesResult = await this.targetPool.query(currentValuesQuery);
|
|
171
|
-
const currentValues = currentValuesResult.rows.map(r => r[columnName]);
|
|
172
|
-
|
|
173
|
-
// Find invalid values
|
|
174
|
-
const invalidValues = currentValues.filter(val => !validEnumValues.includes(val));
|
|
175
|
-
|
|
176
|
-
if (invalidValues.length > 0) {
|
|
177
|
-
this.logger.log(`Found invalid values for enum ${enumTypeName}: ${invalidValues.join(', ')}`);
|
|
178
|
-
|
|
179
|
-
// For each invalid value, try to map it to a valid one or set to NULL
|
|
180
|
-
for (const invalidValue of invalidValues) {
|
|
181
|
-
// Try to find a case-insensitive match
|
|
182
|
-
const matchingValidValue = validEnumValues.find(
|
|
183
|
-
v => v.toLowerCase() === invalidValue.toLowerCase()
|
|
184
|
-
);
|
|
185
|
-
|
|
186
|
-
let updateQuery;
|
|
187
|
-
if (matchingValidValue) {
|
|
188
|
-
// If we found a case-insensitive match, use it
|
|
189
|
-
updateQuery = `
|
|
190
|
-
UPDATE "${schema}"."${tableName}"
|
|
191
|
-
SET "${columnName}" = $1
|
|
192
|
-
WHERE "${columnName}" = $2
|
|
193
|
-
`;
|
|
194
|
-
await this.targetPool.query(updateQuery, [matchingValidValue, invalidValue]);
|
|
195
|
-
this.logger.log(`Updated invalid value "${invalidValue}" to "${matchingValidValue}"`);
|
|
196
|
-
} else {
|
|
197
|
-
// Otherwise set to NULL or default value
|
|
198
|
-
updateQuery = `
|
|
199
|
-
UPDATE "${schema}"."${tableName}"
|
|
200
|
-
SET "${columnName}" = NULL
|
|
201
|
-
WHERE "${columnName}" = $1
|
|
202
|
-
`;
|
|
203
|
-
await this.targetPool.query(updateQuery, [invalidValue]);
|
|
204
|
-
this.logger.log(`Set invalid value "${invalidValue}" to NULL`);
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
} else {
|
|
208
|
-
this.logger.log(`No invalid enum values found for ${columnName} in ${schema}.${tableName}`);
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
this.logger.log(`Completed processing enum fields for schema: ${schema}`);
|
|
213
|
-
} catch (error) {
|
|
214
|
-
this.logger.error(
|
|
215
|
-
`Error processing enum fields for schema ${schema}: ${error.message}`,
|
|
216
|
-
error.stack
|
|
217
|
-
);
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
private async cleanup() {
|
|
222
|
-
this.logger.log("Cleaning up database connections");
|
|
223
|
-
await this.sourcePool.end();
|
|
224
|
-
await this.targetPool.end();
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
// Script para ejecutar desde línea de comandos
|
|
229
|
-
if (require.main === module) {
|
|
230
|
-
const run = async () => {
|
|
231
|
-
try {
|
|
232
|
-
const fixer = new DataTypeFixer();
|
|
233
|
-
await fixer.fixDataTypes();
|
|
234
|
-
process.exit(0);
|
|
235
|
-
} catch (error) {
|
|
236
|
-
console.error("Error:", error.message);
|
|
237
|
-
process.exit(1);
|
|
238
|
-
}
|
|
239
|
-
};
|
|
240
|
-
|
|
241
|
-
run();
|
|
1
|
+
import { PrismaClient } from "@prisma/client";
|
|
2
|
+
import * as dotenv from "dotenv";
|
|
3
|
+
import { Logger } from "@nestjs/common";
|
|
4
|
+
import * as pg from "pg";
|
|
5
|
+
|
|
6
|
+
dotenv.config();
|
|
7
|
+
|
|
8
|
+
export class DataTypeFixer {
|
|
9
|
+
private readonly logger = new Logger("DataTypeFixer");
|
|
10
|
+
private readonly sourcePool: pg.Pool;
|
|
11
|
+
private readonly targetPool: pg.Pool;
|
|
12
|
+
|
|
13
|
+
constructor() {
|
|
14
|
+
// Source database connection
|
|
15
|
+
this.sourcePool = new pg.Pool({
|
|
16
|
+
connectionString: process.env.SOURCE_DATABASE_URL,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
// Target database connection
|
|
20
|
+
this.targetPool = new pg.Pool({
|
|
21
|
+
connectionString: process.env.DATABASE_URL,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async fixDataTypes() {
|
|
26
|
+
try {
|
|
27
|
+
this.logger.log("Starting data type fixing process");
|
|
28
|
+
|
|
29
|
+
// Get all schemas (tenants) from the target database
|
|
30
|
+
const schemasQuery = `
|
|
31
|
+
SELECT schema_name
|
|
32
|
+
FROM information_schema.schemata
|
|
33
|
+
WHERE schema_name NOT IN ('public', 'information_schema', 'pg_catalog', 'pg_toast')
|
|
34
|
+
AND schema_name NOT LIKE 'pg_%';
|
|
35
|
+
`;
|
|
36
|
+
|
|
37
|
+
const schemasResult = await this.targetPool.query(schemasQuery);
|
|
38
|
+
const schemas = schemasResult.rows.map(row => row.schema_name);
|
|
39
|
+
|
|
40
|
+
this.logger.log(`Found ${schemas.length} schemas to process`);
|
|
41
|
+
|
|
42
|
+
// Process each schema
|
|
43
|
+
for (const schema of schemas) {
|
|
44
|
+
await this.fixNumericFieldsForSchema(schema);
|
|
45
|
+
await this.fixEnumFieldsForSchema(schema);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
this.logger.log("Data type fixing completed successfully");
|
|
49
|
+
} catch (error) {
|
|
50
|
+
this.logger.error(
|
|
51
|
+
`Error during data type fixing: ${error.message}`,
|
|
52
|
+
error.stack
|
|
53
|
+
);
|
|
54
|
+
} finally {
|
|
55
|
+
await this.cleanup();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
private async fixNumericFieldsForSchema(schema: string) {
|
|
60
|
+
this.logger.log(`Processing numeric fields for schema: ${schema}`);
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
// Get all tables with numeric columns in this schema
|
|
64
|
+
const numericColumnsQuery = `
|
|
65
|
+
SELECT
|
|
66
|
+
table_name,
|
|
67
|
+
column_name
|
|
68
|
+
FROM
|
|
69
|
+
information_schema.columns
|
|
70
|
+
WHERE
|
|
71
|
+
table_schema = $1
|
|
72
|
+
AND data_type = 'numeric'
|
|
73
|
+
`;
|
|
74
|
+
|
|
75
|
+
const numericColumnsResult = await this.targetPool.query(numericColumnsQuery, [schema]);
|
|
76
|
+
|
|
77
|
+
// Process each table with numeric columns
|
|
78
|
+
for (const row of numericColumnsResult.rows) {
|
|
79
|
+
const tableName = row.table_name;
|
|
80
|
+
const columnName = row.column_name;
|
|
81
|
+
|
|
82
|
+
this.logger.log(`Fixing numeric column ${columnName} in table ${schema}.${tableName}`);
|
|
83
|
+
|
|
84
|
+
// Update the column to cast text values to numeric
|
|
85
|
+
const updateQuery = `
|
|
86
|
+
UPDATE "${schema}"."${tableName}"
|
|
87
|
+
SET "${columnName}" = CASE
|
|
88
|
+
WHEN "${columnName}" IS NULL THEN NULL
|
|
89
|
+
WHEN "${columnName}" = '' THEN NULL
|
|
90
|
+
ELSE CAST("${columnName}" AS NUMERIC)
|
|
91
|
+
END
|
|
92
|
+
WHERE "${columnName}" IS NOT NULL
|
|
93
|
+
AND "${columnName}" != ''
|
|
94
|
+
AND "${columnName}" ~ '^[0-9]+(\.[0-9]+)?$';
|
|
95
|
+
`;
|
|
96
|
+
|
|
97
|
+
try {
|
|
98
|
+
await this.targetPool.query(updateQuery);
|
|
99
|
+
this.logger.log(`Successfully fixed numeric column ${columnName} in table ${schema}.${tableName}`);
|
|
100
|
+
} catch (updateError) {
|
|
101
|
+
this.logger.error(
|
|
102
|
+
`Error fixing numeric column ${columnName} in table ${schema}.${tableName}: ${updateError.message}`
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
this.logger.log(`Completed processing numeric fields for schema: ${schema}`);
|
|
108
|
+
} catch (error) {
|
|
109
|
+
this.logger.error(
|
|
110
|
+
`Error processing numeric fields for schema ${schema}: ${error.message}`,
|
|
111
|
+
error.stack
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
private async fixEnumFieldsForSchema(schema: string) {
|
|
117
|
+
this.logger.log(`Processing enum fields for schema: ${schema}`);
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
// Get all tables with enum columns in this schema
|
|
121
|
+
const enumColumnsQuery = `
|
|
122
|
+
SELECT
|
|
123
|
+
c.table_name,
|
|
124
|
+
c.column_name,
|
|
125
|
+
c.udt_name
|
|
126
|
+
FROM
|
|
127
|
+
information_schema.columns c
|
|
128
|
+
WHERE
|
|
129
|
+
c.table_schema = $1
|
|
130
|
+
AND c.data_type = 'USER-DEFINED'
|
|
131
|
+
AND c.udt_name LIKE 'enum_%'
|
|
132
|
+
`;
|
|
133
|
+
|
|
134
|
+
const enumColumnsResult = await this.targetPool.query(enumColumnsQuery, [schema]);
|
|
135
|
+
|
|
136
|
+
// Process each table with enum columns
|
|
137
|
+
for (const row of enumColumnsResult.rows) {
|
|
138
|
+
const tableName = row.table_name;
|
|
139
|
+
const columnName = row.column_name;
|
|
140
|
+
const enumTypeName = row.udt_name;
|
|
141
|
+
|
|
142
|
+
this.logger.log(`Fixing enum column ${columnName} (${enumTypeName}) in table ${schema}.${tableName}`);
|
|
143
|
+
|
|
144
|
+
// Get the valid enum values
|
|
145
|
+
const enumValuesQuery = `
|
|
146
|
+
SELECT e.enumlabel
|
|
147
|
+
FROM pg_enum e
|
|
148
|
+
JOIN pg_type t ON e.enumtypid = t.oid
|
|
149
|
+
WHERE t.typname = $1
|
|
150
|
+
ORDER BY e.enumsortorder
|
|
151
|
+
`;
|
|
152
|
+
|
|
153
|
+
const enumValuesResult = await this.targetPool.query(enumValuesQuery, [enumTypeName]);
|
|
154
|
+
const validEnumValues = enumValuesResult.rows.map(r => r.enumlabel);
|
|
155
|
+
|
|
156
|
+
if (validEnumValues.length === 0) {
|
|
157
|
+
this.logger.warn(`No enum values found for type ${enumTypeName}. Skipping.`);
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
this.logger.log(`Valid values for ${enumTypeName}: ${validEnumValues.join(', ')}`);
|
|
162
|
+
|
|
163
|
+
// Get current values in the column
|
|
164
|
+
const currentValuesQuery = `
|
|
165
|
+
SELECT DISTINCT "${columnName}"
|
|
166
|
+
FROM "${schema}"."${tableName}"
|
|
167
|
+
WHERE "${columnName}" IS NOT NULL
|
|
168
|
+
`;
|
|
169
|
+
|
|
170
|
+
const currentValuesResult = await this.targetPool.query(currentValuesQuery);
|
|
171
|
+
const currentValues = currentValuesResult.rows.map(r => r[columnName]);
|
|
172
|
+
|
|
173
|
+
// Find invalid values
|
|
174
|
+
const invalidValues = currentValues.filter(val => !validEnumValues.includes(val));
|
|
175
|
+
|
|
176
|
+
if (invalidValues.length > 0) {
|
|
177
|
+
this.logger.log(`Found invalid values for enum ${enumTypeName}: ${invalidValues.join(', ')}`);
|
|
178
|
+
|
|
179
|
+
// For each invalid value, try to map it to a valid one or set to NULL
|
|
180
|
+
for (const invalidValue of invalidValues) {
|
|
181
|
+
// Try to find a case-insensitive match
|
|
182
|
+
const matchingValidValue = validEnumValues.find(
|
|
183
|
+
v => v.toLowerCase() === invalidValue.toLowerCase()
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
let updateQuery;
|
|
187
|
+
if (matchingValidValue) {
|
|
188
|
+
// If we found a case-insensitive match, use it
|
|
189
|
+
updateQuery = `
|
|
190
|
+
UPDATE "${schema}"."${tableName}"
|
|
191
|
+
SET "${columnName}" = $1
|
|
192
|
+
WHERE "${columnName}" = $2
|
|
193
|
+
`;
|
|
194
|
+
await this.targetPool.query(updateQuery, [matchingValidValue, invalidValue]);
|
|
195
|
+
this.logger.log(`Updated invalid value "${invalidValue}" to "${matchingValidValue}"`);
|
|
196
|
+
} else {
|
|
197
|
+
// Otherwise set to NULL or default value
|
|
198
|
+
updateQuery = `
|
|
199
|
+
UPDATE "${schema}"."${tableName}"
|
|
200
|
+
SET "${columnName}" = NULL
|
|
201
|
+
WHERE "${columnName}" = $1
|
|
202
|
+
`;
|
|
203
|
+
await this.targetPool.query(updateQuery, [invalidValue]);
|
|
204
|
+
this.logger.log(`Set invalid value "${invalidValue}" to NULL`);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
} else {
|
|
208
|
+
this.logger.log(`No invalid enum values found for ${columnName} in ${schema}.${tableName}`);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
this.logger.log(`Completed processing enum fields for schema: ${schema}`);
|
|
213
|
+
} catch (error) {
|
|
214
|
+
this.logger.error(
|
|
215
|
+
`Error processing enum fields for schema ${schema}: ${error.message}`,
|
|
216
|
+
error.stack
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
private async cleanup() {
|
|
222
|
+
this.logger.log("Cleaning up database connections");
|
|
223
|
+
await this.sourcePool.end();
|
|
224
|
+
await this.targetPool.end();
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Script para ejecutar desde línea de comandos
|
|
229
|
+
if (require.main === module) {
|
|
230
|
+
const run = async () => {
|
|
231
|
+
try {
|
|
232
|
+
const fixer = new DataTypeFixer();
|
|
233
|
+
await fixer.fixDataTypes();
|
|
234
|
+
process.exit(0);
|
|
235
|
+
} catch (error) {
|
|
236
|
+
console.error("Error:", error.message);
|
|
237
|
+
process.exit(1);
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
run();
|
|
242
242
|
}
|