sequelize
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.
519 lines (518 loc) • 18.1 kB
JavaScript
;
var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
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;
};
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
var __markAsModule = (target) => __defProp(target, "__esModule", { value: true });
var __export = (target, all) => {
__markAsModule(target);
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
__export(exports, {
OracleQuery: () => OracleQuery
});
const AbstractQuery = require("../abstract/query");
const SequelizeErrors = require("../../errors");
const parserStore = require("../parserStore")("oracle");
const _ = require("lodash");
const Utils = require("../../utils");
const { logger } = require("../../utils/logger");
const debug = logger.debugContext("sql:oracle");
class OracleQuery extends AbstractQuery {
constructor(connection, sequelize, options) {
super(connection, sequelize, options);
this.options = _.extend({
logging: console.log,
plain: false,
raw: false
}, options || {});
this.checkLoggingOption();
this.outFormat = options.outFormat || this.sequelize.connectionManager.lib.OBJECT;
}
getInsertIdField() {
return "id";
}
getExecOptions() {
const execOpts = { outFormat: this.outFormat, autoCommit: this.autoCommit };
const oracledb = this.sequelize.connectionManager.lib;
if (this.model && this.isSelectQuery()) {
const fInfo = {};
const keys = Object.keys(this.model.tableAttributes);
for (const key of keys) {
const keyValue = this.model.tableAttributes[key];
if (keyValue.type.key === "DECIMAL") {
fInfo[key] = { type: oracledb.STRING };
}
if (keyValue.type.key === "BIGINT") {
fInfo[key] = { type: oracledb.STRING };
}
}
if (fInfo) {
execOpts.fetchInfo = fInfo;
}
}
return execOpts;
}
_convertBindAttributes(bindingDictionary, oracledb) {
if (this.model && this.options[bindingDictionary]) {
const keys = Object.keys(this.model.tableAttributes);
for (const key of keys) {
const keyValue = this.model.tableAttributes[key];
if (keyValue.type.key === "BIGINT") {
const oldBinding = this.options[bindingDictionary][key];
if (oldBinding) {
this.options[bindingDictionary][key] = __spreadProps(__spreadValues({}, oldBinding), {
type: oracledb.STRING,
maxSize: 1e7
});
}
}
}
}
}
async run(sql, parameters) {
const oracledb = this.sequelize.connectionManager.lib;
const complete = this._logQuery(sql, debug, parameters);
const outParameters = [];
const bindParameters = [];
const bindDef = [];
if (!sql.match(/END;$/)) {
this.sql = sql.replace(/; *$/, "");
} else {
this.sql = sql;
}
if (this.options.outBindAttributes && (Array.isArray(parameters) || _.isPlainObject(parameters))) {
this._convertBindAttributes("outBindAttributes", oracledb);
outParameters.push(...Object.values(this.options.outBindAttributes));
if (this.isUpsertQuery()) {
outParameters.push({ dir: oracledb.BIND_OUT });
}
}
this.bindParameters = outParameters;
if (Array.isArray(parameters) || _.isPlainObject(parameters)) {
if (this.options.executeMany) {
this._convertBindAttributes("inbindAttributes", oracledb);
bindDef.push(...Object.values(this.options.inbindAttributes));
bindDef.push(...outParameters);
this.bindParameters = parameters;
} else if (this.isRawQuery()) {
this.bindParameters = parameters;
} else {
Object.values(parameters).forEach((value) => {
bindParameters.push(value);
});
bindParameters.push(...outParameters);
Object.assign(this.bindParameters, bindParameters);
}
}
if (this.sql.startsWith("BEGIN TRANSACTION")) {
this.autocommit = false;
return Promise.resolve();
}
if (this.sql.startsWith("SET AUTOCOMMIT ON")) {
this.autocommit = true;
return Promise.resolve();
}
if (this.sql.startsWith("SET AUTOCOMMIT OFF")) {
this.autocommit = false;
return Promise.resolve();
}
if (this.sql.startsWith("DECLARE x NUMBER")) {
if (this.autoCommit === void 0) {
if (this.connection.uuid) {
this.autoCommit = false;
} else {
this.autoCommit = true;
}
}
try {
await this.connection.execute(this.sql, this.bindParameters, { autoCommit: this.autoCommit });
return Object.create(null);
} catch (error) {
throw this.formatError(error);
} finally {
complete();
}
}
if (this.sql.startsWith("BEGIN")) {
if (this.autoCommit === void 0) {
if (this.connection.uuid) {
this.autoCommit = false;
} else {
this.autoCommit = true;
}
}
try {
const result = await this.connection.execute(this.sql, this.bindParameters, {
outFormat: this.outFormat,
autoCommit: this.autoCommit
});
if (!Array.isArray(result.outBinds)) {
return [result.outBinds];
}
return result.outBinds;
} catch (error) {
throw this.formatError(error);
} finally {
complete();
}
}
if (this.sql.startsWith("COMMIT TRANSACTION")) {
try {
await this.connection.commit();
return Object.create(null);
} catch (error) {
throw this.formatError(error);
} finally {
complete();
}
}
if (this.sql.startsWith("ROLLBACK TRANSACTION")) {
try {
await this.connection.rollback();
return Object.create(null);
} catch (error) {
throw this.formatError(error);
} finally {
complete();
}
}
if (this.sql.startsWith("SET TRANSACTION")) {
try {
await this.connection.execute(this.sql, [], { autoCommit: false });
return Object.create(null);
} catch (error) {
throw this.formatError(error);
} finally {
complete();
}
}
if (this.autoCommit === void 0) {
if (this.connection.uuid) {
this.autoCommit = false;
} else {
this.autoCommit = true;
}
}
if ("inputParameters" in this.options && this.options.inputParameters !== null) {
Object.assign(this.bindParameters, this.options.inputParameters);
}
const execOpts = this.getExecOptions();
if (this.options.executeMany && bindDef.length > 0) {
execOpts.bindDefs = bindDef;
}
const executePromise = this.options.executeMany ? this.connection.executeMany(this.sql, this.bindParameters, execOpts) : this.connection.execute(this.sql, this.bindParameters, execOpts);
try {
const result = await executePromise;
return this.formatResults(result);
} catch (error) {
throw this.formatError(error);
} finally {
complete();
}
}
static formatBindParameters(sql, values, dialect) {
const replacementFunc = (match, key, values2) => {
if (values2[key] !== void 0) {
return `:${key}`;
}
return void 0;
};
sql = AbstractQuery.formatBindParameters(sql, values, dialect, replacementFunc)[0];
return [sql, values];
}
_getAttributeMap(attrsMap, rawAttributes) {
attrsMap = Object.assign(attrsMap, _.reduce(rawAttributes, (mp, _2, key) => {
const catalogKey = this.sequelize.queryInterface.queryGenerator.getCatalogName(key);
mp[catalogKey] = key;
return mp;
}, {}));
}
_processRows(rows) {
let result = rows;
let attrsMap = {};
if (this.sequelize.options.quoteIdentifiers === false) {
attrsMap = _.reduce(this.options.attributes, (mp, v) => {
if (typeof v === "object") {
v = v[1];
}
const catalogv = this.sequelize.queryInterface.queryGenerator.getCatalogName(v);
mp[catalogv] = v;
return mp;
}, {});
if (this.model) {
this._getAttributeMap(attrsMap, this.model.rawAttributes);
}
if (this.options.aliasesMapping) {
const obj = Object.fromEntries(this.options.aliasesMapping);
rows = rows.map((row) => _.toPairs(row).reduce((acc, [key, value]) => {
const mapping = Object.values(obj).find((element) => {
const catalogElement = this.sequelize.queryInterface.queryGenerator.getCatalogName(element);
return catalogElement === key;
});
if (mapping)
acc[mapping || key] = value;
return acc;
}, {}));
}
result = rows.map((row) => {
return _.mapKeys(row, (value, key) => {
const targetAttr = attrsMap[key];
if (typeof targetAttr === "string" && targetAttr !== key) {
return targetAttr;
}
return key;
});
});
}
if (this.model) {
result = result.map((row) => {
return _.mapValues(row, (value, key) => {
if (this.model.rawAttributes[key] && this.model.rawAttributes[key].type) {
let typeid = this.model.rawAttributes[key].type.toLocaleString();
if (this.model.rawAttributes[key].type.key === "JSON") {
value = JSON.parse(value);
}
if (typeid.indexOf("(") > -1 && this.model.rawAttributes[key].type.key !== "BOOLEAN") {
typeid = typeid.substr(0, typeid.indexOf("("));
}
const parse = parserStore.get(typeid);
if (value !== null & !!parse) {
value = parse(value);
}
}
return value;
});
});
}
return result;
}
formatResults(data) {
let result = this.instance;
if (this.isInsertQuery(data)) {
let insertData;
if (data.outBinds) {
const keys = Object.keys(this.options.outBindAttributes);
insertData = data.outBinds;
if (this.instance) {
insertData = [insertData];
}
const res = insertData.map((row) => {
const obj = {};
row.forEach((element, index) => {
obj[keys[index]] = element[0];
});
return obj;
});
insertData = res;
if (!this.instance) {
result = res;
}
}
this.handleInsertQuery(insertData);
return [result, data.rowsAffected];
}
if (this.isShowTablesQuery()) {
result = this.handleShowTablesQuery(data.rows);
} else if (this.isDescribeQuery()) {
result = {};
const table = Object.keys(this.sequelize.models);
const modelAttributes = {};
if (this.sequelize.models && table.length > 0) {
this._getAttributeMap(modelAttributes, this.sequelize.models[table[0]].rawAttributes);
}
data.rows.forEach((_result) => {
if (_result.Default) {
_result.Default = _result.Default.replace("('", "").replace("')", "").replace(/'/g, "");
}
if (!(modelAttributes[_result.COLUMN_NAME] in result)) {
let key = modelAttributes[_result.COLUMN_NAME];
if (!key) {
key = _result.COLUMN_NAME;
}
result[key] = {
type: _result.DATA_TYPE.toUpperCase(),
allowNull: _result.NULLABLE === "N" ? false : true,
defaultValue: void 0,
primaryKey: _result.CONSTRAINT_TYPE === "P"
};
}
});
} else if (this.isShowIndexesQuery()) {
result = this.handleShowIndexesQuery(data.rows);
} else if (this.isSelectQuery()) {
const rows = data.rows;
const result2 = this._processRows(rows);
return this.handleSelectQuery(result2);
} else if (this.isCallQuery()) {
result = data.rows[0];
} else if (this.isUpdateQuery()) {
result = [result, data.rowsAffected];
} else if (this.isBulkUpdateQuery()) {
result = data.rowsAffected;
} else if (this.isBulkDeleteQuery()) {
result = data.rowsAffected;
} else if (this.isVersionQuery()) {
const version = data.rows[0].VERSION_FULL;
if (version) {
const versions = version.split(".");
result = `${versions[0]}.${versions[1]}.${versions[2]}`;
} else {
result = "0.0.0";
}
} else if (this.isForeignKeysQuery()) {
result = data.rows;
} else if (this.isUpsertQuery()) {
data = data.outBinds;
const keys = Object.keys(this.options.outBindAttributes);
const obj = {};
for (const k in keys) {
obj[keys[k]] = data[k];
}
obj.isUpdate = data[data.length - 1];
data = obj;
result = [{ isNewRecord: data.isUpdate, value: data }, data.isUpdate == 0];
} else if (this.isShowConstraintsQuery()) {
result = this.handleShowConstraintsQuery(data);
} else if (this.isRawQuery()) {
if (data && data.rows) {
return [data.rows, data.metaData];
}
return [data, data];
}
return result;
}
handleShowConstraintsQuery(data) {
return data.rows.map((result) => {
const constraint = {};
for (const key in result) {
constraint[_.camelCase(key)] = result[key].toLowerCase();
}
return constraint;
});
}
handleShowTablesQuery(results) {
return results.map((resultSet) => {
return {
tableName: resultSet.TABLE_NAME,
schema: resultSet.TABLE_SCHEMA
};
});
}
formatError(err) {
let match;
match = err.message.match(/unique constraint ([\s\S]*) violated/);
if (match && match.length > 1) {
match[1] = match[1].replace("(", "").replace(")", "").split(".")[1];
const errors = [];
let fields = [], message = "Validation error", uniqueKey = null;
if (this.model) {
const uniqueKeys = Object.keys(this.model.uniqueKeys);
const currKey = uniqueKeys.find((key) => {
return key.toUpperCase() === match[1].toUpperCase() || key.toUpperCase() === `"${match[1].toUpperCase()}"`;
});
if (currKey) {
uniqueKey = this.model.uniqueKeys[currKey];
fields = uniqueKey.fields;
}
if (uniqueKey && !!uniqueKey.msg) {
message = uniqueKey.msg;
}
fields.forEach((field) => {
errors.push(new SequelizeErrors.ValidationErrorItem(this.getUniqueConstraintErrorMessage(field), "unique violation", field, null));
});
}
return new SequelizeErrors.UniqueConstraintError({
message,
errors,
err,
fields
});
}
match = err.message.match(/ORA-02291/) || err.message.match(/ORA-02292/);
if (match && match.length > 0) {
return new SequelizeErrors.ForeignKeyConstraintError({
fields: null,
index: match[1],
parent: err
});
}
match = err.message.match(/ORA-02443/);
if (match && match.length > 0) {
return new SequelizeErrors.UnknownConstraintError(match[1]);
}
return new SequelizeErrors.DatabaseError(err);
}
isShowIndexesQuery() {
return this.sql.indexOf("SELECT i.index_name,i.table_name, i.column_name, u.uniqueness") > -1;
}
isSelectCountQuery() {
return this.sql.toUpperCase().indexOf("SELECT COUNT(") > -1;
}
handleShowIndexesQuery(data) {
const acc = [];
data.forEach((indexRecord) => {
if (!acc[indexRecord.INDEX_NAME]) {
acc[indexRecord.INDEX_NAME] = {
unique: indexRecord.UNIQUENESS === "UNIQUE" ? true : false,
primary: indexRecord.CONSTRAINT_TYPE === "P",
name: indexRecord.INDEX_NAME.toLowerCase(),
tableName: indexRecord.TABLE_NAME.toLowerCase(),
type: void 0
};
acc[indexRecord.INDEX_NAME].fields = [];
}
acc[indexRecord.INDEX_NAME].fields.push({
attribute: indexRecord.COLUMN_NAME,
length: void 0,
order: indexRecord.DESCEND,
collate: void 0
});
});
const returnIndexes = [];
const accKeys = Object.keys(acc);
for (const accKey of accKeys) {
const columns = {};
columns.fields = acc[accKey].fields;
if (acc[accKey].name.match(/sys_c[0-9]*/)) {
acc[accKey].name = Utils.nameIndex(columns, acc[accKey].tableName).name;
}
returnIndexes.push(acc[accKey]);
}
return returnIndexes;
}
handleInsertQuery(results, metaData) {
if (this.instance && results.length > 0) {
if ("pkReturnVal" in results[0]) {
results[0][this.model.primaryKeyAttribute] = results[0].pkReturnVal;
delete results[0].pkReturnVal;
}
const autoIncrementField = this.model.autoIncrementAttribute;
let autoIncrementFieldAlias = null, id = null;
if (Object.prototype.hasOwnProperty.call(this.model.rawAttributes, autoIncrementField) && this.model.rawAttributes[autoIncrementField].field !== void 0)
autoIncrementFieldAlias = this.model.rawAttributes[autoIncrementField].field;
id = id || results && results[0][this.getInsertIdField()];
id = id || metaData && metaData[this.getInsertIdField()];
id = id || results && results[0][autoIncrementField];
id = id || autoIncrementFieldAlias && results && results[0][autoIncrementFieldAlias];
this.instance[autoIncrementField] = id;
}
}
}
//# sourceMappingURL=query.js.map