This commit is contained in:
2025-12-17 00:33:13 +01:00
parent 8c67081953
commit f01e01e50c
186 changed files with 9242 additions and 1342 deletions

View File

@@ -4,26 +4,31 @@
* Represents a championship standing 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 { LeagueId } from './LeagueId';
import { DriverId } from './DriverId';
import { Points } from '../value-objects/Points';
import { Position } from './championship/Position';
export class Standing implements IEntity<string> {
readonly id: string;
readonly leagueId: string;
readonly driverId: string;
readonly points: number;
readonly leagueId: LeagueId;
readonly driverId: DriverId;
readonly points: Points;
readonly wins: number;
readonly position: number;
readonly position: Position;
readonly racesCompleted: number;
private constructor(props: {
id: string;
leagueId: string;
driverId: string;
points: number;
leagueId: LeagueId;
driverId: DriverId;
points: Points;
wins: number;
position: number;
position: Position;
racesCompleted: number;
}) {
this.id = props.id;
@@ -47,19 +52,24 @@ export class Standing implements IEntity<string> {
position?: number;
racesCompleted?: number;
}): Standing {
this.validate(props);
Standing.validate(props);
const id = props.id && props.id.trim().length > 0
? props.id
: `${props.leagueId}:${props.driverId}`;
const leagueId = LeagueId.create(props.leagueId);
const driverId = DriverId.create(props.driverId);
const points = Points.create(props.points ?? 0);
const position = Position.create(props.position ?? 1); // Default to 1 for position
return new Standing({
id,
leagueId: props.leagueId,
driverId: props.driverId,
points: props.points ?? 0,
leagueId,
driverId,
points,
wins: props.wins ?? 0,
position: props.position ?? 0,
position,
racesCompleted: props.racesCompleted ?? 0,
});
}
@@ -75,7 +85,7 @@ export class Standing implements IEntity<string> {
if (!props.leagueId || props.leagueId.trim().length === 0) {
throw new RacingDomainValidationError('League ID is required');
}
if (!props.driverId || props.driverId.trim().length === 0) {
throw new RacingDomainValidationError('Driver ID is required');
}
@@ -88,13 +98,16 @@ export class Standing implements IEntity<string> {
const racePoints = pointsSystem[position] ?? 0;
const isWin = position === 1;
const newPoints = Points.create(this.points.toNumber() + racePoints);
const newPosition = this.position; // Position might be updated separately
return new Standing({
id: this.id,
leagueId: this.leagueId,
driverId: this.driverId,
points: this.points + racePoints,
points: newPoints,
wins: this.wins + (isWin ? 1 : 0),
position: this.position,
position: newPosition,
racesCompleted: this.racesCompleted + 1,
});
}
@@ -103,17 +116,15 @@ export class Standing implements IEntity<string> {
* Update championship position
*/
updatePosition(position: number): Standing {
if (!Number.isInteger(position) || position < 1) {
throw new RacingDomainValidationError('Position must be a positive integer');
}
const newPosition = Position.create(position);
return Standing.create({
return new Standing({
id: this.id,
leagueId: this.leagueId,
driverId: this.driverId,
points: this.points,
wins: this.wins,
position,
position: newPosition,
racesCompleted: this.racesCompleted,
});
}
@@ -123,7 +134,7 @@ export class Standing implements IEntity<string> {
*/
getAveragePoints(): number {
if (this.racesCompleted === 0) return 0;
return this.points / this.racesCompleted;
return this.points.toNumber() / this.racesCompleted;
}
/**