From fd00e0a1591c04549420873177eaf1f948a7d74e Mon Sep 17 00:00:00 2001 From: Carlos Date: Wed, 1 Oct 2025 21:08:50 +0200 Subject: [PATCH 1/7] fix deletion from qf project middle table --- .../1779182511001-AddIdToProjectQfRound.ts | 51 ++++++++++++++++--- src/entities/projectQfRound.ts | 14 ++--- 2 files changed, 51 insertions(+), 14 deletions(-) diff --git a/migration/1779182511001-AddIdToProjectQfRound.ts b/migration/1779182511001-AddIdToProjectQfRound.ts index 53f9ba187..87ab6e11c 100644 --- a/migration/1779182511001-AddIdToProjectQfRound.ts +++ b/migration/1779182511001-AddIdToProjectQfRound.ts @@ -4,29 +4,64 @@ export class AddIdToProjectQfRound1779182511001 implements MigrationInterface { name = 'AddIdToProjectQfRound1779182511001'; public async up(queryRunner: QueryRunner): Promise { - // Add the new id column as auto-incrementing column (not primary key) + // Drop the existing composite primary key await queryRunner.query(` ALTER TABLE "project_qf_rounds_qf_round" - ADD COLUMN "id" SERIAL + DROP CONSTRAINT IF EXISTS "PK_project_qf_rounds_qf_round" `); - // Add index on the id column for performance + // Add the new id column as auto-incrementing primary key await queryRunner.query(` - CREATE INDEX "IDX_project_qf_rounds_id" - ON "project_qf_rounds_qf_round" ("id") + ALTER TABLE "project_qf_rounds_qf_round" + ADD COLUMN "id" SERIAL PRIMARY KEY + `); + + // Add unique constraint on the composite key to maintain uniqueness + await queryRunner.query(` + ALTER TABLE "project_qf_rounds_qf_round" + ADD CONSTRAINT "UQ_project_qf_rounds_composite" + UNIQUE ("projectId", "qfRoundId") + `); + + // Add indexes on projectId and qfRoundId for performance + await queryRunner.query(` + CREATE INDEX "IDX_project_qf_rounds_projectId" + ON "project_qf_rounds_qf_round" ("projectId") + `); + + await queryRunner.query(` + CREATE INDEX "IDX_project_qf_rounds_qfRoundId" + ON "project_qf_rounds_qf_round" ("qfRoundId") `); } public async down(queryRunner: QueryRunner): Promise { - // Drop the index first + // Drop the indexes first await queryRunner.query(` - DROP INDEX IF EXISTS "IDX_project_qf_rounds_id" + DROP INDEX IF EXISTS "IDX_project_qf_rounds_projectId" `); - // Drop the id column + await queryRunner.query(` + DROP INDEX IF EXISTS "IDX_project_qf_rounds_qfRoundId" + `); + + // Drop the unique constraint + await queryRunner.query(` + ALTER TABLE "project_qf_rounds_qf_round" + DROP CONSTRAINT IF EXISTS "UQ_project_qf_rounds_composite" + `); + + // Drop the id column (which is the primary key) await queryRunner.query(` ALTER TABLE "project_qf_rounds_qf_round" DROP COLUMN IF EXISTS "id" `); + + // Restore the composite primary key + await queryRunner.query(` + ALTER TABLE "project_qf_rounds_qf_round" + ADD CONSTRAINT "PK_project_qf_rounds_qf_round" + PRIMARY KEY ("projectId", "qfRoundId") + `); } } diff --git a/src/entities/projectQfRound.ts b/src/entities/projectQfRound.ts index 1cf23254c..1c3489ec1 100644 --- a/src/entities/projectQfRound.ts +++ b/src/entities/projectQfRound.ts @@ -1,6 +1,6 @@ import { Field, ID, ObjectType, Float, Int } from 'type-graphql'; import { - PrimaryColumn, + PrimaryGeneratedColumn, Column, Entity, ManyToOne, @@ -8,25 +8,27 @@ import { CreateDateColumn, UpdateDateColumn, Index, + Unique, } from 'typeorm'; import { Project } from './project'; import { QfRound } from './qfRound'; @Entity('project_qf_rounds_qf_round') @ObjectType() +@Unique(['projectId', 'qfRoundId']) // Ensure uniqueness of the composite key export class ProjectQfRound extends BaseEntity { @Field(_type => ID) - @Column({ generated: 'increment' }) - @Index() - @PrimaryColumn() + @PrimaryGeneratedColumn() // Make this the primary key id: number; @Field(_type => ID) - @PrimaryColumn() + @Column() + @Index() projectId: number; @Field(_type => ID) - @PrimaryColumn() + @Column() + @Index() qfRoundId: number; @ManyToOne(_type => Project, project => project.projectQfRoundRelations) From efab1500c75b4b8eb1b09dcf9b88a36d6423a976 Mon Sep 17 00:00:00 2001 From: Carlos Date: Thu, 2 Oct 2025 00:23:23 +0200 Subject: [PATCH 2/7] fix migration --- .../1779182511001-AddIdToProjectQfRound.ts | 46 ++++++++++++++++--- 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/migration/1779182511001-AddIdToProjectQfRound.ts b/migration/1779182511001-AddIdToProjectQfRound.ts index 87ab6e11c..df722c103 100644 --- a/migration/1779182511001-AddIdToProjectQfRound.ts +++ b/migration/1779182511001-AddIdToProjectQfRound.ts @@ -4,10 +4,26 @@ export class AddIdToProjectQfRound1779182511001 implements MigrationInterface { name = 'AddIdToProjectQfRound1779182511001'; public async up(queryRunner: QueryRunner): Promise { + // First, check if the table exists and get the current primary key constraint name + const tableExists = await queryRunner.hasTable('project_qf_rounds_qf_round'); + if (!tableExists) { + throw new Error('Table project_qf_rounds_qf_round does not exist'); + } + + // Get the current primary key constraint name + const primaryKeyQuery = await queryRunner.query(` + SELECT constraint_name + FROM information_schema.table_constraints + WHERE table_name = 'project_qf_rounds_qf_round' + AND constraint_type = 'PRIMARY KEY' + `); + + const primaryKeyName = primaryKeyQuery[0]?.constraint_name || 'PK_project_qf_rounds_qf_round'; + // Drop the existing composite primary key await queryRunner.query(` ALTER TABLE "project_qf_rounds_qf_round" - DROP CONSTRAINT IF EXISTS "PK_project_qf_rounds_qf_round" + DROP CONSTRAINT "${primaryKeyName}" `); // Add the new id column as auto-incrementing primary key @@ -18,7 +34,7 @@ export class AddIdToProjectQfRound1779182511001 implements MigrationInterface { // Add unique constraint on the composite key to maintain uniqueness await queryRunner.query(` - ALTER TABLE "project_qf_rounds_qf_round" + ALTER TABLE IF EXISTS "project_qf_rounds_qf_round" ADD CONSTRAINT "UQ_project_qf_rounds_composite" UNIQUE ("projectId", "qfRoundId") `); @@ -47,19 +63,37 @@ export class AddIdToProjectQfRound1779182511001 implements MigrationInterface { // Drop the unique constraint await queryRunner.query(` - ALTER TABLE "project_qf_rounds_qf_round" + ALTER TABLE IF EXISTS "project_qf_rounds_qf_round" DROP CONSTRAINT IF EXISTS "UQ_project_qf_rounds_composite" `); - // Drop the id column (which is the primary key) + // Get the current primary key constraint name for the id column + const primaryKeyQuery = await queryRunner.query(` + SELECT constraint_name + FROM information_schema.table_constraints + WHERE table_name = 'project_qf_rounds_qf_round' + AND constraint_type = 'PRIMARY KEY' + `); + + const primaryKeyName = primaryKeyQuery[0]?.constraint_name; + + if (primaryKeyName) { + // Drop the id primary key constraint + await queryRunner.query(` + ALTER TABLE IF EXISTS "project_qf_rounds_qf_round" + DROP CONSTRAINT "${primaryKeyName}" + `); + } + + // Drop the id column await queryRunner.query(` - ALTER TABLE "project_qf_rounds_qf_round" + ALTER TABLE IF EXISTS "project_qf_rounds_qf_round" DROP COLUMN IF EXISTS "id" `); // Restore the composite primary key await queryRunner.query(` - ALTER TABLE "project_qf_rounds_qf_round" + ALTER TABLE IF EXISTS "project_qf_rounds_qf_round" ADD CONSTRAINT "PK_project_qf_rounds_qf_round" PRIMARY KEY ("projectId", "qfRoundId") `); From 6595f6d0e20c776b9dec993a2bb7173a2ac78a36 Mon Sep 17 00:00:00 2001 From: Carlos Date: Thu, 2 Oct 2025 11:28:41 +0200 Subject: [PATCH 3/7] run linter --- .../1779182511001-AddIdToProjectQfRound.ts | 67 ++++++++++++++++--- 1 file changed, 57 insertions(+), 10 deletions(-) diff --git a/migration/1779182511001-AddIdToProjectQfRound.ts b/migration/1779182511001-AddIdToProjectQfRound.ts index df722c103..c1692287e 100644 --- a/migration/1779182511001-AddIdToProjectQfRound.ts +++ b/migration/1779182511001-AddIdToProjectQfRound.ts @@ -5,7 +5,9 @@ export class AddIdToProjectQfRound1779182511001 implements MigrationInterface { public async up(queryRunner: QueryRunner): Promise { // First, check if the table exists and get the current primary key constraint name - const tableExists = await queryRunner.hasTable('project_qf_rounds_qf_round'); + const tableExists = await queryRunner.hasTable( + 'project_qf_rounds_qf_round', + ); if (!tableExists) { throw new Error('Table project_qf_rounds_qf_round does not exist'); } @@ -18,13 +20,44 @@ export class AddIdToProjectQfRound1779182511001 implements MigrationInterface { AND constraint_type = 'PRIMARY KEY' `); - const primaryKeyName = primaryKeyQuery[0]?.constraint_name || 'PK_project_qf_rounds_qf_round'; + const primaryKeyName = primaryKeyQuery[0]?.constraint_name; - // Drop the existing composite primary key - await queryRunner.query(` - ALTER TABLE "project_qf_rounds_qf_round" - DROP CONSTRAINT "${primaryKeyName}" - `); + // Drop the existing composite primary key if it exists + if (primaryKeyName) { + try { + await queryRunner.query(` + ALTER TABLE "project_qf_rounds_qf_round" + DROP CONSTRAINT "${primaryKeyName}" + `); + } catch (error) { + console.log( + `Failed to drop constraint ${primaryKeyName}, trying alternative approach...`, + ); + // Try with IF EXISTS as fallback + await queryRunner.query(` + ALTER TABLE "project_qf_rounds_qf_round" + DROP CONSTRAINT IF EXISTS "${primaryKeyName}" + `); + } + } else { + // Fallback: try to drop with constraint detection + const constraintQuery = await queryRunner.query(` + SELECT conname + FROM pg_constraint + WHERE conrelid = ( + SELECT oid + FROM pg_class + WHERE relname = 'project_qf_rounds_qf_round' + ) AND contype = 'p' + `); + + if (constraintQuery[0]?.conname) { + await queryRunner.query(` + ALTER TABLE "project_qf_rounds_qf_round" + DROP CONSTRAINT "${constraintQuery[0].conname}" + `); + } + } // Add the new id column as auto-incrementing primary key await queryRunner.query(` @@ -78,10 +111,24 @@ export class AddIdToProjectQfRound1779182511001 implements MigrationInterface { const primaryKeyName = primaryKeyQuery[0]?.constraint_name; if (primaryKeyName) { - // Drop the id primary key constraint + try { + // Drop the id primary key constraint + await queryRunner.query(` + ALTER TABLE "project_qf_rounds_qf_round" + DROP CONSTRAINT "${primaryKeyName}" + `); + } catch (error) { + // Fallback with IF EXISTS + await queryRunner.query(` + ALTER TABLE "project_qf_rounds_qf_round" + DROP CONSTRAINT IF EXISTS "${primaryKeyName}" + `); + } + } else { + // Fallback: drop all possible primary key constraints await queryRunner.query(` - ALTER TABLE IF EXISTS "project_qf_rounds_qf_round" - DROP CONSTRAINT "${primaryKeyName}" + ALTER TABLE "project_qf_rounds_qf_round" + DROP CONSTRAINT IF EXISTS "UQ_project_qf_rounds_qf_round" `); } From bcde46fffbdce32f9b361ac2e9424358bf06f27b Mon Sep 17 00:00:00 2001 From: Carlos Date: Thu, 2 Oct 2025 11:28:41 +0200 Subject: [PATCH 4/7] run linter --- .../1779182511001-AddIdToProjectQfRound.ts | 115 ++++++++++-------- 1 file changed, 63 insertions(+), 52 deletions(-) diff --git a/migration/1779182511001-AddIdToProjectQfRound.ts b/migration/1779182511001-AddIdToProjectQfRound.ts index df722c103..9cf910ff1 100644 --- a/migration/1779182511001-AddIdToProjectQfRound.ts +++ b/migration/1779182511001-AddIdToProjectQfRound.ts @@ -4,55 +4,84 @@ export class AddIdToProjectQfRound1779182511001 implements MigrationInterface { name = 'AddIdToProjectQfRound1779182511001'; public async up(queryRunner: QueryRunner): Promise { - // First, check if the table exists and get the current primary key constraint name - const tableExists = await queryRunner.hasTable('project_qf_rounds_qf_round'); - if (!tableExists) { - throw new Error('Table project_qf_rounds_qf_round does not exist'); + // Try to drop primary key constraints with common names first + const commonConstraintNames = [ + 'pk_project_qf_rounds_qf_round', + 'project_qf_rounds_qf_round_pkey', + 'PK_project_qf_rounds_qf_round', + ]; + + for (const constraintName of commonConstraintNames) { + try { + await queryRunner.query(` + ALTER TABLE "project_qf_rounds_qf_round" + DROP CONSTRAINT IF EXISTS "${constraintName}" + `); + } catch (error) { + // Continue to next constraint name if this fails + continue; + } } - // Get the current primary key constraint name - const primaryKeyQuery = await queryRunner.query(` - SELECT constraint_name - FROM information_schema.table_constraints - WHERE table_name = 'project_qf_rounds_qf_round' - AND constraint_type = 'PRIMARY KEY' - `); - - const primaryKeyName = primaryKeyQuery[0]?.constraint_name || 'PK_project_qf_rounds_qf_round'; - - // Drop the existing composite primary key - await queryRunner.query(` - ALTER TABLE "project_qf_rounds_qf_round" - DROP CONSTRAINT "${primaryKeyName}" - `); + // Then try to find and drop any remaining primary key constraints + try { + await queryRunner.query(` + DO $$ + DECLARE + constraint_name TEXT; + BEGIN + -- Get all primary key constraint names for this table + SELECT conname INTO constraint_name + FROM pg_constraint c + JOIN pg_class t ON c.conrelid = t.oid + WHERE t.relname = 'project_qf_rounds_qf_round' + AND c.contype = 'p' + LIMIT 1; + + IF constraint_name IS NOT NULL THEN + -- Try a direct drop first + BEGIN + EXECUTE 'ALTER TABLE project_qf_rounds_qf_round DROP CONSTRAINT ' || constraint_name; + EXCEPTION + WHEN OTHERS THEN + -- If it fails, just continue - constraint might not exist + NULL; + END; + END IF; + END $$; + `); + } catch (error) { + // If the whole DO block fails, continue - table might not have constraints + // silently continue + } - // Add the new id column as auto-incrementing primary key + // Add id column as primary key await queryRunner.query(` - ALTER TABLE "project_qf_rounds_qf_round" - ADD COLUMN "id" SERIAL PRIMARY KEY + ALTER TABLE IF EXISTS "project_qf_rounds_qf_round" + ADD COLUMN IF NOT EXISTS "id" SERIAL PRIMARY KEY `); - // Add unique constraint on the composite key to maintain uniqueness + // Add unique constraint on projectId and qfRoundId await queryRunner.query(` ALTER TABLE IF EXISTS "project_qf_rounds_qf_round" - ADD CONSTRAINT "UQ_project_qf_rounds_composite" + ADD CONSTRAINT IF NOT EXISTS "UQ_project_qf_rounds_composite" UNIQUE ("projectId", "qfRoundId") `); - // Add indexes on projectId and qfRoundId for performance + // Add indexes await queryRunner.query(` - CREATE INDEX "IDX_project_qf_rounds_projectId" + CREATE INDEX IF NOT EXISTS "IDX_project_qf_rounds_projectId" ON "project_qf_rounds_qf_round" ("projectId") `); await queryRunner.query(` - CREATE INDEX "IDX_project_qf_rounds_qfRoundId" + CREATE INDEX IF NOT EXISTS "IDX_project_qf_rounds_qfRoundId" ON "project_qf_rounds_qf_round" ("qfRoundId") `); } public async down(queryRunner: QueryRunner): Promise { - // Drop the indexes first + // Drop indexes await queryRunner.query(` DROP INDEX IF EXISTS "IDX_project_qf_rounds_projectId" `); @@ -61,39 +90,21 @@ export class AddIdToProjectQfRound1779182511001 implements MigrationInterface { DROP INDEX IF EXISTS "IDX_project_qf_rounds_qfRoundId" `); - // Drop the unique constraint + // Drop unique constraint await queryRunner.query(` - ALTER TABLE IF EXISTS "project_qf_rounds_qf_round" + ALTER TABLE "project_qf_rounds_qf_round" DROP CONSTRAINT IF EXISTS "UQ_project_qf_rounds_composite" `); - // Get the current primary key constraint name for the id column - const primaryKeyQuery = await queryRunner.query(` - SELECT constraint_name - FROM information_schema.table_constraints - WHERE table_name = 'project_qf_rounds_qf_round' - AND constraint_type = 'PRIMARY KEY' - `); - - const primaryKeyName = primaryKeyQuery[0]?.constraint_name; - - if (primaryKeyName) { - // Drop the id primary key constraint - await queryRunner.query(` - ALTER TABLE IF EXISTS "project_qf_rounds_qf_round" - DROP CONSTRAINT "${primaryKeyName}" - `); - } - - // Drop the id column + // Drop id column (which includes dropping its primary key constraint) await queryRunner.query(` - ALTER TABLE IF EXISTS "project_qf_rounds_qf_round" + ALTER TABLE "project_qf_rounds_qf_round" DROP COLUMN IF EXISTS "id" `); - // Restore the composite primary key + // Restore composite primary key await queryRunner.query(` - ALTER TABLE IF EXISTS "project_qf_rounds_qf_round" + ALTER TABLE "project_qf_rounds_qf_round" ADD CONSTRAINT "PK_project_qf_rounds_qf_round" PRIMARY KEY ("projectId", "qfRoundId") `); From 498acb4e20e6f292b268208f990805c982593397 Mon Sep 17 00:00:00 2001 From: kkatusic Date: Thu, 2 Oct 2025 13:46:30 +0200 Subject: [PATCH 5/7] update migration file --- .../1779182511001-AddIdToProjectQfRound.ts | 219 ++++++++++++++---- 1 file changed, 179 insertions(+), 40 deletions(-) diff --git a/migration/1779182511001-AddIdToProjectQfRound.ts b/migration/1779182511001-AddIdToProjectQfRound.ts index c1692287e..188791025 100644 --- a/migration/1779182511001-AddIdToProjectQfRound.ts +++ b/migration/1779182511001-AddIdToProjectQfRound.ts @@ -1,4 +1,5 @@ import { MigrationInterface, QueryRunner } from 'typeorm'; +import { logger } from '../src/utils/logger'; export class AddIdToProjectQfRound1779182511001 implements MigrationInterface { name = 'AddIdToProjectQfRound1779182511001'; @@ -12,74 +13,212 @@ export class AddIdToProjectQfRound1779182511001 implements MigrationInterface { throw new Error('Table project_qf_rounds_qf_round does not exist'); } - // Get the current primary key constraint name - const primaryKeyQuery = await queryRunner.query(` - SELECT constraint_name - FROM information_schema.table_constraints - WHERE table_name = 'project_qf_rounds_qf_round' - AND constraint_type = 'PRIMARY KEY' + // Check if the id column already exists (migration already ran) + const idColumnExists = await queryRunner.hasColumn( + 'project_qf_rounds_qf_round', + 'id', + ); + + if (idColumnExists) { + return; + } + + // Get all primary key constraints for this table + const allConstraintsQuery = await queryRunner.query(` + SELECT conname, contype + FROM pg_constraint + WHERE conrelid = ( + SELECT oid + FROM pg_class + WHERE relname = 'project_qf_rounds_qf_round' + ) AND contype = 'p' `); - const primaryKeyName = primaryKeyQuery[0]?.constraint_name; + // Drop all primary key constraints + for (const constraint of allConstraintsQuery) { + try { + await queryRunner.query(` + ALTER TABLE "project_qf_rounds_qf_round" + DROP CONSTRAINT IF EXISTS "${constraint.conname}" + `); + } catch (error) { + // Continue with other constraints + } + } - // Drop the existing composite primary key if it exists - if (primaryKeyName) { + // Also try to drop the standard constraint names that might exist + const possibleConstraints = [ + 'PK_046d515dee2988817725ec75ebf', + 'project_qf_rounds_qf_round_pkey', + 'PK_project_qf_rounds_qf_round', + ]; + + for (const constraintName of possibleConstraints) { try { await queryRunner.query(` ALTER TABLE "project_qf_rounds_qf_round" - DROP CONSTRAINT "${primaryKeyName}" + DROP CONSTRAINT IF EXISTS "${constraintName}" + `); + } catch (error) { + // Ignore errors for constraints that don't exist + } + } + + // PostgreSQL doesn't support column positioning, so we need to recreate the table + // to have id as the first column + await this.resetTableStructure(queryRunner); + } + + // Emergency method to completely reset the table if needed + private async resetTableStructure(queryRunner: QueryRunner): Promise { + // Step 1: Backup existing data + await queryRunner.query(` + CREATE TEMP TABLE project_qf_rounds_backup AS + SELECT "projectId", "qfRoundId", "sumDonationValueUsd", "countUniqueDonors", "createdAt", "updatedAt" + FROM "project_qf_rounds_qf_round" + `); + + // Step 2: Drop the problematic table + await queryRunner.query(` + DROP TABLE IF EXISTS "project_qf_rounds_qf_round" CASCADE + `); + + // Step 3: Recreate the table with proper structure + await queryRunner.query(` + CREATE TABLE "project_qf_rounds_qf_round" ( + "id" SERIAL PRIMARY KEY, + "projectId" INTEGER NOT NULL, + "qfRoundId" INTEGER NOT NULL, + "sumDonationValueUsd" REAL DEFAULT 0, + "countUniqueDonors" INTEGER DEFAULT 0, + "createdAt" TIMESTAMP DEFAULT NOW(), + "updatedAt" TIMESTAMP DEFAULT NOW(), + CONSTRAINT "UQ_project_qf_rounds_composite" UNIQUE ("projectId", "qfRoundId") + ) + `); + + // Step 4: Create indexes + await queryRunner.query(` + CREATE INDEX "IDX_project_qf_rounds_projectId" ON "project_qf_rounds_qf_round" ("projectId") + `); + + await queryRunner.query(` + CREATE INDEX "IDX_project_qf_rounds_qfRoundId" ON "project_qf_rounds_qf_round" ("qfRoundId") + `); + + // Step 5: Restore data with new auto-incrementing IDs + await queryRunner.query(` + INSERT INTO "project_qf_rounds_qf_round" ("projectId", "qfRoundId", "sumDonationValueUsd", "countUniqueDonors", "createdAt", "updatedAt") + SELECT "projectId", "qfRoundId", "sumDonationValueUsd", "countUniqueDonors", "createdAt", "updatedAt" + FROM project_qf_rounds_backup + `); + + // Clean up + await queryRunner.query(`DROP TABLE project_qf_rounds_backup`); + } + + // Alternative method using the constraint fix approach + private async fixConstraintsOnly(queryRunner: QueryRunner): Promise { + // Drop all possible primary key constraints + const allConstraints = await queryRunner.query(` + SELECT conname + FROM pg_constraint + WHERE conrelid = ( + SELECT oid + FROM pg_class + WHERE relname = 'project_qf_rounds_qf_round' + ) AND contype = 'p' + `); + + for (const constraint of allConstraints) { + try { + await queryRunner.query(` + ALTER TABLE "project_qf_rounds_qf_round" + DROP CONSTRAINT IF EXISTS "${constraint.conname}" `); } catch (error) { - console.log( - `Failed to drop constraint ${primaryKeyName}, trying alternative approach...`, - ); - // Try with IF EXISTS as fallback + logger.error(`Error dropping constraint ${constraint.conname}:`, error); + } + } + + // Also try common constraint names + const commonConstraints = [ + 'PK_046d515dee2988817725ec75ebf', + 'project_qf_rounds_qf_round_pkey', + 'PK_project_qf_rounds_qf_round', + ]; + + for (const constraintName of commonConstraints) { + try { await queryRunner.query(` ALTER TABLE "project_qf_rounds_qf_round" - DROP CONSTRAINT IF EXISTS "${primaryKeyName}" + DROP CONSTRAINT IF EXISTS "${constraintName}" `); + } catch (error) { + // Ignore errors for constraints that don't exist } + } + + // Check if id column exists, if not add it + const idColumnExists = await queryRunner.hasColumn( + 'project_qf_rounds_qf_round', + 'id', + ); + + if (!idColumnExists) { + // First add the column as SERIAL (auto-incrementing) + await queryRunner.query(` + ALTER TABLE "project_qf_rounds_qf_round" ADD COLUMN id SERIAL + `); + + // Then add the primary key constraint + await queryRunner.query(` + ALTER TABLE "project_qf_rounds_qf_round" + ADD CONSTRAINT "PK_project_qf_rounds_qf_round_id" PRIMARY KEY (id) + `); } else { - // Fallback: try to drop with constraint detection - const constraintQuery = await queryRunner.query(` - SELECT conname - FROM pg_constraint - WHERE conrelid = ( - SELECT oid - FROM pg_class - WHERE relname = 'project_qf_rounds_qf_round' - ) AND contype = 'p' + // Check if there are records without IDs (shouldn't happen with SERIAL) + const recordsWithoutIdResult = await queryRunner.query(` + SELECT COUNT(*) as count + FROM "project_qf_rounds_qf_round" + WHERE id IS NULL `); + const recordsWithoutId = recordsWithoutIdResult[0]?.count || 0; - if (constraintQuery[0]?.conname) { + if (recordsWithoutId > 0) { + // Fix records without ID await queryRunner.query(` - ALTER TABLE "project_qf_rounds_qf_round" - DROP CONSTRAINT "${constraintQuery[0].conname}" + UPDATE "project_qf_rounds_qf_round" + SET id = nextval(pg_get_serial_sequence('project_qf_rounds_qf_round', 'id')) + WHERE id IS NULL `); } } - // Add the new id column as auto-incrementing primary key - await queryRunner.query(` - ALTER TABLE "project_qf_rounds_qf_round" - ADD COLUMN "id" SERIAL PRIMARY KEY + // Add unique constraint if it doesn't exist + const uniqueConstraintExists = await queryRunner.query(` + SELECT 1 + FROM information_schema.table_constraints + WHERE table_name = 'project_qf_rounds_qf_round' + AND constraint_name = 'UQ_project_qf_rounds_composite' `); - // Add unique constraint on the composite key to maintain uniqueness - await queryRunner.query(` - ALTER TABLE IF EXISTS "project_qf_rounds_qf_round" - ADD CONSTRAINT "UQ_project_qf_rounds_composite" - UNIQUE ("projectId", "qfRoundId") - `); + if (!uniqueConstraintExists || uniqueConstraintExists.length === 0) { + await queryRunner.query(` + ALTER TABLE "project_qf_rounds_qf_round" + ADD CONSTRAINT "UQ_project_qf_rounds_composite" + UNIQUE ("projectId", "qfRoundId") + `); + } - // Add indexes on projectId and qfRoundId for performance + // Add indexes if they don't exist await queryRunner.query(` - CREATE INDEX "IDX_project_qf_rounds_projectId" + CREATE INDEX IF NOT EXISTS "IDX_project_qf_rounds_projectId" ON "project_qf_rounds_qf_round" ("projectId") `); await queryRunner.query(` - CREATE INDEX "IDX_project_qf_rounds_qfRoundId" + CREATE INDEX IF NOT EXISTS "IDX_project_qf_rounds_qfRoundId" ON "project_qf_rounds_qf_round" ("qfRoundId") `); } From f1d00964cd1cfa1d84795f772dd96aebf30108b7 Mon Sep 17 00:00:00 2001 From: kkatusic Date: Thu, 2 Oct 2025 14:04:17 +0200 Subject: [PATCH 6/7] new fix --- migration/1779182511001-AddIdToProjectQfRound.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/migration/1779182511001-AddIdToProjectQfRound.ts b/migration/1779182511001-AddIdToProjectQfRound.ts index d33d56194..188791025 100644 --- a/migration/1779182511001-AddIdToProjectQfRound.ts +++ b/migration/1779182511001-AddIdToProjectQfRound.ts @@ -224,7 +224,7 @@ export class AddIdToProjectQfRound1779182511001 implements MigrationInterface { } public async down(queryRunner: QueryRunner): Promise { - // Drop indexes + // Drop the indexes first await queryRunner.query(` DROP INDEX IF EXISTS "IDX_project_qf_rounds_projectId" `); @@ -233,9 +233,9 @@ export class AddIdToProjectQfRound1779182511001 implements MigrationInterface { DROP INDEX IF EXISTS "IDX_project_qf_rounds_qfRoundId" `); - // Drop unique constraint + // Drop the unique constraint await queryRunner.query(` - ALTER TABLE "project_qf_rounds_qf_round" + ALTER TABLE IF EXISTS "project_qf_rounds_qf_round" DROP CONSTRAINT IF EXISTS "UQ_project_qf_rounds_composite" `); @@ -273,13 +273,13 @@ export class AddIdToProjectQfRound1779182511001 implements MigrationInterface { // Drop the id column await queryRunner.query(` - ALTER TABLE "project_qf_rounds_qf_round" + ALTER TABLE IF EXISTS "project_qf_rounds_qf_round" DROP COLUMN IF EXISTS "id" `); - // Restore composite primary key + // Restore the composite primary key await queryRunner.query(` - ALTER TABLE "project_qf_rounds_qf_round" + ALTER TABLE IF EXISTS "project_qf_rounds_qf_round" ADD CONSTRAINT "PK_project_qf_rounds_qf_round" PRIMARY KEY ("projectId", "qfRoundId") `); From 066fa45e96bdf4b96294b66c40f1d152cdabafb6 Mon Sep 17 00:00:00 2001 From: kkatusic Date: Thu, 2 Oct 2025 14:17:50 +0200 Subject: [PATCH 7/7] again --- .../1779182511001-AddIdToProjectQfRound.ts | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/migration/1779182511001-AddIdToProjectQfRound.ts b/migration/1779182511001-AddIdToProjectQfRound.ts index 188791025..1d3a4b7aa 100644 --- a/migration/1779182511001-AddIdToProjectQfRound.ts +++ b/migration/1779182511001-AddIdToProjectQfRound.ts @@ -47,6 +47,7 @@ export class AddIdToProjectQfRound1779182511001 implements MigrationInterface { } // Also try to drop the standard constraint names that might exist + // Use a more robust approach to handle constraint dropping const possibleConstraints = [ 'PK_046d515dee2988817725ec75ebf', 'project_qf_rounds_qf_round_pkey', @@ -55,12 +56,24 @@ export class AddIdToProjectQfRound1779182511001 implements MigrationInterface { for (const constraintName of possibleConstraints) { try { - await queryRunner.query(` - ALTER TABLE "project_qf_rounds_qf_round" - DROP CONSTRAINT IF EXISTS "${constraintName}" + // First check if constraint exists before trying to drop it + const constraintExists = await queryRunner.query(` + SELECT 1 FROM pg_constraint + WHERE conname = '${constraintName}' + AND conrelid = ( + SELECT oid FROM pg_class WHERE relname = 'project_qf_rounds_qf_round' + ) `); + + if (constraintExists && constraintExists.length > 0) { + await queryRunner.query(` + ALTER TABLE "project_qf_rounds_qf_round" + DROP CONSTRAINT "${constraintName}" + `); + } } catch (error) { // Ignore errors for constraints that don't exist + logger.error(`Error handling constraint ${constraintName}:`, error); } }