Estructura inicial del proyecto
This commit is contained in:
323
backend/node_modules/mssql/lib/base/transaction.js
generated
vendored
Normal file
323
backend/node_modules/mssql/lib/base/transaction.js
generated
vendored
Normal file
@ -0,0 +1,323 @@
|
||||
'use strict'
|
||||
|
||||
const debug = require('debug')('mssql:base')
|
||||
const { EventEmitter } = require('node:events')
|
||||
const { IDS, getPoolId } = require('../utils')
|
||||
const globalConnection = require('../global-connection')
|
||||
const { TransactionError } = require('../error')
|
||||
const shared = require('../shared')
|
||||
const ISOLATION_LEVEL = require('../isolationlevel')
|
||||
const { CHANNELS, publish } = require('../diagnostics')
|
||||
|
||||
const ISOLATION_LEVEL_NAMES = Object.fromEntries(
|
||||
Object.entries(ISOLATION_LEVEL).map(([name, value]) => [value, name])
|
||||
)
|
||||
|
||||
/**
|
||||
* Class Transaction.
|
||||
*
|
||||
* @property {Number} isolationLevel Controls the locking and row versioning behavior of TSQL statements issued by a connection. READ_COMMITTED by default.
|
||||
* @property {String} name Transaction name. Empty string by default.
|
||||
*
|
||||
* @fires Transaction#begin
|
||||
* @fires Transaction#commit
|
||||
* @fires Transaction#rollback
|
||||
*/
|
||||
|
||||
class Transaction extends EventEmitter {
|
||||
/**
|
||||
* Create new Transaction.
|
||||
*
|
||||
* @param {Connection} [parent] If omitted, global connection is used instead.
|
||||
* @param {{ requestTimeout?: number }} [overrides]
|
||||
*/
|
||||
|
||||
constructor (parent, overrides = {}) {
|
||||
super()
|
||||
|
||||
IDS.add(this, 'Transaction')
|
||||
debug('transaction(%d): created', IDS.get(this))
|
||||
|
||||
this.parent = parent || globalConnection.pool
|
||||
this.isolationLevel = Transaction.defaultIsolationLevel
|
||||
this.name = ''
|
||||
this.overrides = {}
|
||||
if (Number.isFinite(overrides?.requestTimeout) && overrides.requestTimeout >= 0) {
|
||||
this.overrides.requestTimeout = overrides.requestTimeout
|
||||
}
|
||||
}
|
||||
|
||||
get config () {
|
||||
return this.parent.config
|
||||
}
|
||||
|
||||
get connected () {
|
||||
return this.parent.connected
|
||||
}
|
||||
|
||||
/**
|
||||
* Acquire connection from connection pool.
|
||||
*
|
||||
* @param {Request} request Request.
|
||||
* @param {ConnectionPool~acquireCallback} [callback] A callback which is called after connection has established, or an error has occurred. If omited, method returns Promise.
|
||||
* @return {Transaction|Promise}
|
||||
*/
|
||||
|
||||
acquire (request, callback) {
|
||||
if (!this._acquiredConnection) {
|
||||
setImmediate(callback, new TransactionError('Transaction has not begun. Call begin() first.', 'ENOTBEGUN'))
|
||||
return this
|
||||
}
|
||||
|
||||
if (this._activeRequest) {
|
||||
setImmediate(callback, new TransactionError("Can't acquire connection for the request. There is another request in progress.", 'EREQINPROG'))
|
||||
return this
|
||||
}
|
||||
|
||||
this._activeRequest = request
|
||||
setImmediate(callback, null, this._acquiredConnection, this._acquiredConfig)
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Release connection back to the pool.
|
||||
*
|
||||
* @param {Connection} connection Previously acquired connection.
|
||||
* @return {Transaction}
|
||||
*/
|
||||
|
||||
release (connection) {
|
||||
if (connection === this._acquiredConnection) {
|
||||
this._activeRequest = null
|
||||
}
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Begin a transaction.
|
||||
*
|
||||
* @param {Number} [isolationLevel] Controls the locking and row versioning behavior of TSQL statements issued by a connection.
|
||||
* @param {basicCallback} [callback] A callback which is called after transaction has began, or an error has occurred. If omited, method returns Promise.
|
||||
* @return {Transaction|Promise}
|
||||
*/
|
||||
|
||||
begin (isolationLevel, callback) {
|
||||
if (isolationLevel instanceof Function) {
|
||||
callback = isolationLevel
|
||||
isolationLevel = undefined
|
||||
}
|
||||
|
||||
if (typeof callback === 'function') {
|
||||
this._begin(isolationLevel, err => {
|
||||
if (!err) {
|
||||
publish(CHANNELS.TRANSACTION_BEGIN, () => ({
|
||||
transactionId: IDS.get(this),
|
||||
isolationLevel: this.isolationLevel,
|
||||
isolationLevelName: ISOLATION_LEVEL_NAMES[this.isolationLevel],
|
||||
poolId: getPoolId(this)
|
||||
}))
|
||||
this.emit('begin')
|
||||
}
|
||||
callback(err)
|
||||
})
|
||||
return this
|
||||
}
|
||||
|
||||
return new shared.Promise((resolve, reject) => {
|
||||
this._begin(isolationLevel, err => {
|
||||
if (err) return reject(err)
|
||||
publish(CHANNELS.TRANSACTION_BEGIN, () => ({
|
||||
transactionId: IDS.get(this),
|
||||
isolationLevel: this.isolationLevel,
|
||||
isolationLevelName: ISOLATION_LEVEL_NAMES[this.isolationLevel],
|
||||
poolId: getPoolId(this)
|
||||
}))
|
||||
this.emit('begin')
|
||||
resolve(this)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {Number} [isolationLevel]
|
||||
* @param {basicCallback} [callback]
|
||||
* @return {Transaction}
|
||||
*/
|
||||
|
||||
_begin (isolationLevel, callback) {
|
||||
if (this._acquiredConnection) {
|
||||
return setImmediate(callback, new TransactionError('Transaction has already begun.', 'EALREADYBEGUN'))
|
||||
}
|
||||
|
||||
this._aborted = false
|
||||
this._abortReason = null
|
||||
this._rollbackRequested = false
|
||||
if (isolationLevel) {
|
||||
if (Object.keys(ISOLATION_LEVEL).some(key => {
|
||||
return ISOLATION_LEVEL[key] === isolationLevel
|
||||
})) {
|
||||
this.isolationLevel = isolationLevel
|
||||
} else {
|
||||
throw new TransactionError('Invalid isolation level.')
|
||||
}
|
||||
}
|
||||
|
||||
setImmediate(callback)
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit a transaction.
|
||||
*
|
||||
* @param {basicCallback} [callback] A callback which is called after transaction has commited, or an error has occurred. If omited, method returns Promise.
|
||||
* @return {Transaction|Promise}
|
||||
*/
|
||||
|
||||
commit (callback) {
|
||||
if (typeof callback === 'function') {
|
||||
this._commit(err => {
|
||||
if (!err) {
|
||||
publish(CHANNELS.TRANSACTION_COMMIT, () => ({
|
||||
transactionId: IDS.get(this)
|
||||
}))
|
||||
this.emit('commit')
|
||||
}
|
||||
callback(err)
|
||||
})
|
||||
return this
|
||||
}
|
||||
|
||||
return new shared.Promise((resolve, reject) => {
|
||||
this._commit(err => {
|
||||
if (err) return reject(err)
|
||||
publish(CHANNELS.TRANSACTION_COMMIT, () => ({
|
||||
transactionId: IDS.get(this)
|
||||
}))
|
||||
this.emit('commit')
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a TransactionError for an aborted transaction, preserving the
|
||||
* original abort reason (if any) as `originalError`.
|
||||
*
|
||||
* @private
|
||||
* @return {TransactionError}
|
||||
*/
|
||||
|
||||
_createAbortError () {
|
||||
const err = new TransactionError('Transaction has been aborted.', 'EABORT')
|
||||
if (this._abortReason) {
|
||||
Object.defineProperty(err, 'originalError', { enumerable: true, value: this._abortReason })
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {basicCallback} [callback]
|
||||
* @return {Transaction}
|
||||
*/
|
||||
|
||||
_commit (callback) {
|
||||
if (this._aborted) {
|
||||
return setImmediate(callback, this._createAbortError())
|
||||
}
|
||||
|
||||
if (!this._acquiredConnection) {
|
||||
return setImmediate(callback, new TransactionError('Transaction has not begun. Call begin() first.', 'ENOTBEGUN'))
|
||||
}
|
||||
|
||||
if (this._activeRequest) {
|
||||
return setImmediate(callback, new TransactionError("Can't commit transaction. There is a request in progress.", 'EREQINPROG'))
|
||||
}
|
||||
|
||||
setImmediate(callback)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns new request using this transaction.
|
||||
*
|
||||
* @param {{ requestTimeout?: number }} [config]
|
||||
* @return {Request}
|
||||
*/
|
||||
|
||||
request (config) {
|
||||
const overrides = { ...this.overrides }
|
||||
if (Number.isFinite(config?.requestTimeout) && config.requestTimeout >= 0) {
|
||||
overrides.requestTimeout = config.requestTimeout
|
||||
}
|
||||
return new shared.driver.Request(this, overrides)
|
||||
}
|
||||
|
||||
/**
|
||||
* Rollback a transaction.
|
||||
*
|
||||
* @param {basicCallback} [callback] A callback which is called after transaction has rolled back, or an error has occurred. If omited, method returns Promise.
|
||||
* @return {Transaction|Promise}
|
||||
*/
|
||||
|
||||
rollback (callback) {
|
||||
if (typeof callback === 'function') {
|
||||
this._rollback(err => {
|
||||
if (!err) {
|
||||
publish(CHANNELS.TRANSACTION_ROLLBACK, () => ({
|
||||
transactionId: IDS.get(this),
|
||||
aborted: this._aborted
|
||||
}))
|
||||
this.emit('rollback', this._aborted)
|
||||
}
|
||||
callback(err)
|
||||
})
|
||||
return this
|
||||
}
|
||||
|
||||
return new shared.Promise((resolve, reject) => {
|
||||
return this._rollback(err => {
|
||||
if (err) return reject(err)
|
||||
publish(CHANNELS.TRANSACTION_ROLLBACK, () => ({
|
||||
transactionId: IDS.get(this),
|
||||
aborted: this._aborted
|
||||
}))
|
||||
this.emit('rollback', this._aborted)
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {basicCallback} [callback]
|
||||
* @return {Transaction}
|
||||
*/
|
||||
|
||||
_rollback (callback) {
|
||||
if (this._aborted) {
|
||||
return setImmediate(callback, this._createAbortError())
|
||||
}
|
||||
|
||||
if (!this._acquiredConnection) {
|
||||
return setImmediate(callback, new TransactionError('Transaction has not begun. Call begin() first.', 'ENOTBEGUN'))
|
||||
}
|
||||
|
||||
if (this._activeRequest) {
|
||||
return setImmediate(callback, new TransactionError("Can't rollback transaction. There is a request in progress.", 'EREQINPROG'))
|
||||
}
|
||||
|
||||
this._rollbackRequested = true
|
||||
|
||||
setImmediate(callback)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Default isolation level used for any transactions that don't explicitly specify an isolation level.
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
Transaction.defaultIsolationLevel = ISOLATION_LEVEL.READ_COMMITTED
|
||||
|
||||
module.exports = Transaction
|
||||
Reference in New Issue
Block a user