mongoose-revisionist
Advanced tools
Comparing version 0.1.2 to 0.2.0
@@ -0,1 +1,6 @@ | ||
##0.2.0 | ||
- Removes `created`, `createdBy`, `modified` and `modifiedBy`. Those are not required for this library to function and should be details left to the user. | ||
- Adds `diff` for versions and dates. | ||
- Condenses the unit tests considerably by breaking out model creation. | ||
##0.1.2 | ||
@@ -2,0 +7,0 @@ - Changes out nodeunit for mocha to get a little more control over when connections and models are created for testing. This also prevents connection thrashing. |
{ | ||
"name": "mongoose-revisionist", | ||
"version": "0.1.2", | ||
"version": "0.2.0", | ||
"description": "Oplog-like tracking for mongoose", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -9,12 +9,4 @@ Creates Mongo's oplog-like records for Mongoose operations. | ||
The Mongoose plugin adds a handful of fields to the schema if they do not exist already: | ||
The Mongoose plugin adds a `revision` field of type `Number` to the target schema, which is autoincremented every save. The plugin will also add a collection of revisions that are _close_ to (but not quite exactly) oplog records: | ||
- *modified* - `Date` - when the document was last modified. | ||
- *modifiedBy* - `String` - who/what last modified the document. | ||
- *created* - `Date` - when the document was created. | ||
- *createdBy* - `String` - who/what created the document. | ||
- *revision* - `Number` - the revision of the document, autoincremented every save. | ||
The plugin will also add a collection of revisions that are _close_ to (but not quite exactly) oplog records: | ||
- *ts* - `Date` - the timestamp of the operation, defaults to `Date.now`. | ||
@@ -53,9 +45,27 @@ - *v* - `Number` - the Mongoose-internal version of the document. | ||
- *versions* - gets the valid versions for a given Mongoose document. Calls back with an array of integers. | ||
- *getVersion* - gets a specific version of a given Mongoose document. The first argument of the call can be a version number, a date (to get by date), "current" to get the current version, or not specified, also to get the current version. | ||
#### .versions(cb) | ||
Gets the valid versions for a given Mongoose document. Calls back with an array of integers. | ||
### Static Methods | ||
#### .getVersion([versionNumber|date|'current', ] cb) | ||
Gets a specific version of a given Mongoose document. The first argument of the call can be a version number, a date (to get by date), "current" to get the current version, or not specified, also to get the current version. Calls back with the collapsed version as it would have appeared at that number/date. | ||
- *getVersion* - gets a specific version of a given Mongoose document. The first argument must be the document ID to retrieve. The rest is exactly the same as the intance method: The second argument of the call can be a version number, a date (to get by date), "current" to get the current version, or not specified, also to get the current version. | ||
#### .diff(versionNumber|date, versionNumber|date, cb) | ||
Gets the difference in versions or between dates specified. Calls back with an object with three hashes: `added`, `removed`, `updated`. Each hash has member paths denoting they were changed, as well as what the value was changed from and to along with the version the change happened in. For example: | ||
```js | ||
{ | ||
added: {}, | ||
updated: { | ||
name: { | ||
from: 'bar', | ||
to: 'baz', | ||
revision: 4 | ||
} | ||
}, | ||
removed: {} | ||
} | ||
``` | ||
... would denote that the `name` field was updated from `bar` to `baz` in the 4th revision. | ||
### Static Methods | ||
Each of the above instance methods are also available as static methods on the Mongoose model. The only additional parameter required is a valid Mongo ID as the first parameter. For example, `instance.diff()` would have the signature `Model.diff(id, versionNumber|date, versionNumber| date, cb)`. |
var _ = require('lodash'), | ||
util = require('util'), | ||
async = require('async'), | ||
argx = require('argx'), | ||
moment = require('moment'), | ||
mongoose = require('mongoose'); | ||
util = require('util'), | ||
async = require('async'), | ||
argx = require('argx'), | ||
moment = require('moment'), | ||
mongoose = require('mongoose'); | ||
_.mixin({ | ||
keysDeep: function(thing) { | ||
var paths = []; | ||
var t = function(thing, path) { | ||
_.each(thing, function(value, key) { | ||
path.push(key); | ||
keysDeep: function(thing, leafsOnly) { | ||
var paths = []; | ||
var t = function(thing, path) { | ||
_.each(thing, function(value, key) { | ||
path.push(key); | ||
var isLeaf = true; | ||
if (!/^[a-fA-F0-9]{24}/.test(thing[key].toString()) && (_.isObject(thing[key]) || _.isArray(thing[key]))) { | ||
isLeaf = false; | ||
t(thing[key], path); | ||
} | ||
if (leafsOnly && isLeaf) { | ||
paths.push(path.join('.')); | ||
} | ||
if (!/^[a-fA-F0-9]{24}/.test(thing[key].toString()) && (_.isObject(thing[key]) || _.isArray(thing[key]))) { | ||
t(thing[key], path); | ||
} else {} | ||
paths.push(path.join('.')); | ||
path.pop(); | ||
}); | ||
}; | ||
t(thing, []); | ||
return paths; | ||
} | ||
if (!leafsOnly) { | ||
paths.push(path.join('.')); | ||
} | ||
path.pop(); | ||
}); | ||
}; | ||
t(thing, []); | ||
return paths; | ||
} | ||
}); | ||
var revisionist = { | ||
schema: new mongoose.Schema({ | ||
ts: { | ||
type: Date, | ||
default: Date.now | ||
}, | ||
v: Number, | ||
op: String, | ||
ns: String, | ||
o: mongoose.Schema.Types.Mixed, | ||
o2: { | ||
type: mongoose.Schema.Types.Mixed, | ||
required: false | ||
}, | ||
revision: Number, | ||
referenceId: mongoose.Schema.Types.ObjectId | ||
}), | ||
plugin: function(schema, options) { | ||
options = _.defaultsDeep(options || {}, { | ||
modelName: 'Revisionist' | ||
}); | ||
schema: new mongoose.Schema({ | ||
ts: { | ||
type: Date, | ||
default: Date.now | ||
}, | ||
v: Number, | ||
op: String, | ||
ns: String, | ||
o: mongoose.Schema.Types.Mixed, | ||
o2: { | ||
type: mongoose.Schema.Types.Mixed, | ||
required: false | ||
}, | ||
revision: Number, | ||
referenceId: mongoose.Schema.Types.ObjectId | ||
}), | ||
plugin: function(schema, options) { | ||
options = _.defaultsDeep(options || {}, { | ||
modelName: 'Revisionist' | ||
}); | ||
schema.add({ | ||
modified: Date, | ||
modifiedBy: String, | ||
created: Date, | ||
createdBy: String, | ||
revision: Number | ||
schema.add({ | ||
revision: Number | ||
}); | ||
schema.method('versions', function(cb) { | ||
this.collection.conn.models[options.modelName].find({ | ||
referenceId: this._id | ||
}, { | ||
revision: 1 | ||
}) | ||
.exec(function(err, revisions) { | ||
cb(err, _.uniq(revisions)); | ||
}); | ||
}); | ||
schema.method('versions', function(cb) { | ||
this.collection.conn.models[options.modelName].find({ | ||
referenceId: this._id | ||
}, { | ||
revision: 1 | ||
}) | ||
.exec(function(err, revisions) { | ||
cb(err, _.uniq(revisions)); | ||
}); | ||
schema.static('versions', function(id, cb) { | ||
this.collection.conn.models[options.modelName].find({ | ||
referenceId: id | ||
}, { | ||
revision: 1 | ||
}) | ||
.exec(function(err, revisions) { | ||
cb(err, _.uniq(revisions)); | ||
}); | ||
}); | ||
var collapse = function() { | ||
var args = argx(arguments); | ||
var collapse = function() { | ||
var args = argx(arguments); | ||
var cb = args.pop('function') || function() {}, | ||
referenceId = args.shift(), | ||
connection = args.shift(), | ||
values = args.remain(); | ||
var cb = args.pop('function') || function() {}, | ||
referenceId = args.shift(), | ||
connection = args.shift(), | ||
values = args.remain(); | ||
var version, date; | ||
if (values.length == 0) { | ||
version = 'current'; | ||
} else if (values.length == 1) { | ||
if (moment.isMoment(values[0]) || | ||
_.isDate(values[0])) { | ||
date = moment(values[0]); | ||
} else { | ||
version = values[0]; | ||
var version, date; | ||
if (values.length == 0) { | ||
version = 'current'; | ||
} else if (values.length == 1) { | ||
if (moment.isMoment(values[0]) || | ||
_.isDate(values[0])) { | ||
date = moment(values[0]); | ||
} else { | ||
version = values[0]; | ||
} | ||
} else { | ||
throw 'Too many arguments specified for getVersion.'; | ||
} | ||
var query = { | ||
referenceId: referenceId | ||
}; | ||
if (!!version && version != 'current') { | ||
query.revision = { | ||
$lte: version | ||
}; | ||
} else if (!!date) { | ||
query.ts = { | ||
$lte: date.toDate() | ||
}; | ||
} | ||
connection.models[options.modelName].find(query) | ||
.exec(function(err, revisions) { | ||
var collapsed = revisions.length == 0 ? undefined : {}; | ||
_.each(revisions, function(revision) { | ||
revision = revision.toObject(); | ||
//check for 'o' | ||
//nb: o can be omitted in the update immediately prior to a deletion | ||
if (revision.hasOwnProperty('o')) { | ||
if (revision.op == 'i' || (revision.op == 'u' && revision.o.hasOwnProperty('_id'))) { | ||
_.each(revision.o['_$set'], function(value, key) { | ||
collapsed[key] = value; | ||
}); | ||
} else if (revision.op == 'u') { | ||
if (revision.o.hasOwnProperty('_$set')) { | ||
_.each(revision.o['_$set'], function(value, key) { | ||
collapsed[key] = value; | ||
}); | ||
} | ||
} else { | ||
throw 'Too many arguments specified for getVersion.'; | ||
if (revision.o.hasOwnProperty('_$unset')) { | ||
_.each(revision.o['_$unset'], function(value, key) { | ||
delete collapsed[key]; | ||
}); | ||
} | ||
} | ||
} | ||
}) | ||
cb(err, collapsed); | ||
}); | ||
}; | ||
var query = { | ||
referenceId: referenceId | ||
var diff = function() { | ||
var args = argx(arguments); | ||
var cb = args.pop('function') || function() {}, | ||
referenceId = args.shift(), | ||
connection = args.shift(), | ||
values = args.remain(); | ||
var startDate, endDate, startVersion, endVersion; | ||
if (values.length == 2) { | ||
if ((moment.isMoment(values[0]) || _.isDate(values[0])) && | ||
(moment.isMoment(values[1]) || _.isDate(values[1]))) { | ||
startDate = moment(values[0]); | ||
endDate = moment(values[1]); | ||
} else { | ||
startVersion = values[0]; | ||
endVersion = values[1]; | ||
} | ||
} else { | ||
throw 'invalid arguments specified for diff.'; | ||
} | ||
var query = { | ||
referenceId: referenceId | ||
}; | ||
if (startDate && endDate) { | ||
query.ts = { | ||
$lte: endDate.toDate(), | ||
$gte: startDate.toDate() | ||
}; | ||
} else if (startVersion && endVersion) { | ||
query.revision = { | ||
$lte: endVersion, | ||
$gte: startVersion | ||
}; | ||
} | ||
connection.models[options.modelName].find(query) | ||
.exec(function(err, revisions) { | ||
var collapsed = revisions.length == 0 ? undefined : { | ||
added: {}, | ||
updated: {}, | ||
removed: {} | ||
}; | ||
var modify = function(key, value, revision, collection) { | ||
var from = (collapsed[collection][key] || {}) | ||
.to; | ||
_.each(_.keys(collapsed), function(collectionKey) { | ||
if (collapsed[collectionKey][key]) { | ||
from = collapsed[collectionKey][key].to; | ||
delete collapsed[collection][key]; | ||
} | ||
}); | ||
collapsed[collection][key] = { | ||
from: from, | ||
to: (/^[a-fA-F0-9]{24}/.test(value.toString()) ? value.toString() : value), | ||
revision: revision | ||
}; | ||
if (!!version && version != 'current') { | ||
query.revision = { | ||
$lte: version | ||
}; | ||
} else if (!!date) { | ||
query.ts = { | ||
$lte: date.toDate() | ||
}; | ||
} | ||
}; | ||
connection.models[options.modelName].find(query) | ||
.exec(function(err, revisions) { | ||
var collapsed = revisions.length == 0 ? undefined : {}; | ||
_.each(revisions, function(revision) { | ||
if (revision.op == 'i' || (revision.op == 'u' && revision.o.hasOwnProperty('_id'))) { | ||
_.each(revision.o['_$set'], function(value, key) { | ||
collapsed[key] = value; | ||
}); | ||
} else if (revision.op == 'u') { | ||
if (revision.o.hasOwnProperty('_$set')) { | ||
_.each(revision.o['_$set'], function(value, key) { | ||
collapsed[key] = value; | ||
}); | ||
} | ||
if (revision.o.hasOwnProperty('_$unset')) { | ||
_.each(revision.o['_$unset'], function(value, key) { | ||
delete collapsed[key]; | ||
}); | ||
} | ||
} | ||
}) | ||
_.each(revisions, function(revision) { | ||
if (revision.op == 'i' || (revision.op == 'u' && revision.o.hasOwnProperty('_id'))) { | ||
_.each(_.keysDeep(revision.o['_$set'], true), function(key) { | ||
modify(key, _.get(revision.o['_$set'], key), revision.revision, 'added'); | ||
}); | ||
cb(err, collapsed); | ||
} else if (revision.op == 'u') { | ||
if (revision.o.hasOwnProperty('_$set')) { | ||
_.each(_.keysDeep(revision.o['_$set'], true), function(key) { | ||
modify(key, _.get(revision.o['_$set'], key), revision.revision, 'updated'); | ||
}); | ||
}; | ||
} | ||
if (revision.o.hasOwnProperty('_$unset')) { | ||
_.each(_.keysDeep(revision.o['_$unset'], true), function(key) { | ||
modify(key, _.get(revision.o['_$unset'], key), reivsion.revision, 'removed'); | ||
}); | ||
schema.method('getVersion', function() { | ||
var args = [].slice.call(arguments); | ||
args.unshift(this.collection.conn), | ||
args.unshift(this._id); | ||
collapse.apply(null, args); | ||
}); | ||
} | ||
} | ||
}) | ||
schema.static('getVersion', function() { | ||
var args = [].slice.call(arguments); | ||
args.splice(1, 0, this.db); | ||
collapse.apply(null, args); | ||
cb(err, collapsed); | ||
}); | ||
}; | ||
schema.pre('save', function(next) { | ||
var self = this, | ||
connection = this.collection.conn; | ||
schema.method('getVersion', function() { | ||
var args = [].slice.call(arguments); | ||
args.unshift(this.collection.conn), | ||
args.unshift(this._id); | ||
collapse.apply(null, args); | ||
}); | ||
schema.static('getVersion', function() { | ||
var args = [].slice.call(arguments); | ||
args.splice(1, 0, this.db); | ||
collapse.apply(null, args); | ||
}); | ||
if (!!options.connectionString) { | ||
connection = mongoose.createConnection(options.connectionString); | ||
} | ||
schema.method('diff', function() { | ||
var args = [].slice.call(arguments); | ||
args.unshift(this.collection.conn), | ||
args.unshift(this._id); | ||
diff.apply(null, args); | ||
}); | ||
//add the revisionist schema | ||
var revisionistModel = connection.model(options.modelName, revisionist.schema); | ||
schema.static('diff', function() { | ||
var args = [].slice.call(arguments); | ||
args.splice(1, 0, this.db); | ||
diff.apply(null, args); | ||
}); | ||
//get the original and update object | ||
var original = self._original, | ||
update = self.toObject(), | ||
operation = 'u'; | ||
schema.pre('save', function(next) { | ||
var self = this, | ||
connection = this.collection.conn; | ||
//determine what kind of operation this is | ||
if (!original) { | ||
operation = 'i'; | ||
self.created = moment() | ||
.toDate(); | ||
//check createdBy | ||
if (!self.createdBy && !self.modifiedBy) { | ||
console.warn('mongoose-revisionist: no createdBy specified for %s in model %s', self._id, self.constructor.modelName); | ||
self.createdBy = '[unknown]'; | ||
} else if (!self.createdBy) { | ||
self.createdBy = self.modifiedBy; | ||
} | ||
} | ||
if (!!options.connectionString) { | ||
connection = mongoose.createConnection(options.connectionString); | ||
} | ||
//set the modified date | ||
self.modified = moment() | ||
.toDate(); | ||
//add the revisionist schema | ||
var revisionistModel = connection.model(options.modelName, revisionist.schema); | ||
//check modifiedBy | ||
if (!self.modifiedBy && operation == 'i') { | ||
self.modifiedBy = self.createdBy; | ||
} else if (!self.modifiedBy) { | ||
console.warn('mongoose-revisionist: no modifiedBy specified for %s in model %s', self._id, self.constructor.modelName); | ||
self.modifiedBy = '[unknown]'; | ||
} | ||
//get the original and update object | ||
var original = self._original, | ||
update = self.toObject(), | ||
operation = 'u'; | ||
//first, determine what overlaps, and what is different in that set | ||
var set = _.chain(original) | ||
.keysDeep() | ||
.intersection(_.keysDeep(update)) | ||
.map(function(key) { | ||
var temp = self.schema.path(key); | ||
return { | ||
key: key, | ||
type: (self.schema.path(key) || {}) | ||
.instance | ||
}; | ||
}) | ||
.filter(function(key) { | ||
return !!key.type | ||
}) | ||
.map(function(key) { | ||
return key.key; | ||
}) | ||
.map(function(key) { | ||
var getValue = function(value, instance) { | ||
if (_.isDate(value)) { | ||
//if the member is a date, compare the integer representation | ||
//hack: consider using getTime() instead of + | ||
originalValue = +originalValue; | ||
newValue = +newValue | ||
} else if (_.isObject(value) && /^[0-9a-fA-F]{24}$/.test(value.toString())) { | ||
//if the member is a schema ID, compare the strings | ||
//hack: using isObject and a hex regex also feels bad. | ||
value = value.toString(); | ||
} else if (_.isObject(value) && instance == 'ObjectID') { | ||
//if the member is a schema ID but is loaded - failing the schema ID check above, | ||
//check the IDs | ||
value = value._id.toString(); | ||
} else if (_.isArray(value)) { | ||
//dope array for array checking | ||
} else if (_.isObject(value)) { | ||
//leave object alone, use _.isEqual to check | ||
//todo: nested objects? | ||
} else { | ||
//otherwise, the member is an ordinary primitive, compare those | ||
} | ||
//determine what kind of operation this is | ||
if (!original) { | ||
operation = 'i'; | ||
} | ||
return value; | ||
}, | ||
//get the original compare value | ||
originalValue = getValue(_.get(original, key), self.schema.path(key) | ||
.instance), | ||
//get the new compare value | ||
newValue = getValue(_.get(update, key), self.schema.path(key) | ||
.instance); | ||
//first, determine what overlaps, and what is different in that set | ||
var set = _.chain(original) | ||
.keysDeep() | ||
.intersection(_.keysDeep(update)) | ||
.map(function(key) { | ||
var temp = self.schema.path(key); | ||
return { | ||
key: key, | ||
type: (self.schema.path(key) || {}) | ||
.instance | ||
}; | ||
}) | ||
.filter(function(key) { | ||
return !!key.type | ||
}) | ||
.map(function(key) { | ||
return key.key; | ||
}) | ||
.map(function(key) { | ||
var getValue = function(value, instance) { | ||
if (_.isDate(value)) { | ||
//if the member is a date, compare the integer representation | ||
//hack: consider using getTime() instead of + | ||
originalValue = +originalValue; | ||
newValue = +newValue | ||
} else if (_.isObject(value) && /^[0-9a-fA-F]{24}$/.test(value.toString())) { | ||
//if the member is a schema ID, compare the strings | ||
//hack: using isObject and a hex regex also feels bad. | ||
value = value.toString(); | ||
} else if (_.isObject(value) && instance == 'ObjectID') { | ||
//if the member is a schema ID but is loaded - failing the schema ID check above, | ||
//check the IDs | ||
value = value._id.toString(); | ||
} else if (_.isArray(value)) { | ||
//dope array for array checking | ||
} else if (_.isObject(value)) { | ||
//leave object alone, use _.isEqual to check | ||
//todo: nested objects? | ||
} else { | ||
//otherwise, the member is an ordinary primitive, compare those | ||
} | ||
if (!_.isEqual(newValue, originalValue)) { | ||
//if the values don't match, return the key with the unmodified update value | ||
return { | ||
key: key, | ||
value: _.get(update, key) | ||
}; | ||
} | ||
}) | ||
.compact() | ||
.reduce(function(result, member, ix) { | ||
if (self.schema.path(member.key) | ||
.instance == 'ObjectID' && !/^[0-9a-fA-F]{24}$/.test(member.value.toString())) { | ||
_.set(result, member.key, member.value._id); | ||
} else { | ||
_.set(result, member.key, member.value); | ||
} | ||
return result; | ||
}, {}) | ||
.value(); | ||
return value; | ||
}, | ||
//get the original compare value | ||
originalValue = getValue(_.get(original, key), self.schema.path(key) | ||
.instance), | ||
//get the new compare value | ||
newValue = getValue(_.get(update, key), self.schema.path(key) | ||
.instance); | ||
//merge in the new values | ||
set = _.merge(set, _.chain(update) | ||
.keysDeep() | ||
.difference(_.keysDeep(original)) | ||
.map(function(key) { | ||
var temp = self.schema.path(key); | ||
return { | ||
key: key, | ||
type: (self.schema.path(key) || {}) | ||
.instance | ||
}; | ||
}) | ||
.filter(function(key) { | ||
return !!key.type | ||
}) | ||
.map(function(key) { | ||
return key.key; | ||
}) | ||
.map(function(key) { | ||
return { | ||
key: key, | ||
value: _.get(update, key) | ||
}; | ||
}) | ||
.reduce(function(result, member, ix) { | ||
if (self.schema.path(member.key) | ||
.instance == 'ObjectID' && !/^[0-9a-fA-F]{24}$/.test(member.value.toString())) { | ||
_.set(result, member.key, member.value._id); | ||
} else { | ||
_.set(result, member.key, member.value); | ||
} | ||
return result; | ||
}, {}) | ||
.value()); | ||
if (!_.isEqual(newValue, originalValue)) { | ||
//if the values don't match, return the key with the unmodified update value | ||
return { | ||
key: key, | ||
value: _.get(update, key) | ||
}; | ||
} | ||
}) | ||
.compact() | ||
.reduce(function(result, member, ix) { | ||
if (self.schema.path(member.key) | ||
.instance == 'ObjectID' && !/^[0-9a-fA-F]{24}$/.test(member.value.toString())) { | ||
_.set(result, member.key, member.value._id); | ||
} else { | ||
_.set(result, member.key, member.value); | ||
} | ||
return result; | ||
}, {}) | ||
.value(); | ||
//make the unset | ||
var unset = _.chain(original) | ||
.keysDeep() | ||
.difference(_.keysDeep(update)) | ||
.map(function(key) { | ||
var temp = self.schema.path(key); | ||
return { | ||
key: key, | ||
type: (self.schema.path(key) || {}) | ||
.instance | ||
}; | ||
}) | ||
.filter(function(key) { | ||
return !!key.type | ||
}) | ||
.map(function(key) { | ||
return key.key; | ||
}) | ||
.reduce(function(result, key, ix) { | ||
_.set(result, key, 1); | ||
return result; | ||
}, {}) | ||
.value(); | ||
//merge in the new values | ||
set = _.merge(set, _.chain(update) | ||
.keysDeep() | ||
.difference(_.keysDeep(original)) | ||
.map(function(key) { | ||
var temp = self.schema.path(key); | ||
return { | ||
key: key, | ||
type: (self.schema.path(key) || {}) | ||
.instance | ||
}; | ||
}) | ||
.filter(function(key) { | ||
return !!key.type | ||
}) | ||
.map(function(key) { | ||
return key.key; | ||
}) | ||
.map(function(key) { | ||
return { | ||
key: key, | ||
value: _.get(update, key) | ||
}; | ||
}) | ||
.reduce(function(result, member, ix) { | ||
if (self.schema.path(member.key) | ||
.instance == 'ObjectID' && !/^[0-9a-fA-F]{24}$/.test(member.value.toString())) { | ||
_.set(result, member.key, member.value._id); | ||
} else { | ||
_.set(result, member.key, member.value); | ||
} | ||
return result; | ||
}, {}) | ||
.value()); | ||
//make the unset | ||
var unset = _.chain(original) | ||
.keysDeep() | ||
.difference(_.keysDeep(update)) | ||
.map(function(key) { | ||
var temp = self.schema.path(key); | ||
return { | ||
key: key, | ||
type: (self.schema.path(key) || {}) | ||
.instance | ||
}; | ||
}) | ||
.filter(function(key) { | ||
return !!key.type | ||
}) | ||
.map(function(key) { | ||
return key.key; | ||
}) | ||
.reduce(function(result, key, ix) { | ||
_.set(result, key, 1); | ||
return result; | ||
}, {}) | ||
.value(); | ||
var o2 = null; | ||
if (operation == 'u') { | ||
o2 = { | ||
_id: original._id | ||
}; | ||
delete set._id; | ||
} | ||
//create the revisionist record | ||
(new revisionistModel({ | ||
ts: new Date(), | ||
op: operation, | ||
v: (original || {}) | ||
.__v, | ||
ns: self.collection.collectionName, | ||
o: { | ||
'_$set': set, | ||
'_$unset': unset | ||
}, | ||
o2: o2, | ||
revision: ++(original || { | ||
revision: 0 | ||
}) | ||
.revision, | ||
referenceId: self._id | ||
})) | ||
.save(function(err, revision) { | ||
self.revision = revision.revision; | ||
next(); | ||
}); | ||
var o2 = null; | ||
if (operation == 'u') { | ||
o2 = { | ||
_id: original._id | ||
}; | ||
delete set._id; | ||
} | ||
//create the revisionist record | ||
(new revisionistModel({ | ||
ts: new Date(), | ||
op: operation, | ||
v: (original || {}) | ||
.__v, | ||
ns: self.collection.collectionName, | ||
o: { | ||
'_$set': set, | ||
'_$unset': unset | ||
}, | ||
o2: o2, | ||
revision: ++(original || { | ||
revision: 0 | ||
}) | ||
.revision, | ||
referenceId: self._id | ||
})) | ||
.save(function(err, revision) { | ||
self.revision = revision.revision; | ||
next(); | ||
}); | ||
schema.pre('remove', function(next) { | ||
var self = this, | ||
connection = this.collection.conn; | ||
}); | ||
self.save(function(err) { | ||
schema.pre('remove', function(next) { | ||
var self = this, | ||
connection = this.collection.conn; | ||
if (!!options.connectionString) { | ||
connection = mongoose.createConnection(options.connectionString); | ||
} | ||
self.save(function(err) { | ||
//add the revisionist schema | ||
var revisionistModel = connection.model(options.modelName, revisionist.schema); | ||
if (!!options.connectionString) { | ||
connection = mongoose.createConnection(options.connectionString); | ||
} | ||
//create the revisionist record | ||
(new revisionistModel({ | ||
ts: new Date(), | ||
op: 'd', | ||
v: (self._original || {}) | ||
.__v, | ||
ns: self.collection.collectionName, | ||
o: { | ||
_id: self._id | ||
}, | ||
revision: ++(self._original || { | ||
revision: 0 | ||
}) | ||
.revision, | ||
referenceId: self._id | ||
})) | ||
.save(function(err, revision) { | ||
self.revision = revision.revision; | ||
next(); | ||
}); | ||
}); | ||
//add the revisionist schema | ||
var revisionistModel = connection.model(options.modelName, revisionist.schema); | ||
}); | ||
//create the revisionist record | ||
(new revisionistModel({ | ||
ts: new Date(), | ||
op: 'd', | ||
v: (self._original || {}) | ||
.__v, | ||
ns: self.collection.collectionName, | ||
o: { | ||
_id: self._id | ||
}, | ||
revision: ++(self._original || { | ||
revision: 0 | ||
}) | ||
.revision, | ||
referenceId: self._id | ||
})) | ||
.save(function(err, revision) { | ||
self.revision = revision.revision; | ||
next(); | ||
}); | ||
}); | ||
schema.post('save', function() { | ||
this._original = this.toObject(); | ||
}); | ||
}); | ||
schema.post('init', function() { | ||
//when the db value is pulled, make a copy-on-write copy of the original values for audit purposes later | ||
this._original = this.toObject(); | ||
//todo: add a dirty flag | ||
}); | ||
schema.post('save', function() { | ||
this._original = this.toObject(); | ||
}); | ||
}, | ||
schema.post('init', function() { | ||
//when the db value is pulled, make a copy-on-write copy of the original values for audit purposes later | ||
this._original = this.toObject(); | ||
//todo: add a dirty flag | ||
}); | ||
}, | ||
}; | ||
module.exports = exports = revisionist; |
module.exports = exports = { | ||
"info": require("./info"), | ||
"methods": require("./methods"), | ||
"types": require("./types"), | ||
"util": require("./util"), | ||
}; |
module.exports = exports = { | ||
"getVersionByDate": require("./getVersionByDate"), | ||
"diff": require("./diff"), | ||
"getVersion": require("./getVersion"), | ||
"versions": require("./versions"), | ||
}; |
var mongoose = require('mongoose'), | ||
util = require('util'), | ||
async = require('async'), | ||
_ = require('lodash'), | ||
logger = require('winston'), | ||
should = require('should'), | ||
testUtil = require('../util'); | ||
util = require('util'), | ||
async = require('async'), | ||
_ = require('lodash'), | ||
logger = require('winston'), | ||
should = require('should'), | ||
testUtil = require('../util'); | ||
describe('composite', function() { | ||
it('creates', function(done) { | ||
var self = this; | ||
async.waterfall([ | ||
it('creates', function(done) { | ||
var self = this; | ||
async.waterfall([ | ||
function(cb) { | ||
var composite = new self.Composite({ | ||
name: 'stuff', | ||
telephone: '999-999-9999', | ||
someCompositeThing: { | ||
compositeMemberOne: 'one', | ||
compositeMemberTwo: 'two' | ||
}, | ||
createdBy: 'test' | ||
}); | ||
function(cb) { | ||
var composite = new self.Composite({ | ||
name: 'stuff', | ||
telephone: '999-999-9999', | ||
someCompositeThing: { | ||
compositeMemberOne: 'one', | ||
compositeMemberTwo: 'two' | ||
}, | ||
createdBy: 'test' | ||
}); | ||
composite.save(function(err, composite) { | ||
cb(err, { | ||
composite: composite | ||
}); | ||
}); | ||
}, | ||
function(p, cb) { | ||
self.connection.db.collection('revisionists', function(err, revisionistCollection) { | ||
p.revisionistModel = revisionistCollection; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
p.revisionistModel.find({ | ||
referenceId: p.composite._id | ||
}) | ||
.toArray(function(err, revisions) { | ||
p.revisions = revisions; | ||
cb(err, p); | ||
}); | ||
} | ||
], function(err, p) { | ||
if (err) return done(err); | ||
should(p.revisions) | ||
.be.ok(); | ||
should(p.revisions[0]) | ||
.be.ok(); | ||
p.revisions.length.should.equal(1); | ||
p.revisions[0].revision.should.equal(1); | ||
p.revisions[0].op.should.equal('i'); | ||
done(); | ||
composite.save(function(err, composite) { | ||
cb(err, { | ||
composite: composite | ||
}); | ||
}); | ||
}, | ||
function(p, cb) { | ||
self.connection.db.collection('revisionists', function(err, revisionistCollection) { | ||
p.revisionistModel = revisionistCollection; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
p.revisionistModel.find({ | ||
referenceId: p.composite._id | ||
}) | ||
.toArray(function(err, revisions) { | ||
p.revisions = revisions; | ||
cb(err, p); | ||
}); | ||
} | ||
], function(err, p) { | ||
if (err) return done(err); | ||
should(p.revisions) | ||
.be.ok(); | ||
should(p.revisions[0]) | ||
.be.ok(); | ||
p.revisions.length.should.equal(1); | ||
p.revisions[0].revision.should.equal(1); | ||
p.revisions[0].op.should.equal('i'); | ||
done(); | ||
}); | ||
}); | ||
it('updates', function(done) { | ||
var self = this; | ||
async.waterfall([ | ||
it('updates', function(done) { | ||
var self = this; | ||
async.waterfall([ | ||
function(cb) { | ||
var composite = new self.Composite({ | ||
name: 'stuff', | ||
telephone: '999-999-9999', | ||
createdBy: 'test', | ||
someCompositeThing: { | ||
compositeMemberOne: 'one', | ||
compositeMemberTwo: 'two' | ||
}, | ||
}); | ||
function(cb) { | ||
var composite = new self.Composite({ | ||
name: 'stuff', | ||
telephone: '999-999-9999', | ||
createdBy: 'test', | ||
someCompositeThing: { | ||
compositeMemberOne: 'one', | ||
compositeMemberTwo: 'two' | ||
}, | ||
}); | ||
composite.save(function(err, composite) { | ||
cb(err, { | ||
composite: composite | ||
}); | ||
}); | ||
}, | ||
function(p, cb) { | ||
p.composite.someCompositeThing.compositeMemberOne = 'three'; | ||
p.composite.modifiedBy = 'test'; | ||
p.composite.save(function(err, composite) { | ||
p.composite = composite; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
self.connection.db.collection('revisionists', function(err, revisionistCollection) { | ||
p.revisionistModel = revisionistCollection; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
p.revisionistModel.find({ | ||
referenceId: p.composite._id | ||
}) | ||
.toArray(function(err, revisions) { | ||
p.revisions = revisions; | ||
cb(err, p); | ||
}); | ||
} | ||
], function(err, p) { | ||
if (err) return done(err); | ||
should(p.revisions) | ||
.be.ok(); | ||
should(p.revisions[1]) | ||
.be.ok(); | ||
p.revisions.length.should.equal(2); | ||
p.revisions[1].revision.should.equal(2); | ||
p.revisions[1].op.should.equal('u'); | ||
p.revisions[1].o['_$set'].someCompositeThing.compositeMemberOne.should.equal('three'); | ||
done(); | ||
composite.save(function(err, composite) { | ||
cb(err, { | ||
composite: composite | ||
}); | ||
}); | ||
}, | ||
function(p, cb) { | ||
p.composite.someCompositeThing.compositeMemberOne = 'three'; | ||
p.composite.modifiedBy = 'test'; | ||
p.composite.save(function(err, composite) { | ||
p.composite = composite; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
self.connection.db.collection('revisionists', function(err, revisionistCollection) { | ||
p.revisionistModel = revisionistCollection; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
p.revisionistModel.find({ | ||
referenceId: p.composite._id | ||
}) | ||
.toArray(function(err, revisions) { | ||
p.revisions = revisions; | ||
cb(err, p); | ||
}); | ||
} | ||
], function(err, p) { | ||
if (err) return done(err); | ||
should(p.revisions) | ||
.be.ok(); | ||
should(p.revisions[1]) | ||
.be.ok(); | ||
p.revisions.length.should.equal(2); | ||
p.revisions[1].revision.should.equal(2); | ||
p.revisions[1].op.should.equal('u'); | ||
p.revisions[1].o['_$set'].someCompositeThing.compositeMemberOne.should.equal('three'); | ||
done(); | ||
}); | ||
}); | ||
it('updates with unset', function(done) { | ||
var self = this; | ||
async.waterfall([ | ||
it('updates with unset', function(done) { | ||
var self = this; | ||
async.waterfall([ | ||
function(cb) { | ||
var composite = new self.Composite({ | ||
name: 'stuff', | ||
telephone: '999-999-9999', | ||
createdBy: 'test', | ||
someCompositeThing: { | ||
compositeMemberOne: 'one', | ||
compositeMemberTwo: 'two' | ||
}, | ||
}); | ||
function(cb) { | ||
var composite = new self.Composite({ | ||
name: 'stuff', | ||
telephone: '999-999-9999', | ||
createdBy: 'test', | ||
someCompositeThing: { | ||
compositeMemberOne: 'one', | ||
compositeMemberTwo: 'two' | ||
}, | ||
}); | ||
composite.save(function(err, composite) { | ||
cb(err, { | ||
composite: composite | ||
}); | ||
}); | ||
}, | ||
function(p, cb) { | ||
//note: for mongo to pick up a $unset from mongoose, | ||
//note: the member must be explicitly set to undefined. | ||
//note: setting the member to null will save as null, | ||
//note: deleting the member will cause the member to be ignored. | ||
p.composite.someCompositeThing.compositeMemberTwo = undefined; | ||
p.composite.modifiedBy = 'test'; | ||
p.composite.save(function(err, composite) { | ||
p.composite = composite; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
self.connection.db.collection('revisionists', function(err, revisionistCollection) { | ||
p.revisionistModel = revisionistCollection; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
p.revisionistModel.find({ | ||
referenceId: p.composite._id | ||
}) | ||
.toArray(function(err, revisions) { | ||
p.revisions = revisions; | ||
cb(err, p); | ||
}); | ||
} | ||
], function(err, p) { | ||
if (err) return done(err); | ||
should(p.revisions) | ||
.be.ok(); | ||
should(p.revisions[1]) | ||
.be.ok(); | ||
should(p.revisions[1].o) | ||
.be.ok(); | ||
should(p.revisions[1].o['_$unset']) | ||
.be.ok(); | ||
should(p.revisions[1].o['_$unset'].someCompositeThing) | ||
.be.ok(); | ||
should(p.revisions[1].o['_$unset'].someCompositeThing.compositeMemberTwo) | ||
.be.ok(); | ||
p.revisions[1].op.should.equal('u'); | ||
done(); | ||
composite.save(function(err, composite) { | ||
cb(err, { | ||
composite: composite | ||
}); | ||
}); | ||
}, | ||
function(p, cb) { | ||
//note: for mongo to pick up a $unset from mongoose, | ||
//note: the member must be explicitly set to undefined. | ||
//note: setting the member to null will save as null, | ||
//note: deleting the member will cause the member to be ignored. | ||
p.composite.someCompositeThing.compositeMemberTwo = undefined; | ||
p.composite.modifiedBy = 'test'; | ||
p.composite.save(function(err, composite) { | ||
p.composite = composite; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
self.connection.db.collection('revisionists', function(err, revisionistCollection) { | ||
p.revisionistModel = revisionistCollection; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
p.revisionistModel.find({ | ||
referenceId: p.composite._id | ||
}) | ||
.toArray(function(err, revisions) { | ||
p.revisions = revisions; | ||
cb(err, p); | ||
}); | ||
} | ||
], function(err, p) { | ||
if (err) return done(err); | ||
should(p.revisions) | ||
.be.ok(); | ||
should(p.revisions[1]) | ||
.be.ok(); | ||
should(p.revisions[1].o) | ||
.be.ok(); | ||
should(p.revisions[1].o['_$unset']) | ||
.be.ok(); | ||
should(p.revisions[1].o['_$unset'].someCompositeThing) | ||
.be.ok(); | ||
should(p.revisions[1].o['_$unset'].someCompositeThing.compositeMemberTwo) | ||
.be.ok(); | ||
p.revisions[1].op.should.equal('u'); | ||
done(); | ||
}); | ||
}); | ||
it('removes', function(done) { | ||
var self = this; | ||
async.waterfall([ | ||
it('removes', function(done) { | ||
var self = this; | ||
async.waterfall([ | ||
function(cb) { | ||
var composite = new self.Composite({ | ||
name: 'stuff', | ||
telephone: '999-999-9999', | ||
createdBy: 'test', | ||
someCompositeThing: { | ||
compositeMemberOne: 'one', | ||
compositeMemberTwo: 'two' | ||
}, | ||
}); | ||
function(cb) { | ||
var composite = new self.Composite({ | ||
name: 'stuff', | ||
telephone: '999-999-9999', | ||
createdBy: 'test', | ||
someCompositeThing: { | ||
compositeMemberOne: 'one', | ||
compositeMemberTwo: 'two' | ||
}, | ||
}); | ||
composite.save(function(err, composite) { | ||
cb(err, { | ||
composite: composite | ||
}); | ||
}); | ||
}, | ||
function(p, cb) { | ||
p.composite.modifiedBy = 'remove test'; | ||
p.composite.remove(function(err) { | ||
cb(err, p) | ||
}); | ||
}, | ||
function(p, cb) { | ||
self.connection.db.collection('revisionists', function(err, revisionistCollection) { | ||
p.revisionistModel = revisionistCollection; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
p.revisionistModel.find({ | ||
referenceId: p.composite._id | ||
}) | ||
.toArray(function(err, revisions) { | ||
p.revisions = revisions; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
self.Composite.getVersion(p.composite._id, function(err, version) { | ||
p.v1_byId = version; | ||
cb(err, p); | ||
}); | ||
} | ||
], function(err, p) { | ||
if (err) return done(err); | ||
should(p.revisions) | ||
.be.ok(); | ||
should(p.revisions[1]) | ||
.be.ok(); | ||
should(p.revisions[2]) | ||
.be.ok(); | ||
should(p.v1_byId) | ||
.be.ok(); | ||
p.revisions.length.should.equal(3); | ||
p.revisions[1].revision.should.equal(2); | ||
p.revisions[2].op.should.equal('d'); | ||
p.v1_byId.modifiedBy.should.equal('remove test'); | ||
done(); | ||
composite.save(function(err, composite) { | ||
cb(err, { | ||
composite: composite | ||
}); | ||
}); | ||
}, | ||
function(p, cb) { | ||
p.composite.remove(function(err) { | ||
cb(err, p) | ||
}); | ||
}, | ||
function(p, cb) { | ||
self.connection.db.collection('revisionists', function(err, revisionistCollection) { | ||
p.revisionistModel = revisionistCollection; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
p.revisionistModel.find({ | ||
referenceId: p.composite._id | ||
}) | ||
.toArray(function(err, revisions) { | ||
p.revisions = revisions; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
self.Composite.getVersion(p.composite._id, function(err, version) { | ||
p.v1_byId = version; | ||
cb(err, p); | ||
}); | ||
} | ||
], function(err, p) { | ||
if (err) return done(err); | ||
should(p.revisions) | ||
.be.ok(); | ||
should(p.revisions[1]) | ||
.be.ok(); | ||
should(p.revisions[2]) | ||
.be.ok(); | ||
should(p.v1_byId) | ||
.be.ok(); | ||
p.revisions.length.should.equal(3); | ||
p.revisions[1].revision.should.equal(2); | ||
p.revisions[2].op.should.equal('d'); | ||
done(); | ||
}); | ||
}); | ||
}); |
var mongoose = require('mongoose'), | ||
util = require('util'), | ||
async = require('async'), | ||
_ = require('lodash'), | ||
should = require('should'), | ||
logger = require('winston'), | ||
testUtil = require('../util'); | ||
util = require('util'), | ||
async = require('async'), | ||
_ = require('lodash'), | ||
should = require('should'), | ||
logger = require('winston'), | ||
testUtil = require('../util'); | ||
describe('composite with array', function() { | ||
it('creates', function(done) { | ||
var self = this; | ||
async.waterfall([ | ||
it('creates', function(done) { | ||
var self = this; | ||
async.waterfall([ | ||
function(cb) { | ||
var composite = new self.CompositeWithArray({ | ||
name: 'stuff', | ||
telephone: '999-999-9999', | ||
compositeArray: [{ | ||
arrayMemberOne: 'one', | ||
arrayMemberTwo: 'two' | ||
}], | ||
createdBy: 'test' | ||
}); | ||
function(cb) { | ||
var composite = new self.CompositeWithArray({ | ||
name: 'stuff', | ||
telephone: '999-999-9999', | ||
compositeArray: [{ | ||
arrayMemberOne: 'one', | ||
arrayMemberTwo: 'two' | ||
}], | ||
createdBy: 'test' | ||
}); | ||
composite.save(function(err, composite) { | ||
cb(err, { | ||
composite: composite | ||
}); | ||
}); | ||
}, | ||
function(p, cb) { | ||
self.connection.db.collection('revisionists', function(err, revisionistCollection) { | ||
p.revisionistModel = revisionistCollection; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
p.revisionistModel.find({ | ||
referenceId: p.composite._id | ||
}) | ||
.toArray(function(err, revisions) { | ||
p.revisions = revisions; | ||
cb(err, p); | ||
}); | ||
} | ||
], function(err, p) { | ||
if (err) return done(err); | ||
should(p.revisions) | ||
.be.ok(); | ||
should(p.revisions[0]) | ||
.be.ok(); | ||
p.revisions.length.should.equal(1); | ||
p.revisions[0].revision.should.equal(1); | ||
p.revisions[0].op.should.equal('i'); | ||
done(); | ||
composite.save(function(err, composite) { | ||
cb(err, { | ||
composite: composite | ||
}); | ||
}); | ||
}, | ||
function(p, cb) { | ||
self.connection.db.collection('revisionists', function(err, revisionistCollection) { | ||
p.revisionistModel = revisionistCollection; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
p.revisionistModel.find({ | ||
referenceId: p.composite._id | ||
}) | ||
.toArray(function(err, revisions) { | ||
p.revisions = revisions; | ||
cb(err, p); | ||
}); | ||
} | ||
], function(err, p) { | ||
if (err) return done(err); | ||
should(p.revisions) | ||
.be.ok(); | ||
should(p.revisions[0]) | ||
.be.ok(); | ||
p.revisions.length.should.equal(1); | ||
p.revisions[0].revision.should.equal(1); | ||
p.revisions[0].op.should.equal('i'); | ||
done(); | ||
}); | ||
}); | ||
it('updates', function(done) { | ||
var self = this; | ||
async.waterfall([ | ||
it('updates', function(done) { | ||
var self = this; | ||
async.waterfall([ | ||
function(cb) { | ||
var composite = new self.CompositeWithArray({ | ||
name: 'stuff', | ||
telephone: '999-999-9999', | ||
createdBy: 'test', | ||
compositeArray: [{ | ||
arrayMemberOne: 'one', | ||
arrayMemberTwo: 'two' | ||
}], | ||
}); | ||
function(cb) { | ||
var composite = new self.CompositeWithArray({ | ||
name: 'stuff', | ||
telephone: '999-999-9999', | ||
createdBy: 'test', | ||
compositeArray: [{ | ||
arrayMemberOne: 'one', | ||
arrayMemberTwo: 'two' | ||
}], | ||
}); | ||
composite.save(function(err, composite) { | ||
cb(err, { | ||
composite: composite | ||
}); | ||
}); | ||
}, | ||
function(p, cb) { | ||
p.composite.compositeArray[0].arrayMemberOne = 'three'; | ||
p.composite.modifiedBy = 'test'; | ||
p.composite.save(function(err, composite) { | ||
p.composite = composite; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
self.connection.db.collection('revisionists', function(err, revisionistCollection) { | ||
p.revisionistModel = revisionistCollection; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
p.revisionistModel.find({ | ||
referenceId: p.composite._id | ||
}) | ||
.toArray(function(err, revisions) { | ||
p.revisions = revisions; | ||
cb(err, p); | ||
}); | ||
} | ||
], function(err, p) { | ||
composite.save(function(err, composite) { | ||
cb(err, { | ||
composite: composite | ||
}); | ||
}); | ||
}, | ||
function(p, cb) { | ||
p.composite.compositeArray[0].arrayMemberOne = 'three'; | ||
p.composite.modifiedBy = 'test'; | ||
p.composite.save(function(err, composite) { | ||
p.composite = composite; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
self.connection.db.collection('revisionists', function(err, revisionistCollection) { | ||
p.revisionistModel = revisionistCollection; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
p.revisionistModel.find({ | ||
referenceId: p.composite._id | ||
}) | ||
.toArray(function(err, revisions) { | ||
p.revisions = revisions; | ||
cb(err, p); | ||
}); | ||
} | ||
], function(err, p) { | ||
if (err) return done(err); | ||
should(p.revisions) | ||
.be.ok(); | ||
should(p.revisions[1]) | ||
.be.ok(); | ||
p.revisions.length.should.equal(2); | ||
p.revisions[1].revision.should.equal(2); | ||
p.revisions[1].op.should.equal('u'); | ||
p.revisions[1].o['_$set'].compositeArray[0].arrayMemberOne.should.equal('three'); | ||
done(); | ||
}); | ||
if (err) return done(err); | ||
should(p.revisions) | ||
.be.ok(); | ||
should(p.revisions[1]) | ||
.be.ok(); | ||
p.revisions.length.should.equal(2); | ||
p.revisions[1].revision.should.equal(2); | ||
p.revisions[1].op.should.equal('u'); | ||
p.revisions[1].o['_$set'].compositeArray[0].arrayMemberOne.should.equal('three'); | ||
done(); | ||
}); | ||
}); | ||
it('updates with unset', function(done) { | ||
var self = this; | ||
async.waterfall([ | ||
it('updates with unset', function(done) { | ||
var self = this; | ||
async.waterfall([ | ||
function(cb) { | ||
var composite = new self.CompositeWithArray({ | ||
name: 'stuff', | ||
telephone: '999-999-9999', | ||
createdBy: 'test', | ||
compositeArray: [{ | ||
arrayMemberOne: 'one', | ||
arrayMemberTwo: 'two' | ||
}], | ||
}); | ||
function(cb) { | ||
var composite = new self.CompositeWithArray({ | ||
name: 'stuff', | ||
telephone: '999-999-9999', | ||
createdBy: 'test', | ||
compositeArray: [{ | ||
arrayMemberOne: 'one', | ||
arrayMemberTwo: 'two' | ||
}], | ||
}); | ||
composite.save(function(err, composite) { | ||
cb(err, { | ||
composite: composite | ||
}); | ||
}); | ||
}, | ||
function(p, cb) { | ||
//note: for mongo to pick up a $unset from mongoose, | ||
//note: the member must be explicitly set to undefined. | ||
//note: setting the member to null will save as null, | ||
//note: deleting the member will cause the member to be ignored. | ||
p.composite.compositeArray[0].arrayMemberTwo = undefined; | ||
p.composite.save(function(err, composite) { | ||
p.composite = composite; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
self.connection.db.collection('revisionists', function(err, revisionistCollection) { | ||
p.revisionistModel = revisionistCollection; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
p.revisionistModel.find({ | ||
referenceId: p.composite._id | ||
}) | ||
.toArray(function(err, revisions) { | ||
p.revisions = revisions; | ||
cb(err, p); | ||
}); | ||
} | ||
], function(err, p) { | ||
if (err) return done(err); | ||
should(p.revisions) | ||
.be.ok(); | ||
should(p.revisions[1]) | ||
.be.ok(); | ||
should(p.revisions[1].o) | ||
.be.ok(); | ||
should(p.revisions[1].o['_$unset']) | ||
.be.ok(); | ||
should(p.revisions[1].o['_$unset'].compositeArray) | ||
.be.ok(); | ||
should(p.revisions[1].o['_$unset'].compositeArray[0].arrayMemberTwo) | ||
.be.ok(); | ||
p.revisions[1].op.should.equal('u'); | ||
done(); | ||
composite.save(function(err, composite) { | ||
cb(err, { | ||
composite: composite | ||
}); | ||
}); | ||
}, | ||
function(p, cb) { | ||
//note: for mongo to pick up a $unset from mongoose, | ||
//note: the member must be explicitly set to undefined. | ||
//note: setting the member to null will save as null, | ||
//note: deleting the member will cause the member to be ignored. | ||
p.composite.compositeArray[0].arrayMemberTwo = undefined; | ||
p.composite.save(function(err, composite) { | ||
p.composite = composite; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
self.connection.db.collection('revisionists', function(err, revisionistCollection) { | ||
p.revisionistModel = revisionistCollection; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
p.revisionistModel.find({ | ||
referenceId: p.composite._id | ||
}) | ||
.toArray(function(err, revisions) { | ||
p.revisions = revisions; | ||
cb(err, p); | ||
}); | ||
} | ||
], function(err, p) { | ||
if (err) return done(err); | ||
should(p.revisions) | ||
.be.ok(); | ||
should(p.revisions[1]) | ||
.be.ok(); | ||
should(p.revisions[1].o) | ||
.be.ok(); | ||
should(p.revisions[1].o['_$unset']) | ||
.be.ok(); | ||
should(p.revisions[1].o['_$unset'].compositeArray) | ||
.be.ok(); | ||
should(p.revisions[1].o['_$unset'].compositeArray[0].arrayMemberTwo) | ||
.be.ok(); | ||
p.revisions[1].op.should.equal('u'); | ||
done(); | ||
}); | ||
}); | ||
it('removes', function(done) { | ||
var self = this; | ||
async.waterfall([ | ||
it('removes', function(done) { | ||
var self = this; | ||
async.waterfall([ | ||
function(cb) { | ||
var composite = new self.CompositeWithArray({ | ||
name: 'stuff', | ||
telephone: '999-999-9999', | ||
createdBy: 'test', | ||
compositeArray: { | ||
arrayMemberOne: 'one', | ||
arrayMemberTwo: 'two' | ||
}, | ||
}); | ||
function(cb) { | ||
var composite = new self.CompositeWithArray({ | ||
name: 'stuff', | ||
telephone: '999-999-9999', | ||
createdBy: 'test', | ||
compositeArray: { | ||
arrayMemberOne: 'one', | ||
arrayMemberTwo: 'two' | ||
}, | ||
}); | ||
composite.save(function(err, composite) { | ||
cb(err, { | ||
composite: composite | ||
}); | ||
}); | ||
}, | ||
function(p, cb) { | ||
p.composite.modifiedBy = 'remove test'; | ||
p.composite.remove(function(err) { | ||
cb(err, p) | ||
}); | ||
}, | ||
function(p, cb) { | ||
self.connection.db.collection('revisionists', function(err, revisionistCollection) { | ||
p.revisionistModel = revisionistCollection; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
p.revisionistModel.find({ | ||
referenceId: p.composite._id | ||
}) | ||
.toArray(function(err, revisions) { | ||
p.revisions = revisions; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
self.CompositeWithArray.getVersion(p.composite._id, function(err, version) { | ||
p.v1_byId = version; | ||
cb(err, p); | ||
}); | ||
} | ||
], function(err, p) { | ||
if (err) return done(err); | ||
should(p.revisions) | ||
.be.ok(); | ||
should(p.revisions[1]) | ||
.be.ok(); | ||
should(p.revisions[2]) | ||
.be.ok(); | ||
should(p.v1_byId) | ||
.be.ok(); | ||
composite.save(function(err, composite) { | ||
cb(err, { | ||
composite: composite | ||
}); | ||
}); | ||
}, | ||
function(p, cb) { | ||
p.composite.remove(function(err) { | ||
cb(err, p) | ||
}); | ||
}, | ||
function(p, cb) { | ||
self.connection.db.collection('revisionists', function(err, revisionistCollection) { | ||
p.revisionistModel = revisionistCollection; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
p.revisionistModel.find({ | ||
referenceId: p.composite._id | ||
}) | ||
.toArray(function(err, revisions) { | ||
p.revisions = revisions; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
self.CompositeWithArray.getVersion(p.composite._id, function(err, version) { | ||
p.v1_byId = version; | ||
cb(err, p); | ||
}); | ||
} | ||
], function(err, p) { | ||
if (err) return done(err); | ||
should(p.revisions) | ||
.be.ok(); | ||
should(p.revisions[1]) | ||
.be.ok(); | ||
should(p.revisions[2]) | ||
.be.ok(); | ||
should(p.v1_byId) | ||
.be.ok(); | ||
p.revisions.length.should.equal(3); | ||
p.revisions[1].revision.should.equal(2); | ||
p.revisions[2].op.should.equal('d'); | ||
p.v1_byId.modifiedBy.should.equal('remove test'); | ||
done(); | ||
}); | ||
p.revisions.length.should.equal(3); | ||
p.revisions[1].revision.should.equal(2); | ||
p.revisions[2].op.should.equal('d'); | ||
done(); | ||
}); | ||
}); | ||
}); |
@@ -1,6 +0,7 @@ | ||
module.exports = exports = { | ||
"composite": require("./composite"), | ||
"compositeWithArray": require("./compositeWithArray"), | ||
"reference": require("./reference"), | ||
"simple": require("./simple"), | ||
}; | ||
require('../util'); | ||
describe('types', function(){ | ||
require("./composite"); | ||
require("./compositeWithArray"); | ||
require("./reference"); | ||
require("./simple"); | ||
}); |
var mongoose = require('mongoose'), | ||
util = require('util'), | ||
async = require('async'), | ||
_ = require('lodash'), | ||
should = require('should'), | ||
logger = require('winston'), | ||
testUtil = require('../util'); | ||
util = require('util'), | ||
async = require('async'), | ||
_ = require('lodash'), | ||
should = require('should'), | ||
logger = require('winston'), | ||
testUtil = require('../util'); | ||
describe('reference', function() { | ||
it('creates', function(done) { | ||
var self = this; | ||
async.waterfall([ | ||
it('creates', function(done) { | ||
var self = this; | ||
async.waterfall([ | ||
function(cb) { | ||
var simple = new self.Simple({ | ||
name: 'stuff', | ||
telephone: '999-999-9999', | ||
createdBy: 'test' | ||
}); | ||
function(cb) { | ||
var simple = new self.Simple({ | ||
name: 'stuff', | ||
telephone: '999-999-9999', | ||
createdBy: 'test' | ||
}); | ||
simple.save(function(err, simple) { | ||
cb(err, { | ||
simple: simple | ||
}); | ||
}); | ||
}, | ||
function(p, cb) { | ||
var composite = new self.Composite({ | ||
name: 'stuff', | ||
telephone: '999-999-9999', | ||
someCompositeThing: { | ||
compositeMemberOne: 'one', | ||
compositeMemberTwo: 'two' | ||
}, | ||
createdBy: 'test' | ||
}); | ||
simple.save(function(err, simple) { | ||
cb(err, { | ||
simple: simple | ||
}); | ||
}); | ||
}, | ||
function(p, cb) { | ||
var composite = new self.Composite({ | ||
name: 'stuff', | ||
telephone: '999-999-9999', | ||
someCompositeThing: { | ||
compositeMemberOne: 'one', | ||
compositeMemberTwo: 'two' | ||
}, | ||
createdBy: 'test' | ||
}); | ||
composite.save(function(err, composite) { | ||
p.composite = composite; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
var compositeWithArray = new self.CompositeWithArray({ | ||
name: 'stuff', | ||
telephone: '999-999-9999', | ||
compositeArray: [{ | ||
arrayMemberOne: 'one', | ||
arrayMemberTwo: 'two' | ||
}], | ||
createdBy: 'test' | ||
}); | ||
composite.save(function(err, composite) { | ||
p.composite = composite; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
var compositeWithArray = new self.CompositeWithArray({ | ||
name: 'stuff', | ||
telephone: '999-999-9999', | ||
compositeArray: [{ | ||
arrayMemberOne: 'one', | ||
arrayMemberTwo: 'two' | ||
}], | ||
createdBy: 'test' | ||
}); | ||
compositeWithArray.save(function(err, compositeWithArray) { | ||
p.compositeWithArray = compositeWithArray; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
var reference = new self.Reference({ | ||
name: 'stuff', | ||
telephone: '999-999-9999', | ||
createdBy: 'test', | ||
simple: p.simple, | ||
composite: p.composite, | ||
compositeArray: p.compositeWithArray | ||
}); | ||
compositeWithArray.save(function(err, compositeWithArray) { | ||
p.compositeWithArray = compositeWithArray; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
var reference = new self.Reference({ | ||
name: 'stuff', | ||
telephone: '999-999-9999', | ||
createdBy: 'test', | ||
simple: p.simple, | ||
composite: p.composite, | ||
compositeArray: p.compositeWithArray | ||
}); | ||
reference.save(function(err, reference) { | ||
p.reference = reference; | ||
cb(err, p); | ||
}); | ||
}, | ||
reference.save(function(err, reference) { | ||
p.reference = reference; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
self.connection.db.collection('revisionists', function(err, revisionistCollection) { | ||
p.revisionistModel = revisionistCollection; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
p.revisionistModel.find({ | ||
referenceId: p.reference._id | ||
}) | ||
.toArray(function(err, revisions) { | ||
p.revisions = revisions; | ||
cb(err, p); | ||
}); | ||
} | ||
], function(err, p) { | ||
if (err) return done(err); | ||
should(p.revisions) | ||
.be.ok(); | ||
should(p.revisions[0]) | ||
.be.ok(); | ||
p.revisions.length.should.equal(1); | ||
p.revisions[0].revision.should.equal(1); | ||
p.revisions[0].op.should.equal('i'); | ||
done(); | ||
function(p, cb) { | ||
self.connection.db.collection('revisionists', function(err, revisionistCollection) { | ||
p.revisionistModel = revisionistCollection; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
p.revisionistModel.find({ | ||
referenceId: p.reference._id | ||
}) | ||
.toArray(function(err, revisions) { | ||
p.revisions = revisions; | ||
cb(err, p); | ||
}); | ||
} | ||
], function(err, p) { | ||
if (err) return done(err); | ||
should(p.revisions) | ||
.be.ok(); | ||
should(p.revisions[0]) | ||
.be.ok(); | ||
p.revisions.length.should.equal(1); | ||
p.revisions[0].revision.should.equal(1); | ||
p.revisions[0].op.should.equal('i'); | ||
done(); | ||
}); | ||
}); | ||
it('updates', function(done) { | ||
var self = this; | ||
async.waterfall([ | ||
it('updates', function(done) { | ||
var self = this; | ||
async.waterfall([ | ||
function(cb) { | ||
var simple = new self.Simple({ | ||
name: 'stuff', | ||
telephone: '999-999-9999', | ||
createdBy: 'test' | ||
}); | ||
function(cb) { | ||
var simple = new self.Simple({ | ||
name: 'stuff', | ||
telephone: '999-999-9999', | ||
createdBy: 'test' | ||
}); | ||
simple.save(function(err, simple) { | ||
cb(err, { | ||
simple: simple | ||
}); | ||
}); | ||
}, | ||
function(p, cb) { | ||
var composite = new self.Composite({ | ||
name: 'stuff', | ||
telephone: '999-999-9999', | ||
someCompositeThing: { | ||
compositeMemberOne: 'one', | ||
compositeMemberTwo: 'two' | ||
}, | ||
createdBy: 'test' | ||
}); | ||
simple.save(function(err, simple) { | ||
cb(err, { | ||
simple: simple | ||
}); | ||
}); | ||
}, | ||
function(p, cb) { | ||
var composite = new self.Composite({ | ||
name: 'stuff', | ||
telephone: '999-999-9999', | ||
someCompositeThing: { | ||
compositeMemberOne: 'one', | ||
compositeMemberTwo: 'two' | ||
}, | ||
createdBy: 'test' | ||
}); | ||
composite.save(function(err, composite) { | ||
p.composite = composite; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
var compositeWithArray = new self.CompositeWithArray({ | ||
name: 'stuff', | ||
telephone: '999-999-9999', | ||
compositeArray: [{ | ||
arrayMemberOne: 'one', | ||
arrayMemberTwo: 'two' | ||
}], | ||
createdBy: 'test' | ||
}); | ||
composite.save(function(err, composite) { | ||
p.composite = composite; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
var compositeWithArray = new self.CompositeWithArray({ | ||
name: 'stuff', | ||
telephone: '999-999-9999', | ||
compositeArray: [{ | ||
arrayMemberOne: 'one', | ||
arrayMemberTwo: 'two' | ||
}], | ||
createdBy: 'test' | ||
}); | ||
compositeWithArray.save(function(err, compositeWithArray) { | ||
p.compositeWithArray = compositeWithArray; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
var reference = new self.Reference({ | ||
name: 'stuff', | ||
telephone: '999-999-9999', | ||
createdBy: 'test', | ||
simple: p.simple, | ||
composite: p.composite, | ||
compositeArray: p.compositeWithArray | ||
}); | ||
compositeWithArray.save(function(err, compositeWithArray) { | ||
p.compositeWithArray = compositeWithArray; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
var reference = new self.Reference({ | ||
name: 'stuff', | ||
telephone: '999-999-9999', | ||
createdBy: 'test', | ||
simple: p.simple, | ||
composite: p.composite, | ||
compositeArray: p.compositeWithArray | ||
}); | ||
reference.save(function(err, reference) { | ||
p.reference = reference; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
var simple = new self.Simple({ | ||
name: 'stuff', | ||
telephone: '999-999-9999', | ||
createdBy: 'test' | ||
}); | ||
reference.save(function(err, reference) { | ||
p.reference = reference; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
var simple = new self.Simple({ | ||
name: 'stuff', | ||
telephone: '999-999-9999', | ||
createdBy: 'test' | ||
}); | ||
simple.save(function(err, simple) { | ||
p.simple2 = simple; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
p.reference.simple = p.simple2; | ||
p.reference.save(function(err, reference) { | ||
p.reference = reference; | ||
cb(err, p); | ||
}); | ||
}, | ||
simple.save(function(err, simple) { | ||
p.simple2 = simple; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
p.reference.simple = p.simple2; | ||
p.reference.save(function(err, reference) { | ||
p.reference = reference; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
self.connection.db.collection('revisionists', function(err, revisionistCollection) { | ||
p.revisionistModel = revisionistCollection; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
p.revisionistModel.find({ | ||
referenceId: p.reference._id | ||
}) | ||
.toArray(function(err, revisions) { | ||
p.revisions = revisions; | ||
cb(err, p); | ||
}); | ||
} | ||
], function(err, p) { | ||
if (err) return done(err); | ||
should(p.revisions) | ||
.be.ok(); | ||
should(p.revisions[1]) | ||
.be.ok(); | ||
p.revisions.length.should.equal(2); | ||
p.revisions[1].revision.should.equal(2); | ||
p.revisions[1].op.should.equal('u'); | ||
done(); | ||
function(p, cb) { | ||
self.connection.db.collection('revisionists', function(err, revisionistCollection) { | ||
p.revisionistModel = revisionistCollection; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
p.revisionistModel.find({ | ||
referenceId: p.reference._id | ||
}) | ||
.toArray(function(err, revisions) { | ||
p.revisions = revisions; | ||
cb(err, p); | ||
}); | ||
} | ||
], function(err, p) { | ||
if (err) return done(err); | ||
should(p.revisions) | ||
.be.ok(); | ||
should(p.revisions[1]) | ||
.be.ok(); | ||
p.revisions.length.should.equal(2); | ||
p.revisions[1].revision.should.equal(2); | ||
p.revisions[1].op.should.equal('u'); | ||
done(); | ||
}); | ||
}); | ||
it('updates with unset'); | ||
it('removes'); | ||
it('updates with unset', function(done) { | ||
var self = this; | ||
async.waterfall([ | ||
function(cb) { | ||
testUtil.shorthand.reference(self, cb); | ||
}, | ||
function(p, cb) { | ||
//note: for mongo to pick up a $unset from mongoose, | ||
//note: the member must be explicitly set to undefined. | ||
//note: setting the member to null will save as null, | ||
//note: deleting the member will cause the member to be ignored. | ||
p.reference.composite = undefined; | ||
p.reference.save(function(err, reference) { | ||
p.reference = reference; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
self.connection.db.collection('revisionists', function(err, revisionistCollection) { | ||
p.revisionistModel = revisionistCollection; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
p.revisionistModel.find({ | ||
referenceId: p.reference._id | ||
}) | ||
.toArray(function(err, revisions) { | ||
p.revisions = revisions; | ||
cb(err, p); | ||
}); | ||
} | ||
], function(err, p) { | ||
if (err) return done(err); | ||
should(p.revisions) | ||
.be.ok(); | ||
should(p.revisions[3]) | ||
.be.ok(); | ||
should(p.revisions[3].o) | ||
.be.ok(); | ||
should(p.revisions[3].o['_$unset']) | ||
.be.ok(); | ||
should(p.revisions[3].o['_$unset'].composite) | ||
.be.ok(); | ||
p.revisions[3].op.should.equal('u'); | ||
done(); | ||
}); | ||
}); | ||
it('removes', function(done) { | ||
var self = this; | ||
async.waterfall([ | ||
function(cb) { | ||
testUtil.shorthand.reference(self, cb); | ||
}, | ||
function(p, cb) { | ||
p.reference.remove(function(err) { | ||
cb(err, p) | ||
}); | ||
}, | ||
function(p, cb) { | ||
self.connection.db.collection('revisionists', function(err, revisionistCollection) { | ||
p.revisionistModel = revisionistCollection; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
p.revisionistModel.find({ | ||
referenceId: p.reference._id | ||
}) | ||
.toArray(function(err, revisions) { | ||
p.revisions = revisions; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
self.Simple.getVersion(p.simple._id, function(err, version) { | ||
p.v1_byId = version; | ||
cb(err, p); | ||
}); | ||
} | ||
], function(err, p) { | ||
if (err) return done(err); | ||
should(p.revisions) | ||
.be.ok(); | ||
should(p.revisions[1]) | ||
.be.ok(); | ||
should(p.revisions[2]) | ||
.be.ok(); | ||
should(p.v1_byId) | ||
.be.ok(); | ||
p.revisions.length.should.equal(5); | ||
p.revisions[1].revision.should.equal(2); | ||
p.revisions[4].op.should.equal('d'); | ||
done(); | ||
}); | ||
}); | ||
}); |
var mongoose = require('mongoose'), | ||
util = require('util'), | ||
async = require('async'), | ||
_ = require('lodash'), | ||
should = require('should'), | ||
logger = require('winston'), | ||
testUtil = require('../util'); | ||
util = require('util'), | ||
async = require('async'), | ||
_ = require('lodash'), | ||
should = require('should'), | ||
logger = require('winston'), | ||
testUtil = require('../util'); | ||
describe('simple', function() { | ||
it('creates', function(done) { | ||
var self = this; | ||
async.waterfall([ | ||
it('creates', function(done) { | ||
var self = this; | ||
async.waterfall([ | ||
function(cb) { | ||
var simple = new self.Simple({ | ||
name: 'stuff', | ||
telephone: '999-999-9999', | ||
createdBy: 'test' | ||
}); | ||
function(cb) { | ||
var simple = new self.Simple({ | ||
name: 'stuff', | ||
telephone: '999-999-9999', | ||
createdBy: 'test' | ||
}); | ||
simple.save(function(err, simple) { | ||
cb(err, { | ||
simple: simple | ||
}); | ||
}); | ||
}, | ||
function(p, cb) { | ||
self.connection.db.collection('revisionists', function(err, revisionistCollection) { | ||
p.revisionistModel = revisionistCollection; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
p.revisionistModel.find({ | ||
referenceId: p.simple._id | ||
}) | ||
.toArray(function(err, revisions) { | ||
p.revisions = revisions; | ||
cb(err, p); | ||
}); | ||
} | ||
], function(err, p) { | ||
if (err) return done(err); | ||
should(p.revisions) | ||
.be.ok(); | ||
should(p.revisions[0]) | ||
.be.ok(); | ||
p.revisions.length.should.equal(1); | ||
p.revisions[0].revision.should.equal(1); | ||
p.revisions[0].op.should.equal('i'); | ||
done(); | ||
simple.save(function(err, simple) { | ||
cb(err, { | ||
simple: simple | ||
}); | ||
}); | ||
}, | ||
function(p, cb) { | ||
self.connection.db.collection('revisionists', function(err, revisionistCollection) { | ||
p.revisionistModel = revisionistCollection; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
p.revisionistModel.find({ | ||
referenceId: p.simple._id | ||
}) | ||
.toArray(function(err, revisions) { | ||
p.revisions = revisions; | ||
cb(err, p); | ||
}); | ||
} | ||
], function(err, p) { | ||
if (err) return done(err); | ||
should(p.revisions) | ||
.be.ok(); | ||
should(p.revisions[0]) | ||
.be.ok(); | ||
p.revisions.length.should.equal(1); | ||
p.revisions[0].revision.should.equal(1); | ||
p.revisions[0].op.should.equal('i'); | ||
done(); | ||
}); | ||
}); | ||
it('updates', function(done) { | ||
var self = this; | ||
async.waterfall([ | ||
it('updates', function(done) { | ||
var self = this; | ||
async.waterfall([ | ||
function(cb) { | ||
var simple = new self.Simple({ | ||
name: 'stuff', | ||
telephone: '999-999-9999', | ||
createdBy: 'test' | ||
}); | ||
function(cb) { | ||
var simple = new self.Simple({ | ||
name: 'stuff', | ||
telephone: '999-999-9999', | ||
createdBy: 'test' | ||
}); | ||
simple.save(function(err, simple) { | ||
cb(err, { | ||
simple: simple | ||
}); | ||
}); | ||
}, | ||
function(p, cb) { | ||
p.simple.name = 'more stuff'; | ||
p.simple.modifiedBy = 'test'; | ||
p.simple.save(function(err, simple) { | ||
p.simple = simple; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
self.connection.db.collection('revisionists', function(err, revisionistCollection) { | ||
p.revisionistModel = revisionistCollection; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
p.revisionistModel.find({ | ||
referenceId: p.simple._id | ||
}) | ||
.toArray(function(err, revisions) { | ||
p.revisions = revisions; | ||
cb(err, p); | ||
}); | ||
} | ||
], function(err, p) { | ||
if (err) return done(err); | ||
should(p.revisions) | ||
.be.ok(); | ||
should(p.revisions[1]) | ||
.be.ok(); | ||
p.revisions.length.should.equal(2); | ||
p.revisions[1].revision.should.equal(2); | ||
p.revisions[1].op.should.equal('u'); | ||
p.revisions[1].o['_$set'].name.should.equal('more stuff'); | ||
done(); | ||
simple.save(function(err, simple) { | ||
cb(err, { | ||
simple: simple | ||
}); | ||
}); | ||
}, | ||
function(p, cb) { | ||
p.simple.name = 'more stuff'; | ||
p.simple.modifiedBy = 'test'; | ||
p.simple.save(function(err, simple) { | ||
p.simple = simple; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
self.connection.db.collection('revisionists', function(err, revisionistCollection) { | ||
p.revisionistModel = revisionistCollection; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
p.revisionistModel.find({ | ||
referenceId: p.simple._id | ||
}) | ||
.toArray(function(err, revisions) { | ||
p.revisions = revisions; | ||
cb(err, p); | ||
}); | ||
} | ||
], function(err, p) { | ||
if (err) return done(err); | ||
should(p.revisions) | ||
.be.ok(); | ||
should(p.revisions[1]) | ||
.be.ok(); | ||
p.revisions.length.should.equal(2); | ||
p.revisions[1].revision.should.equal(2); | ||
p.revisions[1].op.should.equal('u'); | ||
p.revisions[1].o['_$set'].name.should.equal('more stuff'); | ||
done(); | ||
}); | ||
}); | ||
it('updates with unset', function(done) { | ||
var self = this; | ||
async.waterfall([ | ||
it('updates with unset', function(done) { | ||
var self = this; | ||
async.waterfall([ | ||
function(cb) { | ||
var simple = new self.Simple({ | ||
name: 'stuff', | ||
telephone: '999-999-9999', | ||
createdBy: 'test' | ||
}); | ||
function(cb) { | ||
var simple = new self.Simple({ | ||
name: 'stuff', | ||
telephone: '999-999-9999', | ||
createdBy: 'test' | ||
}); | ||
simple.save(function(err, simple) { | ||
cb(err, { | ||
simple: simple | ||
}); | ||
}); | ||
}, | ||
function(p, cb) { | ||
//note: for mongo to pick up a $unset from mongoose, | ||
//note: the member must be explicitly set to undefined. | ||
//note: setting the member to null will save as null, | ||
//note: deleting the member will cause the member to be ignored. | ||
p.simple.telephone = undefined; | ||
p.simple.save(function(err, simple) { | ||
p.simple = simple; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
self.connection.db.collection('revisionists', function(err, revisionistCollection) { | ||
p.revisionistModel = revisionistCollection; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
p.revisionistModel.find({ | ||
referenceId: p.simple._id | ||
}) | ||
.toArray(function(err, revisions) { | ||
p.revisions = revisions; | ||
cb(err, p); | ||
}); | ||
} | ||
], function(err, p) { | ||
if (err) return done(err); | ||
should(p.revisions) | ||
.be.ok(); | ||
should(p.revisions[1]) | ||
.be.ok(); | ||
should(p.revisions[1].o) | ||
.be.ok(); | ||
should(p.revisions[1].o['_$unset']) | ||
.be.ok(); | ||
should(p.revisions[1].o['_$unset'].telephone) | ||
.be.ok(); | ||
p.revisions[1].op.should.equal('u'); | ||
done(); | ||
simple.save(function(err, simple) { | ||
cb(err, { | ||
simple: simple | ||
}); | ||
}); | ||
}, | ||
function(p, cb) { | ||
//note: for mongo to pick up a $unset from mongoose, | ||
//note: the member must be explicitly set to undefined. | ||
//note: setting the member to null will save as null, | ||
//note: deleting the member will cause the member to be ignored. | ||
p.simple.telephone = undefined; | ||
p.simple.save(function(err, simple) { | ||
p.simple = simple; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
self.connection.db.collection('revisionists', function(err, revisionistCollection) { | ||
p.revisionistModel = revisionistCollection; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
p.revisionistModel.find({ | ||
referenceId: p.simple._id | ||
}) | ||
.toArray(function(err, revisions) { | ||
p.revisions = revisions; | ||
cb(err, p); | ||
}); | ||
} | ||
], function(err, p) { | ||
if (err) return done(err); | ||
should(p.revisions) | ||
.be.ok(); | ||
should(p.revisions[1]) | ||
.be.ok(); | ||
should(p.revisions[1].o) | ||
.be.ok(); | ||
should(p.revisions[1].o['_$unset']) | ||
.be.ok(); | ||
should(p.revisions[1].o['_$unset'].telephone) | ||
.be.ok(); | ||
p.revisions[1].op.should.equal('u'); | ||
done(); | ||
}); | ||
}); | ||
it('removes', function(done){ | ||
var self = this; | ||
async.waterfall([ | ||
it('removes', function(done) { | ||
var self = this; | ||
async.waterfall([ | ||
function(cb) { | ||
var simple = new self.Simple({ | ||
name: 'stuff', | ||
telephone: '999-999-9999', | ||
createdBy: 'test' | ||
}); | ||
function(cb) { | ||
var simple = new self.Simple({ | ||
name: 'stuff', | ||
telephone: '999-999-9999', | ||
createdBy: 'test' | ||
}); | ||
simple.save(function(err, simple) { | ||
cb(err, { | ||
simple: simple | ||
}); | ||
}); | ||
}, | ||
function(p, cb) { | ||
p.simple.modifiedBy = 'remove test'; | ||
p.simple.remove(function(err) { | ||
cb(err, p) | ||
}); | ||
}, | ||
function(p, cb) { | ||
self.connection.db.collection('revisionists', function(err, revisionistCollection) { | ||
p.revisionistModel = revisionistCollection; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
p.revisionistModel.find({ | ||
referenceId: p.simple._id | ||
}) | ||
.toArray(function(err, revisions) { | ||
p.revisions = revisions; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
self.Simple.getVersion(p.simple._id, function(err, version) { | ||
p.v1_byId = version; | ||
cb(err, p); | ||
}); | ||
} | ||
], function(err, p) { | ||
if (err) return done(err); | ||
should(p.revisions) | ||
.be.ok(); | ||
should(p.revisions[1]) | ||
.be.ok(); | ||
should(p.revisions[2]) | ||
.be.ok(); | ||
should(p.v1_byId) | ||
.be.ok(); | ||
simple.save(function(err, simple) { | ||
cb(err, { | ||
simple: simple | ||
}); | ||
}); | ||
}, | ||
function(p, cb) { | ||
p.simple.remove(function(err) { | ||
cb(err, p) | ||
}); | ||
}, | ||
function(p, cb) { | ||
self.connection.db.collection('revisionists', function(err, revisionistCollection) { | ||
p.revisionistModel = revisionistCollection; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
p.revisionistModel.find({ | ||
referenceId: p.simple._id | ||
}) | ||
.toArray(function(err, revisions) { | ||
p.revisions = revisions; | ||
cb(err, p); | ||
}); | ||
}, | ||
function(p, cb) { | ||
self.Simple.getVersion(p.simple._id, function(err, version) { | ||
p.v1_byId = version; | ||
cb(err, p); | ||
}); | ||
} | ||
], function(err, p) { | ||
if (err) return done(err); | ||
should(p.revisions) | ||
.be.ok(); | ||
should(p.revisions[1]) | ||
.be.ok(); | ||
should(p.revisions[2]) | ||
.be.ok(); | ||
should(p.v1_byId) | ||
.be.ok(); | ||
p.revisions.length.should.equal(3); | ||
p.revisions[1].revision.should.equal(2); | ||
p.revisions[2].op.should.equal('d'); | ||
p.v1_byId.modifiedBy.should.equal('remove test'); | ||
done(); | ||
}); | ||
p.revisions.length.should.equal(3); | ||
p.revisions[1].revision.should.equal(2); | ||
p.revisions[2].op.should.equal('d'); | ||
done(); | ||
}); | ||
}); | ||
}); |
module.exports = exports = { | ||
"fixDates": require("./fixDates"), | ||
"models": require("./models"), | ||
"setup": require("./setup"), | ||
"shorthand": require("./shorthand"), | ||
}; |
@@ -30,2 +30,3 @@ var logger = require('winston'), | ||
after(function(done) { | ||
logger.silly('closing connection'); | ||
this.connection.close(); | ||
@@ -32,0 +33,0 @@ done(); |
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
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
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
43
3514
70
105395
1