@tsed/mikro-orm 6.118.0-rc.1 → 6.119.1
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/lib/cjs/interceptors/TransactionalInterceptor.d.ts +3 -1
- package/lib/cjs/interceptors/TransactionalInterceptor.js +19 -11
- package/lib/cjs/interceptors/TransactionalInterceptor.js.map +1 -1
- package/lib/esm/interceptors/TransactionalInterceptor.js +19 -11
- package/lib/esm/interceptors/TransactionalInterceptor.js.map +1 -1
- package/lib/types/interceptors/TransactionalInterceptor.d.ts +3 -1
- package/package.json +11 -14
- package/readme.md +38 -16
|
@@ -3,10 +3,12 @@ import { Logger } from "@tsed/logger";
|
|
|
3
3
|
import { RetryStrategy } from "../services/RetryStrategy";
|
|
4
4
|
import { MikroOrmContext } from "../services/MikroOrmContext";
|
|
5
5
|
import { MikroOrmRegistry } from "../services/MikroOrmRegistry";
|
|
6
|
-
import { IsolationLevel } from "@mikro-orm/core";
|
|
6
|
+
import { FlushMode, IsolationLevel } from "@mikro-orm/core";
|
|
7
7
|
export interface TransactionOptions {
|
|
8
8
|
retry?: boolean;
|
|
9
|
+
disabled?: boolean;
|
|
9
10
|
isolationLevel?: IsolationLevel;
|
|
11
|
+
flushMode?: FlushMode;
|
|
10
12
|
contextName?: string;
|
|
11
13
|
/**
|
|
12
14
|
* @deprecated Since 2022-02-01. Use {@link contextName} instead
|
|
@@ -41,9 +41,11 @@ let TransactionalInterceptor = class TransactionalInterceptor {
|
|
|
41
41
|
return this.context.run([orm.em], () => this.runWithinCtx(next, options));
|
|
42
42
|
}
|
|
43
43
|
extractContextName(context) {
|
|
44
|
-
const options = context.options || {};
|
|
44
|
+
const options = (context.options || {});
|
|
45
45
|
let isolationLevel;
|
|
46
|
+
let disabled;
|
|
46
47
|
let contextName;
|
|
48
|
+
let flushMode;
|
|
47
49
|
let retry;
|
|
48
50
|
if (typeof options === "string") {
|
|
49
51
|
contextName = options;
|
|
@@ -52,21 +54,27 @@ let TransactionalInterceptor = class TransactionalInterceptor {
|
|
|
52
54
|
contextName = options.contextName ?? options.connectionName;
|
|
53
55
|
isolationLevel = options.isolationLevel;
|
|
54
56
|
retry = options.retry;
|
|
57
|
+
disabled = options.disabled;
|
|
58
|
+
flushMode = options.flushMode;
|
|
55
59
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
isolationLevel = core_1.IsolationLevel.READ_COMMITTED;
|
|
64
|
-
}
|
|
65
|
-
return { contextName, isolationLevel, retry };
|
|
60
|
+
return {
|
|
61
|
+
flushMode,
|
|
62
|
+
retry: retry ?? false,
|
|
63
|
+
disabled: disabled ?? false,
|
|
64
|
+
contextName: contextName ?? "default",
|
|
65
|
+
isolationLevel: isolationLevel ?? core_1.IsolationLevel.READ_COMMITTED
|
|
66
|
+
};
|
|
66
67
|
}
|
|
67
68
|
async executeInTransaction(next, options) {
|
|
68
69
|
const manager = this.context.get(options.contextName);
|
|
70
|
+
if (!manager) {
|
|
71
|
+
throw new Error(`No such context: ${options.contextName}. Please check if the async context is lost in one of the asynchronous operations.`);
|
|
72
|
+
}
|
|
73
|
+
if (options.disabled) {
|
|
74
|
+
return next();
|
|
75
|
+
}
|
|
69
76
|
return manager.transactional(() => next(), {
|
|
77
|
+
flushMode: options.flushMode,
|
|
70
78
|
isolationLevel: options.isolationLevel
|
|
71
79
|
});
|
|
72
80
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TransactionalInterceptor.js","sourceRoot":"","sources":["../../../src/interceptors/TransactionalInterceptor.ts"],"names":[],"mappings":";;;;AAAA,iCAAsG;AACtG,yCAAoC;AACpC,6DAAwD;AACxD,iEAA4D;AAC5D,mEAA8D;AAC9D,
|
|
1
|
+
{"version":3,"file":"TransactionalInterceptor.js","sourceRoot":"","sources":["../../../src/interceptors/TransactionalInterceptor.ts"],"names":[],"mappings":"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","sourcesContent":["import {Inject, Interceptor, InterceptorContext, InterceptorMethods, InterceptorNext} from \"@tsed/di\";\nimport {Logger} from \"@tsed/logger\";\nimport {RetryStrategy} from \"../services/RetryStrategy\";\nimport {MikroOrmContext} from \"../services/MikroOrmContext\";\nimport {MikroOrmRegistry} from \"../services/MikroOrmRegistry\";\nimport {FlushMode, IsolationLevel} from \"@mikro-orm/core\";\n\nexport interface TransactionOptions {\n retry?: boolean;\n disabled?: boolean;\n isolationLevel?: IsolationLevel;\n flushMode?: FlushMode;\n contextName?: string;\n /**\n * @deprecated Since 2022-02-01. Use {@link contextName} instead\n */\n connectionName?: string;\n}\n\ntype TransactionSettings = Required<Omit<TransactionOptions, \"connectionName\" | \"flushMode\">> & {flushMode?: FlushMode};\n\n@Interceptor()\nexport class TransactionalInterceptor implements InterceptorMethods {\n constructor(\n @Inject() private readonly registry: MikroOrmRegistry,\n @Inject() private readonly context: MikroOrmContext,\n @Inject() private readonly logger: Logger,\n @Inject(RetryStrategy)\n private readonly retryStrategy?: RetryStrategy\n ) {}\n\n public async intercept(context: InterceptorContext<unknown>, next: InterceptorNext): Promise<unknown> {\n const options = this.extractContextName(context);\n\n if (options.retry && !this.retryStrategy) {\n this.logger.warn(`To retry a transaction you have to implement a \"${RetryStrategy.description}\" interface`);\n }\n\n if (this.context.has(options.contextName)) {\n return this.runWithinCtx(next, options);\n }\n\n return this.runWithinNewCtx(next, options);\n }\n\n private runWithinCtx(next: InterceptorNext, options: TransactionSettings): Promise<unknown> | unknown {\n const callback = () => this.executeInTransaction(next, options);\n\n return options.retry && this.retryStrategy ? this.retryStrategy.acquire(callback) : callback();\n }\n\n private runWithinNewCtx(next: InterceptorNext, options: TransactionSettings): Promise<unknown> | unknown {\n const orm = this.registry.get(options.contextName);\n\n if (!orm) {\n throw new Error(\n `No such context: ${options.contextName}. Please register a corresponding MikroOrm instance using '@Configuration()' decorator.`\n );\n }\n\n return this.context.run([orm.em], () => this.runWithinCtx(next, options));\n }\n\n private extractContextName(context: InterceptorContext<unknown>): TransactionSettings {\n const options = (context.options || {}) as TransactionOptions | string;\n\n let isolationLevel: IsolationLevel | undefined;\n let disabled: boolean | undefined;\n let contextName: string | undefined;\n let flushMode: FlushMode | undefined;\n let retry: boolean | undefined;\n\n if (typeof options === \"string\") {\n contextName = options;\n } else if (options) {\n contextName = options.contextName ?? options.connectionName;\n isolationLevel = options.isolationLevel;\n retry = options.retry;\n disabled = options.disabled;\n flushMode = options.flushMode;\n }\n\n return {\n flushMode,\n retry: retry ?? false,\n disabled: disabled ?? false,\n contextName: contextName ?? \"default\",\n isolationLevel: isolationLevel ?? IsolationLevel.READ_COMMITTED\n };\n }\n\n private async executeInTransaction(next: InterceptorNext, options: TransactionSettings): Promise<unknown> {\n const manager = this.context.get(options.contextName);\n\n if (!manager) {\n throw new Error(\n `No such context: ${options.contextName}. Please check if the async context is lost in one of the asynchronous operations.`\n );\n }\n\n if (options.disabled) {\n return next();\n }\n\n return manager.transactional(() => next(), {\n flushMode: options.flushMode,\n isolationLevel: options.isolationLevel\n });\n }\n}\n"]}
|
|
@@ -38,9 +38,11 @@ let TransactionalInterceptor = class TransactionalInterceptor {
|
|
|
38
38
|
return this.context.run([orm.em], () => this.runWithinCtx(next, options));
|
|
39
39
|
}
|
|
40
40
|
extractContextName(context) {
|
|
41
|
-
const options = context.options || {};
|
|
41
|
+
const options = (context.options || {});
|
|
42
42
|
let isolationLevel;
|
|
43
|
+
let disabled;
|
|
43
44
|
let contextName;
|
|
45
|
+
let flushMode;
|
|
44
46
|
let retry;
|
|
45
47
|
if (typeof options === "string") {
|
|
46
48
|
contextName = options;
|
|
@@ -49,21 +51,27 @@ let TransactionalInterceptor = class TransactionalInterceptor {
|
|
|
49
51
|
contextName = options.contextName ?? options.connectionName;
|
|
50
52
|
isolationLevel = options.isolationLevel;
|
|
51
53
|
retry = options.retry;
|
|
54
|
+
disabled = options.disabled;
|
|
55
|
+
flushMode = options.flushMode;
|
|
52
56
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
isolationLevel = IsolationLevel.READ_COMMITTED;
|
|
61
|
-
}
|
|
62
|
-
return { contextName, isolationLevel, retry };
|
|
57
|
+
return {
|
|
58
|
+
flushMode,
|
|
59
|
+
retry: retry ?? false,
|
|
60
|
+
disabled: disabled ?? false,
|
|
61
|
+
contextName: contextName ?? "default",
|
|
62
|
+
isolationLevel: isolationLevel ?? IsolationLevel.READ_COMMITTED
|
|
63
|
+
};
|
|
63
64
|
}
|
|
64
65
|
async executeInTransaction(next, options) {
|
|
65
66
|
const manager = this.context.get(options.contextName);
|
|
67
|
+
if (!manager) {
|
|
68
|
+
throw new Error(`No such context: ${options.contextName}. Please check if the async context is lost in one of the asynchronous operations.`);
|
|
69
|
+
}
|
|
70
|
+
if (options.disabled) {
|
|
71
|
+
return next();
|
|
72
|
+
}
|
|
66
73
|
return manager.transactional(() => next(), {
|
|
74
|
+
flushMode: options.flushMode,
|
|
67
75
|
isolationLevel: options.isolationLevel
|
|
68
76
|
});
|
|
69
77
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TransactionalInterceptor.js","sourceRoot":"","sources":["../../../src/interceptors/TransactionalInterceptor.ts"],"names":[],"mappings":";AAAA,OAAO,EAAC,MAAM,EAAE,WAAW,EAA0D,MAAM,UAAU,CAAC;AACtG,OAAO,EAAC,MAAM,EAAC,MAAM,cAAc,CAAC;AACpC,OAAO,EAAC,aAAa,EAAC,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAC,eAAe,EAAC,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAC,gBAAgB,EAAC,MAAM,8BAA8B,CAAC;AAC9D,OAAO,
|
|
1
|
+
{"version":3,"file":"TransactionalInterceptor.js","sourceRoot":"","sources":["../../../src/interceptors/TransactionalInterceptor.ts"],"names":[],"mappings":";AAAA,OAAO,EAAC,MAAM,EAAE,WAAW,EAA0D,MAAM,UAAU,CAAC;AACtG,OAAO,EAAC,MAAM,EAAC,MAAM,cAAc,CAAC;AACpC,OAAO,EAAC,aAAa,EAAC,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAC,eAAe,EAAC,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAC,gBAAgB,EAAC,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAAY,cAAc,EAAC,MAAM,iBAAiB,CAAC;AAiB1D,IAAa,wBAAwB,GAArC,MAAa,wBAAwB;IAEN;IACA;IACA;IAEV;IALnB,YAC6B,QAA0B,EAC1B,OAAwB,EACxB,MAAc,EAExB,aAA6B;QAJnB,aAAQ,GAAR,QAAQ,CAAkB;QAC1B,YAAO,GAAP,OAAO,CAAiB;QACxB,WAAM,GAAN,MAAM,CAAQ;QAExB,kBAAa,GAAb,aAAa,CAAgB;IAC7C,CAAC;IAEG,KAAK,CAAC,SAAS,CAAC,OAAoC,EAAE,IAAqB;QAChF,MAAM,OAAO,GAAG,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;QAEjD,IAAI,OAAO,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE;YACxC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,mDAAmD,aAAa,CAAC,WAAW,aAAa,CAAC,CAAC;SAC7G;QAED,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE;YACzC,OAAO,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;SACzC;QAED,OAAO,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC7C,CAAC;IAEO,YAAY,CAAC,IAAqB,EAAE,OAA4B;QACtE,MAAM,QAAQ,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,oBAAoB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAEhE,OAAO,OAAO,CAAC,KAAK,IAAI,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IACjG,CAAC;IAEO,eAAe,CAAC,IAAqB,EAAE,OAA4B;QACzE,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;QAEnD,IAAI,CAAC,GAAG,EAAE;YACR,MAAM,IAAI,KAAK,CACb,oBAAoB,OAAO,CAAC,WAAW,yFAAyF,CACjI,CAAC;SACH;QAED,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;IAC5E,CAAC;IAEO,kBAAkB,CAAC,OAAoC;QAC7D,MAAM,OAAO,GAAG,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,CAAgC,CAAC;QAEvE,IAAI,cAA0C,CAAC;QAC/C,IAAI,QAA6B,CAAC;QAClC,IAAI,WAA+B,CAAC;QACpC,IAAI,SAAgC,CAAC;QACrC,IAAI,KAA0B,CAAC;QAE/B,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE;YAC/B,WAAW,GAAG,OAAO,CAAC;SACvB;aAAM,IAAI,OAAO,EAAE;YAClB,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,cAAc,CAAC;YAC5D,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC;YACxC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;YACtB,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;YAC5B,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;SAC/B;QAED,OAAO;YACL,SAAS;YACT,KAAK,EAAE,KAAK,IAAI,KAAK;YACrB,QAAQ,EAAE,QAAQ,IAAI,KAAK;YAC3B,WAAW,EAAE,WAAW,IAAI,SAAS;YACrC,cAAc,EAAE,cAAc,IAAI,cAAc,CAAC,cAAc;SAChE,CAAC;IACJ,CAAC;IAEO,KAAK,CAAC,oBAAoB,CAAC,IAAqB,EAAE,OAA4B;QACpF,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;QAEtD,IAAI,CAAC,OAAO,EAAE;YACZ,MAAM,IAAI,KAAK,CACb,oBAAoB,OAAO,CAAC,WAAW,oFAAoF,CAC5H,CAAC;SACH;QAED,IAAI,OAAO,CAAC,QAAQ,EAAE;YACpB,OAAO,IAAI,EAAE,CAAC;SACf;QAED,OAAO,OAAO,CAAC,aAAa,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE;YACzC,SAAS,EAAE,OAAO,CAAC,SAAS;YAC5B,cAAc,EAAE,OAAO,CAAC,cAAc;SACvC,CAAC,CAAC;IACL,CAAC;CACF,CAAA;AAvFY,wBAAwB;IADpC,WAAW,EAAE;IAGT,WAAA,MAAM,EAAE,CAAA;IACR,WAAA,MAAM,EAAE,CAAA;IACR,WAAA,MAAM,EAAE,CAAA;IACR,WAAA,MAAM,CAAC,aAAa,CAAC,CAAA;qCAHe,gBAAgB;QACjB,eAAe;QAChB,MAAM;GAJhC,wBAAwB,CAuFpC;SAvFY,wBAAwB","sourcesContent":["import {Inject, Interceptor, InterceptorContext, InterceptorMethods, InterceptorNext} from \"@tsed/di\";\nimport {Logger} from \"@tsed/logger\";\nimport {RetryStrategy} from \"../services/RetryStrategy\";\nimport {MikroOrmContext} from \"../services/MikroOrmContext\";\nimport {MikroOrmRegistry} from \"../services/MikroOrmRegistry\";\nimport {FlushMode, IsolationLevel} from \"@mikro-orm/core\";\n\nexport interface TransactionOptions {\n retry?: boolean;\n disabled?: boolean;\n isolationLevel?: IsolationLevel;\n flushMode?: FlushMode;\n contextName?: string;\n /**\n * @deprecated Since 2022-02-01. Use {@link contextName} instead\n */\n connectionName?: string;\n}\n\ntype TransactionSettings = Required<Omit<TransactionOptions, \"connectionName\" | \"flushMode\">> & {flushMode?: FlushMode};\n\n@Interceptor()\nexport class TransactionalInterceptor implements InterceptorMethods {\n constructor(\n @Inject() private readonly registry: MikroOrmRegistry,\n @Inject() private readonly context: MikroOrmContext,\n @Inject() private readonly logger: Logger,\n @Inject(RetryStrategy)\n private readonly retryStrategy?: RetryStrategy\n ) {}\n\n public async intercept(context: InterceptorContext<unknown>, next: InterceptorNext): Promise<unknown> {\n const options = this.extractContextName(context);\n\n if (options.retry && !this.retryStrategy) {\n this.logger.warn(`To retry a transaction you have to implement a \"${RetryStrategy.description}\" interface`);\n }\n\n if (this.context.has(options.contextName)) {\n return this.runWithinCtx(next, options);\n }\n\n return this.runWithinNewCtx(next, options);\n }\n\n private runWithinCtx(next: InterceptorNext, options: TransactionSettings): Promise<unknown> | unknown {\n const callback = () => this.executeInTransaction(next, options);\n\n return options.retry && this.retryStrategy ? this.retryStrategy.acquire(callback) : callback();\n }\n\n private runWithinNewCtx(next: InterceptorNext, options: TransactionSettings): Promise<unknown> | unknown {\n const orm = this.registry.get(options.contextName);\n\n if (!orm) {\n throw new Error(\n `No such context: ${options.contextName}. Please register a corresponding MikroOrm instance using '@Configuration()' decorator.`\n );\n }\n\n return this.context.run([orm.em], () => this.runWithinCtx(next, options));\n }\n\n private extractContextName(context: InterceptorContext<unknown>): TransactionSettings {\n const options = (context.options || {}) as TransactionOptions | string;\n\n let isolationLevel: IsolationLevel | undefined;\n let disabled: boolean | undefined;\n let contextName: string | undefined;\n let flushMode: FlushMode | undefined;\n let retry: boolean | undefined;\n\n if (typeof options === \"string\") {\n contextName = options;\n } else if (options) {\n contextName = options.contextName ?? options.connectionName;\n isolationLevel = options.isolationLevel;\n retry = options.retry;\n disabled = options.disabled;\n flushMode = options.flushMode;\n }\n\n return {\n flushMode,\n retry: retry ?? false,\n disabled: disabled ?? false,\n contextName: contextName ?? \"default\",\n isolationLevel: isolationLevel ?? IsolationLevel.READ_COMMITTED\n };\n }\n\n private async executeInTransaction(next: InterceptorNext, options: TransactionSettings): Promise<unknown> {\n const manager = this.context.get(options.contextName);\n\n if (!manager) {\n throw new Error(\n `No such context: ${options.contextName}. Please check if the async context is lost in one of the asynchronous operations.`\n );\n }\n\n if (options.disabled) {\n return next();\n }\n\n return manager.transactional(() => next(), {\n flushMode: options.flushMode,\n isolationLevel: options.isolationLevel\n });\n }\n}\n"]}
|
|
@@ -3,10 +3,12 @@ import { Logger } from "@tsed/logger";
|
|
|
3
3
|
import { RetryStrategy } from "../services/RetryStrategy";
|
|
4
4
|
import { MikroOrmContext } from "../services/MikroOrmContext";
|
|
5
5
|
import { MikroOrmRegistry } from "../services/MikroOrmRegistry";
|
|
6
|
-
import { IsolationLevel } from "@mikro-orm/core";
|
|
6
|
+
import { FlushMode, IsolationLevel } from "@mikro-orm/core";
|
|
7
7
|
export interface TransactionOptions {
|
|
8
8
|
retry?: boolean;
|
|
9
|
+
disabled?: boolean;
|
|
9
10
|
isolationLevel?: IsolationLevel;
|
|
11
|
+
flushMode?: FlushMode;
|
|
10
12
|
contextName?: string;
|
|
11
13
|
/**
|
|
12
14
|
* @deprecated Since 2022-02-01. Use {@link contextName} instead
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tsed/mikro-orm",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.119.1",
|
|
4
4
|
"description": "MikroORM package for Ts.ED framework",
|
|
5
5
|
"private": false,
|
|
6
6
|
"source": "./src/index.ts",
|
|
@@ -26,20 +26,20 @@
|
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@mikro-orm/core": "^5.2.2",
|
|
28
28
|
"@mikro-orm/mongodb": "^5.2.2",
|
|
29
|
-
"@tsed/common": "6.
|
|
30
|
-
"@tsed/core": "6.
|
|
31
|
-
"@tsed/di": "6.
|
|
32
|
-
"@tsed/json-mapper": "6.
|
|
29
|
+
"@tsed/common": "6.119.1",
|
|
30
|
+
"@tsed/core": "6.119.1",
|
|
31
|
+
"@tsed/di": "6.119.1",
|
|
32
|
+
"@tsed/json-mapper": "6.119.1",
|
|
33
33
|
"@tsed/logger": ">=6.2.0",
|
|
34
|
-
"@tsed/schema": "6.
|
|
35
|
-
"@tsed/testing-mongoose": "6.
|
|
34
|
+
"@tsed/schema": "6.119.1",
|
|
35
|
+
"@tsed/testing-mongoose": "6.119.1",
|
|
36
36
|
"ts-mockito": "^2.6.1"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"@mikro-orm/core": ">=4.5.9",
|
|
40
|
-
"@tsed/common": "^6.
|
|
41
|
-
"@tsed/core": "^6.
|
|
42
|
-
"@tsed/di": "^6.
|
|
40
|
+
"@tsed/common": "^6.119.1",
|
|
41
|
+
"@tsed/core": "^6.119.1",
|
|
42
|
+
"@tsed/di": "^6.119.1",
|
|
43
43
|
"@tsed/logger": ">=6.2.0"
|
|
44
44
|
},
|
|
45
45
|
"repository": "https://github.com/tsedio/tsed",
|
|
@@ -48,8 +48,5 @@
|
|
|
48
48
|
},
|
|
49
49
|
"homepage": "https://github.com/tsedio/tsed/tree/production/packages/orm/mikro-orm",
|
|
50
50
|
"author": "Romain Lenzotti",
|
|
51
|
-
"license": "MIT"
|
|
52
|
-
"publishConfig": {
|
|
53
|
-
"tag": "rc"
|
|
54
|
-
}
|
|
51
|
+
"license": "MIT"
|
|
55
52
|
}
|
package/readme.md
CHANGED
|
@@ -132,7 +132,7 @@ export class UsersService {
|
|
|
132
132
|
|
|
133
133
|
It's also possible to inject an ORM by its context name:
|
|
134
134
|
|
|
135
|
-
```
|
|
135
|
+
```typescript
|
|
136
136
|
import {Injectable} from "@tsed/di";
|
|
137
137
|
|
|
138
138
|
@Injectable()
|
|
@@ -273,11 +273,47 @@ export class UsersCtrl {
|
|
|
273
273
|
}
|
|
274
274
|
```
|
|
275
275
|
|
|
276
|
+
By default, `IsolationLevel.READ_COMMITTED` is used. You can override it, specifying the isolation level for the transaction by supplying it as the `isolationLevel` parameter in the `@Transactional` decorator:
|
|
277
|
+
|
|
278
|
+
```typescript
|
|
279
|
+
@Post("/")
|
|
280
|
+
@Transactional({isolationLevel: IsolationLevel.SERIALIZABLE})
|
|
281
|
+
create(@BodyParams() user: User): Promise<User> {
|
|
282
|
+
return this.usersService.create(user);
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
The MikroORM supports the standard isolation levels such as `SERIALIZABLE` or `REPEATABLE READ`, the full list of available options see [here](https://mikro-orm.io/docs/transactions#isolation-levels).
|
|
287
|
+
|
|
288
|
+
You can also set the [flushing strategy](https://mikro-orm.io/docs/unit-of-work#flush-modes) for the transaction by setting the `flushMode`:
|
|
289
|
+
|
|
290
|
+
```typescript
|
|
291
|
+
@Post("/")
|
|
292
|
+
@Transactional({flushMode: FlushMode.AUTO})
|
|
293
|
+
create(@BodyParams() user: User): Promise<User> {
|
|
294
|
+
return this.usersService.create(user);
|
|
295
|
+
}
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
In some cases, you might need to avoid an explicit transaction, but preserve an async context to prevent the usage of the global identity map. For example, starting with v3.4, the MongoDB driver supports transactions. Yet, you have to use a replica set, otherwise, the driver will raise an exception.
|
|
299
|
+
|
|
300
|
+
To prevent `@Transactional()` use of an explicit transaction, you just need to set the `disabled` field to `true`:
|
|
301
|
+
|
|
302
|
+
```typescript
|
|
303
|
+
@Post("/")
|
|
304
|
+
@Transactional({disabled: true})
|
|
305
|
+
create(@BodyParams() user: User): Promise<User> {
|
|
306
|
+
return this.usersService.create(user);
|
|
307
|
+
}
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
## Retry policy
|
|
311
|
+
|
|
276
312
|
By default, the automatic retry policy is disabled. You can implement your own to match the business requirements and the nature of the failure. For some noncritical operations, it is better to fail as soon as possible rather than retry a coupe of times. For example, in an interactive web application, it is better to fail right after a smaller number of retries with only a short delay between retry attempts, and display a message to the user (for example, "please try again later").
|
|
277
313
|
|
|
278
314
|
The `@Transactional()` decorator allows you to enable a retry policy for the particular resources. You just need to implement the `RetryStrategy` interface and use `registerProvider()` or `@OverrideProvider()` to register it in the IoC container. Below you can find an example to handle occurred optimistic locks based on [an exponential backoff retry strategy](https://en.wikipedia.org/wiki/Exponential_backoff).
|
|
279
315
|
|
|
280
|
-
```
|
|
316
|
+
```typescript
|
|
281
317
|
import {OptimisticLockError} from "@mikro-orm/core";
|
|
282
318
|
import {RetryStrategy} from "@tsed/mikro-orm";
|
|
283
319
|
|
|
@@ -353,20 +389,6 @@ export class UsersCtrl {
|
|
|
353
389
|
}
|
|
354
390
|
```
|
|
355
391
|
|
|
356
|
-
## Transaction isolation levels
|
|
357
|
-
|
|
358
|
-
By default, `IsolationLevel.READ_COMMITTED` is used. You can override it, specifying the isolation level for the transaction by supplying it as the `isolationLevel` parameter in the `@Transactional` decorator:
|
|
359
|
-
|
|
360
|
-
```typescript
|
|
361
|
-
@Post("/")
|
|
362
|
-
@Transactional({isolationLevel: IsolationLevel.SERIALIZABLE})
|
|
363
|
-
create(@BodyParams() user: User): Promise<User> {
|
|
364
|
-
return this.usersService.create(user);
|
|
365
|
-
}
|
|
366
|
-
```
|
|
367
|
-
|
|
368
|
-
The MikroORM supports the standard isolation levels such as `SERIALIZABLE` or `REPEATABLE READ`, the full list of available options see [here](https://mikro-orm.io/docs/transactions#isolation-levels).
|
|
369
|
-
|
|
370
392
|
## Contributors
|
|
371
393
|
|
|
372
394
|
Please read [contributing guidelines here](https://tsed.io/CONTRIBUTING.html)
|