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

Commit b71cd05b by Mikxail Committed by GitHub

fix(query): preserve cls context for logger (#12328)

1 parent 95f7fb5c
...@@ -44,48 +44,29 @@ class Query extends AbstractQuery { ...@@ -44,48 +44,29 @@ class Query extends AbstractQuery {
return paramType; return paramType;
} }
_run(connection, sql, parameters) { async _run(connection, sql, parameters) {
this.sql = sql; this.sql = sql;
const { options } = this; const { options } = this;
const complete = this._logQuery(sql, debug, parameters); const complete = this._logQuery(sql, debug, parameters);
return new Promise((resolve, reject) => { const query = new Promise((resolve, reject) => {
const handleTransaction = err => {
if (err) {
err.sql = sql;
err.parameters = parameters;
reject(this.formatError(err));
return;
}
resolve(this.formatResults());
};
// TRANSACTION SUPPORT // TRANSACTION SUPPORT
if (sql.startsWith('BEGIN TRANSACTION')) { if (sql.startsWith('BEGIN TRANSACTION')) {
return connection.beginTransaction(handleTransaction, options.transaction.name, connection.lib.ISOLATION_LEVEL[options.isolationLevel]); return connection.beginTransaction(error => error ? reject(error) : resolve([]), options.transaction.name, connection.lib.ISOLATION_LEVEL[options.isolationLevel]);
} }
if (sql.startsWith('COMMIT TRANSACTION')) { if (sql.startsWith('COMMIT TRANSACTION')) {
return connection.commitTransaction(handleTransaction); return connection.commitTransaction(error => error ? reject(error) : resolve([]));
} }
if (sql.startsWith('ROLLBACK TRANSACTION')) { if (sql.startsWith('ROLLBACK TRANSACTION')) {
return connection.rollbackTransaction(handleTransaction, options.transaction.name); return connection.rollbackTransaction(error => error ? reject(error) : resolve([]), options.transaction.name);
} }
if (sql.startsWith('SAVE TRANSACTION')) { if (sql.startsWith('SAVE TRANSACTION')) {
return connection.saveTransaction(handleTransaction, options.transaction.name); return connection.saveTransaction(error => error ? reject(error) : resolve([]), options.transaction.name);
} }
const results = [];
const request = new connection.lib.Request(sql, (err, rowCount) => {
complete();
if (err) { const rows = [];
err.sql = sql; const request = new connection.lib.Request(sql, (err, rowCount) => err ? reject(err) : resolve([rows, rowCount]));
err.parameters = parameters;
reject(this.formatError(err));
} else {
resolve(this.formatResults(results, rowCount));
}
});
if (parameters) { if (parameters) {
_.forOwn(parameters, (value, key) => { _.forOwn(parameters, (value, key) => {
...@@ -95,6 +76,27 @@ class Query extends AbstractQuery { ...@@ -95,6 +76,27 @@ class Query extends AbstractQuery {
} }
request.on('row', columns => { request.on('row', columns => {
rows.push(columns);
});
connection.execSql(request);
});
let rows, rowCount;
try {
[rows, rowCount] = await query;
} catch (err) {
err.sql = sql;
err.parameters = parameters;
throw this.formatError(err);
}
complete();
if (Array.isArray(rows)) {
rows = rows.map(columns => {
const row = {}; const row = {};
for (const column of columns) { for (const column of columns) {
const typeid = column.metadata.type.id; const typeid = column.metadata.type.id;
...@@ -106,12 +108,11 @@ class Query extends AbstractQuery { ...@@ -106,12 +108,11 @@ class Query extends AbstractQuery {
} }
row[column.metadata.colName] = value; row[column.metadata.colName] = value;
} }
return row;
results.push(row);
}); });
}
connection.execSql(request); return this.formatResults(rows, rowCount);
});
} }
run(sql, parameters) { run(sql, parameters) {
......
...@@ -35,30 +35,27 @@ class Query extends AbstractQuery { ...@@ -35,30 +35,27 @@ class Query extends AbstractQuery {
const complete = this._logQuery(sql, debug, parameters); const complete = this._logQuery(sql, debug, parameters);
const results = await new Promise((resolve, reject) => { const query = parameters && parameters.length
const handler = (err, results) => { ? new Promise((resolve, reject) => connection.execute(sql, parameters, (error, result) => error ? reject(error) : resolve(result)).setMaxListeners(100))
complete(); : new Promise((resolve, reject) => connection.query({ sql }, (error, result) => error ? reject(error) : resolve(result)).setMaxListeners(100));
if (err) { let results;
// MySQL automatically rolls-back transactions in the event of a deadlock
if (options.transaction && err.errno === 1213) { try {
options.transaction.finished = 'rollback'; results = await query;
} } catch (err) {
err.sql = sql; // MySQL automatically rolls-back transactions in the event of a deadlock
err.parameters = parameters; if (options.transaction && err.errno === 1213) {
options.transaction.finished = 'rollback';
reject(this.formatError(err));
} else {
resolve(results);
}
};
if (parameters) {
debug('parameters(%j)', parameters);
connection.execute(sql, parameters, handler).setMaxListeners(100);
} else {
connection.query({ sql }, handler).setMaxListeners(100);
} }
}); err.sql = sql;
err.parameters = parameters;
throw this.formatError(err);
}
complete();
// Log warnings if we've got them. // Log warnings if we've got them.
if (showWarnings && results && results.warningStatus > 0) { if (showWarnings && results && results.warningStatus > 0) {
await this.logWarnings(results); await this.logWarnings(results);
......
...@@ -6,7 +6,8 @@ const chai = require('chai'), ...@@ -6,7 +6,8 @@ const chai = require('chai'),
Sequelize = Support.Sequelize, Sequelize = Support.Sequelize,
cls = require('cls-hooked'), cls = require('cls-hooked'),
current = Support.sequelize, current = Support.sequelize,
delay = require('delay'); delay = require('delay'),
sinon = require('sinon');
if (current.dialect.supports.transactions) { if (current.dialect.supports.transactions) {
describe(Support.getTestDialectTeaser('CLS (Async hooks)'), () => { describe(Support.getTestDialectTeaser('CLS (Async hooks)'), () => {
...@@ -146,5 +147,35 @@ if (current.dialect.supports.transactions) { ...@@ -146,5 +147,35 @@ if (current.dialect.supports.transactions) {
} }
); );
}); });
it('custom logging with benchmarking has correct CLS context', async function() {
const logger = sinon.spy(() => {
return this.ns.get('value');
});
const sequelize = Support.createSequelizeInstance({
logging: logger,
benchmark: true
});
const result = this.ns.runPromise(async () => {
this.ns.set('value', 1);
await delay(500);
return sequelize.query('select 1;');
});
await this.ns.runPromise(() => {
this.ns.set('value', 2);
return sequelize.query('select 2;');
});
await result;
expect(logger.calledTwice).to.be.true;
expect(logger.firstCall.args[0]).to.be.match(/Executed \((\d*|default)\): select 2/);
expect(logger.firstCall.returnValue).to.be.equal(2);
expect(logger.secondCall.args[0]).to.be.match(/Executed \((\d*|default)\): select 1/);
expect(logger.secondCall.returnValue).to.be.equal(1);
});
}); });
} }
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!