You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
190 lines
5.7 KiB
190 lines
5.7 KiB
/*
|
|
* Copyright (c) 2015-present, Vitaly Tomilov
|
|
*
|
|
* See the LICENSE file at the top-level directory of this distribution
|
|
* for licensing information.
|
|
*
|
|
* Removal or modification of this copyright notice is prohibited.
|
|
*/
|
|
|
|
const {InnerState} = require(`./inner-state`);
|
|
const {addInspection} = require(`./utils`);
|
|
const {assertOptions} = require(`assert-options`);
|
|
|
|
/**
|
|
* @enum {number}
|
|
* @alias txMode.isolationLevel
|
|
* @readonly
|
|
* @summary Transaction Isolation Level.
|
|
* @description
|
|
* The type is available from the {@link txMode} namespace.
|
|
*
|
|
* @see $[Transaction Isolation]
|
|
*/
|
|
const isolationLevel = {
|
|
/** Isolation level not specified. */
|
|
none: 0,
|
|
|
|
/** ISOLATION LEVEL SERIALIZABLE */
|
|
serializable: 1,
|
|
|
|
/** ISOLATION LEVEL REPEATABLE READ */
|
|
repeatableRead: 2,
|
|
|
|
/** ISOLATION LEVEL READ COMMITTED */
|
|
readCommitted: 3
|
|
|
|
// From the official documentation: http://www.postgresql.org/docs/9.5/static/sql-set-transaction.html
|
|
// The SQL standard defines one additional level, READ UNCOMMITTED. In PostgreSQL READ UNCOMMITTED is treated as READ COMMITTED.
|
|
// => skipping `READ UNCOMMITTED`.
|
|
};
|
|
|
|
/**
|
|
* @class txMode.TransactionMode
|
|
* @description
|
|
* Constructs a complete transaction-opening `BEGIN` command, from these options:
|
|
* - isolation level
|
|
* - access mode
|
|
* - deferrable mode
|
|
*
|
|
* The type is available from the {@link txMode} namespace.
|
|
*
|
|
* @param {} [options]
|
|
* Transaction Mode options.
|
|
*
|
|
* @param {txMode.isolationLevel} [options.tiLevel]
|
|
* Transaction Isolation Level.
|
|
*
|
|
* @param {boolean} [options.readOnly]
|
|
* Sets transaction access mode based on the read-only flag:
|
|
* - `undefined` - access mode not specified (default)
|
|
* - `true` - access mode is set to `READ ONLY`
|
|
* - `false` - access mode is set to `READ WRITE`
|
|
*
|
|
* @param {boolean} [options.deferrable]
|
|
* Sets transaction deferrable mode based on the boolean value:
|
|
* - `undefined` - deferrable mode not specified (default)
|
|
* - `true` - mode is set to `DEFERRABLE`
|
|
* - `false` - mode is set to `NOT DEFERRABLE`
|
|
*
|
|
* It is used only when `tiLevel`=`isolationLevel.serializable`
|
|
* and `readOnly`=`true`, or else it is ignored.
|
|
*
|
|
* @returns {txMode.TransactionMode}
|
|
*
|
|
* @see $[BEGIN], {@link txMode.isolationLevel}
|
|
*
|
|
* @example
|
|
*
|
|
* const {TransactionMode, isolationLevel} = pgp.txMode;
|
|
*
|
|
* // Create a reusable transaction mode (serializable + read-only + deferrable):
|
|
* const mode = new TransactionMode({
|
|
* tiLevel: isolationLevel.serializable,
|
|
* readOnly: true,
|
|
* deferrable: true
|
|
* });
|
|
*
|
|
* db.tx({mode}, t => {
|
|
* return t.any('SELECT * FROM table');
|
|
* })
|
|
* .then(data => {
|
|
* // success;
|
|
* })
|
|
* .catch(error => {
|
|
* // error
|
|
* });
|
|
*
|
|
* // Instead of the default BEGIN, such transaction will start with:
|
|
*
|
|
* // BEGIN ISOLATION LEVEL SERIALIZABLE READ ONLY DEFERRABLE
|
|
*
|
|
*/
|
|
class TransactionMode extends InnerState {
|
|
|
|
constructor(options) {
|
|
options = assertOptions(options, [`tiLevel`, `deferrable`, `readOnly`]);
|
|
const {readOnly, deferrable} = options;
|
|
let {tiLevel} = options;
|
|
let level, accessMode, deferrableMode, begin = `begin`;
|
|
tiLevel = (tiLevel > 0) ? parseInt(tiLevel) : 0;
|
|
|
|
if (tiLevel > 0 && tiLevel < 4) {
|
|
const values = [`serializable`, `repeatable read`, `read committed`];
|
|
level = `isolation level ` + values[tiLevel - 1];
|
|
}
|
|
if (readOnly) {
|
|
accessMode = `read only`;
|
|
} else {
|
|
if (readOnly !== undefined) {
|
|
accessMode = `read write`;
|
|
}
|
|
}
|
|
// From the official documentation: http://www.postgresql.org/docs/9.5/static/sql-set-transaction.html
|
|
// The DEFERRABLE transaction property has no effect unless the transaction is also SERIALIZABLE and READ ONLY
|
|
if (tiLevel === isolationLevel.serializable && readOnly) {
|
|
if (deferrable) {
|
|
deferrableMode = `deferrable`;
|
|
} else {
|
|
if (deferrable !== undefined) {
|
|
deferrableMode = `not deferrable`;
|
|
}
|
|
}
|
|
}
|
|
if (level) {
|
|
begin += ` ` + level;
|
|
}
|
|
if (accessMode) {
|
|
begin += ` ` + accessMode;
|
|
}
|
|
if (deferrableMode) {
|
|
begin += ` ` + deferrableMode;
|
|
}
|
|
|
|
super({begin, capBegin: begin.toUpperCase()});
|
|
}
|
|
|
|
/**
|
|
* @method txMode.TransactionMode#begin
|
|
* @description
|
|
* Returns a complete BEGIN statement, according to all the parameters passed into the class.
|
|
*
|
|
* This method is primarily for internal use by the library.
|
|
*
|
|
* @param {boolean} [cap=false]
|
|
* Indicates whether the returned SQL must be capitalized.
|
|
*
|
|
* @returns {string}
|
|
*/
|
|
begin(cap) {
|
|
return cap ? this._inner.capBegin : this._inner.begin;
|
|
}
|
|
}
|
|
|
|
addInspection(TransactionMode, function () {
|
|
return this.begin(true);
|
|
});
|
|
|
|
/**
|
|
* @namespace txMode
|
|
* @description
|
|
* Transaction Mode namespace, available as `pgp.txMode`, before and after initializing the library.
|
|
*
|
|
* Extends the default `BEGIN` with Transaction Mode parameters:
|
|
* - isolation level
|
|
* - access mode
|
|
* - deferrable mode
|
|
*
|
|
* @property {function} TransactionMode
|
|
* {@link txMode.TransactionMode TransactionMode} class constructor.
|
|
*
|
|
* @property {txMode.isolationLevel} isolationLevel
|
|
* Transaction Isolation Level enumerator
|
|
*
|
|
* @see $[BEGIN]
|
|
*/
|
|
module.exports = {
|
|
isolationLevel,
|
|
TransactionMode
|
|
};
|
|
|
|
|