Add support for hasMany-through and more tests
This commit is contained in:
parent
4fbec288c4
commit
68cf633795
|
@ -12,6 +12,7 @@ var EventEmitter = require('events').EventEmitter;
|
|||
var util = require('util');
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
var assert = require('assert');
|
||||
var async = require('async');
|
||||
|
||||
var existsSync = fs.existsSync || path.existsSync;
|
||||
|
@ -302,6 +303,13 @@ DataSource.prototype.setup = function(name, settings) {
|
|||
};
|
||||
};
|
||||
|
||||
function isModelClass(cls) {
|
||||
if(!cls) {
|
||||
return false;
|
||||
}
|
||||
return cls.prototype instanceof ModelBaseClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define a model class
|
||||
*
|
||||
|
@ -383,33 +391,62 @@ DataSource.prototype.createModel = DataSource.prototype.define = function define
|
|||
var relations = settings.relationships || settings.relations;
|
||||
|
||||
// Create a function for the closure in the loop
|
||||
var createListener = function(name, relation, targetModel) {
|
||||
targetModel.once('defined', function(model) {
|
||||
// The target model is resolved
|
||||
var params = {
|
||||
foreignKey: relation.foreignKey,
|
||||
as: name,
|
||||
model: model
|
||||
};
|
||||
NewClass[relation.type].call(NewClass, name, params);
|
||||
});
|
||||
var createListener = function (name, relation, targetModel, throughModel) {
|
||||
if (targetModel && targetModel.settings.unresolved) {
|
||||
targetModel.once('defined', function (model) {
|
||||
// Check if the through model doesn't exist or resolved
|
||||
if (!throughModel || !throughModel.settings.unresolved) {
|
||||
// The target model is resolved
|
||||
var params = {
|
||||
foreignKey: relation.foreignKey,
|
||||
as: name,
|
||||
model: model
|
||||
};
|
||||
if (throughModel) {
|
||||
params.through = throughModel;
|
||||
}
|
||||
NewClass[relation.type].call(NewClass, name, params);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (throughModel && throughModel.settings.unresolved) {
|
||||
// Set up a listener to the through model
|
||||
throughModel.once('defined', function (model) {
|
||||
if (!targetModel.settings.unresolved) {
|
||||
// The target model is resolved
|
||||
var params = {
|
||||
foreignKey: relation.foreignKey,
|
||||
as: name,
|
||||
model: targetModel,
|
||||
through: model
|
||||
};
|
||||
NewClass[relation.type].call(NewClass, name, params);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Set up the relations
|
||||
if (relations) {
|
||||
for (var rn in relations) {
|
||||
var r = relations[rn];
|
||||
if (!r.type) {
|
||||
throw new Error('Relation type is required for ' + r);
|
||||
}
|
||||
var targetModel = this.models[r.model];
|
||||
assert(['belongsTo', 'hasMany', 'hasAndBelongsToMany'].indexOf(r.type) !== -1, "Invalid relation type: " + r.type);
|
||||
var targetModel = isModelClass(r.model) ? r.model : this.models[r.model];
|
||||
if(!targetModel) {
|
||||
// The target model doesn't exist, let create a place holder for it
|
||||
targetModel = this.define(r.model, {}, {unresolved: true});
|
||||
}
|
||||
if(targetModel.settings.unresolved) {
|
||||
var throughModel = null;
|
||||
if(r.through) {
|
||||
throughModel = isModelClass(r.through) ? r.through : this.models[r.through];
|
||||
if(!throughModel) {
|
||||
// The through model doesn't exist, let create a place holder for it
|
||||
throughModel = this.define(r.through, {}, {unresolved: true});
|
||||
}
|
||||
}
|
||||
if(targetModel.settings.unresolved || (throughModel && throughModel.settings.unresolved)) {
|
||||
// Create a listener to defer the relation set up
|
||||
createListener(rn, r, targetModel);
|
||||
createListener(rn, r, targetModel, throughModel);
|
||||
} else {
|
||||
// The target model is resolved
|
||||
var params = {
|
||||
|
@ -417,6 +454,9 @@ DataSource.prototype.createModel = DataSource.prototype.define = function define
|
|||
as: rn,
|
||||
model: targetModel
|
||||
};
|
||||
if(throughModel) {
|
||||
params.through = throughModel;
|
||||
}
|
||||
NewClass[r.type].call(NewClass, rn, params);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -444,6 +444,10 @@ describe('Load models with relations', function () {
|
|||
var ds = new DataSource('memory');
|
||||
|
||||
var User = ds.define('User', {name: String}, {relations: {posts: {type: 'hasMany', model: 'Post'}, accounts: {type: 'hasMany', model: 'Account'}}});
|
||||
|
||||
assert(!User.relations['posts']);
|
||||
assert(!User.relations['accounts']);
|
||||
|
||||
var Post = ds.define('Post', {userId: Number, content: String}, {relations: {user: {type: 'belongsTo', model: 'User'}}});
|
||||
|
||||
var Account = ds.define('Account', {userId: Number, type: String}, {relations: {user: {type: 'belongsTo', model: 'User'}}});
|
||||
|
@ -489,6 +493,44 @@ describe('Load models with relations', function () {
|
|||
|
||||
});
|
||||
|
||||
it('should throw if the relation type is invalid', function (done) {
|
||||
var ds = new DataSource('memory');
|
||||
|
||||
var Post = ds.define('Post', {userId: Number, content: String});
|
||||
|
||||
try {
|
||||
var User = ds.define('User', {name: String}, {relations: {posts: {type: 'hasXYZ', model: 'Post'}}});
|
||||
} catch (e) {
|
||||
done();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
it('should handle hasMany through', function (done) {
|
||||
var ds = new DataSource('memory');
|
||||
var Physician = ds.createModel('Physician', {
|
||||
name: String
|
||||
}, {relations: {patients: {model: 'Patient', type: 'hasMany', through: 'Appointment'}}});
|
||||
|
||||
var Patient = ds.createModel('Patient', {
|
||||
name: String
|
||||
}, {relations: {physicians: {model: 'Physician', type: 'hasMany', through: 'Appointment'}}});
|
||||
|
||||
assert(!Physician.relations['patients']); // Appointment hasn't been resolved yet
|
||||
assert(!Patient.relations['physicians']); // Appointment hasn't been resolved yet
|
||||
|
||||
var Appointment = ds.createModel('Appointment', {
|
||||
physicianId: Number,
|
||||
patientId: Number,
|
||||
appointmentDate: Date
|
||||
}, {relations: {patient: {type: 'belongsTo', model: 'Patient'}, physician: {type: 'belongsTo', model: 'Physician'}}});
|
||||
|
||||
assert(Physician.relations['patients']);
|
||||
assert(Patient.relations['physicians']);
|
||||
done();
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
describe('Load models from json', function () {
|
||||
|
|
Loading…
Reference in New Issue