seed data

This commit is contained in:
2025-12-26 23:14:50 +01:00
parent f3a89ed87f
commit 64661d903e
4 changed files with 79 additions and 62 deletions

View File

@@ -12,7 +12,7 @@ import type { IFeedRepository } from '@core/social/domain/repositories/IFeedRepo
import type { ISocialGraphRepository } from '@core/social/domain/repositories/ISocialGraphRepository'; import type { ISocialGraphRepository } from '@core/social/domain/repositories/ISocialGraphRepository';
import { createRacingSeed } from './racing/RacingSeed'; import { createRacingSeed } from './racing/RacingSeed';
export type InMemorySeedDependencies = { export type RacingSeedDependencies = {
driverRepository: IDriverRepository; driverRepository: IDriverRepository;
leagueRepository: ILeagueRepository; leagueRepository: ILeagueRepository;
raceRepository: IRaceRepository; raceRepository: IRaceRepository;
@@ -26,16 +26,16 @@ export type InMemorySeedDependencies = {
socialGraphRepository: ISocialGraphRepository; socialGraphRepository: ISocialGraphRepository;
}; };
export class SeedInMemoryRacingData { export class SeedRacingData {
constructor( constructor(
private readonly logger: Logger, private readonly logger: Logger,
private readonly seedDeps: InMemorySeedDependencies, private readonly seedDeps: RacingSeedDependencies,
) {} ) {}
async execute(): Promise<void> { async execute(): Promise<void> {
const existingDrivers = await this.seedDeps.driverRepository.findAll(); const existingDrivers = await this.seedDeps.driverRepository.findAll();
if (existingDrivers.length > 0) { if (existingDrivers.length > 0) {
this.logger.info('[Bootstrap] In-memory racing seed skipped (drivers already exist)'); this.logger.info('[Bootstrap] Racing seed skipped (drivers already exist)');
return; return;
} }
@@ -128,7 +128,7 @@ export class SeedInMemoryRacingData {
} }
this.logger.info( this.logger.info(
`[Bootstrap] Seeded in-memory racing data: drivers=${seed.drivers.length}, leagues=${seed.leagues.length}, races=${seed.races.length}`, `[Bootstrap] Seeded racing data: drivers=${seed.drivers.length}, leagues=${seed.leagues.length}, races=${seed.races.length}`,
); );
} }
} }

View File

@@ -5,6 +5,7 @@ import { AuthModule } from './domain/auth/AuthModule';
import { BootstrapModule } from './domain/bootstrap/BootstrapModule'; import { BootstrapModule } from './domain/bootstrap/BootstrapModule';
import { DashboardModule } from './domain/dashboard/DashboardModule'; import { DashboardModule } from './domain/dashboard/DashboardModule';
import { DatabaseModule } from './domain/database/DatabaseModule'; import { DatabaseModule } from './domain/database/DatabaseModule';
import { InMemoryPersistenceModule } from './domain/persistence/InMemoryPersistenceModule';
import { DriverModule } from './domain/driver/DriverModule'; import { DriverModule } from './domain/driver/DriverModule';
import { HelloModule } from './domain/hello/HelloModule'; import { HelloModule } from './domain/hello/HelloModule';
import { LeagueModule } from './domain/league/LeagueModule'; import { LeagueModule } from './domain/league/LeagueModule';
@@ -29,6 +30,7 @@ const ENABLE_BOOTSTRAP = getEnableBootstrap();
imports: [ imports: [
HelloModule, HelloModule,
...(USE_DATABASE ? [DatabaseModule] : []), ...(USE_DATABASE ? [DatabaseModule] : []),
...(!USE_DATABASE ? [InMemoryPersistenceModule] : []),
LoggingModule, LoggingModule,
...(ENABLE_BOOTSTRAP ? [BootstrapModule] : []), ...(ENABLE_BOOTSTRAP ? [BootstrapModule] : []),
AnalyticsModule, AnalyticsModule,

View File

@@ -1,6 +1,9 @@
import type { Logger } from '@core/shared/application';
import { EnsureInitialData } from '../../../../../adapters/bootstrap/EnsureInitialData'; import { EnsureInitialData } from '../../../../../adapters/bootstrap/EnsureInitialData';
import { SeedInMemoryRacingData } from '../../../../../adapters/bootstrap/SeedInMemoryRacingData'; import { SeedRacingData, type RacingSeedDependencies } from '../../../../../adapters/bootstrap/SeedRacingData';
import { Module, OnModuleInit } from '@nestjs/common'; import { Module, OnModuleInit } from '@nestjs/common';
import { ModuleRef } from '@nestjs/core';
import { getApiPersistence } from '../../env';
import { BootstrapProviders } from './BootstrapProviders'; import { BootstrapProviders } from './BootstrapProviders';
@Module({ @Module({
@@ -9,7 +12,7 @@ import { BootstrapProviders } from './BootstrapProviders';
export class BootstrapModule implements OnModuleInit { export class BootstrapModule implements OnModuleInit {
constructor( constructor(
private readonly ensureInitialData: EnsureInitialData, private readonly ensureInitialData: EnsureInitialData,
private readonly seedInMemoryRacingData: SeedInMemoryRacingData, private readonly moduleRef: ModuleRef,
) {} ) {}
async onModuleInit() { async onModuleInit() {
@@ -17,8 +20,15 @@ export class BootstrapModule implements OnModuleInit {
try { try {
await this.ensureInitialData.execute(); await this.ensureInitialData.execute();
if (this.shouldSeedInMemory()) { if (this.shouldSeedRacingData()) {
await this.seedInMemoryRacingData.execute(); const logger = this.tryGet<Logger>('Logger');
const seedDeps = this.tryGetSeedDeps();
if (!logger || !seedDeps) {
console.log('[Bootstrap] Racing seed skipped (missing providers)');
} else {
await new SeedRacingData(logger, seedDeps).execute();
}
} }
console.log('[Bootstrap] Application data initialized successfully'); console.log('[Bootstrap] Application data initialized successfully');
@@ -28,12 +38,65 @@ export class BootstrapModule implements OnModuleInit {
} }
} }
private shouldSeedInMemory(): boolean { private shouldSeedRacingData(): boolean {
const configured = (process.env.GRIDPILOT_API_PERSISTENCE ?? '').toLowerCase(); return getApiPersistence() === 'inmemory';
if (configured) { }
return configured === 'inmemory';
private tryGet<T>(token: string): T | undefined {
try {
return this.moduleRef.get(token, { strict: false });
} catch {
return undefined;
}
}
private tryGetSeedDeps(): RacingSeedDependencies | undefined {
const driverRepository = this.tryGet<RacingSeedDependencies['driverRepository']>('IDriverRepository');
const leagueRepository = this.tryGet<RacingSeedDependencies['leagueRepository']>('ILeagueRepository');
const raceRepository = this.tryGet<RacingSeedDependencies['raceRepository']>('IRaceRepository');
const resultRepository = this.tryGet<RacingSeedDependencies['resultRepository']>('IResultRepository');
const standingRepository = this.tryGet<RacingSeedDependencies['standingRepository']>('IStandingRepository');
const leagueMembershipRepository = this.tryGet<RacingSeedDependencies['leagueMembershipRepository']>(
'ILeagueMembershipRepository',
);
const raceRegistrationRepository = this.tryGet<RacingSeedDependencies['raceRegistrationRepository']>(
'IRaceRegistrationRepository',
);
const teamRepository = this.tryGet<RacingSeedDependencies['teamRepository']>('ITeamRepository');
const teamMembershipRepository = this.tryGet<RacingSeedDependencies['teamMembershipRepository']>(
'ITeamMembershipRepository',
);
const feedRepository = this.tryGet<RacingSeedDependencies['feedRepository']>('IFeedRepository');
const socialGraphRepository = this.tryGet<RacingSeedDependencies['socialGraphRepository']>('ISocialGraphRepository');
if (
!driverRepository ||
!leagueRepository ||
!raceRepository ||
!resultRepository ||
!standingRepository ||
!leagueMembershipRepository ||
!raceRegistrationRepository ||
!teamRepository ||
!teamMembershipRepository ||
!feedRepository ||
!socialGraphRepository
) {
return undefined;
} }
return process.env.DATABASE_URL === undefined; return {
driverRepository,
leagueRepository,
raceRepository,
resultRepository,
standingRepository,
leagueMembershipRepository,
raceRegistrationRepository,
teamRepository,
teamMembershipRepository,
feedRepository,
socialGraphRepository,
};
} }
} }

View File

@@ -1,6 +1,5 @@
import { Provider } from '@nestjs/common'; import { Provider } from '@nestjs/common';
import { EnsureInitialData } from '../../../../../adapters/bootstrap/EnsureInitialData'; import { EnsureInitialData } from '../../../../../adapters/bootstrap/EnsureInitialData';
import { SeedInMemoryRacingData, type InMemorySeedDependencies } from '../../../../../adapters/bootstrap/SeedInMemoryRacingData';
import { SignupWithEmailUseCase, type SignupWithEmailResult } from '@core/identity/application/use-cases/SignupWithEmailUseCase'; import { SignupWithEmailUseCase, type SignupWithEmailResult } from '@core/identity/application/use-cases/SignupWithEmailUseCase';
import { import {
CreateAchievementUseCase, CreateAchievementUseCase,
@@ -97,51 +96,4 @@ export const BootstrapProviders: Provider[] = [
'Logger', 'Logger',
], ],
}, },
{
provide: SeedInMemoryRacingData,
useFactory: (
logger: Logger,
driverRepository: InMemorySeedDependencies['driverRepository'],
leagueRepository: InMemorySeedDependencies['leagueRepository'],
raceRepository: InMemorySeedDependencies['raceRepository'],
resultRepository: InMemorySeedDependencies['resultRepository'],
standingRepository: InMemorySeedDependencies['standingRepository'],
leagueMembershipRepository: InMemorySeedDependencies['leagueMembershipRepository'],
raceRegistrationRepository: InMemorySeedDependencies['raceRegistrationRepository'],
teamRepository: InMemorySeedDependencies['teamRepository'],
teamMembershipRepository: InMemorySeedDependencies['teamMembershipRepository'],
feedRepository: InMemorySeedDependencies['feedRepository'],
socialGraphRepository: InMemorySeedDependencies['socialGraphRepository'],
) => {
const deps: InMemorySeedDependencies = {
driverRepository,
leagueRepository,
raceRepository,
resultRepository,
standingRepository,
leagueMembershipRepository,
raceRegistrationRepository,
teamRepository,
teamMembershipRepository,
feedRepository,
socialGraphRepository,
};
return new SeedInMemoryRacingData(logger, deps);
},
inject: [
'Logger',
'IDriverRepository',
'ILeagueRepository',
'IRaceRepository',
'IResultRepository',
'IStandingRepository',
'ILeagueMembershipRepository',
'IRaceRegistrationRepository',
'ITeamRepository',
'ITeamMembershipRepository',
'IFeedRepository',
'ISocialGraphRepository',
],
},
]; ];