applyTimestamps.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. 'use strict';
  2. const handleTimestampOption = require('../schema/handleTimestampOption');
  3. const mpath = require('mpath');
  4. const utils = require('../../utils');
  5. module.exports = applyTimestamps;
  6. /**
  7. * Apply a given schema's timestamps to the given POJO
  8. *
  9. * @param {Schema} schema
  10. * @param {Object} obj
  11. * @param {Object} [options]
  12. * @param {Boolean} [options.isUpdate=false] if true, treat this as an update: just set updatedAt, skip setting createdAt. If false, set both createdAt and updatedAt
  13. * @param {Function} [options.currentTime] if set, Mongoose will call this function to get the current time.
  14. */
  15. function applyTimestamps(schema, obj, options) {
  16. if (obj == null) {
  17. return obj;
  18. }
  19. applyTimestampsToChildren(schema, obj, options);
  20. return applyTimestampsToDoc(schema, obj, options);
  21. }
  22. /**
  23. * Apply timestamps to any subdocuments
  24. *
  25. * @param {Schema} schema subdocument schema
  26. * @param {Object} res subdocument
  27. * @param {Object} [options]
  28. * @param {Boolean} [options.isUpdate=false] if true, treat this as an update: just set updatedAt, skip setting createdAt. If false, set both createdAt and updatedAt
  29. * @param {Function} [options.currentTime] if set, Mongoose will call this function to get the current time.
  30. */
  31. function applyTimestampsToChildren(schema, res, options) {
  32. for (const childSchema of schema.childSchemas) {
  33. const _path = childSchema.model.path;
  34. const _schema = childSchema.schema;
  35. if (!_path) {
  36. continue;
  37. }
  38. const _obj = mpath.get(_path, res);
  39. if (_obj == null || (Array.isArray(_obj) && _obj.flat(Infinity).length === 0)) {
  40. continue;
  41. }
  42. applyTimestamps(_schema, _obj, options);
  43. }
  44. }
  45. /**
  46. * Apply timestamps to a given document. Does not apply timestamps to subdocuments: use `applyTimestampsToChildren` instead
  47. *
  48. * @param {Schema} schema
  49. * @param {Object} obj
  50. * @param {Object} [options]
  51. * @param {Boolean} [options.isUpdate=false] if true, treat this as an update: just set updatedAt, skip setting createdAt. If false, set both createdAt and updatedAt
  52. * @param {Function} [options.currentTime] if set, Mongoose will call this function to get the current time.
  53. */
  54. function applyTimestampsToDoc(schema, obj, options) {
  55. if (obj == null || typeof obj !== 'object') {
  56. return;
  57. }
  58. if (Array.isArray(obj)) {
  59. for (const el of obj) {
  60. applyTimestampsToDoc(schema, el, options);
  61. }
  62. return;
  63. }
  64. if (schema.discriminators && utils.hasOwnKeys(schema.discriminators)) {
  65. for (const discriminatorKey of Object.keys(schema.discriminators)) {
  66. const discriminator = schema.discriminators[discriminatorKey];
  67. const key = discriminator.discriminatorMapping.key;
  68. const value = discriminator.discriminatorMapping.value;
  69. if (obj[key] == value) {
  70. schema = discriminator;
  71. break;
  72. }
  73. }
  74. }
  75. const createdAt = handleTimestampOption(schema.options.timestamps, 'createdAt');
  76. const updatedAt = handleTimestampOption(schema.options.timestamps, 'updatedAt');
  77. const currentTime = options?.currentTime;
  78. let ts = null;
  79. if (currentTime != null) {
  80. ts = currentTime();
  81. } else if (schema.base?.now) {
  82. ts = schema.base.now();
  83. } else {
  84. ts = new Date();
  85. }
  86. if (createdAt && obj[createdAt] == null && !options?.isUpdate) {
  87. obj[createdAt] = ts;
  88. }
  89. if (updatedAt) {
  90. obj[updatedAt] = ts;
  91. }
  92. }