Nest: Defer init of TypeORM import (async dynamic modules)

Created on 21 Jun 2018  路  11Comments  路  Source: nestjs/nest

I'm submitting a...


[ ] Regression 
[ ] Bug report
[ ] Feature request
[x] Documentation issue or request
[x] Support request => Please do not submit support request here, instead post your question on Stack Overflow.

I tried asking this question on StackOverflow, but it got ignored and now I don't think I'll get any answers. I hope that me posting here is ok.

Expected behavior


I would like to defer the initialization of the TypeORM connection with TypeOrmModul.forRoot() until an in-memory mongodb is started using mongo-unit. I could imagine something like async module imports, but they do not work, and I can't figure out if I can use async providers or what to do otherwise.

What I tried

  • using a promise in the import statement: imports: [Promise.resolve(TypeOrmModule.forRoot(...))]
  • making the AppModule dynamic:
    ts @Module({}) export class AppModule { static async withMongoUnit() { // this does not work, it's just an idea const dbUrl = new URL(await mongoUnit.start()); return { imports: [ TypeOrmModule.forRoot({ type: 'mongodb', host: dbUrl.host, port: dbUrl.port, database: 'test', entities: [__dirname + '/**/*.entity{.ts,.js}'], synchronize: true, }), ], }; } }

Minimal reproduction of the problem with instructions


Create a module that imports a TypeOrmModule. Try to delay the initialization until after a promise resolves (in my case mongoUnit.start()).

// app.test.module.ts

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import * as mongoUnit from 'mongo-unit';

@Module({})
export class AppModule {
  static async withMongoUnit() {  // this does not work, it's just an idea
    const dbUrl = new URL(await mongoUnit.start());
    return {
      imports: [
        TypeOrmModule.forRoot({
          type: 'mongodb',
          host: dbUrl.host,
          port: dbUrl.port,
          database: 'test',
          entities: [__dirname + '/**/*.entity{.ts,.js}'],
          synchronize: true,
        }),
      ],
    };
  }
}
// main.ts
...
async function bootstrap() {
  const app = await NestFactory.create(await AppModule.withMongoUnit());
  await app.listen(3000);
}

Environment


Nest version: 5.0.1
done 馃憦 type question 馃檶

Most helpful comment

Nest 5.1.0 is published already

All 11 comments

That's impossible. I'd suggest initializing Mongo before creating app instance.

Is there a technical reason why this doesn't work or is it simply currently not implemented?

@Y0hy0h modules are initialized in definition order, so if you're going to create an MongoModule where you will have an async provider, that will do your job to bring up mongo in memory, then you will be able to use it wherever you wanna.

So I could create a module that wraps TypeOrmModule and sets it up how I want, while having the same exports? (Basically, is there a way to replace TypeOrmModule with something, such that it's async but all its users don't have to change?)

I might have a closer look at how exactly async providers interact later. Maybe I missed something.

Thanks for your reply, @cojack!

@Y0hy0h I have some boilerplate for nest with some additional stuff that Im using to start working on new project every time and Im trying to improve it if I feel that it needs some additional polishing. You can take a look at https://github.com/neoteric-eu/nestjs-auth
But Im not using a TypeOrmModule package, just create my own DatabaseModule where I perform connection to the Mongo, so, if you will create an additional provider there lets assume it will be called MongoMemory and then you will use it as dependency for DB_CON_TOKEN provider it will wait till your mongo memory database will be available. But rather doing that, I will follow @kamilmysliwiec thoughts about how it should be initialised.

Please consider to exclude mongo bootstrap from code and place it in the script that will bring your environment up, fe: docker-compose, also in the repo I've made, there is available docker-compose.yml file for development purpose to work with postgresql (I'm RDBMS lover :heart:) Take a look!

Regards!

Thanks, @cojack, for your answer! I appreciate your boilerplate. Still, I would prefer to reuse as much stuff, and write as little own code, as possible. That's why I'm pushing a bit to consider this in Nest.

Maybe in my use case it's best to take care of this outside the app. But more generally, wouldn't async dependencies be useful?

What I can do now, if I understood correctly, is write a module that depends on an async module, like e. g. TypeOrmModule, and then does its initialization after TypeOrmModule is started. But my use case is slightly different, in that I want to wrap TypeOrmModule to do additional work before it is initialized.
What is missing for this use case is basically a way to asynchronously create a dynamic module, i. e. call TypeOrmModule.forRoot() in an async function. For now, dynamic modules have to be created synchronously, and I wondered whether that is necessary.

I would totally understand if this is either technically impossible or would make the implementation too complicated. That was just idea I had and I think it makes sense in general, so I wanted to propose and discuss it.

What is missing for this use case is basically a way to asynchronously create a dynamic module, i. e. call TypeOrmModule.forRoot() in an async function. For now, dynamic modules have to be created synchronously, and I wondered whether that is necessary.

This feature will be available in the upcoming release.

Wow, that is amazing! :) Thanks for your quick reply!

Nest 5.1.0 is published already

This feature seems like exactly what I'm looking for in my efforts to establish consistent e2e testing without the need to mock repositories or stand up a test database. I'm trying to override my TypeORM module provider to instead use a SQLite in-memory database instance to back up my repositories. @Y0hy0h @kamilmysliwiec Do you perhaps have an example of how you've used this to override the TypeORM configuration for testing? I've tried every permutation I can think of (including those mentioned in this and related threads) but I have been unable to do so.

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.

Was this page helpful?
0 / 5 - 0 ratings