@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.
Files changed (50) hide show
  1. package/.github/CODEOWNERS +1 -1
  2. package/README.md +269 -269
  3. package/migration-config.json +63 -63
  4. package/migration-config.json.bk +95 -95
  5. package/migrations/add_reserved_amount.sql +7 -7
  6. package/package.json +44 -44
  7. package/prisma/migrations/add_uuid_to_transactions.sql +13 -13
  8. package/prisma/schema.prisma +609 -601
  9. package/src/index.ts +23 -23
  10. package/src/prisma-factory.service.ts +40 -40
  11. package/src/prisma.module.ts +9 -9
  12. package/src/prisma.service.ts +16 -16
  13. package/src/scripts/add-uuid-to-table.ts +138 -138
  14. package/src/scripts/create-tenant-schemas.ts +145 -145
  15. package/src/scripts/data-migration/batch-migrator.ts +248 -248
  16. package/src/scripts/data-migration/data-transformer.ts +426 -426
  17. package/src/scripts/data-migration/db-connector.ts +120 -120
  18. package/src/scripts/data-migration/dependency-resolver.ts +174 -174
  19. package/src/scripts/data-migration/entity-discovery.ts +196 -196
  20. package/src/scripts/data-migration/foreign-key-manager.ts +277 -277
  21. package/src/scripts/data-migration/migration-config.json +63 -63
  22. package/src/scripts/data-migration/migration-tool.ts +509 -509
  23. package/src/scripts/data-migration/schema-utils.ts +248 -248
  24. package/src/scripts/data-migration/tenant-migrator.ts +201 -201
  25. package/src/scripts/data-migration/typecast-manager.ts +193 -193
  26. package/src/scripts/data-migration/types.ts +113 -113
  27. package/src/scripts/database-initializer.ts +49 -49
  28. package/src/scripts/drop-database.ts +104 -104
  29. package/src/scripts/dump-source-db.sh +61 -61
  30. package/src/scripts/encrypt-user-passwords.ts +36 -36
  31. package/src/scripts/error-handler.ts +117 -117
  32. package/src/scripts/fix-data-types.ts +241 -241
  33. package/src/scripts/fix-enum-values.ts +357 -357
  34. package/src/scripts/fix-schema-discrepancies.ts +317 -317
  35. package/src/scripts/fix-table-indexes.ts +601 -601
  36. package/src/scripts/migrate-schema-structure.ts +90 -90
  37. package/src/scripts/migrate-uuid.ts +76 -76
  38. package/src/scripts/post-migration-validator.ts +526 -526
  39. package/src/scripts/pre-migration-validator.ts +610 -610
  40. package/src/scripts/reset-database.ts +263 -263
  41. package/src/scripts/retry-failed-migrations.ts +416 -416
  42. package/src/scripts/run-migration.ts +707 -707
  43. package/src/scripts/schema-sync.ts +128 -128
  44. package/src/scripts/sequence-sync-cli.ts +416 -416
  45. package/src/scripts/sequence-synchronizer.ts +127 -127
  46. package/src/scripts/sync-enum-types.ts +170 -170
  47. package/src/scripts/sync-enum-values.ts +563 -563
  48. package/src/scripts/truncate-database.ts +123 -123
  49. package/src/scripts/verify-migration-setup.ts +135 -135
  50. 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
  }