paranoid.test.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. 'use strict';
  2. const Support = require('../support');
  3. const { DataTypes } = require('@sequelize/core');
  4. const chai = require('chai');
  5. const expect = chai.expect;
  6. const sinon = require('sinon');
  7. const current = Support.sequelize;
  8. const { dialect } = current;
  9. const dialectName = dialect.name;
  10. describe('Paranoid Model', () => {
  11. before(function () {
  12. this.clock = sinon.useFakeTimers();
  13. });
  14. after(function () {
  15. this.clock.restore();
  16. });
  17. it('should be able to soft delete with timestamps', async function () {
  18. const Account = this.sequelize.define(
  19. 'Account',
  20. {
  21. ownerId: {
  22. type: DataTypes.INTEGER,
  23. allowNull: false,
  24. field: 'owner_id',
  25. },
  26. name: {
  27. type: DataTypes.STRING,
  28. },
  29. },
  30. {
  31. paranoid: true,
  32. timestamps: true,
  33. },
  34. );
  35. await Account.sync({ force: true });
  36. await Account.create({ ownerId: 12 });
  37. const count2 = await Account.count();
  38. expect(count2).to.equal(1);
  39. const result = await Account.destroy({ where: { ownerId: 12 } });
  40. expect(result).to.equal(1);
  41. const count1 = await Account.count();
  42. expect(count1).to.equal(0);
  43. const count0 = await Account.count({ paranoid: false });
  44. expect(count0).to.equal(1);
  45. await Account.restore({ where: { ownerId: 12 } });
  46. const count = await Account.count();
  47. expect(count).to.equal(1);
  48. });
  49. it('should be able to soft delete without timestamps', async function () {
  50. const Account = this.sequelize.define(
  51. 'Account',
  52. {
  53. ownerId: {
  54. type: DataTypes.INTEGER,
  55. allowNull: false,
  56. field: 'owner_id',
  57. },
  58. name: {
  59. type: DataTypes.STRING,
  60. },
  61. deletedAt: {
  62. allowNull: true,
  63. field: 'deleted_at',
  64. },
  65. },
  66. {
  67. paranoid: true,
  68. timestamps: true,
  69. deletedAt: 'deletedAt',
  70. createdAt: false,
  71. updatedAt: false,
  72. },
  73. );
  74. await Account.sync({ force: true });
  75. await Account.create({ ownerId: 12 });
  76. const count2 = await Account.count();
  77. expect(count2).to.equal(1);
  78. await Account.destroy({ where: { ownerId: 12 } });
  79. const count1 = await Account.count();
  80. expect(count1).to.equal(0);
  81. const count0 = await Account.count({ paranoid: false });
  82. expect(count0).to.equal(1);
  83. await Account.restore({ where: { ownerId: 12 } });
  84. const count = await Account.count();
  85. expect(count).to.equal(1);
  86. });
  87. if (current.dialect.supports.jsonOperations && current.dialect.supports.jsonExtraction.quoted) {
  88. describe('JSON Operations', () => {
  89. before(function () {
  90. this.Model = this.sequelize.define(
  91. 'Model',
  92. {
  93. name: {
  94. type: DataTypes.STRING,
  95. },
  96. data: {
  97. type: dialectName === 'postgres' ? DataTypes.JSONB : DataTypes.JSON,
  98. },
  99. deletedAt: {
  100. type: DataTypes.DATE,
  101. allowNull: true,
  102. field: 'deleted_at',
  103. },
  104. },
  105. {
  106. paranoid: true,
  107. timestamps: true,
  108. deletedAt: 'deletedAt',
  109. },
  110. );
  111. });
  112. beforeEach(async function () {
  113. await this.Model.sync({ force: true });
  114. });
  115. it('should soft delete with JSON condition', async function () {
  116. await this.Model.bulkCreate([
  117. {
  118. name: 'One',
  119. data: {
  120. field: {
  121. deep: true,
  122. },
  123. },
  124. },
  125. {
  126. name: 'Two',
  127. data: {
  128. field: {
  129. deep: false,
  130. },
  131. },
  132. },
  133. ]);
  134. await this.Model.destroy({
  135. where: {
  136. data: {
  137. field: {
  138. deep: true,
  139. },
  140. },
  141. },
  142. });
  143. const records = await this.Model.findAll();
  144. expect(records.length).to.equal(1);
  145. expect(records[0].get('name')).to.equal('Two');
  146. });
  147. });
  148. }
  149. it(`prevents finding deleted records`, async function () {
  150. const User = this.sequelize.define(
  151. 'UserCol',
  152. {
  153. username: DataTypes.STRING,
  154. },
  155. { paranoid: true },
  156. );
  157. await User.sync({ force: true });
  158. await User.bulkCreate([{ username: 'Toni' }, { username: 'Tobi' }, { username: 'Max' }]);
  159. const user = await User.findByPk(1);
  160. await user.destroy();
  161. expect(await User.findByPk(1)).to.be.null;
  162. expect(await User.count()).to.equal(2);
  163. expect(await User.findAll()).to.have.length(2);
  164. });
  165. it('allows finding deleted records if paranoid:false is used in the query', async function () {
  166. const User = this.sequelize.define(
  167. 'UserCol',
  168. {
  169. username: DataTypes.STRING,
  170. },
  171. { paranoid: true },
  172. );
  173. await User.sync({ force: true });
  174. await User.bulkCreate([{ username: 'Toni' }, { username: 'Tobi' }, { username: 'Max' }]);
  175. const user = await User.findByPk(1);
  176. await user.destroy();
  177. expect(await User.findOne({ where: { id: 1 }, paranoid: false })).to.exist;
  178. expect(await User.findByPk(1)).to.be.null;
  179. expect(await User.count()).to.equal(2);
  180. expect(await User.count({ paranoid: false })).to.equal(3);
  181. });
  182. it('should include deleted associated records if include has paranoid marked as false', async function () {
  183. const User = this.sequelize.define(
  184. 'User',
  185. {
  186. username: DataTypes.STRING,
  187. },
  188. { paranoid: true },
  189. );
  190. const Pet = this.sequelize.define(
  191. 'Pet',
  192. {
  193. name: DataTypes.STRING,
  194. userId: DataTypes.INTEGER,
  195. },
  196. { paranoid: true },
  197. );
  198. User.hasMany(Pet);
  199. Pet.belongsTo(User);
  200. await User.sync({ force: true });
  201. await Pet.sync({ force: true });
  202. const userId = (await User.create({ username: 'Joe' })).id;
  203. await Pet.bulkCreate([
  204. { name: 'Fido', userId },
  205. { name: 'Fifi', userId },
  206. ]);
  207. const pet = await Pet.findByPk(1);
  208. await pet.destroy();
  209. const user = await User.findOne({
  210. where: { id: userId },
  211. include: Pet,
  212. });
  213. const userWithDeletedPets = await User.findOne({
  214. where: { id: userId },
  215. include: { model: Pet, paranoid: false },
  216. });
  217. expect(user).to.exist;
  218. expect(user.pets).to.have.length(1);
  219. expect(userWithDeletedPets).to.exist;
  220. expect(userWithDeletedPets.pets).to.have.length(2);
  221. });
  222. });