Implemented polymorphic hasMany through inverse

Added option invert: true to enable inverse polymorphic hasMany
relations.

Fixed missing fk1 in query of HasManyThrough.prototype.exists.
This commit is contained in:
Fabien Franzen 2014-07-26 21:11:25 +02:00
parent d1896553fd
commit 5e30ec8637
2 changed files with 86 additions and 10 deletions

View File

@ -371,8 +371,10 @@ RelationDefinition.hasMany = function hasMany(modelFrom, modelTo, params) {
if (typeof params.polymorphic === 'string') { if (typeof params.polymorphic === 'string') {
var polymorphic = params.polymorphic; var polymorphic = params.polymorphic;
fk = i8n.camelize(polymorphic + '_id', true);
typeTo = i8n.camelize(polymorphic + '_type', true); typeTo = i8n.camelize(polymorphic + '_type', true);
if (!params.invert) {
fk = i8n.camelize(polymorphic + '_id', true);
}
if (!params.through) { if (!params.through) {
modelTo.dataSource.defineProperty(modelTo.modelName, typeTo, { type: 'string', index: true }); modelTo.dataSource.defineProperty(modelTo.modelName, typeTo, { type: 'string', index: true });
} }
@ -445,7 +447,11 @@ RelationDefinition.hasMany = function hasMany(modelFrom, modelTo, params) {
definition.applyScope(this, filter); definition.applyScope(this, filter);
if (params.through) { if (params.through && params.polymorphic && params.invert) {
filter.where[typeTo] = modelTo.modelName; // overwrite
filter.collect = params.polymorphic;
filter.include = filter.collect;
} else if (params.through) {
filter.collect = i8n.camelize(modelTo.modelName, true); filter.collect = i8n.camelize(modelTo.modelName, true);
filter.include = filter.collect; filter.include = filter.collect;
} }
@ -758,7 +764,6 @@ HasManyThrough.prototype.exists = function (acInst, done) {
var modelThrough = definition.modelThrough; var modelThrough = definition.modelThrough;
var pk1 = definition.keyFrom; var pk1 = definition.keyFrom;
var data = {};
var query = {}; var query = {};
// The primary key for the target model // The primary key for the target model
@ -768,12 +773,14 @@ HasManyThrough.prototype.exists = function (acInst, done) {
var fk1 = keys[0]; var fk1 = keys[0];
var fk2 = keys[1]; var fk2 = keys[1];
query[fk1] = this.modelInstance[pk1];
query[fk2] = (acInst instanceof definition.modelTo) ? acInst[pk2] : acInst; query[fk2] = (acInst instanceof definition.modelTo) ? acInst[pk2] : acInst;
data[fk1] = this.modelInstance[pk1]; var filter = { where: query };
data[fk2] = (acInst instanceof definition.modelTo) ? acInst[pk2] : acInst;
definition.applyScope(this.modelInstance, filter);
modelThrough.count(query, function(err, ac) {
modelThrough.count(filter.where, function(err, ac) {
done(err, ac > 0); done(err, ac > 0);
}); });
}; };

View File

@ -788,6 +788,8 @@ describe('relations', function () {
it('can be declared', function (done) { it('can be declared', function (done) {
Author.hasAndBelongsToMany(Picture, { through: PictureLink, polymorphic: 'imageable' }); Author.hasAndBelongsToMany(Picture, { through: PictureLink, polymorphic: 'imageable' });
Reader.hasAndBelongsToMany(Picture, { through: PictureLink, polymorphic: 'imageable' }); Reader.hasAndBelongsToMany(Picture, { through: PictureLink, polymorphic: 'imageable' });
Picture.hasMany(Author, { through: PictureLink, polymorphic: 'imageable', invert: true });
Picture.hasMany(Reader, { through: PictureLink, polymorphic: 'imageable', invert: true });
db.automigrate(done); db.automigrate(done);
}); });
@ -821,7 +823,11 @@ describe('relations', function () {
link.pictureId.should.equal(1); link.pictureId.should.equal(1);
link.imageableId.should.equal(4); link.imageableId.should.equal(4);
link.imageableType.should.equal('Author'); link.imageableType.should.equal('Author');
done(); link.imageable(function(err, imageable) {
imageable.should.be.instanceof(Author);
imageable.id.should.equal(4);
done();
});
}); });
}); });
@ -856,6 +862,7 @@ describe('relations', function () {
Author.find({ include: 'pictures' }, function(err, authors) { Author.find({ include: 'pictures' }, function(err, authors) {
authors.should.have.length(1); authors.should.have.length(1);
authors[0].pictures(function(err, pics) { authors[0].pictures(function(err, pics) {
pics.should.have.length(2);
pics[0].name.should.equal('Author Pic 1'); pics[0].name.should.equal('Author Pic 1');
pics[1].name.should.equal('Author Pic 2'); pics[1].name.should.equal('Author Pic 2');
done(); done();
@ -878,7 +885,7 @@ describe('relations', function () {
}); });
it('should create polymorphic through model', function (done) { it('should create polymorphic through model', function (done) {
PictureLink.findOne({ where: { pictureId: 7 } }, function(err, link) { PictureLink.findOne({ where: { pictureId: 7, imageableType: 'Author' } }, function(err, link) {
should.not.exist(err); should.not.exist(err);
link.pictureId.should.equal(7); link.pictureId.should.equal(7);
link.imageableId.should.equal(4); link.imageableId.should.equal(4);
@ -887,6 +894,57 @@ describe('relations', function () {
}); });
}); });
it('should add to a polymorphic relation - author', function (done) {
Author.create({ id: 5, name: 'Author 2' }, function (err, author) {
author.pictures.add(7, function (err, p) {
should.not.exist(err);
done();
});
});
});
it('should add to a polymorphic relation - author', function (done) {
Reader.create({ id: 5, name: 'Reader 2' }, function (err, reader) {
reader.pictures.add(7, function (err, p) {
should.not.exist(err);
done();
});
});
});
it('should get the inverse polymorphic relation - author', function (done) {
Picture.findById(7, function(err, p) {
p.authors(function(err, authors) {
authors.should.have.length(2);
authors[0].name.should.equal('Author 1');
authors[1].name.should.equal('Author 2');
done();
});
});
});
it('should get the inverse polymorphic relation - reader', function (done) {
Picture.findById(7, function(err, p) {
p.readers(function(err, readers) {
readers.should.have.length(1);
readers[0].name.should.equal('Reader 2');
done();
});
});
});
it('should find polymorphic items - author', function (done) {
Author.findById(4, function(err, author) {
author.pictures(function(err, pics) {
pics.should.have.length(3);
pics[0].name.should.equal('Author Pic 1');
pics[1].name.should.equal('Author Pic 2');
pics[2].name.should.equal('Example');
done();
});
});
});
it('should check if polymorphic relation exists - author', function (done) { it('should check if polymorphic relation exists - author', function (done) {
Author.findById(4, function(err, author) { Author.findById(4, function(err, author) {
author.pictures.exists(7, function(err, exists) { author.pictures.exists(7, function(err, exists) {
@ -905,6 +963,17 @@ describe('relations', function () {
}); });
}); });
it('should find polymorphic items - author', function (done) {
Author.findById(4, function(err, author) {
author.pictures(function(err, pics) {
pics.should.have.length(2);
pics[0].name.should.equal('Author Pic 1');
pics[1].name.should.equal('Author Pic 2');
done();
});
});
});
it('should check if polymorphic relation exists - author', function (done) { it('should check if polymorphic relation exists - author', function (done) {
Author.findById(4, function(err, author) { Author.findById(4, function(err, author) {
author.pictures.exists(7, function(err, exists) { author.pictures.exists(7, function(err, exists) {