This commit is contained in:
2025-12-11 11:25:22 +01:00
parent 6a427eab57
commit e4c1be628d
86 changed files with 1222 additions and 736 deletions

View File

@@ -1,5 +1,8 @@
/**
* Domain Entity: Protest
*/
import { RacingDomainValidationError, RacingDomainInvariantError } from '../errors/RacingDomainError';
*
* Represents a protest filed by a driver against another driver for an incident during a race.
*
@@ -67,13 +70,13 @@ export class Protest {
private constructor(private readonly props: ProtestProps) {}
static create(props: ProtestProps): Protest {
if (!props.id) throw new Error('Protest ID is required');
if (!props.raceId) throw new Error('Race ID is required');
if (!props.protestingDriverId) throw new Error('Protesting driver ID is required');
if (!props.accusedDriverId) throw new Error('Accused driver ID is required');
if (!props.incident) throw new Error('Incident details are required');
if (props.incident.lap < 0) throw new Error('Lap number must be non-negative');
if (!props.incident.description?.trim()) throw new Error('Incident description is required');
if (!props.id) throw new RacingDomainValidationError('Protest ID is required');
if (!props.raceId) throw new RacingDomainValidationError('Race ID is required');
if (!props.protestingDriverId) throw new RacingDomainValidationError('Protesting driver ID is required');
if (!props.accusedDriverId) throw new RacingDomainValidationError('Accused driver ID is required');
if (!props.incident) throw new RacingDomainValidationError('Incident details are required');
if (props.incident.lap < 0) throw new RacingDomainValidationError('Lap number must be non-negative');
if (!props.incident.description?.trim()) throw new RacingDomainValidationError('Incident description is required');
return new Protest({
...props,
@@ -131,7 +134,7 @@ export class Protest {
*/
requestDefense(stewardId: string): Protest {
if (!this.canRequestDefense()) {
throw new Error('Defense can only be requested for pending protests without existing defense');
throw new RacingDomainInvariantError('Defense can only be requested for pending protests without existing defense');
}
return new Protest({
...this.props,
@@ -146,10 +149,10 @@ export class Protest {
*/
submitDefense(statement: string, videoUrl?: string): Protest {
if (!this.canSubmitDefense()) {
throw new Error('Defense can only be submitted when protest is awaiting defense');
throw new RacingDomainInvariantError('Defense can only be submitted when protest is awaiting defense');
}
if (!statement?.trim()) {
throw new Error('Defense statement is required');
throw new RacingDomainValidationError('Defense statement is required');
}
return new Protest({
...this.props,
@@ -167,7 +170,7 @@ export class Protest {
*/
startReview(stewardId: string): Protest {
if (!this.isPending() && !this.isAwaitingDefense()) {
throw new Error('Only pending or awaiting-defense protests can be put under review');
throw new RacingDomainInvariantError('Only pending or awaiting-defense protests can be put under review');
}
return new Protest({
...this.props,
@@ -181,7 +184,7 @@ export class Protest {
*/
uphold(stewardId: string, decisionNotes: string): Protest {
if (!this.isPending() && !this.isUnderReview() && !this.isAwaitingDefense()) {
throw new Error('Only pending, awaiting-defense, or under-review protests can be upheld');
throw new RacingDomainInvariantError('Only pending, awaiting-defense, or under-review protests can be upheld');
}
return new Protest({
...this.props,
@@ -197,7 +200,7 @@ export class Protest {
*/
dismiss(stewardId: string, decisionNotes: string): Protest {
if (!this.isPending() && !this.isUnderReview() && !this.isAwaitingDefense()) {
throw new Error('Only pending, awaiting-defense, or under-review protests can be dismissed');
throw new RacingDomainInvariantError('Only pending, awaiting-defense, or under-review protests can be dismissed');
}
return new Protest({
...this.props,
@@ -213,7 +216,7 @@ export class Protest {
*/
withdraw(): Protest {
if (this.isResolved()) {
throw new Error('Cannot withdraw a resolved protest');
throw new RacingDomainInvariantError('Cannot withdraw a resolved protest');
}
return new Protest({
...this.props,