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

Commit 597fc8ae by Andy Edwards Committed by GitHub

refactor: replace bluebird .each (#12074)

1 parent 72a940d8
'use strict';
const _ = require('lodash');
const Promise = require('../../promise');
const sequelizeErrors = require('../../errors');
const QueryTypes = require('../../query-types');
......@@ -27,17 +26,16 @@ const QueryTypes = require('../../query-types');
@since 1.6.0
@private
*/
function removeColumn(qi, tableName, attributeName, options) {
async function removeColumn(qi, tableName, attributeName, options) {
options = options || {};
return qi.describeTable(tableName, options).then(fields => {
delete fields[attributeName];
const fields = await qi.describeTable(tableName, options);
delete fields[attributeName];
const sql = qi.QueryGenerator.removeColumnQuery(tableName, fields);
const subQueries = sql.split(';').filter(q => q !== '');
const sql = qi.QueryGenerator.removeColumnQuery(tableName, fields);
const subQueries = sql.split(';').filter(q => q !== '');
return Promise.each(subQueries, subQuery => qi.sequelize.query(`${subQuery};`, Object.assign({ raw: true }, options)));
});
for (const subQuery of subQueries) await qi.sequelize.query(`${subQuery};`, Object.assign({ raw: true }, options));
}
exports.removeColumn = removeColumn;
......@@ -55,18 +53,17 @@ exports.removeColumn = removeColumn;
@since 1.6.0
@private
*/
function changeColumn(qi, tableName, attributes, options) {
async function changeColumn(qi, tableName, attributes, options) {
const attributeName = Object.keys(attributes)[0];
options = options || {};
return qi.describeTable(tableName, options).then(fields => {
fields[attributeName] = attributes[attributeName];
const fields = await qi.describeTable(tableName, options);
fields[attributeName] = attributes[attributeName];
const sql = qi.QueryGenerator.removeColumnQuery(tableName, fields);
const subQueries = sql.split(';').filter(q => q !== '');
const sql = qi.QueryGenerator.removeColumnQuery(tableName, fields);
const subQueries = sql.split(';').filter(q => q !== '');
return Promise.each(subQueries, subQuery => qi.sequelize.query(`${subQuery};`, Object.assign({ raw: true }, options)));
});
for (const subQuery of subQueries) await qi.sequelize.query(`${subQuery};`, Object.assign({ raw: true }, options));
}
exports.changeColumn = changeColumn;
......@@ -85,18 +82,17 @@ exports.changeColumn = changeColumn;
@since 1.6.0
@private
*/
function renameColumn(qi, tableName, attrNameBefore, attrNameAfter, options) {
async function renameColumn(qi, tableName, attrNameBefore, attrNameAfter, options) {
options = options || {};
return qi.describeTable(tableName, options).then(fields => {
fields[attrNameAfter] = _.clone(fields[attrNameBefore]);
delete fields[attrNameBefore];
const fields = await qi.describeTable(tableName, options);
fields[attrNameAfter] = _.clone(fields[attrNameBefore]);
delete fields[attrNameBefore];
const sql = qi.QueryGenerator.renameColumnQuery(tableName, attrNameBefore, attrNameAfter, fields);
const subQueries = sql.split(';').filter(q => q !== '');
const sql = qi.QueryGenerator.renameColumnQuery(tableName, attrNameBefore, attrNameAfter, fields);
const subQueries = sql.split(';').filter(q => q !== '');
return Promise.each(subQueries, subQuery => qi.sequelize.query(`${subQuery};`, Object.assign({ raw: true }, options)));
});
for (const subQuery of subQueries) await qi.sequelize.query(`${subQuery};`, Object.assign({ raw: true }, options));
}
exports.renameColumn = renameColumn;
......@@ -108,45 +104,42 @@ exports.renameColumn = renameColumn;
*
* @private
*/
function removeConstraint(qi, tableName, constraintName, options) {
async function removeConstraint(qi, tableName, constraintName, options) {
let createTableSql;
return qi.showConstraint(tableName, constraintName)
.then(constraints => {
// sqlite can't show only one constraint, so we find here the one to remove
const constraint = constraints.find(constaint => constaint.constraintName === constraintName);
if (constraint) {
createTableSql = constraint.sql;
constraint.constraintName = qi.QueryGenerator.quoteIdentifier(constraint.constraintName);
let constraintSnippet = `, CONSTRAINT ${constraint.constraintName} ${constraint.constraintType} ${constraint.constraintCondition}`;
if (constraint.constraintType === 'FOREIGN KEY') {
const referenceTableName = qi.QueryGenerator.quoteTable(constraint.referenceTableName);
constraint.referenceTableKeys = constraint.referenceTableKeys.map(columnName => qi.QueryGenerator.quoteIdentifier(columnName));
const referenceTableKeys = constraint.referenceTableKeys.join(', ');
constraintSnippet += ` REFERENCES ${referenceTableName} (${referenceTableKeys})`;
constraintSnippet += ` ON UPDATE ${constraint.updateAction}`;
constraintSnippet += ` ON DELETE ${constraint.deleteAction}`;
}
createTableSql = createTableSql.replace(constraintSnippet, '');
createTableSql += ';';
return qi.describeTable(tableName, options);
}
throw new sequelizeErrors.UnknownConstraintError({
message: `Constraint ${constraintName} on table ${tableName} does not exist`,
constraint: constraintName,
table: tableName
});
})
.then(fields => {
const sql = qi.QueryGenerator._alterConstraintQuery(tableName, fields, createTableSql);
const subQueries = sql.split(';').filter(q => q !== '');
return Promise.each(subQueries, subQuery => qi.sequelize.query(`${subQuery};`, Object.assign({ raw: true }, options)));
const constraints = await qi.showConstraint(tableName, constraintName);
// sqlite can't show only one constraint, so we find here the one to remove
const constraint = constraints.find(constaint => constaint.constraintName === constraintName);
if (!constraint) {
throw new sequelizeErrors.UnknownConstraintError({
message: `Constraint ${constraintName} on table ${tableName} does not exist`,
constraint: constraintName,
table: tableName
});
}
createTableSql = constraint.sql;
constraint.constraintName = qi.QueryGenerator.quoteIdentifier(constraint.constraintName);
let constraintSnippet = `, CONSTRAINT ${constraint.constraintName} ${constraint.constraintType} ${constraint.constraintCondition}`;
if (constraint.constraintType === 'FOREIGN KEY') {
const referenceTableName = qi.QueryGenerator.quoteTable(constraint.referenceTableName);
constraint.referenceTableKeys = constraint.referenceTableKeys.map(columnName => qi.QueryGenerator.quoteIdentifier(columnName));
const referenceTableKeys = constraint.referenceTableKeys.join(', ');
constraintSnippet += ` REFERENCES ${referenceTableName} (${referenceTableKeys})`;
constraintSnippet += ` ON UPDATE ${constraint.updateAction}`;
constraintSnippet += ` ON DELETE ${constraint.deleteAction}`;
}
createTableSql = createTableSql.replace(constraintSnippet, '');
createTableSql += ';';
const fields = await qi.describeTable(tableName, options);
const sql = qi.QueryGenerator._alterConstraintQuery(tableName, fields, createTableSql);
const subQueries = sql.split(';').filter(q => q !== '');
for (const subQuery of subQueries) await qi.sequelize.query(`${subQuery};`, Object.assign({ raw: true }, options));
}
exports.removeConstraint = removeConstraint;
......@@ -157,27 +150,22 @@ exports.removeConstraint = removeConstraint;
*
* @private
*/
function addConstraint(qi, tableName, options) {
async function addConstraint(qi, tableName, options) {
const constraintSnippet = qi.QueryGenerator.getConstraintSnippet(tableName, options);
const describeCreateTableSql = qi.QueryGenerator.describeCreateTableQuery(tableName);
let createTableSql;
return qi.sequelize.query(describeCreateTableSql, Object.assign({}, options, { type: QueryTypes.SELECT, raw: true }))
.then(constraints => {
const sql = constraints[0].sql;
const index = sql.length - 1;
//Replace ending ')' with constraint snippet - Simulates String.replaceAt
//http://stackoverflow.com/questions/1431094
createTableSql = `${sql.substr(0, index)}, ${constraintSnippet})${sql.substr(index + 1)};`;
return qi.describeTable(tableName, options);
})
.then(fields => {
const sql = qi.QueryGenerator._alterConstraintQuery(tableName, fields, createTableSql);
const subQueries = sql.split(';').filter(q => q !== '');
return Promise.each(subQueries, subQuery => qi.sequelize.query(`${subQuery};`, Object.assign({ raw: true }, options)));
});
const constraints = await qi.sequelize.query(describeCreateTableSql, Object.assign({}, options, { type: QueryTypes.SELECT, raw: true }));
let sql = constraints[0].sql;
const index = sql.length - 1;
//Replace ending ')' with constraint snippet - Simulates String.replaceAt
//http://stackoverflow.com/questions/1431094
const createTableSql = `${sql.substr(0, index)}, ${constraintSnippet})${sql.substr(index + 1)};`;
const fields = await qi.describeTable(tableName, options);
sql = qi.QueryGenerator._alterConstraintQuery(tableName, fields, createTableSql);
const subQueries = sql.split(';').filter(q => q !== '');
for (const subQuery of subQueries) await qi.sequelize.query(`${subQuery};`, Object.assign({ raw: true }, options));
}
exports.addConstraint = addConstraint;
......
......@@ -2,7 +2,6 @@
const _ = require('lodash');
const { logger } = require('./utils/logger');
const Promise = require('./promise');
const debug = logger.debugContext('hooks');
const hookTypes = {
......@@ -89,7 +88,7 @@ const Hooks = {
});
},
runHooks(hooks, ...hookArgs) {
async runHooks(hooks, ...hookArgs) {
if (!hooks) throw new Error('runHooks requires at least 1 argument');
let hookType;
......@@ -121,14 +120,14 @@ const Hooks = {
}
// asynchronous hooks (default)
return Promise.each(hooks, hook => {
for (let hook of hooks) {
if (typeof hook === 'object') {
hook = hook.fn;
}
debug(`running hook ${hookType}`);
return hook.apply(this, hookArgs);
}).then(() => undefined);
await hook.apply(this, hookArgs);
}
},
/**
......
......@@ -1272,109 +1272,102 @@ class Model {
*
* @returns {Promise<Model>}
*/
static sync(options) {
static async sync(options) {
options = Object.assign({}, this.options, options);
options.hooks = options.hooks === undefined ? true : !!options.hooks;
const attributes = this.tableAttributes;
const rawAttributes = this.fieldRawAttributesMap;
return Promise.resolve().then(() => {
if (options.hooks) {
return this.runHooks('beforeSync', options);
}
}).then(() => {
if (options.force) {
return this.drop(options);
}
})
.then(() => this.QueryInterface.createTable(this.getTableName(options), attributes, options, this))
.then(() => {
if (!options.alter) {
return;
if (options.hooks) {
await this.runHooks('beforeSync', options);
}
if (options.force) {
await this.drop(options);
}
await this.QueryInterface.createTable(this.getTableName(options), attributes, options, this);
if (options.alter) {
const tableInfos = await Promise.all([
this.QueryInterface.describeTable(this.getTableName(options)),
this.QueryInterface.getForeignKeyReferencesForTable(this.getTableName(options))
]);
const columns = tableInfos[0];
// Use for alter foreign keys
const foreignKeyReferences = tableInfos[1];
const removedConstraints = {};
for (const columnName in attributes) {
if (!Object.prototype.hasOwnProperty.call(attributes, columnName)) continue;
if (!columns[columnName] && !columns[attributes[columnName].field]) {
await this.QueryInterface.addColumn(this.getTableName(options), attributes[columnName].field || columnName, attributes[columnName]);
}
return Promise.all([
this.QueryInterface.describeTable(this.getTableName(options)),
this.QueryInterface.getForeignKeyReferencesForTable(this.getTableName(options))
])
.then(tableInfos => {
const columns = tableInfos[0];
// Use for alter foreign keys
const foreignKeyReferences = tableInfos[1];
const changes = []; // array of promises to run
const removedConstraints = {};
_.each(attributes, (columnDesc, columnName) => {
if (!columns[columnName] && !columns[attributes[columnName].field]) {
changes.push(() => this.QueryInterface.addColumn(this.getTableName(options), attributes[columnName].field || columnName, attributes[columnName]));
}
});
}
if (options.alter === true || typeof options.alter === 'object' && options.alter.drop !== false) {
_.each(columns, (columnDesc, columnName) => {
const currentAttribute = rawAttributes[columnName];
if (!currentAttribute) {
changes.push(() => this.QueryInterface.removeColumn(this.getTableName(options), columnName, options));
} else if (!currentAttribute.primaryKey) {
// Check foreign keys. If it's a foreign key, it should remove constraint first.
const references = currentAttribute.references;
if (currentAttribute.references) {
const database = this.sequelize.config.database;
const schema = this.sequelize.config.schema;
// Find existed foreign keys
_.each(foreignKeyReferences, foreignKeyReference => {
const constraintName = foreignKeyReference.constraintName;
if (!!constraintName
&& foreignKeyReference.tableCatalog === database
&& (schema ? foreignKeyReference.tableSchema === schema : true)
&& foreignKeyReference.referencedTableName === references.model
&& foreignKeyReference.referencedColumnName === references.key
&& (schema ? foreignKeyReference.referencedTableSchema === schema : true)
&& !removedConstraints[constraintName]) {
// Remove constraint on foreign keys.
changes.push(() => this.QueryInterface.removeConstraint(this.getTableName(options), constraintName, options));
removedConstraints[constraintName] = true;
}
});
}
changes.push(() => this.QueryInterface.changeColumn(this.getTableName(options), columnName, currentAttribute));
}
});
if (options.alter === true || typeof options.alter === 'object' && options.alter.drop !== false) {
for (const columnName in columns) {
if (!Object.prototype.hasOwnProperty.call(columns, columnName)) continue;
const currentAttribute = rawAttributes[columnName];
if (!currentAttribute) {
await this.QueryInterface.removeColumn(this.getTableName(options), columnName, options);
continue;
}
if (currentAttribute.primaryKey) continue;
// Check foreign keys. If it's a foreign key, it should remove constraint first.
const references = currentAttribute.references;
if (currentAttribute.references) {
const database = this.sequelize.config.database;
const schema = this.sequelize.config.schema;
// Find existed foreign keys
for (const foreignKeyReference of foreignKeyReferences) {
const constraintName = foreignKeyReference.constraintName;
if (!!constraintName
&& foreignKeyReference.tableCatalog === database
&& (schema ? foreignKeyReference.tableSchema === schema : true)
&& foreignKeyReference.referencedTableName === references.model
&& foreignKeyReference.referencedColumnName === references.key
&& (schema ? foreignKeyReference.referencedTableSchema === schema : true)
&& !removedConstraints[constraintName]) {
// Remove constraint on foreign keys.
await this.QueryInterface.removeConstraint(this.getTableName(options), constraintName, options);
removedConstraints[constraintName] = true;
}
}
return Promise.each(changes, f => f());
});
})
.then(() => this.QueryInterface.showIndex(this.getTableName(options), options))
.then(indexes => {
indexes = this._indexes.filter(item1 =>
!indexes.some(item2 => item1.name === item2.name)
).sort((index1, index2) => {
if (this.sequelize.options.dialect === 'postgres') {
// move concurrent indexes to the bottom to avoid weird deadlocks
if (index1.concurrently === true) return 1;
if (index2.concurrently === true) return -1;
}
await this.QueryInterface.changeColumn(this.getTableName(options), columnName, currentAttribute);
}
}
}
let indexes = await this.QueryInterface.showIndex(this.getTableName(options), options);
indexes = this._indexes.filter(item1 =>
!indexes.some(item2 => item1.name === item2.name)
).sort((index1, index2) => {
if (this.sequelize.options.dialect === 'postgres') {
// move concurrent indexes to the bottom to avoid weird deadlocks
if (index1.concurrently === true) return 1;
if (index2.concurrently === true) return -1;
}
return 0;
});
return 0;
});
return Promise.each(indexes, index => this.QueryInterface.addIndex(
this.getTableName(options),
Object.assign({
logging: options.logging,
benchmark: options.benchmark,
transaction: options.transaction,
schema: options.schema
}, index),
this.tableName
));
}).then(() => {
if (options.hooks) {
return this.runHooks('afterSync', options);
}
}).then(() => this);
for (const index of indexes) {
await this.QueryInterface.addIndex(
this.getTableName(options),
Object.assign({
logging: options.logging,
benchmark: options.benchmark,
transaction: options.transaction,
schema: options.schema
}, index),
this.tableName
);
}
if (options.hooks) {
await this.runHooks('afterSync', options);
}
return this;
}
/**
......@@ -2341,7 +2334,8 @@ class Model {
}
return [instance, true];
}).catch(sequelizeErrors.UniqueConstraintError, err => {
}).catch(err => {
if (!(err instanceof sequelizeErrors.UniqueConstraintError)) throw err;
const flattenedWhere = Utils.flattenObjectDeep(options.where);
const flattenedWhereKeys = Object.keys(flattenedWhere).map(name => _.last(name.split('.')));
const whereFields = flattenedWhereKeys.map(name => _.get(this.rawAttributes, `${name}.field`, name));
......@@ -2413,7 +2407,10 @@ class Model {
return this.create(values, options)
.then(result => [result, true])
.catch(sequelizeErrors.UniqueConstraintError, () => this.findOne(options).then(result => [result, false]));
.catch(err => {
if (!(err instanceof sequelizeErrors.UniqueConstraintError)) throw err;
return this.findOne(options).then(result => [result, false]);
});
});
}
......
......@@ -289,48 +289,46 @@ class QueryInterface {
*
* @returns {Promise}
*/
dropAllTables(options) {
async dropAllTables(options) {
options = options || {};
const skip = options.skip || [];
const dropAllTables = tableNames => Promise.each(tableNames, tableName => {
// if tableName is not in the Array of tables names then don't drop it
if (!skip.includes(tableName.tableName || tableName)) {
return this.dropTable(tableName, Object.assign({}, options, { cascade: true }) );
}
});
return this.showAllTables(options).then(tableNames => {
if (this.sequelize.options.dialect === 'sqlite') {
return this.sequelize.query('PRAGMA foreign_keys;', options).then(result => {
const foreignKeysAreEnabled = result.foreign_keys === 1;
const dropAllTables = async tableNames => {
for (const tableName of tableNames) {
// if tableName is not in the Array of tables names then don't drop it
if (!skip.includes(tableName.tableName || tableName)) {
await this.dropTable(tableName, Object.assign({}, options, { cascade: true }) );
}
}
};
if (foreignKeysAreEnabled) {
return this.sequelize.query('PRAGMA foreign_keys = OFF', options)
.then(() => dropAllTables(tableNames))
.then(() => this.sequelize.query('PRAGMA foreign_keys = ON', options));
}
return dropAllTables(tableNames);
});
const tableNames = await this.showAllTables(options);
if (this.sequelize.options.dialect === 'sqlite') {
const result = await this.sequelize.query('PRAGMA foreign_keys;', options);
const foreignKeysAreEnabled = result.foreign_keys === 1;
if (foreignKeysAreEnabled) {
await this.sequelize.query('PRAGMA foreign_keys = OFF', options);
await dropAllTables(tableNames);
await this.sequelize.query('PRAGMA foreign_keys = ON', options);
} else {
await dropAllTables(tableNames);
}
return this.getForeignKeysForTables(tableNames, options).then(foreignKeys => {
const queries = [];
tableNames.forEach(tableName => {
let normalizedTableName = tableName;
if (_.isObject(tableName)) {
normalizedTableName = `${tableName.schema}.${tableName.tableName}`;
}
} else {
const foreignKeys = await this.getForeignKeysForTables(tableNames, options);
foreignKeys[normalizedTableName].forEach(foreignKey => {
queries.push(this.QueryGenerator.dropForeignKeyQuery(tableName, foreignKey));
});
});
for (const tableName of tableNames) {
let normalizedTableName = tableName;
if (_.isObject(tableName)) {
normalizedTableName = `${tableName.schema}.${tableName.tableName}`;
}
return Promise.each(queries, q => this.sequelize.query(q, options))
.then(() => dropAllTables(tableNames));
});
});
for (const foreignKey of foreignKeys[normalizedTableName]) {
await this.sequelize.query(this.QueryGenerator.dropForeignKeyQuery(tableName, foreignKey));
}
}
await dropAllTables(tableNames);
}
}
/**
......@@ -485,7 +483,7 @@ class QueryInterface {
return data;
}).catch(e => {
if (e.original && e.original.code === 'ER_NO_SUCH_TABLE') {
throw Error(`No description found for "${tableName}" table. Check the table name and schema; remember, they _are_ case sensitive.`);
throw new Error(`No description found for "${tableName}" table. Check the table name and schema; remember, they _are_ case sensitive.`);
}
throw e;
......@@ -1056,7 +1054,7 @@ class QueryInterface {
return this.sequelize.query(sql, options);
}
delete(instance, tableName, identifier, options) {
async delete(instance, tableName, identifier, options) {
const cascades = [];
const sql = this.QueryGenerator.deleteQuery(tableName, identifier, {}, instance.constructor);
......@@ -1078,21 +1076,15 @@ class QueryInterface {
}
}
return Promise.each(cascades, cascade => {
return instance[cascade](options).then(instances => {
// Check for hasOne relationship with non-existing associate ("has zero")
if (!instances) {
return Promise.resolve();
}
if (!Array.isArray(instances)) instances = [instances];
return Promise.each(instances, instance => instance.destroy(options));
});
}).then(() => {
options.instance = instance;
return this.sequelize.query(sql, options);
});
for (const cascade of cascades) {
let instances = await instance[cascade](options);
// Check for hasOne relationship with non-existing associate ("has zero")
if (!instances) continue;
if (!Array.isArray(instances)) instances = [instances];
for (const instance of instances) await instance.destroy(options);
}
options.instance = instance;
return await this.sequelize.query(sql, options);
}
/**
......
......@@ -786,47 +786,45 @@ class Sequelize {
*
* @returns {Promise}
*/
sync(options) {
async sync(options) {
options = _.clone(options) || {};
options.hooks = options.hooks === undefined ? true : !!options.hooks;
options = _.defaults(options, this.options.sync, this.options);
if (options.match) {
if (!options.match.test(this.config.database)) {
return Promise.reject(new Error(`Database "${this.config.database}" does not match sync match parameter "${options.match}"`));
throw new Error(`Database "${this.config.database}" does not match sync match parameter "${options.match}"`);
}
}
return Promise.resolve().then(() => {
if (options.hooks) {
return this.runHooks('beforeBulkSync', options);
}
}).then(() => {
if (options.force) {
return this.drop(options);
}
}).then(() => {
const models = [];
// Topologically sort by foreign key constraints to give us an appropriate
// creation order
this.modelManager.forEachModel(model => {
if (model) {
models.push(model);
} else {
// DB should throw an SQL error if referencing non-existent table
}
});
// no models defined, just authenticate
if (!models.length) return this.authenticate(options);
if (options.hooks) {
await this.runHooks('beforeBulkSync', options);
}
if (options.force) {
await this.drop(options);
}
const models = [];
return Promise.each(models, model => model.sync(options));
}).then(() => {
if (options.hooks) {
return this.runHooks('afterBulkSync', options);
// Topologically sort by foreign key constraints to give us an appropriate
// creation order
this.modelManager.forEachModel(model => {
if (model) {
models.push(model);
} else {
// DB should throw an SQL error if referencing non-existent table
}
}).then(() => this);
});
// no models defined, just authenticate
if (!models.length) {
await this.authenticate(options);
} else {
for (const model of models) await model.sync(options);
}
if (options.hooks) {
await this.runHooks('afterBulkSync', options);
}
return this;
}
/**
......@@ -840,7 +838,7 @@ class Sequelize {
* @see
* {@link Model.truncate} for more information
*/
truncate(options) {
async truncate(options) {
const models = [];
this.modelManager.forEachModel(model => {
......@@ -849,12 +847,11 @@ class Sequelize {
}
}, { reverse: false });
const truncateModel = model => model.truncate(options);
if (options && options.cascade) {
return Promise.each(models, truncateModel);
for (const model of models) model.truncate(options);
} else {
await Promise.all(models.map(model => model.truncate(options)));
}
return Promise.all(models.map(truncateModel));
}
/**
......@@ -869,7 +866,7 @@ class Sequelize {
*
* @returns {Promise}
*/
drop(options) {
async drop(options) {
const models = [];
this.modelManager.forEachModel(model => {
......@@ -878,7 +875,7 @@ class Sequelize {
}
}, { reverse: false });
return Promise.each(models, model => model.drop(options));
for (const model of models) await model.drop(options);
}
/**
......
......@@ -52,28 +52,24 @@ class Transaction {
*
* @returns {Promise}
*/
commit() {
async commit() {
if (this.finished) {
return Promise.reject(new Error(`Transaction cannot be committed because it has been finished with state: ${this.finished}`));
throw new Error(`Transaction cannot be committed because it has been finished with state: ${this.finished}`);
}
this._clearCls();
return this
.sequelize
.getQueryInterface()
.commitTransaction(this, this.options)
.finally(() => {
this.finished = 'commit';
if (!this.parent) {
return this.cleanup();
}
return null;
}).then(
result => Promise.resolve(Promise.each(
this._afterCommitHooks,
hook => Promise.resolve(hook.apply(this, [this])))).then(() => result)
);
try {
return await this.sequelize.getQueryInterface().commitTransaction(this, this.options);
} finally {
this.finished = 'commit';
if (!this.parent) {
await this.cleanup();
}
for (const hook of this._afterCommitHooks) {
await hook.apply(this, [this]);
}
}
}
/**
......
......@@ -1300,7 +1300,8 @@ describe(Support.getTestDialectTeaser('HasMany'), () => {
ctx.task = task;
return user.setTasks([task]);
}).then(() => {
return ctx.user.destroy().catch(Sequelize.ForeignKeyConstraintError, () => {
return ctx.user.destroy().catch(err => {
if (!(err instanceof Sequelize.ForeignKeyConstraintError)) throw err;
// Should fail due to FK violation
return Task.findAll();
});
......@@ -1329,8 +1330,9 @@ describe(Support.getTestDialectTeaser('HasMany'), () => {
const tableName = user.sequelize.getQueryInterface().QueryGenerator.addSchema(user.constructor);
return user.sequelize.getQueryInterface().update(user, tableName, { id: 999 }, { id: user.id })
.catch(Sequelize.ForeignKeyConstraintError, () => {
// Should fail due to FK violation
.catch(err => {
if (!(err instanceof Sequelize.ForeignKeyConstraintError)) throw err;
// Should fail due to FK violation
return Task.findAll();
});
}).then(tasks => {
......@@ -1362,21 +1364,20 @@ describe(Support.getTestDialectTeaser('HasMany'), () => {
expect(Account.rawAttributes.UserId.field).to.equal('UserId');
});
it('can specify data type for auto-generated relational keys', function() {
it('can specify data type for auto-generated relational keys', async function() {
const User = this.sequelize.define('UserXYZ', { username: DataTypes.STRING }),
dataTypes = [Sequelize.INTEGER, Sequelize.BIGINT, Sequelize.STRING],
Tasks = {};
return Promise.each(dataTypes, dataType => {
for (const dataType of dataTypes) {
const tableName = `TaskXYZ_${dataType.key}`;
Tasks[dataType] = this.sequelize.define(tableName, { title: DataTypes.STRING });
User.hasMany(Tasks[dataType], { foreignKey: 'userId', keyType: dataType, constraints: false });
return Tasks[dataType].sync({ force: true }).then(() => {
expect(Tasks[dataType].rawAttributes.userId.type).to.be.an.instanceof(dataType);
});
});
await Tasks[dataType].sync({ force: true });
expect(Tasks[dataType].rawAttributes.userId.type).to.be.an.instanceof(dataType);
}
});
it('infers the keyType if none provided', function() {
......
......@@ -272,29 +272,25 @@ describe(Support.getTestDialectTeaser('associations'), () => {
expect(logs[0]).to.equal(logs[1]);
});
});
it('should created included association with scope values', function() {
return this.sequelize.sync({ force: true }).then(() => {
return this.Post.create({
comments: [{
title: 'I am a comment created with a post'
}, {
title: 'I am a second comment created with a post'
}]
it('should created included association with scope values', async function() {
await this.sequelize.sync({ force: true });
let post = await this.Post.create({
comments: [{
title: 'I am a comment created with a post'
}, {
include: [{ model: this.Comment, as: 'comments' }]
});
}).then(post => {
this.post = post;
return post.comments;
}).each(comment => {
title: 'I am a second comment created with a post'
}]
}, {
include: [{ model: this.Comment, as: 'comments' }]
});
this.post = post;
for (const comment of post.comments) {
expect(comment.get('commentable')).to.equal('post');
}).then(() => {
return this.Post.scope('withComments').findByPk(this.post.id);
}).then(post => {
return post.getComments();
}).each(comment => {
}
post = await this.Post.scope('withComments').findByPk(this.post.id);
for (const comment of post.comments) {
expect(comment.get('commentable')).to.equal('post');
});
}
});
it('should include associations with operator scope values', function() {
return this.sequelize.sync({ force: true }).then(() => {
......
......@@ -312,7 +312,10 @@ describe(Support.getTestDialectTeaser('Sequelize Errors'), () => {
return this.sequelize.sync({ force: true }).then(() => {
return User.create(record);
}).then(() => {
return User.create(record).catch(constraintTest.exception, spy);
return User.create(record).catch(err => {
if (!(err instanceof constraintTest.exception)) throw err;
return spy(err);
});
}).then(() => {
expect(spy).to.have.been.calledOnce;
});
......@@ -333,7 +336,10 @@ describe(Support.getTestDialectTeaser('Sequelize Errors'), () => {
return User.create({ name: 'jan' });
}).then(() => {
// If the error was successfully parsed, we can catch it!
return User.create({ name: 'jan' }).catch(Sequelize.UniqueConstraintError, spy);
return User.create({ name: 'jan' }).catch(err => {
if (!(err instanceof Sequelize.UniqueConstraintError)) throw err;
return spy(err);
});
}).then(() => {
expect(spy).to.have.been.calledOnce;
});
......
......@@ -287,7 +287,8 @@ describe(Support.getTestDialectTeaser('Model'), () => {
await Sequelize.Promise.all([
User.create({ username: 'tobi', email: 'tobi@tobi.me' }),
User.create({ username: 'tobi', email: 'tobi@tobi.me' })
]).catch(Sequelize.UniqueConstraintError, err => {
]).catch(err => {
if (!(err instanceof Sequelize.UniqueConstraintError)) throw err;
expect(err.message).to.equal('User and email must be unique');
});
});
......@@ -321,7 +322,8 @@ describe(Support.getTestDialectTeaser('Model'), () => {
await Sequelize.Promise.all([
User.create({ user_id: 1, email: 'tobi@tobi.me' }),
User.create({ user_id: 1, email: 'tobi@tobi.me' })
]).catch(Sequelize.UniqueConstraintError, err => {
]).catch(err => {
if (!(err instanceof Sequelize.UniqueConstraintError)) throw err;
expect(err.message).to.equal('User and email must be unique');
});
});
......
......@@ -417,10 +417,12 @@ describe(Support.getTestDialectTeaser('Model'), () => {
}
})
.timeout(1000)
.catch(Promise.TimeoutError, e => {
.catch(e => {
if (!(e instanceof Promise.TimeoutError)) throw e;
throw new Error(e);
})
.catch(Sequelize.ValidationError, () => {
.catch(err => {
if (!(err instanceof Sequelize.ValidationError)) throw err;
return test(times + 1);
});
};
......@@ -1003,7 +1005,8 @@ describe(Support.getTestDialectTeaser('Model'), () => {
return User.sync({ force: true }).then(() => {
return User.create({ username: 'foo' }).then(() => {
return User.create({ username: 'foo' }).catch(Sequelize.UniqueConstraintError, err => {
return User.create({ username: 'foo' }).catch(err => {
if (!(err instanceof Sequelize.UniqueConstraintError)) throw err;
expect(err).to.be.ok;
});
});
......@@ -1020,7 +1023,8 @@ describe(Support.getTestDialectTeaser('Model'), () => {
return User.create({ username: 'foo' });
}).then(() => {
return User.create({ username: 'fOO' });
}).catch(Sequelize.UniqueConstraintError, err => {
}).catch(err => {
if (!(err instanceof Sequelize.UniqueConstraintError)) throw err;
expect(err).to.be.ok;
});
});
......@@ -1040,7 +1044,8 @@ describe(Support.getTestDialectTeaser('Model'), () => {
return User.create({ username: 'foo' });
}).then(() => {
return User.create({ username: 'foo' });
}).catch(Sequelize.UniqueConstraintError, err => {
}).catch(err => {
if (!(err instanceof Sequelize.UniqueConstraintError)) throw err;
expect(err).to.be.ok;
});
});
......@@ -1075,7 +1080,8 @@ describe(Support.getTestDialectTeaser('Model'), () => {
return UserNull.sync({ force: true }).then(() => {
return UserNull.create({ username: 'foo', smth: 'foo' }).then(() => {
return UserNull.create({ username: 'foo', smth: 'bar' }).catch(Sequelize.UniqueConstraintError, err => {
return UserNull.create({ username: 'foo', smth: 'bar' }).catch(err => {
if (!(err instanceof Sequelize.UniqueConstraintError)) throw err;
expect(err).to.be.ok;
});
});
......
......@@ -45,7 +45,8 @@ describe(Support.getTestDialectTeaser('Model'), () => {
.then(() => {
expect.fail('expected to fail');
})
.catch(/abort/, () => {
.catch(err => {
if (!/abort/.test(err.message)) throw err;
expect(this.clsStub.calledOnce).to.equal(true, 'expected to ask for transaction');
});
......@@ -63,7 +64,8 @@ describe(Support.getTestDialectTeaser('Model'), () => {
.then(() => {
expect.fail('expected to fail');
})
.catch(/abort/, () => {
.catch(err => {
if (!/abort/.test(err.message)) throw err;
expect(this.clsStub.called).to.equal(false);
});
});
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!