This commit is contained in:
2025-12-10 12:38:55 +01:00
parent 0f7fe67d3c
commit fbbcf414a4
87 changed files with 11972 additions and 390 deletions

View File

@@ -0,0 +1,61 @@
/**
* Infrastructure Adapter: InMemoryGameRepository
*
* In-memory implementation of IGameRepository.
*/
import { Game } from '../../domain/entities/Game';
import type { IGameRepository } from '../../domain/repositories/IGameRepository';
export class InMemoryGameRepository implements IGameRepository {
private games: Map<string, Game>;
constructor(seedData?: Game[]) {
this.games = new Map();
if (seedData) {
seedData.forEach(game => {
this.games.set(game.id, game);
});
} else {
// Default seed data for common sim racing games
const defaultGames = [
Game.create({ id: 'iracing', name: 'iRacing' }),
Game.create({ id: 'acc', name: 'Assetto Corsa Competizione' }),
Game.create({ id: 'ac', name: 'Assetto Corsa' }),
Game.create({ id: 'rf2', name: 'rFactor 2' }),
Game.create({ id: 'ams2', name: 'Automobilista 2' }),
Game.create({ id: 'lmu', name: 'Le Mans Ultimate' }),
];
defaultGames.forEach(game => {
this.games.set(game.id, game);
});
}
}
async findById(id: string): Promise<Game | null> {
return this.games.get(id) ?? null;
}
async findAll(): Promise<Game[]> {
return Array.from(this.games.values()).sort((a, b) => a.name.localeCompare(b.name));
}
/**
* Utility method to add a game
*/
async create(game: Game): Promise<Game> {
if (this.games.has(game.id)) {
throw new Error(`Game with ID ${game.id} already exists`);
}
this.games.set(game.id, game);
return game;
}
/**
* Test helper to clear data
*/
clear(): void {
this.games.clear();
}
}

View File

@@ -30,6 +30,16 @@ export class InMemoryLiveryRepository implements ILiveryRepository {
return null;
}
async findDriverLiveriesByGameId(gameId: string): Promise<DriverLivery[]> {
return Array.from(this.driverLiveries.values()).filter(l => l.gameId === gameId);
}
async findDriverLiveryByDriverAndGame(driverId: string, gameId: string): Promise<DriverLivery[]> {
return Array.from(this.driverLiveries.values()).filter(
l => l.driverId === driverId && l.gameId === gameId
);
}
async createDriverLivery(livery: DriverLivery): Promise<DriverLivery> {
if (this.driverLiveries.has(livery.id)) {
throw new Error('DriverLivery with this ID already exists');

View File

@@ -0,0 +1,67 @@
/**
* InMemory implementation of ISponsorshipPricingRepository
*/
import type { ISponsorshipPricingRepository } from '../../domain/repositories/ISponsorshipPricingRepository';
import { SponsorshipPricing } from '../../domain/value-objects/SponsorshipPricing';
import type { SponsorableEntityType } from '../../domain/entities/SponsorshipRequest';
interface StorageKey {
entityType: SponsorableEntityType;
entityId: string;
}
export class InMemorySponsorshipPricingRepository implements ISponsorshipPricingRepository {
private pricings: Map<string, { entityType: SponsorableEntityType; entityId: string; pricing: SponsorshipPricing }> = new Map();
private makeKey(entityType: SponsorableEntityType, entityId: string): string {
return `${entityType}:${entityId}`;
}
async findByEntity(entityType: SponsorableEntityType, entityId: string): Promise<SponsorshipPricing | null> {
const key = this.makeKey(entityType, entityId);
const entry = this.pricings.get(key);
return entry?.pricing ?? null;
}
async save(entityType: SponsorableEntityType, entityId: string, pricing: SponsorshipPricing): Promise<void> {
const key = this.makeKey(entityType, entityId);
this.pricings.set(key, { entityType, entityId, pricing });
}
async delete(entityType: SponsorableEntityType, entityId: string): Promise<void> {
const key = this.makeKey(entityType, entityId);
this.pricings.delete(key);
}
async exists(entityType: SponsorableEntityType, entityId: string): Promise<boolean> {
const key = this.makeKey(entityType, entityId);
return this.pricings.has(key);
}
async findAcceptingApplications(entityType: SponsorableEntityType): Promise<Array<{
entityId: string;
pricing: SponsorshipPricing;
}>> {
return Array.from(this.pricings.values())
.filter(entry => entry.entityType === entityType && entry.pricing.acceptingApplications)
.map(entry => ({ entityId: entry.entityId, pricing: entry.pricing }));
}
/**
* Seed initial data
*/
seed(data: Array<{ entityType: SponsorableEntityType; entityId: string; pricing: SponsorshipPricing }>): void {
for (const entry of data) {
const key = this.makeKey(entry.entityType, entry.entityId);
this.pricings.set(key, entry);
}
}
/**
* Clear all data (for testing)
*/
clear(): void {
this.pricings.clear();
}
}

View File

@@ -0,0 +1,107 @@
/**
* InMemory implementation of ISponsorshipRequestRepository
*/
import type { ISponsorshipRequestRepository } from '../../domain/repositories/ISponsorshipRequestRepository';
import {
SponsorshipRequest,
type SponsorableEntityType,
type SponsorshipRequestStatus
} from '../../domain/entities/SponsorshipRequest';
export class InMemorySponsorshipRequestRepository implements ISponsorshipRequestRepository {
private requests: Map<string, SponsorshipRequest> = new Map();
async findById(id: string): Promise<SponsorshipRequest | null> {
return this.requests.get(id) ?? null;
}
async findByEntity(entityType: SponsorableEntityType, entityId: string): Promise<SponsorshipRequest[]> {
return Array.from(this.requests.values()).filter(
request => request.entityType === entityType && request.entityId === entityId
);
}
async findPendingByEntity(entityType: SponsorableEntityType, entityId: string): Promise<SponsorshipRequest[]> {
return Array.from(this.requests.values()).filter(
request =>
request.entityType === entityType &&
request.entityId === entityId &&
request.status === 'pending'
);
}
async findBySponsorId(sponsorId: string): Promise<SponsorshipRequest[]> {
return Array.from(this.requests.values()).filter(
request => request.sponsorId === sponsorId
);
}
async findByStatus(status: SponsorshipRequestStatus): Promise<SponsorshipRequest[]> {
return Array.from(this.requests.values()).filter(
request => request.status === status
);
}
async findBySponsorIdAndStatus(sponsorId: string, status: SponsorshipRequestStatus): Promise<SponsorshipRequest[]> {
return Array.from(this.requests.values()).filter(
request => request.sponsorId === sponsorId && request.status === status
);
}
async hasPendingRequest(sponsorId: string, entityType: SponsorableEntityType, entityId: string): Promise<boolean> {
return Array.from(this.requests.values()).some(
request =>
request.sponsorId === sponsorId &&
request.entityType === entityType &&
request.entityId === entityId &&
request.status === 'pending'
);
}
async countPendingByEntity(entityType: SponsorableEntityType, entityId: string): Promise<number> {
return Array.from(this.requests.values()).filter(
request =>
request.entityType === entityType &&
request.entityId === entityId &&
request.status === 'pending'
).length;
}
async create(request: SponsorshipRequest): Promise<SponsorshipRequest> {
this.requests.set(request.id, request);
return request;
}
async update(request: SponsorshipRequest): Promise<SponsorshipRequest> {
if (!this.requests.has(request.id)) {
throw new Error(`SponsorshipRequest ${request.id} not found`);
}
this.requests.set(request.id, request);
return request;
}
async delete(id: string): Promise<void> {
this.requests.delete(id);
}
async exists(id: string): Promise<boolean> {
return this.requests.has(id);
}
/**
* Seed initial data
*/
seed(requests: SponsorshipRequest[]): void {
for (const request of requests) {
this.requests.set(request.id, request);
}
}
/**
* Clear all data (for testing)
*/
clear(): void {
this.requests.clear();
}
}