Permalink
Browse files

More work on 'through' associations

  • Loading branch information...
1 parent ad4a623 commit ff09665d1da7e0366f46ab88bb86aa9f3f4371bf mde committed Mar 28, 2013
Showing with 68 additions and 15 deletions.
  1. +55 −9 lib/index.js
  2. +13 −4 test/adapters/shared.js
  3. +0 −2 test/fixtures/membership.js
View
@@ -41,7 +41,8 @@ User.prototype.someMethod = function () {
User = model.register('User', User);
*/
-var model = {}
+var util = require('util') // Native Node util module
+ , model = {}
, EventEmitter = require('events').EventEmitter
, utils = require('utilities')
, adapters = require('./adapters')
@@ -205,7 +206,8 @@ utils.mixin(model, new (function () {
, queryName
, reg = model.descriptionRegistry
, assn = reg[this.type].associations[assnType]
- , modelName;
+ , modelName
+ , through;
// Bail out if the association doesn't exist
if (!assn) {
@@ -214,6 +216,7 @@ utils.mixin(model, new (function () {
}
modelName = assn[assnName].model;
+ through = assn[assnName].through;
// Normalize inflection
modelName = utils.inflection.singularize(modelName);
@@ -253,7 +256,40 @@ utils.mixin(model, new (function () {
}
queryName = assnType == 'hasMany' ? 'all' : 'first';
- model[modelName][queryName](query, opts, callback);
+
+ // -----------
+ // FIXME: This is pretty terrible -- should really do these
+ // async queries in some sort of composable Promisey API
+ // -----------
+ // Through's -- get the join-model instances, and re-fetch
+ // actual assns
+ if (through) {
+ through = utils.string.getInflection(through, 'constructor', 'singular');
+ model[through][queryName](query, opts, function (err, data) {
+ var query = {}
+ , idColName = utils.string.getInflection(modelName,
+ 'property', 'singular') + 'Id'
+ , idParam;
+ if (err) {
+ return callback(err, null);
+ }
+ if (assnType == 'hasMany') {
+ idParam = [];
+ data.forEach(function (item) {
+ idParam.push(item[idColName]);
+ });
+ }
+ else {
+ idParam = item[idColName];
+ }
+ query.id = idParam;
+ model[modelName][queryName](query, opts, callback);
+ });
+ }
+ // Normal assns, just do the damn query
+ else {
+ model[modelName][queryName](query, opts, callback);
+ }
};
this._createAssociation = function () {
@@ -268,7 +304,8 @@ utils.mixin(model, new (function () {
, modelName
, through
, joinInstance
- , unsaved;
+ , unsaved
+ , params;
// Bail out if the association doesn't exist
if (!assn) {
@@ -311,17 +348,26 @@ utils.mixin(model, new (function () {
'if it is not yet saved.');
}
+ // ---------------
+ // FIXME: This chained saving happens automagically, so
+ // validation errors in the instances just throw, with
+ // no visible .errors property
+ // ---------------
// Through assn
if (through) {
through = utils.string.getInflection(through, 'constructor', 'singular');
// Create join-instance
- joinInstance = model[through].create({
- otherKeyName: data.id
- , selfKeyName: this.id
- });
+ params = {};
+ params[selfKeyName] = this.id;
+ joinInstance = model[through].create(params);
unsaved = this._unsavedAssociations || [];
// Mark actual assn for chained save
unsaved.push(data);
+ // When this item gets saved, update the join-instance
+ // with the correct assn foreign key
+ data.on('save', function () {
+ joinInstance[otherKeyName] = data.id;
+ });
// Mark join-instance for chained save
unsaved.push(joinInstance);
this._unsavedAssociations = unsaved;
@@ -645,7 +691,7 @@ utils.mixin(model, new (function () {
ModelCtor.prototype = new model.ModelBase();
// Add eventing to instances
- utils.enhance(ModelCtor.prototype, new EventEmitter());
+ util.inherits(ModelCtor, EventEmitter);
// Preserve any inherited shit from the definition proto
utils.enhance(ModelCtor.prototype, origProto);
View
@@ -552,12 +552,21 @@ tests = {
throw err;
}
var u = data;
- var t = Team.create({
+ u.addTeam(Team.create({
name: 'foo'
- });
- u.addTeam(t);
+ }));
+ u.addTeam(Team.create({
+ name: 'bar'
+ }));
u.save(function (err, data) {
- next();
+ console.log('save completed');
+ u.getTeams(function (err, data) {
+ assert.equal(2, data.length);
+ data.forEach(function (item) {
+ assert.equal('Team', item.type);
+ });
+ next();
+ });
});
});
}
@@ -1,8 +1,6 @@
var model = require('../../lib');
var Membership = function () {
- this.property('name', 'string', {required: true});
-
this.belongsTo('User');
this.belongsTo('Team');
};

0 comments on commit ff09665

Please sign in to comment.