Brings in the First Loot slice. Resolved additively: - MonsterDefinition keeps both the new iconPath and master's lootTableId. - The seed keeps the four-monster pool and the local view content, and gives the two new monsters existing loot tables — the road dog shares the beast table, the charred looter the raider table. - The local location view migration moves to 1788700000000 so it orders deterministically after the loot migration, which claimed the same timestamp. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
72 lines
2.4 KiB
TypeScript
72 lines
2.4 KiB
TypeScript
import 'reflect-metadata';
|
|
import { readFileSync } from 'node:fs';
|
|
import { join } from 'node:path';
|
|
import { getMetadataArgsStorage } from 'typeorm';
|
|
import { MonsterDefinition } from '../../monsters/entities/monster-definition.entity';
|
|
import { LocationDefinition } from '../../world/entities/location-definition.entity';
|
|
|
|
const MIGRATION_SQL = readFileSync(
|
|
join(__dirname, '1788700000000-CreateLocalLocationView.ts'),
|
|
'utf8',
|
|
);
|
|
|
|
function columnNames(target: unknown): string[] {
|
|
return getMetadataArgsStorage()
|
|
.columns.filter((column) => column.target === target)
|
|
.map((column) => column.options.name)
|
|
.filter((name): name is string => typeof name === 'string');
|
|
}
|
|
|
|
describe('local location view schema', () => {
|
|
const newLocationColumns = [
|
|
'region_name',
|
|
'region_tier_label',
|
|
'location_type',
|
|
'local_description',
|
|
'local_artwork_path',
|
|
'local_points_of_interest',
|
|
'local_primary_actions',
|
|
'local_reward_preview',
|
|
];
|
|
|
|
it.each(newLocationColumns)(
|
|
'maps %s on LocationDefinition',
|
|
(name: string) => {
|
|
expect(columnNames(LocationDefinition)).toContain(name);
|
|
},
|
|
);
|
|
|
|
it.each(newLocationColumns)('adds %s in the migration', (name: string) => {
|
|
expect(MIGRATION_SQL).toContain(
|
|
`ALTER TABLE "location_definitions" ADD COLUMN "${name}"`,
|
|
);
|
|
expect(MIGRATION_SQL).toContain(
|
|
`ALTER TABLE "location_definitions" DROP COLUMN "${name}"`,
|
|
);
|
|
});
|
|
|
|
it('adds the monster icon path in both the entity and the migration', () => {
|
|
expect(columnNames(MonsterDefinition)).toContain('icon_path');
|
|
expect(MIGRATION_SQL).toContain(
|
|
'ALTER TABLE "monster_definitions" ADD COLUMN "icon_path"',
|
|
);
|
|
expect(MIGRATION_SQL).toContain(
|
|
'ALTER TABLE "monster_definitions" DROP COLUMN "icon_path"',
|
|
);
|
|
});
|
|
|
|
it('keeps the map-level columns untouched so the world screen is unaffected', () => {
|
|
expect(MIGRATION_SQL).not.toContain('DROP COLUMN "description"');
|
|
expect(MIGRATION_SQL).not.toContain('DROP COLUMN "artwork_path"');
|
|
expect(columnNames(LocationDefinition)).toEqual(
|
|
expect.arrayContaining(['description', 'artwork_path', 'region_key']),
|
|
);
|
|
});
|
|
|
|
it('backfills existing rows so no location renders an empty breadcrumb', () => {
|
|
expect(MIGRATION_SQL).toContain(
|
|
'UPDATE "location_definitions" SET "region_name" = "region_key"',
|
|
);
|
|
});
|
|
});
|