queryInterface.addColumn ignores transaction and takes the 'after' option in the wrong place
See original GitHub issueWhat 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:
- Created 4 years ago
- Reactions:8
- Comments:10 (3 by maintainers)
Top 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 >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
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 theQueryInterfaceOptions
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.
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