application.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  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. const getAllModel = data => {
  85. if(_.isFunction(data)) return data;
  86. const keys = Object.keys(data);
  87. const arr = [];
  88. for (const key of keys) {
  89. const model = data[key];
  90. if(_.isFunction(model)) arr.push(model)
  91. else arr.push(...getAllModel(model))
  92. }
  93. return arr;
  94. }
  95. // this 就是 app 对象,在其中可以调用 app 上的其他方法,或访问属性
  96. module.exports = {
  97. // 多租户系统中的model对象
  98. tenantModel(tenant) {
  99. const { defaultTenant: _defaultTenant } = this.config.multiTenancy || {};
  100. if (tenant /* && tenant !== _defaultTenant*/) {
  101. // 非默认租户,加载租户model
  102. if (!this[TENANT_MODELS]) {
  103. this[TENANT_MODELS] = [];
  104. }
  105. const models = this[TENANT_MODELS];
  106. if (!models[tenant]) {
  107. // 加载租户Model
  108. models[tenant] = loadModel2(this, tenant);
  109. }
  110. return models[tenant];
  111. }
  112. // 默认租户返回原始model对象
  113. return this.model;
  114. },
  115. };