refactor racing use cases
This commit is contained in:
@@ -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),
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user