Skip to content

Commit

Permalink
feat(core): add autoLoadEntities option
Browse files Browse the repository at this point in the history
Closes #8
  • Loading branch information
B4nan committed Sep 23, 2020
1 parent 68886f4 commit ceaf16e
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 15 deletions.
37 changes: 37 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,43 @@ export class PhotoService {
}
```

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

```ts
@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.
## Using `AsyncLocalStorage` for request context

By default, `domain` api use used in the `RequestContext` helper. Since `@mikro-orm/core@4.0.3`,
Expand Down
13 changes: 6 additions & 7 deletions src/mikro-orm-core.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,13 @@ export class MikroOrmCoreModule implements OnApplicationShutdown {
return;
}

const isNestMiddleware = (consumer: MiddlewareConsumer): consumer is NestMiddlewareConsumer => {
return typeof (consumer as any).httpAdapter === 'object';
};

const isNestMiddleware = (
consumer: MiddlewareConsumer
): consumer is NestMiddlewareConsumer =>
typeof (consumer as any).httpAdapter === 'object';

const usingFastify = (consumer: NestMiddlewareConsumer) =>
consumer.httpAdapter.constructor.name.toLowerCase().startsWith('fastify');
const usingFastify = (consumer: NestMiddlewareConsumer) => {
return consumer.httpAdapter.constructor.name.toLowerCase().startsWith('fastify');
};

const forRoutesPath =
this.options.forRoutesPath ??
Expand Down
3 changes: 2 additions & 1 deletion src/mikro-orm.common.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { EntityName, MikroORM, Utils } from '@mikro-orm/core';
import { AnyEntity, EntityName, MikroORM, Utils } from '@mikro-orm/core';
import { Inject, Logger } from '@nestjs/common';

export const MIKRO_ORM_MODULE_OPTIONS = Symbol('mikro-orm-module-options');
export const REGISTERED_ENTITIES = new Set<EntityName<AnyEntity>>();
export const logger = new Logger(MikroORM.name);
export const getRepositoryToken = <T> (entity: EntityName<T>) => `${Utils.className(entity)}Repository`;
export const InjectRepository = <T> (entity: EntityName<T>) => Inject(getRepositoryToken(entity));
9 changes: 8 additions & 1 deletion src/mikro-orm.module.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { AnyEntity, EntityName } from '@mikro-orm/core';
import { AnyEntity, EntityName, Utils } from '@mikro-orm/core';
import { DynamicModule, Module } from '@nestjs/common';

import { createMikroOrmRepositoryProviders } from './mikro-orm.providers';
import { MikroOrmCoreModule } from './mikro-orm-core.module';
import { MikroOrmModuleAsyncOptions, MikroOrmModuleOptions } from './typings';
import { REGISTERED_ENTITIES } from './mikro-orm.common';

@Module({})
export class MikroOrmModule {
Expand All @@ -26,6 +27,12 @@ export class MikroOrmModule {
const entities = Array.isArray(options) ? options : (options.entities || []);
const providers = createMikroOrmRepositoryProviders(entities);

for (const e of entities) {
if (!Utils.isString(e)) {
REGISTERED_ENTITIES.add(e);
}
}

return {
module: MikroOrmModule,
providers: [...providers],
Expand Down
21 changes: 15 additions & 6 deletions src/mikro-orm.providers.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
import { getRepositoryToken, logger, MIKRO_ORM_MODULE_OPTIONS } from './mikro-orm.common';
import { AnyEntity, Configuration, ConfigurationLoader, EntityManager, EntityName, MikroORM, Options } from '@mikro-orm/core';
import { getRepositoryToken, logger, MIKRO_ORM_MODULE_OPTIONS, REGISTERED_ENTITIES } from './mikro-orm.common';
import { AnyEntity, ConfigurationLoader, EntityManager, EntityName, MikroORM } from '@mikro-orm/core';

import { MikroOrmModuleAsyncOptions, MikroOrmOptionsFactory } from './typings';
import { MikroOrmModuleAsyncOptions, MikroOrmModuleOptions, MikroOrmOptionsFactory } from './typings';
import { Provider } from '@nestjs/common';

export const createMikroOrmProvider = (): Provider => ({
provide: MikroORM,
useFactory: async (options?: Options | Configuration) => {
useFactory: async (options?: MikroOrmModuleOptions) => {
if (options?.autoLoadEntities) {
options.entities = [...(options.entities || []), ...REGISTERED_ENTITIES.values()];
options.entitiesTs = [...(options.entitiesTs || []), ...REGISTERED_ENTITIES.values()];
delete options.autoLoadEntities;
}

REGISTERED_ENTITIES.clear();

if (!options || Object.keys(options).length === 0) {
options = await ConfigurationLoader.getConfiguration();
options.set('logger', logger.log.bind(logger));
const config = await ConfigurationLoader.getConfiguration();
config.set('logger', logger.log.bind(logger));
options = config as unknown as MikroOrmModuleOptions;
}

return MikroORM.init(options);
Expand Down
1 change: 1 addition & 0 deletions src/typings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export interface NestMiddlewareConsumer extends MiddlewareConsumer {

export type MikroOrmModuleOptions<D extends IDatabaseDriver = IDatabaseDriver> = {
registerRequestContext?: boolean;
autoLoadEntities?: boolean;
/**
* Routes to apply the middleware.
*
Expand Down

0 comments on commit ceaf16e

Please sign in to comment.