#Issue when trying to create async Mongoose connection in dynamic module

9 messages · Page 1 of 1 (latest)

ebon rose
#

I was using a plain mongo client in my event sourcing library beforehand and am adding support for schema validation to it using mongoose. Been scouring online as well as looking in the common errors page which seems to have a template that directly fits this error, except it's not being very specific as to where the problem is exactly.

I have been struggling to get the hang of the dependency injection for async dependencies.

Error: Nest can't resolve dependencies of the MongooseCoreModule (MongooseConnectionName, ?). Please make sure that the argument ModuleRef at index [1] is available in the MongooseCoreModule context.

I've stripped down everything to essentially the bare minimum basics to try and debug it. Here is my AppModule:

@Module({
    imports: [
        ConfigModule.forRoot({ isGlobal: true, envFilePath: '.env' }),
        EventSourcingModule.registerAsync({
            imports: [ConfigModule],
            inject: [ConfigService],
            useFactory: async (configService: ConfigService): Promise<any> => {
                return {
                    eventStoreConfig: {
                        uri: configService.get('EVENT_STORE_MONGO_URI'),
                        dbName: configService.get('EVENT_MONGO_DB_NAME'),
                        token: 'test-eventstore-token',
                    },
                };
            },
        }),
    ],
})
export class AppModule {
}

And here is my event sourcing module:

@Global()
@Module({})
export class EventSourcingModule {
  static registerAsync(
    config: {
      imports: Array<Type<any> | ForwardReference | DynamicModule>;
      useFactory: (...args: any[]) => Promise<EventSourcingModuleConfig> | EventSourcingModuleConfig;
      inject?: any[];
    },
    eventStoreToken: string = undefined
  ): DynamicModule {
    return {
      module: EventSourcingModule,
      imports: [
        ...config.imports,
        MongooseModule.forRootAsync({
          connectionName: `${eventStoreToken}eventstoreCounterConnection`,
          useFactory: async (eventSourcingConfig: EventSourcingModuleConfig) => {
            return {
              uri: eventSourcingConfig.eventStoreConfig.uri,
              dbName: eventSourcingConfig.eventStoreConfig.dbName,
            }
          },
          inject: ['EVENT_SOURCING_MODULE_OPTIONS'],
        }),
        MongooseModule.forFeatureAsync(
          [{
            name: 'counter',
            useFactory: (): any => new mongoose.Schema({ _id: String, sequence_value: Number }, { collection: 'eventstore' }),
            collection: 'eventstore',
          }], 
        `${eventStoreToken}eventstoreCounterConnection`
        ),
      ],
      providers: [
        {
          provide: 'EVENT_SOURCING_MODULE_OPTIONS',
          useFactory: config.useFactory,
          inject: config.inject,
        },
        {
          provide: 'ENVIRONMENT_NAME',
          useFactory: (config: EventSourcingModuleConfig) => {
            return config && config.environmentName ? config.environmentName : '';
          },
          inject: ['EVENT_SOURCING_MODULE_OPTIONS'],
        },
        ...this.createProvidersAsync(eventStoreToken),
        ConfigService,
      ],
      exports: [
        ...this.createExportsAsync(eventStoreToken),
      ],
    };
  }

  private static createProvidersAsync(eventStoreToken: string) {
    const providers = [];

    providers.push({
      provide: eventStoreToken ?? MongoEventStore,
      useFactory: async (
        config: EventSourcingModuleConfig,
        connection: mongoose.Connection,
        counterModel: Model<any>
      ) => {
        if (config && config.eventStoreConfig)
          return new MongoEventStore(connection, counterModel);
        return null;
      },
      inject: ['EVENT_SOURCING_MODULE_OPTIONS', getConnectionToken()],
    });

    return providers;
  }

  private static createExportsAsync(eventStoreToken: string) {
    return [eventStoreToken ?? MongoEventStore];
  }
}
ebon rose
#

An update to this post, I have gotten it completely working without a library. If I copy paste the library code into the service I am using, it works fine. The moment I extract the exact same module into a library and export it, it gives the same error specified above.

dim solstice
#

Do you have @nestjs/core installed as a devDependency in your library ?

#

ModuleRef is imported from there. Maybe that's why the injection failed for that dependency

#

@ebon rose

ebon rose
#

It's a peer dependency. Would that cause an issue when including the library locally for development?

#

Yeah including it as a dev dependency doesn't help fix it. It only happens when developing locally. There seem to be some other people commenting on this behavior in the issues as well: https://github.com/nestjs/nest/issues/11595#issuecomment-2133778412

GitHub

Is there an existing issue for this? I have searched the existing issues Current behavior Throwing error woth mongoose [Nest] 10469 - 05/04/2023, 2:05:32 PM ERROR [ExceptionHandler] Nest can't ...

#

I can copy paste my module into my service and it works fine. I can publish my library to NPM and include it from there and it works fine. But if I use npm link to include my local version of the library to develop it, then it doesn't work.

dim solstice
#

Okay, Have you considered bumping @nestjs/common and @nestjs/core from 9.0.0 to something like 9.3 ? Maybe that's a bug in the core modules ?