test(renown): pin the migration's backfill and constraint statement ordering
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -134,6 +134,7 @@ export class CreateRenownAndReputation1791000000000 implements MigrationInterfac
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query('DROP INDEX "IDX_turn_in_definitions_key"');
|
||||
await queryRunner.query('DROP TABLE "turn_in_definitions"');
|
||||
|
||||
await queryRunner.query(
|
||||
|
||||
@@ -32,22 +32,29 @@ describe('CreateRenownAndReputation1791000000000', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('clamps existing level into the 1-15 Renown range before dropping it', async () => {
|
||||
it('backfills renown from level BEFORE dropping the level column', async () => {
|
||||
const up = await runUp();
|
||||
|
||||
expect(up).toEqual(
|
||||
expect.arrayContaining([expect.stringContaining('LEAST(GREATEST("level", 1), 15)')]),
|
||||
);
|
||||
const backfillIndex = up.findIndex((sql) => sql.includes('LEAST(GREATEST("level", 1), 15)'));
|
||||
const dropLevelIndex = up.findIndex((sql) => sql.includes('DROP COLUMN "level"'));
|
||||
|
||||
expect(backfillIndex).toBeGreaterThanOrEqual(0);
|
||||
expect(dropLevelIndex).toBeGreaterThanOrEqual(0);
|
||||
// Reversing these two would silently discard every character's progression.
|
||||
expect(backfillIndex).toBeLessThan(dropLevelIndex);
|
||||
});
|
||||
|
||||
it('enforces the renown range at the database level', async () => {
|
||||
it('adds the renown range constraint only AFTER the backfill has populated valid values', async () => {
|
||||
const up = await runUp();
|
||||
|
||||
expect(up).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.stringContaining('CHK_characters_renown'),
|
||||
]),
|
||||
);
|
||||
const backfillIndex = up.findIndex((sql) => sql.includes('LEAST(GREATEST("level", 1), 15)'));
|
||||
const constraintIndex = up.findIndex((sql) => sql.includes('CHK_characters_renown'));
|
||||
|
||||
expect(backfillIndex).toBeGreaterThanOrEqual(0);
|
||||
expect(constraintIndex).toBeGreaterThanOrEqual(0);
|
||||
// ADD CONSTRAINT validates the whole table; running it before the backfill
|
||||
// would only pass by coincidence of the column DEFAULT being in range.
|
||||
expect(backfillIndex).toBeLessThan(constraintIndex);
|
||||
});
|
||||
|
||||
it('drops required_level from item_definitions', async () => {
|
||||
@@ -125,10 +132,15 @@ describe('CreateRenownAndReputation1791000000000', () => {
|
||||
expect.stringContaining('ALTER TABLE "characters" DROP COLUMN "renown"'),
|
||||
]),
|
||||
);
|
||||
// The dropped turn_in_definitions table must be the very first statement
|
||||
// in down() -- it's the last thing up() created, and it has FK
|
||||
// dependencies on reputation_factions/item_definitions that must be
|
||||
// gone before those tables can be touched.
|
||||
expect(down[0]).toContain('DROP TABLE "turn_in_definitions"');
|
||||
const turnInDropIndex = down.findIndex((sql) => sql.includes('DROP TABLE "turn_in_definitions"'));
|
||||
const reputationFactionsDropIndex = down.findIndex((sql) =>
|
||||
sql.includes('DROP TABLE "reputation_factions"'),
|
||||
);
|
||||
|
||||
expect(turnInDropIndex).toBeGreaterThanOrEqual(0);
|
||||
expect(reputationFactionsDropIndex).toBeGreaterThanOrEqual(0);
|
||||
// turn_in_definitions has FK dependencies on reputation_factions and
|
||||
// item_definitions that must be gone before those tables are touched.
|
||||
expect(turnInDropIndex).toBeLessThan(reputationFactionsDropIndex);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user