dberror

package module
v0.0.0-...-14c0463 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 18, 2022 License: MIT Imports: 8 Imported by: 0

README

Readable database errors

Do you like forcing constraint validation down into the database, but dislike the native error messages returned by Postgres?

invalid input syntax for uuid: "foo"

invalid input value for enum account_status: "blah"

new row for relation "accounts" violates check constraint "accounts_balance_check"

null value in column "id" violates not-null constraint

This library attempts to parse those error messages and return error messages that you can expose via your API.

No id was provided. Please provide a id

Cannot write a negative balance

Invalid input syntax for type uuid: "foo"

Invalid account_status: "blah"

Can't save to payments because the account_id (91f47e99-d616-4d8c-9c02-cbd13bceac60) isn't present in the accounts table

A email already exists with this value (test@example.com)

In addition, this library exports common Postgres error codes, so you can check against them in your application.

Basic Usage

import dberror "github.com/Shyp/go-dberror"

func main() {
	_, err := db.Exec("INSERT INTO accounts (id) VALUES (null)")
	dberr := dberror.GetError(err)
	switch e := dberr.(type) {
	case *dberror.Error:
		fmt.Println(e.Error()) // "No id was provided. Please provide a id"
	default:
		// not a pq error
}
Database Constraints

Failed check constraints are tricky - the native error messages just say "failed", and don't reference a column.

So you can define your own constraint handlers, and then register them:

import dberror "github.com/Shyp/go-dberror"
import "github.com/lib/pq"

func init()
	constraint := &dberror.Constraint{
		Name: "accounts_balance_check",
		GetError: func(e *pq.Error) *dberror.Error {
			return &dberror.Error{
				Message:  "Cannot write a negative balance",
				Severity: e.Severity,
				Table:    e.Table,
				Detail:   e.Detail,
				Code:     string(e.Code),
			}
		},
	}
	dberror.RegisterConstraint(constraint)

	// test.AssertEquals(t, e.Error(), "Cannot write a negative balance")
}

If we get a constraint failure, we'll call your GetError handler, to get a well-formatted message.

Documentation

Index

Examples

Constants

View Source
const (
	CodeNumericValueOutOfRange    = "22003"
	CodeInvalidTextRepresentation = "22P02"
	CodeNotNullViolation          = "23502"
	CodeForeignKeyViolation       = "23503"
	CodeUniqueViolation           = "23505"
	CodeCheckViolation            = "23514"
	CodeLockNotAvailable          = "55P03"
)

See http://www.postgresql.org/docs/9.3/static/errcodes-appendix.html for a full listing of the error codes present here.

Variables

This section is empty.

Functions

func GetError

func GetError(err error) error

GetError parses a given database error and returns a human-readable version of that error. If the error is unknown, it's returned as is, however, all errors of type `pq.Error` are re-thrown as an Error, so it's impossible to get a `pq.Error` back from this function.

func RegisterConstraint

func RegisterConstraint(c *Constraint)

RegisterConstraint tells dberror about your custom constraint and its error handling. RegisterConstraint panics if you attempt to register two constraints with the same name.

Example
package main

import (
	dberror "github.com/Shyp/go-dberror"
	"github.com/lib/pq"
)

func main() {
	constraint := &dberror.Constraint{
		Name: "accounts_balance_check",
		GetError: func(e *pq.Error) *dberror.Error {
			return &dberror.Error{
				Message:  "Cannot write a negative balance",
				Severity: e.Severity,
				Table:    e.Table,
				Detail:   e.Detail,
				Code:     string(e.Code),
			}
		},
	}
	dberror.RegisterConstraint(constraint)
}
Output:

Types

type Constraint

type Constraint struct {
	Name     string
	GetError func(*pq.Error) *Error
}

Constraint is a custom database check constraint you've defined, like "CHECK balance > 0". Postgres doesn't define a very useful message for constraint failures (new row for relation "accounts" violates check constraint), so you can define your own. The Name should be the name of the constraint in the database. Define GetError to provide your own custom error handler for this constraint failure, with a custom message.

type Error

type Error struct {
	Message    string
	Code       string
	Constraint string
	Severity   string
	Routine    string
	Table      string
	Detail     string
	Column     string
}

Error is a human-readable database error. Message should always be a non-empty, readable string, and is returned when you call err.Error(). The other fields may or may not be empty.

func (*Error) Error

func (dbe *Error) Error() string

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL