117 lines
3.9 KiB
TypeScript
117 lines
3.9 KiB
TypeScript
/**
|
|
* Infrastructure Adapter: InMemoryRaceRegistrationRepository
|
|
*
|
|
* In-memory implementation of IRaceRegistrationRepository.
|
|
* Stores race registrations in Maps keyed by raceId and driverId.
|
|
*/
|
|
|
|
import type { RaceRegistration } from '@gridpilot/racing/domain/entities/RaceRegistration';
|
|
import type { IRaceRegistrationRepository } from '@gridpilot/racing/domain/repositories/IRaceRegistrationRepository';
|
|
|
|
type RaceRegistrationSeed = Pick<RaceRegistration, 'raceId' | 'driverId' | 'registeredAt'>;
|
|
|
|
export class InMemoryRaceRegistrationRepository implements IRaceRegistrationRepository {
|
|
private registrationsByRace: Map<string, Set<string>>;
|
|
private registrationsByDriver: Map<string, Set<string>>;
|
|
|
|
constructor(seedRegistrations?: RaceRegistrationSeed[]) {
|
|
this.registrationsByRace = new Map();
|
|
this.registrationsByDriver = new Map();
|
|
|
|
if (seedRegistrations) {
|
|
seedRegistrations.forEach((registration) => {
|
|
this.addToIndexes(registration.raceId, registration.driverId, registration.registeredAt);
|
|
});
|
|
}
|
|
}
|
|
|
|
private addToIndexes(raceId: string, driverId: string, _registeredAt: Date): void {
|
|
let raceSet = this.registrationsByRace.get(raceId);
|
|
if (!raceSet) {
|
|
raceSet = new Set();
|
|
this.registrationsByRace.set(raceId, raceSet);
|
|
}
|
|
raceSet.add(driverId);
|
|
|
|
let driverSet = this.registrationsByDriver.get(driverId);
|
|
if (!driverSet) {
|
|
driverSet = new Set();
|
|
this.registrationsByDriver.set(driverId, driverSet);
|
|
}
|
|
driverSet.add(raceId);
|
|
}
|
|
|
|
private removeFromIndexes(raceId: string, driverId: string): void {
|
|
const raceSet = this.registrationsByRace.get(raceId);
|
|
if (raceSet) {
|
|
raceSet.delete(driverId);
|
|
if (raceSet.size === 0) {
|
|
this.registrationsByRace.delete(raceId);
|
|
}
|
|
}
|
|
|
|
const driverSet = this.registrationsByDriver.get(driverId);
|
|
if (driverSet) {
|
|
driverSet.delete(raceId);
|
|
if (driverSet.size === 0) {
|
|
this.registrationsByDriver.delete(driverId);
|
|
}
|
|
}
|
|
}
|
|
|
|
async isRegistered(raceId: string, driverId: string): Promise<boolean> {
|
|
const raceSet = this.registrationsByRace.get(raceId);
|
|
if (!raceSet) return false;
|
|
return raceSet.has(driverId);
|
|
}
|
|
|
|
async getRegisteredDrivers(raceId: string): Promise<string[]> {
|
|
const raceSet = this.registrationsByRace.get(raceId);
|
|
if (!raceSet) return [];
|
|
return Array.from(raceSet.values());
|
|
}
|
|
|
|
async getRegistrationCount(raceId: string): Promise<number> {
|
|
const raceSet = this.registrationsByRace.get(raceId);
|
|
return raceSet ? raceSet.size : 0;
|
|
}
|
|
|
|
async register(registration: RaceRegistration): Promise<void> {
|
|
const alreadyRegistered = await this.isRegistered(registration.raceId, registration.driverId);
|
|
if (alreadyRegistered) {
|
|
throw new Error('Already registered for this race');
|
|
}
|
|
this.addToIndexes(registration.raceId, registration.driverId, registration.registeredAt);
|
|
}
|
|
|
|
async withdraw(raceId: string, driverId: string): Promise<void> {
|
|
const alreadyRegistered = await this.isRegistered(raceId, driverId);
|
|
if (!alreadyRegistered) {
|
|
throw new Error('Not registered for this race');
|
|
}
|
|
this.removeFromIndexes(raceId, driverId);
|
|
}
|
|
|
|
async getDriverRegistrations(driverId: string): Promise<string[]> {
|
|
const driverSet = this.registrationsByDriver.get(driverId);
|
|
if (!driverSet) return [];
|
|
return Array.from(driverSet.values());
|
|
}
|
|
|
|
async clearRaceRegistrations(raceId: string): Promise<void> {
|
|
const raceSet = this.registrationsByRace.get(raceId);
|
|
if (!raceSet) return;
|
|
|
|
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.registrationsByRace.delete(raceId);
|
|
}
|
|
} |