Skip to content

Commit

Permalink
Merge pull request #7 from GenesisEducationKyiv/hw9-saga
Browse files Browse the repository at this point in the history
  • Loading branch information
vladyslavpavlenko authored Jul 18, 2024
2 parents 4c5e719 + 17078b1 commit 851274e
Show file tree
Hide file tree
Showing 17 changed files with 347 additions and 129 deletions.
2 changes: 0 additions & 2 deletions .github/workflows/golangci-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ name: Lint

on:
push:
branches:
- main
pull_request:
branches:
- main
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ require (
github.com/go-chi/chi v1.5.5
github.com/go-chi/chi/v5 v5.0.12
github.com/golang/mock v1.6.0
github.com/google/uuid v1.6.0
github.com/jackc/pgx/v5 v5.4.3
github.com/kelseyhightower/envconfig v1.4.0
github.com/pkg/errors v0.9.1
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+Licev
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/influxdata/tdigest v0.0.1 h1:XpFptwYmnEKUqmkcDjrzffswZ3nvNeevbUSLPP/ZzIY=
github.com/influxdata/tdigest v0.0.1/go.mod h1:Z0kXnxzbTC2qrx4NaIzYkE1k66+6oEDQTvL95hQFh5Y=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
Expand Down
34 changes: 20 additions & 14 deletions internal/app/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import (
"log"
"net/http"

"github.com/vladyslavpavlenko/genesis-api-project/internal/subscriber/gormsubscriber"

"github.com/vladyslavpavlenko/genesis-api-project/internal/storage/gormstorage"

notifierpkg "github.com/vladyslavpavlenko/genesis-api-project/internal/notifier"
"github.com/vladyslavpavlenko/genesis-api-project/internal/outbox/gormoutbox"
producerpkg "github.com/vladyslavpavlenko/genesis-api-project/internal/outbox/producer"
Expand All @@ -13,8 +17,6 @@ import (

"github.com/vladyslavpavlenko/genesis-api-project/internal/app/config"
"github.com/vladyslavpavlenko/genesis-api-project/internal/models"
"github.com/vladyslavpavlenko/genesis-api-project/internal/storage/gormrepo"

"github.com/vladyslavpavlenko/genesis-api-project/internal/rateapi"
"github.com/vladyslavpavlenko/genesis-api-project/internal/rateapi/chain"
"gopkg.in/gomail.v2"
Expand All @@ -36,11 +38,12 @@ type envVariables struct {
}

type services struct {
DBConn *gormrepo.Connection
Sender *email.GomailSender
Fetcher *chain.Node
Notifier *notifierpkg.Notifier
Outbox producerpkg.Outbox
DBConn *gormstorage.Connection
Sender *email.GomailSender
Fetcher *chain.Node
Notifier *notifierpkg.Notifier
Subscriber *gormsubscriber.Subscriber
Outbox producerpkg.Outbox
}

func setup(app *config.AppConfig) (*services, error) {
Expand Down Expand Up @@ -78,12 +81,15 @@ func setup(app *config.AppConfig) (*services, error) {
return nil, fmt.Errorf("failed to create outbox: %w", err)
}

notifier := notifierpkg.NewNotifier(dbConn, fetcher, outbox)
subscriber := gormsubscriber.NewSubscriber(dbConn.DB())

notifier := notifierpkg.NewNotifier(subscriber, fetcher, outbox)

repo := handlers.NewRepo(app, &handlers.Services{
Fetcher: fetcher,
Notifier: notifier,
}, dbConn)
Fetcher: fetcher,
Notifier: notifier,
Subscriber: subscriber,
})
handlers.NewHandlers(repo)

return &services{
Expand All @@ -105,8 +111,8 @@ func readEnv() (envVariables, error) {
}

// connectDB sets up a GORM database connection and returns an interface.
func connectDB(dsn string) (*gormrepo.Connection, error) {
var conn gormrepo.Connection
func connectDB(dsn string) (*gormstorage.Connection, error) {
var conn gormstorage.Connection

err := conn.Setup(dsn)
if err != nil {
Expand All @@ -117,7 +123,7 @@ func connectDB(dsn string) (*gormrepo.Connection, error) {
}

// migrateDB runs database migrations.
func migrateDB(conn *gormrepo.Connection) error {
func migrateDB(conn *gormstorage.Connection) error {
log.Println("Running migrations...")

err := conn.Migrate(&models.Subscription{}, &outboxpkg.Event{})
Expand Down
4 changes: 2 additions & 2 deletions internal/handlers/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func (m *Repository) Subscribe(w http.ResponseWriter, r *http.Request) {
return
}

err = m.DB.AddSubscription(email)
err = m.Services.Subscriber.AddSubscription(email)
if err != nil {
_ = jsonutils.ErrorJSON(w, err, http.StatusInternalServerError)
return
Expand All @@ -89,7 +89,7 @@ func (m *Repository) Unsubscribe(w http.ResponseWriter, r *http.Request) {
return
}

err = m.DB.DeleteSubscription(email)
err = m.Services.Subscriber.DeleteSubscription(email)
if err != nil {
_ = jsonutils.ErrorJSON(w, err, http.StatusInternalServerError)
return
Expand Down
13 changes: 6 additions & 7 deletions internal/handlers/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,19 @@ import (
type (
// Services is the repository type.
Services struct {
Fetcher rateapi.Fetcher
Notifier *notifier.Notifier
Fetcher rateapi.Fetcher
Notifier *notifier.Notifier
Subscriber subscriber
}

// Repository is the repository type
Repository struct {
App *config.AppConfig
DB dbConnection
Services *Services
}

// dbConnection defines an interface for the database connection.
dbConnection interface {
// subscriber defines an interface for managing subscriptions.
subscriber interface {
AddSubscription(emailAddr string) error
DeleteSubscription(emailAddr string) error
GetSubscriptions(limit, offset int) ([]models.Subscription, error)
Expand All @@ -33,10 +33,9 @@ type (
var Repo *Repository

// NewRepo creates a new Repository
func NewRepo(a *config.AppConfig, services *Services, conn dbConnection) *Repository {
func NewRepo(a *config.AppConfig, services *Services) *Repository {
return &Repository{
App: a,
DB: conn,
Services: services,
}
}
Expand Down
23 changes: 10 additions & 13 deletions internal/handlers/repository_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import (
"context"
"testing"

"github.com/vladyslavpavlenko/genesis-api-project/internal/storage/gormrepo"

"github.com/stretchr/testify/mock"
"github.com/vladyslavpavlenko/genesis-api-project/internal/email"
"github.com/vladyslavpavlenko/genesis-api-project/internal/models"
Expand All @@ -25,21 +23,21 @@ func (m *MockSender) Send(cfg email.Config, params email.Params) error {
return args.Error(0)
}

type MockDB struct {
type MockSubscriber struct {
mock.Mock
}

func (m *MockDB) GetSubscriptions(_, _ int) ([]models.Subscription, error) {
func (m *MockSubscriber) GetSubscriptions(_, _ int) ([]models.Subscription, error) {
args := m.Called()
return args.Get(0).([]models.Subscription), args.Error(1)
}

func (m *MockDB) AddSubscription(emailAddr string) error {
func (m *MockSubscriber) AddSubscription(emailAddr string) error {
args := m.Called(emailAddr)
return args.Error(0)
}

func (m *MockDB) DeleteSubscription(emailAddr string) error {
func (m *MockSubscriber) DeleteSubscription(emailAddr string) error {
args := m.Called(emailAddr)
return args.Error(0)
}
Expand All @@ -57,11 +55,10 @@ func (m *MockFetcher) Fetch(ctx context.Context, base, target string) (string, e
func TestNewRepo(t *testing.T) {
appConfig := &config.AppConfig{}
services := &handlers.Services{
Fetcher: &MockFetcher{},
Fetcher: &MockFetcher{},
Subscriber: &MockSubscriber{},
}
dbConn := &gormrepo.Connection{}

repo := handlers.NewRepo(appConfig, services, dbConn)
repo := handlers.NewRepo(appConfig, services)

assert.NotNil(t, repo)
assert.Equal(t, appConfig, repo.App)
Expand All @@ -72,11 +69,11 @@ func TestNewRepo(t *testing.T) {
func TestNewHandlers(t *testing.T) {
appConfig := &config.AppConfig{}
services := &handlers.Services{
Fetcher: &MockFetcher{},
Fetcher: &MockFetcher{},
Subscriber: &MockSubscriber{},
}
dbConn := &gormrepo.Connection{}

repo := handlers.NewRepo(appConfig, services, dbConn)
repo := handlers.NewRepo(appConfig, services)
handlers.NewHandlers(repo)

assert.Equal(t, repo, handlers.Repo)
Expand Down
20 changes: 10 additions & 10 deletions internal/notifier/notifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import (

const batchSize = 100

// dbConnection defines an interface for the database connection.
type dbConnection interface {
// subscriber defines an interface for managing subscribers.
type subscriber interface {
GetSubscriptions(limit, offset int) ([]models.Subscription, error)
}

Expand All @@ -28,17 +28,17 @@ type outbox interface {
}

type Notifier struct {
DB dbConnection
Fetcher fetcher
Outbox outbox
Subscriber subscriber
Fetcher fetcher
Outbox outbox
}

// NewNotifier creates a new Notifier.
func NewNotifier(db dbConnection, f fetcher, o outbox) *Notifier {
func NewNotifier(s subscriber, f fetcher, o outbox) *Notifier {
return &Notifier{
DB: db,
Fetcher: f,
Outbox: o,
Subscriber: s,
Fetcher: f,
Outbox: o,
}
}

Expand All @@ -57,7 +57,7 @@ func (n *Notifier) Start() error {
var offset int
errChan := make(chan error, 1)
for {
subscriptions, err := n.DB.GetSubscriptions(batchSize, offset)
subscriptions, err := n.Subscriber.GetSubscriptions(batchSize, offset)
if err != nil {
return err
}
Expand Down
69 changes: 0 additions & 69 deletions internal/storage/gormrepo/subscription.go

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package gormrepo
package gormstorage

import (
"context"
Expand All @@ -8,7 +8,7 @@ import (

// AddConsumedEvent creates a new consumer.ConsumedEvent record.
func (c *Connection) AddConsumedEvent(event consumer.ConsumedEvent) error {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), RequestTimeout)
defer cancel()

result := c.db.WithContext(ctx).Create(event)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package gormrepo
package gormstorage

import (
"context"
Expand All @@ -10,7 +10,7 @@ import (
"gorm.io/gorm"
)

const timeout = time.Second * 5
const RequestTimeout = time.Second * 5

type Connection struct {
db *gorm.DB
Expand Down Expand Up @@ -65,7 +65,7 @@ func (c *Connection) Close() error {

// Migrate performs a database migration for given models.
func (c *Connection) Migrate(models ...any) error {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), RequestTimeout)
defer cancel()

err := c.db.WithContext(ctx).AutoMigrate(models...)
Expand All @@ -78,7 +78,7 @@ func (c *Connection) Migrate(models ...any) error {

// BeginTransaction begins a transaction.
func (c *Connection) BeginTransaction() (*gorm.DB, error) {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
ctx, cancel := context.WithTimeout(context.Background(), RequestTimeout)
defer cancel()

tx := c.db.WithContext(ctx).Begin()
Expand Down
Loading

0 comments on commit 851274e

Please sign in to comment.