This repository has been archived by the owner on Oct 9, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 63
/
postgres.go
95 lines (85 loc) · 3.41 KB
/
postgres.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
// Postgres-specific implementation of an ErrorTransformer.
// This errors utility translates postgres application error codes into internal error types.
// The go postgres driver defines possible error codes here: https://github.com/lib/pq/blob/master/error.go
// And the postgres standard defines error responses here:
// https://www.postgresql.org/docs/current/static/protocol-error-fields.html
// Inspired by https://www.codementor.io/tamizhvendan/managing-data-in-golang-using-gorm-part-1-a9cdjb8nb
package errors
import (
"fmt"
"github.com/flyteorg/flytestdlib/promutils"
"github.com/prometheus/client_golang/prometheus"
"github.com/flyteorg/flyteadmin/pkg/errors"
"github.com/jinzhu/gorm"
"github.com/lib/pq"
"google.golang.org/grpc/codes"
)
// Postgres error codes
const (
uniqueConstraintViolationCode = "23505"
undefinedTable = "42P01"
)
// Error message format strings
const (
unexpectedType = "unexpected error type for: %v"
uniqueConstraintViolation = "value with matching %s already exists (%s)"
defaultPgError = "failed database operation with %s"
unsupportedTableOperation = "cannot query with specified table attributes: %s"
)
type postgresErrorTransformerMetrics struct {
Scope promutils.Scope
NotFound prometheus.Counter
GormError prometheus.Counter
AlreadyExistsError prometheus.Counter
UndefinedTable prometheus.Counter
PostgresError prometheus.Counter
}
type postgresErrorTransformer struct {
metrics postgresErrorTransformerMetrics
}
func (p *postgresErrorTransformer) fromGormError(err error) errors.FlyteAdminError {
switch err.Error() {
case gorm.ErrRecordNotFound.Error():
p.metrics.NotFound.Inc()
return errors.NewFlyteAdminErrorf(codes.NotFound, "entry not found")
// If we want to intercept other gorm errors, add additional case statements here.
default:
p.metrics.GormError.Inc()
return errors.NewFlyteAdminErrorf(codes.Internal, unexpectedType, err)
}
}
func (p *postgresErrorTransformer) ToFlyteAdminError(err error) errors.FlyteAdminError {
pqError, ok := err.(*pq.Error)
if !ok {
return p.fromGormError(err)
}
switch pqError.Code {
case uniqueConstraintViolationCode:
p.metrics.AlreadyExistsError.Inc()
return errors.NewFlyteAdminErrorf(codes.AlreadyExists, uniqueConstraintViolation, pqError.Constraint, pqError.Message)
case undefinedTable:
p.metrics.UndefinedTable.Inc()
return errors.NewFlyteAdminErrorf(codes.InvalidArgument, unsupportedTableOperation, pqError.Message)
default:
p.metrics.PostgresError.Inc()
return errors.NewFlyteAdminError(codes.Unknown, fmt.Sprintf(defaultPgError, pqError.Message))
}
}
func NewPostgresErrorTransformer(scope promutils.Scope) ErrorTransformer {
metrics := postgresErrorTransformerMetrics{
Scope: scope,
NotFound: scope.MustNewCounter("not_found",
"count of all queries for entities not found in the database"),
GormError: scope.MustNewCounter("gorm_error",
"unspecified gorm error returned by database operation"),
AlreadyExistsError: scope.MustNewCounter("already_exists",
"counts for when a unique constraint was violated in a database operation"),
UndefinedTable: scope.MustNewCounter("undefined_table",
"database operations referencing an undefined table"),
PostgresError: scope.MustNewCounter("postgres_error",
"unspecified postgres error returned in a database operation"),
}
return &postgresErrorTransformer{
metrics: metrics,
}
}