refactor
This commit is contained in:
@@ -14,43 +14,13 @@ import {
|
||||
LeagueVisibility,
|
||||
MIN_RANKED_LEAGUE_DRIVERS,
|
||||
} from '../../domain/value-objects/LeagueVisibility';
|
||||
|
||||
/**
|
||||
* League visibility/ranking mode.
|
||||
* - 'ranked' (or legacy 'public'): Competitive, public, affects driver ratings. Min 10 drivers.
|
||||
* - 'unranked' (or legacy 'private'): Casual with friends, no rating impact.
|
||||
*/
|
||||
export type LeagueVisibilityInput = 'ranked' | 'unranked' | 'public' | 'private';
|
||||
|
||||
export interface CreateLeagueWithSeasonAndScoringCommand {
|
||||
name: string;
|
||||
description?: string;
|
||||
/**
|
||||
* League visibility/ranking mode.
|
||||
* - 'ranked' (or legacy 'public'): Competitive, public, affects ratings. Requires min 10 drivers.
|
||||
* - 'unranked' (or legacy 'private'): Casual with friends, no rating impact.
|
||||
*/
|
||||
visibility: LeagueVisibilityInput;
|
||||
ownerId: string;
|
||||
gameId: string;
|
||||
maxDrivers?: number;
|
||||
maxTeams?: number;
|
||||
enableDriverChampionship: boolean;
|
||||
enableTeamChampionship: boolean;
|
||||
enableNationsChampionship: boolean;
|
||||
enableTrophyChampionship: boolean;
|
||||
scoringPresetId?: string;
|
||||
}
|
||||
|
||||
export interface CreateLeagueWithSeasonAndScoringResultDTO {
|
||||
leagueId: string;
|
||||
seasonId: string;
|
||||
scoringPresetId?: string;
|
||||
scoringPresetName?: string;
|
||||
}
|
||||
import { Result } from '@core/shared/result/Result';
|
||||
import { RacingDomainValidationError } from '../../domain/errors/RacingDomainError';
|
||||
import type { CreateLeagueWithSeasonAndScoringCommand } from './CreateLeagueWithSeasonAndScoringCommand';
|
||||
import type { CreateLeagueWithSeasonAndScoringResultDTO } from '../dto/CreateLeagueWithSeasonAndScoringResultDTO';
|
||||
|
||||
export class CreateLeagueWithSeasonAndScoringUseCase
|
||||
implements AsyncUseCase<CreateLeagueWithSeasonAndScoringCommand, CreateLeagueWithSeasonAndScoringResultDTO> {
|
||||
implements AsyncUseCase<CreateLeagueWithSeasonAndScoringCommand, Result<CreateLeagueWithSeasonAndScoringResultDTO, RacingDomainValidationError>> {
|
||||
constructor(
|
||||
private readonly leagueRepository: ILeagueRepository,
|
||||
private readonly seasonRepository: ISeasonRepository,
|
||||
@@ -61,11 +31,14 @@ export class CreateLeagueWithSeasonAndScoringUseCase
|
||||
|
||||
async execute(
|
||||
command: CreateLeagueWithSeasonAndScoringCommand,
|
||||
): Promise<CreateLeagueWithSeasonAndScoringResultDTO> {
|
||||
): Promise<Result<CreateLeagueWithSeasonAndScoringResultDTO, RacingDomainValidationError>> {
|
||||
this.logger.debug('Executing CreateLeagueWithSeasonAndScoringUseCase', { command });
|
||||
const validation = this.validate(command);
|
||||
if (validation.isErr()) {
|
||||
return Result.err(validation.unwrapErr());
|
||||
}
|
||||
this.logger.info('Command validated successfully.');
|
||||
try {
|
||||
this.validate(command);
|
||||
this.logger.info('Command validated successfully.');
|
||||
|
||||
const leagueId = uuidv4();
|
||||
this.logger.debug(`Generated leagueId: ${leagueId}`);
|
||||
@@ -108,7 +81,7 @@ export class CreateLeagueWithSeasonAndScoringUseCase
|
||||
|
||||
if (!preset) {
|
||||
this.logger.error(`Unknown scoring preset: ${presetId}`);
|
||||
throw new Error(`Unknown scoring preset: ${presetId}`);
|
||||
return Result.err(new RacingDomainValidationError(`Unknown scoring preset: ${presetId}`));
|
||||
}
|
||||
this.logger.info(`Scoring preset ${preset.name} (${preset.id}) retrieved.`);
|
||||
|
||||
@@ -119,45 +92,44 @@ export class CreateLeagueWithSeasonAndScoringUseCase
|
||||
await this.leagueScoringConfigRepository.save(finalConfig);
|
||||
this.logger.info(`Scoring configuration saved for season ${seasonId}.`);
|
||||
|
||||
const result = {
|
||||
const result: CreateLeagueWithSeasonAndScoringResultDTO = {
|
||||
leagueId: league.id,
|
||||
seasonId,
|
||||
scoringPresetId: preset.id,
|
||||
scoringPresetName: preset.name,
|
||||
};
|
||||
this.logger.debug('CreateLeagueWithSeasonAndScoringUseCase completed successfully.', { result });
|
||||
return result;
|
||||
return Result.ok(result);
|
||||
} catch (error) {
|
||||
this.logger.error('Error during CreateLeagueWithSeasonAndScoringUseCase execution.', error, { command });
|
||||
throw error;
|
||||
return Result.err(new RacingDomainValidationError(error instanceof Error ? error.message : 'Unknown error'));
|
||||
}
|
||||
}
|
||||
|
||||
private validate(command: CreateLeagueWithSeasonAndScoringCommand): void {
|
||||
private validate(command: CreateLeagueWithSeasonAndScoringCommand): Result<void, RacingDomainValidationError> {
|
||||
this.logger.debug('Validating CreateLeagueWithSeasonAndScoringCommand', { command });
|
||||
if (!command.name || command.name.trim().length === 0) {
|
||||
this.logger.warn('Validation failed: League name is required', { command });
|
||||
throw new Error('League name is required');
|
||||
return Result.err(new RacingDomainValidationError('League name is required'));
|
||||
}
|
||||
if (!command.ownerId || command.ownerId.trim().length === 0) {
|
||||
this.logger.warn('Validation failed: League ownerId is required', { command });
|
||||
throw new Error('League ownerId is required');
|
||||
return Result.err(new RacingDomainValidationError('League ownerId is required'));
|
||||
}
|
||||
if (!command.gameId || command.gameId.trim().length === 0) {
|
||||
this.logger.warn('Validation failed: gameId is required', { command });
|
||||
throw new Error('gameId is required');
|
||||
return Result.err(new RacingDomainValidationError('gameId is required'));
|
||||
}
|
||||
if (!command.visibility) {
|
||||
this.logger.warn('Validation failed: visibility is required', { command });
|
||||
throw new Error('visibility is required');
|
||||
return Result.err(new RacingDomainValidationError('visibility is required'));
|
||||
}
|
||||
if (command.maxDrivers !== undefined && command.maxDrivers <= 0) {
|
||||
this.logger.warn('Validation failed: maxDrivers must be greater than 0 when provided', { command });
|
||||
throw new Error('maxDrivers must be greater than 0 when provided');
|
||||
return Result.err(new RacingDomainValidationError('maxDrivers must be greater than 0 when provided'));
|
||||
}
|
||||
|
||||
const visibility = LeagueVisibility.fromString(command.visibility);
|
||||
|
||||
|
||||
if (visibility.isRanked()) {
|
||||
const driverCount = command.maxDrivers ?? 0;
|
||||
if (driverCount < MIN_RANKED_LEAGUE_DRIVERS) {
|
||||
@@ -165,13 +137,14 @@ export class CreateLeagueWithSeasonAndScoringUseCase
|
||||
`Validation failed: Ranked leagues require at least ${MIN_RANKED_LEAGUE_DRIVERS} drivers. Current setting: ${driverCount}.`,
|
||||
{ command }
|
||||
);
|
||||
throw new Error(
|
||||
return Result.err(new RacingDomainValidationError(
|
||||
`Ranked leagues require at least ${MIN_RANKED_LEAGUE_DRIVERS} drivers. ` +
|
||||
`Current setting: ${driverCount}. ` +
|
||||
`For smaller groups, consider creating an Unranked (Friends) league instead.`
|
||||
);
|
||||
));
|
||||
}
|
||||
}
|
||||
this.logger.debug('Validation successful.');
|
||||
return Result.ok(undefined);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user