question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

queryInterface.addColumn ignores transaction and takes the 'after' option in the wrong place

See original GitHub issue

What was unclear/insufficient/not covered in the documentation

The documentation suggests the after and transaction options are passed in the last options parameters, but in fact after must be specified in the attributes (second to last) and transactions are not working at all.

documentation and tests:

// in the reference - http://docs.sequelizejs.com/class/lib/query-interface.js~QueryInterface.html#instance-method-addColumn
queryInterface.addColumn('tableA', 'columnC', Sequelize.STRING, {
   after: 'columnB' // after option is only supported by MySQL
});

// or in migrations.md - https://github.com/sequelize/sequelize/blob/e7c862833e9ed389a5411c281ab3b8bc80b7a17b/docs/migrations.md
return Promise.all([
    queryInterface.addColumn('Person', 'petName', {
        type: Sequelize.STRING
    }, { transaction: t }),
    queryInterface.addColumn('Person', 'favoriteColor', {
        type: Sequelize.STRING,
    }, { transaction: t })
])

But this is how it actually works for after:

queryInterface.addColumn(
  'account',
  'type',
  {
    type: DataTypes.INTEGER,
    after: 'id',
  }
);

The worse problem are transactions that are not working, here is a simple reproduction migration file:

const { DataTypes } = require('sequelize');

module.exports = {
  up: async queryInterface => {
    const { sequelize } = queryInterface;

    return sequelize.transaction(async transaction => {
      await queryInterface.addColumn(
        'account',
        'type',
        {
          type: DataTypes.INTEGER,
          after: 'id',
        },
        {
          transaction,
        }
      );

      throw new Error('err');
    }
  }
}

The new column will be created every time, no matter if the transaction fails or not.


Tested on Sequelize: 5.7.6

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:8
  • Comments:10 (3 by maintainers)

github_iconTop GitHub Comments

2reactions
RocheValcommented, Apr 22, 2020

So I confirm that the problem of rollback come from MySQL and only for DDL statement.

But considering the problem of the “after” attribute, it would be nice to update the doc or to put it in the good place. A second issue link to this problem, is that in Typescript “after” is not present in any Types used by the addColumn function (nor in ModelAttributeColumnOptions | AbstractDataTypeConstructor | AbstractDataType for the “attribute” input and nor in the QueryInterfaceOptions for the “options” input). So Typescript complains that this property doesn’t exist and we have to use @ts-ignore to make it work, which is a bit ugly.

Just for information I’m currently using sequelize 5.21.5 and sequelize-typescript 1.1.0.

2reactions
automatensalatcommented, Oct 16, 2019

For everyone running into the same issue: This seems to be a MySQL issue, not the fault of sequelize.

According to the MySQL docs, DDL statements like ALTER COLUMN which are generated by sequelize.addColumn() calls are not subject to transactions and so are not rolled back regardless of whether the transaction fails or succeeds: Some statements cannot be rolled back. In general, these include data definition language (DDL) statements, such as those that create or drop databases, those that create, drop, or alter tables or stored routines. See: https://dev.mysql.com/doc/refman/8.0/en/cannot-roll-back.html

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to Add, Delete new Columns in Sequelize CLI
For 1. You just add multiple addColumn statements in the up function and then the corresponding removeColumn s in the down function.
Read more >
QueryInterface - Sequelize
Returns a promise that will resolve to true if the table exists in the database, false otherwise.
Read more >
Database Engine events and errors - SQL Server
Consult this MSSQL error code list to find explanations for error messages for SQL Server database engine events.
Read more >
GRDB Reference - Gwendal Roué
The write method wraps your database statements in a transaction that commits if and only if no error occurs. On the first unhandled...
Read more >
TSQL Error Messages | HealthShare Health Connect 2022.2
The option is ignored. 3921, Cannot get a transaction token if there is no transaction active. Reissue the statement after a transaction has...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found