This commit is contained in:
2025-12-31 19:55:43 +01:00
parent 8260bf7baf
commit 167e82a52b
66 changed files with 5124 additions and 228 deletions

View File

@@ -0,0 +1,46 @@
import { Column, Entity, PrimaryColumn } from 'typeorm';
@Entity({ name: 'driver_stats' })
export class DriverStatsOrmEntity {
@PrimaryColumn({ type: 'uuid' })
driverId!: string;
@Column({ type: 'integer' })
rating!: number;
@Column({ type: 'integer' })
safetyRating!: number;
@Column({ type: 'numeric', precision: 3, scale: 1 })
sportsmanshipRating!: number;
@Column({ type: 'integer' })
totalRaces!: number;
@Column({ type: 'integer' })
wins!: number;
@Column({ type: 'integer' })
podiums!: number;
@Column({ type: 'integer' })
dnfs!: number;
@Column({ type: 'numeric', precision: 5, scale: 2 })
avgFinish!: number;
@Column({ type: 'integer' })
bestFinish!: number;
@Column({ type: 'integer' })
worstFinish!: number;
@Column({ type: 'integer' })
consistency!: number;
@Column({ type: 'text' })
experienceLevel!: string;
@Column({ type: 'integer', nullable: true })
overallRank!: number | null;
}

View File

@@ -0,0 +1,65 @@
import type { DriverStats } from '@core/racing/application/use-cases/IDriverStatsUseCase';
import { DriverStatsOrmEntity } from '../entities/DriverStatsOrmEntity';
import {
assertNonEmptyString,
assertInteger,
assertNumber
} from '../schema/TypeOrmSchemaGuards';
export class DriverStatsOrmMapper {
toOrmEntity(driverId: string, domain: DriverStats): DriverStatsOrmEntity {
const entity = new DriverStatsOrmEntity();
entity.driverId = driverId;
entity.rating = domain.rating;
entity.safetyRating = domain.safetyRating;
entity.sportsmanshipRating = domain.sportsmanshipRating;
entity.totalRaces = domain.totalRaces;
entity.wins = domain.wins;
entity.podiums = domain.podiums;
entity.dnfs = domain.dnfs;
entity.avgFinish = domain.avgFinish;
entity.bestFinish = domain.bestFinish;
entity.worstFinish = domain.worstFinish;
entity.consistency = domain.consistency;
entity.experienceLevel = domain.experienceLevel;
entity.overallRank = domain.overallRank ?? null;
return entity;
}
toDomain(entity: DriverStatsOrmEntity): DriverStats {
const entityName = 'DriverStats';
assertNonEmptyString(entityName, 'driverId', entity.driverId);
assertInteger(entityName, 'rating', entity.rating);
assertInteger(entityName, 'safetyRating', entity.safetyRating);
assertInteger(entityName, 'sportsmanshipRating', entity.sportsmanshipRating);
assertInteger(entityName, 'totalRaces', entity.totalRaces);
assertInteger(entityName, 'wins', entity.wins);
assertInteger(entityName, 'podiums', entity.podiums);
assertInteger(entityName, 'dnfs', entity.dnfs);
assertNumber(entityName, 'avgFinish', entity.avgFinish);
assertInteger(entityName, 'bestFinish', entity.bestFinish);
assertInteger(entityName, 'worstFinish', entity.worstFinish);
assertInteger(entityName, 'consistency', entity.consistency);
assertNonEmptyString(entityName, 'experienceLevel', entity.experienceLevel);
const result: DriverStats = {
rating: entity.rating,
safetyRating: entity.safetyRating,
sportsmanshipRating: entity.sportsmanshipRating,
totalRaces: entity.totalRaces,
wins: entity.wins,
podiums: entity.podiums,
dnfs: entity.dnfs,
avgFinish: entity.avgFinish,
bestFinish: entity.bestFinish,
worstFinish: entity.worstFinish,
consistency: entity.consistency,
experienceLevel: entity.experienceLevel,
overallRank: entity.overallRank ?? null,
};
return result;
}
}

View File

@@ -0,0 +1,45 @@
import type { IDriverStatsRepository } from '@core/racing/domain/repositories/IDriverStatsRepository';
import type { DriverStats } from '@core/racing/application/use-cases/IDriverStatsUseCase';
import type { Repository } from 'typeorm';
import { DriverStatsOrmEntity } from '../entities/DriverStatsOrmEntity';
import { DriverStatsOrmMapper } from '../mappers/DriverStatsOrmMapper';
export class TypeOrmDriverStatsRepository implements IDriverStatsRepository {
constructor(
private readonly repo: Repository<DriverStatsOrmEntity>,
private readonly mapper: DriverStatsOrmMapper,
) {}
async getDriverStats(driverId: string): Promise<DriverStats | null> {
const entity = await this.repo.findOne({ where: { driverId } });
return entity ? this.mapper.toDomain(entity) : null;
}
getDriverStatsSync(_driverId: string): DriverStats | null {
// TypeORM repositories don't support synchronous operations
// This method is provided for interface compatibility but should not be used
// with TypeORM implementations. Return null to indicate it's not supported.
return null;
}
async saveDriverStats(driverId: string, stats: DriverStats): Promise<void> {
const entity = this.mapper.toOrmEntity(driverId, stats);
await this.repo.save(entity);
}
async getAllStats(): Promise<Map<string, DriverStats>> {
const entities = await this.repo.find();
const statsMap = new Map<string, DriverStats>();
for (const entity of entities) {
statsMap.set(entity.driverId, this.mapper.toDomain(entity));
}
return statsMap;
}
async clear(): Promise<void> {
await this.repo.clear();
}
}