@javalabs/prisma-client 1.0.18 → 1.0.20

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 (101) hide show
  1. package/.github/CODEOWNERS +1 -0
  2. package/README.md +269 -269
  3. package/dist/index.d.ts +1 -1
  4. package/dist/prisma.service.d.ts +1 -1
  5. package/dist/scripts/add-uuid-to-table.js +32 -32
  6. package/dist/scripts/data-migration/batch-migrator.js +12 -12
  7. package/dist/scripts/data-migration/data-transformer.js +14 -14
  8. package/dist/scripts/data-migration/dependency-resolver.js +23 -23
  9. package/dist/scripts/data-migration/entity-discovery.js +68 -68
  10. package/dist/scripts/data-migration/foreign-key-manager.js +23 -23
  11. package/dist/scripts/data-migration/migration-tool.js +5 -5
  12. package/dist/scripts/data-migration/schema-utils.js +74 -74
  13. package/dist/scripts/data-migration/typecast-manager.js +4 -4
  14. package/dist/scripts/database-initializer.js +5 -5
  15. package/dist/scripts/drop-database.js +5 -5
  16. package/dist/scripts/fix-data-types.js +53 -53
  17. package/dist/scripts/fix-enum-values.js +34 -34
  18. package/dist/scripts/fix-schema-discrepancies.js +40 -40
  19. package/dist/scripts/fix-table-indexes.js +81 -81
  20. package/dist/scripts/migrate-schema-structure.js +4 -4
  21. package/dist/scripts/migrate-uuid.js +19 -19
  22. package/dist/scripts/post-migration-validator.js +49 -49
  23. package/dist/scripts/pre-migration-validator.js +107 -107
  24. package/dist/scripts/reset-database.js +21 -21
  25. package/dist/scripts/retry-failed-migrations.js +28 -28
  26. package/dist/scripts/run-migration.js +5 -5
  27. package/dist/scripts/schema-sync.js +18 -18
  28. package/dist/scripts/sequence-sync-cli.js +55 -55
  29. package/dist/scripts/sequence-synchronizer.js +20 -20
  30. package/dist/scripts/sync-enum-types.js +30 -30
  31. package/dist/scripts/sync-enum-values.js +52 -52
  32. package/dist/scripts/truncate-database.js +10 -10
  33. package/dist/scripts/verify-migration-setup.js +10 -10
  34. package/dist/tsconfig.tsbuildinfo +1 -1
  35. package/migration-config.json +63 -63
  36. package/migration-config.json.bk +95 -95
  37. package/migrations/add_reserved_amount.sql +8 -0
  38. package/package.json +44 -44
  39. package/prisma/migrations/add_uuid_to_transactions.sql +13 -13
  40. package/prisma/schema.prisma +601 -554
  41. package/src/index.ts +23 -23
  42. package/src/prisma-factory.service.ts +40 -40
  43. package/src/prisma.module.ts +9 -9
  44. package/src/prisma.service.ts +16 -16
  45. package/src/scripts/add-uuid-to-table.ts +138 -138
  46. package/src/scripts/create-tenant-schemas.ts +145 -145
  47. package/src/scripts/data-migration/batch-migrator.ts +248 -248
  48. package/src/scripts/data-migration/data-transformer.ts +426 -426
  49. package/src/scripts/data-migration/db-connector.ts +120 -120
  50. package/src/scripts/data-migration/dependency-resolver.ts +174 -174
  51. package/src/scripts/data-migration/entity-discovery.ts +196 -196
  52. package/src/scripts/data-migration/foreign-key-manager.ts +277 -277
  53. package/src/scripts/data-migration/migration-config.json +63 -63
  54. package/src/scripts/data-migration/migration-tool.ts +509 -509
  55. package/src/scripts/data-migration/schema-utils.ts +248 -248
  56. package/src/scripts/data-migration/tenant-migrator.ts +201 -201
  57. package/src/scripts/data-migration/typecast-manager.ts +193 -193
  58. package/src/scripts/data-migration/types.ts +113 -113
  59. package/src/scripts/database-initializer.ts +49 -49
  60. package/src/scripts/drop-database.ts +104 -104
  61. package/src/scripts/dump-source-db.sh +61 -61
  62. package/src/scripts/encrypt-user-passwords.ts +36 -36
  63. package/src/scripts/error-handler.ts +117 -117
  64. package/src/scripts/fix-data-types.ts +241 -241
  65. package/src/scripts/fix-enum-values.ts +357 -357
  66. package/src/scripts/fix-schema-discrepancies.ts +317 -317
  67. package/src/scripts/fix-table-indexes.ts +601 -601
  68. package/src/scripts/migrate-schema-structure.ts +90 -90
  69. package/src/scripts/migrate-uuid.ts +76 -76
  70. package/src/scripts/post-migration-validator.ts +526 -526
  71. package/src/scripts/pre-migration-validator.ts +610 -610
  72. package/src/scripts/reset-database.ts +263 -263
  73. package/src/scripts/retry-failed-migrations.ts +416 -416
  74. package/src/scripts/run-migration.ts +707 -707
  75. package/src/scripts/schema-sync.ts +128 -128
  76. package/src/scripts/sequence-sync-cli.ts +416 -416
  77. package/src/scripts/sequence-synchronizer.ts +127 -127
  78. package/src/scripts/sync-enum-types.ts +170 -170
  79. package/src/scripts/sync-enum-values.ts +563 -563
  80. package/src/scripts/truncate-database.ts +123 -123
  81. package/src/scripts/verify-migration-setup.ts +135 -135
  82. package/tsconfig.json +17 -17
  83. package/dist/scripts/data-migration/dependency-manager.d.ts +0 -9
  84. package/dist/scripts/data-migration/dependency-manager.js +0 -86
  85. package/dist/scripts/data-migration/dependency-manager.js.map +0 -1
  86. package/dist/scripts/data-migration/migration-config.json +0 -63
  87. package/dist/scripts/data-migration/migration-phases.d.ts +0 -5
  88. package/dist/scripts/data-migration/migration-phases.js +0 -55
  89. package/dist/scripts/data-migration/migration-phases.js.map +0 -1
  90. package/dist/scripts/data-migration/multi-source-migrator.d.ts +0 -17
  91. package/dist/scripts/data-migration/multi-source-migrator.js +0 -130
  92. package/dist/scripts/data-migration/multi-source-migrator.js.map +0 -1
  93. package/dist/scripts/data-migration/phase-generator.d.ts +0 -15
  94. package/dist/scripts/data-migration/phase-generator.js +0 -187
  95. package/dist/scripts/data-migration/phase-generator.js.map +0 -1
  96. package/dist/scripts/data-migration.d.ts +0 -22
  97. package/dist/scripts/data-migration.js +0 -593
  98. package/dist/scripts/data-migration.js.map +0 -1
  99. package/dist/scripts/multi-db-migration.d.ts +0 -1
  100. package/dist/scripts/multi-db-migration.js +0 -55
  101. package/dist/scripts/multi-db-migration.js.map +0 -1
@@ -1,127 +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
+ 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,171 +1,171 @@
1
- import * as pg from 'pg';
2
- import * as dotenv from 'dotenv';
3
- import { Logger } from '@nestjs/common';
4
-
5
- dotenv.config();
6
-
7
- export class EnumSynchronizer {
8
- private readonly logger = new Logger('EnumSynchronizer');
9
- private readonly sourcePool: pg.Pool;
10
- private readonly targetPool: pg.Pool;
11
-
12
- constructor(
13
- private readonly sourceUrl: string = process.env.SOURCE_DATABASE_URL,
14
- private readonly targetUrl: string = process.env.DATABASE_URL
15
- ) {
16
- this.sourcePool = new pg.Pool({
17
- connectionString: this.sourceUrl,
18
- });
19
-
20
- this.targetPool = new pg.Pool({
21
- connectionString: this.targetUrl,
22
- });
23
- }
24
-
25
- async synchronizeEnums() {
26
- try {
27
- this.logger.log('Starting enum synchronization');
28
-
29
- // Obtener todos los tipos enum en la base de datos de origen
30
- const sourceEnumsResult = await this.sourcePool.query(`
31
- SELECT t.typname AS enum_name
32
- FROM pg_type t
33
- JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace
34
- WHERE t.typtype = 'e'
35
- AND n.nspname = 'public'
36
- `);
37
-
38
- this.logger.log(`Found ${sourceEnumsResult.rows.length} enum types in source database`);
39
-
40
- // Para cada tipo enum, sincronizar sus valores
41
- for (const enumRow of sourceEnumsResult.rows) {
42
- const enumName = enumRow.enum_name;
43
- await this.synchronizeEnumType(enumName);
44
- }
45
-
46
- this.logger.log('Enum synchronization completed successfully');
47
- } catch (error) {
48
- this.logger.error(`Error during enum synchronization: ${error.message}`, error.stack);
49
- } finally {
50
- await this.cleanup();
51
- }
52
- }
53
-
54
- private async synchronizeEnumType(enumName: string) {
55
- this.logger.log(`Synchronizing enum type: ${enumName}`);
56
-
57
- try {
58
- // Obtener valores del enum en la base de datos de origen
59
- const sourceEnumValuesResult = await this.sourcePool.query(`
60
- SELECT e.enumlabel
61
- FROM pg_enum e
62
- JOIN pg_type t ON e.enumtypid = t.oid
63
- WHERE t.typname = $1
64
- ORDER BY e.enumsortorder
65
- `, [enumName]);
66
-
67
- const sourceEnumValues = sourceEnumValuesResult.rows.map(row => row.enumlabel);
68
- this.logger.log(`Source enum ${enumName} has values: ${sourceEnumValues.join(', ')}`);
69
-
70
- // Verificar si el enum existe en la base de datos de destino
71
- const targetEnumExistsResult = await this.targetPool.query(`
72
- SELECT 1
73
- FROM pg_type t
74
- JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace
75
- WHERE t.typtype = 'e'
76
- AND t.typname = $1
77
- AND n.nspname = 'public'
78
- LIMIT 1
79
- `, [enumName]);
80
-
81
- if (targetEnumExistsResult.rows.length === 0) {
82
- // Si el enum no existe en el destino, crearlo
83
- await this.createEnumType(enumName, sourceEnumValues);
84
- } else {
85
- // Si el enum existe, actualizar sus valores
86
- await this.updateEnumValues(enumName, sourceEnumValues);
87
- }
88
- } catch (error) {
89
- this.logger.error(`Error synchronizing enum type ${enumName}: ${error.message}`);
90
- }
91
- }
92
-
93
- private async createEnumType(enumName: string, values: string[]) {
94
- this.logger.log(`Creating enum type ${enumName} in target database`);
95
-
96
- try {
97
- // Escapar los valores para la consulta SQL
98
- const escapedValues = values.map(value => `'${value.replace(/'/g, "''")}'`).join(', ');
99
-
100
- // Crear el tipo enum
101
- await this.targetPool.query(`
102
- CREATE TYPE ${enumName} AS ENUM (${escapedValues})
103
- `);
104
-
105
- this.logger.log(`Successfully created enum type ${enumName} with values: ${values.join(', ')}`);
106
- } catch (error) {
107
- this.logger.error(`Error creating enum type ${enumName}: ${error.message}`);
108
- }
109
- }
110
-
111
- private async updateEnumValues(enumName: string, sourceValues: string[]) {
112
- this.logger.log(`Updating enum type ${enumName} in target database`);
113
-
114
- try {
115
- // Obtener valores actuales del enum en la base de datos de destino
116
- const targetEnumValuesResult = await this.targetPool.query(`
117
- SELECT e.enumlabel
118
- FROM pg_enum e
119
- JOIN pg_type t ON e.enumtypid = t.oid
120
- WHERE t.typname = $1
121
- ORDER BY e.enumsortorder
122
- `, [enumName]);
123
-
124
- const targetEnumValues = targetEnumValuesResult.rows.map(row => row.enumlabel);
125
- this.logger.log(`Target enum ${enumName} has values: ${targetEnumValues.join(', ')}`);
126
-
127
- // Encontrar valores que están en el origen pero no en el destino
128
- const missingValues = sourceValues.filter(value => !targetEnumValues.includes(value));
129
-
130
- if (missingValues.length === 0) {
131
- this.logger.log(`Enum type ${enumName} is already up to date`);
132
- return;
133
- }
134
-
135
- this.logger.log(`Adding ${missingValues.length} new values to enum ${enumName}: ${missingValues.join(', ')}`);
136
-
137
- // Agregar los valores faltantes al enum
138
- for (const value of missingValues) {
139
- await this.targetPool.query(`
140
- ALTER TYPE ${enumName} ADD VALUE '${value.replace(/'/g, "''")}'
141
- `);
142
- }
143
-
144
- this.logger.log(`Successfully updated enum type ${enumName}`);
145
- } catch (error) {
146
- this.logger.error(`Error updating enum type ${enumName}: ${error.message}`);
147
- }
148
- }
149
-
150
- private async cleanup() {
151
- this.logger.log('Cleaning up database connections');
152
- await this.sourcePool.end();
153
- await this.targetPool.end();
154
- }
155
- }
156
-
157
- // Script para ejecutar desde línea de comandos
158
- if (require.main === module) {
159
- const run = async () => {
160
- try {
161
- const synchronizer = new EnumSynchronizer();
162
- await synchronizer.synchronizeEnums();
163
- process.exit(0);
164
- } catch (error) {
165
- console.error('Error:', error.message);
166
- process.exit(1);
167
- }
168
- };
169
-
170
- run();
1
+ import * as pg from 'pg';
2
+ import * as dotenv from 'dotenv';
3
+ import { Logger } from '@nestjs/common';
4
+
5
+ dotenv.config();
6
+
7
+ export class EnumSynchronizer {
8
+ private readonly logger = new Logger('EnumSynchronizer');
9
+ private readonly sourcePool: pg.Pool;
10
+ private readonly targetPool: pg.Pool;
11
+
12
+ constructor(
13
+ private readonly sourceUrl: string = process.env.SOURCE_DATABASE_URL,
14
+ private readonly targetUrl: string = process.env.DATABASE_URL
15
+ ) {
16
+ this.sourcePool = new pg.Pool({
17
+ connectionString: this.sourceUrl,
18
+ });
19
+
20
+ this.targetPool = new pg.Pool({
21
+ connectionString: this.targetUrl,
22
+ });
23
+ }
24
+
25
+ async synchronizeEnums() {
26
+ try {
27
+ this.logger.log('Starting enum synchronization');
28
+
29
+ // Obtener todos los tipos enum en la base de datos de origen
30
+ const sourceEnumsResult = await this.sourcePool.query(`
31
+ SELECT t.typname AS enum_name
32
+ FROM pg_type t
33
+ JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace
34
+ WHERE t.typtype = 'e'
35
+ AND n.nspname = 'public'
36
+ `);
37
+
38
+ this.logger.log(`Found ${sourceEnumsResult.rows.length} enum types in source database`);
39
+
40
+ // Para cada tipo enum, sincronizar sus valores
41
+ for (const enumRow of sourceEnumsResult.rows) {
42
+ const enumName = enumRow.enum_name;
43
+ await this.synchronizeEnumType(enumName);
44
+ }
45
+
46
+ this.logger.log('Enum synchronization completed successfully');
47
+ } catch (error) {
48
+ this.logger.error(`Error during enum synchronization: ${error.message}`, error.stack);
49
+ } finally {
50
+ await this.cleanup();
51
+ }
52
+ }
53
+
54
+ private async synchronizeEnumType(enumName: string) {
55
+ this.logger.log(`Synchronizing enum type: ${enumName}`);
56
+
57
+ try {
58
+ // Obtener valores del enum en la base de datos de origen
59
+ const sourceEnumValuesResult = await this.sourcePool.query(`
60
+ SELECT e.enumlabel
61
+ FROM pg_enum e
62
+ JOIN pg_type t ON e.enumtypid = t.oid
63
+ WHERE t.typname = $1
64
+ ORDER BY e.enumsortorder
65
+ `, [enumName]);
66
+
67
+ const sourceEnumValues = sourceEnumValuesResult.rows.map(row => row.enumlabel);
68
+ this.logger.log(`Source enum ${enumName} has values: ${sourceEnumValues.join(', ')}`);
69
+
70
+ // Verificar si el enum existe en la base de datos de destino
71
+ const targetEnumExistsResult = await this.targetPool.query(`
72
+ SELECT 1
73
+ FROM pg_type t
74
+ JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace
75
+ WHERE t.typtype = 'e'
76
+ AND t.typname = $1
77
+ AND n.nspname = 'public'
78
+ LIMIT 1
79
+ `, [enumName]);
80
+
81
+ if (targetEnumExistsResult.rows.length === 0) {
82
+ // Si el enum no existe en el destino, crearlo
83
+ await this.createEnumType(enumName, sourceEnumValues);
84
+ } else {
85
+ // Si el enum existe, actualizar sus valores
86
+ await this.updateEnumValues(enumName, sourceEnumValues);
87
+ }
88
+ } catch (error) {
89
+ this.logger.error(`Error synchronizing enum type ${enumName}: ${error.message}`);
90
+ }
91
+ }
92
+
93
+ private async createEnumType(enumName: string, values: string[]) {
94
+ this.logger.log(`Creating enum type ${enumName} in target database`);
95
+
96
+ try {
97
+ // Escapar los valores para la consulta SQL
98
+ const escapedValues = values.map(value => `'${value.replace(/'/g, "''")}'`).join(', ');
99
+
100
+ // Crear el tipo enum
101
+ await this.targetPool.query(`
102
+ CREATE TYPE ${enumName} AS ENUM (${escapedValues})
103
+ `);
104
+
105
+ this.logger.log(`Successfully created enum type ${enumName} with values: ${values.join(', ')}`);
106
+ } catch (error) {
107
+ this.logger.error(`Error creating enum type ${enumName}: ${error.message}`);
108
+ }
109
+ }
110
+
111
+ private async updateEnumValues(enumName: string, sourceValues: string[]) {
112
+ this.logger.log(`Updating enum type ${enumName} in target database`);
113
+
114
+ try {
115
+ // Obtener valores actuales del enum en la base de datos de destino
116
+ const targetEnumValuesResult = await this.targetPool.query(`
117
+ SELECT e.enumlabel
118
+ FROM pg_enum e
119
+ JOIN pg_type t ON e.enumtypid = t.oid
120
+ WHERE t.typname = $1
121
+ ORDER BY e.enumsortorder
122
+ `, [enumName]);
123
+
124
+ const targetEnumValues = targetEnumValuesResult.rows.map(row => row.enumlabel);
125
+ this.logger.log(`Target enum ${enumName} has values: ${targetEnumValues.join(', ')}`);
126
+
127
+ // Encontrar valores que están en el origen pero no en el destino
128
+ const missingValues = sourceValues.filter(value => !targetEnumValues.includes(value));
129
+
130
+ if (missingValues.length === 0) {
131
+ this.logger.log(`Enum type ${enumName} is already up to date`);
132
+ return;
133
+ }
134
+
135
+ this.logger.log(`Adding ${missingValues.length} new values to enum ${enumName}: ${missingValues.join(', ')}`);
136
+
137
+ // Agregar los valores faltantes al enum
138
+ for (const value of missingValues) {
139
+ await this.targetPool.query(`
140
+ ALTER TYPE ${enumName} ADD VALUE '${value.replace(/'/g, "''")}'
141
+ `);
142
+ }
143
+
144
+ this.logger.log(`Successfully updated enum type ${enumName}`);
145
+ } catch (error) {
146
+ this.logger.error(`Error updating enum type ${enumName}: ${error.message}`);
147
+ }
148
+ }
149
+
150
+ private async cleanup() {
151
+ this.logger.log('Cleaning up database connections');
152
+ await this.sourcePool.end();
153
+ await this.targetPool.end();
154
+ }
155
+ }
156
+
157
+ // Script para ejecutar desde línea de comandos
158
+ if (require.main === module) {
159
+ const run = async () => {
160
+ try {
161
+ const synchronizer = new EnumSynchronizer();
162
+ await synchronizer.synchronizeEnums();
163
+ process.exit(0);
164
+ } catch (error) {
165
+ console.error('Error:', error.message);
166
+ process.exit(1);
167
+ }
168
+ };
169
+
170
+ run();
171
171
  }