[ ] Regression
[ ] Bug report
[ ] Feature request
[X] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.
I have a custom DB module to initialize TypeOrm (= Nestjs's TypeOrmModule). I want to pass an TypeormLoggerService (which relies on an app-wide LoggerService). This is the code:
db.module.ts:
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { TypeormLoggerService } from './typeorm-logger.service';
@Module({
controllers: [],
providers: [],
imports: [
TypeOrmModule.forRootAsync({
inject: [TypeormLoggerService],
useFactory: async (typeormLoggerService: TypeormLoggerService): Promise<any> => ({
type: 'sqlite',
database: `var/nest.db`,
entities: [`src/**/**.entity{.ts,.js}`],
logger: typeormLoggerService,
logging: true
}),
})
]
})
export class DbModule {}
Node crashes with the following error:
1: node::Abort() [/usr/local/bin/node]
2: node::Chdir(v8::FunctionCallbackInfo<v8::Value> const&) [/usr/local/bin/node]
3: v8::internal::FunctionCallbackArguments::Call(void (*)(v8::FunctionCallbackInfo<v8::Value> const&)) [/usr/local/bin/node]
4: v8::internal::MaybeHandle<v8::internal::Object> v8::internal::(anonymous namespace)::HandleApiCallHelper<false>(v8::internal::Isolate*, v8::internal::Handle<v8::internal::HeapObject>, v8::internal::Handle<v8::internal::HeapObject>, v8::internal::Handle<v8::internal::FunctionTemplateInfo>, v8::internal::Handle<v8::internal::Object>, v8::internal::BuiltinArguments) [/usr/local/bin/node]
5: v8::internal::Builtin_Impl_HandleApiCall(v8::internal::BuiltinArguments, v8::internal::Isolate*) [/usr/local/bin/node]
6: 0x1776425042fd
nest/typeorm version: 5.2.2
nest/common version: 5.3.5
nest/core version: 5.3.4
Are you sure that this is a full node output? Also, where is your TypeormLoggerService
registered?
We need your full logs.
Are you sure that this is a full node output? Also, where is your
TypeormLoggerService
registered?
regarding Logs)
Yes, this is the full output. No more messages, besides that:
[nodemon] app crashed - waiting for file changes before starting...
[nodemon] restarting due to changes...
[nodemon] starting `ts-node -r tsconfig-paths/register src/main.ts`
(after reload crashes again and so on)
regarding registration)
TypeormLoggerService is part of the same module (DbModule). I've added it now also to "providers" of the DbModule and to "inject" of TypeOrmModule.forRootAsync(), but nothing changed.
This is the TypeormLoggerService (if needed):
import { Injectable } from '@nestjs/common';
import { Logger, QueryRunner } from 'typeorm';
import { LogService } from 'common/misc/log.service';
@Injectable()
export class TypeormLoggerService implements Logger {
constructor(
private logService: LogService
) {}
public logQuery(query: string, parameters?: any[], queryRunner?: QueryRunner) {
this.logService.trace(query, parameters, queryRunner);
}
public logQueryError(error: string, query: string, parameters?: any[], queryRunner?: QueryRunner) {
this.logService.error(query, parameters, queryRunner);
}
public logQuerySlow(time: number, query: string, parameters?: any[], queryRunner?: QueryRunner) {
this.logService.warn(`Slow query took ${time} ms: %o %o %o`, query, parameters, queryRunner);
}
public logSchemaBuild(message: string, queryRunner?: QueryRunner) {
this.logService.info(message, queryRunner);
}
public logMigration(message: string, queryRunner?: QueryRunner) {
this.logService.info(message, queryRunner);
}
public log(level: 'log' | 'info' | 'warn', message: any, queryRunner?: QueryRunner) {
switch (level) {
case 'log': this.logService.info(message, queryRunner); break;
case 'info': this.logService.info(message, queryRunner); break;
case 'warn': this.logService.warn(message, queryRunner); break;
}
}
}
We need a reproduction repository
Repository is here:
https://github.com/cvh23/nestjs-typeorm-logger/tree/master/src/common
Now with the minimal example I get a little better log output. Looks like typeormLogService
cant be resolved in src/common/db/db.module.ts
. What could be the reason?
[Nest] 80989 - 2018-11-20 18:22:08 [NestFactory] Starting Nest application...
[Nest] 80989 - 2018-11-20 18:22:08 [InstanceLoader] AppModule dependencies initialized +23ms
[Nest] 80989 - 2018-11-20 18:22:08 [InstanceLoader] CommonModule dependencies initialized +0ms
[Nest] 80989 - 2018-11-20 18:22:08 [InstanceLoader] MiscModule dependencies initialized +1ms
[Nest] 80989 - 2018-11-20 18:22:08 [InstanceLoader] TypeOrmModule dependencies initialized +0ms
[Nest] 80989 - 2018-11-20 18:22:08 [ExceptionHandler] Nest can't resolve dependencies of the TypeOrmModuleOptions (?). Please make sure that the argument at index [0] is available in the current context. +20ms
Error: Nest can't resolve dependencies of the TypeOrmModuleOptions (?). Please make sure that the argument at index [0] is available in the current context.
at Injector.lookupComponentInExports (/home/cvh23/nestjs-typeorm-logger/node_modules/@nestjs/core/injector/injector.js:146:19)
at <anonymous>
at process._tickDomainCallback (internal/process/next_tick.js:228:7)
at Function.Module.runMain (module.js:695:11)
at Object.<anonymous> (/home/cvh23/nestjs-typeorm-logger/node_modules/ts-node/src/_bin.ts:177:12)
at Module._compile (module.js:652:30)
at Object.Module._extensions..js (module.js:663:10)
at Module.load (module.js:565:32)
at tryModuleLoad (module.js:505:12)
at Function.Module._load (module.js:497:3)
1: node::Abort() [/usr/local/bin/node]
2: node::Chdir(v8::FunctionCallbackInfo<v8::Value> const&) [/usr/local/bin/node]
3: v8::internal::FunctionCallbackArguments::Call(void (*)(v8::FunctionCallbackInfo<v8::Value> const&)) [/usr/local/bin/node]
4: v8::internal::MaybeHandle<v8::internal::Object> v8::internal::(anonymous namespace)::HandleApiCallHelper<false>(v8::internal::Isolate*, v8::internal::Handle<v8::internal::HeapObject>, v8::internal::Handle<v8::internal::HeapObject>, v8::internal::Handle<v8::internal::FunctionTemplateInfo>, v8::internal::Handle<v8::internal::Object>, v8::internal::BuiltinArguments) [/usr/local/bin/node]
5: v8::internal::Builtin_Impl_HandleApiCall(v8::internal::BuiltinArguments, v8::internal::Isolate*) [/usr/local/bin/node]
6: 0x28e724f042fd
[nodemon] app crashed - waiting for file changes before starting...
That is exactly what I was asking about, TypeormLoggerService
is not present in this scope
But isnt the inject
providing the service to the scope?
TypeOrmModule.forRootAsync({
inject: [TypeormLoggerService],
useFactory: ...
I ran into a similar problem with nestjs/terminus which is built similar as nestjs/typeorm
What fixed it for me is to use @Inject
in combination with useClass
(terminus example).
import { Module } from '@nestjs/common';
import { TypeOrmModule, TypeOrmOptionsFactory } from '@nestjs/typeorm';
import { TypeormLoggerService } from './typeorm-logger.service';
class TypeOrmOptions implements TypeOrmOptionsFactory {
constructor(@Inject(TypeormLoggerService) private readonly typeormLoggerService: TypeormLoggerService){}
createTypeOrmOptions(): TypeOrmModuleOptions {
return {
type: 'sqlite',
database: `var/nest.db`,
entities: [`src/**/**.entity{.ts,.js}`],
logger: this.typeormLoggerService,
logging: true
};
}
}
@Module({
controllers: [],
providers: [],
imports: [
TypeOrmModule.forRootAsync({
inject: [TypeormLoggerService],
useClass: TypeOrmOptions,
})
]
})
export class DbModule {}
Can you try this out? @cvh23
Is this the recommended way? @kamilmysliwiec
@BrunnerLivio @Inject()
definitely shouldn't be required in this case.
But isnt the inject providing the service to the scope?
Actually, no. It works in the same way as a typical custom provider, therefore TypeormLoggerService
has to be defined as providers somewhere, for example, in the imported module (that is why you have imports
array in forRootAsync()
). Perhaps, we should think about extraProviders
property that would define and make provider available in the async scope.
@BrunnerLivio Same error, now in TypeOrmOption.
[Nest] 82715 - 2018-11-20 23:49:38 [ExceptionHandler] Nest can't resolve dependencies of the TypeOrmOptions (?). Please make sure that the argument at index [0] is available in the current context. +15ms
Error: Nest can't resolve dependencies of the TypeOrmOptions (?). Please make sure that the argument at index [0] is available in the current context.
at Injector.lookupComponentInExports (/home/cvh23/nestjs-typeorm-logger/node_modules/@nestjs/core/injector/injector.js:146:19)
at <anonymous>
at process._tickDomainCallback (internal/process/next_tick.js:228:7)
at Function.Module.runMain (module.js:695:11)
at Object.<anonymous> (/home/cvh23/nestjs-typeorm-logger/node_modules/ts-node/src/_bin.ts:177:12)
at Module._compile (module.js:652:30)
at Object.Module._extensions..js (module.js:663:10)
at Module.load (module.js:565:32)
at tryModuleLoad (module.js:505:12)
at Function.Module._load (module.js:497:3)
1: node::Abort() [/usr/local/bin/node]
@kamilmysliwiec
TypeormLoggerService
is in the same module and it is declared in providers
of the module definition.
TypeormLoggerService is in the same module and it is declared in providers of the module definition.
forRootAsync()
creates a separated scope - it is actually extending TypeOrmModule
with extra options which means that registering TypeormLoggerService
in DbModule
wouldn't be enough
So there is no possibility to achieve that at the moment?
I got it working with imports
, but I really do not know if this is intended behavior...
import { Module, Inject } from '@nestjs/common';
import { TypeOrmModule, TypeOrmOptionsFactory, TypeOrmModuleOptions } from '@nestjs/typeorm';
import { TypeormLoggerService } from './typeorm-logger.service';
class TypeOrmOptions implements TypeOrmOptionsFactory {
// If this @Inject gets removed, logger will be undefined (???)
constructor(@Inject(TypeormLoggerService) private readonly logger: TypeormLoggerService){}
createTypeOrmOptions(): TypeOrmModuleOptions {
this.logger.log('log', 'asdf'); // prints: asdf
return {
type: 'sqlite',
database: `var/nest.db`,
entities: [`src/**/**.entity{.ts,.js}`],
logger: this.logger,
logging: true,
};
}
}
@Module({
providers: [TypeormLoggerService],
exports: [TypeormLoggerService],
imports: [
TypeOrmModule.forRootAsync({
// Thats the silver bullet
// But I recommend to create a separate module, instead of this strange
// circular importing. Why is this even possible?
imports: [DbModule],
useClass: TypeOrmOptions,
}),
],
})
export class DbModule { }
Funnily enough, if you remove @Inject()
in the constructor of TypeOrmOptions, then logger is undefined
. I think I am performing some dark magic..
TypeOrmModule.forRootAsync({
inject: [TypeormLoggerService],
useFactory: ...,
})
You are trying to inject TypeormLoggerService
which is unavailable in the TypeOrmModule
. In order to provide it, you would have to import a module that exports TypeormLoggerService
, for example:
TypeOrmModule.forRootAsync({
imports: [TypeOrmLoggerModule], <------ THIS
inject: [TypeormLoggerService],
useFactory: ...,
})
I had to export TypeormLoggerService from DbModule and import it in TypeOrmModule although TypeOrmModule is included in the Module of TypeormLoggerService (DbModule). That was a bit confusing. But now I understand and it's working. Thanks a lot!
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Most helpful comment
You are trying to inject
TypeormLoggerService
which is unavailable in theTypeOrmModule
. In order to provide it, you would have to import a module that exportsTypeormLoggerService
, for example: