Skip to content

Commit

Permalink
feat(Model): add pick, omit, merge methods
Browse files Browse the repository at this point in the history
  • Loading branch information
patrickhulce committed Sep 4, 2016
1 parent 8db7cbf commit 78466d4
Show file tree
Hide file tree
Showing 2 changed files with 149 additions and 0 deletions.
19 changes: 19 additions & 0 deletions lib/Model.js
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,25 @@ Model.prototype.children = function (children) {
}
};

Model.prototype.pick = function (fields) {
var matched = _.filter(this.spec.children || [], item => _.includes(fields, item.name));
return this.children(matched);
};

Model.prototype.omit = function (fields) {
var matched = _.reject(this.spec.children || [], item => _.includes(fields, item.name));
return this.children(matched);
};

Model.prototype.merge = function (other) {
assert.ok(other instanceof Model, 'can only merge with another model');
var matched = (this.spec.children || []).concat(other.spec.children || []);
var uniq = _(matched).map('name').uniq().value();

assert.equal(matched.length, uniq.length, 'cannot merge conflicting models');
return this.children(matched);
};

Model.prototype.validations = function (validations) {
assert.ok(_.isArray(validations), 'validations must be an array');
return validations.reduce(function (model, validation) {
Expand Down
130 changes: 130 additions & 0 deletions test/Model.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,136 @@ defineTest('Model.js', function (Model) {
});
});

describe('#pick', function () {
it('should limit the children to named fields', function () {
var childModel = {
first: new Model({type: 'string'}),
second: new Model({type: 'number'}),
third: new Model({type: 'object'}),
};

var model = new Model().type('object').children(childModel);
model.spec.should.have.property('children').length(3);
model.pick(['first', 'third']).spec.should.have.property('children').eql([
{name: 'first', model: childModel.first},
{name: 'third', model: childModel.third},
]);
});

it('should limit the children to named single field', function () {
var childModel = {
first: new Model({type: 'string'}),
second: new Model({type: 'number'}),
third: new Model({type: 'object'}),
};

var model = new Model().type('object').children(childModel);
model.spec.should.have.property('children').length(3);
model.pick('second').spec.should.have.property('children').eql([
{name: 'second', model: childModel.second},
]);
});

it('should not fail when no children exist', function () {
var model = new Model().type('object');
model.pick('second').spec.should.have.property('children').eql([]);
});
});

describe('#omit', function () {
it('should limit the children to not named fields', function () {
var childModel = {
first: new Model({type: 'string'}),
second: new Model({type: 'number'}),
third: new Model({type: 'object'}),
};

var model = new Model().type('object').children(childModel);
model.spec.should.have.property('children').length(3);
model.omit(['second', 'first']).spec.should.have.property('children').eql([
{name: 'third', model: childModel.third},
]);
});

it('should limit the children to not the named field', function () {
var childModel = {
first: new Model({type: 'string'}),
second: new Model({type: 'number'}),
third: new Model({type: 'object'}),
};

var model = new Model().type('object').children(childModel);
model.spec.should.have.property('children').length(3);
model.omit('first').spec.should.have.property('children').eql([
{name: 'second', model: childModel.second},
{name: 'third', model: childModel.third},
]);
});

it('should not fail when no children exist', function () {
var model = new Model().type('object');
model.omit('random').spec.should.have.property('children').eql([]);
});
});

describe('#merge', function () {
it('should take the union of both objects', function () {
var childModelA = {
first: new Model({type: 'string'}),
second: new Model({type: 'number'}),
};

var childModelB = {
third: new Model({type: 'boolean'}),
fourth: new Model({type: 'string'}),
};

var modelA = new Model().type('object').children(childModelA);
var modelB = new Model().type('object').children(childModelB);
modelA.merge(modelB).spec.should.have.property('children').eql([
{name: 'first', model: childModelA.first},
{name: 'second', model: childModelA.second},
{name: 'third', model: childModelB.third},
{name: 'fourth', model: childModelB.fourth},
]);
});

it('should fail when given a conflicting model', function () {
var childModelA = {
first: new Model({type: 'string'}),
second: new Model({type: 'number'}),
third: new Model({type: 'object'}),
};

var childModelB = {second: new Model({type: 'boolean'})};

var modelA = new Model().type('object').children(childModelA);
var modelB = new Model().type('object').children(childModelB);
(function () {
modelA.merge(modelB);
}).should.throw(/cannot merge conflicting models/);
});

it('should fail when given a non-model', function () {
var childModel = {
first: new Model({type: 'string'}),
second: new Model({type: 'number'}),
third: new Model({type: 'object'}),
};

var model = new Model().type('object').children(childModel);
(function () {
model.merge({});
}).should.throw(/can only merge with another model/);
});

it('should not fail when no children exist', function () {
var modelA = new Model().type('object');
var modelB = new Model().type('object');
modelA.merge(modelB).spec.should.have.property('children').eql([]);
});
});

describe('#validations', function () {
it('should set spec.validations when regex', function () {
var regex = /^something|else$/;
Expand Down

0 comments on commit 78466d4

Please sign in to comment.