From 5e30ec863797e5b3e0ce09e60283e81bced47891 Mon Sep 17 00:00:00 2001 From: Fabien Franzen Date: Sat, 26 Jul 2014 21:11:25 +0200 Subject: [PATCH] Implemented polymorphic hasMany through inverse Added option invert: true to enable inverse polymorphic hasMany relations. Fixed missing fk1 in query of HasManyThrough.prototype.exists. --- lib/relation-definition.js | 23 +++++++----- test/relations.test.js | 73 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 86 insertions(+), 10 deletions(-) diff --git a/lib/relation-definition.js b/lib/relation-definition.js index 5ab62a55..d85f04a0 100644 --- a/lib/relation-definition.js +++ b/lib/relation-definition.js @@ -371,8 +371,10 @@ RelationDefinition.hasMany = function hasMany(modelFrom, modelTo, params) { if (typeof params.polymorphic === 'string') { var polymorphic = params.polymorphic; - fk = i8n.camelize(polymorphic + '_id', true); typeTo = i8n.camelize(polymorphic + '_type', true); + if (!params.invert) { + fk = i8n.camelize(polymorphic + '_id', true); + } if (!params.through) { 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); - 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.include = filter.collect; } @@ -758,7 +764,6 @@ HasManyThrough.prototype.exists = function (acInst, done) { var modelThrough = definition.modelThrough; var pk1 = definition.keyFrom; - var data = {}; var query = {}; // The primary key for the target model @@ -768,12 +773,14 @@ HasManyThrough.prototype.exists = function (acInst, done) { var fk1 = keys[0]; var fk2 = keys[1]; + query[fk1] = this.modelInstance[pk1]; query[fk2] = (acInst instanceof definition.modelTo) ? acInst[pk2] : acInst; - - data[fk1] = this.modelInstance[pk1]; - data[fk2] = (acInst instanceof definition.modelTo) ? acInst[pk2] : acInst; - - modelThrough.count(query, function(err, ac) { + + var filter = { where: query }; + + definition.applyScope(this.modelInstance, filter); + + modelThrough.count(filter.where, function(err, ac) { done(err, ac > 0); }); }; diff --git a/test/relations.test.js b/test/relations.test.js index fe2751d6..8e66dfee 100644 --- a/test/relations.test.js +++ b/test/relations.test.js @@ -788,6 +788,8 @@ describe('relations', function () { it('can be declared', function (done) { Author.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); }); @@ -821,7 +823,11 @@ describe('relations', function () { link.pictureId.should.equal(1); link.imageableId.should.equal(4); 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) { authors.should.have.length(1); authors[0].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(); @@ -878,7 +885,7 @@ describe('relations', function () { }); 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); link.pictureId.should.equal(7); 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) { Author.findById(4, function(err, author) { 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) { Author.findById(4, function(err, author) { author.pictures.exists(7, function(err, exists) {