UNPKG

typeorm-transactional-async-callbacks

Version:

A Transactional Method Decorator for typeorm that uses cls-hooked to handle and propagate transactions between different repositories and service methods. Inpired by Spring Trasnactional Annotation and Sequelize CLS

180 lines 7.98 kB
"use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.setHookInContext = exports.getHookInContext = exports.deleteDataSourceByName = exports.getDataSourceByName = exports.addTransactionalDataSource = exports.initializeTransactionalContext = exports.getTransactionalOptions = exports.setEntityManagerByDataSourceName = exports.getEntityManagerByDataSourceName = exports.getTransactionalContext = void 0; var typeorm_1 = require("typeorm"); var constants_1 = require("./constants"); var storage_driver_1 = require("../enums/storage-driver"); var typeorm_updated_patch_1 = require("../errors/typeorm-updated-patch"); var utils_1 = require("../utils"); var storage_1 = require("../storage"); /** * Map of added data sources. * * The property "name" in the `DataSource` is deprecated, so we add own names to distinguish data sources. */ var dataSources = new Map(); /** * Default library's state */ var data = { options: { maxHookHandlers: 10, storageDriver: storage_driver_1.StorageDriver.CLS_HOOKED, }, }; var getTransactionalContext = function () { return storage_1.storage.get(); }; exports.getTransactionalContext = getTransactionalContext; var getEntityManagerByDataSourceName = function (context, name) { if (!dataSources.has(name)) return null; return context.get(constants_1.TYPEORM_DATA_SOURCE_NAME_PREFIX + name) || null; }; exports.getEntityManagerByDataSourceName = getEntityManagerByDataSourceName; var setEntityManagerByDataSourceName = function (context, name, entityManager) { if (!dataSources.has(name)) return; context.set(constants_1.TYPEORM_DATA_SOURCE_NAME_PREFIX + name, entityManager); }; exports.setEntityManagerByDataSourceName = setEntityManagerByDataSourceName; var getEntityManagerInContext = function (dataSourceName) { var context = (0, exports.getTransactionalContext)(); if (!context || !context.active) return null; return (0, exports.getEntityManagerByDataSourceName)(context, dataSourceName); }; var patchDataSource = function (dataSource) { var originalManager = dataSource.manager; Object.defineProperty(dataSource, 'manager', { configurable: true, get: function () { return (getEntityManagerInContext(this[constants_1.TYPEORM_DATA_SOURCE_NAME]) || originalManager); }, set: function (manager) { originalManager = manager; }, }); var originalQuery = typeorm_1.DataSource.prototype.query; if (originalQuery.length !== 3) { throw new typeorm_updated_patch_1.TypeOrmUpdatedPatchError(); } dataSource.query = function () { var _a; var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } args[2] = args[2] || ((_a = this.manager) === null || _a === void 0 ? void 0 : _a.queryRunner); return originalQuery.apply(this, args); }; var originalCreateQueryBuilder = typeorm_1.DataSource.prototype.createQueryBuilder; if (originalCreateQueryBuilder.length !== 3) { throw new typeorm_updated_patch_1.TypeOrmUpdatedPatchError(); } dataSource.createQueryBuilder = function () { var _a, _b; var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } if (args.length === 0) { return originalCreateQueryBuilder.apply(this, [(_a = this.manager) === null || _a === void 0 ? void 0 : _a.queryRunner]); } args[2] = args[2] || ((_b = this.manager) === null || _b === void 0 ? void 0 : _b.queryRunner); return originalCreateQueryBuilder.apply(this, args); }; dataSource.transaction = function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore return originalManager.transaction.apply(originalManager, args); }; }; var setTransactionalOptions = function (options) { data.options = __assign(__assign({}, data.options), (options || {})); }; var getTransactionalOptions = function () { return data.options; }; exports.getTransactionalOptions = getTransactionalOptions; var initializeTransactionalContext = function (options) { setTransactionalOptions(options); var patchManager = function (repositoryType) { Object.defineProperty(repositoryType, 'manager', { configurable: true, get: function () { return (getEntityManagerInContext(this[constants_1.TYPEORM_ENTITY_MANAGER_NAME].connection[constants_1.TYPEORM_DATA_SOURCE_NAME]) || this[constants_1.TYPEORM_ENTITY_MANAGER_NAME]); }, set: function (manager) { this[constants_1.TYPEORM_ENTITY_MANAGER_NAME] = manager; }, }); }; var getRepository = function (originalFn) { return function patchRepository() { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } var repository = originalFn.apply(this, args); if (!(constants_1.TYPEORM_ENTITY_MANAGER_NAME in repository)) { /** * Store current manager */ repository[constants_1.TYPEORM_ENTITY_MANAGER_NAME] = repository.manager; } return repository; }; }; var originalGetRepository = typeorm_1.EntityManager.prototype.getRepository; var originalExtend = typeorm_1.Repository.prototype.extend; typeorm_1.EntityManager.prototype.getRepository = getRepository(originalGetRepository); typeorm_1.Repository.prototype.extend = getRepository(originalExtend); patchManager(typeorm_1.Repository.prototype); var storageDriver = (0, exports.getTransactionalOptions)().storageDriver; return storage_1.storage.create(storageDriver); }; exports.initializeTransactionalContext = initializeTransactionalContext; var addTransactionalDataSource = function (input) { if ((0, utils_1.isDataSource)(input)) { input = { name: 'default', dataSource: input, patch: true }; } var _a = input.name, name = _a === void 0 ? 'default' : _a, dataSource = input.dataSource, _b = input.patch, patch = _b === void 0 ? true : _b; if (dataSources.has(name)) { throw new Error("DataSource with name \"".concat(name, "\" has already added.")); } if (patch) { patchDataSource(dataSource); } dataSources.set(name, dataSource); // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore dataSource[constants_1.TYPEORM_DATA_SOURCE_NAME] = name; return input.dataSource; }; exports.addTransactionalDataSource = addTransactionalDataSource; var getDataSourceByName = function (name) { return dataSources.get(name); }; exports.getDataSourceByName = getDataSourceByName; var deleteDataSourceByName = function (name) { return dataSources.delete(name); }; exports.deleteDataSourceByName = deleteDataSourceByName; var getHookInContext = function (context) { return context === null || context === void 0 ? void 0 : context.get(constants_1.TYPEORM_HOOK_NAME); }; exports.getHookInContext = getHookInContext; var setHookInContext = function (context, emitter) { return context.set(constants_1.TYPEORM_HOOK_NAME, emitter); }; exports.setHookInContext = setHookInContext; //# sourceMappingURL=index.js.map