index.test.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. 'use strict';
  2. const Support = require('../../support');
  3. const { literal, Op } = require('@sequelize/core');
  4. const expectsql = Support.expectsql;
  5. const current = Support.sequelize;
  6. const sql = current.dialect.queryGenerator;
  7. // Notice: [] will be replaced by dialect specific tick/quote character when there is not dialect specific expectation but only a default expectation
  8. const TICK_LEFT = Support.sequelize.dialect.TICK_CHAR_LEFT;
  9. const TICK_RIGHT = Support.sequelize.dialect.TICK_CHAR_RIGHT;
  10. describe(Support.getTestDialectTeaser('SQL'), () => {
  11. if (current.dialect.name === 'snowflake') {
  12. return;
  13. }
  14. describe('addIndex', () => {
  15. it('naming', () => {
  16. expectsql(sql.addIndexQuery('table', ['column1', 'column2'], {}, 'table'), {
  17. default: 'CREATE INDEX [table_column1_column2] ON [table] ([column1], [column2])',
  18. 'mariadb mysql':
  19. 'ALTER TABLE `table` ADD INDEX `table_column1_column2` (`column1`, `column2`)',
  20. });
  21. if (current.dialect.supports.schemas) {
  22. expectsql(sql.addIndexQuery('schema.table', ['column1', 'column2'], {}), {
  23. default:
  24. 'CREATE INDEX [schema_table_column1_column2] ON [schema.table] ([column1], [column2])',
  25. 'mariadb mysql':
  26. 'ALTER TABLE `schema.table` ADD INDEX `schema_table_column1_column2` (`column1`, `column2`)',
  27. });
  28. expectsql(
  29. sql.addIndexQuery(
  30. {
  31. schema: 'schema',
  32. tableName: 'table',
  33. },
  34. ['column1', 'column2'],
  35. {},
  36. 'schema_table',
  37. ),
  38. {
  39. default:
  40. 'CREATE INDEX [schema_table_column1_column2] ON [schema].[table] ([column1], [column2])',
  41. db2: 'CREATE INDEX "schema"."schema_table_column1_column2" ON "schema"."table" ("column1", "column2")',
  42. 'mariadb mysql':
  43. 'ALTER TABLE `schema`.`table` ADD INDEX `schema_table_column1_column2` (`column1`, `column2`)',
  44. },
  45. );
  46. expectsql(
  47. sql.addIndexQuery(
  48. // quoteTable will produce '"schema"."table"'
  49. // that is a perfectly valid table name, so passing it to quoteTable again (through addIndexQuery) must produce this:
  50. // '"""schema"".""table"""'
  51. // the double-quotes are duplicated because they are escaped
  52. sql.quoteTable({
  53. schema: 'schema',
  54. tableName: 'table',
  55. }),
  56. ['column1', 'column2'],
  57. {},
  58. ),
  59. {
  60. // using TICK variables directly because it's impossible for expectsql to know whether the TICK inside ticks is meant to be a tick or just part of the string
  61. default: `CREATE INDEX ${TICK_LEFT}${TICK_LEFT}${TICK_LEFT}schema${TICK_RIGHT}${TICK_RIGHT}_${TICK_LEFT}${TICK_LEFT}table${TICK_RIGHT}${TICK_RIGHT}_column1_column2${TICK_RIGHT} ON ${TICK_LEFT}${TICK_LEFT}${TICK_LEFT}schema${TICK_RIGHT}${TICK_RIGHT}.${TICK_LEFT}${TICK_LEFT}table${TICK_RIGHT}${TICK_RIGHT}${TICK_RIGHT} ([column1], [column2])`,
  62. 'mariadb mysql':
  63. 'ALTER TABLE ```schema``.``table``` ADD INDEX ```schema``_``table``_column1_column2` (`column1`, `column2`)',
  64. },
  65. );
  66. }
  67. });
  68. it('type and using', () => {
  69. expectsql(
  70. sql.addIndexQuery('User', ['fieldC'], {
  71. type: 'FULLTEXT',
  72. concurrently: true,
  73. }),
  74. {
  75. ibmi: 'CREATE INDEX "user_field_c" ON "User" ("fieldC")',
  76. sqlite3: 'CREATE INDEX `user_field_c` ON `User` (`fieldC`)',
  77. db2: 'CREATE INDEX "user_field_c" ON "User" ("fieldC")',
  78. mssql: 'CREATE FULLTEXT INDEX [user_field_c] ON [User] ([fieldC])',
  79. postgres: 'CREATE INDEX CONCURRENTLY "user_field_c" ON "User" ("fieldC")',
  80. mariadb: 'ALTER TABLE `User` ADD FULLTEXT INDEX `user_field_c` (`fieldC`)',
  81. mysql: 'ALTER TABLE `User` ADD FULLTEXT INDEX `user_field_c` (`fieldC`)',
  82. },
  83. );
  84. expectsql(
  85. sql.addIndexQuery(
  86. 'User',
  87. ['fieldB', { attribute: 'fieldA', collate: 'en_US', order: 'DESC', length: 5 }],
  88. {
  89. name: 'a_b_uniq',
  90. unique: true,
  91. using: 'BTREE',
  92. parser: 'foo',
  93. },
  94. ),
  95. {
  96. sqlite3:
  97. 'CREATE UNIQUE INDEX `a_b_uniq` ON `User` (`fieldB`, `fieldA` COLLATE `en_US` DESC)',
  98. mssql: 'CREATE UNIQUE INDEX [a_b_uniq] ON [User] ([fieldB], [fieldA] DESC)',
  99. db2: 'CREATE UNIQUE INDEX "a_b_uniq" ON "User" ("fieldB", "fieldA" DESC)',
  100. ibmi: `BEGIN
  101. DECLARE CONTINUE HANDLER FOR SQLSTATE VALUE '42891'
  102. BEGIN END;
  103. ALTER TABLE "User" ADD CONSTRAINT "a_b_uniq" UNIQUE ("fieldB", "fieldA" DESC);
  104. END`,
  105. postgres:
  106. 'CREATE UNIQUE INDEX "a_b_uniq" ON "User" USING BTREE ("fieldB", "fieldA" COLLATE "en_US" DESC)',
  107. mariadb:
  108. 'ALTER TABLE `User` ADD UNIQUE INDEX `a_b_uniq` USING BTREE (`fieldB`, `fieldA`(5) DESC) WITH PARSER foo',
  109. mysql:
  110. 'ALTER TABLE `User` ADD UNIQUE INDEX `a_b_uniq` USING BTREE (`fieldB`, `fieldA`(5) DESC) WITH PARSER foo',
  111. },
  112. );
  113. });
  114. it('POJO field', () => {
  115. expectsql(
  116. sql.addIndexQuery(
  117. 'table',
  118. [{ name: 'column', collate: 'BINARY', length: 5, order: 'DESC' }],
  119. {},
  120. 'table',
  121. ),
  122. {
  123. default: 'CREATE INDEX [table_column] ON [table] ([column] COLLATE [BINARY] DESC)',
  124. mssql: 'CREATE INDEX [table_column] ON [table] ([column] DESC)',
  125. db2: 'CREATE INDEX "table_column" ON "table" ("column" DESC)',
  126. ibmi: 'CREATE INDEX "table_column" ON "table" ("column" DESC)',
  127. mariadb: 'ALTER TABLE `table` ADD INDEX `table_column` (`column`(5) DESC)',
  128. mysql: 'ALTER TABLE `table` ADD INDEX `table_column` (`column`(5) DESC)',
  129. },
  130. );
  131. });
  132. it('function', () => {
  133. expectsql(
  134. sql.addIndexQuery('table', [current.fn('UPPER', current.col('test'))], { name: 'myindex' }),
  135. {
  136. default: 'CREATE INDEX [myindex] ON [table] (UPPER([test]))',
  137. mariadb: 'ALTER TABLE `table` ADD INDEX `myindex` (UPPER(`test`))',
  138. mysql: 'ALTER TABLE `table` ADD INDEX `myindex` (UPPER(`test`))',
  139. },
  140. );
  141. });
  142. if (current.dialect.supports.index.using === 2) {
  143. it('USING', () => {
  144. expectsql(
  145. sql.addIndexQuery('table', {
  146. fields: ['event'],
  147. using: 'gin',
  148. }),
  149. {
  150. postgres: 'CREATE INDEX "table_event" ON "table" USING gin ("event")',
  151. },
  152. );
  153. });
  154. }
  155. if (current.dialect.supports.index.where) {
  156. it('WHERE', () => {
  157. expectsql(
  158. sql.addIndexQuery('table', {
  159. fields: ['type'],
  160. where: {
  161. type: 'public',
  162. },
  163. }),
  164. {
  165. ibmi: 'CREATE INDEX "table_type" ON "table" ("type") WHERE "type" = \'public\'',
  166. sqlite3: "CREATE INDEX `table_type` ON `table` (`type`) WHERE `type` = 'public'",
  167. db2: 'CREATE INDEX "table_type" ON "table" ("type") WHERE "type" = \'public\'',
  168. postgres: 'CREATE INDEX "table_type" ON "table" ("type") WHERE "type" = \'public\'',
  169. mssql: "CREATE INDEX [table_type] ON [table] ([type]) WHERE [type] = N'public'",
  170. },
  171. );
  172. expectsql(
  173. sql.addIndexQuery('table', {
  174. fields: ['type'],
  175. where: {
  176. type: {
  177. [Op.or]: ['group', 'private'],
  178. },
  179. },
  180. }),
  181. {
  182. ibmi: 'CREATE INDEX "table_type" ON "table" ("type") WHERE "type" = \'group\' OR "type" = \'private\'',
  183. sqlite3:
  184. "CREATE INDEX `table_type` ON `table` (`type`) WHERE `type` = 'group' OR `type` = 'private'",
  185. db2: 'CREATE INDEX "table_type" ON "table" ("type") WHERE "type" = \'group\' OR "type" = \'private\'',
  186. postgres:
  187. 'CREATE INDEX "table_type" ON "table" ("type") WHERE "type" = \'group\' OR "type" = \'private\'',
  188. mssql:
  189. "CREATE INDEX [table_type] ON [table] ([type]) WHERE [type] = N'group' OR [type] = N'private'",
  190. },
  191. );
  192. expectsql(
  193. sql.addIndexQuery('table', {
  194. fields: ['type'],
  195. where: {
  196. type: {
  197. [Op.ne]: null,
  198. },
  199. },
  200. }),
  201. {
  202. ibmi: 'CREATE INDEX "table_type" ON "table" ("type") WHERE "type" IS NOT NULL',
  203. sqlite3: 'CREATE INDEX `table_type` ON `table` (`type`) WHERE `type` IS NOT NULL',
  204. db2: 'CREATE INDEX "table_type" ON "table" ("type") WHERE "type" IS NOT NULL',
  205. postgres: 'CREATE INDEX "table_type" ON "table" ("type") WHERE "type" IS NOT NULL',
  206. mssql: 'CREATE INDEX [table_type] ON [table] ([type]) WHERE [type] IS NOT NULL',
  207. },
  208. );
  209. });
  210. }
  211. if (current.dialect.supports.dataTypes.JSONB) {
  212. it('operator', () => {
  213. expectsql(
  214. sql.addIndexQuery('table', {
  215. fields: ['event'],
  216. using: 'gin',
  217. operator: 'jsonb_path_ops',
  218. }),
  219. {
  220. postgres: 'CREATE INDEX "table_event" ON "table" USING gin ("event" jsonb_path_ops)',
  221. },
  222. );
  223. });
  224. }
  225. if (current.dialect.supports.index.operator) {
  226. it('operator with multiple fields', () => {
  227. expectsql(
  228. sql.addIndexQuery('table', {
  229. fields: ['column1', 'column2'],
  230. using: 'gist',
  231. operator: 'inet_ops',
  232. }),
  233. {
  234. postgres:
  235. 'CREATE INDEX "table_column1_column2" ON "table" USING gist ("column1" inet_ops, "column2" inet_ops)',
  236. },
  237. );
  238. });
  239. it('operator in fields', () => {
  240. expectsql(
  241. sql.addIndexQuery('table', {
  242. fields: [
  243. {
  244. name: 'column',
  245. operator: 'inet_ops',
  246. },
  247. ],
  248. using: 'gist',
  249. }),
  250. {
  251. postgres: 'CREATE INDEX "table_column" ON "table" USING gist ("column" inet_ops)',
  252. },
  253. );
  254. });
  255. it('operator in fields with order', () => {
  256. expectsql(
  257. sql.addIndexQuery('table', {
  258. fields: [
  259. {
  260. name: 'column',
  261. order: 'DESC',
  262. operator: 'inet_ops',
  263. },
  264. ],
  265. using: 'gist',
  266. }),
  267. {
  268. postgres: 'CREATE INDEX "table_column" ON "table" USING gist ("column" inet_ops DESC)',
  269. },
  270. );
  271. });
  272. it('operator in multiple fields #1', () => {
  273. expectsql(
  274. sql.addIndexQuery('table', {
  275. fields: [
  276. {
  277. name: 'column1',
  278. order: 'DESC',
  279. operator: 'inet_ops',
  280. },
  281. 'column2',
  282. ],
  283. using: 'gist',
  284. }),
  285. {
  286. postgres:
  287. 'CREATE INDEX "table_column1_column2" ON "table" USING gist ("column1" inet_ops DESC, "column2")',
  288. },
  289. );
  290. });
  291. it('operator in multiple fields #2', () => {
  292. expectsql(
  293. sql.addIndexQuery('table', {
  294. fields: [
  295. {
  296. name: 'path',
  297. operator: 'text_pattern_ops',
  298. },
  299. 'level',
  300. {
  301. name: 'name',
  302. operator: 'varchar_pattern_ops',
  303. },
  304. ],
  305. using: 'btree',
  306. }),
  307. {
  308. postgres:
  309. 'CREATE INDEX "table_path_level_name" ON "table" USING btree ("path" text_pattern_ops, "level", "name" varchar_pattern_ops)',
  310. },
  311. );
  312. });
  313. }
  314. it('include columns with unique index', () => {
  315. expectsql(
  316. () =>
  317. sql.addIndexQuery('User', {
  318. name: 'email_include_name',
  319. fields: ['email'],
  320. include: ['first_name', 'last_name'],
  321. unique: true,
  322. }),
  323. {
  324. default: new Error(
  325. `The include attribute for indexes is not supported by ${current.dialect.name} dialect`,
  326. ),
  327. mssql:
  328. 'CREATE UNIQUE INDEX [email_include_name] ON [User] ([email]) INCLUDE ([first_name], [last_name])',
  329. 'db2 postgres':
  330. 'CREATE UNIQUE INDEX "email_include_name" ON "User" ("email") INCLUDE ("first_name", "last_name")',
  331. },
  332. );
  333. });
  334. it('include columns with non-unique index', () => {
  335. expectsql(
  336. () =>
  337. sql.addIndexQuery('User', {
  338. name: 'email_include_name',
  339. fields: ['email'],
  340. include: ['first_name', 'last_name'],
  341. }),
  342. {
  343. db2: new Error('DB2 does not support non-unique indexes with INCLUDE syntax.'),
  344. default: new Error(
  345. `The include attribute for indexes is not supported by ${current.dialect.name} dialect`,
  346. ),
  347. mssql:
  348. 'CREATE INDEX [email_include_name] ON [User] ([email]) INCLUDE ([first_name], [last_name])',
  349. postgres:
  350. 'CREATE INDEX "email_include_name" ON "User" ("email") INCLUDE ("first_name", "last_name")',
  351. },
  352. );
  353. });
  354. it('include columns using a liternal with non-unique index', () => {
  355. expectsql(
  356. () =>
  357. sql.addIndexQuery('User', {
  358. name: 'email_include_name',
  359. fields: ['email'],
  360. include: literal('(first_name, last_name)'),
  361. }),
  362. {
  363. db2: new Error('DB2 does not support non-unique indexes with INCLUDE syntax.'),
  364. default: new Error(
  365. `The include attribute for indexes is not supported by ${current.dialect.name} dialect`,
  366. ),
  367. mssql:
  368. 'CREATE INDEX [email_include_name] ON [User] ([email]) INCLUDE (first_name, last_name)',
  369. postgres:
  370. 'CREATE INDEX "email_include_name" ON "User" ("email") INCLUDE (first_name, last_name)',
  371. },
  372. );
  373. });
  374. it('include columns using an array of liternals with non-unique index', () => {
  375. expectsql(
  376. () =>
  377. sql.addIndexQuery('User', {
  378. name: 'email_include_name',
  379. fields: ['email'],
  380. include: [literal('first_name'), literal('last_name')],
  381. }),
  382. {
  383. db2: new Error('DB2 does not support non-unique indexes with INCLUDE syntax.'),
  384. default: new Error(
  385. `The include attribute for indexes is not supported by ${current.dialect.name} dialect`,
  386. ),
  387. mssql:
  388. 'CREATE INDEX [email_include_name] ON [User] ([email]) INCLUDE (first_name, last_name)',
  389. postgres:
  390. 'CREATE INDEX "email_include_name" ON "User" ("email") INCLUDE (first_name, last_name)',
  391. },
  392. );
  393. });
  394. });
  395. });