Skip to content

Commit

Permalink
feat(core): add @UseRequestContext() decorator
Browse files Browse the repository at this point in the history
Closes #5
  • Loading branch information
B4nan committed Sep 23, 2020
1 parent ceaf16e commit 7aeac9d
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 1 deletion.
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,34 @@ object.
> 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.

```ts
@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, `domain` api use used in the `RequestContext` helper. Since `@mikro-orm/core@4.0.3`,
Expand Down
23 changes: 22 additions & 1 deletion src/mikro-orm.common.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,29 @@
import { AnyEntity, EntityName, MikroORM, Utils } from '@mikro-orm/core';
import { AnyEntity, EntityName, MikroORM, RequestContext, 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));

export function UseRequestContext() {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = async function (...args: any[]) {
// eslint-disable-next-line @typescript-eslint/no-this-alias
const context: any = this;

if (!(context.orm instanceof MikroORM)) {
throw new Error('@UseRequestContext() decorator can only be applied to methods of classes that carry `orm: MikroORM`');
}

await RequestContext.createAsync(context.orm.em, async () => {
await originalMethod.apply(context, args);
});
};

return descriptor;
};
}

0 comments on commit 7aeac9d

Please sign in to comment.