diff --git a/lib/relation-definition.js b/lib/relation-definition.js index c46b1c3a..bf7d3826 100644 --- a/lib/relation-definition.js +++ b/lib/relation-definition.js @@ -328,6 +328,19 @@ function lookupModel(models, modelName) { } } +/*! + * Normalize polymorphic parameters + * @param {Object|String} params Name of the polymorphic relation or params + * @returns {Object} The normalized parameters + */ +function polymorphicParams(params) { + if (typeof params === 'string') params = { as: params }; + if (typeof params.as !== 'string') params.as = 'reference'; // default + params.foreignKey = params.foreignKey || i8n.camelize(params.as + '_id', true); + params.discriminator = params.discriminator || i8n.camelize(params.as + '_type', true); + return params; +}; + /** * Define a "one to many" relationship by specifying the model name * @@ -369,11 +382,11 @@ RelationDefinition.hasMany = function hasMany(modelFrom, modelTo, params) { var idName = modelFrom.dataSource.idName(modelFrom.modelName) || 'id'; var discriminator; - if (typeof params.polymorphic === 'string') { - var polymorphic = params.polymorphic; - discriminator = i8n.camelize(polymorphic + '_type', true); + if (params.polymorphic) { + var polymorphic = polymorphicParams(params.polymorphic); + discriminator = polymorphic.discriminator; if (!params.invert) { - fk = i8n.camelize(polymorphic + '_id', true); + fk = polymorphic.foreignKey; } if (!params.through) { modelTo.dataSource.defineProperty(modelTo.modelName, discriminator, { type: 'string', index: true }); @@ -857,16 +870,22 @@ RelationDefinition.belongsTo = function (modelFrom, modelTo, params) { } if (params.polymorphic) { - var polymorphic = modelTo; + if (params.polymorphic === true) { + // modelTo will be the name of the polymorphic relation (string) + var polymorphic = polymorphicParams(modelTo); + } else { + var polymorphic = polymorphicParams(params.polymorphic); + } + modelTo = null; // will lookup dynamically var idName = params.idName || 'id'; - var relationName = params.as || i8n.camelize(polymorphic, true); - var fk = i8n.camelize(polymorphic + '_id', true); - var discriminator = i8n.camelize(polymorphic + '_type', true); + var relationName = params.as || polymorphic.as; + var fk = polymorphic.foreignKey; + var discriminator = polymorphic.discriminator; - if (typeof params.idType === 'string') { // explicit key type - modelFrom.dataSource.defineProperty(modelFrom.modelName, fk, { type: params.idType, index: true }); + if (typeof polymorphic.idType === 'string') { // explicit key type + modelFrom.dataSource.defineProperty(modelFrom.modelName, fk, { type: polymorphic.idType, index: true }); } else { // try to use the same foreign key type as modelFrom modelFrom.dataSource.defineForeignKey(modelFrom.modelName, fk, modelFrom.modelName); } diff --git a/test/relations.test.js b/test/relations.test.js index a6580649..6809e43b 100644 --- a/test/relations.test.js +++ b/test/relations.test.js @@ -641,7 +641,10 @@ describe('relations', function () { it('can be declared', function (done) { Author.hasMany(Picture, { polymorphic: 'imageable' }); - Reader.hasMany(Picture, { polymorphic: 'imageable' }); + Reader.hasMany(Picture, { polymorphic: { // alt syntax + as: 'imageable', foreignKey: 'imageableId', + discriminator: 'imageableType' + } }); Picture.belongsTo('imageable', { polymorphic: true }); db.automigrate(done); });