Skip to content

Commit 4063c2a

Browse files
authored
refactor(query): similar code for mysql and mariadb (sequelize#12981)
1 parent e45df29 commit 4063c2a

File tree

2 files changed

+59
-48
lines changed

2 files changed

+59
-48
lines changed

lib/dialects/mariadb/query.js

Lines changed: 22 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -19,30 +19,29 @@ class Query extends AbstractQuery {
1919

2020
static formatBindParameters(sql, values, dialect) {
2121
const bindParam = [];
22-
const replacementFunc = (match, key, val) => {
23-
if (val[key] !== undefined) {
24-
bindParam.push(val[key]);
22+
const replacementFunc = (match, key, values_) => {
23+
if (values_[key] !== undefined) {
24+
bindParam.push(values_[key]);
2525
return '?';
2626
}
2727
return undefined;
2828
};
29-
sql = AbstractQuery.formatBindParameters(sql, values, dialect,
30-
replacementFunc)[0];
29+
sql = AbstractQuery.formatBindParameters(sql, values, dialect, replacementFunc)[0];
3130
return [sql, bindParam.length > 0 ? bindParam : undefined];
3231
}
3332

3433
async run(sql, parameters) {
3534
this.sql = sql;
3635
const { connection, options } = this;
3736

38-
const showWarnings = this.sequelize.options.showWarnings
39-
|| options.showWarnings;
37+
const showWarnings = this.sequelize.options.showWarnings || options.showWarnings;
4038

4139
const complete = this._logQuery(sql, debug, parameters);
4240

4341
if (parameters) {
4442
debug('parameters(%j)', parameters);
4543
}
44+
4645
let results;
4746

4847
try {
@@ -120,13 +119,14 @@ class Query extends AbstractQuery {
120119

121120
if (!this.instance) {
122121
// handle bulkCreate AI primary key
123-
if (this.model
122+
if (
123+
this.model
124124
&& this.model.autoIncrementAttribute
125125
&& this.model.autoIncrementAttribute === this.model.primaryKeyAttribute
126126
&& this.model.rawAttributes[this.model.primaryKeyAttribute]
127127
) {
128-
//ONLY TRUE IF @auto_increment_increment is set to 1 !!
129-
//Doesn't work with GALERA => each node will reserve increment (x for first server, x+1 for next node ...
128+
// ONLY TRUE IF @auto_increment_increment is set to 1 !!
129+
// Doesn't work with GALERA => each node will reserve increment (x for first server, x+1 for next node...)
130130
const startId = data[this.getInsertIdField()];
131131
result = new Array(data.affectedRows);
132132
const pkField = this.model.rawAttributes[this.model.primaryKeyAttribute].field;
@@ -195,7 +195,7 @@ class Query extends AbstractQuery {
195195
for (const _field of Object.keys(this.model.fieldRawAttributesMap)) {
196196
const modelField = this.model.fieldRawAttributesMap[_field];
197197
if (modelField.type instanceof DataTypes.JSON) {
198-
//value is return as String, no JSON
198+
// Value is returned as String, not JSON
199199
rows = rows.map(row => {
200200
row[modelField.fieldName] = row[modelField.fieldName] ? JSON.parse(
201201
row[modelField.fieldName]) : null;
@@ -211,21 +211,18 @@ class Query extends AbstractQuery {
211211

212212
async logWarnings(results) {
213213
const warningResults = await this.run('SHOW WARNINGS');
214-
const warningMessage = `MariaDB Warnings (${this.connection.uuid
215-
|| 'default'}): `;
214+
const warningMessage = `MariaDB Warnings (${this.connection.uuid || 'default'}): `;
216215
const messages = [];
217216
for (const _warningRow of warningResults) {
218-
if (_warningRow === undefined || typeof _warningRow[Symbol.iterator]
219-
!== 'function') {
217+
if (_warningRow === undefined || typeof _warningRow[Symbol.iterator] !== 'function') {
220218
continue;
221219
}
222220
for (const _warningResult of _warningRow) {
223221
if (Object.prototype.hasOwnProperty.call(_warningResult, 'Message')) {
224222
messages.push(_warningResult.Message);
225223
} else {
226224
for (const _objectKey of _warningResult.keys()) {
227-
messages.push(
228-
[_objectKey, _warningResult[_objectKey]].join(': '));
225+
messages.push([_objectKey, _warningResult[_objectKey]].join(': '));
229226
}
230227
}
231228
}
@@ -250,9 +247,7 @@ class Query extends AbstractQuery {
250247
const uniqueKey = this.model && this.model.uniqueKeys[fieldKey];
251248

252249
if (uniqueKey) {
253-
if (uniqueKey.msg) {
254-
message = uniqueKey.msg;
255-
}
250+
if (uniqueKey.msg) message = uniqueKey.msg;
256251
fields = _.zipObject(uniqueKey.fields, values);
257252
} else {
258253
fields[fieldKey] = fieldVal;
@@ -270,24 +265,23 @@ class Query extends AbstractQuery {
270265
));
271266
});
272267

273-
return new sequelizeErrors.UniqueConstraintError(
274-
{ message, errors, parent: err, fields });
268+
return new sequelizeErrors.UniqueConstraintError({ message, errors, parent: err, fields });
275269
}
276270

277271
case ER_ROW_IS_REFERENCED:
278272
case ER_NO_REFERENCED_ROW: {
279273
// e.g. CONSTRAINT `example_constraint_name` FOREIGN KEY (`example_id`) REFERENCES `examples` (`id`)
280274
const match = err.message.match(
281-
/CONSTRAINT ([`"])(.*)\1 FOREIGN KEY \(\1(.*)\1\) REFERENCES \1(.*)\1 \(\1(.*)\1\)/);
275+
/CONSTRAINT ([`"])(.*)\1 FOREIGN KEY \(\1(.*)\1\) REFERENCES \1(.*)\1 \(\1(.*)\1\)/
276+
);
282277
const quoteChar = match ? match[1] : '`';
283-
const fields = match ? match[3].split(
284-
new RegExp(`${quoteChar}, *${quoteChar}`)) : undefined;
278+
const fields = match ? match[3].split(new RegExp(`${quoteChar}, *${quoteChar}`)) : undefined;
279+
285280
return new sequelizeErrors.ForeignKeyConstraintError({
286-
reltype: err.errno === 1451 ? 'parent' : 'child',
281+
reltype: err.errno === ER_ROW_IS_REFERENCED ? 'parent' : 'child',
287282
table: match ? match[4] : undefined,
288283
fields,
289-
value: fields && fields.length && this.instance
290-
&& this.instance[fields[0]] || undefined,
284+
value: fields && fields.length && this.instance && this.instance[fields[0]] || undefined,
291285
index: match ? match[2] : undefined,
292286
parent: err
293287
});

lib/dialects/mysql/query.js

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@ const sequelizeErrors = require('../../errors');
55
const _ = require('lodash');
66
const { logger } = require('../../utils/logger');
77

8-
const debug = logger.debugContext('sql:mysql');
8+
const ER_DUP_ENTRY = 1062;
9+
const ER_ROW_IS_REFERENCED = 1451;
10+
const ER_NO_REFERENCED_ROW = 1452;
911

12+
const debug = logger.debugContext('sql:mysql');
1013

1114
class Query extends AbstractQuery {
1215
constructor(connection, sequelize, options) {
@@ -15,9 +18,9 @@ class Query extends AbstractQuery {
1518

1619
static formatBindParameters(sql, values, dialect) {
1720
const bindParam = [];
18-
const replacementFunc = (match, key, values) => {
19-
if (values[key] !== undefined) {
20-
bindParam.push(values[key]);
21+
const replacementFunc = (match, key, values_) => {
22+
if (values_[key] !== undefined) {
23+
bindParam.push(values_[key]);
2124
return '?';
2225
}
2326
return undefined;
@@ -30,37 +33,46 @@ class Query extends AbstractQuery {
3033
this.sql = sql;
3134
const { connection, options } = this;
3235

33-
//do we need benchmark for this query execution
3436
const showWarnings = this.sequelize.options.showWarnings || options.showWarnings;
3537

3638
const complete = this._logQuery(sql, debug, parameters);
3739

38-
const query = parameters && parameters.length
39-
? new Promise((resolve, reject) => connection.execute(sql, parameters, (error, result) => error ? reject(error) : resolve(result)).setMaxListeners(100))
40-
: new Promise((resolve, reject) => connection.query({ sql }, (error, result) => error ? reject(error) : resolve(result)).setMaxListeners(100));
40+
if (parameters) {
41+
debug('parameters(%j)', parameters);
42+
}
4143

4244
let results;
4345

4446
try {
45-
results = await query;
47+
if (parameters && parameters.length) {
48+
results = await new Promise((resolve, reject) => {
49+
connection
50+
.execute(sql, parameters, (error, result) => error ? reject(error) : resolve(result))
51+
.setMaxListeners(100);
52+
});
53+
} else {
54+
results = await new Promise((resolve, reject) => {
55+
connection
56+
.query({ sql }, (error, result) => error ? reject(error) : resolve(result))
57+
.setMaxListeners(100);
58+
});
59+
}
4660
} catch (err) {
4761
// MySQL automatically rolls-back transactions in the event of a deadlock
4862
if (options.transaction && err.errno === 1213) {
4963
options.transaction.finished = 'rollback';
5064
}
65+
5166
err.sql = sql;
5267
err.parameters = parameters;
53-
5468
throw this.formatError(err);
5569
}
5670

5771
complete();
5872

59-
// Log warnings if we've got them.
6073
if (showWarnings && results && results.warningStatus > 0) {
6174
await this.logWarnings(results);
6275
}
63-
// Return formatted results...
6476
return this.formatResults(results);
6577
}
6678

@@ -88,7 +100,7 @@ class Query extends AbstractQuery {
88100
this.handleInsertQuery(data);
89101

90102
if (!this.instance) {
91-
// handle bulkCreate AI primiary key
103+
// handle bulkCreate AI primary key
92104
if (
93105
data.constructor.name === 'ResultSetHeader'
94106
&& this.model
@@ -123,7 +135,8 @@ class Query extends AbstractQuery {
123135
allowNull: _result.Null === 'YES',
124136
defaultValue: _result.Default,
125137
primaryKey: _result.Key === 'PRI',
126-
autoIncrement: Object.prototype.hasOwnProperty.call(_result, 'Extra') && _result.Extra.toLowerCase() === 'auto_increment',
138+
autoIncrement: Object.prototype.hasOwnProperty.call(_result, 'Extra')
139+
&& _result.Extra.toLowerCase() === 'auto_increment',
127140
comment: _result.Comment ? _result.Comment : null
128141
};
129142
}
@@ -166,7 +179,9 @@ class Query extends AbstractQuery {
166179
const warningMessage = `MySQL Warnings (${this.connection.uuid || 'default'}): `;
167180
const messages = [];
168181
for (const _warningRow of warningResults) {
169-
if (_warningRow === undefined || typeof _warningRow[Symbol.iterator] !== 'function') continue;
182+
if (_warningRow === undefined || typeof _warningRow[Symbol.iterator] !== 'function') {
183+
continue;
184+
}
170185
for (const _warningResult of _warningRow) {
171186
if (Object.prototype.hasOwnProperty.call(_warningResult, 'Message')) {
172187
messages.push(_warningResult.Message);
@@ -187,7 +202,7 @@ class Query extends AbstractQuery {
187202
const errCode = err.errno || err.code;
188203

189204
switch (errCode) {
190-
case 1062: {
205+
case ER_DUP_ENTRY: {
191206
const match = err.message.match(/Duplicate entry '([\s\S]*)' for key '?((.|\s)*?)'?$/);
192207
let fields = {};
193208
let message = 'Validation error';
@@ -218,15 +233,17 @@ class Query extends AbstractQuery {
218233
return new sequelizeErrors.UniqueConstraintError({ message, errors, parent: err, fields });
219234
}
220235

221-
case 1451:
222-
case 1452: {
236+
case ER_ROW_IS_REFERENCED:
237+
case ER_NO_REFERENCED_ROW: {
223238
// e.g. CONSTRAINT `example_constraint_name` FOREIGN KEY (`example_id`) REFERENCES `examples` (`id`)
224-
const match = err.message.match(/CONSTRAINT ([`"])(.*)\1 FOREIGN KEY \(\1(.*)\1\) REFERENCES \1(.*)\1 \(\1(.*)\1\)/);
239+
const match = err.message.match(
240+
/CONSTRAINT ([`"])(.*)\1 FOREIGN KEY \(\1(.*)\1\) REFERENCES \1(.*)\1 \(\1(.*)\1\)/
241+
);
225242
const quoteChar = match ? match[1] : '`';
226243
const fields = match ? match[3].split(new RegExp(`${quoteChar}, *${quoteChar}`)) : undefined;
227244

228245
return new sequelizeErrors.ForeignKeyConstraintError({
229-
reltype: String(errCode) === '1451' ? 'parent' : 'child',
246+
reltype: String(errCode) === String(ER_ROW_IS_REFERENCED) ? 'parent' : 'child',
230247
table: match ? match[4] : undefined,
231248
fields,
232249
value: fields && fields.length && this.instance && this.instance[fields[0]] || undefined,

0 commit comments

Comments
 (0)