/** * Domain Entity: Driver * * Represents a driver profile in the GridPilot platform. * Immutable entity with factory methods and domain validation. */ export class Driver { readonly id: string; readonly iracingId: string; readonly name: string; readonly country: string; readonly bio?: string; readonly joinedAt: Date; private constructor(props: { id: string; iracingId: string; name: string; country: string; bio?: string; joinedAt: Date; }) { this.id = props.id; this.iracingId = props.iracingId; this.name = props.name; this.country = props.country; this.bio = props.bio; this.joinedAt = props.joinedAt; } /** * Factory method to create a new Driver entity */ static create(props: { id: string; iracingId: string; name: string; country: string; bio?: string; joinedAt?: Date; }): Driver { this.validate(props); return new Driver({ ...props, joinedAt: props.joinedAt ?? new Date(), }); } /** * Domain validation logic */ private static validate(props: { id: string; iracingId: string; name: string; country: string; }): void { if (!props.id || props.id.trim().length === 0) { throw new Error('Driver ID is required'); } if (!props.iracingId || props.iracingId.trim().length === 0) { throw new Error('iRacing ID is required'); } if (!props.name || props.name.trim().length === 0) { throw new Error('Driver name is required'); } if (!props.country || props.country.trim().length === 0) { throw new Error('Country code is required'); } // Validate ISO country code format (2-3 letters) if (!/^[A-Z]{2,3}$/i.test(props.country)) { throw new Error('Country must be a valid ISO code (2-3 letters)'); } } /** * Create a copy with updated properties */ update(props: Partial<{ name: string; country: string; bio: string; }>): Driver { return new Driver({ id: this.id, iracingId: this.iracingId, name: props.name ?? this.name, country: props.country ?? this.country, bio: props.bio ?? this.bio, joinedAt: this.joinedAt, }); } }