Permalink
Browse files

Merge relations between super/subModels more thoroughly. Fixes #273.

  • Loading branch information...
1 parent 21a0f66 commit d14608b319b9581216327cd4cafc90dbea505d04 @PaulUithol committed Mar 14, 2013
Showing with 108 additions and 9 deletions.
  1. +7 −9 backbone-relational.js
  2. +101 −0 test/tests.js
View
16 backbone-relational.js
@@ -1561,17 +1561,15 @@
// inherited automatically (due to a redefinition of 'relations').
// Otherwise, make sure we don't get here again for this type by making '_superModel' false so we fail
// the isUndefined/isNull check next time.
- if ( this._superModel ) {
- //
- if ( this._superModel.prototype.relations ) {
- var supermodelRelationsExist = _.any( this.prototype.relations || [], function( rel ) {
- return rel.model && rel.model !== this;
+ if ( this._superModel && this._superModel.prototype.relations ) {
+ // Find relations that exist on the `_superModel`, but not yet on this model.
+ var inheritedRelations = _.select( this._superModel.prototype.relations || [], function( superRel ) {
+ return !_.any( this.prototype.relations || [], function( rel ) {
+ return superRel.relatedModel === rel.relatedModel && superRel.key === rel.key;
}, this );
+ }, this );
- if ( !supermodelRelationsExist ) {
- this.prototype.relations = this._superModel.prototype.relations.concat( this.prototype.relations );
- }
- }
+ this.prototype.relations = inheritedRelations.concat( this.prototype.relations );
}
else {
this._superModel = false;
View
101 test/tests.js
@@ -1389,6 +1389,107 @@ $(document).ready(function() {
ok( dog.get( 'fleas' ).at( 0 ) === flea, "Dog has a working fleas relation." );
});
+
+ test( "Overriding of supermodel relations", function() {
+ var models = {};
+ Backbone.Relational.store.addModelScope( models );
+
+ models.URL = Backbone.RelationalModel.extend({});
+
+ models.File = Backbone.RelationalModel.extend({
+ subModelTypes: {
+ 'video': 'Video',
+ 'publication': 'Publication'
+ },
+
+ relations: [{
+ type: Backbone.HasOne,
+ key: 'url',
+ relatedModel: models.URL
+ }]
+ });
+
+ models.Video = models.File.extend({});
+
+ // Publication redefines the `url` relation
+ models.Publication = Backbone.RelationalModel.extend({
+ relations: [{
+ type: Backbone.HasMany,
+ key: 'url',
+ relatedModel: models.URL
+ }]
+ });
+
+ models.Project = Backbone.RelationalModel.extend({
+ relations: [{
+ type: Backbone.HasMany,
+ key: 'files',
+ relatedModel: models.File,
+ reverseRelation: {
+ key: 'project'
+ }
+ }]
+ });
+
+ equal( models.File.prototype.relations.length, 2, "2 relations on File" );
+ equal( models.Video.prototype.relations.length, 1, "1 relation on Video" );
+ equal( models.Publication.prototype.relations.length, 1, "1 relation on Publication" );
+
+ // Instantiating the superModel should instantiate the modelHierarchy, and copy relations over to subModels
+ var file = new models.File();
+
+ equal( models.File.prototype.relations.length, 2, "2 relations on File" );
+ equal( models.Video.prototype.relations.length, 2, "2 relations on Video" );
+ equal( models.Publication.prototype.relations.length, 2, "2 relations on Publication" );
+
+ var projectDecription = {
+ name: 'project1',
+
+ files: [
+ {
+ name: 'file1 - video subclass',
+ type: 'video',
+ url: {
+ location: 'http://www.myurl.com/file1.avi'
+ }
+ },
+ {
+ name: 'file2 - file baseclass',
+ url: {
+ location: 'http://www.myurl.com/file2.jpg'
+ }
+ },
+ {
+ name: 'file3 - publication',
+ type: 'publication',
+ url: [
+ { location: 'http://www.myurl.com/file3.pdf' },
+ { location: 'http://www.anotherurl.com/file3.doc' }
+ ]
+ }
+ ]
+ };
+
+ var project = new models.Project( projectDecription ),
+ files = project.get( 'files' ),
+ file1 = files.at( 0 ),
+ file2 = files.at( 1 ),
+ file3 = files.at( 2 );
+
+ equal( models.File.prototype.relations.length, 2, "2 relations on File" );
+ equal( models.Video.prototype.relations.length, 2, "2 relations on Video" );
+ equal( models.Publication.prototype.relations.length, 2, "2 relations on Publication" );
+
+ equal( _.size( file1._relations ), 2 );
+ equal( _.size( file2._relations ), 2 );
+ equal( _.size( file3._relations ), 2 );
+
+ ok( file1.get( 'url' ) instanceof Backbone.Model, '`url` on Video is a model' );
+ ok( file1.getRelation( 'url' ) instanceof Backbone.HasOne, '`url` relation on Video is HasOne' );
+
+ ok( file3.get( 'url' ) instanceof Backbone.Collection, '`url` on Publication is a collection' );
+ ok( file3.getRelation( 'url' ) instanceof Backbone.HasMany, '`url` relation on Publication is HasMany' );
+ });
test( "toJSON includes the type", function() {
var scope = {};

0 comments on commit d14608b

Please sign in to comment.