Skip to content

Commit 7845fc7

Browse files
committed
Better errors - include origin, query, parameters
Fixes porsager#17
1 parent 4156c3f commit 7845fc7

File tree

4 files changed

+50
-3
lines changed

4 files changed

+50
-3
lines changed

README.md

+4
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,10 @@ sql.unsafe('select ' + danger + ' from users where id = ' + dragons)
493493

494494
Errors are all thrown to related queries and never globally. Errors coming from PostgreSQL itself are always in the [native Postgres format](https://www.postgresql.org/docs/current/errcodes-appendix.html), and the same goes for any [Node.js errors](https://nodejs.org/api/errors.html#errors_common_system_errors) eg. coming from the underlying connection.
495495

496+
Query errors will contain a stored error with the origin of the query to aid in tracing errors.
497+
498+
Query errors will also contain the `query` string and the `parameters` which are not enumerable to avoid accidentally leaking confidential information in logs. To log these it is required to specifically access `error.query` and `error.parameters`.
499+
496500
There are also the following errors specifically for this library.
497501

498502
##### MESSAGE_NOT_SUPPORTED

lib/connection.js

+20-3
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,8 @@ function Connection(options = {}) {
108108
}
109109

110110
function send(query, { sig, str, args = [] }) {
111+
query.str = str
112+
query.args = args
111113
query.result = []
112114
query.result.count = null
113115
timeout && clearTimeout(timer)
@@ -158,9 +160,24 @@ function Connection(options = {}) {
158160
}
159161

160162
function onready(err) {
161-
err
162-
? (backend.query ? backend.query.reject(err) : error(err))
163-
: (backend.query && backend.query.resolve(backend.query.results || backend.query.result))
163+
if (err) {
164+
if (backend.query) {
165+
err.origin = backend.query.origin
166+
Object.defineProperty(err, 'query', {
167+
value: backend.query.str,
168+
enumerable: false
169+
})
170+
Object.defineProperty(err, 'parameters', {
171+
value: backend.query.args,
172+
enumerable: false
173+
})
174+
backend.query.reject(err)
175+
} else {
176+
error(err)
177+
}
178+
} else if (backend.query) {
179+
backend.query.resolve(backend.query.results || backend.query.result)
180+
}
164181

165182
backend.query = backend.error = null
166183
timeout && queries.length === 0 && idle()

lib/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ function Postgres(a, b) {
159159
}
160160

161161
function query(query, connection, xs, args) {
162+
query.origin = new Error('Query failed')
162163
if (!query.raw && (!Array.isArray(xs) || !Array.isArray(xs.raw)))
163164
return nested(xs, args)
164165

tests/index.js

+25
Original file line numberDiff line numberDiff line change
@@ -874,3 +874,28 @@ t('numeric is returned as string', async() => [
874874
'string',
875875
typeof (await sql`select 1.2 as x`)[0].x
876876
])
877+
878+
t('Error contains origin', async() => [
879+
true,
880+
(await sql`selec 1`.catch(err => 'origin' in err))
881+
])
882+
883+
t('Error contains query string', async() => [
884+
'selec 1',
885+
(await sql`selec 1`.catch(err => err.query))
886+
])
887+
888+
t('Error contains query parameters', async() => [
889+
'1',
890+
(await sql`selec ${ 1 }`.catch(err => err.parameters[0].value))
891+
])
892+
893+
t('Query string is not enumerable', async() => [
894+
-1,
895+
(await sql`selec 1`.catch(err => Object.keys(err).indexOf('query')))
896+
])
897+
898+
t('Query parameters are not enumerable', async() => [
899+
-1,
900+
(await sql`selec ${ 1 }`.catch(err => Object.keys(err).indexOf('parameters')))
901+
])

0 commit comments

Comments
 (0)