query-generator.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  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 Utils = require("../../utils");
  22. const Transaction = require("../../transaction");
  23. const _ = require("lodash");
  24. const MySqlQueryGenerator = require("../mysql/query-generator");
  25. const AbstractQueryGenerator = require("../abstract/query-generator");
  26. class SQLiteQueryGenerator extends MySqlQueryGenerator {
  27. createSchema() {
  28. return "SELECT name FROM `sqlite_master` WHERE type='table' and name!='sqlite_sequence';";
  29. }
  30. showSchemasQuery() {
  31. return "SELECT name FROM `sqlite_master` WHERE type='table' and name!='sqlite_sequence';";
  32. }
  33. versionQuery() {
  34. return "SELECT sqlite_version() as `version`";
  35. }
  36. createTableQuery(tableName, attributes, options) {
  37. options = options || {};
  38. const primaryKeys = [];
  39. const needsMultiplePrimaryKeys = Object.values(attributes).filter((definition) => definition.includes("PRIMARY KEY")).length > 1;
  40. const attrArray = [];
  41. for (const attr in attributes) {
  42. if (Object.prototype.hasOwnProperty.call(attributes, attr)) {
  43. const dataType = attributes[attr];
  44. const containsAutoIncrement = dataType.includes("AUTOINCREMENT");
  45. let dataTypeString = dataType;
  46. if (dataType.includes("PRIMARY KEY")) {
  47. if (dataType.includes("INT")) {
  48. dataTypeString = containsAutoIncrement ? "INTEGER PRIMARY KEY AUTOINCREMENT" : "INTEGER PRIMARY KEY";
  49. if (dataType.includes(" REFERENCES")) {
  50. dataTypeString += dataType.substr(dataType.indexOf(" REFERENCES"));
  51. }
  52. }
  53. if (needsMultiplePrimaryKeys) {
  54. primaryKeys.push(attr);
  55. if (dataType.includes("NOT NULL")) {
  56. dataTypeString = dataType.replace(" PRIMARY KEY", "");
  57. } else {
  58. dataTypeString = dataType.replace("PRIMARY KEY", "NOT NULL");
  59. }
  60. }
  61. }
  62. attrArray.push(`${this.quoteIdentifier(attr)} ${dataTypeString}`);
  63. }
  64. }
  65. const table = this.quoteTable(tableName);
  66. let attrStr = attrArray.join(", ");
  67. const pkString = primaryKeys.map((pk) => this.quoteIdentifier(pk)).join(", ");
  68. if (options.uniqueKeys) {
  69. _.each(options.uniqueKeys, (columns) => {
  70. if (columns.customIndex) {
  71. attrStr += `, UNIQUE (${columns.fields.map((field) => this.quoteIdentifier(field)).join(", ")})`;
  72. }
  73. });
  74. }
  75. if (pkString.length > 0) {
  76. attrStr += `, PRIMARY KEY (${pkString})`;
  77. }
  78. const sql = `CREATE TABLE IF NOT EXISTS ${table} (${attrStr});`;
  79. return this.replaceBooleanDefaults(sql);
  80. }
  81. booleanValue(value) {
  82. return value ? 1 : 0;
  83. }
  84. _checkValidJsonStatement(stmt) {
  85. if (typeof stmt !== "string") {
  86. return false;
  87. }
  88. const jsonFunctionRegex = /^\s*(json(?:_[a-z]+){0,2})\([^)]*\)/i;
  89. const tokenCaptureRegex = /^\s*((?:([`"'])(?:(?!\2).|\2{2})*\2)|[\w\d\s]+|[().,;+-])/i;
  90. let currentIndex = 0;
  91. let openingBrackets = 0;
  92. let closingBrackets = 0;
  93. let hasJsonFunction = false;
  94. let hasInvalidToken = false;
  95. while (currentIndex < stmt.length) {
  96. const string = stmt.substr(currentIndex);
  97. const functionMatches = jsonFunctionRegex.exec(string);
  98. if (functionMatches) {
  99. currentIndex += functionMatches[0].indexOf("(");
  100. hasJsonFunction = true;
  101. continue;
  102. }
  103. const tokenMatches = tokenCaptureRegex.exec(string);
  104. if (tokenMatches) {
  105. const capturedToken = tokenMatches[1];
  106. if (capturedToken === "(") {
  107. openingBrackets++;
  108. } else if (capturedToken === ")") {
  109. closingBrackets++;
  110. } else if (capturedToken === ";") {
  111. hasInvalidToken = true;
  112. break;
  113. }
  114. currentIndex += tokenMatches[0].length;
  115. continue;
  116. }
  117. break;
  118. }
  119. hasInvalidToken |= openingBrackets !== closingBrackets;
  120. if (hasJsonFunction && hasInvalidToken) {
  121. throw new Error(`Invalid json statement: ${stmt}`);
  122. }
  123. return hasJsonFunction;
  124. }
  125. _toJSONValue(value) {
  126. if (value instanceof Date) {
  127. return value.toISOString();
  128. }
  129. if (Array.isArray(value) && value[0] instanceof Date) {
  130. return value.map((val) => val.toISOString());
  131. }
  132. return value;
  133. }
  134. handleSequelizeMethod(smth, tableName, factory, options, prepend) {
  135. if (smth instanceof Utils.Json) {
  136. return super.handleSequelizeMethod(smth, tableName, factory, options, prepend);
  137. }
  138. if (smth instanceof Utils.Cast) {
  139. if (/timestamp/i.test(smth.type)) {
  140. smth.type = "datetime";
  141. }
  142. }
  143. return AbstractQueryGenerator.prototype.handleSequelizeMethod.call(this, smth, tableName, factory, options, prepend);
  144. }
  145. addColumnQuery(table, key, dataType) {
  146. const attributes = {};
  147. attributes[key] = dataType;
  148. const fields = this.attributesToSQL(attributes, { context: "addColumn" });
  149. const attribute = `${this.quoteIdentifier(key)} ${fields[key]}`;
  150. const sql = `ALTER TABLE ${this.quoteTable(table)} ADD ${attribute};`;
  151. return this.replaceBooleanDefaults(sql);
  152. }
  153. showTablesQuery() {
  154. return "SELECT name FROM `sqlite_master` WHERE type='table' and name!='sqlite_sequence';";
  155. }
  156. updateQuery(tableName, attrValueHash, where, options, attributes) {
  157. options = options || {};
  158. _.defaults(options, this.options);
  159. attrValueHash = Utils.removeNullValuesFromHash(attrValueHash, options.omitNull, options);
  160. const modelAttributeMap = {};
  161. const values = [];
  162. const bind = [];
  163. const bindParam = options.bindParam || this.bindParam(bind);
  164. if (attributes) {
  165. _.each(attributes, (attribute, key) => {
  166. modelAttributeMap[key] = attribute;
  167. if (attribute.field) {
  168. modelAttributeMap[attribute.field] = attribute;
  169. }
  170. });
  171. }
  172. for (const key in attrValueHash) {
  173. const value = attrValueHash[key];
  174. if (value instanceof Utils.SequelizeMethod || options.bindParam === false) {
  175. values.push(`${this.quoteIdentifier(key)}=${this.escape(value, modelAttributeMap && modelAttributeMap[key] || void 0, { context: "UPDATE" })}`);
  176. } else {
  177. values.push(`${this.quoteIdentifier(key)}=${this.format(value, modelAttributeMap && modelAttributeMap[key] || void 0, { context: "UPDATE" }, bindParam)}`);
  178. }
  179. }
  180. let query;
  181. const whereOptions = __spreadProps(__spreadValues({}, options), { bindParam });
  182. if (options.limit) {
  183. query = `UPDATE ${this.quoteTable(tableName)} SET ${values.join(",")} WHERE rowid IN (SELECT rowid FROM ${this.quoteTable(tableName)} ${this.whereQuery(where, whereOptions)} LIMIT ${this.escape(options.limit)})`;
  184. } else {
  185. query = `UPDATE ${this.quoteTable(tableName)} SET ${values.join(",")} ${this.whereQuery(where, whereOptions)}`;
  186. }
  187. return { query, bind };
  188. }
  189. truncateTableQuery(tableName, options = {}) {
  190. return [
  191. `DELETE FROM ${this.quoteTable(tableName)}`,
  192. options.restartIdentity ? `; DELETE FROM ${this.quoteTable("sqlite_sequence")} WHERE ${this.quoteIdentifier("name")} = ${Utils.addTicks(Utils.removeTicks(this.quoteTable(tableName), "`"), "'")};` : ""
  193. ].join("");
  194. }
  195. deleteQuery(tableName, where, options = {}, model) {
  196. _.defaults(options, this.options);
  197. let whereClause = this.getWhereConditions(where, null, model, options);
  198. if (whereClause) {
  199. whereClause = `WHERE ${whereClause}`;
  200. }
  201. if (options.limit) {
  202. whereClause = `WHERE rowid IN (SELECT rowid FROM ${this.quoteTable(tableName)} ${whereClause} LIMIT ${this.escape(options.limit)})`;
  203. }
  204. return `DELETE FROM ${this.quoteTable(tableName)} ${whereClause}`;
  205. }
  206. attributesToSQL(attributes) {
  207. const result = {};
  208. for (const name in attributes) {
  209. const dataType = attributes[name];
  210. const fieldName = dataType.field || name;
  211. if (_.isObject(dataType)) {
  212. let sql = dataType.type.toString();
  213. if (Object.prototype.hasOwnProperty.call(dataType, "allowNull") && !dataType.allowNull) {
  214. sql += " NOT NULL";
  215. }
  216. if (Utils.defaultValueSchemable(dataType.defaultValue)) {
  217. sql += ` DEFAULT ${this.escape(dataType.defaultValue, dataType)}`;
  218. }
  219. if (dataType.unique === true) {
  220. sql += " UNIQUE";
  221. }
  222. if (dataType.primaryKey) {
  223. sql += " PRIMARY KEY";
  224. if (dataType.autoIncrement) {
  225. sql += " AUTOINCREMENT";
  226. }
  227. }
  228. if (dataType.references) {
  229. const referencesTable = this.quoteTable(dataType.references.model);
  230. let referencesKey;
  231. if (dataType.references.key) {
  232. referencesKey = this.quoteIdentifier(dataType.references.key);
  233. } else {
  234. referencesKey = this.quoteIdentifier("id");
  235. }
  236. sql += ` REFERENCES ${referencesTable} (${referencesKey})`;
  237. if (dataType.onDelete) {
  238. sql += ` ON DELETE ${dataType.onDelete.toUpperCase()}`;
  239. }
  240. if (dataType.onUpdate) {
  241. sql += ` ON UPDATE ${dataType.onUpdate.toUpperCase()}`;
  242. }
  243. }
  244. result[fieldName] = sql;
  245. } else {
  246. result[fieldName] = dataType;
  247. }
  248. }
  249. return result;
  250. }
  251. showIndexesQuery(tableName) {
  252. return `PRAGMA INDEX_LIST(${this.quoteTable(tableName)})`;
  253. }
  254. showConstraintsQuery(tableName, constraintName) {
  255. let sql = `SELECT sql FROM sqlite_master WHERE tbl_name='${tableName}'`;
  256. if (constraintName) {
  257. sql += ` AND sql LIKE '%${constraintName}%'`;
  258. }
  259. return `${sql};`;
  260. }
  261. removeIndexQuery(tableName, indexNameOrAttributes) {
  262. let indexName = indexNameOrAttributes;
  263. if (typeof indexName !== "string") {
  264. indexName = Utils.underscore(`${tableName}_${indexNameOrAttributes.join("_")}`);
  265. }
  266. return `DROP INDEX IF EXISTS ${this.quoteIdentifier(indexName)}`;
  267. }
  268. describeTableQuery(tableName, schema, schemaDelimiter) {
  269. const table = {
  270. _schema: schema,
  271. _schemaDelimiter: schemaDelimiter,
  272. tableName
  273. };
  274. return `PRAGMA TABLE_INFO(${this.quoteTable(this.addSchema(table))});`;
  275. }
  276. describeCreateTableQuery(tableName) {
  277. return `SELECT sql FROM sqlite_master WHERE tbl_name='${tableName}';`;
  278. }
  279. removeColumnQuery(tableName, attributes) {
  280. attributes = this.attributesToSQL(attributes);
  281. let backupTableName;
  282. if (typeof tableName === "object") {
  283. backupTableName = {
  284. tableName: `${tableName.tableName}_backup`,
  285. schema: tableName.schema
  286. };
  287. } else {
  288. backupTableName = `${tableName}_backup`;
  289. }
  290. const quotedTableName = this.quoteTable(tableName);
  291. const quotedBackupTableName = this.quoteTable(backupTableName);
  292. const attributeNames = Object.keys(attributes).map((attr) => this.quoteIdentifier(attr)).join(", ");
  293. return `${this.createTableQuery(backupTableName, attributes)}INSERT INTO ${quotedBackupTableName} SELECT ${attributeNames} FROM ${quotedTableName};DROP TABLE ${quotedTableName};${this.createTableQuery(tableName, attributes)}INSERT INTO ${quotedTableName} SELECT ${attributeNames} FROM ${quotedBackupTableName};DROP TABLE ${quotedBackupTableName};`;
  294. }
  295. _alterConstraintQuery(tableName, attributes, createTableSql) {
  296. let backupTableName;
  297. attributes = this.attributesToSQL(attributes);
  298. if (typeof tableName === "object") {
  299. backupTableName = {
  300. tableName: `${tableName.tableName}_backup`,
  301. schema: tableName.schema
  302. };
  303. } else {
  304. backupTableName = `${tableName}_backup`;
  305. }
  306. const quotedTableName = this.quoteTable(tableName);
  307. const quotedBackupTableName = this.quoteTable(backupTableName);
  308. const attributeNames = Object.keys(attributes).map((attr) => this.quoteIdentifier(attr)).join(", ");
  309. return `${createTableSql.replace(`CREATE TABLE ${quotedTableName}`, `CREATE TABLE ${quotedBackupTableName}`).replace(`CREATE TABLE ${quotedTableName.replace(/`/g, '"')}`, `CREATE TABLE ${quotedBackupTableName}`)}INSERT INTO ${quotedBackupTableName} SELECT ${attributeNames} FROM ${quotedTableName};DROP TABLE ${quotedTableName};ALTER TABLE ${quotedBackupTableName} RENAME TO ${quotedTableName};`;
  310. }
  311. renameColumnQuery(tableName, attrNameBefore, attrNameAfter, attributes) {
  312. let backupTableName;
  313. attributes = this.attributesToSQL(attributes);
  314. if (typeof tableName === "object") {
  315. backupTableName = {
  316. tableName: `${tableName.tableName}_backup`,
  317. schema: tableName.schema
  318. };
  319. } else {
  320. backupTableName = `${tableName}_backup`;
  321. }
  322. const quotedTableName = this.quoteTable(tableName);
  323. const quotedBackupTableName = this.quoteTable(backupTableName);
  324. const attributeNamesImport = Object.keys(attributes).map((attr) => attrNameAfter === attr ? `${this.quoteIdentifier(attrNameBefore)} AS ${this.quoteIdentifier(attr)}` : this.quoteIdentifier(attr)).join(", ");
  325. const attributeNamesExport = Object.keys(attributes).map((attr) => this.quoteIdentifier(attr)).join(", ");
  326. return `${this.createTableQuery(backupTableName, attributes)}INSERT INTO ${quotedBackupTableName} SELECT ${attributeNamesImport} FROM ${quotedTableName};DROP TABLE ${quotedTableName};${this.createTableQuery(tableName, attributes)}INSERT INTO ${quotedTableName} SELECT ${attributeNamesExport} FROM ${quotedBackupTableName};DROP TABLE ${quotedBackupTableName};`;
  327. }
  328. startTransactionQuery(transaction) {
  329. if (transaction.parent) {
  330. return `SAVEPOINT ${this.quoteIdentifier(transaction.name)};`;
  331. }
  332. return `BEGIN ${transaction.options.type} TRANSACTION;`;
  333. }
  334. setIsolationLevelQuery(value) {
  335. switch (value) {
  336. case Transaction.ISOLATION_LEVELS.REPEATABLE_READ:
  337. return "-- SQLite is not able to choose the isolation level REPEATABLE READ.";
  338. case Transaction.ISOLATION_LEVELS.READ_UNCOMMITTED:
  339. return "PRAGMA read_uncommitted = ON;";
  340. case Transaction.ISOLATION_LEVELS.READ_COMMITTED:
  341. return "PRAGMA read_uncommitted = OFF;";
  342. case Transaction.ISOLATION_LEVELS.SERIALIZABLE:
  343. return "-- SQLite's default isolation level is SERIALIZABLE. Nothing to do.";
  344. default:
  345. throw new Error(`Unknown isolation level: ${value}`);
  346. }
  347. }
  348. replaceBooleanDefaults(sql) {
  349. return sql.replace(/DEFAULT '?false'?/g, "DEFAULT 0").replace(/DEFAULT '?true'?/g, "DEFAULT 1");
  350. }
  351. getForeignKeysQuery(tableName) {
  352. return `PRAGMA foreign_key_list(${this.quoteTable(this.addSchema(tableName))})`;
  353. }
  354. tableExistsQuery(tableName) {
  355. return `SELECT name FROM sqlite_master WHERE type='table' AND name=${this.escape(this.addSchema(tableName))};`;
  356. }
  357. quoteIdentifier(identifier, force) {
  358. return Utils.addTicks(Utils.removeTicks(identifier, "`"), "`");
  359. }
  360. }
  361. module.exports = SQLiteQueryGenerator;
  362. //# sourceMappingURL=query-generator.js.map