150 lines
4.3 KiB
TypeScript
150 lines
4.3 KiB
TypeScript
import { Result } from '@core/shared/domain/Result';
|
|
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
|
|
import type { Driver } from '../../domain/entities/Driver';
|
|
import type { League } from '../../domain/entities/League';
|
|
import type { Race } from '../../domain/entities/Race';
|
|
import type { Penalty } from '../../domain/entities/penalty/Penalty';
|
|
import type { Result as DomainResult } from '../../domain/entities/result/Result';
|
|
import type { DriverRepository } from '../../domain/repositories/DriverRepository';
|
|
import type { LeagueRepository } from '../../domain/repositories/LeagueRepository';
|
|
import type { PenaltyRepository } from '../../domain/repositories/PenaltyRepository';
|
|
import type { RaceRepository } from '../../domain/repositories/RaceRepository';
|
|
import type { ResultRepository } from '../../domain/repositories/ResultRepository';
|
|
|
|
export type GetRaceResultsDetailInput = {
|
|
raceId: string;
|
|
driverId?: string;
|
|
};
|
|
|
|
export type GetRaceResultsDetailErrorCode =
|
|
| 'RACE_NOT_FOUND'
|
|
| 'REPOSITORY_ERROR';
|
|
|
|
export type GetRaceResultsDetailResult = {
|
|
race: Race;
|
|
league: League | null;
|
|
results: DomainResult[];
|
|
drivers: Driver[];
|
|
penalties: Penalty[];
|
|
pointsSystem?: Record<number, number>;
|
|
fastestLapTime?: number;
|
|
currentDriverId?: string;
|
|
};
|
|
|
|
export class GetRaceResultsDetailUseCase {
|
|
constructor(
|
|
private readonly raceRepository: RaceRepository,
|
|
private readonly leagueRepository: LeagueRepository,
|
|
private readonly resultRepository: ResultRepository,
|
|
private readonly driverRepository: DriverRepository,
|
|
private readonly penaltyRepository: PenaltyRepository,
|
|
) {}
|
|
|
|
async execute(
|
|
params: GetRaceResultsDetailInput,
|
|
): Promise<
|
|
Result<GetRaceResultsDetailResult, ApplicationErrorCode<GetRaceResultsDetailErrorCode, { message: string }>>
|
|
> {
|
|
try {
|
|
const { raceId, driverId } = params;
|
|
|
|
const race = await this.raceRepository.findById(raceId);
|
|
|
|
if (!race) {
|
|
return Result.err({
|
|
code: 'RACE_NOT_FOUND',
|
|
details: { message: 'Race not found' },
|
|
});
|
|
}
|
|
|
|
const [league, results, drivers, penalties] = await Promise.all([
|
|
this.leagueRepository.findById(race.leagueId),
|
|
this.resultRepository.findByRaceId(raceId),
|
|
this.driverRepository.findAll(),
|
|
this.penaltyRepository.findByRaceId(raceId),
|
|
]);
|
|
|
|
const effectiveCurrentDriverId =
|
|
driverId ?? (drivers.length > 0 ? drivers[0]!.id : undefined);
|
|
|
|
const pointsSystem = this.buildPointsSystem(league);
|
|
const fastestLapTime = this.getFastestLapTime(results);
|
|
|
|
const result: GetRaceResultsDetailResult = {
|
|
race,
|
|
league,
|
|
results,
|
|
drivers,
|
|
penalties,
|
|
...(pointsSystem ? { pointsSystem } : {}),
|
|
...(fastestLapTime !== undefined ? { fastestLapTime } : {}),
|
|
...(effectiveCurrentDriverId ? { currentDriverId: effectiveCurrentDriverId } : {}),
|
|
};
|
|
|
|
return Result.ok(result);
|
|
} catch (error: unknown) {
|
|
const message =
|
|
error instanceof Error && typeof error.message === 'string'
|
|
? error.message
|
|
: 'Failed to load race results detail';
|
|
|
|
return Result.err({
|
|
code: 'REPOSITORY_ERROR',
|
|
details: { message },
|
|
});
|
|
}
|
|
}
|
|
|
|
private buildPointsSystem(league: League | null): Record<number, number> | undefined {
|
|
if (!league) return undefined;
|
|
|
|
const pointsSystems: Record<string, Record<number, number>> = {
|
|
'f1-2024': {
|
|
1: 25,
|
|
2: 18,
|
|
3: 15,
|
|
4: 12,
|
|
5: 10,
|
|
6: 8,
|
|
7: 6,
|
|
8: 4,
|
|
9: 2,
|
|
10: 1,
|
|
},
|
|
indycar: {
|
|
1: 50,
|
|
2: 40,
|
|
3: 35,
|
|
4: 32,
|
|
5: 30,
|
|
6: 28,
|
|
7: 26,
|
|
8: 24,
|
|
9: 22,
|
|
10: 20,
|
|
11: 19,
|
|
12: 18,
|
|
13: 17,
|
|
14: 16,
|
|
15: 15,
|
|
},
|
|
};
|
|
|
|
const customPoints = league.settings.customPoints;
|
|
if (customPoints) {
|
|
return customPoints;
|
|
}
|
|
|
|
const preset = pointsSystems[league.settings.pointsSystem];
|
|
if (preset) {
|
|
return preset;
|
|
}
|
|
|
|
return pointsSystems['f1-2024'];
|
|
}
|
|
|
|
private getFastestLapTime(results: DomainResult[]): number | undefined {
|
|
if (results.length === 0) return undefined;
|
|
return Math.min(...results.map(r => r.fastestLap.toNumber()));
|
|
}
|
|
} |