Merge pull request #286 from fabien/fix/polymorphic-transient

getTransientDataSource helper + embedsMany/polymorphic test case fix
This commit is contained in:
Raymond Feng 2014-09-04 09:21:38 -07:00
commit 5c7a9aee3a
3 changed files with 38 additions and 19 deletions

View File

@ -391,13 +391,13 @@ util.inherits(HasOne, Relation);
* EmbedsOne subclass
* @param {RelationDefinition|Object} definition
* @param {Object} modelInstance
* @returns {EmbedsMany}
* @returns {EmbedsOne}
* @constructor
* @class EmbedsOne
*/
function EmbedsOne(definition, modelInstance) {
if (!(this instanceof EmbedsOne)) {
return new EmbedsMany(definition, modelInstance);
return new EmbedsOne(definition, modelInstance);
}
assert(definition.type === RelationTypes.embedsOne);
Relation.apply(this, arguments);
@ -503,9 +503,9 @@ function lookupModelTo(modelFrom, modelTo, params, singularize) {
* @param {Object|String} params Name of the polymorphic relation or params
* @returns {Object} The normalized parameters
*/
function polymorphicParams(params) {
function polymorphicParams(params, as) {
if (typeof params === 'string') params = { as: params };
if (typeof params.as !== 'string') params.as = 'reference'; // default
if (typeof params.as !== 'string') params.as = 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;
@ -1079,21 +1079,23 @@ RelationDefinition.belongsTo = function (modelFrom, modelTo, params) {
var idName, relationName, fk;
if (params.polymorphic) {
relationName = params.as || (typeof modelTo === 'string' ? modelTo : null); // initially
if (params.polymorphic === true) {
// modelTo arg will be the name of the polymorphic relation (string)
polymorphic = polymorphicParams(modelTo);
polymorphic = polymorphicParams(modelTo, relationName);
} else {
polymorphic = polymorphicParams(params.polymorphic);
polymorphic = polymorphicParams(params.polymorphic, relationName);
}
modelTo = null; // will lookup dynamically
idName = params.idName || 'id';
relationName = params.as || polymorphic.as;
relationName = params.as || polymorphic.as; // finally
fk = polymorphic.foreignKey;
discriminator = polymorphic.discriminator;
if (typeof polymorphic.idType === 'string') { // explicit key type
if (polymorphic.idType) { // 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);
@ -2208,10 +2210,7 @@ EmbedsMany.prototype.build = function(targetModelData) {
var assignId = (forceId || targetModelData[pk] === undefined);
if (assignId && typeof connector.generateId === 'function') {
var id = connector.generateId(modelTo.modelName, targetModelData, pk);
targetModelData[pk] = id;
} else if (assignId && pkType === Number) {
if (assignId && pkType === Number) {
var ids = embeddedList.map(function(m) {
return (typeof m[pk] === 'number' ? m[pk] : 0);
});
@ -2220,6 +2219,9 @@ EmbedsMany.prototype.build = function(targetModelData) {
} else {
targetModelData[pk] = 1;
}
} else if (assignId && typeof connector.generateId === 'function') {
var id = connector.generateId(modelTo.modelName, targetModelData, pk);
targetModelData[pk] = id;
}
this.definition.applyProperties(modelInstance, targetModelData);

View File

@ -1,5 +1,7 @@
// This test written in mocha+should.js
var should = require('./init.js');
var jdb = require('../');
var DataSource = jdb.DataSource;
var db, tmp, Book, Chapter, Author, Reader;
var Category, Job;
@ -7,6 +9,10 @@ var Picture, PictureLink;
var Person, Address;
var Link;
var getTransientDataSource = function(settings) {
return new DataSource('transient', settings, db.modelBuilder);
};
describe('relations', function () {
describe('hasMany', function () {
@ -1679,7 +1685,7 @@ describe('relations', function () {
var Other;
before(function () {
tmp = getSchema('transient');
tmp = getTransientDataSource();
db = getSchema();
Person = db.define('Person', {name: String});
Passport = tmp.define('Passport',
@ -1828,7 +1834,7 @@ describe('relations', function () {
var address1, address2;
before(function (done) {
tmp = getSchema('transient', {defaultIdType: Number});
tmp = getTransientDataSource({defaultIdType: Number});
db = getSchema();
Person = db.define('Person', {name: String});
Address = tmp.define('Address', {street: String});
@ -2008,7 +2014,7 @@ describe('relations', function () {
describe('embedsMany - explicit ids', function () {
before(function (done) {
tmp = getSchema('transient');
tmp = getTransientDataSource();
db = getSchema();
Person = db.define('Person', {name: String});
Address = tmp.define('Address', {street: String});
@ -2415,11 +2421,16 @@ describe('relations', function () {
before(function (done) {
db = getSchema();
tmp = getTransientDataSource();
Book = db.define('Book', {name: String});
Author = db.define('Author', {name: String});
Reader = db.define('Reader', {name: String});
Link = db.define('Link', {name: String, notes: String}); // generic model
Link = tmp.define('Link', {
id: {type: Number, id: true},
name: String, notes: String
}); // generic model
Link.validatesPresenceOf('linkedId');
Link.validatesPresenceOf('linkedType');
@ -2433,13 +2444,15 @@ describe('relations', function () {
});
it('can be declared', function (done) {
var idType = db.connector.getDefaultIdType();
Book.embedsMany(Link, { as: 'people',
polymorphic: 'linked',
scope: { include: 'linked' }
});
Link.belongsTo('linked', {
polymorphic: true, // needs unique auto-id
properties: { name: 'name' }, // denormalized
polymorphic: { idType: idType }, // native type
properties: { name: 'name' }, // denormalized
options: { invertProperties: true }
});
db.automigrate(done);

View File

@ -6,10 +6,14 @@ var should = require('./init.js');
var db, TransientModel, Person, Widget, Item;
var getTransientDataSource = function(settings) {
return new DataSource('transient', settings);
};
describe('Transient connector', function () {
before(function () {
db = getSchema('transient');
db = getTransientDataSource();
TransientModel = db.define('TransientModel', {}, { idInjection: false });
Person = TransientModel.extend('Person', {name: String});