query-interface.js 47 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469
  1. 'use strict';
  2. const _ = require('lodash');
  3. const Utils = require('./utils');
  4. const DataTypes = require('./data-types');
  5. const SQLiteQueryInterface = require('./dialects/sqlite/query-interface');
  6. const MSSQLQueryInterface = require('./dialects/mssql/query-interface');
  7. const MySQLQueryInterface = require('./dialects/mysql/query-interface');
  8. const PostgresQueryInterface = require('./dialects/postgres/query-interface');
  9. const Transaction = require('./transaction');
  10. const Promise = require('./promise');
  11. const QueryTypes = require('./query-types');
  12. const Op = require('./operators');
  13. /**
  14. * The interface that Sequelize uses to talk to all databases
  15. *
  16. * @class QueryInterface
  17. */
  18. class QueryInterface {
  19. constructor(sequelize) {
  20. this.sequelize = sequelize;
  21. this.QueryGenerator = this.sequelize.dialect.QueryGenerator;
  22. }
  23. /**
  24. * Create a database
  25. *
  26. * @param {string} database Database name to create
  27. * @param {Object} [options] Query options
  28. * @param {string} [options.charset] Database default character set, MYSQL only
  29. * @param {string} [options.collate] Database default collation
  30. * @param {string} [options.encoding] Database default character set, PostgreSQL only
  31. * @param {string} [options.ctype] Database character classification, PostgreSQL only
  32. * @param {string} [options.template] The name of the template from which to create the new database, PostgreSQL only
  33. *
  34. * @returns {Promise}
  35. */
  36. createDatabase(database, options) {
  37. options = options || {};
  38. const sql = this.QueryGenerator.createDatabaseQuery(database, options);
  39. return this.sequelize.query(sql, options);
  40. }
  41. /**
  42. * Drop a database
  43. *
  44. * @param {string} database Database name to drop
  45. * @param {Object} [options] Query options
  46. *
  47. * @returns {Promise}
  48. */
  49. dropDatabase(database, options) {
  50. options = options || {};
  51. const sql = this.QueryGenerator.dropDatabaseQuery(database);
  52. return this.sequelize.query(sql, options);
  53. }
  54. /**
  55. * Create a schema
  56. *
  57. * @param {string} schema Schema name to create
  58. * @param {Object} [options] Query options
  59. *
  60. * @returns {Promise}
  61. */
  62. createSchema(schema, options) {
  63. options = options || {};
  64. const sql = this.QueryGenerator.createSchema(schema);
  65. return this.sequelize.query(sql, options);
  66. }
  67. /**
  68. * Drop a schema
  69. *
  70. * @param {string} schema Schema name to drop
  71. * @param {Object} [options] Query options
  72. *
  73. * @returns {Promise}
  74. */
  75. dropSchema(schema, options) {
  76. options = options || {};
  77. const sql = this.QueryGenerator.dropSchema(schema);
  78. return this.sequelize.query(sql, options);
  79. }
  80. /**
  81. * Drop all schemas
  82. *
  83. * @param {Object} [options] Query options
  84. *
  85. * @returns {Promise}
  86. */
  87. dropAllSchemas(options) {
  88. options = options || {};
  89. if (!this.QueryGenerator._dialect.supports.schemas) {
  90. return this.sequelize.drop(options);
  91. }
  92. return this.showAllSchemas(options).map(schemaName => this.dropSchema(schemaName, options));
  93. }
  94. /**
  95. * Show all schemas
  96. *
  97. * @param {Object} [options] Query options
  98. *
  99. * @returns {Promise<Array>}
  100. */
  101. showAllSchemas(options) {
  102. options = Object.assign({}, options, {
  103. raw: true,
  104. type: this.sequelize.QueryTypes.SELECT
  105. });
  106. const showSchemasSql = this.QueryGenerator.showSchemasQuery(options);
  107. return this.sequelize.query(showSchemasSql, options).then(schemaNames => _.flatten(
  108. schemaNames.map(value => value.schema_name ? value.schema_name : value)
  109. ));
  110. }
  111. /**
  112. * Return database version
  113. *
  114. * @param {Object} [options] Query options
  115. * @param {QueryType} [options.type] Query type
  116. *
  117. * @returns {Promise}
  118. * @private
  119. */
  120. databaseVersion(options) {
  121. return this.sequelize.query(
  122. this.QueryGenerator.versionQuery(),
  123. Object.assign({}, options, { type: QueryTypes.VERSION })
  124. );
  125. }
  126. /**
  127. * Create a table with given set of attributes
  128. *
  129. * ```js
  130. * queryInterface.createTable(
  131. * 'nameOfTheNewTable',
  132. * {
  133. * id: {
  134. * type: Sequelize.INTEGER,
  135. * primaryKey: true,
  136. * autoIncrement: true
  137. * },
  138. * createdAt: {
  139. * type: Sequelize.DATE
  140. * },
  141. * updatedAt: {
  142. * type: Sequelize.DATE
  143. * },
  144. * attr1: Sequelize.STRING,
  145. * attr2: Sequelize.INTEGER,
  146. * attr3: {
  147. * type: Sequelize.BOOLEAN,
  148. * defaultValue: false,
  149. * allowNull: false
  150. * },
  151. * //foreign key usage
  152. * attr4: {
  153. * type: Sequelize.INTEGER,
  154. * references: {
  155. * model: 'another_table_name',
  156. * key: 'id'
  157. * },
  158. * onUpdate: 'cascade',
  159. * onDelete: 'cascade'
  160. * }
  161. * },
  162. * {
  163. * engine: 'MYISAM', // default: 'InnoDB'
  164. * charset: 'latin1', // default: null
  165. * schema: 'public', // default: public, PostgreSQL only.
  166. * comment: 'my table', // comment for table
  167. * collate: 'latin1_danish_ci' // collation, MYSQL only
  168. * }
  169. * )
  170. * ```
  171. *
  172. * @param {string} tableName Name of table to create
  173. * @param {Object} attributes Object representing a list of table attributes to create
  174. * @param {Object} [options] create table and query options
  175. * @param {Model} [model] model class
  176. *
  177. * @returns {Promise}
  178. */
  179. createTable(tableName, attributes, options, model) {
  180. let sql = '';
  181. let promise;
  182. options = _.clone(options) || {};
  183. if (options && options.uniqueKeys) {
  184. _.forOwn(options.uniqueKeys, uniqueKey => {
  185. if (uniqueKey.customIndex === undefined) {
  186. uniqueKey.customIndex = true;
  187. }
  188. });
  189. }
  190. if (model) {
  191. options.uniqueKeys = options.uniqueKeys || model.uniqueKeys;
  192. }
  193. attributes = _.mapValues(
  194. attributes,
  195. attribute => this.sequelize.normalizeAttribute(attribute)
  196. );
  197. // Postgres requires special SQL commands for ENUM/ENUM[]
  198. if (this.sequelize.options.dialect === 'postgres') {
  199. promise = PostgresQueryInterface.ensureEnums(this, tableName, attributes, options, model);
  200. } else {
  201. promise = Promise.resolve();
  202. }
  203. if (
  204. !tableName.schema &&
  205. (options.schema || !!model && model._schema)
  206. ) {
  207. tableName = this.QueryGenerator.addSchema({
  208. tableName,
  209. _schema: !!model && model._schema || options.schema
  210. });
  211. }
  212. attributes = this.QueryGenerator.attributesToSQL(attributes, { table: tableName, context: 'createTable' });
  213. sql = this.QueryGenerator.createTableQuery(tableName, attributes, options);
  214. return promise.then(() => this.sequelize.query(sql, options));
  215. }
  216. /**
  217. * Drop a table from database
  218. *
  219. * @param {string} tableName Table name to drop
  220. * @param {Object} options Query options
  221. *
  222. * @returns {Promise}
  223. */
  224. dropTable(tableName, options) {
  225. // if we're forcing we should be cascading unless explicitly stated otherwise
  226. options = _.clone(options) || {};
  227. options.cascade = options.cascade || options.force || false;
  228. let sql = this.QueryGenerator.dropTableQuery(tableName, options);
  229. return this.sequelize.query(sql, options).then(() => {
  230. const promises = [];
  231. // Since postgres has a special case for enums, we should drop the related
  232. // enum type within the table and attribute
  233. if (this.sequelize.options.dialect === 'postgres') {
  234. const instanceTable = this.sequelize.modelManager.getModel(tableName, { attribute: 'tableName' });
  235. if (instanceTable) {
  236. const getTableName = (!options || !options.schema || options.schema === 'public' ? '' : `${options.schema}_`) + tableName;
  237. const keys = Object.keys(instanceTable.rawAttributes);
  238. const keyLen = keys.length;
  239. for (let i = 0; i < keyLen; i++) {
  240. if (instanceTable.rawAttributes[keys[i]].type instanceof DataTypes.ENUM) {
  241. sql = this.QueryGenerator.pgEnumDrop(getTableName, keys[i]);
  242. options.supportsSearchPath = false;
  243. promises.push(this.sequelize.query(sql, Object.assign({}, options, { raw: true })));
  244. }
  245. }
  246. }
  247. }
  248. return Promise.all(promises).get(0);
  249. });
  250. }
  251. /**
  252. * Drop all tables from database
  253. *
  254. * @param {Object} [options] query options
  255. * @param {Array} [options.skip] List of table to skip
  256. *
  257. * @returns {Promise}
  258. */
  259. dropAllTables(options) {
  260. options = options || {};
  261. const skip = options.skip || [];
  262. const dropAllTables = tableNames => Promise.each(tableNames, tableName => {
  263. // if tableName is not in the Array of tables names then don't drop it
  264. if (!skip.includes(tableName.tableName || tableName)) {
  265. return this.dropTable(tableName, Object.assign({}, options, { cascade: true }) );
  266. }
  267. });
  268. return this.showAllTables(options).then(tableNames => {
  269. if (this.sequelize.options.dialect === 'sqlite') {
  270. return this.sequelize.query('PRAGMA foreign_keys;', options).then(result => {
  271. const foreignKeysAreEnabled = result.foreign_keys === 1;
  272. if (foreignKeysAreEnabled) {
  273. return this.sequelize.query('PRAGMA foreign_keys = OFF', options)
  274. .then(() => dropAllTables(tableNames))
  275. .then(() => this.sequelize.query('PRAGMA foreign_keys = ON', options));
  276. }
  277. return dropAllTables(tableNames);
  278. });
  279. }
  280. return this.getForeignKeysForTables(tableNames, options).then(foreignKeys => {
  281. const queries = [];
  282. tableNames.forEach(tableName => {
  283. let normalizedTableName = tableName;
  284. if (_.isObject(tableName)) {
  285. normalizedTableName = `${tableName.schema}.${tableName.tableName}`;
  286. }
  287. foreignKeys[normalizedTableName].forEach(foreignKey => {
  288. queries.push(this.QueryGenerator.dropForeignKeyQuery(tableName, foreignKey));
  289. });
  290. });
  291. return Promise.each(queries, q => this.sequelize.query(q, options))
  292. .then(() => dropAllTables(tableNames));
  293. });
  294. });
  295. }
  296. /**
  297. * Drop specified enum from database (Postgres only)
  298. *
  299. * @param {string} [enumName] Enum name to drop
  300. * @param {Object} options Query options
  301. *
  302. * @returns {Promise}
  303. * @private
  304. */
  305. dropEnum(enumName, options) {
  306. if (this.sequelize.getDialect() !== 'postgres') {
  307. return Promise.resolve();
  308. }
  309. options = options || {};
  310. return this.sequelize.query(
  311. this.QueryGenerator.pgEnumDrop(null, null, this.QueryGenerator.pgEscapeAndQuote(enumName)),
  312. Object.assign({}, options, { raw: true })
  313. );
  314. }
  315. /**
  316. * Drop all enums from database (Postgres only)
  317. *
  318. * @param {Object} options Query options
  319. *
  320. * @returns {Promise}
  321. * @private
  322. */
  323. dropAllEnums(options) {
  324. if (this.sequelize.getDialect() !== 'postgres') {
  325. return Promise.resolve();
  326. }
  327. options = options || {};
  328. return this.pgListEnums(null, options).map(result => this.sequelize.query(
  329. this.QueryGenerator.pgEnumDrop(null, null, this.QueryGenerator.pgEscapeAndQuote(result.enum_name)),
  330. Object.assign({}, options, { raw: true })
  331. ));
  332. }
  333. /**
  334. * List all enums (Postgres only)
  335. *
  336. * @param {string} [tableName] Table whose enum to list
  337. * @param {Object} [options] Query options
  338. *
  339. * @returns {Promise}
  340. * @private
  341. */
  342. pgListEnums(tableName, options) {
  343. options = options || {};
  344. const sql = this.QueryGenerator.pgListEnums(tableName);
  345. return this.sequelize.query(sql, Object.assign({}, options, { plain: false, raw: true, type: QueryTypes.SELECT }));
  346. }
  347. /**
  348. * Rename a table
  349. *
  350. * @param {string} before Current name of table
  351. * @param {string} after New name from table
  352. * @param {Object} [options] Query options
  353. *
  354. * @returns {Promise}
  355. */
  356. renameTable(before, after, options) {
  357. options = options || {};
  358. const sql = this.QueryGenerator.renameTableQuery(before, after);
  359. return this.sequelize.query(sql, options);
  360. }
  361. /**
  362. * Get all tables in current database
  363. *
  364. * @param {Object} [options] Query options
  365. * @param {boolean} [options.raw=true] Run query in raw mode
  366. * @param {QueryType} [options.type=QueryType.SHOWTABLE] query type
  367. *
  368. * @returns {Promise<Array>}
  369. * @private
  370. */
  371. showAllTables(options) {
  372. options = Object.assign({}, options, {
  373. raw: true,
  374. type: QueryTypes.SHOWTABLES
  375. });
  376. const showTablesSql = this.QueryGenerator.showTablesQuery(this.sequelize.config.database);
  377. return this.sequelize.query(showTablesSql, options).then(tableNames => _.flatten(tableNames));
  378. }
  379. /**
  380. * Describe a table structure
  381. *
  382. * This method returns an array of hashes containing information about all attributes in the table.
  383. *
  384. * ```js
  385. * {
  386. * name: {
  387. * type: 'VARCHAR(255)', // this will be 'CHARACTER VARYING' for pg!
  388. * allowNull: true,
  389. * defaultValue: null
  390. * },
  391. * isBetaMember: {
  392. * type: 'TINYINT(1)', // this will be 'BOOLEAN' for pg!
  393. * allowNull: false,
  394. * defaultValue: false
  395. * }
  396. * }
  397. * ```
  398. *
  399. * @param {string} tableName table name
  400. * @param {Object} [options] Query options
  401. *
  402. * @returns {Promise<Object>}
  403. */
  404. describeTable(tableName, options) {
  405. if (this.sequelize.options.dialect === 'sqlite') {
  406. // sqlite needs some special treatment as it cannot rename a column
  407. return SQLiteQueryInterface.describeTable(this, tableName, options);
  408. }
  409. let schema = null;
  410. let schemaDelimiter = null;
  411. if (typeof options === 'string') {
  412. schema = options;
  413. } else if (typeof options === 'object' && options !== null) {
  414. schema = options.schema || null;
  415. schemaDelimiter = options.schemaDelimiter || null;
  416. }
  417. if (typeof tableName === 'object' && tableName !== null) {
  418. schema = tableName.schema;
  419. tableName = tableName.tableName;
  420. }
  421. const sql = this.QueryGenerator.describeTableQuery(tableName, schema, schemaDelimiter);
  422. options = Object.assign({}, options, { type: QueryTypes.DESCRIBE });
  423. return this.sequelize.query(sql, options).then(data => {
  424. /*
  425. * If no data is returned from the query, then the table name may be wrong.
  426. * Query generators that use information_schema for retrieving table info will just return an empty result set,
  427. * it will not throw an error like built-ins do (e.g. DESCRIBE on MySql).
  428. */
  429. if (_.isEmpty(data)) {
  430. throw new Error(`No description found for "${tableName}" table. Check the table name and schema; remember, they _are_ case sensitive.`);
  431. }
  432. return data;
  433. }).catch(e => {
  434. if (e.original && e.original.code === 'ER_NO_SUCH_TABLE') {
  435. throw Error(`No description found for "${tableName}" table. Check the table name and schema; remember, they _are_ case sensitive.`);
  436. }
  437. throw e;
  438. });
  439. }
  440. /**
  441. * Add a new column to a table
  442. *
  443. * ```js
  444. * queryInterface.addColumn('tableA', 'columnC', Sequelize.STRING, {
  445. * after: 'columnB' // after option is only supported by MySQL
  446. * });
  447. * ```
  448. *
  449. * @param {string} table Table to add column to
  450. * @param {string} key Column name
  451. * @param {Object} attribute Attribute definition
  452. * @param {Object} [options] Query options
  453. *
  454. * @returns {Promise}
  455. */
  456. addColumn(table, key, attribute, options) {
  457. if (!table || !key || !attribute) {
  458. throw new Error('addColumn takes at least 3 arguments (table, attribute name, attribute definition)');
  459. }
  460. options = options || {};
  461. attribute = this.sequelize.normalizeAttribute(attribute);
  462. return this.sequelize.query(this.QueryGenerator.addColumnQuery(table, key, attribute), options);
  463. }
  464. /**
  465. * Remove a column from a table
  466. *
  467. * @param {string} tableName Table to remove column from
  468. * @param {string} attributeName Column name to remove
  469. * @param {Object} [options] Query options
  470. *
  471. * @returns {Promise}
  472. */
  473. removeColumn(tableName, attributeName, options) {
  474. options = options || {};
  475. switch (this.sequelize.options.dialect) {
  476. case 'sqlite':
  477. // sqlite needs some special treatment as it cannot drop a column
  478. return SQLiteQueryInterface.removeColumn(this, tableName, attributeName, options);
  479. case 'mssql':
  480. // mssql needs special treatment as it cannot drop a column with a default or foreign key constraint
  481. return MSSQLQueryInterface.removeColumn(this, tableName, attributeName, options);
  482. case 'mysql':
  483. case 'mariadb':
  484. // mysql/mariadb need special treatment as it cannot drop a column with a foreign key constraint
  485. return MySQLQueryInterface.removeColumn(this, tableName, attributeName, options);
  486. default:
  487. return this.sequelize.query(this.QueryGenerator.removeColumnQuery(tableName, attributeName), options);
  488. }
  489. }
  490. /**
  491. * Change a column definition
  492. *
  493. * @param {string} tableName Table name to change from
  494. * @param {string} attributeName Column name
  495. * @param {Object} dataTypeOrOptions Attribute definition for new column
  496. * @param {Object} [options] Query options
  497. *
  498. * @returns {Promise}
  499. */
  500. changeColumn(tableName, attributeName, dataTypeOrOptions, options) {
  501. const attributes = {};
  502. options = options || {};
  503. if (_.values(DataTypes).includes(dataTypeOrOptions)) {
  504. attributes[attributeName] = { type: dataTypeOrOptions, allowNull: true };
  505. } else {
  506. attributes[attributeName] = dataTypeOrOptions;
  507. }
  508. attributes[attributeName] = this.sequelize.normalizeAttribute(attributes[attributeName]);
  509. if (this.sequelize.options.dialect === 'sqlite') {
  510. // sqlite needs some special treatment as it cannot change a column
  511. return SQLiteQueryInterface.changeColumn(this, tableName, attributes, options);
  512. }
  513. const query = this.QueryGenerator.attributesToSQL(attributes, {
  514. context: 'changeColumn',
  515. table: tableName
  516. });
  517. const sql = this.QueryGenerator.changeColumnQuery(tableName, query);
  518. return this.sequelize.query(sql, options);
  519. }
  520. /**
  521. * Rename a column
  522. *
  523. * @param {string} tableName Table name whose column to rename
  524. * @param {string} attrNameBefore Current column name
  525. * @param {string} attrNameAfter New column name
  526. * @param {Object} [options] Query option
  527. *
  528. * @returns {Promise}
  529. */
  530. renameColumn(tableName, attrNameBefore, attrNameAfter, options) {
  531. options = options || {};
  532. return this.describeTable(tableName, options).then(data => {
  533. if (!data[attrNameBefore]) {
  534. throw new Error(`Table ${tableName} doesn't have the column ${attrNameBefore}`);
  535. }
  536. data = data[attrNameBefore] || {};
  537. const _options = {};
  538. _options[attrNameAfter] = {
  539. attribute: attrNameAfter,
  540. type: data.type,
  541. allowNull: data.allowNull,
  542. defaultValue: data.defaultValue
  543. };
  544. // fix: a not-null column cannot have null as default value
  545. if (data.defaultValue === null && !data.allowNull) {
  546. delete _options[attrNameAfter].defaultValue;
  547. }
  548. if (this.sequelize.options.dialect === 'sqlite') {
  549. // sqlite needs some special treatment as it cannot rename a column
  550. return SQLiteQueryInterface.renameColumn(this, tableName, attrNameBefore, attrNameAfter, options);
  551. }
  552. const sql = this.QueryGenerator.renameColumnQuery(
  553. tableName,
  554. attrNameBefore,
  555. this.QueryGenerator.attributesToSQL(_options)
  556. );
  557. return this.sequelize.query(sql, options);
  558. });
  559. }
  560. /**
  561. * Add an index to a column
  562. *
  563. * @param {string|Object} tableName Table name to add index on, can be a object with schema
  564. * @param {Array} [attributes] Use options.fields instead, List of attributes to add index on
  565. * @param {Object} options indexes options
  566. * @param {Array} options.fields List of attributes to add index on
  567. * @param {boolean} [options.concurrently] Pass CONCURRENT so other operations run while the index is created
  568. * @param {boolean} [options.unique] Create a unique index
  569. * @param {string} [options.using] Useful for GIN indexes
  570. * @param {string} [options.operator] Index operator
  571. * @param {string} [options.type] Type of index, available options are UNIQUE|FULLTEXT|SPATIAL
  572. * @param {string} [options.name] Name of the index. Default is <table>_<attr1>_<attr2>
  573. * @param {Object} [options.where] Where condition on index, for partial indexes
  574. * @param {string} [rawTablename] table name, this is just for backward compatibiity
  575. *
  576. * @returns {Promise}
  577. */
  578. addIndex(tableName, attributes, options, rawTablename) {
  579. // Support for passing tableName, attributes, options or tableName, options (with a fields param which is the attributes)
  580. if (!Array.isArray(attributes)) {
  581. rawTablename = options;
  582. options = attributes;
  583. attributes = options.fields;
  584. }
  585. if (!rawTablename) {
  586. // Map for backwards compat
  587. rawTablename = tableName;
  588. }
  589. options = Utils.cloneDeep(options);
  590. options.fields = attributes;
  591. const sql = this.QueryGenerator.addIndexQuery(tableName, options, rawTablename);
  592. return this.sequelize.query(sql, Object.assign({}, options, { supportsSearchPath: false }));
  593. }
  594. /**
  595. * Show indexes on a table
  596. *
  597. * @param {string} tableName table name
  598. * @param {Object} [options] Query options
  599. *
  600. * @returns {Promise<Array>}
  601. * @private
  602. */
  603. showIndex(tableName, options) {
  604. const sql = this.QueryGenerator.showIndexesQuery(tableName, options);
  605. return this.sequelize.query(sql, Object.assign({}, options, { type: QueryTypes.SHOWINDEXES }));
  606. }
  607. getForeignKeysForTables(tableNames, options) {
  608. if (tableNames.length === 0) {
  609. return Promise.resolve({});
  610. }
  611. options = Object.assign({}, options || {}, { type: QueryTypes.FOREIGNKEYS });
  612. return Promise.map(tableNames, tableName =>
  613. this.sequelize.query(this.QueryGenerator.getForeignKeysQuery(tableName, this.sequelize.config.database), options)
  614. ).then(results => {
  615. const result = {};
  616. tableNames.forEach((tableName, i) => {
  617. if (_.isObject(tableName)) {
  618. tableName = `${tableName.schema}.${tableName.tableName}`;
  619. }
  620. result[tableName] = Array.isArray(results[i])
  621. ? results[i].map(r => r.constraint_name)
  622. : [results[i] && results[i].constraint_name];
  623. result[tableName] = result[tableName].filter(_.identity);
  624. });
  625. return result;
  626. });
  627. }
  628. /**
  629. * Get foreign key references details for the table
  630. *
  631. * Those details contains constraintSchema, constraintName, constraintCatalog
  632. * tableCatalog, tableSchema, tableName, columnName,
  633. * referencedTableCatalog, referencedTableCatalog, referencedTableSchema, referencedTableName, referencedColumnName.
  634. * Remind: constraint informations won't return if it's sqlite.
  635. *
  636. * @param {string} tableName table name
  637. * @param {Object} [options] Query options
  638. *
  639. * @returns {Promise}
  640. */
  641. getForeignKeyReferencesForTable(tableName, options) {
  642. const queryOptions = Object.assign({}, options, {
  643. type: QueryTypes.FOREIGNKEYS
  644. });
  645. const catalogName = this.sequelize.config.database;
  646. switch (this.sequelize.options.dialect) {
  647. case 'sqlite':
  648. // sqlite needs some special treatment.
  649. return SQLiteQueryInterface.getForeignKeyReferencesForTable(this, tableName, queryOptions);
  650. case 'postgres':
  651. {
  652. // postgres needs some special treatment as those field names returned are all lowercase
  653. // in order to keep same result with other dialects.
  654. const query = this.QueryGenerator.getForeignKeyReferencesQuery(tableName, catalogName);
  655. return this.sequelize.query(query, queryOptions)
  656. .then(result => result.map(Utils.camelizeObjectKeys));
  657. }
  658. case 'mssql':
  659. case 'mysql':
  660. case 'mariadb':
  661. default: {
  662. const query = this.QueryGenerator.getForeignKeysQuery(tableName, catalogName);
  663. return this.sequelize.query(query, queryOptions);
  664. }
  665. }
  666. }
  667. /**
  668. * Remove an already existing index from a table
  669. *
  670. * @param {string} tableName Table name to drop index from
  671. * @param {string} indexNameOrAttributes Index name
  672. * @param {Object} [options] Query options
  673. *
  674. * @returns {Promise}
  675. */
  676. removeIndex(tableName, indexNameOrAttributes, options) {
  677. options = options || {};
  678. const sql = this.QueryGenerator.removeIndexQuery(tableName, indexNameOrAttributes);
  679. return this.sequelize.query(sql, options);
  680. }
  681. /**
  682. * Add a constraint to a table
  683. *
  684. * Available constraints:
  685. * - UNIQUE
  686. * - DEFAULT (MSSQL only)
  687. * - CHECK (MySQL - Ignored by the database engine )
  688. * - FOREIGN KEY
  689. * - PRIMARY KEY
  690. *
  691. * @example <caption>UNIQUE</caption>
  692. * queryInterface.addConstraint('Users', ['email'], {
  693. * type: 'unique',
  694. * name: 'custom_unique_constraint_name'
  695. * });
  696. *
  697. * @example <caption>CHECK</caption>
  698. * queryInterface.addConstraint('Users', ['roles'], {
  699. * type: 'check',
  700. * where: {
  701. * roles: ['user', 'admin', 'moderator', 'guest']
  702. * }
  703. * });
  704. *
  705. * @example <caption>Default - MSSQL only</caption>
  706. * queryInterface.addConstraint('Users', ['roles'], {
  707. * type: 'default',
  708. * defaultValue: 'guest'
  709. * });
  710. *
  711. * @example <caption>Primary Key</caption>
  712. * queryInterface.addConstraint('Users', ['username'], {
  713. * type: 'primary key',
  714. * name: 'custom_primary_constraint_name'
  715. * });
  716. *
  717. * @example <caption>Foreign Key</caption>
  718. * queryInterface.addConstraint('Posts', ['username'], {
  719. * type: 'foreign key',
  720. * name: 'custom_fkey_constraint_name',
  721. * references: { //Required field
  722. * table: 'target_table_name',
  723. * field: 'target_column_name'
  724. * },
  725. * onDelete: 'cascade',
  726. * onUpdate: 'cascade'
  727. * });
  728. *
  729. * @param {string} tableName Table name where you want to add a constraint
  730. * @param {Array} attributes Array of column names to apply the constraint over
  731. * @param {Object} options An object to define the constraint name, type etc
  732. * @param {string} options.type Type of constraint. One of the values in available constraints(case insensitive)
  733. * @param {string} [options.name] Name of the constraint. If not specified, sequelize automatically creates a named constraint based on constraint type, table & column names
  734. * @param {string} [options.defaultValue] The value for the default constraint
  735. * @param {Object} [options.where] Where clause/expression for the CHECK constraint
  736. * @param {Object} [options.references] Object specifying target table, column name to create foreign key constraint
  737. * @param {string} [options.references.table] Target table name
  738. * @param {string} [options.references.field] Target column name
  739. * @param {string} [rawTablename] Table name, for backward compatibility
  740. *
  741. * @returns {Promise}
  742. */
  743. addConstraint(tableName, attributes, options, rawTablename) {
  744. if (!Array.isArray(attributes)) {
  745. rawTablename = options;
  746. options = attributes;
  747. attributes = options.fields;
  748. }
  749. if (!options.type) {
  750. throw new Error('Constraint type must be specified through options.type');
  751. }
  752. if (!rawTablename) {
  753. // Map for backwards compat
  754. rawTablename = tableName;
  755. }
  756. options = Utils.cloneDeep(options);
  757. options.fields = attributes;
  758. if (this.sequelize.dialect.name === 'sqlite') {
  759. return SQLiteQueryInterface.addConstraint(this, tableName, options, rawTablename);
  760. }
  761. const sql = this.QueryGenerator.addConstraintQuery(tableName, options, rawTablename);
  762. return this.sequelize.query(sql, options);
  763. }
  764. showConstraint(tableName, constraintName, options) {
  765. const sql = this.QueryGenerator.showConstraintsQuery(tableName, constraintName);
  766. return this.sequelize.query(sql, Object.assign({}, options, { type: QueryTypes.SHOWCONSTRAINTS }));
  767. }
  768. /**
  769. * Remove a constraint from a table
  770. *
  771. * @param {string} tableName Table name to drop constraint from
  772. * @param {string} constraintName Constraint name
  773. * @param {Object} options Query options
  774. *
  775. * @returns {Promise}
  776. */
  777. removeConstraint(tableName, constraintName, options) {
  778. options = options || {};
  779. switch (this.sequelize.options.dialect) {
  780. case 'mysql':
  781. case 'mariadb':
  782. //does not support DROP CONSTRAINT. Instead DROP PRIMARY, FOREIGN KEY, INDEX should be used
  783. return MySQLQueryInterface.removeConstraint(this, tableName, constraintName, options);
  784. case 'sqlite':
  785. return SQLiteQueryInterface.removeConstraint(this, tableName, constraintName, options);
  786. default:
  787. const sql = this.QueryGenerator.removeConstraintQuery(tableName, constraintName);
  788. return this.sequelize.query(sql, options);
  789. }
  790. }
  791. insert(instance, tableName, values, options) {
  792. options = Utils.cloneDeep(options);
  793. options.hasTrigger = instance && instance.constructor.options.hasTrigger;
  794. const sql = this.QueryGenerator.insertQuery(tableName, values, instance && instance.constructor.rawAttributes, options);
  795. options.type = QueryTypes.INSERT;
  796. options.instance = instance;
  797. return this.sequelize.query(sql, options).then(results => {
  798. if (instance) results[0].isNewRecord = false;
  799. return results;
  800. });
  801. }
  802. /**
  803. * Upsert
  804. *
  805. * @param {string} tableName table to upsert on
  806. * @param {Object} insertValues values to be inserted, mapped to field name
  807. * @param {Object} updateValues values to be updated, mapped to field name
  808. * @param {Object} where various conditions
  809. * @param {Model} model Model to upsert on
  810. * @param {Object} options query options
  811. *
  812. * @returns {Promise<boolean,?number>} Resolves an array with <created, primaryKey>
  813. */
  814. upsert(tableName, insertValues, updateValues, where, model, options) {
  815. const wheres = [];
  816. const attributes = Object.keys(insertValues);
  817. let indexes = [];
  818. let indexFields;
  819. options = _.clone(options);
  820. if (!Utils.isWhereEmpty(where)) {
  821. wheres.push(where);
  822. }
  823. // Lets combine unique keys and indexes into one
  824. indexes = _.map(model.uniqueKeys, value => {
  825. return value.fields;
  826. });
  827. model._indexes.forEach(value => {
  828. if (value.unique) {
  829. // fields in the index may both the strings or objects with an attribute property - lets sanitize that
  830. indexFields = value.fields.map(field => {
  831. if (_.isPlainObject(field)) {
  832. return field.attribute;
  833. }
  834. return field;
  835. });
  836. indexes.push(indexFields);
  837. }
  838. });
  839. for (const index of indexes) {
  840. if (_.intersection(attributes, index).length === index.length) {
  841. where = {};
  842. for (const field of index) {
  843. where[field] = insertValues[field];
  844. }
  845. wheres.push(where);
  846. }
  847. }
  848. where = { [Op.or]: wheres };
  849. options.type = QueryTypes.UPSERT;
  850. options.raw = true;
  851. const sql = this.QueryGenerator.upsertQuery(tableName, insertValues, updateValues, where, model, options);
  852. return this.sequelize.query(sql, options).then(result => {
  853. switch (this.sequelize.options.dialect) {
  854. case 'postgres':
  855. return [result.created, result.primary_key];
  856. case 'mssql':
  857. return [
  858. result.$action === 'INSERT',
  859. result[model.primaryKeyField]
  860. ];
  861. // MySQL returns 1 for inserted, 2 for updated
  862. // http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html.
  863. case 'mysql':
  864. case 'mariadb':
  865. return [result === 1, undefined];
  866. default:
  867. return [result, undefined];
  868. }
  869. });
  870. }
  871. /**
  872. * Insert multiple records into a table
  873. *
  874. * @example
  875. * queryInterface.bulkInsert('roles', [{
  876. * label: 'user',
  877. * createdAt: new Date(),
  878. * updatedAt: new Date()
  879. * }, {
  880. * label: 'admin',
  881. * createdAt: new Date(),
  882. * updatedAt: new Date()
  883. * }]);
  884. *
  885. * @param {string} tableName Table name to insert record to
  886. * @param {Array} records List of records to insert
  887. * @param {Object} options Various options, please see Model.bulkCreate options
  888. * @param {Object} attributes Various attributes mapped by field name
  889. *
  890. * @returns {Promise}
  891. */
  892. bulkInsert(tableName, records, options, attributes) {
  893. options = _.clone(options) || {};
  894. options.type = QueryTypes.INSERT;
  895. return this.sequelize.query(
  896. this.QueryGenerator.bulkInsertQuery(tableName, records, options, attributes),
  897. options
  898. ).then(results => results[0]);
  899. }
  900. update(instance, tableName, values, identifier, options) {
  901. options = _.clone(options || {});
  902. options.hasTrigger = !!(instance && instance._modelOptions && instance._modelOptions.hasTrigger);
  903. const sql = this.QueryGenerator.updateQuery(tableName, values, identifier, options, instance.constructor.rawAttributes);
  904. options.type = QueryTypes.UPDATE;
  905. options.instance = instance;
  906. return this.sequelize.query(sql, options);
  907. }
  908. /**
  909. * Update multiple records of a table
  910. *
  911. * @example
  912. * queryInterface.bulkUpdate('roles', {
  913. * label: 'admin',
  914. * }, {
  915. * userType: 3,
  916. * },
  917. * );
  918. *
  919. * @param {string} tableName Table name to update
  920. * @param {Object} values Values to be inserted, mapped to field name
  921. * @param {Object} identifier A hash with conditions OR an ID as integer OR a string with conditions
  922. * @param {Object} [options] Various options, please see Model.bulkCreate options
  923. * @param {Object} [attributes] Attributes on return objects if supported by SQL dialect
  924. *
  925. * @returns {Promise}
  926. */
  927. bulkUpdate(tableName, values, identifier, options, attributes) {
  928. options = Utils.cloneDeep(options);
  929. if (typeof identifier === 'object') identifier = Utils.cloneDeep(identifier);
  930. const sql = this.QueryGenerator.updateQuery(tableName, values, identifier, options, attributes);
  931. const table = _.isObject(tableName) ? tableName : { tableName };
  932. const model = _.find(this.sequelize.modelManager.models, { tableName: table.tableName });
  933. options.type = QueryTypes.BULKUPDATE;
  934. options.model = model;
  935. return this.sequelize.query(sql, options);
  936. }
  937. delete(instance, tableName, identifier, options) {
  938. const cascades = [];
  939. const sql = this.QueryGenerator.deleteQuery(tableName, identifier, {}, instance.constructor);
  940. options = _.clone(options) || {};
  941. // Check for a restrict field
  942. if (!!instance.constructor && !!instance.constructor.associations) {
  943. const keys = Object.keys(instance.constructor.associations);
  944. const length = keys.length;
  945. let association;
  946. for (let i = 0; i < length; i++) {
  947. association = instance.constructor.associations[keys[i]];
  948. if (association.options && association.options.onDelete &&
  949. association.options.onDelete.toLowerCase() === 'cascade' &&
  950. association.options.useHooks === true) {
  951. cascades.push(association.accessors.get);
  952. }
  953. }
  954. }
  955. return Promise.each(cascades, cascade => {
  956. return instance[cascade](options).then(instances => {
  957. // Check for hasOne relationship with non-existing associate ("has zero")
  958. if (!instances) {
  959. return Promise.resolve();
  960. }
  961. if (!Array.isArray(instances)) instances = [instances];
  962. return Promise.each(instances, instance => instance.destroy(options));
  963. });
  964. }).then(() => {
  965. options.instance = instance;
  966. return this.sequelize.query(sql, options);
  967. });
  968. }
  969. /**
  970. * Delete multiple records from a table
  971. *
  972. * @param {string} tableName table name from where to delete records
  973. * @param {Object} where where conditions to find records to delete
  974. * @param {Object} [options] options
  975. * @param {boolean} [options.truncate] Use truncate table command
  976. * @param {boolean} [options.cascade=false] Only used in conjunction with TRUNCATE. Truncates all tables that have foreign-key references to the named table, or to any tables added to the group due to CASCADE.
  977. * @param {boolean} [options.restartIdentity=false] Only used in conjunction with TRUNCATE. Automatically restart sequences owned by columns of the truncated table.
  978. * @param {Model} [model] Model
  979. *
  980. * @returns {Promise}
  981. */
  982. bulkDelete(tableName, where, options, model) {
  983. options = Utils.cloneDeep(options);
  984. options = _.defaults(options, { limit: null });
  985. if (options.truncate === true) {
  986. return this.sequelize.query(
  987. this.QueryGenerator.truncateTableQuery(tableName, options),
  988. options
  989. );
  990. }
  991. if (typeof identifier === 'object') where = Utils.cloneDeep(where);
  992. return this.sequelize.query(
  993. this.QueryGenerator.deleteQuery(tableName, where, options, model),
  994. options
  995. );
  996. }
  997. select(model, tableName, optionsArg) {
  998. const options = Object.assign({}, optionsArg, { type: QueryTypes.SELECT, model });
  999. return this.sequelize.query(
  1000. this.QueryGenerator.selectQuery(tableName, options, model),
  1001. options
  1002. );
  1003. }
  1004. increment(model, tableName, values, identifier, options) {
  1005. options = Utils.cloneDeep(options);
  1006. const sql = this.QueryGenerator.arithmeticQuery('+', tableName, values, identifier, options, options.attributes);
  1007. options.type = QueryTypes.UPDATE;
  1008. options.model = model;
  1009. return this.sequelize.query(sql, options);
  1010. }
  1011. decrement(model, tableName, values, identifier, options) {
  1012. options = Utils.cloneDeep(options);
  1013. const sql = this.QueryGenerator.arithmeticQuery('-', tableName, values, identifier, options, options.attributes);
  1014. options.type = QueryTypes.UPDATE;
  1015. options.model = model;
  1016. return this.sequelize.query(sql, options);
  1017. }
  1018. rawSelect(tableName, options, attributeSelector, Model) {
  1019. options = Utils.cloneDeep(options);
  1020. options = _.defaults(options, {
  1021. raw: true,
  1022. plain: true,
  1023. type: QueryTypes.SELECT
  1024. });
  1025. const sql = this.QueryGenerator.selectQuery(tableName, options, Model);
  1026. if (attributeSelector === undefined) {
  1027. throw new Error('Please pass an attribute selector!');
  1028. }
  1029. return this.sequelize.query(sql, options).then(data => {
  1030. if (!options.plain) {
  1031. return data;
  1032. }
  1033. const result = data ? data[attributeSelector] : null;
  1034. if (!options || !options.dataType) {
  1035. return result;
  1036. }
  1037. const dataType = options.dataType;
  1038. if (dataType instanceof DataTypes.DECIMAL || dataType instanceof DataTypes.FLOAT) {
  1039. if (result !== null) {
  1040. return parseFloat(result);
  1041. }
  1042. }
  1043. if (dataType instanceof DataTypes.INTEGER || dataType instanceof DataTypes.BIGINT) {
  1044. return parseInt(result, 10);
  1045. }
  1046. if (dataType instanceof DataTypes.DATE) {
  1047. if (result !== null && !(result instanceof Date)) {
  1048. return new Date(result);
  1049. }
  1050. }
  1051. return result;
  1052. });
  1053. }
  1054. createTrigger(tableName, triggerName, timingType, fireOnArray, functionName, functionParams, optionsArray, options) {
  1055. const sql = this.QueryGenerator.createTrigger(tableName, triggerName, timingType, fireOnArray, functionName, functionParams, optionsArray);
  1056. options = options || {};
  1057. if (sql) {
  1058. return this.sequelize.query(sql, options);
  1059. }
  1060. return Promise.resolve();
  1061. }
  1062. dropTrigger(tableName, triggerName, options) {
  1063. const sql = this.QueryGenerator.dropTrigger(tableName, triggerName);
  1064. options = options || {};
  1065. if (sql) {
  1066. return this.sequelize.query(sql, options);
  1067. }
  1068. return Promise.resolve();
  1069. }
  1070. renameTrigger(tableName, oldTriggerName, newTriggerName, options) {
  1071. const sql = this.QueryGenerator.renameTrigger(tableName, oldTriggerName, newTriggerName);
  1072. options = options || {};
  1073. if (sql) {
  1074. return this.sequelize.query(sql, options);
  1075. }
  1076. return Promise.resolve();
  1077. }
  1078. /**
  1079. * Create an SQL function
  1080. *
  1081. * @example
  1082. * queryInterface.createFunction(
  1083. * 'someFunction',
  1084. * [
  1085. * {type: 'integer', name: 'param', direction: 'IN'}
  1086. * ],
  1087. * 'integer',
  1088. * 'plpgsql',
  1089. * 'RETURN param + 1;',
  1090. * [
  1091. * 'IMMUTABLE',
  1092. * 'LEAKPROOF'
  1093. * ],
  1094. * {
  1095. * variables:
  1096. * [
  1097. * {type: 'integer', name: 'myVar', default: 100}
  1098. * ],
  1099. * force: true
  1100. * };
  1101. * );
  1102. *
  1103. * @param {string} functionName Name of SQL function to create
  1104. * @param {Array} params List of parameters declared for SQL function
  1105. * @param {string} returnType SQL type of function returned value
  1106. * @param {string} language The name of the language that the function is implemented in
  1107. * @param {string} body Source code of function
  1108. * @param {Array} optionsArray Extra-options for creation
  1109. * @param {Object} [options] query options
  1110. * @param {boolean} options.force If force is true, any existing functions with the same parameters will be replaced. For postgres, this means using `CREATE OR REPLACE FUNCTION` instead of `CREATE FUNCTION`. Default is false
  1111. * @param {Array<Object>} options.variables List of declared variables. Each variable should be an object with string fields `type` and `name`, and optionally having a `default` field as well.
  1112. *
  1113. * @returns {Promise}
  1114. */
  1115. createFunction(functionName, params, returnType, language, body, optionsArray, options) {
  1116. const sql = this.QueryGenerator.createFunction(functionName, params, returnType, language, body, optionsArray, options);
  1117. options = options || {};
  1118. if (sql) {
  1119. return this.sequelize.query(sql, options);
  1120. }
  1121. return Promise.resolve();
  1122. }
  1123. /**
  1124. * Drop an SQL function
  1125. *
  1126. * @example
  1127. * queryInterface.dropFunction(
  1128. * 'someFunction',
  1129. * [
  1130. * {type: 'varchar', name: 'param1', direction: 'IN'},
  1131. * {type: 'integer', name: 'param2', direction: 'INOUT'}
  1132. * ]
  1133. * );
  1134. *
  1135. * @param {string} functionName Name of SQL function to drop
  1136. * @param {Array} params List of parameters declared for SQL function
  1137. * @param {Object} [options] query options
  1138. *
  1139. * @returns {Promise}
  1140. */
  1141. dropFunction(functionName, params, options) {
  1142. const sql = this.QueryGenerator.dropFunction(functionName, params);
  1143. options = options || {};
  1144. if (sql) {
  1145. return this.sequelize.query(sql, options);
  1146. }
  1147. return Promise.resolve();
  1148. }
  1149. /**
  1150. * Rename an SQL function
  1151. *
  1152. * @example
  1153. * queryInterface.renameFunction(
  1154. * 'fooFunction',
  1155. * [
  1156. * {type: 'varchar', name: 'param1', direction: 'IN'},
  1157. * {type: 'integer', name: 'param2', direction: 'INOUT'}
  1158. * ],
  1159. * 'barFunction'
  1160. * );
  1161. *
  1162. * @param {string} oldFunctionName Current name of function
  1163. * @param {Array} params List of parameters declared for SQL function
  1164. * @param {string} newFunctionName New name of function
  1165. * @param {Object} [options] query options
  1166. *
  1167. * @returns {Promise}
  1168. */
  1169. renameFunction(oldFunctionName, params, newFunctionName, options) {
  1170. const sql = this.QueryGenerator.renameFunction(oldFunctionName, params, newFunctionName);
  1171. options = options || {};
  1172. if (sql) {
  1173. return this.sequelize.query(sql, options);
  1174. }
  1175. return Promise.resolve();
  1176. }
  1177. // Helper methods useful for querying
  1178. /**
  1179. * Escape an identifier (e.g. a table or attribute name)
  1180. *
  1181. * @param {string} identifier identifier to quote
  1182. * @param {boolean} [force] If force is true,the identifier will be quoted even if the `quoteIdentifiers` option is false.
  1183. *
  1184. * @private
  1185. */
  1186. quoteIdentifier(identifier, force) {
  1187. return this.QueryGenerator.quoteIdentifier(identifier, force);
  1188. }
  1189. quoteTable(identifier) {
  1190. return this.QueryGenerator.quoteTable(identifier);
  1191. }
  1192. /**
  1193. * Quote array of identifiers at once
  1194. *
  1195. * @param {string[]} identifiers array of identifiers to quote
  1196. * @param {boolean} [force] If force is true,the identifier will be quoted even if the `quoteIdentifiers` option is false.
  1197. *
  1198. * @private
  1199. */
  1200. quoteIdentifiers(identifiers, force) {
  1201. return this.QueryGenerator.quoteIdentifiers(identifiers, force);
  1202. }
  1203. /**
  1204. * Escape a value (e.g. a string, number or date)
  1205. *
  1206. * @param {string} value string to escape
  1207. *
  1208. * @private
  1209. */
  1210. escape(value) {
  1211. return this.QueryGenerator.escape(value);
  1212. }
  1213. setIsolationLevel(transaction, value, options) {
  1214. if (!transaction || !(transaction instanceof Transaction)) {
  1215. throw new Error('Unable to set isolation level for a transaction without transaction object!');
  1216. }
  1217. if (transaction.parent || !value) {
  1218. // Not possible to set a separate isolation level for savepoints
  1219. return Promise.resolve();
  1220. }
  1221. options = Object.assign({}, options, {
  1222. transaction: transaction.parent || transaction
  1223. });
  1224. const sql = this.QueryGenerator.setIsolationLevelQuery(value, {
  1225. parent: transaction.parent
  1226. });
  1227. if (!sql) return Promise.resolve();
  1228. return this.sequelize.query(sql, options);
  1229. }
  1230. startTransaction(transaction, options) {
  1231. if (!transaction || !(transaction instanceof Transaction)) {
  1232. throw new Error('Unable to start a transaction without transaction object!');
  1233. }
  1234. options = Object.assign({}, options, {
  1235. transaction: transaction.parent || transaction
  1236. });
  1237. options.transaction.name = transaction.parent ? transaction.name : undefined;
  1238. const sql = this.QueryGenerator.startTransactionQuery(transaction);
  1239. return this.sequelize.query(sql, options);
  1240. }
  1241. deferConstraints(transaction, options) {
  1242. options = Object.assign({}, options, {
  1243. transaction: transaction.parent || transaction
  1244. });
  1245. const sql = this.QueryGenerator.deferConstraintsQuery(options);
  1246. if (sql) {
  1247. return this.sequelize.query(sql, options);
  1248. }
  1249. return Promise.resolve();
  1250. }
  1251. commitTransaction(transaction, options) {
  1252. if (!transaction || !(transaction instanceof Transaction)) {
  1253. throw new Error('Unable to commit a transaction without transaction object!');
  1254. }
  1255. if (transaction.parent) {
  1256. // Savepoints cannot be committed
  1257. return Promise.resolve();
  1258. }
  1259. options = Object.assign({}, options, {
  1260. transaction: transaction.parent || transaction,
  1261. supportsSearchPath: false,
  1262. completesTransaction: true
  1263. });
  1264. const sql = this.QueryGenerator.commitTransactionQuery(transaction);
  1265. const promise = this.sequelize.query(sql, options);
  1266. transaction.finished = 'commit';
  1267. return promise;
  1268. }
  1269. rollbackTransaction(transaction, options) {
  1270. if (!transaction || !(transaction instanceof Transaction)) {
  1271. throw new Error('Unable to rollback a transaction without transaction object!');
  1272. }
  1273. options = Object.assign({}, options, {
  1274. transaction: transaction.parent || transaction,
  1275. supportsSearchPath: false,
  1276. completesTransaction: true
  1277. });
  1278. options.transaction.name = transaction.parent ? transaction.name : undefined;
  1279. const sql = this.QueryGenerator.rollbackTransactionQuery(transaction);
  1280. const promise = this.sequelize.query(sql, options);
  1281. transaction.finished = 'rollback';
  1282. return promise;
  1283. }
  1284. }
  1285. module.exports = QueryInterface;
  1286. module.exports.QueryInterface = QueryInterface;
  1287. module.exports.default = QueryInterface;