UNPKG

@tsrt/typeorm-transactions

Version:
272 lines 14 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.TransactionManager = exports.UnitOfWork = exports.Transaction = exports.execInTransactionsNamespace = exports.bindTransactionsNamespace = exports.getTransactionsNamespace = exports.createTransactionsNamespace = void 0; /* eslint-disable max-classes-per-file */ const typeorm_1 = require("typeorm"); const cls_hooked_1 = require("cls-hooked"); const NAMESPACE = '__typeorm_transactions_legacy_namespace__'; const TRANSACTION_KEY = '__typeorm_transaction_legacy_key__'; // const DEFAULT_TRANSACTION_ID = 'default'; const DEFAULT_TRANSACTION_ID = false; function createTransactionsNamespace() { var _a; return (_a = cls_hooked_1.getNamespace(NAMESPACE)) !== null && _a !== void 0 ? _a : cls_hooked_1.createNamespace(NAMESPACE); } exports.createTransactionsNamespace = createTransactionsNamespace; function getTransactionsNamespace() { return cls_hooked_1.getNamespace(NAMESPACE); } exports.getTransactionsNamespace = getTransactionsNamespace; function bindTransactionsNamespace(req, res, next) { const ns = createTransactionsNamespace(); ns.bindEmitter(req); ns.bindEmitter(res); ns.run(() => next()); } exports.bindTransactionsNamespace = bindTransactionsNamespace; function execInTransactionsNamespace(cb) { return __awaiter(this, void 0, void 0, function* () { return createTransactionsNamespace().runPromise(cb); }); } exports.execInTransactionsNamespace = execInTransactionsNamespace; function setTransactionIntoNs(key, transaction) { const ns = getTransactionsNamespace(); if (ns && ns.active) return ns.set(`${TRANSACTION_KEY}_${key}`, transaction); } function getTransactionFromNs(key) { const ns = getTransactionsNamespace(); if (ns && ns.active) return ns.get(`${TRANSACTION_KEY}_${key}`); } function removeTransactionFromNs(key) { const ns = getTransactionsNamespace(); if (ns && ns.active) ns.set(`${TRANSACTION_KEY}_${key}`, null); } function createRepositories(repositories, manager, constructorParams) { let params = typeof constructorParams === 'function' ? constructorParams() : constructorParams; if (!Array.isArray(params)) params = [params]; // Object.entries(repositories).forEach(([key, Repository]) => { result[key as keyof C] = new Repository(manager, ...params); }); // const instantiated: RepositoriesInstances<C> = { } as RepositoriesInstances<C>; // Object.defineProperty(result, key, { get: () => { // if (!instantiated[key]) instantiated[key as keyof C] = new Repository(manager, ...params); // return instantiated[key]; // } }); const result = {}; Object.entries(repositories).forEach(([key, Repository]) => { Object.defineProperty(result, key, { enumerable: true, configurable: true, get: () => { const value = new Repository(manager, ...params); Object.defineProperty(result, key, { enumerable: true, configurable: false, value }); return value; }, }); }); return result; } function getConnection(connectionFactory, connectionNameFactory) { const connection = typeof connectionFactory === 'function' ? connectionFactory() : connectionFactory; const connectionName = typeof connectionNameFactory === 'function' ? connectionNameFactory() : connectionNameFactory; const result = connection !== null && connection !== void 0 ? connection : typeorm_1.getConnection(connectionName); if (!result.isConnected) throw Error('Please, initialize connection before creating `UnitOfWork` instance'); return result; } function hasProperty(object, prop) { return !!Object.hasOwnProperty.call(object, prop); } function hasOnlyProperties(object, props) { const existingProps = Object.keys(object); return !(existingProps.find((item) => !props.includes(item))); } function hasOnlyOneOfProvidedProperties(object, props) { return props.reduce((acc, curr) => (hasProperty(object, curr) ? acc + 1 : acc), 0) === 1; } class Transaction { constructor(_options) { var _a, _b, _c, _d; this._options = _options; const { connection, connectionName, manager, transaction } = _options; if (transaction) { this._connection = transaction.manager.connection; this._transactionId = `${this._connection.name}__${transaction.id}`; this._parentTransaction = transaction; this._hasParentTransaction = true; this._shouldUseNs = transaction.id !== false; this._queryRunner = transaction.manager.queryRunner; } else { this._connection = (_a = manager === null || manager === void 0 ? void 0 : manager.connection) !== null && _a !== void 0 ? _a : getConnection(connection, connectionName); this._transactionId = `${this._connection.name}__${this.id}`; this._parentTransaction = getTransactionFromNs(this._transactionId); this._hasParentTransaction = !!(manager === null || manager === void 0 ? void 0 : manager.queryRunner) || !!this._parentTransaction; this._shouldUseNs = this.id !== false; this._queryRunner = (_d = (_b = manager === null || manager === void 0 ? void 0 : manager.queryRunner) !== null && _b !== void 0 ? _b : (_c = this._parentTransaction) === null || _c === void 0 ? void 0 : _c.manager.queryRunner) !== null && _d !== void 0 ? _d : this._connection.createQueryRunner(); } if (this._shouldUseNs) { this._validateNsAvailability(); setTransactionIntoNs(this._transactionId, this); } } get repositories() { if (!this._repositories) { const { repositories, repositoryConstructorParams } = this._options; this._repositories = createRepositories(repositories, this.manager, repositoryConstructorParams); } return this._repositories; } get manager() { return this._queryRunner.manager; } get id() { var _a; return (_a = this._options.id) !== null && _a !== void 0 ? _a : DEFAULT_TRANSACTION_ID; } begin() { return __awaiter(this, void 0, void 0, function* () { if (this._hasParentTransaction) return; if (!this._queryRunner.isTransactionActive) yield this._queryRunner.startTransaction(this._options.isolationLevel); else throw new Error('Transaction is already started'); }); } commit() { var _a, _b; return __awaiter(this, void 0, void 0, function* () { if (this._hasParentTransaction) return; if (this._queryRunner.isTransactionActive && !((_a = this._options.manager) === null || _a === void 0 ? void 0 : _a.queryRunner)) yield this._queryRunner.commitTransaction(); if (!this._queryRunner.isReleased && !((_b = this._options.manager) === null || _b === void 0 ? void 0 : _b.queryRunner)) yield this._queryRunner.release(); if (this._shouldUseNs) removeTransactionFromNs(this._transactionId); }); } rollback(error) { var _a, _b; return __awaiter(this, void 0, void 0, function* () { if (this._hasParentTransaction) return; if (this._queryRunner.isTransactionActive && !((_a = this._options.manager) === null || _a === void 0 ? void 0 : _a.queryRunner)) yield this._queryRunner.rollbackTransaction(); if (!this._queryRunner.isReleased && !((_b = this._options.manager) === null || _b === void 0 ? void 0 : _b.queryRunner)) yield this._queryRunner.release(); if (this._shouldUseNs) removeTransactionFromNs(this._transactionId); if (error && typeof error === 'string') throw new Error(error); else if (error) throw error; }); } _validateNsAvailability() { if (!this._shouldUseNs) return; const ns = getTransactionsNamespace(); if (!ns) throw new Error('Please, create Namespace using `createTransactionsNamespace` method.'); if (!ns.active) throw new Error('Please, bind Namespace using `bindTransactionsNamespace` or `execInTransactionsNamespace` method.'); } } exports.Transaction = Transaction; class UnitOfWork { constructor(_options = {}) { this._options = _options; } exec(cb) { return __awaiter(this, void 0, void 0, function* () { const { connection, connectionName, manager, isolationLevel } = this._options; this._connection = getConnection(connection, connectionName); const getRepositories = this._getRepositories.bind(this); const execute = (mgr) => __awaiter(this, void 0, void 0, function* () { return cb({ manager: mgr, get repositories() { return getRepositories(mgr); } }); }); return manager ? execute(manager) : this._connection.transaction(isolationLevel, execute); // return manager ? manager.transaction(isolationLevel, execute) : this._connection.transaction(isolationLevel, execute); }); } _getRepositories(manager) { if (!this._repositories) { const { repositories, repositoryConstructorParams } = this._options; this._repositories = createRepositories(repositories, manager, repositoryConstructorParams); } return this._repositories; } } exports.UnitOfWork = UnitOfWork; class TransactionManager { constructor(_options = {}) { this._options = _options; } unitOfWork(cb, options = {}) { return __awaiter(this, void 0, void 0, function* () { return this.createUnitOfWork(options).exec(cb); }); } createUnitOfWork(options = {}) { return new UnitOfWork(this._getDefaults(options)); } transaction(cbOrOptions, options) { return __awaiter(this, void 0, void 0, function* () { const opts = this._getDefaults(typeof cbOrOptions === 'function' ? options : cbOrOptions); const transaction = this.createTransaction(opts); if (!transaction.manager.queryRunner.isTransactionActive) yield transaction.begin(); return typeof cbOrOptions === 'function' ? cbOrOptions(transaction) .then((result) => __awaiter(this, void 0, void 0, function* () { yield transaction.rollback(); return result; })) .catch((err) => __awaiter(this, void 0, void 0, function* () { return yield transaction.rollback(err); })) : transaction; }); } createTransaction(options = {}) { return new Transaction(this._getDefaults(options)); } get connection() { var _a; const { manager, connection, connectionName } = this._options; if (!this._connection) this._connection = (_a = manager === null || manager === void 0 ? void 0 : manager.connection) !== null && _a !== void 0 ? _a : getConnection(connection, connectionName); return this._connection; } get repositories() { if (!this._repositories) { const { repositories, repositoryConstructorParams } = this._options; this._repositories = createRepositories(repositories, this.connection.manager, repositoryConstructorParams); } return this._repositories; } _getDefaults(options) { var _a, _b, _c, _d, _e, _f, _g, _h; const result = Object.assign(Object.assign({}, options), { connection: this.connection, connectionName: this.connection.name, repositories: (_a = options === null || options === void 0 ? void 0 : options.repositories) !== null && _a !== void 0 ? _a : (_b = this._options) === null || _b === void 0 ? void 0 : _b.repositories, repositoryConstructorParams: (_c = options === null || options === void 0 ? void 0 : options.repositoryConstructorParams) !== null && _c !== void 0 ? _c : (_d = this._options) === null || _d === void 0 ? void 0 : _d.repositoryConstructorParams, isolationLevel: (_e = options === null || options === void 0 ? void 0 : options.isolationLevel) !== null && _e !== void 0 ? _e : (_f = this._options) === null || _f === void 0 ? void 0 : _f.isolationLevel, id: (_g = options === null || options === void 0 ? void 0 : options.id) !== null && _g !== void 0 ? _g : (_h = this._options) === null || _h === void 0 ? void 0 : _h.defaultTransactionId }); this._validateOptions(result); return result; } _validateOptions(options) { const { manager, transaction } = options; if (manager && manager.connection.name !== this.connection.name) { throw new Error('Provided `manager` option with invalid (another) connection'); } if (transaction && transaction.manager.connection.name !== this.connection.name) { throw new Error('Provided `transaction` option with invalid (another) connection'); } } } exports.TransactionManager = TransactionManager; //# sourceMappingURL=TransactionManager.js.map