@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,264 +1,264 @@
|
|
|
1
|
-
import * as pg from "pg";
|
|
2
|
-
import * as dotenv from "dotenv";
|
|
3
|
-
import { Logger } from "@nestjs/common";
|
|
4
|
-
import { execSync } from "child_process";
|
|
5
|
-
import { PrismaClient } from "@prisma/client";
|
|
6
|
-
|
|
7
|
-
dotenv.config();
|
|
8
|
-
|
|
9
|
-
export class DatabaseResetTool {
|
|
10
|
-
private readonly logger = new Logger("DatabaseResetTool");
|
|
11
|
-
private readonly pool: pg.Pool;
|
|
12
|
-
private readonly adminPool: pg.Pool;
|
|
13
|
-
private readonly prisma: PrismaClient;
|
|
14
|
-
|
|
15
|
-
constructor(private readonly databaseUrl: string) {
|
|
16
|
-
// Conexión a la base de datos específica
|
|
17
|
-
this.pool = new pg.Pool({
|
|
18
|
-
connectionString: this.databaseUrl,
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
// Conexión a la base de datos postgres (admin)
|
|
22
|
-
const adminUrl = this.databaseUrl.replace(/\/[^/]+$/, "/postgres");
|
|
23
|
-
this.adminPool = new pg.Pool({
|
|
24
|
-
connectionString: adminUrl,
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
// Cliente Prisma
|
|
28
|
-
this.prisma = new PrismaClient({
|
|
29
|
-
datasources: {
|
|
30
|
-
db: {
|
|
31
|
-
url: this.databaseUrl,
|
|
32
|
-
},
|
|
33
|
-
},
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
async resetDatabase(recreateDb = false) {
|
|
38
|
-
try {
|
|
39
|
-
this.logger.log("Starting complete database reset process");
|
|
40
|
-
|
|
41
|
-
// Extraer el nombre de la base de datos de la URL
|
|
42
|
-
const dbName = this.extractDatabaseName(this.databaseUrl);
|
|
43
|
-
|
|
44
|
-
if (!dbName) {
|
|
45
|
-
throw new Error("Could not extract database name from connection URL");
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// 1. Eliminar todos los schemas personalizados y sus contenidos
|
|
49
|
-
await this.dropAllSchemas();
|
|
50
|
-
|
|
51
|
-
// 2. Eliminar todas las tablas del schema public
|
|
52
|
-
await this.dropAllPublicTables();
|
|
53
|
-
|
|
54
|
-
// 3. Eliminar todos los tipos personalizados (enums, etc.)
|
|
55
|
-
await this.dropAllCustomTypes();
|
|
56
|
-
|
|
57
|
-
if (recreateDb) {
|
|
58
|
-
// 4. Terminar todas las conexiones y eliminar la base de datos
|
|
59
|
-
await this.terminateConnections(dbName);
|
|
60
|
-
await this.adminPool.query(`DROP DATABASE IF EXISTS "${dbName}"`);
|
|
61
|
-
|
|
62
|
-
// 5. Recrear la base de datos
|
|
63
|
-
this.logger.log(`Recreating database: ${dbName}`);
|
|
64
|
-
await this.adminPool.query(`CREATE DATABASE "${dbName}"`);
|
|
65
|
-
|
|
66
|
-
// 6. Ejecutar prisma migrate para recrear el esquema base
|
|
67
|
-
this.logger.log("Running prisma migrate to recreate base schema");
|
|
68
|
-
try {
|
|
69
|
-
execSync(`DATABASE_URL="${this.databaseUrl}" npx prisma migrate deploy`, {
|
|
70
|
-
stdio: 'inherit'
|
|
71
|
-
});
|
|
72
|
-
} catch (migrationError) {
|
|
73
|
-
this.logger.error(`Error running prisma migrate: ${migrationError.message}`);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
this.logger.log("Database has been completely reset");
|
|
78
|
-
return true;
|
|
79
|
-
} catch (error) {
|
|
80
|
-
this.logger.error(
|
|
81
|
-
`Error resetting database: ${error.message}`,
|
|
82
|
-
error.stack
|
|
83
|
-
);
|
|
84
|
-
return false;
|
|
85
|
-
} finally {
|
|
86
|
-
await this.cleanup();
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
private async dropAllSchemas() {
|
|
91
|
-
this.logger.log("Dropping all custom schemas");
|
|
92
|
-
|
|
93
|
-
try {
|
|
94
|
-
// Obtener todos los schemas excepto los del sistema
|
|
95
|
-
const schemas = await this.getCustomSchemas();
|
|
96
|
-
this.logger.log(`Found ${schemas.length} custom schemas to drop`);
|
|
97
|
-
|
|
98
|
-
// Desactivar restricciones de clave foránea temporalmente
|
|
99
|
-
await this.pool.query(`SET session_replication_role = 'replica'`);
|
|
100
|
-
|
|
101
|
-
// Eliminar cada schema y su contenido
|
|
102
|
-
for (const schema of schemas) {
|
|
103
|
-
try {
|
|
104
|
-
await this.pool.query(`DROP SCHEMA IF EXISTS "${schema}" CASCADE`);
|
|
105
|
-
this.logger.log(`Dropped schema: ${schema}`);
|
|
106
|
-
} catch (error) {
|
|
107
|
-
this.logger.error(`Error dropping schema ${schema}: ${error.message}`);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// Reactivar restricciones de clave foránea
|
|
112
|
-
await this.pool.query(`SET session_replication_role = 'origin'`);
|
|
113
|
-
} catch (error) {
|
|
114
|
-
this.logger.error(`Error dropping schemas: ${error.message}`);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
private async dropAllPublicTables() {
|
|
119
|
-
this.logger.log("Dropping all tables in public schema");
|
|
120
|
-
|
|
121
|
-
try {
|
|
122
|
-
// Obtener todas las tablas del schema public
|
|
123
|
-
const tables = await this.getPublicTables();
|
|
124
|
-
this.logger.log(`Found ${tables.length} tables in public schema to drop`);
|
|
125
|
-
|
|
126
|
-
if (tables.length > 0) {
|
|
127
|
-
// Desactivar restricciones de clave foránea temporalmente
|
|
128
|
-
await this.pool.query(`SET session_replication_role = 'replica'`);
|
|
129
|
-
|
|
130
|
-
// Eliminar todas las tablas en una sola operación
|
|
131
|
-
const tableList = tables.map(table => `"${table}"`).join(", ");
|
|
132
|
-
if (tableList) {
|
|
133
|
-
await this.pool.query(`DROP TABLE IF EXISTS ${tableList} CASCADE`);
|
|
134
|
-
this.logger.log("Dropped all tables in public schema");
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// Reactivar restricciones de clave foránea
|
|
138
|
-
await this.pool.query(`SET session_replication_role = 'origin'`);
|
|
139
|
-
}
|
|
140
|
-
} catch (error) {
|
|
141
|
-
this.logger.error(`Error dropping public tables: ${error.message}`);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
private async dropAllCustomTypes() {
|
|
146
|
-
this.logger.log("Dropping all custom types (enums, domains, etc.)");
|
|
147
|
-
|
|
148
|
-
try {
|
|
149
|
-
// Obtener todos los tipos personalizados
|
|
150
|
-
const typesQuery = `
|
|
151
|
-
SELECT t.typname AS name
|
|
152
|
-
FROM pg_type t
|
|
153
|
-
JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace
|
|
154
|
-
WHERE n.nspname = 'public'
|
|
155
|
-
AND t.typtype = 'e' -- enum types
|
|
156
|
-
`;
|
|
157
|
-
|
|
158
|
-
const typesResult = await this.pool.query(typesQuery);
|
|
159
|
-
const types = typesResult.rows.map(row => row.name);
|
|
160
|
-
|
|
161
|
-
this.logger.log(`Found ${types.length} custom types to drop`);
|
|
162
|
-
|
|
163
|
-
// Eliminar cada tipo
|
|
164
|
-
for (const type of types) {
|
|
165
|
-
try {
|
|
166
|
-
await this.pool.query(`DROP TYPE IF EXISTS "${type}" CASCADE`);
|
|
167
|
-
this.logger.log(`Dropped type: ${type}`);
|
|
168
|
-
} catch (error) {
|
|
169
|
-
this.logger.error(`Error dropping type ${type}: ${error.message}`);
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
} catch (error) {
|
|
173
|
-
this.logger.error(`Error dropping custom types: ${error.message}`);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
private async getCustomSchemas(): Promise<string[]> {
|
|
178
|
-
const result = await this.pool.query(`
|
|
179
|
-
SELECT schema_name
|
|
180
|
-
FROM information_schema.schemata
|
|
181
|
-
WHERE schema_name NOT IN ('public', 'information_schema', 'pg_catalog', 'pg_toast')
|
|
182
|
-
AND schema_name NOT LIKE 'pg_%'
|
|
183
|
-
`);
|
|
184
|
-
|
|
185
|
-
return result.rows.map(row => row.schema_name);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
private async getPublicTables(): Promise<string[]> {
|
|
189
|
-
const result = await this.pool.query(`
|
|
190
|
-
SELECT table_name
|
|
191
|
-
FROM information_schema.tables
|
|
192
|
-
WHERE table_schema = 'public'
|
|
193
|
-
AND table_type = 'BASE TABLE'
|
|
194
|
-
`);
|
|
195
|
-
|
|
196
|
-
return result.rows.map(row => row.table_name);
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
private extractDatabaseName(url: string): string | null {
|
|
200
|
-
// Extraer el nombre de la base de datos de la URL de conexión
|
|
201
|
-
const matches = url.match(/\/([^/?]+)($|\?)/);
|
|
202
|
-
return matches ? matches[1] : null;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
private async terminateConnections(dbName: string) {
|
|
206
|
-
this.logger.log(`Terminating all connections to database: ${dbName}`);
|
|
207
|
-
|
|
208
|
-
try {
|
|
209
|
-
await this.adminPool.query(`
|
|
210
|
-
SELECT pg_terminate_backend(pg_stat_activity.pid)
|
|
211
|
-
FROM pg_stat_activity
|
|
212
|
-
WHERE pg_stat_activity.datname = $1
|
|
213
|
-
AND pid <> pg_backend_pid()
|
|
214
|
-
`, [dbName]);
|
|
215
|
-
|
|
216
|
-
this.logger.log("All connections terminated successfully");
|
|
217
|
-
} catch (error) {
|
|
218
|
-
this.logger.error(`Error terminating connections: ${error.message}`);
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
private async cleanup() {
|
|
223
|
-
this.logger.log("Cleaning up database connections");
|
|
224
|
-
await this.prisma.$disconnect();
|
|
225
|
-
await this.pool.end();
|
|
226
|
-
await this.adminPool.end();
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
// Script para ejecutar desde línea de comandos
|
|
231
|
-
if (require.main === module) {
|
|
232
|
-
const run = async () => {
|
|
233
|
-
try {
|
|
234
|
-
// Load environment variables first
|
|
235
|
-
dotenv.config();
|
|
236
|
-
|
|
237
|
-
// Get database URL from command line args or .env
|
|
238
|
-
const databaseUrl = process.argv[2] || process.env.DATABASE_URL;
|
|
239
|
-
|
|
240
|
-
if (!databaseUrl) {
|
|
241
|
-
console.error("Error: DATABASE_URL not found in environment variables or command line arguments");
|
|
242
|
-
process.exit(1);
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
// Check for recreate flag
|
|
246
|
-
const recreateFlag = process.argv.includes('--recreate') || process.argv.includes('-r');
|
|
247
|
-
|
|
248
|
-
const resetTool = new DatabaseResetTool(databaseUrl);
|
|
249
|
-
const success = await resetTool.resetDatabase(recreateFlag);
|
|
250
|
-
|
|
251
|
-
if (!success) {
|
|
252
|
-
console.error("Database reset failed");
|
|
253
|
-
process.exit(1);
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
process.exit(0);
|
|
257
|
-
} catch (error) {
|
|
258
|
-
console.error("Error:", error.message);
|
|
259
|
-
process.exit(1);
|
|
260
|
-
}
|
|
261
|
-
};
|
|
262
|
-
|
|
263
|
-
run();
|
|
1
|
+
import * as pg from "pg";
|
|
2
|
+
import * as dotenv from "dotenv";
|
|
3
|
+
import { Logger } from "@nestjs/common";
|
|
4
|
+
import { execSync } from "child_process";
|
|
5
|
+
import { PrismaClient } from "@prisma/client";
|
|
6
|
+
|
|
7
|
+
dotenv.config();
|
|
8
|
+
|
|
9
|
+
export class DatabaseResetTool {
|
|
10
|
+
private readonly logger = new Logger("DatabaseResetTool");
|
|
11
|
+
private readonly pool: pg.Pool;
|
|
12
|
+
private readonly adminPool: pg.Pool;
|
|
13
|
+
private readonly prisma: PrismaClient;
|
|
14
|
+
|
|
15
|
+
constructor(private readonly databaseUrl: string) {
|
|
16
|
+
// Conexión a la base de datos específica
|
|
17
|
+
this.pool = new pg.Pool({
|
|
18
|
+
connectionString: this.databaseUrl,
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
// Conexión a la base de datos postgres (admin)
|
|
22
|
+
const adminUrl = this.databaseUrl.replace(/\/[^/]+$/, "/postgres");
|
|
23
|
+
this.adminPool = new pg.Pool({
|
|
24
|
+
connectionString: adminUrl,
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// Cliente Prisma
|
|
28
|
+
this.prisma = new PrismaClient({
|
|
29
|
+
datasources: {
|
|
30
|
+
db: {
|
|
31
|
+
url: this.databaseUrl,
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async resetDatabase(recreateDb = false) {
|
|
38
|
+
try {
|
|
39
|
+
this.logger.log("Starting complete database reset process");
|
|
40
|
+
|
|
41
|
+
// Extraer el nombre de la base de datos de la URL
|
|
42
|
+
const dbName = this.extractDatabaseName(this.databaseUrl);
|
|
43
|
+
|
|
44
|
+
if (!dbName) {
|
|
45
|
+
throw new Error("Could not extract database name from connection URL");
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// 1. Eliminar todos los schemas personalizados y sus contenidos
|
|
49
|
+
await this.dropAllSchemas();
|
|
50
|
+
|
|
51
|
+
// 2. Eliminar todas las tablas del schema public
|
|
52
|
+
await this.dropAllPublicTables();
|
|
53
|
+
|
|
54
|
+
// 3. Eliminar todos los tipos personalizados (enums, etc.)
|
|
55
|
+
await this.dropAllCustomTypes();
|
|
56
|
+
|
|
57
|
+
if (recreateDb) {
|
|
58
|
+
// 4. Terminar todas las conexiones y eliminar la base de datos
|
|
59
|
+
await this.terminateConnections(dbName);
|
|
60
|
+
await this.adminPool.query(`DROP DATABASE IF EXISTS "${dbName}"`);
|
|
61
|
+
|
|
62
|
+
// 5. Recrear la base de datos
|
|
63
|
+
this.logger.log(`Recreating database: ${dbName}`);
|
|
64
|
+
await this.adminPool.query(`CREATE DATABASE "${dbName}"`);
|
|
65
|
+
|
|
66
|
+
// 6. Ejecutar prisma migrate para recrear el esquema base
|
|
67
|
+
this.logger.log("Running prisma migrate to recreate base schema");
|
|
68
|
+
try {
|
|
69
|
+
execSync(`DATABASE_URL="${this.databaseUrl}" npx prisma migrate deploy`, {
|
|
70
|
+
stdio: 'inherit'
|
|
71
|
+
});
|
|
72
|
+
} catch (migrationError) {
|
|
73
|
+
this.logger.error(`Error running prisma migrate: ${migrationError.message}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
this.logger.log("Database has been completely reset");
|
|
78
|
+
return true;
|
|
79
|
+
} catch (error) {
|
|
80
|
+
this.logger.error(
|
|
81
|
+
`Error resetting database: ${error.message}`,
|
|
82
|
+
error.stack
|
|
83
|
+
);
|
|
84
|
+
return false;
|
|
85
|
+
} finally {
|
|
86
|
+
await this.cleanup();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
private async dropAllSchemas() {
|
|
91
|
+
this.logger.log("Dropping all custom schemas");
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
// Obtener todos los schemas excepto los del sistema
|
|
95
|
+
const schemas = await this.getCustomSchemas();
|
|
96
|
+
this.logger.log(`Found ${schemas.length} custom schemas to drop`);
|
|
97
|
+
|
|
98
|
+
// Desactivar restricciones de clave foránea temporalmente
|
|
99
|
+
await this.pool.query(`SET session_replication_role = 'replica'`);
|
|
100
|
+
|
|
101
|
+
// Eliminar cada schema y su contenido
|
|
102
|
+
for (const schema of schemas) {
|
|
103
|
+
try {
|
|
104
|
+
await this.pool.query(`DROP SCHEMA IF EXISTS "${schema}" CASCADE`);
|
|
105
|
+
this.logger.log(`Dropped schema: ${schema}`);
|
|
106
|
+
} catch (error) {
|
|
107
|
+
this.logger.error(`Error dropping schema ${schema}: ${error.message}`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Reactivar restricciones de clave foránea
|
|
112
|
+
await this.pool.query(`SET session_replication_role = 'origin'`);
|
|
113
|
+
} catch (error) {
|
|
114
|
+
this.logger.error(`Error dropping schemas: ${error.message}`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
private async dropAllPublicTables() {
|
|
119
|
+
this.logger.log("Dropping all tables in public schema");
|
|
120
|
+
|
|
121
|
+
try {
|
|
122
|
+
// Obtener todas las tablas del schema public
|
|
123
|
+
const tables = await this.getPublicTables();
|
|
124
|
+
this.logger.log(`Found ${tables.length} tables in public schema to drop`);
|
|
125
|
+
|
|
126
|
+
if (tables.length > 0) {
|
|
127
|
+
// Desactivar restricciones de clave foránea temporalmente
|
|
128
|
+
await this.pool.query(`SET session_replication_role = 'replica'`);
|
|
129
|
+
|
|
130
|
+
// Eliminar todas las tablas en una sola operación
|
|
131
|
+
const tableList = tables.map(table => `"${table}"`).join(", ");
|
|
132
|
+
if (tableList) {
|
|
133
|
+
await this.pool.query(`DROP TABLE IF EXISTS ${tableList} CASCADE`);
|
|
134
|
+
this.logger.log("Dropped all tables in public schema");
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Reactivar restricciones de clave foránea
|
|
138
|
+
await this.pool.query(`SET session_replication_role = 'origin'`);
|
|
139
|
+
}
|
|
140
|
+
} catch (error) {
|
|
141
|
+
this.logger.error(`Error dropping public tables: ${error.message}`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
private async dropAllCustomTypes() {
|
|
146
|
+
this.logger.log("Dropping all custom types (enums, domains, etc.)");
|
|
147
|
+
|
|
148
|
+
try {
|
|
149
|
+
// Obtener todos los tipos personalizados
|
|
150
|
+
const typesQuery = `
|
|
151
|
+
SELECT t.typname AS name
|
|
152
|
+
FROM pg_type t
|
|
153
|
+
JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace
|
|
154
|
+
WHERE n.nspname = 'public'
|
|
155
|
+
AND t.typtype = 'e' -- enum types
|
|
156
|
+
`;
|
|
157
|
+
|
|
158
|
+
const typesResult = await this.pool.query(typesQuery);
|
|
159
|
+
const types = typesResult.rows.map(row => row.name);
|
|
160
|
+
|
|
161
|
+
this.logger.log(`Found ${types.length} custom types to drop`);
|
|
162
|
+
|
|
163
|
+
// Eliminar cada tipo
|
|
164
|
+
for (const type of types) {
|
|
165
|
+
try {
|
|
166
|
+
await this.pool.query(`DROP TYPE IF EXISTS "${type}" CASCADE`);
|
|
167
|
+
this.logger.log(`Dropped type: ${type}`);
|
|
168
|
+
} catch (error) {
|
|
169
|
+
this.logger.error(`Error dropping type ${type}: ${error.message}`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
} catch (error) {
|
|
173
|
+
this.logger.error(`Error dropping custom types: ${error.message}`);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
private async getCustomSchemas(): Promise<string[]> {
|
|
178
|
+
const result = await this.pool.query(`
|
|
179
|
+
SELECT schema_name
|
|
180
|
+
FROM information_schema.schemata
|
|
181
|
+
WHERE schema_name NOT IN ('public', 'information_schema', 'pg_catalog', 'pg_toast')
|
|
182
|
+
AND schema_name NOT LIKE 'pg_%'
|
|
183
|
+
`);
|
|
184
|
+
|
|
185
|
+
return result.rows.map(row => row.schema_name);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
private async getPublicTables(): Promise<string[]> {
|
|
189
|
+
const result = await this.pool.query(`
|
|
190
|
+
SELECT table_name
|
|
191
|
+
FROM information_schema.tables
|
|
192
|
+
WHERE table_schema = 'public'
|
|
193
|
+
AND table_type = 'BASE TABLE'
|
|
194
|
+
`);
|
|
195
|
+
|
|
196
|
+
return result.rows.map(row => row.table_name);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
private extractDatabaseName(url: string): string | null {
|
|
200
|
+
// Extraer el nombre de la base de datos de la URL de conexión
|
|
201
|
+
const matches = url.match(/\/([^/?]+)($|\?)/);
|
|
202
|
+
return matches ? matches[1] : null;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
private async terminateConnections(dbName: string) {
|
|
206
|
+
this.logger.log(`Terminating all connections to database: ${dbName}`);
|
|
207
|
+
|
|
208
|
+
try {
|
|
209
|
+
await this.adminPool.query(`
|
|
210
|
+
SELECT pg_terminate_backend(pg_stat_activity.pid)
|
|
211
|
+
FROM pg_stat_activity
|
|
212
|
+
WHERE pg_stat_activity.datname = $1
|
|
213
|
+
AND pid <> pg_backend_pid()
|
|
214
|
+
`, [dbName]);
|
|
215
|
+
|
|
216
|
+
this.logger.log("All connections terminated successfully");
|
|
217
|
+
} catch (error) {
|
|
218
|
+
this.logger.error(`Error terminating connections: ${error.message}`);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
private async cleanup() {
|
|
223
|
+
this.logger.log("Cleaning up database connections");
|
|
224
|
+
await this.prisma.$disconnect();
|
|
225
|
+
await this.pool.end();
|
|
226
|
+
await this.adminPool.end();
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Script para ejecutar desde línea de comandos
|
|
231
|
+
if (require.main === module) {
|
|
232
|
+
const run = async () => {
|
|
233
|
+
try {
|
|
234
|
+
// Load environment variables first
|
|
235
|
+
dotenv.config();
|
|
236
|
+
|
|
237
|
+
// Get database URL from command line args or .env
|
|
238
|
+
const databaseUrl = process.argv[2] || process.env.DATABASE_URL;
|
|
239
|
+
|
|
240
|
+
if (!databaseUrl) {
|
|
241
|
+
console.error("Error: DATABASE_URL not found in environment variables or command line arguments");
|
|
242
|
+
process.exit(1);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Check for recreate flag
|
|
246
|
+
const recreateFlag = process.argv.includes('--recreate') || process.argv.includes('-r');
|
|
247
|
+
|
|
248
|
+
const resetTool = new DatabaseResetTool(databaseUrl);
|
|
249
|
+
const success = await resetTool.resetDatabase(recreateFlag);
|
|
250
|
+
|
|
251
|
+
if (!success) {
|
|
252
|
+
console.error("Database reset failed");
|
|
253
|
+
process.exit(1);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
process.exit(0);
|
|
257
|
+
} catch (error) {
|
|
258
|
+
console.error("Error:", error.message);
|
|
259
|
+
process.exit(1);
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
run();
|
|
264
264
|
}
|