fix seeds
This commit is contained in:
@@ -1,18 +1,21 @@
|
||||
import type { Logger } from '@core/shared/application';
|
||||
import { EnsureInitialData } from '../../../../../adapters/bootstrap/EnsureInitialData';
|
||||
import type { EnsureInitialData } from '../../../../../adapters/bootstrap/EnsureInitialData';
|
||||
import { SeedRacingData, type RacingSeedDependencies } from '../../../../../adapters/bootstrap/SeedRacingData';
|
||||
import { Module, OnModuleInit } from '@nestjs/common';
|
||||
import { ModuleRef } from '@nestjs/core';
|
||||
import { Inject, Module, OnModuleInit } from '@nestjs/common';
|
||||
import { getApiPersistence } from '../../env';
|
||||
import { BootstrapProviders } from './BootstrapProviders';
|
||||
import { InMemoryRacingPersistenceModule } from '../../persistence/inmemory/InMemoryRacingPersistenceModule';
|
||||
import { InMemorySocialPersistenceModule } from '../../persistence/inmemory/InMemorySocialPersistenceModule';
|
||||
import { BootstrapProviders, ENSURE_INITIAL_DATA_TOKEN } from './BootstrapProviders';
|
||||
|
||||
@Module({
|
||||
imports: [InMemoryRacingPersistenceModule, InMemorySocialPersistenceModule],
|
||||
providers: BootstrapProviders,
|
||||
})
|
||||
export class BootstrapModule implements OnModuleInit {
|
||||
constructor(
|
||||
private readonly ensureInitialData: EnsureInitialData,
|
||||
private readonly moduleRef: ModuleRef,
|
||||
@Inject(ENSURE_INITIAL_DATA_TOKEN) private readonly ensureInitialData: EnsureInitialData,
|
||||
@Inject('Logger') private readonly logger: Logger,
|
||||
@Inject('RacingSeedDependencies') private readonly seedDeps: RacingSeedDependencies,
|
||||
) {}
|
||||
|
||||
async onModuleInit() {
|
||||
@@ -21,14 +24,7 @@ export class BootstrapModule implements OnModuleInit {
|
||||
await this.ensureInitialData.execute();
|
||||
|
||||
if (this.shouldSeedRacingData()) {
|
||||
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();
|
||||
}
|
||||
await new SeedRacingData(this.logger, this.seedDeps).execute();
|
||||
}
|
||||
|
||||
console.log('[Bootstrap] Application data initialized successfully');
|
||||
@@ -41,62 +37,4 @@ export class BootstrapModule implements OnModuleInit {
|
||||
private shouldSeedRacingData(): boolean {
|
||||
return getApiPersistence() === '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 {
|
||||
driverRepository,
|
||||
leagueRepository,
|
||||
raceRepository,
|
||||
resultRepository,
|
||||
standingRepository,
|
||||
leagueMembershipRepository,
|
||||
raceRegistrationRepository,
|
||||
teamRepository,
|
||||
teamMembershipRepository,
|
||||
feedRepository,
|
||||
socialGraphRepository,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Provider } from '@nestjs/common';
|
||||
import { EnsureInitialData } from '../../../../../adapters/bootstrap/EnsureInitialData';
|
||||
import type { RacingSeedDependencies } from '../../../../../adapters/bootstrap/SeedRacingData';
|
||||
import { SignupWithEmailUseCase, type SignupWithEmailResult } from '@core/identity/application/use-cases/SignupWithEmailUseCase';
|
||||
import {
|
||||
CreateAchievementUseCase,
|
||||
@@ -21,6 +22,9 @@ export const IDENTITY_SESSION_PORT_TOKEN = 'IdentitySessionPort_Bootstrap';
|
||||
export const SIGNUP_USE_CASE_TOKEN = 'SignupWithEmailUseCase_Bootstrap';
|
||||
export const CREATE_ACHIEVEMENT_USE_CASE_TOKEN = 'CreateAchievementUseCase_Bootstrap';
|
||||
|
||||
export const RACING_SEED_DEPENDENCIES_TOKEN = 'RacingSeedDependencies';
|
||||
export const ENSURE_INITIAL_DATA_TOKEN = 'EnsureInitialData_Bootstrap';
|
||||
|
||||
// Adapter classes for output ports
|
||||
class SignupWithEmailOutputAdapter implements UseCaseOutputPort<SignupWithEmailResult> {
|
||||
present(result: SignupWithEmailResult): void {
|
||||
@@ -37,6 +41,47 @@ class CreateAchievementOutputAdapter implements UseCaseOutputPort<CreateAchievem
|
||||
}
|
||||
|
||||
export const BootstrapProviders: Provider[] = [
|
||||
{
|
||||
provide: RACING_SEED_DEPENDENCIES_TOKEN,
|
||||
useFactory: (
|
||||
driverRepository: RacingSeedDependencies['driverRepository'],
|
||||
leagueRepository: RacingSeedDependencies['leagueRepository'],
|
||||
raceRepository: RacingSeedDependencies['raceRepository'],
|
||||
resultRepository: RacingSeedDependencies['resultRepository'],
|
||||
standingRepository: RacingSeedDependencies['standingRepository'],
|
||||
leagueMembershipRepository: RacingSeedDependencies['leagueMembershipRepository'],
|
||||
raceRegistrationRepository: RacingSeedDependencies['raceRegistrationRepository'],
|
||||
teamRepository: RacingSeedDependencies['teamRepository'],
|
||||
teamMembershipRepository: RacingSeedDependencies['teamMembershipRepository'],
|
||||
feedRepository: RacingSeedDependencies['feedRepository'],
|
||||
socialGraphRepository: RacingSeedDependencies['socialGraphRepository'],
|
||||
): RacingSeedDependencies => ({
|
||||
driverRepository,
|
||||
leagueRepository,
|
||||
raceRepository,
|
||||
resultRepository,
|
||||
standingRepository,
|
||||
leagueMembershipRepository,
|
||||
raceRegistrationRepository,
|
||||
teamRepository,
|
||||
teamMembershipRepository,
|
||||
feedRepository,
|
||||
socialGraphRepository,
|
||||
}),
|
||||
inject: [
|
||||
'IDriverRepository',
|
||||
'ILeagueRepository',
|
||||
'IRaceRepository',
|
||||
'IResultRepository',
|
||||
'IStandingRepository',
|
||||
'ILeagueMembershipRepository',
|
||||
'IRaceRegistrationRepository',
|
||||
'ITeamRepository',
|
||||
'ITeamMembershipRepository',
|
||||
'IFeedRepository',
|
||||
'ISocialGraphRepository',
|
||||
],
|
||||
},
|
||||
{
|
||||
provide: USER_REPOSITORY_TOKEN,
|
||||
useFactory: (logger: Logger) => new InMemoryUserRepository(logger),
|
||||
@@ -82,7 +127,7 @@ export const BootstrapProviders: Provider[] = [
|
||||
inject: [ACHIEVEMENT_REPOSITORY_TOKEN, 'Logger'],
|
||||
},
|
||||
{
|
||||
provide: EnsureInitialData,
|
||||
provide: ENSURE_INITIAL_DATA_TOKEN,
|
||||
useFactory: (
|
||||
signupUseCase: SignupWithEmailUseCase,
|
||||
createAchievementUseCase: CreateAchievementUseCase,
|
||||
@@ -90,10 +135,6 @@ export const BootstrapProviders: Provider[] = [
|
||||
) => {
|
||||
return new EnsureInitialData(signupUseCase, createAchievementUseCase, logger);
|
||||
},
|
||||
inject: [
|
||||
SIGNUP_USE_CASE_TOKEN,
|
||||
CREATE_ACHIEVEMENT_USE_CASE_TOKEN,
|
||||
'Logger',
|
||||
],
|
||||
inject: [SIGNUP_USE_CASE_TOKEN, CREATE_ACHIEVEMENT_USE_CASE_TOKEN, 'Logger'],
|
||||
},
|
||||
];
|
||||
52
apps/api/src/domain/bootstrap/BootstrapSeed.http.test.ts
Normal file
52
apps/api/src/domain/bootstrap/BootstrapSeed.http.test.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import 'reflect-metadata';
|
||||
|
||||
import { Test } from '@nestjs/testing';
|
||||
import type { TestingModule } from '@nestjs/testing';
|
||||
import request from 'supertest';
|
||||
import { afterAll, beforeAll, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
describe('Bootstrap seeding (HTTP, inmemory)', () => {
|
||||
const originalEnv = { ...process.env };
|
||||
|
||||
let module: TestingModule | undefined;
|
||||
let app: any;
|
||||
|
||||
beforeAll(async () => {
|
||||
vi.resetModules();
|
||||
|
||||
process.env.GRIDPILOT_API_PERSISTENCE = 'inmemory';
|
||||
process.env.GRIDPILOT_API_BOOTSTRAP = 'true';
|
||||
delete process.env.DATABASE_URL;
|
||||
|
||||
const { AppModule } = await import('../../app.module');
|
||||
|
||||
module = await Test.createTestingModule({
|
||||
imports: [AppModule],
|
||||
}).compile();
|
||||
|
||||
app = module.createNestApplication();
|
||||
await app.init();
|
||||
}, 20_000);
|
||||
|
||||
afterAll(async () => {
|
||||
await app?.close();
|
||||
await module?.close();
|
||||
|
||||
process.env = originalEnv;
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it('exposes seeded leagues via HTTP (regression for repo instance mismatch)', async () => {
|
||||
const leaguesRes = await request(app.getHttpServer()).get('/leagues/total-leagues').expect(200);
|
||||
|
||||
expect(leaguesRes.body).toBeDefined();
|
||||
expect(typeof leaguesRes.body.totalLeagues).toBe('number');
|
||||
expect(leaguesRes.body.totalLeagues).toBeGreaterThan(0);
|
||||
|
||||
const racesRes = await request(app.getHttpServer()).get('/races/total-races').expect(200);
|
||||
|
||||
expect(racesRes.body).toBeDefined();
|
||||
expect(typeof racesRes.body.totalRaces).toBe('number');
|
||||
expect(racesRes.body.totalRaces).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user