/** * Domain Entity: Result * * Represents a race result in the GridPilot platform. * Immutable entity with factory methods and domain validation. */ export class Result { readonly id: string; readonly raceId: string; readonly driverId: string; readonly position: number; readonly fastestLap: number; readonly incidents: number; readonly startPosition: number; private constructor(props: { id: string; raceId: string; driverId: string; position: number; fastestLap: number; incidents: number; startPosition: number; }) { this.id = props.id; this.raceId = props.raceId; this.driverId = props.driverId; this.position = props.position; this.fastestLap = props.fastestLap; this.incidents = props.incidents; this.startPosition = props.startPosition; } /** * Factory method to create a new Result entity */ static create(props: { id: string; raceId: string; driverId: string; position: number; fastestLap: number; incidents: number; startPosition: number; }): Result { this.validate(props); return new Result(props); } /** * Domain validation logic */ private static validate(props: { id: string; raceId: string; driverId: string; position: number; fastestLap: number; incidents: number; startPosition: number; }): void { if (!props.id || props.id.trim().length === 0) { throw new Error('Result ID is required'); } if (!props.raceId || props.raceId.trim().length === 0) { throw new Error('Race ID is required'); } if (!props.driverId || props.driverId.trim().length === 0) { throw new Error('Driver ID is required'); } if (!Number.isInteger(props.position) || props.position < 1) { throw new Error('Position must be a positive integer'); } if (props.fastestLap < 0) { throw new Error('Fastest lap cannot be negative'); } if (!Number.isInteger(props.incidents) || props.incidents < 0) { throw new Error('Incidents must be a non-negative integer'); } if (!Number.isInteger(props.startPosition) || props.startPosition < 1) { throw new Error('Start position must be a positive integer'); } } /** * Calculate positions gained/lost */ getPositionChange(): number { return this.startPosition - this.position; } /** * Check if driver finished on podium */ isPodium(): boolean { return this.position <= 3; } /** * Check if driver had a clean race (0 incidents) */ isClean(): boolean { return this.incidents === 0; } }