applyMethods.js 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. 'use strict';
  2. const get = require('../get');
  3. const utils = require('../../utils');
  4. /**
  5. * Register methods for this model
  6. *
  7. * @param {Model} model
  8. * @param {Schema} schema
  9. * @api private
  10. */
  11. module.exports = function applyMethods(model, schema) {
  12. const Model = require('../../model');
  13. function apply(method, schema) {
  14. Object.defineProperty(model.prototype, method, {
  15. get: function() {
  16. const h = {};
  17. for (const k in schema.methods[method]) {
  18. h[k] = schema.methods[method][k].bind(this);
  19. }
  20. return h;
  21. },
  22. configurable: true
  23. });
  24. }
  25. for (const method of Object.keys(schema.methods)) {
  26. const fn = schema.methods[method];
  27. if (Object.hasOwn(schema.tree, method)) {
  28. throw new Error('You have a method and a property in your schema both ' +
  29. 'named "' + method + '"');
  30. }
  31. // Avoid making custom methods if user sets a method to itself, e.g.
  32. // `schema.method(save, Document.prototype.save)`. Can happen when
  33. // calling `loadClass()` with a class that `extends Document`. See gh-12254
  34. if (typeof fn === 'function' &&
  35. Model.prototype[method] === fn) {
  36. delete schema.methods[method];
  37. continue;
  38. }
  39. if (schema.reserved[method] &&
  40. !get(schema, `methodOptions.${method}.suppressWarning`, false)) {
  41. utils.warn(`mongoose: the method name "${method}" is used by mongoose ` +
  42. 'internally, overwriting it may cause bugs. If you\'re sure you know ' +
  43. 'what you\'re doing, you can suppress this error by using ' +
  44. `\`schema.method('${method}', fn, { suppressWarning: true })\`.`);
  45. }
  46. if (typeof fn === 'function') {
  47. model.prototype[method] = fn;
  48. } else {
  49. apply(method, schema);
  50. }
  51. }
  52. // Recursively call `applyMethods()` on child schemas
  53. model.$appliedMethods = true;
  54. for (const key of Object.keys(schema.paths)) {
  55. const type = schema.paths[key];
  56. if (type.$isSingleNested && !type.Constructor.$appliedMethods) {
  57. applyMethods(type.Constructor, type.schema);
  58. }
  59. if (type.$isMongooseDocumentArray && !type.Constructor.$appliedMethods) {
  60. applyMethods(type.Constructor, type.schema);
  61. }
  62. }
  63. };