@rsdk/db.typeorm 2.5.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/.env +2 -0
- package/CHANGELOG.md +155 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/context.d.ts +46 -0
- package/dist/internal/context.js +123 -0
- package/dist/internal/context.js.map +1 -0
- package/dist/internal/exceptions.d.ts +67 -0
- package/dist/internal/exceptions.js +99 -0
- package/dist/internal/exceptions.js.map +1 -0
- package/dist/internal/initializer.d.ts +15 -0
- package/dist/internal/initializer.js +158 -0
- package/dist/internal/initializer.js.map +1 -0
- package/dist/internal/strategy.d.ts +55 -0
- package/dist/internal/strategy.js +109 -0
- package/dist/internal/strategy.js.map +1 -0
- package/dist/internal/test/strategy.test.e2e.d.ts +5 -0
- package/dist/internal/test/strategy.test.e2e.js +779 -0
- package/dist/internal/test/strategy.test.e2e.js.map +1 -0
- package/dist/internal/test/util.d.ts +22 -0
- package/dist/internal/test/util.js +72 -0
- package/dist/internal/test/util.js.map +1 -0
- package/dist/providers/index.d.ts +3 -0
- package/dist/providers/index.js +20 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/typeorm-logger.adapter.d.ts +13 -0
- package/dist/providers/typeorm-logger.adapter.js +61 -0
- package/dist/providers/typeorm-logger.adapter.js.map +1 -0
- package/dist/providers/typeorm.config.d.ts +10 -0
- package/dist/providers/typeorm.config.js +79 -0
- package/dist/providers/typeorm.config.js.map +1 -0
- package/dist/providers/typeorm.healthcheck.d.ts +8 -0
- package/dist/providers/typeorm.healthcheck.js +36 -0
- package/dist/providers/typeorm.healthcheck.js.map +1 -0
- package/dist/typeorm.errors-transformer.d.ts +5 -0
- package/dist/typeorm.errors-transformer.js +32 -0
- package/dist/typeorm.errors-transformer.js.map +1 -0
- package/dist/typeorm.plugin.d.ts +15 -0
- package/dist/typeorm.plugin.js +67 -0
- package/dist/typeorm.plugin.js.map +1 -0
- package/dist/types.d.ts +14 -0
- package/dist/types.js +18 -0
- package/dist/types.js.map +1 -0
- package/jest.config.js +7 -0
- package/package.json +26 -0
- package/src/index.ts +9 -0
- package/src/internal/context.ts +164 -0
- package/src/internal/exceptions.ts +96 -0
- package/src/internal/initializer.ts +213 -0
- package/src/internal/strategy.ts +149 -0
- package/src/internal/test/strategy.test.e2e.ts +1050 -0
- package/src/internal/test/util.ts +51 -0
- package/src/providers/index.ts +3 -0
- package/src/providers/typeorm-logger.adapter.ts +59 -0
- package/src/providers/typeorm.config.ts +61 -0
- package/src/providers/typeorm.healthcheck.ts +20 -0
- package/src/typeorm.errors-transformer.ts +35 -0
- package/src/typeorm.plugin.ts +83 -0
- package/src/types.ts +23 -0
- package/tsconfig.build.json +9 -0
- package/tsconfig.json +9 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Initializer = void 0;
|
|
4
|
+
const db_1 = require("@rsdk/db");
|
|
5
|
+
const typeorm_1 = require("typeorm");
|
|
6
|
+
const exceptions_1 = require("./exceptions");
|
|
7
|
+
const originalCreateQueryRunner = typeorm_1.DataSource.prototype.createQueryRunner;
|
|
8
|
+
class Initializer {
|
|
9
|
+
static storage = new db_1.ContextStorage();
|
|
10
|
+
/**
|
|
11
|
+
* Патчинг всех необходимых методов из typeorm
|
|
12
|
+
*/
|
|
13
|
+
static initialize() {
|
|
14
|
+
Object.defineProperty(typeorm_1.DataSource.prototype, 'createQueryRunner', {
|
|
15
|
+
value: Initializer.wrappedCreateQueryRunner,
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
static wrappedCreateQueryRunner(...args) {
|
|
19
|
+
const originalQueryRunner = originalCreateQueryRunner.call(this, ...args);
|
|
20
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
21
|
+
const dataSource = this;
|
|
22
|
+
const proxiesQueryRunner = new Proxy(originalQueryRunner, {
|
|
23
|
+
get(target, propertyKey) {
|
|
24
|
+
const originalQueryRunnerProp = target[propertyKey];
|
|
25
|
+
/**
|
|
26
|
+
* Мы сами контролируем то когда будет освобожден queryRunner
|
|
27
|
+
* Даже сейчас есть проблема с тем что в пул может попасть соединение в котором не была завершена транзакция
|
|
28
|
+
*/
|
|
29
|
+
if (propertyKey === 'release') {
|
|
30
|
+
return Initializer.getWrappedRelease(target);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* ATTENTION: Очень важна последовательность, потому что ряд драйверов (postgres например) делает так
|
|
34
|
+
* @see https://github.com/typeorm/typeorm/blob/f5b93c14b5efa1a55aed0211a4757af1b3d6e66b/src/driver/postgres/PostgresQueryRunner.ts#L148
|
|
35
|
+
* Ничего сверх критичного не происходит, или по крайней мере я не нашёл этого
|
|
36
|
+
* Единственное, уходит в бесконечную проверку коннекты к бд не висят, но `DataSource.destroy` уходит в бесконечный цикл
|
|
37
|
+
* @see https://github.com/typeorm/typeorm/blob/f5b93c14b5efa1a55aed0211a4757af1b3d6e66b/src/driver/postgres/PostgresDriver.ts#L1532
|
|
38
|
+
*/
|
|
39
|
+
/**
|
|
40
|
+
* Защита от дурака
|
|
41
|
+
*/
|
|
42
|
+
/**
|
|
43
|
+
* class A {
|
|
44
|
+
* queryRunner: QueryRunner
|
|
45
|
+
*
|
|
46
|
+
* constructor(private dataSource: DataSource) {
|
|
47
|
+
* this.queryRunner = this.dataSource.createQueryRunner()
|
|
48
|
+
* }
|
|
49
|
+
*
|
|
50
|
+
* @Transactional()
|
|
51
|
+
* transactionDo() {
|
|
52
|
+
* // wtf -_-
|
|
53
|
+
* this.queryRunner.query('drop database')
|
|
54
|
+
* }
|
|
55
|
+
* }
|
|
56
|
+
*/
|
|
57
|
+
if (typeof originalQueryRunnerProp === 'function') {
|
|
58
|
+
return Initializer.getProxiesMethod(dataSource, originalQueryRunnerProp, target);
|
|
59
|
+
}
|
|
60
|
+
const context = Initializer.storage.getContext();
|
|
61
|
+
if (!context) {
|
|
62
|
+
return originalQueryRunnerProp;
|
|
63
|
+
}
|
|
64
|
+
if (context.isReleased) {
|
|
65
|
+
throw new exceptions_1.ContextIsReleased();
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Если кто-то обратился к любому queryRunner во время исполнения функции контекста, а в контексте ещё нет queryRunner
|
|
69
|
+
* Этот queryRunner добавляем в контекст
|
|
70
|
+
*/
|
|
71
|
+
if (!context.queryRunner &&
|
|
72
|
+
/**
|
|
73
|
+
* Дополнительно проверяем не является ли этот queryRunner релизнутым/с активной транзакцией
|
|
74
|
+
*/
|
|
75
|
+
target.isTransactionActive &&
|
|
76
|
+
!target.isReleased) {
|
|
77
|
+
context.attach(originalQueryRunner);
|
|
78
|
+
}
|
|
79
|
+
if (propertyKey === 'manager') {
|
|
80
|
+
/**
|
|
81
|
+
* Из-за того что у manager должен быть линк на queryRunner
|
|
82
|
+
*/
|
|
83
|
+
return dataSource.createEntityManager(proxiesQueryRunner);
|
|
84
|
+
}
|
|
85
|
+
return originalQueryRunnerProp;
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
return proxiesQueryRunner;
|
|
89
|
+
}
|
|
90
|
+
static getValidQueryRunner(dataSource, originalQueryRunner) {
|
|
91
|
+
/**
|
|
92
|
+
* Теоретически может быть ситуация в которой оригинальный
|
|
93
|
+
* queryRunner уже кто-то использует в транзакции или его уже релизнули
|
|
94
|
+
*/
|
|
95
|
+
if (originalQueryRunner.isTransactionActive ||
|
|
96
|
+
originalQueryRunner.isReleased) {
|
|
97
|
+
/**
|
|
98
|
+
* Так как это нежелательное поведение показываем варнинг
|
|
99
|
+
*/
|
|
100
|
+
Initializer.warnOnBusyQueryRunner(originalQueryRunner);
|
|
101
|
+
return originalCreateQueryRunner.call(dataSource, originalQueryRunner.getReplicationMode());
|
|
102
|
+
}
|
|
103
|
+
return originalQueryRunner;
|
|
104
|
+
}
|
|
105
|
+
static getWrappedRelease(originalQueryRunner) {
|
|
106
|
+
return async function () {
|
|
107
|
+
const ctx = Initializer.storage.getContext();
|
|
108
|
+
const contextQueryRunner = ctx?.queryRunner;
|
|
109
|
+
if (ctx && contextQueryRunner === originalQueryRunner) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
return originalQueryRunner.release.call(originalQueryRunner);
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
static getProxiesMethod(dataSource, originalQueryRunnerProp, originalQueryRunner) {
|
|
116
|
+
// Чтобы ts не нервничал
|
|
117
|
+
if (typeof originalQueryRunnerProp !== 'function') {
|
|
118
|
+
throw new exceptions_1.ProxiedMethodIsNotFunction();
|
|
119
|
+
}
|
|
120
|
+
const originalQueryRunnerFunc = originalQueryRunnerProp;
|
|
121
|
+
return async function (...args) {
|
|
122
|
+
const context = Initializer.storage.getContext();
|
|
123
|
+
if (!context) {
|
|
124
|
+
/**
|
|
125
|
+
* Если мы не в контексте просто даём делать свою работу
|
|
126
|
+
*/
|
|
127
|
+
return originalQueryRunnerFunc.call(originalQueryRunner, ...args);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Если у нас уже есть проинициализированный queryRunner делегируем работу ему
|
|
131
|
+
*/
|
|
132
|
+
if (context.isInitialized()) {
|
|
133
|
+
return originalQueryRunnerFunc.call(context.queryRunner, ...args);
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Если в контексте нет queryRunner его надо установить перед тем как инициализировать транзакцию
|
|
137
|
+
*/
|
|
138
|
+
if (!context.queryRunner) {
|
|
139
|
+
const resultedQueryRunner = Initializer.getValidQueryRunner(dataSource, originalQueryRunner);
|
|
140
|
+
context.attach(resultedQueryRunner);
|
|
141
|
+
}
|
|
142
|
+
await context.initialize();
|
|
143
|
+
return await originalQueryRunnerFunc.call(context.queryRunner, ...args);
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
static warnOnBusyQueryRunner(potentialQueryRunner) {
|
|
147
|
+
const warnMessage = Initializer.getWarnMessage(potentialQueryRunner);
|
|
148
|
+
console.warn(warnMessage);
|
|
149
|
+
}
|
|
150
|
+
static getWarnMessage(potentialQueryRunner) {
|
|
151
|
+
return `[Initializer -> getProxiesMethod] originalQueryRunner already - ${[
|
|
152
|
+
potentialQueryRunner.isTransactionActive && 'used in transaction',
|
|
153
|
+
potentialQueryRunner.isReleased && 'released',
|
|
154
|
+
].join(' and ')}`;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
exports.Initializer = Initializer;
|
|
158
|
+
//# sourceMappingURL=initializer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"initializer.js","sourceRoot":"","sources":["../../src/internal/initializer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { CallBack, TransactionalStrategy } from '@rsdk/db';
|
|
2
|
+
import type { IsolationLevel } from '../types';
|
|
3
|
+
import { TypeOrmContext } from './context';
|
|
4
|
+
export declare class TypeormTransactionalStrategy implements TransactionalStrategy<IsolationLevel, TypeOrmContext> {
|
|
5
|
+
/**
|
|
6
|
+
* Возвращает текущий контекст если вызвано внутри него
|
|
7
|
+
*/
|
|
8
|
+
getContext(): TypeOrmContext | undefined;
|
|
9
|
+
/**
|
|
10
|
+
* Возвращает обернутую в контекст функцию
|
|
11
|
+
* @param fn
|
|
12
|
+
* @param propagationLevel
|
|
13
|
+
* @param options
|
|
14
|
+
*/
|
|
15
|
+
bindContext<TResult, TArgs extends any[]>(fn: CallBack<TArgs, TResult>, options?: IsolationLevel): CallBack<TArgs, Promise<TResult>>;
|
|
16
|
+
/**
|
|
17
|
+
* Находимся ли мы в контексте и не является ли он suspend
|
|
18
|
+
*/
|
|
19
|
+
isRunning(): boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Вызывает функцию, обернутую внутри контекста с заданными параметрами и корректной обработкой транзакции
|
|
22
|
+
* @param isolation
|
|
23
|
+
* @param fn
|
|
24
|
+
* @param args
|
|
25
|
+
*/
|
|
26
|
+
runInContext<TResult, TArgs extends any[]>(isolation: IsolationLevel, fn: CallBack<TArgs, TResult>, ...args: TArgs): Promise<TResult>;
|
|
27
|
+
/**
|
|
28
|
+
* Вызывает функцию в новом контексте, игнорируя внешний если он существует
|
|
29
|
+
* @param isolationLevel
|
|
30
|
+
* @param fn
|
|
31
|
+
* @param args
|
|
32
|
+
*/
|
|
33
|
+
runFromNewContext<TResult, TArgs extends any[]>(isolationLevel: IsolationLevel, fn: CallBack<TArgs, TResult>, ...args: TArgs): Promise<TResult>;
|
|
34
|
+
/**
|
|
35
|
+
* Создаёт новый контекст внутри которого не будет создаваться/использоваться транзакция и игнорироваться внешняя
|
|
36
|
+
* @param fn
|
|
37
|
+
* @param args
|
|
38
|
+
*/
|
|
39
|
+
runOutTransactionalContext<TResult, TArgs extends any[]>(fn: CallBack<TArgs, TResult>, ...args: TArgs): Promise<TResult>;
|
|
40
|
+
/**
|
|
41
|
+
* Вызывает функцию во вложенном уровне контекста
|
|
42
|
+
* @param context
|
|
43
|
+
* @param isolationLevel
|
|
44
|
+
* @param fn
|
|
45
|
+
* @param args
|
|
46
|
+
*/
|
|
47
|
+
nestedExecute<TResult, TArgs extends any[]>(context: TypeOrmContext, isolationLevel: IsolationLevel, fn: CallBack<TArgs, TResult>, ...args: TArgs): Promise<TResult>;
|
|
48
|
+
/**
|
|
49
|
+
* Оборачивает функцию для корректного завершения транзакции, если она была проинициализирована внутри функции
|
|
50
|
+
* Важно - не оборачивает в вызов с контекстом
|
|
51
|
+
* @param mustReleased
|
|
52
|
+
* @param fn
|
|
53
|
+
*/
|
|
54
|
+
private wrapInTransactionContext;
|
|
55
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TypeormTransactionalStrategy = void 0;
|
|
4
|
+
const types_1 = require("../types");
|
|
5
|
+
const context_1 = require("./context");
|
|
6
|
+
const exceptions_1 = require("./exceptions");
|
|
7
|
+
const initializer_1 = require("./initializer");
|
|
8
|
+
class TypeormTransactionalStrategy {
|
|
9
|
+
/**
|
|
10
|
+
* Возвращает текущий контекст если вызвано внутри него
|
|
11
|
+
*/
|
|
12
|
+
getContext() {
|
|
13
|
+
return initializer_1.Initializer.storage.getContext();
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Возвращает обернутую в контекст функцию
|
|
17
|
+
* @param fn
|
|
18
|
+
* @param propagationLevel
|
|
19
|
+
* @param options
|
|
20
|
+
*/
|
|
21
|
+
bindContext(fn, options = types_1.DEFAULT_ISOLATION_LEVEL) {
|
|
22
|
+
return (...args) => this.runInContext(options, fn, ...args);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Находимся ли мы в контексте и не является ли он suspend
|
|
26
|
+
*/
|
|
27
|
+
isRunning() {
|
|
28
|
+
const context = initializer_1.Initializer.storage.getContext();
|
|
29
|
+
if (!context) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
return Boolean(context.suspended);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Вызывает функцию, обернутую внутри контекста с заданными параметрами и корректной обработкой транзакции
|
|
36
|
+
* @param isolation
|
|
37
|
+
* @param fn
|
|
38
|
+
* @param args
|
|
39
|
+
*/
|
|
40
|
+
async runInContext(isolation, fn, ...args) {
|
|
41
|
+
const currentContext = initializer_1.Initializer.storage.getContext();
|
|
42
|
+
if (!currentContext) {
|
|
43
|
+
return await this.runFromNewContext(isolation, fn, ...args);
|
|
44
|
+
}
|
|
45
|
+
return await this.nestedExecute(currentContext, isolation, fn, ...args);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Вызывает функцию в новом контексте, игнорируя внешний если он существует
|
|
49
|
+
* @param isolationLevel
|
|
50
|
+
* @param fn
|
|
51
|
+
* @param args
|
|
52
|
+
*/
|
|
53
|
+
async runFromNewContext(isolationLevel, fn, ...args) {
|
|
54
|
+
const typeormContext = context_1.TypeOrmContext.create(isolationLevel);
|
|
55
|
+
const wrapped = this.wrapInTransactionContext(true, fn);
|
|
56
|
+
return initializer_1.Initializer.storage.run(typeormContext, wrapped, ...args);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Создаёт новый контекст внутри которого не будет создаваться/использоваться транзакция и игнорироваться внешняя
|
|
60
|
+
* @param fn
|
|
61
|
+
* @param args
|
|
62
|
+
*/
|
|
63
|
+
async runOutTransactionalContext(fn, ...args) {
|
|
64
|
+
const typeormContext = context_1.TypeOrmContext.createSuspended();
|
|
65
|
+
const wrapped = this.wrapInTransactionContext(true, fn);
|
|
66
|
+
return initializer_1.Initializer.storage.run(typeormContext, wrapped, ...args);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Вызывает функцию во вложенном уровне контекста
|
|
70
|
+
* @param context
|
|
71
|
+
* @param isolationLevel
|
|
72
|
+
* @param fn
|
|
73
|
+
* @param args
|
|
74
|
+
*/
|
|
75
|
+
async nestedExecute(context, isolationLevel, fn, ...args) {
|
|
76
|
+
context.assertIsolationCompatibility(isolationLevel);
|
|
77
|
+
const wrapped = this.wrapInTransactionContext(false, fn);
|
|
78
|
+
context.addNestLayer();
|
|
79
|
+
return initializer_1.Initializer.storage.run(context, wrapped, ...args);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Оборачивает функцию для корректного завершения транзакции, если она была проинициализирована внутри функции
|
|
83
|
+
* Важно - не оборачивает в вызов с контекстом
|
|
84
|
+
* @param mustReleased
|
|
85
|
+
* @param fn
|
|
86
|
+
*/
|
|
87
|
+
wrapInTransactionContext(mustReleased, fn) {
|
|
88
|
+
return async (...args) => {
|
|
89
|
+
const context = initializer_1.Initializer.storage.getContext();
|
|
90
|
+
if (!context) {
|
|
91
|
+
throw new exceptions_1.ContextMustBeProvided();
|
|
92
|
+
}
|
|
93
|
+
try {
|
|
94
|
+
const result = await fn(...args);
|
|
95
|
+
await context.commitTransaction();
|
|
96
|
+
return result;
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
await context.rollbackTransaction();
|
|
100
|
+
throw error;
|
|
101
|
+
}
|
|
102
|
+
finally {
|
|
103
|
+
await context.finalize(mustReleased);
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
exports.TypeormTransactionalStrategy = TypeormTransactionalStrategy;
|
|
109
|
+
//# sourceMappingURL=strategy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"strategy.js","sourceRoot":"","sources":["../../src/internal/strategy.ts"],"names":[],"mappings":"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"}
|