"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 AbstractQueryGenerator = require("../abstract/query-generator"); const util = require("util"); const Op = require("../../operators"); const JSON_FUNCTION_REGEX = /^\s*((?:[a-z]+_){0,2}jsonb?(?:_[a-z]+){0,2})\([^)]*\)/i; const JSON_OPERATOR_REGEX = /^\s*(->>?|@>|<@|\?[|&]?|\|{2}|#-)/i; const TOKEN_CAPTURE_REGEX = /^\s*((?:([`"'])(?:(?!\2).|\2{2})*\2)|[\w\d\s]+|[().,;+-])/i; const FOREIGN_KEY_FIELDS = [ "CONSTRAINT_NAME as constraint_name", "CONSTRAINT_NAME as constraintName", "CONSTRAINT_SCHEMA as constraintSchema", "CONSTRAINT_SCHEMA as constraintCatalog", "TABLE_NAME as tableName", "TABLE_SCHEMA as tableSchema", "TABLE_SCHEMA as tableCatalog", "COLUMN_NAME as columnName", "REFERENCED_TABLE_SCHEMA as referencedTableSchema", "REFERENCED_TABLE_SCHEMA as referencedTableCatalog", "REFERENCED_TABLE_NAME as referencedTableName", "REFERENCED_COLUMN_NAME as referencedColumnName" ].join(","); const SNOWFLAKE_RESERVED_WORDS = "account,all,alter,and,any,as,between,by,case,cast,check,column,connect,connections,constraint,create,cross,current,current_date,current_time,current_timestamp,current_user,database,delete,distinct,drop,else,exists,false,following,for,from,full,grant,group,gscluster,having,ilike,in,increment,inner,insert,intersect,into,is,issue,join,lateral,left,like,localtime,localtimestamp,minus,natural,not,null,of,on,or,order,organization,qualify,regexp,revoke,right,rlike,row,rows,sample,schema,select,set,some,start,table,tablesample,then,to,trigger,true,try_cast,union,unique,update,using,values,view,when,whenever,where,with".split(","); const typeWithoutDefault = /* @__PURE__ */ new Set(["BLOB", "TEXT", "GEOMETRY", "JSON"]); class SnowflakeQueryGenerator extends AbstractQueryGenerator { constructor(options) { super(options); this.OperatorMap = __spreadProps(__spreadValues({}, this.OperatorMap), { [Op.regexp]: "REGEXP", [Op.notRegexp]: "NOT REGEXP" }); } createDatabaseQuery(databaseName, options) { options = __spreadValues({ charset: null, collate: null }, options); return Utils.joinSQLFragments([ "CREATE DATABASE IF NOT EXISTS", this.quoteIdentifier(databaseName), options.charset && `DEFAULT CHARACTER SET ${this.escape(options.charset)}`, options.collate && `DEFAULT COLLATE ${this.escape(options.collate)}`, ";" ]); } dropDatabaseQuery(databaseName) { return `DROP DATABASE IF EXISTS ${this.quoteIdentifier(databaseName)};`; } createSchema() { return "SHOW TABLES"; } showSchemasQuery() { return "SHOW TABLES"; } versionQuery() { return "SELECT CURRENT_VERSION()"; } createTableQuery(tableName, attributes, options) { options = __spreadValues({ charset: null, rowFormat: null }, options); const primaryKeys = []; const foreignKeys = {}; const attrStr = []; for (const attr in attributes) { if (!Object.prototype.hasOwnProperty.call(attributes, attr)) continue; const dataType = attributes[attr]; let match; if (dataType.includes("PRIMARY KEY")) { primaryKeys.push(attr); if (dataType.includes("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 (dataType.includes("REFERENCES")) { match = dataType.match(/^(.+) (REFERENCES.*)$/); attrStr.push(`${this.quoteIdentifier(attr)} ${match[1]}`); foreignKeys[attr] = match[2]; } else { attrStr.push(`${this.quoteIdentifier(attr)} ${dataType}`); } } const table = this.quoteTable(tableName); let attributesClause = attrStr.join(", "); const pkString = primaryKeys.map((pk) => this.quoteIdentifier(pk)).join(", "); if (options.uniqueKeys) { _.each(options.uniqueKeys, (columns, indexName) => { if (columns.customIndex) { if (typeof indexName !== "string") { indexName = `uniq_${tableName}_${columns.fields.join("_")}`; } attributesClause += `, UNIQUE ${this.quoteIdentifier(indexName)} (${columns.fields.map((field) => this.quoteIdentifier(field)).join(", ")})`; } }); } if (pkString.length > 0) { attributesClause += `, PRIMARY KEY (${pkString})`; } for (const fkey in foreignKeys) { if (Object.prototype.hasOwnProperty.call(foreignKeys, fkey)) { attributesClause += `, FOREIGN KEY (${this.quoteIdentifier(fkey)}) ${foreignKeys[fkey]}`; } } return Utils.joinSQLFragments([ "CREATE TABLE IF NOT EXISTS", table, `(${attributesClause})`, options.comment && typeof options.comment === "string" && `COMMENT ${this.escape(options.comment)}`, options.charset && `DEFAULT CHARSET=${options.charset}`, options.collate && `COLLATE ${options.collate}`, options.rowFormat && `ROW_FORMAT=${options.rowFormat}`, ";" ]); } describeTableQuery(tableName, schema, schemaDelimiter) { const table = this.quoteTable(this.addSchema({ tableName, _schema: schema, _schemaDelimiter: schemaDelimiter })); return `SHOW FULL COLUMNS FROM ${table};`; } showTablesQuery(database) { return Utils.joinSQLFragments([ "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE'", database ? `AND TABLE_SCHEMA = ${this.escape(database)}` : "AND TABLE_SCHEMA NOT IN ( 'INFORMATION_SCHEMA', 'PERFORMANCE_SCHEMA', 'SYS')", ";" ]); } addColumnQuery(table, key, dataType) { return Utils.joinSQLFragments([ "ALTER TABLE", this.quoteTable(table), "ADD", this.quoteIdentifier(key), this.attributeToSQL(dataType, { context: "addColumn", tableName: table, foreignKey: key }), ";" ]); } removeColumnQuery(tableName, attributeName) { return Utils.joinSQLFragments([ "ALTER TABLE", this.quoteTable(tableName), "DROP", this.quoteIdentifier(attributeName), ";" ]); } changeColumnQuery(tableName, attributes) { const query = (...subQuerys) => Utils.joinSQLFragments([ "ALTER TABLE", this.quoteTable(tableName), "ALTER COLUMN", ...subQuerys, ";" ]); const sql = []; for (const attributeName in attributes) { let definition = this.dataTypeMapping(tableName, attributeName, attributes[attributeName]); const attrSql = []; if (definition.includes("NOT NULL")) { attrSql.push(query(this.quoteIdentifier(attributeName), "SET NOT NULL")); definition = definition.replace("NOT NULL", "").trim(); } else if (!definition.includes("REFERENCES")) { attrSql.push(query(this.quoteIdentifier(attributeName), "DROP NOT NULL")); } if (definition.includes("DEFAULT")) { attrSql.push(query(this.quoteIdentifier(attributeName), "SET DEFAULT", definition.match(/DEFAULT ([^;]+)/)[1])); definition = definition.replace(/(DEFAULT[^;]+)/, "").trim(); } else if (!definition.includes("REFERENCES")) { attrSql.push(query(this.quoteIdentifier(attributeName), "DROP DEFAULT")); } if (definition.match(/UNIQUE;*$/)) { definition = definition.replace(/UNIQUE;*$/, ""); attrSql.push(query("ADD UNIQUE (", this.quoteIdentifier(attributeName), ")").replace("ALTER COLUMN", "")); } if (definition.includes("REFERENCES")) { definition = definition.replace(/.+?(?=REFERENCES)/, ""); attrSql.push(query("ADD FOREIGN KEY (", this.quoteIdentifier(attributeName), ")", definition).replace("ALTER COLUMN", "")); } else { attrSql.push(query(this.quoteIdentifier(attributeName), "TYPE", definition)); } sql.push(attrSql.join("")); } return sql.join(""); } renameColumnQuery(tableName, attrBefore, attributes) { const attrString = []; for (const attrName in attributes) { const definition = attributes[attrName]; attrString.push(`'${attrBefore}' '${attrName}' ${definition}`); } return Utils.joinSQLFragments([ "ALTER TABLE", this.quoteTable(tableName), "RENAME COLUMN", attrString.join(" to "), ";" ]); } handleSequelizeMethod(attr, tableName, factory, options, prepend) { if (attr instanceof Utils.Json) { if (attr.conditions) { const conditions = this.parseConditionObject(attr.conditions).map((condition) => `${this.jsonPathExtractionQuery(condition.path[0], _.tail(condition.path))} = '${condition.value}'`); return conditions.join(" AND "); } if (attr.path) { let str; if (this._checkValidJsonStatement(attr.path)) { str = attr.path; } else { const paths = _.toPath(attr.path); const column = paths.shift(); str = this.jsonPathExtractionQuery(column, paths); } if (attr.value) { str += util.format(" = %s", this.escape(attr.value)); } return str; } } else if (attr instanceof Utils.Cast) { if (/timestamp/i.test(attr.type)) { attr.type = "datetime"; } else if (attr.json && /boolean/i.test(attr.type)) { attr.type = "char"; } else if (/double precision/i.test(attr.type) || /boolean/i.test(attr.type) || /integer/i.test(attr.type)) { attr.type = "decimal"; } else if (/text/i.test(attr.type)) { attr.type = "char"; } } return super.handleSequelizeMethod(attr, tableName, factory, options, prepend); } truncateTableQuery(tableName) { return Utils.joinSQLFragments([ "TRUNCATE", this.quoteTable(tableName) ]); } deleteQuery(tableName, where, options = {}, model) { const table = this.quoteTable(tableName); let whereClause = this.getWhereConditions(where, null, model, options); const limit = options.limit && ` LIMIT ${this.escape(options.limit)}`; let primaryKeys = ""; let primaryKeysSelection = ""; if (whereClause) { whereClause = `WHERE ${whereClause}`; } if (limit) { if (!model) { throw new Error("Cannot LIMIT delete without a model."); } const pks = Object.values(model.primaryKeys).map((pk) => this.quoteIdentifier(pk.field)).join(","); primaryKeys = model.primaryKeyAttributes.length > 1 ? `(${pks})` : pks; primaryKeysSelection = pks; return Utils.joinSQLFragments([ "DELETE FROM", table, "WHERE", primaryKeys, "IN (SELECT", primaryKeysSelection, "FROM", table, whereClause, limit, ")", ";" ]); } return Utils.joinSQLFragments([ "DELETE FROM", table, whereClause, ";" ]); } showIndexesQuery() { return "SELECT '' FROM DUAL"; } showConstraintsQuery(table, constraintName) { const tableName = table.tableName || table; const schemaName = table.schema; return Utils.joinSQLFragments([ "SELECT CONSTRAINT_CATALOG AS constraintCatalog,", "CONSTRAINT_NAME AS constraintName,", "CONSTRAINT_SCHEMA AS constraintSchema,", "CONSTRAINT_TYPE AS constraintType,", "TABLE_NAME AS tableName,", "TABLE_SCHEMA AS tableSchema", "from INFORMATION_SCHEMA.TABLE_CONSTRAINTS", `WHERE table_name='${tableName}'`, constraintName && `AND constraint_name = '${constraintName}'`, schemaName && `AND TABLE_SCHEMA = '${schemaName}'`, ";" ]); } removeIndexQuery(tableName, indexNameOrAttributes) { let indexName = indexNameOrAttributes; if (typeof indexName !== "string") { indexName = Utils.underscore(`${tableName}_${indexNameOrAttributes.join("_")}`); } return Utils.joinSQLFragments([ "DROP INDEX", this.quoteIdentifier(indexName), "ON", this.quoteTable(tableName), ";" ]); } attributeToSQL(attribute, options) { if (!_.isPlainObject(attribute)) { attribute = { type: attribute }; } const attributeString = attribute.type.toString({ escape: this.escape.bind(this) }); let template = attributeString; if (attribute.allowNull === false) { template += " NOT NULL"; } if (attribute.autoIncrement) { template += " AUTOINCREMENT"; } if (!typeWithoutDefault.has(attributeString) && 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 (attribute.comment) { template += ` COMMENT ${this.escape(attribute.comment)}`; } if (attribute.first) { template += " FIRST"; } if (attribute.after) { template += ` AFTER ${this.quoteIdentifier(attribute.after)}`; } if (attribute.references) { if (options && options.context === "addColumn" && options.foreignKey) { const attrName = this.quoteIdentifier(options.foreignKey); const fkName = this.quoteIdentifier(`${options.tableName}_${attrName}_foreign_idx`); template += `, ADD 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) { template += ` ON UPDATE ${attribute.onUpdate.toUpperCase()}`; } } return template; } attributesToSQL(attributes, options) { const result = {}; for (const key in attributes) { const attribute = attributes[key]; result[attribute.field || key] = this.attributeToSQL(attribute, options); } return result; } _checkValidJsonStatement(stmt) { if (typeof stmt !== "string") { return false; } let currentIndex = 0; let openingBrackets = 0; let closingBrackets = 0; let hasJsonFunction = false; let hasInvalidToken = false; while (currentIndex < stmt.length) { const string = stmt.substr(currentIndex); const functionMatches = JSON_FUNCTION_REGEX.exec(string); if (functionMatches) { currentIndex += functionMatches[0].indexOf("("); hasJsonFunction = true; continue; } const operatorMatches = JSON_OPERATOR_REGEX.exec(string); if (operatorMatches) { currentIndex += operatorMatches[0].length; hasJsonFunction = true; continue; } const tokenMatches = TOKEN_CAPTURE_REGEX.exec(string); if (tokenMatches) { const capturedToken = tokenMatches[1]; if (capturedToken === "(") { openingBrackets++; } else if (capturedToken === ")") { closingBrackets++; } else if (capturedToken === ";") { hasInvalidToken = true; break; } currentIndex += tokenMatches[0].length; continue; } break; } if (hasJsonFunction && (hasInvalidToken || openingBrackets !== closingBrackets)) { throw new Error(`Invalid json statement: ${stmt}`); } return hasJsonFunction; } dataTypeMapping(tableName, attr, dataType) { if (dataType.includes("PRIMARY KEY")) { dataType = dataType.replace("PRIMARY KEY", ""); } if (dataType.includes("SERIAL")) { if (dataType.includes("BIGINT")) { dataType = dataType.replace("SERIAL", "BIGSERIAL"); dataType = dataType.replace("BIGINT", ""); } else if (dataType.includes("SMALLINT")) { dataType = dataType.replace("SERIAL", "SMALLSERIAL"); dataType = dataType.replace("SMALLINT", ""); } else { dataType = dataType.replace("INTEGER", ""); } dataType = dataType.replace("NOT NULL", ""); } return dataType; } getForeignKeysQuery(table, schemaName) { const tableName = table.tableName || table; return Utils.joinSQLFragments([ "SELECT", FOREIGN_KEY_FIELDS, `FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE where TABLE_NAME = '${tableName}'`, `AND CONSTRAINT_NAME!='PRIMARY' AND CONSTRAINT_SCHEMA='${schemaName}'`, "AND REFERENCED_TABLE_NAME IS NOT NULL", ";" ]); } getForeignKeyQuery(table, columnName) { const quotedSchemaName = table.schema ? wrapSingleQuote(table.schema) : ""; const quotedTableName = wrapSingleQuote(table.tableName || table); const quotedColumnName = wrapSingleQuote(columnName); return Utils.joinSQLFragments([ "SELECT", FOREIGN_KEY_FIELDS, "FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE", "WHERE (", [ `REFERENCED_TABLE_NAME = ${quotedTableName}`, table.schema && `AND REFERENCED_TABLE_SCHEMA = ${quotedSchemaName}`, `AND REFERENCED_COLUMN_NAME = ${quotedColumnName}` ], ") OR (", [ `TABLE_NAME = ${quotedTableName}`, table.schema && `AND TABLE_SCHEMA = ${quotedSchemaName}`, `AND COLUMN_NAME = ${quotedColumnName}`, "AND REFERENCED_TABLE_NAME IS NOT NULL" ], ")" ]); } dropForeignKeyQuery(tableName, foreignKey) { return Utils.joinSQLFragments([ "ALTER TABLE", this.quoteTable(tableName), "DROP FOREIGN KEY", this.quoteIdentifier(foreignKey), ";" ]); } addLimitAndOffset(options) { let fragment = []; if (options.offset !== null && options.offset !== void 0 && options.offset !== 0) { fragment = fragment.concat([" LIMIT ", this.escape(options.limit), " OFFSET ", this.escape(options.offset)]); } else if (options.limit !== null && options.limit !== void 0) { fragment = [" LIMIT ", this.escape(options.limit)]; } return fragment.join(""); } quoteIdentifier(identifier, force) { const optForceQuote = force || false; const optQuoteIdentifiers = this.options.quoteIdentifiers !== false; const rawIdentifier = Utils.removeTicks(identifier, '"'); if (optForceQuote === true || optQuoteIdentifiers !== false || identifier.includes(".") || identifier.includes("->") || SNOWFLAKE_RESERVED_WORDS.includes(rawIdentifier.toLowerCase())) { return Utils.addTicks(rawIdentifier, '"'); } return rawIdentifier; } } function wrapSingleQuote(identifier) { return Utils.addTicks(identifier, "'"); } module.exports = SnowflakeQueryGenerator; //# sourceMappingURL=query-generator.js.map