/** * Infrastructure Adapter: InMemoryTrackRepository * * In-memory implementation of ITrackRepository. * Stores data in Map structure with UUID generation. */ import { Track, TrackCategory } from '@core/racing/domain/entities/Track'; import type { TrackRepository } from '@core/racing/domain/repositories/TrackRepository'; import type { Logger } from '@core/shared/domain/Logger'; import { v4 as uuidv4 } from 'uuid'; export class InMemoryTrackRepository implements TrackRepository { private tracks: Map; private readonly logger: Logger; constructor(logger: Logger) { this.logger = logger; this.logger.info('InMemoryTrackRepository initialized.'); this.tracks = new Map(); } async findById(id: string): Promise { this.logger.debug(`Finding track by id: ${id}`); try { const track = this.tracks.get(id) ?? null; if (track) { this.logger.info(`Found track: ${id}.`); } else { this.logger.warn(`Track with id ${id} not found.`); } return track; } catch (error) { this.logger.error(`Error finding track by id ${id}:`, error instanceof Error ? error : new Error(String(error))); throw error; } } async findAll(): Promise { this.logger.debug('Finding all tracks.'); try { const tracks = Array.from(this.tracks.values()); this.logger.info(`Found ${tracks.length} tracks.`); return tracks; } catch (error) { this.logger.error('Error finding all tracks:', error instanceof Error ? error : new Error(String(error))); throw error; } } async findByGameId(gameId: string): Promise { this.logger.debug(`Finding tracks by game id: ${gameId}`); try { const tracks = Array.from(this.tracks.values()) .filter(track => track.gameId.toString() === gameId) .sort((a, b) => a.name.toString().localeCompare(b.name.toString())); this.logger.info(`Found ${tracks.length} tracks for game id: ${gameId}.`); return tracks; } catch (error) { this.logger.error(`Error finding tracks by game id ${gameId}:`, error instanceof Error ? error : new Error(String(error))); throw error; } } async findByCategory(category: TrackCategory): Promise { this.logger.debug(`Finding tracks by category: ${category}`); try { const tracks = Array.from(this.tracks.values()) .filter(track => track.category === category) .sort((a, b) => a.name.toString().localeCompare(b.name.toString())); this.logger.info(`Found ${tracks.length} tracks for category: ${category}.`); return tracks; } catch (error) { this.logger.error(`Error finding tracks by category ${category}:`, error instanceof Error ? error : new Error(String(error))); throw error; } } async findByCountry(country: string): Promise { this.logger.debug(`Finding tracks by country: ${country}`); try { const tracks = Array.from(this.tracks.values()) .filter(track => track.country.toString().toLowerCase() === country.toLowerCase()) .sort((a, b) => a.name.toString().localeCompare(b.name.toString())); this.logger.info(`Found ${tracks.length} tracks for country: ${country}.`); return tracks; } catch (error) { this.logger.error(`Error finding tracks by country ${country}:`, error instanceof Error ? error : new Error(String(error))); throw error; } } async searchByName(query: string): Promise { this.logger.debug(`Searching tracks by name query: ${query}`); try { const lowerQuery = query.toLowerCase(); const tracks = Array.from(this.tracks.values()) .filter(track => track.name.toString().toLowerCase().includes(lowerQuery) || track.shortName.toString().toLowerCase().includes(lowerQuery) ) .sort((a, b) => a.name.toString().localeCompare(b.name.toString())); this.logger.info(`Found ${tracks.length} tracks matching search query: ${query}.`); return tracks; } catch (error) { this.logger.error(`Error searching tracks by name query ${query}:`, error instanceof Error ? error : new Error(String(error))); throw error; } } async create(track: Track): Promise { this.logger.debug(`Creating track: ${track.id}`); try { if (await this.exists(track.id)) { this.logger.warn(`Track with ID ${track.id} already exists.`); throw new Error(`Track with ID ${track.id} already exists`); } this.tracks.set(track.id, track); this.logger.info(`Track ${track.id} created successfully.`); return track; } catch (error) { this.logger.error(`Error creating track ${track.id}:`, error instanceof Error ? error : new Error(String(error))); throw error; } } async update(track: Track): Promise { this.logger.debug(`Updating track: ${track.id}`); try { if (!await this.exists(track.id)) { this.logger.warn(`Track with ID ${track.id} not found for update.`); throw new Error(`Track with ID ${track.id} not found`); } this.tracks.set(track.id, track); this.logger.info(`Track ${track.id} updated successfully.`); return track; } catch (error) { this.logger.error(`Error updating track ${track.id}:`, error instanceof Error ? error : new Error(String(error))); throw error; } } async delete(id: string): Promise { this.logger.debug(`Deleting track: ${id}`); try { if (!await this.exists(id)) { this.logger.warn(`Track with ID ${id} not found for deletion.`); throw new Error(`Track with ID ${id} not found`); } this.tracks.delete(id); this.logger.info(`Track ${id} deleted successfully.`); } catch (error) { this.logger.error(`Error deleting track ${id}:`, error instanceof Error ? error : new Error(String(error))); throw error; } } async exists(id: string): Promise { this.logger.debug(`Checking existence of track with id: ${id}`); try { const exists = this.tracks.has(id); this.logger.debug(`Track ${id} exists: ${exists}.`); return exists; } catch (error) { this.logger.error(`Error checking existence of track with id ${id}:`, error instanceof Error ? error : new Error(String(error))); throw error; } } /** * Utility method to generate a new UUID */ static generateId(): string { return uuidv4(); } }