Tests for polymorphic embedsMany

This commit is contained in:
Fabien Franzen 2014-07-29 13:57:49 +02:00
parent da303b72a5
commit 13cee9502c
3 changed files with 150 additions and 26 deletions

View File

@ -94,7 +94,7 @@ Inclusion.include = function (objects, include, cb) {
subInclude = null; subInclude = null;
} }
var relation = relations[relationName]; var relation = relations[relationName];
if (!relation) { if (!relation) {
cb(new Error('Relation "' + relationName + '" is not defined for ' cb(new Error('Relation "' + relationName + '" is not defined for '
+ self.modelName + ' model')); + self.modelName + ' model'));
@ -106,7 +106,7 @@ Inclusion.include = function (objects, include, cb) {
cb(); cb();
return; return;
} }
// Calling the relation method for each object // Calling the relation method for each object
async.each(objs, function (obj, callback) { async.each(objs, function (obj, callback) {
if(relation.type === 'belongsTo') { if(relation.type === 'belongsTo') {
@ -133,11 +133,11 @@ Inclusion.include = function (objects, include, cb) {
obj.__cachedRelations[relationName] = result; obj.__cachedRelations[relationName] = result;
if(obj === inst) { if(obj === inst) {
obj.__data[relationName] = result; obj.__data[relationName] = result;
obj.strict = false; obj.__strict = false;
} else { } else {
obj[relationName] = result; obj[relationName] = result;
} }
if (subInclude && result) { if (subInclude && result) {
var subItems = relation.multiple ? result : [result]; var subItems = relation.multiple ? result : [result];
// Recursively include the related models // Recursively include the related models

View File

@ -1443,7 +1443,7 @@ RelationDefinition.embedsMany = function hasMany(modelFrom, modelTo, params) {
var fk = modelTo.dataSource.idName(modelTo.modelName) || 'id'; var fk = modelTo.dataSource.idName(modelTo.modelName) || 'id';
var idName = modelFrom.dataSource.idName(modelFrom.modelName) || 'id'; var idName = modelFrom.dataSource.idName(modelFrom.modelName) || 'id';
var definition = new RelationDefinition({ var definition = modelFrom.relations[accessorName] = new RelationDefinition({
name: relationName, name: relationName,
type: RelationTypes.embedsMany, type: RelationTypes.embedsMany,
modelFrom: modelFrom, modelFrom: modelFrom,
@ -1463,17 +1463,20 @@ RelationDefinition.embedsMany = function hasMany(modelFrom, modelTo, params) {
// unique id is required // unique id is required
modelTo.validatesPresenceOf(idName); modelTo.validatesPresenceOf(idName);
modelFrom.validate(relationName, function(err) {
var embeddedList = this[relationName] || []; if (!params.polymorphic) {
var ids = embeddedList.map(function(m) { return m[idName]; }); modelFrom.validate(relationName, function(err) {
var uniqueIds = ids.filter(function(id, pos) { var embeddedList = this[relationName] || [];
return ids.indexOf(id) === pos; var ids = embeddedList.map(function(m) { return m[idName]; });
}); var uniqueIds = ids.filter(function(id, pos) {
if (ids.length !== uniqueIds.length) { return ids.indexOf(id) === pos;
this.errors.add(relationName, 'Contains duplicate `' + idName + '`', 'uniqueness'); });
err(false); if (ids.length !== uniqueIds.length) {
} this.errors.add(relationName, 'Contains duplicate `' + idName + '`', 'uniqueness');
}, { code: 'uniqueness' }) err(false);
}
}, { code: 'uniqueness' })
}
// validate all embedded items // validate all embedded items
if (definition.options.validate) { if (definition.options.validate) {
@ -1568,10 +1571,6 @@ EmbedsMany.prototype.related = function(receiver, scopeParams, condOrRefresh, cb
} }
}; };
if (actualRefresh) {
}
returnRelated(embeddedList); returnRelated(embeddedList);
}; };

View File

@ -1580,7 +1580,7 @@ describe('relations', function () {
}); });
}); });
it('should create item on scope', function(done) { it('should create items on scope', function(done) {
Category.create({ name: 'Category A' }, function(err, cat) { Category.create({ name: 'Category A' }, function(err, cat) {
var link = cat.items.build(); var link = cat.items.build();
link.product(product1); link.product(product1);
@ -1588,10 +1588,10 @@ describe('relations', function () {
link.product(product2); link.product(product2);
cat.save(function(err, cat) { cat.save(function(err, cat) {
var product = cat.items.at(0); var product = cat.items.at(0);
product.id.should.equal(product1.id); product.id.should.eql(product1.id);
product.name.should.equal(product1.name); product.name.should.equal(product1.name);
var product = cat.items.at(1); var product = cat.items.at(1);
product.id.should.equal(product2.id); product.id.should.eql(product2.id);
product.name.should.equal(product2.name); product.name.should.equal(product2.name);
done(); done();
}); });
@ -1603,9 +1603,9 @@ describe('relations', function () {
cat.links.should.have.length(2); cat.links.should.have.length(2);
// denormalized properties: // denormalized properties:
cat.items.at(0).id.should.equal(product1.id); cat.items.at(0).id.should.eql(product1.id);
cat.items.at(0).name.should.equal(product1.name); cat.items.at(0).name.should.equal(product1.name);
cat.items.at(1).id.should.equal(product2.id); cat.items.at(1).id.should.eql(product2.id);
cat.items.at(1).name.should.equal(product2.name); cat.items.at(1).name.should.equal(product2.name);
// lazy-loaded relations // lazy-loaded relations
@ -1635,7 +1635,7 @@ describe('relations', function () {
it('should find items on scope', function(done) { it('should find items on scope', function(done) {
Category.findOne(function(err, cat) { Category.findOne(function(err, cat) {
cat.links.should.have.length(1); cat.links.should.have.length(1);
cat.items.at(0).id.should.equal(product2.id); cat.items.at(0).id.should.eql(product2.id);
cat.items.at(0).name.should.equal(product2.name); cat.items.at(0).name.should.equal(product2.name);
// lazy-loaded relations // lazy-loaded relations
@ -1650,5 +1650,130 @@ describe('relations', function () {
}); });
}); });
describe('embedsMany - polymorphic relations', function () {
var person1, person2;
before(function (done) {
db = getSchema();
Book = db.define('Book', {name: String});
Author = db.define('Author', {name: String});
Reader = db.define('Reader', {name: String});
Link = db.define('Link'); // generic model
Link.validatesPresenceOf('linkedId');
Link.validatesPresenceOf('linkedType');
db.automigrate(function () {
Book.destroyAll(function() {
Author.destroyAll(function() {
Reader.destroyAll(done);
});
});
});
});
it('can be declared', function (done) {
Book.embedsMany(Link, { as: 'people',
polymorphic: 'linked',
scope: { include: 'linked' }
});
Link.belongsTo('linked', {
polymorphic: true,
properties: { name: 'name' } // denormalized
});
db.automigrate(done);
});
it('should setup related items', function(done) {
Author.create({ name: 'Author 1' }, function(err, p) {
person1 = p;
Reader.create({ name: 'Reader 1' }, function(err, p) {
person2 = p;
done();
});
});
});
it('should create items on scope', function(done) {
Book.create({ name: 'Book' }, function(err, book) {
var link = book.people.build({ notes: 'Something ...' });
link.linked(person1);
var link = book.people.build();
link.linked(person2);
book.save(function(err, book) {
should.not.exist(err);
var link = book.people.at(0);
link.should.be.instanceof(Link);
link.id.should.equal(1);
link.linkedId.should.eql(person1.id);
link.linkedType.should.equal('Author');
link.name.should.equal('Author 1');
var link = book.people.at(1);
link.should.be.instanceof(Link);
link.id.should.equal(2);
link.linkedId.should.eql(person2.id);
link.linkedType.should.equal('Reader');
link.name.should.equal('Reader 1');
done();
});
});
});
it('should include related items on scope', function(done) {
Book.findOne(function(err, book) {
book.links.should.have.length(2);
var link = book.people.at(0);
link.should.be.instanceof(Link);
link.id.should.equal(1);
link.linkedId.should.eql(person1.id);
link.linkedType.should.equal('Author');
link.notes.should.equal('Something ...');
var link = book.people.at(1);
link.should.be.instanceof(Link);
link.id.should.equal(2);
link.linkedId.should.eql(person2.id);
link.linkedType.should.equal('Reader');
// lazy-loaded relations
should.not.exist(book.people.at(0).linked());
should.not.exist(book.people.at(1).linked());
book.people(function(err, people) {
people[0].linked().should.be.instanceof(Author);
people[0].linked().name.should.equal('Author 1');
people[1].linked().should.be.instanceof(Reader);
people[1].linked().name.should.equal('Reader 1');
done();
});
});
});
it('should include nested related items on scope', function(done) {
Book.find({ include: 'people' }, function(err, books) {
var obj = books[0].toObject();
obj.should.have.property('links');
obj.should.have.property('people');
obj.links.should.have.length(2);
obj.links[0].name.should.equal('Author 1');
obj.links[1].name.should.equal('Reader 1');
obj.people.should.have.length(2);
obj.people[0].linked.name.should.equal('Author 1');
obj.people[1].linked.name.should.equal('Reader 1');
done();
});
});
});
}); });