mongoose-transaction-decorator
Version:
mongoose transaction decorator
103 lines (102 loc) • 4.13 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.transaction = void 0;
const mongoose_1 = require("mongoose");
const decorator_1 = require("./decorator");
const als_1 = require("./als");
const modelDistinct = 'distinct';
const specials = {
documentAndQueryMiddlewares: ['remove', 'updateOne', 'deleteOne'],
modelMethods: ['bulkSave', 'bulkWrite', 'watch', modelDistinct], // 与事务相关却无中间件可触发的model方法
};
// 根据mongoose所有类型中间件(已剔除事务无关中间件)的配置
const middlewareGroups = {
["document" /* document */]: ['save', ...specials.documentAndQueryMiddlewares],
["query" /* query */]: [
'count',
'countDocuments',
'deleteMany',
'deleteOne',
'estimatedDocumentCount',
'find',
'findOne',
'findOneAndDelete',
'findOneAndRemove',
'findOneAndReplace',
'findOneAndUpdate',
'remove',
'replaceOne',
'update',
'updateOne',
'updateMany',
],
["aggregate" /* aggregate */]: ['aggregate'],
["model" /* model */]: ['insertMany'], // mongoose model无法获取options参数,需要重写方法方式拦截处理
};
/**
* 中间件前置钩子,为带事务相关操作的方法自动注入装饰器session
* - 若用户无手动设置session时,自动注入事务装饰器的session;否,则不处理
* @param next
*/
function preCb(next) {
const als = new als_1.ALS();
const session = als.get(decorator_1.TRANSACTION_SESSION);
if (this instanceof mongoose_1.Document) {
this.$session() || this.$session(session);
}
else if (this instanceof mongoose_1.Query) {
this.getOptions().session || this.session(session);
}
else if (this instanceof mongoose_1.Aggregate) {
// FIXME:mongoose类型声明文件不完整,持续关注https://github.com/Automattic/mongoose/issues/11594
this.options.session || this.session(session);
}
next();
}
/**
* 重写由于model无法获取options参数的带事务相关的方法
* - 若用户无手动设置session时,自动注入事务装饰器的session;否,则不处理
* @param schema
* @param method
*/
function overwriteMethod(schema, method) {
if ([...middlewareGroups.model, ...specials.modelMethods].includes(method)) {
const als = new als_1.ALS();
schema.statics[method] = function (...args) {
const session = als.get(decorator_1.TRANSACTION_SESSION);
if (method !== modelDistinct) {
// FIXME: Modle.distinct返回Query, 如果用户后续再继续手动Query.session(userSession)那么自动注入的session将被覆盖
// 持续关注https://github.com/Automattic/mongoose/issues/11587,等待官方提供支持
return mongoose_1.Model.distinct.apply(this, args).session(session);
}
else {
const options = args[1] || {}; // method options parameter
if (!(options === null || options === void 0 ? void 0 : options.session)) {
args[1] = Object.assign(options, { session });
}
return mongoose_1.Model[method].apply(this, args);
}
};
}
}
/**
* 自动注入session的mongoose插件
* @param schema
*/
function transaction(schema) {
for (const middlewareType in middlewareGroups) {
middlewareGroups[middlewareType].forEach(method => {
if (middlewareType === "model" /* model */) {
overwriteMethod(schema, method);
}
else if (middlewareType === "document" /* document */ &&
specials.documentAndQueryMiddlewares.includes(method)) {
schema.pre(method, { document: true, query: true }, preCb);
}
else {
schema.pre(method, preCb);
}
});
}
}
exports.transaction = transaction;