refactor racing use cases
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
import type { ISeasonRepository } from '../../domain/repositories/ISeasonRepository';
|
||||
import type { ILeagueRepository } from '../../domain/repositories/ILeagueRepository';
|
||||
import type { SeasonStatus } from '../../domain/entities/season/Season';
|
||||
import { Result } from '@core/shared/application/Result';
|
||||
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
|
||||
import type { UseCaseOutputPort } from '@core/shared/application';
|
||||
|
||||
export type SeasonLifecycleTransition =
|
||||
| 'activate'
|
||||
@@ -9,20 +11,29 @@ export type SeasonLifecycleTransition =
|
||||
| 'archive'
|
||||
| 'cancel';
|
||||
|
||||
export interface ManageSeasonLifecycleCommand {
|
||||
export type ManageSeasonLifecycleInput = {
|
||||
leagueId: string;
|
||||
seasonId: string;
|
||||
transition: SeasonLifecycleTransition;
|
||||
}
|
||||
};
|
||||
|
||||
export interface ManageSeasonLifecycleResultDTO {
|
||||
seasonId: string;
|
||||
status: import('../../domain/entities/Season').SeasonStatus;
|
||||
export type ManagedSeasonState = {
|
||||
id: string;
|
||||
leagueId: string;
|
||||
status: SeasonStatus;
|
||||
startDate?: Date;
|
||||
endDate?: Date;
|
||||
}
|
||||
};
|
||||
|
||||
type ManageSeasonLifecycleErrorCode = 'LEAGUE_NOT_FOUND' | 'SEASON_NOT_FOUND' | 'INVALID_TRANSITION';
|
||||
export type ManageSeasonLifecycleResult = {
|
||||
season: ManagedSeasonState;
|
||||
};
|
||||
|
||||
export type ManageSeasonLifecycleErrorCode =
|
||||
| 'LEAGUE_NOT_FOUND'
|
||||
| 'SEASON_NOT_FOUND'
|
||||
| 'INVALID_TRANSITION'
|
||||
| 'REPOSITORY_ERROR';
|
||||
|
||||
/**
|
||||
* ManageSeasonLifecycleUseCase
|
||||
@@ -31,59 +42,76 @@ export class ManageSeasonLifecycleUseCase {
|
||||
constructor(
|
||||
private readonly leagueRepository: ILeagueRepository,
|
||||
private readonly seasonRepository: ISeasonRepository,
|
||||
private readonly output: UseCaseOutputPort<ManageSeasonLifecycleResult>,
|
||||
) {}
|
||||
|
||||
async execute(
|
||||
command: ManageSeasonLifecycleCommand,
|
||||
): Promise<Result<ManageSeasonLifecycleResultDTO, ApplicationErrorCode<ManageSeasonLifecycleErrorCode>>> {
|
||||
const league = await this.leagueRepository.findById(command.leagueId);
|
||||
if (!league) {
|
||||
return Result.err({
|
||||
code: 'LEAGUE_NOT_FOUND',
|
||||
details: { message: `League not found: ${command.leagueId}` },
|
||||
});
|
||||
}
|
||||
|
||||
const season = await this.seasonRepository.findById(command.seasonId);
|
||||
if (!season || season.leagueId !== league.id) {
|
||||
return Result.err({
|
||||
code: 'SEASON_NOT_FOUND',
|
||||
details: { message: `Season ${command.seasonId} does not belong to league ${league.id}` },
|
||||
});
|
||||
}
|
||||
|
||||
let updated;
|
||||
input: ManageSeasonLifecycleInput,
|
||||
): Promise<Result<void, ApplicationErrorCode<ManageSeasonLifecycleErrorCode, { message: string }>>> {
|
||||
try {
|
||||
switch (command.transition) {
|
||||
case 'activate':
|
||||
updated = season.activate();
|
||||
break;
|
||||
case 'complete':
|
||||
updated = season.complete();
|
||||
break;
|
||||
case 'archive':
|
||||
updated = season.archive();
|
||||
break;
|
||||
case 'cancel':
|
||||
updated = season.cancel();
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unsupported Season lifecycle transition`);
|
||||
const league = await this.leagueRepository.findById(input.leagueId);
|
||||
if (!league) {
|
||||
return Result.err({
|
||||
code: 'LEAGUE_NOT_FOUND',
|
||||
details: { message: `League not found: ${input.leagueId}` },
|
||||
});
|
||||
}
|
||||
|
||||
const season = await this.seasonRepository.findById(input.seasonId);
|
||||
if (!season || season.leagueId !== league.id) {
|
||||
return Result.err({
|
||||
code: 'SEASON_NOT_FOUND',
|
||||
details: { message: `Season ${input.seasonId} does not belong to league ${league.id}` },
|
||||
});
|
||||
}
|
||||
|
||||
let updated;
|
||||
try {
|
||||
switch (input.transition) {
|
||||
case 'activate':
|
||||
updated = season.activate();
|
||||
break;
|
||||
case 'complete':
|
||||
updated = season.complete();
|
||||
break;
|
||||
case 'archive':
|
||||
updated = season.archive();
|
||||
break;
|
||||
case 'cancel':
|
||||
updated = season.cancel();
|
||||
break;
|
||||
default:
|
||||
throw new Error('Unsupported Season lifecycle transition');
|
||||
}
|
||||
} catch (error) {
|
||||
return Result.err({
|
||||
code: 'INVALID_TRANSITION',
|
||||
details: { message: `Invalid transition: ${(error as Error).message}` },
|
||||
});
|
||||
}
|
||||
|
||||
await this.seasonRepository.update(updated);
|
||||
|
||||
const result: ManageSeasonLifecycleResult = {
|
||||
season: {
|
||||
id: updated.id,
|
||||
leagueId: updated.leagueId,
|
||||
status: updated.status,
|
||||
...(updated.startDate !== undefined ? { startDate: updated.startDate } : {}),
|
||||
...(updated.endDate !== undefined ? { endDate: updated.endDate } : {}),
|
||||
},
|
||||
};
|
||||
|
||||
this.output.present(result);
|
||||
|
||||
return Result.ok(undefined);
|
||||
} catch (error) {
|
||||
return Result.err({
|
||||
code: 'INVALID_TRANSITION',
|
||||
details: { message: `Invalid transition: ${(error as Error).message}` },
|
||||
code: 'REPOSITORY_ERROR',
|
||||
details: {
|
||||
message: (error as Error).message || 'Failed to manage season lifecycle',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
await this.seasonRepository.update(updated);
|
||||
|
||||
return Result.ok({
|
||||
seasonId: updated.id,
|
||||
status: updated.status,
|
||||
...(updated.startDate !== undefined ? { startDate: updated.startDate } : {}),
|
||||
...(updated.endDate !== undefined ? { endDate: updated.endDate } : {}),
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user