@tsed/mikro-orm 6.96.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/jest.config.js +14 -0
- package/lib/cjs/MikroOrmModule.d.ts +19 -0
- package/lib/cjs/MikroOrmModule.js +31 -0
- package/lib/cjs/MikroOrmModule.js.map +1 -0
- package/lib/cjs/decorators/connection.d.ts +1 -0
- package/lib/cjs/decorators/connection.js +8 -0
- package/lib/cjs/decorators/connection.js.map +1 -0
- package/lib/cjs/decorators/index.d.ts +2 -0
- package/lib/cjs/decorators/index.js +6 -0
- package/lib/cjs/decorators/index.js.map +1 -0
- package/lib/cjs/decorators/transactional.d.ts +2 -0
- package/lib/cjs/decorators/transactional.js +8 -0
- package/lib/cjs/decorators/transactional.js.map +1 -0
- package/lib/cjs/filters/OptimisticLockErrorFilter.d.ts +5 -0
- package/lib/cjs/filters/OptimisticLockErrorFilter.js +20 -0
- package/lib/cjs/filters/OptimisticLockErrorFilter.js.map +1 -0
- package/lib/cjs/filters/index.d.ts +1 -0
- package/lib/cjs/filters/index.js +5 -0
- package/lib/cjs/filters/index.js.map +1 -0
- package/lib/cjs/index.d.ts +5 -0
- package/lib/cjs/index.js +9 -0
- package/lib/cjs/index.js.map +1 -0
- package/lib/cjs/interceptors/TransactionalInterceptor.d.ts +16 -0
- package/lib/cjs/interceptors/TransactionalInterceptor.js +64 -0
- package/lib/cjs/interceptors/TransactionalInterceptor.js.map +1 -0
- package/lib/cjs/interceptors/index.d.ts +1 -0
- package/lib/cjs/interceptors/index.js +5 -0
- package/lib/cjs/interceptors/index.js.map +1 -0
- package/lib/cjs/services/DBContext.d.ts +9 -0
- package/lib/cjs/services/DBContext.js +37 -0
- package/lib/cjs/services/DBContext.js.map +1 -0
- package/lib/cjs/services/MikroOrmFactory.d.ts +5 -0
- package/lib/cjs/services/MikroOrmFactory.js +24 -0
- package/lib/cjs/services/MikroOrmFactory.js.map +1 -0
- package/lib/cjs/services/MikroOrmRegistry.d.ts +14 -0
- package/lib/cjs/services/MikroOrmRegistry.js +51 -0
- package/lib/cjs/services/MikroOrmRegistry.js.map +1 -0
- package/lib/cjs/services/RetryStrategy.d.ts +3 -0
- package/lib/cjs/services/RetryStrategy.js +3 -0
- package/lib/cjs/services/RetryStrategy.js.map +1 -0
- package/lib/cjs/services/index.d.ts +4 -0
- package/lib/cjs/services/index.js +8 -0
- package/lib/cjs/services/index.js.map +1 -0
- package/lib/esm/MikroOrmModule.js +28 -0
- package/lib/esm/MikroOrmModule.js.map +1 -0
- package/lib/esm/decorators/connection.js +4 -0
- package/lib/esm/decorators/connection.js.map +1 -0
- package/lib/esm/decorators/index.js +3 -0
- package/lib/esm/decorators/index.js.map +1 -0
- package/lib/esm/decorators/transactional.js +4 -0
- package/lib/esm/decorators/transactional.js.map +1 -0
- package/lib/esm/filters/OptimisticLockErrorFilter.js +17 -0
- package/lib/esm/filters/OptimisticLockErrorFilter.js.map +1 -0
- package/lib/esm/filters/index.js +2 -0
- package/lib/esm/filters/index.js.map +1 -0
- package/lib/esm/index.js +6 -0
- package/lib/esm/index.js.map +1 -0
- package/lib/esm/interceptors/TransactionalInterceptor.js +61 -0
- package/lib/esm/interceptors/TransactionalInterceptor.js.map +1 -0
- package/lib/esm/interceptors/index.js +2 -0
- package/lib/esm/interceptors/index.js.map +1 -0
- package/lib/esm/services/DBContext.js +34 -0
- package/lib/esm/services/DBContext.js.map +1 -0
- package/lib/esm/services/MikroOrmFactory.js +21 -0
- package/lib/esm/services/MikroOrmFactory.js.map +1 -0
- package/lib/esm/services/MikroOrmRegistry.js +48 -0
- package/lib/esm/services/MikroOrmRegistry.js.map +1 -0
- package/lib/esm/services/RetryStrategy.js +2 -0
- package/lib/esm/services/RetryStrategy.js.map +1 -0
- package/lib/esm/services/index.js +5 -0
- package/lib/esm/services/index.js.map +1 -0
- package/lib/types/MikroOrmModule.d.ts +19 -0
- package/lib/types/decorators/connection.d.ts +1 -0
- package/lib/types/decorators/index.d.ts +2 -0
- package/lib/types/decorators/transactional.d.ts +2 -0
- package/lib/types/filters/OptimisticLockErrorFilter.d.ts +5 -0
- package/lib/types/filters/index.d.ts +1 -0
- package/lib/types/index.d.ts +5 -0
- package/lib/types/interceptors/TransactionalInterceptor.d.ts +16 -0
- package/lib/types/interceptors/index.d.ts +1 -0
- package/lib/types/services/DBContext.d.ts +9 -0
- package/lib/types/services/MikroOrmFactory.d.ts +5 -0
- package/lib/types/services/MikroOrmRegistry.d.ts +14 -0
- package/lib/types/services/RetryStrategy.d.ts +3 -0
- package/lib/types/services/index.d.ts +4 -0
- package/package.json +49 -0
- package/readme.md +237 -0
- package/tsconfig.compile.esm.json +23 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC","sourcesContent":["export * from \"./decorators\";\nexport * from \"./filters\";\nexport * from \"./interceptors\";\nexport * from \"./services\";\nexport * from \"./MikroOrmModule\";\n"]}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { __decorate, __metadata, __param } from "tslib";
|
|
2
|
+
import { DBContext, MikroOrmRegistry } from "../services";
|
|
3
|
+
import { Inject, Interceptor } from "@tsed/di";
|
|
4
|
+
let TransactionalInterceptor = class TransactionalInterceptor {
|
|
5
|
+
constructor(registry, context) {
|
|
6
|
+
this.registry = registry;
|
|
7
|
+
this.context = context;
|
|
8
|
+
}
|
|
9
|
+
async intercept(context, next) {
|
|
10
|
+
const options = this.extractContextName(context);
|
|
11
|
+
const ctx = this.context.getContext();
|
|
12
|
+
if (!ctx) {
|
|
13
|
+
return this.runWithinNewCtx(next, options);
|
|
14
|
+
}
|
|
15
|
+
if (ctx.has(options.connectionName)) {
|
|
16
|
+
return next();
|
|
17
|
+
}
|
|
18
|
+
return this.runUnderCtx(next, ctx, options);
|
|
19
|
+
}
|
|
20
|
+
runWithinNewCtx(next, options) {
|
|
21
|
+
const ctx = new Map();
|
|
22
|
+
return this.runUnderCtx(next, ctx, options);
|
|
23
|
+
}
|
|
24
|
+
runUnderCtx(next, ctx, options) {
|
|
25
|
+
const orm = this.registry.get(options.connectionName);
|
|
26
|
+
const em = orm.em.fork(true, true);
|
|
27
|
+
ctx.set(em.name, em);
|
|
28
|
+
const runInTransaction = () => this.executeInTransaction(options.connectionName, next);
|
|
29
|
+
return this.context.run(ctx, () => (options.retryStrategy ? options.retryStrategy.acquire(runInTransaction) : runInTransaction()));
|
|
30
|
+
}
|
|
31
|
+
extractContextName(context) {
|
|
32
|
+
const options = context.options || {};
|
|
33
|
+
let connectionName;
|
|
34
|
+
let retryStrategy;
|
|
35
|
+
if (typeof options === "string") {
|
|
36
|
+
connectionName = options;
|
|
37
|
+
}
|
|
38
|
+
else if (options) {
|
|
39
|
+
connectionName = options.connectionName;
|
|
40
|
+
retryStrategy = options.retryStrategy;
|
|
41
|
+
}
|
|
42
|
+
if (!connectionName) {
|
|
43
|
+
connectionName = "default";
|
|
44
|
+
}
|
|
45
|
+
return { connectionName, retryStrategy };
|
|
46
|
+
}
|
|
47
|
+
async executeInTransaction(connectionName, next) {
|
|
48
|
+
const em = this.context.get(connectionName);
|
|
49
|
+
const result = await next();
|
|
50
|
+
await (em === null || em === void 0 ? void 0 : em.flush());
|
|
51
|
+
return result;
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
TransactionalInterceptor = __decorate([
|
|
55
|
+
Interceptor(),
|
|
56
|
+
__param(0, Inject()),
|
|
57
|
+
__param(1, Inject()),
|
|
58
|
+
__metadata("design:paramtypes", [MikroOrmRegistry, DBContext])
|
|
59
|
+
], TransactionalInterceptor);
|
|
60
|
+
export { TransactionalInterceptor };
|
|
61
|
+
//# sourceMappingURL=TransactionalInterceptor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TransactionalInterceptor.js","sourceRoot":"","sources":["../../../src/interceptors/TransactionalInterceptor.ts"],"names":[],"mappings":";AAAA,OAAO,EAAC,SAAS,EAAE,gBAAgB,EAAgB,MAAM,aAAa,CAAC;AACvE,OAAO,EAAC,MAAM,EAAE,WAAW,EAA0D,MAAM,UAAU,CAAC;AAStG,IAAa,wBAAwB,GAArC,MAAa,wBAAwB;IACnC,YAAuC,QAA0B,EAA6B,OAAkB;QAAzE,aAAQ,GAAR,QAAQ,CAAkB;QAA6B,YAAO,GAAP,OAAO,CAAW;IAAG,CAAC;IAE7G,KAAK,CAAC,SAAS,CAAC,OAAoC,EAAE,IAAqB;QAChF,MAAM,OAAO,GAAG,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;QAEjD,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;QAEtC,IAAI,CAAC,GAAG,EAAE;YACR,OAAO,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;SAC5C;QAED,IAAI,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,cAAe,CAAC,EAAE;YACpC,OAAO,IAAI,EAAE,CAAC;SACf;QAED,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;IAC9C,CAAC;IAEO,eAAe,CAAC,IAAqB,EAAE,OAA2B;QACxE,MAAM,GAAG,GAAG,IAAI,GAAG,EAAyB,CAAC;QAE7C,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;IAC9C,CAAC;IAEO,WAAW,CAAC,IAAqB,EAAE,GAA+B,EAAE,OAA2B;QACrG,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;QACtD,MAAM,EAAE,GAAG,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAEnC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAErB,MAAM,gBAAgB,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,oBAAoB,CAAC,OAAO,CAAC,cAAe,EAAE,IAAI,CAAC,CAAC;QAExF,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC;IACrI,CAAC;IAEO,kBAAkB,CAAC,OAAoC;QAC7D,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAK,EAA2C,CAAC;QAEhF,IAAI,cAAkC,CAAC;QACvC,IAAI,aAAwC,CAAC;QAE7C,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE;YAC/B,cAAc,GAAG,OAAO,CAAC;SAC1B;aAAM,IAAI,OAAO,EAAE;YAClB,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC;YACxC,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;SACvC;QAED,IAAI,CAAC,cAAc,EAAE;YACnB,cAAc,GAAG,SAAS,CAAC;SAC5B;QAED,OAAO,EAAC,cAAc,EAAE,aAAa,EAAC,CAAC;IACzC,CAAC;IAEO,KAAK,CAAC,oBAAoB,CAAC,cAAsB,EAAE,IAAqB;QAC9E,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QAE5C,MAAM,MAAM,GAAG,MAAM,IAAI,EAAE,CAAC;QAE5B,MAAM,CAAA,EAAE,aAAF,EAAE,uBAAF,EAAE,CAAE,KAAK,EAAE,CAAA,CAAC;QAElB,OAAO,MAAM,CAAC;IAChB,CAAC;CACF,CAAA;AAjEY,wBAAwB;IADpC,WAAW,EAAE;IAEC,WAAA,MAAM,EAAE,CAAA;IAA+C,WAAA,MAAM,EAAE,CAAA;qCAA3B,gBAAgB,EAAsC,SAAS;GADrG,wBAAwB,CAiEpC;SAjEY,wBAAwB","sourcesContent":["import {DBContext, MikroOrmRegistry, RetryStrategy} from \"../services\";\nimport {Inject, Interceptor, InterceptorContext, InterceptorMethods, InterceptorNext} from \"@tsed/di\";\nimport {EntityManager} from \"@mikro-orm/core\";\n\nexport interface TransactionOptions {\n connectionName?: string;\n retryStrategy?: RetryStrategy;\n}\n\n@Interceptor()\nexport class TransactionalInterceptor implements InterceptorMethods {\n constructor(@Inject() private readonly registry: MikroOrmRegistry, @Inject() private readonly context: DBContext) {}\n\n public async intercept(context: InterceptorContext<unknown>, next: InterceptorNext): Promise<unknown> {\n const options = this.extractContextName(context);\n\n const ctx = this.context.getContext();\n\n if (!ctx) {\n return this.runWithinNewCtx(next, options);\n }\n\n if (ctx.has(options.connectionName!)) {\n return next();\n }\n\n return this.runUnderCtx(next, ctx, options);\n }\n\n private runWithinNewCtx(next: InterceptorNext, options: TransactionOptions): Promise<unknown> | unknown {\n const ctx = new Map<string, EntityManager>();\n\n return this.runUnderCtx(next, ctx, options);\n }\n\n private runUnderCtx(next: InterceptorNext, ctx: Map<string, EntityManager>, options: TransactionOptions): Promise<unknown> | unknown {\n const orm = this.registry.get(options.connectionName);\n const em = orm.em.fork(true, true);\n\n ctx.set(em.name, em);\n\n const runInTransaction = () => this.executeInTransaction(options.connectionName!, next);\n\n return this.context.run(ctx, () => (options.retryStrategy ? options.retryStrategy.acquire(runInTransaction) : runInTransaction()));\n }\n\n private extractContextName(context: InterceptorContext<unknown>): TransactionOptions {\n const options = context.options || ({} as Partial<TransactionOptions> | string);\n\n let connectionName: string | undefined;\n let retryStrategy: RetryStrategy | undefined;\n\n if (typeof options === \"string\") {\n connectionName = options;\n } else if (options) {\n connectionName = options.connectionName;\n retryStrategy = options.retryStrategy;\n }\n\n if (!connectionName) {\n connectionName = \"default\";\n }\n\n return {connectionName, retryStrategy};\n }\n\n private async executeInTransaction(connectionName: string, next: InterceptorNext): Promise<unknown> {\n const em = this.context.get(connectionName);\n\n const result = await next();\n\n await em?.flush();\n\n return result;\n }\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/interceptors/index.ts"],"names":[],"mappings":"AAAA,cAAc,4BAA4B,CAAC","sourcesContent":["export * from \"./TransactionalInterceptor\";\n"]}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { __decorate, __metadata } from "tslib";
|
|
2
|
+
import { Injectable } from "@tsed/di";
|
|
3
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
4
|
+
let DBContext = class DBContext {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.storage = new AsyncLocalStorage();
|
|
7
|
+
if (AsyncLocalStorage) {
|
|
8
|
+
this.storage = new AsyncLocalStorage();
|
|
9
|
+
}
|
|
10
|
+
else {
|
|
11
|
+
throw new Error(`AsyncLocalStorage is not available for your Node.js version (${process.versions.node}).`);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
run(ctx, callback) {
|
|
15
|
+
return this.storage.run(ctx, callback);
|
|
16
|
+
}
|
|
17
|
+
getContext() {
|
|
18
|
+
return this.storage.getStore();
|
|
19
|
+
}
|
|
20
|
+
get(contextName) {
|
|
21
|
+
const context = this.getContext();
|
|
22
|
+
return context === null || context === void 0 ? void 0 : context.get(contextName);
|
|
23
|
+
}
|
|
24
|
+
has(contextName) {
|
|
25
|
+
const context = this.getContext();
|
|
26
|
+
return !!(context === null || context === void 0 ? void 0 : context.has(contextName));
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
DBContext = __decorate([
|
|
30
|
+
Injectable(),
|
|
31
|
+
__metadata("design:paramtypes", [])
|
|
32
|
+
], DBContext);
|
|
33
|
+
export { DBContext };
|
|
34
|
+
//# sourceMappingURL=DBContext.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DBContext.js","sourceRoot":"","sources":["../../../src/services/DBContext.ts"],"names":[],"mappings":";AAAA,OAAO,EAAC,UAAU,EAAC,MAAM,UAAU,CAAC;AAEpC,OAAO,EAAC,iBAAiB,EAAC,MAAM,aAAa,CAAC;AAG9C,IAAa,SAAS,GAAtB,MAAa,SAAS;IAGpB;QAFiB,YAAO,GAAG,IAAI,iBAAiB,EAA8B,CAAC;QAG7E,IAAI,iBAAiB,EAAE;YACrB,IAAI,CAAC,OAAO,GAAG,IAAI,iBAAiB,EAAE,CAAC;SACxC;aAAM;YACL,MAAM,IAAI,KAAK,CAAC,gEAAgE,OAAO,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,CAAC;SAC5G;IACH,CAAC;IAEM,GAAG,CAAI,GAA+B,EAAE,QAA+B;QAC5E,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IACzC,CAAC;IAEM,UAAU;QACf,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;IACjC,CAAC;IAEM,GAAG,CAAC,WAAmB;QAC5B,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;QAElC,OAAO,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,GAAG,CAAC,WAAW,CAAC,CAAC;IACnC,CAAC;IAEM,GAAG,CAAC,WAAmB;QAC5B,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;QAElC,OAAO,CAAC,CAAC,CAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,GAAG,CAAC,WAAW,CAAC,CAAA,CAAC;IACrC,CAAC;CACF,CAAA;AA9BY,SAAS;IADrB,UAAU,EAAE;;GACA,SAAS,CA8BrB;SA9BY,SAAS","sourcesContent":["import {Injectable} from \"@tsed/di\";\nimport {EntityManager} from \"@mikro-orm/core\";\nimport {AsyncLocalStorage} from \"async_hooks\";\n\n@Injectable()\nexport class DBContext {\n private readonly storage = new AsyncLocalStorage<Map<string, EntityManager>>();\n\n constructor() {\n if (AsyncLocalStorage) {\n this.storage = new AsyncLocalStorage();\n } else {\n throw new Error(`AsyncLocalStorage is not available for your Node.js version (${process.versions.node}).`);\n }\n }\n\n public run<R>(ctx: Map<string, EntityManager>, callback: (...args: any[]) => R): R {\n return this.storage.run(ctx, callback);\n }\n\n public getContext(): Map<string, EntityManager> | undefined {\n return this.storage.getStore();\n }\n\n public get(contextName: string): EntityManager | undefined {\n const context = this.getContext();\n\n return context?.get(contextName);\n }\n\n public has(contextName: string): boolean {\n const context = this.getContext();\n\n return !!context?.has(contextName);\n }\n}\n"]}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { __decorate, __metadata } from "tslib";
|
|
2
|
+
import { DBContext } from "./DBContext";
|
|
3
|
+
import { MikroORM } from "@mikro-orm/core";
|
|
4
|
+
import { Inject, Injectable } from "@tsed/di";
|
|
5
|
+
let MikroOrmFactory = class MikroOrmFactory {
|
|
6
|
+
create(connectionOptions) {
|
|
7
|
+
return MikroORM.init({
|
|
8
|
+
...connectionOptions,
|
|
9
|
+
context: (name) => this.dbContext.get(name)
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
__decorate([
|
|
14
|
+
Inject(),
|
|
15
|
+
__metadata("design:type", DBContext)
|
|
16
|
+
], MikroOrmFactory.prototype, "dbContext", void 0);
|
|
17
|
+
MikroOrmFactory = __decorate([
|
|
18
|
+
Injectable()
|
|
19
|
+
], MikroOrmFactory);
|
|
20
|
+
export { MikroOrmFactory };
|
|
21
|
+
//# sourceMappingURL=MikroOrmFactory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MikroOrmFactory.js","sourceRoot":"","sources":["../../../src/services/MikroOrmFactory.ts"],"names":[],"mappings":";AAAA,OAAO,EAAC,SAAS,EAAC,MAAM,aAAa,CAAC;AACtC,OAAO,EAAC,QAAQ,EAAU,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAC,MAAM,EAAE,UAAU,EAAC,MAAM,UAAU,CAAC;AAG5C,IAAa,eAAe,GAA5B,MAAa,eAAe;IAInB,MAAM,CAAC,iBAA0B;QACtC,OAAO,QAAQ,CAAC,IAAI,CAAC;YACnB,GAAG,iBAAiB;YACpB,OAAO,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;SACpD,CAAC,CAAC;IACL,CAAC;CACF,CAAA;AARC;IADC,MAAM,EAAE;8BACoB,SAAS;kDAAC;AAF5B,eAAe;IAD3B,UAAU,EAAE;GACA,eAAe,CAU3B;SAVY,eAAe","sourcesContent":["import {DBContext} from \"./DBContext\";\nimport {MikroORM, Options} from \"@mikro-orm/core\";\nimport {Inject, Injectable} from \"@tsed/di\";\n\n@Injectable()\nexport class MikroOrmFactory {\n @Inject()\n private readonly dbContext!: DBContext;\n\n public create(connectionOptions: Options): Promise<MikroORM> {\n return MikroORM.init({\n ...connectionOptions,\n context: (name: string) => this.dbContext.get(name)\n });\n }\n}\n"]}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { __decorate, __metadata, __param } from "tslib";
|
|
2
|
+
import { MikroOrmFactory } from "./MikroOrmFactory";
|
|
3
|
+
import { Inject, Injectable, InjectorService } from "@tsed/di";
|
|
4
|
+
import { catchAsyncError, getValue } from "@tsed/core";
|
|
5
|
+
let MikroOrmRegistry = class MikroOrmRegistry {
|
|
6
|
+
constructor(injector, mikroOrmFactory) {
|
|
7
|
+
this.injector = injector;
|
|
8
|
+
this.mikroOrmFactory = mikroOrmFactory;
|
|
9
|
+
this.connections = new Map();
|
|
10
|
+
}
|
|
11
|
+
async createConnection(connectionOptions) {
|
|
12
|
+
const connectionName = getValue(connectionOptions, "contextName", "default");
|
|
13
|
+
if (this.has(connectionName)) {
|
|
14
|
+
return this.get(connectionName);
|
|
15
|
+
}
|
|
16
|
+
this.injector.logger.info(`Create connection with MikroOrm to database: %s`, connectionName);
|
|
17
|
+
this.injector.logger.debug(`options: %j`, connectionOptions);
|
|
18
|
+
const connection = await this.mikroOrmFactory.create(connectionOptions);
|
|
19
|
+
this.connections.set(connectionName, connection);
|
|
20
|
+
this.injector.logger.info(`Connected with MikroOrm to database: %s`, connectionName);
|
|
21
|
+
return connection;
|
|
22
|
+
}
|
|
23
|
+
get(id = "default") {
|
|
24
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
25
|
+
return this.connections.get(id);
|
|
26
|
+
}
|
|
27
|
+
has(id = "default") {
|
|
28
|
+
return this.connections.has(id);
|
|
29
|
+
}
|
|
30
|
+
async closeConnections() {
|
|
31
|
+
const connections = [...this.connections.values()];
|
|
32
|
+
await Promise.all(connections.map((connection) => catchAsyncError(() => this.dispose(connection))));
|
|
33
|
+
this.connections.clear();
|
|
34
|
+
}
|
|
35
|
+
async dispose(connection) {
|
|
36
|
+
if (await connection.isConnected()) {
|
|
37
|
+
await connection.close(false);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
MikroOrmRegistry = __decorate([
|
|
42
|
+
Injectable(),
|
|
43
|
+
__param(0, Inject()),
|
|
44
|
+
__param(1, Inject()),
|
|
45
|
+
__metadata("design:paramtypes", [InjectorService, MikroOrmFactory])
|
|
46
|
+
], MikroOrmRegistry);
|
|
47
|
+
export { MikroOrmRegistry };
|
|
48
|
+
//# sourceMappingURL=MikroOrmRegistry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MikroOrmRegistry.js","sourceRoot":"","sources":["../../../src/services/MikroOrmRegistry.ts"],"names":[],"mappings":";AAAA,OAAO,EAAC,eAAe,EAAC,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAC,MAAM,EAAE,UAAU,EAAE,eAAe,EAAC,MAAM,UAAU,CAAC;AAE7D,OAAO,EAAC,eAAe,EAAE,QAAQ,EAAC,MAAM,YAAY,CAAC;AAGrD,IAAa,gBAAgB,GAA7B,MAAa,gBAAgB;IAG3B,YAAuC,QAAyB,EAA6B,eAAgC;QAAtF,aAAQ,GAAR,QAAQ,CAAiB;QAA6B,oBAAe,GAAf,eAAe,CAAiB;QAF5G,gBAAW,GAAG,IAAI,GAAG,EAAoB,CAAC;IAEqE,CAAC;IAE1H,KAAK,CAAC,gBAAgB,CAA2B,iBAA6B;QACnF,MAAM,cAAc,GAAG,QAAQ,CAAS,iBAAiB,EAAE,aAAa,EAAE,SAAS,CAAC,CAAC;QAErF,IAAI,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE;YAC5B,OAAO,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;SACjC;QAED,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,iDAAiD,EAAE,cAAc,CAAC,CAAC;QAC7F,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,EAAE,iBAAiB,CAAC,CAAC;QAE7D,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC;QAExE,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,cAAc,EAAE,UAAU,CAAC,CAAC;QAEjD,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,yCAAyC,EAAE,cAAc,CAAC,CAAC;QAErF,OAAO,UAAU,CAAC;IACpB,CAAC;IAEM,GAAG,CAAC,KAAa,SAAS;QAC/B,oEAAoE;QACpE,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAE,CAAC;IACnC,CAAC;IAEM,GAAG,CAAC,KAAa,SAAS;QAC/B,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAClC,CAAC;IAEM,KAAK,CAAC,gBAAgB;QAC3B,MAAM,WAAW,GAAG,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC;QAEnD,MAAM,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,UAAoB,EAAE,EAAE,CAAC,eAAe,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;QAE9G,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC;IAC3B,CAAC;IAEO,KAAK,CAAC,OAAO,CAAC,UAAoB;QACxC,IAAI,MAAM,UAAU,CAAC,WAAW,EAAE,EAAE;YAClC,MAAM,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;SAC/B;IACH,CAAC;CACF,CAAA;AA9CY,gBAAgB;IAD5B,UAAU,EAAE;IAIE,WAAA,MAAM,EAAE,CAAA;IAA8C,WAAA,MAAM,EAAE,CAAA;qCAA1B,eAAe,EAA8C,eAAe;GAHlH,gBAAgB,CA8C5B;SA9CY,gBAAgB","sourcesContent":["import {MikroOrmFactory} from \"./MikroOrmFactory\";\nimport {Inject, Injectable, InjectorService} from \"@tsed/di\";\nimport {IDatabaseDriver as DatabaseDriver, MikroORM, Options} from \"@mikro-orm/core\";\nimport {catchAsyncError, getValue} from \"@tsed/core\";\n\n@Injectable()\nexport class MikroOrmRegistry {\n private readonly connections = new Map<string, MikroORM>();\n\n constructor(@Inject() private readonly injector: InjectorService, @Inject() private readonly mikroOrmFactory: MikroOrmFactory) {}\n\n public async createConnection<T extends DatabaseDriver>(connectionOptions: Options<T>): Promise<MikroORM> {\n const connectionName = getValue<string>(connectionOptions, \"contextName\", \"default\");\n\n if (this.has(connectionName)) {\n return this.get(connectionName);\n }\n\n this.injector.logger.info(`Create connection with MikroOrm to database: %s`, connectionName);\n this.injector.logger.debug(`options: %j`, connectionOptions);\n\n const connection = await this.mikroOrmFactory.create(connectionOptions);\n\n this.connections.set(connectionName, connection);\n\n this.injector.logger.info(`Connected with MikroOrm to database: %s`, connectionName);\n\n return connection;\n }\n\n public get(id: string = \"default\"): MikroORM {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n return this.connections.get(id)!;\n }\n\n public has(id: string = \"default\"): boolean {\n return this.connections.has(id);\n }\n\n public async closeConnections(): Promise<void> {\n const connections = [...this.connections.values()];\n\n await Promise.all(connections.map((connection: MikroORM) => catchAsyncError(() => this.dispose(connection))));\n\n this.connections.clear();\n }\n\n private async dispose(connection: MikroORM): Promise<void> {\n if (await connection.isConnected()) {\n await connection.close(false);\n }\n }\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RetryStrategy.js","sourceRoot":"","sources":["../../../src/services/RetryStrategy.ts"],"names":[],"mappings":"","sourcesContent":["export interface RetryStrategy {\n acquire<T extends (...args: unknown[]) => unknown>(task: T): Promise<ReturnType<T>>;\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/services/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC","sourcesContent":["export * from \"./DBContext\";\nexport * from \"./MikroOrmFactory\";\nexport * from \"./MikroOrmRegistry\";\nexport * from \"./RetryStrategy\";\n"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { OnDestroy, OnInit } from "@tsed/di";
|
|
2
|
+
import { Options } from "@mikro-orm/core";
|
|
3
|
+
declare global {
|
|
4
|
+
namespace TsED {
|
|
5
|
+
interface Configuration {
|
|
6
|
+
/**
|
|
7
|
+
* The the ORM configuration, entity metadata.
|
|
8
|
+
* If you omit the `options` parameter, your CLI config will be used.
|
|
9
|
+
*/
|
|
10
|
+
mikroOrm?: Options[];
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export declare class MikroOrmModule implements OnDestroy, OnInit {
|
|
15
|
+
private readonly settings;
|
|
16
|
+
private readonly mikroOrmRegistry;
|
|
17
|
+
$onInit(): Promise<void>;
|
|
18
|
+
$onDestroy(): Promise<void>;
|
|
19
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const Connection: (connectionName?: string | undefined) => PropertyDecorator;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { ExceptionFilterMethods, PlatformContext } from "@tsed/common";
|
|
2
|
+
import { OptimisticLockError } from "@mikro-orm/core";
|
|
3
|
+
export declare class OptimisticLockErrorFilter implements ExceptionFilterMethods<OptimisticLockError> {
|
|
4
|
+
catch(exception: OptimisticLockError, ctx: PlatformContext): void;
|
|
5
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./OptimisticLockErrorFilter";
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { DBContext, MikroOrmRegistry, RetryStrategy } from "../services";
|
|
2
|
+
import { InterceptorContext, InterceptorMethods, InterceptorNext } from "@tsed/di";
|
|
3
|
+
export interface TransactionOptions {
|
|
4
|
+
connectionName?: string;
|
|
5
|
+
retryStrategy?: RetryStrategy;
|
|
6
|
+
}
|
|
7
|
+
export declare class TransactionalInterceptor implements InterceptorMethods {
|
|
8
|
+
private readonly registry;
|
|
9
|
+
private readonly context;
|
|
10
|
+
constructor(registry: MikroOrmRegistry, context: DBContext);
|
|
11
|
+
intercept(context: InterceptorContext<unknown>, next: InterceptorNext): Promise<unknown>;
|
|
12
|
+
private runWithinNewCtx;
|
|
13
|
+
private runUnderCtx;
|
|
14
|
+
private extractContextName;
|
|
15
|
+
private executeInTransaction;
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./TransactionalInterceptor";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { EntityManager } from "@mikro-orm/core";
|
|
2
|
+
export declare class DBContext {
|
|
3
|
+
private readonly storage;
|
|
4
|
+
constructor();
|
|
5
|
+
run<R>(ctx: Map<string, EntityManager>, callback: (...args: any[]) => R): R;
|
|
6
|
+
getContext(): Map<string, EntityManager> | undefined;
|
|
7
|
+
get(contextName: string): EntityManager | undefined;
|
|
8
|
+
has(contextName: string): boolean;
|
|
9
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { MikroOrmFactory } from "./MikroOrmFactory";
|
|
2
|
+
import { InjectorService } from "@tsed/di";
|
|
3
|
+
import { IDatabaseDriver as DatabaseDriver, MikroORM, Options } from "@mikro-orm/core";
|
|
4
|
+
export declare class MikroOrmRegistry {
|
|
5
|
+
private readonly injector;
|
|
6
|
+
private readonly mikroOrmFactory;
|
|
7
|
+
private readonly connections;
|
|
8
|
+
constructor(injector: InjectorService, mikroOrmFactory: MikroOrmFactory);
|
|
9
|
+
createConnection<T extends DatabaseDriver>(connectionOptions: Options<T>): Promise<MikroORM>;
|
|
10
|
+
get(id?: string): MikroORM;
|
|
11
|
+
has(id?: string): boolean;
|
|
12
|
+
closeConnections(): Promise<void>;
|
|
13
|
+
private dispose;
|
|
14
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tsed/mikro-orm",
|
|
3
|
+
"version": "6.96.0",
|
|
4
|
+
"description": "MikroORM package for Ts.ED framework",
|
|
5
|
+
"private": false,
|
|
6
|
+
"source": "./src/index.ts",
|
|
7
|
+
"main": "./lib/cjs/index.js",
|
|
8
|
+
"typings": "./lib/types/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
"types": "./lib/types/index.d.ts",
|
|
11
|
+
"import": "./lib/esm/index.js",
|
|
12
|
+
"require": "./lib/cjs/index.js",
|
|
13
|
+
"default": "./lib/esm/index.js"
|
|
14
|
+
},
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "yarn run build:esm && yarn run build:cjs",
|
|
17
|
+
"build:cjs": "tsc --build tsconfig.compile.json",
|
|
18
|
+
"build:esm": "tsc --build tsconfig.compile.esm.json",
|
|
19
|
+
"test": "cross-env NODE_ENV=test jest"
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"tslib": "2.2.0"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@mikro-orm/core": "^4.5.9",
|
|
26
|
+
"@mikro-orm/mongodb": "^4.5.9",
|
|
27
|
+
"@tsed/common": "6.96.0",
|
|
28
|
+
"@tsed/core": "6.96.0",
|
|
29
|
+
"@tsed/di": "6.96.0",
|
|
30
|
+
"@tsed/json-mapper": "6.96.0",
|
|
31
|
+
"@tsed/schema": "6.96.0",
|
|
32
|
+
"ts-mockito": "^2.6.1"
|
|
33
|
+
},
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"@mikro-orm/core": ">=4.5.9",
|
|
36
|
+
"@tsed/common": "^6.96.0",
|
|
37
|
+
"@tsed/core": "^6.96.0",
|
|
38
|
+
"@tsed/di": "^6.96.0",
|
|
39
|
+
"@tsed/json-mapper": "^6.96.0",
|
|
40
|
+
"@tsed/schema": "^6.96.0"
|
|
41
|
+
},
|
|
42
|
+
"repository": "https://github.com/tsedio/tsed",
|
|
43
|
+
"bugs": {
|
|
44
|
+
"url": "https://github.com/tsedio/tsed/issues"
|
|
45
|
+
},
|
|
46
|
+
"homepage": "https://github.com/tsedio/tsed/tree/production/packages/orm/mikro-orm",
|
|
47
|
+
"author": "Romain Lenzotti",
|
|
48
|
+
"license": "MIT"
|
|
49
|
+
}
|
package/readme.md
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
<p style="text-align: center" align="center">
|
|
2
|
+
<a href="https://tsed.io" target="_blank"><img src="https://tsed.io/tsed-og.png" width="200" alt="Ts.ED logo"/></a>
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<div align="center">
|
|
6
|
+
<h1>MikroORM</h1>
|
|
7
|
+
|
|
8
|
+
[](https://github.com/tsedio/tsed/actions?query=workflow%3A%22Build+%26+Release%22)
|
|
9
|
+
[](https://github.com/tsedio/tsed/blob/master/CONTRIBUTING.md)
|
|
10
|
+
[](https://coveralls.io/github/tsedio/tsed?branch=production)
|
|
11
|
+
[](https://badge.fury.io/js/%40tsed%2Fcommon)
|
|
12
|
+
[](https://github.com/semantic-release/semantic-release)
|
|
13
|
+
[](https://github.com/prettier/prettier)
|
|
14
|
+
[](https://opencollective.com/tsed)
|
|
15
|
+
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
<div align="center">
|
|
19
|
+
<a href="https://tsed.io/">Website</a>
|
|
20
|
+
<span> • </span>
|
|
21
|
+
<a href="https://tsed.io/getting-started/">Getting started</a>
|
|
22
|
+
<span> • </span>
|
|
23
|
+
<a href="https://api.tsed.io/rest/slack/tsedio/tsed">Slack</a>
|
|
24
|
+
<span> • </span>
|
|
25
|
+
<a href="https://twitter.com/TsED_io">Twitter</a>
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
<hr />
|
|
29
|
+
|
|
30
|
+
A package of Ts.ED framework. See website: https://tsed.io/tutorials/mikro-orm
|
|
31
|
+
|
|
32
|
+
## Feature
|
|
33
|
+
|
|
34
|
+
Currently, `@tsed/mikro-orm` allows you:
|
|
35
|
+
|
|
36
|
+
- Configure one or more MikroOrm connections via the `@ServerSettings` configuration. All databases will be initialized
|
|
37
|
+
when the server starts during the server's `OnInit` phase.
|
|
38
|
+
- Use the Entity MikroOrm as Model for Controllers, AJV Validation and Swagger.
|
|
39
|
+
|
|
40
|
+
## Installation
|
|
41
|
+
|
|
42
|
+
To begin, install the MikroOrm module for TS.ED:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
npm install --save @tsed/mikro-orm
|
|
46
|
+
npm install --save @mikro-orm/core
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Then import `@tsed/mikro-orm` in your Server:
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
import {Configuration} from "@tsed/common";
|
|
53
|
+
import {MikroOrmModule} from "@tsed/mikro-orm";
|
|
54
|
+
|
|
55
|
+
@Configuration({
|
|
56
|
+
imports: [MikroOrmModule],
|
|
57
|
+
mikroOrm: [
|
|
58
|
+
{
|
|
59
|
+
contextName: 'default',
|
|
60
|
+
type: 'postgres',
|
|
61
|
+
...,
|
|
62
|
+
|
|
63
|
+
entities: [
|
|
64
|
+
`${__dirname}/entity/*{.ts,.js}`
|
|
65
|
+
]
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
contextName: 'mongo',
|
|
69
|
+
type: 'mongo',
|
|
70
|
+
...
|
|
71
|
+
}
|
|
72
|
+
]
|
|
73
|
+
})
|
|
74
|
+
export class Server {
|
|
75
|
+
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
For more information about MikroOrm look his documentation [here](https://mikro-orm.io/docs);
|
|
80
|
+
|
|
81
|
+
## Obtain a connection
|
|
82
|
+
|
|
83
|
+
`Connection` decorator lets you retrieve an instance of MikroOrm Connection.
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
import {Injectable, AfterRoutesInit} from "@tsed/common";
|
|
87
|
+
import {Connection} from "@tsed/mikro-orm";
|
|
88
|
+
import {MikroORM} from "@mikro-orm/core";
|
|
89
|
+
|
|
90
|
+
@Injectable()
|
|
91
|
+
export class UsersService {
|
|
92
|
+
@Connection()
|
|
93
|
+
private readonly connection!: MikroORM;
|
|
94
|
+
|
|
95
|
+
async create(user: User): Promise<User> {
|
|
96
|
+
|
|
97
|
+
// do something
|
|
98
|
+
// ...
|
|
99
|
+
// Then save
|
|
100
|
+
await this.connection.em.persistAndFlush(user);
|
|
101
|
+
console.log("Saved a new user with id: " + user.id);
|
|
102
|
+
|
|
103
|
+
return user;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async find(): Promise<User[]> {
|
|
107
|
+
const users = await this.connection.em.find(User, {});
|
|
108
|
+
console.log("Loaded users: ", users);
|
|
109
|
+
|
|
110
|
+
return users;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Use Entity with Controller
|
|
116
|
+
|
|
117
|
+
To begin, we need to define an Entity MikroOrm like this and use Ts.ED Decorator to define the JSON Schema.
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
import {Property, MaxLength, Required} from "@tsed/common";
|
|
121
|
+
import {Entity, Property, PrimaryKey, Property as Column} from "@mikro-orm/core";
|
|
122
|
+
|
|
123
|
+
@Entity()
|
|
124
|
+
export class User {
|
|
125
|
+
|
|
126
|
+
@PrimaryKey()
|
|
127
|
+
@Property()
|
|
128
|
+
id: number;
|
|
129
|
+
|
|
130
|
+
@Column()
|
|
131
|
+
@MaxLength(100)
|
|
132
|
+
@Required()
|
|
133
|
+
firstName: string;
|
|
134
|
+
|
|
135
|
+
@Column()
|
|
136
|
+
@MaxLength(100)
|
|
137
|
+
@Required()
|
|
138
|
+
lastName: string;
|
|
139
|
+
|
|
140
|
+
@Column()
|
|
141
|
+
@Mininum(0)
|
|
142
|
+
@Maximum(100)
|
|
143
|
+
age: number;
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Now, the model is correctly defined and can be used with a [Controller](https://tsed.io/docs/controllers.html)
|
|
148
|
+
, [AJV validation](tutorials/ajv.md),
|
|
149
|
+
[Swagger](tutorials/swagger.md) and [MikroOrm](https://mikro-orm.io/docs/defining-entities).
|
|
150
|
+
|
|
151
|
+
We can use this model with a Controller like that:
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
import {Controller, Post, BodyParams, Inject, Post, Get} from "@tsed/common";
|
|
155
|
+
|
|
156
|
+
@Controller("/users")
|
|
157
|
+
export class UsersCtrl {
|
|
158
|
+
@Inject()
|
|
159
|
+
private usersService: UsersService;
|
|
160
|
+
|
|
161
|
+
@Post("/")
|
|
162
|
+
create(@BodyParams() user: User): Promise<User> {
|
|
163
|
+
return this.usersService.create(user);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
@Get("/")
|
|
167
|
+
getList(): Promise<User[]> {
|
|
168
|
+
return this.usersService.find();
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## Transactions and Request context
|
|
174
|
+
|
|
175
|
+
As mentioned in the [docs](https://mikro-orm.io/docs/identity-map), we need to isolate a state for each request. That is
|
|
176
|
+
handled automatically thanks to the `AsyncLocalStorage` registered via interceptor.
|
|
177
|
+
|
|
178
|
+
We can use the `@Transactional()` decorator, which will register a new request context for your method and execute it
|
|
179
|
+
inside the context.
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
import {Controller, Post, BodyParams, Inject, Get} from "@tsed/common";
|
|
183
|
+
import {Transactional} from "@tsed/mikro-orm";
|
|
184
|
+
|
|
185
|
+
@Controller("/users")
|
|
186
|
+
export class UsersCtrl {
|
|
187
|
+
@Inject()
|
|
188
|
+
private usersService: UsersService;
|
|
189
|
+
|
|
190
|
+
@Post("/")
|
|
191
|
+
@Transactional()
|
|
192
|
+
create(@BodyParams() user: User): Promise<User> {
|
|
193
|
+
return this.usersService.create(user);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
@Get("/")
|
|
197
|
+
getList(): Promise<User[]> {
|
|
198
|
+
return this.usersService.find();
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## Contributors
|
|
204
|
+
|
|
205
|
+
Please read [contributing guidelines here](https://tsed.io/CONTRIBUTING.html)
|
|
206
|
+
|
|
207
|
+
<a href="https://github.com/tsedio/ts-express-decorators/graphs/contributors"><img src="https://opencollective.com/tsed/contributors.svg?width=890" /></a>
|
|
208
|
+
|
|
209
|
+
## Backers
|
|
210
|
+
|
|
211
|
+
Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/tsed#backer)]
|
|
212
|
+
|
|
213
|
+
<a href="https://opencollective.com/tsed#backers" target="_blank"><img src="https://opencollective.com/tsed/backers.svg?width=890"></a>
|
|
214
|
+
|
|
215
|
+
## Sponsors
|
|
216
|
+
|
|
217
|
+
Support this project by becoming a sponsor. Your logo will show up here with a link to your
|
|
218
|
+
website. [[Become a sponsor](https://opencollective.com/tsed#sponsor)]
|
|
219
|
+
|
|
220
|
+
## License
|
|
221
|
+
|
|
222
|
+
The MIT License (MIT)
|
|
223
|
+
|
|
224
|
+
Copyright (c) 2016 - 2018 Romain Lenzotti
|
|
225
|
+
|
|
226
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
|
227
|
+
documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
|
|
228
|
+
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
|
|
229
|
+
persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
230
|
+
|
|
231
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
|
|
232
|
+
Software.
|
|
233
|
+
|
|
234
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
|
235
|
+
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
236
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
|
237
|
+
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|