Giter VIP home page Giter VIP logo

nestjs's Introduction

MikroORM

TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, MariaDB, PostgreSQL and SQLite (including libSQL) databases.

Heavily inspired by Doctrine and Hibernate.

NPM version NPM dev version Chat on discord Downloads Coverage Status Maintainability Build Status

๐Ÿค” Unit of What?

You might be asking: What the hell is Unit of Work and why should I care about it?

Unit of Work maintains a list of objects (entities) affected by a business transaction and coordinates the writing out of changes. (Martin Fowler)

Identity Map ensures that each object (entity) gets loaded only once by keeping every loaded object in a map. Looks up objects using the map when referring to them. (Martin Fowler)

So what benefits does it bring to us?

Implicit Transactions

First and most important implication of having Unit of Work is that it allows handling transactions automatically.

When you call em.flush(), all computed changes are queried inside a database transaction (if supported by given driver). This means that you can control the boundaries of transactions simply by calling em.persistLater() and once all your changes are ready, calling flush() will run them inside a transaction.

You can also control the transaction boundaries manually via em.transactional(cb).

const user = await em.findOneOrFail(User, 1);
user.email = '[email protected]';
const car = new Car();
user.cars.add(car);

// thanks to bi-directional cascading we only need to persist user entity
// flushing will create a transaction, insert new car and update user with new email
// as user entity is managed, calling flush() is enough
await em.flush();

ChangeSet based persistence

MikroORM allows you to implement your domain/business logic directly in the entities. To maintain always valid entities, you can use constructors to mark required properties. Let's define the User entity used in previous example:

@Entity()
export class User {

  @PrimaryKey()
  id!: number;

  @Property()
  name!: string;

  @OneToOne(() => Address)
  address?: Address;

  @ManyToMany(() => Car)
  cars = new Collection<Car>(this);

  constructor(name: string) {
    this.name = name;
  }

}

Now to create new instance of the User entity, we are forced to provide the name:

const user = new User('John Doe'); // name is required to create new user instance
user.address = new Address('10 Downing Street'); // address is optional

Once your entities are loaded, make a number of synchronous actions on your entities, then call em.flush(). This will trigger computing of change sets. Only entities (and properties) that were changed will generate database queries, if there are no changes, no transaction will be started.

const user = await em.findOneOrFail(User, 1, {
  populate: ['cars', 'address.city'],
});
user.title = 'Mr.';
user.address.street = '10 Downing Street'; // address is 1:1 relation of Address entity
user.cars.getItems().forEach(car => car.forSale = true); // cars is 1:m collection of Car entities
const car = new Car('VW');
user.cars.add(car);

// now we can flush all changes done to managed entities
await em.flush();

em.flush() will then execute these queries from the example above:

begin;
update "user" set "title" = 'Mr.' where "id" = 1;
update "user_address" set "street" = '10 Downing Street' where "id" = 123;
update "car"
  set "for_sale" = case
    when ("id" = 1) then true
    when ("id" = 2) then true
    when ("id" = 3) then true
    else "for_sale" end
  where "id" in (1, 2, 3)
insert into "car" ("brand", "owner") values ('VW', 1);
commit;

Identity Map

Thanks to Identity Map, you will always have only one instance of given entity in one context. This allows for some optimizations (skipping loading of already loaded entities), as well as comparison by identity (ent1 === ent2).

๐Ÿ“– Documentation

MikroORM documentation, included in this repo in the root directory, is built with Docusaurus and publicly hosted on GitHub Pages at https://mikro-orm.io.

There is also auto-generated CHANGELOG.md file based on commit messages (via semantic-release).

โœจ Core Features

๐Ÿ“ฆ Example Integrations

You can find example integrations for some popular frameworks in the mikro-orm-examples repository:

TypeScript Examples

JavaScript Examples

๐Ÿš€ Quick Start

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

Since v4, you should install the driver package, but not the db connector itself, e.g. install @mikro-orm/sqlite, but not sqlite3 as that is already included in the driver package.

yarn add @mikro-orm/core @mikro-orm/mongodb       # for mongo
yarn add @mikro-orm/core @mikro-orm/mysql         # for mysql/mariadb
yarn add @mikro-orm/core @mikro-orm/mariadb       # for mysql/mariadb
yarn add @mikro-orm/core @mikro-orm/postgresql    # for postgresql
yarn add @mikro-orm/core @mikro-orm/mssql         # for mssql
yarn add @mikro-orm/core @mikro-orm/sqlite        # for sqlite
yarn add @mikro-orm/core @mikro-orm/better-sqlite # for better-sqlite
yarn add @mikro-orm/core @mikro-orm/libsql        # for libsql

or

npm i -s @mikro-orm/core @mikro-orm/mongodb       # for mongo
npm i -s @mikro-orm/core @mikro-orm/mysql         # for mysql/mariadb
npm i -s @mikro-orm/core @mikro-orm/mariadb       # for mysql/mariadb
npm i -s @mikro-orm/core @mikro-orm/postgresql    # for postgresql
npm i -s @mikro-orm/core @mikro-orm/mssql         # for mssql
npm i -s @mikro-orm/core @mikro-orm/sqlite        # for sqlite
npm i -s @mikro-orm/core @mikro-orm/better-sqlite # for better-sqlite
npm i -s @mikro-orm/core @mikro-orm/libsql        # for libsql

Next, if you want to use decorators for your entity definition, you will need to enable support for decorators as well as esModuleInterop in tsconfig.json via:

"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"esModuleInterop": true,

Alternatively, you can use EntitySchema.

Then call MikroORM.init as part of bootstrapping your app:

To access driver specific methods like em.createQueryBuilder() we need to specify the driver type when calling MikroORM.init(). Alternatively we can cast the orm.em to EntityManager exported from the driver package:

import { EntityManager } from '@mikro-orm/postgresql';
const em = orm.em as EntityManager;
const qb = em.createQueryBuilder(...);
import type { PostgreSqlDriver } from '@mikro-orm/postgresql'; // or any other SQL driver package

const orm = await MikroORM.init<PostgreSqlDriver>({
  entities: ['./dist/entities'], // path to your JS entities (dist), relative to `baseDir`
  dbName: 'my-db-name',
  type: 'postgresql',
});
console.log(orm.em); // access EntityManager via `em` property

There are more ways to configure your entities, take a look at installation page.

Read more about all the possible configuration options in Advanced Configuration section.

Then you will need to fork entity manager for each request so their identity maps will not collide. To do so, use the RequestContext helper:

const app = express();

app.use((req, res, next) => {
  RequestContext.create(orm.em, next);
});

You should register this middleware as the last one just before request handlers and before any of your custom middleware that is using the ORM. There might be issues when you register it before request processing middleware like queryParser or bodyParser, so definitely register the context after them.

More info about RequestContext is described here.

Now you can start defining your entities (in one of the entities folders). This is how simple entity can look like in mongo driver:

./entities/MongoBook.ts

@Entity()
export class MongoBook {

  @PrimaryKey()
  _id: ObjectID;

  @SerializedPrimaryKey()
  id: string;

  @Property()
  title: string;

  @ManyToOne(() => Author)
  author: Author;

  @ManyToMany(() => BookTag)
  tags = new Collection<BookTag>(this);

  constructor(title: string, author: Author) {
    this.title = title;
    this.author = author;
  }

}

For SQL drivers, you can use id: number PK:

./entities/SqlBook.ts

@Entity()
export class SqlBook {

  @PrimaryKey()
  id: number;

}

Or if you want to use UUID primary keys:

./entities/UuidBook.ts

import { v4 } from 'uuid';

@Entity()
export class UuidBook {

  @PrimaryKey()
  uuid = v4();

}

More information can be found in defining entities section in docs.

When you have your entities defined, you can start using ORM either via EntityManager or via EntityRepositorys.

To save entity state to database, you need to persist it. Persist takes care or deciding whether to use insert or update and computes appropriate change-set. Entity references that are not persisted yet (does not have identifier) will be cascade persisted automatically.

// use constructors in your entities for required parameters
const author = new Author('Jon Snow', '[email protected]');
author.born = new Date();

const publisher = new Publisher('7K publisher');

const book1 = new Book('My Life on The Wall, part 1', author);
book1.publisher = publisher;
const book2 = new Book('My Life on The Wall, part 2', author);
book2.publisher = publisher;
const book3 = new Book('My Life on The Wall, part 3', author);
book3.publisher = publisher;

// just persist books, author and publisher will be automatically cascade persisted
await em.persistAndFlush([book1, book2, book3]);

To fetch entities from database you can use find() and findOne() of EntityManager:

const authors = em.find(Author, {}, { populate: ['books'] });

for (const author of authors) {
  console.log(author); // instance of Author entity
  console.log(author.name); // Jon Snow

  for (const book of author.books) { // iterating books collection
    console.log(book); // instance of Book entity
    console.log(book.title); // My Life on The Wall, part 1/2/3
  }
}

More convenient way of fetching entities from database is by using EntityRepository, that carries the entity name, so you do not have to pass it to every find and findOne calls:

const booksRepository = em.getRepository(Book);

const books = await booksRepository.find({ author: '...' }, { 
  populate: ['author'],
  limit: 1,
  offset: 2,
  orderBy: { title: QueryOrder.DESC },
});

console.log(books); // Loaded<Book, 'author'>[]

Take a look at docs about working with EntityManager or using EntityRepository instead.

๐Ÿค Contributing

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

Authors

๐Ÿ‘ค 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

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!

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?

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

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

@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

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 :)

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",

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)

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

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.

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:   })

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

[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.

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

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; } }

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){}

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

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

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.

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

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 ?

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

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

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 |

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.

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 ?

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!

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

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",

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

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

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

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.

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

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

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

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.

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

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.

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

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?

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

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.