This commit is contained in:
2025-12-14 18:11:59 +01:00
parent acc15e8d8d
commit 217337862c
91 changed files with 5919 additions and 1999 deletions

View File

@@ -13,6 +13,7 @@ import type {
IImportRaceResultsPresenter,
ImportRaceResultsSummaryViewModel,
} from '../presenters/IImportRaceResultsPresenter';
import type { ILogger } from '../../../shared/src/logging/ILogger';
export interface ImportRaceResultDTO {
id: string;
@@ -39,53 +40,72 @@ export class ImportRaceResultsUseCase
private readonly driverRepository: IDriverRepository,
private readonly standingRepository: IStandingRepository,
public readonly presenter: IImportRaceResultsPresenter,
private readonly logger: ILogger,
) {}
async execute(params: ImportRaceResultsParams): Promise<void> {
this.logger.debug('ImportRaceResultsUseCase:execute', { params });
const { raceId, results } = params;
const race = await this.raceRepository.findById(raceId);
if (!race) {
throw new EntityNotFoundError({ entity: 'race', id: raceId });
try {
const race = await this.raceRepository.findById(raceId);
if (!race) {
this.logger.warn(`ImportRaceResultsUseCase: Race with ID ${raceId} not found.`);
throw new EntityNotFoundError({ entity: 'race', id: raceId });
}
this.logger.debug(`ImportRaceResultsUseCase: Race ${raceId} found.`);
const league = await this.leagueRepository.findById(race.leagueId);
if (!league) {
this.logger.warn(`ImportRaceResultsUseCase: League with ID ${race.leagueId} not found for race ${raceId}.`);
throw new EntityNotFoundError({ entity: 'league', id: race.leagueId });
}
this.logger.debug(`ImportRaceResultsUseCase: League ${league.id} found.`);
const existing = await this.resultRepository.existsByRaceId(raceId);
if (existing) {
this.logger.warn(`ImportRaceResultsUseCase: Results already exist for race ID: ${raceId}.`);
throw new BusinessRuleViolationError('Results already exist for this race');
}
this.logger.debug(`ImportRaceResultsUseCase: No existing results for race ${raceId}.`);
// Lookup drivers by iracingId and create results with driver.id
const entities = await Promise.all(
results.map(async (dto) => {
const driver = await this.driverRepository.findByIRacingId(dto.driverId);
if (!driver) {
this.logger.warn(`ImportRaceResultsUseCase: Driver with iRacing ID ${dto.driverId} not found for race ${raceId}.`);
throw new BusinessRuleViolationError(`Driver with iRacing ID ${dto.driverId} not found`);
}
return Result.create({
id: dto.id,
raceId: dto.raceId,
driverId: driver.id,
position: dto.position,
fastestLap: dto.fastestLap,
incidents: dto.incidents,
startPosition: dto.startPosition,
});
}),
);
this.logger.debug('ImportRaceResultsUseCase:entities created', { count: entities.length });
await this.resultRepository.createMany(entities);
this.logger.info('ImportRaceResultsUseCase:race results created', { raceId });
await this.standingRepository.recalculate(league.id);
this.logger.info('ImportRaceResultsUseCase:standings recalculated', { leagueId: league.id });
const viewModel: ImportRaceResultsSummaryViewModel = {
importedCount: results.length,
standingsRecalculated: true,
};
this.logger.debug('ImportRaceResultsUseCase:presenting view model', { viewModel });
this.presenter.present(viewModel);
} catch (error) {
this.logger.error('ImportRaceResultsUseCase:execution error', { error });
throw error;
}
const league = await this.leagueRepository.findById(race.leagueId);
if (!league) {
throw new EntityNotFoundError({ entity: 'league', id: race.leagueId });
}
const existing = await this.resultRepository.existsByRaceId(raceId);
if (existing) {
throw new BusinessRuleViolationError('Results already exist for this race');
}
// Lookup drivers by iracingId and create results with driver.id
const entities = await Promise.all(
results.map(async (dto) => {
const driver = await this.driverRepository.findByIRacingId(dto.driverId);
if (!driver) {
throw new BusinessRuleViolationError(`Driver with iRacing ID ${dto.driverId} not found`);
}
return Result.create({
id: dto.id,
raceId: dto.raceId,
driverId: driver.id,
position: dto.position,
fastestLap: dto.fastestLap,
incidents: dto.incidents,
startPosition: dto.startPosition,
});
}),
);
await this.resultRepository.createMany(entities);
await this.standingRepository.recalculate(league.id);
const viewModel: ImportRaceResultsSummaryViewModel = {
importedCount: results.length,
standingsRecalculated: true,
};
this.presenter.present(viewModel);
}
}
}