| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131 |
- 'use strict';
- /*!
- * ignore
- */
- const get = require('../get');
- const utils = require('../../utils');
- module.exports = applyTimestampsToUpdate;
- /*!
- * ignore
- */
- function applyTimestampsToUpdate(now, createdAt, updatedAt, currentUpdate, options, isReplace) {
- const updates = currentUpdate;
- let _updates = updates;
- const timestamps = get(options, 'timestamps', true);
- // Support skipping timestamps at the query level, see gh-6980
- if (!timestamps || updates == null) {
- return currentUpdate;
- }
- const skipCreatedAt = timestamps?.createdAt === false;
- const skipUpdatedAt = timestamps?.updatedAt === false;
- if (isReplace) {
- if (currentUpdate?.$set) {
- currentUpdate = currentUpdate.$set;
- updates.$set = {};
- _updates = updates.$set;
- }
- if (!skipUpdatedAt && updatedAt && !currentUpdate[updatedAt]) {
- _updates[updatedAt] = now;
- }
- if (!skipCreatedAt && createdAt && !currentUpdate[createdAt]) {
- _updates[createdAt] = now;
- }
- return updates;
- }
- currentUpdate = currentUpdate || {};
- if (Array.isArray(updates)) {
- // Update with aggregation pipeline
- if (updatedAt == null) {
- return updates;
- }
- updates.push({ $set: { [updatedAt]: now } });
- return updates;
- }
- updates.$set = updates.$set || {};
- if (!skipUpdatedAt && updatedAt &&
- !currentUpdate.$currentDate?.[updatedAt]) {
- let timestampSet = false;
- if (updatedAt.indexOf('.') !== -1) {
- const pieces = updatedAt.split('.');
- for (let i = 1; i < pieces.length; ++i) {
- const remnant = pieces.slice(-i).join('.');
- const start = pieces.slice(0, -i).join('.');
- if (currentUpdate[start] != null) {
- currentUpdate[start][remnant] = now;
- timestampSet = true;
- break;
- } else if (currentUpdate.$set?.[start]) {
- currentUpdate.$set[start][remnant] = now;
- timestampSet = true;
- break;
- }
- }
- }
- if (!timestampSet) {
- updates.$set[updatedAt] = now;
- }
- if (Object.hasOwn(updates, updatedAt)) {
- delete updates[updatedAt];
- }
- }
- if (!skipCreatedAt && createdAt) {
- const overwriteImmutable = get(options, 'overwriteImmutable', false);
- const hasUserCreatedAt = currentUpdate[createdAt] != null || currentUpdate.$set?.[createdAt] != null;
- // If overwriteImmutable is true and user provided createdAt, keep their value
- if (overwriteImmutable && hasUserCreatedAt) {
- // Move createdAt from top-level to $set if needed
- if (currentUpdate[createdAt] != null) {
- updates.$set[createdAt] = currentUpdate[createdAt];
- delete currentUpdate[createdAt];
- }
- // User's value is already in $set, nothing more to do
- } else {
- if (currentUpdate[createdAt]) {
- delete currentUpdate[createdAt];
- }
- if (currentUpdate.$set?.[createdAt]) {
- delete currentUpdate.$set[createdAt];
- }
- let timestampSet = false;
- if (createdAt.indexOf('.') !== -1) {
- const pieces = createdAt.split('.');
- for (let i = 1; i < pieces.length; ++i) {
- const remnant = pieces.slice(-i).join('.');
- const start = pieces.slice(0, -i).join('.');
- if (currentUpdate[start] != null) {
- currentUpdate[start][remnant] = now;
- timestampSet = true;
- break;
- } else if (currentUpdate.$set?.[start]) {
- currentUpdate.$set[start][remnant] = now;
- timestampSet = true;
- break;
- }
- }
- }
- if (!timestampSet) {
- updates.$setOnInsert = updates.$setOnInsert || {};
- updates.$setOnInsert[createdAt] = now;
- }
- }
- }
- if (utils.hasOwnKeys(updates.$set) === false) {
- delete updates.$set;
- }
- return updates;
- }
|