From 47931ff7173b52b88e50e36973f821f7e7f0140e Mon Sep 17 00:00:00 2001 From: Bastian Wagner Date: Wed, 19 Aug 2026 15:34:46 +0200 Subject: [PATCH] feat(combat): add CreateCombatSystem migration --- .../1788100000000-CreateCombatSystem.ts | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 apps/api/src/database/migrations/1788100000000-CreateCombatSystem.ts diff --git a/apps/api/src/database/migrations/1788100000000-CreateCombatSystem.ts b/apps/api/src/database/migrations/1788100000000-CreateCombatSystem.ts new file mode 100644 index 0000000..26fd03b --- /dev/null +++ b/apps/api/src/database/migrations/1788100000000-CreateCombatSystem.ts @@ -0,0 +1,89 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class CreateCombatSystem1788100000000 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'ALTER TABLE "hunt_encounters" ADD COLUMN "consumed_at" TIMESTAMP WITH TIME ZONE', + ); + + await queryRunner.query( + "CREATE TYPE \"combat_status_enum\" AS ENUM ('ACTIVE', 'WON', 'LOST')", + ); + await queryRunner.query( + "CREATE TYPE \"combat_event_type_enum\" AS ENUM ('DAMAGE', 'COMBAT_WON', 'COMBAT_LOST')", + ); + await queryRunner.query( + "CREATE TYPE \"combatant_enum\" AS ENUM ('PLAYER', 'MONSTER')", + ); + + await queryRunner.query(`CREATE TABLE "combats" ( + "id" uuid NOT NULL DEFAULT gen_random_uuid(), + "character_id" uuid NOT NULL, + "hunt_encounter_id" uuid NOT NULL, + "monster_definition_id" uuid NOT NULL, + "status" "combat_status_enum" NOT NULL, + "round" integer NOT NULL, + "player_max_hp" integer NOT NULL, + "player_current_hp" integer NOT NULL, + "monster_max_hp" integer NOT NULL, + "monster_current_hp" integer NOT NULL, + "player_state" jsonb NOT NULL, + "monster_state" jsonb NOT NULL, + "created_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), + "updated_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), + "completed_at" TIMESTAMP WITH TIME ZONE, + CONSTRAINT "PK_combats" PRIMARY KEY ("id"), + CONSTRAINT "FK_combats_character" FOREIGN KEY ("character_id") REFERENCES "characters"("id") ON DELETE RESTRICT ON UPDATE NO ACTION, + CONSTRAINT "FK_combats_hunt_encounter" FOREIGN KEY ("hunt_encounter_id") REFERENCES "hunt_encounters"("id") ON DELETE RESTRICT ON UPDATE NO ACTION, + CONSTRAINT "FK_combats_monster_definition" FOREIGN KEY ("monster_definition_id") REFERENCES "monster_definitions"("id") ON DELETE RESTRICT ON UPDATE NO ACTION + )`); + await queryRunner.query( + 'CREATE INDEX "IDX_combats_character" ON "combats" ("character_id")', + ); + await queryRunner.query( + 'CREATE UNIQUE INDEX "IDX_combats_hunt_encounter" ON "combats" ("hunt_encounter_id")', + ); + await queryRunner.query( + 'CREATE INDEX "IDX_combats_monster_definition" ON "combats" ("monster_definition_id")', + ); + await queryRunner.query(`CREATE UNIQUE INDEX "IDX_active_combat_per_character" + ON "combats" ("character_id") + WHERE "status" = 'ACTIVE'`); + + await queryRunner.query(`CREATE TABLE "combat_events" ( + "id" uuid NOT NULL DEFAULT gen_random_uuid(), + "combat_id" uuid NOT NULL, + "round" integer NOT NULL, + "sequence" integer NOT NULL, + "type" "combat_event_type_enum" NOT NULL, + "source" "combatant_enum" NOT NULL, + "target" "combatant_enum" NOT NULL, + "amount" integer, + "created_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), + CONSTRAINT "PK_combat_events" PRIMARY KEY ("id"), + CONSTRAINT "FK_combat_events_combat" FOREIGN KEY ("combat_id") REFERENCES "combats"("id") ON DELETE CASCADE ON UPDATE NO ACTION + )`); + await queryRunner.query( + 'CREATE INDEX "IDX_combat_events_combat" ON "combat_events" ("combat_id")', + ); + await queryRunner.query(`CREATE UNIQUE INDEX "IDX_combat_events_combat_sequence" + ON "combat_events" ("combat_id", "sequence")`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query('DROP INDEX "IDX_combat_events_combat_sequence"'); + await queryRunner.query('DROP INDEX "IDX_combat_events_combat"'); + await queryRunner.query('DROP TABLE "combat_events"'); + await queryRunner.query('DROP INDEX "IDX_active_combat_per_character"'); + await queryRunner.query('DROP INDEX "IDX_combats_monster_definition"'); + await queryRunner.query('DROP INDEX "IDX_combats_hunt_encounter"'); + await queryRunner.query('DROP INDEX "IDX_combats_character"'); + await queryRunner.query('DROP TABLE "combats"'); + await queryRunner.query('DROP TYPE "combatant_enum"'); + await queryRunner.query('DROP TYPE "combat_event_type_enum"'); + await queryRunner.query('DROP TYPE "combat_status_enum"'); + await queryRunner.query( + 'ALTER TABLE "hunt_encounters" DROP COLUMN "consumed_at"', + ); + } +}