Files
gridpilot.gg/core/racing/domain/entities/Track.ts
Marc Mintel 6df38a462a
Some checks failed
CI / lint-typecheck (pull_request) Failing after 4m50s
CI / tests (pull_request) Has been skipped
CI / contract-tests (pull_request) Has been skipped
CI / e2e-tests (pull_request) Has been skipped
CI / comment-pr (pull_request) Has been skipped
CI / commit-types (pull_request) Has been skipped
integration tests
2026-01-23 11:44:59 +01:00

117 lines
3.8 KiB
TypeScript

/**
* Domain Entity: Track
*
* Represents a racing track/circuit in the GridPilot platform.
* Immutable entity with factory methods and domain validation.
*/
import { Entity } from '@core/shared/domain/Entity';
import { RacingDomainValidationError } from '../errors/RacingDomainError';
import { TrackCountry } from '../value-objects/TrackCountry';
import { TrackGameId } from '../value-objects/TrackGameId';
import { TrackImageUrl } from '../value-objects/TrackImageUrl';
import { TrackLength } from '../value-objects/TrackLength';
import { TrackName } from '../value-objects/TrackName';
import { TrackShortName } from '../value-objects/TrackShortName';
import { TrackTurns } from '../value-objects/TrackTurns';
export type TrackCategory = 'oval' | 'road' | 'street' | 'dirt';
export type TrackDifficulty = 'beginner' | 'intermediate' | 'advanced' | 'expert';
export class Track extends Entity<string> {
readonly name: TrackName;
readonly shortName: TrackShortName;
readonly country: TrackCountry;
readonly category: TrackCategory;
readonly difficulty: TrackDifficulty;
readonly lengthKm: TrackLength;
readonly turns: TrackTurns;
readonly imageUrl: TrackImageUrl;
readonly gameId: TrackGameId;
private constructor(props: {
id: string;
name: TrackName;
shortName: TrackShortName;
country: TrackCountry;
category: TrackCategory;
difficulty: TrackDifficulty;
lengthKm: TrackLength;
turns: TrackTurns;
imageUrl: TrackImageUrl;
gameId: TrackGameId;
}) {
super(props.id);
this.name = props.name;
this.shortName = props.shortName;
this.country = props.country;
this.category = props.category;
this.difficulty = props.difficulty;
this.lengthKm = props.lengthKm;
this.turns = props.turns;
this.imageUrl = props.imageUrl;
this.gameId = props.gameId;
}
/**
* Factory method to create a new Track entity
*/
static create(props: {
id: string;
name: string;
shortName?: string;
country: string;
category?: TrackCategory;
difficulty?: TrackDifficulty;
lengthKm: number;
turns: number;
imageUrl?: string;
gameId: string;
}): Track {
if (!props.id || props.id.trim().length === 0) {
throw new RacingDomainValidationError('Track ID is required');
}
const shortNameValue = props.shortName ?? props.name.slice(0, 3).toUpperCase();
return new Track({
id: props.id,
name: TrackName.create(props.name),
shortName: TrackShortName.create(shortNameValue),
country: TrackCountry.create(props.country),
category: props.category ?? 'road',
difficulty: props.difficulty ?? 'intermediate',
lengthKm: TrackLength.create(props.lengthKm),
turns: TrackTurns.create(props.turns),
imageUrl: TrackImageUrl.create(props.imageUrl),
gameId: TrackGameId.create(props.gameId),
});
}
update(props: Partial<{
name: string;
shortName: string;
country: string;
category: TrackCategory;
difficulty: TrackDifficulty;
lengthKm: number;
turns: number;
imageUrl: string;
gameId: string;
}>): Track {
return new Track({
id: this.id,
name: props.name ? TrackName.create(props.name) : this.name,
shortName: props.shortName ? TrackShortName.create(props.shortName) : this.shortName,
country: props.country ? TrackCountry.create(props.country) : this.country,
category: props.category ?? this.category,
difficulty: props.difficulty ?? this.difficulty,
lengthKm: props.lengthKm ? TrackLength.create(props.lengthKm) : this.lengthKm,
turns: props.turns ? TrackTurns.create(props.turns) : this.turns,
imageUrl: props.imageUrl ? TrackImageUrl.create(props.imageUrl) : this.imageUrl,
gameId: props.gameId ? TrackGameId.create(props.gameId) : this.gameId,
});
}
}