/** * Infrastructure Adapter: InMemoryRaceRegistrationRepository * * In-memory implementation of IRaceRegistrationRepository. * Stores race registrations in Maps keyed by raceId and driverId. */ import type { ILogger } from '@gridpilot/shared/logging/ILogger'; import type { RaceRegistration } from '@gridpilot/racing/domain/entities/RaceRegistration'; import type { IRaceRegistrationRepository } from '@gridpilot/racing/domain/repositories/IRaceRegistrationRepository'; type RaceRegistrationSeed = Pick; export class InMemoryRaceRegistrationRepository implements IRaceRegistrationRepository { private registrationsByRace: Map>; private registrationsByDriver: Map>; private readonly logger: ILogger; constructor(logger: ILogger, seedRegistrations?: RaceRegistrationSeed[]) { this.logger = logger; this.logger.info('InMemoryRaceRegistrationRepository initialized.'); this.registrationsByRace = new Map(); this.registrationsByDriver = new Map(); if (seedRegistrations) { this.logger.debug('Seeding with initial registrations', { count: seedRegistrations.length }); seedRegistrations.forEach((registration) => { this.addToIndexes(registration.raceId, registration.driverId, registration.registeredAt); }); } } private addToIndexes(raceId: string, driverId: string, _registeredAt: Date): void { this.logger.debug('Attempting to add race registration to indexes', { raceId, driverId }); let raceSet = this.registrationsByRace.get(raceId); if (!raceSet) { raceSet = new Set(); this.registrationsByRace.set(raceId, raceSet); this.logger.debug('Created new race set as none existed', { raceId }); } raceSet.add(driverId); this.logger.debug('Added driver to race set', { raceId, driverId }); let driverSet = this.registrationsByDriver.get(driverId); if (!driverSet) { driverSet = new Set(); this.registrationsByDriver.set(driverId, driverSet); this.logger.debug('Created new driver set as none existed', { driverId }); } driverSet.add(raceId); this.logger.debug('Added race to driver set', { raceId, driverId }); this.logger.info('Successfully added race registration to indexes', { raceId, driverId }); } private removeFromIndexes(raceId: string, driverId: string): void { this.logger.debug('Attempting to remove race registration from indexes', { raceId, driverId }); const raceSet = this.registrationsByRace.get(raceId); if (raceSet) { raceSet.delete(driverId); this.logger.debug('Removed driver from race set', { raceId, driverId }); if (raceSet.size === 0) { this.registrationsByRace.delete(raceId); this.logger.debug('Deleted race set as it is now empty', { raceId }); } } else { this.logger.warn('Race set not found during removal, potential inconsistency', { raceId }); } const driverSet = this.registrationsByDriver.get(driverId); if (driverSet) { driverSet.delete(raceId); this.logger.debug('Removed race from driver set', { raceId, driverId }); if (driverSet.size === 0) { this.registrationsByDriver.delete(driverId); this.logger.debug('Deleted driver set as it is now empty', { driverId }); } } else { this.logger.warn('Driver set not found during removal, potential inconsistency', { driverId }); } this.logger.info('Successfully removed race registration from indexes', { raceId, driverId }); } async isRegistered(raceId: string, driverId: string): Promise { this.logger.info('Checking if driver is registered for race', { raceId, driverId }); const raceSet = this.registrationsByRace.get(raceId); if (!raceSet) { this.logger.debug('Race set not found, driver not registered', { raceId, driverId }); return false; } const isRegistered = raceSet.has(driverId); this.logger.debug('Registration status result', { raceId, driverId, isRegistered }); return isRegistered; } async getRegisteredDrivers(raceId: string): Promise { this.logger.info('Attempting to fetch registered drivers for race', { raceId }); const raceSet = this.registrationsByRace.get(raceId); if (!raceSet) { this.logger.debug('No registered drivers found for race', { raceId }); return []; } const drivers = Array.from(raceSet.values()); this.logger.debug('Found registered drivers for race', { raceId, count: drivers.length }); this.logger.info('Successfully fetched registered drivers for race', { raceId, count: drivers.length }); return drivers; } async getRegistrationCount(raceId: string): Promise { this.logger.info('Attempting to get registration count for race', { raceId }); const raceSet = this.registrationsByRace.get(raceId); const count = raceSet ? raceSet.size : 0; this.logger.debug('Registration count for race', { raceId, count }); this.logger.info('Returning registration count for race', { raceId, count }); return count; } async register(registration: RaceRegistration): Promise { this.logger.info('Attempting to register driver for race', { raceId: registration.raceId, driverId: registration.driverId }); const alreadyRegistered = await this.isRegistered(registration.raceId, registration.driverId); if (alreadyRegistered) { this.logger.warn('Driver already registered for race, registration aborted', { raceId: registration.raceId, driverId: registration.driverId }); throw new Error('Already registered for this race'); } this.addToIndexes(registration.raceId, registration.driverId, registration.registeredAt); this.logger.info('Driver successfully registered for race', { raceId: registration.raceId, driverId: registration.driverId }); } async withdraw(raceId: string, driverId: string): Promise { this.logger.info('Attempting to withdraw driver from race', { raceId, driverId }); const alreadyRegistered = await this.isRegistered(raceId, driverId); if (!alreadyRegistered) { this.logger.warn('Driver not registered for race, withdrawal aborted', { raceId, driverId }); throw new Error('Not registered for this race'); } this.removeFromIndexes(raceId, driverId); this.logger.info('Driver successfully withdrew from race', { raceId, driverId }); } async getDriverRegistrations(driverId: string): Promise { this.logger.info('Attempting to fetch registrations for driver', { driverId }); const driverSet = this.registrationsByDriver.get(driverId); if (!driverSet) { this.logger.debug('No registrations found for driver', { driverId }); return []; } const registrations = Array.from(driverSet.values()); this.logger.debug('Found registrations for driver', { driverId, count: registrations.length }); this.logger.info('Successfully fetched registrations for driver', { driverId, count: registrations.length }); return registrations; } async clearRaceRegistrations(raceId: string): Promise { this.logger.info('Attempting to clear all registrations for race', { raceId }); const raceSet = this.registrationsByRace.get(raceId); if (!raceSet) { this.logger.debug('No registrations to clear for race (race set not found)', { raceId }); return; } this.logger.debug('Found registrations to clear', { raceId, count: raceSet.size }); for (const driverId of raceSet.values()) { const driverSet = this.registrationsByDriver.get(driverId); if (driverSet) { driverSet.delete(raceId); if (driverSet.size === 0) { this.registrationsByDriver.delete(driverId); this.logger.debug('Deleted driver set as it is now empty during race clear', { raceId, driverId }); } } else { this.logger.warn('Driver set not found during race clear, potential inconsistency', { raceId, driverId }); } this.logger.debug('Removed race from driver set during race clear', { raceId, driverId }); } this.registrationsByRace.delete(raceId); this.logger.info('Successfully cleared all registrations for race', { raceId }); } }