Files
gridpilot.gg/packages/racing/domain/value-objects/SeasonDropPolicy.ts
2025-12-12 14:23:40 +01:00

59 lines
1.7 KiB
TypeScript

import { RacingDomainValidationError } from '../errors/RacingDomainError';
import type { IValueObject } from '@gridpilot/shared/domain';
export type SeasonDropStrategy = 'none' | 'bestNResults' | 'dropWorstN';
export interface SeasonDropPolicyProps {
strategy: SeasonDropStrategy;
/**
* Number of results to consider for strategies that require a count.
* - bestNResults: keep best N
* - dropWorstN: drop worst N
*/
n?: number;
}
export class SeasonDropPolicy implements IValueObject<SeasonDropPolicyProps> {
readonly strategy: SeasonDropStrategy;
readonly n?: number;
constructor(props: SeasonDropPolicyProps) {
if (!props.strategy) {
throw new RacingDomainValidationError(
'SeasonDropPolicy.strategy is required',
);
}
if (props.strategy === 'bestNResults' || props.strategy === 'dropWorstN') {
if (props.n === undefined || !Number.isInteger(props.n) || props.n <= 0) {
throw new RacingDomainValidationError(
'SeasonDropPolicy.n must be a positive integer when using bestNResults or dropWorstN',
);
}
}
if (props.strategy === 'none' && props.n !== undefined) {
throw new RacingDomainValidationError(
'SeasonDropPolicy.n must be undefined when strategy is none',
);
}
this.strategy = props.strategy;
if (props.n !== undefined) {
this.n = props.n;
}
}
get props(): SeasonDropPolicyProps {
return {
strategy: this.strategy,
...(this.n !== undefined ? { n: this.n } : {}),
};
}
equals(other: IValueObject<SeasonDropPolicyProps>): boolean {
const a = this.props;
const b = other.props;
return a.strategy === b.strategy && a.n === b.n;
}
}