Skip to content

Commit

Permalink
feat(collection): $addUnique for MongoDB $addToSet support (from yone…
Browse files Browse the repository at this point in the history
…al PR #252)

- $addUnique or MongoDB $addToSet support
- Added more tests for $addUnique
- normalize  value to Array before calling _.union()
  • Loading branch information
yoneal authored and NicolasRitouet committed Nov 10, 2014
1 parent 29cf94b commit 730e980
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 2 deletions.
13 changes: 11 additions & 2 deletions lib/resources/collection/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ var validation = require('validation')
, EventEmitter = require('events').EventEmitter
, debug = require('debug')('collection')
, path = require('path')
, Script = require('../../script');
, Script = require('../../script')
, _ = require('underscore');

/**
* A `Collection` validates incoming requests then proxies them into a `Store`.
Expand Down Expand Up @@ -681,6 +682,14 @@ Collection.prototype.execCommands = function (type, obj, commands) {
}
}
}
if (k === '$addUnique') {
val = Array.isArray(val) ? val : [val];
if(Array.isArray(obj[key])) {
obj[key] = _.union(obj[key], val);
} else {
obj[key] = val;
}
}
});
}
});
Expand All @@ -697,4 +706,4 @@ Collection.prototype.shouldRunEvent = function(ev, ctx) {
return !rootPrevent && ev;
};

module.exports = Collection;
module.exports = Collection;
80 changes: 80 additions & 0 deletions test-app/public/test/collection.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,86 @@ describe('Collection', function() {
});
});

describe('.put(id, {tags: {$addUnique: "red"}}, fn)', function() {
it('should update a set', function(done) {
chain(function(next) {
dpd.todos.post({title: 'foobar', tags: ['blue', 'green']}, next);
}).chain(function(next, result) {
dpd.todos.put(result.id, {tags: {$addUnique: "red"}}, next);
}).chain(function(next, result) {
expect(result.tags.length).to.equal(3);
expect(result.tags).to.include("red").and.include("blue").and.include("green");
done();
});
});

it('should update an empty array', function(done) {
chain(function(next) {
dpd.todos.post({title: 'foobar'}, next);
}).chain(function(next, result) {
dpd.todos.put(result.id, {tags: {$addUnique: "red"}}, next);
}).chain(function(next, result) {
expect(result.tags.length).to.equal(1);
expect(result.tags).to.include("red");
done();
});
});

it('should not update a set if element already exists', function(done) {
chain(function(next) {
dpd.todos.post({title: 'foobar', tags: ['red', 'green']}, next);
}).chain(function(next, result) {
dpd.todos.put(result.id, {tags: {$addUnique: "red"}}, next);
}).chain(function(next, result) {
expect(result.tags.length).to.equal(2);
expect(result.tags).to.include("red").and.include("green");
done();
});
});

});

describe('.put(id, {tags: {$addUnique: ["yellow", "magenta", "violet"]}}, fn)', function() {
it('should update a set', function(done) {
chain(function(next) {
dpd.todos.post({title: 'foobar', tags: ['red', 'blue', 'green']}, next);
}).chain(function(next, result) {
dpd.todos.put(result.id, {tags: {$addUnique: ["yellow", "magenta", "violet"]}}, next);
}).chain(function(next, result) {
expect(result.tags.length).to.equal(6);
expect(result.tags).to.include("red").and.include("blue").and.include("green")
.and.include("yellow").and.include("magenta").and.include("violet");
done();
});
});

it('should update an empty array', function(done) {
chain(function(next) {
dpd.todos.post({title: 'foobar'}, next);
}).chain(function(next, result) {
dpd.todos.put(result.id, {tags: {$addUnique: ["yellow", "magenta", "violet"]}}, next);
}).chain(function(next, result) {
expect(result.tags.length).to.equal(3);
expect(result.tags).to.include("yellow").and.include("magenta").and.include("violet");
done();
});
});

it('should not update a set if element already exists', function(done) {
chain(function(next) {
dpd.todos.post({title: 'foobar', tags: ['red', 'blue', 'green', 'yellow', 'magenta']}, next);
}).chain(function(next, result) {
dpd.todos.put(result.id, {tags: {$addUnique: ["yellow", "magenta", "violet"]}}, next);
}).chain(function(next, result) {
expect(result.tags.length).to.equal(6);
expect(result.tags).to.include("red").and.include("blue").and.include("green")
.and.include("yellow").and.include("magenta").and.include("violet");
done();
});
});

});

describe('.put({done: true})', function(){
it('should not update multiple items', function(done) {
chain(function(next) {
Expand Down
61 changes: 61 additions & 0 deletions test/collection.unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,51 @@ describe('collection', function(){
});
});

it('should pass $addUnique command', function(done) {
var c = new Collection('persons', {db: db.create(TEST_DB), config: { properties: {names: {type: 'array'}}}});

c.save({body: {names: ['jim','sam']}}, function (err, item) {
expect(item.id).to.exist;
expect(err).to.not.exist;
c.save({body: {names: {$addUnique: 'joe'}}, query: {id: item.id}}, function (err, updated) {
expect(err).to.not.exist;
expect(updated).to.exist;
expect(updated.names).to.eql(['jim', 'sam', 'joe']);
done(err);
});
});
});

it('should not add duplicate element on $addUnique', function(done) {
var c = new Collection('persons', {db: db.create(TEST_DB), config: { properties: {names: {type: 'array'}}}});

c.save({body: {names: ['jim','sam', 'joe']}}, function (err, item) {
expect(item.id).to.exist;
expect(err).to.not.exist;
c.save({body: {names: {$addUnique: 'joe'}}, query: {id: item.id}}, function (err, updated) {
expect(err).to.not.exist;
expect(updated).to.exist;
expect(updated.names).to.eql(['jim', 'sam', 'joe']);
done(err);
});
});
});

it('should not add duplicate elements and add unique elements on $addUnique', function(done) {
var c = new Collection('persons', {db: db.create(TEST_DB), config: { properties: {names: {type: 'array'}}}});

c.save({body: {names: ['jim','sam', 'joe']}}, function (err, item) {
expect(item.id).to.exist;
expect(err).to.not.exist;
c.save({body: {names: {$addUnique: ['carmen', 'jim', 'keith', 'paulus', 'sam', 'joe']}}, query: {id: item.id}}, function (err, updated) {
expect(err).to.not.exist;
expect(updated).to.exist;
expect(updated.names).to.eql(['jim', 'sam', 'joe', 'carmen', 'keith', 'paulus']);
done(err);
});
});
});

// it('should pass commands to the validation listener', function(done) {
// var c = new Collection({
// onValidate: 'if(typeof this.count != "object") throw "didnt pass command to listener"',
Expand Down Expand Up @@ -307,6 +352,22 @@ describe('collection', function(){
expect(item.names).to.eql(['joe', 'bob', 'jim', 'sam']);
});

it('$addUnique - should add an object to a set', function () {
var c = new Collection()
, item = {names: ['joe', 'bob']};

c.execCommands('update', item, {names: {$addUnique: 'sam'}});
expect(item.names).to.eql(['joe', 'bob', 'sam']);
});

it('$addUnique - should add only an object that is unique to the set', function () {
var c = new Collection()
, item = {names: ['joe', 'bob']};

c.execCommands('update', item, {names: {$addUnique: 'joe'}});
expect(item.names).to.eql(['joe', 'bob']);
});

it('should not throw', function() {
var c = new Collection()
, item = {names: 78};
Expand Down

0 comments on commit 730e980

Please sign in to comment.