Dashboard Temp Share Shortlinks Frames API

HTMLify

setDefaultsOnInsert.js
Views: 6 | Author: cody
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
'use strict';
const modifiedPaths = require('./common').modifiedPaths;
const get = require('./get');

/**
 * Applies defaults to update and findOneAndUpdate operations.
 *
 * @param {Object} filter
 * @param {Schema} schema
 * @param {Object} castedDoc
 * @param {Object} options
 * @method setDefaultsOnInsert
 * @api private
 */

module.exports = function(filter, schema, castedDoc, options) {
  const keys = Object.keys(castedDoc || {});
  const updatedKeys = {};
  const updatedValues = {};
  const numKeys = keys.length;
  const modified = {};

  let hasDollarUpdate = false;

  options = options || {};

  if (!options.upsert || !options.setDefaultsOnInsert) {
    return castedDoc;
  }

  for (let i = 0; i < numKeys; ++i) {
    if (keys[i].startsWith('$')) {
      modifiedPaths(castedDoc[keys[i]], '', modified);
      hasDollarUpdate = true;
    }
  }

  if (!hasDollarUpdate) {
    modifiedPaths(castedDoc, '', modified);
  }

  const paths = Object.keys(filter);
  const numPaths = paths.length;
  for (let i = 0; i < numPaths; ++i) {
    const path = paths[i];
    const condition = filter[path];
    if (condition && typeof condition === 'object') {
      const conditionKeys = Object.keys(condition);
      const numConditionKeys = conditionKeys.length;
      let hasDollarKey = false;
      for (let j = 0; j < numConditionKeys; ++j) {
        if (conditionKeys[j].startsWith('$')) {
          hasDollarKey = true;
          break;
        }
      }
      if (hasDollarKey) {
        continue;
      }
    }
    updatedKeys[path] = true;
    modified[path] = true;
  }

  if (options && options.overwrite && !hasDollarUpdate) {
    // Defaults will be set later, since we're overwriting we'll cast
    // the whole update to a document
    return castedDoc;
  }

  schema.eachPath(function(path, schemaType) {
    // Skip single nested paths if underneath a map
    const isUnderneathMap = schemaType.path.endsWith('.$*') ||
      schemaType.path.indexOf('.$*.') !== -1;
    if (schemaType.$isSingleNested && !isUnderneathMap) {
      // Only handle nested schemas 1-level deep to avoid infinite
      // recursion re: https://github.com/mongodb-js/mongoose-autopopulate/issues/11
      schemaType.schema.eachPath(function(_path, _schemaType) {
        if (_path === '_id' && _schemaType.auto) {
          // Ignore _id if auto id so we don't create subdocs
          return;
        }

        const def = _schemaType.getDefault(null, true);
        if (!isModified(modified, path + '.' + _path) &&
            typeof def !== 'undefined') {
          castedDoc = castedDoc || {};
          castedDoc.$setOnInsert = castedDoc.$setOnInsert || {};
          castedDoc.$setOnInsert[path + '.' + _path] = def;
          updatedValues[path + '.' + _path] = def;
        }
      });
    } else {
      const def = schemaType.getDefault(null, true);
      if (!isModified(modified, path) && typeof def !== 'undefined') {
        castedDoc = castedDoc || {};
        castedDoc.$setOnInsert = castedDoc.$setOnInsert || {};
        if (get(castedDoc, path) == null) {
          castedDoc.$setOnInsert[path] = def;
        }
        updatedValues[path] = def;
      }
    }
  });

  return castedDoc;
};

function isModified(modified, path) {
  if (modified[path]) {
    return true;
  }
  const sp = path.split('.');
  let cur = sp[0];
  for (let i = 1; i < sp.length; ++i) {
    if (modified[cur]) {
      return true;
    }
    cur += '.' + sp[i];
  }
  return false;
}