linkgress-orm 0.4.9 → 0.4.11
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/dist/entity/db-context.d.ts +7 -3
- package/dist/entity/db-context.d.ts.map +1 -1
- package/dist/entity/db-context.js +24 -23
- package/dist/entity/db-context.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/migration/db-schema-manager.d.ts +3 -0
- package/dist/migration/db-schema-manager.d.ts.map +1 -1
- package/dist/migration/db-schema-manager.js +81 -80
- package/dist/migration/db-schema-manager.js.map +1 -1
- package/dist/migration/enum-migrator.d.ts +3 -0
- package/dist/migration/enum-migrator.d.ts.map +1 -1
- package/dist/migration/enum-migrator.js +15 -14
- package/dist/migration/enum-migrator.js.map +1 -1
- package/dist/migration/migration-runner.d.ts.map +1 -1
- package/dist/migration/migration-runner.js +14 -14
- package/dist/migration/migration-runner.js.map +1 -1
- package/dist/migration/migration.interface.d.ts +3 -2
- package/dist/migration/migration.interface.d.ts.map +1 -1
- package/dist/query/conditions.d.ts +1 -1
- package/dist/query/conditions.d.ts.map +1 -1
- package/dist/query/conditions.js.map +1 -1
- package/package.json +1 -1
|
@@ -46,6 +46,7 @@ class DbSchemaManager {
|
|
|
46
46
|
this.schemaRegistry = schemaRegistry;
|
|
47
47
|
this.rl = null;
|
|
48
48
|
this.logQueries = options?.logQueries ?? false;
|
|
49
|
+
this.logger = options?.logger ?? console.log;
|
|
49
50
|
this.postMigrationHook = options?.postMigrationHook;
|
|
50
51
|
this.sequenceRegistry = options?.sequenceRegistry ?? new Map();
|
|
51
52
|
}
|
|
@@ -90,16 +91,16 @@ class DbSchemaManager {
|
|
|
90
91
|
if (schemas.size === 0)
|
|
91
92
|
return;
|
|
92
93
|
if (this.logQueries) {
|
|
93
|
-
|
|
94
|
+
this.logger('Creating schemas...\n');
|
|
94
95
|
}
|
|
95
96
|
for (const schemaName of schemas) {
|
|
96
97
|
const createSchemaSQL = `CREATE SCHEMA IF NOT EXISTS "${schemaName}"`;
|
|
97
98
|
if (this.logQueries) {
|
|
98
|
-
|
|
99
|
+
this.logger(` Creating schema "${schemaName}"...`);
|
|
99
100
|
}
|
|
100
101
|
await this.client.query(createSchemaSQL);
|
|
101
102
|
if (this.logQueries) {
|
|
102
|
-
|
|
103
|
+
this.logger(` ✓ Schema "${schemaName}" created\n`);
|
|
103
104
|
}
|
|
104
105
|
}
|
|
105
106
|
}
|
|
@@ -111,7 +112,7 @@ class DbSchemaManager {
|
|
|
111
112
|
if (enums.size === 0)
|
|
112
113
|
return;
|
|
113
114
|
if (this.logQueries) {
|
|
114
|
-
|
|
115
|
+
this.logger('Creating ENUM types...\n');
|
|
115
116
|
}
|
|
116
117
|
for (const [enumName, enumDef] of enums.entries()) {
|
|
117
118
|
// Check if enum already exists
|
|
@@ -126,15 +127,15 @@ class DbSchemaManager {
|
|
|
126
127
|
const values = enumDef.values.map(v => `'${v}'`).join(', ');
|
|
127
128
|
const createEnumSQL = `CREATE TYPE "${enumName}" AS ENUM (${values})`;
|
|
128
129
|
if (this.logQueries) {
|
|
129
|
-
|
|
130
|
+
this.logger(` Creating ENUM type "${enumName}"...`);
|
|
130
131
|
}
|
|
131
132
|
await this.client.query(createEnumSQL);
|
|
132
133
|
if (this.logQueries) {
|
|
133
|
-
|
|
134
|
+
this.logger(` ✓ ENUM type "${enumName}" created\n`);
|
|
134
135
|
}
|
|
135
136
|
}
|
|
136
137
|
else if (this.logQueries) {
|
|
137
|
-
|
|
138
|
+
this.logger(` ENUM type "${enumName}" already exists, skipping\n`);
|
|
138
139
|
}
|
|
139
140
|
}
|
|
140
141
|
}
|
|
@@ -145,7 +146,7 @@ class DbSchemaManager {
|
|
|
145
146
|
if (this.sequenceRegistry.size === 0)
|
|
146
147
|
return;
|
|
147
148
|
if (this.logQueries) {
|
|
148
|
-
|
|
149
|
+
this.logger('Creating sequences...\n');
|
|
149
150
|
}
|
|
150
151
|
for (const [_, config] of this.sequenceRegistry.entries()) {
|
|
151
152
|
const qualifiedName = config.schema
|
|
@@ -190,15 +191,15 @@ class DbSchemaManager {
|
|
|
190
191
|
createSQL += ` ${options.join(' ')}`;
|
|
191
192
|
}
|
|
192
193
|
if (this.logQueries) {
|
|
193
|
-
|
|
194
|
+
this.logger(` Creating sequence ${qualifiedName}...`);
|
|
194
195
|
}
|
|
195
196
|
await this.client.query(createSQL);
|
|
196
197
|
if (this.logQueries) {
|
|
197
|
-
|
|
198
|
+
this.logger(` ✓ Sequence ${qualifiedName} created\n`);
|
|
198
199
|
}
|
|
199
200
|
}
|
|
200
201
|
else if (this.logQueries) {
|
|
201
|
-
|
|
202
|
+
this.logger(` Sequence ${qualifiedName} already exists, skipping\n`);
|
|
202
203
|
}
|
|
203
204
|
}
|
|
204
205
|
}
|
|
@@ -294,11 +295,11 @@ class DbSchemaManager {
|
|
|
294
295
|
)
|
|
295
296
|
`;
|
|
296
297
|
if (this.logQueries) {
|
|
297
|
-
|
|
298
|
+
this.logger(` Creating table ${qualifiedTableName}...`);
|
|
298
299
|
}
|
|
299
300
|
await this.client.query(createTableSQL);
|
|
300
301
|
if (this.logQueries) {
|
|
301
|
-
|
|
302
|
+
this.logger(` ✓ Table ${qualifiedTableName} created\n`);
|
|
302
303
|
}
|
|
303
304
|
}
|
|
304
305
|
/**
|
|
@@ -322,11 +323,11 @@ class DbSchemaManager {
|
|
|
322
323
|
alterSQL += ` ON UPDATE ${fk.onUpdate.toUpperCase()}`;
|
|
323
324
|
}
|
|
324
325
|
if (this.logQueries) {
|
|
325
|
-
|
|
326
|
+
this.logger(` Adding foreign key ${fk.name} to ${qualifiedTableName}...`);
|
|
326
327
|
}
|
|
327
328
|
await this.client.query(alterSQL);
|
|
328
329
|
if (this.logQueries) {
|
|
329
|
-
|
|
330
|
+
this.logger(` ✓ Foreign key ${fk.name} added\n`);
|
|
330
331
|
}
|
|
331
332
|
}
|
|
332
333
|
// Fallback: Add foreign key constraints from column references (for backward compatibility)
|
|
@@ -337,11 +338,11 @@ class DbSchemaManager {
|
|
|
337
338
|
const fkName = `fk_${tableName}_${config.name}`;
|
|
338
339
|
const alterSQL = `ALTER TABLE ${qualifiedTableName} ADD CONSTRAINT "${fkName}" FOREIGN KEY ("${config.name}") REFERENCES "${config.references.table}"("${config.references.column}")`;
|
|
339
340
|
if (this.logQueries) {
|
|
340
|
-
|
|
341
|
+
this.logger(` Adding foreign key ${fkName} to ${qualifiedTableName}...`);
|
|
341
342
|
}
|
|
342
343
|
await this.client.query(alterSQL);
|
|
343
344
|
if (this.logQueries) {
|
|
344
|
-
|
|
345
|
+
this.logger(` ✓ Foreign key ${fkName} added\n`);
|
|
345
346
|
}
|
|
346
347
|
}
|
|
347
348
|
}
|
|
@@ -407,7 +408,7 @@ class DbSchemaManager {
|
|
|
407
408
|
// Fall back to original order and let the database handle it
|
|
408
409
|
if (sorted.length !== tables.length) {
|
|
409
410
|
if (this.logQueries) {
|
|
410
|
-
|
|
411
|
+
this.logger('Warning: Circular dependency detected in table foreign keys, using original order\n', 'warn');
|
|
411
412
|
}
|
|
412
413
|
return tables;
|
|
413
414
|
}
|
|
@@ -418,7 +419,7 @@ class DbSchemaManager {
|
|
|
418
419
|
*/
|
|
419
420
|
async ensureCreated() {
|
|
420
421
|
if (this.logQueries) {
|
|
421
|
-
|
|
422
|
+
this.logger('Creating database schema...\n');
|
|
422
423
|
}
|
|
423
424
|
// Create schemas first
|
|
424
425
|
await this.createSchemas();
|
|
@@ -436,16 +437,16 @@ class DbSchemaManager {
|
|
|
436
437
|
await this.createIndexes(tableName, tableSchema);
|
|
437
438
|
}
|
|
438
439
|
if (this.logQueries) {
|
|
439
|
-
|
|
440
|
+
this.logger('✓ Database schema created successfully\n');
|
|
440
441
|
}
|
|
441
442
|
// Execute post-migration hook if provided
|
|
442
443
|
if (this.postMigrationHook) {
|
|
443
444
|
if (this.logQueries) {
|
|
444
|
-
|
|
445
|
+
this.logger('Executing post-migration scripts...\n');
|
|
445
446
|
}
|
|
446
447
|
await this.postMigrationHook(this.client);
|
|
447
448
|
if (this.logQueries) {
|
|
448
|
-
|
|
449
|
+
this.logger('✓ Post-migration scripts completed\n');
|
|
449
450
|
}
|
|
450
451
|
}
|
|
451
452
|
}
|
|
@@ -463,46 +464,46 @@ class DbSchemaManager {
|
|
|
463
464
|
*/
|
|
464
465
|
async ensureDeleted() {
|
|
465
466
|
if (this.logQueries) {
|
|
466
|
-
|
|
467
|
+
this.logger('Dropping database schema...\n');
|
|
467
468
|
}
|
|
468
469
|
for (const [tableName, tableSchema] of this.schemaRegistry.entries()) {
|
|
469
470
|
const qualifiedTableName = this.getQualifiedTableName(tableName, tableSchema.schema);
|
|
470
471
|
if (this.logQueries) {
|
|
471
|
-
|
|
472
|
+
this.logger(` Dropping table ${qualifiedTableName}...`);
|
|
472
473
|
}
|
|
473
474
|
await this.client.query(`DROP TABLE IF EXISTS ${qualifiedTableName} CASCADE`);
|
|
474
475
|
if (this.logQueries) {
|
|
475
|
-
|
|
476
|
+
this.logger(` ✓ Table ${qualifiedTableName} dropped\n`);
|
|
476
477
|
}
|
|
477
478
|
}
|
|
478
479
|
// Drop sequences
|
|
479
480
|
if (this.sequenceRegistry.size > 0 && this.logQueries) {
|
|
480
|
-
|
|
481
|
+
this.logger('Dropping sequences...\n');
|
|
481
482
|
}
|
|
482
483
|
for (const [_, config] of this.sequenceRegistry.entries()) {
|
|
483
484
|
const qualifiedName = config.schema
|
|
484
485
|
? `"${config.schema}"."${config.name}"`
|
|
485
486
|
: `"${config.name}"`;
|
|
486
487
|
if (this.logQueries) {
|
|
487
|
-
|
|
488
|
+
this.logger(` Dropping sequence ${qualifiedName}...`);
|
|
488
489
|
}
|
|
489
490
|
await this.client.query(`DROP SEQUENCE IF EXISTS ${qualifiedName} CASCADE`);
|
|
490
491
|
if (this.logQueries) {
|
|
491
|
-
|
|
492
|
+
this.logger(` ✓ Sequence ${qualifiedName} dropped\n`);
|
|
492
493
|
}
|
|
493
494
|
}
|
|
494
495
|
// Drop enum types
|
|
495
496
|
const enums = enum_builder_1.EnumTypeRegistry.getAll();
|
|
496
497
|
if (enums.size > 0 && this.logQueries) {
|
|
497
|
-
|
|
498
|
+
this.logger('Dropping ENUM types...\n');
|
|
498
499
|
}
|
|
499
500
|
for (const [enumName, _] of enums.entries()) {
|
|
500
501
|
if (this.logQueries) {
|
|
501
|
-
|
|
502
|
+
this.logger(` Dropping ENUM type "${enumName}"...`);
|
|
502
503
|
}
|
|
503
504
|
await this.client.query(`DROP TYPE IF EXISTS "${enumName}" CASCADE`);
|
|
504
505
|
if (this.logQueries) {
|
|
505
|
-
|
|
506
|
+
this.logger(` ✓ ENUM type "${enumName}" dropped\n`);
|
|
506
507
|
}
|
|
507
508
|
}
|
|
508
509
|
// Drop schemas (note: CASCADE will drop all objects in the schema)
|
|
@@ -513,26 +514,26 @@ class DbSchemaManager {
|
|
|
513
514
|
}
|
|
514
515
|
}
|
|
515
516
|
if (schemas.size > 0 && this.logQueries) {
|
|
516
|
-
|
|
517
|
+
this.logger('Dropping schemas...\n');
|
|
517
518
|
}
|
|
518
519
|
for (const schemaName of schemas) {
|
|
519
520
|
if (this.logQueries) {
|
|
520
|
-
|
|
521
|
+
this.logger(` Dropping schema "${schemaName}"...`);
|
|
521
522
|
}
|
|
522
523
|
await this.client.query(`DROP SCHEMA IF EXISTS "${schemaName}" CASCADE`);
|
|
523
524
|
if (this.logQueries) {
|
|
524
|
-
|
|
525
|
+
this.logger(` ✓ Schema "${schemaName}" dropped\n`);
|
|
525
526
|
}
|
|
526
527
|
}
|
|
527
528
|
if (this.logQueries) {
|
|
528
|
-
|
|
529
|
+
this.logger('✓ Database schema dropped successfully\n');
|
|
529
530
|
}
|
|
530
531
|
}
|
|
531
532
|
/**
|
|
532
533
|
* Analyze differences between current DB and model schema
|
|
533
534
|
*/
|
|
534
535
|
async analyze() {
|
|
535
|
-
|
|
536
|
+
this.logger('🔍 Analyzing database schema...\n');
|
|
536
537
|
const operations = [];
|
|
537
538
|
// Check schemas
|
|
538
539
|
const modelSchemas = new Set();
|
|
@@ -662,7 +663,7 @@ class DbSchemaManager {
|
|
|
662
663
|
try {
|
|
663
664
|
const operations = await this.analyze();
|
|
664
665
|
if (operations.length === 0) {
|
|
665
|
-
|
|
666
|
+
this.logger('✓ Database schema is already in sync with model\n');
|
|
666
667
|
return;
|
|
667
668
|
}
|
|
668
669
|
// Separate operations into phases:
|
|
@@ -744,43 +745,43 @@ class DbSchemaManager {
|
|
|
744
745
|
}
|
|
745
746
|
}
|
|
746
747
|
const totalOps = phase1Ops.length + phase2Ops.length + phase3Ops.length;
|
|
747
|
-
|
|
748
|
+
this.logger(`📋 Found ${totalOps} operations to perform:\n`);
|
|
748
749
|
// Show all operations
|
|
749
750
|
let opNum = 1;
|
|
750
751
|
for (const op of [...phase1Ops, ...phase2Ops, ...phase3Ops]) {
|
|
751
|
-
|
|
752
|
+
this.logger(`${opNum++}. ${this.describeOperation(op)}`);
|
|
752
753
|
}
|
|
753
|
-
|
|
754
|
+
this.logger('');
|
|
754
755
|
// Phase 1: Create schemas, enums, tables (without FKs), column changes
|
|
755
756
|
if (phase1Ops.length > 0) {
|
|
756
|
-
|
|
757
|
+
this.logger('📦 Phase 1: Creating schemas, enums, and tables...\n');
|
|
757
758
|
for (const operation of phase1Ops) {
|
|
758
759
|
await this.executeOperation(operation, { skipForeignKeys: tablesToCreate.has(operation.tableName) });
|
|
759
760
|
}
|
|
760
761
|
}
|
|
761
762
|
// Phase 2: Add foreign key constraints
|
|
762
763
|
if (phase2Ops.length > 0) {
|
|
763
|
-
|
|
764
|
+
this.logger('🔗 Phase 2: Adding foreign key constraints...\n');
|
|
764
765
|
for (const operation of phase2Ops) {
|
|
765
766
|
await this.executeOperation(operation);
|
|
766
767
|
}
|
|
767
768
|
}
|
|
768
769
|
// Phase 3: Create indexes and other operations
|
|
769
770
|
if (phase3Ops.length > 0) {
|
|
770
|
-
|
|
771
|
+
this.logger('📇 Phase 3: Creating indexes...\n');
|
|
771
772
|
for (const operation of phase3Ops) {
|
|
772
773
|
await this.executeOperation(operation);
|
|
773
774
|
}
|
|
774
775
|
}
|
|
775
|
-
|
|
776
|
+
this.logger('\n✓ Migration completed successfully\n');
|
|
776
777
|
// Execute post-migration hook if provided
|
|
777
778
|
if (this.postMigrationHook) {
|
|
778
779
|
if (this.logQueries) {
|
|
779
|
-
|
|
780
|
+
this.logger('Executing post-migration scripts...\n');
|
|
780
781
|
}
|
|
781
782
|
await this.postMigrationHook(this.client);
|
|
782
783
|
if (this.logQueries) {
|
|
783
|
-
|
|
784
|
+
this.logger('✓ Post-migration scripts completed\n');
|
|
784
785
|
}
|
|
785
786
|
}
|
|
786
787
|
}
|
|
@@ -810,7 +811,7 @@ class DbSchemaManager {
|
|
|
810
811
|
await this.executeDropTable(operation.tableName);
|
|
811
812
|
}
|
|
812
813
|
else {
|
|
813
|
-
|
|
814
|
+
this.logger(` ⊘ Skipped dropping table "${operation.tableName}"\n`, 'warn');
|
|
814
815
|
}
|
|
815
816
|
break;
|
|
816
817
|
case 'add_column':
|
|
@@ -821,7 +822,7 @@ class DbSchemaManager {
|
|
|
821
822
|
await this.executeDropColumn(operation.tableName, operation.columnName, operation.schema);
|
|
822
823
|
}
|
|
823
824
|
else {
|
|
824
|
-
|
|
825
|
+
this.logger(` ⊘ Skipped dropping column "${operation.tableName}"."${operation.columnName}"\n`, 'warn');
|
|
825
826
|
}
|
|
826
827
|
break;
|
|
827
828
|
case 'alter_column':
|
|
@@ -835,7 +836,7 @@ class DbSchemaManager {
|
|
|
835
836
|
await this.executeDropIndex(operation.indexName, operation.schema);
|
|
836
837
|
}
|
|
837
838
|
else {
|
|
838
|
-
|
|
839
|
+
this.logger(` ⊘ Skipped dropping index "${operation.indexName}"\n`, 'warn');
|
|
839
840
|
}
|
|
840
841
|
break;
|
|
841
842
|
case 'create_foreign_key':
|
|
@@ -846,7 +847,7 @@ class DbSchemaManager {
|
|
|
846
847
|
await this.executeDropForeignKey(operation.tableName, operation.constraintName, operation.schema);
|
|
847
848
|
}
|
|
848
849
|
else {
|
|
849
|
-
|
|
850
|
+
this.logger(` ⊘ Skipped dropping foreign key "${operation.constraintName}"\n`, 'warn');
|
|
850
851
|
}
|
|
851
852
|
break;
|
|
852
853
|
}
|
|
@@ -855,18 +856,18 @@ class DbSchemaManager {
|
|
|
855
856
|
* Execute create schema
|
|
856
857
|
*/
|
|
857
858
|
async executeCreateSchema(schemaName) {
|
|
858
|
-
|
|
859
|
+
this.logger(` Creating schema "${schemaName}"...`);
|
|
859
860
|
await this.client.query(`CREATE SCHEMA IF NOT EXISTS "${schemaName}"`);
|
|
860
|
-
|
|
861
|
+
this.logger(` ✓ Schema "${schemaName}" created\n`);
|
|
861
862
|
}
|
|
862
863
|
/**
|
|
863
864
|
* Execute create enum
|
|
864
865
|
*/
|
|
865
866
|
async executeCreateEnum(enumName, values) {
|
|
866
|
-
|
|
867
|
+
this.logger(` Creating ENUM type "${enumName}"...`);
|
|
867
868
|
const valueList = values.map(v => `'${v}'`).join(', ');
|
|
868
869
|
await this.client.query(`CREATE TYPE "${enumName}" AS ENUM (${valueList})`);
|
|
869
|
-
|
|
870
|
+
this.logger(` ✓ ENUM type "${enumName}" created\n`);
|
|
870
871
|
}
|
|
871
872
|
/**
|
|
872
873
|
* Execute create sequence
|
|
@@ -875,7 +876,7 @@ class DbSchemaManager {
|
|
|
875
876
|
const qualifiedName = config.schema
|
|
876
877
|
? `"${config.schema}"."${config.name}"`
|
|
877
878
|
: `"${config.name}"`;
|
|
878
|
-
|
|
879
|
+
this.logger(` Creating sequence ${qualifiedName}...`);
|
|
879
880
|
// Build CREATE SEQUENCE statement
|
|
880
881
|
let createSQL = `CREATE SEQUENCE ${qualifiedName}`;
|
|
881
882
|
const options = [];
|
|
@@ -901,22 +902,22 @@ class DbSchemaManager {
|
|
|
901
902
|
createSQL += ` ${options.join(' ')}`;
|
|
902
903
|
}
|
|
903
904
|
await this.client.query(createSQL);
|
|
904
|
-
|
|
905
|
+
this.logger(` ✓ Sequence ${qualifiedName} created\n`);
|
|
905
906
|
}
|
|
906
907
|
/**
|
|
907
908
|
* Execute drop table
|
|
908
909
|
*/
|
|
909
910
|
async executeDropTable(tableName) {
|
|
910
|
-
|
|
911
|
+
this.logger(` Dropping table "${tableName}"...`);
|
|
911
912
|
await this.client.query(`DROP TABLE "${tableName}" CASCADE`);
|
|
912
|
-
|
|
913
|
+
this.logger(` ✓ Table "${tableName}" dropped\n`);
|
|
913
914
|
}
|
|
914
915
|
/**
|
|
915
916
|
* Execute add column
|
|
916
917
|
*/
|
|
917
918
|
async executeAddColumn(tableName, columnName, config, schema) {
|
|
918
919
|
const qualifiedTableName = this.getQualifiedTableName(tableName, schema);
|
|
919
|
-
|
|
920
|
+
this.logger(` Adding column ${qualifiedTableName}."${columnName}"...`);
|
|
920
921
|
let def = `${config.type}`;
|
|
921
922
|
if (config.length) {
|
|
922
923
|
def += `(${config.length})`;
|
|
@@ -938,25 +939,25 @@ class DbSchemaManager {
|
|
|
938
939
|
}
|
|
939
940
|
const sql = `ALTER TABLE ${qualifiedTableName} ADD COLUMN "${columnName}" ${def}`;
|
|
940
941
|
await this.client.query(sql);
|
|
941
|
-
|
|
942
|
+
this.logger(` ✓ Column ${qualifiedTableName}."${columnName}" added\n`);
|
|
942
943
|
}
|
|
943
944
|
/**
|
|
944
945
|
* Execute drop column
|
|
945
946
|
*/
|
|
946
947
|
async executeDropColumn(tableName, columnName, schema) {
|
|
947
948
|
const qualifiedTableName = this.getQualifiedTableName(tableName, schema);
|
|
948
|
-
|
|
949
|
+
this.logger(` Dropping column ${qualifiedTableName}."${columnName}"...`);
|
|
949
950
|
await this.client.query(`ALTER TABLE ${qualifiedTableName} DROP COLUMN "${columnName}"`);
|
|
950
|
-
|
|
951
|
+
this.logger(` ✓ Column ${qualifiedTableName}."${columnName}" dropped\n`);
|
|
951
952
|
}
|
|
952
953
|
/**
|
|
953
954
|
* Execute alter column
|
|
954
955
|
*/
|
|
955
956
|
async executeAlterColumn(tableName, columnName, from, to, schema) {
|
|
956
957
|
const qualifiedTableName = this.getQualifiedTableName(tableName, schema);
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
958
|
+
this.logger(` Altering column ${qualifiedTableName}."${columnName}"...`);
|
|
959
|
+
this.logger(` From: ${this.describeDbColumn(from)}`);
|
|
960
|
+
this.logger(` To: ${this.describeModelColumn(to)}`);
|
|
960
961
|
// PostgreSQL requires separate ALTER COLUMN commands for different changes
|
|
961
962
|
// Change type if needed - resolve ARRAY/USER-DEFINED via udt_name before normalizing
|
|
962
963
|
const fromType = this.normalizeType(this.resolveDbType(from));
|
|
@@ -964,7 +965,7 @@ class DbSchemaManager {
|
|
|
964
965
|
if (fromType !== toType) {
|
|
965
966
|
const typeDef = this.buildTypeDefinition(to);
|
|
966
967
|
await this.client.query(`ALTER TABLE ${qualifiedTableName} ALTER COLUMN "${columnName}" TYPE ${typeDef} USING "${columnName}"::${typeDef}`);
|
|
967
|
-
|
|
968
|
+
this.logger(` ✓ Type changed from ${fromType} to ${toType}`);
|
|
968
969
|
}
|
|
969
970
|
// Change nullability if needed
|
|
970
971
|
const fromNullable = from.is_nullable === 'YES';
|
|
@@ -972,11 +973,11 @@ class DbSchemaManager {
|
|
|
972
973
|
if (fromNullable !== toNullable) {
|
|
973
974
|
if (toNullable) {
|
|
974
975
|
await this.client.query(`ALTER TABLE ${qualifiedTableName} ALTER COLUMN "${columnName}" DROP NOT NULL`);
|
|
975
|
-
|
|
976
|
+
this.logger(` ✓ Nullability changed to NULLABLE`);
|
|
976
977
|
}
|
|
977
978
|
else {
|
|
978
979
|
await this.client.query(`ALTER TABLE ${qualifiedTableName} ALTER COLUMN "${columnName}" SET NOT NULL`);
|
|
979
|
-
|
|
980
|
+
this.logger(` ✓ Nullability changed to NOT NULL`);
|
|
980
981
|
}
|
|
981
982
|
}
|
|
982
983
|
// Change default if needed
|
|
@@ -985,14 +986,14 @@ class DbSchemaManager {
|
|
|
985
986
|
if (fromDefault !== toDefault) {
|
|
986
987
|
if (toDefault !== null) {
|
|
987
988
|
await this.client.query(`ALTER TABLE ${qualifiedTableName} ALTER COLUMN "${columnName}" SET DEFAULT ${toDefault}`);
|
|
988
|
-
|
|
989
|
+
this.logger(` ✓ Default changed to ${toDefault}`);
|
|
989
990
|
}
|
|
990
991
|
else {
|
|
991
992
|
await this.client.query(`ALTER TABLE ${qualifiedTableName} ALTER COLUMN "${columnName}" DROP DEFAULT`);
|
|
992
|
-
|
|
993
|
+
this.logger(` ✓ Default removed`);
|
|
993
994
|
}
|
|
994
995
|
}
|
|
995
|
-
|
|
996
|
+
this.logger(` ✓ Column ${qualifiedTableName}."${columnName}" altered\n`);
|
|
996
997
|
}
|
|
997
998
|
/**
|
|
998
999
|
* Execute create index
|
|
@@ -1000,20 +1001,20 @@ class DbSchemaManager {
|
|
|
1000
1001
|
async executeCreateIndex(tableName, indexName, columns, isUnique, schema) {
|
|
1001
1002
|
const uniqueStr = isUnique ? 'UNIQUE ' : '';
|
|
1002
1003
|
const qualifiedTableName = this.getQualifiedTableName(tableName, schema);
|
|
1003
|
-
|
|
1004
|
+
this.logger(` Creating ${uniqueStr}index "${indexName}" on ${qualifiedTableName}...`);
|
|
1004
1005
|
const columnList = columns.map(col => `"${col}"`).join(', ');
|
|
1005
1006
|
const sql = `CREATE ${uniqueStr}INDEX IF NOT EXISTS "${indexName}" ON ${qualifiedTableName} (${columnList})`;
|
|
1006
1007
|
await this.client.query(sql);
|
|
1007
|
-
|
|
1008
|
+
this.logger(` ✓ ${uniqueStr}Index "${indexName}" created\n`);
|
|
1008
1009
|
}
|
|
1009
1010
|
/**
|
|
1010
1011
|
* Execute drop index
|
|
1011
1012
|
*/
|
|
1012
1013
|
async executeDropIndex(indexName, schema) {
|
|
1013
1014
|
const qualifiedIndexName = schema ? `"${schema}"."${indexName}"` : `"${indexName}"`;
|
|
1014
|
-
|
|
1015
|
+
this.logger(` Dropping index ${qualifiedIndexName}...`);
|
|
1015
1016
|
await this.client.query(`DROP INDEX ${qualifiedIndexName}`);
|
|
1016
|
-
|
|
1017
|
+
this.logger(` ✓ Index ${qualifiedIndexName} dropped\n`);
|
|
1017
1018
|
}
|
|
1018
1019
|
/**
|
|
1019
1020
|
* Execute create foreign key
|
|
@@ -1022,7 +1023,7 @@ class DbSchemaManager {
|
|
|
1022
1023
|
const qualifiedTableName = this.getQualifiedTableName(tableName, schema);
|
|
1023
1024
|
const referencedTableSchema = this.schemaRegistry?.get(constraint.referencedTable);
|
|
1024
1025
|
const qualifiedReferencedTable = this.getQualifiedTableName(constraint.referencedTable, referencedTableSchema?.schema);
|
|
1025
|
-
|
|
1026
|
+
this.logger(` Creating foreign key constraint "${constraint.name}" on ${qualifiedTableName}...`);
|
|
1026
1027
|
const columnList = constraint.columns.map((col) => `"${col}"`).join(', ');
|
|
1027
1028
|
const refColumnList = constraint.referencedColumns.map((col) => `"${col}"`).join(', ');
|
|
1028
1029
|
let sql = `ALTER TABLE ${qualifiedTableName} ADD CONSTRAINT "${constraint.name}" `;
|
|
@@ -1035,16 +1036,16 @@ class DbSchemaManager {
|
|
|
1035
1036
|
sql += ` ON UPDATE ${constraint.onUpdate.toUpperCase()}`;
|
|
1036
1037
|
}
|
|
1037
1038
|
await this.client.query(sql);
|
|
1038
|
-
|
|
1039
|
+
this.logger(` ✓ Foreign key constraint "${constraint.name}" created\n`);
|
|
1039
1040
|
}
|
|
1040
1041
|
/**
|
|
1041
1042
|
* Execute drop foreign key
|
|
1042
1043
|
*/
|
|
1043
1044
|
async executeDropForeignKey(tableName, constraintName, schema) {
|
|
1044
1045
|
const qualifiedTableName = this.getQualifiedTableName(tableName, schema);
|
|
1045
|
-
|
|
1046
|
+
this.logger(` Dropping foreign key constraint "${constraintName}" from ${qualifiedTableName}...`);
|
|
1046
1047
|
await this.client.query(`ALTER TABLE ${qualifiedTableName} DROP CONSTRAINT "${constraintName}"`);
|
|
1047
|
-
|
|
1048
|
+
this.logger(` ✓ Foreign key constraint "${constraintName}" dropped\n`);
|
|
1048
1049
|
}
|
|
1049
1050
|
/**
|
|
1050
1051
|
* Get all existing tables in the database across all schemas used by the model
|
|
@@ -1376,7 +1377,7 @@ class DbSchemaManager {
|
|
|
1376
1377
|
async confirm(question) {
|
|
1377
1378
|
// If not running in a TTY (like in tests), default to NO for destructive operations
|
|
1378
1379
|
if (!process.stdin.isTTY) {
|
|
1379
|
-
|
|
1380
|
+
this.logger(`\n⚠️ ${question} [y/N]: N (non-interactive mode, defaulting to NO)`, 'warn');
|
|
1380
1381
|
return false;
|
|
1381
1382
|
}
|
|
1382
1383
|
const rl = this.getReadlineInterface();
|