query-generator.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. "use strict";
  2. var __defProp = Object.defineProperty;
  3. var __defProps = Object.defineProperties;
  4. var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
  5. var __getOwnPropSymbols = Object.getOwnPropertySymbols;
  6. var __hasOwnProp = Object.prototype.hasOwnProperty;
  7. var __propIsEnum = Object.prototype.propertyIsEnumerable;
  8. var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
  9. var __spreadValues = (a, b) => {
  10. for (var prop in b || (b = {}))
  11. if (__hasOwnProp.call(b, prop))
  12. __defNormalProp(a, prop, b[prop]);
  13. if (__getOwnPropSymbols)
  14. for (var prop of __getOwnPropSymbols(b)) {
  15. if (__propIsEnum.call(b, prop))
  16. __defNormalProp(a, prop, b[prop]);
  17. }
  18. return a;
  19. };
  20. var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
  21. const _ = require("lodash");
  22. const Utils = require("../../utils");
  23. const AbstractQueryGenerator = require("../abstract/query-generator");
  24. const util = require("util");
  25. const Op = require("../../operators");
  26. const JSON_FUNCTION_REGEX = /^\s*((?:[a-z]+_){0,2}jsonb?(?:_[a-z]+){0,2})\([^)]*\)/i;
  27. const JSON_OPERATOR_REGEX = /^\s*(->>?|@>|<@|\?[|&]?|\|{2}|#-)/i;
  28. const TOKEN_CAPTURE_REGEX = /^\s*((?:([`"'])(?:(?!\2).|\2{2})*\2)|[\w\d\s]+|[().,;+-])/i;
  29. const FOREIGN_KEY_FIELDS = [
  30. "CONSTRAINT_NAME as constraint_name",
  31. "CONSTRAINT_NAME as constraintName",
  32. "CONSTRAINT_SCHEMA as constraintSchema",
  33. "CONSTRAINT_SCHEMA as constraintCatalog",
  34. "TABLE_NAME as tableName",
  35. "TABLE_SCHEMA as tableSchema",
  36. "TABLE_SCHEMA as tableCatalog",
  37. "COLUMN_NAME as columnName",
  38. "REFERENCED_TABLE_SCHEMA as referencedTableSchema",
  39. "REFERENCED_TABLE_SCHEMA as referencedTableCatalog",
  40. "REFERENCED_TABLE_NAME as referencedTableName",
  41. "REFERENCED_COLUMN_NAME as referencedColumnName"
  42. ].join(",");
  43. const typeWithoutDefault = /* @__PURE__ */ new Set(["BLOB", "TEXT", "GEOMETRY", "JSON"]);
  44. class MySQLQueryGenerator extends AbstractQueryGenerator {
  45. constructor(options) {
  46. super(options);
  47. this.OperatorMap = __spreadProps(__spreadValues({}, this.OperatorMap), {
  48. [Op.regexp]: "REGEXP",
  49. [Op.notRegexp]: "NOT REGEXP"
  50. });
  51. }
  52. createDatabaseQuery(databaseName, options) {
  53. options = __spreadValues({
  54. charset: null,
  55. collate: null
  56. }, options);
  57. return Utils.joinSQLFragments([
  58. "CREATE DATABASE IF NOT EXISTS",
  59. this.quoteIdentifier(databaseName),
  60. options.charset && `DEFAULT CHARACTER SET ${this.escape(options.charset)}`,
  61. options.collate && `DEFAULT COLLATE ${this.escape(options.collate)}`,
  62. ";"
  63. ]);
  64. }
  65. dropDatabaseQuery(databaseName) {
  66. return `DROP DATABASE IF EXISTS ${this.quoteIdentifier(databaseName)};`;
  67. }
  68. createSchema() {
  69. return "SHOW TABLES";
  70. }
  71. showSchemasQuery() {
  72. return "SHOW TABLES";
  73. }
  74. versionQuery() {
  75. return "SELECT VERSION() as `version`";
  76. }
  77. createTableQuery(tableName, attributes, options) {
  78. options = __spreadValues({
  79. engine: "InnoDB",
  80. charset: null,
  81. rowFormat: null
  82. }, options);
  83. const primaryKeys = [];
  84. const foreignKeys = {};
  85. const attrStr = [];
  86. for (const attr in attributes) {
  87. if (!Object.prototype.hasOwnProperty.call(attributes, attr))
  88. continue;
  89. const dataType = attributes[attr];
  90. let match;
  91. if (dataType.includes("PRIMARY KEY")) {
  92. primaryKeys.push(attr);
  93. if (dataType.includes("REFERENCES")) {
  94. match = dataType.match(/^(.+) (REFERENCES.*)$/);
  95. attrStr.push(`${this.quoteIdentifier(attr)} ${match[1].replace("PRIMARY KEY", "")}`);
  96. foreignKeys[attr] = match[2];
  97. } else {
  98. attrStr.push(`${this.quoteIdentifier(attr)} ${dataType.replace("PRIMARY KEY", "")}`);
  99. }
  100. } else if (dataType.includes("REFERENCES")) {
  101. match = dataType.match(/^(.+) (REFERENCES.*)$/);
  102. attrStr.push(`${this.quoteIdentifier(attr)} ${match[1]}`);
  103. foreignKeys[attr] = match[2];
  104. } else {
  105. attrStr.push(`${this.quoteIdentifier(attr)} ${dataType}`);
  106. }
  107. }
  108. const table = this.quoteTable(tableName);
  109. let attributesClause = attrStr.join(", ");
  110. const pkString = primaryKeys.map((pk) => this.quoteIdentifier(pk)).join(", ");
  111. if (options.uniqueKeys) {
  112. _.each(options.uniqueKeys, (columns, indexName) => {
  113. if (columns.customIndex) {
  114. if (typeof indexName !== "string") {
  115. indexName = `uniq_${tableName}_${columns.fields.join("_")}`;
  116. }
  117. attributesClause += `, UNIQUE ${this.quoteIdentifier(indexName)} (${columns.fields.map((field) => this.quoteIdentifier(field)).join(", ")})`;
  118. }
  119. });
  120. }
  121. if (pkString.length > 0) {
  122. attributesClause += `, PRIMARY KEY (${pkString})`;
  123. }
  124. for (const fkey in foreignKeys) {
  125. if (Object.prototype.hasOwnProperty.call(foreignKeys, fkey)) {
  126. attributesClause += `, FOREIGN KEY (${this.quoteIdentifier(fkey)}) ${foreignKeys[fkey]}`;
  127. }
  128. }
  129. return Utils.joinSQLFragments([
  130. "CREATE TABLE IF NOT EXISTS",
  131. table,
  132. `(${attributesClause})`,
  133. `ENGINE=${options.engine}`,
  134. options.comment && typeof options.comment === "string" && `COMMENT ${this.escape(options.comment)}`,
  135. options.charset && `DEFAULT CHARSET=${options.charset}`,
  136. options.collate && `COLLATE ${options.collate}`,
  137. options.initialAutoIncrement && `AUTO_INCREMENT=${options.initialAutoIncrement}`,
  138. options.rowFormat && `ROW_FORMAT=${options.rowFormat}`,
  139. ";"
  140. ]);
  141. }
  142. describeTableQuery(tableName, schema, schemaDelimiter) {
  143. const table = this.quoteTable(this.addSchema({
  144. tableName,
  145. _schema: schema,
  146. _schemaDelimiter: schemaDelimiter
  147. }));
  148. return `SHOW FULL COLUMNS FROM ${table};`;
  149. }
  150. showTablesQuery(database) {
  151. let query = "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE'";
  152. if (database) {
  153. query += ` AND TABLE_SCHEMA = ${this.escape(database)}`;
  154. } else {
  155. query += " AND TABLE_SCHEMA NOT IN ('MYSQL', 'INFORMATION_SCHEMA', 'PERFORMANCE_SCHEMA', 'SYS', 'mysql', 'information_schema', 'performance_schema', 'sys')";
  156. }
  157. return `${query};`;
  158. }
  159. tableExistsQuery(table) {
  160. const tableName = this.escape(this.quoteTable(table).slice(1, -1));
  161. return `SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_NAME = ${tableName} AND TABLE_SCHEMA = ${this.escape(this.sequelize.config.database)}`;
  162. }
  163. addColumnQuery(table, key, dataType) {
  164. return Utils.joinSQLFragments([
  165. "ALTER TABLE",
  166. this.quoteTable(table),
  167. "ADD",
  168. this.quoteIdentifier(key),
  169. this.attributeToSQL(dataType, {
  170. context: "addColumn",
  171. tableName: table,
  172. foreignKey: key
  173. }),
  174. ";"
  175. ]);
  176. }
  177. removeColumnQuery(tableName, attributeName) {
  178. return Utils.joinSQLFragments([
  179. "ALTER TABLE",
  180. this.quoteTable(tableName),
  181. "DROP",
  182. this.quoteIdentifier(attributeName),
  183. ";"
  184. ]);
  185. }
  186. changeColumnQuery(tableName, attributes) {
  187. const attrString = [];
  188. const constraintString = [];
  189. for (const attributeName in attributes) {
  190. let definition = attributes[attributeName];
  191. if (definition.includes("REFERENCES")) {
  192. const attrName = this.quoteIdentifier(attributeName);
  193. definition = definition.replace(/.+?(?=REFERENCES)/, "");
  194. constraintString.push(`FOREIGN KEY (${attrName}) ${definition}`);
  195. } else {
  196. attrString.push(`\`${attributeName}\` \`${attributeName}\` ${definition}`);
  197. }
  198. }
  199. return Utils.joinSQLFragments([
  200. "ALTER TABLE",
  201. this.quoteTable(tableName),
  202. attrString.length && `CHANGE ${attrString.join(", ")}`,
  203. constraintString.length && `ADD ${constraintString.join(", ")}`,
  204. ";"
  205. ]);
  206. }
  207. renameColumnQuery(tableName, attrBefore, attributes) {
  208. const attrString = [];
  209. for (const attrName in attributes) {
  210. const definition = attributes[attrName];
  211. attrString.push(`\`${attrBefore}\` \`${attrName}\` ${definition}`);
  212. }
  213. return Utils.joinSQLFragments([
  214. "ALTER TABLE",
  215. this.quoteTable(tableName),
  216. "CHANGE",
  217. attrString.join(", "),
  218. ";"
  219. ]);
  220. }
  221. handleSequelizeMethod(smth, tableName, factory, options, prepend) {
  222. if (smth instanceof Utils.Json) {
  223. if (smth.conditions) {
  224. const conditions = this.parseConditionObject(smth.conditions).map((condition) => `${this.jsonPathExtractionQuery(condition.path[0], _.tail(condition.path))} = '${condition.value}'`);
  225. return conditions.join(" AND ");
  226. }
  227. if (smth.path) {
  228. let str;
  229. if (this._checkValidJsonStatement(smth.path)) {
  230. str = smth.path;
  231. } else {
  232. const paths = _.toPath(smth.path);
  233. const column = paths.shift();
  234. str = this.jsonPathExtractionQuery(column, paths);
  235. }
  236. if (smth.value) {
  237. str += util.format(" = %s", this.escape(smth.value));
  238. }
  239. return str;
  240. }
  241. } else if (smth instanceof Utils.Cast) {
  242. if (/timestamp/i.test(smth.type)) {
  243. smth.type = "datetime";
  244. } else if (smth.json && /boolean/i.test(smth.type)) {
  245. smth.type = "char";
  246. } else if (/double precision/i.test(smth.type) || /boolean/i.test(smth.type) || /integer/i.test(smth.type)) {
  247. smth.type = "decimal";
  248. } else if (/text/i.test(smth.type)) {
  249. smth.type = "char";
  250. }
  251. }
  252. return super.handleSequelizeMethod(smth, tableName, factory, options, prepend);
  253. }
  254. _toJSONValue(value) {
  255. if (typeof value === "boolean") {
  256. return value.toString();
  257. }
  258. if (value === null) {
  259. return "null";
  260. }
  261. return value;
  262. }
  263. truncateTableQuery(tableName) {
  264. return `TRUNCATE ${this.quoteTable(tableName)}`;
  265. }
  266. deleteQuery(tableName, where, options = {}, model) {
  267. let limit = "";
  268. let query = `DELETE FROM ${this.quoteTable(tableName)}`;
  269. if (options.limit) {
  270. limit = ` LIMIT ${this.escape(options.limit)}`;
  271. }
  272. where = this.getWhereConditions(where, null, model, options);
  273. if (where) {
  274. query += ` WHERE ${where}`;
  275. }
  276. return query + limit;
  277. }
  278. showIndexesQuery(tableName, options) {
  279. return Utils.joinSQLFragments([
  280. `SHOW INDEX FROM ${this.quoteTable(tableName)}`,
  281. options && options.database && `FROM \`${options.database}\``
  282. ]);
  283. }
  284. showConstraintsQuery(table, constraintName) {
  285. const tableName = table.tableName || table;
  286. const schemaName = table.schema;
  287. return Utils.joinSQLFragments([
  288. "SELECT CONSTRAINT_CATALOG AS constraintCatalog,",
  289. "CONSTRAINT_NAME AS constraintName,",
  290. "CONSTRAINT_SCHEMA AS constraintSchema,",
  291. "CONSTRAINT_TYPE AS constraintType,",
  292. "TABLE_NAME AS tableName,",
  293. "TABLE_SCHEMA AS tableSchema",
  294. "from INFORMATION_SCHEMA.TABLE_CONSTRAINTS",
  295. `WHERE table_name='${tableName}'`,
  296. constraintName && `AND constraint_name = '${constraintName}'`,
  297. schemaName && `AND TABLE_SCHEMA = '${schemaName}'`,
  298. ";"
  299. ]);
  300. }
  301. removeIndexQuery(tableName, indexNameOrAttributes) {
  302. let indexName = indexNameOrAttributes;
  303. if (typeof indexName !== "string") {
  304. indexName = Utils.underscore(`${tableName}_${indexNameOrAttributes.join("_")}`);
  305. }
  306. return Utils.joinSQLFragments([
  307. "DROP INDEX",
  308. this.quoteIdentifier(indexName),
  309. "ON",
  310. this.quoteTable(tableName)
  311. ]);
  312. }
  313. attributeToSQL(attribute, options) {
  314. if (!_.isPlainObject(attribute)) {
  315. attribute = {
  316. type: attribute
  317. };
  318. }
  319. const attributeString = attribute.type.toString({ escape: this.escape.bind(this) });
  320. let template = attributeString;
  321. if (attribute.allowNull === false) {
  322. template += " NOT NULL";
  323. }
  324. if (attribute.autoIncrement) {
  325. template += " auto_increment";
  326. }
  327. if (!typeWithoutDefault.has(attributeString) && attribute.type._binary !== true && Utils.defaultValueSchemable(attribute.defaultValue)) {
  328. template += ` DEFAULT ${this.escape(attribute.defaultValue)}`;
  329. }
  330. if (attribute.unique === true) {
  331. template += " UNIQUE";
  332. }
  333. if (attribute.primaryKey) {
  334. template += " PRIMARY KEY";
  335. }
  336. if (attribute.comment) {
  337. template += ` COMMENT ${this.escape(attribute.comment)}`;
  338. }
  339. if (attribute.first) {
  340. template += " FIRST";
  341. }
  342. if (attribute.after) {
  343. template += ` AFTER ${this.quoteIdentifier(attribute.after)}`;
  344. }
  345. if ((!options || !options.withoutForeignKeyConstraints) && attribute.references) {
  346. if (options && options.context === "addColumn" && options.foreignKey) {
  347. const attrName = this.quoteIdentifier(options.foreignKey);
  348. const fkName = this.quoteIdentifier(`${options.tableName}_${attrName}_foreign_idx`);
  349. template += `, ADD CONSTRAINT ${fkName} FOREIGN KEY (${attrName})`;
  350. }
  351. template += ` REFERENCES ${this.quoteTable(attribute.references.model)}`;
  352. if (attribute.references.key) {
  353. template += ` (${this.quoteIdentifier(attribute.references.key)})`;
  354. } else {
  355. template += ` (${this.quoteIdentifier("id")})`;
  356. }
  357. if (attribute.onDelete) {
  358. template += ` ON DELETE ${attribute.onDelete.toUpperCase()}`;
  359. }
  360. if (attribute.onUpdate) {
  361. template += ` ON UPDATE ${attribute.onUpdate.toUpperCase()}`;
  362. }
  363. }
  364. return template;
  365. }
  366. attributesToSQL(attributes, options) {
  367. const result = {};
  368. for (const key in attributes) {
  369. const attribute = attributes[key];
  370. result[attribute.field || key] = this.attributeToSQL(attribute, options);
  371. }
  372. return result;
  373. }
  374. _checkValidJsonStatement(stmt) {
  375. if (typeof stmt !== "string") {
  376. return false;
  377. }
  378. let currentIndex = 0;
  379. let openingBrackets = 0;
  380. let closingBrackets = 0;
  381. let hasJsonFunction = false;
  382. let hasInvalidToken = false;
  383. while (currentIndex < stmt.length) {
  384. const string = stmt.substr(currentIndex);
  385. const functionMatches = JSON_FUNCTION_REGEX.exec(string);
  386. if (functionMatches) {
  387. currentIndex += functionMatches[0].indexOf("(");
  388. hasJsonFunction = true;
  389. continue;
  390. }
  391. const operatorMatches = JSON_OPERATOR_REGEX.exec(string);
  392. if (operatorMatches) {
  393. currentIndex += operatorMatches[0].length;
  394. hasJsonFunction = true;
  395. continue;
  396. }
  397. const tokenMatches = TOKEN_CAPTURE_REGEX.exec(string);
  398. if (tokenMatches) {
  399. const capturedToken = tokenMatches[1];
  400. if (capturedToken === "(") {
  401. openingBrackets++;
  402. } else if (capturedToken === ")") {
  403. closingBrackets++;
  404. } else if (capturedToken === ";") {
  405. hasInvalidToken = true;
  406. break;
  407. }
  408. currentIndex += tokenMatches[0].length;
  409. continue;
  410. }
  411. break;
  412. }
  413. if (hasJsonFunction && (hasInvalidToken || openingBrackets !== closingBrackets)) {
  414. throw new Error(`Invalid json statement: ${stmt}`);
  415. }
  416. return hasJsonFunction;
  417. }
  418. getForeignKeysQuery(table, schemaName) {
  419. const tableName = table.tableName || table;
  420. return Utils.joinSQLFragments([
  421. "SELECT",
  422. FOREIGN_KEY_FIELDS,
  423. `FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE where TABLE_NAME = '${tableName}'`,
  424. `AND CONSTRAINT_NAME!='PRIMARY' AND CONSTRAINT_SCHEMA='${schemaName}'`,
  425. "AND REFERENCED_TABLE_NAME IS NOT NULL",
  426. ";"
  427. ]);
  428. }
  429. getForeignKeyQuery(table, columnName) {
  430. const quotedSchemaName = table.schema ? wrapSingleQuote(table.schema) : "";
  431. const quotedTableName = wrapSingleQuote(table.tableName || table);
  432. const quotedColumnName = wrapSingleQuote(columnName);
  433. return Utils.joinSQLFragments([
  434. "SELECT",
  435. FOREIGN_KEY_FIELDS,
  436. "FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE",
  437. "WHERE (",
  438. [
  439. `REFERENCED_TABLE_NAME = ${quotedTableName}`,
  440. table.schema && `AND REFERENCED_TABLE_SCHEMA = ${quotedSchemaName}`,
  441. `AND REFERENCED_COLUMN_NAME = ${quotedColumnName}`
  442. ],
  443. ") OR (",
  444. [
  445. `TABLE_NAME = ${quotedTableName}`,
  446. table.schema && `AND TABLE_SCHEMA = ${quotedSchemaName}`,
  447. `AND COLUMN_NAME = ${quotedColumnName}`,
  448. "AND REFERENCED_TABLE_NAME IS NOT NULL"
  449. ],
  450. ")"
  451. ]);
  452. }
  453. dropForeignKeyQuery(tableName, foreignKey) {
  454. return Utils.joinSQLFragments([
  455. "ALTER TABLE",
  456. this.quoteTable(tableName),
  457. "DROP FOREIGN KEY",
  458. this.quoteIdentifier(foreignKey),
  459. ";"
  460. ]);
  461. }
  462. quoteIdentifier(identifier, force) {
  463. return Utils.addTicks(Utils.removeTicks(identifier, "`"), "`");
  464. }
  465. }
  466. function wrapSingleQuote(identifier) {
  467. return Utils.addTicks(identifier, "'");
  468. }
  469. module.exports = MySQLQueryGenerator;
  470. //# sourceMappingURL=query-generator.js.map