more seeds

This commit is contained in:
2025-12-27 02:00:17 +01:00
parent 15435c93fc
commit 58d9a1c762
4 changed files with 258 additions and 38 deletions

View File

@@ -10,16 +10,28 @@ export class RacingLeagueFactory {
create(): League[] {
const leagueCount = 20;
const pointsSystems = ['f1-2024', 'indycar', 'custom'] as const;
const qualifyingFormats = ['open', 'single-lap'] as const;
// Create diverse league configurations
const leagueConfigs = [
// Small sprint leagues
{ maxDrivers: 16, sessionDuration: 30, pointsSystem: 'f1-2024' as const, qualifyingFormat: 'single-lap' as const },
{ maxDrivers: 20, sessionDuration: 45, pointsSystem: 'f1-2024' as const, qualifyingFormat: 'open' as const },
// Medium endurance leagues
{ maxDrivers: 24, sessionDuration: 60, pointsSystem: 'indycar' as const, qualifyingFormat: 'open' as const },
{ maxDrivers: 28, sessionDuration: 90, pointsSystem: 'custom' as const, qualifyingFormat: 'open' as const },
// Large mixed leagues
{ maxDrivers: 32, sessionDuration: 120, pointsSystem: 'f1-2024' as const, qualifyingFormat: 'open' as const },
{ maxDrivers: 36, sessionDuration: 75, pointsSystem: 'indycar' as const, qualifyingFormat: 'single-lap' as const },
{ maxDrivers: 40, sessionDuration: 100, pointsSystem: 'custom' as const, qualifyingFormat: 'open' as const },
{ maxDrivers: 44, sessionDuration: 85, pointsSystem: 'f1-2024' as const, qualifyingFormat: 'open' as const },
{ maxDrivers: 48, sessionDuration: 110, pointsSystem: 'indycar' as const, qualifyingFormat: 'single-lap' as const },
{ maxDrivers: 50, sessionDuration: 95, pointsSystem: 'custom' as const, qualifyingFormat: 'open' as const },
];
return Array.from({ length: leagueCount }, (_, idx) => {
const i = idx + 1;
const owner = faker.helpers.arrayElement(this.drivers);
const socialLinks: { discordUrl?: string; youtubeUrl?: string; websiteUrl?: string } = {};
if (faker.datatype.boolean()) socialLinks.discordUrl = faker.internet.url();
if (faker.datatype.boolean()) socialLinks.youtubeUrl = faker.internet.url();
if (faker.datatype.boolean()) socialLinks.websiteUrl = faker.internet.url();
const config = leagueConfigs[idx % leagueConfigs.length]!;
const leagueData: {
id: string;
@@ -39,15 +51,24 @@ export class RacingLeagueFactory {
name: faker.company.name() + ' Racing League',
description: faker.lorem.sentences(2),
ownerId: owner.id.toString(),
settings: {
pointsSystem: faker.helpers.arrayElement(pointsSystems),
maxDrivers: faker.number.int({ min: 20, max: 50 }),
sessionDuration: faker.number.int({ min: 30, max: 180 }),
qualifyingFormat: faker.helpers.arrayElement(qualifyingFormats),
},
settings: config,
createdAt: faker.date.past({ years: 2, refDate: this.baseDate }),
};
// Add social links with varying completeness
const socialLinks: { discordUrl?: string; youtubeUrl?: string; websiteUrl?: string } = {};
const socialLinkTypes = ['discord', 'youtube', 'website'] as const;
// Ensure some leagues have no social links, some have partial, some have all
const numSocialLinks = idx % 4; // 0, 1, 2, or 3
const selectedTypes = faker.helpers.arrayElements(socialLinkTypes, numSocialLinks);
selectedTypes.forEach(type => {
if (type === 'discord') socialLinks.discordUrl = faker.internet.url();
if (type === 'youtube') socialLinks.youtubeUrl = faker.internet.url();
if (type === 'website') socialLinks.websiteUrl = faker.internet.url();
});
if (Object.keys(socialLinks).length > 0) {
leagueData.socialLinks = socialLinks;
}

View File

@@ -14,11 +14,41 @@ export class RacingRaceFactory {
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 <= 50; i++) {
const leagueId = leagueIds[(i - 1) % leagueIds.length] ?? demoLeagueId;
const trackId = trackIds[(i - 1) % trackIds.length]!;
const track = tracks.find(t => t.id === trackId)!;
const scheduledAt = this.addDays(this.baseDate, i <= 10 ? -35 + i : 1 + (i - 10) * 2);
// 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: `race-${i}`,
@@ -29,34 +59,53 @@ export class RacingRaceFactory {
car: cars[(i - 1) % cars.length]!,
};
if (i === 1) {
// Special case for running race
if (status === 'running') {
races.push(
Race.create({
...base,
leagueId: demoLeagueId,
scheduledAt: this.addMinutes(this.baseDate, -30),
status: 'running',
strengthOfField: 1530,
registeredCount: 16,
strengthOfField: 1400 + (i * 10), // Varying SOF
registeredCount: 12 + (i % 5), // Varying registration counts
}),
);
continue;
}
if (scheduledAt < this.baseDate) {
// Add varying SOF and registration counts for completed races
if (status === 'completed') {
races.push(
Race.create({
...base,
status: 'completed',
strengthOfField: 1200 + (i * 15),
registeredCount: 8 + (i % 8),
}),
);
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: 1300 + (i * 8),
registeredCount: 5 + (i % 10),
}),
}),
);
continue;
}
// Cancelled races
races.push(
Race.create({
...base,
status: 'scheduled',
status: 'cancelled',
}),
);
}
@@ -67,8 +116,4 @@ export class RacingRaceFactory {
private addDays(date: Date, days: number): Date {
return new Date(date.getTime() + days * 24 * 60 * 60 * 1000);
}
private addMinutes(date: Date, minutes: number): Date {
return new Date(date.getTime() + minutes * 60 * 1000);
}
}

View File

@@ -38,9 +38,35 @@ export class RacingTeamFactory {
const memberships: TeamMembership[] = [];
const usedDrivers = new Set<string>();
teams.forEach((team) => {
teams.forEach((team, teamIndex) => {
const availableDrivers = drivers.filter(d => !usedDrivers.has(d.id.toString()) && d.id.toString() !== team.ownerId.toString());
const memberCount = faker.number.int({ min: 1, max: 8 });
// Create varied team compositions
let memberCount: number;
let hasManager: boolean;
if (teamIndex % 5 === 0) {
// Solo teams (just owner)
memberCount = 0;
hasManager = false;
} else if (teamIndex % 5 === 1) {
// Small teams (2-3 members)
memberCount = faker.number.int({ min: 1, max: 2 });
hasManager = faker.datatype.boolean();
} else if (teamIndex % 5 === 2) {
// Medium teams (3-5 members)
memberCount = faker.number.int({ min: 2, max: 4 });
hasManager = true;
} else if (teamIndex % 5 === 3) {
// Large teams (5-7 members)
memberCount = faker.number.int({ min: 4, max: 6 });
hasManager = true;
} else {
// Mixed - sometimes with manager, sometimes without
memberCount = faker.number.int({ min: 1, max: 5 });
hasManager = faker.datatype.boolean();
}
const members = faker.helpers.arrayElements(availableDrivers, memberCount);
// Add owner
@@ -53,16 +79,32 @@ export class RacingTeamFactory {
});
usedDrivers.add(team.ownerId.toString());
// Add members
members.forEach((driver) => {
// Add manager if needed
if (hasManager && members.length > 0) {
const managerIndex = faker.number.int({ min: 0, max: members.length - 1 });
const manager = members[managerIndex]!;
memberships.push({
teamId: team.id.toString(),
driverId: driver.id.toString(),
role: faker.helpers.arrayElement(['driver', 'manager']),
driverId: manager.id.toString(),
role: 'manager',
status: 'active',
joinedAt: faker.date.past({ years: 1, refDate: team.createdAt.toDate() }),
});
usedDrivers.add(driver.id.toString());
usedDrivers.add(manager.id.toString());
}
// Add remaining members as drivers
members.forEach((driver) => {
if (!usedDrivers.has(driver.id.toString())) {
memberships.push({
teamId: team.id.toString(),
driverId: driver.id.toString(),
role: 'driver',
status: 'active',
joinedAt: faker.date.past({ years: 1, refDate: team.createdAt.toDate() }),
});
usedDrivers.add(driver.id.toString());
}
});
});

View File

@@ -3,6 +3,7 @@ import { Track } from '@core/racing/domain/entities/Track';
export class RacingTrackFactory {
create(): Track[] {
return [
// Road tracks - various difficulties
Track.create({
id: 'track-spa',
name: 'Spa-Francorchamps',
@@ -63,6 +64,67 @@ export class RacingTrackFactory {
imageUrl: '/images/tracks/suzuka.jpg',
gameId: 'iracing',
}),
Track.create({
id: 'track-laguna',
name: 'WeatherTech Raceway Laguna Seca',
shortName: 'LAG',
country: 'United States',
category: 'road',
difficulty: 'advanced',
lengthKm: 3.602,
turns: 11,
imageUrl: '/images/tracks/laguna.jpg',
gameId: 'iracing',
}),
Track.create({
id: 'track-zandvoort',
name: 'Circuit Zandvoort',
shortName: 'ZAN',
country: 'Netherlands',
category: 'road',
difficulty: 'intermediate',
lengthKm: 4.259,
turns: 14,
imageUrl: '/images/tracks/zandvoort.jpg',
gameId: 'iracing',
}),
Track.create({
id: 'track-imola',
name: 'Autodromo Enzo e Dino Ferrari',
shortName: 'IMO',
country: 'Italy',
category: 'road',
difficulty: 'advanced',
lengthKm: 4.909,
turns: 19,
imageUrl: '/images/tracks/imola.jpg',
gameId: 'iracing',
}),
Track.create({
id: 'track-le-mans',
name: 'Circuit de la Sarthe',
shortName: 'LEM',
country: 'France',
category: 'road',
difficulty: 'expert',
lengthKm: 13.626,
turns: 38,
imageUrl: '/images/tracks/le-mans.jpg',
gameId: 'iracing',
}),
Track.create({
id: 'track-hockenheim',
name: 'Hockenheimring',
shortName: 'HOC',
country: 'Germany',
category: 'road',
difficulty: 'intermediate',
lengthKm: 4.574,
turns: 17,
imageUrl: '/images/tracks/hockenheim.jpg',
gameId: 'iracing',
}),
// Oval tracks
Track.create({
id: 'track-daytona',
name: 'Daytona International Speedway',
@@ -76,15 +138,65 @@ export class RacingTrackFactory {
gameId: 'iracing',
}),
Track.create({
id: 'track-laguna',
name: 'WeatherTech Raceway Laguna Seca',
shortName: 'LAG',
id: 'track-indianapolis',
name: 'Indianapolis Motor Speedway',
shortName: 'IMS',
country: 'United States',
category: 'road',
category: 'oval',
difficulty: 'advanced',
lengthKm: 3.602,
turns: 11,
imageUrl: '/images/tracks/laguna.jpg',
lengthKm: 4.192,
turns: 4,
imageUrl: '/images/tracks/indianapolis.jpg',
gameId: 'iracing',
}),
Track.create({
id: 'track-talladega',
name: 'Talladega Superspeedway',
shortName: 'TAL',
country: 'United States',
category: 'oval',
difficulty: 'beginner',
lengthKm: 4.280,
turns: 4,
imageUrl: '/images/tracks/talladega.jpg',
gameId: 'iracing',
}),
// Street tracks
Track.create({
id: 'track-miami',
name: 'Miami Street Circuit',
shortName: 'MIA',
country: 'United States',
category: 'street',
difficulty: 'intermediate',
lengthKm: 5.410,
turns: 19,
imageUrl: '/images/tracks/miami.jpg',
gameId: 'iracing',
}),
Track.create({
id: 'track-las-vegas',
name: 'Las Vegas Street Circuit',
shortName: 'VEG',
country: 'United States',
category: 'street',
difficulty: 'advanced',
lengthKm: 6.201,
turns: 17,
imageUrl: '/images/tracks/las-vegas.jpg',
gameId: 'iracing',
}),
// Dirt tracks
Track.create({
id: 'track-eldo',
name: 'Eldora Speedway',
shortName: 'ELD',
country: 'United States',
category: 'dirt',
difficulty: 'beginner',
lengthKm: 0.805,
turns: 4,
imageUrl: '/images/tracks/eldora.jpg',
gameId: 'iracing',
}),
];