sequelize-dm
Version:
Sequelize is a promise-based Node.js ORM tool for Postgres, MySQL, MariaDB, SQLite, Microsoft SQL Server, Amazon Redshift and Snowflake’s Data Cloud. It features solid transaction support, relations, eager and lazy loading, read replication and more.
260 lines (259 loc) • 9.6 kB
JavaScript
;
var __defProp = Object.defineProperty;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
const AbstractQuery = require("../abstract/query");
const sequelizeErrors = require("../../errors");
const _ = require("lodash");
const { logger } = require("../../utils/logger");
const { isStream, streamToString } = require("./utils");
const DmError = require("./error");
const ER_DUP_ENTRY = 1062;
const ER_DEADLOCK = 1213;
const ER_ROW_IS_REFERENCED = 1451;
const ER_NO_REFERENCED_ROW = 1452;
const debug = logger.debugContext("sql:dmdb");
class Query extends AbstractQuery {
constructor(connection, sequelize, options) {
super(connection, sequelize, __spreadValues({ showWarnings: false }, options));
}
static formatBindParameters(sql, values, dialect) {
const bindParam = [];
const replacementFunc = (match, key, values_) => {
if (values_[key] !== void 0) {
bindParam.push(values_[key]);
return "?";
}
};
sql = AbstractQuery.formatBindParameters(sql, values, dialect, replacementFunc)[0];
return [sql, bindParam.length > 0 ? bindParam : void 0];
}
async run(sql, parameters) {
this.sql = sql;
const { connection, options } = this;
const showWarnings = this.sequelize.options.showWarnings || options.showWarnings;
const complete = this._logQuery(sql, debug, parameters);
if (parameters) {
debug("parameters(%j)", parameters);
}
let results;
try {
results = await new Promise((resolve, reject) => {
connection.execute(sql, parameters, (error, result) => error ? reject(error) : resolve(result));
});
} catch (error) {
throw new DmError(error, sql, parameters);
} finally {
complete();
}
if (showWarnings && results && results.warningStatus > 0) {
await this.logWarnings(results);
}
return this.formatResults(results);
}
formatResults(data) {
let result = this.instance;
if (this.isInsertQuery(data)) {
this.handleInsertQuery(data);
if (!this.instance) {
if (data.constructor.name === "ResultSetHeader" && this.model && this.model.autoIncrementAttribute && this.model.autoIncrementAttribute === this.model.primaryKeyAttribute && this.model.rawAttributes[this.model.primaryKeyAttribute]) {
const startId = data[this.getInsertIdField()];
result = [];
for (let i = startId; i < startId + data.affectedRows; i++) {
result.push({ [this.model.rawAttributes[this.model.primaryKeyAttribute].field]: i });
}
} else {
result = data[this.getInsertIdField()];
}
}
}
if (this.isSelectQuery()) {
return this.handleSelectQuery(data);
}
if (this.isShowTablesQuery()) {
return this.handleShowTablesQuery(data);
}
if (this.isDescribeQuery()) {
result = {};
for (const _result of data) {
const enumRegex = /^enum/i;
result[_result.Field] = {
type: enumRegex.test(_result.Type) ? _result.Type.replace(enumRegex, "ENUM") : _result.Type.toUpperCase(),
allowNull: _result.Null === "YES",
defaultValue: _result.Default,
primaryKey: _result.Key === "PRI",
autoIncrement: Object.prototype.hasOwnProperty.call(_result, "Extra") && _result.Extra.toLowerCase() === "auto_increment",
comment: _result.Comment ? _result.Comment : null
};
}
return result;
}
if (this.isShowIndexesQuery()) {
return this.handleShowIndexesQuery(data);
}
if (this.isCallQuery()) {
return data[0];
}
if (this.isBulkUpdateQuery() || this.isBulkDeleteQuery()) {
return data.rowsAffected;
}
if (this.isVersionQuery()) {
return "1.0.0";
}
if (this.isForeignKeysQuery()) {
return data;
}
if (this.isUpsertQuery()) {
return [result, data.affectedRows === 1];
}
if (this.isInsertQuery()) {
return [result, data.rowsAffected];
}
if (this.isUpdateQuery()) {
return [result, data.rowsAffected];
}
if (this.isShowConstraintsQuery()) {
return data;
}
if (this.isRawQuery()) {
return [data, data];
}
return result;
}
async resultRawToArray(response) {
const results = [];
for (const row of response.rows) {
const data = {};
for (let i = 0; i < response.metaData.length; i++) {
if (isStream(row[i])) {
data[response.metaData[i].name] = await streamToString(row[i]);
} else if (typeof row[i] === "bigint") {
data[response.metaData[i].name] = Number(row[i]);
} else {
data[response.metaData[i].name] = row[i];
}
if (this.model && this.model._jsonAttributes.has(response.metaData[i].name)) {
data[response.metaData[i].name] = JSON.parse(data[response.metaData[i].name]);
}
}
results.push(data);
}
return results;
}
async handleSelectQuery(response) {
const results = await this.resultRawToArray(response);
return super.handleSelectQuery(results);
}
handleInsertQuery(results, metaData) {
if (this.instance) {
const autoIncrementAttribute = this.model.autoIncrementAttribute;
const id = results.outBinds[0] || null;
this.instance[autoIncrementAttribute] = id;
}
}
async logWarnings(results) {
const warningResults = await this.run("SHOW WARNINGS");
const warningMessage = `MySQL Warnings (${this.connection.uuid || "default"}): `;
const messages = [];
for (const _warningRow of warningResults) {
if (_warningRow === void 0 || typeof _warningRow[Symbol.iterator] !== "function") {
continue;
}
for (const _warningResult of _warningRow) {
if (Object.prototype.hasOwnProperty.call(_warningResult, "Message")) {
messages.push(_warningResult.Message);
} else {
for (const _objectKey of _warningResult.keys()) {
messages.push([_objectKey, _warningResult[_objectKey]].join(": "));
}
}
}
}
this.sequelize.log(warningMessage + messages.join("; "), this.options);
return results;
}
formatError(err, errStack) {
const errCode = err.errno || err.code;
switch (errCode) {
case ER_DUP_ENTRY: {
const match = err.message.match(/Duplicate entry '([\S\s]*)' for key '?((.|\s)*?)'?$/);
let fields = {};
let message = "Validation error";
const values = match ? match[1].split("-") : void 0;
const fieldKey = match ? match[2].split(".").pop() : void 0;
const fieldVal = match ? match[1] : void 0;
const uniqueKey = this.model && this.model.uniqueKeys[fieldKey];
if (uniqueKey) {
if (uniqueKey.msg) {
message = uniqueKey.msg;
}
fields = _.zipObject(uniqueKey.fields, values);
} else {
fields[fieldKey] = fieldVal;
}
const errors = [];
_.forOwn(fields, (value, field) => {
errors.push(new sequelizeErrors.ValidationErrorItem(this.getUniqueConstraintErrorMessage(field), "unique violation", field, value, this.instance, "not_unique"));
});
return new sequelizeErrors.UniqueConstraintError({ message, errors, parent: err, fields, stack: errStack });
}
case ER_ROW_IS_REFERENCED:
case ER_NO_REFERENCED_ROW: {
const match = err.message.match(/CONSTRAINT (["`])(.*)\1 FOREIGN KEY \(\1(.*)\1\) REFERENCES \1(.*)\1 \(\1(.*)\1\)/);
const quoteChar = match ? match[1] : "`";
const fields = match ? match[3].split(new RegExp(`${quoteChar}, *${quoteChar}`)) : void 0;
return new sequelizeErrors.ForeignKeyConstraintError({
reltype: String(errCode) === String(ER_ROW_IS_REFERENCED) ? "parent" : "child",
table: match ? match[4] : void 0,
fields,
value: fields && fields.length && this.instance && this.instance[fields[0]] || void 0,
index: match ? match[2] : void 0,
parent: err,
stack: errStack
});
}
default:
return new sequelizeErrors.DatabaseError(err, { stack: errStack });
}
}
handleShowIndexesQuery(data) {
data = data.reduce((acc, item) => {
if (!(item.Key_name in acc)) {
acc[item.Key_name] = item;
item.fields = [];
}
acc[item.Key_name].fields[item.Seq_in_index - 1] = {
attribute: item.Column_name,
length: item.Sub_part || void 0,
order: item.Collation === "A" ? "ASC" : void 0
};
delete item.column_name;
return acc;
}, {});
return _.map(data, (item) => ({
primary: item.Key_name === "PRIMARY",
fields: item.fields,
name: item.Key_name,
tableName: item.Table,
unique: item.Non_unique !== 1,
type: item.Index_type
}));
}
}
module.exports = Query;
module.exports.Query = Query;
module.exports.default = Query;
//# sourceMappingURL=query.js.map