@javalabs/prisma-client 1.0.18 → 1.0.19
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/.dockerignore +14 -0
- package/Dockerfile +23 -0
- package/README.md +269 -269
- package/dist/index.d.ts +1 -1
- package/dist/prisma.service.d.ts +1 -1
- package/dist/scripts/add-uuid-to-table.js +32 -32
- package/dist/scripts/data-migration/batch-migrator.js +12 -12
- package/dist/scripts/data-migration/data-transformer.js +14 -14
- package/dist/scripts/data-migration/dependency-resolver.js +23 -23
- package/dist/scripts/data-migration/entity-discovery.js +68 -68
- package/dist/scripts/data-migration/foreign-key-manager.js +23 -23
- package/dist/scripts/data-migration/migration-tool.js +5 -5
- package/dist/scripts/data-migration/schema-utils.js +74 -74
- package/dist/scripts/data-migration/typecast-manager.js +4 -4
- package/dist/scripts/database-initializer.js +5 -5
- package/dist/scripts/drop-database.js +5 -5
- package/dist/scripts/fix-data-types.js +53 -53
- package/dist/scripts/fix-enum-values.js +34 -34
- package/dist/scripts/fix-schema-discrepancies.js +40 -40
- package/dist/scripts/fix-table-indexes.js +81 -81
- package/dist/scripts/migrate-schema-structure.js +4 -4
- package/dist/scripts/migrate-uuid.js +19 -19
- package/dist/scripts/post-migration-validator.js +49 -49
- package/dist/scripts/pre-migration-validator.js +107 -107
- package/dist/scripts/reset-database.js +21 -21
- package/dist/scripts/retry-failed-migrations.js +28 -28
- package/dist/scripts/run-migration.js +5 -5
- package/dist/scripts/schema-sync.js +18 -18
- package/dist/scripts/sequence-sync-cli.js +55 -55
- package/dist/scripts/sequence-synchronizer.js +20 -20
- package/dist/scripts/sync-enum-types.js +30 -30
- package/dist/scripts/sync-enum-values.js +52 -52
- package/dist/scripts/truncate-database.js +10 -10
- package/dist/scripts/verify-migration-setup.js +10 -10
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/migration-config.json +63 -63
- package/migration-config.json.bk +95 -95
- package/package.json +44 -44
- package/prisma/migrations/add_accepts_partial_payments_to_users.sql +19 -0
- package/prisma/migrations/add_amount_received_to_manual_payments.sql +19 -0
- package/prisma/migrations/add_commission_fields.sql +33 -0
- package/prisma/migrations/add_uuid_to_transactions.sql +13 -13
- package/prisma/migrations/complete_partial_payments_migration.sql +53 -0
- package/prisma/migrations/create_settlements_table.sql +60 -0
- package/prisma/schema.prisma +47 -1
- 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
- package/dist/scripts/data-migration/dependency-manager.d.ts +0 -9
- package/dist/scripts/data-migration/dependency-manager.js +0 -86
- package/dist/scripts/data-migration/dependency-manager.js.map +0 -1
- package/dist/scripts/data-migration/migration-config.json +0 -63
- package/dist/scripts/data-migration/migration-phases.d.ts +0 -5
- package/dist/scripts/data-migration/migration-phases.js +0 -55
- package/dist/scripts/data-migration/migration-phases.js.map +0 -1
- package/dist/scripts/data-migration/multi-source-migrator.d.ts +0 -17
- package/dist/scripts/data-migration/multi-source-migrator.js +0 -130
- package/dist/scripts/data-migration/multi-source-migrator.js.map +0 -1
- package/dist/scripts/data-migration/phase-generator.d.ts +0 -15
- package/dist/scripts/data-migration/phase-generator.js +0 -187
- package/dist/scripts/data-migration/phase-generator.js.map +0 -1
- package/dist/scripts/data-migration.d.ts +0 -22
- package/dist/scripts/data-migration.js +0 -593
- package/dist/scripts/data-migration.js.map +0 -1
- package/dist/scripts/multi-db-migration.d.ts +0 -1
- package/dist/scripts/multi-db-migration.js +0 -55
- package/dist/scripts/multi-db-migration.js.map +0 -1
|
@@ -11,28 +11,28 @@ class SchemaUtils {
|
|
|
11
11
|
const pool = dbType === "source"
|
|
12
12
|
? this.connections.sourcePool
|
|
13
13
|
: this.connections.targetPool;
|
|
14
|
-
const query = `
|
|
15
|
-
SELECT
|
|
16
|
-
c.table_name,
|
|
17
|
-
c.column_name,
|
|
18
|
-
c.data_type,
|
|
19
|
-
c.udt_name,
|
|
20
|
-
c.character_maximum_length,
|
|
21
|
-
c.is_nullable,
|
|
22
|
-
c.column_default,
|
|
23
|
-
tc.constraint_type
|
|
24
|
-
FROM
|
|
25
|
-
information_schema.columns c
|
|
26
|
-
LEFT JOIN information_schema.constraint_column_usage ccu
|
|
27
|
-
ON c.column_name = ccu.column_name
|
|
28
|
-
AND c.table_name = ccu.table_name
|
|
29
|
-
LEFT JOIN information_schema.table_constraints tc
|
|
30
|
-
ON ccu.constraint_name = tc.constraint_name
|
|
31
|
-
WHERE
|
|
32
|
-
c.table_schema = $1
|
|
33
|
-
AND c.table_name = $2
|
|
34
|
-
ORDER BY
|
|
35
|
-
c.ordinal_position
|
|
14
|
+
const query = `
|
|
15
|
+
SELECT
|
|
16
|
+
c.table_name,
|
|
17
|
+
c.column_name,
|
|
18
|
+
c.data_type,
|
|
19
|
+
c.udt_name,
|
|
20
|
+
c.character_maximum_length,
|
|
21
|
+
c.is_nullable,
|
|
22
|
+
c.column_default,
|
|
23
|
+
tc.constraint_type
|
|
24
|
+
FROM
|
|
25
|
+
information_schema.columns c
|
|
26
|
+
LEFT JOIN information_schema.constraint_column_usage ccu
|
|
27
|
+
ON c.column_name = ccu.column_name
|
|
28
|
+
AND c.table_name = ccu.table_name
|
|
29
|
+
LEFT JOIN information_schema.table_constraints tc
|
|
30
|
+
ON ccu.constraint_name = tc.constraint_name
|
|
31
|
+
WHERE
|
|
32
|
+
c.table_schema = $1
|
|
33
|
+
AND c.table_name = $2
|
|
34
|
+
ORDER BY
|
|
35
|
+
c.ordinal_position
|
|
36
36
|
`;
|
|
37
37
|
try {
|
|
38
38
|
const result = await pool.query(query, [schema, tableName]);
|
|
@@ -45,10 +45,10 @@ class SchemaUtils {
|
|
|
45
45
|
}
|
|
46
46
|
async checkSchemaExists(schemaName) {
|
|
47
47
|
try {
|
|
48
|
-
const query = `
|
|
49
|
-
SELECT schema_name
|
|
50
|
-
FROM information_schema.schemata
|
|
51
|
-
WHERE schema_name = $1
|
|
48
|
+
const query = `
|
|
49
|
+
SELECT schema_name
|
|
50
|
+
FROM information_schema.schemata
|
|
51
|
+
WHERE schema_name = $1
|
|
52
52
|
`;
|
|
53
53
|
const result = await this.connections.targetPool.query(query, [
|
|
54
54
|
schemaName,
|
|
@@ -62,11 +62,11 @@ class SchemaUtils {
|
|
|
62
62
|
}
|
|
63
63
|
async getTargetTables(schemaName) {
|
|
64
64
|
try {
|
|
65
|
-
const query = `
|
|
66
|
-
SELECT table_name
|
|
67
|
-
FROM information_schema.tables
|
|
68
|
-
WHERE table_schema = $1
|
|
69
|
-
AND table_type = 'BASE TABLE'
|
|
65
|
+
const query = `
|
|
66
|
+
SELECT table_name
|
|
67
|
+
FROM information_schema.tables
|
|
68
|
+
WHERE table_schema = $1
|
|
69
|
+
AND table_type = 'BASE TABLE'
|
|
70
70
|
`;
|
|
71
71
|
const result = await this.connections.targetPool.query(query, [
|
|
72
72
|
schemaName,
|
|
@@ -84,13 +84,13 @@ class SchemaUtils {
|
|
|
84
84
|
}
|
|
85
85
|
async getEnumValues(schemaName, enumName) {
|
|
86
86
|
try {
|
|
87
|
-
const query = `
|
|
88
|
-
SELECT e.enumlabel
|
|
89
|
-
FROM pg_type t
|
|
90
|
-
JOIN pg_enum e ON t.oid = e.enumtypid
|
|
91
|
-
JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace
|
|
92
|
-
WHERE t.typname = $1
|
|
93
|
-
AND n.nspname = $2
|
|
87
|
+
const query = `
|
|
88
|
+
SELECT e.enumlabel
|
|
89
|
+
FROM pg_type t
|
|
90
|
+
JOIN pg_enum e ON t.oid = e.enumtypid
|
|
91
|
+
JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace
|
|
92
|
+
WHERE t.typname = $1
|
|
93
|
+
AND n.nspname = $2
|
|
94
94
|
`;
|
|
95
95
|
const result = await this.connections.targetPool.query(query, [
|
|
96
96
|
enumName,
|
|
@@ -112,25 +112,25 @@ class SchemaUtils {
|
|
|
112
112
|
async createMissingColumns(tableName, schema, columns) {
|
|
113
113
|
for (const column of columns) {
|
|
114
114
|
try {
|
|
115
|
-
const query = `
|
|
116
|
-
ALTER TABLE "${schema}"."${tableName}"
|
|
117
|
-
ADD COLUMN IF NOT EXISTS "${column.column_name}" ${column.data_type}
|
|
118
|
-
${column.is_nullable === "NO" ? "NOT NULL" : ""}
|
|
119
|
-
${column.column_default ? `DEFAULT ${column.column_default}` : ""}
|
|
115
|
+
const query = `
|
|
116
|
+
ALTER TABLE "${schema}"."${tableName}"
|
|
117
|
+
ADD COLUMN IF NOT EXISTS "${column.column_name}" ${column.data_type}
|
|
118
|
+
${column.is_nullable === "NO" ? "NOT NULL" : ""}
|
|
119
|
+
${column.column_default ? `DEFAULT ${column.column_default}` : ""}
|
|
120
120
|
`;
|
|
121
121
|
await this.connections.targetPool.query(query);
|
|
122
122
|
if (column.constraint_type === "UNIQUE") {
|
|
123
123
|
const constraintName = `${tableName}_${column.column_name}_unique`;
|
|
124
|
-
const uniqueQuery = `
|
|
125
|
-
DO $$
|
|
126
|
-
BEGIN
|
|
127
|
-
IF NOT EXISTS (
|
|
128
|
-
SELECT 1 FROM pg_constraint WHERE conname = '${constraintName}'
|
|
129
|
-
) THEN
|
|
130
|
-
ALTER TABLE "${schema}"."${tableName}"
|
|
131
|
-
ADD CONSTRAINT "${constraintName}" UNIQUE ("${column.column_name}");
|
|
132
|
-
END IF;
|
|
133
|
-
END $$;
|
|
124
|
+
const uniqueQuery = `
|
|
125
|
+
DO $$
|
|
126
|
+
BEGIN
|
|
127
|
+
IF NOT EXISTS (
|
|
128
|
+
SELECT 1 FROM pg_constraint WHERE conname = '${constraintName}'
|
|
129
|
+
) THEN
|
|
130
|
+
ALTER TABLE "${schema}"."${tableName}"
|
|
131
|
+
ADD CONSTRAINT "${constraintName}" UNIQUE ("${column.column_name}");
|
|
132
|
+
END IF;
|
|
133
|
+
END $$;
|
|
134
134
|
`;
|
|
135
135
|
await this.connections.targetPool.query(uniqueQuery);
|
|
136
136
|
}
|
|
@@ -146,10 +146,10 @@ class SchemaUtils {
|
|
|
146
146
|
await this.connections.targetPool.query(`CREATE SCHEMA IF NOT EXISTS "${schemaName}"`);
|
|
147
147
|
const tables = await this.getPublicTables();
|
|
148
148
|
for (const table of tables) {
|
|
149
|
-
await this.connections.targetPool.query(`
|
|
150
|
-
CREATE TABLE IF NOT EXISTS "${schemaName}"."${table}" (
|
|
151
|
-
LIKE public."${table}" INCLUDING ALL
|
|
152
|
-
);
|
|
149
|
+
await this.connections.targetPool.query(`
|
|
150
|
+
CREATE TABLE IF NOT EXISTS "${schemaName}"."${table}" (
|
|
151
|
+
LIKE public."${table}" INCLUDING ALL
|
|
152
|
+
);
|
|
153
153
|
`);
|
|
154
154
|
}
|
|
155
155
|
this.logger.log(`Created schema ${schemaName} with all tables`);
|
|
@@ -160,27 +160,27 @@ class SchemaUtils {
|
|
|
160
160
|
}
|
|
161
161
|
}
|
|
162
162
|
async getPublicTables() {
|
|
163
|
-
const result = await this.connections.targetPool.query(`
|
|
164
|
-
SELECT tablename
|
|
165
|
-
FROM pg_tables
|
|
166
|
-
WHERE schemaname = 'public'
|
|
163
|
+
const result = await this.connections.targetPool.query(`
|
|
164
|
+
SELECT tablename
|
|
165
|
+
FROM pg_tables
|
|
166
|
+
WHERE schemaname = 'public'
|
|
167
167
|
`);
|
|
168
168
|
return result.rows.map((row) => row.tablename);
|
|
169
169
|
}
|
|
170
170
|
async getTableColumns(schema, table) {
|
|
171
|
-
const query = `
|
|
172
|
-
SELECT
|
|
173
|
-
column_name,
|
|
174
|
-
data_type,
|
|
175
|
-
is_nullable,
|
|
176
|
-
column_default,
|
|
177
|
-
character_maximum_length,
|
|
178
|
-
numeric_precision,
|
|
179
|
-
numeric_scale
|
|
180
|
-
FROM information_schema.columns
|
|
181
|
-
WHERE table_schema = $1
|
|
182
|
-
AND table_name = $2
|
|
183
|
-
ORDER BY ordinal_position;
|
|
171
|
+
const query = `
|
|
172
|
+
SELECT
|
|
173
|
+
column_name,
|
|
174
|
+
data_type,
|
|
175
|
+
is_nullable,
|
|
176
|
+
column_default,
|
|
177
|
+
character_maximum_length,
|
|
178
|
+
numeric_precision,
|
|
179
|
+
numeric_scale
|
|
180
|
+
FROM information_schema.columns
|
|
181
|
+
WHERE table_schema = $1
|
|
182
|
+
AND table_name = $2
|
|
183
|
+
ORDER BY ordinal_position;
|
|
184
184
|
`;
|
|
185
185
|
try {
|
|
186
186
|
const result = await this.connections.sourcePool.query(query, [
|
|
@@ -56,10 +56,10 @@ class TypecastManager {
|
|
|
56
56
|
return tableSchema === null || tableSchema === void 0 ? void 0 : tableSchema.get(columnName);
|
|
57
57
|
}
|
|
58
58
|
async loadTableSchema(tableName) {
|
|
59
|
-
const columns = await this.prisma.$queryRawUnsafe(`
|
|
60
|
-
SELECT column_name, data_type, udt_name, is_nullable
|
|
61
|
-
FROM information_schema.columns
|
|
62
|
-
WHERE table_name = '${tableName}'
|
|
59
|
+
const columns = await this.prisma.$queryRawUnsafe(`
|
|
60
|
+
SELECT column_name, data_type, udt_name, is_nullable
|
|
61
|
+
FROM information_schema.columns
|
|
62
|
+
WHERE table_name = '${tableName}'
|
|
63
63
|
`);
|
|
64
64
|
const tableSchema = new Map();
|
|
65
65
|
for (const column of columns) {
|
|
@@ -14,11 +14,11 @@ class DatabaseInitializer {
|
|
|
14
14
|
const { Pool } = await Promise.resolve().then(() => require("pg"));
|
|
15
15
|
const pool = new Pool({ connectionString: this.databaseUrl });
|
|
16
16
|
try {
|
|
17
|
-
const result = await pool.query(`
|
|
18
|
-
SELECT COUNT(*)
|
|
19
|
-
FROM information_schema.tables
|
|
20
|
-
WHERE table_schema = 'public'
|
|
21
|
-
AND table_type = 'BASE TABLE'
|
|
17
|
+
const result = await pool.query(`
|
|
18
|
+
SELECT COUNT(*)
|
|
19
|
+
FROM information_schema.tables
|
|
20
|
+
WHERE table_schema = 'public'
|
|
21
|
+
AND table_type = 'BASE TABLE'
|
|
22
22
|
`);
|
|
23
23
|
const tableCount = parseInt(result.rows[0].count);
|
|
24
24
|
if (tableCount === 0) {
|
|
@@ -41,11 +41,11 @@ class DatabaseDropTool {
|
|
|
41
41
|
async terminateConnections(dbName) {
|
|
42
42
|
this.logger.log(`Terminating all connections to database: ${dbName}`);
|
|
43
43
|
try {
|
|
44
|
-
await this.adminPool.query(`
|
|
45
|
-
SELECT pg_terminate_backend(pg_stat_activity.pid)
|
|
46
|
-
FROM pg_stat_activity
|
|
47
|
-
WHERE pg_stat_activity.datname = $1
|
|
48
|
-
AND pid <> pg_backend_pid()
|
|
44
|
+
await this.adminPool.query(`
|
|
45
|
+
SELECT pg_terminate_backend(pg_stat_activity.pid)
|
|
46
|
+
FROM pg_stat_activity
|
|
47
|
+
WHERE pg_stat_activity.datname = $1
|
|
48
|
+
AND pid <> pg_backend_pid()
|
|
49
49
|
`, [dbName]);
|
|
50
50
|
this.logger.log("All connections terminated successfully");
|
|
51
51
|
}
|
|
@@ -18,11 +18,11 @@ class DataTypeFixer {
|
|
|
18
18
|
async fixDataTypes() {
|
|
19
19
|
try {
|
|
20
20
|
this.logger.log("Starting data type fixing process");
|
|
21
|
-
const schemasQuery = `
|
|
22
|
-
SELECT schema_name
|
|
23
|
-
FROM information_schema.schemata
|
|
24
|
-
WHERE schema_name NOT IN ('public', 'information_schema', 'pg_catalog', 'pg_toast')
|
|
25
|
-
AND schema_name NOT LIKE 'pg_%';
|
|
21
|
+
const schemasQuery = `
|
|
22
|
+
SELECT schema_name
|
|
23
|
+
FROM information_schema.schemata
|
|
24
|
+
WHERE schema_name NOT IN ('public', 'information_schema', 'pg_catalog', 'pg_toast')
|
|
25
|
+
AND schema_name NOT LIKE 'pg_%';
|
|
26
26
|
`;
|
|
27
27
|
const schemasResult = await this.targetPool.query(schemasQuery);
|
|
28
28
|
const schemas = schemasResult.rows.map(row => row.schema_name);
|
|
@@ -43,31 +43,31 @@ class DataTypeFixer {
|
|
|
43
43
|
async fixNumericFieldsForSchema(schema) {
|
|
44
44
|
this.logger.log(`Processing numeric fields for schema: ${schema}`);
|
|
45
45
|
try {
|
|
46
|
-
const numericColumnsQuery = `
|
|
47
|
-
SELECT
|
|
48
|
-
table_name,
|
|
49
|
-
column_name
|
|
50
|
-
FROM
|
|
51
|
-
information_schema.columns
|
|
52
|
-
WHERE
|
|
53
|
-
table_schema = $1
|
|
54
|
-
AND data_type = 'numeric'
|
|
46
|
+
const numericColumnsQuery = `
|
|
47
|
+
SELECT
|
|
48
|
+
table_name,
|
|
49
|
+
column_name
|
|
50
|
+
FROM
|
|
51
|
+
information_schema.columns
|
|
52
|
+
WHERE
|
|
53
|
+
table_schema = $1
|
|
54
|
+
AND data_type = 'numeric'
|
|
55
55
|
`;
|
|
56
56
|
const numericColumnsResult = await this.targetPool.query(numericColumnsQuery, [schema]);
|
|
57
57
|
for (const row of numericColumnsResult.rows) {
|
|
58
58
|
const tableName = row.table_name;
|
|
59
59
|
const columnName = row.column_name;
|
|
60
60
|
this.logger.log(`Fixing numeric column ${columnName} in table ${schema}.${tableName}`);
|
|
61
|
-
const updateQuery = `
|
|
62
|
-
UPDATE "${schema}"."${tableName}"
|
|
63
|
-
SET "${columnName}" = CASE
|
|
64
|
-
WHEN "${columnName}" IS NULL THEN NULL
|
|
65
|
-
WHEN "${columnName}" = '' THEN NULL
|
|
66
|
-
ELSE CAST("${columnName}" AS NUMERIC)
|
|
67
|
-
END
|
|
68
|
-
WHERE "${columnName}" IS NOT NULL
|
|
69
|
-
AND "${columnName}" != ''
|
|
70
|
-
AND "${columnName}" ~ '^[0-9]+(\.[0-9]+)?$';
|
|
61
|
+
const updateQuery = `
|
|
62
|
+
UPDATE "${schema}"."${tableName}"
|
|
63
|
+
SET "${columnName}" = CASE
|
|
64
|
+
WHEN "${columnName}" IS NULL THEN NULL
|
|
65
|
+
WHEN "${columnName}" = '' THEN NULL
|
|
66
|
+
ELSE CAST("${columnName}" AS NUMERIC)
|
|
67
|
+
END
|
|
68
|
+
WHERE "${columnName}" IS NOT NULL
|
|
69
|
+
AND "${columnName}" != ''
|
|
70
|
+
AND "${columnName}" ~ '^[0-9]+(\.[0-9]+)?$';
|
|
71
71
|
`;
|
|
72
72
|
try {
|
|
73
73
|
await this.targetPool.query(updateQuery);
|
|
@@ -86,17 +86,17 @@ class DataTypeFixer {
|
|
|
86
86
|
async fixEnumFieldsForSchema(schema) {
|
|
87
87
|
this.logger.log(`Processing enum fields for schema: ${schema}`);
|
|
88
88
|
try {
|
|
89
|
-
const enumColumnsQuery = `
|
|
90
|
-
SELECT
|
|
91
|
-
c.table_name,
|
|
92
|
-
c.column_name,
|
|
93
|
-
c.udt_name
|
|
94
|
-
FROM
|
|
95
|
-
information_schema.columns c
|
|
96
|
-
WHERE
|
|
97
|
-
c.table_schema = $1
|
|
98
|
-
AND c.data_type = 'USER-DEFINED'
|
|
99
|
-
AND c.udt_name LIKE 'enum_%'
|
|
89
|
+
const enumColumnsQuery = `
|
|
90
|
+
SELECT
|
|
91
|
+
c.table_name,
|
|
92
|
+
c.column_name,
|
|
93
|
+
c.udt_name
|
|
94
|
+
FROM
|
|
95
|
+
information_schema.columns c
|
|
96
|
+
WHERE
|
|
97
|
+
c.table_schema = $1
|
|
98
|
+
AND c.data_type = 'USER-DEFINED'
|
|
99
|
+
AND c.udt_name LIKE 'enum_%'
|
|
100
100
|
`;
|
|
101
101
|
const enumColumnsResult = await this.targetPool.query(enumColumnsQuery, [schema]);
|
|
102
102
|
for (const row of enumColumnsResult.rows) {
|
|
@@ -104,12 +104,12 @@ class DataTypeFixer {
|
|
|
104
104
|
const columnName = row.column_name;
|
|
105
105
|
const enumTypeName = row.udt_name;
|
|
106
106
|
this.logger.log(`Fixing enum column ${columnName} (${enumTypeName}) in table ${schema}.${tableName}`);
|
|
107
|
-
const enumValuesQuery = `
|
|
108
|
-
SELECT e.enumlabel
|
|
109
|
-
FROM pg_enum e
|
|
110
|
-
JOIN pg_type t ON e.enumtypid = t.oid
|
|
111
|
-
WHERE t.typname = $1
|
|
112
|
-
ORDER BY e.enumsortorder
|
|
107
|
+
const enumValuesQuery = `
|
|
108
|
+
SELECT e.enumlabel
|
|
109
|
+
FROM pg_enum e
|
|
110
|
+
JOIN pg_type t ON e.enumtypid = t.oid
|
|
111
|
+
WHERE t.typname = $1
|
|
112
|
+
ORDER BY e.enumsortorder
|
|
113
113
|
`;
|
|
114
114
|
const enumValuesResult = await this.targetPool.query(enumValuesQuery, [enumTypeName]);
|
|
115
115
|
const validEnumValues = enumValuesResult.rows.map(r => r.enumlabel);
|
|
@@ -118,10 +118,10 @@ class DataTypeFixer {
|
|
|
118
118
|
continue;
|
|
119
119
|
}
|
|
120
120
|
this.logger.log(`Valid values for ${enumTypeName}: ${validEnumValues.join(', ')}`);
|
|
121
|
-
const currentValuesQuery = `
|
|
122
|
-
SELECT DISTINCT "${columnName}"
|
|
123
|
-
FROM "${schema}"."${tableName}"
|
|
124
|
-
WHERE "${columnName}" IS NOT NULL
|
|
121
|
+
const currentValuesQuery = `
|
|
122
|
+
SELECT DISTINCT "${columnName}"
|
|
123
|
+
FROM "${schema}"."${tableName}"
|
|
124
|
+
WHERE "${columnName}" IS NOT NULL
|
|
125
125
|
`;
|
|
126
126
|
const currentValuesResult = await this.targetPool.query(currentValuesQuery);
|
|
127
127
|
const currentValues = currentValuesResult.rows.map(r => r[columnName]);
|
|
@@ -132,19 +132,19 @@ class DataTypeFixer {
|
|
|
132
132
|
const matchingValidValue = validEnumValues.find(v => v.toLowerCase() === invalidValue.toLowerCase());
|
|
133
133
|
let updateQuery;
|
|
134
134
|
if (matchingValidValue) {
|
|
135
|
-
updateQuery = `
|
|
136
|
-
UPDATE "${schema}"."${tableName}"
|
|
137
|
-
SET "${columnName}" = $1
|
|
138
|
-
WHERE "${columnName}" = $2
|
|
135
|
+
updateQuery = `
|
|
136
|
+
UPDATE "${schema}"."${tableName}"
|
|
137
|
+
SET "${columnName}" = $1
|
|
138
|
+
WHERE "${columnName}" = $2
|
|
139
139
|
`;
|
|
140
140
|
await this.targetPool.query(updateQuery, [matchingValidValue, invalidValue]);
|
|
141
141
|
this.logger.log(`Updated invalid value "${invalidValue}" to "${matchingValidValue}"`);
|
|
142
142
|
}
|
|
143
143
|
else {
|
|
144
|
-
updateQuery = `
|
|
145
|
-
UPDATE "${schema}"."${tableName}"
|
|
146
|
-
SET "${columnName}" = NULL
|
|
147
|
-
WHERE "${columnName}" = $1
|
|
144
|
+
updateQuery = `
|
|
145
|
+
UPDATE "${schema}"."${tableName}"
|
|
146
|
+
SET "${columnName}" = NULL
|
|
147
|
+
WHERE "${columnName}" = $1
|
|
148
148
|
`;
|
|
149
149
|
await this.targetPool.query(updateQuery, [invalidValue]);
|
|
150
150
|
this.logger.log(`Set invalid value "${invalidValue}" to NULL`);
|
|
@@ -52,28 +52,28 @@ class EnumFixer {
|
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
async getSchemas() {
|
|
55
|
-
const result = await this.pool.query(`
|
|
56
|
-
SELECT schema_name
|
|
57
|
-
FROM information_schema.schemata
|
|
58
|
-
WHERE schema_name NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
|
|
59
|
-
AND schema_name NOT LIKE 'pg_%'
|
|
55
|
+
const result = await this.pool.query(`
|
|
56
|
+
SELECT schema_name
|
|
57
|
+
FROM information_schema.schemata
|
|
58
|
+
WHERE schema_name NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
|
|
59
|
+
AND schema_name NOT LIKE 'pg_%'
|
|
60
60
|
`);
|
|
61
61
|
return result.rows.map((row) => row.schema_name);
|
|
62
62
|
}
|
|
63
63
|
async fixEnumValuesForSchema(schema) {
|
|
64
64
|
this.logger.log(`Processing enum fields for schema: ${schema}`);
|
|
65
65
|
try {
|
|
66
|
-
const enumColumnsQuery = `
|
|
67
|
-
SELECT
|
|
68
|
-
c.table_name,
|
|
69
|
-
c.column_name,
|
|
70
|
-
c.udt_name
|
|
71
|
-
FROM
|
|
72
|
-
information_schema.columns c
|
|
73
|
-
WHERE
|
|
74
|
-
c.table_schema = $1
|
|
75
|
-
AND c.data_type = 'USER-DEFINED'
|
|
76
|
-
AND c.udt_name LIKE 'enum_%'
|
|
66
|
+
const enumColumnsQuery = `
|
|
67
|
+
SELECT
|
|
68
|
+
c.table_name,
|
|
69
|
+
c.column_name,
|
|
70
|
+
c.udt_name
|
|
71
|
+
FROM
|
|
72
|
+
information_schema.columns c
|
|
73
|
+
WHERE
|
|
74
|
+
c.table_schema = $1
|
|
75
|
+
AND c.data_type = 'USER-DEFINED'
|
|
76
|
+
AND c.udt_name LIKE 'enum_%'
|
|
77
77
|
`;
|
|
78
78
|
const enumColumnsResult = await this.pool.query(enumColumnsQuery, [
|
|
79
79
|
schema,
|
|
@@ -111,10 +111,10 @@ class EnumFixer {
|
|
|
111
111
|
return;
|
|
112
112
|
}
|
|
113
113
|
this.logger.log(`Valid values for ${enumTypeName}: ${validEnumValues.join(", ")}`);
|
|
114
|
-
const currentValuesQuery = `
|
|
115
|
-
SELECT DISTINCT "${columnName}"
|
|
116
|
-
FROM "${schema}"."${tableName}"
|
|
117
|
-
WHERE "${columnName}" IS NOT NULL
|
|
114
|
+
const currentValuesQuery = `
|
|
115
|
+
SELECT DISTINCT "${columnName}"
|
|
116
|
+
FROM "${schema}"."${tableName}"
|
|
117
|
+
WHERE "${columnName}" IS NOT NULL
|
|
118
118
|
`;
|
|
119
119
|
const currentValuesResult = await this.pool.query(currentValuesQuery);
|
|
120
120
|
const currentValues = currentValuesResult.rows.map((r) => r[columnName]);
|
|
@@ -162,15 +162,15 @@ class EnumFixer {
|
|
|
162
162
|
}
|
|
163
163
|
}
|
|
164
164
|
const updateQuery = mappedValue !== null
|
|
165
|
-
? `
|
|
166
|
-
UPDATE "${schema}"."${tableName}"
|
|
167
|
-
SET "${columnName}" = CAST($1 AS "${enumTypeName}")
|
|
168
|
-
WHERE "${columnName}" = $2
|
|
165
|
+
? `
|
|
166
|
+
UPDATE "${schema}"."${tableName}"
|
|
167
|
+
SET "${columnName}" = CAST($1 AS "${enumTypeName}")
|
|
168
|
+
WHERE "${columnName}" = $2
|
|
169
169
|
`
|
|
170
|
-
: `
|
|
171
|
-
UPDATE "${schema}"."${tableName}"
|
|
172
|
-
SET "${columnName}" = NULL
|
|
173
|
-
WHERE "${columnName}" = $1
|
|
170
|
+
: `
|
|
171
|
+
UPDATE "${schema}"."${tableName}"
|
|
172
|
+
SET "${columnName}" = NULL
|
|
173
|
+
WHERE "${columnName}" = $1
|
|
174
174
|
`;
|
|
175
175
|
const updateParams = mappedValue !== null ? [mappedValue, invalidValue] : [invalidValue];
|
|
176
176
|
const updateResult = await this.pool.query(updateQuery, updateParams);
|
|
@@ -183,12 +183,12 @@ class EnumFixer {
|
|
|
183
183
|
}
|
|
184
184
|
async getEnumValues(enumTypeName) {
|
|
185
185
|
try {
|
|
186
|
-
const enumQuery = `
|
|
187
|
-
SELECT e.enumlabel
|
|
188
|
-
FROM pg_enum e
|
|
189
|
-
JOIN pg_type t ON e.enumtypid = t.oid
|
|
190
|
-
WHERE t.typname = $1
|
|
191
|
-
ORDER BY e.enumsortorder
|
|
186
|
+
const enumQuery = `
|
|
187
|
+
SELECT e.enumlabel
|
|
188
|
+
FROM pg_enum e
|
|
189
|
+
JOIN pg_type t ON e.enumtypid = t.oid
|
|
190
|
+
WHERE t.typname = $1
|
|
191
|
+
ORDER BY e.enumsortorder
|
|
192
192
|
`;
|
|
193
193
|
const result = await this.pool.query(enumQuery, [enumTypeName]);
|
|
194
194
|
return result.rows.map((row) => row.enumlabel);
|
|
@@ -119,11 +119,11 @@ class SchemaDiscrepancyFixer {
|
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
121
|
async getTargetSchemas() {
|
|
122
|
-
const query = `
|
|
123
|
-
SELECT schema_name
|
|
124
|
-
FROM information_schema.schemata
|
|
125
|
-
WHERE schema_name NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
|
|
126
|
-
AND schema_name NOT LIKE 'pg_%'
|
|
122
|
+
const query = `
|
|
123
|
+
SELECT schema_name
|
|
124
|
+
FROM information_schema.schemata
|
|
125
|
+
WHERE schema_name NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
|
|
126
|
+
AND schema_name NOT LIKE 'pg_%'
|
|
127
127
|
`;
|
|
128
128
|
const result = await this.targetPool.query(query);
|
|
129
129
|
return result.rows.map(row => row.schema_name);
|
|
@@ -133,22 +133,22 @@ class SchemaDiscrepancyFixer {
|
|
|
133
133
|
this.columnTypeCache[table] = {};
|
|
134
134
|
}
|
|
135
135
|
const columnsStr = columns.map(c => `'${c}'`).join(',');
|
|
136
|
-
const query = `
|
|
137
|
-
SELECT column_name, data_type,
|
|
138
|
-
CASE
|
|
139
|
-
WHEN data_type = 'character varying' THEN data_type || '(' || character_maximum_length || ')'
|
|
140
|
-
WHEN data_type = 'numeric' THEN
|
|
141
|
-
CASE
|
|
142
|
-
WHEN numeric_precision IS NOT NULL AND numeric_scale IS NOT NULL
|
|
143
|
-
THEN data_type || '(' || numeric_precision || ',' || numeric_scale || ')'
|
|
144
|
-
ELSE data_type
|
|
145
|
-
END
|
|
146
|
-
ELSE data_type
|
|
147
|
-
END as full_data_type
|
|
148
|
-
FROM information_schema.columns
|
|
149
|
-
WHERE table_schema = 'public'
|
|
150
|
-
AND table_name = $1
|
|
151
|
-
AND column_name IN (${columnsStr})
|
|
136
|
+
const query = `
|
|
137
|
+
SELECT column_name, data_type,
|
|
138
|
+
CASE
|
|
139
|
+
WHEN data_type = 'character varying' THEN data_type || '(' || character_maximum_length || ')'
|
|
140
|
+
WHEN data_type = 'numeric' THEN
|
|
141
|
+
CASE
|
|
142
|
+
WHEN numeric_precision IS NOT NULL AND numeric_scale IS NOT NULL
|
|
143
|
+
THEN data_type || '(' || numeric_precision || ',' || numeric_scale || ')'
|
|
144
|
+
ELSE data_type
|
|
145
|
+
END
|
|
146
|
+
ELSE data_type
|
|
147
|
+
END as full_data_type
|
|
148
|
+
FROM information_schema.columns
|
|
149
|
+
WHERE table_schema = 'public'
|
|
150
|
+
AND table_name = $1
|
|
151
|
+
AND column_name IN (${columnsStr})
|
|
152
152
|
`;
|
|
153
153
|
const result = await this.sourcePool.query(query, [table]);
|
|
154
154
|
for (const row of result.rows) {
|
|
@@ -156,33 +156,33 @@ class SchemaDiscrepancyFixer {
|
|
|
156
156
|
}
|
|
157
157
|
}
|
|
158
158
|
async checkTableExists(schema, table) {
|
|
159
|
-
const query = `
|
|
160
|
-
SELECT EXISTS (
|
|
161
|
-
SELECT FROM information_schema.tables
|
|
162
|
-
WHERE table_schema = $1
|
|
163
|
-
AND table_name = $2
|
|
164
|
-
);
|
|
159
|
+
const query = `
|
|
160
|
+
SELECT EXISTS (
|
|
161
|
+
SELECT FROM information_schema.tables
|
|
162
|
+
WHERE table_schema = $1
|
|
163
|
+
AND table_name = $2
|
|
164
|
+
);
|
|
165
165
|
`;
|
|
166
166
|
const result = await this.targetPool.query(query, [schema, table]);
|
|
167
167
|
return result.rows[0].exists;
|
|
168
168
|
}
|
|
169
169
|
async checkColumnExists(schema, table, column) {
|
|
170
|
-
const query = `
|
|
171
|
-
SELECT EXISTS (
|
|
172
|
-
SELECT FROM information_schema.columns
|
|
173
|
-
WHERE table_schema = $1
|
|
174
|
-
AND table_name = $2
|
|
175
|
-
AND column_name = $3
|
|
176
|
-
);
|
|
170
|
+
const query = `
|
|
171
|
+
SELECT EXISTS (
|
|
172
|
+
SELECT FROM information_schema.columns
|
|
173
|
+
WHERE table_schema = $1
|
|
174
|
+
AND table_name = $2
|
|
175
|
+
AND column_name = $3
|
|
176
|
+
);
|
|
177
177
|
`;
|
|
178
178
|
const result = await this.targetPool.query(query, [schema, table, column]);
|
|
179
179
|
return result.rows[0].exists;
|
|
180
180
|
}
|
|
181
181
|
async addColumn(schema, table, column, type) {
|
|
182
182
|
try {
|
|
183
|
-
const query = `
|
|
184
|
-
ALTER TABLE "${schema}"."${table}"
|
|
185
|
-
ADD COLUMN IF NOT EXISTS "${column}" ${type};
|
|
183
|
+
const query = `
|
|
184
|
+
ALTER TABLE "${schema}"."${table}"
|
|
185
|
+
ADD COLUMN IF NOT EXISTS "${column}" ${type};
|
|
186
186
|
`;
|
|
187
187
|
await this.targetPool.query(query);
|
|
188
188
|
this.logger.log(`Added column "${column}" to "${schema}"."${table}" with type "${type}"`);
|
|
@@ -195,9 +195,9 @@ class SchemaDiscrepancyFixer {
|
|
|
195
195
|
async addUniqueConstraint(schema, table, column) {
|
|
196
196
|
try {
|
|
197
197
|
const constraintName = `${table}_${column}_unique`;
|
|
198
|
-
const query = `
|
|
199
|
-
ALTER TABLE "${schema}"."${table}"
|
|
200
|
-
ADD CONSTRAINT "${constraintName}" UNIQUE ("${column}");
|
|
198
|
+
const query = `
|
|
199
|
+
ALTER TABLE "${schema}"."${table}"
|
|
200
|
+
ADD CONSTRAINT "${constraintName}" UNIQUE ("${column}");
|
|
201
201
|
`;
|
|
202
202
|
await this.targetPool.query(query);
|
|
203
203
|
this.logger.log(`Added UNIQUE constraint on "${column}" to "${schema}"."${table}"`);
|