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

Commit 7f00a55b by Simon Schick Committed by Erik Seliger

docs(define): Update docs to use classes instead of `define` (#10584)

First step in dealing with issues like #10576 
by moving docs towards the more es6-ish and static analysable `Model.init` calls.
1 parent 0b868c83
......@@ -15,13 +15,19 @@ associations available in Sequelize
Let's first begin with a basic concept that you will see used in most associations, **source** and **target** model. Suppose you are trying to add an association between two Models. Here we are adding a `hasOne` association between `User` and `Project`.
```js
const User = sequelize.define('User', {
class User extends Model {}
User.init({
name: Sequelize.STRING,
email: Sequelize.STRING
}, {
sequelize,
});
const Project = sequelize.define('Project', {
class Project extends Model {}
Project.init({
name: Sequelize.STRING
}, {
sequelize,
});
User.hasOne(Project);
......@@ -34,8 +40,10 @@ User.hasOne(Project);
When you create associations between your models in sequelize, foreign key references with constraints will automatically be created. The setup below:
```js
const Task = sequelize.define('task', { title: Sequelize.STRING });
const User = sequelize.define('user', { username: Sequelize.STRING });
class Task extends Model {}
Task.init({ title: Sequelize.STRING }, { sequelize });
class User extends Model {}
User.init({ username: Sequelize.STRING }, { sequelize });
User.hasMany(Task); // Will add userId to Task model
Task.belongsTo(User); // Will also add userId to Task model
......@@ -77,16 +85,20 @@ foreign keys generated by associations.
Let's modify last example to use `underscored` option.
```js
const Task = sequelize.define('task', {
class Task extends Model {}
Task.init({
title: Sequelize.STRING
}, {
underscored: true
underscored: true,
sequelize,
});
const User = sequelize.define('user', {
class User extends Model {}
User.init({
username: Sequelize.STRING
}, {
underscored: true
underscored: true,
sequelize,
});
// Will add userId to Task model, but field will be set to `user_id`
......@@ -128,12 +140,14 @@ With the underscored option attributes injected to model are still camel cased b
Adding constraints between tables means that tables must be created in the database in a certain order, when using `sequelize.sync`. If `Task` has a reference to `User`, the `users` table must be created before the `tasks` table can be created. This can sometimes lead to circular references, where sequelize cannot find an order in which to sync. Imagine a scenario of documents and versions. A document can have multiple versions, and for convenience, a document has a reference to its current version.
```js
const Document = sequelize.define('document', {
class Document extends Model {}
Document.init({
author: Sequelize.STRING
});
const Version = sequelize.define('version', {
}, { sequelize });
class Version extends Model {}
Version.init({
timestamp: Sequelize.DATE
});
}, { sequelize });
Document.hasMany(Version); // This adds documentId attribute to version
Document.belongsTo(Version, {
......@@ -184,14 +198,16 @@ CREATE TABLE IF NOT EXISTS "versions" (
Sometimes you may want to reference another table, without adding any constraints, or associations. In that case you can manually add the reference attributes to your schema definition, and mark the relations between them.
```js 
const Trainer = sequelize.define('trainer', {
class Trainer extends Model {}
Trainer.init({
firstName: Sequelize.STRING,
lastName: Sequelize.STRING
});
}, { sequelize });
// Series will have a trainerId = Trainer.id foreign reference key
// after we call Trainer.hasMany(series)
const Series = sequelize.define('series', {
class Series extends Model {}
Series.init({
title: Sequelize.STRING,
subTitle: Sequelize.STRING,
description: Sequelize.TEXT,
......@@ -203,11 +219,12 @@ const Series = sequelize.define('series', {
key: 'id'
}
}
});
}, { sequelize });
// Video will have seriesId = Series.id foreign reference key
// after we call Series.hasOne(Video)
const Video = sequelize.define('video', {
class Video extends Model {}
Video.init({
title: Sequelize.STRING,
sequence: Sequelize.INTEGER,
description: Sequelize.TEXT,
......@@ -219,7 +236,7 @@ const Video = sequelize.define('video', {
key: 'id'
}
}
});
}, { sequelize });
Series.hasOne(Video);
Trainer.hasMany(Series);
......@@ -235,8 +252,10 @@ BelongsTo associations are associations where the foreign key for the one-to-one
A simple example would be a **Player** being part of a **Team** with the foreign key on the player.
```js
const Player = this.sequelize.define('player', {/* attributes */});
const Team = this.sequelize.define('team', {/* attributes */});
class Player extends Model {}
Player.init({/* attributes */}, { sequelize });
class Team extends Model {}
Team.init({/* attributes */}, { sequelize });
Player.belongsTo(Team); // Will add a teamId attribute to Player to hold the primary key value for Team
```
......@@ -248,19 +267,23 @@ By default the foreign key for a belongsTo relation will be generated from the t
The default casing is `camelCase`. If the source model is configured with `underscored: true` the foreignKey will be created with field `snake_case`.
```js
const User = this.sequelize.define('user', {/* attributes */})
const Company = this.sequelize.define('company', {/* attributes */});
class User extends Model {}
User.init({/* attributes */}, { sequelize })
class Company extends Model {}
Company.init({/* attributes */}, { sequelize });
// will add companyId to user
User.belongsTo(Company);
const User = this.sequelize.define('user', {/* attributes */}, {underscored: true})
const Company = this.sequelize.define('company', {
class User extends Model {}
User.init({/* attributes */}, {underscored: true, sequelize})
class Company extends Model {}
Company.init({
uuid: {
type: Sequelize.UUID,
primaryKey: true
}
});
}, { sequelize });
// will add companyUuid to user with field company_uuid
User.belongsTo(Company);
......@@ -269,8 +292,10 @@ User.belongsTo(Company);
In cases where `as` has been defined it will be used in place of the target model name.
```js
const User = this.sequelize.define('user', {/* attributes */})
const UserRole = this.sequelize.define('userRole', {/* attributes */});
class User extends Model {}
User.init({/* attributes */}, { sequelize })
class UserRole extends Model {}
UserRole.init({/* attributes */}, { sequelize });
User.belongsTo(UserRole, {as: 'role'}); // Adds roleId to user rather than userRoleId
```
......@@ -279,8 +304,10 @@ In all cases the default foreign key can be overwritten with the `foreignKey` op
When the foreign key option is used, Sequelize will use it as-is:
```js
const User = this.sequelize.define('user', {/* attributes */})
const Company = this.sequelize.define('company', {/* attributes */});
class User extends Model {}
User.init({/* attributes */}, { sequelize })
class Company extends Model {}
Company.init({/* attributes */}, { sequelize });
User.belongsTo(Company, {foreignKey: 'fk_company'}); // Adds fk_company to User
```
......@@ -290,8 +317,10 @@ User.belongsTo(Company, {foreignKey: 'fk_company'}); // Adds fk_company to User
The target key is the column on the target model that the foreign key column on the source model points to. By default the target key for a belongsTo relation will be the target model's primary key. To define a custom column, use the `targetKey` option.
```js
const User = this.sequelize.define('user', {/* attributes */})
const Company = this.sequelize.define('company', {/* attributes */});
class User extends Model {}
User.init({/* attributes */}, { sequelize })
class Company extends Model {}
Company.init({/* attributes */}, { sequelize });
User.belongsTo(Company, {foreignKey: 'fk_companyname', targetKey: 'name'}); // Adds fk_companyname to User
```
......@@ -301,8 +330,10 @@ User.belongsTo(Company, {foreignKey: 'fk_companyname', targetKey: 'name'}); // A
HasOne associations are associations where the foreign key for the one-to-one relation exists on the **target model**.
```js
const User = sequelize.define('user', {/* ... */})
const Project = sequelize.define('project', {/* ... */})
class User extends Model {}
User.init({/* ... */}, { sequelize })
class Project extends Model {}
Project.init({/* ... */}, { sequelize })
 
// One-way associations
Project.hasOne(User)
......@@ -330,7 +361,8 @@ Project.hasOne(User, { as: 'Initiator' })
// Now you will get Project.getInitiator and Project.setInitiator
 
// Or let's define some self references
const Person = sequelize.define('person', { /* ... */})
class Person extends Model {}
Person.init({ /* ... */}, { sequelize })
 
Person.hasOne(Person, {as: 'Father'})
// this will add the attribute FatherId to Person
......@@ -357,8 +389,10 @@ Even though it is called a HasOne association, for most 1:1 relations you usuall
The source key is the attribute on the source model that the foreign key attribute on the target model points to. By default the source key for a `hasOne` relation will be the source model's primary attribute. To use a custom attribute, use the `sourceKey` option.
```js
const User = this.sequelize.define('user', {/* attributes */})
const Company = this.sequelize.define('company', {/* attributes */});
class User extends Model {}
User.init({/* attributes */}, { sequelize })
class Company extends Model {}
Company.init({/* attributes */}, { sequelize });
// Adds companyName attribute to User
// Use name attribute from Company as source attribute
......@@ -372,8 +406,10 @@ In Sequelize 1:1 relationship can be set using HasOne and BelongsTo. They are su
Suppose we have two tables to link **Player** and **Team**. Lets define their models.
```js
const Player = this.sequelize.define('player', {/* attributes */})
const Team = this.sequelize.define('team', {/* attributes */});
class Player extends Model {}
Player.init({/* attributes */}, { sequelize })
class Team extends Model {}
Team.init({/* attributes */}, { sequelize });
```
When we link two models in Sequelize we can refer them as pairs of **source** and **target** models. Like this
......@@ -397,9 +433,12 @@ HasOne and BelongsTo insert the association key in different models from each ot
Here is an example demonstrating use cases of BelongsTo and HasOne.
```js
const Player = this.sequelize.define('player', {/* attributes */})
const Coach = this.sequelize.define('coach', {/* attributes */})
const Team = this.sequelize.define('team', {/* attributes */});
class Player extends Model {}
Player.init({/* attributes */}, { sequelize })
class Coach extends Model {}
Coach.init({/* attributes */}, { sequelize })
class Team extends Model {}
Team.init({/* attributes */}, { sequelize });
```
Suppose our `Player` model has information about its team as `teamId` column. Information about each Team's `Coach` is stored in the `Team` model as `coachId` column. These both scenarios requires different kind of 1:1 relation because foreign key relation is present on different models each time.
......@@ -420,8 +459,10 @@ Coach.hasOne(Team) // `coachId` will be added on Team / Target model
One-To-Many associations are connecting one source with multiple targets. The targets however are again connected to exactly one specific source.
```js
const User = sequelize.define('user', {/* ... */})
const Project = sequelize.define('project', {/* ... */})
class User extends Model {}
User.init({/* ... */}, { sequelize })
class Project extends Model {}
Project.init({/* ... */}, { sequelize })
 
// OK. Now things get more complicated (not really visible to the user :)).
// First let's define a hasMany association
......@@ -433,8 +474,10 @@ This will add the attribute `projectId` to User. Depending on your setting for u
Sometimes you may need to associate records on different columns, you may use `sourceKey` option:
```js
const City = sequelize.define('city', { countryCode: Sequelize.STRING });
const Country = sequelize.define('country', { isoCode: Sequelize.STRING });
class City extends Model {}
City.init({ countryCode: Sequelize.STRING }, { sequelize });
class Country extends Model {}
Country.init({ isoCode: Sequelize.STRING }, { sequelize });
// Here we can connect countries and cities base on country code
Country.hasMany(City, {foreignKey: 'countryCode', sourceKey: 'isoCode'});
......@@ -481,11 +524,14 @@ Person.belongsToMany(Person, { as: 'Children', through: 'PersonChildren' })
If you want additional attributes in your join table, you can define a model for the join table in sequelize, before you define the association, and then tell sequelize that it should use that model for joining, instead of creating a new one:
```js
const User = sequelize.define('user', {})
const Project = sequelize.define('project', {})
const UserProjects = sequelize.define('userProjects', {
class User extends Model {}
User.init({}, { sequelize })
class Project extends Model {}
Project.init({}, { sequelize })
class UserProjects extends Model {}
UserProjects.init({
status: DataTypes.STRING
})
}, { sequelize })
 
User.belongsToMany(Project, { through: UserProjects })
Project.belongsToMany(User, { through: UserProjects })
......@@ -500,14 +546,15 @@ user.addProject(project, { through: { status: 'started' }})
By default the code above will add projectId and userId to the UserProjects table, and _remove any previously defined primary key attribute_ - the table will be uniquely identified by the combination of the keys of the two tables, and there is no reason to have other PK columns. To enforce a primary key on the `UserProjects` model you can add it manually.
```js
const UserProjects = sequelize.define('userProjects', {
class UserProjects extends Model {}
UserProjects.init({
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
status: DataTypes.STRING
})
}, { sequelize })
```
With Belongs-To-Many you can query based on **through** relation and select specific attributes. For example using `findAll` with **through**
......@@ -542,11 +589,13 @@ User.belongsToMany(Project, { as: { singular: 'task', plural: 'tasks' }})
If you know that a model will always use the same alias in associations, you can provide it when creating the model
```js
const Project = sequelize.define('project', attributes, {
class Project extends Model {}
Project.init(attributes, {
name: {
singular: 'task',
plural: 'tasks',
}
},
sequelize,
})
 
User.belongsToMany(Project);
......@@ -727,21 +776,24 @@ Association scopes allow you to place a scope (a set of default attributes for `
Assume we have models Comment, Post, and Image. A comment can be associated to either an image or a post via `commentableId` and `commentable` - we say that Post and Image are `Commentable`
```js
const Post = sequelize.define('post', {
class Post extends Model {}
Post.init({
title: Sequelize.STRING,
text: Sequelize.STRING
});
}, { sequelize });
const Image = sequelize.define('image', {
class Image extends Model {}
Image.init({
title: Sequelize.STRING,
link: Sequelize.STRING
});
}, { sequelize });
const Comment = sequelize.define('comment', {
class Comment extends Model {}
Comment.init({
title: Sequelize.STRING,
commentable: Sequelize.STRING,
commentableId: Sequelize.INTEGER
});
}, { sequelize });
Comment.prototype.getItem = function(options) {
return this[
......@@ -811,7 +863,8 @@ Continuing with the idea of a polymorphic model, consider a tag table - an item
For brevity, the example only shows a Post model, but in reality Tag would be related to several other models.
```js
const ItemTag = sequelize.define('item_tag', {
class ItemTag extends Model {}
ItemTag.init({
id: {
type: Sequelize.INTEGER,
primaryKey: true,
......@@ -830,12 +883,13 @@ const ItemTag = sequelize.define('item_tag', {
unique: 'item_tag_taggable',
references: null
}
});
}, { sequelize });
const Tag = sequelize.define('tag', {
class Tag extends Model {}
Tag.init({
name: Sequelize.STRING,
status: Sequelize.STRING
});
}, { sequelize });
Post.belongsToMany(Tag, {
through: {
......@@ -915,21 +969,24 @@ An instance can be created with nested association in one step, provided all ele
Consider the following models:
```js
const Product = this.sequelize.define('product', {
class Product extends Model {}
Product.init({
title: Sequelize.STRING
});
const User = this.sequelize.define('user', {
}, { sequelize });
class User extends Model {}
User.init({
firstName: Sequelize.STRING,
lastName: Sequelize.STRING
});
const Address = this.sequelize.define('address', {
}, { sequelize });
class Address extends Model {}
Address.init({
type: Sequelize.STRING,
line1: Sequelize.STRING,
line2: Sequelize.STRING,
city: Sequelize.STRING,
state: Sequelize.STRING,
zip: Sequelize.STRING,
});
}, { sequelize });
Product.User = Product.belongsTo(User);
User.Addresses = User.hasMany(Address);
......@@ -985,9 +1042,10 @@ return Product.create({
Let's introduce the ability to associate a product with many tags. Setting up the models could look like:
```js
const Tag = this.sequelize.define('tag', {
class Tag extends Model {}
Tag.init({
name: Sequelize.STRING
});
}, { sequelize });
Product.hasMany(Tag);
// Also works for `belongsToMany`.
......
......@@ -91,12 +91,13 @@ Usage in object notation:
```js
// for enums:
sequelize.define('model', {
class MyModel extends Model {}
MyModel.init({
states: {
type: Sequelize.ENUM,
values: ['active', 'pending', 'deleted']
}
})
}, { sequelize })
```
### Array(ENUM)
......
......@@ -90,10 +90,33 @@ Sequelize will keep the connection open by default, and use the same connection
## Modeling a table
Models are defined with `sequelize.define('name', attributes, options)`:
Models are defined with `Model.init(attributes, options)`:
```js
class User extends Model {}
User.init({
// attributes
firstName: {
type: Sequelize.STRING,
allowNull: false
},
lastName: {
type: Sequelize.STRING
// allowNull defaults to true
}
}, {
sequelize,
// options
});
```
Alternatively (legacy):
```js
const User = sequelize.define('user', {
const User = sequelize.define('User', {
// attributes
firstName: {
type: Sequelize.STRING,
allowNull: false
......@@ -102,6 +125,8 @@ const User = sequelize.define('user', {
type: Sequelize.STRING
// allowNull defaults to true
}
}, {
// options
});
```
......@@ -123,10 +148,12 @@ const sequelize = new Sequelize(connectionURI, {
});
// Here `timestamps` will be false, so the `createdAt` and `updatedAt` fields will not be created.
const Foo = sequelize.define('foo', { /* ... */ });
class Foo extends Model {}
Foo.init({ /* ... */ }, { sequelize });
// Here `timestamps` is directly set to true, so the `createdAt` and `updatedAt` fields will be created.
const Bar = sequelize.define('bar', { /* ... */ }, { timestamps: true });
class Bar extends Model {}
Bar.init({ /* ... */ }, { sequelize, timestamps: true });
```
You can read more about creating models in the [define API Reference](/class/lib/sequelize.js~Sequelize.html#instance-method-define) and the [Model API reference](/class/lib/model.js~Model.html).
......
......@@ -47,8 +47,9 @@ Arguments to hooks are passed by reference. This means, that you can change the
There are currently three ways to programmatically add hooks:
```js
// Method 1 via the .define() method
const User = sequelize.define('user', {
// Method 1 via the .init() method
class User extends Model {}
User.init({
username: DataTypes.STRING,
mood: {
type: DataTypes.ENUM,
......@@ -62,7 +63,8 @@ const User = sequelize.define('user', {
afterValidate: (user, options) => {
user.username = 'Toni';
}
}
},
sequelize
});
// Method 2 via the .addHook() method
......@@ -91,9 +93,10 @@ User.afterValidate('myHookAfter', (user, options) => {
Only a hook with name param can be removed.
```js
const Book = sequelize.define('book', {
class Book extends Model {}
Book.init({
title: DataTypes.STRING
});
}, { sequelize });
Book.addHook('afterCreate', 'notifyUsers', (book, options) => {
// ...
......@@ -123,13 +126,16 @@ const sequelize = new Sequelize(..., {
This adds a default hook to all models, which is run if the model does not define its own `beforeCreate` hook:
```js
const User = sequelize.define('user');
const Project = sequelize.define('project', {}, {
class User extends Model {}
User.init({}, { sequelize });
class Project extends Model {}
Project.init({}, {
hooks: {
beforeCreate: () => {
// Do other stuff
}
}
},
sequelize
});
User.create() // Runs the global hook
......@@ -146,13 +152,16 @@ sequelize.addHook('beforeCreate', () => {
This hook is always run before create, regardless of whether the model specifies its own `beforeCreate` hook. Local hooks are always run before global hooks:
```js
const User = sequelize.define('user');
const Project = sequelize.define('project', {}, {
class User extends Model {}
User.init({}, { sequelize });
class Project extends Model {}
Project.init({}, {
hooks: {
beforeCreate: () => {
// Do other stuff
}
}
},
sequelize
});
User.create() // Runs the global hook
......@@ -318,13 +327,15 @@ For the most part hooks will work the same for instances when being associated e
2. The only way to call beforeDestroy/afterDestroy hooks are on associations with `onDelete: 'cascade'` and the option `hooks: true`. For instance:
```js
const Projects = sequelize.define('projects', {
class Projects extends Model {}
Projects.init({
title: DataTypes.STRING
});
}, { sequelize });
const Tasks = sequelize.define('tasks', {
class Tasks extends Model {}
Tasks.init({
title: DataTypes.STRING
});
}, { sequelize });
Projects.hasMany(Tasks, { onDelete: 'cascade', hooks: true });
Tasks.belongsTo(Projects);
......
......@@ -33,10 +33,11 @@ You are currently looking at the **Tutorials and Guides** for Sequelize. You mig
const Sequelize = require('sequelize');
const sequelize = new Sequelize('postgres://user:pass@example.com:5432/dbname');
const User = sequelize.define('user', {
class User extends Model {}
User.init({
username: Sequelize.STRING,
birthday: Sequelize.DATE
});
}, { sequelize });
sequelize.sync()
.then(() => User.create({
......
......@@ -21,10 +21,11 @@ Built instances will automatically get default values when they were defined&col
```js
// first define the model
const Task = sequelize.define('task', {
class Task extends Model {}
Task.init({
title: Sequelize.STRING,
rating: { type: Sequelize.TINYINT, defaultValue: 3 }
})
}, { sequelize });
 
// now instantiate an object
const task = Task.build({title: 'very important task'})
......@@ -227,7 +228,8 @@ User.bulkCreate([
`bulkCreate` was originally made to be a mainstream/fast way of inserting records, however, sometimes you want the luxury of being able to insert multiple rows at once without sacrificing model validations even when you explicitly tell Sequelize which columns to sift through. You can do by adding a `validate: true` property to the options object.
```js
const Tasks = sequelize.define('task', {
class Tasks extends Model {}
Tasks.init({
name: {
type: Sequelize.STRING,
validate: {
......@@ -240,7 +242,7 @@ const Tasks = sequelize.define('task', {
len: [3, 10]
}
}
})
}, { sequelize })
 
Tasks.bulkCreate([
{name: 'foo', code: '123'},
......
......@@ -4,21 +4,24 @@ While out of the box Sequelize will seem a bit opinionated it's easy to work leg
## Tables
```js
sequelize.define('user', {
class User extends Model {}
User.init({
// ...
}, {
tableName: 'users'
tableName: 'users',
sequelize,
});
```
## Fields
```js
sequelize.define('modelName', {
class MyModel extends Model {}
MyModel.init({
userId: {
type: Sequelize.INTEGER,
field: 'user_id'
}
});
}, { sequelize });
```
## Primary keys
......@@ -27,20 +30,22 @@ Sequelize will assume your table has a `id` primary key property by default.
To define your own primary key:
```js
sequelize.define('collection', {
class Collection extends Model {}
Collection.init({
uid: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true // Automatically gets converted to SERIAL for postgres
}
});
}, { sequelize });
sequelize.define('collection', {
class Collection extends Model {}
Collection.init({
uuid: {
type: Sequelize.UUID,
primaryKey: true
}
});
}, { sequelize });
```
And if your model has no primary key at all you can use `Model.removeAttribute('id');`
......
......@@ -3,22 +3,25 @@
To define mappings between a model and a table, use the `define` method. Each column must have a datatype, see more about [datatypes][1].
```js
const Project = sequelize.define('project', {
class Project extends Model {}
Project.init({
title: Sequelize.STRING,
description: Sequelize.TEXT
})
}, { sequelize });
const Task = sequelize.define('task', {
class Task extends Model {}
Task.init({
title: Sequelize.STRING,
description: Sequelize.TEXT,
deadline: Sequelize.DATE
})
}, { sequelize })
```
Apart from [datatypes][1], there are plenty of options that you can set on each column.
```js
const Foo = sequelize.define('foo', {
class Foo extends Model {}
Foo.init({
// instantiating will automatically set the flag to true if not set
flag: { type: Sequelize.BOOLEAN, allowNull: false, defaultValue: true },
......@@ -74,7 +77,7 @@ const Foo = sequelize.define('foo', {
comment: 'This is a column name that has a comment'
}
})
}, { sequelize });
```
The comment option can also be used on a table, see [model configuration][0].
......@@ -143,7 +146,8 @@ Getters and Setters can be defined in 2 ways (you can mix and match these 2 appr
### Defining as part of a property
```js
const Employee = sequelize.define('employee', {
class Employee extends Model {}
Employee.init({
name: {
type: Sequelize.STRING,
allowNull: false,
......@@ -160,7 +164,7 @@ const Employee = sequelize.define('employee', {
this.setDataValue('title', val.toUpperCase());
}
}
});
}, { sequelize });
Employee
.create({ name: 'John Doe', title: 'senior engineer' })
......@@ -179,7 +183,26 @@ The `fullName` getter, is an example of how you can define pseudo properties on
Note that the `this.firstname` and `this.lastname` references in the `fullName` getter function will trigger a call to the respective getter functions. If you do not want that then use the `getDataValue()` method to access the raw value (see below).
```js
const Foo = sequelize.define('foo', {
class Foo extends Model {
get fullName() {
return this.firstname + ' ' + this.lastname;
}
set fullName(value) {
const names = value.split(' ');
this.setDataValue('firstname', names.slice(0, -1).join(' '));
this.setDataValue('lastname', names.slice(-1).join(' '));
}
}
Foo.init({
firstname: Sequelize.STRING,
lastname: Sequelize.STRING
}, {
sequelize,
});
// legacy with `sequelize.define`
sequelize.define('Foo', {
firstname: Sequelize.STRING,
lastname: Sequelize.STRING
}, {
......@@ -197,9 +220,10 @@ const Foo = sequelize.define('foo', {
this.setDataValue('lastname', names.slice(-1).join(' '));
}
}
});
} );
```
### Helper functions for use inside getter and setter definitions
* retrieving an underlying property value - always use `this.getDataValue()`
......@@ -233,7 +257,8 @@ Validations are automatically run on `create`, `update` and `save`. You can also
You can define your custom validators or use several built-in validators, implemented by [validator.js][3], as shown below.
```js
const ValidateMe = sequelize.define('foo', {
class ValidateMe extends Model {}
ValidateMe.init({
bar: {
type: Sequelize.STRING,
validate: {
......@@ -283,7 +308,7 @@ const ValidateMe = sequelize.define('foo', {
}
}
}
});
}, { sequelize });
```
Note that where multiple arguments need to be passed to the built-in validation functions, the arguments to be passed must be in an array. But if a single array argument is to be passed, for instance an array of acceptable strings for `isIn`, this will be interpreted as multiple string arguments instead of one array argument. To work around this pass a single-length array of arguments, such as `[['one', 'two']]` as shown above.
......@@ -320,7 +345,8 @@ On the other hand, if it is set to allow null (with `allowNull: true`) and that
This means you can, for instance, have a string field which validates its length to be between 5 and 10 characters, but which also allows `null` (since the length validator will be skipped automatically when the value is `null`):
```js
const User = sequelize.define('user', {
class User extends Model {}
User.init({
username: {
type: Sequelize.STRING,
allowNull: true,
......@@ -328,32 +354,34 @@ const User = sequelize.define('user', {
len: [5, 10]
}
}
});
}, { sequelize });
```
You also can conditionally allow `null` values, with a custom validator, since it won't be skipped:
```js
const User = sequelize.define('user', {
class User extends Model {}
User.init({
age: Sequelize.INTEGER,
name: {
type: Sequelize.STRING,
allowNull: true,
validate: {
customValidator: function(value) {
customValidator(value) {
if (value === null && this.age !== 10) {
throw new Error("name can't be null unless age is 10");
}
})
}
}
});
}, { sequelize });
```
You can customize `allowNull` error message by setting the `notNull` validator:
```js
const User = sequelize.define('user', {
class User extends Model {}
User.init({
name: {
type: Sequelize.STRING,
allowNull: false,
......@@ -363,7 +391,7 @@ const User = sequelize.define('user', {
}
}
}
});
}, { sequelize });
```
### Model-wide validations
......@@ -377,7 +405,8 @@ Any error messages collected are put in the validation result object alongside t
An example:
```js
const Pub = Sequelize.define('pub', {
class Pub extends Model {}
Pub.init({
name: { type: Sequelize.STRING },
address: { type: Sequelize.STRING },
latitude: {
......@@ -399,7 +428,8 @@ const Pub = Sequelize.define('pub', {
throw new Error('Require either both latitude and longitude or neither')
}
}
}
},
sequelize,
})
```
......@@ -419,7 +449,8 @@ Such validation could have also been done with a custom validator defined on a s
You can also influence the way Sequelize handles your column names:
```js
const Bar = sequelize.define('bar', { /* bla */ }, {
class Bar extends Model {}
Bar.init({ /* bla */ }, {
// don't add the timestamp attributes (updatedAt, createdAt)
timestamps: false,
......@@ -443,14 +474,18 @@ const Bar = sequelize.define('bar', { /* bla */ }, {
// Enable optimistic locking. When enabled, sequelize will add a version count attribute
// to the model and throw an OptimisticLockingError error when stale instances are saved.
// Set to true or a string with the attribute name you want to use to enable.
version: true
version: true,
// Sequelize instance
sequelize,
})
```
If you want sequelize to handle timestamps, but only want some of them, or want your timestamps to be called something else, you can override each column individually:
```js
const Foo = sequelize.define('foo', { /* bla */ }, {
class Foo extends Model {}
Foo.init({ /* bla */ }, {
// don't forget to enable timestamps!
timestamps: true,
......@@ -462,15 +497,19 @@ const Foo = sequelize.define('foo', { /* bla */ }, {
// And deletedAt to be called destroyTime (remember to enable paranoid for this to work)
deletedAt: 'destroyTime',
paranoid: true
paranoid: true,
sequelize,
})
```
You can also change the database engine, e.g. to MyISAM. InnoDB is the default.
```js
const Person = sequelize.define('person', { /* attributes */ }, {
engine: 'MYISAM'
class Person extends Model {}
Person.init({ /* attributes */ }, {
engine: 'MYISAM',
sequelize
})
// or globally
......@@ -482,8 +521,10 @@ const sequelize = new Sequelize(db, user, pw, {
Finally you can specify a comment for the table in MySQL and PG
```js
const Person = sequelize.define('person', { /* attributes */ }, {
comment: "I'm a table comment!"
class Person extends Model {}
Person.init({ /* attributes */ }, {
comment: "I'm a table comment!",
sequelize
})
```
......@@ -498,10 +539,12 @@ const Project = sequelize.import(__dirname + "/path/to/models/project")
// The model definition is done in /path/to/models/project.js
// As you might notice, the DataTypes are the very same as explained above
module.exports = (sequelize, DataTypes) => {
return sequelize.define("project", {
class Project extends sequelize.Model { }
Project.init({
name: DataTypes.STRING,
description: DataTypes.TEXT
})
}, { sequelize });
return Projectl
}
```
......@@ -509,10 +552,12 @@ The `import` method can also accept a callback as an argument.
```js
sequelize.import('project', (sequelize, DataTypes) => {
return sequelize.define("project", {
class Project extends sequelize.Model {}
Project.init({
name: DataTypes.STRING,
description: DataTypes.TEXT
})
}, { sequelize })
return Project;
})
```
......@@ -600,7 +645,8 @@ sequelize.sync({ force: true, match: /_test$/ });
Sequelize Models are ES6 classes. You can very easily add custom instance or class level methods.
```js
const User = sequelize.define('user', { firstname: Sequelize.STRING });
class User extends Model {}
User.init({ firstname: Sequelize.STRING }, { sequelize });
// Adding a class level method
User.classLevelMethod = function() {
......@@ -616,7 +662,8 @@ User.prototype.instanceLevelMethod = function() {
Of course you can also access the instance's data and generate virtual getters:
```js
const User = sequelize.define('user', { firstname: Sequelize.STRING, lastname: Sequelize.STRING });
class User extends Model {}
User.init({ firstname: Sequelize.STRING, lastname: Sequelize.STRING }, { sequelize });
User.prototype.getFullname = function() {
return [this.firstname, this.lastname].join(' ');
......@@ -630,7 +677,8 @@ User.build({ firstname: 'foo', lastname: 'bar' }).getFullname() // 'foo bar'
Sequelize supports adding indexes to the model definition which will be created during `Model.sync()` or `sequelize.sync`.
```js
sequelize.define('user', {}, {
class User extends Model {}
User.init({}, {
indexes: [
// Create a unique index on email
{
......@@ -661,8 +709,9 @@ sequelize.define('user', {}, {
method: 'BTREE',
fields: ['author', {attribute: 'title', collate: 'en_US', order: 'DESC', length: 5}]
}
]
})
],
sequelize
});
```
......
......@@ -410,9 +410,12 @@ Project.sum('age', { where: { age: { [Op.gt]: 5 } } }).then(sum => {
When you are retrieving data from the database there is a fair chance that you also want to get associations with the same query - this is called eager loading. The basic idea behind that, is the use of the attribute `include` when you are calling `find` or `findAll`. Lets assume the following setup:
```js
const User = sequelize.define('user', { name: Sequelize.STRING })
const Task = sequelize.define('task', { name: Sequelize.STRING })
const Tool = sequelize.define('tool', { name: Sequelize.STRING })
class User extends Model {}
User.init({ name: Sequelize.STRING }, { sequelize })
class Task extends Model {}
Task.init({ name: Sequelize.STRING }, { sequelize })
class Tool extends Model {}
Tool.init({ name: Sequelize.STRING }, { sequelize })
Task.belongsTo(User)
User.hasMany(Task)
......
......@@ -7,7 +7,8 @@ Scoping allows you to define commonly used queries that you can easily use later
Scopes are defined in the model definition and can be finder objects, or functions returning finder objects - except for the default scope, which can only be an object:
```js
const Project = sequelize.define('project', {
class Project extends Model {}
Project.init({
// Attributes
}, {
defaultScope: {
......@@ -26,14 +27,14 @@ const Project = sequelize.define('project', {
{ model: User, where: { active: true }}
]
},
random: function () {
random () {
return {
where: {
someNumber: Math.random()
}
}
},
accessLevel: function (value) {
accessLevel (value) {
return {
where: {
accessLevel: {
......@@ -42,6 +43,7 @@ const Project = sequelize.define('project', {
}
}
}
sequelize,
}
});
```
......@@ -175,10 +177,14 @@ Includes are merged recursively based on the models being included. This is a ve
Consider four models: Foo, Bar, Baz and Qux, with has-many associations as follows:
```js
Foo = sequelize.define('foo', { name: Sequelize.STRING };
Bar = sequelize.define('bar', { name: Sequelize.STRING };
Baz = sequelize.define('baz', { name: Sequelize.STRING };
Qux = sequelize.define('qux', { name: Sequelize.STRING };
class Foo extends Model {}
class Bar extends Model {}
class Baz extends Model {}
class Qux extends Model {}
Foo.init({ name: Sequelize.STRING }, { sequelize });
Bar.init({ name: Sequelize.STRING }, { sequelize });
Baz.init({ name: Sequelize.STRING }, { sequelize });
Qux.init({ name: Sequelize.STRING }, { sequelize });
Foo.hasMany(Bar, { foreignKey: 'fooId' });
Bar.hasMany(Baz, { foreignKey: 'barId' });
Baz.hasMany(Qux, { foreignKey: 'bazId' });
......@@ -282,7 +288,8 @@ User.getPosts({ scope: ['scope1', 'scope2']});
If you want to create a shortcut method to a scope on an associated model, you can pass the scoped model to the association. Consider a shortcut to get all deleted posts for a user:
```js
const Post = sequelize.define('post', attributes, {
class Post extends Model {}
Post.init(attributes, {
defaultScope: {
where: {
active: true
......@@ -294,7 +301,8 @@ const Post = sequelize.define('post', attributes, {
deleted: true
}
}
}
},
sequelize,
});
User.hasMany(Post); // regular getPosts association
......
......@@ -94,7 +94,8 @@ const sequelize = new Sequelize('database', 'username', 'password', {
// The following example:
// define: { timestamps: false }
// is basically the same as:
// sequelize.define(name, attributes, { timestamps: false })
// Model.init(attributes, { timestamps: false });
// sequelize.define(name, attributes, { timestamps: false });
// so defining the timestamps for each model will be not necessary
define: {
underscored: false,
......
/**
* The datatypes are used when defining a new model using `Sequelize.define`, like this:
* The datatypes are used when defining a new model using `Model.init`, like this:
* ```js
* sequelize.define('model', {
* column: DataTypes.INTEGER
* })
* class MyModel extends MyModel {}
* MyModel.init({ column: DataTypes.INTEGER }, { sequelize });
* ```
* When defining a model you can just as easily pass a string as type, but often using the types defined here is beneficial. For example, using `DataTypes.BLOB`, mean
* that that column will be returned as an instance of `Buffer` when being fetched by sequelize.
......@@ -17,27 +16,29 @@
* Three of the values provided here (`NOW`, `UUIDV1` and `UUIDV4`) are special default values, that should not be used to define types. Instead they are used as shorthands for
* defining default values. For example, to get a uuid field with a default value generated following v1 of the UUID standard:
* ```js
* sequelize.define('model', {
* class MyModel extends Model {}
* MyModel.init({
* uuid: {
* type: DataTypes.UUID,
* defaultValue: DataTypes.UUIDV1,
* primaryKey: true
* }
* })
* }, { sequelize })
* ```
* There may be times when you want to generate your own UUID conforming to some other algorithm. This is accomplised
* using the defaultValue property as well, but instead of specifying one of the supplied UUID types, you return a value
* from a function.
* ```js
* sequelize.define('model', {
* class MyModel extends Model {}
* MyModel.init({
* uuid: {
* type: DataTypes.UUID,
* defaultValue: function() {
* defaultValue() {
* return generateMyId()
* },
* primaryKey: true
* }
* })
* }, { sequelize })
* ```
*/
......@@ -424,23 +425,24 @@ export const UUIDV4: AbstractDataTypeConstructor;
*
* You could also use it to validate a value before permuting and storing it. Checking password length before hashing it for example:
* ```js
* sequelize.define('user', {
* class User extends Model {}
* User.init({
* password_hash: DataTypes.STRING,
* password: {
* type: DataTypes.VIRTUAL,
* set: function (val) {
* set (val) {
* this.setDataValue('password', val); // Remember to set the data value, otherwise it won't be validated
* this.setDataValue('password_hash', this.salt + val);
* },
* validate: {
* isLongEnough: function (val) {
* isLongEnough (val) {
* if (val.length < 7) {
* throw new Error("Please choose a longer password")
* }
* }
* }
* }
* })
* }, { sequelize });
* ```
*
* VIRTUAL also takes a return type and dependency fields as arguments
......@@ -450,7 +452,7 @@ export const UUIDV4: AbstractDataTypeConstructor;
* {
* active: {
* type: new DataTypes.VIRTUAL(DataTypes.BOOLEAN, ['createdAt']),
* get: function() {
* get() {
* return this.get('createdAt') > Date.now() - (7 * 24 * 60 * 60 * 1000)
* }
* }
......
......@@ -7,7 +7,8 @@
* that will check the constraints immediately when the data was inserted.
*
* ```js
* sequelize.define('Model', {
* class MyModel extends Model {}
* MyModel.init({
* foreign_id: {
* type: Sequelize.INTEGER,
* references: {
......@@ -16,7 +17,7 @@
* deferrable: Sequelize.Deferrable.INITIALLY_IMMEDIATE
* }
* }
* });
* }, { sequelize });
* ```
*
* The constraints can be configured in a transaction like this. It will
......
......@@ -1201,12 +1201,13 @@ export interface ModelAttributeColumnOptions extends ColumnOptions {
* Usage in object notation
*
* ```js
* sequelize.define('model', {
* class MyModel extends Model {}
* MyModel.init({
* states: {
* type: Sequelize.ENUM,
* values: ['active', 'pending', 'deleted']
* }
* })
* }, { sequelize })
* ```
*/
values?: string[];
......@@ -1516,7 +1517,8 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
/**
* Apply a scope created in `define` to the model. First let's look at how to create scopes:
* ```js
* const Model = sequelize.define('model', attributes, {
* class MyModel extends Model {}
* MyModel.init(attributes, {
* defaultScope: {
* where: {
* username: 'dan'
......@@ -1529,7 +1531,7 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* stuff: 'cake'
* }
* },
* complexFunction: function(email, accessLevel) {
* complexFunction(email, accessLevel) {
* return {
* where: {
* email: {
......@@ -1541,7 +1543,8 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* }
* }
* }
* }
* },
* sequelize,
* })
* ```
* Now, since you defined a default scope, every time you do Model.find, the default scope is appended to
......@@ -2227,9 +2230,10 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* ways. Consider users and projects from before with a join table that stores whether the project has been
* started yet:
* ```js
* const UserProjects = sequelize.define('userprojects', {
* class UserProjects extends Model {}
* UserProjects.init({
* started: Sequelize.BOOLEAN
* })
* }, { sequelize })
* User.hasMany(Project, { through: UserProjects })
* Project.hasMany(User, { through: UserProjects })
* ```
......@@ -2279,9 +2283,10 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* associations in two ways. Consider users and projects from before with a join table that stores whether
* the project has been started yet:
* ```js
* const UserProjects = sequelize.define('userprojects', {
* class UserProjects extends Model {}
* UserProjects.init({
* started: Sequelize.BOOLEAN
* })
* }, { sequelize });
* User.belongsToMany(Project, { through: UserProjects })
* Project.belongsToMany(User, { through: UserProjects })
* ```
......
......@@ -974,7 +974,8 @@ export class Sequelize extends Hooks {
* represents a column. A short table definition might look like this:
*
* ```js
* sequelize.define('modelName', {
* class MyModel extends Model {}
* MyModel.init({
* columnA: {
* type: Sequelize.BOOLEAN,
* validate: {
......@@ -990,7 +991,7 @@ export class Sequelize extends Hooks {
* },
* columnB: Sequelize.STRING,
* columnC: 'MY VERY OWN COLUMN TYPE'
* })
* }, { sequelize })
*
* sequelize.models.modelName // The model will now be available in models under the name given to define
* ```
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!