@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,248 +1,248 @@
|
|
|
1
|
-
import { Logger } from "@nestjs/common";
|
|
2
|
-
import { ColumnSchema } from "./types";
|
|
3
|
-
|
|
4
|
-
export class SchemaUtils {
|
|
5
|
-
private readonly logger = new Logger("SchemaUtils");
|
|
6
|
-
|
|
7
|
-
constructor(private readonly connections: any) {}
|
|
8
|
-
|
|
9
|
-
// En el método getTableSchema de SchemaUtils
|
|
10
|
-
async getTableSchema(
|
|
11
|
-
tableName: string,
|
|
12
|
-
dbType: "source" | "target",
|
|
13
|
-
schema: string = "public"
|
|
14
|
-
): Promise<ColumnSchema[]> {
|
|
15
|
-
const pool =
|
|
16
|
-
dbType === "source"
|
|
17
|
-
? this.connections.sourcePool
|
|
18
|
-
: this.connections.targetPool;
|
|
19
|
-
|
|
20
|
-
const query = `
|
|
21
|
-
SELECT
|
|
22
|
-
c.table_name,
|
|
23
|
-
c.column_name,
|
|
24
|
-
c.data_type,
|
|
25
|
-
c.udt_name,
|
|
26
|
-
c.character_maximum_length,
|
|
27
|
-
c.is_nullable,
|
|
28
|
-
c.column_default,
|
|
29
|
-
tc.constraint_type
|
|
30
|
-
FROM
|
|
31
|
-
information_schema.columns c
|
|
32
|
-
LEFT JOIN information_schema.constraint_column_usage ccu
|
|
33
|
-
ON c.column_name = ccu.column_name
|
|
34
|
-
AND c.table_name = ccu.table_name
|
|
35
|
-
LEFT JOIN information_schema.table_constraints tc
|
|
36
|
-
ON ccu.constraint_name = tc.constraint_name
|
|
37
|
-
WHERE
|
|
38
|
-
c.table_schema = $1
|
|
39
|
-
AND c.table_name = $2
|
|
40
|
-
ORDER BY
|
|
41
|
-
c.ordinal_position
|
|
42
|
-
`;
|
|
43
|
-
|
|
44
|
-
try {
|
|
45
|
-
const result = await pool.query(query, [schema, tableName]);
|
|
46
|
-
// No transformar los nombres de las columnas, mantener el case original
|
|
47
|
-
return result.rows;
|
|
48
|
-
} catch (error) {
|
|
49
|
-
this.logger.error(
|
|
50
|
-
`Error getting schema for ${schema}.${tableName}: ${error.message}`
|
|
51
|
-
);
|
|
52
|
-
return [];
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
async checkSchemaExists(schemaName: string): Promise<boolean> {
|
|
57
|
-
try {
|
|
58
|
-
const query = `
|
|
59
|
-
SELECT schema_name
|
|
60
|
-
FROM information_schema.schemata
|
|
61
|
-
WHERE schema_name = $1
|
|
62
|
-
`;
|
|
63
|
-
const result = await this.connections.targetPool.query(query, [
|
|
64
|
-
schemaName,
|
|
65
|
-
]);
|
|
66
|
-
return result.rows.length > 0;
|
|
67
|
-
} catch (error) {
|
|
68
|
-
this.logger.error(`Error checking if schema exists: ${error.message}`);
|
|
69
|
-
return false;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
async getTargetTables(schemaName: string): Promise<string[]> {
|
|
74
|
-
try {
|
|
75
|
-
const query = `
|
|
76
|
-
SELECT table_name
|
|
77
|
-
FROM information_schema.tables
|
|
78
|
-
WHERE table_schema = $1
|
|
79
|
-
AND table_type = 'BASE TABLE'
|
|
80
|
-
`;
|
|
81
|
-
const result = await this.connections.targetPool.query(query, [
|
|
82
|
-
schemaName,
|
|
83
|
-
]);
|
|
84
|
-
|
|
85
|
-
// Log para depuración
|
|
86
|
-
this.logger.log(
|
|
87
|
-
`Found ${result.rows.length} tables in schema ${schemaName}`
|
|
88
|
-
);
|
|
89
|
-
result.rows.forEach((row) => {
|
|
90
|
-
this.logger.log(`Table in schema ${schemaName}: ${row.table_name}`);
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
return result.rows.map((row) => row.table_name);
|
|
94
|
-
} catch (error) {
|
|
95
|
-
this.logger.error(`Error getting target tables: ${error.message}`);
|
|
96
|
-
return [];
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
async getEnumValues(schemaName: string, enumName: string): Promise<string[]> {
|
|
101
|
-
try {
|
|
102
|
-
// Consulta para obtener los valores posibles de un enum
|
|
103
|
-
const query = `
|
|
104
|
-
SELECT e.enumlabel
|
|
105
|
-
FROM pg_type t
|
|
106
|
-
JOIN pg_enum e ON t.oid = e.enumtypid
|
|
107
|
-
JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace
|
|
108
|
-
WHERE t.typname = $1
|
|
109
|
-
AND n.nspname = $2
|
|
110
|
-
`;
|
|
111
|
-
const result = await this.connections.targetPool.query(query, [
|
|
112
|
-
enumName,
|
|
113
|
-
schemaName,
|
|
114
|
-
]);
|
|
115
|
-
return result.rows.map((row) => row.enumlabel);
|
|
116
|
-
} catch (error) {
|
|
117
|
-
this.logger.error(
|
|
118
|
-
`Error getting enum values for ${enumName}: ${error.message}`
|
|
119
|
-
);
|
|
120
|
-
return [];
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
async executeQuery(query: string, params: any[] = []): Promise<any> {
|
|
125
|
-
return this.connections.targetPool.query(query, params);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
async queryTargetDb(query: string, params: any[]): Promise<{ rows: any[] }> {
|
|
129
|
-
return this.connections.targetPool.query(query, params);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
async createMissingColumns(
|
|
133
|
-
tableName: string,
|
|
134
|
-
schema: string,
|
|
135
|
-
columns: ColumnSchema[]
|
|
136
|
-
) {
|
|
137
|
-
for (const column of columns) {
|
|
138
|
-
try {
|
|
139
|
-
const query = `
|
|
140
|
-
ALTER TABLE "${schema}"."${tableName}"
|
|
141
|
-
ADD COLUMN IF NOT EXISTS "${column.column_name}" ${column.data_type}
|
|
142
|
-
${column.is_nullable === "NO" ? "NOT NULL" : ""}
|
|
143
|
-
${column.column_default ? `DEFAULT ${column.column_default}` : ""}
|
|
144
|
-
`;
|
|
145
|
-
await this.connections.targetPool.query(query);
|
|
146
|
-
|
|
147
|
-
// Add unique constraint if needed
|
|
148
|
-
if (column.constraint_type === "UNIQUE") {
|
|
149
|
-
const constraintName = `${tableName}_${column.column_name}_unique`;
|
|
150
|
-
const uniqueQuery = `
|
|
151
|
-
DO $$
|
|
152
|
-
BEGIN
|
|
153
|
-
IF NOT EXISTS (
|
|
154
|
-
SELECT 1 FROM pg_constraint WHERE conname = '${constraintName}'
|
|
155
|
-
) THEN
|
|
156
|
-
ALTER TABLE "${schema}"."${tableName}"
|
|
157
|
-
ADD CONSTRAINT "${constraintName}" UNIQUE ("${column.column_name}");
|
|
158
|
-
END IF;
|
|
159
|
-
END $$;
|
|
160
|
-
`;
|
|
161
|
-
await this.connections.targetPool.query(uniqueQuery);
|
|
162
|
-
}
|
|
163
|
-
} catch (error) {
|
|
164
|
-
this.logger.error(
|
|
165
|
-
`Error creating column ${column.column_name}: ${error.message}`
|
|
166
|
-
);
|
|
167
|
-
throw error;
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
async createSchema(schemaName: string): Promise<void> {
|
|
173
|
-
try {
|
|
174
|
-
// Create schema
|
|
175
|
-
await this.connections.targetPool.query(
|
|
176
|
-
`CREATE SCHEMA IF NOT EXISTS "${schemaName}"`
|
|
177
|
-
);
|
|
178
|
-
|
|
179
|
-
// Copy table structure from public schema
|
|
180
|
-
const tables = await this.getPublicTables();
|
|
181
|
-
|
|
182
|
-
for (const table of tables) {
|
|
183
|
-
await this.connections.targetPool.query(`
|
|
184
|
-
CREATE TABLE IF NOT EXISTS "${schemaName}"."${table}" (
|
|
185
|
-
LIKE public."${table}" INCLUDING ALL
|
|
186
|
-
);
|
|
187
|
-
`);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
this.logger.log(`Created schema ${schemaName} with all tables`);
|
|
191
|
-
} catch (error) {
|
|
192
|
-
this.logger.error(
|
|
193
|
-
`Error creating schema ${schemaName}: ${error.message}`
|
|
194
|
-
);
|
|
195
|
-
throw error;
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
private async getPublicTables(): Promise<string[]> {
|
|
200
|
-
const result = await this.connections.targetPool.query(`
|
|
201
|
-
SELECT tablename
|
|
202
|
-
FROM pg_tables
|
|
203
|
-
WHERE schemaname = 'public'
|
|
204
|
-
`);
|
|
205
|
-
return result.rows.map((row) => row.tablename);
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
async getTableColumns(
|
|
209
|
-
schema: string,
|
|
210
|
-
table: string
|
|
211
|
-
): Promise<ColumnSchema[]> {
|
|
212
|
-
const query = `
|
|
213
|
-
SELECT
|
|
214
|
-
column_name,
|
|
215
|
-
data_type,
|
|
216
|
-
is_nullable,
|
|
217
|
-
column_default,
|
|
218
|
-
character_maximum_length,
|
|
219
|
-
numeric_precision,
|
|
220
|
-
numeric_scale
|
|
221
|
-
FROM information_schema.columns
|
|
222
|
-
WHERE table_schema = $1
|
|
223
|
-
AND table_name = $2
|
|
224
|
-
ORDER BY ordinal_position;
|
|
225
|
-
`;
|
|
226
|
-
|
|
227
|
-
try {
|
|
228
|
-
const result = await this.connections.sourcePool.query(query, [
|
|
229
|
-
schema,
|
|
230
|
-
table,
|
|
231
|
-
]);
|
|
232
|
-
return result.rows.map((row: any) => ({
|
|
233
|
-
column_name: row.column_name,
|
|
234
|
-
data_type: row.data_type,
|
|
235
|
-
is_nullable: row.is_nullable,
|
|
236
|
-
column_default: row.column_default,
|
|
237
|
-
character_maximum_length: row.character_maximum_length,
|
|
238
|
-
numeric_precision: row.numeric_precision,
|
|
239
|
-
numeric_scale: row.numeric_scale,
|
|
240
|
-
}));
|
|
241
|
-
} catch (error) {
|
|
242
|
-
this.logger.error(
|
|
243
|
-
`Error obteniendo columnas para ${schema}.${table}: ${error.message}`
|
|
244
|
-
);
|
|
245
|
-
throw error;
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
}
|
|
1
|
+
import { Logger } from "@nestjs/common";
|
|
2
|
+
import { ColumnSchema } from "./types";
|
|
3
|
+
|
|
4
|
+
export class SchemaUtils {
|
|
5
|
+
private readonly logger = new Logger("SchemaUtils");
|
|
6
|
+
|
|
7
|
+
constructor(private readonly connections: any) {}
|
|
8
|
+
|
|
9
|
+
// En el método getTableSchema de SchemaUtils
|
|
10
|
+
async getTableSchema(
|
|
11
|
+
tableName: string,
|
|
12
|
+
dbType: "source" | "target",
|
|
13
|
+
schema: string = "public"
|
|
14
|
+
): Promise<ColumnSchema[]> {
|
|
15
|
+
const pool =
|
|
16
|
+
dbType === "source"
|
|
17
|
+
? this.connections.sourcePool
|
|
18
|
+
: this.connections.targetPool;
|
|
19
|
+
|
|
20
|
+
const query = `
|
|
21
|
+
SELECT
|
|
22
|
+
c.table_name,
|
|
23
|
+
c.column_name,
|
|
24
|
+
c.data_type,
|
|
25
|
+
c.udt_name,
|
|
26
|
+
c.character_maximum_length,
|
|
27
|
+
c.is_nullable,
|
|
28
|
+
c.column_default,
|
|
29
|
+
tc.constraint_type
|
|
30
|
+
FROM
|
|
31
|
+
information_schema.columns c
|
|
32
|
+
LEFT JOIN information_schema.constraint_column_usage ccu
|
|
33
|
+
ON c.column_name = ccu.column_name
|
|
34
|
+
AND c.table_name = ccu.table_name
|
|
35
|
+
LEFT JOIN information_schema.table_constraints tc
|
|
36
|
+
ON ccu.constraint_name = tc.constraint_name
|
|
37
|
+
WHERE
|
|
38
|
+
c.table_schema = $1
|
|
39
|
+
AND c.table_name = $2
|
|
40
|
+
ORDER BY
|
|
41
|
+
c.ordinal_position
|
|
42
|
+
`;
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
const result = await pool.query(query, [schema, tableName]);
|
|
46
|
+
// No transformar los nombres de las columnas, mantener el case original
|
|
47
|
+
return result.rows;
|
|
48
|
+
} catch (error) {
|
|
49
|
+
this.logger.error(
|
|
50
|
+
`Error getting schema for ${schema}.${tableName}: ${error.message}`
|
|
51
|
+
);
|
|
52
|
+
return [];
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async checkSchemaExists(schemaName: string): Promise<boolean> {
|
|
57
|
+
try {
|
|
58
|
+
const query = `
|
|
59
|
+
SELECT schema_name
|
|
60
|
+
FROM information_schema.schemata
|
|
61
|
+
WHERE schema_name = $1
|
|
62
|
+
`;
|
|
63
|
+
const result = await this.connections.targetPool.query(query, [
|
|
64
|
+
schemaName,
|
|
65
|
+
]);
|
|
66
|
+
return result.rows.length > 0;
|
|
67
|
+
} catch (error) {
|
|
68
|
+
this.logger.error(`Error checking if schema exists: ${error.message}`);
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async getTargetTables(schemaName: string): Promise<string[]> {
|
|
74
|
+
try {
|
|
75
|
+
const query = `
|
|
76
|
+
SELECT table_name
|
|
77
|
+
FROM information_schema.tables
|
|
78
|
+
WHERE table_schema = $1
|
|
79
|
+
AND table_type = 'BASE TABLE'
|
|
80
|
+
`;
|
|
81
|
+
const result = await this.connections.targetPool.query(query, [
|
|
82
|
+
schemaName,
|
|
83
|
+
]);
|
|
84
|
+
|
|
85
|
+
// Log para depuración
|
|
86
|
+
this.logger.log(
|
|
87
|
+
`Found ${result.rows.length} tables in schema ${schemaName}`
|
|
88
|
+
);
|
|
89
|
+
result.rows.forEach((row) => {
|
|
90
|
+
this.logger.log(`Table in schema ${schemaName}: ${row.table_name}`);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
return result.rows.map((row) => row.table_name);
|
|
94
|
+
} catch (error) {
|
|
95
|
+
this.logger.error(`Error getting target tables: ${error.message}`);
|
|
96
|
+
return [];
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async getEnumValues(schemaName: string, enumName: string): Promise<string[]> {
|
|
101
|
+
try {
|
|
102
|
+
// Consulta para obtener los valores posibles de un enum
|
|
103
|
+
const query = `
|
|
104
|
+
SELECT e.enumlabel
|
|
105
|
+
FROM pg_type t
|
|
106
|
+
JOIN pg_enum e ON t.oid = e.enumtypid
|
|
107
|
+
JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace
|
|
108
|
+
WHERE t.typname = $1
|
|
109
|
+
AND n.nspname = $2
|
|
110
|
+
`;
|
|
111
|
+
const result = await this.connections.targetPool.query(query, [
|
|
112
|
+
enumName,
|
|
113
|
+
schemaName,
|
|
114
|
+
]);
|
|
115
|
+
return result.rows.map((row) => row.enumlabel);
|
|
116
|
+
} catch (error) {
|
|
117
|
+
this.logger.error(
|
|
118
|
+
`Error getting enum values for ${enumName}: ${error.message}`
|
|
119
|
+
);
|
|
120
|
+
return [];
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async executeQuery(query: string, params: any[] = []): Promise<any> {
|
|
125
|
+
return this.connections.targetPool.query(query, params);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async queryTargetDb(query: string, params: any[]): Promise<{ rows: any[] }> {
|
|
129
|
+
return this.connections.targetPool.query(query, params);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
async createMissingColumns(
|
|
133
|
+
tableName: string,
|
|
134
|
+
schema: string,
|
|
135
|
+
columns: ColumnSchema[]
|
|
136
|
+
) {
|
|
137
|
+
for (const column of columns) {
|
|
138
|
+
try {
|
|
139
|
+
const query = `
|
|
140
|
+
ALTER TABLE "${schema}"."${tableName}"
|
|
141
|
+
ADD COLUMN IF NOT EXISTS "${column.column_name}" ${column.data_type}
|
|
142
|
+
${column.is_nullable === "NO" ? "NOT NULL" : ""}
|
|
143
|
+
${column.column_default ? `DEFAULT ${column.column_default}` : ""}
|
|
144
|
+
`;
|
|
145
|
+
await this.connections.targetPool.query(query);
|
|
146
|
+
|
|
147
|
+
// Add unique constraint if needed
|
|
148
|
+
if (column.constraint_type === "UNIQUE") {
|
|
149
|
+
const constraintName = `${tableName}_${column.column_name}_unique`;
|
|
150
|
+
const uniqueQuery = `
|
|
151
|
+
DO $$
|
|
152
|
+
BEGIN
|
|
153
|
+
IF NOT EXISTS (
|
|
154
|
+
SELECT 1 FROM pg_constraint WHERE conname = '${constraintName}'
|
|
155
|
+
) THEN
|
|
156
|
+
ALTER TABLE "${schema}"."${tableName}"
|
|
157
|
+
ADD CONSTRAINT "${constraintName}" UNIQUE ("${column.column_name}");
|
|
158
|
+
END IF;
|
|
159
|
+
END $$;
|
|
160
|
+
`;
|
|
161
|
+
await this.connections.targetPool.query(uniqueQuery);
|
|
162
|
+
}
|
|
163
|
+
} catch (error) {
|
|
164
|
+
this.logger.error(
|
|
165
|
+
`Error creating column ${column.column_name}: ${error.message}`
|
|
166
|
+
);
|
|
167
|
+
throw error;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
async createSchema(schemaName: string): Promise<void> {
|
|
173
|
+
try {
|
|
174
|
+
// Create schema
|
|
175
|
+
await this.connections.targetPool.query(
|
|
176
|
+
`CREATE SCHEMA IF NOT EXISTS "${schemaName}"`
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
// Copy table structure from public schema
|
|
180
|
+
const tables = await this.getPublicTables();
|
|
181
|
+
|
|
182
|
+
for (const table of tables) {
|
|
183
|
+
await this.connections.targetPool.query(`
|
|
184
|
+
CREATE TABLE IF NOT EXISTS "${schemaName}"."${table}" (
|
|
185
|
+
LIKE public."${table}" INCLUDING ALL
|
|
186
|
+
);
|
|
187
|
+
`);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
this.logger.log(`Created schema ${schemaName} with all tables`);
|
|
191
|
+
} catch (error) {
|
|
192
|
+
this.logger.error(
|
|
193
|
+
`Error creating schema ${schemaName}: ${error.message}`
|
|
194
|
+
);
|
|
195
|
+
throw error;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
private async getPublicTables(): Promise<string[]> {
|
|
200
|
+
const result = await this.connections.targetPool.query(`
|
|
201
|
+
SELECT tablename
|
|
202
|
+
FROM pg_tables
|
|
203
|
+
WHERE schemaname = 'public'
|
|
204
|
+
`);
|
|
205
|
+
return result.rows.map((row) => row.tablename);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
async getTableColumns(
|
|
209
|
+
schema: string,
|
|
210
|
+
table: string
|
|
211
|
+
): Promise<ColumnSchema[]> {
|
|
212
|
+
const query = `
|
|
213
|
+
SELECT
|
|
214
|
+
column_name,
|
|
215
|
+
data_type,
|
|
216
|
+
is_nullable,
|
|
217
|
+
column_default,
|
|
218
|
+
character_maximum_length,
|
|
219
|
+
numeric_precision,
|
|
220
|
+
numeric_scale
|
|
221
|
+
FROM information_schema.columns
|
|
222
|
+
WHERE table_schema = $1
|
|
223
|
+
AND table_name = $2
|
|
224
|
+
ORDER BY ordinal_position;
|
|
225
|
+
`;
|
|
226
|
+
|
|
227
|
+
try {
|
|
228
|
+
const result = await this.connections.sourcePool.query(query, [
|
|
229
|
+
schema,
|
|
230
|
+
table,
|
|
231
|
+
]);
|
|
232
|
+
return result.rows.map((row: any) => ({
|
|
233
|
+
column_name: row.column_name,
|
|
234
|
+
data_type: row.data_type,
|
|
235
|
+
is_nullable: row.is_nullable,
|
|
236
|
+
column_default: row.column_default,
|
|
237
|
+
character_maximum_length: row.character_maximum_length,
|
|
238
|
+
numeric_precision: row.numeric_precision,
|
|
239
|
+
numeric_scale: row.numeric_scale,
|
|
240
|
+
}));
|
|
241
|
+
} catch (error) {
|
|
242
|
+
this.logger.error(
|
|
243
|
+
`Error obteniendo columnas para ${schema}.${table}: ${error.message}`
|
|
244
|
+
);
|
|
245
|
+
throw error;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|