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

Commit c1e7317a by Andy Edwards Committed by GitHub

refactor(lib): asyncify remaining methods (#12173)

1 parent e7d5f0ac
...@@ -415,7 +415,7 @@ class BelongsToMany extends Association { ...@@ -415,7 +415,7 @@ class BelongsToMany extends Association {
* *
* @returns {Promise<Array<Model>>} * @returns {Promise<Array<Model>>}
*/ */
get(instance, options) { async get(instance, options) {
options = Utils.cloneDeep(options) || {}; options = Utils.cloneDeep(options) || {};
const through = this.through; const through = this.through;
...@@ -483,7 +483,7 @@ class BelongsToMany extends Association { ...@@ -483,7 +483,7 @@ class BelongsToMany extends Association {
* *
* @returns {Promise<number>} * @returns {Promise<number>}
*/ */
count(instance, options) { async count(instance, options) {
const sequelize = this.target.sequelize; const sequelize = this.target.sequelize;
options = Utils.cloneDeep(options); options = Utils.cloneDeep(options);
...@@ -494,7 +494,9 @@ class BelongsToMany extends Association { ...@@ -494,7 +494,9 @@ class BelongsToMany extends Association {
options.raw = true; options.raw = true;
options.plain = true; options.plain = true;
return this.get(instance, options).then(result => parseInt(result.count, 10)); const result = await this.get(instance, options);
return parseInt(result.count, 10);
} }
/** /**
...@@ -506,7 +508,7 @@ class BelongsToMany extends Association { ...@@ -506,7 +508,7 @@ class BelongsToMany extends Association {
* *
* @returns {Promise<boolean>} * @returns {Promise<boolean>}
*/ */
has(sourceInstance, instances, options) { async has(sourceInstance, instances, options) {
if (!Array.isArray(instances)) { if (!Array.isArray(instances)) {
instances = [instances]; instances = [instances];
} }
...@@ -535,10 +537,10 @@ class BelongsToMany extends Association { ...@@ -535,10 +537,10 @@ class BelongsToMany extends Association {
] ]
}; };
return this.get(sourceInstance, options).then(associatedObjects => const associatedObjects = await this.get(sourceInstance, options);
_.differenceWith(instancePrimaryKeys, associatedObjects,
(a, b) => _.isEqual(a[this.targetKey], b[this.targetKey])).length === 0 return _.differenceWith(instancePrimaryKeys, associatedObjects,
); (a, b) => _.isEqual(a[this.targetKey], b[this.targetKey])).length === 0;
} }
/** /**
...@@ -553,7 +555,7 @@ class BelongsToMany extends Association { ...@@ -553,7 +555,7 @@ class BelongsToMany extends Association {
* *
* @returns {Promise} * @returns {Promise}
*/ */
set(sourceInstance, newAssociatedObjects, options) { async set(sourceInstance, newAssociatedObjects, options) {
options = options || {}; options = options || {};
const sourceKey = this.sourceKey; const sourceKey = this.sourceKey;
...@@ -640,12 +642,13 @@ class BelongsToMany extends Association { ...@@ -640,12 +642,13 @@ class BelongsToMany extends Association {
return Promise.all(promises); return Promise.all(promises);
}; };
return this.through.model.findAll(_.defaults({ where, raw: true }, options)) try {
.then(currentRows => updateAssociations(currentRows)) const currentRows = await this.through.model.findAll(_.defaults({ where, raw: true }, options));
.catch(error => { return await updateAssociations(currentRows);
if (error instanceof EmptyResultError) return updateAssociations([]); } catch (error) {
throw error; if (error instanceof EmptyResultError) return updateAssociations([]);
}); throw error;
}
} }
/** /**
...@@ -660,7 +663,7 @@ class BelongsToMany extends Association { ...@@ -660,7 +663,7 @@ class BelongsToMany extends Association {
* *
* @returns {Promise} * @returns {Promise}
*/ */
add(sourceInstance, newInstances, options) { async add(sourceInstance, newInstances, options) {
// If newInstances is null or undefined, no-op // If newInstances is null or undefined, no-op
if (!newInstances) return Promise.resolve(); if (!newInstances) return Promise.resolve();
...@@ -734,13 +737,14 @@ class BelongsToMany extends Association { ...@@ -734,13 +737,14 @@ class BelongsToMany extends Association {
return Promise.all(promises); return Promise.all(promises);
}; };
return association.through.model.findAll(_.defaults({ where, raw: true }, options)) try {
.then(currentRows => updateAssociations(currentRows)) const currentRows = await association.through.model.findAll(_.defaults({ where, raw: true }, options));
.then(([associations]) => associations) const [associations] = await updateAssociations(currentRows);
.catch(error => { return associations;
if (error instanceof EmptyResultError) return updateAssociations(); } catch (error) {
throw error; if (error instanceof EmptyResultError) return updateAssociations();
}); throw error;
}
} }
/** /**
...@@ -777,7 +781,7 @@ class BelongsToMany extends Association { ...@@ -777,7 +781,7 @@ class BelongsToMany extends Association {
* *
* @returns {Promise} * @returns {Promise}
*/ */
create(sourceInstance, values, options) { async create(sourceInstance, values, options) {
const association = this; const association = this;
options = options || {}; options = options || {};
...@@ -797,9 +801,10 @@ class BelongsToMany extends Association { ...@@ -797,9 +801,10 @@ class BelongsToMany extends Association {
} }
// Create the related model instance // Create the related model instance
return association.target.create(values, options).then(newAssociatedObject => const newAssociatedObject = await association.target.create(values, options);
sourceInstance[association.accessors.add](newAssociatedObject, _.omit(options, ['fields'])).then(() => newAssociatedObject)
); await sourceInstance[association.accessors.add](newAssociatedObject, _.omit(options, ['fields']));
return newAssociatedObject;
} }
verifyAssociationAlias(alias) { verifyAssociationAlias(alias) {
......
...@@ -25,7 +25,7 @@ class ConnectionManager extends AbstractConnectionManager { ...@@ -25,7 +25,7 @@ class ConnectionManager extends AbstractConnectionManager {
parserStore.clear(); parserStore.clear();
} }
connect(config) { async connect(config) {
const connectionConfig = { const connectionConfig = {
server: config.host, server: config.host,
authentication: { authentication: {
...@@ -58,57 +58,59 @@ class ConnectionManager extends AbstractConnectionManager { ...@@ -58,57 +58,59 @@ class ConnectionManager extends AbstractConnectionManager {
Object.assign(connectionConfig.options, config.dialectOptions.options); Object.assign(connectionConfig.options, config.dialectOptions.options);
} }
return new Promise((resolve, reject) => { try {
const connection = new this.lib.Connection(connectionConfig); return await new Promise((resolve, reject) => {
connection.queue = new AsyncQueue(); const connection = new this.lib.Connection(connectionConfig);
connection.lib = this.lib; connection.queue = new AsyncQueue();
connection.lib = this.lib;
const connectHandler = error => {
connection.removeListener('end', endHandler); const connectHandler = error => {
connection.removeListener('error', errorHandler); connection.removeListener('end', endHandler);
connection.removeListener('error', errorHandler);
if (error) return reject(error);
if (error) return reject(error);
debug('connection acquired');
resolve(connection); debug('connection acquired');
}; resolve(connection);
};
const endHandler = () => {
connection.removeListener('connect', connectHandler); const endHandler = () => {
connection.removeListener('error', errorHandler); connection.removeListener('connect', connectHandler);
reject(new Error('Connection was closed by remote server')); connection.removeListener('error', errorHandler);
}; reject(new Error('Connection was closed by remote server'));
};
const errorHandler = error => {
connection.removeListener('connect', connectHandler); const errorHandler = error => {
connection.removeListener('end', endHandler); connection.removeListener('connect', connectHandler);
reject(error); connection.removeListener('end', endHandler);
}; reject(error);
};
connection.once('error', errorHandler);
connection.once('end', endHandler); connection.once('error', errorHandler);
connection.once('connect', connectHandler); connection.once('end', endHandler);
connection.once('connect', connectHandler);
/*
* Permanently attach this event before connection is even acquired /*
* tedious sometime emits error even after connect(with error). * Permanently attach this event before connection is even acquired
* * tedious sometime emits error even after connect(with error).
* If we dont attach this even that unexpected error event will crash node process *
* * If we dont attach this even that unexpected error event will crash node process
* E.g. connectTimeout is set higher than requestTimeout *
*/ * E.g. connectTimeout is set higher than requestTimeout
connection.on('error', error => { */
switch (error.code) { connection.on('error', error => {
case 'ESOCKET': switch (error.code) {
case 'ECONNRESET': case 'ESOCKET':
this.pool.destroy(connection); case 'ECONNRESET':
this.pool.destroy(connection);
}
});
if (config.dialectOptions && config.dialectOptions.debug) {
connection.on('debug', debugTedious.log.bind(debugTedious));
} }
}); });
} catch (error) {
if (config.dialectOptions && config.dialectOptions.debug) {
connection.on('debug', debugTedious.log.bind(debugTedious));
}
}).catch(error => {
if (!error.code) { if (!error.code) {
throw new sequelizeErrors.ConnectionError(error); throw new sequelizeErrors.ConnectionError(error);
} }
...@@ -139,13 +141,13 @@ class ConnectionManager extends AbstractConnectionManager { ...@@ -139,13 +141,13 @@ class ConnectionManager extends AbstractConnectionManager {
default: default:
throw new sequelizeErrors.ConnectionError(error); throw new sequelizeErrors.ConnectionError(error);
} }
}); }
} }
disconnect(connection) { async disconnect(connection) {
// Don't disconnect a connection that is already disconnected // Don't disconnect a connection that is already disconnected
if (connection.closed) { if (connection.closed) {
return Promise.resolve(); return;
} }
connection.queue.close(); connection.queue.close();
......
...@@ -20,47 +20,32 @@ ...@@ -20,47 +20,32 @@
@private @private
*/ */
const removeColumn = function(qi, tableName, attributeName, options) { const removeColumn = async function(qi, tableName, attributeName, options) {
options = Object.assign({ raw: true }, options || {}); options = Object.assign({ raw: true }, options || {});
const findConstraintSql = qi.QueryGenerator.getDefaultConstraintQuery(tableName, attributeName); const findConstraintSql = qi.QueryGenerator.getDefaultConstraintQuery(tableName, attributeName);
return qi.sequelize.query(findConstraintSql, options) const [results0] = await qi.sequelize.query(findConstraintSql, options);
.then(([results]) => { if (results0.length) {
if (!results.length) { // No default constraint found -- we can cleanly remove the column
// No default constraint found -- we can cleanly remove the column const dropConstraintSql = qi.QueryGenerator.dropConstraintQuery(tableName, results0[0].name);
return; await qi.sequelize.query(dropConstraintSql, options);
} }
const dropConstraintSql = qi.QueryGenerator.dropConstraintQuery(tableName, results[0].name); const findForeignKeySql = qi.QueryGenerator.getForeignKeyQuery(tableName, attributeName);
return qi.sequelize.query(dropConstraintSql, options); const [results] = await qi.sequelize.query(findForeignKeySql, options);
}) if (results.length) {
.then(() => { // No foreign key constraints found, so we can remove the column
const findForeignKeySql = qi.QueryGenerator.getForeignKeyQuery(tableName, attributeName); const dropForeignKeySql = qi.QueryGenerator.dropForeignKeyQuery(tableName, results[0].constraint_name);
return qi.sequelize.query(findForeignKeySql, options); await qi.sequelize.query(dropForeignKeySql, options);
}) }
.then(([results]) => { //Check if the current column is a primaryKey
if (!results.length) { const primaryKeyConstraintSql = qi.QueryGenerator.getPrimaryKeyConstraintQuery(tableName, attributeName);
// No foreign key constraints found, so we can remove the column const [result] = await qi.sequelize.query(primaryKeyConstraintSql, options);
return; if (result.length) {
} const dropConstraintSql = qi.QueryGenerator.dropConstraintQuery(tableName, result[0].constraintName);
const dropForeignKeySql = qi.QueryGenerator.dropForeignKeyQuery(tableName, results[0].constraint_name); await qi.sequelize.query(dropConstraintSql, options);
return qi.sequelize.query(dropForeignKeySql, options); }
}) const removeSql = qi.QueryGenerator.removeColumnQuery(tableName, attributeName);
.then(() => { return qi.sequelize.query(removeSql, options);
//Check if the current column is a primaryKey
const primaryKeyConstraintSql = qi.QueryGenerator.getPrimaryKeyConstraintQuery(tableName, attributeName);
return qi.sequelize.query(primaryKeyConstraintSql, options);
})
.then(([result]) => {
if (!result.length) {
return;
}
const dropConstraintSql = qi.QueryGenerator.dropConstraintQuery(tableName, result[0].constraintName);
return qi.sequelize.query(dropConstraintSql, options);
})
.then(() => {
const removeSql = qi.QueryGenerator.removeColumnQuery(tableName, attributeName);
return qi.sequelize.query(removeSql, options);
});
}; };
module.exports = { module.exports = {
......
...@@ -25,13 +25,12 @@ class ConnectionManager extends AbstractConnectionManager { ...@@ -25,13 +25,12 @@ class ConnectionManager extends AbstractConnectionManager {
this.refreshTypeParser(dataTypes); this.refreshTypeParser(dataTypes);
} }
_onProcessExit() { async _onProcessExit() {
const promises = Object.getOwnPropertyNames(this.connections) await Promise.all(
.map(connection => promisify(callback => this.connections[connection].close(callback))()); Object.getOwnPropertyNames(this.connections)
.map(connection => promisify(callback => this.connections[connection].close(callback))())
return Promise );
.all(promises) return super._onProcessExit.call(this);
.then(() => super._onProcessExit.call(this));
} }
// Expose this as a method so that the parsing may be updated when the user has added additional, custom types // Expose this as a method so that the parsing may be updated when the user has added additional, custom types
...@@ -43,7 +42,7 @@ class ConnectionManager extends AbstractConnectionManager { ...@@ -43,7 +42,7 @@ class ConnectionManager extends AbstractConnectionManager {
parserStore.clear(); parserStore.clear();
} }
getConnection(options) { async getConnection(options) {
options = options || {}; options = options || {};
options.uuid = options.uuid || 'default'; options.uuid = options.uuid || 'default';
options.storage = this.sequelize.options.storage || this.sequelize.options.host || ':memory:'; options.storage = this.sequelize.options.storage || this.sequelize.options.host || ':memory:';
...@@ -55,7 +54,7 @@ class ConnectionManager extends AbstractConnectionManager { ...@@ -55,7 +54,7 @@ class ConnectionManager extends AbstractConnectionManager {
options.readWriteMode = dialectOptions && dialectOptions.mode || defaultReadWriteMode; options.readWriteMode = dialectOptions && dialectOptions.mode || defaultReadWriteMode;
if (this.connections[options.inMemory || options.uuid]) { if (this.connections[options.inMemory || options.uuid]) {
return Promise.resolve(this.connections[options.inMemory || options.uuid]); return this.connections[options.inMemory || options.uuid];
} }
if (!options.inMemory && (options.readWriteMode & this.lib.OPEN_CREATE) !== 0) { if (!options.inMemory && (options.readWriteMode & this.lib.OPEN_CREATE) !== 0) {
...@@ -63,7 +62,7 @@ class ConnectionManager extends AbstractConnectionManager { ...@@ -63,7 +62,7 @@ class ConnectionManager extends AbstractConnectionManager {
fs.mkdirSync(path.dirname(options.storage), { recursive: true }); fs.mkdirSync(path.dirname(options.storage), { recursive: true });
} }
return new Promise((resolve, reject) => { const connection = await new Promise((resolve, reject) => {
this.connections[options.inMemory || options.uuid] = new this.lib.Database( this.connections[options.inMemory || options.uuid] = new this.lib.Database(
options.storage, options.storage,
options.readWriteMode, options.readWriteMode,
...@@ -73,18 +72,19 @@ class ConnectionManager extends AbstractConnectionManager { ...@@ -73,18 +72,19 @@ class ConnectionManager extends AbstractConnectionManager {
resolve(this.connections[options.inMemory || options.uuid]); resolve(this.connections[options.inMemory || options.uuid]);
} }
); );
}).then(connection => {
if (this.sequelize.config.password) {
// Make it possible to define and use password for sqlite encryption plugin like sqlcipher
connection.run(`PRAGMA KEY=${this.sequelize.escape(this.sequelize.config.password)}`);
}
if (this.sequelize.options.foreignKeys !== false) {
// Make it possible to define and use foreign key constraints unless
// explicitly disallowed. It's still opt-in per relation
connection.run('PRAGMA FOREIGN_KEYS=ON');
}
return connection;
}); });
if (this.sequelize.config.password) {
// Make it possible to define and use password for sqlite encryption plugin like sqlcipher
connection.run(`PRAGMA KEY=${this.sequelize.escape(this.sequelize.config.password)}`);
}
if (this.sequelize.options.foreignKeys !== false) {
// Make it possible to define and use foreign key constraints unless
// explicitly disallowed. It's still opt-in per relation
connection.run('PRAGMA FOREIGN_KEYS=ON');
}
return connection;
} }
releaseConnection(connection, force) { releaseConnection(connection, force) {
......
...@@ -177,20 +177,18 @@ exports.addConstraint = addConstraint; ...@@ -177,20 +177,18 @@ exports.addConstraint = addConstraint;
* @private * @private
* @returns {Promise} * @returns {Promise}
*/ */
function getForeignKeyReferencesForTable(qi, tableName, options) { async function getForeignKeyReferencesForTable(qi, tableName, options) {
const database = qi.sequelize.config.database; const database = qi.sequelize.config.database;
const query = qi.QueryGenerator.getForeignKeysQuery(tableName, database); const query = qi.QueryGenerator.getForeignKeysQuery(tableName, database);
return qi.sequelize.query(query, options) const result = await qi.sequelize.query(query, options);
.then(result => { return result.map(row => ({
return result.map(row => ({ tableName,
tableName, columnName: row.from,
columnName: row.from, referencedTableName: row.table,
referencedTableName: row.table, referencedColumnName: row.to,
referencedColumnName: row.to, tableCatalog: database,
tableCatalog: database, referencedTableCatalog: database
referencedTableCatalog: database }));
}));
});
} }
exports.getForeignKeyReferencesForTable = getForeignKeyReferencesForTable; exports.getForeignKeyReferencesForTable = getForeignKeyReferencesForTable;
...@@ -216,7 +216,7 @@ class Query extends AbstractQuery { ...@@ -216,7 +216,7 @@ class Query extends AbstractQuery {
return result; return result;
} }
run(sql, parameters) { async run(sql, parameters) {
const conn = this.connection; const conn = this.connection;
this.sql = sql; this.sql = sql;
const method = this.getDatabaseMethod(); const method = this.getDatabaseMethod();
...@@ -231,69 +231,67 @@ class Query extends AbstractQuery { ...@@ -231,69 +231,67 @@ class Query extends AbstractQuery {
} }
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => conn.serialize(async () => {
const columnTypes = {}; const columnTypes = {};
conn.serialize(() => { const executeSql = () => {
const executeSql = () => { if (sql.startsWith('-- ')) {
if (sql.startsWith('-- ')) { return resolve();
return resolve(); }
} const query = this;
const query = this; // cannot use arrow function here because the function is bound to the statement
// cannot use arrow function here because the function is bound to the statement function afterExecute(executionError, results) {
function afterExecute(executionError, results) { try {
try { complete();
complete(); // `this` is passed from sqlite, we have no control over this.
// `this` is passed from sqlite, we have no control over this. // eslint-disable-next-line no-invalid-this
// eslint-disable-next-line no-invalid-this resolve(query._handleQueryResponse(this, columnTypes, executionError, results));
resolve(query._handleQueryResponse(this, columnTypes, executionError, results)); return;
return; } catch (error) {
} catch (error) { reject(error);
reject(error);
}
} }
}
if (method === 'exec') { if (method === 'exec') {
// exec does not support bind parameter // exec does not support bind parameter
conn[method](sql, afterExecute); conn[method](sql, afterExecute);
} else { } else {
if (!parameters) parameters = []; if (!parameters) parameters = [];
conn[method](sql, parameters, afterExecute); conn[method](sql, parameters, afterExecute);
} }
return null; return null;
}; };
if (this.getDatabaseMethod() === 'all') { if (this.getDatabaseMethod() === 'all') {
let tableNames = []; let tableNames = [];
if (this.options && this.options.tableNames) { if (this.options && this.options.tableNames) {
tableNames = this.options.tableNames; tableNames = this.options.tableNames;
} else if (/FROM `(.*?)`/i.exec(this.sql)) { } else if (/FROM `(.*?)`/i.exec(this.sql)) {
tableNames.push(/FROM `(.*?)`/i.exec(this.sql)[1]); tableNames.push(/FROM `(.*?)`/i.exec(this.sql)[1]);
} }
// If we already have the metadata for the table, there's no need to ask for it again // If we already have the metadata for the table, there's no need to ask for it again
tableNames = tableNames.filter(tableName => !(tableName in columnTypes) && tableName !== 'sqlite_master'); tableNames = tableNames.filter(tableName => !(tableName in columnTypes) && tableName !== 'sqlite_master');
if (!tableNames.length) { if (!tableNames.length) {
return executeSql(); return executeSql();
}
return Promise.all(tableNames.map(tableName =>
new Promise(resolve => {
tableName = tableName.replace(/`/g, '');
columnTypes[tableName] = {};
conn.all(`PRAGMA table_info(\`${tableName}\`)`, (err, results) => {
if (!err) {
for (const result of results) {
columnTypes[tableName][result.name] = result.type;
}
}
resolve();
});
}))).then(executeSql);
} }
return executeSql(); await Promise.all(tableNames.map(tableName =>
}); new Promise(resolve => {
}); tableName = tableName.replace(/`/g, '');
columnTypes[tableName] = {};
conn.all(`PRAGMA table_info(\`${tableName}\`)`, (err, results) => {
if (!err) {
for (const result of results) {
columnTypes[tableName][result.name] = result.type;
}
}
resolve();
});
})));
}
return executeSql();
}));
} }
parseConstraintsFromSql(sql) { parseConstraintsFromSql(sql) {
...@@ -419,24 +417,23 @@ class Query extends AbstractQuery { ...@@ -419,24 +417,23 @@ class Query extends AbstractQuery {
} }
} }
handleShowIndexesQuery(data) { async handleShowIndexesQuery(data) {
// Sqlite returns indexes so the one that was defined last is returned first. Lets reverse that! // Sqlite returns indexes so the one that was defined last is returned first. Lets reverse that!
return Promise.all(data.reverse().map(item => { return Promise.all(data.reverse().map(async item => {
item.fields = []; item.fields = [];
item.primary = false; item.primary = false;
item.unique = !!item.unique; item.unique = !!item.unique;
item.constraintName = item.name; item.constraintName = item.name;
return this.run(`PRAGMA INDEX_INFO(\`${item.name}\`)`).then(columns => { const columns = await this.run(`PRAGMA INDEX_INFO(\`${item.name}\`)`);
for (const column of columns) { for (const column of columns) {
item.fields[column.seqno] = { item.fields[column.seqno] = {
attribute: column.name, attribute: column.name,
length: undefined, length: undefined,
order: undefined order: undefined
}; };
} }
return item; return item;
});
})); }));
} }
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!