123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284 |
- import { DataTypes } from '@sequelize/core';
- import { expect } from 'chai';
- import { getTestDialect, getTestDialectTeaser, sequelize } from '../support';
- const dialectName = getTestDialect();
- const queryInterface = sequelize.queryInterface;
- describe(getTestDialectTeaser('QueryInterface#removeColumn'), () => {
- describe('Without schema', () => {
- beforeEach(async () => {
- await queryInterface.createTable('users', {
- id: {
- type: DataTypes.INTEGER,
- primaryKey: true,
- autoIncrement: true,
- },
- firstName: {
- type: DataTypes.STRING,
- defaultValue: 'Someone',
- },
- lastName: {
- type: DataTypes.STRING,
- },
- manager: {
- type: DataTypes.INTEGER,
- references: {
- table: 'users',
- key: 'id',
- },
- },
- email: {
- type: DataTypes.STRING,
- allowNull: false,
- unique: true,
- },
- });
- });
- if (sequelize.dialect.supports.removeColumn.cascade) {
- it('should be able to remove a column with cascade', async () => {
- await queryInterface.createTable('level', {
- id: {
- type: DataTypes.INTEGER,
- primaryKey: true,
- autoIncrement: true,
- },
- name: {
- type: DataTypes.STRING,
- allowNull: false,
- },
- });
- await queryInterface.addColumn('users', 'level_id', {
- type: DataTypes.INTEGER,
- references: { key: 'id', table: 'level' },
- });
- await queryInterface.removeColumn('level', 'id', { cascade: true });
- const levelTable = await queryInterface.describeTable('level');
- expect(levelTable).to.not.have.property('id');
- const usersTable = await queryInterface.describeTable('users');
- expect(usersTable).to.have.property('level_id');
- });
- }
- if (sequelize.dialect.supports.removeColumn.ifExists) {
- it('should not throw an error for a non-existant column', async () => {
- await queryInterface.removeColumn('users', 'bla', { ifExists: true });
- });
- }
- it('should be able to remove a column with a default value', async () => {
- await queryInterface.removeColumn('users', 'firstName');
- const table = await queryInterface.describeTable('users');
- expect(table).to.not.have.property('firstName');
- });
- it('should be able to remove a column without default value', async () => {
- await queryInterface.removeColumn('users', 'lastName');
- const table = await queryInterface.describeTable('users');
- expect(table).to.not.have.property('lastName');
- });
- it('should be able to remove a column with a foreign key constraint', async () => {
- await queryInterface.removeColumn('users', 'manager');
- const table = await queryInterface.describeTable('users');
- expect(table).to.not.have.property('manager');
- });
- it('should be able to remove a column with primaryKey', async () => {
- await queryInterface.removeColumn('users', 'manager');
- const table0 = await queryInterface.describeTable('users');
- expect(table0).to.not.have.property('manager');
- await queryInterface.removeColumn('users', 'id');
- const table = await queryInterface.describeTable('users');
- expect(table).to.not.have.property('id');
- });
- // From MSSQL documentation on ALTER COLUMN:
- // The modified column cannot be any one of the following:
- // - Used in a CHECK or UNIQUE constraint.
- // https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-table-transact-sql#arguments
- if (dialectName !== 'mssql') {
- it('should be able to remove a column with unique contraint', async () => {
- await queryInterface.removeColumn('users', 'email');
- const table = await queryInterface.describeTable('users');
- expect(table).to.not.have.property('email');
- });
- }
- // sqlite has limited ALTER TABLE capapibilites which requires a workaround involving recreating tables.
- // This leads to issues with losing data or losing foreign key references.
- // The tests below address these problems
- it('should remove a column with from table with foreign key constraints without losing data', async () => {
- await queryInterface.createTable('level', {
- id: {
- type: DataTypes.INTEGER,
- primaryKey: true,
- autoIncrement: true,
- },
- name: {
- type: DataTypes.STRING,
- allowNull: false,
- },
- });
- await queryInterface.createTable('actors', {
- id: {
- type: DataTypes.INTEGER,
- primaryKey: true,
- autoIncrement: true,
- },
- name: {
- type: DataTypes.STRING,
- allowNull: true,
- },
- level_id: {
- type: DataTypes.INTEGER,
- allowNull: false,
- references: {
- key: 'id',
- table: 'level',
- },
- onDelete: 'CASCADE',
- onUpdate: 'CASCADE',
- },
- });
- await queryInterface.bulkInsert('level', [{ name: 'L1' }, { name: 'L2' }, { name: 'L3' }]);
- await queryInterface.bulkInsert('actors', [
- { name: 'Keanu Reeves', level_id: 2 },
- { name: 'Laurence Fishburne', level_id: 1 },
- ]);
- await queryInterface.removeColumn('level', 'name');
- const actors = await queryInterface.select(null, 'actors', {});
- expect(actors).to.deep.equal([
- { id: 1, name: 'Keanu Reeves', level_id: 2 },
- { id: 2, name: 'Laurence Fishburne', level_id: 1 },
- ]);
- });
- it('should retain ON UPDATE and ON DELETE constraints after a column is removed', async () => {
- await queryInterface.createTable('level', {
- id: {
- type: DataTypes.INTEGER,
- primaryKey: true,
- autoIncrement: true,
- },
- name: {
- type: DataTypes.STRING,
- allowNull: false,
- },
- });
- await queryInterface.createTable('actors', {
- id: {
- type: DataTypes.INTEGER,
- primaryKey: true,
- autoIncrement: true,
- },
- name: {
- type: DataTypes.STRING,
- allowNull: true,
- },
- level_id: {
- type: DataTypes.INTEGER,
- allowNull: false,
- },
- });
- await queryInterface.addConstraint('actors', {
- name: 'actors_level_id_fkey',
- type: 'FOREIGN KEY',
- fields: ['level_id'],
- references: { field: 'id', table: 'level' },
- onDelete: 'CASCADE',
- });
- await queryInterface.removeColumn('actors', 'name');
- const defaultSchema = sequelize.dialect.getDefaultSchema();
- const constraints = await queryInterface.showConstraints('actors', {
- constraintType: 'FOREIGN KEY',
- });
- expect(constraints).to.deep.equal([
- {
- ...(['mssql', 'postgres'].includes(dialectName) && {
- constraintCatalog: 'sequelize_test',
- }),
- constraintSchema: defaultSchema,
- constraintName: dialectName === 'sqlite3' ? 'FOREIGN' : 'actors_level_id_fkey',
- constraintType: 'FOREIGN KEY',
- ...(['mssql', 'postgres'].includes(dialectName) && { tableCatalog: 'sequelize_test' }),
- tableSchema: defaultSchema,
- tableName: 'actors',
- columnNames: ['level_id'],
- referencedTableName: 'level',
- referencedTableSchema: defaultSchema,
- referencedColumnNames: ['id'],
- deleteAction: 'CASCADE',
- updateAction:
- dialectName === 'mariadb' ? 'RESTRICT' : dialectName === 'sqlite3' ? '' : 'NO ACTION',
- ...(sequelize.dialect.supports.constraints.deferrable && {
- deferrable: 'INITIALLY_IMMEDIATE',
- }),
- },
- ]);
- });
- });
- if (sequelize.dialect.supports.schemas) {
- describe('With schema', () => {
- beforeEach(async () => {
- await sequelize.createSchema('archive');
- await queryInterface.createTable(
- {
- tableName: 'users',
- schema: 'archive',
- },
- {
- id: {
- type: DataTypes.INTEGER,
- primaryKey: true,
- autoIncrement: true,
- },
- firstName: {
- type: DataTypes.STRING,
- defaultValue: 'Someone',
- },
- lastName: {
- type: DataTypes.STRING,
- },
- email: {
- type: DataTypes.STRING,
- unique: true,
- allowNull: false,
- },
- },
- );
- });
- it('should be able to remove a column', async () => {
- await queryInterface.removeColumn(
- {
- tableName: 'users',
- schema: 'archive',
- },
- 'lastName',
- );
- const table = await queryInterface.describeTable({
- tableName: 'users',
- schema: 'archive',
- });
- expect(table).to.not.have.property('lastName');
- });
- });
- }
- });
|