不要怂,就是干,撸起袖子干!

Commit 07e9c9e4 by Jan Aagaard Meier

RTD migration

1 parent 02f7cf26
<script type="text/javascript">
fromGithub = function (partialId, ext) {
ext = ext || '';
var $partial = $("#" + partialId)
$.get("https://cdn.rawgit.com/sequelize/express-example/master/" + partialId.replace("_", "/") + ext, function (code) {
if (ext === '.js') {
code = hljs.highlight('js', code).value;
}
code = '<div class="highlight"><pre>' + code + '</pre></div>';
$partial.replaceWith(code);
}, 'html');
}
</script>
## Introduction
This article explains the usage of Sequelize with the MVC framework Express.You will learn how and where to define models and how to load them when needed.
## A minimal express application
In order to create a minimal express application, we need to install express first and scaffold a project. We can do this via the following commands:
```bash
$ mkdir example-app
$ cd example-app
$ npm install express express-generator
$ node_modules/.bin/express . -f
$ npm install
$ ./bin/www
```
You should now be able to see a tiny welcome page on `http://localhost:3000`
## Adding Sequelize to the application
Now that we have the express application in place, we can start adding Sequelize to it. What we need for that are the following packages: sequelize, sequelize-cli, sqlite3. Please note, that for the sake of simplicity this tutorial will use SQLite.
```bash
$ npm install --save sequelize@2.0.0-rc1 sequelize-cli sqlite3
```
This will install the respective packages and uses the upcoming major release of sequelize. We can now let the sequelize CLI initialize the project's directory:
```bash
$ node_modules/.bin/sequelize init
```
Running this command will create the folders `config`, `migrations` and `models`.
## Implementing a todo app
As an example application we will create a very basic and simple todo tool, which allows the creation of users and the management of their tasks.
### bin/www
In order to create a maintainable application, we will put all the database logic into the `models` folder. When the application gets fired up, sequelize will sync the models with the database and afterwards start the server. This way we don't clutter the application while making use of sequelize's features.
<div id="bin_www"></div>
<script>$(function () { fromGithub("bin_www") })</script>
### models/index.js
This file has been generated with the sequelize CLI and collects all the models from the `models` directory and associates them if needed.
<div id="models_index"></div>
<script>$(function () { fromGithub("models_index", '.js') })</script>
### models/user.js
All models of our application are located as separate files in the `models` folder. If you want to add a new model, just add it to this folder and everything will work automagically. Also you can use the sequelize CLI's `sequelize model:create`.
**Notice** that the `associate` method receives a parameter `models`, which contains every declared model within the models directory.
<div id="models_user"></div>
<script>$(function () { fromGithub("models_user", '.js') })</script>
### models/task.js
The other needed model is `Task`. It relates to the `User`.
<div id="models_task"></div>
<script>$(function () { fromGithub("models_task", '.js') })</script>
### routes/index.js
The file `routes/index.js` contains the logic for a request against the main homepage. It loads the models module and uses it to load all the users and tasks from the database.
<div id="routes_index"></div>
<script>$(function () { fromGithub("routes_index", '.js') })</script>
This will allow us to iterate over the users in the view file. We will skip the rest of the route files for this article.
### views/index.jade
As we passed the users to the view and include the tasks for each user, we can access the data in the view's template file. Besides listing the users and tasks, there are also forms for creating new instances.
<div id="views_index"></div>
<script>$(function () { fromGithub("views_index", '.jade') })</script>
## What's next?
This article shows a basic approach of how to integrate Sequelize into an ExpressJS application. It allows the very easy management of models by adding new files to a specific folder. Starting the application will automatically sync the schema with the database.
If you don't want to have automatic schema synchronization and instead want migrations, just add a respective step to your deployment script. When you use the CLI for the model generation, you will gain the migration scripts for free as well.
You can find the complete application code [on Github](https://github.com/sequelize/express-example). Feel free to add pull requests to it.
Besides the use of Sequelize as model backend in your ExpressJS application, you might also want to turn your server into a restful API. If that is the case, check out [the repository on Github](https://github.com/sequelize/sequelize-restful)
\ No newline at end of file
## Introduction
This section covers the use of Sequelize on Heroku. It will explain how to get started with Heroku and what is necessary to setup a proper environment. We will use MySQL on the development machine and PostgreSQL on the remote servers.
## Getting started with Heroku
Before we can roll out any software on the Heroku cluster, we need to sign up and have to connect our development environment. Here are the most basic steps:
* [Sign up][0] for a Heroku account.
* [Install][1] the Heroku Toolbelt. This tool will let you create applications and is a handy way to configure them on the command line.
* Use the new binary to login. Run the following command on command line:`heroku login`
And that's it. You should now be able to do things like `heroku apps`. This should list all applications you've currently created on the Heroku cluster. If you've just created a new account, this should show you an empty list. [You can get further information about the registration process here][2].
## A minimal express application
In order to create a minimal express application, we need to install express first. We can do this via the following commands:
```bash
$ mkdir example-app
$ cd example-app
$ npm install express
$ node_modules/.bin/express . -f
$ npm install
$ node app.js
```
So now we have a default express application. If you point your browser to `http://localhost:8080`, you will see a tiny page welcoming you.
Next step: Deploy the application to Heroku.
## Deployment to Heroku
First of all, we need to add the right version of Node.JS and NPM to the `package.json`. The file should look similiar to this:
```js
{
"name": "application-name",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node app.js"
},
"dependencies": {
"express": "3.1.1",
"jade": "*"
},
"engines": {
"node": "0.8.x",
"npm": "1.1.x"
}
}
```
Now we can create a Heroku application and deploy to it:
```bash
$ echo "web: node app.js" > Procfile
$ echo "node_modules" > .gitignore
$ git init
$ git add .
$ git commit -m "initial commit"
$ heroku create
$ git push heroku master
$ heroku ps:scale web=1
$ heroku open
```
You should now see a browser with the same application as on your local machine.
## Spawning a database on Heroku
In order to get a database on Heroku we can use their CLI. Just run the following command and take a closer look at it's output:
```bash
$ heroku addons:add heroku-postgresql:dev
```
This will result in something like this:
```bash
Adding heroku-postgresql:dev on fast-dusk-7858... done, v5 (free)
Attached as HEROKU_POSTGRESQL_BRONZE_URL
Database has been created and is available
! This database is empty. If upgrading, you can transfer
! data from another database with pgbackups:restore.
Use `heroku addons:docs heroku-postgresql:dev` to view documentation.
```
What we will need is the color (sounds strange right?) of the database. In this case we just created a `bronze` one. That means, that we will have an environment variable `HEROKU_POSTGRESQL_BRONZE_URL` containing the URI of the database.
If you are interested in the URI, you can just run this command:
```bash
$ heroku config:get HEROKU_POSTGRESQL_BRONZE_URL
$ # => postgres://pfforbjhkrletg:aic5oO6Cran1g3hk6mJa5QqNZB@ec2-23-21-91-97.compute-1.amazonaws.com:5432/dek11b2j1g3mfb
```
## Adding Sequelize to the application
The following commands will install `sequelize`, the needed PostgreSQL library as well as the MySQL bindings. Also we will create a folder `models`, that will contain the model definitions.
```bash
$ npm install --save sequelize pg mysql
$ mkdir models
```
### app.js
In order to create a maintainable application, we will put all the database logic into the `models` folder. The application's main file will then just sync the models with the database and run the server. This way we don't clutter the application.
```js
var express = require('express')
, routes = require('./routes')
, user = require('./routes/user')
, http = require('http')
, path = require('path')
, db = require('./models');
var app = express();
// all environments
app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));
// development only
if ('development' === app.get('env')) {
app.use(express.errorHandler());
}
app.get('/', routes.index);
app.get('/users', user.list);
db.sequelize.sync().then(function() {
http.createServer(app).listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
});
});
```
### models/index.js
The idea of this file is to configure a connection to the database and to collect all model definitions. Once everything is in place we will store the stuff in a singleton. This will make it possible to load the file whenever we need database access without running into issues with duplicated database access.
This file will also differ between the local machine and the Heroku server.
```js
if (!global.hasOwnProperty('db')) {
var Sequelize = require('sequelize')
, sequelize = null
if (process.env.HEROKU_POSTGRESQL_BRONZE_URL) {
// the application is executed on Heroku ... use the postgres database
sequelize = new Sequelize(process.env.HEROKU_POSTGRESQL_BRONZE_URL, {
dialect: 'postgres',
protocol: 'postgres',
port: match[4],
host: match[3],
logging: true //false
})
} else {
// the application is executed on the local machine ... use mysql
sequelize = new Sequelize('example-app-db', 'root', null)
}
global.db = {
Sequelize: Sequelize,
sequelize: sequelize,
User: sequelize.import(__dirname + '/user') 
// add your other models here
}
/*
Associations can be defined here. E.g. like this:
global.db.User.hasMany(global.db.SomethingElse)
*/
}
module.exports = global.db
```
### models/user.js
All the other models of our application will be located as separate files in the `models` folder. We will use the `import`-method of Sequelize to load those files.
```js
module.exports = function(sequelize, DataTypes) {
return sequelize.define("User", {
username: DataTypes.STRING
})
}
```
## Running Migrations
To run migrations on Heroku you must have the following entry in your config/config.json file:
```js
"production": {
"use_env_variable": "DATABASE_URL"
}
```
Which also means you must make sure your Heroku environment has [a promoted database.][3] Then from the command line run
```bash
$ heroku run bash
$ sequelize -m
```
## tl;dr
This article explains a straight-forward but maintainable approach for hosting an express application on Heroku. If you don't want to read all the stuff mentioned, just execute the following stuff and have fun.
```bash
$ mkdir example-app
$ cd example-app
$ npm install express
$ node_modules/.bin/express . -f
$ npm install
$ curl -s https://gist.github.com/sdepold/ced7d2a4a847f38901ef/raw/459c923dd0a14841c932bb95ff3be8a8170bd563/package.json > package.json
$ echo "web: node app.js" > Procfile
$ echo "node_modules" > .gitignore
$ npm install --save sequelize pg mysql
$ mkdir models
$ git init
$ git add .
$ git commit -m "initial commit"
$ heroku create
$ git push heroku master
$ heroku ps:scale web=1
$ heroku addons:add heroku-postgresql:dev
$ curl -s https://gist.github.com/sdepold/ced7d2a4a847f38901ef/raw/6db41e130a8b901cd0843bf52390b7cb11db5f15/app.js > app.js
$ curl -s https://gist.github.com/sdepold/ced7d2a4a847f38901ef/raw/26c5a94d74db4a242464b02aa8e0ae4b3bac6880/models-index.js > models/index.js
$ curl -s https://gist.github.com/sdepold/ced7d2a4a847f38901ef/raw/3b37b0e5d459b2e4b3833a63a018b600a1001795/models-user.js > models/user.js
$ clear
$ # Now run the following command and change HEROKU_POSTGRESQL_BRONZE_URL in
$ # the file "models/index.js" to its result:
$ heroku config|grep HEROKU_POSTGRESQL|cut -d : -f 1
$ git add .
$ git commit -m "sequelize application"
$ git push heroku master
$ heroku open
```
[0]: https://api.heroku.com/signup/devcenter
[1]: https://toolbelt.heroku.com/
[2]: https://devcenter.heroku.com/articles/quickstart
[3]: https://devcenter.heroku.com/articles/heroku-postgresql#establish-primary-db
\ No newline at end of file
table {
width:100%;
}
th:nth-child(1),
td:nth-child(1) {
width: 35%;
word-break: break-all;
}
td:nth-child(2),
td:nth-child(2) {
width: 20%;
word-break: break-word;
}
td,
th {
padding: 6px 13px;
border: 1px solid #ddd;
}
tr:nth-child(2n) {
background-color: #f8f8f8;
}
\ No newline at end of file
"use strict";
var dox = require('dox')
, program = require('commander')
, fs = require('fs')
, path = require('path')
, git = require('git')
, _ = require('lodash');
program
.version('0.0.2')
.option('-f, --file [file]', 'Process a single file', '')
.option('-a, --all', 'Process all files, generate index etc. (default if no options are specified')
.option('-o --out [dir]', '', path.dirname(__filename) + '/api')
.parse(process.argv);
var files;
if (program.file) {
files = [{file: program.file, output: 'tmp'}];
} else {
files = [
{file:'lib/errors.js', output: 'errors'},
{file:'lib/sequelize.js', output: 'sequelize'},
{file:'lib/instance.js', output: 'instance'},
{file:'lib/model.js', output: 'model'},
{file:'lib/hooks.js', output: 'hooks'},
{file:'lib/associations/mixin.js', output: 'associations'},
{file:'lib/promise.js', output: 'promise'},
{file:'lib/transaction.js', output: 'transaction'},
{file:'lib/data-types.js', output: 'datatypes'}
];
}
var Comment = function(data, file) {
this.data = data;
this.file = file;
this.string = '';
};
Comment.prototype.getTag = function(tagName) {
return _.find(this.data.tags, function (tag) {
return tag.type === tagName;
});
};
Comment.prototype.getTags = function(tagName) {
return _.where(this.data.tags, function (tag) {
return tag.type === tagName;
});
};
Comment.prototype.hasTag = function(tagName) {
return this.getTag(tagName) !== undefined;
};
Comment.prototype.getName = function () {
var tag;
tag = this.getTag('name');
if (tag) {
return tag.string;
}
tag = this.getTag('class');
if (tag) {
return tag.string;
}
tag = this.getTag('property');
if (tag) {
return tag.types[0];
}
tag = this.getTag('method');
if (tag) {
return tag.string;
}
return this.data.ctx.name;
};
Comment.prototype.getParams = function () {
if (this.isProperty()) {
return '';
}
// Only show params without a dot in them (dots means attributes of object, so no need to clutter the signature too much)
var params = [] ;
this.getTags('param').forEach(function (paramTag) {
if (paramTag.name.indexOf('.') === -1) {
params.push(paramTag.name);
}
});
return '(' + params.join(', ') + ')';
};
Comment.prototype.isProperty = function () {
return !this.hasTag('method') && this.data.ctx && this.data.ctx.type === 'property';
};
Comment.prototype.putString = function(str) {
this.string += str;
};
Comment.prototype.putLine = function(str) {
str = str || '';
this.putString(str + "\n");
};
Comment.prototype.putLines = function(lines) {
lines.forEach(function (line) {
this.putLine(line);
}, this);
};
Comment.prototype.toString = function () {
return this.string + "\n";
};
['class', 'mixin', 'constructor'].forEach(function (prop) {
Comment.prototype['is' + prop.charAt(0).toUpperCase() + prop.slice(1)] = function () {
return this.hasTag(prop);
};
});
Comment.prototype.githubLink = function() {
return 'https://github.com/sequelize/sequelize/blob/' + Comment.commit + '/' + this.file + '#L' + this.data.codeStart;
};
Comment.concatTypes = function (types, convertEntities) {
if (convertEntities === undefined) {
convertEntities = true;
}
var type = types.join('|');
if (type.indexOf('<') !== -1 && type.indexOf('>') === -1) {
// If the string is Array<something|somethingelse> the closing > disappears...
type += '>';
}
if (convertEntities) {
// Convert a couple of things to their HTML-entities
// The spacing around | is intentional, in order to introduce some linebreaks in the params table
type = type.replace('|', ' &#124; ')
.replace('>', '&gt;')
.replace('<', '&lt;');
}
return type;
};
var parseComments = function (comments, file) {
var output = ''
, comment
, name
, returns
, mixes
, deprecated
, see
, params
, extend
, aliases;
comments.forEach(function (data) {
if (data.tags.length) {
comment = new Comment(data, file);
name = comment.getName();
comment.putLine('<a name="' + name.toLowerCase() + '"></a>');
if (comment.isClass()) {
comment.putLine('# Class ' + name);
} else if (comment.isMixin()) {
comment.putLine('# Mixin ' + name);
} else if (comment.isConstructor()) {
comment.putLine('## `new ' + name + comment.getParams() + '`');
} else {
comment.putString('## `' + name + comment.getParams() + '`');
if (comment.hasTag('return')) {
returns = comment.getTag('return');
var returnType = Comment.concatTypes(returns.types, false); // We don't convert HTML entities since tihs is displayed in a literal block
comment.putString(' -> `' + returnType + '`');
}
comment.putLine();
}
comment.putLine('[View code](' + comment.githubLink() + ')');
comment.putLine(comment.data.description.full);
if ((mixes = comment.getTags('mixes')).length) {
comment.putLine('### Mixes:');
mixes.forEach(function (mixin) {
comment.putLine('* ' + mixin.string);
});
}
if (deprecated = comment.getTag('deprecated')) {
comment.putLine('**Deprecated** ' + deprecated.string);
}
if ((see = comment.getTags('see')).length) {
comment.putLine();
comment.putLine('**See:**');
comment.putLine();
var link;
see.forEach(function (see) {
if (see.local) {
link = see.local.match(/{(.*?(?:|#.*?))}/)[1];
comment.putLine('* [' + link + '](' + link.toLowerCase() + ')');
} else {
comment.putLine('* [' + see.title | see.url + '](' + see.url + ')');
}
});
comment.putLine();
}
if (comment.hasTag('param')) {
params = comment.getTags('param');
comment.putLines([
'',
'**Params:**',
'',
'| Name | Type | Description |',
'| ---- | ---- | ----------- |'
]);
var type;
params.forEach(function (param) {
type = Comment.concatTypes(param.types);
comment.putLine('| ' + param.name + ' | ' + type + ' | ' + param.description + ' |');
});
comment.putLine();
}
if (returns && returns.description) {
comment.putLine('__Returns:__ ' + returns.description);
}
if ((aliases = comment.getTags('alias')).length) {
comment.putLine('__Aliases:__ ' + aliases.map(function (a) {
return a.string;
}).join(', '));
}
if (extend = comment.getTag('extends')) {
comment.putLine();
comment.putLine('__Extends:__ ' + extend.otherClass);
}
comment.putLine();
comment.putLine('***');
output += comment.toString();
}
});
output += '_This document is automatically generated based on source code comments. Please do not edit it directly, as your changes will be ignored. Please write on <a href="irc://irc.freenode.net/#sequelizejs">IRC</a>, open an issue or a create a pull request if you feel something can be improved. For help on how to write source code documentation see [JSDoc](http://usejsdoc.org) and [dox](https://github.com/tj/dox)_';
return output;
};
var code, obj, output, path;
new git.Repo(path.dirname(__filename) + '/..', function (err, repo) {
repo.head(function (err, status) {
Comment.commit = status.commit;
files.forEach(function (file) {
fs.readFile(file.file, function (err, code) {
obj = dox.parseComments(code.toString(), { raw: true});
path = program.out + '/' + file.output + '.md';
console.log(path)
var output = parseComments(obj, file.file);
fs.writeFile(path, output);
});
});
});
});
## Hooks
Hooks (also known as callbacks or lifecycle events), are functions which are called before and after calls in sequelize are executed. For example, if you want to always set a value on a model before saving it, you can add a`beforeUpdate`hook.
### Order of Operations
(1)
beforeBulkCreate(daos, fields, fn)
beforeBulkDestroy(daos, fields, fn)
beforeBulkUpdate(daos, fields, fn)
(2)
beforeValidate(dao, fn)
(-)
validate
(3)
afterValidate(dao, fn)
(4)
beforeCreate(dao, fn)
beforeDestroy(dao, fn)
beforeUpdate(dao, fn)
(-)
create
destroy
update
(5)
afterCreate(dao, fn)
afterDestroy(dao, fn)
afterUpdate(dao, fn)
(6)
afterBulkCreate(daos, fields, fn)
afterBulkDestory(daos, fields, fn)
afterBulkUpdate(daos, fields, fn)
### Declaring Hooks
There are currently three ways to programmatically add hooks. A hook function always runs asynchronousĺy, and can be resolved either by calling a callback (passed as the last argument),
or by returning a promise.
// Method 1 via the .define() method
var User = sequelize.define('User', {
username: DataTypes.STRING,
mood: {
type: DataTypes.ENUM,
values: ['happy', 'sad', 'neutral']
}
}, {
hooks: {
beforeValidate: function(user, fn) {
user.mood = 'happy'
fn(null, user)
},
afterValidate: function(user, fn) {
user.username = 'Toni'
fn(null, user)
}
}
})
// Method 2 via the .hook() method
var User = sequelize.define('User', {
username: DataTypes.STRING,
mood: {
type: DataTypes.ENUM,
values: ['happy', 'sad', 'neutral']
}
})
User.hook('beforeValidate', function(user, fn) {
user.mood = 'happy'
fn(null, user)
})
User.hook('afterValidate', function(user) {
return sequelize.Promise.reject("I'm afraid I can't let you do that!")
})
// Method 3 via the direct method
var User = sequelize.define('User', {
username: DataTypes.STRING,
mood: {
type: DataTypes.ENUM,
values: ['happy', 'sad', 'neutral']
}
})
User.beforeValidate(function(user) {
user.mood = 'happy'
return sequelize.Promise.resolve(user)
})
User.afterValidate(function(user, fn) {
user.username = 'Toni'
fn(null, user)
})
#### Instance hooks
The following hooks will emit whenever you're editing a single object...
beforeValidate
afterValidate
beforeCreate / beforeUpdate / beforeDestroy
afterCreate / afterUpdate / afterDestroy
// ...define ...
User.beforeCreate(function(user, fn) {
if (user.accessLevel > 10 && user.username !== "Boss") {
return fn("You can't grant this user an access level above 10!")
}
return fn()
})
This example will emit an error:
User.create({username: 'Not a Boss', accessLevel: 20}).error(function(err) {
console.log(err) // You can't grant this user an access level above 10!
})
The following example would emit a success event:
User.create({username: 'Boss', accessLevel: 20}).success(function(user) {
console.log(user) // user object with username as Boss and accessLevel of 20
})
#### Model hooks
Sometimes you'll be editing more than one record at a time by utilizing the`bulkCreate, update, destroy`methods on the model. The following will emit whenever you're using one of those methods.
beforeBulkCreate / beforeBulkUpdate / beforeBulkDestroy
afterBulkCreate / afterBulkUpdate / afterBulkDestroy
If you want to emit hooks for each individual record, along with the bulk hooks you can pass`individualHooks: true`to the call.
Model.destroy({accessLevel: 0}, {individualHooks: true})
// Will select all records that are about to be deleted and emit before- + after- Destroy on each instance
Model.update({username: 'Toni'}, {accessLevel: 0}, {individualHooks: true})
// Will select all records that are about to be updated and emit before- + after- Update on each instance
Model.bulkCreate({accessLevel: 0}, null, {individualHooks: true})
// Will select all records that are about to be deleted and emit before- + after- Create on each instance
Some model hooks have two or three parameters sent to each hook depending on it's type.
Model.beforeBulkCreate(function(records, fields, fn) {
// records = the first argument sent to .bulkCreate
// fields = the second argument sent to .bulkCreate
})
Model.bulkCreate([
{username: 'Toni'}, // part of records argument
{username: 'Tobi'} // part of records argument
], ['username'] /* part of fields argument */)
Model.beforeBulkUpdate(function(attributes, where, fn) {
// attributes = first argument sent to Model.update
// where = second argument sent to Model.update
})
Model.update({gender: 'Male'} /*attributes argument*/, {username: 'Tom'} /*where argument*/)
Model.beforeBulkDestroy(function(whereClause, fn) {
// whereClause = first argument sent to Model.destroy
})
Model.destroy({username: 'Tom'} /*whereClause argument*/)
## Associations
For the most part hooks will work the same for instances when being associated except a few things
1. When using add/set\[s\] functions the beforeUpdate/afterUpdate hooks will run.
2. The only way to call beforeDestroy/afterDestroy hooks are on associations with`onDelete: 'cascade'`and the option`hooks: true`. For instance:
var Projects = sequelize.define('Projects', {
title: DataTypes.STRING
})
var Tasks = sequelize.define('Tasks', {
title: DataTypes.STRING
})
Projects.hasMany(Tasks, {onDelete: 'cascade', hooks: true})
Tasks.belongsTo(Projects)
This code will run beforeDestroy/afterDestroy on the Tasks table. Sequelize, by default, will try to optimize your queries as much as possible.
When calling cascade on delete, Sequelize will simply execute a
DELETE FROM `table` WHERE associatedIdentifiier = associatedIdentifier.primaryKey
However, adding`hooks: true`explicitly tells Sequelize that optimization is not of your concern and will perform a`SELECT`on the associated objects and destroy each instance one by one in order to be able to call the hooks with the right parameters.
## Installation
You have two options to install Sequelize&colon;
1&period; Install it via NPM&colon;
# Use npm on the commandline:
npm install sequelize
// Then require the installed library in your application code:
var Sequelize = require("sequelize")
2&period; Download the code from the git repository and require it's entry file index&period;js&colon;
# Checkout the current code from the repository using the commandline
cd path/to/lib
git clone git://github.com/sequelize/sequelize.git
Then require the installed library in your application code&colon;
var Sequelize = require(__dirname + "/lib/sequelize/index")
This will make the class`Sequelize`available&period;
## Migrations
Sequelize`v1&period;3&period;0`introduced migrations&period; With those mechanism you can transform your existing database into another state and vice versa&period; Those state transitions are saved in migration files&comma; which describe the way how to get to the new state and how to revert the changes in order to get back to the old state&period;
### The binary
In order to run migrations&comma; sequelize comes with a handy binary file which can setup your project and run migrations&period; The following snippet shows the possible things&colon;
sequelize -h
sequelize --help
# prints the help
sequelize -V
sequelize --version
# prints the version
sequelize -i
sequelize --init
# creates a migration folder
# creates a config folder
# saves a config.json inside the config folder
sequelize -e [environment]
sequelize --env [environment]
# Use the passed environment. Default: development
sequelize -i -f
sequelize --init --force
# forced creation of migration and config folder
# existing data will be deleted first
sequelize -m
sequelize --migrate
# needs a valid config.json
# runs pending migrations
# saves successfully executed migrations inside the database
sequelize -m -u
sequelize --migrate --undo
# needs a valid config.json
# reverts the last successfull migration
# when there were multiple executed migrations, all of them are reverted
sequelize -c [migration-name]
sequelize --create-migration [migration-name]
# creates the migrations folder
# creates a file with current timestamp + migration-name
# migration-name has the default 'unnamed-migration'
sequelize -p [path]
sequelize --migration-path [path]
# Defines the path to the migration directory.
sequelize -o [path]
sequelize --options-path [path]
# Defines the path to the options file.
# The options file (.js or .json) needs to return an object.
# Keys / values references cli options
# e.g.: { migrationPath: 'db/migrations' }
sequelize --config [path]
# Defines the path to the configuration file.
sequelize --coffee
# Enables coffeescript support.
### Skeleton
The following skeleton shows a typical migration file&period; All migrations are expected to be located in a folder called`migrations`at the very top of the project&period; Sequelize`1&period;4&period;1`added the possibility to let the sequelize binary generate a migration skeleton&period; See the aboves section for more details&period;
module.exports = {
up: function(migration, DataTypes, done) {
// logic for transforming into the new state
done() // sets the migration as finished
},
 
down: function(migration, DataTypes, done) {
// logic for reverting the changes
done() // sets the migration as finished
}
}
The passed`migration`object can be used to modify the database&period; The`DataTypes`object stores the available data types such as`STRING`or`INTEGER`&period; The third parameter is a callback function which needs to be called once everything was executed&period; The first parameter of the callback function can be used to pass a possible error&period; In that case&comma; the migration will be marked as failed&period; Here is some code&colon;
module.exports = {
up: function(migration, DataTypes, done) {
migration.dropAllTables().complete(done)
 
// equals:
migration.dropAllTables().complete(function(err) {
if (err) {
done(err)
} else {
done(null)
}
})
}
}
The available methods of the migration object are the following&period;
### Functions
Using the`migration`object describe before&comma; you will have access to most of already introduced functions&period; Furthermore there are some other methods&comma; which are designed to actually change the database schema&period;
#### createTable&lpar;tableName&comma; attributes&comma; options&rpar;
This method allows creation of new tables&period; It is allowed to pass simple or complex attribute definitions&period; You can define the encoding of the table and the table's engine via options
migration.createTable(
'nameOfTheNewTable',
{
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
createdAt: {
type: DataTypes.DATE
},
updatedAt: {
type: DataTypes.DATE
},
attr1: DataTypes.STRING,
attr2: DataTypes.INTEGER,
attr3: {
type: DataTypes.BOOLEAN,
defaultValue: false,
allowNull: false
}
},
{
engine: 'MYISAM', // default: 'InnoDB'
charset: 'latin1' // default: null
}
)
#### dropTable&lpar;tableName&rpar;
This method allows deletion of an existing table&period;
migration.dropTable('nameOfTheExistingTable')
#### dropAllTables&lpar;&rpar;
This method allows deletion of all existing tables in the database&period;
migration.dropAllTables()
#### renameTable&lpar;before&comma; after&rpar;
This method allows renaming of an existing table&period;
migration.renameTable('Person', 'User')
#### showAllTables&lpar;&rpar;
This method returns the name of all existing tables in the database&period;
migration.showAllTables().success(function(tableNames) {})
#### describeTable&lpar;tableName&rpar;
This method returns an array of hashes containing information about all attributes in the table&period;
migration.describeTable('Person').success(function(attributes) {
/*
attributes will be something like:
 
{
name: {
type: 'VARCHAR(255)', // this will be 'CHARACTER VARYING' for pg!
allowNull: true,
defaultValue: null
},
isBetaMember: {
type: 'TINYINT(1)', // this will be 'BOOLEAN' for pg!
allowNull: false,
defaultValue: false
}
}
*/
})
#### addColumn&lpar;tableName&comma; attributeName&comma; dataTypeOrOptions&rpar;
This method allows adding columns to an existing table&period; The data type can be simple or complex&period;
migration.addColumn(
'nameOfAnExistingTable',
'nameOfTheNewAttribute',
DataTypes.STRING
)
 
// or
 
migration.addColumn(
'nameOfAnExistingTable',
'nameOfTheNewAttribute',
{
type: DataTypes.STRING,
allowNull: false
}
)
#### removeColumn&lpar;tableName&comma; attributeName&rpar;
This method allows deletion of a specific column of an existing table&period;
migration.removeColumn('Person', 'signature')
#### changeColumn&lpar;tableName&comma; attributeName&comma; dataTypeOrOptions&rpar;
This method changes the meta data of an attribute&period; It is possible to change the default value&comma; allowance of null or the data type&period; Please make sure&comma; that you are completely describing the new data type&period; Missing information are expected to be defaults&period;
migration.changeColumn(
'nameOfAnExistingTable',
'nameOfAnExistingAttribute',
DataTypes.STRING
)
 
// or
 
migration.changeColumn(
'nameOfAnExistingTable',
'nameOfAnExistingAttribute',
{
type: DataTypes.FLOAT,
allowNull: false,
default: 0.0
}
)
#### renameColumn&lpar;tableName&comma; attrNameBefore&comma; attrNameAfter&rpar;
This methods allows renaming attributes&period;
migration.renameColumn('Person', 'signature', 'sig')
#### addIndex&lpar;tableName&comma; attributes&comma; options&rpar;
This methods creates indexes for specific attributes of a table&period; The index name will be automatically generated if it is not passed via in the options &lpar;see below&rpar;&period;
// This example will create the index person_firstname_lastname
migration.addIndex('Person', ['firstname', 'lastname'])
// This example will create a unique index with the name SuperDuperIndex using the optional 'options' field.
// Possible options:
// - indicesType: UNIQUE|FULLTEXT|SPATIAL
// - indexName: The name of the index. Default is __
// - parser: For FULLTEXT columns set your parser
// - indexType: Set a type for the index, e.g. BTREE. See the documentation of the used dialect
migration.addIndex(
'Person',
['firstname', 'lastname'],
{
indexName: 'SuperDuperIndex',
indicesType: 'UNIQUE'
}
)
#### removeIndex&lpar;tableName&comma; indexNameOrAttributes&rpar;
This method deletes an existing index of a table&period;
migration.removeIndex('Person', 'SuperDuperIndex')
 
// or
 
migration.removeIndex('Person', ['firstname', 'lastname'])
### Programmatic use
If you need to interact with the migrator within your code,
you can easily achieve that via `sequelize.getMigrator`.
You can specify the path to your migrations as well as a pattern
which represents the files that contain the migrations.
var migrator = sequelize.getMigrator({
path: process.cwd() + '/database/migrations',
filesFilter: /\.coffee$/
})
Once you have a migrator object, you can run its migration
with `migrator.migrate`. By default, this will
execute all the up methods within your pending migrations.
If you want to rollback a migration, just call it like this:
migrator
.migrate({ method: 'down' })
.success(function() {
// The migrations have been executed!
})
## Misc
### Compatibility
Sequelize is compatible to the following versions of Node.JS:
* 0.8.x
* 0.10.x
### Asynchronicity
Since`v1&period;3&period;0`there are multiple ways of adding listeners to asynchronous requests&period; First of all&comma; each time you call a finder method or save an object&comma; sequelize triggers asynchronous logic&period; To react to the success or the failure &lpar;or both&rpar; of the request&comma; you can do the following&colon;
// the old, pre-v1.3.0 way
Model.findAll().on('success', function(models) { /* foo */ })
Model.findAll().on('failure', function(err) { /* bar */ })
 
// the new, >=v1.3.0 way
// each one is valid
Model.findAll().on('success', function(models) { /* foo */ })
Model.findAll().success(function(models) { /* foo */ })
Model.findAll().ok(function(models) { /* foo */ })
 
// Model.findAll().on('failure', function(err) { /* bar */ }) ==> invalid since v1.5.0
Model.findAll().on('error', function(err) { /* bar */ }) // ==> new since v1.5.0
Model.findAll().error(function(err) { /* bar */ })
Model.findAll().failure(function(err) { /* bar */ })
Model.findAll().fail(function(err) { /* bar */ })
 
Model.findAll().complete(function(err, result) { /* bar */ })
Model.findAll().done(function(err, result) { /* bar */ })
 
// As of 1.7.0 we support Promises/A
var self = User
 
user.find(1).then(function(user1) {
return user1.increment(['aNumber'], 2)
}).then(function(user2) {
return user.find(1)
}).then(function(user3) {
console.log(user3.aNumber) // 2
}, function(err) {
// err...
})
 
 
// For functions with multiple success values (e.g. findOrCreate) there is also spread
 
user.findOrCreate(...).spread(function(user, wasCreated) {
// all arguments are passed
})
user.findOrCreate(...).then(function(user) {
// only the first argument is passed
})
**Please notice&colon;**Since v1&period;5&period;0 the 'error' event is used to notify about errors&period; If such events aren't caught however&comma; Node&period;JS will throw an error&period; So you would probably like to catch them &colon;D
### Additional links
If you want to keep track about latest development of sequelize or to just discuss things with other sequelize users you might want to take a look at the following resources&colon;
* [Twitter&colon; &commat;sdepold][0]
* [Twitter&colon; &commat;sequelizejs][1]
* [ADN&colon; &commat;sdepold][2]
* [IRC&colon; sequelizejs&commat;freenode&period;net][3]
* [XING][4]
* [Facebook][5]
### Company & Projects
Here is a list of companies and projects that are using Sequelize in real world applications&colon;
#### [Shutterstock][6]
Shutterstock Images LLC is a leading global provider of high-quality stock footage&comma; stock photography&comma; vectors and illustrations to creative industry professionals around the world&period; Shutterstock works closely with its growing contributor community of artists&comma; photographers&comma; videographers and illustrators to curate a global marketplace for royalty-free&comma; top-quality imagery&period; Shutterstock adds tens of thousands of rights-cleared images and footage clips each week&comma; with more than 18 million files currently available&period;
#### [Clevertech][7]
Clevertech builds web and mobile applications for startups using Lean and Agile methodologies. Clevertech relies on Sequelize for its applications, its speed, versatility and data flexibility. Clevertech contributes back to open source development and its expert developers support the continuing effort to make sequelize the best ORM for Node projects.
#### [Metamarkets][8]
Metamarkets enables buyers and sellers of digital media to visualize insights and make decisions with real-time pricing&comma; performance&comma; and audience data&period;
#### [Innofluence][9]
On Innofluence&comma; people meet and engage in challenges&comma; questions&comma; and dilemmas -- big and small -- to be inspired&comma; to explore&comma; and to find better solutions and answers&period; Together&period; Ask the network a question&comma; and they will in return reply with Input&comma; exciting points of view&comma; and new reflections&period; Or help and inspire others in need of your input&period;
#### [Using sequelize&quest;][10]
If you want to get listed here&comma; just drop me a line or send me a pull-request on Github&excl;
[0]: http://twitter.com/sdepold
[1]: http://twitter.com/sequelizejs
[2]: https://alpha.app.net/sdepold
[3]: irc://irc.freenode.net/sequelizejs
[4]: https://www.xing.com/net/priec1b5cx/sequelize
[5]: https://www.facebook.com/sequelize
[6]: http://www.shutterstock.com
[7]: http://www.clevertech.biz
[8]: http://metamarkets.com/
[9]: https://innofluence.com
[10]: https://github.com/sequelize/sequelize/tree/gh-pages
## Transactions
sequelize.transaction(function(t) {
// we just opened a new connection to the database which is transaction exclusive.
// also we send some first transaction queries to the database.
// do some async stuff ...
// if everything is ok ... commit the transaction
t.commit().success(function() {})
// if something failed ... rollback the transaction
t.rollback().success(function() {})
// the commit / rollback will emit events which can be observed via:
t.done(function() {
/* we will be here once the transaction
has been committed / reverted */
})
})
sequelize.transaction(function(t) {
User.create({ username: 'foo' }, { transaction: t }).success(function() {
// this user will only be available inside the session
User.all({ transaction: t }) // will return the user
User.all() // will not return the user
})
})
## Utils
Sequelize comes with some handy utils including references to`lodash`as well as some individual helpers&period; You can access them via`Sequelize&period;Utils`&period;
### Lodash.js
You can access all the methods of lodash like this&colon;
Sequelize.Utils._.each(/* ... */)
Sequelize.Utils._.map(/* ... */)
Sequelize.Utils._...
Also Sequelize ships the Underscore extension`underscore&period;string`&comma; which allows nifty string manipulation&colon;
Sequelize.Utils._.camelize('something') // Something
Check out the page of [Lodash][0]&comma; [Underscore][1] and [underscore&period;string][2] for further information&period;
### QueryChainer
Because you will want to save&sol;create&sol;delete several items at once and just go on after all of them are saved&comma; Sequelize provides the`QueryChainer`module&period; It can be used like this&colon;
var chainer = new Sequelize.Utils.QueryChainer
chainer.add(/* Query | EventEmitter */)
chainer.run().success(function(){}).error(function(errors){})
And a real world example&colon;
var chainer = new Sequelize.Utils.QueryChainer
var Task = sequelize.define('Task', /* ... */)
 
chainer
.add(Task.drop())
.add(Task.sync())
 
for(var i = 0; i < 20; i++)
chainer.add(Task.create({}))
 
chainer
.run()
.success(function(){})
.error(function(errors){})
It is also possible to force a serial run of the query chainer by using the following syntax:
new Sequelize.Utils.QueryChainer()
.add(Model, 'function', [param1, param2])
.add(Model, 'function2', [param1, param2])
.runSerially()
.success(function() { /* no problems :) */ })
.error(function(err) { /* hmm not good :> */ })
 
// and with options:
 
new Sequelize.Utils.QueryChainer()
.add(Model, 'function', [param1, param2], {
// Will be executed before Model#function is called
before: function(model) {},
 
/*
Will be executed after Model#function was called
and the function emitted a success or error event.
If the following success option is passed, the function
will be executed after the success function.
*/
after: function(migration) {},
 
// Will be executed if Model#function emits a success event.
success: function(migration, callback) {}
})
// skipOnError: don't execute functions once one has emitted an failure event.
.runSerially({ skipOnError: true })
.success(function() { /* no problems :) */ })
.error(function(err) { /* hmm not good :> */ })
If the success callbacks of the added methods are passing values&comma; they can be utilized in the actual`success`method of the query chainer&colon;
chainer.add(Project.getTasks())
chainer.add(Project.getTeam())
chainer.run().success(function(results){
var tasks = results[0]
var team = results[1]
})
### CustomEventEmitter
One of the core components of the library is the `CustomEventEmitter`,
which takes an (asynchronous) function, allows the binding to certain events
and finally runs the passed function. Within the function, the user gets
access to the emitter instance and can (once the function's logic is done)
emit success / error events. The basic look is the following:
new Sequelize.Utils.CustomEventEmitter(function(emitter) {
doAsyncLogic(function(err) {
if (err) {
emitter.emit('error', err)
} else {
emitter.emit('success')
}
})
})
.success(function() { /* success! */ })
.error(function(err) { /* error */ })
.run()
As you can probably see, the event observing is the very same
as for all the asynchronous methods in the Sequelize universe.
That's because every asynchronouse function in Sequelize
returns an instance of the CustomEventEmitter.
If you are afraid, that the passed function might have been
executed already just before you bound the event observers:
The execution of the function is delayed minimally.
Because of that you can also just call `.run()`
and bind the events afterwards.
Because there is a fair chance, that you already have an emitter
and you just want to pipe the events from one emitter to the other,
each instance has a method called `.proxy()`:
new Sequelize.Utils.CustomEventEmitter(function(emitter) {
asyncAuthLogic(function(err) {
if (err) {
return emitter.emit('err')
}
 
Model
.find()
.proxy(emitter, { events: ['error'] })
.success(function(result) {
emitter.emit('success', parseInt(result.stringifiedAge, 10))
})
})
})
.error(function(err) { console.log(err) })
.success(function(ageAsInteger) { console.log(ageAsInteger) })
.run()
In this example we first do an asynchronous authentication check,
receive an instance from the database afterwards and finally
transform its data. As we aren't interested in a special treatment
for the different error case, we will just observe the error event
once and pipe the error cases of the `Model.find()` call
to the outer emitter.
[0]: http://lodash.com/
[1]: http://underscorejs.org/
[2]: https://github.com/epeli/underscore.string
No preview for this file type
# Imprint - Boring legal stuff for the rest of us.
As there are people who are suing for fun and glory, you can find the respective information about the author of the page right here. Have fun reading ...
## AUTHOR(S)
```
Main author:
Sascha Depold
Uhlandstr. 122
10717 Berlin
sascha [at] depold [dot] com
```
## INHALTLICHE VERANTWORTUNG
```
Ich übernehme keine Haftung für ausgehende Links.
Daher musst du dich bei Problemen an deren Betreiber wenden!
```
\ No newline at end of file
The Sequelize library provides easy access to MySQL, MariaDB, SQLite or PostgreSQL databases by mapping database entries to objects and vice versa. To put it in a nutshell, it's an ORM (Object-Relational-Mapper). The library is written entirely in JavaScript and can be used in the Node.JS environment.
## Easy installation
```bash
$ npm install sequelize
$ npm install mysql
```
## Simple usage
```js
var Sequelize = require('sequelize')
, sequelize = new Sequelize('database', 'username', 'password')
var User = sequelize.define('User', {
username: Sequelize.STRING,
birthday: Sequelize.DATE
})
sequelize.sync().success(function() {
User.create({
username: 'sdepold',
birthday: new Date(1986, 06, 28)
}).success(function(sdepold) {
console.log(sdepold.values)
})
})
```
## Trusted and used by
[![](/images/shutterstock.png)](docs/misc#shutterstock)
[![](/images/clevertech.png)](docs/misc#clevertech)
[![](/images/metamarkets.png)](docs/misc#metamarkets)
[![](/images/filsh.png)](docs/misc#filsh)
(c) Sascha Depold, [et al.](https://github.com/sequelize/sequelize-doc/graphs/contributors) 2006 - 2014 [Imprint](imprint)
\ No newline at end of file
<!DOCTYPE html>
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
{% block htmltitle %}
<title>{{ page_title }}</title>
{% endblock %}
{# CSS #}
<link href='https://fonts.googleapis.com/css?family=Lato:400,700|Roboto+Slab:400,700|Inconsolata:400,700' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="{{ base_url }}/css/theme.css" type="text/css" />
{%- for path in extra_css %}
<link href="{{ path }}" rel="stylesheet">
{%- endfor %}
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/modernizr/2.8.3/modernizr.min.js"></script>
<script src="{{ base_url }}/js/theme.js"></script>
{%- for path in extra_javascript %}
<script src="{{ path }}"></script>
{%- endfor %}
<style>
body {font-size: 90%;}
pre, code {font-size: 100%;}
h3, h4, h5, h6 {color: #2980b9; font-weight: 300}
</style>
{%- block extrahead %} {% endblock %}
</head>
<body class="wy-body-for-nav" role="document">
<div class="wy-grid-for-nav">
{# SIDE NAV, TOGGLES ON MOBILE #}
<nav data-toggle="wy-nav-shift" class="wy-nav-side stickynav">
<div class="wy-side-nav-search">
<a href="{{ homepage_url }}" class="icon icon-home"> {{ site_name }}</a>
{% include "searchbox.html" %}
</div>
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
{% include "toc.html" %}
</div>
&nbsp;
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
{# MOBILE NAV, TRIGGLES SIDE NAV ON TOGGLE #}
<nav class="wy-nav-top" role="navigation" aria-label="top navigation">
<i data-toggle="wy-nav-top" class="icon icon-reorder"></i>
<a href="{{ homepage_url }}">{{ project }}</a>
</nav>
{# PAGE CONTENT #}
<div class="wy-nav-content">
<div class="rst-content">
{% include "breadcrumbs.html" %}
<div role="main">
<div class="section">
{{ content }}
</div>
</div>
{%- block footer %}
{% include "footer.html" %}
{% endblock %}
</div>
</div>
</section>
</div>
<div class="rst-versions" role="note" style="cursor: pointer">
<span class="rst-current-version" data-toggle="rst-current-version">
{% if repo_name == 'GitHub' %}
<a class="icon icon-github" style="float: left; color: #fcfcfc"> GitHub</a>
{% elif repo_name == 'Bitbucket' %}
<a class="icon icon-bitbucket" style="float: left; color: #fcfcfc"> BitBucket</a>
{% endif %}
<span><a href="" style="color: #fcfcfc;">&laquo; Previous</a></span>
<span style="margin-left: 15px"><a href="" style="color: #fcfcfc">Next &raquo;</a></span>
</span>
</div>
</body>
</html>
<div role="navigation" aria-label="breadcrumbs navigation">
<ul class="wy-breadcrumbs">
<li><a href="{{ homepage_url }}">Docs</a> &raquo;</li>
<li>{{ current_page.title }}</li>
<li class="wy-breadcrumbs-aside">
{% if repo_url %}
{% if repo_name == 'GitHub' %}
<a href="{{ repo_url }}" class="icon icon-github"> Edit on GitHub</a>
{% elif repo_name == 'Bitbucket' %}
<a href="{{ repo_url }}" class="icon icon-bitbucket"> Edit on BitBucket</a>
{% endif %}
{% endif %}
</li>
</ul>
<hr/>
</div>
This diff could not be displayed because it is too large.
<footer>
{% if next_page or previous_page %}
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
{% if next_page %}
<a href="{{ next_page.url }}" class="btn btn-neutral float-right" title="{{ next_page.title }}"/>Next <span class="icon icon-circle-arrow-right"></span></a>
{% endif %}
{% if previous_page %}
<a href="{{ previous_page.url }}" class="btn btn-neutral" title="{{ previous_page.title }}"><span class="icon icon-circle-arrow-left"></span> Previous</a>
{% endif %}
</div>
{% endif %}
<hr/>
<div role="contentinfo">
<p>
<!-- Copyright etc -->
</p>
</div>
Built with <a href="http://www.mkdocs.org">MkDocs</a>, using a <a href="https://github.com/snide/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
No preview for this file type
$( document ).ready(function() {
// Shift nav in mobile when clicking the menu.
$(document).on('click', "[data-toggle='wy-nav-top']", function() {
$("[data-toggle='wy-nav-shift']").toggleClass("shift");
$("[data-toggle='rst-versions']").toggleClass("shift");
});
// Close menu when you click a link.
$(document).on('click', ".wy-menu-vertical .current ul li a", function() {
$("[data-toggle='wy-nav-shift']").removeClass("shift");
$("[data-toggle='rst-versions']").toggleClass("shift");
});
$(document).on('click', "[data-toggle='rst-current-version']", function() {
$("[data-toggle='rst-versions']").toggleClass("shift-up");
});
// Make tables responsive
$("table.docutils:not(.field-list)").wrap("<div class='wy-table-responsive'></div>");
});
window.SphinxRtdTheme = (function (jquery) {
var stickyNav = (function () {
var navBar,
win,
stickyNavCssClass = 'stickynav',
applyStickNav = function () {
if (navBar.height() <= win.height()) {
navBar.addClass(stickyNavCssClass);
} else {
navBar.removeClass(stickyNavCssClass);
}
},
enable = function () {
applyStickNav();
win.on('resize', applyStickNav);
},
init = function () {
navBar = jquery('nav.wy-nav-side:first');
win = jquery(window);
};
jquery(init);
return {
enable : enable
};
}());
return {
StickyNav : stickyNav
};
}($));
{#
basic/search.html
~~~~~~~~~~~~~~~~~
Template for the search page.
:copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
#}
{%- extends "layout.html" %}
{% set title = _('Search') %}
{% set script_files = script_files + ['_static/searchtools.js'] %}
{% block extrahead %}
<script type="text/javascript">
jQuery(function() { Search.loadIndex("{{ pathto('searchindex.js', 1) }}"); });
</script>
{# this is used when loading the search index using $.ajax fails,
such as on Chrome for documents on localhost #}
<script type="text/javascript" id="searchindexloader"></script>
{{ super() }}
{% endblock %}
{% block body %}
<noscript>
<div id="fallback" class="admonition warning">
<p class="last">
{% trans %}Please activate JavaScript to enable the search
functionality.{% endtrans %}
</p>
</div>
</noscript>
{% if search_performed %}
<h2>{{ _('Search Results') }}</h2>
{% if not search_results %}
<p>{{ _('Your search did not match any documents. Please make sure that all words are spelled correctly and that you\'ve selected enough categories.') }}</p>
{% endif %}
{% endif %}
<div id="search-results">
{% if search_results %}
<ul>
{% for href, caption, context in search_results %}
<li>
<a href="{{ pathto(item.href) }}">{{ caption }}</a>
<p class="context">{{ context|e }}</p>
</li>
{% endfor %}
</ul>
{% endif %}
</div>
{% endblock %}
<div role="search">
<form id ="rtd-search-form" class="wy-form" action="" method="get">
<input type="text" name="q" placeholder="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
<ul class="current">
{% for nav_item in nav %}
{% if nav_item.children %}
<span class="toctree-l0">{{ nav_item.title }}</span>
{% for nav_item in nav_item.children %}
<li class="toctree-l1 {% if nav_item.active%}current{%endif%}">
<a class="{% if nav_item.active%}current{%endif%}" href="{{ nav_item.url }}">{{ nav_item.title }}</a>
{% if nav_item == current_page %}
<ul>
{% for toc_item in toc %}
<li class="toctree-l2"><a href="{{ toc_item.url }}">{{ toc_item.title }}</a></li>
{% for toc_item in toc_item.children %}
<li><a class="toctree-l3" href="{{ toc_item.url }}">{{ toc_item.title }}</a></li>
{% endfor %}
{% endfor %}
</ul>
{% endif %}
</li>
{% endfor %}
{% else %}
<li class="toctree-l1 {% if nav_item.active%}current{%endif%}">
<a class="{% if nav_item.active%}current{%endif%}" href="{{ nav_item.url }}">{{ nav_item.title }}</a>
</li>
{% endif %}
{% endfor %}
</ul>
git+https://github.com/dart-lang/py-gfm.git
site_name: Sequelize - node.js ORM for Postgres, MySQl, MariaDB and SQLite
theme_dir: docs/readthedocs_theme
repo_url: https://github.com/sequelize/sequelize
site_favicon: favicon.ico
markdown_extensions: [gfm]
extra_css:
- css/custom.css
extra_javascript:
- //cdnjs.cloudflare.com/ajax/libs/highlight.js/8.4/highlight.min.js
pages:
- ['index.md', 'Home', 'Welcome']
- ['imprint.md', 'Home', 'Imprint']
- ['articles/getting-started.md', 'Articles', 'Getting started']
- ['articles/heroku.md', 'Articles', 'Heroku']
- ['articles/express.md', 'Articles', 'Usage with Express.JS']
- ['docs/installation.md', 'Docs', 'Installation']
- ['docs/usage.md', 'Docs', 'Usage']
- ['docs/models.md', 'Docs', 'Models']
- ['docs/instances.md', 'Docs', 'Instances']
- ['docs/associations.md', 'Docs', 'Associations']
- ['docs/hooks.md', 'Docs', 'Hooks']
- ['docs/transactions.md', 'Docs', 'Transactions']
- ['docs/migrations.md', 'Docs', 'Migrations']
- ['docs/misc.md', 'Docs', 'Misc']
- ['docs/utils.md', 'Docs', 'Utils']
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!