Giter Site home page Giter Site logo

nestjs's Introduction

Nest Logo
MikroORM

Based on dario1985/nestjs-mikro-orm.

NPM version Chat on slack Downloads Build Status

Description

The MikroORM module for NestJS.

🚀 Quick Start

First install the module via yarn or npm and do not forget to install the database driver as well:

$ yarn add @mikro-orm/core @mikro-orm/nestjs @mikro-orm/mongodb     # for mongo
$ yarn add @mikro-orm/core @mikro-orm/nestjs @mikro-orm/mysql       # for mysql/mariadb
$ yarn add @mikro-orm/core @mikro-orm/nestjs @mikro-orm/mariadb     # for mysql/mariadb
$ yarn add @mikro-orm/core @mikro-orm/nestjs @mikro-orm/postgresql  # for postgresql
$ yarn add @mikro-orm/core @mikro-orm/nestjs @mikro-orm/sqlite      # for sqlite

or

$ npm i -s @mikro-orm/core @mikro-orm/nestjs @mikro-orm/mongodb     # for mongo
$ npm i -s @mikro-orm/core @mikro-orm/nestjs @mikro-orm/mysql       # for mysql/mariadb
$ npm i -s @mikro-orm/core @mikro-orm/nestjs @mikro-orm/mariadb     # for mysql/mariadb
$ npm i -s @mikro-orm/core @mikro-orm/nestjs @mikro-orm/postgresql  # for postgresql
$ npm i -s @mikro-orm/core @mikro-orm/nestjs @mikro-orm/sqlite      # for sqlite

Once the installation process is completed, we can import the MikroOrmModule into the root AppModule.

@Module({
  imports: [
    MikroOrmModule.forRoot({
      entities: ['../dist/entities'],
      entitiesTs: ['../src/entities'],
      dbName: 'my-db-name.sqlite3',
      type: 'sqlite',
      baseDir: __dirname,
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

The forRoot() method accepts the same configuration object as init() from the MikroORM package. You can also omit the parameter to use the CLI config.

Afterward, the EntityManager will be available to inject across entire project (without importing any module elsewhere).

@Injectable()
export class MyService {

  constructor(private readonly orm: MikroORM,
              private readonly em: EntityManager) { }

}

To define which repositories shall be registered in the current scope you can use the forFeature() method. For example, in this way:

You should not register your base entities via forFeature(), as there are no repositories for those. On the other hand, base entities need to be part of the list in forRoot() (or in the ORM config in general).

// photo.module.ts

@Module({
  imports: [MikroOrmModule.forFeature([Photo])],
  providers: [PhotoService],
  controllers: [PhotoController],
})
export class PhotoModule {}

and import it into the root AppModule:

// app.module.ts
@Module({
  imports: [MikroOrmModule.forRoot(...), PhotoModule],
})
export class AppModule {}

In this way we can inject the PhotoRepository to the PhotoService using the @InjectRepository() decorator:

@Injectable()
export class PhotoService {
  constructor(
    @InjectRepository(Photo)
    private readonly photoRepository: EntityRepository<Photo>
  ) {}

  // ...

}

Auto entities automatically

Manually adding entities to the entities array of the connection options can be tedious. In addition, referencing entities from the root module breaks application domain boundaries and causes leaking implementation details to other parts of the application. To solve this issue, static glob paths can be used.

Note, however, that glob paths are not supported by webpack, so if you are building your application within a monorepo, you won't be able to use them. To address this issue, an alternative solution is provided. To automatically load entities, set the autoLoadEntities property of the configuration object (passed into the forRoot() method) to true, as shown below:

@Module({
  imports: [
    MikroOrmModule.forRoot({
      ...
      autoLoadEntities: true,
    }),
  ],
})
export class AppModule {}

With that option specified, every entity registered through the forFeature() method will be automatically added to the entities array of the configuration object.

Note that entities that aren't registered through the forFeature() method, but are only referenced from the entity (via a relationship), won't be included by way of the autoLoadEntities setting.

Using autoLoadEntities also has no effect on the MikroORM CLI - for that we still need CLI config with the full list of entities. On the other hand, we can use globs there, as the CLI won't go thru webpack.

Request scoped handlers in queues

As mentioned in the docs, we need a clean state for each request. That is handled automatically thanks to the RequestContext helper registered via middleware.

But middlewares are executed only for regular HTTP request handles, what if we need a request scoped method outside of that? One example of that is queue handlers or scheduled tasks.

We can use the @UseRequestContext() decorator. It requires you to first inject the MikroORM instance to current context, it will be then used to create the context for you. Under the hood, the decorator will register new request context for your method and execute it inside the context.

@Injectable()
export class MyService {

  constructor(private readonly orm: MikroORM) { }

  @UseRequestContext()
  async doSomething() {
    // this will be executed in a separate context
  }

}

Serialization caveat

NestJS built-in serialization relies on class-transformer. Since MikroORM wraps every single entity relation in a Reference or a Collection instance (for type-safety), this will make the built-in ClassSerializerInterceptor blind to any wrapped relations. In other words, if you return MikroORM entities from your HTTP or WebSocket handlers, all of their relations will NOT be serialized.

Luckily, MikroORM provides a serialization API which can be used in lieu of ClassSerializerInterceptor.

@Entity()
export class Book {

  @Property({ hidden: true })   // --> Equivalent of class-transformer's `@Exclude`
  hiddenField: number = Date.now();
  
  @Property({ persist: false }) // --> Will only exist in memory (and will be serialized). Similar to class-transformer's `@Expose()`
  count?: number;
  
  @ManyToOne({ serializer: value => value.name, serializedName: 'authorName' })   // Equivalent of class-transformer's `@Transform()`
  author: Author;

}

Using AsyncLocalStorage for request context

Since v5 AsyncLocalStorage is used inside RequestContext helper so this section is no longer valid.

By default, the domain api is used in the RequestContext helper. Since @mikro-orm/[email protected], you can use the new AsyncLocalStorage too, if you are on up to date node version:

// create new (global) storage instance
const storage = new AsyncLocalStorage<EntityManager>();

@Module({
  imports: [
    MikroOrmModule.forRoot({
      // ...
      registerRequestContext: false, // disable automatatic middleware
      context: () => storage.getStore(), // use our AsyncLocalStorage instance
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

// register the request context middleware
const app = await NestFactory.create(AppModule, { ... });

app.use((req, res, next) => {
  storage.run(orm.em.fork(true, true), next);
});

Using NestJS Injection Scopes for request context

Since @nestjs/common@6, you can use the new Injection Scopes (https://docs.nestjs.com/fundamentals/injection-scopes) too:

import { Scope } from '@nestjs/common';

@Module({
  imports: [
    MikroOrmModule.forRoot({
      // ...
      registerRequestContext: false, // disable automatatic middleware
      scope: Scope.REQUEST
    }),
  ],
  controllers: [AppController],
  providers: [AppService]
})
export class AppModule {}

Or, if you're using the Async provider:

import { Scope } from '@nestjs/common';

@Module({
  imports: [
    MikroOrmModule.forRootAsync({
      // ...
      useFactory: () => ({
        // ...
        registerRequestContext: false, // disable automatatic middleware
      }),
      scope: Scope.REQUEST
    })
  ],
  controllers: [AppController],
  providers: [AppService]
})
export class AppModule {}

Please note that this might have some impact on performance, see: https://docs.nestjs.com/fundamentals/injection-scopes#performance

Using custom repositories

When using custom repositories, we can get around the need for @InjectRepository() decorator by naming our repositories the same way as getRepositoryToken() method do:

export const getRepositoryToken = <T> (entity: EntityName<T>) => `${Utils.className(entity)}Repository`;

In other words, as long as we name the repository same was as the entity is called, appending Repository suffix, the repository will be registered automatically in the Nest.js DI container.

**./author.entity.ts**

@Entity({ customRepository: () => AuthorRepository })
export class Author {

  // to allow inference in `em.getRepository()`
  [EntityRepositoryType]?: AuthorRepository;

}

**./author.repository.ts**

export class AuthorRepository extends EntityRepository<Author> {

  // your custom methods...

}

As the custom repository name is the same as what getRepositoryToken() would return, we do not need the @InjectRepository() decorator anymore:

@Injectable()
export class MyService {

  constructor(private readonly repo: AuthorRepository) { }

}

App shutdown and cleanup

By default, NestJS does not listen for system process termination signals (for example SIGTERM). Because of this, the MikroORM shutdown logic will never executed if the process is terminated, which could lead to database connections remaining open and consuming resources. To enable this, the enableShutdownHooks function needs to be called when starting up the application.

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  // Starts listening for shutdown hooks
  app.enableShutdownHooks();

  await app.listen(3000);
}

More information about enableShutdownHooks

Multiple Database Connections

You can define multiple database connections by registering multiple MikroOrmModule and setting their contextName. If you want to use middleware request context you must disable automatic middleware and register MikroOrmModule with forMiddleware() or use NestJS Injection Scope

@Module({
  imports: [
    MikroOrmModule.forRoot({
      contextName: 'db1',
      registerRequestContext: false, // disable automatatic middleware
      ...
    }),
    MikroOrmModule.forRoot({
      contextName: 'db2',
      registerRequestContext: false, // disable automatatic middleware
      ...
    }),
    MikroOrmModule.forMiddleware()
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

To access different MikroORM/EntityManager connections you have to use the new injection tokens @InjectMikroORM()/@InjectEntityManager() where you are required to pass the contextName in:

@Injectable()
export class MyService {

  constructor(@InjectMikroORM('db1') private readonly orm1: MikroORM,
              @InjectMikroORM('db2') private readonly orm2: MikroORM,
              @InjectEntityManager('db1') private readonly em1: EntityManager,
              @InjectEntityManager('db2') private readonly em2: EntityManager) { }

}

When defining your repositories with forFeature() method you will need to set which contextName you want it registered against:

// photo.module.ts

@Module({
  imports: [MikroOrmModule.forFeature([Photo], 'db1')],
  providers: [PhotoService],
  controllers: [PhotoController],
})
export class PhotoModule {}

When using the @InjectRepository decorator you will also need to pass the contextName you want to get it from:

@Injectable()
export class PhotoService {
  constructor(
    @InjectRepository(Photo, 'db1')
    private readonly photoRepository: EntityRepository<Photo>
  ) {}

  // ...

}

Testing

The nestjs-mikro-orm package exposes getRepositoryToken() function that returns prepared token based on a given entity to allow mocking the repository.

@Module({
  providers: [
    PhotoService,
    {
      provide: getRepositoryToken(Photo),
      useValue: mockedRepository,
    },
  ],
})
export class PhotoModule {}

🤝 Contributing

Contributions, issues and feature requests are welcome. Please read CONTRIBUTING.md for details on the process for submitting pull requests to us.

Authors

👤 Dario Mancuso

👤 Martin Adámek

See also the list of contributors who participated in this project.

Show Your Support

Please ⭐️ this repository if this project helped you!

📝 License

Copyright © 2018 Martin Adámek.

This project is licensed under the MIT License - see the LICENSE file for details.

nestjs's People

Contributors

b4nan avatar dario1985 avatar dependabot[bot] avatar evantrimboli avatar jsprw avatar lioness100 avatar marcpicaud avatar quinnturner avatar renovate-bot avatar renovate[bot] avatar rogrdat avatar ssut avatar steadexe avatar strikeforcezero avatar thiagomini avatar tlmak0 avatar tsangste avatar tukusejssirs avatar tychota avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

nestjs's Issues

[Question] Using AsyncLocalStorage

I currently going to refactor previous orm on our nestjs backend from Typeorm to Mikro ORM, i see using Mikro ORM with nestjs requiring RequestContext Middleware to ensure each request have clean entity manager state. Because middleware is only for regular http request and cannot be used on background job, queue, or any task running on background.

So using entity manager outside request scope the function should be anotated with @UseRequestContext (i aware with this because we have large codebase that mostly run on background will cause DRY Code)

If using AsyncLocalStorage instead RequestContext still we need anotate the function with UseRequestContext ? i look into UseRequestContext there no conditional case if context handled by request or local storage

Bull - Scoped Jobs

Is your feature request related to a problem? Please describe.
We're experiencing issues with Bull where the Entity Manager is shared across all running jobs. That leads to errors memory leaks.

Describe the solution you'd like
There is this open issue on the nestjs/bull side which might be a dependency here, but I ideally would like pretty much the same mechanism as RequestContext middleware but applied to Bull Jobs (which obviously are not considered Requests by nest)

Describe alternatives you've considered
I don't have any ideas for alternative but I'm happy to hear some if you do.

Request scoping when using microservices

Perhaps I'm missing something or the docs are a little unclear on this so this is more of a question. I have a number of microservices that I would like to migrate from mongoose to mikro-orm, but it seems like the middleware is specifically for express instances (with some caveats for fastify)

  use(req: unknown, res: unknown, next: (...args: any[]) => void) {
    RequestContext.create(this.orm.em, next);
  }

So It seems the automatic middleware is out, so if I disable that and use ALS, I still need to have access to the request object:

// register the request context middleware
const app = await NestFactory.create(AppModule, { ... });

const orm = app.get(MikroORM);
app.use((req, res, next) => {
  storage.run(orm.em.fork({ useContext: true }), next);
});

The microservice app context is incompatible with that obviously:

const app = await NestFactory.createMicroservice<MicroserviceOptions>(.....);

In this case, is it possible to hook in to each transport request to create a new context?

Cant not inject Entity Manager

Describe the bug
My project is working before but suddently, it stop working because DI cant load EntityManager, While the InjectRepository still working in the same class

Stack trace

@Injectable()
export class MeterInfoService implements IMeterInfoService {
  constructor(
    @InjectRepository(Site)
    private readonly siteRepository: EntityRepository<Site>,
    @InjectRepository(Meter)
    private readonly meterRepository: EntityRepository<Meter>,
    @InjectRepository(Channel)
    private readonly channelRepository: EntityRepository<Channel>,
    private readonly em: EntityManager,
  ) {}

...

Got below error

ERROR [ExceptionHandler] Nest can't resolve dependencies of the MeterInfoService (SiteRepository, MeterRepository, ChannelRepository, ?). Please make sure that the argument SqlEntityManager at index [3] is available in the MeterInfoModule context.

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

Error: Nest can't resolve dependencies of the MeterInfoService (SiteRepository, MeterRepository, ChannelRepository, ?). Please make sure that the argument SqlEntityManager at index [3] is available in the MeterInfoModule context.

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

After dig deeper in the code, I found that there is another package using @mikro-orm/knex so that why it make the injection look for SQLEntityManager

To Reproduce
Steps to reproduce the behavior:

  1. setup monorepo with nestjs application is not the root workspace
  2. enable yarn workspace v2 that make all the package going to top level node_modules (../../)
  3. run yarn start:dev

Expected behavior
The EntityManager should able to inject

Additional context
Add any other context about the problem here.

Versions

Dependency Version
node ?
typescript ?
mikro-orm ?
your-driver ?

Custom repository injection without naming convention

Is your feature request related to a problem? Please describe.
I am replacing typeorm with mikro-orm for a project. I replaced all decorators and repositories but just one repository didn't work. After my 4 hour struggle, I realized that I have a typo in the repository name.

Describe the solution you'd like
I am not nestjs pro but inject and resolve repositories from @Entity decorators customRepository or EntityRepositoryType symbol would be nice.

Describe alternatives you've considered
Get repository from entity manager

Additional context
And in the custom repository examples document entity and repository names not like nestjs required naming convention so this can be misleading

autoLoadEntities does not work when using Test.createTestingModule

Describe the bug

I recently switched to the autoLoadEntities way to load entities.

Imagine the following "flow"

  • MainAppModule
    • imports AuthModule
      • imports UserModule
        • imports MikroOrmModule.forFeature([User])

This works perfectly while running the application.

But when testing this, the entities do not get loaded.

  beforeEach(async () => {
    const moduleFixture: TestingModule = await Test.createTestingModule({
      imports: [MainAppModule],
    }).compile();

Gives me the following stack trace

    No entities found, please use `entities` option

      at Configuration.validateOptions (../../node_modules/@mikro-orm/core/utils/Configuration.js:146:19)
      at new Configuration (../../node_modules/@mikro-orm/core/utils/Configuration.js:22:18)
      at new MikroORM (../../node_modules/@mikro-orm/core/MikroORM.js:20:27)
      at Function.init (../../node_modules/@mikro-orm/core/MikroORM.js:38:21)
      at InstanceWrapper.useFactory [as metatype] (../../node_modules/@mikro-orm/nestjs/mikro-orm.providers.js:21:32)
      at Injector.instantiateClass (../../node_modules/@nestjs/core/injector/injector.js:289:55)
      at callback (../../node_modules/@nestjs/core/injector/injector.js:42:41)
      at Injector.resolveConstructorParams (../../node_modules/@nestjs/core/injector/injector.js:114:24)
      at Injector.loadInstance (../../node_modules/@nestjs/core/injector/injector.js:46:9)

I can work around it by putting a MikroOrmModule.forFeature for all entities referenced when initializing the testing module but this is less than optimal.

Versions

Dependency Version
node v14.15.1
typescript 4.1.3
mikro-orm 4.4.0
mongo 3.6.3

DI failing to find Mikro-Orm repositories after upgrading to NestJs v8

Describe the bug
Dependency injection errors are thrown as a result of Nest not being able to find an entity's repository. Repositories are all imported in a single module (database.module.ts) using the forFeature() function.

Stack trace

 at Injector.lookupComponentInParentModules (/home/reganvanheerden/WebstormProjects/EntrostatProjects/askgogo-git-issue/backend/node_modules/@nestjs/core/injector/injector.js:193:19)
    at Injector.resolveComponentInstance (/home/reganvanheerden/WebstormProjects/EntrostatProjects/askgogo-git-issue/backend/node_modules/@nestjs/core/injector/injector.js:149:33)
    at resolveParam (/home/reganvanheerden/WebstormProjects/EntrostatProjects/askgogo-git-issue/backend/node_modules/@nestjs/core/injector/injector.js:103:38)
    at async Promise.all (index 0)
    at Injector.resolveConstructorParams (/home/reganvanheerden/WebstormProjects/EntrostatProjects/askgogo-git-issue/backend/node_modules/@nestjs/core/injector/injector.js:118:27)
    at Injector.loadInstance (/home/reganvanheerden/WebstormProjects/EntrostatProjects/askgogo-git-issue/backend/node_modules/@nestjs/core/injector/injector.js:47:9)
    at Injector.loadProvider (/home/reganvanheerden/WebstormProjects/EntrostatProjects/askgogo-git-issue/backend/node_modules/@nestjs/core/injector/injector.js:69:9)
    at async Promise.all (index 3)
    at InstanceLoader.createInstancesOfProviders (/home/reganvanheerden/WebstormProjects/EntrostatProjects/askgogo-git-issue/backend/node_modules/@nestjs/core/injector/instance-loader.js:44:9)
    at /home/reganvanheerden/WebstormProjects/EntrostatProjects/askgogo-git-issue/backend/node_modules/@nestjs/core/injector/instance-loader.js:29:13


To Reproduce
Steps to reproduce the behavior:

  1. Open repo : [email protected]:Regan-entrostat/askgogo_issue_1.git
  2. Run 'npm install && nest start' in the backend folder

Expected behavior

  • Repository is supposed to be injected into the service.

Additional context
can get rid of this particular error by putting MikroOrmModule.forFeature([Profanity]) in the imports section of profanity.module.ts file; except this is not a good solution as the errors continue onto the next repository until I come across a repository that is used across multiple services all provided in different modules.

Versions

"@mikro-orm/cli": "^4.5.7",
"@mikro-orm/core": "^4.5.7",
"@mikro-orm/nestjs": "^4.3.0",
"@mikro-orm/postgresql": "^4.5.7",
"@mikro-orm/reflection": "^4.5.7",
"@mikro-orm/sql-highlighter": "^1.0.1",
"@nestjs/common": "^8.0.6",
"@nestjs/core": "^8.0.6",
"@nestjs/jwt": "^8.0.0",
"@nestjs/passport": "^8.0.1",
"@nestjs/platform-express": "^8.0.6",
"@nestjs/throttler": "^2.0.0",	

Node version: 14.17.5
Platform: Linux

Custom decorators using class validator

Does MikroORM allow the querying of entities inside a custom decorator using class validator. For instance like this

Screenshot 2021-01-30 at 13 20 12

When i execute the above code out, i get an error "Cannot read property 'findOne' of undefined"
So am wondering if MikroORM does support querying of entities inside custom decorator using class validator.
The code that executes the custom decorator is this

Screenshot 2021-01-30 at 13 23 46

I will highly appreciate your assistance

@mikro-orm/entity-generator is causing error

Describe the bug
I made a repo to reproduce the bug: https://github.com/rizchaerul/bug

Hi, so earlier i made an issue here #40. I found out what causing it, it's the entity-generator.

To Reproduce
Steps to reproduce the behavior:

  1. Clone from https://github.com/rizchaerul/bug
  2. Run pnpm i
  3. Run yarn start:dev
  4. It will show error
  5. Run pnpm uninstall @mikro-orm/entity-generator
  6. The error is gone

Versions

Dependency Version
node ?
typescript 4.3.5
mikro-orm 4.5.9
your-driver postgresql

Move into the mikro-orm repo

The MikroORM repo contains a lot of different packages: cli, db-adapters, knex, core, migrations. It seems weird that the nestjs package is not in this repo.
There are also a few advantages to mergen this into the main repo. It would keep the version at the same level as the main MikroORM package, keeps dependencies up to date and with that shows users that this package is serious and begin kept up to date and it looked after.

Conflicting Peer Dependencies

Hi,

I am currently upgrading NestJS to version 8 as it is supposed to work now with MikroORM.

However, I am receiving the following issues after a clean npm install and running npm audit fix.

npm audit fix
npm ERR! code ERESOLVE
npm ERR! ERESOLVE could not resolve
npm ERR! 
npm ERR! While resolving: @mikro-orm/[email protected]
npm ERR! Found: @nestjs/[email protected]
npm ERR! node_modules/@nestjs/common
npm ERR!   @nestjs/common@"^8.0.11" from the root project
npm ERR!   peer @nestjs/common@"^7.0.0||^8.0.0" from @mikro-orm/[email protected]
npm ERR!   node_modules/@mikro-orm/nestjs
npm ERR!     @mikro-orm/nestjs@"^4.3.0" from the root project
npm ERR!   10 more (@nestjs/config, @nestjs/core, @nestjs/event-emitter, ...)
npm ERR! 
npm ERR! Could not resolve dependency:
npm ERR! peer @nestjs/common@"^7.0.0||^8.0.0" from @mikro-orm/[email protected]
npm ERR! node_modules/@mikro-orm/nestjs
npm ERR!   @mikro-orm/nestjs@"^4.3.0" from the root project
npm ERR! 
npm ERR! Conflicting peer dependency: @nestjs/[email protected]
npm ERR! node_modules/@nestjs/common
npm ERR!   peer @nestjs/common@"^7.0.0||^8.0.0" from @mikro-orm/[email protected]
npm ERR!   node_modules/@mikro-orm/nestjs
npm ERR!     @mikro-orm/nestjs@"^4.3.0" from the root project

As far as I would understand it, peer @nestjs/common@"^7.0.0||^8.0.0" from @mikro-orm/[email protected] would also include version 8.0.11 which I have installed (@nestjs/common)

Any idea on how to fix this so that it does not show up anymore?

Was running npm audit fix --legacy-peer-depsto resolve it for now.

Multiple database connections

We currently have two MikroORM instances, one connecting to a MongoDB and another connecting to a PostgreSQL, but we are facing troubles as the configs are being confused.

We implemented it like this.

This is the module that allows us to choose if we want to use real or fake repositories on the tests suites

@Module({})
export class MikroOrmSwitcherModule {
  static init({ disable }: { disable: boolean }): DynamicModule {
    if (disable) {
      return {
        module: MikroOrmSwitcherModule,
      };
    }

    return {
      module: MikroOrmSwitcherModule,
      imports: [
        MikroOrmModule.forRoot(mikroOrmPostgresConfig),
        MikroOrmModule.forRoot(mikroOrmMongoConfig),
      ],
    };
  }
}

This is the mikro-orm-mongo.config.ts:

const mikroOrmMongoConfig: Options = {
  type: 'mongo',
  contextName: 'mongoConfig',
  name: 'mongoDB',
  host: config.transactionsDatabase.host,
  port: config.transactionsDatabase.port,
  user: config.transactionsDatabase.username,
  password: config.transactionsDatabase.password,
  dbName: config.transactionsDatabase.database,
  entities: [CustomerOrderEntity, CancelationEntity, OrderLineEntity, LocationEntity],
  debug: true,
  metadataProvider: TsMorphMetadataProvider,
};

export default mikroOrmMongoConfig;

This is the mikro-orm-postgres.config.ts:

const mikroOrmPostgresConfig: Options = {
  type: 'postgresql',
  contextName: 'postgreSQLConfig',
  name: 'postgreSQL',
  host: config.ledgersDatabase.host,
  port: config.ledgersDatabase.port,
  user: config.ledgersDatabase.username,
  password: config.ledgersDatabase.password,
  dbName: config.ledgersDatabase.database,
  entities: [LedgerEntity],
  migrations: {
    path: 'src/migrations',
  },
  debug: true,
  metadataProvider: TsMorphMetadataProvider,
};

export default mikroOrmPostgresConfig;

The failures we are getting are that sometimes our orm instances trys to use the PostgreSQL driver for the MongoDB repository and sometimes the opposite.

At the config files we tried to add only the entities that each instance is going to use, but that gives us the following error also:
[Nest] 24318 - 25/03/2021 11:17:27 [ExceptionHandler] Metadata for entity CustomerOrderEntity not found +0ms

We haven't found a proper way to achieve this in the documentation. Thanks in advance!

usage of UseRequestContext decorator

hello, im just starting using mikro-orm with nestjs and grpc, i saw in the documentation that a clean state is needed for each request https://mikro-orm.io/docs/usage-with-nestjs/#request-scoped-handlers-in-queues

so i added this decorator to the "getUser" service method like this

@Injectable()
export class UserService{
  private readonly orm:MikroORM;
  private userRepository:EntityRepository<User>;
	  
  constructor(orm:MikroORM,@InjectRepository(User) userRepository:EntityRepository<User>){
    this.orm=orm;
    this.userRepository=userRepository;
  
  }
  
  @UseRequestContext()
  getUser(data:{id:string}):Promise<User>{
    return this.userRepository.findOne(
	    {'_id':data.id},
	    {populate:['type']}
    )
    .then((res:User):User=>{
	    if(!res) throw new Error('user not found');
	    else return res;
    });
  }
}

but in the controller the returned value from the service is undefined, when i remove the decorator from the service's method "getUser" the value returned is no longer undefined, it is the value i expect, a User object

@Controller()
export class UserController{
	private readonly userService:UserService;
	
	constructor(userService:UserService){
		this.userService=userService;
		
	}
	
        @GrpcMethod()
	getUser(data:{id:string):void{
		this.userService.getUser(data)
		.then((res:UserResponse.AsObject):void=>{
			console.log('res',res)  // undefined when userService.getUser has decorator
		});
	}
	
}

this is the module in which the service and controller are defined

@Module({
	imports: [
		MikroOrmModule.forFeature([UserType,User])
	],
	controllers:[UserController],
	providers:[UserService]
})
export class UserModule{}

this is the root module

@Module({
	imports:[
		ConfigModule.forRoot({
			isGlobal:true,
			ignoreEnvFile:true,
			load:[config]
		}),
		MikroOrmModule.forRoot({
			clientUrl:process.env.MONGO_DATABASE_URL,
			type:'mongo',
			autoLoadEntities:true
		}),
		UtilitiesModule,
		UserModule
	],
	controllers:[AppController,HealthController],
	providers:[AppService]
})
export class AppModule{}

and this is the entity

@Entity({collection:'User'})
export class User{
	@PrimaryKey()
	_id:string;
	@SerializedPrimaryKey()
	id:string;
	@ManyToOne({entity:()=>UserType})
	type:UserType;
	@Property()
	email:string;
	@Property()
	firstName:string;
	@Property()
	lastName:string;
	@Property()
	deletedAt:Date;
	@Property({onUpdate:()=>new Date()})
	updatedAt:Date=new Date();
	@Property()
	createdAt:Date=new Date();
}

i wanted to ask what would be the correct way of implementing this decorator or to return the value of a function that is decorated?, thanks.

Mikroorm Scope.REQUEST breaks scheduler

Describe the bug
When using MikroOrmModule.forRootAsync with scope: Scope.REQUEST it breaks cron module.

To Reproduce
Steps to reproduce the behavior:

  1. npm install --save @nestjs/schedule @nestjs @mikro-orm/core @mikro-orm/nestjs @mikro-orm/sqlite
  2. define cron schedule like in example on botton
  3. load mikroOrmModule.forRootAsync with parameter scope: Scope.REQUEST

Expected behavior
Cron schedule should be executed the same as when choosing any other scope

Additional context

      {
        useFactory: ()=>(
          {
            entitiesTs: ['./src/backend/entities'],
            dbName: 'database.sqlite3',
            type: 'sqlite',
            port: 3307,
            highlighter: new SqlHighlighter(),
            debug: false,
            // metadataProvider: ReflectMetadataProvider,
  
            // logger: logger.log.bind(logger),
            autoLoadEntities: false,
            discovery: {
              warnWhenNoEntities: false, // by default, discovery throws when no entity is processed
              //requireEntitiesArray: true, // force usage of class refrences in `entities` instead of paths
              alwaysAnalyseProperties: true, // do not analyse properties when not needed (with ts-morph)
            },
            registerRequestContext: false,
            context: () => storage.getStore(), // use our AsyncLocalStorage instance

          }),
        scope: Scope.REQUEST
        
        
        // context: () => storage.getStore(),
      }
    ),```
```@Cron(CronExpression.EVERY_10_SECONDS)
    async HealthCheck(): Promise<void>
    {
      this.logger.log('HealthCheck');
    }

Versions

| Dependency | Version |

| node | 16.0.0 |
"typescript": "~4.3.5",
"@mikro-orm/core": "^4.5.9",
"@mikro-orm/nestjs": "^4.3.0",

Dependency resolution fails with `@mikro-orm/cli` and `pnpm`

Describe the bug
NestJS is unable to resolve SqlEntityManager in a pnpm monorepo only when @mikro-orm/cli is installed.

Stack trace

ERROR [ExceptionHandler] Nest can't resolve dependencies of the AppService (?). Please make sure that the argument SqlEntityManager at index [0] is available in the AppModule context.

Reproduction (duckies/mikro-orm-cli-issue)
I created a minimal reproduction that should fail on pnpm i && pnpm dev, but will work once @mikro-orm/cli is removed from the ./packages/server/package.json's dependencies and commands reran. I also included a yarn@v1 branch and NestJS is working with all dependencies installed.

Additional context
I'm unsure if this is an issue with mikro-orm, pnpm, or otherwise. I know pnpm often duplicates, and thus breaks, @nestjs/core, but I don't think this is the case here.

Versions

Dependency Version
node 16.13.1
typescript 4.7.4
mikro-orm 5.3.1
your-driver postgresql

Jest test suite leaking memory

Describe the bug
While running tests the test suite is leaking memory. We found out when at some point in time our tests crashed due to being out of memory.

I believe this has to do with mikro-orm and not with jest or nestjs, because I created a new nestjs project. The tests then worked. After adding @mikro-orm/core and @mikro-orm/nestjs the tests came up with the error.

Stack trace

Test suite failed to run

    EXPERIMENTAL FEATURE!
    Your test suite is leaking memory. Please ensure all references are cleaned.

    There is a number of things that can leak memory:
      - Async operations that have not finished (e.g. fs.readFile).
      - Timers not properly mocked (e.g. setInterval, setTimeout).
      - Keeping references to the global scope.

      at onResult (../../../node_modules/@jest/core/build/TestScheduler.js:190:18)
      at ../../../node_modules/@jest/core/build/TestScheduler.js:304:17
      at ../../../node_modules/emittery/index.js:260:13
          at Array.map (<anonymous>)
      at Emittery.Typed.emit (../../../node_modules/emittery/index.js:258:23)

<--- Last few GCs --->

[82559:0x59204c0]   161826 ms: Mark-sweep 2039.8 (2052.5) -> 2039.1 (2052.3) MB, 726.0 / 0.2 ms  (average mu = 0.079, current mu = 0.006) allocation failure scavenge might not succeed
[82559:0x59204c0]   162561 ms: Mark-sweep 2040.1 (2052.3) -> 2039.7 (2053.0) MB, 731.2 / 0.2 ms  (average mu = 0.043, current mu = 0.005) allocation failure scavenge might not succeed


<--- JS stacktrace --->

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
 1: 0xa2b020 node::Abort() [/home/langstra/.nvm/versions/node/v14.4.0/bin/node]
 2: 0x97a467 node::FatalError(char const*, char const*) [/home/langstra/.nvm/versions/node/v14.4.0/bin/node]
 3: 0xb9e0ee v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, bool) [/home/langstra/.nvm/versions/node/v14.4.0/bin/node]
 4: 0xb9e467 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, bool) [/home/langstra/.nvm/versions/node/v14.4.0/bin/node]
 5: 0xd3e875  [/home/langstra/.nvm/versions/node/v14.4.0/bin/node]
 6: 0xd3f21b v8::internal::Heap::RecomputeLimits(v8::internal::GarbageCollector) [/home/langstra/.nvm/versions/node/v14.4.0/bin/node]
 7: 0xd4d012 v8::internal::Heap::PerformGarbageCollection(v8::internal::GarbageCollector, v8::GCCallbackFlags) [/home/langstra/.nvm/versions/node/v14.4.0/bin/node]
 8: 0xd4de65 v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollectionReason, v8::GCCallbackFlags) [/home/langstra/.nvm/versions/node/v14.4.0/bin/node]
 9: 0xd5082c v8::internal::Heap::AllocateRawWithRetryOrFailSlowPath(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [/home/langstra/.nvm/versions/node/v14.4.0/bin/node]
10: 0xd1fecb v8::internal::Factory::NewFillerObject(int, bool, v8::internal::AllocationType, v8::internal::AllocationOrigin) [/home/langstra/.nvm/versions/node/v14.4.0/bin/node]
11: 0x10501ef v8::internal::Runtime_AllocateInYoungGeneration(int, unsigned long*, v8::internal::Isolate*) [/home/langstra/.nvm/versions/node/v14.4.0/bin/node]
12: 0x13a9ed9  [/home/langstra/.nvm/versions/node/v14.4.0/bin/node]
Aborted (core dumped)
error Command failed with exit code 134.

To Reproduce
Steps to reproduce the behavior:

  1. git clone https://github.com/Langstra/nest-mikro-orm-jest-leak
  2. cd nest-mikro-orm-jest-leak
  3. yarn
  4. yarn test:e2e

Expected behavior
No memory leaks

Versions

Dependency Version
node 14.4.0
typescript 3.7.4
mikro-orm/core 4.0.0-rc.8
mikro-orm/mysql 4.0.0-rc.8
mikro-orm/nestjs 4.0.0.alpha-4

When use FastifyAdapter, the unit of work is shared between requests

Describe the bug
I'm not sure that this is an incorrect behavior. When print EntityRepository from a controller action, it always return the same EntityManager:

SqlEntityRepository { _em: [EntityManager<1>], entityName: 'Book' }
[Nest] 35606   - 08/03/2021, 10:59:57 AM   [MikroORM] [query] select `e0`.* from `author` as `e0` where `e0`.`id` = 1 limit 1 [took 1 ms]
[Nest] 35606   - 08/03/2021, 10:59:57 AM   [MikroORM] [query] select `e0`.* from `book` as `e0` where `e0`.`author_id` in (1) order by `e0`.`author_id` asc [took 1 ms]
SqlEntityRepository { _em: [EntityManager<1>], entityName: 'Book' }
[Nest] 35606   - 08/03/2021, 11:06:18 AM   [MikroORM] [query] select `e0`.* from `author` as `e0` where `e0`.`id` = 1 limit 1 [took 1 ms]
[Nest] 35606   - 08/03/2021, 11:06:18 AM   [MikroORM] [query] select `e0`.* from `book` as `e0` where `e0`.`author_id` in (1) order by `e0`.`author_id` asc [took 1 ms]

but mikro-orm middleware creates a new context in every request, so a fork of EntityManager is created:

RequestContext { map: Map { 'default' => [EntityManager<2>] }, id: 1 }
SqlEntityRepository { _em: [EntityManager<1>], entityName: 'Book' }
[Nest] 38056   - 08/03/2021, 11:11:37 AM   [MikroORM] [query] select `e0`.* from `author` as `e0` where `e0`.`id` = 1 limit 1 [took 2 ms]
[Nest] 38056   - 08/03/2021, 11:11:37 AM   [MikroORM] [query] select `e0`.* from `book` as `e0` where `e0`.`author_id` in (1) order by `e0`.`author_id` asc [took 1 ms]
RequestContext { map: Map { 'default' => [EntityManager<3>] }, id: 2 }
SqlEntityRepository { _em: [EntityManager<1>], entityName: 'Book' }
[Nest] 38056   - 08/03/2021, 11:11:41 AM   [MikroORM] [query] select `e0`.* from `author` as `e0` where `e0`.`id` = 1 limit 1 [took 5 ms]
[Nest] 38056   - 08/03/2021, 11:11:41 AM   [MikroORM] [query] select `e0`.* from `book` as `e0` where `e0`.`author_id` in (1) order by `e0`.`author_id` asc [took 3 ms]

In my project I when some request fail and request again, the last entity added with fail to the EntityManager exists in the new request. So my concern is that the EntityRepository is not changing to new fork of the EntityManager.

I'm trying to reproduce this behavior in the project https://github.com/mikro-orm/nestjs-example-app and I have the same EntityManager for every request (described in the logs), but the repo doesn't have the entities added in the last failed request.

Is this EntityManager behavior correct?

Load EntitySchema

Is it possible to load EntitySchemas the way Entities are loaded at MikroOrmModule?
How could it be done?

Use Case:

export const fooSchema = new EntitySchema<Foo>({
  class: Foo,
  properties: {
    id: { type: 'uuid', primary: true },
    name: { type: 'string' },
  },
});
  imports: [MikroOrmModule.forFeature(/* ??? */)],

Note: Foo is a plain class (not annotated with @Entity decorator)

Importing EntityManager fails when using webpack

Describe the bug
I've got an issue with webpack not being able to dynamically import '@mikro-orm/knex' or '@mikro-orm/mongodb' in the whenModuleAvailable function. Since these are imported as enums (e.g. import(EntityManagerModuleName.Knex)) webpack does not bundle these modules. It's possible to fix this by importing with strings import("@mikro-orm/knex"). I can write a pull request if this would help :)

Versions

Dependency Version
node 14
typescript 4.1.6
mikro-orm 5.x

Out of date info in README.md

Describe the bug
Hi, I believe that the Custom Repository section of README.md needs updating, as the @Repository decorator has been removed. Not sure how to migrate my **./*.repository.ts** files to v5 :)

Support connect argument from MikroORM.init()

Is your feature request related to a problem? Please describe.

When testing it can be useful to initial MikroORM without connecting to a database. MikroORM supports this through the connect argument in MikroORM.init().

Currently the nestjs module doesn't support this.

Describe the solution you'd like

Either add a argument to MikroORMModule.forRoot()/forRootAsync() or add it to the module options object.

Add support for `autoLoadEntities`

Describe the bug
First off, great project - I'm really grateful for all the work you've put in on this.

The issue I'm running into with this module is when it's run within a nest monorepo the glob patterns for entity discovery does not work (for js or ts files). This appears to be a known issue also faced with TypeORM where they have added an autoLoadEntities prop in order to resolve it.

Not importing entities in manually results in a No entities were discovered error on startup.

I can (and am presently) importing files manually but this seems a bit unintuitive given that now I have to expose these from scoped libraries within the larger nest monorepo.

To Reproduce
Steps to reproduce the behavior:

  1. Create a new nest project as a monorepo
  2. Install and configure @mikro-orm/nestjs as a library module
  3. Configure an entity or two and use the glob patter in the Mikro ORM config
  4. Run the application

Expected behavior
All entities should be discovered based on their glob and load within Mikro ORM.

Additional context
I'd be happy to do this another way if I can scope a Mikro ORM instance per library module if that's better but I'm unsure if Mikro ORM sets itself up globally and wouldn't allow this.

Versions

Dependency Version
node 12.x
@nestjs/core 7.0.0
@mikro-orm/core 4.0.3
@mikro-orm/nestjs 4.0.0

MikroOrmCoreModule is very slow to initialize

Hi, I have a very basic nestjs application with just a couple routes and entities, but initializing the MikroOrmCoreModule is very slow every time I want to hot reload the app. Here is the console output showing that it takes almost 22 seconds to initialize. Am I doing something wrong here or is this a bug? Can anyone else reproduce this?

[Nest] 31700  - 27/11/2021, 12:27:45     LOG [NestFactory] Starting Nest application...
[Nest] 31700  - 27/11/2021, 12:27:45     LOG [InstanceLoader] AppModule dependencies initialized +28ms    
[Nest] 31700  - 27/11/2021, 12:27:45     LOG [InstanceLoader] OrmModule dependencies initialized +0ms     
[Nest] 31700  - 27/11/2021, 12:27:45     LOG [InstanceLoader] MikroOrmModule dependencies initialized +0ms
[Nest] 31700  - 27/11/2021, 12:28:06     LOG [InstanceLoader] MikroOrmCoreModule dependencies initialized +21172ms
[Nest] 31700  - 27/11/2021, 12:28:06     LOG [InstanceLoader] MikroOrmModule dependencies initialized +1ms
[Nest] 31700  - 27/11/2021, 12:28:06     LOG [InstanceLoader] AuthModule dependencies initialized +0ms    
[Nest] 31700  - 27/11/2021, 12:28:06     LOG [RoutesResolver] AuthController {/auth}: +6ms
[Nest] 31700  - 27/11/2021, 12:28:06     LOG [RouterExplorer] Mapped {/auth/login, GET} route +2ms        
[Nest] 31700  - 27/11/2021, 12:28:06     LOG [RouterExplorer] Mapped {/auth/register, POST} route +1ms    
[Nest] 31700  - 27/11/2021, 12:28:06     LOG [NestApplication] Nest application successfully started +2ms

Injectable EventSubscribers

Is your feature request related to a problem? Please describe.
It would be awesome if EventSubscriber classes could support NestJs DI so we can inject dependencies in them.

Describe the solution you'd like
The current @Subscriber() decorator cannot be used as it directly creates a new instance:
https://github.com/mikro-orm/mikro-orm/blob/master/packages/core/src/decorators/Subscriber.ts#L8
And I didn't find a clear solution to remove the attached subscriber before MikroORM init.

I think the easiest way is to have a new decorator (could be @InjectableSubscriber(), that also wraps Nestjs @Injectable() ?) that simply adds a metadata to the class prototype flagging it as a Subscriber, then the class has to be registered as a provider inside a Module (like any nestjs providers).

Then follow a common Nestjs pattern, "disover" this providers via the custom metadata and do stuff with them, in our case
register them as subscriber (em.getEventManager().registerSubscriber()).

Additional context
As a reference, @nestjs/bull does the same for registering queue processors https://github.com/nestjs/bull/blob/master/lib/bull.explorer.ts .
It is a bit more complicated since it has to check every class methods instead of just the class, what we need are just the first lines of explore():

const providers: InstanceWrapper[] = this.discoveryService
      .getProviders()
      .filter((wrapper: InstanceWrapper) =>
        this.metadataAccessor.isQueueComponent(wrapper.metatype),
      );

Replace isQueueComponent with something like isSubscriberComponent and voilà, we have an array of all provided subscribers.

Nest can't resolve dependencies of the MikroOrmCoreModule (Symbol(mikro-orm-module-options), ?). Please make sure that the argument ModuleRef at index [1] is available in the MikroOrmCoreModule context.

Describe the bug

I've tried several configurations, but I keep getting this error.

Stack trace


[Nest] 69475  - 07/17/2021, 4:01:41 PM     LOG [NestFactory] Starting Nest application...
[Nest] 69475  - 07/17/2021, 4:01:41 PM     LOG [InstanceLoader] ConfigModule dependencies initialized +188ms
[Nest] 69475  - 07/17/2021, 4:01:41 PM     LOG [InstanceLoader] DomainModule dependencies initialized +1ms
[Nest] 69475  - 07/17/2021, 4:01:41 PM     LOG [InstanceLoader] MikroOrmModule dependencies initialized +0ms
[Nest] 69475  - 07/17/2021, 4:01:41 PM   ERROR [ExceptionHandler] Nest can't resolve dependencies of the MikroOrmCoreModule (Symbol(mikro-orm-module-options), ?). Please make sure that the argument ModuleRef at index [1] is available in the MikroOrmCoreModule context.

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

Error: Nest can't resolve dependencies of the MikroOrmCoreModule (Symbol(mikro-orm-module-options), ?). Please make sure that the argument ModuleRef at index [1] is available in the MikroOrmCoreModule context.

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

    at Injector.lookupComponentInParentModules (/App/node_modules/@my-org/api/node_modules/@nestjs/core/injector/injector.js:189:19)
    at processTicksAndRejections (internal/process/task_queues.js:97:5)
    at Injector.resolveComponentInstance (/App/node_modules/@my-org/api/node_modules/@nestjs/core/injector/injector.js:145:33)
    at resolveParam (/App/node_modules/@my-org/api/node_modules/@nestjs/core/injector/injector.js:99:38)
    at async Promise.all (index 1)
    at Injector.resolveConstructorParams (/App/node_modules/@my-org/api/node_modules/@nestjs/core/injector/injector.js:114:27)
    at Injector.loadInstance (/App/node_modules/@my-org/api/node_modules/@nestjs/core/injector/injector.js:47:9)
    at Injector.loadProvider (/App/node_modules/@my-org/api/node_modules/@nestjs/core/injector/injector.js:69:9)
    at async Promise.all (index 0)
    at InstanceLoader.createInstancesOfProviders (/App/node_modules/@my-org/api/node_modules/@nestjs/core/injector/instance-loader.js:44:9)

To Reproduce

import { Module } from '@nestjs/common';
import { GraphQLModule } from '@nestjs/graphql';
import { ConfigModule, DatabaseModule } from '@my-org/infra';
import { ApiModule, ApiController, ApiService } from '@my-org/api';
import { Config } from '@my-org/config';
import { MikroOrmModule } from '@mikro-orm/nestjs';
import { getRootPath } from '@my-org/utils';
import { DomainModule } from '@project/domain';

import { ProjectAppController } from './app.controller';
import { ProjectAppService } from './app.service';

@Module({
  imports: [
    ConfigModule,
    DomainModule,
    GraphQLModule.forRoot({
      debug: false,
      playground: true,
      autoSchemaFile: getRootPath('apps/project-api/graphql-schema.gql'),
      path: Config.serviceGraphqlApiEndpoint,
    }),
    MikroOrmModule.forRoot(
      Config.getMikroOrmConfig({
        migrations: {
          migrationsList: [],
        },
      })
    ),
    DatabaseModule,
  ],
  controllers: [ProjectAppController, ApiController],
  providers: [ProjectAppService, ApiService],
})
export class AppModule extends ApiModule {}

DomainModule imports ResourceModule

import { Module } from '@nestjs/common';
import { ResourceService } from './resource-manifest.service';
import { ResourceResolver } from './resource-manifest.resolver';
import { MikroOrmModule } from '@mikro-orm/nestjs';
import { Resource } from './entities/resource-manifest.entity';

@Module({
  providers: [ResourceResolver, ResourceService],
  imports: [MikroOrmModule.forFeature([Resource])],
})
export class ResourceModule {}

Expected behavior

To see dependencies resolved

Additional context
Add any other context about the problem here.

Versions

Dependency Version
node v12.18.3
typescript 4.3.5
    "@mikro-orm/core": "^4.5.7",
    "@mikro-orm/migrations": "^4.5.7",
    "@mikro-orm/nestjs": "^4.2.0",
    "@mikro-orm/postgresql": "^4.5.7",

RequestContext example for GraphQL

Is your feature request related to a problem? Please describe.
I'm using GraphQL with NestJS but noticing that the same entity manager is being used for all requests and I'm not sure how to proceed with establishing a new context per request.

Describe the solution you'd like
It'd be great if this library just worked out of the box with NestJS GraphQL but if not maybe some example code would be great to help people get started.

Thanks!

MikroOrmModule.forRootAsync ignores MikroOrm provider useFactory function

Describe the bug
When importing MikroOrm with forRootAsync and using Factory provider: useFactory the given options are ignored and defaults are used instead.
From the stack trace it looks like it is instantiating MikroOrm class directly instead of using useFactory from the MikroOrm custom provider that uses MikroOrm.init() method.
https://github.com/mikro-orm/nestjs/blob/master/src/mikro-orm.providers.ts#L24
But these are my suppositions and I feel I'm missing something.

Stack trace

[Nest] 65   - 01/08/2021, 9:00:27 PM   [ExceptionHandler] No platform type specified, please fill in `type` or provide custom driver class in `driver` option. Available platforms types: [ 'mongo', 'mysql', 'mariadb', 'postgresql', 'sqlite' ] +30ms
Error: No platform type specified, please fill in `type` or provide custom driver class in `driver` option. Available platforms types: [ 'mongo', 'mysql', 'mariadb', 'postgresql', 'sqlite' ]
    at Configuration.validateOptions (/app/node_modules/@mikro-orm/core/utils/Configuration.js:170:13)
    at new Configuration (/app/node_modules/@mikro-orm/core/utils/Configuration.js:25:12)
    at new MikroORM (/app/node_modules/@mikro-orm/core/MikroORM.js:23:21)
    at Injector.instantiateClass (/app/node_modules/@nestjs/core/injector/injector.js:286:19)
    at callback (/app/node_modules/@nestjs/core/injector/injector.js:42:41)
    at processTicksAndRejections (internal/process/task_queues.js:93:5)
    at async Injector.resolveConstructorParams (/app/node_modules/@nestjs/core/injector/injector.js:114:24)
    at async Injector.loadInstance (/app/node_modules/@nestjs/core/injector/injector.js:46:9)
    at async Injector.loadProvider (/app/node_modules/@nestjs/core/injector/injector.js:68:9)
    at async Promise.all (index 4)

To Reproduce
Simply use MikroOrmModule.forRootAsync() in imports[] in Nestjs AppModule.
In my case I'm injecting ConfigService from Nestjs, but i don't think this should change something.

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
      load: [configuration]
    }),
    MikroOrmModule.forRootAsync({
      useFactory: (configService: ConfigService) => ({
        metadataProvider: TsMorphMetadataProvider,
        namingStrategy: EntityCaseNamingStrategy,
        entities: ["./dist/**/entities/*.entity.js"],
        entitiesTs: ["./src/**/entities/*.entity.ts"],
        type: "postgresql",
        dbName: configService.get("database.name"),
        host: configService.get("database.host"),
        port: configService.get("database.port"),
        user: configService.get("database.user"),
        password: configService.get("database.password")
      }),
      inject: [ConfigService]
    })
  ],
  controllers: [AppController],
  providers: [AppService, MikroORM]
})

Expected behavior
Get a MikroOrm instance with provided configuration.

Versions

Dependency Version
node 14
typescript 3.7.4
mikro-orm/core 4.3.4
mikro-orm/nestjs 4.2.0
mikro-orm/postgresql 4.3.4
mikro-orm/reflection 4.3.4

The UseRequestContext make the method return void

Describe the bug
I am develop chat app with nestjs gateway(socketio). I apply UseRequestContext on a method in the service that have it return a value, but it return void instead. When I remove UseRequestContext it return value normal

To Reproduce
Steps to reproduce the behavior:

  1. Write a Service with method return value
  2. Apply UseRequestContext to method
  3. Call it

Expected behavior
Method return value

Versions
"@mikro-orm/core": "^4.3.4",
"@mikro-orm/nestjs": "^4.2.0",

Dependency Version
node 10.19.0
typescript ^3.7.4
mikro-orm ^4.3.4
postgres ^4.3.4

forFeature method not accepting EntitySchema as valid type for entities argument

Describe the bug
First of all, awesome project, keep the great work! :)

I´m trying to use to use MikroORM in NestJS setup as a monorepo (so no glob file patterns for me), and trying to use the autoLoadEntities option to be able declare the entities in each module via forFeature.
The problem is that I would like to use EntitySchema declaration instead of using decorators, and the type in the forFeature method doesn't allow them.
I've checked that, if I ignore the typescript error, everything works fine, so my guess is that it's just an oversight of not also declaring EntitySchema as a valid type there.

Stack trace

Type 'EntitySchema<Account, undefined>' is not assignable to type 'EntityName<AnyEntity<any>>'.

To Reproduce
Steps to reproduce the behavior:

  1. Instantiate MikroOrmModule with autoLoadEntities option enabled.
  2. Declare in the forFeature method the EntitySchema you want to use.
  3. Typescript explodes
  4. Ignore TS error
  5. Everything works as expected

Expected behavior
forFeature method to allow for EntitySchema type.

Versions

Dependency Version
node 16.15.1
typescript 4.7.4
mikro-orm 5.2.0
mongodb-driver 5.2.0

nestjs news version upgrade and MikroOrmCoreModule bugs

image

iam upgrade nestjs and

api:dev: 
api:dev: [Nest] 912594  - 06/01/2022, 3:52:04 PM   ERROR [ExceptionHandler] Nest can't resolve dependencies of the MikroOrmCoreModule (Symbol(mikro-orm-module-options), ?). Please make sure that the argument ModuleRef at index [1] is available in the MikroOrmCoreModule context.
api:dev: 
api:dev: Potential solutions:
api:dev: - If ModuleRef is a provider, is it part of the current MikroOrmCoreModule?
api:dev: - If ModuleRef is exported from a separate @Module, is that module imported within MikroOrmCoreModule?
api:dev:   @Module({
api:dev:     imports: [ /* the Module containing ModuleRef */ ]
api:dev:   })
api:dev: 
api:dev: Error: Nest can't resolve dependencies of the MikroOrmCoreModule (Symbol(mikro-orm-module-options), ?). Please make sure that the argument ModuleRef at index [1] is available in the MikroOrmCoreModule context.
api:dev: 
api:dev: Potential solutions:
api:dev: - If ModuleRef is a provider, is it part of the current MikroOrmCoreModule?
api:dev: - If ModuleRef is exported from a separate @Module, is that module imported within MikroOrmCoreModule?
api:dev:   @Module({
api:dev:     imports: [ /* the Module containing ModuleRef */ ]
api:dev:   })

TypeError: Cannot read property 'getContext' of undefined

Hello am trying to retrieve one record from the database am getting this error "TypeError: Cannot read property 'getContext' of undefined". What could be the issue?

Below is my code in an entity repository that's being called in a service in Nest Js Framework

async validateUserPassword(signInCredentialsDto: SignInCredentialsDto): Promise<LoginUsers | null> { const { email, password } = signInCredentialsDto; const user = await this.em.findOne(LoginUsers, { email: email }) console.log(user) if(user && await user.validatePassword(password)){ return user; }else{ return null; } }

Error when using ResolveField of graphql and populate of mikro-orm

Describe the bug
If mikro-orm populate in community <- board <- post relationship,
board Collection object, ResolveField continues to run and an error appears.
I want to use both. Is there a solution?

Entitiy

@ObjectType('Community')
@Entity({ tableName: 'community.community'})
export class Community {

  @Field(() => ID)
  @PrimaryKey({ type: BigIntType })
  id?: string;
}
@Entity({ tableName: 'community.board' })
@ObjectType('Board')
export class Board {
  @PrimaryKey({ type: BigIntType})
  @Field(() => ID)
  id: string;

  @ManyToOne(() => Community, { fieldName: 'community_id'})
  community: Community;

  @OneToMany(() => Post, (post) => post.board, { orphanRemoval: true })
  post? = new Collection<Post>(this);

  @Field({ defaultValue: 0 })
  postCnt?: number;
}
@Entity({ tableName: 'community.post' })
@ObjectType('Post')
export class Post {
  @PrimaryKey({ type: BigIntType })
  @Field(() => ID)
  id: string;

  @ManyToOne(() => Board, { fieldName: 'board_id'})
  board: Board;
}

Resolver

@Resolver(() => Board)
@UseGuards(SessionGuard)
export class BoardResolver {
  constructor(private readonly em: EntityManager) {}

  @Query(() => [Board], { nullable: true })
  async getBoardList(@Args('communityId') communityId: number): Promise<Board[]> {
    return await this.em.find(Board, { community: { id: String(communityId) } }, ['post']);
  }

  @ResolveField(() => Int, { name: 'postCnt' })
  async getPostCnt(@Parent() board: Board) {
    return await this.em.count(Post, { board: board.id });
  }
}

Error message

console

[NestWinston] Error     2021. 3. 3. 오후 1:43:09 /graphQL Maximum call stack size exceeded undefined INTERNAL_SERVER_ERROR - {}

graphql error message

{
  "errors": [
    {
      "message": "Maximum call stack size exceeded"
    }
  ],
  "data": {
    "getBoardList": null
  }
}

Versions

Dependency Version
node v14.15.4
typescript 4.1.3
mikro-orm 4.4.3
postgresql ?

Custom repositories not sharing the same request scoped Entity Manager

Describe the bug
When injecting both the EntityManager and a custom repository I noticed that the EntityManager bound to the repository is not the same EntityManager. I expect to always get the same EntityManager for a given request.

@Injectable()
export class CatService {
  constructor(
    public readonly em: EntityManager,
    public readonly repo: CatRepository,
  ) {}

  compareEntityManagers() {
    return this.em.id === this.repo.getEntityManager().id; // expect this to be true
  }
}

Stack trace

...

To Reproduce
Steps to reproduce the behavior:

  1. Clone repository github.com/christiaan-lombard/nestjs-mikro-orm-test
  2. npm install
  3. docker-compose up to start up a mysql instance
  4. npm run test to run test src/app.module.spec.ts

Expected behavior
I would like to be able to inject both custom repositories and the EntityManager in a service and have them share the same EntityManager for the current request.

I expect the following test to pass:

import { EntityManager } from '@mikro-orm/mysql';
import { ContextId, ContextIdFactory } from '@nestjs/core';
import { REQUEST_CONTEXT_ID } from '@nestjs/core/router/request/request-constants';
import { Test, TestingModule } from '@nestjs/testing';
import { AppModule } from './app.module';
import { Cat } from './entities/cat.entity';
import { CatRepository } from './repositories/cat.repository';

describe('AppModule', () => {
  let module: TestingModule;
  let contextId: ContextId;

  beforeAll(async () => {
    module = await Test.createTestingModule({
      imports: [AppModule],
    }).compile();

    contextId = ContextIdFactory.create();

    module.registerRequestByContextId(
      { [REQUEST_CONTEXT_ID]: contextId },
      contextId,
    );
  });

  afterAll(async () => await module.close());

  it('resolves same EntityManager', async () => {
    const em = await module.resolve<EntityManager>(EntityManager, contextId);
    const em2 = await module.resolve<EntityManager>(EntityManager, contextId);

    expect(em.id).toBe(em2.id);
    expect(em).toStrictEqual(em2);
  });

  it('resolves same EntityManager for repositories created by EM', async () => {
    const em = await module.resolve<EntityManager>(EntityManager, contextId);
    const repo = em.getRepository(Cat);
    expect(repo).toBeInstanceOf(CatRepository);
    expect(em.id).toBe(repo.getEntityManager().id);
    expect(em).toStrictEqual(repo.getEntityManager());
  });

  it('resolves same EntityManager for repositories', async () => {
    const em = await module.resolve<EntityManager>(EntityManager, contextId);
    const repo = await module.resolve<CatRepository>(CatRepository, contextId);

    expect(em.id).toBe(repo.getEntityManager().id); // fails
  });
});

Versions

Dependency Version
node v16.13.0
typescript ^4.3.5
mikro-orm ^5.1.0
nestjs ^8.0.0

Request-scoped transaction is better served by NestJS Injection Scoping

@Injectable()
export class MikroOrmMiddleware implements NestMiddleware {
constructor(private readonly orm: MikroORM) {}
use(req: unknown, res: unknown, next: (...args: any[]) => void) {
RequestContext.create(this.orm.em, next);
}
}

It seems like this would be better served using a request-based injection-scope as described here (https://docs.nestjs.com/fundamentals/injection-scopes) and using that for the middleware.

I can prototype something up, too.

failing npm audit fix caused to dependency conflict

Describe the bug
I receive a peer dependency conflict with nestjs@8 and mikroorm/[email protected] when calling npm audit fix.

Stack trace

 % npm audit fix
npm ERR! code ERESOLVE
npm ERR! ERESOLVE could not resolve
npm ERR! 
npm ERR! While resolving: @mikro-orm/[email protected]
npm ERR! Found: @nestjs/[email protected]
npm ERR! node_modules/@nestjs/core
npm ERR!   @nestjs/core@"^8.0.9" from the root project
npm ERR!   peer @nestjs/core@"^7.0.0||^8.0.0" from @mikro-orm/[email protected]
npm ERR!   node_modules/@mikro-orm/nestjs
npm ERR!     @mikro-orm/nestjs@"^4.3.0" from the root project
npm ERR!   5 more (@nestjs/microservices, @nestjs/platform-express, ...)
npm ERR! 
npm ERR! Could not resolve dependency:
npm ERR! peer @nestjs/core@"^7.0.0||^8.0.0" from @mikro-orm/[email protected]
npm ERR! node_modules/@mikro-orm/nestjs
npm ERR!   @mikro-orm/nestjs@"^4.3.0" from the root project
npm ERR! 
npm ERR! Conflicting peer dependency: @nestjs/[email protected]
npm ERR! node_modules/@nestjs/core
npm ERR!   peer @nestjs/core@"^7.0.0||^8.0.0" from @mikro-orm/[email protected]
npm ERR!   node_modules/@mikro-orm/nestjs
npm ERR!     @mikro-orm/nestjs@"^4.3.0" from the root project
npm ERR! 
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.
npm ERR! 
npm ERR! See .../.npm/eresolve-report.txt for a full report.

npm ERR! A complete log of this run can be found in:
npm ERR!     .../.npm/_logs/2021-10-21T09_18_54_823Z-debug.log

To Reproduce
Steps to reproduce the behavior:
The execution happened within of the project https://github.com/hpi-schul-cloud/schulcloud-server/tree/765c1f3a632ae2c539575ab4d9d061898c0d96e9

Expected behavior
A clear and concise description of what you expected to happen.

  • npm exits without error

Additional context
Add any other context about the problem here.

Versions

| Dependency | Version |
| npm | 8 |
| node | 16 |
| mikro-orm/nestjs | 4.3.0 |
| nestjs/core | 8.1.1 or 8.0.9 |

Question: how to mock orm:MikroOrm in a class that uses UseRequestContext decorator

Describe the bug
hello i am trying to unit test a class that have the UseRequestContext decorator like this

@Controller()
export class AuthenticationController{
        // class need to have this.orm for the UseRequestContext decorator to work
	private readonly orm:MikroORM<MongoDriver>;
	private readonly authenticationService:AuthenticationService;
	
	constructor(
		orm:MikroORM<MongoDriver>,
		authenticationService:AuthenticationService
	){
		this.orm=orm;
		this.authenticationService=authenticationService;
		
	}
	
	@GrpcMethod()
	@UseRequestContext()
	login(data:LoginRequest.AsObject):Promise<LoginResponse.AsObject>{
		return this.authenticationService.login(data);
	}
	
}

but i can't mock the orm property of the class, this is the test file im using, i use MikroORM.init and use that value for the mock

describe('AuthenticationController',():void=>{
	let controller:AuthenticationController;

        beforeEach(async():Promise<void>=>{
		const module:TestingModule=await Test.createTestingModule({
			controllers:[AuthenticationController],
			providers:[
				AuthenticationService,
				{
					provide:MikroORM,
					useValue:await MikroORM.init<MongoDriver>({type:'mongo',entities:[User,UserRole],dbName:'test'})
				}
			]
		}).compile();
		
		controller=module.get<AuthenticationController>(AuthenticationController);
		authenticationService=module.get<AuthenticationService>(AuthenticationService);
		
	});
	
	it('should be defined',():void=>{
		expect(controller).toBeDefined();
	});

});

im getting this error because the MikroORM.init method is trying to connect to a database

Exceeded timeout of 5000 ms for a hook

i tried to set the option connect: false for the MikroORM.init method to no try to connect to any database like stated in this comment mikro-orm/nestjs-realworld-example-app#7 (comment)
but typescript complains that the connect option is not a valid property

{
	provide:MikroORM,
        // @ts-ignore
	useValue:await MikroORM.init<MongoDriver>({type:'mongo',entities:[User,UserRole],dbName:'test',connect:false})
}
TS2345: Argument of type '{ type: "mongo"; entities: (typeof User | typeof UserRole)[]; dbName: string; connect: boolean; }' is not assignable to parameter of type 'Options<MongoDriver> | Configuration<MongoDriver>'.   Object literal may only specify known properties, and 'connect' does not exist in type 'Options<MongoDriver> | Configuration<MongoDriver>'.

i tried to ignore the typescript error with @ts-ignore but still i get the Exceeded timeout error

also if i pass a empty to mock

{
    provide:MikroORM,
    useValue:{}
}

i get this error

@UseRequestContext() decorator can only be applied to methods of classes that carry `orm: MikroORM`

if i pass a empty object to the MikroORM.init method

{
    provide:MikroORM,
    useValue:await MikroORM.init<MongoDriver>({})
}

i get an error too that says i must provide the options
type: 'mongo', 'mysql', 'mariadb', 'postgresql' or 'sqlite'
entities: non empty array of entitites
dbName or clientUrl

my question is: what is the recommended way to mock the orm:MikroORM property in a class that uses the UseRequestContext decorator?

Versions

Dependency Version
node 16.13.0
typescript 4.5.4
mikro-orm 4.5.9
your-driver mongo

Alternative NestJS Approach

In moving to a persist/flush model system like Mikro, I find it important to prevent developers on my team from making mistakes like using some global entity manager with a persisted identity map across requests. At the moment, it is very easy to inject Mikro into any service, controller, etc without realizing the repercussions. At a high level, these are my requirements:

  • No one should be able access a singleton instance of EntityManager except for the Mikro module itself.
  • If there is ever a need to access the application-level singleton, it should be done through some obvious abstraction like orm.getGlobalEntityManager()
  • No magic should be involved with request scopes such as node.js domains (deprecated) or pulling things from global statics. Given that a service does not know if it needs to be ran in a transaction or not, guidance/best practice should be to always pass an instance of EntityManager to your downstream services via function arguments
  • The Mikro NestJS module should provide interceptors and decorators for making request scoped work easier (i'm using this for both REST and GraphQL endpoints), example:

EntityManagerInterceptor.ts

import { createParamDecorator, ExecutionContext } from '@nestjs/common';
import { EntityManager } from '@mikro-orm/postgresql';
import { CallHandler, ExecutionContext, NestInterceptor } from '@nestjs/common';
import { Observable } from 'rxjs';
import { mergeMap } from 'rxjs/operators';

export default class EntityManagerInterceptor implements NestInterceptor {
  constructor(private em: EntityManager) {}

  async intercept(context: ExecutionContext, next: CallHandler<any>): Promise<Observable<any>> {
    context['em'] = this.em.fork();

    return next.handle().pipe(
      mergeMap(async (output) => {
        await context['em'].flush();

        return output;
      })
    );
  }
}

RequestEntityManager.ts

export default createParamDecorator((data: unknown, context: ExecutionContext) => {
  if (!context['em']) {
    throw new Error('Could not find a request-scoped EntityManager');
  }

  return context['em'];
});
// graphql
@Mutation()
myMutation(@RequestEntityManager() em: EntityManager){}

// rest
@Get()
async myEndpoint(@RequestEntityManager() em: EntityManager){}

Invalid wildcard path for configuration with path-to-regexp v6 (Fastify v3)

Describe the bug

path-to-regexp deprecated the usage of * for a wildcard route:

No wildcard asterisk (*) - use parameters instead ((.*) or :splat*)

While using Fastify v3, which uses path-to-regexp v6, and setting app.setGlobalPrefix('api'); the project doesn't run.

Changing * to (.*) worked locally for me, though I have not confirmed if that will work with path-to-regexp pre v6.

Stack trace

(node:29800) UnhandledPromiseRejectionWarning: TypeError: Unexpected MODIFIER at 13, expected END
    at mustConsume (/Users/quinn/Dev/project/Phoenix/node_modules/middie/node_modules/path-to-regexp/src/index.ts:157:11)
    at parse (/Users/quinn/Dev/project/node_modules/middie/node_modules/path-to-regexp/src/index.ts:228:5)
    at stringToRegexp (/Users/quinn/Dev/project/node_modules/middie/node_modules/path-to-regexp/src/index.ts:494:25)
    at pathToRegexp (/Users/quinn/Dev/project/node_modules/middie/node_modules/path-to-regexp/src/index.ts:616:10)
    at Object.use (/Users/quinn/Dev/project/node_modules/middie/engine.js:23:16)
    at Object.use (/Users/quinn/Dev/project/node_modules/middie/index.js:30:21)
    at /Users/quinn/Dev/project/node_modules/@nestjs/platform-fastify/adapters/fastify-adapter.js:127:27
    at MiddlewareModule.registerHandler (/Users/quinn/Dev/project/node_modules/@nestjs/core/middleware/middleware-module.js:138:9)
    at MiddlewareModule.bindHandler (/Users/quinn/Dev/project/node_modules/@nestjs/core/middleware/middleware-module.js:96:25)
    at processTicksAndRejections (internal/process/task_queues.js:97:5)

To Reproduce
Steps to reproduce the behavior:

  1. In main.ts, add a global prefix: app.setGlobalPrefix('api');
  2. Initialize the app with MikroOrmModule.forRoot()

Expected behavior
Should properly set the global prefix and also initialize MikroOrm

Versions

Dependency Version
node v14
@mikro-orm/core v4 (latest)
@mikro-orm/nestjs v4 (latest)
@nestjs/core v7.4.1

Add a standard interceptor for the transformation of instance into POJO

For most simple CRUDs don't often have to resort to mapping the entity via the response DTO, but often need to hide fields in the entity using mikro-orm or decorators from the class-transformer library. All this leads to writing similar code for the service (see below). This typing causes nestjs plugins working with Abstract Syntax Tree analysis, such as - @nestjs/swagger/plugin, to simply break, and fail to generate the API schema

...

  public async create(data: CreateUserDto): Promise<EntityData<UserEntity>> {
    const entity = this.sqlEntityRepository.create(data);
    await this.sqlEntityRepository.persistAndFlush(entity)
    return entity.toPOJO();
  }

...

The proposed version of serialization works before the serializer nestjs and gives the prepared class further down the call chain (the order of interceptor calls is important) without breaking service typing and does not require creating a DTO response

// mikro-orm-serializer.interceptor.ts
import { isObject } from '@nestjs/common/utils/shared.utils';
import { BaseEntity } from '@mikro-orm/core';
import { map, Observable } from 'rxjs';
import {
  Injectable,
  CallHandler,
  StreamableFile,
  NestInterceptor,
  ExecutionContext,
  PlainLiteralObject,
} from '@nestjs/common';

@Injectable()
export class MikroOrmSerializerInterceptor implements NestInterceptor {

  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    return next
      .handle()
      .pipe(map((res: PlainLiteralObject | Array<PlainLiteralObject>) => this.serialize(res)));
  }

  /**
   * Serializes responses that are non-null objects nor streamable files.
   */
  serialize(
    response: PlainLiteralObject | Array<PlainLiteralObject>,
  ): PlainLiteralObject | Array<PlainLiteralObject> {
    if (!isObject(response) || response instanceof StreamableFile) return response;
    return Array.isArray(response)
      ? response.map((item) => this.transformToPOJO(item))
      : this.transformToPOJO(response);
  }

  /**
   * Transformation to POJO if argument is a BaseEntity instance
   */
  transformToPOJO(plainOrEntity: any): PlainLiteralObject {
    return plainOrEntity instanceof BaseEntity ? plainOrEntity.toPOJO() : plainOrEntity;
  }
}
  • Use as a global interceptor in conjunction with ClassSerializerInterceptor
//main.ts
   ...

  const classSerializerInterceptor = new ClassSerializerInterceptor(app.get(Reflector));
  const mikroOrmSerializerInterceptor = new MikroOrmSerializerInterceptor();

  return app
    .useGlobalInterceptors(classSerializerInterceptor, mikroOrmSerializerInterceptor)
    .listen(configService.get('PORT'), configService.get('HOST'));

Alternatively, can rewrite all logic related to metadata reflection using the class-transformer library

But I don't think that's a good option for upcoming releases

Handling multiple database connections

Is your feature request related to a problem? Please describe.
Looking for examples on how to handle multiple postgres database connections with NestJS.

Describe alternatives you've considered
Tried initializing multiple MikroORM modules but there doesn't seem a clear way to specify the database name (only schema) on the model.

@Module({
  imports: [ConfigModule.forRoot(),
  MikroOrmModule.forRoot({
    entities: ['./dist/entities/*'],
    entitiesTs: ['./src/entities/!(*.spec).ts'],
    dbName: 'foo"
    type: 'postgresql',
    password: ...
    host: ...
  }),
  MikroOrmModule.forRoot({
    entities: ['./dist/entities/*'],
    entitiesTs: ['./src/entities/!(*.spec).ts'],
    dbName: 'bar',
    type: 'postgresql',
    password: ...
    host: ...
  }),

Additional context
N/A

Please make sure that the argument SqlEntityManager at index [1] is available in the AppModule context.

Describe the bug
I got this error when injecting EntityManager from @mikro-orm/postgresql. Right now my solution is just to import EntityManager from @mikro-orm/knex or @mikro-orm/core and it can run without error. But earlier when i tried MikroORM v5, i got the same error when importing from @mikro-orm/knex. Now the only one that works is from @mikro-orm/core.

image

To Reproduce
Steps to reproduce the behavior:

  1. Create new nestjs project
  2. Install MikroORM dependency (https://mikro-orm.io/docs/next/usage-with-nestjs/#installation)
  3. Register MikroORM module in AppModule
    image
  4. Inject EntityManager from @mikro-orm/postgresql
    image

Additional context
Add any other context about the problem here.

Versions

Dependency Version
node ?
nestjs ^8.1.1
typescript ^4.4.4
mikro-orm ^4.5.9
your-driver postgresql

RequestContext cannot be accessed inside middleware

|When accessing the RequestContext inside a controller like RequestContext.currentRequestContext() you get an Object and it is even possible to add new properties to it. However, inside nestjs middleware you get 'undefined' instead of an Object.

Stack trace

console.log
    undefined

      at ContextMiddleware.use (../src/context.middleware.ts:8:13)

To Reproduce
Steps to reproduce the behavior:

  1. git clone https://github.com/RiskChallenger/mikro-orm-issue
  2. yarn
  3. yarn start:dev

Expected behavior
Expected to get the RequestContext inside the middleware instead of undefined

Versions

Dependency Version
mikro-orm 4.0.0-alpha.12
mikro-orm/nestjs 4.0.0-alpha.1
node 14.4.0
knex 0.21.2
mysql 2 2.1.0
typescript 3.9.7

No entities found, please use `entities` option

Describe the bug
When I use forRootAsync in the AppModule and define entities in their own modules using forFeature I get: "Error: No entities found, please use entities option" when I try to compile.

I read in the documentation and it says you only need define base entities in forRootAsync so I am confused.

Stack trace
N/a

To Reproduce
Steps to reproduce the behavior:

  1. Import forRootAsync in AppModule with no entities
  2. Import forFeature in each module with their own entity
  3. Import each module (that uses forFeature) in AppModule

Expected behavior
forRootAsync should recognize that I have entities defined using forFeature and therefore not require that I define any entities in forRootAsync.

Additional context
N/a

Versions

Dependency Version
node v12.16.3
typescript v3.7.4
mikro-orm v4.2.1 (nestjs v4.2.0)
your-driver mongodb

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.