application.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. 'use strict';
  2. const _ = require('lodash');
  3. const TENANT_MODELS = Symbol('Context#models@tenant');
  4. // 已废弃
  5. const _loadModel = (app, tenant) => {
  6. app.logger.info(`[multi-tenancy] Load tenant models for ${tenant}`);
  7. const model = {};
  8. _.forEach(app.model, (val, key) => {
  9. const modelName = `${val.modelName}@${tenant}`;
  10. const collName = `_${tenant}.${val.collection.name}`;
  11. const multiTenancy = val.schema.get('multi-tenancy');
  12. if (multiTenancy) {
  13. app.logger.debug(`[multi-tenancy] ${modelName} loaded`);
  14. model[key] = val.db.model(modelName, val.schema, collName);
  15. } else {
  16. app.logger.debug(`[multi-tenancy] skip ${val.modelName}, schema not enable multi-tenancy.`);
  17. model[key] = val;
  18. }
  19. });
  20. return model;
  21. };
  22. const multiTenancyPlugin = (schema, options = {}) => {
  23. const { defaultTenant = 'master' } = options;
  24. schema.add({
  25. _tenant: { type: String, default: defaultTenant, index: true },
  26. });
  27. schema.pre('save', async function() {
  28. const tenant = schema.get('x-tenant');
  29. if (tenant !== 'global') {
  30. this._tenant = schema.get('x-tenant');
  31. }
  32. });
  33. const querys = [ 'count', 'countDocuments', 'find', 'findOne', 'findOneAndRemove', 'findOneAndUpdate', 'remove', 'deleteOne', 'deleteMany', 'update', 'updateOne', 'updateMany' ];
  34. querys.forEach(action => {
  35. schema.pre(action, async function() {
  36. const tenant = schema.get('x-tenant');
  37. if (tenant !== 'global') {
  38. this.where('_tenant').equals(schema.get('x-tenant'));
  39. }
  40. });
  41. });
  42. };
  43. const loadModel2 = (app, tenant) => {
  44. app.logger.info(`[multi-tenancy] Load tenant models for ${tenant}`);
  45. let model = {};
  46. const setModel = (val,key) =>{
  47. const obj = {};
  48. const modelName = `${val.modelName}@${tenant}`;
  49. const collName = `${val.collection.name}`;
  50. const multiTenancy = val.schema.get('multi-tenancy');
  51. if (multiTenancy) {
  52. app.logger.debug(`[multi-tenancy] ${modelName} loaded`);
  53. const schema = val.schema.clone();
  54. schema.set('x-tenant', tenant);
  55. schema.plugin(multiTenancyPlugin, app.config.multiTenancy);
  56. obj[key] = val.db.model(modelName, schema, collName);
  57. } else {
  58. app.logger.debug(`[multi-tenancy] skip ${val.modelName}, schema not enable multi-tenancy.`);
  59. obj[key] = val;
  60. }
  61. return obj;
  62. }
  63. _.forEach(app.model, (val, key) => {
  64. const nval = getAllModel(val);
  65. // 文件夹分层级后,val不再只是Function,也有可能是Object,添加个方法,获取所有model
  66. if(!_.isArray(nval)) {
  67. let mod = {};
  68. mod = setModel(nval,key);
  69. model = {...model,...mod};
  70. }
  71. else {
  72. let mods = {};
  73. mods[key] = {};
  74. for (const model of nval) {
  75. const nkey = _.upperFirst(model.modelName);
  76. let mod = setModel(model,nkey);
  77. mods[key] = {...mods[key],...mod};
  78. }
  79. model = {...model,...mods};
  80. }
  81. });
  82. return model;
  83. };
  84. // this 就是 app 对象,在其中可以调用 app 上的其他方法,或访问属性
  85. module.exports = {
  86. // 多租户系统中的model对象
  87. tenantModel(tenant) {
  88. const { defaultTenant: _defaultTenant } = this.config.multiTenancy || {};
  89. if (tenant /* && tenant !== _defaultTenant*/) {
  90. // 非默认租户,加载租户model
  91. if (!this[TENANT_MODELS]) {
  92. this[TENANT_MODELS] = [];
  93. }
  94. const models = this[TENANT_MODELS];
  95. if (!models[tenant]) {
  96. // 加载租户Model
  97. models[tenant] = loadModel2(this, tenant);
  98. }
  99. return models[tenant];
  100. }
  101. // 默认租户返回原始model对象
  102. return this.model;
  103. },
  104. };