Merge branch 'fabien-feature/polymorphic-rel'
This commit is contained in:
commit
c8c499320c
|
@ -64,8 +64,11 @@ function RelationDefinition(definition) {
|
||||||
assert(this.modelFrom, 'Source model is required');
|
assert(this.modelFrom, 'Source model is required');
|
||||||
this.keyFrom = definition.keyFrom;
|
this.keyFrom = definition.keyFrom;
|
||||||
this.modelTo = definition.modelTo;
|
this.modelTo = definition.modelTo;
|
||||||
assert(this.modelTo, 'Target model is required');
|
|
||||||
this.keyTo = definition.keyTo;
|
this.keyTo = definition.keyTo;
|
||||||
|
this.discriminator = definition.discriminator;
|
||||||
|
if (!this.discriminator) {
|
||||||
|
assert(this.modelTo, 'Target model is required');
|
||||||
|
}
|
||||||
this.modelThrough = definition.modelThrough;
|
this.modelThrough = definition.modelThrough;
|
||||||
this.keyThrough = definition.keyThrough;
|
this.keyThrough = definition.keyThrough;
|
||||||
this.multiple = (this.type !== 'belongsTo' && this.type !== 'hasOne');
|
this.multiple = (this.type !== 'belongsTo' && this.type !== 'hasOne');
|
||||||
|
@ -97,13 +100,18 @@ RelationDefinition.prototype.toJSON = function () {
|
||||||
* @param {Object} filter (where, order, limit, fields, ...)
|
* @param {Object} filter (where, order, limit, fields, ...)
|
||||||
*/
|
*/
|
||||||
RelationDefinition.prototype.applyScope = function(modelInstance, filter) {
|
RelationDefinition.prototype.applyScope = function(modelInstance, filter) {
|
||||||
|
filter.where = filter.where || {};
|
||||||
|
if ((this.type !== 'belongsTo' || this.type === 'hasOne')
|
||||||
|
&& typeof this.discriminator === 'string') { // polymorphic
|
||||||
|
filter.where[this.discriminator] = this.modelFrom.modelName;
|
||||||
|
}
|
||||||
if (typeof this.scope === 'function') {
|
if (typeof this.scope === 'function') {
|
||||||
var scope = this.scope.call(this, modelInstance, filter);
|
var scope = this.scope.call(this, modelInstance, filter);
|
||||||
if (typeof scope === 'object') {
|
} else {
|
||||||
mergeQuery(filter, scope);
|
var scope = this.scope;
|
||||||
}
|
}
|
||||||
} else if (typeof this.scope === 'object') {
|
if (typeof scope === 'object') {
|
||||||
mergeQuery(filter, this.scope);
|
mergeQuery(filter, scope);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -124,6 +132,10 @@ RelationDefinition.prototype.applyProperties = function(modelInstance, target) {
|
||||||
target[key] = modelInstance[k];
|
target[key] = modelInstance[k];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ((this.type !== 'belongsTo' || this.type === 'hasOne')
|
||||||
|
&& typeof this.discriminator === 'string') { // polymorphic
|
||||||
|
target[this.discriminator] = this.modelFrom.modelName;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -316,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
|
* Define a "one to many" relationship by specifying the model name
|
||||||
*
|
*
|
||||||
|
@ -350,10 +375,23 @@ RelationDefinition.hasMany = function hasMany(modelFrom, modelTo, params) {
|
||||||
modelTo = lookupModel(modelFrom.dataSource.modelBuilder.models, modelToName);
|
modelTo = lookupModel(modelFrom.dataSource.modelBuilder.models, modelToName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var relationName = params.as || i8n.camelize(modelTo.pluralModelName, true);
|
var relationName = params.as || i8n.camelize(modelTo.pluralModelName, true);
|
||||||
var fk = params.foreignKey || i8n.camelize(thisClassName + '_id', true);
|
var fk = params.foreignKey || i8n.camelize(thisClassName + '_id', true);
|
||||||
|
|
||||||
var idName = modelFrom.dataSource.idName(modelFrom.modelName) || 'id';
|
var idName = modelFrom.dataSource.idName(modelFrom.modelName) || 'id';
|
||||||
|
var discriminator;
|
||||||
|
|
||||||
|
if (params.polymorphic) {
|
||||||
|
var polymorphic = polymorphicParams(params.polymorphic);
|
||||||
|
discriminator = polymorphic.discriminator;
|
||||||
|
if (!params.invert) {
|
||||||
|
fk = polymorphic.foreignKey;
|
||||||
|
}
|
||||||
|
if (!params.through) {
|
||||||
|
modelTo.dataSource.defineProperty(modelTo.modelName, discriminator, { type: 'string', index: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var definition = new RelationDefinition({
|
var definition = new RelationDefinition({
|
||||||
name: relationName,
|
name: relationName,
|
||||||
|
@ -361,6 +399,7 @@ RelationDefinition.hasMany = function hasMany(modelFrom, modelTo, params) {
|
||||||
modelFrom: modelFrom,
|
modelFrom: modelFrom,
|
||||||
keyFrom: idName,
|
keyFrom: idName,
|
||||||
keyTo: fk,
|
keyTo: fk,
|
||||||
|
discriminator: discriminator,
|
||||||
modelTo: modelTo,
|
modelTo: modelTo,
|
||||||
multiple: true,
|
multiple: true,
|
||||||
properties: params.properties,
|
properties: params.properties,
|
||||||
|
@ -368,16 +407,17 @@ RelationDefinition.hasMany = function hasMany(modelFrom, modelTo, params) {
|
||||||
options: params.options
|
options: params.options
|
||||||
});
|
});
|
||||||
|
|
||||||
if (params.through) {
|
definition.modelThrough = params.through;
|
||||||
definition.modelThrough = params.through;
|
|
||||||
var keyThrough = definition.throughKey || i8n.camelize(modelTo.modelName + '_id', true);
|
var keyThrough = definition.throughKey || i8n.camelize(modelTo.modelName + '_id', true);
|
||||||
definition.keyThrough = keyThrough;
|
definition.keyThrough = keyThrough;
|
||||||
}
|
|
||||||
|
|
||||||
modelFrom.relations[relationName] = definition;
|
modelFrom.relations[relationName] = definition;
|
||||||
|
|
||||||
if (!params.through) {
|
if (!params.through) {
|
||||||
// obviously, modelTo should have attribute called `fk`
|
// obviously, modelTo should have attribute called `fk`
|
||||||
|
// for polymorphic relations, it is assumed to share the same fk type for all
|
||||||
|
// polymorphic models
|
||||||
modelTo.dataSource.defineForeignKey(modelTo.modelName, fk, modelFrom.modelName);
|
modelTo.dataSource.defineForeignKey(modelTo.modelName, fk, modelFrom.modelName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -423,10 +463,15 @@ 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[discriminator] = 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
return filter;
|
return filter;
|
||||||
}, scopeMethods);
|
}, scopeMethods);
|
||||||
|
|
||||||
|
@ -555,6 +600,21 @@ HasMany.prototype.destroyById = function (fkId, cb) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var throughKeys = function(definition) {
|
||||||
|
var modelThrough = definition.modelThrough;
|
||||||
|
var pk2 = definition.modelTo.definition.idName();
|
||||||
|
|
||||||
|
if (definition.discriminator) { // 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);
|
||||||
|
}
|
||||||
|
return [fk1, fk2];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find a related item by foreign key
|
* Find a related item by foreign key
|
||||||
* @param {*} fkId The foreign key value
|
* @param {*} fkId The foreign key value
|
||||||
|
@ -629,7 +689,7 @@ HasManyThrough.prototype.create = function create(data, done) {
|
||||||
var definition = this.definition;
|
var definition = this.definition;
|
||||||
var modelTo = definition.modelTo;
|
var modelTo = definition.modelTo;
|
||||||
var modelThrough = definition.modelThrough;
|
var modelThrough = definition.modelThrough;
|
||||||
|
|
||||||
if (typeof data === 'function' && !done) {
|
if (typeof data === 'function' && !done) {
|
||||||
done = data;
|
done = data;
|
||||||
data = {};
|
data = {};
|
||||||
|
@ -644,9 +704,11 @@ HasManyThrough.prototype.create = function create(data, done) {
|
||||||
}
|
}
|
||||||
// The primary key for the target model
|
// The primary key for the target model
|
||||||
var pk2 = definition.modelTo.definition.idName();
|
var pk2 = definition.modelTo.definition.idName();
|
||||||
var fk1 = findBelongsTo(modelThrough, definition.modelFrom,
|
|
||||||
definition.keyFrom);
|
var keys = throughKeys(definition);
|
||||||
var fk2 = findBelongsTo(modelThrough, definition.modelTo, pk2);
|
var fk1 = keys[0];
|
||||||
|
var fk2 = keys[1];
|
||||||
|
|
||||||
var d = {};
|
var d = {};
|
||||||
d[fk1] = modelInstance[definition.keyFrom];
|
d[fk1] = modelInstance[definition.keyFrom];
|
||||||
d[fk2] = to[pk2];
|
d[fk2] = to[pk2];
|
||||||
|
@ -668,6 +730,8 @@ HasManyThrough.prototype.create = function create(data, done) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add the target model instance to the 'hasMany' relation
|
* Add the target model instance to the 'hasMany' relation
|
||||||
* @param {Object|ID} acInst The actual instance or id value
|
* @param {Object|ID} acInst The actual instance or id value
|
||||||
|
@ -680,14 +744,13 @@ HasManyThrough.prototype.add = function (acInst, done) {
|
||||||
|
|
||||||
var data = {};
|
var data = {};
|
||||||
var query = {};
|
var query = {};
|
||||||
|
|
||||||
var fk1 = findBelongsTo(modelThrough, definition.modelFrom,
|
|
||||||
definition.keyFrom);
|
|
||||||
|
|
||||||
// The primary key for the target model
|
// The primary key for the target model
|
||||||
var pk2 = definition.modelTo.definition.idName();
|
var pk2 = definition.modelTo.definition.idName();
|
||||||
|
|
||||||
var fk2 = findBelongsTo(modelThrough, definition.modelTo, pk2);
|
var keys = throughKeys(definition);
|
||||||
|
var fk1 = keys[0];
|
||||||
|
var fk2 = keys[1];
|
||||||
|
|
||||||
query[fk1] = this.modelInstance[pk1];
|
query[fk1] = this.modelInstance[pk1];
|
||||||
query[fk2] = (acInst instanceof definition.modelTo) ? acInst[pk2] : acInst;
|
query[fk2] = (acInst instanceof definition.modelTo) ? acInst[pk2] : acInst;
|
||||||
|
@ -698,6 +761,7 @@ HasManyThrough.prototype.add = function (acInst, done) {
|
||||||
|
|
||||||
data[fk1] = this.modelInstance[pk1];
|
data[fk1] = this.modelInstance[pk1];
|
||||||
data[fk2] = (acInst instanceof definition.modelTo) ? acInst[pk2] : acInst;
|
data[fk2] = (acInst instanceof definition.modelTo) ? acInst[pk2] : acInst;
|
||||||
|
|
||||||
definition.applyProperties(this.modelInstance, data);
|
definition.applyProperties(this.modelInstance, data);
|
||||||
|
|
||||||
// Create an instance of the through model
|
// Create an instance of the through model
|
||||||
|
@ -722,18 +786,21 @@ HasManyThrough.prototype.exists = function (acInst, done) {
|
||||||
|
|
||||||
var query = {};
|
var query = {};
|
||||||
|
|
||||||
var fk1 = findBelongsTo(modelThrough, definition.modelFrom,
|
|
||||||
definition.keyFrom);
|
|
||||||
|
|
||||||
// The primary key for the target model
|
// The primary key for the target model
|
||||||
var pk2 = definition.modelTo.definition.idName();
|
var pk2 = definition.modelTo.definition.idName();
|
||||||
|
|
||||||
var fk2 = findBelongsTo(modelThrough, definition.modelTo, pk2);
|
var keys = throughKeys(definition);
|
||||||
|
var fk1 = keys[0];
|
||||||
|
var fk2 = keys[1];
|
||||||
|
|
||||||
query[fk1] = this.modelInstance[pk1];
|
query[fk1] = this.modelInstance[pk1];
|
||||||
query[fk2] = (acInst instanceof definition.modelTo) ? acInst[pk2] : acInst;
|
query[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);
|
done(err, ac > 0);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -750,13 +817,12 @@ HasManyThrough.prototype.remove = function (acInst, done) {
|
||||||
|
|
||||||
var query = {};
|
var query = {};
|
||||||
|
|
||||||
var fk1 = findBelongsTo(modelThrough, definition.modelFrom,
|
|
||||||
definition.keyFrom);
|
|
||||||
|
|
||||||
// The primary key for the target model
|
// The primary key for the target model
|
||||||
var pk2 = definition.modelTo.definition.idName();
|
var pk2 = definition.modelTo.definition.idName();
|
||||||
|
|
||||||
var fk2 = findBelongsTo(modelThrough, definition.modelTo, pk2);
|
var keys = throughKeys(definition);
|
||||||
|
var fk1 = keys[0];
|
||||||
|
var fk2 = keys[1];
|
||||||
|
|
||||||
query[fk1] = this.modelInstance[pk1];
|
query[fk1] = this.modelInstance[pk1];
|
||||||
query[fk2] = (acInst instanceof definition.modelTo) ? acInst[pk2] : acInst;
|
query[fk2] = (acInst instanceof definition.modelTo) ? acInst[pk2] : acInst;
|
||||||
|
@ -764,7 +830,7 @@ HasManyThrough.prototype.remove = function (acInst, done) {
|
||||||
var filter = { where: query };
|
var filter = { where: query };
|
||||||
|
|
||||||
definition.applyScope(this.modelInstance, filter);
|
definition.applyScope(this.modelInstance, filter);
|
||||||
|
|
||||||
modelThrough.deleteAll(filter.where, function (err) {
|
modelThrough.deleteAll(filter.where, function (err) {
|
||||||
if (!err) {
|
if (!err) {
|
||||||
self.removeFromCache(query[fk2]);
|
self.removeFromCache(query[fk2]);
|
||||||
|
@ -799,8 +865,9 @@ HasManyThrough.prototype.remove = function (acInst, done) {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
RelationDefinition.belongsTo = function (modelFrom, modelTo, params) {
|
RelationDefinition.belongsTo = function (modelFrom, modelTo, params) {
|
||||||
|
var discriminator, polymorphic;
|
||||||
params = params || {};
|
params = params || {};
|
||||||
if ('string' === typeof modelTo) {
|
if ('string' === typeof modelTo && !params.polymorphic) {
|
||||||
params.as = modelTo;
|
params.as = modelTo;
|
||||||
if (params.model) {
|
if (params.model) {
|
||||||
modelTo = params.model;
|
modelTo = params.model;
|
||||||
|
@ -810,9 +877,36 @@ RelationDefinition.belongsTo = function (modelFrom, modelTo, params) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var idName = modelFrom.dataSource.idName(modelTo.modelName) || 'id';
|
var idName, relationName, fk;
|
||||||
var relationName = params.as || i8n.camelize(modelTo.modelName, true);
|
if (params.polymorphic) {
|
||||||
var fk = params.foreignKey || relationName + 'Id';
|
if (params.polymorphic === true) {
|
||||||
|
// modelTo arg will be the name of the polymorphic relation (string)
|
||||||
|
polymorphic = polymorphicParams(modelTo);
|
||||||
|
} else {
|
||||||
|
polymorphic = polymorphicParams(params.polymorphic);
|
||||||
|
}
|
||||||
|
|
||||||
|
modelTo = null; // will lookup dynamically
|
||||||
|
|
||||||
|
idName = params.idName || 'id';
|
||||||
|
relationName = params.as || polymorphic.as;
|
||||||
|
fk = polymorphic.foreignKey;
|
||||||
|
discriminator = polymorphic.discriminator;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
modelFrom.dataSource.defineProperty(modelFrom.modelName, discriminator, { type: 'string', index: true });
|
||||||
|
} else {
|
||||||
|
idName = modelFrom.dataSource.idName(modelTo.modelName) || 'id';
|
||||||
|
relationName = params.as || i8n.camelize(modelTo.modelName, true);
|
||||||
|
fk = params.foreignKey || relationName + 'Id';
|
||||||
|
|
||||||
|
modelFrom.dataSource.defineForeignKey(modelFrom.modelName, fk, modelTo.modelName);
|
||||||
|
}
|
||||||
|
|
||||||
var relationDef = modelFrom.relations[relationName] = new RelationDefinition({
|
var relationDef = modelFrom.relations[relationName] = new RelationDefinition({
|
||||||
name: relationName,
|
name: relationName,
|
||||||
|
@ -820,14 +914,13 @@ RelationDefinition.belongsTo = function (modelFrom, modelTo, params) {
|
||||||
modelFrom: modelFrom,
|
modelFrom: modelFrom,
|
||||||
keyFrom: fk,
|
keyFrom: fk,
|
||||||
keyTo: idName,
|
keyTo: idName,
|
||||||
|
discriminator: discriminator,
|
||||||
modelTo: modelTo,
|
modelTo: modelTo,
|
||||||
properties: params.properties,
|
properties: params.properties,
|
||||||
scope: params.scope,
|
scope: params.scope,
|
||||||
options: params.options
|
options: params.options
|
||||||
});
|
});
|
||||||
|
|
||||||
modelFrom.dataSource.defineForeignKey(modelFrom.modelName, fk, modelTo.modelName);
|
|
||||||
|
|
||||||
// Define a property for the scope so that we have 'this' for the scoped methods
|
// Define a property for the scope so that we have 'this' for the scoped methods
|
||||||
Object.defineProperty(modelFrom.prototype, relationName, {
|
Object.defineProperty(modelFrom.prototype, relationName, {
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
|
@ -837,7 +930,9 @@ RelationDefinition.belongsTo = function (modelFrom, modelTo, params) {
|
||||||
var relationMethod = relation.related.bind(relation);
|
var relationMethod = relation.related.bind(relation);
|
||||||
relationMethod.create = relation.create.bind(relation);
|
relationMethod.create = relation.create.bind(relation);
|
||||||
relationMethod.build = relation.build.bind(relation);
|
relationMethod.build = relation.build.bind(relation);
|
||||||
relationMethod._targetClass = relationDef.modelTo.modelName;
|
if (relationDef.modelTo) {
|
||||||
|
relationMethod._targetClass = relationDef.modelTo.modelName;
|
||||||
|
}
|
||||||
return relationMethod;
|
return relationMethod;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -865,7 +960,7 @@ BelongsTo.prototype.create = function(targetModelData, cb) {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.definition.applyProperties(modelInstance, targetModelData || {});
|
this.definition.applyProperties(modelInstance, targetModelData || {});
|
||||||
|
|
||||||
modelTo.create(targetModelData, function(err, targetModel) {
|
modelTo.create(targetModelData, function(err, targetModel) {
|
||||||
if(!err) {
|
if(!err) {
|
||||||
modelInstance[fk] = targetModel[pk];
|
modelInstance[fk] = targetModel[pk];
|
||||||
|
@ -896,7 +991,9 @@ BelongsTo.prototype.build = function(targetModelData) {
|
||||||
*/
|
*/
|
||||||
BelongsTo.prototype.related = function (refresh, params) {
|
BelongsTo.prototype.related = function (refresh, params) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
var modelFrom = this.definition.modelFrom;
|
||||||
var modelTo = this.definition.modelTo;
|
var modelTo = this.definition.modelTo;
|
||||||
|
var discriminator = this.definition.discriminator;
|
||||||
var pk = this.definition.keyTo;
|
var pk = this.definition.keyTo;
|
||||||
var fk = this.definition.keyFrom;
|
var fk = this.definition.keyFrom;
|
||||||
var modelInstance = this.modelInstance;
|
var modelInstance = this.modelInstance;
|
||||||
|
@ -907,15 +1004,30 @@ BelongsTo.prototype.related = function (refresh, params) {
|
||||||
} else if (arguments.length > 2) {
|
} else if (arguments.length > 2) {
|
||||||
throw new Error('Method can\'t be called with more than two arguments');
|
throw new Error('Method can\'t be called with more than two arguments');
|
||||||
}
|
}
|
||||||
|
|
||||||
var cachedValue;
|
var cachedValue;
|
||||||
if (!refresh) {
|
if (!refresh) {
|
||||||
cachedValue = self.getCache();
|
cachedValue = self.getCache();
|
||||||
}
|
}
|
||||||
if (params instanceof ModelBaseClass) { // acts as setter
|
if (params instanceof ModelBaseClass) { // acts as setter
|
||||||
|
modelTo = params.constructor;
|
||||||
modelInstance[fk] = params[pk];
|
modelInstance[fk] = params[pk];
|
||||||
|
if (discriminator) modelInstance[discriminator] = params.constructor.modelName;
|
||||||
self.resetCache(params);
|
self.resetCache(params);
|
||||||
} else if (typeof params === 'function') { // acts as async getter
|
} else if (typeof params === 'function') { // acts as async getter
|
||||||
|
|
||||||
|
if (discriminator && !modelTo) {
|
||||||
|
var modelToName = modelInstance[discriminator];
|
||||||
|
if (typeof modelToName !== 'string') {
|
||||||
|
throw new Error('Polymorphic model not found: `' + discriminator + '` not set');
|
||||||
|
}
|
||||||
|
modelToName = modelToName.toLowerCase();
|
||||||
|
modelTo = lookupModel(modelFrom.dataSource.modelBuilder.models, modelToName);
|
||||||
|
if (!modelTo) {
|
||||||
|
throw new Error('Polymorphic model not found: `' + modelToName + '`');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var cb = params;
|
var cb = params;
|
||||||
if (cachedValue === undefined) {
|
if (cachedValue === undefined) {
|
||||||
var query = {where: {}};
|
var query = {where: {}};
|
||||||
|
@ -987,24 +1099,40 @@ RelationDefinition.hasAndBelongsToMany = function hasAndBelongsToMany(modelFrom,
|
||||||
if (params.model) {
|
if (params.model) {
|
||||||
modelTo = params.model;
|
modelTo = params.model;
|
||||||
} else {
|
} else {
|
||||||
modelTo = lookupModel(models, i8n.singularize(modelTo)) ||
|
modelTo = lookupModel(models, i8n.singularize(modelTo)) || modelTo;
|
||||||
modelTo;
|
|
||||||
}
|
}
|
||||||
if (typeof modelTo === 'string') {
|
if (typeof modelTo === 'string') {
|
||||||
throw new Error('Could not find "' + modelTo + '" relation for ' + modelFrom.modelName);
|
throw new Error('Could not find "' + modelTo + '" relation for ' + modelFrom.modelName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!params.through) {
|
if (!params.through) {
|
||||||
|
if (params.polymorphic) throw new Error('Polymorphic relations need a through model');
|
||||||
var name1 = modelFrom.modelName + modelTo.modelName;
|
var name1 = modelFrom.modelName + modelTo.modelName;
|
||||||
var name2 = modelTo.modelName + modelFrom.modelName;
|
var name2 = modelTo.modelName + modelFrom.modelName;
|
||||||
params.through = lookupModel(models, name1) || lookupModel(models, name2) ||
|
params.through = lookupModel(models, name1) || lookupModel(models, name2) ||
|
||||||
modelFrom.dataSource.define(name1);
|
modelFrom.dataSource.define(name1);
|
||||||
}
|
}
|
||||||
params.through.belongsTo(modelFrom);
|
|
||||||
|
var options = {as: params.as, through: params.through};
|
||||||
|
options.properties = params.properties;
|
||||||
|
options.scope = params.scope;
|
||||||
|
|
||||||
|
if (params.polymorphic) {
|
||||||
|
var polymorphic = polymorphicParams(params.polymorphic);
|
||||||
|
options.polymorphic = polymorphic; // pass through
|
||||||
|
var accessor = params.through.prototype[polymorphic.as];
|
||||||
|
if (typeof accessor !== 'function') { // declare once
|
||||||
|
// use the name of the polymorphic rel, not modelTo
|
||||||
|
params.through.belongsTo(polymorphic.as, { polymorphic: true });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
params.through.belongsTo(modelFrom);
|
||||||
|
}
|
||||||
|
|
||||||
params.through.belongsTo(modelTo);
|
params.through.belongsTo(modelTo);
|
||||||
|
|
||||||
this.hasMany(modelFrom, modelTo, {as: params.as, through: params.through});
|
this.hasMany(modelFrom, modelTo, options);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1039,6 +1167,16 @@ RelationDefinition.hasOne = function (modelFrom, modelTo, params) {
|
||||||
var relationName = params.as || i8n.camelize(modelTo.modelName, true);
|
var relationName = params.as || i8n.camelize(modelTo.modelName, true);
|
||||||
|
|
||||||
var fk = params.foreignKey || i8n.camelize(modelFrom.modelName + '_id', true);
|
var fk = params.foreignKey || i8n.camelize(modelFrom.modelName + '_id', true);
|
||||||
|
var discriminator;
|
||||||
|
|
||||||
|
if (params.polymorphic) {
|
||||||
|
var polymorphic = polymorphicParams(params.polymorphic);
|
||||||
|
fk = polymorphic.foreignKey;
|
||||||
|
discriminator = polymorphic.discriminator;
|
||||||
|
if (!params.through) {
|
||||||
|
modelTo.dataSource.defineProperty(modelTo.modelName, discriminator, { type: 'string', index: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var relationDef = modelFrom.relations[relationName] = new RelationDefinition({
|
var relationDef = modelFrom.relations[relationName] = new RelationDefinition({
|
||||||
name: relationName,
|
name: relationName,
|
||||||
|
@ -1046,6 +1184,7 @@ RelationDefinition.hasOne = function (modelFrom, modelTo, params) {
|
||||||
modelFrom: modelFrom,
|
modelFrom: modelFrom,
|
||||||
keyFrom: pk,
|
keyFrom: pk,
|
||||||
keyTo: fk,
|
keyTo: fk,
|
||||||
|
discriminator: discriminator,
|
||||||
modelTo: modelTo,
|
modelTo: modelTo,
|
||||||
properties: params.properties,
|
properties: params.properties,
|
||||||
options: params.options
|
options: params.options
|
||||||
|
|
|
@ -3,6 +3,7 @@ var should = require('./init.js');
|
||||||
|
|
||||||
var db, Book, Chapter, Author, Reader;
|
var db, Book, Chapter, Author, Reader;
|
||||||
var Category, Product;
|
var Category, Product;
|
||||||
|
var Picture, PictureLink;
|
||||||
|
|
||||||
describe('relations', function () {
|
describe('relations', function () {
|
||||||
|
|
||||||
|
@ -526,6 +527,481 @@ describe('relations', function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('polymorphic hasOne', function () {
|
||||||
|
before(function (done) {
|
||||||
|
db = getSchema();
|
||||||
|
Picture = db.define('Picture', {name: String});
|
||||||
|
Author = db.define('Author', {name: String});
|
||||||
|
Reader = db.define('Reader', {name: String});
|
||||||
|
|
||||||
|
db.automigrate(function () {
|
||||||
|
Picture.destroyAll(function () {
|
||||||
|
Author.destroyAll(function () {
|
||||||
|
Reader.destroyAll(done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can be declared', function (done) {
|
||||||
|
Author.hasOne(Picture, { as: 'avatar', polymorphic: 'imageable' });
|
||||||
|
Reader.hasOne(Picture, { as: 'mugshot', polymorphic: 'imageable' });
|
||||||
|
Picture.belongsTo('imageable', { polymorphic: true });
|
||||||
|
db.automigrate(done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create polymorphic relation - author', function (done) {
|
||||||
|
Author.create({name: 'Author 1' }, function (err, author) {
|
||||||
|
author.avatar.create({ name: 'Avatar' }, function (err, p) {
|
||||||
|
should.not.exist(err);
|
||||||
|
should.exist(p);
|
||||||
|
p.imageableId.should.equal(author.id);
|
||||||
|
p.imageableType.should.equal('Author');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create polymorphic relation - reader', function (done) {
|
||||||
|
Reader.create({name: 'Reader 1' }, function (err, reader) {
|
||||||
|
reader.mugshot.create({ name: 'Mugshot' }, function (err, p) {
|
||||||
|
should.not.exist(err);
|
||||||
|
should.exist(p);
|
||||||
|
p.imageableId.should.equal(reader.id);
|
||||||
|
p.imageableType.should.equal('Reader');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should find polymorphic relation - author', function (done) {
|
||||||
|
Author.findOne(function (err, author) {
|
||||||
|
author.avatar(function (err, p) {
|
||||||
|
should.not.exist(err);
|
||||||
|
p.name.should.equal('Avatar');
|
||||||
|
p.imageableId.should.equal(author.id);
|
||||||
|
p.imageableType.should.equal('Author');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should find polymorphic relation - reader', function (done) {
|
||||||
|
Reader.findOne(function (err, reader) {
|
||||||
|
reader.mugshot(function (err, p) {
|
||||||
|
should.not.exist(err);
|
||||||
|
p.name.should.equal('Mugshot');
|
||||||
|
p.imageableId.should.equal(reader.id);
|
||||||
|
p.imageableType.should.equal('Reader');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should find inverse polymorphic relation - author', function (done) {
|
||||||
|
Picture.findOne({ where: { name: 'Avatar' } }, function (err, p) {
|
||||||
|
p.imageable(function (err, imageable) {
|
||||||
|
should.not.exist(err);
|
||||||
|
imageable.should.be.instanceof(Author);
|
||||||
|
imageable.name.should.equal('Author 1');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should find inverse polymorphic relation - reader', function (done) {
|
||||||
|
Picture.findOne({ where: { name: 'Mugshot' } }, function (err, p) {
|
||||||
|
p.imageable(function (err, imageable) {
|
||||||
|
should.not.exist(err);
|
||||||
|
imageable.should.be.instanceof(Reader);
|
||||||
|
imageable.name.should.equal('Reader 1');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('polymorphic hasMany', function () {
|
||||||
|
before(function (done) {
|
||||||
|
db = getSchema();
|
||||||
|
Picture = db.define('Picture', {name: String});
|
||||||
|
Author = db.define('Author', {name: String});
|
||||||
|
Reader = db.define('Reader', {name: String});
|
||||||
|
|
||||||
|
db.automigrate(function () {
|
||||||
|
Picture.destroyAll(function () {
|
||||||
|
Author.destroyAll(function () {
|
||||||
|
Reader.destroyAll(done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can be declared', function (done) {
|
||||||
|
Author.hasMany(Picture, { polymorphic: 'imageable' });
|
||||||
|
Reader.hasMany(Picture, { polymorphic: { // alt syntax
|
||||||
|
as: 'imageable', foreignKey: 'imageableId',
|
||||||
|
discriminator: 'imageableType'
|
||||||
|
} });
|
||||||
|
Picture.belongsTo('imageable', { polymorphic: true });
|
||||||
|
db.automigrate(done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create polymorphic relation - author', function (done) {
|
||||||
|
Author.create({ name: 'Author 1' }, function (err, author) {
|
||||||
|
author.pictures.create({ name: 'Author Pic' }, function (err, p) {
|
||||||
|
should.not.exist(err);
|
||||||
|
should.exist(p);
|
||||||
|
p.imageableId.should.equal(author.id);
|
||||||
|
p.imageableType.should.equal('Author');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create polymorphic relation - reader', function (done) {
|
||||||
|
Reader.create({ name: 'Reader 1' }, function (err, reader) {
|
||||||
|
reader.pictures.create({ name: 'Reader Pic' }, function (err, p) {
|
||||||
|
should.not.exist(err);
|
||||||
|
should.exist(p);
|
||||||
|
p.imageableId.should.equal(reader.id);
|
||||||
|
p.imageableType.should.equal('Reader');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should find polymorphic items - author', function (done) {
|
||||||
|
Author.findOne(function (err, author) {
|
||||||
|
author.pictures(function (err, pics) {
|
||||||
|
should.not.exist(err);
|
||||||
|
pics.should.have.length(1);
|
||||||
|
pics[0].name.should.equal('Author Pic');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should find polymorphic items - reader', function (done) {
|
||||||
|
Reader.findOne(function (err, reader) {
|
||||||
|
reader.pictures(function (err, pics) {
|
||||||
|
should.not.exist(err);
|
||||||
|
pics.should.have.length(1);
|
||||||
|
pics[0].name.should.equal('Reader Pic');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should find the inverse of polymorphic relation - author', function (done) {
|
||||||
|
Picture.findOne({ where: { name: 'Author Pic' } }, function (err, p) {
|
||||||
|
should.not.exist(err);
|
||||||
|
p.imageableType.should.equal('Author');
|
||||||
|
p.imageable(function(err, imageable) {
|
||||||
|
should.not.exist(err);
|
||||||
|
imageable.should.be.instanceof(Author);
|
||||||
|
imageable.name.should.equal('Author 1');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should find the inverse of polymorphic relation - reader', function (done) {
|
||||||
|
Picture.findOne({ where: { name: 'Reader Pic' } }, function (err, p) {
|
||||||
|
should.not.exist(err);
|
||||||
|
p.imageableType.should.equal('Reader');
|
||||||
|
p.imageable(function(err, imageable) {
|
||||||
|
should.not.exist(err);
|
||||||
|
imageable.should.be.instanceof(Reader);
|
||||||
|
imageable.name.should.equal('Reader 1');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should include the inverse of polymorphic relation', function (done) {
|
||||||
|
Picture.find({ include: 'imageable' }, function (err, pics) {
|
||||||
|
should.not.exist(err);
|
||||||
|
pics.should.have.length(2);
|
||||||
|
pics[0].name.should.equal('Author Pic');
|
||||||
|
pics[0].imageable().name.should.equal('Author 1');
|
||||||
|
pics[1].name.should.equal('Reader Pic');
|
||||||
|
pics[1].imageable().name.should.equal('Reader 1');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should assign a polymorphic relation', function(done) {
|
||||||
|
Author.create({ name: 'Author 2' }, function(err, author) {
|
||||||
|
var p = new Picture({ name: 'Sample' });
|
||||||
|
p.imageable(author); // assign
|
||||||
|
p.imageableId.should.equal(author.id);
|
||||||
|
p.imageableType.should.equal('Author');
|
||||||
|
p.save(done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should find polymorphic items - author', function (done) {
|
||||||
|
Author.findOne({ where: { name: 'Author 2' } }, function (err, author) {
|
||||||
|
author.pictures(function (err, pics) {
|
||||||
|
should.not.exist(err);
|
||||||
|
pics.should.have.length(1);
|
||||||
|
pics[0].name.should.equal('Sample');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should find the inverse of polymorphic relation - author', function (done) {
|
||||||
|
Picture.findOne({ where: { name: 'Sample' } }, function (err, p) {
|
||||||
|
should.not.exist(err);
|
||||||
|
p.imageableType.should.equal('Author');
|
||||||
|
p.imageable(function(err, imageable) {
|
||||||
|
should.not.exist(err);
|
||||||
|
imageable.should.be.instanceof(Author);
|
||||||
|
imageable.name.should.equal('Author 2');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
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' });
|
||||||
|
// Optionally, define inverse relations:
|
||||||
|
Picture.hasMany(Author, { through: PictureLink, polymorphic: 'imageable', invert: true });
|
||||||
|
Picture.hasMany(Reader, { through: PictureLink, polymorphic: 'imageable', invert: true });
|
||||||
|
db.automigrate(done);
|
||||||
|
});
|
||||||
|
|
||||||
|
var author, reader, pictures = [];
|
||||||
|
it('should create polymorphic relation - author', function (done) {
|
||||||
|
Author.create({ name: 'Author 1' }, function (err, a) {
|
||||||
|
should.not.exist(err);
|
||||||
|
author = a;
|
||||||
|
author.pictures.create({ name: 'Author Pic 1' }, function (err, p) {
|
||||||
|
should.not.exist(err);
|
||||||
|
pictures.push(p);
|
||||||
|
author.pictures.create({ name: 'Author Pic 2' }, function (err, p) {
|
||||||
|
should.not.exist(err);
|
||||||
|
pictures.push(p);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create polymorphic relation - reader', function (done) {
|
||||||
|
Reader.create({ name: 'Reader 1' }, function (err, r) {
|
||||||
|
should.not.exist(err);
|
||||||
|
reader = r;
|
||||||
|
reader.pictures.create({ name: 'Reader Pic 1' }, function (err, p) {
|
||||||
|
should.not.exist(err);
|
||||||
|
pictures.push(p);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create polymorphic through model', function (done) {
|
||||||
|
PictureLink.findOne(function(err, link) {
|
||||||
|
should.not.exist(err);
|
||||||
|
link.pictureId.should.eql(pictures[0].id); // eql for mongo ObjectId
|
||||||
|
link.imageableId.should.eql(author.id);
|
||||||
|
link.imageableType.should.equal('Author');
|
||||||
|
link.imageable(function(err, imageable) {
|
||||||
|
imageable.should.be.instanceof(Author);
|
||||||
|
imageable.id.should.eql(author.id);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get polymorphic relation through model - author', function (done) {
|
||||||
|
Author.findById(author.id, 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(reader.id, 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();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should include polymorphic items', function (done) {
|
||||||
|
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();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
var anotherPicture;
|
||||||
|
it('should add to a polymorphic relation - author', function (done) {
|
||||||
|
Author.findById(author.id, function(err, author) {
|
||||||
|
Picture.create({name: 'Example' }, function(err, p) {
|
||||||
|
should.not.exist(err);
|
||||||
|
pictures.push(p);
|
||||||
|
anotherPicture = p;
|
||||||
|
author.pictures.add(p, function(err, link) {
|
||||||
|
link.should.be.instanceof(PictureLink);
|
||||||
|
link.pictureId.should.eql(p.id);
|
||||||
|
link.imageableId.should.eql(author.id);
|
||||||
|
link.imageableType.should.equal('Author');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create polymorphic through model', function (done) {
|
||||||
|
PictureLink.findOne({ where: { pictureId: anotherPicture.id, imageableType: 'Author' } }, function(err, link) {
|
||||||
|
should.not.exist(err);
|
||||||
|
link.pictureId.should.eql(anotherPicture.id);
|
||||||
|
link.imageableId.should.eql(author.id);
|
||||||
|
link.imageableType.should.equal('Author');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
var anotherAuthor, anotherReader;
|
||||||
|
it('should add to a polymorphic relation - author', function (done) {
|
||||||
|
Author.create({ name: 'Author 2' }, function (err, author) {
|
||||||
|
should.not.exist(err);
|
||||||
|
anotherAuthor = author;
|
||||||
|
author.pictures.add(anotherPicture.id, function (err, p) {
|
||||||
|
should.not.exist(err);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add to a polymorphic relation - author', function (done) {
|
||||||
|
Reader.create({name: 'Reader 2' }, function (err, reader) {
|
||||||
|
should.not.exist(err);
|
||||||
|
anotherReader = reader;
|
||||||
|
reader.pictures.add(anotherPicture.id, function (err, p) {
|
||||||
|
should.not.exist(err);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get the inverse polymorphic relation - author', function (done) {
|
||||||
|
Picture.findById(anotherPicture.id, 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(anotherPicture.id, 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(author.id, 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(author.id, function(err, author) {
|
||||||
|
author.pictures.exists(anotherPicture.id, function(err, exists) {
|
||||||
|
exists.should.be.true;
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should remove from a polymorphic relation - author', function (done) {
|
||||||
|
Author.findById(author.id, function(err, author) {
|
||||||
|
author.pictures.remove(anotherPicture.id, function(err) {
|
||||||
|
should.not.exist(err);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should find polymorphic items - author', function (done) {
|
||||||
|
Author.findById(author.id, 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(author.id, function(err, author) {
|
||||||
|
author.pictures.exists(7, function(err, exists) {
|
||||||
|
exists.should.be.false;
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
describe('belongsTo', function () {
|
describe('belongsTo', function () {
|
||||||
var List, Item, Fear, Mind;
|
var List, Item, Fear, Mind;
|
||||||
|
@ -596,10 +1072,12 @@ describe('relations', function () {
|
||||||
});
|
});
|
||||||
db.automigrate(done);
|
db.automigrate(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var personCreated;
|
||||||
it('should create record on scope', function (done) {
|
it('should create record on scope', function (done) {
|
||||||
var p = new Passport({ name: 'Passport', notes: 'Some notes...' });
|
var p = new Passport({ name: 'Passport', notes: 'Some notes...' });
|
||||||
p.person.create({ id: 3, name: 'Fred', age: 36 }, function(err, person) {
|
p.person.create({name: 'Fred', age: 36 }, function(err, person) {
|
||||||
|
personCreated = person;
|
||||||
p.personId.should.equal(person.id);
|
p.personId.should.equal(person.id);
|
||||||
p.save(function (err, p) {
|
p.save(function (err, p) {
|
||||||
person.name.should.equal('Fred');
|
person.name.should.equal('Fred');
|
||||||
|
@ -611,7 +1089,7 @@ describe('relations', function () {
|
||||||
|
|
||||||
it('should find record on scope', function (done) {
|
it('should find record on scope', function (done) {
|
||||||
Passport.findOne(function (err, p) {
|
Passport.findOne(function (err, p) {
|
||||||
p.personId.should.equal(3);
|
p.personId.should.equal(personCreated.id);
|
||||||
p.person(function(err, person) {
|
p.person(function(err, person) {
|
||||||
person.name.should.equal('Fred');
|
person.name.should.equal('Fred');
|
||||||
person.should.not.have.property('age');
|
person.should.not.have.property('age');
|
||||||
|
|
Loading…
Reference in New Issue