You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
711 lines
28 KiB
711 lines
28 KiB
2 years ago
|
"use strict";
|
||
|
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));
|
||
|
const _ = require("lodash");
|
||
|
const Utils = require("../../utils");
|
||
|
const DataTypes = require("../../data-types");
|
||
|
const AbstractQueryGenerator = require("../abstract/query-generator");
|
||
|
const randomBytes = require("crypto").randomBytes;
|
||
|
const Op = require("../../operators");
|
||
|
const throwMethodUndefined = function(methodName) {
|
||
|
throw new Error(`The method "${methodName}" is not defined! Please add it to your sql dialect.`);
|
||
|
};
|
||
|
class Db2QueryGenerator extends AbstractQueryGenerator {
|
||
|
constructor(options) {
|
||
|
super(options);
|
||
|
this.OperatorMap = __spreadProps(__spreadValues({}, this.OperatorMap), {
|
||
|
[Op.regexp]: "REGEXP_LIKE",
|
||
|
[Op.notRegexp]: "NOT REGEXP_LIKE"
|
||
|
});
|
||
|
this.autoGenValue = 1;
|
||
|
}
|
||
|
createSchema(schema) {
|
||
|
return [
|
||
|
"CREATE SCHEMA",
|
||
|
this.quoteIdentifier(schema),
|
||
|
";"
|
||
|
].join(" ");
|
||
|
}
|
||
|
dropSchema(schema) {
|
||
|
const query = `CALL SYSPROC.ADMIN_DROP_SCHEMA(${wrapSingleQuote(schema.trim())}, NULL, ? , ?)`;
|
||
|
const sql = { query };
|
||
|
sql.bind = [
|
||
|
{ ParamType: "INOUT", Data: "ERRORSCHEMA" },
|
||
|
{ ParamType: "INOUT", Data: "ERRORTABLE" }
|
||
|
];
|
||
|
return sql;
|
||
|
}
|
||
|
showSchemasQuery() {
|
||
|
return `SELECT SCHEMANAME AS "schema_name" FROM SYSCAT.SCHEMATA WHERE (SCHEMANAME NOT LIKE 'SYS%') AND SCHEMANAME NOT IN ('NULLID', 'SQLJ', 'ERRORSCHEMA')`;
|
||
|
}
|
||
|
versionQuery() {
|
||
|
return "select service_level as VERSION from TABLE (sysproc.env_get_inst_info()) as A";
|
||
|
}
|
||
|
createTableQuery(tableName, attributes, options) {
|
||
|
const query = "CREATE TABLE <%= table %> (<%= attributes %>)", primaryKeys = [], foreignKeys = {}, attrStr = [], commentTemplate = " -- <%= comment %>, TableName = <%= table %>, ColumnName = <%= column %>;";
|
||
|
let commentStr = "";
|
||
|
for (const attr in attributes) {
|
||
|
if (Object.prototype.hasOwnProperty.call(attributes, attr)) {
|
||
|
let dataType = attributes[attr];
|
||
|
let match;
|
||
|
if (dataType.includes("COMMENT ")) {
|
||
|
const commentMatch = dataType.match(/^(.+) (COMMENT.*)$/);
|
||
|
if (commentMatch && commentMatch.length > 2) {
|
||
|
const commentText = commentMatch[2].replace(/COMMENT/, "").trim();
|
||
|
commentStr += _.template(commentTemplate, this._templateSettings)({
|
||
|
table: this.quoteIdentifier(tableName),
|
||
|
comment: this.escape(commentText),
|
||
|
column: this.quoteIdentifier(attr)
|
||
|
});
|
||
|
dataType = commentMatch[1];
|
||
|
}
|
||
|
}
|
||
|
if (_.includes(dataType, "PRIMARY KEY")) {
|
||
|
primaryKeys.push(attr);
|
||
|
if (_.includes(dataType, "REFERENCES")) {
|
||
|
match = dataType.match(/^(.+) (REFERENCES.*)$/);
|
||
|
attrStr.push(`${this.quoteIdentifier(attr)} ${match[1].replace(/PRIMARY KEY/, "")}`);
|
||
|
foreignKeys[attr] = match[2];
|
||
|
} else {
|
||
|
attrStr.push(`${this.quoteIdentifier(attr)} ${dataType.replace(/PRIMARY KEY/, "")}`);
|
||
|
}
|
||
|
} else if (_.includes(dataType, "REFERENCES")) {
|
||
|
match = dataType.match(/^(.+) (REFERENCES.*)$/);
|
||
|
attrStr.push(`${this.quoteIdentifier(attr)} ${match[1]}`);
|
||
|
foreignKeys[attr] = match[2];
|
||
|
} else {
|
||
|
if (options && options.uniqueKeys) {
|
||
|
for (const ukey in options.uniqueKeys) {
|
||
|
if (options.uniqueKeys[ukey].fields.includes(attr) && !_.includes(dataType, "NOT NULL")) {
|
||
|
dataType += " NOT NULL";
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
attrStr.push(`${this.quoteIdentifier(attr)} ${dataType}`);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
const values = {
|
||
|
table: this.quoteTable(tableName),
|
||
|
attributes: attrStr.join(", ")
|
||
|
}, pkString = primaryKeys.map((pk) => {
|
||
|
return this.quoteIdentifier(pk);
|
||
|
}).join(", ");
|
||
|
if (options && options.uniqueKeys) {
|
||
|
_.each(options.uniqueKeys, (columns, indexName) => {
|
||
|
if (columns.customIndex) {
|
||
|
if (!_.isString(indexName)) {
|
||
|
indexName = `uniq_${tableName}_${columns.fields.join("_")}`;
|
||
|
}
|
||
|
values.attributes += `, CONSTRAINT ${this.quoteIdentifier(indexName)} UNIQUE (${columns.fields.map((field) => this.quoteIdentifier(field)).join(", ")})`;
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
if (pkString.length > 0) {
|
||
|
values.attributes += `, PRIMARY KEY (${pkString})`;
|
||
|
}
|
||
|
for (const fkey in foreignKeys) {
|
||
|
if (Object.prototype.hasOwnProperty.call(foreignKeys, fkey)) {
|
||
|
values.attributes += `, FOREIGN KEY (${this.quoteIdentifier(fkey)}) ${foreignKeys[fkey]}`;
|
||
|
}
|
||
|
}
|
||
|
return `${_.template(query, this._templateSettings)(values).trim()};${commentStr}`;
|
||
|
}
|
||
|
describeTableQuery(tableName, schema) {
|
||
|
let sql = [
|
||
|
'SELECT NAME AS "Name", TBNAME AS "Table", TBCREATOR AS "Schema",',
|
||
|
'TRIM(COLTYPE) AS "Type", LENGTH AS "Length", SCALE AS "Scale",',
|
||
|
'NULLS AS "IsNull", DEFAULT AS "Default", COLNO AS "Colno",',
|
||
|
'IDENTITY AS "IsIdentity", KEYSEQ AS "KeySeq", REMARKS AS "Comment"',
|
||
|
"FROM",
|
||
|
"SYSIBM.SYSCOLUMNS",
|
||
|
"WHERE TBNAME =",
|
||
|
wrapSingleQuote(tableName)
|
||
|
].join(" ");
|
||
|
if (schema) {
|
||
|
sql += ` AND TBCREATOR =${wrapSingleQuote(schema)}`;
|
||
|
} else {
|
||
|
sql += " AND TBCREATOR = USER";
|
||
|
}
|
||
|
return `${sql};`;
|
||
|
}
|
||
|
renameTableQuery(before, after) {
|
||
|
const query = "RENAME TABLE <%= before %> TO <%= after %>;";
|
||
|
return _.template(query, this._templateSettings)({
|
||
|
before: this.quoteTable(before),
|
||
|
after: this.quoteTable(after)
|
||
|
});
|
||
|
}
|
||
|
showTablesQuery() {
|
||
|
return `SELECT TABNAME AS "tableName", TRIM(TABSCHEMA) AS "tableSchema" FROM SYSCAT.TABLES WHERE TABSCHEMA = USER AND TYPE = 'T' ORDER BY TABSCHEMA, TABNAME`;
|
||
|
}
|
||
|
tableExistsQuery(table) {
|
||
|
const tableName = table.tableName || table;
|
||
|
const schemaName = table.schema || this.sequelize.config.username.toUpperCase();
|
||
|
return `SELECT name FROM sysibm.systables WHERE NAME = ${wrapSingleQuote(tableName)} AND CREATOR = ${wrapSingleQuote(schemaName)}`;
|
||
|
}
|
||
|
dropTableQuery(tableName) {
|
||
|
const query = "DROP TABLE <%= table %>";
|
||
|
const values = {
|
||
|
table: this.quoteTable(tableName)
|
||
|
};
|
||
|
return `${_.template(query, this._templateSettings)(values).trim()};`;
|
||
|
}
|
||
|
addColumnQuery(table, key, dataType) {
|
||
|
dataType.field = key;
|
||
|
const query = "ALTER TABLE <%= table %> ADD <%= attribute %>;", attribute = _.template("<%= key %> <%= definition %>", this._templateSettings)({
|
||
|
key: this.quoteIdentifier(key),
|
||
|
definition: this.attributeToSQL(dataType, {
|
||
|
context: "addColumn"
|
||
|
})
|
||
|
});
|
||
|
return _.template(query, this._templateSettings)({
|
||
|
table: this.quoteTable(table),
|
||
|
attribute
|
||
|
});
|
||
|
}
|
||
|
removeColumnQuery(tableName, attributeName) {
|
||
|
const query = "ALTER TABLE <%= tableName %> DROP COLUMN <%= attributeName %>;";
|
||
|
return _.template(query, this._templateSettings)({
|
||
|
tableName: this.quoteTable(tableName),
|
||
|
attributeName: this.quoteIdentifier(attributeName)
|
||
|
});
|
||
|
}
|
||
|
changeColumnQuery(tableName, attributes) {
|
||
|
const query = "ALTER TABLE <%= tableName %> <%= query %>;";
|
||
|
const attrString = [], constraintString = [];
|
||
|
for (const attributeName in attributes) {
|
||
|
const attrValue = attributes[attributeName];
|
||
|
let defs = [attrValue];
|
||
|
if (Array.isArray(attrValue)) {
|
||
|
defs = attrValue;
|
||
|
}
|
||
|
for (let i = 0; i < defs.length; i++) {
|
||
|
const definition = defs[i];
|
||
|
if (definition.match(/REFERENCES/)) {
|
||
|
constraintString.push(_.template("<%= fkName %> FOREIGN KEY (<%= attrName %>) <%= definition %>", this._templateSettings)({
|
||
|
fkName: this.quoteIdentifier(`${attributeName}_foreign_idx`),
|
||
|
attrName: this.quoteIdentifier(attributeName),
|
||
|
definition: definition.replace(/.+?(?=REFERENCES)/, "")
|
||
|
}));
|
||
|
} else if (_.startsWith(definition, "DROP ")) {
|
||
|
attrString.push(_.template("<%= attrName %> <%= definition %>", this._templateSettings)({
|
||
|
attrName: this.quoteIdentifier(attributeName),
|
||
|
definition
|
||
|
}));
|
||
|
} else {
|
||
|
attrString.push(_.template("<%= attrName %> SET <%= definition %>", this._templateSettings)({
|
||
|
attrName: this.quoteIdentifier(attributeName),
|
||
|
definition
|
||
|
}));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
let finalQuery = "";
|
||
|
if (attrString.length) {
|
||
|
finalQuery += `ALTER COLUMN ${attrString.join(" ALTER COLUMN ")}`;
|
||
|
finalQuery += constraintString.length ? " " : "";
|
||
|
}
|
||
|
if (constraintString.length) {
|
||
|
finalQuery += `ADD CONSTRAINT ${constraintString.join(" ADD CONSTRAINT ")}`;
|
||
|
}
|
||
|
return _.template(query, this._templateSettings)({
|
||
|
tableName: this.quoteTable(tableName),
|
||
|
query: finalQuery
|
||
|
});
|
||
|
}
|
||
|
renameColumnQuery(tableName, attrBefore, attributes) {
|
||
|
const query = "ALTER TABLE <%= tableName %> RENAME COLUMN <%= before %> TO <%= after %>;", newName = Object.keys(attributes)[0];
|
||
|
return _.template(query, this._templateSettings)({
|
||
|
tableName: this.quoteTable(tableName),
|
||
|
before: this.quoteIdentifier(attrBefore),
|
||
|
after: this.quoteIdentifier(newName)
|
||
|
});
|
||
|
}
|
||
|
addConstraintQuery(tableName, options) {
|
||
|
options = options || {};
|
||
|
if (options.onUpdate && options.onUpdate.toUpperCase() === "CASCADE") {
|
||
|
delete options.onUpdate;
|
||
|
}
|
||
|
const constraintSnippet = this.getConstraintSnippet(tableName, options);
|
||
|
if (typeof tableName === "string") {
|
||
|
tableName = this.quoteIdentifiers(tableName);
|
||
|
} else {
|
||
|
tableName = this.quoteTable(tableName);
|
||
|
}
|
||
|
return `ALTER TABLE ${tableName} ADD ${constraintSnippet};`;
|
||
|
}
|
||
|
bulkInsertQuery(tableName, attrValueHashes, options, attributes) {
|
||
|
options = options || {};
|
||
|
attributes = attributes || {};
|
||
|
let query = "INSERT INTO <%= table %> (<%= attributes %>)<%= output %> VALUES <%= tuples %>;";
|
||
|
if (options.returning) {
|
||
|
query = "SELECT * FROM FINAL TABLE( INSERT INTO <%= table %> (<%= attributes %>)<%= output %> VALUES <%= tuples %>);";
|
||
|
}
|
||
|
const emptyQuery = "INSERT INTO <%= table %>", tuples = [], allAttributes = [], allQueries = [];
|
||
|
let outputFragment;
|
||
|
const valuesForEmptyQuery = [];
|
||
|
if (options.returning) {
|
||
|
outputFragment = "";
|
||
|
}
|
||
|
_.forEach(attrValueHashes, (attrValueHash) => {
|
||
|
const fields = Object.keys(attrValueHash);
|
||
|
const firstAttr = attributes[fields[0]];
|
||
|
if (fields.length === 1 && firstAttr && firstAttr.autoIncrement && attrValueHash[fields[0]] === null) {
|
||
|
valuesForEmptyQuery.push(`(${this.autoGenValue++})`);
|
||
|
return;
|
||
|
}
|
||
|
_.forOwn(attrValueHash, (value, key) => {
|
||
|
if (allAttributes.indexOf(key) === -1) {
|
||
|
if (value === null && attributes[key] && attributes[key].autoIncrement)
|
||
|
return;
|
||
|
allAttributes.push(key);
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
if (valuesForEmptyQuery.length > 0) {
|
||
|
allQueries.push(`${emptyQuery} VALUES ${valuesForEmptyQuery.join(",")}`);
|
||
|
}
|
||
|
if (allAttributes.length > 0) {
|
||
|
_.forEach(attrValueHashes, (attrValueHash) => {
|
||
|
tuples.push(`(${allAttributes.map((key) => this.escape(attrValueHash[key]), void 0, { context: "INSERT" }).join(",")})`);
|
||
|
});
|
||
|
allQueries.push(query);
|
||
|
}
|
||
|
const replacements = {
|
||
|
table: this.quoteTable(tableName),
|
||
|
attributes: allAttributes.map((attr) => this.quoteIdentifier(attr)).join(","),
|
||
|
tuples,
|
||
|
output: outputFragment
|
||
|
};
|
||
|
const generatedQuery = _.template(allQueries.join(";"), this._templateSettings)(replacements);
|
||
|
return generatedQuery;
|
||
|
}
|
||
|
updateQuery(tableName, attrValueHash, where, options, attributes) {
|
||
|
const sql = super.updateQuery(tableName, attrValueHash, where, options, attributes);
|
||
|
options = options || {};
|
||
|
_.defaults(options, this.options);
|
||
|
if (!options.limit) {
|
||
|
sql.query = `SELECT * FROM FINAL TABLE (${sql.query});`;
|
||
|
return sql;
|
||
|
}
|
||
|
attrValueHash = Utils.removeNullValuesFromHash(attrValueHash, options.omitNull, options);
|
||
|
const modelAttributeMap = {};
|
||
|
const values = [];
|
||
|
const bind = [];
|
||
|
const bindParam = options.bindParam || this.bindParam(bind);
|
||
|
if (attributes) {
|
||
|
_.each(attributes, (attribute, key) => {
|
||
|
modelAttributeMap[key] = attribute;
|
||
|
if (attribute.field) {
|
||
|
modelAttributeMap[attribute.field] = attribute;
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
for (const key in attrValueHash) {
|
||
|
const value = attrValueHash[key];
|
||
|
if (value instanceof Utils.SequelizeMethod || options.bindParam === false) {
|
||
|
values.push(`${this.quoteIdentifier(key)}=${this.escape(value, modelAttributeMap && modelAttributeMap[key] || void 0, { context: "UPDATE" })}`);
|
||
|
} else {
|
||
|
values.push(`${this.quoteIdentifier(key)}=${this.format(value, modelAttributeMap && modelAttributeMap[key] || void 0, { context: "UPDATE" }, bindParam)}`);
|
||
|
}
|
||
|
}
|
||
|
let query;
|
||
|
const whereOptions = _.defaults({ bindParam }, options);
|
||
|
query = `UPDATE (SELECT * FROM ${this.quoteTable(tableName)} ${this.whereQuery(where, whereOptions)} FETCH NEXT ${this.escape(options.limit)} ROWS ONLY) SET ${values.join(",")}`;
|
||
|
query = `SELECT * FROM FINAL TABLE (${query});`;
|
||
|
return { query, bind };
|
||
|
}
|
||
|
upsertQuery(tableName, insertValues, updateValues, where, model) {
|
||
|
const targetTableAlias = this.quoteTable(`${tableName}_target`);
|
||
|
const sourceTableAlias = this.quoteTable(`${tableName}_source`);
|
||
|
const primaryKeysAttrs = [];
|
||
|
const identityAttrs = [];
|
||
|
const uniqueAttrs = [];
|
||
|
const tableNameQuoted = this.quoteTable(tableName);
|
||
|
for (const key in model.rawAttributes) {
|
||
|
if (model.rawAttributes[key].primaryKey) {
|
||
|
primaryKeysAttrs.push(model.rawAttributes[key].field || key);
|
||
|
}
|
||
|
if (model.rawAttributes[key].unique) {
|
||
|
uniqueAttrs.push(model.rawAttributes[key].field || key);
|
||
|
}
|
||
|
if (model.rawAttributes[key].autoIncrement) {
|
||
|
identityAttrs.push(model.rawAttributes[key].field || key);
|
||
|
}
|
||
|
}
|
||
|
for (const index of model._indexes) {
|
||
|
if (index.unique && index.fields) {
|
||
|
for (const field of index.fields) {
|
||
|
const fieldName = typeof field === "string" ? field : field.name || field.attribute;
|
||
|
if (uniqueAttrs.indexOf(fieldName) === -1 && model.rawAttributes[fieldName]) {
|
||
|
uniqueAttrs.push(fieldName);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
const updateKeys = Object.keys(updateValues);
|
||
|
const insertKeys = Object.keys(insertValues);
|
||
|
const insertKeysQuoted = insertKeys.map((key) => this.quoteIdentifier(key)).join(", ");
|
||
|
const insertValuesEscaped = insertKeys.map((key) => this.escape(insertValues[key])).join(", ");
|
||
|
const sourceTableQuery = `VALUES(${insertValuesEscaped})`;
|
||
|
let joinCondition;
|
||
|
const clauses = where[Op.or].filter((clause) => {
|
||
|
let valid = true;
|
||
|
for (const key in clause) {
|
||
|
if (!clause[key]) {
|
||
|
valid = false;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return valid;
|
||
|
});
|
||
|
const getJoinSnippet = (array) => {
|
||
|
return array.map((key) => {
|
||
|
key = this.quoteIdentifier(key);
|
||
|
return `${targetTableAlias}.${key} = ${sourceTableAlias}.${key}`;
|
||
|
});
|
||
|
};
|
||
|
if (clauses.length === 0) {
|
||
|
throw new Error("Primary Key or Unique key should be passed to upsert query");
|
||
|
} else {
|
||
|
for (const key in clauses) {
|
||
|
const keys = Object.keys(clauses[key]);
|
||
|
if (primaryKeysAttrs.indexOf(keys[0]) !== -1) {
|
||
|
joinCondition = getJoinSnippet(primaryKeysAttrs).join(" AND ");
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (!joinCondition) {
|
||
|
joinCondition = getJoinSnippet(uniqueAttrs).join(" AND ");
|
||
|
}
|
||
|
}
|
||
|
const filteredUpdateClauses = updateKeys.filter((key) => {
|
||
|
if (identityAttrs.indexOf(key) === -1) {
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}).map((key) => {
|
||
|
const value = this.escape(updateValues[key]);
|
||
|
key = this.quoteIdentifier(key);
|
||
|
return `${targetTableAlias}.${key} = ${value}`;
|
||
|
}).join(", ");
|
||
|
const updateSnippet = filteredUpdateClauses.length > 0 ? `WHEN MATCHED THEN UPDATE SET ${filteredUpdateClauses}` : "";
|
||
|
const insertSnippet = `(${insertKeysQuoted}) VALUES(${insertValuesEscaped})`;
|
||
|
let query = `MERGE INTO ${tableNameQuoted} AS ${targetTableAlias} USING (${sourceTableQuery}) AS ${sourceTableAlias}(${insertKeysQuoted}) ON ${joinCondition}`;
|
||
|
query += ` ${updateSnippet} WHEN NOT MATCHED THEN INSERT ${insertSnippet};`;
|
||
|
return query;
|
||
|
}
|
||
|
truncateTableQuery(tableName) {
|
||
|
return `TRUNCATE TABLE ${this.quoteTable(tableName)} IMMEDIATE`;
|
||
|
}
|
||
|
deleteQuery(tableName, where, options = {}, model) {
|
||
|
const table = this.quoteTable(tableName);
|
||
|
const query = "DELETE FROM <%= table %><%= where %><%= limit %>";
|
||
|
where = this.getWhereConditions(where, null, model, options);
|
||
|
let limit = "";
|
||
|
if (options.offset > 0) {
|
||
|
limit = ` OFFSET ${this.escape(options.offset)} ROWS`;
|
||
|
}
|
||
|
if (options.limit) {
|
||
|
limit += ` FETCH NEXT ${this.escape(options.limit)} ROWS ONLY`;
|
||
|
}
|
||
|
const replacements = {
|
||
|
limit,
|
||
|
table,
|
||
|
where
|
||
|
};
|
||
|
if (replacements.where) {
|
||
|
replacements.where = ` WHERE ${replacements.where}`;
|
||
|
}
|
||
|
return _.template(query, this._templateSettings)(replacements);
|
||
|
}
|
||
|
showIndexesQuery(tableName) {
|
||
|
let sql = 'SELECT NAME AS "name", TBNAME AS "tableName", UNIQUERULE AS "keyType", COLNAMES, INDEXTYPE AS "type" FROM SYSIBM.SYSINDEXES WHERE TBNAME = <%= tableName %>';
|
||
|
let schema = void 0;
|
||
|
if (_.isObject(tableName)) {
|
||
|
schema = tableName.schema;
|
||
|
tableName = tableName.tableName;
|
||
|
}
|
||
|
if (schema) {
|
||
|
sql = `${sql} AND TBCREATOR = <%= schemaName %>`;
|
||
|
}
|
||
|
sql = `${sql} ORDER BY NAME;`;
|
||
|
return _.template(sql, this._templateSettings)({
|
||
|
tableName: wrapSingleQuote(tableName),
|
||
|
schemaName: wrapSingleQuote(schema)
|
||
|
});
|
||
|
}
|
||
|
showConstraintsQuery(tableName, constraintName) {
|
||
|
let sql = `SELECT CONSTNAME AS "constraintName", TRIM(TABSCHEMA) AS "schemaName", TABNAME AS "tableName" FROM SYSCAT.TABCONST WHERE TABNAME = '${tableName}'`;
|
||
|
if (constraintName) {
|
||
|
sql += ` AND CONSTNAME LIKE '%${constraintName}%'`;
|
||
|
}
|
||
|
return `${sql} ORDER BY CONSTNAME;`;
|
||
|
}
|
||
|
removeIndexQuery(tableName, indexNameOrAttributes) {
|
||
|
const sql = "DROP INDEX <%= indexName %>";
|
||
|
let indexName = indexNameOrAttributes;
|
||
|
if (typeof indexName !== "string") {
|
||
|
indexName = Utils.underscore(`${tableName}_${indexNameOrAttributes.join("_")}`);
|
||
|
}
|
||
|
const values = {
|
||
|
tableName: this.quoteIdentifiers(tableName),
|
||
|
indexName: this.quoteIdentifiers(indexName)
|
||
|
};
|
||
|
return _.template(sql, this._templateSettings)(values);
|
||
|
}
|
||
|
attributeToSQL(attribute, options) {
|
||
|
if (!_.isPlainObject(attribute)) {
|
||
|
attribute = {
|
||
|
type: attribute
|
||
|
};
|
||
|
}
|
||
|
let template;
|
||
|
let changeNull = 1;
|
||
|
if (attribute.type instanceof DataTypes.ENUM) {
|
||
|
if (attribute.type.values && !attribute.values)
|
||
|
attribute.values = attribute.type.values;
|
||
|
template = attribute.type.toSql();
|
||
|
template += ` CHECK (${this.quoteIdentifier(attribute.field)} IN(${attribute.values.map((value) => {
|
||
|
return this.escape(value);
|
||
|
}).join(", ")}))`;
|
||
|
} else {
|
||
|
template = attribute.type.toString();
|
||
|
}
|
||
|
if (options && options.context === "changeColumn" && attribute.type) {
|
||
|
template = `DATA TYPE ${template}`;
|
||
|
} else if (attribute.allowNull === false || attribute.primaryKey === true || attribute.unique) {
|
||
|
template += " NOT NULL";
|
||
|
changeNull = 0;
|
||
|
}
|
||
|
if (attribute.autoIncrement) {
|
||
|
let initialValue = 1;
|
||
|
if (attribute.initialAutoIncrement) {
|
||
|
initialValue = attribute.initialAutoIncrement;
|
||
|
}
|
||
|
template += ` GENERATED BY DEFAULT AS IDENTITY(START WITH ${initialValue}, INCREMENT BY 1)`;
|
||
|
}
|
||
|
if (attribute.type !== "TEXT" && attribute.type._binary !== true && Utils.defaultValueSchemable(attribute.defaultValue)) {
|
||
|
template += ` DEFAULT ${this.escape(attribute.defaultValue)}`;
|
||
|
}
|
||
|
if (attribute.unique === true) {
|
||
|
template += " UNIQUE";
|
||
|
}
|
||
|
if (attribute.primaryKey) {
|
||
|
template += " PRIMARY KEY";
|
||
|
}
|
||
|
if ((!options || !options.withoutForeignKeyConstraints) && attribute.references) {
|
||
|
if (options && options.context === "addColumn" && options.foreignKey) {
|
||
|
const attrName = this.quoteIdentifier(options.foreignKey);
|
||
|
const fkName = `${options.tableName}_${attrName}_fidx`;
|
||
|
template += `, CONSTRAINT ${fkName} FOREIGN KEY (${attrName})`;
|
||
|
}
|
||
|
template += ` REFERENCES ${this.quoteTable(attribute.references.model)}`;
|
||
|
if (attribute.references.key) {
|
||
|
template += ` (${this.quoteIdentifier(attribute.references.key)})`;
|
||
|
} else {
|
||
|
template += ` (${this.quoteIdentifier("id")})`;
|
||
|
}
|
||
|
if (attribute.onDelete) {
|
||
|
template += ` ON DELETE ${attribute.onDelete.toUpperCase()}`;
|
||
|
}
|
||
|
if (attribute.onUpdate && attribute.onUpdate.toUpperCase() != "CASCADE") {
|
||
|
template += ` ON UPDATE ${attribute.onUpdate.toUpperCase()}`;
|
||
|
}
|
||
|
}
|
||
|
if (options && options.context === "changeColumn" && changeNull === 1 && attribute.allowNull !== void 0) {
|
||
|
template = [template];
|
||
|
if (attribute.allowNull) {
|
||
|
template.push("DROP NOT NULL");
|
||
|
} else {
|
||
|
template.push("NOT NULL");
|
||
|
}
|
||
|
}
|
||
|
if (attribute.comment && typeof attribute.comment === "string") {
|
||
|
template += ` COMMENT ${attribute.comment}`;
|
||
|
}
|
||
|
return template;
|
||
|
}
|
||
|
attributesToSQL(attributes, options) {
|
||
|
const result = {}, existingConstraints = [];
|
||
|
let key, attribute;
|
||
|
for (key in attributes) {
|
||
|
attribute = attributes[key];
|
||
|
if (attribute.references) {
|
||
|
if (existingConstraints.indexOf(attribute.references.model.toString()) !== -1) {
|
||
|
attribute.onDelete = "";
|
||
|
attribute.onUpdate = "";
|
||
|
} else if (attribute.unique && attribute.unique === true) {
|
||
|
attribute.onDelete = "";
|
||
|
attribute.onUpdate = "";
|
||
|
} else {
|
||
|
existingConstraints.push(attribute.references.model.toString());
|
||
|
}
|
||
|
}
|
||
|
if (key && !attribute.field && typeof attribute === "object")
|
||
|
attribute.field = key;
|
||
|
result[attribute.field || key] = this.attributeToSQL(attribute, options);
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
createTrigger() {
|
||
|
throwMethodUndefined("createTrigger");
|
||
|
}
|
||
|
dropTrigger() {
|
||
|
throwMethodUndefined("dropTrigger");
|
||
|
}
|
||
|
renameTrigger() {
|
||
|
throwMethodUndefined("renameTrigger");
|
||
|
}
|
||
|
createFunction() {
|
||
|
throwMethodUndefined("createFunction");
|
||
|
}
|
||
|
dropFunction() {
|
||
|
throwMethodUndefined("dropFunction");
|
||
|
}
|
||
|
renameFunction() {
|
||
|
throwMethodUndefined("renameFunction");
|
||
|
}
|
||
|
_getForeignKeysQuerySQL(condition) {
|
||
|
return `SELECT R.CONSTNAME AS "constraintName", TRIM(R.TABSCHEMA) AS "constraintSchema", R.TABNAME AS "tableName", TRIM(R.TABSCHEMA) AS "tableSchema", LISTAGG(C.COLNAME,', ') WITHIN GROUP (ORDER BY C.COLNAME) AS "columnName", TRIM(R.REFTABSCHEMA) AS "referencedTableSchema", R.REFTABNAME AS "referencedTableName", TRIM(R.PK_COLNAMES) AS "referencedColumnName" FROM SYSCAT.REFERENCES R, SYSCAT.KEYCOLUSE C WHERE R.CONSTNAME = C.CONSTNAME AND R.TABSCHEMA = C.TABSCHEMA AND R.TABNAME = C.TABNAME${condition} GROUP BY R.REFTABSCHEMA, R.REFTABNAME, R.TABSCHEMA, R.TABNAME, R.CONSTNAME, R.PK_COLNAMES`;
|
||
|
}
|
||
|
getForeignKeysQuery(table, schemaName) {
|
||
|
const tableName = table.tableName || table;
|
||
|
schemaName = table.schema || schemaName;
|
||
|
let sql = "";
|
||
|
if (tableName) {
|
||
|
sql = ` AND R.TABNAME = ${wrapSingleQuote(tableName)}`;
|
||
|
}
|
||
|
if (schemaName) {
|
||
|
sql += ` AND R.TABSCHEMA = ${wrapSingleQuote(schemaName)}`;
|
||
|
}
|
||
|
return this._getForeignKeysQuerySQL(sql);
|
||
|
}
|
||
|
getForeignKeyQuery(table, columnName) {
|
||
|
const tableName = table.tableName || table;
|
||
|
const schemaName = table.schema;
|
||
|
let sql = "";
|
||
|
if (tableName) {
|
||
|
sql = ` AND R.TABNAME = ${wrapSingleQuote(tableName)}`;
|
||
|
}
|
||
|
if (schemaName) {
|
||
|
sql += ` AND R.TABSCHEMA = ${wrapSingleQuote(schemaName)}`;
|
||
|
}
|
||
|
if (columnName) {
|
||
|
sql += ` AND C.COLNAME = ${wrapSingleQuote(columnName)}`;
|
||
|
}
|
||
|
return this._getForeignKeysQuerySQL(sql);
|
||
|
}
|
||
|
getPrimaryKeyConstraintQuery(table, attributeName) {
|
||
|
const tableName = wrapSingleQuote(table.tableName || table);
|
||
|
return [
|
||
|
'SELECT TABNAME AS "tableName",',
|
||
|
'COLNAME AS "columnName",',
|
||
|
'CONSTNAME AS "constraintName"',
|
||
|
"FROM SYSCAT.KEYCOLUSE WHERE CONSTNAME LIKE 'PK_%'",
|
||
|
`AND COLNAME = ${wrapSingleQuote(attributeName)}`,
|
||
|
`AND TABNAME = ${tableName};`
|
||
|
].join(" ");
|
||
|
}
|
||
|
dropForeignKeyQuery(tableName, foreignKey) {
|
||
|
return _.template("ALTER TABLE <%= table %> DROP <%= key %>", this._templateSettings)({
|
||
|
table: this.quoteTable(tableName),
|
||
|
key: this.quoteIdentifier(foreignKey)
|
||
|
});
|
||
|
}
|
||
|
dropConstraintQuery(tableName, constraintName) {
|
||
|
const sql = "ALTER TABLE <%= table %> DROP CONSTRAINT <%= constraint %>;";
|
||
|
return _.template(sql, this._templateSettings)({
|
||
|
table: this.quoteTable(tableName),
|
||
|
constraint: this.quoteIdentifier(constraintName)
|
||
|
});
|
||
|
}
|
||
|
setAutocommitQuery() {
|
||
|
return "";
|
||
|
}
|
||
|
setIsolationLevelQuery() {
|
||
|
}
|
||
|
generateTransactionId() {
|
||
|
return randomBytes(10).toString("hex");
|
||
|
}
|
||
|
startTransactionQuery(transaction) {
|
||
|
if (transaction.parent) {
|
||
|
return `SAVE TRANSACTION ${this.quoteIdentifier(transaction.name)};`;
|
||
|
}
|
||
|
return "BEGIN TRANSACTION;";
|
||
|
}
|
||
|
commitTransactionQuery(transaction) {
|
||
|
if (transaction.parent) {
|
||
|
return;
|
||
|
}
|
||
|
return "COMMIT TRANSACTION;";
|
||
|
}
|
||
|
rollbackTransactionQuery(transaction) {
|
||
|
if (transaction.parent) {
|
||
|
return `ROLLBACK TRANSACTION ${this.quoteIdentifier(transaction.name)};`;
|
||
|
}
|
||
|
return "ROLLBACK TRANSACTION;";
|
||
|
}
|
||
|
addLimitAndOffset(options) {
|
||
|
const offset = options.offset || 0;
|
||
|
let fragment = "";
|
||
|
if (offset > 0) {
|
||
|
fragment += ` OFFSET ${this.escape(offset)} ROWS`;
|
||
|
}
|
||
|
if (options.limit) {
|
||
|
fragment += ` FETCH NEXT ${this.escape(options.limit)} ROWS ONLY`;
|
||
|
}
|
||
|
return fragment;
|
||
|
}
|
||
|
booleanValue(value) {
|
||
|
return value ? 1 : 0;
|
||
|
}
|
||
|
addUniqueFields(dataValues, rawAttributes, uniqno) {
|
||
|
uniqno = uniqno === void 0 ? 1 : uniqno;
|
||
|
for (const key in rawAttributes) {
|
||
|
if (rawAttributes[key].unique && dataValues[key] === void 0) {
|
||
|
if (rawAttributes[key].type instanceof DataTypes.DATE) {
|
||
|
dataValues[key] = Utils.now("db2");
|
||
|
} else if (rawAttributes[key].type instanceof DataTypes.STRING) {
|
||
|
dataValues[key] = `unique${uniqno++}`;
|
||
|
} else if (rawAttributes[key].type instanceof DataTypes.INTEGER) {
|
||
|
dataValues[key] = uniqno++;
|
||
|
} else if (rawAttributes[key].type instanceof DataTypes.BOOLEAN) {
|
||
|
dataValues[key] = new DataTypes.BOOLEAN(false);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return uniqno;
|
||
|
}
|
||
|
quoteIdentifier(identifier, force) {
|
||
|
return Utils.addTicks(Utils.removeTicks(identifier, '"'), '"');
|
||
|
}
|
||
|
}
|
||
|
function wrapSingleQuote(identifier) {
|
||
|
if (identifier) {
|
||
|
return `'${identifier}'`;
|
||
|
}
|
||
|
return "";
|
||
|
}
|
||
|
module.exports = Db2QueryGenerator;
|
||
|
//# sourceMappingURL=query-generator.js.map
|