transaction.test.ts 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. import { IsolationLevel } from '@sequelize/core';
  2. import { expect } from 'chai';
  3. import sinon from 'sinon';
  4. import { beforeAll2, getTestDialect, sequelize } from '../support';
  5. const dialectName = getTestDialect();
  6. describe('Transaction', () => {
  7. // These dialects do not pass transaction queries to queryRaw.
  8. // Instead, they call connection transaction methods directly.
  9. if (sequelize.dialect.supports.connectionTransactionMethods) {
  10. return;
  11. }
  12. const vars = beforeAll2(() => {
  13. sequelize.setDatabaseVersion('does not matter, prevents the SHOW SERVER_VERSION query');
  14. return {
  15. stub: sinon.stub(sequelize, 'queryRaw').resolves([[], {}]),
  16. stubConnection: sinon.stub(sequelize.dialect.connectionManager, 'connect').resolves({
  17. uuid: 'ssfdjd-434fd-43dfg23-2d',
  18. close() {},
  19. }),
  20. stubValidate: sinon.stub(sequelize.dialect.connectionManager, 'validate').returns(true),
  21. stubRelease: sinon.stub(sequelize.dialect.connectionManager, 'disconnect'),
  22. stubTransactionId: sinon
  23. .stub(sequelize.queryGenerator, 'generateTransactionId')
  24. .returns('123'),
  25. };
  26. });
  27. beforeEach(() => {
  28. vars.stub.resetHistory();
  29. vars.stubConnection.resetHistory();
  30. vars.stubValidate.resetHistory();
  31. vars.stubRelease.resetHistory();
  32. });
  33. after(() => {
  34. vars.stub.restore();
  35. vars.stubConnection.restore();
  36. vars.stubValidate.restore();
  37. vars.stubRelease.restore();
  38. vars.stubTransactionId.restore();
  39. });
  40. it('should run auto commit query only when needed', async () => {
  41. sequelize.setDatabaseVersion('does not matter, prevents the SHOW SERVER_VERSION query');
  42. const expectations: Record<string, string[]> = {
  43. all: ['START TRANSACTION'],
  44. snowflake: ['START TRANSACTION NAME "123"'],
  45. sqlite3: ['BEGIN DEFERRED TRANSACTION'],
  46. };
  47. await sequelize.transaction(async () => {
  48. expect(vars.stub.args.map(arg => arg[0])).to.deep.equal(
  49. expectations[dialectName] || expectations.all,
  50. );
  51. });
  52. });
  53. it('should set isolation level correctly', async () => {
  54. const expectations: Record<string, string[]> = {
  55. all: ['SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED', 'START TRANSACTION'],
  56. postgres: ['START TRANSACTION', 'SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED'],
  57. sqlite3: ['BEGIN DEFERRED TRANSACTION', 'PRAGMA read_uncommitted = 1'],
  58. };
  59. try {
  60. await sequelize.transaction({ isolationLevel: IsolationLevel.READ_UNCOMMITTED }, async () => {
  61. expect(vars.stub.args.map(arg => arg[0])).to.deep.equal(
  62. expectations[dialectName] || expectations.all,
  63. );
  64. });
  65. } catch (error) {
  66. if (!sequelize.dialect.supports.isolationLevels) {
  67. expect(error).to.be.instanceOf(
  68. Error,
  69. `Isolation levels are not supported by ${dialectName}.`,
  70. );
  71. } else {
  72. throw error;
  73. }
  74. }
  75. });
  76. });
  77. describe('Sequelize#transaction', () => {
  78. it('throws if the callback is not provided', async () => {
  79. // @ts-expect-error -- this test ensures a helpful error is thrown to ease migration.
  80. await expect(sequelize.transaction()).to.be.rejectedWith(
  81. 'sequelize.transaction requires a callback. If you wish to start an unmanaged transaction, please use sequelize.startUnmanagedTransaction instead',
  82. );
  83. });
  84. });