index.test.ts 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. 'use strict';
  2. import { DataTypes, DatabaseError } from '@sequelize/core';
  3. import { expect } from 'chai';
  4. import { getTestDialect, getTestDialectTeaser, sequelize } from './support';
  5. const dialect = getTestDialect();
  6. describe(getTestDialectTeaser('Indexes'), () => {
  7. describe('Indexes with include', () => {
  8. it('creates unique index', async () => {
  9. const User = sequelize.define(
  10. 'user',
  11. {
  12. username: { type: DataTypes.STRING, unique: true },
  13. first_name: DataTypes.STRING,
  14. last_name: DataTypes.STRING,
  15. },
  16. {
  17. indexes: [{ name: 'unique_names', fields: ['first_name', 'last_name'], unique: true }],
  18. },
  19. );
  20. await sequelize.sync({ force: true });
  21. const indexes = await sequelize.queryInterface.showIndex(User.table);
  22. const indexCheck = indexes.find(index => index.name === 'unique_names');
  23. expect(indexCheck?.name).to.equal('unique_names');
  24. expect(indexCheck?.unique).to.equal(true);
  25. expect(indexCheck?.fields).to.have.length(2);
  26. expect(indexCheck?.fields[0].attribute).to.equal('first_name');
  27. expect(indexCheck?.fields[1].attribute).to.equal('last_name');
  28. });
  29. if (sequelize.dialect.supports.schemas) {
  30. it('creates unique index with a custom schema', async () => {
  31. await sequelize.createSchema('test_schema');
  32. const User = sequelize.define(
  33. 'user',
  34. {
  35. username: { type: DataTypes.STRING, unique: true },
  36. first_name: DataTypes.STRING,
  37. last_name: DataTypes.STRING,
  38. },
  39. {
  40. schema: 'test_schema',
  41. indexes: [{ name: 'unique_names', fields: ['first_name', 'last_name'], unique: true }],
  42. },
  43. );
  44. await sequelize.sync({ force: true });
  45. const indexes = await sequelize.queryInterface.showIndex(User.table);
  46. const indexCheck = indexes.find(index => index.name === 'unique_names');
  47. expect(indexCheck?.name).to.equal('unique_names');
  48. expect(indexCheck?.unique).to.equal(true);
  49. expect(indexCheck?.fields).to.have.length(2);
  50. expect(indexCheck?.fields[0].attribute).to.equal('first_name');
  51. expect(indexCheck?.fields[1].attribute).to.equal('last_name');
  52. });
  53. }
  54. if (sequelize.dialect.supports.index.include) {
  55. it('creates non-unique index with include columns', async () => {
  56. const User = sequelize.define(
  57. 'user',
  58. {
  59. username: DataTypes.STRING,
  60. first_name: DataTypes.STRING,
  61. last_name: DataTypes.STRING,
  62. },
  63. {
  64. indexes: [
  65. {
  66. name: 'user_username',
  67. fields: ['username'],
  68. include: ['first_name', 'last_name'],
  69. unique: false,
  70. },
  71. ],
  72. },
  73. );
  74. if (dialect === 'db2') {
  75. try {
  76. await sequelize.sync({ force: true });
  77. expect.fail('This should have failed');
  78. } catch (error: any) {
  79. expect(error.message).to.equal(
  80. 'DB2 does not support non-unique indexes with INCLUDE syntax.',
  81. );
  82. }
  83. } else {
  84. await sequelize.sync({ force: true });
  85. const indexes = await sequelize.queryInterface.showIndex(User.table);
  86. const indexCheck = indexes.find(index => index.name === 'user_username');
  87. expect(indexCheck?.name).to.equal('user_username');
  88. expect(indexCheck?.fields).to.have.length(1);
  89. expect(indexCheck?.fields[0].attribute).to.equal('username');
  90. expect(indexCheck?.includes).to.have.length(2);
  91. expect(indexCheck?.includes).to.include('first_name');
  92. expect(indexCheck?.includes).to.include('last_name');
  93. }
  94. });
  95. it('creates unique index with include columns', async () => {
  96. const User = sequelize.define(
  97. 'user',
  98. {
  99. username: DataTypes.STRING,
  100. first_name: DataTypes.STRING,
  101. last_name: DataTypes.STRING,
  102. },
  103. {
  104. indexes: [
  105. {
  106. name: 'user_username',
  107. fields: ['username'],
  108. include: ['first_name', 'last_name'],
  109. unique: true,
  110. },
  111. ],
  112. },
  113. );
  114. await sequelize.sync({ force: true });
  115. const indexes = await sequelize.queryInterface.showIndex(User.table);
  116. const indexCheck = indexes.find(index => index.name === 'user_username');
  117. expect(indexCheck?.name).to.equal('user_username');
  118. expect(indexCheck?.unique).to.equal(true);
  119. expect(indexCheck?.fields).to.have.length(1);
  120. expect(indexCheck?.fields[0].attribute).to.equal('username');
  121. expect(indexCheck?.includes).to.have.length(2);
  122. expect(indexCheck?.includes).to.include('first_name');
  123. expect(indexCheck?.includes).to.include('last_name');
  124. });
  125. it('throws an error with duplicate column names', async () => {
  126. const User = sequelize.define(
  127. 'user',
  128. {
  129. username: DataTypes.STRING,
  130. first_name: DataTypes.STRING,
  131. last_name: DataTypes.STRING,
  132. },
  133. {
  134. indexes: [
  135. {
  136. name: 'user_username',
  137. fields: ['username'],
  138. include: ['username', 'first_name', 'last_name'],
  139. unique: true,
  140. },
  141. ],
  142. },
  143. );
  144. try {
  145. await sequelize.sync({ force: true });
  146. if (dialect === 'postgres') {
  147. const indexes = await sequelize.queryInterface.showIndex(User.table);
  148. const indexCheck = indexes.find(index => index.name === 'user_username');
  149. expect(indexCheck?.name).to.equal('user_username');
  150. expect(indexCheck?.unique).to.equal(true);
  151. expect(indexCheck?.fields).to.have.length(1);
  152. expect(indexCheck?.fields[0].attribute).to.equal('username');
  153. expect(indexCheck?.includes).to.have.length(3);
  154. expect(indexCheck?.includes).to.include('username');
  155. expect(indexCheck?.includes).to.include('first_name');
  156. expect(indexCheck?.includes).to.include('last_name');
  157. } else {
  158. expect.fail('This should have failed');
  159. }
  160. } catch (error: any) {
  161. expect(error).to.be.instanceOf(DatabaseError);
  162. expect(error.message).to.match(
  163. /\s|^Cannot use duplicate column names in index. Column name 'username' listed more than once.$/,
  164. );
  165. }
  166. });
  167. it('throws an error with missing column names', async () => {
  168. sequelize.define(
  169. 'user',
  170. {
  171. username: DataTypes.STRING,
  172. first_name: DataTypes.STRING,
  173. last_name: DataTypes.STRING,
  174. },
  175. {
  176. indexes: [
  177. {
  178. name: 'user_username',
  179. fields: ['username'],
  180. include: ['first_name', 'last_name', 'email'],
  181. unique: true,
  182. },
  183. ],
  184. },
  185. );
  186. try {
  187. await sequelize.sync({ force: true });
  188. expect.fail('This should have failed');
  189. } catch (error: any) {
  190. expect(error).to.be.instanceOf(DatabaseError);
  191. expect(error.message).to.match(
  192. /\s|^Column name 'email' does not exist in the target table or view.$/,
  193. );
  194. }
  195. });
  196. it('throws an error with invalid column type', async () => {
  197. sequelize.define(
  198. 'user',
  199. {
  200. username: DataTypes.TEXT,
  201. first_name: DataTypes.STRING,
  202. last_name: DataTypes.STRING,
  203. },
  204. {
  205. indexes: [
  206. {
  207. name: 'user_username',
  208. fields: ['username'],
  209. include: ['first_name', 'last_name', 'email'],
  210. unique: true,
  211. },
  212. ],
  213. },
  214. );
  215. try {
  216. await sequelize.sync({ force: true });
  217. expect.fail('This should have failed');
  218. } catch (error: any) {
  219. expect(error).to.be.instanceOf(DatabaseError);
  220. expect(error.message).to.match(
  221. /\s|^Column 'username' in table 'users' is of a type that is invalid for use as a key column in an index.$/,
  222. );
  223. }
  224. });
  225. }
  226. });
  227. });