Adjust the lines to fit into width of 80

This commit is contained in:
Raymond Feng 2013-08-28 21:41:11 -07:00
parent 8674e67416
commit 28cf9bdd1e
2 changed files with 168 additions and 118 deletions

View File

@ -1,40 +1,52 @@
# LoopBack DataSource and Connector Guide # LoopBack DataSource and Connector Guide
## Overview ## Overview
LoopBack is centered around models, which represent data and behaviors. The concept of `DataSource` is introduced to LoopBack is centered around models, which represent data and behaviors. The
encapsulate business logic to exchange data between models and various data sources. Data sources are typically databases concept of `DataSource` is introduced to encapsulate business logic to exchange
that provide create, retrieve, update, and delete (CRUD) functions. LoopBack also generalize other backend services, data between models and various data sources. Data sources are typically
such as REST APIs, SOAP Web Services, and Storage Services, as data sources. databases that provide create, retrieve, update, and delete (CRUD) functions.
LoopBack also generalize other backend services, such as REST APIs, SOAP Web
Services, and Storage Services, as data sources.
Data sources are backed by connectors which implement the data exchange logic using database drivers or other client APIs. Data sources are backed by connectors which implement the data exchange logic
In general, connectors are not used directly by application code. The `DataSource` class provides APIs to configure the using database drivers or other client APIs. In general, connectors are not used
underlying connector and exposes functions via `DataSource` or model classes. directly by application code. The `DataSource` class provides APIs to configure
the underlying connector and exposes functions via `DataSource` or model classes.
![model-datasource-connector](datasource-connector.png "LoopBack Model, DataSource, and Connector") ![model-datasource-connector](datasource-connector.png "LoopBack Model, DataSource, and Connector")
The diagram above illustrates the relationship between LoopBack `Model`, `DataSource`, and `Connector`. The diagram above illustrates the relationship between LoopBack `Model`,
`DataSource`, and `Connector`.
1. Define the `Model` using [LoopBack Definition Language (LDL)](definition-language.md). Now we have a model definition in 1. Define the Model using [LoopBack Definition Language (LDL)](definition-language.md).
plain JSON or JavaScript object. Now we have a model definition in plain JSON or JavaScript object.
2. Create an instance of `ModelBuilder` or `DataSource`. Please note that `DataSource` extends from `ModelBuilder`. 2. Create an instance of ModelBuilder or DataSource. Please note that
`ModelBuilder` is responsible for compiling model definitions to JavaScript constructors representing model classes. DataSource extends from ModelBuilder. ModelBuilder is responsible for compiling
`DataSource` inherits that function from `ModelBuilder`. In addition, `DataSource` adds behaviors to model classes by model definitions to JavaScript constructors representing model classes.
mixing in methods from the `DataAccessObject` into the model class. DataSource inherits that function from ModelBuilder. In addition, DataSource
adds behaviors to model classes by mixing in methods from the DataAccessObject
into the model class.
3. Use `ModelBuilder` or `DataSource` to build a JavaScript constructor (i.e, the model class) from the model definition. 3. Use ModelBuilder or DataSource to build a JavaScript constructor (i.e,
Model classes built from `ModelBuilder` can be later attached to a `DataSource` to receive the mixin of data access functions. the model class) from the model definition. Model classes built from ModelBuilder
can be later attached to a DataSource to receive the mixin of data access
functions.
4. As part of step 2, `DataSource` initializes the underlying `Connector` with a `settings` object which provides configurations 4. As part of step 2, DataSource initializes the underlying Connector with
to the connector instance. `Connector` collaborates with `DataSource` to define the functions as `DataAccessObject` to be mixed a settings object which provides configurations to the connector instance.
into the model class. The `DataAccessObject` consists of a list of static and prototype methods. It can be CRUD operations Connector collaborates with DataSource to define the functions as
DataAccessObject to be mixed into the model class. The DataAccessObject
consists of a list of static and prototype methods. It can be CRUD operations
or other specific functions depending on the connector's capabilities. or other specific functions depending on the connector's capabilities.
## LoopBack DataSource ## LoopBack DataSource
DataSource is the unified interface for LoopBack applications to integrate with backend systems. It's a factory for DataSource is the unified interface for LoopBack applications to integrate with
data access logic around model classes. With the ability to plug in various connectors, DataSource provides the necessary backend systems. It's a factory for data access logic around model classes. With
abstraction to interact with databases or services to decouple the business logic from plumbing technologies. the ability to plug in various connectors, DataSource provides the necessary
abstraction to interact with databases or services to decouple the business
logic from plumbing technologies.
### Creating a DataSource ### Creating a DataSource
@ -59,14 +71,17 @@ The `connector` argument passed the DataSource constructor can be one of the fol
* The connector module from `require(connectorName)` * The connector module from `require(connectorName)`
* The full name of the connector module, such as 'loopback-connector-oracle' * The full name of the connector module, such as 'loopback-connector-oracle'
* The short name of the connector module, such as 'oracle', which will be converted to 'loopback-connector-<shortName>' * The short name of the connector module, such as 'oracle', which will be converted
to 'loopback-connector-<shortName>'
* A local module under ./connectors/<connectorName> folder * A local module under ./connectors/<connectorName> folder
var ds1 = new DataSource('memory'); var ds1 = new DataSource('memory');
var ds2 = new DataSource('loopback-connector-mongodb')); var ds2 = new DataSource('loopback-connector-mongodb'));
var ds3 = new DataSource(require('loopback-connector-oracle')); var ds3 = new DataSource(require('loopback-connector-oracle'));
**Note**: LoopBack provides a built-in connector named as `memory` to use in-memory store for CRUD operations. **Note**: LoopBack provides a built-in connector named as `memory` to use in-memory
store for CRUD operations.
#### settings #### settings
@ -84,8 +99,9 @@ For connector-specific settings refer to connector's readme file.
## Creating a Model ## Creating a Model
`DataSource` extends from `ModelBuilder`, which is a factory for plain model classes that only have properties. `DataSource` extends from `ModelBuilder`, which is a factory for plain model
`DataSource` connected with specific databases or other backend systems using `Connector`. classes that only have properties. `DataSource` connected with specific databases
or other backend systems using `Connector`.
var DataSource = require('loopback-datasource-juggler').DataSource; var DataSource = require('loopback-datasource-juggler').DataSource;
var ds = new DataSource('memory'); var ds = new DataSource('memory');
@ -98,11 +114,12 @@ For connector-specific settings refer to connector's readme file.
age: Number age: Number
}); });
All model classes within single data source shares same connector type and one database All model classes within single data source shares same connector type and one
connection or connection pool. But it's possible to use more than one data source to connect with database connection or connection pool. But it's possible to use more than one
different databases. data source to connect with different databases.
Alternatively, a plain model constructor created from `ModelBuilder` can be attached a `DataSource`. Alternatively, a plain model constructor created from `ModelBuilder` can be
attached a `DataSource`.
var ModelBuilder = require('loopback-datasource-juggler').ModelBuilder; var ModelBuilder = require('loopback-datasource-juggler').ModelBuilder;
var builder = new ModelBuilder(); var builder = new ModelBuilder();
@ -123,15 +140,16 @@ Alternatively, a plain model constructor created from `ModelBuilder` can be atta
## More DataSource Features ## More DataSource Features
In addition to data access functions mixed into the model class, `DataSource` also provides APIs to interact with the In addition to data access functions mixed into the model class, `DataSource`
underlying backend system. also provides APIs to interact with the underlying backend system.
### Discovering model definitions from the data source ### Discovering model definitions from the data source
Some connectors provide discovery capability so that we can use DataSource to discover model definitions from existing Some connectors provide discovery capability so that we can use DataSource to
database schema. discover model definitions from existing database schema.
The following APIs allow UI or code to discover database schema definitions that can be used to build LoopBack models. The following APIs allow UI or code to discover database schema definitions that
can be used to build LoopBack models.
// List database tables and/or views // List database tables and/or views
ds.discoverModelDefinitions({views: true, limit: 20}, cb); ds.discoverModelDefinitions({views: true, limit: 20}, cb);
@ -174,20 +192,22 @@ You can also discover and build model classes in one shot:
}); });
}); });
In addition to the asynchronous APIs, `DataSource` also provides the synchronous ones. Please refer to the DataSource In addition to the asynchronous APIs, `DataSource` also provides the synchronous
API references. ones. Please refer to the DataSource API references.
### Synchronizing model definitions against the data source ### Synchronizing model definitions against the data source
DataSource instance have two methods for updating db structure: `automigrate` and `autoupdate` for relational DataSource instance have two methods for updating db structure: `automigrate` and
databases. `autoupdate` for relational databases.
The `automigrate` method drop table (if exists) and create it again, `autoupdate` method generates The `automigrate` method drop table (if exists) and create it again, `autoupdate`
ALTER TABLE query. Both method accepts an optional array of model names and a callback function to be method generates ALTER TABLE query. Both method accepts an optional array of
called when migration/update done. If the `models` argument is not present, all models are checked. model names and a callback function to be called when migration/update done. If
the `models` argument is not present, all models are checked.
In the following example, we create first version of the CustomerTest model, use `automigrate` to create the database In the following example, we create first version of the CustomerTest model, use
table, redefine the model with second version, and use `autoupdate` to alter the database table. `automigrate` to create the database table, redefine the model with second
version, and use `autoupdate` to alter the database table.
// Create the 1st version of 'CustomerTest' // Create the 1st version of 'CustomerTest'
ds.createModel(schema_v1.name, schema_v1.properties, schema_v1.options); ds.createModel(schema_v1.name, schema_v1.properties, schema_v1.options);
@ -229,7 +249,8 @@ and a `callback` argument, which receive boolean value depending on db state:
## LoopBack Connector ## LoopBack Connector
Connectors implement the logic to integrate with specific backend systems, such as databases or REST services. Connectors implement the logic to integrate with specific backend systems, such
as databases or REST services.
### LoopBack Connector Modules ### LoopBack Connector Modules
@ -246,7 +267,8 @@ Connectors implement the logic to integrate with specific backend systems, such
#### Initializing connector #### Initializing connector
The connector module can export an `initialize` function to be called by the owning DataSource instance. The connector module can export an `initialize` function to be called by the
owning DataSource instance.
exports.initialize = function (dataSource, postInit) { exports.initialize = function (dataSource, postInit) {
@ -258,26 +280,29 @@ The connector module can export an `initialize` function to be called by the own
... ...
}; };
The DataSource calls the `initialize` method with itself and an optional postInit callback function. The connector The DataSource calls the `initialize` method with itself and an optional `postInit`
receives the settings from the dataSource argument and use it to configure connections to backend systems. callback function. The connector receives the settings from the `dataSource`
argument and use it to configure connections to backend systems.
Please note connector and dataSource set up a reference to each other. Please note connector and dataSource set up a reference to each other.
Upon initialization, the connector might connect to database automatically. Once connection established dataSource Upon initialization, the connector might connect to database automatically.
object emit 'connected' event, and set `connected` flag to true, but it is not necessary to wait for 'connected' event Once connection established dataSource object emit 'connected' event, and set
`connected` flag to true, but it is not necessary to wait for 'connected' event
because all queries cached and executed when dataSource emit 'connected' event. because all queries cached and executed when dataSource emit 'connected' event.
To disconnect from database server call `dataSource.disconnect` method. This call forwarded to connector if connector To disconnect from database server call `dataSource.disconnect` method. This
have ability to connect/disconnect. call is forwarded to the connector if the connector have ability to connect/disconnect.
#### Accessing data/services #### Accessing data/services
The connector instance can have an optional property named as DataAccessObject that provides static and prototype methods to The connector instance can have an optional property named as DataAccessObject
be mixed into the model constructor. DataSource has a built-in DataAccessObject to support CRUD operations. The connector that provides static and prototype methods to be mixed into the model constructor.
can choose to use the CRUD DataAccessObject or define its own. DataSource has a built-in DataAccessObject to support CRUD operations. The
connector can choose to use the CRUD DataAccessObject or define its own.
When a method is invoked from the model class or instance, it's delegated to the DataAccessObject which is backed by When a method is invoked from the model class or instance, it's delegated to the
the connector. DataAccessObject which is backed by the connector.
For example, For example,
@ -285,9 +310,9 @@ For example,
## Building your own connectors ## Building your own connectors
LoopBack connectors provide access to backend systems including databases, REST APIs LoopBack connectors provide access to backend systems including databases, REST
and other services. Connectors are not used directly by application code. We create APIs and other services. Connectors are not used directly by application code.
a DataSource to interact with the connector. We create a DataSource to interact with the connector.
For example, For example,
@ -305,7 +330,8 @@ For example,
### Implementing a generic connector ### Implementing a generic connector
A connector module can implement the following methods to interact with the data source. A connector module can implement the following methods to interact with the data
source.
exports.initialize = function (dataSource, postInit) { exports.initialize = function (dataSource, postInit) {
@ -345,8 +371,8 @@ Another way is to directly export the connection function which takes a settings
### Implementing a CRUD connector ### Implementing a CRUD connector
To support CRUD operations for a model class that is attached to the dataSource/connector, the connector needs to provide To support CRUD operations for a model class that is attached to the
the following functions: dataSource/connector, the connector needs to provide the following functions:
/** /**
* Create a new model instance * Create a new model instance

View File

@ -1,8 +1,9 @@
# LoopBack Definition Language Guide # LoopBack Definition Language Guide
LoopBack Definition Language (LDL) is simple DSL to define data models in JavaScript or plain JSON. With LoopBack, we often LoopBack Definition Language (LDL) is simple DSL to define data models in
start with a model definition which describes the structure and types of data. The model establishes common knowledge of JavaScript or plain JSON. With LoopBack, we often start with a model definition
data in LoopBack. which describes the structure and types of data. The model establishes common
knowledge of data in LoopBack.
## Describing a simple model ## Describing a simple model
@ -20,9 +21,10 @@ The model simply defines a `user` model that consists of three properties:
* firstName - The first name. It's a string. * firstName - The first name. It's a string.
* lastName - The last name. It's a string. * lastName - The last name. It's a string.
Each key in the JSON object defines a property in our model which will be cast to its associated type. The simplest form of Each key in the JSON object defines a property in our model which will be cast
a property definition is `propertyName: type`. The key is the name of the property and the value is the type of the property. to its associated type. The simplest form of a property definition is
We'll cover more advanced form later in this guide. `propertyName: type`. The key is the name of the property and the value is the
type of the property. We'll cover more advanced form later in this guide.
LDL supports a list of built-in types, including the basic types from JSON: LDL supports a list of built-in types, including the basic types from JSON:
@ -32,7 +34,8 @@ LDL supports a list of built-in types, including the basic types from JSON:
* Array * Array
* Object * Object
**Note**: The type name is case-insensitive, i.e., either "Number" or "number" can be used. **Note**: The type name is case-insensitive, i.e., either "Number" or "number"
can be used.
The same model can also be described in JavaScript code: The same model can also be described in JavaScript code:
@ -42,16 +45,18 @@ The same model can also be described in JavaScript code:
lastName: String lastName: String
} }
As we can see, the JavaScript version is less verbose as it doesn't require quotes for property names. The types are As we can see, the JavaScript version is less verbose as it doesn't require
described using JavaScript constructors, for example, `Number` for `"Number"`. String literals are also supported. quotes for property names. The types are described using JavaScript constructors,
for example, `Number` for `"Number"`. String literals are also supported.
Now we have the definition of a model, how do we use it in LoopBack Node.js code? It's easy, LoopBack will build a Now we have the definition of a model, how do we use it in LoopBack Node.js
JavaScript constructor (or class) for you. code? It's easy, LoopBack will build a JavaScript constructor (or class) for you.
## Creating a model constructor ## Creating a model constructor
LDL compiles the model definition into a JavaScript constructor using `ModelBuilder.define` APIs. ModelBuilder is the LDL compiles the model definition into a JavaScript constructor using
basic factory to create model constructors. `ModelBuilder.define` APIs. ModelBuilder is the basic factory to create model
constructors.
ModelBuilder.define() method takes the following arguments: ModelBuilder.define() method takes the following arguments:
@ -86,11 +91,13 @@ Here is an example,
That's it. Now you have a User constructor representing the user model. That's it. Now you have a User constructor representing the user model.
At this point, the constructor only has a set of accessors to model properties. No behaviors have been introduced yet. At this point, the constructor only has a set of accessors to model properties.
No behaviors have been introduced yet.
## Adding logic to a model ## Adding logic to a model
Models describe the shape of data. To leverage the data, we'll add logic to the model for various purposes, such as: Models describe the shape of data. To leverage the data, we'll add logic to the
model for various purposes, such as:
- Interact with the data store for CRUD - Interact with the data store for CRUD
- Add behavior around a model instance - Add behavior around a model instance
@ -131,8 +138,9 @@ A plain model constructor created from `ModelBuilder` can be attached a `DataSou
User.attachTo(ds); // The CRUD methods will be mixed into the User constructor User.attachTo(ds); // The CRUD methods will be mixed into the User constructor
### Manually add methods to the model constructor ### Manually add methods to the model constructor
Static methods can be added by declaring a function as a member of the model constructor. Static methods can be added by declaring a function as a member of the model
Within a class method, other class methods can be called using the model as usual. constructor. Within a class method, other class methods can be called using the
model as usual.
// Define a static method // Define a static method
@ -144,8 +152,8 @@ Within a class method, other class methods can be called using the model as usua
console.log(users); // Print an array of user instances console.log(users); // Print an array of user instances
}); });
Instance methods can be added to the prototype. Within instance methods, the model instance itself can be referenced Instance methods can be added to the prototype. Within instance methods, the
with this keyword. model instance itself can be referenced with this keyword.
// Define a prototype method // Define a prototype method
User.prototype.getFullName = function () { User.prototype.getFullName = function () {
@ -158,7 +166,8 @@ with this keyword.
## Exploring advanced LDL features ## Exploring advanced LDL features
As we mentioned before, a complete model definition is an object with three properties: As we mentioned before, a complete model definition is an object with three
properties:
- name: The model name - name: The model name
- options: An object of options, optional - options: An object of options, optional
@ -176,8 +185,9 @@ There are a set of options to control the model definition.
- false: No `id` property will be added to the model - false: No `id` property will be added to the model
- Data source specific mappings - Data source specific mappings
The model can be decorated with connector-specific options to customize the mapping between the model and the connector. The model can be decorated with connector-specific options to customize the
For example, we can define the corresponding schema/table names for Oracle as follows: mapping between the model and the connector. For example, we can define the
corresponding schema/table names for Oracle as follows:
{ {
"name": "Location", "name": "Location",
@ -192,9 +202,11 @@ For example, we can define the corresponding schema/table names for Oracle as fo
} }
### Property definitions ### Property definitions
A model consists of a list of properties. The basic example use `propertyName: type` to describe a property. A model consists of a list of properties. The basic example use
`propertyName: type` to describe a property.
Properties can have options in addition to the type. LDL uses a JSON object to describe such properties, for example: Properties can have options in addition to the type. LDL uses a JSON object to
describe such properties, for example:
"id": {"type": "number", "id": true, "doc": "User ID"} "id": {"type": "number", "id": true, "doc": "User ID"}
@ -222,7 +234,8 @@ LDL supports array types as follows:
- `{emails: [{type: String, length: 64}]}` - `{emails: [{type: String, length: 64}]}`
##### Object types ##### Object types
A model often has properties that consist of other properties. For example, the user model can have an `address` property A model often has properties that consist of other properties. For example, the
user model can have an `address` property
that in turn has properties such as `street`, `city`, `state`, and `zipCode`. that in turn has properties such as `street`, `city`, `state`, and `zipCode`.
LDL allows inline declaration of such properties, for example, LDL allows inline declaration of such properties, for example,
@ -239,9 +252,11 @@ LDL allows inline declaration of such properties, for example,
... ...
} }
The value of the address is the definition of the `address` type, which can be also considered as an anonymous model. The value of the address is the definition of the `address` type, which can be
also considered as an anonymous model.
If you intend to reuse the address model, we can define it independently and reference it in the user model. For example, If you intend to reuse the address model, we can define it independently and
reference it in the user model. For example,
var AddressModel = { var AddressModel = {
street: String, street: String,
@ -261,26 +276,29 @@ If you intend to reuse the address model, we can define it independently and ref
var User = ds.define('User', UserModel); var User = ds.define('User', UserModel);
**Note**: The user model has to reference the Address constructor or the model name - `'Address'`. **Note**: The user model has to reference the Address constructor or the model
name - `'Address'`.
#### ID(s) for a model #### ID(s) for a model
A model representing data to be persisted in a database usually has one or more properties as an id to uniquely A model representing data to be persisted in a database usually has one or more
identify the model instance. For example, the `user` model can have user ids. properties as an id to uniquely identify the model instance. For example, the
`user` model can have user ids.
By default, if no id properties are defined and the `idInjection` of the model options is false, LDL will automatically By default, if no id properties are defined and the `idInjection` of the model
add an id property to the model as follows: options is false, LDL will automatically add an id property to the model as follows:
id: {type: Number, generated: true, id: true} id: {type: Number, generated: true, id: true}
To explicitly specify a property as `id`, LDL provides an `id` property for the option. The value can be true, false, To explicitly specify a property as `id`, LDL provides an `id` property for the
or a number. option. The value can be true, false, or a number.
- true: It's an id - true: It's an id
- false or any falsey values: It's not an id (default) - false or any falsey values: It's not an id (default)
- a positive number, such as 1 or 2: It's the index of the composite id - a positive number, such as 1 or 2: It's the index of the composite id
LDL supports the definition of a composite id that has more than one properties. For example, LDL supports the definition of a composite id that has more than one properties.
For example,
var InventoryDefinition = var InventoryDefinition =
{ {
@ -313,8 +331,9 @@ Format conversions can also be declared as options, for example:
* format: Format a Date * format: Format a Date
#### Mapping #### Mapping
Data source specific mappings can be added to the property options, for example, to map a property to be a column in Data source specific mappings can be added to the property options, for example,
Oracle database table, you can use the following syntax: to map a property to be a column in Oracle database table, you can use the
following syntax:
"oracle": {"column": "FIRST_NAME", "type": "VARCHAR", "length": 32} "oracle": {"column": "FIRST_NAME", "type": "VARCHAR", "length": 32}
@ -323,10 +342,11 @@ Oracle database table, you can use the following syntax:
#### hasMany #### hasMany
A `hasMany` relation builds a one-to-many connection with another model. You'll often find this relation on A `hasMany` relation builds a one-to-many connection with another model. You'll
the "other side" of a `belongsTo` relation. This relation indicates that each instance of the model has zero often find this relation on the "other side" of a `belongsTo` relation. This
or more instances of another model. For example, in an application containing users and posts, a user has zero relation indicates that each instance of the model has zero or more instances
or more posts. For example, of another model. For example, in an application containing users and posts, a
user has zero or more posts. For example,
// setup relationships // setup relationships
User.hasMany(Post, {as: 'posts', foreignKey: 'userId'}); User.hasMany(Post, {as: 'posts', foreignKey: 'userId'});
@ -352,8 +372,8 @@ Example:
Book.hasMany('chapters', {model: Chapter, foreignKey: 'chapter_id'}); Book.hasMany('chapters', {model: Chapter, foreignKey: 'chapter_id'});
Scope methods created on the base model by hasMany allows to build, create and query instances of other class. Scope methods created on the base model by hasMany allows to build, create and
For example: query instances of other class. For example,
Book.create(function(err, book) { Book.create(function(err, book) {
// using 'chapters' scope for build: // using 'chapters' scope for build:
@ -374,14 +394,16 @@ For example:
#### belongsTo #### belongsTo
A `belongsTo` relation sets up a one-to-one connection with another model, such that each instance of the declaring A `belongsTo` relation sets up a one-to-one connection with another model, such
model "belongs to" one instance of the other model. For example, if your application includes users and posts, that each instance of the declaring model "belongs to" one instance of the other
and each post can be written by exactly one user. model. For example, if your application includes users and posts, and each post
can be written by exactly one user.
Post.belongsTo(User, {as: 'author', foreignKey: 'userId'}); Post.belongsTo(User, {as: 'author', foreignKey: 'userId'});
The code above basically says Post has a reference called `author` to User using the `userId` property of Post as the The code above basically says Post has a reference called `author` to User using
foreign key. Now we can access the author in one of the following styles: the `userId` property of Post as the foreign key. Now we can access the author
in one of the following styles:
post.author(callback); // Get the User object for the post author asynchronously post.author(callback); // Get the User object for the post author asynchronously
@ -389,9 +411,10 @@ foreign key. Now we can access the author in one of the following styles:
post.author(user) // Set the author to be the given user post.author(user) // Set the author to be the given user
#### hasAndBelongsToMany #### hasAndBelongsToMany
A `hasAndBelongsToMany` relation creates a direct many-to-many connection with another model, with no A `hasAndBelongsToMany` relation creates a direct many-to-many connection with
intervening model. For example, if your application includes users and groups, with each group having many users another model, with no intervening model. For example, if your application
and each user appearing in many groups, you could declare the models this way, includes users and groups, with each group having many users and each user
appearing in many groups, you could declare the models this way,
User.hasAndBelongsToMany('groups', {model: Group, foreignKey: 'groupId'}); User.hasAndBelongsToMany('groups', {model: Group, foreignKey: 'groupId'});
user.groups(callback); // get groups of the user user.groups(callback); // get groups of the user
@ -401,8 +424,9 @@ and each user appearing in many groups, you could declare the models this way,
### Extend from a base model ### Extend from a base model
LDL allows a new model to extend from an existing model. For example, Customer can extend from User as follows. The Customer LDL allows a new model to extend from an existing model. For example, Customer
model will inherit properties and methods from the User model. can extend from User as follows. The Customer model will inherit properties and
methods from the User model.
var Customer = User.extend('customer', { var Customer = User.extend('customer', {
accountId: String, accountId: String,
@ -410,8 +434,8 @@ model will inherit properties and methods from the User model.
}); });
### Mix in model definitions ### Mix in model definitions
Some models share the common set of properties and logic around. LDL allows a model to mix in one or more other models. Some models share the common set of properties and logic around. LDL allows a
For example, model to mix in one or more other models. For example,
var TimeStamp = modelBuilder.define('TimeStamp', {created: Date, modified: Date}); var TimeStamp = modelBuilder.define('TimeStamp', {created: Date, modified: Date});
var Group = modelBuilder.define('Group', {groups: [String]}); var Group = modelBuilder.define('Group', {groups: [String]});