126 lines
4.1 KiB
TypeScript
126 lines
4.1 KiB
TypeScript
import { League } from '@core/racing/domain/entities/League';
|
||
import { Race } from '@core/racing/domain/entities/Race';
|
||
import { Track } from '@core/racing/domain/entities/Track';
|
||
import { seedId } from './SeedIdHelper';
|
||
|
||
export class RacingRaceFactory {
|
||
constructor(
|
||
private readonly baseDate: Date,
|
||
private readonly persistence: 'postgres' | 'inmemory' = 'inmemory',
|
||
) {}
|
||
|
||
create(leagues: League[], tracks: Track[]): Race[] {
|
||
const cars = ['GT3 – Porsche 911', 'GT3 – BMW M4', 'LMP3 Prototype', 'GT4 – Alpine', 'Touring – Civic'];
|
||
|
||
const leagueIds = leagues.map((l) => l.id.toString());
|
||
const trackIds = tracks.map((t) => t.id);
|
||
const demoLeagueId = 'league-5';
|
||
|
||
const races: Race[] = [];
|
||
|
||
// Create races with systematic coverage of different statuses and scenarios
|
||
const statuses: Array<'scheduled' | 'running' | 'completed' | 'cancelled'> = ['scheduled', 'running', 'completed', 'cancelled'];
|
||
|
||
for (let i = 1; i <= 100; i++) {
|
||
const leagueId = leagueIds[(i - 1) % leagueIds.length] ?? demoLeagueId;
|
||
const trackId = trackIds[(i - 1) % trackIds.length]!;
|
||
const track = tracks.find(t => t.id === trackId)!;
|
||
|
||
// Determine status systematically to ensure coverage
|
||
let status: 'scheduled' | 'running' | 'completed' | 'cancelled';
|
||
let scheduledAt: Date;
|
||
|
||
if (i <= 4) {
|
||
// First 4 races: one of each status
|
||
status = statuses[i - 1]!;
|
||
scheduledAt = this.addDays(this.baseDate, i <= 2 ? -35 + i : 1 + (i - 2) * 2);
|
||
} else if (i <= 10) {
|
||
// Next 6: completed races
|
||
status = 'completed';
|
||
scheduledAt = this.addDays(this.baseDate, -35 + i);
|
||
} else if (i <= 15) {
|
||
// Next 5: scheduled future races
|
||
status = 'scheduled';
|
||
scheduledAt = this.addDays(this.baseDate, 1 + (i - 10) * 3);
|
||
} else if (i <= 20) {
|
||
// Next 5: cancelled races
|
||
status = 'cancelled';
|
||
scheduledAt = this.addDays(this.baseDate, -20 + (i - 15));
|
||
} else {
|
||
// Rest: mix of scheduled and completed
|
||
status = i % 3 === 0 ? 'completed' : 'scheduled';
|
||
scheduledAt = status === 'completed'
|
||
? this.addDays(this.baseDate, -10 + (i - 20))
|
||
: this.addDays(this.baseDate, 5 + (i - 20) * 2);
|
||
}
|
||
|
||
const base = {
|
||
id: seedId(`race-${i}`, this.persistence),
|
||
leagueId,
|
||
scheduledAt,
|
||
track: track.name.toString(),
|
||
trackId: track.id,
|
||
car: cars[(i - 1) % cars.length]!,
|
||
};
|
||
|
||
// Special case for running race
|
||
if (status === 'running') {
|
||
races.push(
|
||
Race.create({
|
||
...base,
|
||
status: 'running',
|
||
strengthOfField: 45 + (i % 50), // Valid SOF: 0-100
|
||
registeredCount: 12 + (i % 5), // Varying registration counts
|
||
maxParticipants: 24, // Ensure max is set
|
||
}),
|
||
);
|
||
continue;
|
||
}
|
||
|
||
// Add varying SOF and registration counts for completed races
|
||
if (status === 'completed') {
|
||
races.push(
|
||
Race.create({
|
||
...base,
|
||
status: 'completed',
|
||
strengthOfField: 35 + (i % 60), // Valid SOF: 0-100
|
||
registeredCount: 8 + (i % 8),
|
||
maxParticipants: 20, // Ensure max is set
|
||
}),
|
||
);
|
||
continue;
|
||
}
|
||
|
||
// Scheduled races with some having registration data
|
||
if (status === 'scheduled') {
|
||
const hasRegistrations = i % 4 !== 0; // 75% have registrations
|
||
races.push(
|
||
Race.create({
|
||
...base,
|
||
status: 'scheduled',
|
||
...(hasRegistrations && {
|
||
strengthOfField: 40 + (i % 55), // Valid SOF: 0-100
|
||
registeredCount: 5 + (i % 10),
|
||
maxParticipants: 16 + (i % 10), // Ensure max is set and reasonable
|
||
}),
|
||
}),
|
||
);
|
||
continue;
|
||
}
|
||
|
||
// Cancelled races
|
||
races.push(
|
||
Race.create({
|
||
...base,
|
||
status: 'cancelled',
|
||
}),
|
||
);
|
||
}
|
||
|
||
return races;
|
||
}
|
||
|
||
private addDays(date: Date, days: number): Date {
|
||
return new Date(date.getTime() + days * 24 * 60 * 60 * 1000);
|
||
}
|
||
} |