128 lines
2.7 KiB
TypeScript
128 lines
2.7 KiB
TypeScript
/**
|
|
* Domain Value Object: RaceStatus
|
|
*
|
|
* Represents the status of a race with strict lifecycle rules.
|
|
*/
|
|
|
|
import type { ValueObject } from '@core/shared/domain/ValueObject';
|
|
import { RacingDomainValidationError } from '../errors/RacingDomainError';
|
|
|
|
export type RaceStatusValue = 'scheduled' | 'running' | 'completed' | 'cancelled';
|
|
|
|
export interface RaceStatusProps {
|
|
value: RaceStatusValue;
|
|
}
|
|
|
|
export class RaceStatus implements ValueObject<RaceStatusProps> {
|
|
readonly value: RaceStatusValue;
|
|
|
|
private constructor(value: RaceStatusValue) {
|
|
this.value = value;
|
|
}
|
|
|
|
static create(value: RaceStatusValue): RaceStatus {
|
|
if (!value) {
|
|
throw new RacingDomainValidationError('Race status is required');
|
|
}
|
|
return new RaceStatus(value);
|
|
}
|
|
|
|
/**
|
|
* Check if race can be started
|
|
*/
|
|
canStart(): boolean {
|
|
return this.value === 'scheduled';
|
|
}
|
|
|
|
/**
|
|
* Check if race can be completed
|
|
*/
|
|
canComplete(): boolean {
|
|
return this.value === 'running';
|
|
}
|
|
|
|
/**
|
|
* Check if race can be cancelled
|
|
*/
|
|
canCancel(): boolean {
|
|
return this.value === 'scheduled' || this.value === 'running';
|
|
}
|
|
|
|
/**
|
|
* Check if race can be reopened
|
|
*/
|
|
canReopen(): boolean {
|
|
return this.value === 'completed' || this.value === 'cancelled';
|
|
}
|
|
|
|
/**
|
|
* Check if race is in a terminal state
|
|
*/
|
|
isTerminal(): boolean {
|
|
return this.value === 'completed' || this.value === 'cancelled';
|
|
}
|
|
|
|
/**
|
|
* Check if race is running
|
|
*/
|
|
isRunning(): boolean {
|
|
return this.value === 'running';
|
|
}
|
|
|
|
/**
|
|
* Check if race is completed
|
|
*/
|
|
isCompleted(): boolean {
|
|
return this.value === 'completed';
|
|
}
|
|
|
|
/**
|
|
* Check if race is scheduled
|
|
*/
|
|
isScheduled(): boolean {
|
|
return this.value === 'scheduled';
|
|
}
|
|
|
|
/**
|
|
* Check if race is cancelled
|
|
*/
|
|
isCancelled(): boolean {
|
|
return this.value === 'cancelled';
|
|
}
|
|
|
|
/**
|
|
* Validate transition from current status to target status
|
|
*/
|
|
canTransitionTo(target: RaceStatusValue): { valid: boolean; error?: string } {
|
|
const current = this.value;
|
|
|
|
// Define allowed transitions
|
|
const allowedTransitions: Record<RaceStatusValue, RaceStatusValue[]> = {
|
|
scheduled: ['running', 'cancelled'],
|
|
running: ['completed', 'cancelled'],
|
|
completed: ['scheduled'],
|
|
cancelled: ['scheduled'],
|
|
};
|
|
|
|
if (!allowedTransitions[current].includes(target)) {
|
|
return {
|
|
valid: false,
|
|
error: `Cannot transition from ${current} to ${target}`
|
|
};
|
|
}
|
|
|
|
return { valid: true };
|
|
}
|
|
|
|
get props(): RaceStatusProps {
|
|
return { value: this.value };
|
|
}
|
|
|
|
equals(other: ValueObject<RaceStatusProps>): boolean {
|
|
return this.value === other.props.value;
|
|
}
|
|
|
|
toString(): RaceStatusValue {
|
|
return this.value;
|
|
}
|
|
} |