-
Notifications
You must be signed in to change notification settings - Fork 0
/
panopticon.js
94 lines (85 loc) · 2.49 KB
/
panopticon.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
var jsondiffpatch = require('jsondiffpatch'),
_ = require('underscore');
/*
* getNewValue()
*
* Returns the new value of a document property
*
* @param {Array} diffItem representing change to property (see jsondiffpatch)
*/
function getNewValue(diffItem){
if (!_.isArray(diffItem)) {
throw new TypeError('diffItem must be an array');
}
if (diffItem.length === 3) {
return null;
}
return _.last(diffItem);
};
var isDiffArray = function(diff) {
return diff._t === 'a';
};
/*
* applyRules()
*
* Calls rules functions
*
* @param {Object} doc the document just saved
* @param {Object} rules the functions to call when paths in diff
* @param {Object} diff the diff between the old and new document
*
* @throws TypeError if diff is array (rule does not reflect model structure)
* @throws TypeError if rules contains an array (invalid)
*/
var applyRules = function(doc, rules, diff, arrayIndex) {
if (_.isArray(diff)) {
throw new TypeError('diff cannot be an array')
}
_(diff).each(function(diffItem, key){
if (typeof rules[key] === 'function') {
newValue = isDiffArray(diffItem) ? diffItem : getNewValue(diffItem);
var rule = rules[key];
rule.call(doc, newValue);
} else if (_.isObject(rules[key])) {
applyRules(doc, rules[key], diffItem);
}
});
};
/*
* watch()
* <schema> - a Mongoose schema
* <rules> - an object containing watch rules
*
*/
exports.watch = function(schema, rules) {
// SET UP ORIGINAL OBJECT
schema.pre('init', function (next, doc) {
// stringify prunes methods from the document
doc._original = JSON.parse(JSON.stringify(doc));
next();
});
// SET UP POST SAVE WITH DIFFING
/* Example diff:
diff: {
pets: {
name: ['berty', 'fred']
},
email: [oldEmail, newEmail]
}
*/
schema.post('save', function () {
var doc = this;
var original = doc.get('_original');
if (original) {
var updated = JSON.parse(JSON.stringify(doc));
var differ = jsondiffpatch.create({
// this is so the differ can tell what has changed for arrays of objects
objectHash: function(obj) {
return obj.id || obj._id || obj._id || JSON.stringify(obj);
}
});
var diff = differ.diff(original, updated);
applyRules(doc, rules, diff);
}
});
};