Skip to content

Commit da9a355

Browse files
committed
Use a reverseIndex for additions (based on #454, but using store collection cids).
1 parent 42b158d commit da9a355

File tree

1 file changed

+71
-2
lines changed

1 file changed

+71
-2
lines changed

backbone-relational.js

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,12 @@
379379
return type;
380380
},
381381

382+
/**
383+
* Create a store collection to hold a certain type of model
384+
* @param type
385+
* @return {Backbone.Collection}
386+
* @private
387+
*/
382388
_createCollection: function( type ) {
383389
var coll;
384390

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

395402
this._collections.push( coll );
@@ -624,6 +631,7 @@
624631
}
625632

626633
this.setKeyContents( this.instance.get( contentKey ) );
634+
627635
this.relatedCollection = Backbone.Relational.store.getCollection( this.relatedModel );
628636

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

645+
var reverseIndexKey = Backbone.Relational.store.getCollection( this.model ).cid + ":" + this.key;
646+
if ( this.relatedCollection._reverseIndexes == null ) {
647+
this.relatedCollection._reverseIndexes = {};
648+
}
649+
650+
this.reverseIndex = this.relatedCollection._reverseIndexes[ reverseIndexKey ];
651+
652+
if ( this.reverseIndex == null ) {
653+
this.reverseIndex = this.relatedCollection._reverseIndexes[ reverseIndexKey ] = {};
654+
this.relatedCollection.on( 'relational:add relational:change:id', function( model, coll, opts ) {
655+
var id = model.get( model.idAttribute );
656+
if ( id != null ) {
657+
_.each( this.reverseIndex[ id ], function( obj ) {
658+
obj._relations[ this.key ].tryAddRelated( model, coll, opts );
659+
}, this );
660+
}
661+
}, this );
662+
}
663+
637664
this.initialize( opts );
638665

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

643670
// When 'relatedModel' are created or destroyed, check if it affects this relation.
644671
this.listenTo( this.instance, 'destroy', this.destroy )
645-
.listenTo( this.relatedCollection, 'relational:add relational:change:id', this.tryAddRelated )
646672
.listenTo( this.relatedCollection, 'relational:remove', this.removeRelated );
647673
}
648674
};
@@ -784,6 +810,11 @@
784810
var related = this.findRelated( opts );
785811
this.setRelated( related );
786812

813+
if ( this.keyId !== null ) {
814+
var index = this.reverseIndex[this.keyId] || (this.reverseIndex[this.keyId] = {});
815+
index[this.instance.cid] = this.instance;
816+
}
817+
787818
// Notify new 'related' object of the new relation.
788819
_.each( this.getReverseRelations(), function( relation ) {
789820
relation.addRelated( this.instance, opts );
@@ -847,11 +878,24 @@
847878
this.setKeyContents( attr );
848879
var related = this.findRelated( options );
849880
this.setRelated( related );
881+
882+
var id = this.related != null ? this.related.get(this.related.idAttribute) : null;
883+
884+
if ( this.reverseIndex != null && this.related != null && id != null ) {
885+
var reverseIndex = this.reverseIndex[id] || (this.reverseIndex[id] = {});
886+
reverseIndex[this.instance.cid] = this.instance;
887+
}
850888
}
851889

852890
// Notify old 'related' object of the terminated relation
853891
if ( oldRelated && this.related !== oldRelated ) {
854892
_.each( this.getReverseRelations( oldRelated ), function( relation ) {
893+
var id = this.instance.get( this.instance.idAttribute );
894+
if ( this.reverseIndex != null && id != null ) {
895+
var reverseIndex = relation.reverseIndex[id] ||
896+
(relation.reverseIndex[id] = {});
897+
delete reverseIndex[relation.instance.cid];
898+
}
855899
relation.removeRelated( this.instance, null, options );
856900
}, this );
857901
}
@@ -860,7 +904,12 @@
860904
// that can be necessary for bi-directional relations if 'this.instance' was created after 'this.related'.
861905
// In that case, 'this.instance' will already know 'this.related', but the reverse might not exist yet.
862906
_.each( this.getReverseRelations(), function( relation ) {
863-
relation.addRelated( this.instance, options );
907+
var id = this.instance.get( this.instance.idAttribute );
908+
if ( id != null && relation.reverseIndex != null ) {
909+
var reverseIndex = relation.reverseIndex[id] || (relation.reverseIndex[id] = {});
910+
reverseIndex[relation.instance.cid] = this.instance;
911+
}
912+
relation.addRelated( this.instance, options );
864913
}, this );
865914

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

988+
_.each( this.keyIds, function( id ) {
989+
var index = this.reverseIndex[id] || (this.reverseIndex[id] = {});
990+
index[this.instance.cid] = this.instance;
991+
}, this );
992+
939993
var related = this.findRelated( opts );
940994
this.setRelated( related );
941995
},
@@ -1061,12 +1115,27 @@
10611115
*/
10621116
onChange: function( model, attr, options ) {
10631117
options = options ? _.clone( options ) : {};
1118+
1119+
if ( this.reverseIndex !== null ) {
1120+
_.each( this.keyIds, function( keyId ) {
1121+
var index = this.reverseIndex[keyId];
1122+
delete index[this.instance.cid];
1123+
}, this );
1124+
}
1125+
10641126
this.setKeyContents( attr );
10651127
this.changed = false;
10661128

10671129
var related = this.findRelated( options );
10681130
this.setRelated( related );
10691131

1132+
if ( this.reverseIndex !== null && this.keyIds !== null ) {
1133+
_.each( this.keyIds, function( keyId ) {
1134+
var index = this.reverseIndex[keyId] || (this.reverseIndex[keyId] = {});
1135+
index[this.instance.cid] = this.instance;
1136+
}, this );
1137+
}
1138+
10701139
if ( !options.silent ) {
10711140
var dit = this;
10721141
Backbone.Relational.eventQueue.add( function() {

0 commit comments

Comments
 (0)