-
Notifications
You must be signed in to change notification settings - Fork 3
/
index.js
98 lines (79 loc) · 1.68 KB
/
index.js
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
var minify = require('mongo-minify');
var is = require('component-type');
var eql = require('mongo-eql');
/**
* Diff two objects and return a MongoDB update query
*
* @param {Object} a
* @param {Object} b
* @param {Object} [filter]
* @param {String} [prefix]
* @return {Object}
* @api public
*/
module.exports = function (a, b, filter, prefix) {
var ret = {};
if (typeof filter == 'string') {
var tmp = prefix;
prefix = filter;
filter = tmp;
}
if (prefix) {
for (var key in filter) {
filter[join(key, prefix)] = prefix[key];
delete prefix[key];
}
}
filter = filter || {};
diff(a, b, ret, prefix);
return minify(ret, filter);
}
/**
* Traverse both objects and put ops on the `query` object
*/
function diff (a, b, query, prefix) {
for (var key in b) {
var path = join(key, prefix);
// removed
if (b[key] == null) {
unset(query, path);
continue;
}
// no change
if (eql(a[key], b[key])) continue;
// new type
if (is(a[key]) != is(b[key])) {
set(query, path, b[key]);
continue;
}
// object
if (is(a[key]) == 'object') {
diff(a[key], b[key], query, path);
continue;
}
// default
set(query, path, b[key]);
}
}
/**
* $set `field` to `val`
*/
function set (query, field, val) {
query['$set'] = query['$set'] || {};
query['$set'][field] = val;
}
/**
* $unset `field`
*/
function unset (query, field) {
query['$unset'] = query['$unset'] || {};
query['$unset'][field] = '';
};
/**
* Join `key` with `prefix` using dot-notation
*/
function join (key, prefix) {
return prefix
? prefix + '.' + key
: key;
}