Skip to content

Commit

Permalink
Allow change/remove of other pubs docs to fix kadirahq#142
Browse files Browse the repository at this point in the history
Change PublishContext.changed() and PublishContext.removed() to ensure that the
collection exists, and if there isn't a doc with the requested id in the current
publish context, to look for one that was published in another publish context.
If one is found, changed() adds the doc to the current publish context and
removed() does nothing. If there isn't, both throw the same errors that would be
thrown by the merge box.
  • Loading branch information
brettle committed Dec 8, 2015
1 parent e76ae1b commit 7d2346b
Show file tree
Hide file tree
Showing 2 changed files with 131 additions and 3 deletions.
43 changes: 40 additions & 3 deletions lib/server/publish_context.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,16 @@ PublishContext.prototype._ensureCollection = function(collection) {
}
};

PublishContext.prototype._existsInAnotherView = function(collection, id) {
var otherViews = this._context._collectionData[collection] || [];
return otherViews.some(function(view) {
view = view || [];
return view.some(function(doc) {
return doc._id === id;
});
});
};

PublishContext.prototype.added = function(collection, id, fields) {
this._ensureCollection(collection);
var doc = _.clone(fields);
Expand All @@ -49,23 +59,50 @@ PublishContext.prototype.added = function(collection, id, fields) {
};

PublishContext.prototype.changed = function(collection, id, fields) {
this._ensureCollection(collection);
var collectionData = this._collectionData;

var found = false;
collectionData[collection] = collectionData[collection].map(function(doc) {
if (doc._id === id) {
found = true;
return _.extend(doc, fields);
}

return doc;
});
// If we found the doc, then we've changed it so we're done
if (found)
return;
// Otherwise, see if it exists in another view within this context
if (this._existsInAnotherView(collection, id)) {
// Found it, so we can just add it to our view.
this.added(collection, id, fields);
} else {
// We didn't find it, so attempting to change it is an error
throw new Error("Could not find element with id " + id + " to change");
}
};

PublishContext.prototype.removed = function(collection, id) {
this._ensureCollection(collection);
var collectionData = this._collectionData;

var found = false;
collectionData[collection] = collectionData[collection].filter(function(doc) {
return doc._id !== id;
if (doc._id === id) {
found = true;
return false;
} else {
return true;
}
});
// If we found the doc, then we've removed it so we're done
if (found)
return;
// Otherwise, throw an error if it doesn't exists in another view within this
// context.
if (!this._existsInAnotherView(collection, id)) {
throw new Error("Removed nonexistent document " + id);
}
};

PublishContext.prototype.onStop = function(cb) {
Expand Down
91 changes: 91 additions & 0 deletions tests/server/integration.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,97 @@ Tinytest.add('integration - null publications', function(test) {
cursorHandler.stop();
});

Tinytest.add('integration - collection shared by pubs', function(test) {
var collName = Random.id();
var pubName1 = Random.id();
var pubName2 = Random.id();
var path = "/" + Random.id();

// Publish the collection with just one object
Meteor.publish(pubName1, function() {
var self = this;
self.added(collName, 'docToNotChange', {
prop: 'value',
});
self.added(collName, 'docToChange', {
propToNotChange: 'value',
propToChange: 'origValue'
});
self.added(collName, 'docToRemove', {
prop: 'value',
});
self.ready();
});

Meteor.publish(pubName2, function() {
var self = this;

// Removing an object not in the collection should cause an error
test.throws(function() {
self.removed(collName, "missingDoc");
}, 'Removed nonexistent document');

// Changing an object not in the collection should cause an error
test.throws(function() {
self.changed(collName, "missingDoc", { propAdded: 'addedValue' });
}, 'Could not find element');

self.added(collName, "docAdded", {
prop: 'value'
});
self.added(collName, "docAddedAndRemoved", {
prop: 'value'
});
self.removed(collName, "docAddedAndRemoved");

// Changing an object in the collection should work
self.changed(collName, "docToChange", {
propToChange: 'changedValue',
propAdded: 'addedValue'
});

// Removing an object in the collection should not fail (though the object
// won't be removed because we didn't publish it)
self.removed(collName, "docToRemove");
self.ready();
});

FastRender.route(path, function() {
this.subscribe(pubName1);
this.subscribe(pubName2);
});

var data = getFRData(path);
test.equal(data.collectionData[collName], [
[
{
_id: 'docToNotChange',
prop: 'value',
},
{
_id: 'docToChange',
propToNotChange: 'value',
propToChange: 'origValue'
},
{
_id: 'docToRemove',
prop: 'value',
},
],
[
{
_id: 'docAdded',
prop: 'value'
},
{
_id: 'docToChange',
propToChange: 'changedValue',
propAdded: 'addedValue'
},
],
]);
});

Tinytest.add('integration - send data via this.* apis', function(test) {
var collName = Random.id();
var pubName = Random.id();
Expand Down

0 comments on commit 7d2346b

Please sign in to comment.