1 | 'use strict';
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 | const Binary = require('../driver').get().Binary;
|
8 | const Decimal128 = require('../types/decimal128');
|
9 | const ObjectId = require('../types/objectid');
|
10 | const isMongooseObject = require('./isMongooseObject');
|
11 |
|
12 | exports.flatten = flatten;
|
13 | exports.modifiedPaths = modifiedPaths;
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 | function flatten(update, path, options, schema) {
|
20 | let keys;
|
21 | if (update && isMongooseObject(update) && !Buffer.isBuffer(update)) {
|
22 | keys = Object.keys(update.toObject({ transform: false, virtuals: false }));
|
23 | } else {
|
24 | keys = Object.keys(update || {});
|
25 | }
|
26 |
|
27 | const numKeys = keys.length;
|
28 | const result = {};
|
29 | path = path ? path + '.' : '';
|
30 |
|
31 | for (let i = 0; i < numKeys; ++i) {
|
32 | const key = keys[i];
|
33 | const val = update[key];
|
34 | result[path + key] = val;
|
35 |
|
36 |
|
37 | const keySchema = schema && schema.path && schema.path(path + key);
|
38 | const isNested = schema && schema.nested && schema.nested[path + key];
|
39 | if (keySchema && keySchema.instance === 'Mixed') continue;
|
40 |
|
41 | if (shouldFlatten(val)) {
|
42 | if (options && options.skipArrays && Array.isArray(val)) {
|
43 | continue;
|
44 | }
|
45 | const flat = flatten(val, path + key, options, schema);
|
46 | for (const k in flat) {
|
47 | result[k] = flat[k];
|
48 | }
|
49 | if (Array.isArray(val)) {
|
50 | result[path + key] = val;
|
51 | }
|
52 | }
|
53 |
|
54 | if (isNested) {
|
55 | const paths = Object.keys(schema.paths);
|
56 | for (const p of paths) {
|
57 | if (p.startsWith(path + key + '.') && !result.hasOwnProperty(p)) {
|
58 | result[p] = void 0;
|
59 | }
|
60 | }
|
61 | }
|
62 | }
|
63 |
|
64 | return result;
|
65 | }
|
66 |
|
67 |
|
68 |
|
69 |
|
70 |
|
71 | function modifiedPaths(update, path, result) {
|
72 | const keys = Object.keys(update || {});
|
73 | const numKeys = keys.length;
|
74 | result = result || {};
|
75 | path = path ? path + '.' : '';
|
76 |
|
77 | for (let i = 0; i < numKeys; ++i) {
|
78 | const key = keys[i];
|
79 | let val = update[key];
|
80 |
|
81 | result[path + key] = true;
|
82 | if (isMongooseObject(val) && !Buffer.isBuffer(val)) {
|
83 | val = val.toObject({ transform: false, virtuals: false });
|
84 | }
|
85 | if (shouldFlatten(val)) {
|
86 | modifiedPaths(val, path + key, result);
|
87 | }
|
88 | }
|
89 |
|
90 | return result;
|
91 | }
|
92 |
|
93 |
|
94 |
|
95 |
|
96 |
|
97 | function shouldFlatten(val) {
|
98 | return val &&
|
99 | typeof val === 'object' &&
|
100 | !(val instanceof Date) &&
|
101 | !(val instanceof ObjectId) &&
|
102 | (!Array.isArray(val) || val.length > 0) &&
|
103 | !(val instanceof Buffer) &&
|
104 | !(val instanceof Decimal128) &&
|
105 | !(val instanceof Binary);
|
106 | }
|