setupTimestamps.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. 'use strict';
  2. const applyTimestampsToChildren = require('../update/applyTimestampsToChildren');
  3. const applyTimestampsToUpdate = require('../update/applyTimestampsToUpdate');
  4. const get = require('../get');
  5. const handleTimestampOption = require('../schema/handleTimestampOption');
  6. const symbols = require('../../schema/symbols');
  7. module.exports = function setupTimestamps(schema, timestamps) {
  8. const childHasTimestamp = schema.childSchemas.find(withTimestamp);
  9. function withTimestamp(s) {
  10. const ts = s.schema.options.timestamps;
  11. return !!ts;
  12. }
  13. if (!timestamps && !childHasTimestamp) {
  14. return;
  15. }
  16. const createdAt = handleTimestampOption(timestamps, 'createdAt');
  17. const updatedAt = handleTimestampOption(timestamps, 'updatedAt');
  18. const currentTime = timestamps != null && timestamps.hasOwnProperty('currentTime') ?
  19. timestamps.currentTime :
  20. null;
  21. const schemaAdditions = {};
  22. schema.$timestamps = { createdAt: createdAt, updatedAt: updatedAt };
  23. if (updatedAt && !schema.paths[updatedAt]) {
  24. schemaAdditions[updatedAt] = Date;
  25. }
  26. if (createdAt && !schema.paths[createdAt]) {
  27. schemaAdditions[createdAt] = { [schema.options.typeKey || 'type']: Date, immutable: true };
  28. }
  29. schema.add(schemaAdditions);
  30. schema.pre('save', function(next) {
  31. const timestampOption = get(this, '$__.saveOptions.timestamps');
  32. if (timestampOption === false) {
  33. return next();
  34. }
  35. const skipUpdatedAt = timestampOption != null && timestampOption.updatedAt === false;
  36. const skipCreatedAt = timestampOption != null && timestampOption.createdAt === false;
  37. const defaultTimestamp = currentTime != null ?
  38. currentTime() :
  39. this.ownerDocument().constructor.base.now();
  40. if (!skipCreatedAt && this.isNew && createdAt && !this.$__getValue(createdAt) && this.$__isSelected(createdAt)) {
  41. this.$set(createdAt, defaultTimestamp);
  42. }
  43. if (!skipUpdatedAt && updatedAt && (this.isNew || this.$isModified())) {
  44. let ts = defaultTimestamp;
  45. if (this.isNew && createdAt != null) {
  46. ts = this.$__getValue(createdAt);
  47. }
  48. this.$set(updatedAt, ts);
  49. }
  50. next();
  51. });
  52. schema.methods.initializeTimestamps = function() {
  53. const ts = currentTime != null ?
  54. currentTime() :
  55. this.constructor.base.now();
  56. if (createdAt && !this.get(createdAt)) {
  57. this.$set(createdAt, ts);
  58. }
  59. if (updatedAt && !this.get(updatedAt)) {
  60. this.$set(updatedAt, ts);
  61. }
  62. return this;
  63. };
  64. _setTimestampsOnUpdate[symbols.builtInMiddleware] = true;
  65. const opts = { query: true, model: false };
  66. schema.pre('findOneAndReplace', opts, _setTimestampsOnUpdate);
  67. schema.pre('findOneAndUpdate', opts, _setTimestampsOnUpdate);
  68. schema.pre('replaceOne', opts, _setTimestampsOnUpdate);
  69. schema.pre('update', opts, _setTimestampsOnUpdate);
  70. schema.pre('updateOne', opts, _setTimestampsOnUpdate);
  71. schema.pre('updateMany', opts, _setTimestampsOnUpdate);
  72. function _setTimestampsOnUpdate(next) {
  73. const now = currentTime != null ?
  74. currentTime() :
  75. this.model.base.now();
  76. // Replacing with null update should still trigger timestamps
  77. if (this.op === 'findOneAndReplace' && this.getUpdate() == null) {
  78. this.setUpdate({});
  79. }
  80. applyTimestampsToUpdate(now, createdAt, updatedAt, this.getUpdate(),
  81. this.options, this.schema);
  82. applyTimestampsToChildren(now, this.getUpdate(), this.model.schema);
  83. next();
  84. }
  85. };