Coder Social home page Coder Social 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
  }

}

Using AsyncLocalStorage for request context

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

By default, the domain api is used in the RequestContext helper. 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()
export class Author {

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

}

**./author.repository.ts**

@Repository(Author)
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) { }

}

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 jsprw avatar quinnturner avatar

Watchers

 avatar

Forkers

joelvenable

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.