Skip to content

Commit

Permalink
refactor: remove the custom ErrDBUniqueConstraint error (#197)
Browse files Browse the repository at this point in the history
Remove common.ErrDBUniqueConstraint, which was used as a workaround
for the lack of abstraction in gorm.

With the update in go-gorm/gorm#6004 we can now
fully use gorm for db related errors (fe. gorm.ErrDuplicatedKey).
  • Loading branch information
bfabio committed Jun 17, 2023
1 parent fa37c16 commit 60d2758
Show file tree
Hide file tree
Showing 8 changed files with 58 additions and 136 deletions.
43 changes: 19 additions & 24 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@ require (
github.com/go-testfixtures/testfixtures/v3 v3.8.0
github.com/gofiber/contrib/paseto v0.0.0-20220621082844-83549332c36e
github.com/gofiber/fiber/v2 v2.46.0
github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa
github.com/stretchr/testify v1.7.5
gorm.io/driver/postgres v1.3.7
gorm.io/driver/sqlite v1.4.3
gorm.io/gorm v1.24.1
github.com/stretchr/testify v1.8.1
gorm.io/driver/postgres v1.5.2
gorm.io/driver/sqlite v1.5.2
gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55
)

require (
Expand All @@ -26,21 +25,14 @@ require (
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/gofiber/adaptor/v2 v2.1.25 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.18 // indirect
github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/mattn/go-sqlite3 v1.14.16 // indirect
github.com/jackc/pgx/v5 v5.3.1 // indirect
github.com/mattn/go-sqlite3 v1.14.17 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/philhofer/fwd v1.1.2 // indirect
github.com/prometheus/client_golang v1.12.2 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.32.1 // indirect
github.com/prometheus/procfs v0.7.3 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94 // indirect
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect
github.com/tinylib/msgp v1.1.8 // indirect
golang.org/x/net v0.8.0 // indirect
golang.org/x/net v0.9.0 // indirect
google.golang.org/protobuf v1.26.0 // indirect
)

Expand All @@ -59,25 +51,28 @@ require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-playground/locales v0.14.0 // indirect
github.com/go-playground/universal-translator v0.18.0 // indirect
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
github.com/jackc/pgconn v1.12.1
github.com/jackc/pgio v1.0.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgproto3/v2 v2.3.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect
github.com/jackc/pgtype v1.11.0 // indirect
github.com/jackc/pgx/v4 v4.16.1 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/klauspost/compress v1.16.3 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
github.com/lib/pq v1.10.9 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.18 // indirect
github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/philhofer/fwd v1.1.2 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94 // indirect
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect
github.com/tinylib/msgp v1.1.8 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.47.0 // indirect
github.com/valyala/tcplisten v1.0.0 // indirect
golang.org/x/crypto v0.7.0 // indirect
golang.org/x/crypto v0.8.0 // indirect
golang.org/x/sys v0.8.0 // indirect
golang.org/x/text v0.8.0 // indirect
golang.org/x/text v0.9.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
94 changes: 26 additions & 68 deletions go.sum

Large diffs are not rendered by default.

3 changes: 0 additions & 3 deletions internal/common/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@ var (
ErrAuthentication = errors.New("token authentication failed")
ErrInvalidDateTime = errors.New("invalid date time format (RFC 3339 needed)")
ErrKeyLen = errors.New("PASETO_KEY must be 32 bytes long once base64-decoded")

ErrDBUniqueConstraint = errors.New("db constraint violation")
ErrDBRecordNotFound = errors.New("record not found")
)

func Error(status int, title string, detail string) ProblemJSONError {
Expand Down
28 changes: 0 additions & 28 deletions internal/database/database.go
Original file line number Diff line number Diff line change
@@ -1,21 +1,12 @@
package database

import (
"errors"
"log"
"strings"

"github.com/jackc/pgconn"

"github.com/italia/developers-italia-api/internal/common"
"github.com/jackc/pgerrcode"
"gorm.io/gorm"
)

const (
uniqueConstraintFailedErrorSQLite = "UNIQUE constraint failed"
)

type Database interface {
Init(dsn string) (*gorm.DB, error)
}
Expand All @@ -36,22 +27,3 @@ func NewDatabase(env common.Environment) Database {
dsn: env.Database,
}
}

//nolint:errorlint
func WrapErrors(dbError error) error {
if strings.Contains(dbError.Error(), uniqueConstraintFailedErrorSQLite) {
return common.ErrDBUniqueConstraint
}

if e, ok := dbError.(*pgconn.PgError); ok {
if e.Code == pgerrcode.UniqueViolation {
return common.ErrDBUniqueConstraint
}
}

if errors.Is(dbError, gorm.ErrRecordNotFound) {
return common.ErrDBRecordNotFound
}

return dbError
}
3 changes: 2 additions & 1 deletion internal/database/postgres_database.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ func (d *PostgresDB) Init(dsn string) (*gorm.DB, error) {
var err error

database, err := gorm.Open(postgres.Open(dsn), &gorm.Config{
PrepareStmt: true,
TranslateError: true,
PrepareStmt: true,
// Disable logging in production
Logger: logger.Default.LogMode(logger.Silent),
})
Expand Down
2 changes: 1 addition & 1 deletion internal/database/sqlite_database.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ type SQLiteDB struct {
func (d *SQLiteDB) Init(dsn string) (*gorm.DB, error) {
var err error

database, err := gorm.Open(sqlite.Open(dsn), &gorm.Config{})
database, err := gorm.Open(sqlite.Open(dsn), &gorm.Config{TranslateError: true})
if err != nil {
return nil, fmt.Errorf("can't open database: %w", err)
}
Expand Down
7 changes: 3 additions & 4 deletions internal/handlers/publishers.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"net/url"
"sort"

"github.com/italia/developers-italia-api/internal/database"
"golang.org/x/exp/slices"

"github.com/italia/developers-italia-api/internal/handlers/general"
Expand Down Expand Up @@ -135,12 +134,12 @@ func (p *Publisher) PostPublisher(ctx *fiber.Ctx) error {
}

if err := p.db.Create(&publisher).Error; err != nil {
switch database.WrapErrors(err) { //nolint:errorlint
case common.ErrDBRecordNotFound:
switch {
case errors.Is(err, gorm.ErrRecordNotFound):
return common.Error(fiber.StatusNotFound,
"can't create Publisher",
"Publisher was not found")
case common.ErrDBUniqueConstraint:
case errors.Is(err, gorm.ErrDuplicatedKey):
return common.Error(fiber.StatusConflict,
"can't create Publisher",
"description, alternativeId or codeHosting URL already exists")
Expand Down
14 changes: 7 additions & 7 deletions internal/models/models_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func init() {
// TODO: investigate the root cause
sqlitedb.Exec("PRAGMA journal_mode=WAL;")

db, err = gorm.Open(sqlite.Open(dsn), &gorm.Config{})
db, err = gorm.Open(sqlite.Open(dsn), &gorm.Config{TranslateError: true})
if err != nil {
log.Fatal(err)
}
Expand Down Expand Up @@ -93,7 +93,7 @@ func TestSoftwareCreate(t *testing.T) {
PubliccodeYml: "-",
},
).Error
assert.EqualError(t, err, "UNIQUE constraint failed: software.software_url_id")
assert.ErrorIs(t, err, gorm.ErrDuplicatedKey)
}

func TestSoftwareURLCreate(t *testing.T) {
Expand All @@ -117,7 +117,7 @@ func TestSoftwareURLCreate(t *testing.T) {
URL: "https://new-2.example.org",
},
).Error
assert.EqualError(t, err, "UNIQUE constraint failed: software_urls.id")
assert.ErrorIs(t, err, gorm.ErrDuplicatedKey)
}

func TestPublisherCreate(t *testing.T) {
Expand All @@ -144,7 +144,7 @@ func TestPublisherCreate(t *testing.T) {
Email: &email,
},
).Error
assert.EqualError(t, err, "UNIQUE constraint failed: publishers.description")
assert.ErrorIs(t, err, gorm.ErrDuplicatedKey)

// Duplicate alternativeId
alternativeID := "alternative-id-12345"
Expand All @@ -155,7 +155,7 @@ func TestPublisherCreate(t *testing.T) {
AlternativeID: &alternativeID,
},
).Error
assert.EqualError(t, err, "UNIQUE constraint failed: publishers.alternative_id")
assert.ErrorIs(t, err, gorm.ErrDuplicatedKey)
}

func TestWebhookCreate(t *testing.T) {
Expand All @@ -181,7 +181,7 @@ func TestWebhookCreate(t *testing.T) {
URL: "https://new-webhook-2.example.org",
},
).Error
assert.EqualError(t, err, "UNIQUE constraint failed: webhooks.id")
assert.ErrorIs(t, err, gorm.ErrDuplicatedKey)
}

func TestEventCreate(t *testing.T) {
Expand All @@ -207,5 +207,5 @@ func TestEventCreate(t *testing.T) {
EntityType: "software",
},
).Error
assert.EqualError(t, err, "UNIQUE constraint failed: events.id")
assert.ErrorIs(t, err, gorm.ErrDuplicatedKey)
}

0 comments on commit 60d2758

Please sign in to comment.