transaction.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. "use strict";
  2. var __defProp = Object.defineProperty;
  3. var __getOwnPropSymbols = Object.getOwnPropertySymbols;
  4. var __hasOwnProp = Object.prototype.hasOwnProperty;
  5. var __propIsEnum = Object.prototype.propertyIsEnumerable;
  6. var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
  7. var __spreadValues = (a, b) => {
  8. for (var prop in b || (b = {}))
  9. if (__hasOwnProp.call(b, prop))
  10. __defNormalProp(a, prop, b[prop]);
  11. if (__getOwnPropSymbols)
  12. for (var prop of __getOwnPropSymbols(b)) {
  13. if (__propIsEnum.call(b, prop))
  14. __defNormalProp(a, prop, b[prop]);
  15. }
  16. return a;
  17. };
  18. class Transaction {
  19. constructor(sequelize, options) {
  20. this.sequelize = sequelize;
  21. this.savepoints = [];
  22. this._afterCommitHooks = [];
  23. const generateTransactionId = this.sequelize.dialect.queryGenerator.generateTransactionId;
  24. this.options = __spreadValues({
  25. type: sequelize.options.transactionType,
  26. isolationLevel: sequelize.options.isolationLevel,
  27. readOnly: false
  28. }, options);
  29. this.parent = this.options.transaction;
  30. if (this.parent) {
  31. this.id = this.parent.id;
  32. this.parent.savepoints.push(this);
  33. this.name = `${this.id}-sp-${this.parent.savepoints.length}`;
  34. } else {
  35. this.id = this.name = generateTransactionId();
  36. }
  37. delete this.options.transaction;
  38. }
  39. async commit() {
  40. if (this.finished) {
  41. throw new Error(`Transaction cannot be committed because it has been finished with state: ${this.finished}`);
  42. }
  43. try {
  44. await this.sequelize.getQueryInterface().commitTransaction(this, this.options);
  45. this.cleanup();
  46. } catch (e) {
  47. console.warn(`Committing transaction ${this.id} failed with error ${JSON.stringify(e.message)}. We are killing its connection as it is now in an undetermined state.`);
  48. await this.forceCleanup();
  49. throw e;
  50. } finally {
  51. this.finished = "commit";
  52. for (const hook of this._afterCommitHooks) {
  53. await hook.apply(this, [this]);
  54. }
  55. }
  56. }
  57. async rollback() {
  58. if (this.finished) {
  59. throw new Error(`Transaction cannot be rolled back because it has been finished with state: ${this.finished}`);
  60. }
  61. if (!this.connection) {
  62. throw new Error("Transaction cannot be rolled back because it never started");
  63. }
  64. try {
  65. await this.sequelize.getQueryInterface().rollbackTransaction(this, this.options);
  66. this.cleanup();
  67. } catch (e) {
  68. console.warn(`Rolling back transaction ${this.id} failed with error ${JSON.stringify(e.message)}. We are killing its connection as it is now in an undetermined state.`);
  69. await this.forceCleanup();
  70. throw e;
  71. }
  72. }
  73. async prepareEnvironment(useCLS = true) {
  74. let connectionPromise;
  75. if (this.parent) {
  76. connectionPromise = Promise.resolve(this.parent.connection);
  77. } else {
  78. const acquireOptions = { uuid: this.id };
  79. if (this.options.readOnly) {
  80. acquireOptions.type = "SELECT";
  81. }
  82. connectionPromise = this.sequelize.connectionManager.getConnection(acquireOptions);
  83. }
  84. let result;
  85. const connection = await connectionPromise;
  86. this.connection = connection;
  87. this.connection.uuid = this.id;
  88. try {
  89. await this.begin();
  90. result = await this.setDeferrable();
  91. } catch (setupErr) {
  92. try {
  93. result = await this.rollback();
  94. } finally {
  95. throw setupErr;
  96. }
  97. }
  98. if (useCLS && this.sequelize.constructor._cls) {
  99. this.sequelize.constructor._cls.set("transaction", this);
  100. }
  101. return result;
  102. }
  103. async setDeferrable() {
  104. if (this.options.deferrable) {
  105. return await this.sequelize.getQueryInterface().deferConstraints(this, this.options);
  106. }
  107. }
  108. async begin() {
  109. const queryInterface = this.sequelize.getQueryInterface();
  110. if (this.sequelize.dialect.supports.settingIsolationLevelDuringTransaction) {
  111. await queryInterface.startTransaction(this, this.options);
  112. return queryInterface.setIsolationLevel(this, this.options.isolationLevel, this.options);
  113. }
  114. await queryInterface.setIsolationLevel(this, this.options.isolationLevel, this.options);
  115. return queryInterface.startTransaction(this, this.options);
  116. }
  117. cleanup() {
  118. if (this.parent || this.connection.uuid === void 0) {
  119. return;
  120. }
  121. this._clearCls();
  122. this.sequelize.connectionManager.releaseConnection(this.connection);
  123. this.connection.uuid = void 0;
  124. }
  125. async forceCleanup() {
  126. if (this.parent || this.connection.uuid === void 0) {
  127. return;
  128. }
  129. this._clearCls();
  130. await this.sequelize.connectionManager.destroyConnection(this.connection);
  131. this.connection.uuid = void 0;
  132. }
  133. _clearCls() {
  134. const cls = this.sequelize.constructor._cls;
  135. if (cls) {
  136. if (cls.get("transaction") === this) {
  137. cls.set("transaction", null);
  138. }
  139. }
  140. }
  141. afterCommit(fn) {
  142. if (!fn || typeof fn !== "function") {
  143. throw new Error('"fn" must be a function');
  144. }
  145. this._afterCommitHooks.push(fn);
  146. }
  147. static get TYPES() {
  148. return {
  149. DEFERRED: "DEFERRED",
  150. IMMEDIATE: "IMMEDIATE",
  151. EXCLUSIVE: "EXCLUSIVE"
  152. };
  153. }
  154. static get ISOLATION_LEVELS() {
  155. return {
  156. READ_UNCOMMITTED: "READ UNCOMMITTED",
  157. READ_COMMITTED: "READ COMMITTED",
  158. REPEATABLE_READ: "REPEATABLE READ",
  159. SERIALIZABLE: "SERIALIZABLE"
  160. };
  161. }
  162. static get LOCK() {
  163. return {
  164. UPDATE: "UPDATE",
  165. SHARE: "SHARE",
  166. KEY_SHARE: "KEY SHARE",
  167. NO_KEY_UPDATE: "NO KEY UPDATE"
  168. };
  169. }
  170. get LOCK() {
  171. return Transaction.LOCK;
  172. }
  173. }
  174. module.exports = Transaction;
  175. module.exports.Transaction = Transaction;
  176. module.exports.default = Transaction;
  177. //# sourceMappingURL=transaction.js.map