Skip to content

Commit

Permalink
feat: add extra error fields
Browse files Browse the repository at this point in the history
  • Loading branch information
soedirgo committed Oct 10, 2023
1 parent 42649b7 commit f6f505c
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 5 deletions.
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
"pg": "^8.7.1",
"pg-connection-string": "^2.5.0",
"pg-format": "^1.0.4",
"pg-protocol": "^1.6.0",
"pgsql-parser": "^13.3.0",
"pino": "^8.6.1",
"postgres-array": "^3.0.1",
Expand Down
73 changes: 71 additions & 2 deletions src/lib/db.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import pg, { PoolConfig } from 'pg'
import { DatabaseError } from 'pg-protocol'
import { parse as parseArray } from 'postgres-array'
import { PostgresMetaResult } from './types.js'

Expand Down Expand Up @@ -76,8 +77,76 @@ export const init: (config: PoolConfig) => {
res = res.reverse().find((x) => x.rows.length !== 0) ?? { rows: [] }
}
return { data: res.rows, error: null }
} catch (e: any) {
return { data: null, error: { message: e.message } }
} catch (error: any) {
if (error instanceof DatabaseError) {
// Roughly based on:
// - https://github.com/postgres/postgres/blob/fc4089f3c65a5f1b413a3299ba02b66a8e5e37d0/src/interfaces/libpq/fe-protocol3.c#L1018
// - https://github.com/brianc/node-postgres/blob/b1a8947738ce0af004cb926f79829bb2abc64aa6/packages/pg/lib/native/query.js#L33
let formattedError = ''
{
if (error.severity) {
formattedError += `${error.severity}: `
}
if (error.code) {
formattedError += `${error.code}: `
}
if (error.message) {
formattedError += error.message
}
formattedError += '\n'
if (error.position) {
// error.position is 1-based
const position = Number(error.position) - 1

let line = ''
let lineNumber = 0
let lineOffset = 0

const lines = sql.split('\n')
let currentOffset = 0
for (let i = 0; i < lines.length; i++) {
if (currentOffset + lines[i].length > position) {
line = lines[i]
lineNumber = i + 1 // 1-based
lineOffset = position - currentOffset
break
}
currentOffset += lines[i].length + 1 // 1 extra offset for newline
}
formattedError += `LINE ${lineNumber}: ${line}
${' '.repeat(5 + lineNumber.toString().length + 2 + lineOffset)}^
`
}
if (error.detail) {
formattedError += `DETAIL: ${error.detail}
`
}
if (error.hint) {
formattedError += `HINT: ${error.hint}
`
}
if (error.internalQuery) {
formattedError += `QUERY: ${error.internalQuery}
`
}
if (error.where) {
formattedError += `CONTEXT: ${error.where}
`
}
}

return {
data: null,
error: {
...error,
// error.message is non-enumerable
message: error.message,
formattedError,
},
}
}

return { data: null, error: { message: error.message } }
}
},

Expand Down
5 changes: 2 additions & 3 deletions src/lib/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Static, Type } from '@sinclair/typebox'
import { DatabaseError } from 'pg-protocol'
import { Options as PrettierOptions } from 'prettier'

export interface FormatterOptions extends PrettierOptions {}
Expand All @@ -10,9 +11,7 @@ export interface PostgresMetaOk<T> {

export interface PostgresMetaErr {
data: null
error: {
message: string
}
error: Partial<DatabaseError> & { message: string; formattedError?: string }
}

export type PostgresMetaResult<T> = PostgresMetaOk<T> | PostgresMetaErr
Expand Down
20 changes: 20 additions & 0 deletions test/lib/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,27 @@ test('error', async () => {
{
"data": null,
"error": {
"code": "42P01",
"column": undefined,
"constraint": undefined,
"dataType": undefined,
"detail": undefined,
"file": "tablecmds.c",
"formattedError": "ERROR: 42P01: table "missing_table" does not exist
",
"hint": undefined,
"internalPosition": undefined,
"internalQuery": undefined,
"length": 108,
"line": "1259",
"message": "table "missing_table" does not exist",
"name": "error",
"position": undefined,
"routine": "DropErrorMsgNonExistent",
"schema": undefined,
"severity": "ERROR",
"table": undefined,
"where": undefined,
},
}
`)
Expand Down

0 comments on commit f6f505c

Please sign in to comment.