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.
710 lines
28 KiB
710 lines
28 KiB
"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
|
|
|