'use strict'; const _ = require('lodash'); const TENANT_MODELS = Symbol('Context#models@tenant'); // 已废弃 const _loadModel = (app, tenant) => { app.logger.info(`[multi-tenancy] Load tenant models for ${tenant}`); const model = {}; _.forEach(app.model, (val, key) => { const modelName = `${val.modelName}@${tenant}`; const collName = `_${tenant}.${val.collection.name}`; const multiTenancy = val.schema.get('multi-tenancy'); if (multiTenancy) { app.logger.debug(`[multi-tenancy] ${modelName} loaded`); model[key] = val.db.model(modelName, val.schema, collName); } else { app.logger.debug(`[multi-tenancy] skip ${val.modelName}, schema not enable multi-tenancy.`); model[key] = val; } }); return model; }; const multiTenancyPlugin = (schema, options = {}) => { const { defaultTenant = 'master' } = options; schema.add({ _tenant: { type: String, default: defaultTenant, index: true }, }); schema.pre('save', async function() { const tenant = schema.get('x-tenant'); if (tenant !== 'global') { this._tenant = schema.get('x-tenant'); } }); const querys = [ 'count', 'countDocuments', 'find', 'findOne', 'findOneAndRemove', 'findOneAndUpdate', 'remove', 'deleteOne', 'deleteMany', 'update', 'updateOne', 'updateMany' ]; querys.forEach(action => { schema.pre(action, async function() { const tenant = schema.get('x-tenant'); if (tenant !== 'global') { this.where('_tenant').equals(schema.get('x-tenant')); } }); }); }; const loadModel2 = (app, tenant) => { app.logger.info(`[multi-tenancy] Load tenant models for ${tenant}`); let model = {}; const setModel = (val,key) =>{ const obj = {}; const modelName = `${val.modelName}@${tenant}`; const collName = `${val.collection.name}`; const multiTenancy = val.schema.get('multi-tenancy'); if (multiTenancy) { app.logger.debug(`[multi-tenancy] ${modelName} loaded`); const schema = val.schema.clone(); schema.set('x-tenant', tenant); schema.plugin(multiTenancyPlugin, app.config.multiTenancy); obj[key] = val.db.model(modelName, schema, collName); } else { app.logger.debug(`[multi-tenancy] skip ${val.modelName}, schema not enable multi-tenancy.`); obj[key] = val; } return obj; } _.forEach(app.model, (val, key) => { const nval = getAllModel(val); // 文件夹分层级后,val不再只是Function,也有可能是Object,添加个方法,获取所有model if(!_.isArray(nval)) { let mod = {}; mod = setModel(nval,key); model = {...model,...mod}; } else { let mods = {}; mods[key] = {}; for (const model of nval) { const nkey = _.upperFirst(model.modelName); let mod = setModel(model,nkey); mods[key] = {...mods[key],...mod}; } model = {...model,...mods}; } }); return model; }; // this 就是 app 对象,在其中可以调用 app 上的其他方法,或访问属性 module.exports = { // 多租户系统中的model对象 tenantModel(tenant) { const { defaultTenant: _defaultTenant } = this.config.multiTenancy || {}; if (tenant /* && tenant !== _defaultTenant*/) { // 非默认租户,加载租户model if (!this[TENANT_MODELS]) { this[TENANT_MODELS] = []; } const models = this[TENANT_MODELS]; if (!models[tenant]) { // 加载租户Model models[tenant] = loadModel2(this, tenant); } return models[tenant]; } // 默认租户返回原始model对象 return this.model; }, };