File size: 3,105 Bytes
9756872
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
123
124
125
126
127
128
'use strict';

/*!
 * Module dependencies.
 */

const Binary = require('bson').Binary;
const isBsonType = require('./isBsonType');
const isMongooseObject = require('./isMongooseObject');
const MongooseError = require('../error');
const util = require('util');

exports.flatten = flatten;
exports.modifiedPaths = modifiedPaths;

/*!
 * ignore
 */

function flatten(update, path, options, schema) {
  let keys;
  if (update && isMongooseObject(update) && !Buffer.isBuffer(update)) {
    keys = Object.keys(update.toObject({ transform: false, virtuals: false }) || {});
  } else {
    keys = Object.keys(update || {});
  }

  const numKeys = keys.length;
  const result = {};
  path = path ? path + '.' : '';

  for (let i = 0; i < numKeys; ++i) {
    const key = keys[i];
    const val = update[key];
    result[path + key] = val;

    // Avoid going into mixed paths if schema is specified
    const keySchema = schema && schema.path && schema.path(path + key);
    const isNested = schema && schema.nested && schema.nested[path + key];
    if (keySchema && keySchema.instance === 'Mixed') continue;

    if (shouldFlatten(val)) {
      if (options && options.skipArrays && Array.isArray(val)) {
        continue;
      }
      const flat = flatten(val, path + key, options, schema);
      for (const k in flat) {
        result[k] = flat[k];
      }
      if (Array.isArray(val)) {
        result[path + key] = val;
      }
    }

    if (isNested) {
      const paths = Object.keys(schema.paths);
      for (const p of paths) {
        if (p.startsWith(path + key + '.') && !result.hasOwnProperty(p)) {
          result[p] = void 0;
        }
      }
    }
  }

  return result;
}

/*!
 * ignore
 */

function modifiedPaths(update, path, result, recursion = null) {
  if (update == null || typeof update !== 'object') {
    return;
  }

  if (recursion == null) {
    recursion = {
      raw: { update, path },
      trace: new WeakSet()
    };
  }

  if (recursion.trace.has(update)) {
    throw new MongooseError(`a circular reference in the update value, updateValue:
${util.inspect(recursion.raw.update, { showHidden: false, depth: 1 })}
updatePath: '${recursion.raw.path}'`);
  }
  recursion.trace.add(update);

  const keys = Object.keys(update || {});
  const numKeys = keys.length;
  result = result || {};
  path = path ? path + '.' : '';

  for (let i = 0; i < numKeys; ++i) {
    const key = keys[i];
    let val = update[key];

    const _path = path + key;
    result[_path] = true;
    if (!Buffer.isBuffer(val) && isMongooseObject(val)) {
      val = val.toObject({ transform: false, virtuals: false });
    }
    if (shouldFlatten(val)) {
      modifiedPaths(val, path + key, result, recursion);
    }
  }
  recursion.trace.delete(update);

  return result;
}

/*!
 * ignore
 */

function shouldFlatten(val) {
  return val &&
      typeof val === 'object' &&
      !(val instanceof Date) &&
      !isBsonType(val, 'ObjectId') &&
      (!Array.isArray(val) || val.length !== 0) &&
      !(val instanceof Buffer) &&
      !isBsonType(val, 'Decimal128') &&
      !(val instanceof Binary);
}