Upgrade to V4
Sequelize v4 is the current release and it introduces some breaking changes. Majority of sequelize codebase has been refactored to use ES2015 features. The following guide lists some of the changes to upgrade from v3 to v4.
Changelog
Full Changelog for v4 release.
Breaking Changes
Node
To use new ES2015 features, Sequelize v4 requires at least Node v4 or above.
General
- Counter Cache plugin and consequently the
counterCache
option for associations has been removed. - MariaDB dialect now removed. This was just a thin wrapper around MySQL. You can set
dialect: 'mysql'
an d Sequelize should be able to work with MariaDB server. Model.Instance
andinstance.Model
are removed. To access the Model from an instance, simply useinstance.constructor
. The Instance class (Model.Instance
) is now the Model itself.- Sequelize now uses an independent copy of bluebird library.
- Promises returned by sequelize are now instances of
Sequelize.Promise
instead of global bluebirdPromise
. - Pooling library was updated to
v3
, now you will need to callsequelize.close()
to shutdown the pool.
Config / Options
- Removed support for old connection pooling configuration keys. Instead of
Old
pool: {
maxIdleTime: 30000,
minConnections: 20,
maxConnections: 30
}
New
pool: {
idle: 30000,
min: 20,
max: 30
}
- Removed support for
pool: false
. To use a single connection, setpool.max
to 1. - Removed support for
referencesKey
, use a references object
references: {
key: '',
model: ''
}
- Removed
classMethods
andinstanceMethods
options fromsequelize.define
. Sequelize modelsare now ES6 classes. You can set class / instance level methods like this
Old
const Model = sequelize.define('Model', {
...
}, {
classMethods: {
associate: function (model) {...}
},
instanceMethods: {
someMethod: function () { ...}
}
});
New
const Model = sequelize.define('Model', {
...
});
// Class Method
Model.associate = function (models) {
...associate the models
};
// Instance Method
Model.prototype.someMethod = function () {..}
options.order
now only accepts values with type of array or Sequelize method. Support for string values (ie{order: 'name DESC'}
) has been deprecated.With
BelongsToMany
relationshipsadd/set/create
setters now set through attributes by passing them asoptions.through
(previously second argument was used as through attributes, now it's considered options withthrough
being a sub option)- Raw options for where, order and group like
where: { $raw: '..', order: [{ raw: '..' }], group: [{ raw: '..' }] }
have been removed to prevent SQL injection attacks.
Old
user.addProject(project, { status: 'started' });
New
user.addProject(project, { through: { status: 'started' } });
Data Types
- (MySQL/Postgres)
BIGINT
now returned as string. - (MySQL/Postgres)
DECIMAL
andNEWDECIMAL
types now returned as string. - (MSSQL)
DataTypes.DATE
now usesDATETIMEOFFSET
instead ofDATETIME2
sql datatype in case of MSSQL to record timezone. To migrate existingDATETIME2
columns intoDATETIMEOFFSET
, see #7201. DATEONLY
now returns string inYYYY-MM-DD
format rather thanDate
type
Transactions / CLS
- Removed
autocommit: true
default, set this option explicitly to have transactions auto commit. - Removed default
REPEATABLE_READ
transaction isolation. The isolation level now defaults to that of the database. Explicitly pass the required isolation level when initiating the transaction. - The CLS patch does not affect global bluebird promise. Transaction will not automatically get passed to methods when used with
Promise.all
and other bluebird methods. Explicitly patch your bluebird instance to get CLS to work with bluebird methods.
$ npm install --save cls-bluebird
const Sequelize = require('sequelize');
const Promise = require('bluebird');
const clsBluebird = require('cls-bluebird');
const cls = require('continuation-local-storage');
const ns = cls.createNamespace('transaction-namespace');
clsBluebird(ns, Promise);
Sequelize.useCLS(ns);
Raw Queries
- Sequelize now supports bind parameters for all dialects. In v3
bind
option would fallback toreplacements
if dialect didn't supported binding. This could be a breaking change for MySQL / MSSQL where now queries will actually use bind parameters instead of replacements fallback.
Others
Sequelize.Validator
is now an independent copy ofvalidator
library.Model.validate
instance method now runs validation hooks by default. Previously you needed to pass{ hooks: true }
. You can override this behavior by passing{ hooks: false }
.- The resulting promise from the
Model.validate
instance method will be rejected when validation fails. It will fulfill when validation succeeds. Sequelize.Utils
is not longer part of the public API, use it at your own risk.Hooks
should return Promises now. Callbacks are deprecated.- Getters wont run with
instance.get({ raw: true })
, useinstance.get({ plain: true })
required
inside include does not propagate up the include chain.
To get v3 compatible results you'll need to either set required
on the containing include.
Old
user.findOne({
include: {
model: project,
include: {
model: task,
required: true
}
}
});
New
User.findOne({
include: {
model: Project,
required: true,
include: {
model: Task,
required: true
}
}
});
User.findOne({
include: {
model: Project,
required: true,
include: {
model: Task,
where: { type: 'important' } //where cause required to default to true
}
}
});
Optionally you can add a beforeFind
hook to get v3 compatible behavior -
function propagateRequired(modelDescriptor) {
let include = modelDescriptor.include;
if (!include) return false;
if (!Array.isArray(include)) include = [include];
return include.reduce((isRequired, descriptor) => {
const hasRequiredChild = propogateRequired(descriptor);
if ((descriptor.where || hasRequiredChild) && descriptor.required === undefined) {
descriptor.required = true;
}
return descriptor.required || isRequired;
}, false);
}
const sequelize = new Sequelize(..., {
...,
define: {
hooks: {
beforeFind: propagateRequired
}
}
});