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,28 +1,29 @@
import type { Logger , AsyncUseCase } from '@core/shared/application';
import type { Logger } from '@core/shared/application';
import type { ILeagueMembershipRepository } from '@core/racing/domain/repositories/ILeagueMembershipRepository';
import { LeagueMembership, type MembershipRole, type MembershipStatus } from '../../domain/entities/LeagueMembership';
import { Result as SharedResult } from '@core/shared/application/Result';
import { LeagueMembership } from '../../domain/entities/LeagueMembership';
import { Result } from '@core/shared/application/Result';
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
import type { JoinLeagueOutputPort } from '../ports/output/JoinLeagueOutputPort';
import type { UseCaseOutputPort } from '@core/shared/application';
import type { JoinLeagueCommandDTO } from '../dto/JoinLeagueCommandDTO';
export type JoinLeagueErrorCode = 'ALREADY_MEMBER' | 'REPOSITORY_ERROR';
type JoinLeagueErrorCode = 'ALREADY_MEMBER' | 'REPOSITORY_ERROR';
export interface JoinLeagueInput {
leagueId: string;
driverId: string;
}
export class JoinLeagueUseCase implements AsyncUseCase<JoinLeagueCommandDTO, JoinLeagueOutputPort, JoinLeagueErrorCode> {
export interface JoinLeagueResult {
membership: LeagueMembership;
}
export class JoinLeagueUseCase {
constructor(
private readonly membershipRepository: ILeagueMembershipRepository,
private readonly logger: Logger,
private readonly output: UseCaseOutputPort<JoinLeagueResult>,
) {}
/**
* Joins a driver to a league as an active member.
*
* Mirrors the behavior of the legacy joinLeague function:
* - Returns error when membership already exists for this league/driver.
* - Creates a new active membership with role "member" and current timestamp.
*/
async execute(command: JoinLeagueCommandDTO): Promise<SharedResult<JoinLeagueOutputPort, ApplicationErrorCode<JoinLeagueErrorCode>>> {
async execute(command: JoinLeagueInput): Promise<Result<void, ApplicationErrorCode<JoinLeagueErrorCode, { message: string }>>> {
this.logger.debug('Attempting to join league', { command });
const { leagueId, driverId } = command;
@@ -30,26 +31,34 @@ export class JoinLeagueUseCase implements AsyncUseCase<JoinLeagueCommandDTO, Joi
const existing = await this.membershipRepository.getMembership(leagueId, driverId);
if (existing) {
this.logger.warn('Driver already a member or has pending request', { leagueId, driverId });
return SharedResult.err({ code: 'ALREADY_MEMBER' });
return Result.err({
code: 'ALREADY_MEMBER',
details: { message: 'Driver is already a member of this league or has a pending membership.' },
});
}
const membership = LeagueMembership.create({
leagueId,
driverId,
role: 'member' as MembershipRole,
status: 'active' as MembershipStatus,
role: 'member',
status: 'active',
});
const savedMembership = await this.membershipRepository.saveMembership(membership);
this.logger.info('Successfully joined league', { membershipId: savedMembership.id });
return SharedResult.ok({
membershipId: savedMembership.id,
leagueId: savedMembership.leagueId.toString(),
status: savedMembership.status.toString(),
this.output.present({
membership: savedMembership,
});
return Result.ok(undefined);
} catch (error) {
this.logger.error('Failed to join league due to an unexpected error', error instanceof Error ? error : new Error('Unknown error'));
return SharedResult.err({ code: 'REPOSITORY_ERROR' });
const err = error instanceof Error ? error : new Error('Unknown error');
this.logger.error('Failed to join league due to an unexpected error', err);
return Result.err({
code: 'REPOSITORY_ERROR',
details: { message: err.message ?? 'Failed to join league' },
});
}
}
}