#Can't use dynamic provider in same Module it is declared in

20 messages · Page 1 of 1 (latest)

tropic dock
#

I have this Module.
It allows the creation of a Databaseconnection. And takes a provider factory to create a options object (I think this is needed to use ConfigModule, at least I did not find any other examples on how to achieve this)

I need to close the database connection once the Module is unloaded.

Sidequestion, is it guaranteed that the factory to create a driver will only be called once ? Or is it possible that the IoC Container discards the cached instance of that provider at some point and creates a new one if a new one is requested ?

export class Neo4jConnectionModule implements OnModuleDestroy {
  protected static driver: Driver

  static async forRootAsync({
    useFactory,
    inject,
    imports,
  }: {
    useFactory: (
      ...args: any[]
    ) => Neo4jConnectionModuleOptions | Promise<Neo4jConnectionModuleOptions>
    inject: Array<InjectionToken | OptionalFactoryDependency>
    imports: Array<any>
  }): Promise<DynamicModule> {
    return {
      module: Neo4jConnectionModule,
      imports,
      providers: [
        {
          provide: NEO4J_SESSION_STATE,
          useClass: Neo4jSessionState,
          scope: Scope.TRANSIENT,
        },
        {
          provide: NEO4J_OPTIONS,
          useFactory,
          inject,
        },
        {
          provide: NEO4J_DRIVER,                                            // Provides NEO4J_DRIVER
          useFactory: async (options: Neo4jConnectionModuleOptions) => {
            return await driverFactory(options)
          },
          inject: [NEO4J_OPTIONS],
        },
      ],
      exports: [NEO4J_OPTIONS, NEO4J_DRIVER],
    }
  }

  constructor(@Inject(NEO4J_DRIVER) private readonly driver: Driver) {}.   // Can't find NEO4J_DRIVER

  async onModuleDestroy() {
    await this.driver.close()
    Neo4jConnectionLogger.log('Disconnected')
  }
}

But Nest can't resolve the NEO4J_DRIVER in the constructor

I guess I am missing something obvious ^^

snow helm
#

Do you have this imported anywhere with just Neo4jConnectionModule or do you only have it as Neo4jConnectionModule.forRootAsync() everywhere you use it?

tropic dock
dense cipher
#

Does the wrapper re-export the configured dynamic module?

tropic dock
#

yes it does

#

not the configured one but the Neo4jConnectionModule

#
@Module({
  imports: [
    ConfigModule,
    Neo4jConnectionModule.forRootAsync({
      imports: [ConfigModule],
      useFactory: (configService: ConfigService) => {
        return {
          url: configService.get('NEO4J_URL'),
          authToken: auth.basic(
            configService.get('NEO4J_USER'),
            configService.get('NEO4J_PASSWORD'),
          ),
        }
      },
      inject: [ConfigService],
    }),
  ],
  exports: [Neo4jConnectionModule],
})
export class Neo4jModule {}
#

wait, shouldn't i export the dynamic providers in this module ?

dense cipher
#

This look correct. Btw if you only need to inject the NEO4J_DRIVER within the providing module, you don't need to expott it.

#

I don't see what is wrong, can you provide more context? And maybe the full error message

tropic dock
#
Error: Nest can't resolve dependencies of the Neo4jConnectionModule (?). Please make sure that the argument Symbol(NEO4J_DRIVER) at index [0] is available in the Neo4jConnectionModule context.

Potential solutions:
- Is Neo4jConnectionModule a valid NestJS module?
- If Symbol(NEO4J_DRIVER) is a provider, is it part of the current Neo4jConnectionModule?
- If Symbol(NEO4J_DRIVER) is exported from a separate @Module, is that module imported within Neo4jConnectionModule?
  @Module({
    imports: [ /* the Module containing Symbol(NEO4J_DRIVER) */ ]
  })

    at Injector.lookupComponentInParentModules (/Users/lukas/Arbeit/recograph/node_modules/@nestjs/core/injector/injector.js:254:19)
    at processTicksAndRejections (node:internal/process/task_queues:95:5)
    at Injector.resolveComponentInstance (/Users/lukas/Arbeit/recograph/node_modules/@nestjs/core/injector/injector.js:207:33)
    at resolveParam (/Users/lukas/Arbeit/recograph/node_modules/@nestjs/core/injector/injector.js:128:38)
    at async Promise.all (index 0)
    at Injector.resolveConstructorParams (/Users/lukas/Arbeit/recograph/node_modules/@nestjs/core/injector/injector.js:143:27)
    at Injector.loadInstance (/Users/lukas/Arbeit/recograph/node_modules/@nestjs/core/injector/injector.js:70:13)
    at Injector.loadProvider (/Users/lukas/Arbeit/recograph/node_modules/@nestjs/core/injector/injector.js:97:9)
    at /Users/lukas/Arbeit/recograph/node_modules/@nestjs/core/injector/instance-loader.js:56:13
    at async Promise.all (index 0)
#

I tried exporting the providers in the wrapper, but that does not work. Because they are not defined in the wrapper. Makes sense.
But why am I exporting the ConnectionModule, does that export export the providers coming from the forRootAsync ?

dense cipher
snow helm
#

Absolutely certain that youdon't accidentally have Neo4JConnectionModule in an imports array somewhere?

tropic dock
#

I think that was the problem, now it's something else that is missing :)
let me fix that real quick

#

what was the problem with having it imported twice ?
something cyclic ?

tropic dock
snow helm
#

If you only imported the Neo4jConnectionModule, without the .forRootAsync() Nest will try to create the instance of the Neo4jConnectionModule class, which you've declared as having a dependencyon NEO4J_DRIVER, but that provider doesn't exist in the Neo4jConnectionModule class alone, it exists on the dynamic module returned by Neo4jConnectionModule.forRootAsync()

tropic dock
#

ahhh ofc makes total sense
yea not sure if this is possible but if the error included the module that nest tried to create the instance for that would have made it obvious

#

maybe it is in the debug lines but I am having a hard time understanding them quite right :D