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

Commit f1d08764 by Andy Edwards Committed by GitHub

refactor(query-interface): asyncify methods (#12126)

1 parent 39c35012
......@@ -37,10 +37,10 @@ class QueryInterface {
*
* @returns {Promise}
*/
createDatabase(database, options) {
async createDatabase(database, options) {
options = options || {};
const sql = this.QueryGenerator.createDatabaseQuery(database, options);
return this.sequelize.query(sql, options);
return await this.sequelize.query(sql, options);
}
/**
......@@ -51,10 +51,10 @@ class QueryInterface {
*
* @returns {Promise}
*/
dropDatabase(database, options) {
async dropDatabase(database, options) {
options = options || {};
const sql = this.QueryGenerator.dropDatabaseQuery(database);
return this.sequelize.query(sql, options);
return await this.sequelize.query(sql, options);
}
/**
......@@ -65,10 +65,10 @@ class QueryInterface {
*
* @returns {Promise}
*/
createSchema(schema, options) {
async createSchema(schema, options) {
options = options || {};
const sql = this.QueryGenerator.createSchema(schema);
return this.sequelize.query(sql, options);
return await this.sequelize.query(sql, options);
}
/**
......@@ -79,10 +79,10 @@ class QueryInterface {
*
* @returns {Promise}
*/
dropSchema(schema, options) {
async dropSchema(schema, options) {
options = options || {};
const sql = this.QueryGenerator.dropSchema(schema);
return this.sequelize.query(sql, options);
return await this.sequelize.query(sql, options);
}
/**
......@@ -92,15 +92,14 @@ class QueryInterface {
*
* @returns {Promise}
*/
dropAllSchemas(options) {
async dropAllSchemas(options) {
options = options || {};
if (!this.QueryGenerator._dialect.supports.schemas) {
return this.sequelize.drop(options);
}
return this.showAllSchemas(options).then(schemas => Promise.all(
schemas.map(schemaName => this.dropSchema(schemaName, options))
));
const schemas = await this.showAllSchemas(options);
return Promise.all(schemas.map(schemaName => this.dropSchema(schemaName, options)));
}
/**
......@@ -110,7 +109,7 @@ class QueryInterface {
*
* @returns {Promise<Array>}
*/
showAllSchemas(options) {
async showAllSchemas(options) {
options = Object.assign({}, options, {
raw: true,
type: this.sequelize.QueryTypes.SELECT
......@@ -118,9 +117,9 @@ class QueryInterface {
const showSchemasSql = this.QueryGenerator.showSchemasQuery(options);
return this.sequelize.query(showSchemasSql, options).then(schemaNames => _.flatten(
schemaNames.map(value => value.schema_name ? value.schema_name : value)
));
const schemaNames = await this.sequelize.query(showSchemasSql, options);
return _.flatten(schemaNames.map(value => value.schema_name ? value.schema_name : value));
}
/**
......@@ -132,8 +131,8 @@ class QueryInterface {
* @returns {Promise}
* @private
*/
databaseVersion(options) {
return this.sequelize.query(
async databaseVersion(options) {
return await this.sequelize.query(
this.QueryGenerator.versionQuery(),
Object.assign({}, options, { type: QueryTypes.VERSION })
);
......@@ -192,9 +191,8 @@ class QueryInterface {
*
* @returns {Promise}
*/
createTable(tableName, attributes, options, model) {
async createTable(tableName, attributes, options, model) {
let sql = '';
let promise;
options = _.clone(options) || {};
......@@ -217,9 +215,7 @@ class QueryInterface {
// Postgres requires special SQL commands for ENUM/ENUM[]
if (this.sequelize.options.dialect === 'postgres') {
promise = PostgresQueryInterface.ensureEnums(this, tableName, attributes, options, model);
} else {
promise = Promise.resolve();
await PostgresQueryInterface.ensureEnums(this, tableName, attributes, options, model);
}
if (
......@@ -235,7 +231,7 @@ class QueryInterface {
attributes = this.QueryGenerator.attributesToSQL(attributes, { table: tableName, context: 'createTable' });
sql = this.QueryGenerator.createTableQuery(tableName, attributes, options);
return promise.then(() => this.sequelize.query(sql, options));
return await this.sequelize.query(sql, options);
}
/**
......@@ -246,39 +242,40 @@ class QueryInterface {
*
* @returns {Promise}
*/
dropTable(tableName, options) {
async dropTable(tableName, options) {
// if we're forcing we should be cascading unless explicitly stated otherwise
options = _.clone(options) || {};
options.cascade = options.cascade || options.force || false;
let sql = this.QueryGenerator.dropTableQuery(tableName, options);
return this.sequelize.query(sql, options).then(() => {
const promises = [];
await this.sequelize.query(sql, options);
const promises = [];
// Since postgres has a special case for enums, we should drop the related
// enum type within the table and attribute
if (this.sequelize.options.dialect === 'postgres') {
const instanceTable = this.sequelize.modelManager.getModel(tableName, { attribute: 'tableName' });
// Since postgres has a special case for enums, we should drop the related
// enum type within the table and attribute
if (this.sequelize.options.dialect === 'postgres') {
const instanceTable = this.sequelize.modelManager.getModel(tableName, { attribute: 'tableName' });
if (instanceTable) {
const getTableName = (!options || !options.schema || options.schema === 'public' ? '' : `${options.schema}_`) + tableName;
if (instanceTable) {
const getTableName = (!options || !options.schema || options.schema === 'public' ? '' : `${options.schema}_`) + tableName;
const keys = Object.keys(instanceTable.rawAttributes);
const keyLen = keys.length;
const keys = Object.keys(instanceTable.rawAttributes);
const keyLen = keys.length;
for (let i = 0; i < keyLen; i++) {
if (instanceTable.rawAttributes[keys[i]].type instanceof DataTypes.ENUM) {
sql = this.QueryGenerator.pgEnumDrop(getTableName, keys[i]);
options.supportsSearchPath = false;
promises.push(this.sequelize.query(sql, Object.assign({}, options, { raw: true })));
}
for (let i = 0; i < keyLen; i++) {
if (instanceTable.rawAttributes[keys[i]].type instanceof DataTypes.ENUM) {
sql = this.QueryGenerator.pgEnumDrop(getTableName, keys[i]);
options.supportsSearchPath = false;
promises.push(this.sequelize.query(sql, Object.assign({}, options, { raw: true })));
}
}
}
}
return Promise.all(promises).then(obj => obj[0]);
});
const obj = await Promise.all(promises);
return obj[0];
}
/**
......@@ -340,9 +337,9 @@ class QueryInterface {
* @returns {Promise}
* @private
*/
dropEnum(enumName, options) {
async dropEnum(enumName, options) {
if (this.sequelize.getDialect() !== 'postgres') {
return Promise.resolve();
return;
}
options = options || {};
......@@ -361,19 +358,19 @@ class QueryInterface {
* @returns {Promise}
* @private
*/
dropAllEnums(options) {
async dropAllEnums(options) {
if (this.sequelize.getDialect() !== 'postgres') {
return Promise.resolve();
return;
}
options = options || {};
return this.pgListEnums(null, options).then(enums => Promise.all(
enums.map(result => this.sequelize.query(
this.QueryGenerator.pgEnumDrop(null, null, this.QueryGenerator.pgEscapeAndQuote(result.enum_name)),
Object.assign({}, options, { raw: true })
))
));
const enums = await this.pgListEnums(null, options);
return await Promise.all(enums.map(result => this.sequelize.query(
this.QueryGenerator.pgEnumDrop(null, null, this.QueryGenerator.pgEscapeAndQuote(result.enum_name)),
Object.assign({}, options, { raw: true })
)));
}
/**
......@@ -400,10 +397,10 @@ class QueryInterface {
*
* @returns {Promise}
*/
renameTable(before, after, options) {
async renameTable(before, after, options) {
options = options || {};
const sql = this.QueryGenerator.renameTableQuery(before, after);
return this.sequelize.query(sql, options);
return await this.sequelize.query(sql, options);
}
/**
......@@ -416,14 +413,15 @@ class QueryInterface {
* @returns {Promise<Array>}
* @private
*/
showAllTables(options) {
async showAllTables(options) {
options = Object.assign({}, options, {
raw: true,
type: QueryTypes.SHOWTABLES
});
const showTablesSql = this.QueryGenerator.showTablesQuery(this.sequelize.config.database);
return this.sequelize.query(showTablesSql, options).then(tableNames => _.flatten(tableNames));
const tableNames = await this.sequelize.query(showTablesSql, options);
return _.flatten(tableNames);
}
/**
......@@ -451,7 +449,7 @@ class QueryInterface {
*
* @returns {Promise<object>}
*/
describeTable(tableName, options) {
async describeTable(tableName, options) {
let schema = null;
let schemaDelimiter = null;
......@@ -470,7 +468,8 @@ class QueryInterface {
const sql = this.QueryGenerator.describeTableQuery(tableName, schema, schemaDelimiter);
options = Object.assign({}, options, { type: QueryTypes.DESCRIBE });
return this.sequelize.query(sql, options).then(data => {
try {
const data = await this.sequelize.query(sql, options);
/*
* If no data is returned from the query, then the table name may be wrong.
* Query generators that use information_schema for retrieving table info will just return an empty result set,
......@@ -481,13 +480,13 @@ class QueryInterface {
}
return data;
}).catch(e => {
} catch (e) {
if (e.original && e.original.code === 'ER_NO_SUCH_TABLE') {
throw new Error(`No description found for "${tableName}" table. Check the table name and schema; remember, they _are_ case sensitive.`);
}
throw e;
});
}
}
/**
......@@ -506,14 +505,14 @@ class QueryInterface {
*
* @returns {Promise}
*/
addColumn(table, key, attribute, options) {
async addColumn(table, key, attribute, options) {
if (!table || !key || !attribute) {
throw new Error('addColumn takes at least 3 arguments (table, attribute name, attribute definition)');
}
options = options || {};
attribute = this.sequelize.normalizeAttribute(attribute);
return this.sequelize.query(this.QueryGenerator.addColumnQuery(table, key, attribute), options);
return await this.sequelize.query(this.QueryGenerator.addColumnQuery(table, key, attribute), options);
}
/**
......@@ -525,21 +524,21 @@ class QueryInterface {
*
* @returns {Promise}
*/
removeColumn(tableName, attributeName, options) {
async removeColumn(tableName, attributeName, options) {
options = options || {};
switch (this.sequelize.options.dialect) {
case 'sqlite':
// sqlite needs some special treatment as it cannot drop a column
return SQLiteQueryInterface.removeColumn(this, tableName, attributeName, options);
return await SQLiteQueryInterface.removeColumn(this, tableName, attributeName, options);
case 'mssql':
// mssql needs special treatment as it cannot drop a column with a default or foreign key constraint
return MSSQLQueryInterface.removeColumn(this, tableName, attributeName, options);
return await MSSQLQueryInterface.removeColumn(this, tableName, attributeName, options);
case 'mysql':
case 'mariadb':
// mysql/mariadb need special treatment as it cannot drop a column with a foreign key constraint
return MySQLQueryInterface.removeColumn(this, tableName, attributeName, options);
return await MySQLQueryInterface.removeColumn(this, tableName, attributeName, options);
default:
return this.sequelize.query(this.QueryGenerator.removeColumnQuery(tableName, attributeName), options);
return await this.sequelize.query(this.QueryGenerator.removeColumnQuery(tableName, attributeName), options);
}
}
......@@ -553,7 +552,7 @@ class QueryInterface {
*
* @returns {Promise}
*/
changeColumn(tableName, attributeName, dataTypeOrOptions, options) {
async changeColumn(tableName, attributeName, dataTypeOrOptions, options) {
const attributes = {};
options = options || {};
......@@ -575,7 +574,7 @@ class QueryInterface {
});
const sql = this.QueryGenerator.changeColumnQuery(tableName, query);
return this.sequelize.query(sql, options);
return await this.sequelize.query(sql, options);
}
/**
......@@ -588,40 +587,39 @@ class QueryInterface {
*
* @returns {Promise}
*/
renameColumn(tableName, attrNameBefore, attrNameAfter, options) {
async renameColumn(tableName, attrNameBefore, attrNameAfter, options) {
options = options || {};
return this.describeTable(tableName, options).then(data => {
if (!data[attrNameBefore]) {
throw new Error(`Table ${tableName} doesn't have the column ${attrNameBefore}`);
}
let data = await this.describeTable(tableName, options);
if (!data[attrNameBefore]) {
throw new Error(`Table ${tableName} doesn't have the column ${attrNameBefore}`);
}
data = data[attrNameBefore] || {};
data = data[attrNameBefore] || {};
const _options = {};
const _options = {};
_options[attrNameAfter] = {
attribute: attrNameAfter,
type: data.type,
allowNull: data.allowNull,
defaultValue: data.defaultValue
};
_options[attrNameAfter] = {
attribute: attrNameAfter,
type: data.type,
allowNull: data.allowNull,
defaultValue: data.defaultValue
};
// fix: a not-null column cannot have null as default value
if (data.defaultValue === null && !data.allowNull) {
delete _options[attrNameAfter].defaultValue;
}
// fix: a not-null column cannot have null as default value
if (data.defaultValue === null && !data.allowNull) {
delete _options[attrNameAfter].defaultValue;
}
if (this.sequelize.options.dialect === 'sqlite') {
// sqlite needs some special treatment as it cannot rename a column
return SQLiteQueryInterface.renameColumn(this, tableName, attrNameBefore, attrNameAfter, options);
}
const sql = this.QueryGenerator.renameColumnQuery(
tableName,
attrNameBefore,
this.QueryGenerator.attributesToSQL(_options)
);
return this.sequelize.query(sql, options);
});
if (this.sequelize.options.dialect === 'sqlite') {
// sqlite needs some special treatment as it cannot rename a column
return SQLiteQueryInterface.renameColumn(this, tableName, attrNameBefore, attrNameAfter, options);
}
const sql = this.QueryGenerator.renameColumnQuery(
tableName,
attrNameBefore,
this.QueryGenerator.attributesToSQL(_options)
);
return await this.sequelize.query(sql, options);
}
/**
......@@ -642,7 +640,7 @@ class QueryInterface {
*
* @returns {Promise}
*/
addIndex(tableName, attributes, options, rawTablename) {
async addIndex(tableName, attributes, options, rawTablename) {
// Support for passing tableName, attributes, options or tableName, options (with a fields param which is the attributes)
if (!Array.isArray(attributes)) {
rawTablename = options;
......@@ -658,7 +656,7 @@ class QueryInterface {
options = Utils.cloneDeep(options);
options.fields = attributes;
const sql = this.QueryGenerator.addIndexQuery(tableName, options, rawTablename);
return this.sequelize.query(sql, Object.assign({}, options, { supportsSearchPath: false }));
return await this.sequelize.query(sql, Object.assign({}, options, { supportsSearchPath: false }));
}
/**
......@@ -670,9 +668,9 @@ class QueryInterface {
* @returns {Promise<Array>}
* @private
*/
showIndex(tableName, options) {
async showIndex(tableName, options) {
const sql = this.QueryGenerator.showIndexesQuery(tableName, options);
return this.sequelize.query(sql, Object.assign({}, options, { type: QueryTypes.SHOWINDEXES }));
return await this.sequelize.query(sql, Object.assign({}, options, { type: QueryTypes.SHOWINDEXES }));
}
......@@ -684,31 +682,31 @@ class QueryInterface {
*
* @returns {Promise}
*/
getForeignKeysForTables(tableNames, options) {
async getForeignKeysForTables(tableNames, options) {
if (tableNames.length === 0) {
return Promise.resolve({});
return {};
}
options = Object.assign({}, options || {}, { type: QueryTypes.FOREIGNKEYS });
return Promise.all(tableNames.map(tableName =>
this.sequelize.query(this.QueryGenerator.getForeignKeysQuery(tableName, this.sequelize.config.database), options))).then(results => {
const result = {};
const results = await Promise.all(tableNames.map(tableName =>
this.sequelize.query(this.QueryGenerator.getForeignKeysQuery(tableName, this.sequelize.config.database), options)));
tableNames.forEach((tableName, i) => {
if (_.isObject(tableName)) {
tableName = `${tableName.schema}.${tableName.tableName}`;
}
const result = {};
result[tableName] = Array.isArray(results[i])
? results[i].map(r => r.constraint_name)
: [results[i] && results[i].constraint_name];
tableNames.forEach((tableName, i) => {
if (_.isObject(tableName)) {
tableName = `${tableName.schema}.${tableName.tableName}`;
}
result[tableName] = result[tableName].filter(_.identity);
});
result[tableName] = Array.isArray(results[i])
? results[i].map(r => r.constraint_name)
: [results[i] && results[i].constraint_name];
return result;
result[tableName] = result[tableName].filter(_.identity);
});
return result;
}
/**
......@@ -724,7 +722,7 @@ class QueryInterface {
*
* @returns {Promise}
*/
getForeignKeyReferencesForTable(tableName, options) {
async getForeignKeyReferencesForTable(tableName, options) {
const queryOptions = Object.assign({}, options, {
type: QueryTypes.FOREIGNKEYS
});
......@@ -732,21 +730,21 @@ class QueryInterface {
switch (this.sequelize.options.dialect) {
case 'sqlite':
// sqlite needs some special treatment.
return SQLiteQueryInterface.getForeignKeyReferencesForTable(this, tableName, queryOptions);
return await SQLiteQueryInterface.getForeignKeyReferencesForTable(this, tableName, queryOptions);
case 'postgres':
{
// postgres needs some special treatment as those field names returned are all lowercase
// in order to keep same result with other dialects.
const query = this.QueryGenerator.getForeignKeyReferencesQuery(tableName, catalogName);
return this.sequelize.query(query, queryOptions)
.then(result => result.map(Utils.camelizeObjectKeys));
const result = await this.sequelize.query(query, queryOptions);
return result.map(Utils.camelizeObjectKeys);
}
case 'mssql':
case 'mysql':
case 'mariadb':
default: {
const query = this.QueryGenerator.getForeignKeysQuery(tableName, catalogName);
return this.sequelize.query(query, queryOptions);
return await this.sequelize.query(query, queryOptions);
}
}
}
......@@ -760,10 +758,10 @@ class QueryInterface {
*
* @returns {Promise}
*/
removeIndex(tableName, indexNameOrAttributes, options) {
async removeIndex(tableName, indexNameOrAttributes, options) {
options = options || {};
const sql = this.QueryGenerator.removeIndexQuery(tableName, indexNameOrAttributes);
return this.sequelize.query(sql, options);
return await this.sequelize.query(sql, options);
}
/**
......@@ -828,7 +826,7 @@ class QueryInterface {
*
* @returns {Promise}
*/
addConstraint(tableName, attributes, options, rawTablename) {
async addConstraint(tableName, attributes, options, rawTablename) {
if (!Array.isArray(attributes)) {
rawTablename = options;
options = attributes;
......@@ -848,15 +846,15 @@ class QueryInterface {
options.fields = attributes;
if (this.sequelize.dialect.name === 'sqlite') {
return SQLiteQueryInterface.addConstraint(this, tableName, options, rawTablename);
return await SQLiteQueryInterface.addConstraint(this, tableName, options, rawTablename);
}
const sql = this.QueryGenerator.addConstraintQuery(tableName, options, rawTablename);
return this.sequelize.query(sql, options);
return await this.sequelize.query(sql, options);
}
showConstraint(tableName, constraintName, options) {
async showConstraint(tableName, constraintName, options) {
const sql = this.QueryGenerator.showConstraintsQuery(tableName, constraintName);
return this.sequelize.query(sql, Object.assign({}, options, { type: QueryTypes.SHOWCONSTRAINTS }));
return await this.sequelize.query(sql, Object.assign({}, options, { type: QueryTypes.SHOWCONSTRAINTS }));
}
/**
......@@ -868,23 +866,23 @@ class QueryInterface {
*
* @returns {Promise}
*/
removeConstraint(tableName, constraintName, options) {
async removeConstraint(tableName, constraintName, options) {
options = options || {};
switch (this.sequelize.options.dialect) {
case 'mysql':
case 'mariadb':
//does not support DROP CONSTRAINT. Instead DROP PRIMARY, FOREIGN KEY, INDEX should be used
return MySQLQueryInterface.removeConstraint(this, tableName, constraintName, options);
return await MySQLQueryInterface.removeConstraint(this, tableName, constraintName, options);
case 'sqlite':
return SQLiteQueryInterface.removeConstraint(this, tableName, constraintName, options);
return await SQLiteQueryInterface.removeConstraint(this, tableName, constraintName, options);
default:
const sql = this.QueryGenerator.removeConstraintQuery(tableName, constraintName);
return this.sequelize.query(sql, options);
return await this.sequelize.query(sql, options);
}
}
insert(instance, tableName, values, options) {
async insert(instance, tableName, values, options) {
options = Utils.cloneDeep(options);
options.hasTrigger = instance && instance.constructor.options.hasTrigger;
const sql = this.QueryGenerator.insertQuery(tableName, values, instance && instance.constructor.rawAttributes, options);
......@@ -892,10 +890,10 @@ class QueryInterface {
options.type = QueryTypes.INSERT;
options.instance = instance;
return this.sequelize.query(sql, options).then(results => {
if (instance) results[0].isNewRecord = false;
return results;
});
const results = await this.sequelize.query(sql, options);
if (instance) results[0].isNewRecord = false;
return results;
}
/**
......@@ -910,7 +908,7 @@ class QueryInterface {
*
* @returns {Promise<boolean,?number>} Resolves an array with <created, primaryKey>
*/
upsert(tableName, insertValues, updateValues, where, model, options) {
async upsert(tableName, insertValues, updateValues, where, model, options) {
const wheres = [];
const attributes = Object.keys(insertValues);
let indexes = [];
......@@ -956,27 +954,23 @@ class QueryInterface {
options.raw = true;
const sql = this.QueryGenerator.upsertQuery(tableName, insertValues, updateValues, where, model, options);
return this.sequelize.query(sql, options).then(result => {
switch (this.sequelize.options.dialect) {
case 'postgres':
return [result.created, result.primary_key];
case 'mssql':
return [
result.$action === 'INSERT',
result[model.primaryKeyField]
];
const result = await this.sequelize.query(sql, options);
switch (this.sequelize.options.dialect) {
case 'postgres':
return [result.created, result.primary_key];
case 'mssql':
return [
result.$action === 'INSERT',
result[model.primaryKeyField]
];
// MySQL returns 1 for inserted, 2 for updated
// http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html.
case 'mysql':
case 'mariadb':
return [result === 1, undefined];
default:
return [result, undefined];
}
});
case 'mysql':
case 'mariadb':
return [result === 1, undefined];
default:
return [result, undefined];
}
}
/**
......@@ -1000,17 +994,19 @@ class QueryInterface {
*
* @returns {Promise}
*/
bulkInsert(tableName, records, options, attributes) {
async bulkInsert(tableName, records, options, attributes) {
options = _.clone(options) || {};
options.type = QueryTypes.INSERT;
return this.sequelize.query(
const results = await this.sequelize.query(
this.QueryGenerator.bulkInsertQuery(tableName, records, options, attributes),
options
).then(results => results[0]);
);
return results[0];
}
update(instance, tableName, values, identifier, options) {
async update(instance, tableName, values, identifier, options) {
options = _.clone(options || {});
options.hasTrigger = !!(instance && instance._modelOptions && instance._modelOptions.hasTrigger);
......@@ -1019,7 +1015,7 @@ class QueryInterface {
options.type = QueryTypes.UPDATE;
options.instance = instance;
return this.sequelize.query(sql, options);
return await this.sequelize.query(sql, options);
}
/**
......@@ -1041,7 +1037,7 @@ class QueryInterface {
*
* @returns {Promise}
*/
bulkUpdate(tableName, values, identifier, options, attributes) {
async bulkUpdate(tableName, values, identifier, options, attributes) {
options = Utils.cloneDeep(options);
if (typeof identifier === 'object') identifier = Utils.cloneDeep(identifier);
......@@ -1051,7 +1047,7 @@ class QueryInterface {
options.type = QueryTypes.BULKUPDATE;
options.model = model;
return this.sequelize.query(sql, options);
return await this.sequelize.query(sql, options);
}
async delete(instance, tableName, identifier, options) {
......@@ -1081,7 +1077,7 @@ class QueryInterface {
// 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);
for (const _instance of instances) await _instance.destroy(options);
}
options.instance = instance;
return await this.sequelize.query(sql, options);
......@@ -1100,7 +1096,7 @@ class QueryInterface {
*
* @returns {Promise}
*/
bulkDelete(tableName, where, options, model) {
async bulkDelete(tableName, where, options, model) {
options = Utils.cloneDeep(options);
options = _.defaults(options, { limit: null });
......@@ -1113,22 +1109,22 @@ class QueryInterface {
if (typeof identifier === 'object') where = Utils.cloneDeep(where);
return this.sequelize.query(
return await this.sequelize.query(
this.QueryGenerator.deleteQuery(tableName, where, options, model),
options
);
}
select(model, tableName, optionsArg) {
async select(model, tableName, optionsArg) {
const options = Object.assign({}, optionsArg, { type: QueryTypes.SELECT, model });
return this.sequelize.query(
return await this.sequelize.query(
this.QueryGenerator.selectQuery(tableName, options, model),
options
);
}
increment(model, tableName, where, incrementAmountsByField, extraAttributesToBeUpdated, options) {
async increment(model, tableName, where, incrementAmountsByField, extraAttributesToBeUpdated, options) {
options = Utils.cloneDeep(options);
const sql = this.QueryGenerator.arithmeticQuery('+', tableName, where, incrementAmountsByField, extraAttributesToBeUpdated, options);
......@@ -1136,10 +1132,10 @@ class QueryInterface {
options.type = QueryTypes.UPDATE;
options.model = model;
return this.sequelize.query(sql, options);
return await this.sequelize.query(sql, options);
}
decrement(model, tableName, where, incrementAmountsByField, extraAttributesToBeUpdated, options) {
async decrement(model, tableName, where, incrementAmountsByField, extraAttributesToBeUpdated, options) {
options = Utils.cloneDeep(options);
const sql = this.QueryGenerator.arithmeticQuery('-', tableName, where, incrementAmountsByField, extraAttributesToBeUpdated, options);
......@@ -1147,10 +1143,10 @@ class QueryInterface {
options.type = QueryTypes.UPDATE;
options.model = model;
return this.sequelize.query(sql, options);
return await this.sequelize.query(sql, options);
}
rawSelect(tableName, options, attributeSelector, Model) {
async rawSelect(tableName, options, attributeSelector, Model) {
options = Utils.cloneDeep(options);
options = _.defaults(options, {
raw: true,
......@@ -1164,63 +1160,68 @@ class QueryInterface {
throw new Error('Please pass an attribute selector!');
}
return this.sequelize.query(sql, options).then(data => {
if (!options.plain) {
return data;
}
const data = await this.sequelize.query(sql, options);
if (!options.plain) {
return data;
}
const result = data ? data[attributeSelector] : null;
const result = data ? data[attributeSelector] : null;
if (!options || !options.dataType) {
return result;
}
if (!options || !options.dataType) {
return result;
}
const dataType = options.dataType;
const dataType = options.dataType;
if (dataType instanceof DataTypes.DECIMAL || dataType instanceof DataTypes.FLOAT) {
if (result !== null) {
return parseFloat(result);
}
}
if (dataType instanceof DataTypes.INTEGER || dataType instanceof DataTypes.BIGINT) {
return parseInt(result, 10);
if (dataType instanceof DataTypes.DECIMAL || dataType instanceof DataTypes.FLOAT) {
if (result !== null) {
return parseFloat(result);
}
if (dataType instanceof DataTypes.DATE) {
if (result !== null && !(result instanceof Date)) {
return new Date(result);
}
}
if (dataType instanceof DataTypes.INTEGER || dataType instanceof DataTypes.BIGINT) {
return parseInt(result, 10);
}
if (dataType instanceof DataTypes.DATE) {
if (result !== null && !(result instanceof Date)) {
return new Date(result);
}
return result;
});
}
return result;
}
createTrigger(tableName, triggerName, timingType, fireOnArray, functionName, functionParams, optionsArray, options) {
async createTrigger(
tableName,
triggerName,
timingType,
fireOnArray,
functionName,
functionParams,
optionsArray,
options
) {
const sql = this.QueryGenerator.createTrigger(tableName, triggerName, timingType, fireOnArray, functionName, functionParams, optionsArray);
options = options || {};
if (sql) {
return this.sequelize.query(sql, options);
return await this.sequelize.query(sql, options);
}
return Promise.resolve();
}
dropTrigger(tableName, triggerName, options) {
async dropTrigger(tableName, triggerName, options) {
const sql = this.QueryGenerator.dropTrigger(tableName, triggerName);
options = options || {};
if (sql) {
return this.sequelize.query(sql, options);
return await this.sequelize.query(sql, options);
}
return Promise.resolve();
}
renameTrigger(tableName, oldTriggerName, newTriggerName, options) {
async renameTrigger(tableName, oldTriggerName, newTriggerName, options) {
const sql = this.QueryGenerator.renameTrigger(tableName, oldTriggerName, newTriggerName);
options = options || {};
if (sql) {
return this.sequelize.query(sql, options);
return await this.sequelize.query(sql, options);
}
return Promise.resolve();
}
/**
......@@ -1260,14 +1261,13 @@ class QueryInterface {
*
* @returns {Promise}
*/
createFunction(functionName, params, returnType, language, body, optionsArray, options) {
async createFunction(functionName, params, returnType, language, body, optionsArray, options) {
const sql = this.QueryGenerator.createFunction(functionName, params, returnType, language, body, optionsArray, options);
options = options || {};
if (sql) {
return this.sequelize.query(sql, options);
return await this.sequelize.query(sql, options);
}
return Promise.resolve();
}
/**
......@@ -1288,14 +1288,13 @@ class QueryInterface {
*
* @returns {Promise}
*/
dropFunction(functionName, params, options) {
async dropFunction(functionName, params, options) {
const sql = this.QueryGenerator.dropFunction(functionName, params);
options = options || {};
if (sql) {
return this.sequelize.query(sql, options);
return await this.sequelize.query(sql, options);
}
return Promise.resolve();
}
/**
......@@ -1318,14 +1317,13 @@ class QueryInterface {
*
* @returns {Promise}
*/
renameFunction(oldFunctionName, params, newFunctionName, options) {
async renameFunction(oldFunctionName, params, newFunctionName, options) {
const sql = this.QueryGenerator.renameFunction(oldFunctionName, params, newFunctionName);
options = options || {};
if (sql) {
return this.sequelize.query(sql, options);
return await this.sequelize.query(sql, options);
}
return Promise.resolve();
}
// Helper methods useful for querying
......@@ -1369,14 +1367,14 @@ class QueryInterface {
return this.QueryGenerator.escape(value);
}
setIsolationLevel(transaction, value, options) {
async setIsolationLevel(transaction, value, options) {
if (!transaction || !(transaction instanceof Transaction)) {
throw new Error('Unable to set isolation level for a transaction without transaction object!');
}
if (transaction.parent || !value) {
// Not possible to set a separate isolation level for savepoints
return Promise.resolve();
return;
}
options = Object.assign({}, options, {
......@@ -1387,12 +1385,12 @@ class QueryInterface {
parent: transaction.parent
});
if (!sql) return Promise.resolve();
if (!sql) return;
return this.sequelize.query(sql, options);
return await this.sequelize.query(sql, options);
}
startTransaction(transaction, options) {
async startTransaction(transaction, options) {
if (!transaction || !(transaction instanceof Transaction)) {
throw new Error('Unable to start a transaction without transaction object!');
}
......@@ -1403,10 +1401,10 @@ class QueryInterface {
options.transaction.name = transaction.parent ? transaction.name : undefined;
const sql = this.QueryGenerator.startTransactionQuery(transaction);
return this.sequelize.query(sql, options);
return await this.sequelize.query(sql, options);
}
deferConstraints(transaction, options) {
async deferConstraints(transaction, options) {
options = Object.assign({}, options, {
transaction: transaction.parent || transaction
});
......@@ -1414,19 +1412,17 @@ class QueryInterface {
const sql = this.QueryGenerator.deferConstraintsQuery(options);
if (sql) {
return this.sequelize.query(sql, options);
return await this.sequelize.query(sql, options);
}
return Promise.resolve();
}
commitTransaction(transaction, options) {
async commitTransaction(transaction, options) {
if (!transaction || !(transaction instanceof Transaction)) {
throw new Error('Unable to commit a transaction without transaction object!');
}
if (transaction.parent) {
// Savepoints cannot be committed
return Promise.resolve();
return;
}
options = Object.assign({}, options, {
......@@ -1440,10 +1436,10 @@ class QueryInterface {
transaction.finished = 'commit';
return promise;
return await promise;
}
rollbackTransaction(transaction, options) {
async rollbackTransaction(transaction, options) {
if (!transaction || !(transaction instanceof Transaction)) {
throw new Error('Unable to rollback a transaction without transaction object!');
}
......@@ -1459,7 +1455,7 @@ class QueryInterface {
transaction.finished = 'rollback';
return promise;
return await promise;
}
}
......
......@@ -128,34 +128,28 @@ if (dialect.match(/^postgres/)) {
return Promise.all([
// requires functionName
expect(() => {
return this.queryInterface.createFunction(null, [{ name: 'test' }], 'integer', 'plpgsql', body, options);
}).to.throw(/createFunction missing some parameters. Did you pass functionName, returnType, language and body/),
expect(this.queryInterface.createFunction(null, [{ name: 'test' }], 'integer', 'plpgsql', body, options))
.to.be.rejectedWith(/createFunction missing some parameters. Did you pass functionName, returnType, language and body/),
// requires Parameters array
expect(() => {
return this.queryInterface.createFunction('create_job', null, 'integer', 'plpgsql', body, options);
}).to.throw(/function parameters array required/),
expect(this.queryInterface.createFunction('create_job', null, 'integer', 'plpgsql', body, options))
.to.be.rejectedWith(/function parameters array required/),
// requires returnType
expect(() => {
return this.queryInterface.createFunction('create_job', [{ type: 'varchar', name: 'test' }], null, 'plpgsql', body, options);
}).to.throw(/createFunction missing some parameters. Did you pass functionName, returnType, language and body/),
expect(this.queryInterface.createFunction('create_job', [{ type: 'varchar', name: 'test' }], null, 'plpgsql', body, options))
.to.be.rejectedWith(/createFunction missing some parameters. Did you pass functionName, returnType, language and body/),
// requires type in parameter array
expect(() => {
return this.queryInterface.createFunction('create_job', [{ name: 'test' }], 'integer', 'plpgsql', body, options);
}).to.throw(/function or trigger used with a parameter without any type/),
expect(this.queryInterface.createFunction('create_job', [{ name: 'test' }], 'integer', 'plpgsql', body, options))
.to.be.rejectedWith(/function or trigger used with a parameter without any type/),
// requires language
expect(() => {
return this.queryInterface.createFunction('create_job', [{ type: 'varchar', name: 'test' }], 'varchar', null, body, options);
}).to.throw(/createFunction missing some parameters. Did you pass functionName, returnType, language and body/),
expect(this.queryInterface.createFunction('create_job', [{ type: 'varchar', name: 'test' }], 'varchar', null, body, options))
.to.be.rejectedWith(/createFunction missing some parameters. Did you pass functionName, returnType, language and body/),
// requires body
expect(() => {
return this.queryInterface.createFunction('create_job', [{ type: 'varchar', name: 'test' }], 'varchar', 'plpgsql', null, options);
}).to.throw(/createFunction missing some parameters. Did you pass functionName, returnType, language and body/)
expect(this.queryInterface.createFunction('create_job', [{ type: 'varchar', name: 'test' }], 'varchar', 'plpgsql', null, options))
.to.be.rejectedWith(/createFunction missing some parameters. Did you pass functionName, returnType, language and body/)
]);
});
......@@ -176,20 +170,14 @@ if (dialect.match(/^postgres/)) {
it('produces an error when options.variables is missing expected parameters', function() {
const body = 'return 1;';
expect(() => {
const options = { variables: 100 };
return this.queryInterface.createFunction('test_func', [], 'integer', 'plpgsql', body, [], options);
}).to.throw(/expandFunctionVariableList: function variables must be an array/);
expect(() => {
const options = { variables: [{ name: 'myVar' }] };
return this.queryInterface.createFunction('test_func', [], 'integer', 'plpgsql', body, [], options);
}).to.throw(/function variable must have a name and type/);
expect(() => {
const options = { variables: [{ type: 'integer' }] };
return this.queryInterface.createFunction('test_func', [], 'integer', 'plpgsql', body, [], options);
}).to.throw(/function variable must have a name and type/);
expect(this.queryInterface.createFunction('test_func', [], 'integer', 'plpgsql', body, [], { variables: 100 }))
.to.be.rejectedWith(/expandFunctionVariableList: function variables must be an array/);
expect(this.queryInterface.createFunction('test_func', [], 'integer', 'plpgsql', body, [], { variables: [{ name: 'myVar' }] }))
.to.be.rejectedWith(/function variable must have a name and type/);
expect(this.queryInterface.createFunction('test_func', [], 'integer', 'plpgsql', body, [], { variables: [{ type: 'integer' }] }))
.to.be.rejectedWith(/function variable must have a name and type/);
});
it('uses declared variables', function() {
......@@ -229,17 +217,14 @@ if (dialect.match(/^postgres/)) {
it('produces an error when missing expected parameters', function() {
return Promise.all([
expect(() => {
return this.queryInterface.dropFunction();
}).to.throw(/.*requires functionName/),
expect(this.queryInterface.dropFunction())
.to.be.rejectedWith(/.*requires functionName/),
expect(() => {
return this.queryInterface.dropFunction('droptest');
}).to.throw(/.*function parameters array required/),
expect(this.queryInterface.dropFunction('droptest'))
.to.be.rejectedWith(/.*function parameters array required/),
expect(() => {
return this.queryInterface.dropFunction('droptest', [{ name: 'test' }]);
}).to.be.throw(/.*function or trigger used with a parameter without any type/)
expect(this.queryInterface.dropFunction('droptest', [{ name: 'test' }]))
.to.be.rejectedWith(/.*function or trigger used with a parameter without any type/)
]);
});
});
......
......@@ -339,16 +339,12 @@ describe(Support.getTestDialectTeaser('QueryInterface'), () => {
}
});
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)');
};
const testArgs = (...args) => expect(this.queryInterface.addColumn(...args))
.to.be.rejectedWith(Error, 'addColumn takes at least 3 arguments (table, attribute name, attribute definition)');
testArgs('users', 'level_id');
testArgs(null, 'level_id');
testArgs('users', null, {});
await testArgs('users', 'level_id');
await testArgs(null, 'level_id');
await testArgs('users', null, {});
});
it('should work with schemas', async function() {
......@@ -539,14 +535,13 @@ describe(Support.getTestDialectTeaser('QueryInterface'), () => {
expect(constraints).to.not.include('check_user_roles');
});
it('addconstraint missing type', function() {
expect(() => {
it('addconstraint missing type', async function() {
await expect(
this.queryInterface.addConstraint('users', ['roles'], {
where: { roles: ['user', 'admin', 'guest', 'moderator'] },
name: 'check_user_roles'
});
throw new Error('Did not throw immediately...');
}).to.throw(Error, 'Constraint type must be specified through options.type');
})
).to.be.rejectedWith(Error, 'Constraint type must be specified through options.type');
});
});
}
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!