...
1 package sqlcon
2
3 import (
4 "database/sql"
5 "net/http"
6 "strings"
7
8 "google.golang.org/grpc/codes"
9
10 "github.com/go-sql-driver/mysql"
11 "github.com/jackc/pgconn"
12 "github.com/lib/pq"
13 "github.com/pkg/errors"
14
15 "github.com/ory/herodot"
16
17 "github.com/ory/x/errorsx"
18 )
19
20 var (
21
22 ErrUniqueViolation = &herodot.DefaultError{
23 CodeField: http.StatusConflict,
24 GRPCCodeField: codes.AlreadyExists,
25 StatusField: http.StatusText(http.StatusConflict),
26 ErrorField: "Unable to insert or update resource because a resource with that value exists already",
27 }
28
29 ErrNoRows = &herodot.DefaultError{
30 CodeField: http.StatusNotFound,
31 GRPCCodeField: codes.NotFound,
32 StatusField: http.StatusText(http.StatusNotFound),
33 ErrorField: "Unable to locate the resource",
34 }
35
36 ErrConcurrentUpdate = &herodot.DefaultError{
37 CodeField: http.StatusBadRequest,
38 GRPCCodeField: codes.Aborted,
39 StatusField: http.StatusText(http.StatusBadRequest),
40 ErrorField: "Unable to serialize access due to a concurrent update in another session",
41 }
42 )
43
44
45 func HandleError(err error) error {
46 if err == nil {
47 return nil
48 }
49
50 if errors.Is(err, sql.ErrNoRows) {
51 return errors.WithStack(ErrNoRows)
52 }
53
54 switch e := errorsx.Cause(err).(type) {
55 case interface{ SQLState() string }:
56 switch e.SQLState() {
57 case "23505":
58 return errors.Wrap(ErrUniqueViolation, err.Error())
59 case "40001":
60 return errors.Wrap(ErrConcurrentUpdate, err.Error())
61 }
62 case *pq.Error:
63 switch e.Code {
64 case "23505":
65 return errors.Wrap(ErrUniqueViolation, e.Error())
66 case "40001":
67 return errors.Wrap(ErrConcurrentUpdate, e.Error())
68 }
69 case *mysql.MySQLError:
70 switch e.Number {
71 case 1062:
72 return errors.Wrap(ErrUniqueViolation, err.Error())
73 }
74 case *pgconn.PgError:
75 switch e.Code {
76 case "23505":
77 return errors.Wrap(ErrUniqueViolation, e.Error())
78 case "40001":
79 return errors.Wrap(ErrConcurrentUpdate, e.Error())
80 }
81 }
82
83
84 if strings.Contains(err.Error(), "UNIQUE constraint failed") {
85 return errors.Wrap(ErrUniqueViolation, err.Error())
86 }
87
88 return errors.WithStack(err)
89 }
90
View as plain text