seed data

This commit is contained in:
2025-12-30 18:33:15 +01:00
parent 83371ea839
commit 92226800df
306 changed files with 1753 additions and 501 deletions

View File

@@ -4,6 +4,7 @@ import type { ITeamRepository } from '../../domain/repositories/ITeamRepository'
import type { ITeamMembershipRepository } from '../../domain/repositories/ITeamMembershipRepository';
import type { ITeamStatsRepository } from '../../domain/repositories/ITeamStatsRepository';
import type { IMediaRepository } from '../../domain/repositories/IMediaRepository';
import type { IResultRepository } from '../../domain/repositories/IResultRepository';
import type { Logger } from '@core/shared/application';
import type { UseCaseOutputPort } from '@core/shared/application/UseCaseOutputPort';
@@ -34,12 +35,26 @@ describe('GetAllTeamsUseCase', () => {
const mockTeamStatsRepo: ITeamStatsRepository = {
getTeamStats: vi.fn(),
getTeamStatsSync: vi.fn(),
saveTeamStats: vi.fn(),
getAllStats: vi.fn(),
clear: vi.fn(),
};
const mockResultRepo: IResultRepository = {
findAll: vi.fn(),
findById: vi.fn(),
findByRaceId: vi.fn(),
findByDriverId: vi.fn(),
findByDriverIdAndLeagueId: vi.fn(),
create: vi.fn(),
createMany: vi.fn(),
update: vi.fn(),
delete: vi.fn(),
deleteByRaceId: vi.fn(),
exists: vi.fn(),
existsByRaceId: vi.fn(),
};
const mockMediaRepo: IMediaRepository = {
getDriverAvatar: vi.fn(),
getTeamLogo: vi.fn(),
@@ -71,6 +86,7 @@ describe('GetAllTeamsUseCase', () => {
mockTeamMembershipRepo,
mockTeamStatsRepo,
mockMediaRepo,
mockResultRepo,
mockLogger,
output,
);
@@ -138,6 +154,7 @@ describe('GetAllTeamsUseCase', () => {
mockTeamMembershipRepo,
mockTeamStatsRepo,
mockMediaRepo,
mockResultRepo,
mockLogger,
output,
);
@@ -164,6 +181,7 @@ describe('GetAllTeamsUseCase', () => {
mockTeamMembershipRepo,
mockTeamStatsRepo,
mockMediaRepo,
mockResultRepo,
mockLogger,
output,
);

View File

@@ -2,6 +2,7 @@ import type { ITeamRepository } from '../../domain/repositories/ITeamRepository'
import type { ITeamMembershipRepository } from '../../domain/repositories/ITeamMembershipRepository';
import type { ITeamStatsRepository } from '../../domain/repositories/ITeamStatsRepository';
import type { IMediaRepository } from '../../domain/repositories/IMediaRepository';
import type { IResultRepository } from '../../domain/repositories/IResultRepository';
import type { Logger } from '@core/shared/application';
import { Result } from '@core/shared/application/Result';
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
@@ -28,6 +29,8 @@ export interface TeamSummary {
languages?: string[];
logoUrl?: string;
rating?: number;
category?: string | undefined;
isRecruiting: boolean;
}
export interface GetAllTeamsResult {
@@ -44,6 +47,7 @@ export class GetAllTeamsUseCase {
private readonly teamMembershipRepository: ITeamMembershipRepository,
private readonly teamStatsRepository: ITeamStatsRepository,
private readonly mediaRepository: IMediaRepository,
private readonly resultRepository: IResultRepository,
private readonly logger: Logger,
private readonly output: UseCaseOutputPort<GetAllTeamsResult>,
) {}
@@ -60,9 +64,48 @@ export class GetAllTeamsUseCase {
const enrichedTeams: TeamSummary[] = await Promise.all(
teams.map(async (team) => {
const memberCount = await this.teamMembershipRepository.countByTeamId(team.id);
const stats = await this.teamStatsRepository.getTeamStats(team.id);
const logoUrl = await this.mediaRepository.getTeamLogo(team.id);
// Try to get pre-computed stats first
let stats = await this.teamStatsRepository.getTeamStats(team.id);
// If no pre-computed stats, compute them on-the-fly from results
if (!stats) {
this.logger.debug(`Computing stats for team ${team.id} on-the-fly`);
const teamMemberships = await this.teamMembershipRepository.getTeamMembers(team.id);
const teamMemberIds = teamMemberships.map(m => m.driverId.toString());
const allResults = await this.resultRepository.findAll();
const teamResults = allResults.filter(r => teamMemberIds.includes(r.driverId.toString()));
const wins = teamResults.filter(r => r.position.toNumber() === 1).length;
const totalRaces = teamResults.length;
// Calculate rating
const baseRating = 1000;
const winBonus = wins * 50;
const raceBonus = Math.min(totalRaces * 5, 200);
const rating = Math.round(baseRating + winBonus + raceBonus);
// Determine performance level
let performanceLevel: 'beginner' | 'intermediate' | 'advanced' | 'pro';
if (wins >= 20) performanceLevel = 'pro';
else if (wins >= 10) performanceLevel = 'advanced';
else if (wins >= 5) performanceLevel = 'intermediate';
else performanceLevel = 'beginner';
stats = {
logoUrl: await this.mediaRepository.getTeamLogo(team.id) || '',
performanceLevel,
specialization: 'mixed',
region: 'International',
languages: ['en'],
totalWins: wins,
totalRaces,
rating,
};
}
return {
id: team.id,
name: team.name.props,
@@ -72,17 +115,16 @@ export class GetAllTeamsUseCase {
leagues: team.leagues.map(l => l.toString()),
createdAt: team.createdAt.toDate(),
memberCount,
// Add stats fields
...(stats ? {
totalWins: stats.totalWins,
totalRaces: stats.totalRaces,
performanceLevel: stats.performanceLevel,
specialization: stats.specialization,
region: stats.region,
languages: stats.languages,
logoUrl: logoUrl || stats.logoUrl,
rating: stats.rating,
} : {}),
totalWins: stats!.totalWins,
totalRaces: stats!.totalRaces,
performanceLevel: stats!.performanceLevel,
specialization: stats!.specialization,
region: stats!.region,
languages: stats!.languages,
logoUrl: logoUrl || stats!.logoUrl,
rating: stats!.rating,
category: team.category,
isRecruiting: team.isRecruiting,
};
}),
);
@@ -104,4 +146,4 @@ export class GetAllTeamsUseCase {
});
}
}
}
}