refactor racing use cases

This commit is contained in:
2025-12-21 00:43:42 +01:00
parent e9d6f90bb2
commit c12656d671
308 changed files with 14401 additions and 7419 deletions

View File

@@ -1,4 +1,4 @@
import type { AsyncUseCase , Logger } from '@core/shared/application';
import type { Logger } from '@core/shared/application';
import type { IRaceEventRepository } from '../../domain/repositories/IRaceEventRepository';
import type { IRaceRegistrationRepository } from '../../domain/repositories/IRaceRegistrationRepository';
import type { IPenaltyRepository } from '../../domain/repositories/IPenaltyRepository';
@@ -6,8 +6,17 @@ import type { DomainEventPublisher } from '@/shared/domain/DomainEvent';
import { RaceEventStewardingClosedEvent } from '../../domain/events/RaceEventStewardingClosed';
import { Result } from '@core/shared/application/Result';
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
import type { CloseRaceEventStewardingCommand } from '../dto/CloseRaceEventStewardingCommand';
import type { RaceEvent } from '../../domain/entities/RaceEvent';
import type { UseCaseOutputPort } from '@core/shared/application/UseCaseOutputPort';
export type CloseRaceEventStewardingInput = {
raceId: string;
closedById: string;
};
export type CloseRaceEventStewardingResult = {
race: RaceEvent;
};
/**
* Use Case: CloseRaceEventStewardingUseCase
@@ -18,9 +27,7 @@ import type { RaceEvent } from '../../domain/entities/RaceEvent';
* This would typically be run by a scheduled job (e.g., every 5 minutes)
* to automatically close stewarding windows based on league configuration.
*/
export class CloseRaceEventStewardingUseCase
implements AsyncUseCase<CloseRaceEventStewardingCommand, void, string>
{
export class CloseRaceEventStewardingUseCase {
constructor(
private readonly logger: Logger,
@@ -28,22 +35,41 @@ export class CloseRaceEventStewardingUseCase
private readonly raceRegistrationRepository: IRaceRegistrationRepository,
private readonly penaltyRepository: IPenaltyRepository,
private readonly domainEventPublisher: DomainEventPublisher,
private readonly output: UseCaseOutputPort<CloseRaceEventStewardingResult>,
) {}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
async execute(_command: CloseRaceEventStewardingCommand): Promise<Result<void, ApplicationErrorCode<string>>> {
async execute(_: CloseRaceEventStewardingInput): Promise<Result<void, ApplicationErrorCode<'RACE_NOT_FOUND' | 'STEWARDING_ALREADY_CLOSED' | 'REPOSITORY_ERROR'>>> {
try {
// Find all race events awaiting stewarding that have expired windows
const expiredEvents = await this.raceEventRepository.findAwaitingStewardingClose();
const closedRaceEventIds: string[] = [];
for (const raceEvent of expiredEvents) {
await this.closeStewardingForRaceEvent(raceEvent);
closedRaceEventIds.push(raceEvent.id);
}
// When multiple race events are processed, we present the last closed event for simplicity
const lastClosedEventId = closedRaceEventIds[closedRaceEventIds.length - 1];
if (lastClosedEventId) {
const lastClosedEvent = await this.raceEventRepository.findById(lastClosedEventId);
if (lastClosedEvent) {
this.output.present({
race: lastClosedEvent,
});
}
}
return Result.ok(undefined);
} catch (error) {
this.logger.error('Failed to close race event stewarding', error instanceof Error ? error : new Error(String(error)));
return Result.err({ code: 'FAILED_TO_CLOSE_STEWARDING' });
return Result.err({
code: 'REPOSITORY_ERROR',
details: {
message: error instanceof Error ? error.message : String(error),
},
});
}
}