Skip to content

Commit

Permalink
model.save only updates changed data
Browse files Browse the repository at this point in the history
added deep-diff dependency
  • Loading branch information
fractallian committed Jun 24, 2014
1 parent c036a68 commit b796f5b
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 6 deletions.
23 changes: 21 additions & 2 deletions lib/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
Model = function(collectionName, obj, options) {
options = options || {};
this.attributes = obj;
this.syncSavedState();

this._collection = Graviton._collections[collectionName];

Expand Down Expand Up @@ -80,11 +81,29 @@ Model.prototype.persist = function() {
return false;
};

Model.prototype.syncSavedState = function() {
// create a deep clone. is there a better way to do this?
this._savedState = JSON.stringify(this.attributes);
};

Model.prototype.savedState = function() {
// only parse the saved state when needed for efficiency
if (_.isString(this._savedState)) this._savedState = JSON.parse(this._savedState);
return this._savedState;
};

// insert or update
// TODO: track the attributes that have changed and only update those
Model.prototype.save = function() {
if (!this.persist()) {
this._collection.update(this._id, {$set: _.omit(this.attributes, '_id')});
var diff = Graviton.mongoDiff(this.savedState(), this.attributes);
if (!_.isEmpty(diff.operators)) {
this._collection.update(this._id, diff.operators);
this.syncSavedState();
return {updated: true, warnings: diff.warnings};
}
return false;
}
return this;
this.syncSavedState();
return {inserted: true};
};
39 changes: 39 additions & 0 deletions lib/mongo-diff.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
var MongoDiff = function(lhs, rhs, prefilter) {
this._lhs = lhs;
this._rhs = rhs;
this._deepDiffs = DeepDiff.diff(lhs, rhs, prefilter);
this.operators = {};
this.warnings = [];
for (var i in this._deepDiffs) {
this.addDeepDiff(this._deepDiffs[i]);
}
};

MongoDiff.prototype.addOperator = function(operator, path, val) {
var obj = this.operators[operator] = this.operators[operator] || {};
obj[path] = val;
};

MongoDiff.prototype.addDeepDiff = function(diff) {
var path = diff.path.join('.');
switch (diff.kind) {
case 'A':
var set = this.operators.$set;
if (!(set && set[path])) {
this.addOperator("$set", path, Graviton.getProperty(this._rhs, path));
this.warnings.push("Will replace entire array at: '"+path+"'. Individual updates should probably be done manually instead.");
}
break;
case 'E':
case 'N':
this.addOperator("$set", path, diff.rhs);
break;
case 'D':
this.addOperator("$unset", path, "");
break;
}
};

Graviton.mongoDiff = function(lhs, rhs, prefilter) {
return new MongoDiff(lhs, rhs, prefilter);
};
6 changes: 3 additions & 3 deletions package.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,18 @@ Package.describe({

Package.on_use(function (api, where) {
api.use(["underscore"], ["client", "server"]);
api.add_files(['lib/model.js', 'lib/relations.js', 'graviton.js'], ['client', 'server']);
api.use(['deep-diff'], ['client', 'server']);
api.add_files(['lib/model.js', 'lib/relations.js', 'graviton.js', 'lib/mongo-diff.js'], ['client', 'server']);

if (typeof api.export !== 'undefined') {
// api.export("Model", ["client", "server"]);
api.export("Graviton", ["client", "server"]);
}
});

Package.on_test(function (api) {
api.use(['graviton', 'tinytest', 'test-helpers']);

api.add_files('test/graviton-test.js', ['client', 'server']);
api.add_files(['test/graviton-test.js', 'test/mongo-diff-test.js'], ['client', 'server']);
});


4 changes: 3 additions & 1 deletion smart.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,7 @@
"author": "Jeremy Dunn",
"version": "0.0.2",
"git": "https://github.com/fractallian/graviton.git",
"packages": {}
"packages": {
"deep-diff": "0.0.1"
}
}
38 changes: 38 additions & 0 deletions test/mongo-diff-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
var lhs = {
name: 'my object',
description: 'it\'s an object!',
details: {
it: 'has',
an: 'array',
with: ['a', 'few', 'elements'],
array: ['inside', {another: ['array']}]
}
};

var rhs = {
name: 'updated object',
description: 'it\'s an object!',
details: {
it: 'has',
an: 'array',
with: ['a', 'few', 'more', 'elements', { than: 'before' }],
array: ['inside', {another: ['array', 'should not be tested']}]
}
};


var expected = {
$set: {
name: 'updated object',
'details.with': ['a', 'few', 'more', 'elements', { than: 'before' }],
'details.array': ['inside', {another: ['array', 'should not be tested']}]
}
};

var mongoDiff = Graviton.mongoDiff(lhs, rhs);


Tinytest.add('mongo diff', function(test) {
test.isTrue(_.isEqual(mongoDiff.operators, expected));
test.equal(mongoDiff.warnings.length, 2);
});

0 comments on commit b796f5b

Please sign in to comment.