feat(renown): add Reputation/Renown/TurnIn entities and update Character/ItemDefinition/CombatReward

This commit is contained in:
Bastian Wagner
2026-08-21 09:03:37 +02:00
parent 3662029ec9
commit 4fa1923525
10 changed files with 289 additions and 14 deletions

View File

@@ -0,0 +1,71 @@
import 'reflect-metadata';
import { getMetadataArgsStorage } from 'typeorm';
import { Character } from '../../characters/entities/character.entity';
import { ItemDefinition } from '../../items/entities/item-definition.entity';
import { ItemType } from '../../items/item-type.enum';
import { CombatReward } from '../../rewards/entities/combat-reward.entity';
import { ReputationFaction } from '../../reputation/entities/reputation-faction.entity';
import { CharacterReputation } from '../../reputation/entities/character-reputation.entity';
import { RenownMilestoneDefinition } from '../../renown/entities/renown-milestone-definition.entity';
import { CharacterRenownMilestone } from '../../renown/entities/character-renown-milestone.entity';
import { TurnInDefinition } from '../../turn-in/entities/turn-in-definition.entity';
function columnNames(target: unknown): string[] {
return getMetadataArgsStorage()
.columns.filter((column) => column.target === target)
.map((column) => column.propertyName);
}
function uniqueIndexFor(target: unknown, columns: string[]): boolean {
const index = getMetadataArgsStorage().indices.find(
(candidate) =>
candidate.target === target && columns.every((column) => candidate.columns?.includes(column)),
);
const meta = index as typeof index & { options?: { unique?: boolean }; unique?: boolean };
return (meta?.options?.unique ?? meta?.unique) === true;
}
describe('Slice 0.6.5 entity metadata', () => {
it('Character exposes renown and no longer exposes level/experience', () => {
const names = columnNames(Character);
expect(names).toContain('renown');
expect(names).not.toContain('level');
expect(names).not.toContain('experience');
});
it('ItemDefinition no longer exposes requiredLevel', () => {
expect(columnNames(ItemDefinition)).not.toContain('requiredLevel');
});
it('ItemType has exactly the five Slice 0.6.5 values', () => {
expect(Object.values(ItemType).sort()).toEqual(
['CONSUMABLE', 'EQUIPMENT', 'QUEST_ITEM', 'TRADE_GOOD', 'TROPHY'].sort(),
);
});
it('CombatReward no longer exposes experienceGranted', () => {
expect(columnNames(CombatReward)).not.toContain('experienceGranted');
});
it('ReputationFaction has a unique key', () => {
expect(uniqueIndexFor(ReputationFaction, ['key'])).toBe(true);
});
it('CharacterReputation enforces one row per character per faction', () => {
expect(uniqueIndexFor(CharacterReputation, ['characterId', 'factionId'])).toBe(true);
});
it('RenownMilestoneDefinition has a unique key', () => {
expect(uniqueIndexFor(RenownMilestoneDefinition, ['key'])).toBe(true);
});
it('CharacterRenownMilestone enforces one row per character per milestone', () => {
expect(
uniqueIndexFor(CharacterRenownMilestone, ['characterId', 'milestoneId']),
).toBe(true);
});
it('TurnInDefinition has a unique key', () => {
expect(uniqueIndexFor(TurnInDefinition, ['key'])).toBe(true);
});
});