hooks.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. "use strict";
  2. const _ = require("lodash");
  3. const { logger } = require("./utils/logger");
  4. const debug = logger.debugContext("hooks");
  5. const hookTypes = {
  6. beforeValidate: { params: 2 },
  7. afterValidate: { params: 2 },
  8. validationFailed: { params: 3 },
  9. beforeCreate: { params: 2 },
  10. afterCreate: { params: 2 },
  11. beforeDestroy: { params: 2 },
  12. afterDestroy: { params: 2 },
  13. beforeRestore: { params: 2 },
  14. afterRestore: { params: 2 },
  15. beforeUpdate: { params: 2 },
  16. afterUpdate: { params: 2 },
  17. beforeSave: { params: 2, proxies: ["beforeUpdate", "beforeCreate"] },
  18. afterSave: { params: 2, proxies: ["afterUpdate", "afterCreate"] },
  19. beforeUpsert: { params: 2 },
  20. afterUpsert: { params: 2 },
  21. beforeBulkCreate: { params: 2 },
  22. afterBulkCreate: { params: 2 },
  23. beforeBulkDestroy: { params: 1 },
  24. afterBulkDestroy: { params: 1 },
  25. beforeBulkRestore: { params: 1 },
  26. afterBulkRestore: { params: 1 },
  27. beforeBulkUpdate: { params: 1 },
  28. afterBulkUpdate: { params: 1 },
  29. beforeFind: { params: 1 },
  30. beforeFindAfterExpandIncludeAll: { params: 1 },
  31. beforeFindAfterOptions: { params: 1 },
  32. afterFind: { params: 2 },
  33. beforeCount: { params: 1 },
  34. beforeDefine: { params: 2, sync: true, noModel: true },
  35. afterDefine: { params: 1, sync: true, noModel: true },
  36. beforeInit: { params: 2, sync: true, noModel: true },
  37. afterInit: { params: 1, sync: true, noModel: true },
  38. beforeAssociate: { params: 2, sync: true },
  39. afterAssociate: { params: 2, sync: true },
  40. beforeConnect: { params: 1, noModel: true },
  41. afterConnect: { params: 2, noModel: true },
  42. beforeDisconnect: { params: 1, noModel: true },
  43. afterDisconnect: { params: 1, noModel: true },
  44. beforeSync: { params: 1 },
  45. afterSync: { params: 1 },
  46. beforeBulkSync: { params: 1 },
  47. afterBulkSync: { params: 1 },
  48. beforeQuery: { params: 2 },
  49. afterQuery: { params: 2 }
  50. };
  51. exports.hooks = hookTypes;
  52. const getProxiedHooks = (hookType) => hookTypes[hookType].proxies ? hookTypes[hookType].proxies.concat(hookType) : [hookType];
  53. function getHooks(hooked, hookType) {
  54. return (hooked.options.hooks || {})[hookType] || [];
  55. }
  56. const Hooks = {
  57. _setupHooks(hooks) {
  58. this.options.hooks = {};
  59. _.map(hooks || {}, (hooksArray, hookName) => {
  60. if (!Array.isArray(hooksArray))
  61. hooksArray = [hooksArray];
  62. hooksArray.forEach((hookFn) => this.addHook(hookName, hookFn));
  63. });
  64. },
  65. async runHooks(hooks, ...hookArgs) {
  66. if (!hooks)
  67. throw new Error("runHooks requires at least 1 argument");
  68. let hookType;
  69. if (typeof hooks === "string") {
  70. hookType = hooks;
  71. hooks = getHooks(this, hookType);
  72. if (this.sequelize) {
  73. hooks = hooks.concat(getHooks(this.sequelize, hookType));
  74. }
  75. }
  76. if (!Array.isArray(hooks)) {
  77. hooks = [hooks];
  78. }
  79. if (hookTypes[hookType] && hookTypes[hookType].sync) {
  80. for (let hook of hooks) {
  81. if (typeof hook === "object") {
  82. hook = hook.fn;
  83. }
  84. debug(`running hook(sync) ${hookType}`);
  85. hook.apply(this, hookArgs);
  86. }
  87. return;
  88. }
  89. for (let hook of hooks) {
  90. if (typeof hook === "object") {
  91. hook = hook.fn;
  92. }
  93. debug(`running hook ${hookType}`);
  94. await hook.apply(this, hookArgs);
  95. }
  96. },
  97. addHook(hookType, name, fn) {
  98. if (typeof name === "function") {
  99. fn = name;
  100. name = null;
  101. }
  102. debug(`adding hook ${hookType}`);
  103. hookType = getProxiedHooks(hookType);
  104. hookType.forEach((type) => {
  105. const hooks = getHooks(this, type);
  106. hooks.push(name ? { name, fn } : fn);
  107. this.options.hooks[type] = hooks;
  108. });
  109. return this;
  110. },
  111. removeHook(hookType, name) {
  112. const isReference = typeof name === "function" ? true : false;
  113. if (!this.hasHook(hookType)) {
  114. return this;
  115. }
  116. debug(`removing hook ${hookType}`);
  117. hookType = getProxiedHooks(hookType);
  118. for (const type of hookType) {
  119. this.options.hooks[type] = this.options.hooks[type].filter((hook) => {
  120. if (isReference && typeof hook === "function") {
  121. return hook !== name;
  122. }
  123. if (!isReference && typeof hook === "object") {
  124. return hook.name !== name;
  125. }
  126. return true;
  127. });
  128. }
  129. return this;
  130. },
  131. hasHook(hookType) {
  132. return this.options.hooks[hookType] && !!this.options.hooks[hookType].length;
  133. }
  134. };
  135. Hooks.hasHooks = Hooks.hasHook;
  136. function applyTo(target, isModel = false) {
  137. _.mixin(target, Hooks);
  138. for (const hook of Object.keys(hookTypes)) {
  139. if (isModel && hookTypes[hook].noModel) {
  140. continue;
  141. }
  142. target[hook] = function(name, callback) {
  143. return this.addHook(hook, name, callback);
  144. };
  145. }
  146. }
  147. exports.applyTo = applyTo;
  148. //# sourceMappingURL=hooks.js.map