327 lines
11 KiB
TypeScript
327 lines
11 KiB
TypeScript
import type { Logger } from '@core/shared/application';
|
|
import type { IDriverRepository } from '@core/racing/domain/repositories/IDriverRepository';
|
|
import type { ILeagueRepository } from '@core/racing/domain/repositories/ILeagueRepository';
|
|
import type { IRaceRepository } from '@core/racing/domain/repositories/IRaceRepository';
|
|
import type { IResultRepository } from '@core/racing/domain/repositories/IResultRepository';
|
|
import type { IStandingRepository } from '@core/racing/domain/repositories/IStandingRepository';
|
|
import type { ILeagueMembershipRepository } from '@core/racing/domain/repositories/ILeagueMembershipRepository';
|
|
import type { IRaceRegistrationRepository } from '@core/racing/domain/repositories/IRaceRegistrationRepository';
|
|
import type { ITeamRepository } from '@core/racing/domain/repositories/ITeamRepository';
|
|
import type { ITeamMembershipRepository } from '@core/racing/domain/repositories/ITeamMembershipRepository';
|
|
import type { ISponsorRepository } from '@core/racing/domain/repositories/ISponsorRepository';
|
|
import type { ISeasonRepository } from '@core/racing/domain/repositories/ISeasonRepository';
|
|
import type { ILeagueScoringConfigRepository } from '@core/racing/domain/repositories/ILeagueScoringConfigRepository';
|
|
import type { ISeasonSponsorshipRepository } from '@core/racing/domain/repositories/ISeasonSponsorshipRepository';
|
|
import type { ISponsorshipRequestRepository } from '@core/racing/domain/repositories/ISponsorshipRequestRepository';
|
|
import type { ILeagueWalletRepository } from '@core/racing/domain/repositories/ILeagueWalletRepository';
|
|
import type { ITransactionRepository } from '@core/racing/domain/repositories/ITransactionRepository';
|
|
import type { Season } from '@core/racing/domain/entities/season/Season';
|
|
import { getLeagueScoringPresetById } from './LeagueScoringPresets';
|
|
import type { IProtestRepository } from '@core/racing/domain/repositories/IProtestRepository';
|
|
import type { IPenaltyRepository } from '@core/racing/domain/repositories/IPenaltyRepository';
|
|
import type { IFeedRepository } from '@core/social/domain/repositories/IFeedRepository';
|
|
import type { ISocialGraphRepository } from '@core/social/domain/repositories/ISocialGraphRepository';
|
|
import { createRacingSeed } from './racing/RacingSeed';
|
|
|
|
export type RacingSeedDependencies = {
|
|
driverRepository: IDriverRepository;
|
|
leagueRepository: ILeagueRepository;
|
|
seasonRepository: ISeasonRepository;
|
|
leagueScoringConfigRepository: ILeagueScoringConfigRepository;
|
|
seasonSponsorshipRepository: ISeasonSponsorshipRepository;
|
|
sponsorshipRequestRepository: ISponsorshipRequestRepository;
|
|
leagueWalletRepository: ILeagueWalletRepository;
|
|
transactionRepository: ITransactionRepository;
|
|
protestRepository: IProtestRepository;
|
|
penaltyRepository: IPenaltyRepository;
|
|
raceRepository: IRaceRepository;
|
|
resultRepository: IResultRepository;
|
|
standingRepository: IStandingRepository;
|
|
leagueMembershipRepository: ILeagueMembershipRepository;
|
|
raceRegistrationRepository: IRaceRegistrationRepository;
|
|
teamRepository: ITeamRepository;
|
|
teamMembershipRepository: ITeamMembershipRepository;
|
|
sponsorRepository: ISponsorRepository;
|
|
feedRepository: IFeedRepository;
|
|
socialGraphRepository: ISocialGraphRepository;
|
|
};
|
|
|
|
export class SeedRacingData {
|
|
constructor(
|
|
private readonly logger: Logger,
|
|
private readonly seedDeps: RacingSeedDependencies,
|
|
) {}
|
|
|
|
async execute(): Promise<void> {
|
|
const existingDrivers = await this.seedDeps.driverRepository.findAll();
|
|
if (existingDrivers.length > 0) {
|
|
this.logger.info('[Bootstrap] Racing seed skipped (drivers already exist), ensuring scoring configs');
|
|
await this.ensureScoringConfigsForExistingData();
|
|
return;
|
|
}
|
|
|
|
const seed = createRacingSeed();
|
|
|
|
let sponsorshipRequestsSeededViaRepo = false;
|
|
const seedableSponsorshipRequests = this.seedDeps
|
|
.sponsorshipRequestRepository as unknown as { seed?: (input: unknown) => void };
|
|
|
|
if (typeof seedableSponsorshipRequests.seed === 'function') {
|
|
seedableSponsorshipRequests.seed(seed.sponsorshipRequests);
|
|
sponsorshipRequestsSeededViaRepo = true;
|
|
}
|
|
|
|
for (const driver of seed.drivers) {
|
|
try {
|
|
await this.seedDeps.driverRepository.create(driver);
|
|
} catch {
|
|
// ignore duplicates
|
|
}
|
|
}
|
|
|
|
for (const league of seed.leagues) {
|
|
try {
|
|
await this.seedDeps.leagueRepository.create(league);
|
|
} catch {
|
|
// ignore duplicates
|
|
}
|
|
}
|
|
|
|
for (const season of seed.seasons) {
|
|
try {
|
|
await this.seedDeps.seasonRepository.create(season);
|
|
} catch {
|
|
// ignore duplicates
|
|
}
|
|
}
|
|
|
|
const activeSeasons = seed.seasons.filter((season) => season.status.isActive());
|
|
for (const season of activeSeasons) {
|
|
const presetId = this.selectScoringPresetIdForSeason(season);
|
|
const preset = getLeagueScoringPresetById(presetId);
|
|
|
|
if (!preset) {
|
|
this.logger.warn(
|
|
`[Bootstrap] Scoring preset not found (presetId=${presetId}, seasonId=${season.id}, leagueId=${season.leagueId})`,
|
|
);
|
|
continue;
|
|
}
|
|
|
|
const scoringConfig = preset.createConfig({ seasonId: season.id });
|
|
|
|
try {
|
|
await this.seedDeps.leagueScoringConfigRepository.save(scoringConfig);
|
|
} catch {
|
|
// ignore duplicates
|
|
}
|
|
}
|
|
|
|
for (const sponsorship of seed.seasonSponsorships) {
|
|
try {
|
|
await this.seedDeps.seasonSponsorshipRepository.create(sponsorship);
|
|
} catch {
|
|
// ignore duplicates
|
|
}
|
|
}
|
|
|
|
if (!sponsorshipRequestsSeededViaRepo) {
|
|
for (const request of seed.sponsorshipRequests) {
|
|
try {
|
|
await this.seedDeps.sponsorshipRequestRepository.create(request);
|
|
} catch {
|
|
// ignore duplicates
|
|
}
|
|
}
|
|
}
|
|
|
|
for (const wallet of seed.leagueWallets) {
|
|
try {
|
|
await this.seedDeps.leagueWalletRepository.create(wallet);
|
|
} catch {
|
|
// ignore duplicates
|
|
}
|
|
}
|
|
|
|
for (const tx of seed.leagueWalletTransactions) {
|
|
try {
|
|
await this.seedDeps.transactionRepository.create(tx);
|
|
} catch {
|
|
// ignore duplicates
|
|
}
|
|
}
|
|
|
|
for (const protest of seed.protests) {
|
|
try {
|
|
await this.seedDeps.protestRepository.create(protest);
|
|
} catch {
|
|
// ignore duplicates
|
|
}
|
|
}
|
|
|
|
for (const penalty of seed.penalties) {
|
|
try {
|
|
await this.seedDeps.penaltyRepository.create(penalty);
|
|
} catch {
|
|
// ignore duplicates
|
|
}
|
|
}
|
|
|
|
for (const race of seed.races) {
|
|
try {
|
|
await this.seedDeps.raceRepository.create(race);
|
|
} catch {
|
|
// ignore duplicates
|
|
}
|
|
}
|
|
|
|
try {
|
|
await this.seedDeps.resultRepository.createMany(seed.results);
|
|
} catch {
|
|
// ignore duplicates
|
|
}
|
|
|
|
for (const membership of seed.leagueMemberships) {
|
|
try {
|
|
await this.seedDeps.leagueMembershipRepository.saveMembership(membership);
|
|
} catch {
|
|
// ignore duplicates
|
|
}
|
|
}
|
|
|
|
for (const request of seed.leagueJoinRequests) {
|
|
try {
|
|
await this.seedDeps.leagueMembershipRepository.saveJoinRequest(request);
|
|
} catch {
|
|
// ignore duplicates
|
|
}
|
|
}
|
|
|
|
for (const team of seed.teams) {
|
|
try {
|
|
await this.seedDeps.teamRepository.create(team);
|
|
} catch {
|
|
// ignore duplicates
|
|
}
|
|
}
|
|
|
|
for (const sponsor of seed.sponsors) {
|
|
try {
|
|
await this.seedDeps.sponsorRepository.create(sponsor);
|
|
} catch {
|
|
// ignore duplicates
|
|
}
|
|
}
|
|
|
|
for (const membership of seed.teamMemberships) {
|
|
try {
|
|
await this.seedDeps.teamMembershipRepository.saveMembership(membership);
|
|
} catch {
|
|
// ignore duplicates
|
|
}
|
|
}
|
|
|
|
for (const request of seed.teamJoinRequests) {
|
|
try {
|
|
await this.seedDeps.teamMembershipRepository.saveJoinRequest(request);
|
|
} catch {
|
|
// ignore duplicates
|
|
}
|
|
}
|
|
|
|
for (const registration of seed.raceRegistrations) {
|
|
try {
|
|
await this.seedDeps.raceRegistrationRepository.register(registration);
|
|
} catch {
|
|
// ignore duplicates
|
|
}
|
|
}
|
|
|
|
try {
|
|
await this.seedDeps.standingRepository.saveMany(seed.standings);
|
|
} catch {
|
|
// ignore duplicates
|
|
}
|
|
|
|
const seedableFeed = this.seedDeps.feedRepository as unknown as { seed?: (input: unknown) => void };
|
|
if (typeof seedableFeed.seed === 'function') {
|
|
seedableFeed.seed({
|
|
drivers: seed.drivers,
|
|
friendships: seed.friendships,
|
|
feedEvents: seed.feedEvents,
|
|
});
|
|
}
|
|
|
|
const seedableSocial = this.seedDeps.socialGraphRepository as unknown as { seed?: (input: unknown) => void };
|
|
if (typeof seedableSocial.seed === 'function') {
|
|
seedableSocial.seed({
|
|
drivers: seed.drivers,
|
|
friendships: seed.friendships,
|
|
feedEvents: seed.feedEvents,
|
|
});
|
|
}
|
|
|
|
this.logger.info(
|
|
`[Bootstrap] Seeded racing data: drivers=${seed.drivers.length}, leagues=${seed.leagues.length}, races=${seed.races.length}`,
|
|
);
|
|
}
|
|
|
|
private async ensureScoringConfigsForExistingData(): Promise<void> {
|
|
const leagues = await this.seedDeps.leagueRepository.findAll();
|
|
|
|
for (const league of leagues) {
|
|
const seasons = await this.seedDeps.seasonRepository.findByLeagueId(league.id.toString());
|
|
const activeSeasons = seasons.filter((season) => season.status.isActive());
|
|
|
|
for (const season of activeSeasons) {
|
|
const existing = await this.seedDeps.leagueScoringConfigRepository.findBySeasonId(season.id);
|
|
if (existing) continue;
|
|
|
|
const presetId = this.selectScoringPresetIdForSeason(season);
|
|
const preset = getLeagueScoringPresetById(presetId);
|
|
|
|
if (!preset) {
|
|
this.logger.warn(
|
|
`[Bootstrap] Scoring preset not found (presetId=${presetId}, seasonId=${season.id}, leagueId=${season.leagueId})`,
|
|
);
|
|
continue;
|
|
}
|
|
|
|
const scoringConfig = preset.createConfig({ seasonId: season.id });
|
|
|
|
try {
|
|
await this.seedDeps.leagueScoringConfigRepository.save(scoringConfig);
|
|
} catch {
|
|
// ignore duplicates
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private selectScoringPresetIdForSeason(season: Season): string {
|
|
if (season.leagueId === 'league-5' && season.status.isActive()) {
|
|
return 'sprint-main-driver';
|
|
}
|
|
|
|
if (season.leagueId === 'league-3') {
|
|
return season.id.endsWith('-b') ? 'sprint-main-team' : 'club-default-nations';
|
|
}
|
|
|
|
const match = /^league-(\d+)$/.exec(season.leagueId);
|
|
const leagueNumber = match ? Number(match[1]) : undefined;
|
|
|
|
if (leagueNumber !== undefined) {
|
|
switch (leagueNumber % 4) {
|
|
case 0:
|
|
return 'sprint-main-team';
|
|
case 1:
|
|
return 'endurance-main-trophy';
|
|
case 2:
|
|
return 'sprint-main-driver';
|
|
case 3:
|
|
return 'club-default-nations';
|
|
}
|
|
}
|
|
|
|
return 'club-default';
|
|
}
|
|
} |