-
Notifications
You must be signed in to change notification settings - Fork 55
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
mde
committed
Apr 2, 2013
1 parent
cb570f0
commit dcd94f8
Showing
1 changed file
with
199 additions
and
125 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -183,6 +183,182 @@ Model-item instances emit these events: | |
* beforeUpdate | ||
* update | ||
|
||
## Associations | ||
|
||
Model has support for associations: including hasMany/belongsTo and | ||
hasOne/belongsTo. For example, if you had a `User` model with a single | ||
`Profile`, and potentially many `Accounts`: | ||
|
||
```javascript | ||
var User = function () { | ||
this.property('login', 'string', {required: true}); | ||
this.property('password', 'string', {required: true}); | ||
this.property('confirmPassword', 'string', {required: true}); | ||
|
||
this.hasOne('Profile'); | ||
this.hasMany('Accounts'); | ||
}; | ||
``` | ||
|
||
A `Book` model that belongs to an `Author` would look like this: | ||
|
||
```javascript | ||
var Book = function () { | ||
this.property('title', 'string'); | ||
this.property('description', 'text'); | ||
|
||
this.belongsTo('Author'); | ||
}; | ||
``` | ||
|
||
Add the `hasOne` relationship by calling 'set' plus the name of the owned | ||
model in singular (in this case `setProfile`). Retrieve the associated item by | ||
using 'get' plus the name of the owned model in singular (in this case | ||
`getProfile`). Here's an example: | ||
|
||
```javascript | ||
var user = User.create({ | ||
login: 'asdf' | ||
, password: 'zerb' | ||
, confirmPassword: 'zerb' | ||
}); | ||
user.save(function (err, data) { | ||
var profile; | ||
if (err) { | ||
throw err; | ||
} | ||
profile = Profile.create({}); | ||
user.setProfile(profile); | ||
user.save(function (err, data) { | ||
if (err) { | ||
throw err; | ||
} | ||
user.getProfile(function (err, data) { | ||
if (err) { | ||
throw err; | ||
} | ||
console.log(profile.id ' is the same as ' + data.id); | ||
}); | ||
}); | ||
}); | ||
``` | ||
|
||
Set up the `hasMany` relationship by calling 'add' plus the name of the | ||
owned model in singular (in this case `addAccount`). Retrieve the associated | ||
items with a call to 'get' plus the name of the owned model in plural (in | ||
this case `getAccounts`). An example: | ||
|
||
```javascript | ||
var user = User.create({ | ||
login: 'asdf' | ||
, password: 'zerb' | ||
, confirmPassword: 'zerb' | ||
}); | ||
user.save(function (err, data) { | ||
if (err) { | ||
throw err; | ||
} | ||
user.addAccount(Account.create({})); | ||
user.addAccount(Account.create({})); | ||
user.save(function (err, data) { | ||
if (err) { | ||
throw err; | ||
} | ||
user.getAccounts(function (err, data) { | ||
if (err) { | ||
throw err; | ||
} | ||
console.log('This number should be 2: ' + data.length); | ||
}); | ||
}); | ||
}); | ||
``` | ||
|
||
A `belongsTo` relationship is created similarly to a `hasOne`: by calling 'set' | ||
plus the name of the owner model in singular (in this case `setAuthor`). | ||
Retrieve the associated item by using 'get' plus the name of the owner model | ||
in singular (in this case `getAuthor`). Here's an example: | ||
|
||
```javascript | ||
var book = Book.create({ | ||
title: 'How to Eat an Entire Ham' | ||
, description: 'Such a poignant book. I cried.' | ||
}); | ||
book.save(function (err, data) { | ||
if (err) { | ||
throw err; | ||
} | ||
book.setAuthor(Author.create({ | ||
familyName: 'Neeble' | ||
, givenName: 'Leonard' | ||
})); | ||
book.save(function (err, data) { | ||
if (err) { | ||
throw err; | ||
} | ||
book.getAuthor(function (err, data) { | ||
if (err) { | ||
throw err; | ||
} | ||
console.log('This name should be "Neeble": ' + data.familyName); | ||
}); | ||
}); | ||
}); | ||
``` | ||
|
||
### 'Through' associations | ||
|
||
'Through' associations allow a model to be associated with another *through* a | ||
third model. A good example would be a Team linked to Players through | ||
Memberships. | ||
|
||
```javascript | ||
var Player = function () { | ||
this.property('familyName', 'string', {required: true}); | ||
this.property('givenName', 'string', {required: true}); | ||
this.property('jerseyNumber', 'string', {required: true}); | ||
|
||
this.hasMany('Memberships'); | ||
this.hasMany('Teams', {through: 'Memberships'}); | ||
}; | ||
|
||
var Team = function () { | ||
this.property('name', 'string', {required: true}); | ||
|
||
this.hasMany('Memberships'); | ||
this.hasMany('Players', {through: 'Memberships'}); | ||
}; | ||
|
||
var Membership = function () { | ||
this.hasMany('Memberships'); | ||
this.hasMany('Teams'); | ||
}; | ||
``` | ||
|
||
The API for this is the same as with normal associations, using the `set`/`add` | ||
and `get`, with the appropriate association name (not the model name). For | ||
example, in the case of the Team adding Players, you'd use `addPlayer` and | ||
`getPlayer`. | ||
|
||
### Named associations | ||
|
||
Sometimes you need mutliple associations to the same type of model (e.g., I have | ||
lots of Friends and Relatives who are all Users). You can accomplish this in | ||
Model using named associations: | ||
|
||
```javascript | ||
var User = function () { | ||
this.property('familyName', 'string', {required: true}); | ||
this.property('givenName', 'string', {required: true}); | ||
|
||
this.hasMany('Kids', {model: 'Users'}); | ||
}; | ||
``` | ||
|
||
The API for this is the same as with normal associations, using the `set`/`add` | ||
and `get`, with the appropriate association name (not the model name). For | ||
example, in the case of `Kids`, you'd use `addKid` and `getKids`. | ||
|
||
## Querying | ||
|
||
Model uses a simple API for finding and sorting items. Again, it should look | ||
|
@@ -330,149 +506,47 @@ sort-direction is ascending ('asc'), so you can specify a property to sort on | |
|
||
``` | ||
## Associations | ||
Model has basic support for associations: including hasMany/belongsTo and | ||
hasOne/belongsTo. For example, if you had a `User` model with a single | ||
`Profile`, and potentially many `Accounts`: | ||
```javascript | ||
var User = function () { | ||
this.property('login', 'string', {required: true}); | ||
this.property('password', 'string', {required: true}); | ||
this.property('confirmPassword', 'string', {required: true}); | ||
|
||
this.hasOne('Profile'); | ||
this.hasMany('Accounts'); | ||
}; | ||
``` | ||
A `Book` model that belongs to an `Author` would look like this: | ||
```javascript | ||
var Book = function () { | ||
this.property('title', 'string'); | ||
this.property('description', 'text'); | ||
## Eager loading of associations (SQL adpaters only) | ||
this.belongsTo('Author'); | ||
}; | ||
``` | ||
You can use the 'includes' option to specify second-order associations that | ||
should be eager-loaded in a particular query (avoiding the so-called N + 1 Query | ||
Problem). This will also work for 'through' associations. | ||
Add the `hasOne` relationship by calling 'set' plus the name of the owned | ||
model in singular (in this case `setProfile`). Retrieve the associated item by | ||
using 'get' plus the name of the owned model in singular (in this case | ||
`getProfile`). Here's an example: | ||
For example, with a Team that `hasMany` Players through Memberships, you might | ||
want to display the roster of player for every team when you display teams in a | ||
list. You could do it like so: | ||
```javascript | ||
var user = User.create({ | ||
login: 'asdf' | ||
, password: 'zerb' | ||
, confirmPassword: 'zerb' | ||
}); | ||
user.save(function (err, data) { | ||
var profile; | ||
Team.all({}, {includes: ['player']}, function (err, data) { | ||
var teams; | ||
if (err) { | ||
throw err; | ||
} | ||
profile = Profile.create({}); | ||
user.setProfile(profile); | ||
user.save(function (err, data) { | ||
if (err) { | ||
throw err; | ||
} | ||
user.getProfile(function (err, data) { | ||
if (err) { | ||
throw err; | ||
} | ||
console.log(profile.id ' is the same as ' + data.id); | ||
teams = data; | ||
teams.forEach(function (team) { | ||
console.log(team.name); | ||
team.players.forEach(function (player) { | ||
console.log(player.familyName + ', ' + player.givenName); | ||
}); | ||
}); | ||
}); | ||
``` | ||
Set up the `hasMany` relationship by calling 'add' plus the name of the | ||
owned model in singular (in this case `addAccount`). Retrieve the associated | ||
items with a call to 'get' plus the name of the owned model in plural (in | ||
this case `getAccounts`). An example: | ||
The eagerly fetched association will be in a property on the top-level item with | ||
the same name as the association (e.g., Players will be in `players`). | ||
```javascript | ||
var user = User.create({ | ||
login: 'asdf' | ||
, password: 'zerb' | ||
, confirmPassword: 'zerb' | ||
}); | ||
user.save(function (err, data) { | ||
if (err) { | ||
throw err; | ||
} | ||
user.addAccount(Account.create({})); | ||
user.addAccount(Account.create({})); | ||
user.save(function (err, data) { | ||
if (err) { | ||
throw err; | ||
} | ||
user.getAccounts(function (err, data) { | ||
if (err) { | ||
throw err; | ||
} | ||
console.log('This number should be 2: ' + data.length); | ||
}); | ||
}); | ||
}); | ||
``` | ||
A `belongsTo` relationship is created similarly to a `hasOne`: by calling 'set' | ||
plus the name of the owner model in singular (in this case `setAuthor`). | ||
Retrieve the associated item by using 'get' plus the name of the owner model | ||
in singular (in this case `getAuthor`). Here's an example: | ||
If you have an item, and you're not certain whether an association is already | ||
loaded, you can check for the existence of this property before doing a per-item | ||
fetch: | ||
```javascript | ||
var book = Book.create({ | ||
title: 'How to Eat an Entire Ham' | ||
, description: 'Such a poignant book. I cried.' | ||
}); | ||
book.save(function (err, data) { | ||
if (err) { | ||
throw err; | ||
} | ||
book.setAuthor(Author.create({ | ||
familyName: 'Neeble' | ||
, givenName: 'Leonard' | ||
})); | ||
book.save(function (err, data) { | ||
if (err) { | ||
throw err; | ||
} | ||
book.getAuthor(function (err, data) { | ||
if (err) { | ||
throw err; | ||
} | ||
console.log('This name should be "Neeble": ' + data.familyName); | ||
}); | ||
if (!someTeam.players) { | ||
someTeam.getPlayers(function (err, data) { | ||
console.dir(data); | ||
}); | ||
}); | ||
``` | ||
### Named associations | ||
Sometimes you need mutliple associations to the same type of model (e.g., I have | ||
lots of Friends and Relatives who are all Users). You can accomplish this in | ||
Model using named associations: | ||
```javascript | ||
var User = function () { | ||
this.property('familyName', 'string', {required: true}); | ||
this.property('givenName', 'string', {required: true}); | ||
|
||
this.hasMany('Friends', {model: 'Users'}); | ||
this.hasMany('Relatives', {model: 'Users'}); | ||
}; | ||
} | ||
``` | ||
The API for this is the same as with normal associations, using the `set`/`add` | ||
and `get`, with the appropriate association name (not the model name). For | ||
example, in the case of `Friends`, you'd use `addFriend` and `getFriends`. | ||
- - - | ||
Model JavaScript ORM copyright 2112 [email protected]. | ||
|