deferrable.test.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. 'use strict';
  2. const chai = require('chai');
  3. const expect = chai.expect;
  4. const Support = require('../support');
  5. const { ConstraintChecking, DataTypes, Deferrable, Sequelize } = require('@sequelize/core');
  6. if (Support.sequelize.dialect.supports.constraints.deferrable) {
  7. describe(Support.getTestDialectTeaser('Sequelize'), () => {
  8. describe('Deferrable', () => {
  9. const describeDeferrableTest = (title, defineModels) => {
  10. describe(title, () => {
  11. beforeEach(function () {
  12. this.run = async function (deferrable, options) {
  13. options ||= {};
  14. const taskTableName = options.taskTableName || `tasks_${Support.rand()}`;
  15. const transactionOptions = {
  16. constraintChecking: ConstraintChecking.DEFERRED,
  17. ...options,
  18. };
  19. const userTableName = `users_${Support.rand()}`;
  20. const { Task, User } = await defineModels({
  21. sequelize: this.sequelize,
  22. userTableName,
  23. deferrable,
  24. taskTableName,
  25. });
  26. return this.sequelize.transaction(transactionOptions, async t => {
  27. const task0 = await Task.create(
  28. { title: 'a task', user_id: -1 },
  29. { transaction: t },
  30. );
  31. const [task, user] = await Promise.all([
  32. task0,
  33. User.create({}, { transaction: t }),
  34. ]);
  35. task.user_id = user.id;
  36. return task.save({ transaction: t });
  37. });
  38. };
  39. });
  40. describe('NOT', () => {
  41. it('does not allow the violation of the foreign key constraint', async function () {
  42. await expect(this.run(Deferrable.NOT)).to.eventually.be.rejectedWith(
  43. Sequelize.ForeignKeyConstraintError,
  44. );
  45. });
  46. });
  47. describe('INITIALLY_IMMEDIATE', () => {
  48. it('allows the violation of the foreign key constraint if the transaction is deferred', async function () {
  49. const task = await this.run(Deferrable.INITIALLY_IMMEDIATE);
  50. expect(task.title).to.equal('a task');
  51. expect(task.user_id).to.equal(1);
  52. });
  53. it('does not allow the violation of the foreign key constraint if the transaction is not deferred', async function () {
  54. await expect(
  55. this.run(Deferrable.INITIALLY_IMMEDIATE, {
  56. constraintChecking: undefined,
  57. }),
  58. ).to.eventually.be.rejectedWith(Sequelize.ForeignKeyConstraintError);
  59. });
  60. it('allows the violation of the foreign key constraint if the transaction deferred only the foreign key constraint', async function () {
  61. const taskTableName = `tasks_${Support.rand()}`;
  62. const task = await this.run(Deferrable.INITIALLY_IMMEDIATE, {
  63. constraintChecking: ConstraintChecking.DEFERRED([`${taskTableName}_user_id_fkey`]),
  64. taskTableName,
  65. });
  66. expect(task.title).to.equal('a task');
  67. expect(task.user_id).to.equal(1);
  68. });
  69. });
  70. describe('INITIALLY_DEFERRED', () => {
  71. it('allows the violation of the foreign key constraint', async function () {
  72. const task = await this.run(Deferrable.INITIALLY_DEFERRED);
  73. expect(task.title).to.equal('a task');
  74. expect(task.user_id).to.equal(1);
  75. });
  76. });
  77. });
  78. };
  79. describeDeferrableTest(
  80. 'set in define',
  81. async ({ deferrable, sequelize, taskTableName, userTableName }) => {
  82. const User = sequelize.define(
  83. 'User',
  84. { name: DataTypes.STRING },
  85. { tableName: userTableName },
  86. );
  87. const Task = sequelize.define(
  88. 'Task',
  89. {
  90. title: DataTypes.STRING,
  91. user_id: {
  92. allowNull: false,
  93. type: DataTypes.INTEGER,
  94. references: {
  95. table: userTableName,
  96. key: 'id',
  97. deferrable,
  98. },
  99. },
  100. },
  101. {
  102. tableName: taskTableName,
  103. },
  104. );
  105. await User.sync({ force: true });
  106. await Task.sync({ force: true });
  107. return { Task, User };
  108. },
  109. );
  110. describeDeferrableTest(
  111. 'set in addConstraint',
  112. async ({ deferrable, sequelize, taskTableName, userTableName }) => {
  113. const User = sequelize.define(
  114. 'User',
  115. { name: DataTypes.STRING },
  116. { tableName: userTableName },
  117. );
  118. const Task = sequelize.define(
  119. 'Task',
  120. {
  121. title: DataTypes.STRING,
  122. user_id: {
  123. allowNull: false,
  124. type: DataTypes.INTEGER,
  125. },
  126. },
  127. {
  128. tableName: taskTableName,
  129. },
  130. );
  131. await User.sync({ force: true });
  132. await Task.sync({ force: true });
  133. await sequelize.queryInterface.addConstraint(taskTableName, {
  134. fields: ['user_id'],
  135. type: 'FOREIGN KEY',
  136. name: `${taskTableName}_user_id_fkey`,
  137. deferrable,
  138. references: {
  139. table: userTableName,
  140. field: 'id',
  141. },
  142. });
  143. return { Task, User };
  144. },
  145. );
  146. });
  147. });
  148. }