seed data
This commit is contained in:
@@ -2,6 +2,22 @@ import { Driver } from '@core/racing/domain/entities/Driver';
|
||||
import { faker } from '@faker-js/faker';
|
||||
import { seedId } from './SeedIdHelper';
|
||||
|
||||
export interface DriverStats {
|
||||
rating: number;
|
||||
safetyRating: number;
|
||||
sportsmanshipRating: number;
|
||||
totalRaces: number;
|
||||
wins: number;
|
||||
podiums: number;
|
||||
dnfs: number;
|
||||
avgFinish: number;
|
||||
bestFinish: number;
|
||||
worstFinish: number;
|
||||
consistency: number;
|
||||
experienceLevel: 'beginner' | 'intermediate' | 'advanced' | 'veteran';
|
||||
overallRank: number | null;
|
||||
}
|
||||
|
||||
export class RacingDriverFactory {
|
||||
constructor(
|
||||
private readonly driverCount: number,
|
||||
@@ -15,14 +31,156 @@ export class RacingDriverFactory {
|
||||
return Array.from({ length: this.driverCount }, (_, idx) => {
|
||||
const i = idx + 1;
|
||||
|
||||
return Driver.create({
|
||||
// Vary bio presence: 80% have bio, 20% empty
|
||||
const hasBio = i % 5 !== 0;
|
||||
|
||||
// Vary joined dates: some recent (new drivers), some old (veterans)
|
||||
let joinedAt: Date;
|
||||
if (i % 10 === 0) {
|
||||
// Very recent drivers (within last week)
|
||||
joinedAt = faker.date.recent({ days: 7, refDate: this.baseDate });
|
||||
} else if (i % 7 === 0) {
|
||||
// Recent drivers (within last month)
|
||||
joinedAt = faker.date.recent({ days: 30, refDate: this.baseDate });
|
||||
} else if (i % 5 === 0) {
|
||||
// Medium tenure (6-12 months ago)
|
||||
joinedAt = faker.date.between({
|
||||
from: new Date(this.baseDate.getTime() - 365 * 24 * 60 * 60 * 1000),
|
||||
to: new Date(this.baseDate.getTime() - 180 * 24 * 60 * 60 * 1000)
|
||||
});
|
||||
} else {
|
||||
// Veterans (1-2 years ago)
|
||||
joinedAt = faker.date.past({ years: 2, refDate: this.baseDate });
|
||||
}
|
||||
|
||||
const driverData: {
|
||||
id: string;
|
||||
iracingId: string;
|
||||
name: string;
|
||||
country: string;
|
||||
bio?: string;
|
||||
joinedAt?: Date;
|
||||
} = {
|
||||
id: seedId(`driver-${i}`, this.persistence),
|
||||
iracingId: String(100000 + i),
|
||||
name: faker.person.fullName(),
|
||||
country: faker.helpers.arrayElement(countries),
|
||||
bio: faker.lorem.sentences(2),
|
||||
joinedAt: faker.date.past({ years: 2, refDate: this.baseDate }),
|
||||
});
|
||||
joinedAt,
|
||||
};
|
||||
|
||||
if (hasBio) {
|
||||
driverData.bio = faker.lorem.sentences(2);
|
||||
}
|
||||
|
||||
return Driver.create(driverData);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate driver statistics for profile display
|
||||
* This would be stored in a separate stats table/service in production
|
||||
*/
|
||||
generateDriverStats(drivers: Driver[]): Map<string, DriverStats> {
|
||||
const statsMap = new Map<string, DriverStats>();
|
||||
|
||||
drivers.forEach((driver, idx) => {
|
||||
const i = idx + 1;
|
||||
|
||||
// Determine experience level based on join date and index
|
||||
let experienceLevel: 'beginner' | 'intermediate' | 'advanced' | 'veteran';
|
||||
let totalRaces: number;
|
||||
let rating: number;
|
||||
let safetyRating: number;
|
||||
let sportsmanshipRating: number;
|
||||
|
||||
if (i % 10 === 0) {
|
||||
// Very recent drivers
|
||||
experienceLevel = 'beginner';
|
||||
totalRaces = faker.number.int({ min: 1, max: 10 });
|
||||
rating = faker.number.int({ min: 800, max: 1200 });
|
||||
safetyRating = faker.number.int({ min: 60, max: 85 });
|
||||
sportsmanshipRating = Math.round(faker.number.float({ min: 3.0, max: 4.2 }) * 10) / 10;
|
||||
} else if (i % 7 === 0) {
|
||||
// Recent drivers
|
||||
experienceLevel = 'beginner';
|
||||
totalRaces = faker.number.int({ min: 5, max: 25 });
|
||||
rating = faker.number.int({ min: 1000, max: 1400 });
|
||||
safetyRating = faker.number.int({ min: 70, max: 90 });
|
||||
sportsmanshipRating = Math.round(faker.number.float({ min: 3.5, max: 4.5 }) * 10) / 10;
|
||||
} else if (i % 5 === 0) {
|
||||
// Medium tenure
|
||||
experienceLevel = 'intermediate';
|
||||
totalRaces = faker.number.int({ min: 20, max: 60 });
|
||||
rating = faker.number.int({ min: 1300, max: 1700 });
|
||||
safetyRating = faker.number.int({ min: 75, max: 95 });
|
||||
sportsmanshipRating = Math.round(faker.number.float({ min: 3.8, max: 4.8 }) * 10) / 10;
|
||||
} else if (i % 3 === 0) {
|
||||
// Advanced
|
||||
experienceLevel = 'advanced';
|
||||
totalRaces = faker.number.int({ min: 50, max: 120 });
|
||||
rating = faker.number.int({ min: 1600, max: 1900 });
|
||||
safetyRating = faker.number.int({ min: 80, max: 98 });
|
||||
sportsmanshipRating = Math.round(faker.number.float({ min: 4.0, max: 5.0 }) * 10) / 10;
|
||||
} else {
|
||||
// Veterans
|
||||
experienceLevel = 'veteran';
|
||||
totalRaces = faker.number.int({ min: 100, max: 200 });
|
||||
rating = faker.number.int({ min: 1700, max: 2000 });
|
||||
safetyRating = faker.number.int({ min: 85, max: 100 });
|
||||
sportsmanshipRating = Math.round(faker.number.float({ min: 4.2, max: 5.0 }) * 10) / 10;
|
||||
}
|
||||
|
||||
// Calculate performance stats based on total races
|
||||
const winRate = experienceLevel === 'beginner' ? faker.number.float({ min: 0, max: 5, fractionDigits: 1 }) :
|
||||
experienceLevel === 'intermediate' ? faker.number.float({ min: 2, max: 10, fractionDigits: 1 }) :
|
||||
experienceLevel === 'advanced' ? faker.number.float({ min: 5, max: 15, fractionDigits: 1 }) :
|
||||
faker.number.float({ min: 8, max: 20, fractionDigits: 1 });
|
||||
|
||||
const podiumRate = experienceLevel === 'beginner' ? faker.number.float({ min: 5, max: 15, fractionDigits: 1 }) :
|
||||
experienceLevel === 'intermediate' ? faker.number.float({ min: 10, max: 25, fractionDigits: 1 }) :
|
||||
experienceLevel === 'advanced' ? faker.number.float({ min: 15, max: 35, fractionDigits: 1 }) :
|
||||
faker.number.float({ min: 20, max: 45, fractionDigits: 1 });
|
||||
|
||||
const wins = Math.round((winRate / 100) * totalRaces);
|
||||
const podiums = Math.round((podiumRate / 100) * totalRaces);
|
||||
const dnfs = Math.round(faker.number.float({ min: 0.05, max: 0.15, fractionDigits: 2 }) * totalRaces);
|
||||
|
||||
const avgFinish = experienceLevel === 'beginner' ? faker.number.float({ min: 8, max: 15, fractionDigits: 1 }) :
|
||||
experienceLevel === 'intermediate' ? faker.number.float({ min: 5, max: 10, fractionDigits: 1 }) :
|
||||
experienceLevel === 'advanced' ? faker.number.float({ min: 3, max: 7, fractionDigits: 1 }) :
|
||||
faker.number.float({ min: 2, max: 5, fractionDigits: 1 });
|
||||
|
||||
const bestFinish = experienceLevel === 'beginner' ? faker.number.int({ min: 3, max: 8 }) :
|
||||
experienceLevel === 'intermediate' ? faker.number.int({ min: 1, max: 5 }) :
|
||||
faker.number.int({ min: 1, max: 3 });
|
||||
|
||||
const worstFinish = experienceLevel === 'beginner' ? faker.number.int({ min: 12, max: 20 }) :
|
||||
experienceLevel === 'intermediate' ? faker.number.int({ min: 8, max: 15 }) :
|
||||
experienceLevel === 'advanced' ? faker.number.int({ min: 5, max: 12 }) :
|
||||
faker.number.int({ min: 4, max: 10 });
|
||||
|
||||
const consistency = experienceLevel === 'beginner' ? faker.number.float({ min: 40, max: 65, fractionDigits: 0 }) :
|
||||
experienceLevel === 'intermediate' ? faker.number.float({ min: 60, max: 80, fractionDigits: 0 }) :
|
||||
experienceLevel === 'advanced' ? faker.number.float({ min: 75, max: 90, fractionDigits: 0 }) :
|
||||
faker.number.float({ min: 85, max: 98, fractionDigits: 0 });
|
||||
|
||||
statsMap.set(driver.id.toString(), {
|
||||
rating,
|
||||
safetyRating,
|
||||
sportsmanshipRating,
|
||||
totalRaces,
|
||||
wins,
|
||||
podiums,
|
||||
dnfs,
|
||||
avgFinish: parseFloat(avgFinish.toFixed(1)),
|
||||
bestFinish,
|
||||
worstFinish,
|
||||
consistency: parseFloat(consistency.toFixed(1)),
|
||||
experienceLevel,
|
||||
overallRank: null, // Will be calculated after all stats are loaded
|
||||
});
|
||||
});
|
||||
|
||||
return statsMap;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user