119 lines
3.5 KiB
TypeScript
119 lines
3.5 KiB
TypeScript
/**
|
|
* Domain Entity: Car
|
|
*
|
|
* Represents a racing car/vehicle in the GridPilot platform.
|
|
* Immutable entity with factory methods and domain validation.
|
|
*/
|
|
|
|
import type { IEntity } from '@core/shared/domain';
|
|
import { RacingDomainValidationError } from '../errors/RacingDomainError';
|
|
import { CarName } from './CarName';
|
|
import { Manufacturer } from './Manufacturer';
|
|
import { CarClass, CarClassType } from './CarClass';
|
|
import { CarLicense, CarLicenseType } from './CarLicense';
|
|
import { Year } from './Year';
|
|
import { Horsepower } from './Horsepower';
|
|
import { Weight } from './Weight';
|
|
import { GameId } from './GameId';
|
|
import { CarId } from './CarId';
|
|
import { ImageUrl } from './ImageUrl';
|
|
|
|
export class Car implements IEntity<CarId> {
|
|
readonly id: CarId;
|
|
readonly name: CarName;
|
|
readonly shortName: string;
|
|
readonly manufacturer: Manufacturer;
|
|
readonly carClass: CarClass;
|
|
readonly license: CarLicense;
|
|
readonly year: Year;
|
|
readonly horsepower: Horsepower | undefined;
|
|
readonly weight: Weight | undefined;
|
|
readonly imageUrl: ImageUrl | undefined;
|
|
readonly gameId: GameId;
|
|
|
|
private constructor(props: {
|
|
id: CarId;
|
|
name: CarName;
|
|
shortName: string;
|
|
manufacturer: Manufacturer;
|
|
carClass: CarClass;
|
|
license: CarLicense;
|
|
year: Year;
|
|
horsepower?: Horsepower;
|
|
weight?: Weight;
|
|
imageUrl?: ImageUrl;
|
|
gameId: GameId;
|
|
}) {
|
|
this.id = props.id;
|
|
this.name = props.name;
|
|
this.shortName = props.shortName;
|
|
this.manufacturer = props.manufacturer;
|
|
this.carClass = props.carClass;
|
|
this.license = props.license;
|
|
this.year = props.year;
|
|
this.horsepower = props.horsepower;
|
|
this.weight = props.weight;
|
|
this.imageUrl = props.imageUrl;
|
|
this.gameId = props.gameId;
|
|
}
|
|
|
|
/**
|
|
* Factory method to create a new Car entity
|
|
*/
|
|
static create(props: {
|
|
id: string;
|
|
name: string;
|
|
shortName?: string;
|
|
manufacturer: string;
|
|
carClass?: CarClassType;
|
|
license?: CarLicenseType;
|
|
year?: number;
|
|
horsepower?: number;
|
|
weight?: number;
|
|
imageUrl?: string;
|
|
gameId: string;
|
|
}): Car {
|
|
this.validate(props);
|
|
|
|
return new Car({
|
|
id: CarId.create(props.id),
|
|
name: CarName.create(props.name),
|
|
shortName: props.shortName ?? props.name.slice(0, 10),
|
|
manufacturer: Manufacturer.create(props.manufacturer),
|
|
carClass: CarClass.create(props.carClass ?? 'gt'),
|
|
license: CarLicense.create(props.license ?? 'D'),
|
|
year: Year.create(props.year ?? new Date().getFullYear()),
|
|
...(props.horsepower !== undefined ? { horsepower: Horsepower.create(props.horsepower) } : {}),
|
|
...(props.weight !== undefined ? { weight: Weight.create(props.weight) } : {}),
|
|
...(props.imageUrl !== undefined ? { imageUrl: ImageUrl.create(props.imageUrl) } : {}),
|
|
gameId: GameId.create(props.gameId),
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Domain validation logic
|
|
*/
|
|
private static validate(props: {
|
|
id: string;
|
|
name: string;
|
|
manufacturer: string;
|
|
gameId: string;
|
|
}): void {
|
|
if (!props.id || props.id.trim().length === 0) {
|
|
throw new RacingDomainValidationError('Car ID is required');
|
|
}
|
|
|
|
if (!props.name || props.name.trim().length === 0) {
|
|
throw new RacingDomainValidationError('Car name is required');
|
|
}
|
|
|
|
if (!props.manufacturer || props.manufacturer.trim().length === 0) {
|
|
throw new RacingDomainValidationError('Car manufacturer is required');
|
|
}
|
|
|
|
if (!props.gameId || props.gameId.trim().length === 0) {
|
|
throw new RacingDomainValidationError('Game ID is required');
|
|
}
|
|
}
|
|
|
|
} |