tx-mode.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. /*
  2. * Copyright (c) 2015-present, Vitaly Tomilov
  3. *
  4. * See the LICENSE file at the top-level directory of this distribution
  5. * for licensing information.
  6. *
  7. * Removal or modification of this copyright notice is prohibited.
  8. */
  9. const {InnerState} = require('./inner-state');
  10. const {addInspection} = require('./utils');
  11. const {assert} = require('./assert');
  12. /**
  13. * @enum {number}
  14. * @alias txMode.isolationLevel
  15. * @readonly
  16. * @summary Transaction Isolation Level.
  17. * @description
  18. * The type is available from the {@link txMode} namespace.
  19. *
  20. * @see $[Transaction Isolation]
  21. */
  22. const isolationLevel = {
  23. /** Isolation level not specified. */
  24. none: 0,
  25. /** ISOLATION LEVEL SERIALIZABLE */
  26. serializable: 1,
  27. /** ISOLATION LEVEL REPEATABLE READ */
  28. repeatableRead: 2,
  29. /** ISOLATION LEVEL READ COMMITTED */
  30. readCommitted: 3
  31. // From the official documentation: http://www.postgresql.org/docs/9.5/static/sql-set-transaction.html
  32. // The SQL standard defines one additional level, READ UNCOMMITTED. In PostgreSQL READ UNCOMMITTED is treated as READ COMMITTED.
  33. // => skipping `READ UNCOMMITTED`.
  34. };
  35. /**
  36. * @class txMode.TransactionMode
  37. * @description
  38. * Constructs a complete transaction-opening `BEGIN` command, from these options:
  39. * - isolation level
  40. * - access mode
  41. * - deferrable mode
  42. *
  43. * The type is available from the {@link txMode} namespace.
  44. *
  45. * @param {} [options]
  46. * Transaction Mode options.
  47. *
  48. * @param {txMode.isolationLevel} [options.tiLevel]
  49. * Transaction Isolation Level.
  50. *
  51. * @param {boolean} [options.readOnly]
  52. * Sets transaction access mode based on the read-only flag:
  53. * - `undefined` - access mode not specified (default)
  54. * - `true` - access mode is set to `READ ONLY`
  55. * - `false` - access mode is set to `READ WRITE`
  56. *
  57. * @param {boolean} [options.deferrable]
  58. * Sets transaction deferrable mode based on the boolean value:
  59. * - `undefined` - deferrable mode not specified (default)
  60. * - `true` - mode is set to `DEFERRABLE`
  61. * - `false` - mode is set to `NOT DEFERRABLE`
  62. *
  63. * It is used only when `tiLevel`=`isolationLevel.serializable`
  64. * and `readOnly`=`true`, or else it is ignored.
  65. *
  66. * @returns {txMode.TransactionMode}
  67. *
  68. * @see $[BEGIN], {@link txMode.isolationLevel}
  69. *
  70. * @example
  71. *
  72. * const {TransactionMode, isolationLevel} = pgp.txMode;
  73. *
  74. * // Create a reusable transaction mode (serializable + read-only + deferrable):
  75. * const mode = new TransactionMode({
  76. * tiLevel: isolationLevel.serializable,
  77. * readOnly: true,
  78. * deferrable: true
  79. * });
  80. *
  81. * db.tx({mode}, t => {
  82. * return t.any('SELECT * FROM table');
  83. * })
  84. * .then(data => {
  85. * // success;
  86. * })
  87. * .catch(error => {
  88. * // error
  89. * });
  90. *
  91. * // Instead of the default BEGIN, such transaction will start with:
  92. *
  93. * // BEGIN ISOLATION LEVEL SERIALIZABLE READ ONLY DEFERRABLE
  94. *
  95. */
  96. class TransactionMode extends InnerState {
  97. constructor(options) {
  98. options = assert(options, ['tiLevel', 'deferrable', 'readOnly']);
  99. const {readOnly, deferrable} = options;
  100. let {tiLevel} = options;
  101. let level, accessMode, deferrableMode, begin = 'begin';
  102. tiLevel = (tiLevel > 0) ? parseInt(tiLevel) : 0;
  103. if (tiLevel > 0 && tiLevel < 4) {
  104. const values = ['serializable', 'repeatable read', 'read committed'];
  105. level = 'isolation level ' + values[tiLevel - 1];
  106. }
  107. if (readOnly) {
  108. accessMode = 'read only';
  109. } else {
  110. if (readOnly !== undefined) {
  111. accessMode = 'read write';
  112. }
  113. }
  114. // From the official documentation: http://www.postgresql.org/docs/9.5/static/sql-set-transaction.html
  115. // The DEFERRABLE transaction property has no effect unless the transaction is also SERIALIZABLE and READ ONLY
  116. if (tiLevel === isolationLevel.serializable && readOnly) {
  117. if (deferrable) {
  118. deferrableMode = 'deferrable';
  119. } else {
  120. if (deferrable !== undefined) {
  121. deferrableMode = 'not deferrable';
  122. }
  123. }
  124. }
  125. if (level) {
  126. begin += ' ' + level;
  127. }
  128. if (accessMode) {
  129. begin += ' ' + accessMode;
  130. }
  131. if (deferrableMode) {
  132. begin += ' ' + deferrableMode;
  133. }
  134. super({begin, capBegin: begin.toUpperCase()});
  135. }
  136. /**
  137. * @method txMode.TransactionMode#begin
  138. * @description
  139. * Returns a complete BEGIN statement, according to all the parameters passed into the class.
  140. *
  141. * This method is primarily for internal use by the library.
  142. *
  143. * @param {boolean} [cap=false]
  144. * Indicates whether the returned SQL must be capitalized.
  145. *
  146. * @returns {string}
  147. */
  148. begin(cap) {
  149. return cap ? this._inner.capBegin : this._inner.begin;
  150. }
  151. }
  152. addInspection(TransactionMode, function () {
  153. return this.begin(true);
  154. });
  155. /**
  156. * @namespace txMode
  157. * @description
  158. * Transaction Mode namespace, available as `pgp.txMode`, before and after initializing the library.
  159. *
  160. * Extends the default `BEGIN` with Transaction Mode parameters:
  161. * - isolation level
  162. * - access mode
  163. * - deferrable mode
  164. *
  165. * @property {function} TransactionMode
  166. * {@link txMode.TransactionMode TransactionMode} class constructor.
  167. *
  168. * @property {txMode.isolationLevel} isolationLevel
  169. * Transaction Isolation Level enumerator
  170. *
  171. * @see $[BEGIN]
  172. */
  173. module.exports = {
  174. isolationLevel,
  175. TransactionMode
  176. };