wip
This commit is contained in:
@@ -2,26 +2,31 @@ import type { IStandingRepository } from '../../domain/repositories/IStandingRep
|
||||
import type { IResultRepository } from '../../domain/repositories/IResultRepository';
|
||||
import type { IPenaltyRepository } from '../../domain/repositories/IPenaltyRepository';
|
||||
import type { IRaceRepository } from '../../domain/repositories/IRaceRepository';
|
||||
import type { LeagueDriverSeasonStatsDTO } from '../dto/LeagueDriverSeasonStatsDTO';
|
||||
import type { ILeagueDriverSeasonStatsPresenter } from '../presenters/ILeagueDriverSeasonStatsPresenter';
|
||||
|
||||
export interface DriverRatingPort {
|
||||
getRating(driverId: string): { rating: number | null; ratingChange: number | null };
|
||||
}
|
||||
|
||||
export interface GetLeagueDriverSeasonStatsQueryParamsDTO {
|
||||
export interface GetLeagueDriverSeasonStatsUseCaseParams {
|
||||
leagueId: string;
|
||||
}
|
||||
|
||||
export class GetLeagueDriverSeasonStatsQuery {
|
||||
/**
|
||||
* Use Case for retrieving league driver season statistics.
|
||||
* Orchestrates domain logic and delegates presentation to the presenter.
|
||||
*/
|
||||
export class GetLeagueDriverSeasonStatsUseCase {
|
||||
constructor(
|
||||
private readonly standingRepository: IStandingRepository,
|
||||
private readonly resultRepository: IResultRepository,
|
||||
private readonly penaltyRepository: IPenaltyRepository,
|
||||
private readonly raceRepository: IRaceRepository,
|
||||
private readonly driverRatingPort: DriverRatingPort,
|
||||
public readonly presenter: ILeagueDriverSeasonStatsPresenter,
|
||||
) {}
|
||||
|
||||
async execute(params: GetLeagueDriverSeasonStatsQueryParamsDTO): Promise<LeagueDriverSeasonStatsDTO[]> {
|
||||
async execute(params: GetLeagueDriverSeasonStatsUseCaseParams): Promise<void> {
|
||||
const { leagueId } = params;
|
||||
|
||||
// Get standings and races for the league
|
||||
@@ -53,59 +58,26 @@ export class GetLeagueDriverSeasonStatsQuery {
|
||||
penaltiesByDriver.set(p.driverId, current);
|
||||
}
|
||||
|
||||
// Build basic stats per driver from standings
|
||||
const statsByDriver = new Map<string, LeagueDriverSeasonStatsDTO>();
|
||||
|
||||
// Collect driver ratings
|
||||
const driverRatings = new Map<string, { rating: number | null; ratingChange: number | null }>();
|
||||
for (const standing of standings) {
|
||||
const penalty = penaltiesByDriver.get(standing.driverId) ?? { baseDelta: 0, bonusDelta: 0 };
|
||||
const totalPenaltyPoints = penalty.baseDelta;
|
||||
const bonusPoints = penalty.bonusDelta;
|
||||
|
||||
const racesCompleted = standing.racesCompleted;
|
||||
const pointsPerRace = racesCompleted > 0 ? standing.points / racesCompleted : 0;
|
||||
|
||||
const ratingInfo = this.driverRatingPort.getRating(standing.driverId);
|
||||
|
||||
const dto: LeagueDriverSeasonStatsDTO = {
|
||||
leagueId,
|
||||
driverId: standing.driverId,
|
||||
position: standing.position,
|
||||
driverName: '',
|
||||
teamId: undefined,
|
||||
teamName: undefined,
|
||||
totalPoints: standing.points + totalPenaltyPoints + bonusPoints,
|
||||
basePoints: standing.points,
|
||||
penaltyPoints: Math.abs(totalPenaltyPoints),
|
||||
bonusPoints,
|
||||
pointsPerRace,
|
||||
racesStarted: racesCompleted,
|
||||
racesFinished: racesCompleted,
|
||||
dnfs: 0,
|
||||
noShows: 0,
|
||||
avgFinish: null,
|
||||
rating: ratingInfo.rating,
|
||||
ratingChange: ratingInfo.ratingChange,
|
||||
};
|
||||
|
||||
statsByDriver.set(standing.driverId, dto);
|
||||
driverRatings.set(standing.driverId, ratingInfo);
|
||||
}
|
||||
|
||||
// Enhance stats with basic finish-position-based avgFinish from results
|
||||
for (const [driverId, dto] of statsByDriver.entries()) {
|
||||
const driverResults = await this.resultRepository.findByDriverIdAndLeagueId(driverId, leagueId);
|
||||
if (driverResults.length > 0) {
|
||||
const totalPositions = driverResults.reduce((sum, r) => sum + r.position, 0);
|
||||
const avgFinish = totalPositions / driverResults.length;
|
||||
dto.avgFinish = Number.isFinite(avgFinish) ? Number(avgFinish.toFixed(2)) : null;
|
||||
dto.racesStarted = driverResults.length;
|
||||
dto.racesFinished = driverResults.length;
|
||||
}
|
||||
statsByDriver.set(driverId, dto);
|
||||
// Collect driver results
|
||||
const driverResults = new Map<string, Array<{ position: number }>>();
|
||||
for (const standing of standings) {
|
||||
const results = await this.resultRepository.findByDriverIdAndLeagueId(standing.driverId, leagueId);
|
||||
driverResults.set(standing.driverId, results);
|
||||
}
|
||||
|
||||
// Ensure ordering by position
|
||||
const result = Array.from(statsByDriver.values()).sort((a, b) => a.position - b.position);
|
||||
|
||||
return result;
|
||||
this.presenter.present(
|
||||
leagueId,
|
||||
standings,
|
||||
penaltiesByDriver,
|
||||
driverResults,
|
||||
driverRatings
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user