Files
edr-platform/apps/edr-payment-api/src/migrations/1782200000000-DropActiveReferenceUniqueIndex.ts

40 lines
1.9 KiB
TypeScript

import { MigrationInterface, QueryRunner } from "typeorm";
/**
* Drops the per-reference partial UNIQUE index so a domain order may have MANY intents — including
* more than one SUCCEEDED (a second real payment is registered as its own row, not blocked by the
* DB). A plain, non-unique lookup index replaces it for the reference lookups.
*
* DATA SAFETY: dropping an index never touches row data — no rows or column values change, and
* relaxing a constraint cannot conflict with existing rows.
*
* ROLLBACK CAVEAT: `down()` re-creates the UNIQUE index on a best-effort basis. Once the new
* "free initiate" behaviour has produced two active/SUCCEEDED intents for one order, re-creating
* the unique index WILL FAIL (the duplicates violate it). Roll forward is always safe; rolling
* back to the strict constraint is only possible while no duplicates exist.
*/
export class DropActiveReferenceUniqueIndex1782200000000
implements MigrationInterface
{
name = "DropActiveReferenceUniqueIndex1782200000000";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`DROP INDEX IF EXISTS "edr_payment"."uq_payment_intent_active_reference"`,
);
await queryRunner.query(
`CREATE INDEX IF NOT EXISTS "idx_payment_intent_reference" ON "edr_payment"."payment_intent" ("service", "reference_type", "reference_id")`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`DROP INDEX IF EXISTS "edr_payment"."idx_payment_intent_reference"`,
);
// Best-effort restore — fails if duplicate active/SUCCEEDED intents already exist (see note above).
await queryRunner.query(
`CREATE UNIQUE INDEX IF NOT EXISTS "uq_payment_intent_active_reference" ON "edr_payment"."payment_intent" ("service", "reference_type", "reference_id") WHERE status NOT IN ('FAILED','CANCELLED') AND deleted_at IS NULL`,
);
}
}