Merge pull request #577 from eirikhm/master

Backbone Relational added
This commit is contained in:
Boris Yankov
2013-05-23 13:04:25 -07:00
3 changed files with 291 additions and 0 deletions
+1
View File
@@ -30,6 +30,7 @@ List of Definitions
* [AngularJS](http://angularjs.org) (by [Diego Vilar](https://github.com/diegovilar)) ([wiki](https://github.com/borisyankov/DefinitelyTyped/wiki/AngularJS-Definitions-Usage-Notes))
* [async](https://github.com/caolan/async) (by [Boris Yankov](https://github.com/borisyankov))
* [Backbone.js](http://backbonejs.org/) (by [Boris Yankov](https://github.com/borisyankov))
* [Backbone Relational](http://backbonerelational.org/) (by [Eirik Hoem](https://github.com/eirikhm))
* [Bootbox](https://github.com/makeusabrew/bootbox) (by [Vincent Bortone](https://github.com/vbortone/))
* [Bootstrap](http://twitter.github.com/bootstrap/) (by [Boris Yankov](https://github.com/borisyankov))
* [bootstrap-notify](https://github.com/Nijikokun/bootstrap-notify) (by [Blake Niemyjski](https://github.com/niemyjski))
@@ -0,0 +1,122 @@
/// <reference path="../backbone/backbone.d.ts" />
/// <reference path="../underscore/underscore.d.ts" />
/// <reference path="backbone-relational.d.ts" />
class House extends Backbone.RelationalModel {
// The 'relations' property, on the House's prototype. Initialized separately for each
// instance of House. Each relation must define (as a minimum) the 'type', 'key' and
// 'relatedModel'. Options include 'includeInJSON', 'createModels' and 'reverseRelation'.
relations = [
{
type: Backbone.HasMany, // Use the type, or the string 'HasOne' or 'HasMany'.
key: 'occupants',
relatedModel: 'Person',
includeInJSON: true,
collectionType: 'PersonCollection',
reverseRelation: {
key: 'livesIn'
}
}
];
}
class Person extends Backbone.RelationalModel {
relations = [
{ // Create a (recursive) one-to-one relationship
type: Backbone.HasOne,
key: 'user',
relatedModel: 'User',
reverseRelation: {
type: Backbone.HasOne,
key: 'person'
}
}
];
initialize()
{
// do whatever you want :)
}
}
class PersonCollection extends Backbone.Collection {
url(models)
{
// Logic to create a url for the whole collection, or a set of models.
// See the tests, or Backbone-tastypie, for an example.
return '/person/' + ( models ? 'set/' + _.pluck(models, 'id').join(';') + '/' : '' );
}
}
class User extends Backbone.RelationalModel {
}
var paul = new Person({
id: 'person-1',
name: 'Paul',
user: { id: 'user-1', login: 'dude', email: 'me@gmail.com' }
});
// A User object is automatically created from the JSON; so 'login' returns 'dude'.
paul.get('user').get('login');
var ourHouse = new House({
id: 'house-1',
location: 'in the middle of the street',
occupants: ['person-1', 'person-2', 'person-5']
});
// 'ourHouse.occupants' is turned into a Backbone.Collection of Persons.
// The first person in 'ourHouse.occupants' will point to 'paul'.
ourHouse.get('occupants').at(0); // === paul
// If a collection is created from a HasMany relation, it contains a reference
// back to the originator of the relation
ourHouse.get('occupants').livesIn; // === ourHouse
// The `occupants` relation on 'House' has been defined as a HasMany, with a reverse relation
// to `livesIn` on 'Person'. So, 'paul.livesIn' will automatically point back to 'ourHouse'.
paul.get('livesIn'); // === ourHouse
// You can control which relations get serialized to JSON, using the 'includeInJSON'
// property on a Relation. Also, each object will only get serialized once to prevent loops.
alert(JSON.stringify(paul.get('user').toJSON(), null, '\t'));
// Load occupants 'person-2' and 'person-5', which don't exist yet, from the server
ourHouse.fetchRelated('occupants');
// Use the `add` and `remove` events to listen for additions/removals on a HasMany relation.
// Here, we listen for changes to `ourHouse.occupants`.
ourHouse
.on('add:occupants', function (model, coll)
{
console.log('add %o', model);
// Do something. Create a View?
})
.on('remove:occupants', function (model, coll)
{
console.log('remove %o', model);
// Do somehting. Destroy a View?
});
// Use the 'update' event to listen for changes on a HasOne relation (like 'Person.livesIn').
paul.on('change:livesIn', function (model, attr)
{
console.log('change `livesIn` to %o', attr);
});
// Modifying either side of a bi-directional relation updates the other side automatically.
// Take `paul` out or `ourHouse`; this triggers `remove:occupants` on `ourHouse`,
// and `change:livesIn` on `paul`
ourHouse.get('occupants').remove(paul);
alert('paul.livesIn=' + paul.get('livesIn'));
// Move into `theirHouse`; triggers 'add:occupants' on ourHouse, and 'change:livesIn' on paul
var theirHouse = new House({ id: 'house-2' });
paul.set({ 'livesIn': theirHouse });
alert('theirHouse.occupants=' + theirHouse.get('occupants').pluck('name'));
+168
View File
@@ -0,0 +1,168 @@
// Type definitions for Backbone 0.8.5
// Project: http://backbonerelational.org/
// Definitions by: Eirik Hoem <https://github.com/eirikhm/>
// Definitions: https://github.com/borisyankov/DefinitelyTyped
/// <reference path="../jquery/jquery.d.ts" />
/// <reference path="../backbone/backbone.d.ts" />
declare module Backbone {
export class RelationalModel extends Model {
static extend(properties:any, classProperties?:any):any; // do not use, prefer TypeScript's extend functionality
relations:any;
subModelTypes:any;
subModelTypeAttribute:any;
initializeRelations(options:any):void;
updateRelations(options:any):void;
queue(func:any):void;
processQueue():void;
getRelation(name:string):Relation;
getRelations():Relation[];
fetchRelated(key:string, options?:any, update?:bool):any;
toJSON():any;
setup();
build(attributes:any, options?:any);
findOrCreate(attributes:string, options?:any);
findOrCreate(attributes:number, options?:any);
findOrCreate(attributes:any, options?:any);
}
export class Relation extends Model {
options:any;
instance:any;
key:any;
keyContents:any;
relatedModel:any;
relatedCollection:any;
reverseRelation:any;
related:any;
checkPreconditions():bool;
setRelated(related:Model):void;
setRelated(related:Collection):void;
getReverseRelations(model:RelationalModel):Relation;
destroy():void;
}
export class HasOne extends Relation {
collectionType:any;
findRelated(options:any):Model;
setKeyContents(keyContents:string):void;
setKeyContents(keyContents:string[]):void;
setKeyContents(keyContents:number):void;
setKeyContents(keyContents:number[]):void;
setKeyContents(keyContents:Collection):void;
onChange(model:Model, attr:any, options:any):void;
handleAddition(model:Model, coll:Collection, options:any):void;
handleRemoval(model:Model, coll:Collection, options:any):void;
handleReset(coll:Collection, options:any):void;
tryAddRelated(model:Model, coll:any, options:any):void;
addRelated(model:Model, options:any):void;
removeRelated(model:Model, coll:any, options:any):void;
}
export class HasMany extends Relation {
collectionType:any;
findRelated(options:any):Model;
setKeyContents(keyContents:string):void;
setKeyContents(keyContents:number):void;
setKeyContents(keyContents:Model):void;
onChange(model:Model, attr:any, options:any):void;
tryAddRelated(model:Model, coll:any, options:any):void;
addRelated(model:Model, options:any):void;
removeRelated(model:Model, coll:any, options:any):void;
}
export class Store extends Events {
initializeRelation(model, relation, options);
addModelScope(scope:any):void;
removeModelScope(scope):void;
addSubModels(subModelTypes:RelationalModel, superModelType:RelationalModel):void;
setupSuperModel(modelType:RelationalModel):void;
addReverseRelation(relation:any):void;
addOrphanRelation(relation:any):void;
processOrphanRelations():void;
retroFitRelation(relation:RelationalModel, create:bool):Collection;
getCollection(type:RelationalModel, create:bool):Collection;
getObjectByName(name:string):any;
resolveIdForItem(type:any, item:any):any;
find(type:any, item:string):RelationalModel;
find(type:any, item:number):RelationalModel;
find(type:any, item:RelationalModel):RelationalModel;
find(type:any, item:any):RelationalModel;
register(model:RelationalModel):void;
checkId(model:RelationalModel, id:any):void;
update(model:RelationalModel):void;
unregister(model:RelationalModel, collection:Collection, options:any):void;
reset():void;
}
}