Comparing version 1.1.0 to 1.2.0
1.2.0 / 2015-04-07 | ||
================== | ||
* docs: update contribution list | ||
* code: throw error instead of handling error | ||
* code: use promises for hookable | ||
* tests: clean up tests and make sure to restore Document.debug | ||
* code: fix error handling on delete | ||
* code: remove support for documentClass constructor passthrough | ||
* code: remove unused diff code | ||
* code: cleanup and remove errornous callback | ||
* docs: update documentation | ||
* code: convert mongodb driver to use promises | ||
* tests: fix test name | ||
* tests: expect err to exist | ||
* tests: update test case description | ||
* code: cleanup and fixes to document.update | ||
* code: added missing semi-colon | ||
* code: use proper event handler, and check correct iteration loop | ||
* code: deprecate deepmerge and use generic utilities | ||
* tests: added tests for hookable | ||
* build: clean up makefile | ||
* code: remove unused `args.stop` | ||
* doc: update documentation | ||
* config: ignore .editorconfig | ||
1.1.0 / 2015-03-28 | ||
@@ -3,0 +29,0 @@ ================== |
@@ -131,26 +131,18 @@ 'use strict'; | ||
Document.prototype.update = function(payload, cb) { | ||
if(this.model) { | ||
this.model._update(this, payload, cb); | ||
} else { | ||
this._update(payload, cb); | ||
} | ||
return this.model._update(this, payload, cb); | ||
}; | ||
Document.prototype._update = function(payload, cb) { | ||
var updateableProperties; | ||
var updateableProperties = this.model.updateablePropertiesHash; | ||
if ('updateableProperties' in this) { | ||
updateableProperties = this.updateableProperties; | ||
} | ||
if (!updateableProperties && this.model) { | ||
updateableProperties = this.model.updateablePropertiesHash; | ||
} | ||
if (!updateableProperties) { | ||
throw new Error('Update called on a document whose model has no updateable properties. See the docs for updateableProperties for more information.'); | ||
return process.nextTick(function() { | ||
cb(new Error('Update called on a document whose model has no updateable properties. See the docs for updateableProperties for more information.')); | ||
}); | ||
} | ||
if (updateableProperties.constructor.name != 'Object') { | ||
return cb(new Error('Invalid data payload.', 400)); | ||
return process.nextTick(function() { | ||
cb(new Error('Invalid data payload.', 400)); | ||
}); | ||
} | ||
@@ -209,3 +201,3 @@ | ||
return util.inspect(this.toRawJSON()); | ||
} | ||
}; | ||
@@ -212,0 +204,0 @@ Document.prototype.toRawJSON = function() { |
'use strict'; | ||
var es = require('elasticsearch'); | ||
var merge = require('deepmerge'); | ||
var merge = require('node-helper-utilities').merge; | ||
var objectDiff = require('../util/objectdiff'); | ||
@@ -6,0 +6,0 @@ var OsmosError = require('../util/error'); |
'use strict'; | ||
var Promise = require('native-or-bluebird'); | ||
var async = require('async'); | ||
@@ -12,3 +13,4 @@ var mongo = require('mongodb'); | ||
function mongoKey(key) { | ||
if (!key || key.constructor.name == 'ObjectID') return key; | ||
if (!key || key.constructor.name == 'ObjectID') | ||
return key; | ||
@@ -26,145 +28,187 @@ try { | ||
Driver.prototype = { | ||
create : function create(model, cb) { | ||
process.nextTick(function() { | ||
cb(null, {}); | ||
}); | ||
}, | ||
Driver.prototype.create = function(model, done) { | ||
return new Promise(function(resolve) { | ||
return resolve({}); | ||
}).nodeify(done); | ||
}; | ||
get : function get(model, key, cb) { | ||
this.database.collection(model.bucket).findOne( | ||
{ | ||
Driver.prototype.get = function(model, key, done) { | ||
var self = this; | ||
return new Promise(function(resolve, reject) { | ||
var spec = { | ||
_id: mongoKey(key) | ||
}, | ||
}; | ||
function(err, doc) { | ||
if (err) return cb(err); | ||
return self.database.collection(model.bucket).findOne(spec, function(err, doc) { | ||
if(err) { | ||
reject(err); | ||
} else { | ||
if (doc) { | ||
doc._id = doc._id.toHexString ? doc._id.toHexString() : doc._id; | ||
if(doc) { | ||
doc._id = doc._id.toHexString ? doc._id.toHexString() : doc._id; | ||
} | ||
resolve(doc); | ||
} | ||
}); | ||
}).nodeify(done); | ||
}; | ||
cb(null, doc); | ||
Driver.prototype.post = function(document, data, done) { | ||
data._id = mongoKey(data._id); | ||
var self = this; | ||
return new Promise(function(resolve, reject) { | ||
return self.database.collection(document.model.bucket).insert(data, function(err, docs) { | ||
if(err) { | ||
reject(err); | ||
} else { | ||
document.primaryKey = docs[0]._id.toHexString ? docs[0]._id.toHexString() : docs[0]._id; | ||
resolve(); | ||
} | ||
}); | ||
}).nodeify(done); | ||
}; | ||
Driver.prototype.put = function(document, data, done) { | ||
var self = this; | ||
return new Promise(function(resolve, reject) { | ||
if(!(document.model.schema.primaryKey && document.primaryKey)) { | ||
return reject(new OsmosError('You cannot put a document without a primary key')); | ||
} | ||
); | ||
}, | ||
post : function post(document, data, cb) { | ||
data._id = mongoKey(data._id); | ||
if(document.__originalData__[document.model.schema.primaryKey] === undefined) { | ||
return self.post(document, data).then(function() { | ||
resolve(); | ||
}).catch(function(err) { | ||
resolve(err); | ||
}); | ||
} | ||
this.database.collection(document.model.bucket).insert(data, function(err, docs) { | ||
if (err) return cb(err); | ||
var changes = objectDiff.diff(document.__originalData__, data); | ||
document.primaryKey = docs[0]._id.toHexString ? docs[0]._id.toHexString() : docs[0]._id; | ||
if(changes.changed === 'equal') { | ||
// nothing to update | ||
return resolve(); | ||
} | ||
cb(null); | ||
}); | ||
}, | ||
var diff = {}; | ||
var set = {}; | ||
var unset = {}; | ||
put : function put(document, data, cb) { | ||
var self = this; | ||
Object.keys(changes.value).forEach(function(k) { | ||
var v = data[k]; | ||
process.nextTick(function() { | ||
if (!document.model.schema.primaryKey || !document.primaryKey) { | ||
throw new OsmosError('You cannot put a document without a primary key'); | ||
} | ||
if(changes.value[k].changed !== 'equal') { | ||
diff[k] = v; | ||
if (document.__originalData__[document.model.schema.primaryKey] === undefined) { | ||
return self.post(document, data, cb); | ||
if(v === undefined) { | ||
unset[k] = ''; | ||
} else { | ||
set[k] = v; | ||
} | ||
} | ||
}); | ||
var changes = objectDiff.diff(document.__originalData__, data); | ||
var primaryKey; | ||
if (changes.changed === 'equal') return cb(null); // Nothing to update. | ||
if(diff[document.schema.primaryKey]) { | ||
primaryKey = document.__originalData__[document.schema.primaryKey]; | ||
} else { | ||
primaryKey = document.primaryKey; | ||
} | ||
var diff = {}; | ||
var set = {}; | ||
var unset = {}; | ||
var payload = {}; | ||
Object.keys(changes.value).forEach(function(key) { | ||
var val = data[key]; | ||
if (Object.keys(set).length) { | ||
payload.$set = set; | ||
} | ||
if (changes.value[key].changed !== 'equal') { | ||
diff[key] = val; | ||
if (Object.keys(unset).length) { | ||
payload.$unset = unset; | ||
} | ||
if (val === undefined) { | ||
unset[key] = ''; | ||
} else { | ||
set[key] = val; | ||
} | ||
} | ||
}); | ||
var primaryKey; | ||
if (diff[document.schema.primaryKey]) { | ||
primaryKey = document.__originalData__[document.schema.primaryKey]; | ||
return self.database.collection(document.model.bucket).update({ | ||
_id: mongoKey(primaryKey) | ||
}, payload, { upsert: true }, function(err) { | ||
if(err) { | ||
reject(err); | ||
} else { | ||
primaryKey = document.primaryKey; | ||
resolve(); | ||
} | ||
}); | ||
}).nodeify(done); | ||
}; | ||
var payload = {}; | ||
Driver.prototype.del = function(model, key, done) { | ||
if (key.constructor.name === 'Object') { | ||
key = key[Object.keys(key)[0]]; | ||
} | ||
if (Object.keys(set).length) { | ||
payload.$set = set; | ||
var self = this; | ||
return new Promise(function(resolve, reject) { | ||
return self.database.collection(model.bucket).remove({ | ||
_id: mongoKey(key) | ||
}, function(err) { | ||
if(err) { | ||
reject(err); | ||
} else { | ||
resolve(); | ||
} | ||
}); | ||
}).nodeify(done); | ||
}; | ||
if (Object.keys(unset).length) { | ||
payload.$unset = unset; | ||
Driver.prototype.count = function(model, spec, done) { | ||
var self = this; | ||
return new Promise(function(resolve, reject) { | ||
return self.database.collection(model.bucket).find(spec).count(function(err, count) { | ||
if(err) { | ||
reject(err); | ||
} else { | ||
resolve(count); | ||
} | ||
self.database.collection(document.model.bucket).update( | ||
{ | ||
_id: mongoKey(primaryKey) | ||
}, | ||
payload, | ||
{ | ||
upsert: true | ||
}, | ||
cb | ||
); | ||
}); | ||
}, | ||
}).nodeify(done); | ||
}; | ||
del : function deleteRecord(model, key, cb) { | ||
if (key.constructor.name === 'Object') { | ||
key = key[Object.keys(key)[0]]; | ||
} | ||
this.database.collection(model.bucket).remove( | ||
{ | ||
_id: mongoKey(key) | ||
}, | ||
cb | ||
); | ||
}, | ||
count: function countRecords(model, spec, cb) { | ||
return this.database.collection(model.bucket).find(spec).count(function(err, count) { | ||
cb(err, count); | ||
Driver.prototype.findOne = function(model, spec, done) { | ||
var self = this; | ||
return new Promise(function(resolve, reject) { | ||
return self.database.collection(model.bucket).findOne(spec, function(err, doc) { | ||
if(err) { | ||
reject(err); | ||
} else { | ||
resolve(doc); | ||
} | ||
}); | ||
}, | ||
}).nodeify(done); | ||
}; | ||
findOne : function findOne(model, spec, cb) { | ||
this.database.collection(model.bucket).findOne(spec, cb); | ||
}, | ||
find : function find(model, spec, cb) { | ||
this.database.collection(model.bucket).find(spec, function(err, rs) { | ||
if (err) return cb(err); | ||
rs.toArray(cb); | ||
Driver.prototype.find = function(model, spec, done) { | ||
var self = this; | ||
return new Promise(function(resolve, reject) { | ||
return self.database.collection(model.bucket).find(spec, function(err, rs) { | ||
if(err) { | ||
reject(err); | ||
} else { | ||
rs.toArray(function(err, docs) { | ||
if(err) { | ||
reject(err); | ||
} else { | ||
resolve(docs); | ||
} | ||
}); | ||
} | ||
}); | ||
}, | ||
}).nodeify(done); | ||
}; | ||
findLimit : function findLimit(model, spec, start, limit, cb) { | ||
var self = this; | ||
var searchSpec = spec.$query ? spec.$query : spec; | ||
Driver.prototype.findLimit = function findLimit(model, spec, start, limit, done) { | ||
var self = this; | ||
var searchSpec = spec.$query ? spec.$query : spec; | ||
async.parallel( | ||
{ | ||
return new Promise(function(resolve, reject) { | ||
async.parallel({ | ||
count: function(cb) { | ||
@@ -180,13 +224,12 @@ self.database.collection(model.bucket).find(searchSpec).count(cb); | ||
} | ||
}, | ||
function(err, result) { | ||
if (err) return cb(err); | ||
cb(err, result); | ||
} | ||
); | ||
} | ||
}, function(err, result) { | ||
if(err) { | ||
reject(err); | ||
} else { | ||
resolve(result); | ||
} | ||
}); | ||
}).nodeify(done); | ||
}; | ||
module.exports = Driver; |
303
lib/model.js
'use strict'; | ||
var deepmerge = require('deepmerge'); | ||
var Promise = require('native-or-bluebird'); | ||
var util = require('util'); | ||
var utilities = require('node-helper-utilities'); | ||
var async = require('async'); | ||
@@ -12,3 +13,3 @@ | ||
var Model = function Model(name, schema, bucket, db, documentClass) { | ||
var Model = function Model(name, schema, bucket, db) { | ||
this.schema = schema; | ||
@@ -20,3 +21,3 @@ this.bucket = bucket; | ||
this.documentClass = null; | ||
this.documentClassConstructor = documentClass || Document; | ||
this.documentClassConstructor = Document; | ||
this.hasInitializedDocumentClass = false; | ||
@@ -86,22 +87,20 @@ | ||
async.series( | ||
[ | ||
function(cb) { | ||
self.callHook('willInitialize', args, cb); | ||
}, | ||
async.series([ | ||
function(cb) { | ||
self.callHook('willInitialize', args, cb); | ||
}, | ||
function(cb) { | ||
args.document = new args.documentClass(self, args.data); | ||
cb(null); | ||
}, | ||
function(cb) { | ||
args.document = new args.documentClass(self, args.data); | ||
cb(null); | ||
}, | ||
function(cb) { | ||
self.callHook('didInitialize', args, cb); | ||
} | ||
], | ||
function(cb) { | ||
self.callHook('didInitialize', args, cb); | ||
} | ||
], | ||
function(err) { | ||
cb(err, args.document); | ||
} | ||
); | ||
function(err) { | ||
cb(err, args.document); | ||
}); | ||
}; | ||
@@ -127,7 +126,3 @@ | ||
if(prop.hasOwnProperty('default')) { | ||
if(prop.type === 'object' && typeof prop.default === 'object' && !!prop.default) { | ||
doc[key] = deepmerge({}, prop.default); | ||
} else { | ||
doc[key] = prop.default; | ||
} | ||
doc[key] = utilities.clone(prop.default); | ||
} | ||
@@ -149,4 +144,3 @@ | ||
var args = { | ||
key: key, | ||
stop: false | ||
key: key | ||
}; | ||
@@ -160,4 +154,2 @@ | ||
function(cb) { | ||
if (args.stop) return cb(null); | ||
self.db.get(self, args.key, function(err, data) { | ||
@@ -186,4 +178,3 @@ if (err) return cb(err); | ||
var args = { | ||
key: data[self.schema.primaryKey], | ||
stop: false | ||
key: data[self.schema.primaryKey] | ||
}; | ||
@@ -197,12 +188,6 @@ | ||
function(cb) { | ||
if (args.stop) { | ||
setImmediate(function() { | ||
cb(null); | ||
}); | ||
} else { | ||
self._initialize(data, function(err, doc) { | ||
args.document = doc; | ||
cb(null); | ||
}); | ||
} | ||
self._initialize(data, function(err, doc) { | ||
args.document = doc; | ||
cb(null); | ||
}); | ||
}, | ||
@@ -237,4 +222,3 @@ | ||
var args = { | ||
spec: spec, | ||
stop: false | ||
spec: spec | ||
}; | ||
@@ -248,26 +232,19 @@ | ||
function(cb) { | ||
if (args.stop) { | ||
setImmediate(function() { | ||
cb(null); | ||
}); | ||
} else { | ||
self.db.find(self, args.spec, function(err, docs) { | ||
if (docs) { | ||
async.map( | ||
docs, | ||
self.db.find(self, args.spec, function(err, docs) { | ||
if (docs) { | ||
async.map( | ||
docs, | ||
function(doc, cb) { | ||
self._initialize(doc, cb); | ||
}, | ||
function(doc, cb) { | ||
self._initialize(doc, cb); | ||
}, | ||
function(err, docs) { | ||
args.documents = docs; | ||
cb(err); | ||
} | ||
); | ||
} else { | ||
cb(err); | ||
} | ||
}); | ||
} | ||
function(err, docs) { | ||
args.documents = docs; | ||
cb(err); | ||
}); | ||
} else { | ||
cb(err); | ||
} | ||
}); | ||
}, | ||
@@ -285,4 +262,3 @@ | ||
var args = { | ||
spec: spec, | ||
stop: false | ||
spec: spec | ||
}; | ||
@@ -296,40 +272,31 @@ | ||
function(cb) { | ||
if (args.stop) { | ||
setImmediate(function() { | ||
cb(null); | ||
}); | ||
} else { | ||
self.db.findLimit(self, args.spec, start, limit, function(err, result) { | ||
args.count = result.count; | ||
self.db.findLimit(self, args.spec, start, limit, function(err, result) { | ||
args.count = result.count; | ||
if (result.docs) { | ||
async.map( | ||
result.docs, | ||
if (result.docs) { | ||
async.map( | ||
result.docs, | ||
function(doc, cb) { | ||
self._initialize(doc, cb); | ||
}, | ||
function(doc, cb) { | ||
self._initialize(doc, cb); | ||
}, | ||
function(err, docs) { | ||
args.documents = docs; | ||
cb(err); | ||
} | ||
); | ||
} else { | ||
cb(err); | ||
} | ||
}); | ||
} | ||
function(err, docs) { | ||
args.documents = docs; | ||
cb(err); | ||
} | ||
); | ||
} else { | ||
cb(err); | ||
} | ||
}); | ||
}, | ||
function(err) { | ||
return cb( | ||
err, | ||
{ | ||
count: args.count, | ||
start: start, | ||
limit: limit, | ||
docs : args.documents | ||
} | ||
); | ||
return cb(err, { | ||
count: args.count, | ||
start: start, | ||
limit: limit, | ||
docs : args.documents | ||
}); | ||
} | ||
@@ -341,4 +308,3 @@ ); | ||
var args = { | ||
spec: spec, | ||
stop: false | ||
spec: spec | ||
}; | ||
@@ -352,12 +318,6 @@ | ||
function(next) { | ||
if(args.stop) { | ||
setImmediate(function() { | ||
next(null); | ||
}); | ||
} else { | ||
self.db.count(self, args.spec, function(err, count) { | ||
args.count = count; | ||
next(null); | ||
}); | ||
} | ||
self.db.count(self, args.spec, function(err, count) { | ||
args.count = count; | ||
next(null); | ||
}); | ||
}, | ||
@@ -374,4 +334,3 @@ function(err) { | ||
var args = { | ||
spec: spec, | ||
stop: false | ||
spec: spec | ||
}; | ||
@@ -385,18 +344,12 @@ | ||
function(cb) { | ||
if (args.stop) { | ||
setImmediate(function() { | ||
cb(null); | ||
}); | ||
} else { | ||
self.db.findOne(self, args.spec, function(err, data) { | ||
if (data) { | ||
self._initialize(data, function(err, doc) { | ||
args.document = doc; | ||
cb(err); | ||
}); | ||
} else { | ||
self.db.findOne(self, args.spec, function(err, data) { | ||
if (data) { | ||
self._initialize(data, function(err, doc) { | ||
args.document = doc; | ||
cb(err); | ||
} | ||
}); | ||
} | ||
}); | ||
} else { | ||
cb(err); | ||
} | ||
}); | ||
}, | ||
@@ -415,4 +368,3 @@ | ||
doc: doc, | ||
payload: payload, | ||
stop: false | ||
payload: payload | ||
}; | ||
@@ -426,9 +378,3 @@ | ||
function(cb) { | ||
if (args.stop) { | ||
setImmediate(function() { | ||
cb(null); | ||
}); | ||
} else { | ||
doc._update(payload, cb); | ||
} | ||
doc._update(payload, cb); | ||
}, | ||
@@ -444,43 +390,35 @@ | ||
var args = { | ||
doc: doc, | ||
stop: false | ||
doc: doc | ||
}; | ||
async.series( | ||
[ | ||
function(cb) { | ||
self.schema.validateDocument(args.doc, function(err) { | ||
if (err) return cb(err); | ||
async.series([ | ||
function(cb) { | ||
self.schema.validateDocument(args.doc, function(err) { | ||
if (err) { | ||
return cb(err); | ||
} | ||
args.payload = args.doc.toRawJSON ? args.doc.toRawJSON() : args.doc; | ||
cb(null); | ||
}); | ||
}, | ||
args.payload = args.doc.toRawJSON ? args.doc.toRawJSON() : args.doc; | ||
cb(null); | ||
}); | ||
}, | ||
function(cb) { | ||
self.performHookCycle( | ||
'Save', | ||
function(cb) { | ||
self.performHookCycle( | ||
'Save', | ||
args, | ||
args, | ||
function(cb) { | ||
if (args.stop) { | ||
setImmediate(function() { | ||
cb(null); | ||
}); | ||
} else { | ||
if (args.doc.primaryKey) { | ||
self.db.put(args.doc, args.payload, cb); | ||
} else { | ||
self.db.post(args.doc, args.payload, cb); | ||
} | ||
} | ||
}, | ||
cb | ||
); | ||
} | ||
], | ||
cb | ||
function(cb) { | ||
if (args.doc.primaryKey) { | ||
self.db.put(args.doc, args.payload, cb); | ||
} else { | ||
self.db.post(args.doc, args.payload, cb); | ||
} | ||
}, | ||
cb | ||
); | ||
} | ||
], | ||
cb | ||
); | ||
@@ -490,3 +428,5 @@ }; | ||
Model.prototype._delete = function(doc, cb) { | ||
if (!doc.primaryKey) throw new OsmosError('This document does not have a primary key'); | ||
if (!doc.primaryKey) { | ||
return cb(new OsmosError('This document does not have a primary key')); | ||
} | ||
@@ -496,4 +436,3 @@ var self = this; | ||
var args = { | ||
doc: doc, | ||
stop: false | ||
doc: doc | ||
}; | ||
@@ -503,17 +442,9 @@ | ||
'Delete', | ||
args, | ||
function(cb) { | ||
if (args.stop) { | ||
setImmediate(function() { | ||
cb(null); | ||
}); | ||
} else { | ||
var spec = {}; | ||
var spec = {}; | ||
spec[args.doc.model.schema.primaryKey] = args.doc.primaryKey; | ||
spec[args.doc.model.schema.primaryKey] = args.doc.primaryKey; | ||
self.db.del(self, spec, cb); | ||
} | ||
self.db.del(self, spec, cb); | ||
}, | ||
@@ -520,0 +451,0 @@ |
@@ -124,3 +124,5 @@ 'use strict'; | ||
self.validator.addSchema(uri, Schema.schemas[uri]); | ||
cb(null); | ||
process.nextTick(function() { | ||
cb(); | ||
}); | ||
} else { | ||
@@ -151,3 +153,2 @@ request.get(uri, function(err, res) { | ||
self.loaded = true; | ||
self.emit('loaded'); | ||
@@ -154,0 +155,0 @@ } |
'use strict'; | ||
var Promise = require('native-or-bluebird'); | ||
var util = require('util'); | ||
@@ -32,19 +33,23 @@ var async = require('async'); | ||
if(!(this.hookCallbacks[hook] && this.hookCallbacks[hook].length)) { | ||
return process.nextTick(function() { | ||
cb(null); | ||
}); | ||
return Promise.resolve(null).nodeify(cb); | ||
} | ||
function iterator(f, cb) { | ||
/*jshint validthis:true */ | ||
f.call(this, args, cb); | ||
} | ||
var self = this; | ||
return new Promise(function(resolve, reject) { | ||
function iterator(fn, next) { | ||
fn.call(this, args, next); | ||
} | ||
async.each( | ||
this.hookCallbacks[hook], | ||
iterator.bind(this), | ||
cb | ||
); | ||
async.each( | ||
self.hookCallbacks[hook], | ||
iterator.bind(self), | ||
function(err) { | ||
if(err) { | ||
reject(err); | ||
} else { | ||
resolve(); | ||
} | ||
} | ||
) | ||
}).nodeify(cb); | ||
}; | ||
@@ -95,3 +100,5 @@ | ||
var index = this.hookCallbacks[hook].indexOf(callback); | ||
var index = this.hookCallbacks[hook] | ||
? this.hookCallbacks[hook].indexOf(callback) | ||
: -1; | ||
@@ -98,0 +105,0 @@ if(index != -1) { |
@@ -95,205 +95,1 @@ /* | ||
}; | ||
/** | ||
* @param {Object} a | ||
* @param {Object} b | ||
* @return {Object} | ||
*/ | ||
objectDiff.diffOwnProperties = function diffOwnProperties(a, b) { | ||
if (a === b) { | ||
return { | ||
changed: 'equal', | ||
value: a | ||
} | ||
} | ||
var diff = {}; | ||
var equal = true; | ||
var keys = Object.keys(a); | ||
for (var i = 0, length = keys.length; i < length; i++) { | ||
var key = keys[i]; | ||
if (b.hasOwnProperty(key)) { | ||
if (a[key] === b[key]) { | ||
diff[key] = { | ||
changed: 'equal', | ||
value: a[key] | ||
} | ||
} else { | ||
var typeA = typeof a[key]; | ||
var typeB = typeof b[key]; | ||
if (a[key] && b[key] && (typeA == 'object' || typeA == 'function') && (typeB == 'object' || typeB == 'function')) { | ||
var valueDiff = diffOwnProperties(a[key], b[key]); | ||
if (valueDiff.changed == 'equal') { | ||
diff[key] = { | ||
changed: 'equal', | ||
value: a[key] | ||
} | ||
} else { | ||
equal = false; | ||
diff[key] = valueDiff; | ||
} | ||
} else { | ||
equal = false; | ||
diff[key] = { | ||
changed: 'primitive change', | ||
removed: a[key], | ||
added: b[key] | ||
} | ||
} | ||
} | ||
} else { | ||
equal = false; | ||
diff[key] = { | ||
changed: 'removed', | ||
value: a[key] | ||
} | ||
} | ||
} | ||
keys = Object.keys(b); | ||
for (i = 0, length = keys.length; i < length; i++) { | ||
key = keys[i]; | ||
if (!a.hasOwnProperty(key)) { | ||
equal = false; | ||
diff[key] = { | ||
changed: 'added', | ||
value: b[key] | ||
} | ||
} | ||
} | ||
if (equal) { | ||
return { | ||
value: a, | ||
changed: 'equal' | ||
} | ||
} else { | ||
return { | ||
changed: 'object change', | ||
value: diff | ||
} | ||
} | ||
}; | ||
(function() { | ||
/** | ||
* @param {Object} changes | ||
* @return {string} | ||
*/ | ||
objectDiff.convertToXMLString = function convertToXMLString(changes) { | ||
var properties = []; | ||
var diff = changes.value; | ||
if (changes.changed == 'equal') { | ||
return inspect(diff); | ||
} | ||
for (var key in diff) { | ||
var changed = diff[key].changed; | ||
switch (changed) { | ||
case 'equal': | ||
properties.push(stringifyObjectKey(escapeHTML(key)) + '<span>: </span>' + inspect(diff[key].value)); | ||
break; | ||
case 'removed': | ||
properties.push('<del class="diff">' + stringifyObjectKey(escapeHTML(key)) + '<span>: </span>' + inspect(diff[key].value) + '</del>'); | ||
break; | ||
case 'added': | ||
properties.push('<ins class="diff">' + stringifyObjectKey(escapeHTML(key)) + '<span>: </span>' + inspect(diff[key].value) + '</ins>'); | ||
break; | ||
case 'primitive change': | ||
var prefix = stringifyObjectKey(escapeHTML(key)) + '<span>: </span>'; | ||
properties.push( | ||
'<del class="diff diff-key">' + prefix + inspect(diff[key].removed) + '</del><span>,</span>\n' + | ||
'<ins class="diff diff-key">' + prefix + inspect(diff[key].added) + '</ins>'); | ||
break; | ||
case 'object change': | ||
properties.push(stringifyObjectKey(key) + '<span>: </span>' + convertToXMLString(diff[key])); | ||
break; | ||
} | ||
} | ||
return '<span>{</span>\n<div class="diff-level">' + properties.join('<span>,</span>\n') + '\n</div><span>}</span>'; | ||
}; | ||
/** | ||
* @param {string} key | ||
* @return {string} | ||
*/ | ||
function stringifyObjectKey(key) { | ||
return /^[a-z0-9_$]*$/i.test(key) ? | ||
key : | ||
JSON.stringify(key); | ||
} | ||
/** | ||
* @param {string} string | ||
* @return {string} | ||
*/ | ||
function escapeHTML(string) { | ||
return string.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'); | ||
} | ||
/** | ||
* @param {Object} obj | ||
* @return {string} | ||
*/ | ||
function inspect(obj) { | ||
return _inspect('', obj); | ||
/** | ||
* @param {string} accumulator | ||
* @param {object} obj | ||
* @see http://jsperf.com/continuation-passing-style/3 | ||
* @return {string} | ||
*/ | ||
function _inspect(accumulator, obj) { | ||
switch(typeof obj) { | ||
case 'object': | ||
if (!obj) { | ||
accumulator += 'null'; | ||
break; | ||
} | ||
var keys = Object.keys(obj); | ||
var length = keys.length; | ||
if (length === 0) { | ||
accumulator += '<span>{}</span>'; | ||
} else { | ||
accumulator += '<span>{</span>\n<div class="diff-level">'; | ||
for (var i = 0; i < length; i++) { | ||
var key = keys[i]; | ||
accumulator = _inspect(accumulator + stringifyObjectKey(escapeHTML(key)) + '<span>: </span>', obj[key]); | ||
if (i < length - 1) { | ||
accumulator += '<span>,</span>\n'; | ||
} | ||
} | ||
accumulator += '\n</div><span>}</span>' | ||
} | ||
break; | ||
case 'string': | ||
accumulator += JSON.stringify(escapeHTML(obj)); | ||
break; | ||
case 'undefined': | ||
accumulator += 'undefined'; | ||
break; | ||
default: | ||
accumulator += escapeHTML(String(obj)); | ||
break; | ||
} | ||
return accumulator; | ||
} | ||
} | ||
})(); |
{ | ||
"name": "osmos-lite", | ||
"version": "1.1.0", | ||
"version": "1.2.0", | ||
"description": "A general purpose, strict, simple ORM for Node.js apps", | ||
@@ -11,3 +11,3 @@ "main": "./lib/index.js", | ||
"async": "^0.9.0", | ||
"deepmerge": "^0.2.7", | ||
"bluebird": "^2.9.24", | ||
"elasticsearch": "^3.1.3", | ||
@@ -17,3 +17,4 @@ "harmony-reflect": "^1.1.2", | ||
"mysql": "^2.6.1", | ||
"node-helper-utilities": "^1.7.4", | ||
"native-or-bluebird": "^1.2.0", | ||
"node-helper-utilities": "^1.7.5", | ||
"request": "^2.54.0", | ||
@@ -20,0 +21,0 @@ "tv4": "^1.1.9" |
@@ -27,3 +27,3 @@ # Osmos: a strict, store-agnostic object data mapper for Node.js | ||
``` | ||
npm install osmos-lite | ||
npm install osmos-lite --save | ||
``` | ||
@@ -49,7 +49,7 @@ | ||
Version 1.x of the project aims at greatly simplifying its structure by using standard validation based on [JSON Schema](http://json-schema.org) and applying many of the lessons learned through its use in production. | ||
Next iteration of updates will focus heavily on the fixes and enhancement for `osmos-lite`, use Promises, and increase the test coverage. | ||
## Contributing | ||
Contributions are always welcomed via pull requests, and they should always have associated tests. TravisCI will need to pass prior to merging. | ||
Contributions are always welcomed via pull requests, and they should always have associated tests. TravisCI will need to pass prior to merging. | ||
@@ -59,13 +59,12 @@ ## Contributors | ||
``` | ||
project : osmos-lite | ||
repo age : 1 year, 10 months | ||
active : 101 days | ||
commits : 296 | ||
files : 45 | ||
project : osmos | ||
repo age : 1 year, 11 months | ||
active : 117 days | ||
commits : 336 | ||
files : 48 | ||
authors : | ||
182 Marco Tabini 61.5% | ||
110 Limian Wang 37.2% | ||
3 Yehezkiel Syamsuhadi 1.0% | ||
1 Daniel Prata 0.3% | ||
182 Marco Tabini 54.2% | ||
150 Limian Wang 44.6% | ||
3 Yehezkiel Syamsuhadi 0.9% | ||
1 Daniel Prata 0.3% | ||
``` | ||
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
580062
10
62
2662
68
+ Addedbluebird@^2.9.24
+ Addednative-or-bluebird@^1.2.0
- Removeddeepmerge@^0.2.7
- Removeddeepmerge@0.2.10(transitive)
Updatednode-helper-utilities@^1.7.5