transactions.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.Transaction = exports.TxnState = void 0;
  4. exports.isTransactionCommand = isTransactionCommand;
  5. const error_1 = require("./error");
  6. const read_concern_1 = require("./read_concern");
  7. const read_preference_1 = require("./read_preference");
  8. const write_concern_1 = require("./write_concern");
  9. /** @internal */
  10. exports.TxnState = Object.freeze({
  11. NO_TRANSACTION: 'NO_TRANSACTION',
  12. STARTING_TRANSACTION: 'STARTING_TRANSACTION',
  13. TRANSACTION_IN_PROGRESS: 'TRANSACTION_IN_PROGRESS',
  14. TRANSACTION_COMMITTED: 'TRANSACTION_COMMITTED',
  15. TRANSACTION_COMMITTED_EMPTY: 'TRANSACTION_COMMITTED_EMPTY',
  16. TRANSACTION_ABORTED: 'TRANSACTION_ABORTED'
  17. });
  18. const stateMachine = {
  19. [exports.TxnState.NO_TRANSACTION]: [exports.TxnState.NO_TRANSACTION, exports.TxnState.STARTING_TRANSACTION],
  20. [exports.TxnState.STARTING_TRANSACTION]: [
  21. exports.TxnState.TRANSACTION_IN_PROGRESS,
  22. exports.TxnState.TRANSACTION_COMMITTED,
  23. exports.TxnState.TRANSACTION_COMMITTED_EMPTY,
  24. exports.TxnState.TRANSACTION_ABORTED
  25. ],
  26. [exports.TxnState.TRANSACTION_IN_PROGRESS]: [
  27. exports.TxnState.TRANSACTION_IN_PROGRESS,
  28. exports.TxnState.TRANSACTION_COMMITTED,
  29. exports.TxnState.TRANSACTION_ABORTED
  30. ],
  31. [exports.TxnState.TRANSACTION_COMMITTED]: [
  32. exports.TxnState.TRANSACTION_COMMITTED,
  33. exports.TxnState.TRANSACTION_COMMITTED_EMPTY,
  34. exports.TxnState.STARTING_TRANSACTION,
  35. exports.TxnState.NO_TRANSACTION
  36. ],
  37. [exports.TxnState.TRANSACTION_ABORTED]: [exports.TxnState.STARTING_TRANSACTION, exports.TxnState.NO_TRANSACTION],
  38. [exports.TxnState.TRANSACTION_COMMITTED_EMPTY]: [
  39. exports.TxnState.TRANSACTION_COMMITTED_EMPTY,
  40. exports.TxnState.NO_TRANSACTION
  41. ]
  42. };
  43. const ACTIVE_STATES = new Set([
  44. exports.TxnState.STARTING_TRANSACTION,
  45. exports.TxnState.TRANSACTION_IN_PROGRESS
  46. ]);
  47. const COMMITTED_STATES = new Set([
  48. exports.TxnState.TRANSACTION_COMMITTED,
  49. exports.TxnState.TRANSACTION_COMMITTED_EMPTY,
  50. exports.TxnState.TRANSACTION_ABORTED
  51. ]);
  52. /**
  53. * @internal
  54. */
  55. class Transaction {
  56. /** Create a transaction */
  57. constructor(options) {
  58. options = options ?? {};
  59. this.state = exports.TxnState.NO_TRANSACTION;
  60. this.options = {};
  61. const writeConcern = write_concern_1.WriteConcern.fromOptions(options);
  62. if (writeConcern) {
  63. if (writeConcern.w === 0) {
  64. throw new error_1.MongoTransactionError('Transactions do not support unacknowledged write concern');
  65. }
  66. this.options.writeConcern = writeConcern;
  67. }
  68. if (options.readConcern) {
  69. this.options.readConcern = read_concern_1.ReadConcern.fromOptions(options);
  70. }
  71. if (options.readPreference) {
  72. this.options.readPreference = read_preference_1.ReadPreference.fromOptions(options);
  73. }
  74. if (options.maxCommitTimeMS) {
  75. this.options.maxTimeMS = options.maxCommitTimeMS;
  76. }
  77. // TODO: This isn't technically necessary
  78. this._pinnedServer = undefined;
  79. this._recoveryToken = undefined;
  80. }
  81. get server() {
  82. return this._pinnedServer;
  83. }
  84. get recoveryToken() {
  85. return this._recoveryToken;
  86. }
  87. get isPinned() {
  88. return !!this.server;
  89. }
  90. /**
  91. * @returns Whether the transaction has started
  92. */
  93. get isStarting() {
  94. return this.state === exports.TxnState.STARTING_TRANSACTION;
  95. }
  96. /**
  97. * @returns Whether this session is presently in a transaction
  98. */
  99. get isActive() {
  100. return ACTIVE_STATES.has(this.state);
  101. }
  102. get isCommitted() {
  103. return COMMITTED_STATES.has(this.state);
  104. }
  105. /**
  106. * Transition the transaction in the state machine
  107. * @param nextState - The new state to transition to
  108. */
  109. transition(nextState) {
  110. const nextStates = stateMachine[this.state];
  111. if (nextStates && nextStates.includes(nextState)) {
  112. this.state = nextState;
  113. if (this.state === exports.TxnState.NO_TRANSACTION ||
  114. this.state === exports.TxnState.STARTING_TRANSACTION ||
  115. this.state === exports.TxnState.TRANSACTION_ABORTED) {
  116. this.unpinServer();
  117. }
  118. return;
  119. }
  120. throw new error_1.MongoRuntimeError(`Attempted illegal state transition from [${this.state}] to [${nextState}]`);
  121. }
  122. pinServer(server) {
  123. if (this.isActive) {
  124. this._pinnedServer = server;
  125. }
  126. }
  127. unpinServer() {
  128. this._pinnedServer = undefined;
  129. }
  130. }
  131. exports.Transaction = Transaction;
  132. function isTransactionCommand(command) {
  133. return !!(command.commitTransaction || command.abortTransaction);
  134. }
  135. //# sourceMappingURL=transactions.js.map