Reputation: 41
After hours of digging, I need your help !
The context
I'm currently creating(early stage) an application with the stack : Nx(monorepo) + NestJS + TypeOrm
Here is my ormconfig file :
"type": "postgres",
"host": "localhost",
"port": 5432,
"username": "***",
"password": "****",
"database": "****",
"synchronize": false,
"logging":false,
"entities": ["apps/api/src/app/**/**.entity.ts"],
"migrations":["apps/api/src/migration/**.ts"],
"cli":{
"migrationsDir":["apps/api/src/migration"],
"entitiesDir":["apps/api/src/app/**/**.entity.ts"]
}
}
Here is my migration file :
import {MigrationInterface, QueryRunner, Table} from "typeorm";
export class users1573343025001 implements MigrationInterface {
public async up (queryRunner: QueryRunner): Promise<any> {
await queryRunner.createTable(new Table({
name: 'users',
columns: [
{ name: 'id', type: 'bigint', isPrimary: true,
isGenerated: true, generationStrategy: 'increment', unsigned: true },
{ name: 'username', type: 'varchar', isNullable: false },
{ name: 'password', type: 'varchar', isNullable: true },
]
}))
}
public async down (queryRunner: QueryRunner): Promise<any> {
await queryRunner.dropTable('users')
}
}
The problem
When I run the command ng serve api to run my backend, I face this issue :
SyntaxError: Unexpected token {...
The error comes from my migration file : apps\api\src\migration\1573343025001-users.ts:1
What bugs me
If I run my migration with typeorm command, typeorm is able to run it without any trouble. Migration users1573343025001 has been executed successfully! So I don't understand why the migration file looks correct to my app during the migration but during the run.
What I have already tried
"typeorm": "ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js",
to perform in typescriptI'm probably missing a basic thing with this technologies that are new to me. Hope all this is clear enough for you to understand the situation.
Thank You,
Séb
Upvotes: 4
Views: 5004
Reputation: 428
Likely the OP has found a solution. This is for others who came across this issue.
Look at https://github.com/nestjs/typeorm/issues/150#issuecomment-510716686 and the next comment for a solution to the problem.
You can't load
.ts
files after transpilation process. Either change path passed to entities based on the environment or put entities directly to this array.
I did not want to have to update the entities array each time a new entity is created, so I chose to update the file glob pattern.
The meat of the solution:
/* replaced original two lines */
// entities: ['**/*.entity{.ts,.js}'],
// migrations: ['src/migration/*.ts'],
/* with these two lines */
entities: [path.join(__dirname, '../**/*.entity{.ts,.js}')],
migrations: [path.join(__dirname, '../migration/*{.ts,.js')],
Now npm run start:dev
or npm run start:debug
does not throw errors.
Here's the full configuration.ts
and app.module.ts
// src/config/configuration.ts
import { TypeOrmModuleOptions } from '@nestjs/typeorm';
import path = require('path');
export default () => {
const customConfigService = new CustomConfigService(
process.env,
).ensureValues([
'DATABASE_HOST',
'DATABASE_PORT',
'DATABASE_USER',
'DATABASE_PASSWORD',
'DATABASE_NAME',
]);
return {
port: parseInt(process.env.PORT, 10) || 4000,
database: {
host: process.env.DATABASE_HOST,
port: parseInt(process.env.DATABASE_PORT, 10) || 5432,
},
typeOrmModuleOptions: customConfigService.getTypeOrmConfig(),
};
};
// see https://medium.com/@gausmann.simon/nestjs-typeorm-and-postgresql-full-example-development-and-project-setup-working-with-database-c1a2b1b11b8f
class CustomConfigService {
constructor(private env: { [k: string]: string | undefined }) {}
private getValue(key: string, throwOnMissing = true): string {
const value = this.env[key];
if ((value === null || value === undefined) && throwOnMissing) {
throw new Error(`config error - missing env.${key}`);
}
return value;
}
public ensureValues(keys: string[]) {
keys.forEach(k => this.getValue(k, true));
return this;
}
public getPort() {
return this.getValue('PORT', true);
}
public isProduction() {
const mode = this.getValue('NODE_ENV', false);
return mode === 'production';
}
public getTypeOrmConfig(): TypeOrmModuleOptions {
return {
type: 'postgres',
host: this.getValue('DATABASE_HOST'),
port: parseInt(this.getValue('DATABASE_PORT')),
username: this.getValue('DATABASE_USER'),
password: this.getValue('DATABASE_PASSWORD'),
database: this.getValue('DATABASE_NAME'),
/* replaced original two lines */
// entities: ['**/*.entity{.ts,.js}'],
// migrations: ['src/migration/*.ts'],
/* with these two lines */
entities: [path.join(__dirname, '../**/*.entity{.ts,.js}')],
migrations: [path.join(__dirname, '../migration/*{.ts,.js')],
migrationsTableName: 'migration',
cli: {
migrationsDir: 'src/migration',
},
ssl: this.isProduction(),
};
}
}
// src/app.module.ts
// lib imports
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { TypeOrmModule, TypeOrmModuleOptions } from '@nestjs/typeorm';
// local imports
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ItemsModule } from './items/items.module';
import configuration from './config/configuration';
const envFilePath =
process.env.NODE_ENV === 'production'
? 'envs/.production.env'
: 'envs/.development.env';
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
envFilePath,
load: [configuration],
}),
// see https://stackoverflow.com/questions/53426486/best-practice-to-use-config-service-in-nestjs-module
// see https://github.com/nestjs/nest/issues/530#issuecomment-415690676
TypeOrmModule.forRootAsync({
imports: [ConfigModule],
useFactory: async (configService: ConfigService) => {
const typeOrmModuleOptions = configService.get<TypeOrmModuleOptions>(
'typeOrmModuleOptions',
);
console.log(`typeOrmModuleOptions= `, typeOrmModuleOptions);
return typeOrmModuleOptions;
},
inject: [ConfigService],
}),
ItemsModule,
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
Upvotes: 4