I am trying to seed my database using NestJS and TypeORM.
I have a migration file that creates an exercise
table, and a seeding file that inserts an ExerciseEntity
into the table. The main difference between these files is that the migration file runs queries directly:
public async up(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(
`CREATE TABLE ...`
);
}
while the seeding file gets the repository:
public async up(queryRunner: QueryRunner): Promise<any> {
await queryRunner.manager.getRepository<ExerciseEntity>(ExerciseEntity).save(
someExerciseEntity
);
}
This getRepository
is the one creating the error.
RepositoryNotFoundError: No repository for "ExerciseEntity" was found. Looks like this entity is not registered in current "default" connection?
at new RepositoryNotFoundError (C:\Users\Dev\Documents\team-management\src\error\RepositoryNotFoundError.ts:10:9)
at EntityManager.getRepository (C:\Users\Dev\Documents\team-management\src\entity-manager\EntityManager.ts:1194:19)
at SeedExercises1584903747780.<anonymous> (C:\Users\Dev\Documents\team-management\dist\apps\api\_seeds\dev\webpack:\_seeds\dev\1584903747780-SeedExercises.ts:7:31)
In a service I get the repository and save entities without an issue. The problem only happens while seeding.
I register TypeORM as follows:
// app.module.ts
@Module({})
export class AppModule implements NestModule {
static forRoot(): DynamicModule {
return {
module: AppModule,
imports: [
ConfigModule.forRoot({
envFilePath: '.env.dev',
validationSchema: validationSchema()
}),
TypeOrmModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: async (configService: ConfigService) => databaseProviders(configService)
}),
ExercisesModule.forRoot()
]
};
}
}
where:
// database.provider.ts
export const databaseProviders = (configService: ConfigService) => {
const normalizePath = (_path: string) => (path.normalize(path.join(__dirname, _path)));
const commonDB: TypeOrmModuleOptions = {
type: 'sqlite',
entities: [...exercisesEntities]
};
// exerciseEntities comes from an index.ts in an exercise library
// import { ExerciseEntity } from './exercise.entity';
// export const exercisesEntities = [ExerciseEntity];
const defaultDB: TypeOrmModuleOptions = {
...commonDB,
database: path.join(
configService.get('APP_ROOT_PATH', '.'),
configService.get('TYPEORM_DATABASE', 'gym-dev.sqlite')
),
logging: configService.get<boolean>('TYPEORM_ENABLE_LOGGING', true) ? ['query', 'error'] : [],
cache: true,
synchronize: configService.get<boolean>('TYPEORM_SYNCHRONIZE', false),
migrations: [normalizePath('_migrations/*.js'), normalizePath('_seeds/dev/*.js')],
migrationsRun: configService.get<boolean>('TYPEORM_MIGRATIONS_RUN', true),
dropSchema: configService.get<boolean>('DROP_SCHEMA', false)
};
return defaultDB;
};
I am using nrwl/nx
for compiling and serving the application using the following webpack configuration:
module.exports = function(config, context) {
const baseDirectory = path.resolve(config.output.path);
const entityPaths = ['libs/feature/api/**/entities/*.js'];
const migrationPaths = ['_migrations/*.js', '_seeds/**/*.js'];
config.entry = {
...config.entry,
...getEntityEntries(entityPaths),
...getMigrationEntries(migrationPaths)
};
// getEntries functions allows the compilation of entities and migrations
// Output
config.output = {
path: baseDirectory,
filename: '[name].js',
libraryTarget: 'commonjs'
};
return config;
};
My dist
structure ends up being:
dist
|-apps
|-api
|-_migrations // contains compiled migrations
|-_seeds // contains compiled seeders
|-lib
|-entities // contains compiled entities
|-main.js
As seen in app.module.ts
I am using TypeOrmModule.forRootAsync
to be able to inject the config service. I am suspecting that maybe when the seeders are executed the repositories are not yet registered. That would explain that later, while running the web application, the service can access the repository.
Any idea how can I solve this?
Is my configuration wrong or missing something? Is there a way in the seeder to wait for the repositories to be registered, if that's the problem?
EDIT:
It doesn't have anything to do with TypeOrmModule.forRootAsync
. I did the following changes:
// app.module.ts
@Module({})
export class AppModule implements NestModule {
static forRoot(): DynamicModule {
return {
module: AppModule,
imports: [
ConfigModule.forRoot({
envFilePath: '.env.dev',
validationSchema: validationSchema()
}),
TypeOrmModule.forRoot(databaseProvidersSync()),
ExercisesModule.forRoot()
]
};
}
}
// database.providers.ts
export const databaseProvidersSync = () => {
const normalizePath = (_path: string) => (path.normalize(path.join(__dirname, _path)));
const defaultDB: TypeOrmModuleOptions = {
type: 'sqlite',
entities: [...exercisesEntities],
database: path.normalize(`C:\\Users\\Dev\\Documents\\team-management\\gym-dev.sqlite`),
logging: ['query', 'error'],
cache: true,
synchronize: false,
migrations: [normalizePath('_migrations/*.js'), normalizePath('_seeds/dev/*.js')],
migrationsRun: true,
dropSchema: true
}
return defaultDB;
}
And the error is the same.