不要怂,就是干,撸起袖子干!

Commit f843582c by Pedro Augusto de Paula Barbosa Committed by Sushant

refactor(tests): use async/await (#11875)

1 parent c41bcf4b
Showing with 429 additions and 524 deletions
...@@ -15,262 +15,229 @@ describe(Support.getTestDialectTeaser('QueryInterface'), () => { ...@@ -15,262 +15,229 @@ describe(Support.getTestDialectTeaser('QueryInterface'), () => {
this.queryInterface = this.sequelize.getQueryInterface(); this.queryInterface = this.sequelize.getQueryInterface();
}); });
afterEach(function() { afterEach(async function() {
return Support.dropTestSchemas(this.sequelize); await Support.dropTestSchemas(this.sequelize);
}); });
describe('dropAllSchema', () => { describe('dropAllSchema', () => {
it('should drop all schema', function() { it('should drop all schema', async function() {
return this.queryInterface.dropAllSchemas( await this.queryInterface.dropAllSchemas({
{ skip: [this.sequelize.config.database] }) skip: [this.sequelize.config.database]
.then(() => { });
return this.queryInterface.showAllSchemas(); const schemaNames = await this.queryInterface.showAllSchemas();
}) await this.queryInterface.createSchema('newSchema');
.then(schemaNames => { const newSchemaNames = await this.queryInterface.showAllSchemas();
if (!current.dialect.supports.schemas) return;
return this.queryInterface.createSchema('newSchema') expect(newSchemaNames).to.have.length(schemaNames.length + 1);
.then(() => { await this.queryInterface.dropSchema('newSchema');
return this.queryInterface.showAllSchemas();
})
.then(newSchemaNames => {
if (!current.dialect.supports.schemas) return;
expect(newSchemaNames).to.have.length(schemaNames.length + 1);
return this.queryInterface.dropSchema('newSchema');
});
});
}); });
}); });
describe('showAllTables', () => { describe('showAllTables', () => {
it('should not contain views', function() { it('should not contain views', async function() {
const cleanup = () => { async function cleanup() {
// NOTE: The syntax "DROP VIEW [IF EXISTS]"" is not part of the standard // NOTE: The syntax "DROP VIEW [IF EXISTS]"" is not part of the standard
// and might not be available on all RDBMSs. Therefore "DROP VIEW" is // and might not be available on all RDBMSs. Therefore "DROP VIEW" is
// the compatible option, which can throw an error in case the VIEW does // the compatible option, which can throw an error in case the VIEW does
// not exist. In case of error, it is ignored by reflect()+tap(). // not exist. In case of error, it is ignored.
return this.sequelize.query('DROP VIEW V_Fail').reflect(); try {
}; await this.sequelize.query('DROP VIEW V_Fail');
return this.queryInterface } catch (error) {
.createTable('my_test_table', { name: DataTypes.STRING }) // Ignore error.
.tap(cleanup) }
.then(() => this.sequelize.query('CREATE VIEW V_Fail AS SELECT 1 Id')) }
.then(() => this.queryInterface.showAllTables()) await this.queryInterface.createTable('my_test_table', { name: DataTypes.STRING });
.tap(cleanup) await cleanup();
.then(tableNames => { await this.sequelize.query('CREATE VIEW V_Fail AS SELECT 1 Id');
if (tableNames[0] && tableNames[0].tableName) { let tableNames = await this.queryInterface.showAllTables();
tableNames = tableNames.map(v => v.tableName); await cleanup();
} if (tableNames[0] && tableNames[0].tableName) {
expect(tableNames).to.deep.equal(['my_test_table']); tableNames = tableNames.map(v => v.tableName);
}); }
expect(tableNames).to.deep.equal(['my_test_table']);
}); });
if (dialect !== 'sqlite' && dialect !== 'postgres') { if (dialect !== 'sqlite' && dialect !== 'postgres') {
// NOTE: sqlite doesn't allow querying between databases and // NOTE: sqlite doesn't allow querying between databases and
// postgres requires creating a new connection to create a new table. // postgres requires creating a new connection to create a new table.
it('should not show tables in other databases', function() { it('should not show tables in other databases', async function() {
return this.queryInterface await this.queryInterface.createTable('my_test_table1', { name: DataTypes.STRING });
.createTable('my_test_table1', { name: DataTypes.STRING }) await this.sequelize.query('CREATE DATABASE my_test_db');
.then(() => this.sequelize.query('CREATE DATABASE my_test_db')) await this.sequelize.query(`CREATE TABLE my_test_db${dialect === 'mssql' ? '.dbo' : ''}.my_test_table2 (id INT)`);
.then(() => this.sequelize.query(`CREATE TABLE my_test_db${dialect === 'mssql' ? '.dbo' : ''}.my_test_table2 (id INT)`)) let tableNames = await this.queryInterface.showAllTables();
.then(() => this.queryInterface.showAllTables()) await this.sequelize.query('DROP DATABASE my_test_db');
.tap(() => this.sequelize.query('DROP DATABASE my_test_db')) if (tableNames[0] && tableNames[0].tableName) {
.then(tableNames => { tableNames = tableNames.map(v => v.tableName);
if (tableNames[0] && tableNames[0].tableName) { }
tableNames = tableNames.map(v => v.tableName); expect(tableNames).to.deep.equal(['my_test_table1']);
}
expect(tableNames).to.deep.equal(['my_test_table1']);
});
}); });
}
if (dialect === 'mysql' || dialect === 'mariadb') { if (dialect === 'mysql' || dialect === 'mariadb') {
it('should show all tables in all databases', function() { it('should show all tables in all databases', async function() {
return this.queryInterface await this.queryInterface.createTable('my_test_table1', { name: DataTypes.STRING });
.createTable('my_test_table1', { name: DataTypes.STRING }) await this.sequelize.query('CREATE DATABASE my_test_db');
.then(() => this.sequelize.query('CREATE DATABASE my_test_db')) await this.sequelize.query('CREATE TABLE my_test_db.my_test_table2 (id INT)');
.then(() => this.sequelize.query('CREATE TABLE my_test_db.my_test_table2 (id INT)')) let tableNames = await this.sequelize.query(
.then(() => this.sequelize.query(this.queryInterface.QueryGenerator.showTablesQuery(), { this.queryInterface.QueryGenerator.showTablesQuery(),
raw: true, {
type: this.sequelize.QueryTypes.SHOWTABLES raw: true,
})) type: this.sequelize.QueryTypes.SHOWTABLES
.tap(() => this.sequelize.query('DROP DATABASE my_test_db')) }
.then(tableNames => { );
if (tableNames[0] && tableNames[0].tableName) { await this.sequelize.query('DROP DATABASE my_test_db');
tableNames = tableNames.map(v => v.tableName); if (tableNames[0] && tableNames[0].tableName) {
} tableNames = tableNames.map(v => v.tableName);
tableNames.sort(); }
expect(tableNames).to.deep.equal(['my_test_table1', 'my_test_table2']); tableNames.sort();
}); expect(tableNames).to.deep.equal(['my_test_table1', 'my_test_table2']);
}); });
}
} }
}); });
describe('renameTable', () => { describe('renameTable', () => {
it('should rename table', function() { it('should rename table', async function() {
return this.queryInterface await this.queryInterface.createTable('my_test_table', {
.createTable('my_test_table', { name: DataTypes.STRING
name: DataTypes.STRING });
}) await this.queryInterface.renameTable('my_test_table', 'my_test_table_new');
.then(() => this.queryInterface.renameTable('my_test_table', 'my_test_table_new')) let tableNames = await this.queryInterface.showAllTables();
.then(() => this.queryInterface.showAllTables()) if (dialect === 'mssql' || dialect === 'mariadb') {
.then(tableNames => { tableNames = tableNames.map(v => v.tableName);
if (dialect === 'mssql' || dialect === 'mariadb') { }
tableNames = tableNames.map(v => v.tableName); expect(tableNames).to.contain('my_test_table_new');
} expect(tableNames).to.not.contain('my_test_table');
expect(tableNames).to.contain('my_test_table_new');
expect(tableNames).to.not.contain('my_test_table');
});
}); });
}); });
describe('dropAllTables', () => { describe('dropAllTables', () => {
it('should drop all tables', function() { it('should drop all tables', async function() {
const filterMSSQLDefault = tableNames => tableNames.filter(t => t.tableName !== 'spt_values');
return this.queryInterface.dropAllTables() // MSSQL includes `spt_values` table which is system defined, hence can't be dropped
.then(() => { const showAllTablesIgnoringSpecialMSSQLTable = async () => {
return this.queryInterface.showAllTables(); const tableNames = await this.queryInterface.showAllTables();
}) return tableNames.filter(t => t.tableName !== 'spt_values');
.then(tableNames => { };
// MSSQL include spt_values table which is system defined, hence cant be dropped
tableNames = filterMSSQLDefault(tableNames); await this.queryInterface.dropAllTables();
expect(tableNames).to.be.empty;
return this.queryInterface.createTable('table', { name: DataTypes.STRING }); expect(
}) await showAllTablesIgnoringSpecialMSSQLTable()
.then(() => { ).to.be.empty;
return this.queryInterface.showAllTables();
}) await this.queryInterface.createTable('table', { name: DataTypes.STRING });
.then(tableNames => {
tableNames = filterMSSQLDefault(tableNames); expect(
expect(tableNames).to.have.length(1); await showAllTablesIgnoringSpecialMSSQLTable()
return this.queryInterface.dropAllTables(); ).to.have.length(1);
})
.then(() => { await this.queryInterface.dropAllTables();
return this.queryInterface.showAllTables();
}) expect(
.then(tableNames => { await showAllTablesIgnoringSpecialMSSQLTable()
// MSSQL include spt_values table which is system defined, hence cant be dropped ).to.be.empty;
tableNames = filterMSSQLDefault(tableNames);
expect(tableNames).to.be.empty;
});
}); });
it('should be able to skip given tables', function() { it('should be able to skip given tables', async function() {
return this.queryInterface.createTable('skipme', { await this.queryInterface.createTable('skipme', {
name: DataTypes.STRING name: DataTypes.STRING
}) });
.then(() => this.queryInterface.dropAllTables({ skip: ['skipme'] })) await this.queryInterface.dropAllTables({ skip: ['skipme'] });
.then(() => this.queryInterface.showAllTables()) let tableNames = await this.queryInterface.showAllTables();
.then(tableNames => { if (dialect === 'mssql' || dialect === 'mariadb') {
if (dialect === 'mssql' || dialect === 'mariadb') { tableNames = tableNames.map(v => v.tableName);
tableNames = tableNames.map(v => v.tableName); }
} expect(tableNames).to.contain('skipme');
expect(tableNames).to.contain('skipme');
});
}); });
}); });
describe('indexes', () => { describe('indexes', () => {
beforeEach(function() { beforeEach(async function() {
return this.queryInterface.dropTable('Group').then(() => { await this.queryInterface.dropTable('Group');
return this.queryInterface.createTable('Group', { await this.queryInterface.createTable('Group', {
username: DataTypes.STRING, username: DataTypes.STRING,
isAdmin: DataTypes.BOOLEAN, isAdmin: DataTypes.BOOLEAN,
from: DataTypes.STRING from: DataTypes.STRING
});
}); });
}); });
it('adds, reads and removes an index to the table', function() { it('adds, reads and removes an index to the table', async function() {
return this.queryInterface.addIndex('Group', ['username', 'isAdmin']).then(() => { await this.queryInterface.addIndex('Group', ['username', 'isAdmin']);
return this.queryInterface.showIndex('Group').then(indexes => { let indexes = await this.queryInterface.showIndex('Group');
let indexColumns = _.uniq(indexes.map(index => { return index.name; })); let indexColumns = _.uniq(indexes.map(index => index.name));
expect(indexColumns).to.include('group_username_is_admin'); expect(indexColumns).to.include('group_username_is_admin');
return this.queryInterface.removeIndex('Group', ['username', 'isAdmin']).then(() => { await this.queryInterface.removeIndex('Group', ['username', 'isAdmin']);
return this.queryInterface.showIndex('Group').then(indexes => { indexes = await this.queryInterface.showIndex('Group');
indexColumns = _.uniq(indexes.map(index => { return index.name; })); indexColumns = _.uniq(indexes.map(index => index.name));
expect(indexColumns).to.be.empty; expect(indexColumns).to.be.empty;
});
});
});
});
}); });
it('works with schemas', function() { it('works with schemas', async function() {
return this.sequelize.createSchema('schema').then(() => { await this.sequelize.createSchema('schema');
return this.queryInterface.createTable('table', { await this.queryInterface.createTable('table', {
name: { name: {
type: DataTypes.STRING type: DataTypes.STRING
}, },
isAdmin: { isAdmin: {
type: DataTypes.STRING type: DataTypes.STRING
} }
}, { }, {
schema: 'schema' schema: 'schema'
}); });
}).then(() => { await this.queryInterface.addIndex(
return this.queryInterface.addIndex({ { schema: 'schema', tableName: 'table' },
schema: 'schema', ['name', 'isAdmin'],
tableName: 'table' null,
}, ['name', 'isAdmin'], null, 'schema_table').then(() => { 'schema_table'
return this.queryInterface.showIndex({ );
schema: 'schema', const indexes = await this.queryInterface.showIndex({
tableName: 'table' schema: 'schema',
}).then(indexes => { tableName: 'table'
expect(indexes.length).to.eq(1);
const index = indexes[0];
expect(index.name).to.eq('table_name_is_admin');
});
});
}); });
expect(indexes.length).to.eq(1);
expect(indexes[0].name).to.eq('table_name_is_admin');
}); });
it('does not fail on reserved keywords', function() { it('does not fail on reserved keywords', async function() {
return this.queryInterface.addIndex('Group', ['from']); await this.queryInterface.addIndex('Group', ['from']);
}); });
}); });
describe('renameColumn', () => { describe('renameColumn', () => {
it('rename a simple column', function() { it('rename a simple column', async function() {
const Users = this.sequelize.define('_Users', { const Users = this.sequelize.define('_Users', {
username: DataTypes.STRING username: DataTypes.STRING
}, { freezeTableName: true }); }, { freezeTableName: true });
return Users.sync({ force: true }).then(() => { await Users.sync({ force: true });
return this.queryInterface.renameColumn('_Users', 'username', 'pseudo'); await this.queryInterface.renameColumn('_Users', 'username', 'pseudo');
}).then(() => { const table = await this.queryInterface.describeTable('_Users');
return this.queryInterface.describeTable('_Users'); expect(table).to.have.property('pseudo');
}).then(table => { expect(table).to.not.have.property('username');
expect(table).to.have.property('pseudo');
expect(table).to.not.have.property('username');
});
}); });
it('works with schemas', function() { it('works with schemas', async function() {
return this.sequelize.createSchema('archive').then(() => { await this.sequelize.createSchema('archive');
const Users = this.sequelize.define('User', { const Users = this.sequelize.define('User', {
username: DataTypes.STRING username: DataTypes.STRING
}, { }, {
tableName: 'Users', tableName: 'Users',
schema: 'archive' schema: 'archive'
}); });
return Users.sync({ force: true }).then(() => { await Users.sync({ force: true });
return this.queryInterface.renameColumn({ await this.queryInterface.renameColumn({
schema: 'archive', schema: 'archive',
tableName: 'Users' tableName: 'Users'
}, 'username', 'pseudo'); }, 'username', 'pseudo');
}); const table = await this.queryInterface.describeTable({
}).then(() => { schema: 'archive',
return this.queryInterface.describeTable({ tableName: 'Users'
schema: 'archive',
tableName: 'Users'
});
}).then(table => {
expect(table).to.have.property('pseudo');
expect(table).to.not.have.property('username');
}); });
expect(table).to.have.property('pseudo');
expect(table).to.not.have.property('username');
}); });
it('rename a column non-null without default value', function() { it('rename a column non-null without default value', async function() {
const Users = this.sequelize.define('_Users', { const Users = this.sequelize.define('_Users', {
username: { username: {
type: DataTypes.STRING, type: DataTypes.STRING,
...@@ -278,17 +245,14 @@ describe(Support.getTestDialectTeaser('QueryInterface'), () => { ...@@ -278,17 +245,14 @@ describe(Support.getTestDialectTeaser('QueryInterface'), () => {
} }
}, { freezeTableName: true }); }, { freezeTableName: true });
return Users.sync({ force: true }).then(() => { await Users.sync({ force: true });
return this.queryInterface.renameColumn('_Users', 'username', 'pseudo'); await this.queryInterface.renameColumn('_Users', 'username', 'pseudo');
}).then(() => { const table = await this.queryInterface.describeTable('_Users');
return this.queryInterface.describeTable('_Users'); expect(table).to.have.property('pseudo');
}).then(table => { expect(table).to.not.have.property('username');
expect(table).to.have.property('pseudo');
expect(table).to.not.have.property('username');
});
}); });
it('rename a boolean column non-null without default value', function() { it('rename a boolean column non-null without default value', async function() {
const Users = this.sequelize.define('_Users', { const Users = this.sequelize.define('_Users', {
active: { active: {
type: DataTypes.BOOLEAN, type: DataTypes.BOOLEAN,
...@@ -297,17 +261,14 @@ describe(Support.getTestDialectTeaser('QueryInterface'), () => { ...@@ -297,17 +261,14 @@ describe(Support.getTestDialectTeaser('QueryInterface'), () => {
} }
}, { freezeTableName: true }); }, { freezeTableName: true });
return Users.sync({ force: true }).then(() => { await Users.sync({ force: true });
return this.queryInterface.renameColumn('_Users', 'active', 'enabled'); await this.queryInterface.renameColumn('_Users', 'active', 'enabled');
}).then(() => { const table = await this.queryInterface.describeTable('_Users');
return this.queryInterface.describeTable('_Users'); expect(table).to.have.property('enabled');
}).then(table => { expect(table).to.not.have.property('active');
expect(table).to.have.property('enabled');
expect(table).to.not.have.property('active');
});
}); });
it('renames a column primary key autoIncrement column', function() { it('renames a column primary key autoIncrement column', async function() {
const Fruits = this.sequelize.define('Fruit', { const Fruits = this.sequelize.define('Fruit', {
fruitId: { fruitId: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
...@@ -317,113 +278,108 @@ describe(Support.getTestDialectTeaser('QueryInterface'), () => { ...@@ -317,113 +278,108 @@ describe(Support.getTestDialectTeaser('QueryInterface'), () => {
} }
}, { freezeTableName: true }); }, { freezeTableName: true });
return Fruits.sync({ force: true }).then(() => { await Fruits.sync({ force: true });
return this.queryInterface.renameColumn('Fruit', 'fruitId', 'fruit_id'); await this.queryInterface.renameColumn('Fruit', 'fruitId', 'fruit_id');
}).then(() => { const table = await this.queryInterface.describeTable('Fruit');
return this.queryInterface.describeTable('Fruit'); expect(table).to.have.property('fruit_id');
}).then(table => { expect(table).to.not.have.property('fruitId');
expect(table).to.have.property('fruit_id');
expect(table).to.not.have.property('fruitId');
});
}); });
it('shows a reasonable error message when column is missing', function() { it('shows a reasonable error message when column is missing', async function() {
const Users = this.sequelize.define('_Users', { const Users = this.sequelize.define('_Users', {
username: DataTypes.STRING username: DataTypes.STRING
}, { freezeTableName: true }); }, { freezeTableName: true });
const outcome = Users.sync({ force: true }).then(() => { await Users.sync({ force: true });
return this.queryInterface.renameColumn('_Users', 'email', 'pseudo'); await expect(
}); this.queryInterface.renameColumn('_Users', 'email', 'pseudo')
).to.be.rejectedWith('Table _Users doesn\'t have the column email');
return expect(outcome).to.be.rejectedWith('Table _Users doesn\'t have the column email');
}); });
}); });
describe('addColumn', () => { describe('addColumn', () => {
beforeEach(function() { beforeEach(async function() {
return this.sequelize.createSchema('archive').then(() => { await this.sequelize.createSchema('archive');
return this.queryInterface.createTable('users', { await this.queryInterface.createTable('users', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
}
});
});
});
it('should be able to add a foreign key reference', function() {
return this.queryInterface.createTable('level', {
id: { id: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
primaryKey: true, primaryKey: true,
autoIncrement: true autoIncrement: true
} }
}).then(() => {
return this.queryInterface.addColumn('users', 'level_id', {
type: DataTypes.INTEGER,
references: {
model: 'level',
key: 'id'
},
onUpdate: 'cascade',
onDelete: 'set null'
});
}).then(() => {
return this.queryInterface.describeTable('users');
}).then(table => {
expect(table).to.have.property('level_id');
}); });
}); });
it('addColumn expected error', function() { it('should be able to add a foreign key reference', async function() {
return this.queryInterface.createTable('level2', { await this.queryInterface.createTable('level', {
id: { id: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
primaryKey: true, primaryKey: true,
autoIncrement: true autoIncrement: true
} }
}).then(() => {
expect(this.queryInterface.addColumn.bind(this, 'users', 'level_id')).to.throw(Error, 'addColumn takes at least 3 arguments (table, attribute name, attribute definition)');
expect(this.queryInterface.addColumn.bind(this, null, 'level_id')).to.throw(Error, 'addColumn takes at least 3 arguments (table, attribute name, attribute definition)');
expect(this.queryInterface.addColumn.bind(this, 'users', null, {})).to.throw(Error, 'addColumn takes at least 3 arguments (table, attribute name, attribute definition)');
}); });
await this.queryInterface.addColumn('users', 'level_id', {
type: DataTypes.INTEGER,
references: {
model: 'level',
key: 'id'
},
onUpdate: 'cascade',
onDelete: 'set null'
});
const table = await this.queryInterface.describeTable('users');
expect(table).to.have.property('level_id');
}); });
it('should work with schemas', function() { it('addColumn expected error', async function() {
return this.queryInterface.createTable({ await this.queryInterface.createTable('level2', {
tableName: 'users',
schema: 'archive'
}, {
id: { id: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
primaryKey: true, primaryKey: true,
autoIncrement: true autoIncrement: true
} }
}).then(() => {
return this.queryInterface.addColumn({
tableName: 'users',
schema: 'archive'
}, 'level_id', {
type: DataTypes.INTEGER
}).then(() => {
return this.queryInterface.describeTable({
tableName: 'users',
schema: 'archive'
});
}).then(table => {
expect(table).to.have.property('level_id');
});
}); });
const testArgs = (...args) => {
expect(() => {
this.queryInterface.addColumn(...args);
throw new Error('Did not throw immediately...');
}).to.throw(Error, 'addColumn takes at least 3 arguments (table, attribute name, attribute definition)');
};
testArgs('users', 'level_id');
testArgs(null, 'level_id');
testArgs('users', null, {});
});
it('should work with schemas', async function() {
await this.queryInterface.createTable(
{ tableName: 'users', schema: 'archive' },
{
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
}
}
);
await this.queryInterface.addColumn(
{ tableName: 'users', schema: 'archive' },
'level_id',
{ type: DataTypes.INTEGER }
);
const table = await this.queryInterface.describeTable({
tableName: 'users',
schema: 'archive'
});
expect(table).to.have.property('level_id');
}); });
it('should work with enums (1)', function() { it('should work with enums (1)', async function() {
return this.queryInterface.addColumn('users', 'someEnum', DataTypes.ENUM('value1', 'value2', 'value3')); await this.queryInterface.addColumn('users', 'someEnum', DataTypes.ENUM('value1', 'value2', 'value3'));
}); });
it('should work with enums (2)', function() { it('should work with enums (2)', async function() {
return this.queryInterface.addColumn('users', 'someOtherEnum', { await this.queryInterface.addColumn('users', 'someOtherEnum', {
type: DataTypes.ENUM, type: DataTypes.ENUM,
values: ['value1', 'value2', 'value3'] values: ['value1', 'value2', 'value3']
}); });
...@@ -431,99 +387,94 @@ describe(Support.getTestDialectTeaser('QueryInterface'), () => { ...@@ -431,99 +387,94 @@ describe(Support.getTestDialectTeaser('QueryInterface'), () => {
}); });
describe('describeForeignKeys', () => { describe('describeForeignKeys', () => {
beforeEach(function() { beforeEach(async function() {
return this.queryInterface.createTable('users', { await this.queryInterface.createTable('users', {
id: { id: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
primaryKey: true, primaryKey: true,
autoIncrement: true autoIncrement: true
} }
}).then(() => { });
return this.queryInterface.createTable('hosts', { await this.queryInterface.createTable('hosts', {
id: { id: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
primaryKey: true, primaryKey: true,
autoIncrement: true autoIncrement: true
}, },
admin: { admin: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
references: { references: {
model: 'users', model: 'users',
key: 'id' key: 'id'
} }
},
operator: {
type: DataTypes.INTEGER,
references: {
model: 'users',
key: 'id'
}, },
operator: { onUpdate: 'cascade'
type: DataTypes.INTEGER, },
references: { owner: {
model: 'users', type: DataTypes.INTEGER,
key: 'id' references: {
}, model: 'users',
onUpdate: 'cascade' key: 'id'
}, },
owner: { onUpdate: 'cascade',
type: DataTypes.INTEGER, onDelete: 'set null'
references: { }
model: 'users',
key: 'id'
},
onUpdate: 'cascade',
onDelete: 'set null'
}
});
}); });
}); });
it('should get a list of foreign keys for the table', function() { it('should get a list of foreign keys for the table', async function() {
const sql = this.queryInterface.QueryGenerator.getForeignKeysQuery('hosts', this.sequelize.config.database);
return this.sequelize.query(sql, { type: this.sequelize.QueryTypes.FOREIGNKEYS }).then(fks => { const foreignKeys = await this.sequelize.query(
expect(fks).to.have.length(3); this.queryInterface.QueryGenerator.getForeignKeysQuery(
const keys = Object.keys(fks[0]), 'hosts',
keys2 = Object.keys(fks[1]), this.sequelize.config.database
keys3 = Object.keys(fks[2]); ),
{ type: this.sequelize.QueryTypes.FOREIGNKEYS }
if (dialect === 'postgres' || dialect === 'postgres-native') { );
expect(keys).to.have.length(6);
expect(keys2).to.have.length(7); expect(foreignKeys).to.have.length(3);
expect(keys3).to.have.length(7);
} else if (dialect === 'sqlite') { if (dialect === 'postgres') {
expect(keys).to.have.length(8); expect(Object.keys(foreignKeys[0])).to.have.length(6);
} else if (dialect === 'mysql' || dialect === 'mssql') { expect(Object.keys(foreignKeys[1])).to.have.length(7);
expect(keys).to.have.length(12); expect(Object.keys(foreignKeys[2])).to.have.length(7);
} else { } else if (dialect === 'sqlite') {
console.log(`This test doesn't support ${dialect}`); expect(Object.keys(foreignKeys[0])).to.have.length(8);
} } else if (dialect === 'mysql' || dialect === 'mariadb' || dialect === 'mssql') {
return fks; expect(Object.keys(foreignKeys[0])).to.have.length(12);
}).then(fks => { } else {
if (dialect === 'mysql') { throw new Error(`This test doesn't support ${dialect}`);
return this.sequelize.query( }
this.queryInterface.QueryGenerator.getForeignKeyQuery('hosts', 'admin'),
{} if (dialect === 'mysql') {
) const [foreignKeysViaDirectMySQLQuery] = await this.sequelize.query(
.then(([fk]) => { this.queryInterface.QueryGenerator.getForeignKeyQuery('hosts', 'admin')
expect(fks[0]).to.deep.eql(fk[0]); );
}); expect(foreignKeysViaDirectMySQLQuery[0]).to.deep.equal(foreignKeys[0]);
} }
return;
});
}); });
it('should get a list of foreign key references details for the table', function() { it('should get a list of foreign key references details for the table', async function() {
return this.queryInterface.getForeignKeyReferencesForTable('hosts', this.sequelize.options) const references = await this.queryInterface.getForeignKeyReferencesForTable('hosts', this.sequelize.options);
.then(references => { expect(references).to.have.length(3);
expect(references).to.have.length(3); for (const ref of references) {
const keys = references.map(reference => { expect(ref.tableName).to.equal('hosts');
expect(reference.tableName).to.eql('hosts'); expect(ref.referencedColumnName).to.equal('id');
expect(reference.referencedColumnName).to.eql('id'); expect(ref.referencedTableName).to.equal('users');
expect(reference.referencedTableName).to.eql('users'); }
return reference.columnName; const columnNames = references.map(reference => reference.columnName);
}); expect(columnNames).to.have.same.members(['owner', 'operator', 'admin']);
expect(keys).to.have.same.members(['owner', 'operator', 'admin']);
});
}); });
}); });
describe('constraints', () => { describe('constraints', () => {
beforeEach(function() { beforeEach(async function() {
this.User = this.sequelize.define('users', { this.User = this.sequelize.define('users', {
username: DataTypes.STRING, username: DataTypes.STRING,
email: DataTypes.STRING, email: DataTypes.STRING,
...@@ -533,203 +484,157 @@ describe(Support.getTestDialectTeaser('QueryInterface'), () => { ...@@ -533,203 +484,157 @@ describe(Support.getTestDialectTeaser('QueryInterface'), () => {
this.Post = this.sequelize.define('posts', { this.Post = this.sequelize.define('posts', {
username: DataTypes.STRING username: DataTypes.STRING
}); });
return this.sequelize.sync({ force: true }); await this.sequelize.sync({ force: true });
}); });
describe('unique', () => { describe('unique', () => {
it('should add, read & remove unique constraint', function() { it('should add, read & remove unique constraint', async function() {
return this.queryInterface.addConstraint('users', ['email'], { await this.queryInterface.addConstraint('users', ['email'], { type: 'unique' });
type: 'unique' let constraints = await this.queryInterface.showConstraint('users');
}) constraints = constraints.map(constraint => constraint.constraintName);
.then(() => this.queryInterface.showConstraint('users')) expect(constraints).to.include('users_email_uk');
.then(constraints => { await this.queryInterface.removeConstraint('users', 'users_email_uk');
constraints = constraints.map(constraint => constraint.constraintName); constraints = await this.queryInterface.showConstraint('users');
expect(constraints).to.include('users_email_uk'); constraints = constraints.map(constraint => constraint.constraintName);
return this.queryInterface.removeConstraint('users', 'users_email_uk'); expect(constraints).to.not.include('users_email_uk');
})
.then(() => this.queryInterface.showConstraint('users'))
.then(constraints => {
constraints = constraints.map(constraint => constraint.constraintName);
expect(constraints).to.not.include('users_email_uk');
});
}); });
it('should add a constraint after another', function() { it('should add a constraint after another', async function() {
return this.queryInterface.addConstraint('users', ['username'], { await this.queryInterface.addConstraint('users', ['username'], { type: 'unique' });
type: 'unique' await this.queryInterface.addConstraint('users', ['email'], { type: 'unique' });
}).then(() => this.queryInterface.addConstraint('users', ['email'], { let constraints = await this.queryInterface.showConstraint('users');
type: 'unique' constraints = constraints.map(constraint => constraint.constraintName);
})) expect(constraints).to.include('users_email_uk');
.then(() => this.queryInterface.showConstraint('users')) expect(constraints).to.include('users_username_uk');
.then(constraints => { await this.queryInterface.removeConstraint('users', 'users_email_uk');
constraints = constraints.map(constraint => constraint.constraintName); constraints = await this.queryInterface.showConstraint('users');
expect(constraints).to.include('users_email_uk'); constraints = constraints.map(constraint => constraint.constraintName);
expect(constraints).to.include('users_username_uk'); expect(constraints).to.not.include('users_email_uk');
return this.queryInterface.removeConstraint('users', 'users_email_uk'); expect(constraints).to.include('users_username_uk');
}) await this.queryInterface.removeConstraint('users', 'users_username_uk');
.then(() => this.queryInterface.showConstraint('users')) constraints = await this.queryInterface.showConstraint('users');
.then(constraints => { constraints = constraints.map(constraint => constraint.constraintName);
constraints = constraints.map(constraint => constraint.constraintName); expect(constraints).to.not.include('users_email_uk');
expect(constraints).to.not.include('users_email_uk'); expect(constraints).to.not.include('users_username_uk');
expect(constraints).to.include('users_username_uk');
return this.queryInterface.removeConstraint('users', 'users_username_uk');
})
.then(() => this.queryInterface.showConstraint('users'))
.then(constraints => {
constraints = constraints.map(constraint => constraint.constraintName);
expect(constraints).to.not.include('users_email_uk');
expect(constraints).to.not.include('users_username_uk');
});
}); });
}); });
if (current.dialect.supports.constraints.check) { if (current.dialect.supports.constraints.check) {
describe('check', () => { describe('check', () => {
it('should add, read & remove check constraint', function() { it('should add, read & remove check constraint', async function() {
return this.queryInterface.addConstraint('users', ['roles'], { await this.queryInterface.addConstraint('users', ['roles'], {
type: 'check', type: 'check',
where: { where: {
roles: ['user', 'admin', 'guest', 'moderator'] roles: ['user', 'admin', 'guest', 'moderator']
}, },
name: 'check_user_roles' name: 'check_user_roles'
}) });
.then(() => this.queryInterface.showConstraint('users')) let constraints = await this.queryInterface.showConstraint('users');
.then(constraints => { constraints = constraints.map(constraint => constraint.constraintName);
constraints = constraints.map(constraint => constraint.constraintName); expect(constraints).to.include('check_user_roles');
expect(constraints).to.include('check_user_roles'); await this.queryInterface.removeConstraint('users', 'check_user_roles');
return this.queryInterface.removeConstraint('users', 'check_user_roles'); constraints = await this.queryInterface.showConstraint('users');
}) constraints = constraints.map(constraint => constraint.constraintName);
.then(() => this.queryInterface.showConstraint('users')) expect(constraints).to.not.include('check_user_roles');
.then(constraints => {
constraints = constraints.map(constraint => constraint.constraintName);
expect(constraints).to.not.include('check_user_roles');
});
}); });
it('addconstraint missing type', function() { it('addconstraint missing type', function() {
expect(this.queryInterface.addConstraint.bind(this, 'users', ['roles'], { expect(() => {
where: { roles: ['user', 'admin', 'guest', 'moderator'] }, this.queryInterface.addConstraint('users', ['roles'], {
name: 'check_user_roles' where: { roles: ['user', 'admin', 'guest', 'moderator'] },
})).to.throw(Error, 'Constraint type must be specified through options.type'); name: 'check_user_roles'
});
throw new Error('Did not throw immediately...');
}).to.throw(Error, 'Constraint type must be specified through options.type');
}); });
}); });
} }
if (current.dialect.supports.constraints.default) { if (current.dialect.supports.constraints.default) {
describe('default', () => { describe('default', () => {
it('should add, read & remove default constraint', function() { it('should add, read & remove default constraint', async function() {
return this.queryInterface.addConstraint('users', ['roles'], { await this.queryInterface.addConstraint('users', ['roles'], {
type: 'default', type: 'default',
defaultValue: 'guest' defaultValue: 'guest'
}) });
.then(() => this.queryInterface.showConstraint('users')) let constraints = await this.queryInterface.showConstraint('users');
.then(constraints => { constraints = constraints.map(constraint => constraint.constraintName);
constraints = constraints.map(constraint => constraint.constraintName); expect(constraints).to.include('users_roles_df');
expect(constraints).to.include('users_roles_df'); await this.queryInterface.removeConstraint('users', 'users_roles_df');
return this.queryInterface.removeConstraint('users', 'users_roles_df'); constraints = await this.queryInterface.showConstraint('users');
}) constraints = constraints.map(constraint => constraint.constraintName);
.then(() => this.queryInterface.showConstraint('users')) expect(constraints).to.not.include('users_roles_df');
.then(constraints => {
constraints = constraints.map(constraint => constraint.constraintName);
expect(constraints).to.not.include('users_roles_df');
});
}); });
}); });
} }
describe('primary key', () => { describe('primary key', () => {
it('should add, read & remove primary key constraint', function() { it('should add, read & remove primary key constraint', async function() {
return this.queryInterface.removeColumn('users', 'id') await this.queryInterface.removeColumn('users', 'id');
.then(() => { await this.queryInterface.changeColumn('users', 'username', {
return this.queryInterface.changeColumn('users', 'username', { type: DataTypes.STRING,
type: DataTypes.STRING, allowNull: false
allowNull: false });
}); await this.queryInterface.addConstraint('users', ['username'], {
}) type: 'PRIMARY KEY'
.then(() => { });
return this.queryInterface.addConstraint('users', ['username'], { let constraints = await this.queryInterface.showConstraint('users');
type: 'PRIMARY KEY' constraints = constraints.map(constraint => constraint.constraintName);
});
}) // The name of primaryKey constraint is always `PRIMARY` in case of MySQL and MariaDB
.then(() => this.queryInterface.showConstraint('users')) const expectedConstraintName = dialect === 'mysql' || dialect === 'mariadb' ? 'PRIMARY' : 'users_username_pk';
.then(constraints => {
constraints = constraints.map(constraint => constraint.constraintName); expect(constraints).to.include(expectedConstraintName);
//The name of primaryKey constraint is always PRIMARY in case of mysql await this.queryInterface.removeConstraint('users', expectedConstraintName);
if (dialect === 'mysql' || dialect === 'mariadb') { constraints = await this.queryInterface.showConstraint('users');
expect(constraints).to.include('PRIMARY'); constraints = constraints.map(constraint => constraint.constraintName);
return this.queryInterface.removeConstraint('users', 'PRIMARY'); expect(constraints).to.not.include(expectedConstraintName);
}
expect(constraints).to.include('users_username_pk');
return this.queryInterface.removeConstraint('users', 'users_username_pk');
})
.then(() => this.queryInterface.showConstraint('users'))
.then(constraints => {
constraints = constraints.map(constraint => constraint.constraintName);
if (dialect === 'mysql' || dialect === 'mariadb') {
expect(constraints).to.not.include('PRIMARY');
} else {
expect(constraints).to.not.include('users_username_pk');
}
});
}); });
}); });
describe('foreign key', () => { describe('foreign key', () => {
it('should add, read & remove foreign key constraint', function() { it('should add, read & remove foreign key constraint', async function() {
return this.queryInterface.removeColumn('users', 'id') await this.queryInterface.removeColumn('users', 'id');
.then(() => { await this.queryInterface.changeColumn('users', 'username', {
return this.queryInterface.changeColumn('users', 'username', { type: DataTypes.STRING,
type: DataTypes.STRING, allowNull: false
allowNull: false });
}); await this.queryInterface.addConstraint('users', {
}) type: 'PRIMARY KEY',
.then(() => { fields: ['username']
return this.queryInterface.addConstraint('users', { });
type: 'PRIMARY KEY', await this.queryInterface.addConstraint('posts', ['username'], {
fields: ['username'] references: {
}); table: 'users',
}) field: 'username'
.then(() => { },
return this.queryInterface.addConstraint('posts', ['username'], { onDelete: 'cascade',
references: { onUpdate: 'cascade',
table: 'users', type: 'foreign key'
field: 'username' });
}, let constraints = await this.queryInterface.showConstraint('posts');
onDelete: 'cascade', constraints = constraints.map(constraint => constraint.constraintName);
onUpdate: 'cascade', expect(constraints).to.include('posts_username_users_fk');
type: 'foreign key' await this.queryInterface.removeConstraint('posts', 'posts_username_users_fk');
}); constraints = await this.queryInterface.showConstraint('posts');
}) constraints = constraints.map(constraint => constraint.constraintName);
.then(() => this.queryInterface.showConstraint('posts')) expect(constraints).to.not.include('posts_username_users_fk');
.then(constraints => {
constraints = constraints.map(constraint => constraint.constraintName);
expect(constraints).to.include('posts_username_users_fk');
return this.queryInterface.removeConstraint('posts', 'posts_username_users_fk');
})
.then(() => this.queryInterface.showConstraint('posts'))
.then(constraints => {
constraints = constraints.map(constraint => constraint.constraintName);
expect(constraints).to.not.include('posts_username_users_fk');
});
}); });
}); });
describe('unknown constraint', () => { describe('unknown constraint', () => {
it('should throw non existent constraints as UnknownConstraintError', function() { it('should throw non existent constraints as UnknownConstraintError', async function() {
const promise = this.queryInterface try {
.removeConstraint('users', 'unknown__constraint__name', { await this.queryInterface.removeConstraint('users', 'unknown__constraint__name', {
type: 'unique' type: 'unique'
})
.catch(e => {
expect(e.table).to.equal('users');
expect(e.constraint).to.equal('unknown__constraint__name');
throw e;
}); });
throw new Error('Error not thrown...');
return expect(promise).to.eventually.be.rejectedWith(Sequelize.UnknownConstraintError); } catch (error) {
expect(error).to.be.instanceOf(Sequelize.UnknownConstraintError);
expect(error.table).to.equal('users');
expect(error.constraint).to.equal('unknown__constraint__name');
}
}); });
}); });
}); });
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!