Implemented polymorphic hasAndBelongsToMany
This commit is contained in:
parent
9b97e1ae77
commit
295e6fc1f1
|
@ -365,13 +365,14 @@ RelationDefinition.hasMany = function hasMany(modelFrom, modelTo, params) {
|
|||
var fk = params.foreignKey || i8n.camelize(thisClassName + '_id', true);
|
||||
|
||||
var idName = modelFrom.dataSource.idName(modelFrom.modelName) || 'id';
|
||||
var typeTo;
|
||||
var polymorphic, typeTo;
|
||||
|
||||
if (typeof params.polymorphic === 'string') {
|
||||
fk = i8n.camelize(params.polymorphic + '_id', true);
|
||||
var typeTo = i8n.camelize(params.polymorphic + '_type', true);
|
||||
polymorphic = params.polymorphic;
|
||||
fk = i8n.camelize(polymorphic + '_id', true);
|
||||
typeTo = i8n.camelize(polymorphic + '_type', true);
|
||||
if (!params.through) {
|
||||
modelTo.dataSource.defineProperty(modelTo.modelName, typeTo, { type: 'string' });
|
||||
modelTo.dataSource.defineProperty(modelTo.modelName, typeTo, { type: 'string', index: true });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -389,12 +390,11 @@ RelationDefinition.hasMany = function hasMany(modelFrom, modelTo, params) {
|
|||
options: params.options
|
||||
});
|
||||
|
||||
if (params.through) {
|
||||
definition.modelThrough = params.through;
|
||||
var keyThrough = definition.throughKey || i8n.camelize(modelTo.modelName + '_id', true);
|
||||
definition.keyThrough = keyThrough;
|
||||
}
|
||||
|
||||
definition.modelThrough = params.through;
|
||||
|
||||
var keyThrough = definition.throughKey || i8n.camelize(modelTo.modelName + '_id', true);
|
||||
definition.keyThrough = keyThrough;
|
||||
|
||||
modelFrom.relations[relationName] = definition;
|
||||
|
||||
if (!params.through) {
|
||||
|
@ -447,6 +447,7 @@ RelationDefinition.hasMany = function hasMany(modelFrom, modelTo, params) {
|
|||
filter.collect = i8n.camelize(modelTo.modelName, true);
|
||||
filter.include = filter.collect;
|
||||
}
|
||||
|
||||
return filter;
|
||||
}, scopeMethods);
|
||||
|
||||
|
@ -645,7 +646,7 @@ HasManyThrough.prototype.create = function create(data, done) {
|
|||
var definition = this.definition;
|
||||
var modelTo = definition.modelTo;
|
||||
var modelThrough = definition.modelThrough;
|
||||
|
||||
|
||||
if (typeof data === 'function' && !done) {
|
||||
done = data;
|
||||
data = {};
|
||||
|
@ -660,9 +661,16 @@ HasManyThrough.prototype.create = function create(data, done) {
|
|||
}
|
||||
// The primary key for the target model
|
||||
var pk2 = definition.modelTo.definition.idName();
|
||||
var fk1 = findBelongsTo(modelThrough, definition.modelFrom,
|
||||
definition.keyFrom);
|
||||
var fk2 = findBelongsTo(modelThrough, definition.modelTo, pk2);
|
||||
|
||||
if (definition.typeTo) { // polymorphic
|
||||
var fk1 = definition.keyTo;
|
||||
var fk2 = definition.keyThrough;
|
||||
} else {
|
||||
var fk1 = findBelongsTo(modelThrough, definition.modelFrom,
|
||||
definition.keyFrom);
|
||||
var fk2 = findBelongsTo(modelThrough, definition.modelTo, pk2);
|
||||
}
|
||||
|
||||
var d = {};
|
||||
d[fk1] = modelInstance[definition.keyFrom];
|
||||
d[fk2] = to[pk2];
|
||||
|
@ -841,12 +849,12 @@ RelationDefinition.belongsTo = function (modelFrom, modelTo, params) {
|
|||
var typeTo = i8n.camelize(polymorphic + '_type', true);
|
||||
|
||||
if (typeof params.idType === 'string') { // explicit key type
|
||||
modelFrom.dataSource.defineProperty(modelFrom.modelName, fk, { type: params.idType });
|
||||
modelFrom.dataSource.defineProperty(modelFrom.modelName, fk, { type: params.idType, index: true });
|
||||
} else { // try to use the same foreign key type as modelFrom
|
||||
modelFrom.dataSource.defineForeignKey(modelFrom.modelName, fk, modelFrom.modelName);
|
||||
}
|
||||
|
||||
modelFrom.dataSource.defineProperty(modelFrom.modelName, typeTo, { type: 'string' });
|
||||
modelFrom.dataSource.defineProperty(modelFrom.modelName, typeTo, { type: 'string', index: true });
|
||||
} else {
|
||||
var idName = modelFrom.dataSource.idName(modelTo.modelName) || 'id';
|
||||
var relationName = params.as || i8n.camelize(modelTo.modelName, true);
|
||||
|
@ -1055,10 +1063,22 @@ RelationDefinition.hasAndBelongsToMany = function hasAndBelongsToMany(modelFrom,
|
|||
params.through = lookupModel(models, name1) || lookupModel(models, name2) ||
|
||||
modelFrom.dataSource.define(name1);
|
||||
}
|
||||
params.through.belongsTo(modelFrom);
|
||||
params.through.belongsTo(modelTo);
|
||||
|
||||
this.hasMany(modelFrom, modelTo, {as: params.as, through: params.through});
|
||||
|
||||
var options = {as: params.as, through: params.through};
|
||||
|
||||
if (typeof params.polymorphic === 'string') {
|
||||
options.polymorphic = params.polymorphic;
|
||||
var accessor = params.through.prototype[params.polymorphic];
|
||||
if (typeof accessor !== 'function') { // declare once
|
||||
params.through.belongsTo(modelTo);
|
||||
params.through.belongsTo(params.polymorphic, { polymorphic: true });
|
||||
}
|
||||
} else {
|
||||
params.through.belongsTo(modelFrom);
|
||||
params.through.belongsTo(modelTo);
|
||||
}
|
||||
|
||||
this.hasMany(modelFrom, modelTo, options);
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ var should = require('./init.js');
|
|||
|
||||
var db, Book, Chapter, Author, Reader;
|
||||
var Category, Product;
|
||||
var Picture;
|
||||
var Picture, PictureLink;
|
||||
|
||||
describe('relations', function () {
|
||||
|
||||
|
@ -670,6 +670,94 @@ describe('relations', function () {
|
|||
});
|
||||
|
||||
});
|
||||
|
||||
describe('polymorphic hasAndBelongsToMany through', function () {
|
||||
before(function (done) {
|
||||
db = getSchema();
|
||||
Picture = db.define('Picture', {name: String});
|
||||
Author = db.define('Author', {name: String});
|
||||
Reader = db.define('Reader', {name: String});
|
||||
PictureLink = db.define('PictureLink', {});
|
||||
|
||||
db.automigrate(function () {
|
||||
Picture.destroyAll(function () {
|
||||
PictureLink.destroyAll(function () {
|
||||
Author.destroyAll(function () {
|
||||
Reader.destroyAll(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('can be declared', function (done) {
|
||||
Author.hasAndBelongsToMany(Picture, { through: PictureLink, polymorphic: 'imageable' });
|
||||
Reader.hasAndBelongsToMany(Picture, { through: PictureLink, polymorphic: 'imageable' });
|
||||
db.automigrate(done);
|
||||
});
|
||||
|
||||
it('should create polymorphic relation - author', function (done) {
|
||||
Author.create({ id: 3, name: 'Author 1' }, function (err, author) {
|
||||
author.pictures.create({ name: 'Author Pic 1' }, function (err, p) {
|
||||
should.not.exist(err);
|
||||
p.id.should.equal(1);
|
||||
author.pictures.create({ name: 'Author Pic 2' }, function (err, p) {
|
||||
should.not.exist(err);
|
||||
p.id.should.equal(2);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should create polymorphic relation - reader', function (done) {
|
||||
Reader.create({ id: 4, name: 'Reader 1' }, function (err, reader) {
|
||||
reader.pictures.create({ name: 'Reader Pic 1' }, function (err, p) {
|
||||
should.not.exist(err);
|
||||
p.id.should.equal(3);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should create polymorphic through model', function (done) {
|
||||
PictureLink.findOne(function(err, link) {
|
||||
should.not.exist(err);
|
||||
link.pictureId.should.equal(1);
|
||||
link.imageableId.should.equal(3);
|
||||
link.imageableType.should.equal('Author');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should get polymorphic relation through model - author', function (done) {
|
||||
Author.findById(3, function(err, author) {
|
||||
should.not.exist(err);
|
||||
author.name.should.equal('Author 1');
|
||||
author.pictures(function(err, pics) {
|
||||
should.not.exist(err);
|
||||
pics.should.have.length(2);
|
||||
pics[0].name.should.equal('Author Pic 1');
|
||||
pics[1].name.should.equal('Author Pic 2');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should get polymorphic relation through model - reader', function (done) {
|
||||
Reader.findById(4, function(err, reader) {
|
||||
should.not.exist(err);
|
||||
reader.name.should.equal('Reader 1');
|
||||
reader.pictures(function(err, pics) {
|
||||
should.not.exist(err);
|
||||
pics.should.have.length(1);
|
||||
pics[0].name.should.equal('Reader Pic 1');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('belongsTo', function () {
|
||||
var List, Item, Fear, Mind;
|
||||
|
|
Loading…
Reference in New Issue