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 and instance.Model are removed. To access the Model from an instance, simply use instance.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 bluebird Promise.
  • Pooling library was updated to v3, now you will need to call sequelize.close() to shutdown the pool.

Config / Options

  • Removed support for old connection pooling configuration keys. Instead of

Old

  1. pool: {
  2. maxIdleTime: 30000,
  3. minConnections: 20,
  4. maxConnections: 30
  5. }

New

  1. pool: {
  2. idle: 30000,
  3. min: 20,
  4. max: 30
  5. }
  • Removed support for pool: false. To use a single connection, set pool.max to 1.
  • Removed support for referencesKey, use a references object
  1. references: {
  2. key: '',
  3. model: ''
  4. }
  • Removed classMethods and instanceMethods options from sequelize.define. Sequelize modelsare now ES6 classes. You can set class / instance level methods like this

Old

  1. const Model = sequelize.define('Model', {
  2. ...
  3. }, {
  4. classMethods: {
  5. associate: function (model) {...}
  6. },
  7. instanceMethods: {
  8. someMethod: function () { ...}
  9. }
  10. });

New

  1. const Model = sequelize.define('Model', {
  2. ...
  3. });
  4. // Class Method
  5. Model.associate = function (models) {
  6. ...associate the models
  7. };
  8. // Instance Method
  9. 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 relationships add/set/create setters now set through attributes by passing them as options.through (previously second argument was used as through attributes, now it's considered options with through 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

  1. user.addProject(project, { status: 'started' });

New

  1. user.addProject(project, { through: { status: 'started' } });

Data Types

  • (MySQL/Postgres) BIGINT now returned as string.
  • (MySQL/Postgres) DECIMAL and NEWDECIMAL types now returned as string.
  • (MSSQL) DataTypes.DATE now uses DATETIMEOFFSET instead of DATETIME2 sql datatype in case of MSSQL to record timezone. To migrate existing DATETIME2 columns into DATETIMEOFFSET, see #7201.
  • DATEONLY now returns string in YYYY-MM-DD format rather than Date 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.
  1. $ npm install --save cls-bluebird
  1. const Sequelize = require('sequelize');
  2. const Promise = require('bluebird');
  3. const clsBluebird = require('cls-bluebird');
  4. const cls = require('continuation-local-storage');
  5. const ns = cls.createNamespace('transaction-namespace');
  6. clsBluebird(ns, Promise);
  7. Sequelize.useCLS(ns);

Raw Queries

  • Sequelize now supports bind parameters for all dialects. In v3 bind option would fallback to replacements 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 of validator 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 }), use instance.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

  1. user.findOne({
  2. include: {
  3. model: project,
  4. include: {
  5. model: task,
  6. required: true
  7. }
  8. }
  9. });

New

  1. User.findOne({
  2. include: {
  3. model: Project,
  4. required: true,
  5. include: {
  6. model: Task,
  7. required: true
  8. }
  9. }
  10. });
  11. User.findOne({
  12. include: {
  13. model: Project,
  14. required: true,
  15. include: {
  16. model: Task,
  17. where: { type: 'important' } //where cause required to default to true
  18. }
  19. }
  20. });

Optionally you can add a beforeFind hook to get v3 compatible behavior -

  1. function propagateRequired(modelDescriptor) {
  2. let include = modelDescriptor.include;
  3. if (!include) return false;
  4. if (!Array.isArray(include)) include = [include];
  5. return include.reduce((isRequired, descriptor) => {
  6. const hasRequiredChild = propogateRequired(descriptor);
  7. if ((descriptor.where || hasRequiredChild) && descriptor.required === undefined) {
  8. descriptor.required = true;
  9. }
  10. return descriptor.required || isRequired;
  11. }, false);
  12. }
  13. const sequelize = new Sequelize(..., {
  14. ...,
  15. define: {
  16. hooks: {
  17. beforeFind: propagateRequired
  18. }
  19. }
  20. });