/** * Domain Entity: Driver * * Represents a driver profile in the GridPilot platform. * Immutable entity with factory methods and domain validation. */ import { MediaReference } from '@core/domain/media/MediaReference'; import { Entity } from '@core/shared/domain/Entity'; import { RacingDomainValidationError } from '../errors/RacingDomainError'; import { CountryCode } from '../value-objects/CountryCode'; import { DriverBio } from '../value-objects/driver/DriverBio'; import { DriverName } from '../value-objects/driver/DriverName'; import { JoinedAt } from '../value-objects/JoinedAt'; import { IRacingId } from '../value-objects/RacingId'; export class Driver extends Entity { readonly iracingId: IRacingId; readonly name: DriverName; readonly country: CountryCode; readonly bio: DriverBio | undefined; readonly joinedAt: JoinedAt; readonly category: string | undefined; readonly avatarRef: MediaReference; private constructor(props: { id: string; iracingId: IRacingId; name: DriverName; country: CountryCode; bio?: DriverBio; joinedAt: JoinedAt; category?: string; avatarRef: MediaReference; }) { super(props.id); this.iracingId = props.iracingId; this.name = props.name; this.country = props.country; this.bio = props.bio; this.joinedAt = props.joinedAt; this.category = props.category; this.avatarRef = props.avatarRef; } /** * Factory method to create a new Driver entity */ static create(props: { id: string; iracingId: string; name: string; country: string; bio?: string; joinedAt?: Date; category?: string; avatarRef?: MediaReference; }): Driver { if (!props.id || props.id.trim().length === 0) { throw new RacingDomainValidationError('Driver ID is required'); } const driverProps: { id: string; iracingId: IRacingId; name: DriverName; country: CountryCode; bio?: DriverBio; joinedAt: JoinedAt; category?: string; avatarRef: MediaReference; } = { id: props.id, iracingId: IRacingId.create(props.iracingId), name: DriverName.create(props.name), country: CountryCode.create(props.country), joinedAt: JoinedAt.create(props.joinedAt ?? new Date()), avatarRef: props.avatarRef ?? MediaReference.createSystemDefault('avatar'), }; if (props.bio !== undefined) { driverProps.bio = DriverBio.create(props.bio); } if (props.category !== undefined) { driverProps.category = props.category; } return new Driver(driverProps); } static rehydrate(props: { id: string; iracingId: string; name: string; country: string; bio?: string; joinedAt: Date; category?: string; avatarRef?: MediaReference; }): Driver { const driverProps: { id: string; iracingId: IRacingId; name: DriverName; country: CountryCode; bio?: DriverBio; joinedAt: JoinedAt; category?: string; avatarRef: MediaReference; } = { id: props.id, iracingId: IRacingId.create(props.iracingId), name: DriverName.create(props.name), country: CountryCode.create(props.country), joinedAt: JoinedAt.create(props.joinedAt), avatarRef: props.avatarRef ?? MediaReference.createSystemDefault('avatar'), }; if (props.bio !== undefined) { driverProps.bio = DriverBio.create(props.bio); } if (props.category !== undefined) { driverProps.category = props.category; } return new Driver(driverProps); } /** * Create a copy with updated properties */ update(props: Partial<{ name: string; country: string; bio: string | undefined; category: string | undefined; avatarRef: MediaReference; }>): Driver { const nextName = 'name' in props ? DriverName.create(props.name!) : this.name; const nextCountry = 'country' in props ? CountryCode.create(props.country!) : this.country; const nextBio = 'bio' in props ? (props.bio ? DriverBio.create(props.bio) : undefined) : this.bio; const nextCategory = 'category' in props ? props.category : this.category; const nextAvatarRef = 'avatarRef' in props ? props.avatarRef! : this.avatarRef; const driverProps: { id: string; iracingId: IRacingId; name: DriverName; country: CountryCode; bio?: DriverBio; joinedAt: JoinedAt; category?: string; avatarRef: MediaReference; } = { id: this.id, iracingId: this.iracingId, name: nextName, country: nextCountry, joinedAt: this.joinedAt, avatarRef: nextAvatarRef, }; if (nextBio !== undefined) { driverProps.bio = nextBio; } if (nextCategory !== undefined) { driverProps.category = nextCategory; } return new Driver(driverProps); } equals(other: Entity): boolean { if (!(other instanceof Driver)) { return false; } return this.id === other.id; } }