sync.test.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715
  1. 'use strict';
  2. const { expect } = require('chai');
  3. const { DataTypes, Deferrable, Model } = require('@sequelize/core');
  4. const { getTestDialect, getTestDialectTeaser, sequelize } = require('../support');
  5. const dialect = getTestDialect();
  6. describe(getTestDialectTeaser('Model.sync & Sequelize#sync'), () => {
  7. it('removes a column if it exists in the databases schema but not the model', async () => {
  8. const User = sequelize.define('testSync', {
  9. name: DataTypes.STRING,
  10. age: DataTypes.INTEGER,
  11. badgeNumber: { type: DataTypes.INTEGER, columnName: 'badge_number' },
  12. });
  13. await sequelize.sync();
  14. const descr1 = await User.describe();
  15. expect(descr1).to.have.ownProperty('name');
  16. expect(descr1).to.have.ownProperty('age');
  17. expect(descr1).to.have.ownProperty('badge_number');
  18. sequelize.define('testSync', {
  19. name: DataTypes.STRING,
  20. });
  21. await sequelize.sync({ alter: true });
  22. const descr2 = await User.describe();
  23. expect(descr2).to.have.ownProperty('name');
  24. expect(descr2).to.not.have.ownProperty('age');
  25. expect(descr2).to.not.have.ownProperty('badge_number');
  26. });
  27. it('adds a column if it exists in the model but not the database', async () => {
  28. const testSync = sequelize.define('testSync', {
  29. name: DataTypes.STRING,
  30. });
  31. await sequelize.sync();
  32. const descr1 = await testSync.describe();
  33. expect(descr1).to.have.ownProperty('name');
  34. await sequelize.define('testSync', {
  35. name: DataTypes.STRING,
  36. age: DataTypes.INTEGER,
  37. height: { type: DataTypes.INTEGER, columnName: 'height_cm' },
  38. });
  39. await sequelize.sync({ alter: true });
  40. const descr2 = await testSync.describe();
  41. expect(descr2).to.have.ownProperty('name');
  42. expect(descr2).to.have.ownProperty('age');
  43. expect(descr2).to.have.ownProperty('height_cm');
  44. expect(descr2).not.to.have.ownProperty('height');
  45. });
  46. it('does not remove columns if drop is set to false in alter configuration', async () => {
  47. const testSync = sequelize.define('testSync', {
  48. name: DataTypes.STRING,
  49. age: DataTypes.INTEGER,
  50. });
  51. await sequelize.sync();
  52. await sequelize.define('testSync', {
  53. name: DataTypes.STRING,
  54. });
  55. await sequelize.sync({ alter: { drop: false } });
  56. const data = await testSync.describe();
  57. expect(data).to.have.ownProperty('name');
  58. expect(data).to.have.ownProperty('age');
  59. });
  60. it('removes columns if drop is set to true in alter configuration', async () => {
  61. const testSync = sequelize.define('testSync', {
  62. name: DataTypes.STRING,
  63. age: DataTypes.INTEGER,
  64. });
  65. await sequelize.sync();
  66. await sequelize.define('testSync', {
  67. name: DataTypes.STRING,
  68. });
  69. await sequelize.sync({ alter: { drop: true } });
  70. const data = await testSync.describe();
  71. expect(data).to.have.ownProperty('name');
  72. expect(data).not.to.have.ownProperty('age');
  73. });
  74. it('alters a column using the correct column name (#9515)', async () => {
  75. const testSync = sequelize.define('testSync', {
  76. name: DataTypes.STRING,
  77. });
  78. await sequelize.sync();
  79. await sequelize.define('testSync', {
  80. name: DataTypes.STRING,
  81. badgeNumber: { type: DataTypes.INTEGER, columnName: 'badge_number' },
  82. });
  83. await sequelize.sync({ alter: true });
  84. const data = await testSync.describe();
  85. expect(data).to.have.ownProperty('badge_number');
  86. expect(data).not.to.have.ownProperty('badgeNumber');
  87. });
  88. // IBM i can't alter INTEGER -> STRING
  89. if (dialect !== 'ibmi') {
  90. it('changes a column if it exists in the model but is different in the database', async () => {
  91. const testSync = sequelize.define('testSync', {
  92. name: DataTypes.STRING,
  93. age: DataTypes.INTEGER,
  94. });
  95. await sequelize.sync();
  96. await sequelize.define('testSync', {
  97. name: DataTypes.STRING,
  98. age: DataTypes.STRING,
  99. });
  100. await sequelize.sync({ alter: true });
  101. const data = await testSync.describe();
  102. expect(data).to.have.ownProperty('age');
  103. if (dialect === 'sqlite3') {
  104. // sqlite3 does not have a text type with a configurable max width. It uses TEXT which is unlimited.
  105. expect(data.age.type).to.have.string('TEXT');
  106. } else {
  107. expect(data.age.type).to.have.string('VAR'); // CHARACTER VARYING, VARCHAR(n)
  108. }
  109. });
  110. }
  111. it('does not alter table if data type does not change', async () => {
  112. const testSync = sequelize.define('testSync', {
  113. name: DataTypes.STRING,
  114. age: DataTypes.STRING,
  115. });
  116. await sequelize.sync();
  117. await testSync.create({ name: 'test', age: '1' });
  118. await sequelize.sync({ alter: true });
  119. const data = await testSync.findOne();
  120. expect(data.name).to.eql('test');
  121. expect(data.age).to.eql('1');
  122. });
  123. it('should properly alter tables when there are foreign keys', async () => {
  124. const foreignKeyTestSyncA = sequelize.define('foreignKeyTestSyncA', {
  125. dummy: DataTypes.STRING,
  126. });
  127. const foreignKeyTestSyncB = sequelize.define('foreignKeyTestSyncB', {
  128. dummy: DataTypes.STRING,
  129. });
  130. foreignKeyTestSyncA.hasMany(foreignKeyTestSyncB);
  131. foreignKeyTestSyncB.belongsTo(foreignKeyTestSyncA);
  132. await sequelize.sync({ alter: true });
  133. await sequelize.sync({ alter: true });
  134. });
  135. it('creates one unique index for unique:true column', async () => {
  136. const User = sequelize.define('testSync', {
  137. email: {
  138. type: DataTypes.STRING,
  139. unique: true,
  140. },
  141. });
  142. await User.sync({ force: true });
  143. const syncResults = await getNonPrimaryIndexes(User);
  144. expect(syncResults).to.have.length(1);
  145. expect(syncResults[0].name).to.eq('test_syncs_email_unique');
  146. expect(getIndexFields(syncResults[0])).to.deep.eq(['email']);
  147. await User.sync({ alter: true });
  148. const alterResults = await getNonPrimaryIndexes(User);
  149. expect(alterResults).to.deep.eq(
  150. syncResults,
  151. '"alter" should not create new indexes if they already exist.',
  152. );
  153. });
  154. it('creates one unique index per unique:true columns, and per entry in options.indexes', async () => {
  155. const User = sequelize.define(
  156. 'testSync',
  157. {
  158. email: {
  159. type: DataTypes.STRING,
  160. unique: true,
  161. },
  162. phone: {
  163. type: DataTypes.STRING,
  164. unique: true,
  165. },
  166. },
  167. {
  168. timestamps: false,
  169. indexes: [{ name: 'wow_my_index', fields: ['email', 'phone'], unique: true }],
  170. },
  171. );
  172. await User.sync({ force: true });
  173. const syncResults = await getNonPrimaryIndexes(User);
  174. syncResults.sort((a, b) => a.name.localeCompare(b.name));
  175. expect(syncResults).to.have.length(3);
  176. expect(syncResults[0].name).to.eq('test_syncs_email_unique');
  177. expect(getIndexFields(syncResults[0])).to.deep.eq(['email']);
  178. expect(syncResults[0].unique).to.eq(true, 'index should be unique');
  179. expect(syncResults[1].name).to.eq('test_syncs_phone_unique');
  180. expect(getIndexFields(syncResults[1])).to.deep.eq(['phone']);
  181. expect(syncResults[1].unique).to.eq(true, 'index should be unique');
  182. expect(syncResults[2].name).to.eq('wow_my_index');
  183. expect(getIndexFields(syncResults[2])).to.deep.eq(['email', 'phone']);
  184. expect(syncResults[2].unique).to.eq(true, 'index should be unique');
  185. await User.sync({ alter: true });
  186. const alterResults = await getNonPrimaryIndexes(User);
  187. expect(syncResults).to.deep.eq(
  188. alterResults,
  189. '"alter" should not create new indexes if they already exist.',
  190. );
  191. });
  192. it('creates one unique index per unique:name column (1 column)', async () => {
  193. const User = sequelize.define('testSync', {
  194. email: {
  195. type: DataTypes.STRING,
  196. unique: 'wow_my_index',
  197. },
  198. });
  199. await User.sync({ force: true });
  200. const syncResults = await getNonPrimaryIndexes(User);
  201. expect(syncResults).to.have.length(1);
  202. expect(syncResults[0].name).to.eq('wow_my_index');
  203. expect(getIndexFields(syncResults[0])).to.deep.eq(['email']);
  204. expect(syncResults[0].unique).to.eq(true, 'index should be unique');
  205. await User.sync({ alter: true });
  206. const alterResults = await getNonPrimaryIndexes(User);
  207. expect(syncResults).to.deep.eq(
  208. alterResults,
  209. '"alter" should not create new indexes if they already exist.',
  210. );
  211. });
  212. it('creates one unique index per unique:name column (multiple columns)', async () => {
  213. const User = sequelize.define('testSync', {
  214. email: {
  215. type: DataTypes.STRING,
  216. unique: 'wow_my_index',
  217. },
  218. phone: {
  219. type: DataTypes.STRING,
  220. unique: 'wow_my_index',
  221. },
  222. });
  223. await User.sync({ force: true });
  224. const syncResults = await getNonPrimaryIndexes(User);
  225. expect(syncResults).to.have.length(1);
  226. expect(syncResults[0].name).to.eq('wow_my_index');
  227. expect(getIndexFields(syncResults[0])).to.deep.eq(['email', 'phone']);
  228. expect(syncResults[0].unique).to.eq(true, 'index should be unique');
  229. await User.sync({ alter: true });
  230. const alterResults = await getNonPrimaryIndexes(User);
  231. expect(syncResults).to.deep.eq(
  232. alterResults,
  233. '"alter" should not create new indexes if they already exist.',
  234. );
  235. });
  236. it('throws if a name collision occurs between two indexes', async () => {
  237. expect(() => {
  238. sequelize.define(
  239. 'testSync',
  240. {
  241. email: {
  242. type: DataTypes.STRING,
  243. unique: true,
  244. },
  245. },
  246. {
  247. timestamps: false,
  248. indexes: [{ fields: ['email'], unique: true }],
  249. },
  250. );
  251. }).to.throwWithCause('Sequelize tried to give the name "test_syncs_email_unique" to index');
  252. });
  253. it('adds missing unique indexes to existing tables (unique attribute option)', async () => {
  254. const User1 = sequelize.define(
  255. 'User',
  256. {
  257. email: {
  258. type: DataTypes.STRING,
  259. },
  260. },
  261. { timestamps: false },
  262. );
  263. // create without the unique index
  264. await User1.sync({ force: true });
  265. // replace model (to emulate code changes)
  266. const User2 = sequelize.define(
  267. 'User',
  268. {
  269. email: {
  270. type: DataTypes.STRING,
  271. unique: true,
  272. },
  273. },
  274. { timestamps: false },
  275. );
  276. const out1 = await getNonPrimaryIndexes(User1);
  277. expect(out1).to.have.length(0);
  278. // alter to add the unique index
  279. await User2.sync({ alter: true });
  280. const out2 = await getNonPrimaryIndexes(User1);
  281. expect(out2).to.have.length(1);
  282. expect(out2[0].name).to.eq('users_email_unique');
  283. expect(getIndexFields(out2[0])).to.deep.eq(['email']);
  284. expect(out2[0].unique).to.eq(true, 'index should be unique');
  285. });
  286. it('adds missing unique indexes to existing tables (index option)', async () => {
  287. const User1 = sequelize.define(
  288. 'User',
  289. {
  290. email: {
  291. type: DataTypes.STRING,
  292. },
  293. },
  294. { timestamps: false },
  295. );
  296. // create without the unique index
  297. await User1.sync({ force: true });
  298. // replace model (to emulate code changes)
  299. const User2 = sequelize.define(
  300. 'User',
  301. {
  302. email: {
  303. type: DataTypes.STRING,
  304. },
  305. },
  306. {
  307. timestamps: false,
  308. indexes: [{ fields: ['email'], unique: true }],
  309. },
  310. );
  311. const out1 = await getNonPrimaryIndexes(User1);
  312. expect(out1).to.have.length(0);
  313. // alter to add the unique index
  314. await User2.sync({ alter: true });
  315. const out2 = await getNonPrimaryIndexes(User1);
  316. expect(out2).to.have.length(1);
  317. expect(out2[0].name).to.eq('users_email_unique');
  318. expect(getIndexFields(out2[0])).to.deep.eq(['email']);
  319. expect(out2[0].unique).to.eq(true, 'index should be unique');
  320. });
  321. it('adds missing non-unique indexes to existing tables (index option)', async () => {
  322. const User1 = sequelize.define(
  323. 'User',
  324. {
  325. email: {
  326. type: DataTypes.STRING,
  327. },
  328. },
  329. { timestamps: false },
  330. );
  331. // create without the unique index
  332. await User1.sync({ force: true });
  333. // replace model (to emulate code changes)
  334. const User2 = sequelize.define(
  335. 'User',
  336. {
  337. email: {
  338. type: DataTypes.STRING,
  339. },
  340. },
  341. {
  342. timestamps: false,
  343. indexes: [{ fields: ['email'] }],
  344. },
  345. );
  346. const out1 = await getNonPrimaryIndexes(User1);
  347. expect(out1).to.have.length(0);
  348. // alter to add the unique index
  349. await User2.sync({ alter: true });
  350. const out2 = await getNonPrimaryIndexes(User1);
  351. expect(out2).to.have.length(1);
  352. expect(out2[0].name).to.eq('users_email');
  353. expect(getIndexFields(out2[0])).to.deep.eq(['email']);
  354. expect(out2[0].unique).to.eq(false, 'index should not be unique');
  355. });
  356. it('adds missing unique columns to existing tables', async () => {
  357. const User1 = sequelize.define('User', {}, { timestamps: false });
  358. // create without the unique index
  359. await User1.sync({ force: true });
  360. await User1.create({ id: 1 });
  361. const out1 = await getNonPrimaryIndexes(User1);
  362. expect(out1).to.have.length(0);
  363. // replace model (to emulate code changes)
  364. const User2 = sequelize.define(
  365. 'User',
  366. {
  367. email: {
  368. type: DataTypes.STRING,
  369. unique: true,
  370. },
  371. },
  372. {
  373. timestamps: false,
  374. },
  375. );
  376. // alter to add the unique index
  377. await User2.sync({ alter: true });
  378. // db2 had a bug which re-created the table in some circumstances.
  379. // this ensures the table is not recreated, but altered.
  380. const existingData = await User2.findAll();
  381. expect(existingData).to.have.length(1);
  382. const out2 = await getNonPrimaryIndexes(User1);
  383. expect(out2).to.have.length(1);
  384. expect(out2[0].name).to.eq('users_email_unique');
  385. expect(getIndexFields(out2[0])).to.deep.eq(['email']);
  386. expect(out2[0].unique).to.eq(true, 'index should not be unique');
  387. });
  388. const SCHEMA_ONE = 'schema_one';
  389. const SCHEMA_TWO = 'schema_two';
  390. if (sequelize.dialect.supports.schemas) {
  391. it('can create two identically named indexes in different schemas', async () => {
  392. await Promise.all([sequelize.createSchema(SCHEMA_ONE), sequelize.createSchema(SCHEMA_TWO)]);
  393. const User = sequelize.define(
  394. 'User1',
  395. {
  396. name: DataTypes.STRING,
  397. },
  398. {
  399. schema: SCHEMA_ONE,
  400. indexes: [
  401. {
  402. name: 'test_slug_idx',
  403. fields: ['name'],
  404. },
  405. ],
  406. },
  407. );
  408. const Task = sequelize.define(
  409. 'Task2',
  410. {
  411. name: DataTypes.STRING,
  412. },
  413. {
  414. schema: SCHEMA_TWO,
  415. indexes: [
  416. {
  417. name: 'test_slug_idx',
  418. fields: ['name'],
  419. },
  420. ],
  421. },
  422. );
  423. await User.sync({ force: true });
  424. await Task.sync({ force: true });
  425. const [userIndexes, taskIndexes] = await Promise.all([
  426. getNonPrimaryIndexes(User),
  427. getNonPrimaryIndexes(Task),
  428. ]);
  429. expect(userIndexes).to.have.length(1);
  430. expect(taskIndexes).to.have.length(1);
  431. expect(userIndexes[0].name).to.eq('test_slug_idx');
  432. expect(taskIndexes[0].name).to.eq('test_slug_idx');
  433. });
  434. it('supports creating two identically named tables in different schemas', async () => {
  435. await sequelize.queryInterface.createSchema('custom_schema');
  436. const Model1 = sequelize.define(
  437. 'A1',
  438. {},
  439. { schema: 'custom_schema', tableName: 'a', timestamps: false },
  440. );
  441. const Model2 = sequelize.define('A2', {}, { tableName: 'a', timestamps: false });
  442. await sequelize.sync({ force: true });
  443. await Model1.create({ id: 1 });
  444. await Model2.create({ id: 2 });
  445. });
  446. }
  447. it('defaults to schema provided to sync() for references #11276', async function () {
  448. // TODO: this should work with MSSQL / MariaDB too
  449. if (!dialect !== 'postgres') {
  450. return;
  451. }
  452. await Promise.all([sequelize.createSchema(SCHEMA_ONE), sequelize.createSchema(SCHEMA_TWO)]);
  453. const User = this.sequelize.define('UserXYZ', {
  454. uid: {
  455. type: DataTypes.INTEGER,
  456. primaryKey: true,
  457. autoIncrement: true,
  458. allowNull: false,
  459. },
  460. });
  461. const Task = this.sequelize.define('TaskXYZ', {});
  462. Task.belongsTo(User);
  463. // TODO: do we really want to keep this? Shouldn't model schemas be defined and fixed?
  464. await User.sync({ force: true, schema: SCHEMA_ONE });
  465. await Task.sync({ force: true, schema: SCHEMA_ONE });
  466. const user0 = await User.withSchema(SCHEMA_ONE).create({});
  467. const task = await Task.withSchema(SCHEMA_ONE).create({});
  468. await task.setUserXYZ(user0);
  469. // TODO: do we really want to keep this? Shouldn't model schemas be defined and fixed?
  470. const user = await task.getUserXYZ({ schema: SCHEMA_ONE });
  471. expect(user).to.be.ok;
  472. });
  473. it('supports creating tables with cyclic associations', async () => {
  474. const A = sequelize.define('A', {}, { timestamps: false });
  475. const B = sequelize.define('B', {}, { timestamps: false });
  476. // mssql refuses cyclic references unless ON DELETE and ON UPDATE is set to NO ACTION
  477. const mssqlConstraints =
  478. dialect === 'mssql' ? { onDelete: 'NO ACTION', onUpdate: 'NO ACTION' } : null;
  479. // These models both have a foreign key that references the other model.
  480. // Sequelize should be able to create them.
  481. A.belongsTo(B, { foreignKey: { allowNull: false, ...mssqlConstraints } });
  482. B.belongsTo(A, { foreignKey: { allowNull: false, ...mssqlConstraints } });
  483. await sequelize.sync();
  484. const [aFks, bFks] = await Promise.all([
  485. sequelize.queryInterface.showConstraints(A, { constraintType: 'FOREIGN KEY' }),
  486. sequelize.queryInterface.showConstraints(B, { constraintType: 'FOREIGN KEY' }),
  487. ]);
  488. expect(aFks.length).to.eq(1);
  489. expect(aFks[0].referencedTableName).to.eq('Bs');
  490. expect(aFks[0].referencedColumnNames).to.deep.eq(['id']);
  491. expect(aFks[0].columnNames).to.deep.eq(['bId']);
  492. expect(bFks.length).to.eq(1);
  493. expect(bFks[0].referencedTableName).to.eq('As');
  494. expect(bFks[0].referencedColumnNames).to.deep.eq(['id']);
  495. expect(bFks[0].columnNames).to.deep.eq(['aId']);
  496. });
  497. // TODO: sqlite3's foreign_key_list pragma does not return the DEFERRABLE status of the column
  498. // so sync({ alter: true }) cannot know whether the column must be updated.
  499. // so for now, deferrable constraints is disabled for sqlite3 (as it's only used in tests)
  500. if (sequelize.dialect.supports.constraints.deferrable) {
  501. it('updates the deferrable property of a foreign key', async () => {
  502. const A = sequelize.define('A', {
  503. BId: {
  504. type: DataTypes.INTEGER,
  505. references: {
  506. deferrable: Deferrable.INITIALLY_IMMEDIATE,
  507. },
  508. },
  509. });
  510. const B = sequelize.define('B');
  511. A.belongsTo(B);
  512. await sequelize.sync();
  513. const aFks = await sequelize.queryInterface.showConstraints(A, {
  514. constraintType: 'FOREIGN KEY',
  515. });
  516. expect(aFks).to.have.length(1);
  517. expect(aFks[0].deferrable).to.eq(Deferrable.INITIALLY_IMMEDIATE);
  518. A.modelDefinition.rawAttributes.bId.references.deferrable = Deferrable.INITIALLY_DEFERRED;
  519. A.modelDefinition.refreshAttributes();
  520. await sequelize.sync({ alter: true });
  521. const aFks2 = await sequelize.queryInterface.showConstraints(A, {
  522. constraintType: 'FOREIGN KEY',
  523. });
  524. expect(aFks2).to.have.length(1);
  525. expect(aFks2[0].deferrable).to.eq(Deferrable.INITIALLY_DEFERRED);
  526. });
  527. }
  528. if (sequelize.dialect.supports.schemas) {
  529. it('should not recreate a foreign key if it already exists when { alter: true } is used with a custom schema', async () => {
  530. const schema = 'test';
  531. await sequelize.createSchema(schema);
  532. const User = sequelize.define('User', {}, { schema });
  533. const BelongsToUser = sequelize.define('BelongsToUser', {}, { schema });
  534. BelongsToUser.belongsTo(User, { foreignKey: { targetKey: 'id', allowNull: false } });
  535. await sequelize.sync({ alter: true });
  536. await sequelize.sync({ alter: true });
  537. const results = await sequelize.queryInterface.showConstraints(BelongsToUser, {
  538. constraintType: 'FOREIGN KEY',
  539. });
  540. expect(results).to.have.length(1);
  541. });
  542. it('should not recreate a foreign key if it already exists when { alter: true } is used with a custom schema (reference attribute is a Model)', async () => {
  543. const schema = 'test';
  544. await sequelize.createSchema(schema);
  545. class User extends Model {}
  546. class BelongsToUser extends Model {}
  547. User.init({}, { sequelize, schema });
  548. BelongsToUser.init(
  549. {
  550. user_id: {
  551. type: DataTypes.INTEGER,
  552. references: {
  553. model: User,
  554. key: 'id',
  555. },
  556. },
  557. },
  558. { sequelize, schema },
  559. );
  560. await sequelize.sync({ alter: true });
  561. await sequelize.sync({ alter: true });
  562. const results = await sequelize.queryInterface.showConstraints(BelongsToUser, {
  563. constraintType: 'FOREIGN KEY',
  564. });
  565. expect(results).to.have.length(1);
  566. });
  567. }
  568. // TODO add support for db2 and mssql dialects
  569. if (dialect !== 'db2' && dialect !== 'mssql') {
  570. it('does not recreate existing enums (#7649)', async () => {
  571. sequelize.define('Media', {
  572. type: DataTypes.ENUM(['video', 'audio']),
  573. });
  574. await sequelize.sync({ alter: true });
  575. sequelize.define('Media', {
  576. type: DataTypes.ENUM(['image', 'video', 'audio']),
  577. });
  578. await sequelize.sync({ alter: true });
  579. });
  580. }
  581. });
  582. async function getNonPrimaryIndexes(model) {
  583. return (await sequelize.queryInterface.showIndex(model.table))
  584. .filter(r => !r.primary)
  585. .sort((a, b) => a.name.localeCompare(b.name));
  586. }
  587. function getIndexFields(index) {
  588. return index.fields.map(field => field.attribute).sort();
  589. }