Skip to content

Commit

Permalink
Use a reverseIndex for additions (based on #454, but using store coll…
Browse files Browse the repository at this point in the history
…ection cids).
  • Loading branch information
PaulUithol committed May 30, 2014
1 parent 42b158d commit da9a355
Showing 1 changed file with 71 additions and 2 deletions.
73 changes: 71 additions & 2 deletions backbone-relational.js
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,12 @@
return type;
},

/**
* Create a store collection to hold a certain type of model
* @param type
* @return {Backbone.Collection}
* @private
*/
_createCollection: function( type ) {
var coll;

Expand All @@ -390,6 +396,7 @@
// Type should inherit from Backbone.RelationalModel.
if ( type.prototype instanceof Backbone.RelationalModel ) {
coll = new Backbone.Collection();
coll.cid = _.uniqueId( 'c' );
coll.model = type;

this._collections.push( coll );
Expand Down Expand Up @@ -624,6 +631,7 @@
}

this.setKeyContents( this.instance.get( contentKey ) );

this.relatedCollection = Backbone.Relational.store.getCollection( this.relatedModel );

// Explicitly clear 'keySource', to prevent a leaky abstraction if 'keySource' differs from 'key'.
Expand All @@ -634,6 +642,25 @@
// Add this Relation to instance._relations
this.instance._relations[ this.key ] = this;

var reverseIndexKey = Backbone.Relational.store.getCollection( this.model ).cid + ":" + this.key;
if ( this.relatedCollection._reverseIndexes == null ) {
this.relatedCollection._reverseIndexes = {};
}

this.reverseIndex = this.relatedCollection._reverseIndexes[ reverseIndexKey ];

if ( this.reverseIndex == null ) {
this.reverseIndex = this.relatedCollection._reverseIndexes[ reverseIndexKey ] = {};
this.relatedCollection.on( 'relational:add relational:change:id', function( model, coll, opts ) {
var id = model.get( model.idAttribute );
if ( id != null ) {
_.each( this.reverseIndex[ id ], function( obj ) {
obj._relations[ this.key ].tryAddRelated( model, coll, opts );
}, this );
}
}, this );
}

this.initialize( opts );

if ( this.options.autoFetch ) {
Expand All @@ -642,7 +669,6 @@

// When 'relatedModel' are created or destroyed, check if it affects this relation.
this.listenTo( this.instance, 'destroy', this.destroy )
.listenTo( this.relatedCollection, 'relational:add relational:change:id', this.tryAddRelated )
.listenTo( this.relatedCollection, 'relational:remove', this.removeRelated );
}
};
Expand Down Expand Up @@ -784,6 +810,11 @@
var related = this.findRelated( opts );
this.setRelated( related );

if ( this.keyId !== null ) {
var index = this.reverseIndex[this.keyId] || (this.reverseIndex[this.keyId] = {});
index[this.instance.cid] = this.instance;
}

// Notify new 'related' object of the new relation.
_.each( this.getReverseRelations(), function( relation ) {
relation.addRelated( this.instance, opts );
Expand Down Expand Up @@ -847,11 +878,24 @@
this.setKeyContents( attr );
var related = this.findRelated( options );
this.setRelated( related );

var id = this.related != null ? this.related.get(this.related.idAttribute) : null;

if ( this.reverseIndex != null && this.related != null && id != null ) {
var reverseIndex = this.reverseIndex[id] || (this.reverseIndex[id] = {});
reverseIndex[this.instance.cid] = this.instance;
}
}

// Notify old 'related' object of the terminated relation
if ( oldRelated && this.related !== oldRelated ) {
_.each( this.getReverseRelations( oldRelated ), function( relation ) {
var id = this.instance.get( this.instance.idAttribute );
if ( this.reverseIndex != null && id != null ) {
var reverseIndex = relation.reverseIndex[id] ||
(relation.reverseIndex[id] = {});
delete reverseIndex[relation.instance.cid];
}
relation.removeRelated( this.instance, null, options );
}, this );
}
Expand All @@ -860,7 +904,12 @@
// that can be necessary for bi-directional relations if 'this.instance' was created after 'this.related'.
// In that case, 'this.instance' will already know 'this.related', but the reverse might not exist yet.
_.each( this.getReverseRelations(), function( relation ) {
relation.addRelated( this.instance, options );
var id = this.instance.get( this.instance.idAttribute );
if ( id != null && relation.reverseIndex != null ) {
var reverseIndex = relation.reverseIndex[id] || (relation.reverseIndex[id] = {});
reverseIndex[relation.instance.cid] = this.instance;
}
relation.addRelated( this.instance, options );
}, this );

// Fire the 'change:<key>' event if 'related' was updated
Expand Down Expand Up @@ -936,6 +985,11 @@
throw new Error( '`collectionType` must inherit from Backbone.Collection' );
}

_.each( this.keyIds, function( id ) {
var index = this.reverseIndex[id] || (this.reverseIndex[id] = {});
index[this.instance.cid] = this.instance;
}, this );

var related = this.findRelated( opts );
this.setRelated( related );
},
Expand Down Expand Up @@ -1061,12 +1115,27 @@
*/
onChange: function( model, attr, options ) {
options = options ? _.clone( options ) : {};

if ( this.reverseIndex !== null ) {
_.each( this.keyIds, function( keyId ) {
var index = this.reverseIndex[keyId];
delete index[this.instance.cid];
}, this );
}

this.setKeyContents( attr );
this.changed = false;

var related = this.findRelated( options );
this.setRelated( related );

if ( this.reverseIndex !== null && this.keyIds !== null ) {
_.each( this.keyIds, function( keyId ) {
var index = this.reverseIndex[keyId] || (this.reverseIndex[keyId] = {});
index[this.instance.cid] = this.instance;
}, this );
}

if ( !options.silent ) {
var dit = this;
Backbone.Relational.eventQueue.add( function() {
Expand Down

0 comments on commit da9a355

Please sign in to comment.