hooks.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  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. beforePoolAcquire: { params: 1, noModel: true },
  45. afterPoolAcquire: { params: 2, noModel: true },
  46. beforeSync: { params: 1 },
  47. afterSync: { params: 1 },
  48. beforeBulkSync: { params: 1 },
  49. afterBulkSync: { params: 1 },
  50. beforeQuery: { params: 2 },
  51. afterQuery: { params: 2 }
  52. };
  53. exports.hooks = hookTypes;
  54. const getProxiedHooks = (hookType) => hookTypes[hookType].proxies ? hookTypes[hookType].proxies.concat(hookType) : [hookType];
  55. function getHooks(hooked, hookType) {
  56. return (hooked.options.hooks || {})[hookType] || [];
  57. }
  58. const Hooks = {
  59. _setupHooks(hooks) {
  60. this.options.hooks = {};
  61. _.map(hooks || {}, (hooksArray, hookName) => {
  62. if (!Array.isArray(hooksArray))
  63. hooksArray = [hooksArray];
  64. hooksArray.forEach((hookFn) => this.addHook(hookName, hookFn));
  65. });
  66. },
  67. async runHooks(hooks, ...hookArgs) {
  68. if (!hooks)
  69. throw new Error("runHooks requires at least 1 argument");
  70. let hookType;
  71. if (typeof hooks === "string") {
  72. hookType = hooks;
  73. hooks = getHooks(this, hookType);
  74. if (this.sequelize) {
  75. hooks = hooks.concat(getHooks(this.sequelize, hookType));
  76. }
  77. }
  78. if (!Array.isArray(hooks)) {
  79. hooks = [hooks];
  80. }
  81. if (hookTypes[hookType] && hookTypes[hookType].sync) {
  82. for (let hook of hooks) {
  83. if (typeof hook === "object") {
  84. hook = hook.fn;
  85. }
  86. debug(`running hook(sync) ${hookType}`);
  87. hook.apply(this, hookArgs);
  88. }
  89. return;
  90. }
  91. for (let hook of hooks) {
  92. if (typeof hook === "object") {
  93. hook = hook.fn;
  94. }
  95. debug(`running hook ${hookType}`);
  96. await hook.apply(this, hookArgs);
  97. }
  98. },
  99. addHook(hookType, name, fn) {
  100. if (typeof name === "function") {
  101. fn = name;
  102. name = null;
  103. }
  104. debug(`adding hook ${hookType}`);
  105. hookType = getProxiedHooks(hookType);
  106. hookType.forEach((type) => {
  107. const hooks = getHooks(this, type);
  108. hooks.push(name ? { name, fn } : fn);
  109. this.options.hooks[type] = hooks;
  110. });
  111. return this;
  112. },
  113. removeHook(hookType, name) {
  114. const isReference = typeof name === "function" ? true : false;
  115. if (!this.hasHook(hookType)) {
  116. return this;
  117. }
  118. debug(`removing hook ${hookType}`);
  119. hookType = getProxiedHooks(hookType);
  120. for (const type of hookType) {
  121. this.options.hooks[type] = this.options.hooks[type].filter((hook) => {
  122. if (isReference && typeof hook === "function") {
  123. return hook !== name;
  124. }
  125. if (!isReference && typeof hook === "object") {
  126. return hook.name !== name;
  127. }
  128. return true;
  129. });
  130. }
  131. return this;
  132. },
  133. hasHook(hookType) {
  134. return this.options.hooks[hookType] && !!this.options.hooks[hookType].length;
  135. }
  136. };
  137. Hooks.hasHooks = Hooks.hasHook;
  138. function applyTo(target, isModel = false) {
  139. _.mixin(target, Hooks);
  140. for (const hook of Object.keys(hookTypes)) {
  141. if (isModel && hookTypes[hook].noModel) {
  142. continue;
  143. }
  144. target[hook] = function(name, callback) {
  145. return this.addHook(hook, name, callback);
  146. };
  147. }
  148. }
  149. exports.applyTo = applyTo;
  150. //# sourceMappingURL=hooks.js.map