Refactor tests and codes
Signed-off-by: Clark Wang <clark.wangs@gmail.com>
This commit is contained in:
parent
26547f8461
commit
b6f2026493
|
@ -540,13 +540,17 @@ RelationDefinition.hasMany = function hasMany(modelFrom, modelTo, params) {
|
||||||
|
|
||||||
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 keyThrough = params.keyThrough || i8n.camelize(modelTo.modelName + '_id', true);
|
||||||
|
|
||||||
var idName = modelFrom.dataSource.idName(modelFrom.modelName) || 'id';
|
var idName = modelFrom.dataSource.idName(modelFrom.modelName) || 'id';
|
||||||
var discriminator, polymorphic;
|
var discriminator, polymorphic;
|
||||||
|
|
||||||
if (params.polymorphic) {
|
if (params.polymorphic) {
|
||||||
polymorphic = polymorphicParams(params.polymorphic);
|
polymorphic = polymorphicParams(params.polymorphic);
|
||||||
if (params.invert) polymorphic.invert = true;
|
if (params.invert) {
|
||||||
|
polymorphic.invert = true;
|
||||||
|
keyThrough = polymorphic.foreignKey;
|
||||||
|
}
|
||||||
discriminator = polymorphic.discriminator;
|
discriminator = polymorphic.discriminator;
|
||||||
if (!params.invert) {
|
if (!params.invert) {
|
||||||
fk = polymorphic.foreignKey;
|
fk = polymorphic.foreignKey;
|
||||||
|
@ -567,14 +571,12 @@ RelationDefinition.hasMany = function hasMany(modelFrom, modelTo, params) {
|
||||||
properties: params.properties,
|
properties: params.properties,
|
||||||
scope: params.scope,
|
scope: params.scope,
|
||||||
options: params.options,
|
options: params.options,
|
||||||
|
keyThrough: keyThrough,
|
||||||
polymorphic: polymorphic
|
polymorphic: polymorphic
|
||||||
});
|
});
|
||||||
|
|
||||||
definition.modelThrough = params.through;
|
definition.modelThrough = params.through;
|
||||||
|
|
||||||
var keyThrough = params.keyThrough || i8n.camelize(modelTo.modelName + '_id', true);
|
|
||||||
definition.keyThrough = keyThrough;
|
|
||||||
|
|
||||||
modelFrom.relations[relationName] = definition;
|
modelFrom.relations[relationName] = definition;
|
||||||
|
|
||||||
if (!params.through) {
|
if (!params.through) {
|
||||||
|
@ -636,32 +638,35 @@ RelationDefinition.hasMany = function hasMany(modelFrom, modelTo, params) {
|
||||||
|
|
||||||
definition.applyScope(this, filter);
|
definition.applyScope(this, filter);
|
||||||
|
|
||||||
if (params.through) {
|
if (definition.modelThrough) {
|
||||||
|
|
||||||
// find corresponding belongsTo relations from through model as include
|
// find corresponding belongsTo relations from through model as collect
|
||||||
var include = [];
|
var throughRelationName;
|
||||||
Object.keys(params.through.relations).forEach(function (rn) {
|
for(var r in definition.modelThrough.relations) {
|
||||||
var relation = params.through.relations[rn];
|
var relation = definition.modelThrough.relations[r];
|
||||||
|
|
||||||
// should be a belongsTo and match modelTo
|
// should be a belongsTo and match modelTo and keyThrough
|
||||||
if (relation.type === RelationTypes.belongsTo && relation.modelTo === modelTo) {
|
// if relation is polymorphic then check keyThrough only
|
||||||
|
if (relation.type === RelationTypes.belongsTo &&
|
||||||
// should match keyThrough if specified
|
(relation.polymorphic && !relation.modelTo || relation.modelTo === definition.modelTo) &&
|
||||||
if (params.keyThrough && relation.keyFrom !== params.keyThrough) return;
|
(relation.keyFrom === definition.keyThrough)
|
||||||
|
) {
|
||||||
if (include.indexOf(relation.name) === -1) {
|
throughRelationName = relation.name;
|
||||||
include.push(relation.name);
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
if (params.polymorphic && params.invert) {
|
if (!throughRelationName) {
|
||||||
filter.where[discriminator] = modelTo.modelName; // overwrite
|
throw new Error('Relation "' + relationName + '": Can\'t find belongsTo relation in through model '
|
||||||
filter.collect = params.polymorphic;
|
+ definition.modelThrough.modelName + '.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (definition.polymorphic && definition.polymorphic.invert) {
|
||||||
|
filter.collect = throughRelationName || definition.polymorphic.as;
|
||||||
filter.include = filter.collect;
|
filter.include = filter.collect;
|
||||||
} else {
|
} else {
|
||||||
filter.collect = i8n.camelize(modelTo.modelName, true);
|
filter.collect = throughRelationName || i8n.camelize(modelTo.modelName, true);
|
||||||
filter.include = include.join();
|
filter.include = filter.collect;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -257,17 +257,6 @@ describe('relations', function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should have scope that includes a relation name which is derived from model\'s name', function (done) {
|
|
||||||
Physician.create(function (err, physician) {
|
|
||||||
should.not.exist(err);
|
|
||||||
should.exist(physician);
|
|
||||||
var scope = physician.patients._scope;
|
|
||||||
scope.should.have.property('collect', 'patient');
|
|
||||||
scope.should.have.property('include', 'patient');
|
|
||||||
done(err);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should build record on scope', function (done) {
|
it('should build record on scope', function (done) {
|
||||||
Physician.create(function (err, physician) {
|
Physician.create(function (err, physician) {
|
||||||
var patient = physician.patients.build();
|
var patient = physician.patients.build();
|
||||||
|
@ -474,133 +463,159 @@ describe('relations', function () {
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('hasMany through with custom relation name', function () {
|
describe('hasMany through - collect', function () {
|
||||||
var Physician, Patient, Appointment, Address;
|
var Physician, Patient, Appointment, Address;
|
||||||
|
|
||||||
describe('and with keyThrough', function () {
|
beforeEach(function (done) {
|
||||||
before(function (done) {
|
db = getSchema();
|
||||||
db = getSchema();
|
Physician = db.define('Physician', {name: String});
|
||||||
Physician = db.define('Physician', {name: String});
|
Patient = db.define('Patient', {name: String});
|
||||||
Patient = db.define('Patient', {name: String});
|
Appointment = db.define('Appointment', {date: {type: Date,
|
||||||
Appointment = db.define('Appointment', {date: {type: Date,
|
default: function () {
|
||||||
default: function () {
|
return new Date();
|
||||||
return new Date();
|
}}});
|
||||||
}}});
|
Address = db.define('Address', {name: String});
|
||||||
Address = db.define('Address', {name: String});
|
|
||||||
|
|
||||||
|
db.automigrate(['Physician', 'Patient', 'Appointment', 'Address'], function (err) {
|
||||||
|
done(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with default options', function () {
|
||||||
|
it('can determine the collect by modelTo\'s name as default', function () {
|
||||||
|
Physician.hasMany(Patient, {through: Appointment});
|
||||||
|
Patient.hasMany(Physician, {through: Appointment});
|
||||||
|
Patient.belongsTo(Address);
|
||||||
|
Appointment.belongsTo(Physician);
|
||||||
|
Appointment.belongsTo(Patient);
|
||||||
|
var physician = new Physician({id: 1});
|
||||||
|
var scope1 = physician.patients._scope;
|
||||||
|
scope1.should.have.property('collect', 'patient');
|
||||||
|
scope1.should.have.property('include', 'patient');
|
||||||
|
var patient = new Patient({id: 1});
|
||||||
|
var scope2 = patient.physicians._scope;
|
||||||
|
scope2.should.have.property('collect', 'physician');
|
||||||
|
scope2.should.have.property('include', 'physician');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be irrelevant to the name of hasManyThrough relation', function () {
|
||||||
|
Physician.hasMany(Patient, {through: Appointment, as: 'xxx'});
|
||||||
|
Patient.hasMany(Physician, {through: Appointment, as: 'yyy'});
|
||||||
|
Patient.belongsTo(Address);
|
||||||
|
Appointment.belongsTo(Physician);
|
||||||
|
Appointment.belongsTo(Patient);
|
||||||
|
var physician = new Physician({id: 1});
|
||||||
|
var scope1 = physician.xxx._scope;
|
||||||
|
scope1.should.have.property('collect', 'patient');
|
||||||
|
scope1.should.have.property('include', 'patient');
|
||||||
|
var patient = new Patient({id: 1});
|
||||||
|
var scope2 = patient.yyy._scope;
|
||||||
|
scope2.should.have.property('collect', 'physician');
|
||||||
|
scope2.should.have.property('include', 'physician');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when custom reverse belongsTo names for both sides', function () {
|
||||||
|
it('can determine the collect via keyThrough', function () {
|
||||||
Physician.hasMany(Patient, {as: 'xxx', foreignKey: 'fooId', keyThrough: 'barId', through: Appointment});
|
Physician.hasMany(Patient, {as: 'xxx', foreignKey: 'fooId', keyThrough: 'barId', through: Appointment});
|
||||||
Patient.hasMany(Physician, {as: 'yyy', foreignKey: 'barId', keyThrough: 'fooId', through: Appointment});
|
Patient.hasMany(Physician, {as: 'yyy', foreignKey: 'barId', keyThrough: 'fooId', through: Appointment});
|
||||||
|
Appointment.belongsTo(Physician, {as: 'foo'});
|
||||||
|
Appointment.belongsTo(Patient, {as: 'bar'});
|
||||||
|
Patient.belongsTo(Address); // jam.
|
||||||
|
Appointment.belongsTo(Patient, {as: 'car'}); // jam. Should we complain in this case???
|
||||||
|
|
||||||
|
var physician = new Physician({id: 1});
|
||||||
|
var scope1 = physician.xxx._scope;
|
||||||
|
scope1.should.have.property('collect', 'bar');
|
||||||
|
scope1.should.have.property('include', 'bar');
|
||||||
|
var patient = new Patient({id: 1});
|
||||||
|
var scope2 = patient.yyy._scope;
|
||||||
|
scope2.should.have.property('collect', 'foo');
|
||||||
|
scope2.should.have.property('include', 'foo');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can determine the collect via modelTo name', function () {
|
||||||
|
Physician.hasMany(Patient, {through: Appointment});
|
||||||
|
Patient.hasMany(Physician, {through: Appointment});
|
||||||
|
Appointment.belongsTo(Physician, {as: 'foo', foreignKey: 'physicianId'});
|
||||||
|
Appointment.belongsTo(Patient, {as: 'bar', foreignKey: 'patientId'});
|
||||||
|
Patient.belongsTo(Address); // jam.
|
||||||
|
|
||||||
|
var physician = new Physician({id: 1});
|
||||||
|
var scope1 = physician.patients._scope;
|
||||||
|
scope1.should.have.property('collect', 'bar');
|
||||||
|
scope1.should.have.property('include', 'bar');
|
||||||
|
var patient = new Patient({id: 1});
|
||||||
|
var scope2 = patient.physicians._scope;
|
||||||
|
scope2.should.have.property('collect', 'foo');
|
||||||
|
scope2.should.have.property('include', 'foo');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can determine the collect via modelTo name - error', function () {
|
||||||
|
Physician.hasMany(Patient, {through: Appointment});
|
||||||
|
Patient.hasMany(Physician, {through: Appointment});
|
||||||
|
Appointment.belongsTo(Physician, {as: 'foo', foreignKey: 'physicianId'});
|
||||||
|
Appointment.belongsTo(Patient, {as: 'bar', foreignKey: 'patientId'});
|
||||||
|
Patient.belongsTo(Address); // jam.
|
||||||
|
Appointment.belongsTo(Physician, {as: 'goo', foreignKey: 'physicianId'}); // jam. Should we complain in this case???
|
||||||
|
Appointment.belongsTo(Patient, {as: 'car', foreignKey: 'patientId'}); // jam. Should we complain in this case???
|
||||||
|
|
||||||
|
var physician = new Physician({id: 1});
|
||||||
|
var scope1 = physician.patients._scope;
|
||||||
|
scope1.should.have.property('collect', 'bar');
|
||||||
|
scope1.should.have.property('include', 'bar');
|
||||||
|
var patient = new Patient({id: 1});
|
||||||
|
var scope2 = patient.physicians._scope;
|
||||||
|
scope2.should.have.property('collect', 'foo');
|
||||||
|
scope2.should.have.property('include', 'foo');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be irrelevant to the name of hasManyThrough relation', function () {
|
||||||
|
Physician.hasMany(Patient, {foreignKey: 'fooId', keyThrough: 'barId', through: Appointment});
|
||||||
|
Patient.hasMany(Physician, {foreignKey: 'barId', keyThrough: 'fooId', through: Appointment});
|
||||||
Patient.belongsTo(Address);
|
Patient.belongsTo(Address);
|
||||||
Appointment.belongsTo(Physician, {as: 'foo'});
|
Appointment.belongsTo(Physician, {as: 'foo'});
|
||||||
Appointment.belongsTo(Patient, {as: 'bar'});
|
Appointment.belongsTo(Patient, {as: 'bar'});
|
||||||
Appointment.belongsTo(Patient, {as: 'car'});
|
|
||||||
Appointment.belongsTo(Patient, {as: 'dar'});
|
|
||||||
db.automigrate(['Physician', 'Patient', 'Appointment', 'Address'], function (err) {
|
|
||||||
done(err);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should have scope that includes relation name which matches keyThrough', function (done) {
|
var physician = new Physician({id: 1});
|
||||||
Physician.create(function (err, physician) {
|
var scope1 = physician.patients._scope;
|
||||||
should.not.exist(err);
|
scope1.should.have.property('collect', 'bar');
|
||||||
should.exist(physician);
|
scope1.should.have.property('include', 'bar');
|
||||||
var scope = physician.xxx._scope;
|
var patient = new Patient({id: 1});
|
||||||
scope.should.have.property('collect', 'patient');
|
var scope2 = patient.physicians._scope;
|
||||||
scope.should.have.property('include', 'bar');
|
scope2.should.have.property('collect', 'foo');
|
||||||
done(err);
|
scope2.should.have.property('include', 'foo');
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should fetch all scoped instances', function (done) {
|
|
||||||
Physician.create(function (err, physician) {
|
|
||||||
physician.xxx.create({name: 'a'}, function () {
|
|
||||||
physician.xxx.create({name: 'z'}, function () {
|
|
||||||
physician.xxx.create({name: 'c'}, function () {
|
|
||||||
verify(physician);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
function verify(physician) {
|
|
||||||
physician.xxx(true, function (err, ch) {
|
|
||||||
should.not.exist(err);
|
|
||||||
should.exist(ch);
|
|
||||||
ch.should.have.lengthOf(3);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('and without keyThrough', function () {
|
describe('when custom reverse belongsTo name for one side only', function () {
|
||||||
before(function (done) {
|
|
||||||
db = getSchema();
|
|
||||||
Physician = db.define('Physician', {name: String});
|
|
||||||
Patient = db.define('Patient', {name: String});
|
|
||||||
Appointment = db.define('Appointment', {date: {type: Date,
|
|
||||||
default: function () {
|
|
||||||
return new Date();
|
|
||||||
}}});
|
|
||||||
Address = db.define('Address', {name: String});
|
|
||||||
|
|
||||||
Physician.hasMany(Patient, {as: 'xxx', foreignKey: 'fooId', through: Appointment});
|
beforeEach(function () {
|
||||||
Patient.hasMany(Physician, {as: 'yyy', foreignKey: 'barId', through: Appointment});
|
Physician.hasMany(Patient, {as: 'xxx', through: Appointment, foreignKey: 'fooId'});
|
||||||
Patient.belongsTo(Address);
|
Patient.hasMany(Physician, {as: 'yyy', through: Appointment, keyThrough: 'fooId'});
|
||||||
Appointment.belongsTo(Physician, {as: 'foo'});
|
Appointment.belongsTo(Physician, {as: 'foo'});
|
||||||
Appointment.belongsTo(Patient, {as: 'bar'});
|
Appointment.belongsTo(Patient);
|
||||||
db.automigrate(['Physician', 'Patient', 'Appointment', 'Address'], function (err) {
|
Patient.belongsTo(Address); // jam.
|
||||||
done(err);
|
Appointment.belongsTo(Physician, {as: 'bar'}); // jam. Should we complain in this case???
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should have scope that includes relation name which matches the name of modelTo', function (done) {
|
it('can determine the collect via model name', function () {
|
||||||
Physician.create(function (err, physician) {
|
var physician = new Physician({id: 1});
|
||||||
should.not.exist(err);
|
var scope1 = physician.xxx._scope;
|
||||||
should.exist(physician);
|
scope1.should.have.property('collect', 'patient');
|
||||||
var scope = physician.xxx._scope;
|
scope1.should.have.property('include', 'patient');
|
||||||
scope.should.have.property('collect', 'patient');
|
|
||||||
scope.should.have.property('include', 'bar');
|
|
||||||
done(err);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('and with multiple relations for same model', function () {
|
|
||||||
before(function (done) {
|
|
||||||
db = getSchema();
|
|
||||||
Physician = db.define('Physician', {name: String});
|
|
||||||
Patient = db.define('Patient', {name: String});
|
|
||||||
Appointment = db.define('Appointment', {date: {type: Date,
|
|
||||||
default: function () {
|
|
||||||
return new Date();
|
|
||||||
}}});
|
|
||||||
Address = db.define('Address', {name: String});
|
|
||||||
|
|
||||||
Physician.hasMany(Patient, {as: 'xxx', foreignKey: 'fooId', through: Appointment});
|
|
||||||
Patient.hasMany(Physician, {as: 'yyy', foreignKey: 'barId', through: Appointment});
|
|
||||||
Patient.belongsTo(Address);
|
|
||||||
Appointment.belongsTo(Physician, {as: 'foo'});
|
|
||||||
Appointment.belongsTo(Patient, {as: 'bar'});
|
|
||||||
Appointment.belongsTo(Patient, {as: 'car'});
|
|
||||||
db.automigrate(['Physician', 'Patient', 'Appointment', 'Address'], function (err) {
|
|
||||||
done(err);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should have scope that includes all relation names which matches the name of modelTo', function (done) {
|
it('can determine the collect via keyThrough', function () {
|
||||||
Physician.create(function (err, physician) {
|
var patient = new Patient({id: 1});
|
||||||
should.not.exist(err);
|
var scope2 = patient.yyy._scope;
|
||||||
should.exist(physician);
|
scope2.should.have.property('collect', 'foo');
|
||||||
var scope = physician.xxx._scope;
|
scope2.should.have.property('include', 'foo');
|
||||||
scope.should.have.property('collect', 'patient');
|
|
||||||
scope.should.have.property('include', 'bar,car');
|
|
||||||
done(err);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('hasMany through between same model', function () {
|
describe('hasMany through - between same model', function () {
|
||||||
var User, Follow, Address;
|
var User, Follow, Address;
|
||||||
|
|
||||||
before(function (done) {
|
before(function (done) {
|
||||||
|
@ -622,18 +637,14 @@ describe('relations', function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should have scope that includes corresponding relation name', function (done) {
|
it('can determine the collect via keyThrough for each side', function () {
|
||||||
User.create(function (err, user) {
|
var user = new User({id: 1});
|
||||||
should.not.exist(err);
|
var scope1 = user.followers._scope;
|
||||||
should.exist(user);
|
scope1.should.have.property('collect', 'follower');
|
||||||
var scope1 = user.followers._scope;
|
scope1.should.have.property('include', 'follower');
|
||||||
scope1.should.have.property('collect', 'user');
|
var scope2 = user.following._scope;
|
||||||
scope1.should.have.property('include', 'follower');
|
scope2.should.have.property('collect', 'followee');
|
||||||
var scope2 = user.following._scope;
|
scope2.should.have.property('include', 'followee');
|
||||||
scope2.should.have.property('collect', 'user');
|
|
||||||
scope2.should.have.property('include', 'followee');
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1089,6 +1100,29 @@ describe('relations', function () {
|
||||||
db.automigrate(done);
|
db.automigrate(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('can determine the collect via modelTo name', function () {
|
||||||
|
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 });
|
||||||
|
var author = new Author({id: 1});
|
||||||
|
var scope1 = author.pictures._scope;
|
||||||
|
scope1.should.have.property('collect', 'picture');
|
||||||
|
scope1.should.have.property('include', 'picture');
|
||||||
|
var reader = new Reader({id: 1});
|
||||||
|
var scope2 = reader.pictures._scope;
|
||||||
|
scope2.should.have.property('collect', 'picture');
|
||||||
|
scope2.should.have.property('include', 'picture');
|
||||||
|
var picture = new Picture({id: 1});
|
||||||
|
var scope3 = picture.authors._scope;
|
||||||
|
scope3.should.have.property('collect', 'imageable');
|
||||||
|
scope3.should.have.property('include', 'imageable');
|
||||||
|
var scope4 = picture.readers._scope;
|
||||||
|
scope4.should.have.property('collect', 'imageable');
|
||||||
|
scope4.should.have.property('include', 'imageable');
|
||||||
|
});
|
||||||
|
|
||||||
var author, reader, pictures = [];
|
var author, reader, pictures = [];
|
||||||
it('should create polymorphic relation - author', function (done) {
|
it('should create polymorphic relation - author', function (done) {
|
||||||
Author.create({ name: 'Author 1' }, function (err, a) {
|
Author.create({ name: 'Author 1' }, function (err, a) {
|
||||||
|
|
Loading…
Reference in New Issue