Skip to content
Browse files

Support is complete now. Tests needed for link/unlink.

  • Loading branch information...
1 parent 5ba4669 commit 267d8dbbc4720ec872f454c7516124a4ffa3b3b1 @yuchi yuchi committed
Showing with 152 additions and 54 deletions.
  1. +47 −22 lib/pubsub.js
  2. +56 −26 lib/relations.js
  3. +9 −2 lib/store.js
  4. +40 −4 test/pubsubTests.js
View
69 lib/pubsub.js
@@ -39,6 +39,8 @@ initialize = function () {
var actionSplitter = /([^:]+)/g; // /([^:]+):([^:]+):?(.*)$/i;
+ Nohm.closePubSub = function(){};
+
/**
* The pub/sub feature is highly optional; Let derivate methods
* like `.subscribe` to call the initialization process. Can be
@@ -47,16 +49,17 @@ initialize = function () {
* sure it's called only once.
*/
- Nohm.pubsubEmitter = null;
- Nohm.initializePubSub = function () {
+ Nohm.pubsubEmitter = new EventEmitter();
+ Nohm.pubsubEmitter.setMaxListeners(0);
+
+ var noop = function () {};
+
+ var __initializePubSub = function () {
var EE, pubSubClient;
// Overwrites itself, ASAP
- Nohm.initializePubSub = function(){};
-
- Nohm.pubsubEmitter = new EventEmitter();
- Nohm.pubsubEmitter.setMaxListeners(0);
+ Nohm.initializePubSub = noop;
pubSubClient = Nohm.getPubSubClient();
@@ -68,7 +71,15 @@ initialize = function () {
var pattern = Nohm.prefix.channel + '*:*';
- pubSubClient.psubscribe(pattern,function(){
+ Nohm.closePubSub = function () {
+ pubSubClient.punsubscribe(pattern, function () {
+ //
+ });
+ Nohm.initializePubSub = __initializePubSub;
+ Nohm.closePubSub = noop;
+ };
+
+ pubSubClient.psubscribe(pattern, function () {
//
});
@@ -105,11 +116,15 @@ initialize = function () {
};
+ Nohm.initializePubSub = __initializePubSub;
+ Nohm.closePubSub = noop;
+
+
/**
*
*/
- var supportedActions = [ 'create', 'update', 'change', 'remove', 'link' ];
+ var supportedActions = [ 'create', 'update', 'change', 'remove', 'unlink', 'link' ];
var messageComposers = {
@@ -118,28 +133,38 @@ initialize = function () {
var result = {
target: {
id: model.id,
+ model: model.modelName,
properties: model.allProperties()
}
};
return result;
- },
+ }
- // This populates the diff property for `change` events.
- change: function changeComposer (action, model, diff) {
- var result = messageComposers.default.apply(this, arguments);
- result.target.diff = diff;
- return result;
- },
+ };
- // This sets the id and properties
- remove: function removeComposer (action, model, id) {
- var result = messageComposers.default.apply(this, arguments);
- result.target.id = id;
- return result;
- },
+ // This populates the diff property for `change` events.
+ messageComposers.change = function changeComposer (action, model, diff) {
+ var result = messageComposers.default.apply(this, arguments);
+ result.target.diff = diff;
+ return result;
+ };
+
+ // This sets the id and properties
+ messageComposers.remove = function removeComposer (action, model, id) {
+ var result = messageComposers.default.apply(this, arguments);
+ result.target.id = id;
+ return result;
+ };
+
+ messageComposers.link = messageComposers.unlink = function relationComposer (action, child, parent, relationName) {
+ var result = {};
+ result.child = messageComposers.default.call(child, action, child).target;
+ result.parent = messageComposers.default.call(parent, action, parent).target;
+ result.relation = relationName;
+ return result;
};
- // Actually only the `action` argument must be declared here, Is the composer
+ // Actually only the `action` argument must be declared here, Is the composer's
// duty to define its signature. I put model here to clarify that `action`
// iself tells nothing about the event.
View
82 lib/relations.js
@@ -80,11 +80,12 @@ exports.numLinks = function numLinks(objName, name) {
});
};
-
var allowedLinkTypes = ['sadd', 'srem'];
-exports.__linkProxied = function __linkProxied(type, obj, name, cb) {
+exports.__linkProxied = function __linkProxied(type, obj, name, options, callback) {
+
var self = this,
+ silent = !!options.silent,
parentName = name === 'child' ? 'parent' : name + 'Parent',
client = self.getClient(),
redisExec = function (err, childFail, childName) {
@@ -100,56 +101,70 @@ exports.__linkProxied = function __linkProxied(type, obj, name, cb) {
}
];
async.forEach(dbVals,
- function (val, callback) {
+ function (val, next) {
client[type](Nohm.prefix.relationKeys+val.keyStore, val.key);
- client[type](val.key, val.id, callback);
+ client[type](val.key, val.id, next);
@yuchi Collaborator
yuchi added a note

I made this change to avoid confusion. Should be made on every async.forEach, IMHO.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
},
function (err) {
- cb.call(self, err);
+
+ if (!options.silent) {
+ Nohm.fire( type === 'sadd' ? 'link' : 'unlink', self, obj, name );
+ }
+
+ callback.call(self, err);
}
);
} else if (err && childFail) {
- cb.call(self, err, childFail, childName);
+ callback.call(self, err, childFail, childName);
} else {
- cb.call(self, err);
+ callback.call(self, err);
}
};
-
+
if (allowedLinkTypes.indexOf(type) === -1) {
- cb.call(self, 'link/unlink type invocation wrong');
+ callback.call(self, 'wrong link/unlink type invocation');
} else if (!this.id) {
- cb.call(self, 'save parent object before adding a child.');
+ callback.call(self, 'save parent object before adding a child.');
} else if (!obj.id) {
- obj.save(redisExec);
+ obj.save(options, redisExec);
} else {
redisExec();
}
};
-exports.__link = function __link(obj, name, cb) {
- this.__linkProxied('sadd', obj, name, cb);
+exports.__link = function __link(obj, name, options, cb) {
+ this.__linkProxied('sadd', obj, name, options, cb);
};
-exports.__unlink = function __unlink(obj, name, cb) {
- this.__linkProxied('srem', obj, name, cb);
+exports.__unlink = function __unlink(obj, name, options, cb) {
+ this.__linkProxied('srem', obj, name, options, cb);
};
/**
* Adds a reference to another object.
*/
exports.link = function link(obj, name, directChange) {
+
+ // TODO
+ var options = {};
+
var callback = h.getCallback(arguments);
name = name && typeof name !== 'function' ? name : 'child';
directChange = typeof directChange !== 'function' ? !!directChange : false;
+
if (this.id && directChange && obj.valid()) {
- this.__link(obj, name, callback);
+
+ this.__link(obj, name, options, callback);
+
} else {
+
this.relationChanges.push({
action: 'link',
object: obj,
name: name,
callback: callback
});
+
}
};
@@ -159,32 +174,47 @@ exports.link = function link(obj, name, directChange) {
* Note: this leaves the given object itself intact.
*/
exports.unlink = function unlink(obj, name, directChange) {
- var callback = h.getCallback(arguments),
- change;
+
+ // TODO
+ var options = {};
@yuchi Collaborator
yuchi added a note

In the commit message I forgot to say that link/unlink do not support {silent:true}. Will be fixed along with the tests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+
+ var change,
+ callback = h.getCallback(arguments),
+ changes = this.relationChanges;
+
name = name && typeof name !== 'function' ? name : 'child';
+ directChange = typeof directChange !== 'function' ? !!directChange : false;
+
if (this.id && directChange && obj.id) {
- this.__unlink(obj, name, callback);
+
+ this.__unlink(obj, name, options, callback);
+
} else if (!this.id) {
+
/* the object hasn't been added to the db yet.
* this means it's still in the relationchanges array
* and we can just take it out there.
* (or it was never added, in which case nothing happens here.)
*/
- for (change in this.relationChanges) {
- if (this.relationChanges.hasOwnProperty(change) &&
- this.relationChanges[change].action === 'add' &&
- this.relationChanges[change].name === name &&
- checkEqual(this.relationChanges[change].object, obj)) {
- delete this.relationChanges[change];
+ for (i in changes) {
+ var change = changes[i];
+ if (changes.hasOwnProperty(i) &&
+ change.action === 'add' &&
+ change.name === name &&
+ checkEqual(change.object, obj)) {
+ delete this.relationChanges[i];
}
}
+
} else {
+
this.relationChanges.push({
action: 'unlink',
name: name,
callback: callback,
object: obj
});
+
}
};
@@ -196,7 +226,7 @@ exports.unlinkAll = function (client, callback) {
var normalClient = this.getClient();
var selfLinks = [];
client = client || normalClient;
-
+
// we usenormalClient for fetching data and client (which could be a provided client in multi mode) for manipulating data
normalClient.smembers(Nohm.prefix.relationKeys+this.modelName+':'+this.id, function (err, keys) {
var others = [];
View
11 lib/store.js
@@ -152,6 +152,9 @@ exports.__index = function __index(p, client) {
* @ignore
*/
var __update = function __update(all, silent, callback) {
+
+ var options = {silent: !!silent};
+
var p,
hmsetArgs = [],
isCreation = !this.__inDB,
@@ -199,8 +202,8 @@ var __update = function __update(all, silent, callback) {
// this way once one fails it goes to error directly
async.forEachSeries(self.relationChanges,
function (item, cb) {
- self['__' + item.action](item.object, item.name, function (err, childFail, childName) {
- item.callback.call(self,
+ self['__' + item.action](item.object, item.name, options, function (err, childFail, childName) {
+ item.callback.call(self,
item.action,
self.modelName,
item.name,
@@ -216,10 +219,14 @@ var __update = function __update(all, silent, callback) {
},
function (err) {
if (typeof callback !== 'function' && err) {
+
Nohm.logError('Nohm: Updating an object resulted in a client error: ' + err);
throw err;
+
} else if (err) {
+
callback.call(self, err.err, true, err.modelName);
+
} else {
var diff = self.propertyDiff();
View
44 test/pubsubTests.js
@@ -27,6 +27,18 @@ var after = function (times, fn) {
};
};
+/*
+exports.setUp = function (cb) {
+ nohm.initializePubSub();
+ cb();
+};
+
+exports.tearDown = function (cb) {
+ nohm.closePubSub();
+ cb();
+};
+*/
+
exports.afterLimiter = function(t) {
var counter = 0;
@@ -57,6 +69,7 @@ exports.creationOnce = function(t) {
var expectedPayload = {
target: {
id: obj.id,
+ model: 'Tester',
properties: {
dummy: 'some string',
id: obj.id
@@ -102,6 +115,7 @@ exports.removeOnce = function (t) {
var expectedPayload = {
target: {
id: _id,
+ model: 'Tester',
properties: {
id: 0,
dummy: 'some string'
@@ -127,7 +141,7 @@ exports.removeOnce = function (t) {
};
-exports.silencedCreation = function (t) {
+exports.silencedUpdate = function (t) {
t.expect(0);
@@ -141,9 +155,9 @@ exports.silencedCreation = function (t) {
obj.p({ dummy: 'some strings' });
- Tester.subscribe('create', function (payload) {
+ Tester.subscribe('update', function (payload) {
var msg = run == 1 ? 'first run' : 'second run, listener not unsubscribed';
- t.ok(false, 'The subscriber has run, during silenced actions ('+msg+')');
+ t.ok(false, 'The subscriber has run, during silent creation ('+msg+')');
});
run = 1;
@@ -154,7 +168,7 @@ exports.silencedCreation = function (t) {
setTimeout(function(){
- Tester.unsubscribe('create');
+ Tester.unsubscribe('update');
run = 2;
obj.p({ dummy: 'some other string' });
@@ -167,3 +181,25 @@ exports.silencedCreation = function (t) {
};
+exports.silencedRemoval = function (t) {
+
+ t.expect(0);
+
+ var _done = after(2, function () {
+ t.done();
+ });
+
+ Tester.subscribe('remove', function (payload) {
+ t.ok(false, 'The subscriber has run, during silent removal.')
+ });
+
+ obj.remove({ silent: true }, function () {
+ _done();
+ });
+
+ setTimeout(function () {
+ _done();
+ }, 500)
+
+};
+

0 comments on commit 267d8db

Please sign in to comment.
Something went wrong with that request. Please try again.