Skip to content

Commit

Permalink
feat: add postgres repository
Browse files Browse the repository at this point in the history
  • Loading branch information
mgjules committed May 18, 2022
1 parent 2b90ceb commit 3360fbf
Show file tree
Hide file tree
Showing 7 changed files with 324 additions and 17 deletions.
4 changes: 4 additions & 0 deletions cmd/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ var serve = &cli.Command{
return fmt.Errorf("new repository: %w", err)
}

if err := repository.Migrate(c.Context); err != nil {
return fmt.Errorf("migrate repository: %w", err)
}

var httpServer *http.Server
httpEnabled := c.Bool("http")
if httpEnabled {
Expand Down
26 changes: 19 additions & 7 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ require (
github.com/gin-gonic/gin v1.7.7
github.com/imdario/mergo v0.3.12
github.com/json-iterator/go v1.1.12
github.com/lib/pq v1.10.4
github.com/magefile/mage v1.13.0
github.com/onsi/ginkgo/v2 v2.1.4
github.com/onsi/gomega v1.19.0
Expand All @@ -17,6 +18,8 @@ require (
go.uber.org/zap v1.21.0
google.golang.org/grpc v1.46.2
google.golang.org/protobuf v1.28.0
gorm.io/driver/postgres v1.3.5
gorm.io/gorm v1.23.5
)

require (
Expand All @@ -30,29 +33,38 @@ require (
github.com/go-openapi/jsonreference v0.19.6 // indirect
github.com/go-openapi/spec v0.20.4 // indirect
github.com/go-openapi/swag v0.19.15 // indirect
github.com/go-playground/locales v0.13.0 // indirect
github.com/go-playground/universal-translator v0.17.0 // indirect
github.com/go-playground/validator/v10 v10.4.1 // indirect
github.com/go-playground/locales v0.14.0 // indirect
github.com/go-playground/universal-translator v0.18.0 // indirect
github.com/go-playground/validator/v10 v10.9.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/go-cmp v0.5.7 // indirect
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
github.com/jackc/pgconn v1.12.1 // indirect
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/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-isatty v0.0.12 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/stretchr/testify v1.7.1 // indirect
github.com/ugorji/go/codec v1.2.4 // indirect
github.com/ugorji/go/codec v1.2.6 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.8.0 // indirect
golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29 // indirect
golang.org/x/crypto v0.0.0-20220518034528-6f7dac969898 // indirect
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 // indirect
golang.org/x/sys v0.0.0-20220330033206-e17cdc41300f // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/tools v0.1.10 // indirect
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)
173 changes: 163 additions & 10 deletions go.sum

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions repo/inmemory/inmemory.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,10 @@ func (r *Repository) Save(_ context.Context, d *deck.Deck) error {

return nil
}

// Migrate migrates the deck model.
func (r *Repository) Migrate(_ context.Context) error {
r.log.Debug("in-memory repository does not need migration")

return nil
}
46 changes: 46 additions & 0 deletions repo/postgres/deck.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package postgres

import (
"fmt"

"github.com/lib/pq"
"github.com/mgjules/deckr/deck"
"gorm.io/gorm"
)

// Deck represents a deck of cards.
type Deck struct {
gorm.Model
ID string `gorm:"primaryKey"`
Shuffled bool
Composition string `gorm:"type:varchar(64)"`
Codes pq.StringArray `gorm:"type:varchar(3)[]"`
}

// DomainDeckToDeck transforms a domain deck to a repo deck.
func DomainDeckToDeck(d *deck.Deck) *Deck {
var rd Deck
rd.ID = d.ID()
rd.Shuffled = d.IsShuffled()
rd.Composition = d.Composition()
for _, card := range d.Cards() {
rd.Codes = append(rd.Codes, card.Code().String())
}

return &rd
}

// DeckToDomainDeck transforms a repo deck to a domain deck.
func DeckToDomainDeck(rd *Deck) (*deck.Deck, error) {
d, err := deck.New(
deck.WithID(rd.ID),
deck.WithShuffled(rd.Shuffled),
deck.WithComposition(rd.Composition),
deck.WithCodes(rd.Codes...),
)
if err != nil {
return nil, fmt.Errorf("new deck: %w", err)
}

return d, nil
}
76 changes: 76 additions & 0 deletions repo/postgres/postgres.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package postgres

import (
"context"
"errors"
"fmt"

"github.com/mgjules/deckr/deck"
"github.com/mgjules/deckr/logger"
"gorm.io/driver/postgres"
"gorm.io/gorm"
)

// ErrDeckNotFound is the error returned when a deck is not found.
var ErrDeckNotFound = errors.New("deck not found")

// Repository is a PostgreSQL implementation of the deckr.Repository interface.
type Repository struct {
log *logger.Logger
db *gorm.DB
}

// NewRepository creates a new PostgreSQL repository.
func NewRepository(uri string, log *logger.Logger) (*Repository, error) {
db, err := gorm.Open(postgres.New(postgres.Config{
DSN: uri,
}))
if err != nil {
return nil, fmt.Errorf("open postgres connection: %w", err)
}

return &Repository{
log: log,
db: db,
}, nil
}

// Get returns the deck with the given id.
func (r *Repository) Get(_ context.Context, id string) (*deck.Deck, error) {
var saved Deck

if err := r.db.First(&saved, id); err != nil {
return nil, fmt.Errorf("deck '%s': %w", id, ErrDeckNotFound)
}

d, err := DeckToDomainDeck(&saved)
if err != nil {
return nil, fmt.Errorf("deck '%s': %w", id, err)
}

r.log.Debugf("get deck '%s'", d.ID)

return d, nil
}

// Save saves the given deck.
func (r *Repository) Save(_ context.Context, d *deck.Deck) error {
save := DomainDeckToDeck(d)

r.db.Save(save)

r.log.Debugf("saved deck '%s'", save.ID)

return nil
}

// Migrate migratess the deck model.
func (r *Repository) Migrate(_ context.Context) error {
if err := r.db.AutoMigrate(&Deck{}); err != nil {
return fmt.Errorf("migrate deck model: %w", err)
}

r.log.Debug("migrated deck model")

return nil
}
9 changes: 9 additions & 0 deletions repo/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ import (
"github.com/mgjules/deckr/deck"
"github.com/mgjules/deckr/logger"
"github.com/mgjules/deckr/repo/inmemory"
"github.com/mgjules/deckr/repo/postgres"
)

// Repository is an interface to get and save a deck.
type Repository interface {
Get(context.Context, string) (*deck.Deck, error)
Save(context.Context, *deck.Deck) error
Migrate(context.Context) error
}

// NewRepository returns a new repository.
Expand All @@ -26,6 +28,13 @@ func NewRepository(uri string, log *logger.Logger) (Repository, error) {
switch u.Scheme {
case "inmemory":
return inmemory.NewRepository(log), nil
case "postgres":
repo, err := postgres.NewRepository(uri, log)
if err != nil {
return nil, fmt.Errorf("new postgres repository: %w", err)
}

return repo, nil
default:
return nil, fmt.Errorf("unknown repository URI scheme: %s", u.Scheme)
}
Expand Down

0 comments on commit 3360fbf

Please sign in to comment.