From 64661d903ea70287ab39424d5b40f0472e1cf2c9 Mon Sep 17 00:00:00 2001 From: Marc Mintel Date: Fri, 26 Dec 2025 23:14:50 +0100 Subject: [PATCH] seed data --- ...nMemoryRacingData.ts => SeedRacingData.ts} | 10 +-- apps/api/src/app.module.ts | 2 + .../src/domain/bootstrap/BootstrapModule.ts | 81 ++++++++++++++++--- .../domain/bootstrap/BootstrapProviders.ts | 48 ----------- 4 files changed, 79 insertions(+), 62 deletions(-) rename adapters/bootstrap/{SeedInMemoryRacingData.ts => SeedRacingData.ts} (91%) diff --git a/adapters/bootstrap/SeedInMemoryRacingData.ts b/adapters/bootstrap/SeedRacingData.ts similarity index 91% rename from adapters/bootstrap/SeedInMemoryRacingData.ts rename to adapters/bootstrap/SeedRacingData.ts index ea3aaa9c0..9bf0bc6e8 100644 --- a/adapters/bootstrap/SeedInMemoryRacingData.ts +++ b/adapters/bootstrap/SeedRacingData.ts @@ -12,7 +12,7 @@ import type { IFeedRepository } from '@core/social/domain/repositories/IFeedRepo import type { ISocialGraphRepository } from '@core/social/domain/repositories/ISocialGraphRepository'; import { createRacingSeed } from './racing/RacingSeed'; -export type InMemorySeedDependencies = { +export type RacingSeedDependencies = { driverRepository: IDriverRepository; leagueRepository: ILeagueRepository; raceRepository: IRaceRepository; @@ -26,16 +26,16 @@ export type InMemorySeedDependencies = { socialGraphRepository: ISocialGraphRepository; }; -export class SeedInMemoryRacingData { +export class SeedRacingData { constructor( private readonly logger: Logger, - private readonly seedDeps: InMemorySeedDependencies, + private readonly seedDeps: RacingSeedDependencies, ) {} async execute(): Promise { const existingDrivers = await this.seedDeps.driverRepository.findAll(); 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; } @@ -128,7 +128,7 @@ export class SeedInMemoryRacingData { } 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}`, ); } } \ No newline at end of file diff --git a/apps/api/src/app.module.ts b/apps/api/src/app.module.ts index 8c9dd60dc..8a24bdee5 100644 --- a/apps/api/src/app.module.ts +++ b/apps/api/src/app.module.ts @@ -5,6 +5,7 @@ import { AuthModule } from './domain/auth/AuthModule'; import { BootstrapModule } from './domain/bootstrap/BootstrapModule'; import { DashboardModule } from './domain/dashboard/DashboardModule'; import { DatabaseModule } from './domain/database/DatabaseModule'; +import { InMemoryPersistenceModule } from './domain/persistence/InMemoryPersistenceModule'; import { DriverModule } from './domain/driver/DriverModule'; import { HelloModule } from './domain/hello/HelloModule'; import { LeagueModule } from './domain/league/LeagueModule'; @@ -29,6 +30,7 @@ const ENABLE_BOOTSTRAP = getEnableBootstrap(); imports: [ HelloModule, ...(USE_DATABASE ? [DatabaseModule] : []), + ...(!USE_DATABASE ? [InMemoryPersistenceModule] : []), LoggingModule, ...(ENABLE_BOOTSTRAP ? [BootstrapModule] : []), AnalyticsModule, diff --git a/apps/api/src/domain/bootstrap/BootstrapModule.ts b/apps/api/src/domain/bootstrap/BootstrapModule.ts index 9470ee711..b9bd86877 100644 --- a/apps/api/src/domain/bootstrap/BootstrapModule.ts +++ b/apps/api/src/domain/bootstrap/BootstrapModule.ts @@ -1,6 +1,9 @@ +import type { Logger } from '@core/shared/application'; 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 { ModuleRef } from '@nestjs/core'; +import { getApiPersistence } from '../../env'; import { BootstrapProviders } from './BootstrapProviders'; @Module({ @@ -9,7 +12,7 @@ import { BootstrapProviders } from './BootstrapProviders'; export class BootstrapModule implements OnModuleInit { constructor( private readonly ensureInitialData: EnsureInitialData, - private readonly seedInMemoryRacingData: SeedInMemoryRacingData, + private readonly moduleRef: ModuleRef, ) {} async onModuleInit() { @@ -17,8 +20,15 @@ export class BootstrapModule implements OnModuleInit { try { await this.ensureInitialData.execute(); - if (this.shouldSeedInMemory()) { - await this.seedInMemoryRacingData.execute(); + if (this.shouldSeedRacingData()) { + const logger = this.tryGet('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'); @@ -28,12 +38,65 @@ export class BootstrapModule implements OnModuleInit { } } - private shouldSeedInMemory(): boolean { - const configured = (process.env.GRIDPILOT_API_PERSISTENCE ?? '').toLowerCase(); - if (configured) { - return configured === 'inmemory'; + private shouldSeedRacingData(): boolean { + return getApiPersistence() === 'inmemory'; + } + + private tryGet(token: string): T | undefined { + try { + return this.moduleRef.get(token, { strict: false }); + } catch { + return undefined; + } + } + + private tryGetSeedDeps(): RacingSeedDependencies | undefined { + const driverRepository = this.tryGet('IDriverRepository'); + const leagueRepository = this.tryGet('ILeagueRepository'); + const raceRepository = this.tryGet('IRaceRepository'); + const resultRepository = this.tryGet('IResultRepository'); + const standingRepository = this.tryGet('IStandingRepository'); + const leagueMembershipRepository = this.tryGet( + 'ILeagueMembershipRepository', + ); + const raceRegistrationRepository = this.tryGet( + 'IRaceRegistrationRepository', + ); + const teamRepository = this.tryGet('ITeamRepository'); + const teamMembershipRepository = this.tryGet( + 'ITeamMembershipRepository', + ); + const feedRepository = this.tryGet('IFeedRepository'); + const socialGraphRepository = this.tryGet('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, + }; } } \ No newline at end of file diff --git a/apps/api/src/domain/bootstrap/BootstrapProviders.ts b/apps/api/src/domain/bootstrap/BootstrapProviders.ts index d8a2969bb..8eb322d14 100644 --- a/apps/api/src/domain/bootstrap/BootstrapProviders.ts +++ b/apps/api/src/domain/bootstrap/BootstrapProviders.ts @@ -1,6 +1,5 @@ import { Provider } from '@nestjs/common'; 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 { CreateAchievementUseCase, @@ -97,51 +96,4 @@ export const BootstrapProviders: Provider[] = [ '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', - ], - }, ]; \ No newline at end of file