Skip to content

Commit

Permalink
Transaction rejects with rethrown error - fixes #289
Browse files Browse the repository at this point in the history
  • Loading branch information
porsager committed Mar 27, 2022
1 parent a782edf commit f7c8ae6
Show file tree
Hide file tree
Showing 9 changed files with 71 additions and 24 deletions.
11 changes: 7 additions & 4 deletions cjs/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -198,22 +198,25 @@ function Postgres(a, b) {
async function scope(c, fn, name) {
const sql = Sql(handler, true)
sql.savepoint = savepoint
let errored
let uncaughtError
name && await sql`savepoint ${ sql(name) }`
try {
const result = await new Promise((resolve, reject) => {
errored = reject
const x = fn(sql)
Promise.resolve(Array.isArray(x) ? Promise.all(x) : x).then(resolve, reject)
})

if (uncaughtError)
throw uncaughtError

!name && await sql`commit`
return result
} catch (e) {
await (name
? sql`rollback to ${ sql(name) }`
: sql`rollback`
)
throw e
throw e instanceof PostgresError && e.code === '25P02' && uncaughtError || e
}

function savepoint(name, fn) {
Expand All @@ -225,7 +228,7 @@ function Postgres(a, b) {
}

function handler(q) {
errored && q.catch(errored)
q.catch(e => uncaughtError || (uncaughtError = e))
c.state === 'full'
? queries.push(q)
: c.execute(q) || (c.state = 'full', full.push(c))
Expand Down
14 changes: 8 additions & 6 deletions cjs/src/query.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,19 @@ const Query = module.exports.Query = class Query extends Promise {
this.executed = false
this.signature = ''

this[originError] = handler.debug || !this.tagged
this[originError] = this.handler.debug
? new Error()
: cachedError(this.strings)
: this.tagged && cachedError(this.strings)
}

get origin() {
return this.handler.debug || !this.tagged
return this.handler.debug
? this[originError].stack
: originStackCache.has(this.strings)
? originStackCache.get(this.strings)
: originStackCache.set(this.strings, this[originError].stack).get(this.strings)
: this.tagged
? originStackCache.has(this.strings)
? originStackCache.get(this.strings)
: originStackCache.set(this.strings, this[originError].stack).get(this.strings)
: ''
}

static get [Symbol.species]() {
Expand Down
1 change: 1 addition & 0 deletions cjs/src/subscribe.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ module.exports = Subscribe;function Subscribe(postgres, options) {

options.max = 1
options.onclose = onclose
options.fetch_types = false
options.connection = {
...options.connection,
replication: 'database'
Expand Down
11 changes: 11 additions & 0 deletions cjs/tests/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,17 @@ t('Uncaught transaction request errors bubbles to transaction', async() => [
)).catch(e => e.code))
])

t('Transaction rejects with rethrown error', async() => [
'WAT',
await sql.begin(async sql => {
try {
await sql`select exception`
} catch (ex) {
throw new Error('WAT')
}
}).catch(e => e.message)
])

t('Parallel transactions', async() => {
await sql`create table test (a int)`
return ['11', (await Promise.all([
Expand Down
11 changes: 7 additions & 4 deletions deno/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -199,22 +199,25 @@ function Postgres(a, b) {
async function scope(c, fn, name) {
const sql = Sql(handler, true)
sql.savepoint = savepoint
let errored
let uncaughtError
name && await sql`savepoint ${ sql(name) }`
try {
const result = await new Promise((resolve, reject) => {
errored = reject
const x = fn(sql)
Promise.resolve(Array.isArray(x) ? Promise.all(x) : x).then(resolve, reject)
})

if (uncaughtError)
throw uncaughtError

!name && await sql`commit`
return result
} catch (e) {
await (name
? sql`rollback to ${ sql(name) }`
: sql`rollback`
)
throw e
throw e instanceof PostgresError && e.code === '25P02' && uncaughtError || e
}

function savepoint(name, fn) {
Expand All @@ -226,7 +229,7 @@ function Postgres(a, b) {
}

function handler(q) {
errored && q.catch(errored)
q.catch(e => uncaughtError || (uncaughtError = e))
c.state === 'full'
? queries.push(q)
: c.execute(q) || (c.state = 'full', full.push(c))
Expand Down
14 changes: 8 additions & 6 deletions deno/src/query.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,19 @@ export class Query extends Promise {
this.executed = false
this.signature = ''

this[originError] = handler.debug || !this.tagged
this[originError] = this.handler.debug
? new Error()
: cachedError(this.strings)
: this.tagged && cachedError(this.strings)
}

get origin() {
return this.handler.debug || !this.tagged
return this.handler.debug
? this[originError].stack
: originStackCache.has(this.strings)
? originStackCache.get(this.strings)
: originStackCache.set(this.strings, this[originError].stack).get(this.strings)
: this.tagged
? originStackCache.has(this.strings)
? originStackCache.get(this.strings)
: originStackCache.set(this.strings, this[originError].stack).get(this.strings)
: ''
}

static get [Symbol.species]() {
Expand Down
11 changes: 11 additions & 0 deletions deno/tests/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,17 @@ t('Uncaught transaction request errors bubbles to transaction', async() => [
)).catch(e => e.code))
])

t('Transaction rejects with rethrown error', async() => [
'WAT',
await sql.begin(async sql => {
try {
await sql`select exception`
} catch (ex) {
throw new Error('WAT')
}
}).catch(e => e.message)
])

t('Parallel transactions', async() => {
await sql`create table test (a int)`
return ['11', (await Promise.all([
Expand Down
11 changes: 7 additions & 4 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -198,22 +198,25 @@ function Postgres(a, b) {
async function scope(c, fn, name) {
const sql = Sql(handler, true)
sql.savepoint = savepoint
let errored
let uncaughtError
name && await sql`savepoint ${ sql(name) }`
try {
const result = await new Promise((resolve, reject) => {
errored = reject
const x = fn(sql)
Promise.resolve(Array.isArray(x) ? Promise.all(x) : x).then(resolve, reject)
})

if (uncaughtError)
throw uncaughtError

!name && await sql`commit`
return result
} catch (e) {
await (name
? sql`rollback to ${ sql(name) }`
: sql`rollback`
)
throw e
throw e instanceof PostgresError && e.code === '25P02' && uncaughtError || e
}

function savepoint(name, fn) {
Expand All @@ -225,7 +228,7 @@ function Postgres(a, b) {
}

function handler(q) {
errored && q.catch(errored)
q.catch(e => uncaughtError || (uncaughtError = e))
c.state === 'full'
? queries.push(q)
: c.execute(q) || (c.state = 'full', full.push(c))
Expand Down
11 changes: 11 additions & 0 deletions tests/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,17 @@ t('Uncaught transaction request errors bubbles to transaction', async() => [
)).catch(e => e.code))
])

t('Transaction rejects with rethrown error', async() => [
'WAT',
await sql.begin(async sql => {
try {
await sql`select exception`
} catch (ex) {
throw new Error('WAT')
}
}).catch(e => e.message)
])

t('Parallel transactions', async() => {
await sql`create table test (a int)`
return ['11', (await Promise.all([
Expand Down

0 comments on commit f7c8ae6

Please sign in to comment.