Skip to content

Instantly share code, notes, and snippets.

@steebchen
Created January 18, 2020 16:57
Show Gist options
  • Save steebchen/51ab929e04ae7436afca6b9d605e78f4 to your computer and use it in GitHub Desktop.
Save steebchen/51ab929e04ae7436afca6b9d605e78f4 to your computer and use it in GitHub Desktop.
Prisma Go database client error handling
package main
import (
"errors"
"fmt"
"log"
)
func main() {
// Since FindMany only reads data, there can be no expected errors. There may
// be unexpected errors such as that the database connection is lost, but this is
// a fatal error which doesn't make sense to be handled individually with `err != nil`
// because they don't provide any more value. Instead, if there's a fatal error, this
// method panics (which will be handled by your webserver to return a 500 code).
users := FindManyUsers()
log.Printf("users: %+v", users)
// FindOne with `ok`, since there would be one error of type ErrNotFound which is not really an error
user, ok := FindOneUser()
if !ok {
fmt.Printf("no user found")
}
log.Printf("%+v", user)
// ------------
// implementing errors
_, delErr := DeleteUser() // returns (User, error)
// the next line won't compile, because `delErr` does not satisfy the parameter
if v, ok := IsUniqueConstraintViolation(delErr); ok { // <- WON'T COMPILE!
// ^^^^^^
// Cannot use 'delErr' (type error) as type CanUniqueConstraintViolation
fmt.Printf("colum %s is not unique", v.Column)
}
// super nice error handling:
_, createErr := CreateUser()
// following line will compile, because `createErr` can have a unique constraint violation
if v, ok := IsUniqueConstraintViolation(createErr); ok {
// v is of type UserConstraintViolation, which contains details such as v.Column of type UniqueColumnUser so you can provide fine-grained error messages
switch v.Column {
case UniqueColumnUserEmail:
fmt.Printf("hey user, email %s is already taken!", v.Column)
default:
fmt.Printf("colum %s is not unique", v.Column)
}
} else {
fmt.Printf("unhandled error")
}
// ------------
// evolution of errors
// 1
var v *ErrUniqueConstraintViolation
if errors.As(createErr, v) {
fmt.Printf("err in column %s", v.Column)
}
// 2
if v := CheckUniqueConstraintViolation(); errors.As(createErr, v) {
fmt.Printf("colum %s is not unique", v.Column)
}
// 3
if v, ok := IsUniqueConstraintViolation(createErr); ok {
fmt.Printf("colum %s is not unique", v.Column)
}
}
func CheckUniqueConstraintViolation() *ErrUniqueConstraintViolation {
return &ErrUniqueConstraintViolation{}
}
type UniqueColumnUser string
const (
UniqueColumnUserID UniqueColumnUser = "id"
UniqueColumnUserEmail UniqueColumnUser = "email"
)
type ErrUniqueConstraintViolation struct {
Column UniqueColumnUser
}
func (e ErrUniqueConstraintViolation) Error() string {
return fmt.Sprintf("unique constraint violated for field %s", e.Column)
}
func IsUniqueConstraintViolation(err CanUniqueConstraintViolation) (*ErrUniqueConstraintViolation, bool) {
var v *ErrUniqueConstraintViolation
if errors.As(err, v) {
fmt.Printf("err in column %s", v.Column)
return v, true
}
return nil, false
}
type CanUniqueConstraintViolation interface {
Error() string
CanUniqueConstraintViolation()
}
type UserCreateError interface {
Error() string
CanUniqueConstraintViolation()
}
type userError struct{}
func (userError) Error() string {
return "stuff"
}
func (userError) CanUniqueConstraintViolation() {}
func CreateUser() (User, UserCreateError) {
return User{}, &userError{}
}
func DeleteUser() (User, error) {
return User{}, errors.New("x")
}
func FindOneUser() (User, bool) {
return User{}, true
}
func FindManyUsers() []User {
return []User{}
}
type User struct {
Name string
}
@steebchen
Copy link
Author

photo_2020-01-18 17 57 03

photo_2020-01-18 17 57 05

photo_2020-01-18 17 57 06

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment