transactions.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.isTransactionCommand = exports.Transaction = exports.TxnState = void 0;
  4. const error_1 = require("./error");
  5. const read_concern_1 = require("./read_concern");
  6. const read_preference_1 = require("./read_preference");
  7. const write_concern_1 = require("./write_concern");
  8. /** @internal */
  9. exports.TxnState = Object.freeze({
  10. NO_TRANSACTION: 'NO_TRANSACTION',
  11. STARTING_TRANSACTION: 'STARTING_TRANSACTION',
  12. TRANSACTION_IN_PROGRESS: 'TRANSACTION_IN_PROGRESS',
  13. TRANSACTION_COMMITTED: 'TRANSACTION_COMMITTED',
  14. TRANSACTION_COMMITTED_EMPTY: 'TRANSACTION_COMMITTED_EMPTY',
  15. TRANSACTION_ABORTED: 'TRANSACTION_ABORTED'
  16. });
  17. const stateMachine = {
  18. [exports.TxnState.NO_TRANSACTION]: [exports.TxnState.NO_TRANSACTION, exports.TxnState.STARTING_TRANSACTION],
  19. [exports.TxnState.STARTING_TRANSACTION]: [
  20. exports.TxnState.TRANSACTION_IN_PROGRESS,
  21. exports.TxnState.TRANSACTION_COMMITTED,
  22. exports.TxnState.TRANSACTION_COMMITTED_EMPTY,
  23. exports.TxnState.TRANSACTION_ABORTED
  24. ],
  25. [exports.TxnState.TRANSACTION_IN_PROGRESS]: [
  26. exports.TxnState.TRANSACTION_IN_PROGRESS,
  27. exports.TxnState.TRANSACTION_COMMITTED,
  28. exports.TxnState.TRANSACTION_ABORTED
  29. ],
  30. [exports.TxnState.TRANSACTION_COMMITTED]: [
  31. exports.TxnState.TRANSACTION_COMMITTED,
  32. exports.TxnState.TRANSACTION_COMMITTED_EMPTY,
  33. exports.TxnState.STARTING_TRANSACTION,
  34. exports.TxnState.NO_TRANSACTION
  35. ],
  36. [exports.TxnState.TRANSACTION_ABORTED]: [exports.TxnState.STARTING_TRANSACTION, exports.TxnState.NO_TRANSACTION],
  37. [exports.TxnState.TRANSACTION_COMMITTED_EMPTY]: [
  38. exports.TxnState.TRANSACTION_COMMITTED_EMPTY,
  39. exports.TxnState.NO_TRANSACTION
  40. ]
  41. };
  42. const ACTIVE_STATES = new Set([
  43. exports.TxnState.STARTING_TRANSACTION,
  44. exports.TxnState.TRANSACTION_IN_PROGRESS
  45. ]);
  46. const COMMITTED_STATES = new Set([
  47. exports.TxnState.TRANSACTION_COMMITTED,
  48. exports.TxnState.TRANSACTION_COMMITTED_EMPTY,
  49. exports.TxnState.TRANSACTION_ABORTED
  50. ]);
  51. /**
  52. * @public
  53. * A class maintaining state related to a server transaction. Internal Only
  54. */
  55. class Transaction {
  56. /** Create a transaction @internal */
  57. constructor(options) {
  58. options = options !== null && options !== void 0 ? 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. /** @internal */
  82. get server() {
  83. return this._pinnedServer;
  84. }
  85. get recoveryToken() {
  86. return this._recoveryToken;
  87. }
  88. get isPinned() {
  89. return !!this.server;
  90. }
  91. /** @returns Whether the transaction has started */
  92. get isStarting() {
  93. return this.state === exports.TxnState.STARTING_TRANSACTION;
  94. }
  95. /**
  96. * @returns Whether this session is presently in a transaction
  97. */
  98. get isActive() {
  99. return ACTIVE_STATES.has(this.state);
  100. }
  101. get isCommitted() {
  102. return COMMITTED_STATES.has(this.state);
  103. }
  104. /**
  105. * Transition the transaction in the state machine
  106. * @internal
  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. /** @internal */
  123. pinServer(server) {
  124. if (this.isActive) {
  125. this._pinnedServer = server;
  126. }
  127. }
  128. /** @internal */
  129. unpinServer() {
  130. this._pinnedServer = undefined;
  131. }
  132. }
  133. exports.Transaction = Transaction;
  134. function isTransactionCommand(command) {
  135. return !!(command.commitTransaction || command.abortTransaction);
  136. }
  137. exports.isTransactionCommand = isTransactionCommand;
  138. //# sourceMappingURL=transactions.js.map