1
0
Fork 0

feat(training): add Repository.FindBySlug() method

This commit is contained in:
Vojtěch Mareš 2024-06-27 09:07:33 +02:00
parent fe38dd6683
commit e0594892d5
Signed by: vojtech.mares
GPG key ID: C6827B976F17240D
4 changed files with 84 additions and 8 deletions

View file

@ -3,7 +3,8 @@ package training
import "errors"
var (
ErrTrainingNotFound = errors.New("training not found")
ErrTrainingDateNotFound = errors.New("training date not found")
ErrTrainingDateAttendeeNotFound = errors.New("training date attendee not found")
ErrTrainingNotFound = errors.New("training not found")
ErrTrainingDateNotFound = errors.New("training date not found")
ErrTrainingDateAttendeeNotFound = errors.New("training date attendee not found")
ErrTrainingWithSlugAlreadyExists = errors.New("training with slug already exists")
)

View file

@ -8,6 +8,7 @@ import (
type InMemoryTrainingRepository struct {
trainings map[ID]Training
slugToID map[string]ID
lock sync.RWMutex
ai int
}
@ -15,6 +16,7 @@ type InMemoryTrainingRepository struct {
func NewInMemoryTrainingRepository() *InMemoryTrainingRepository {
return &InMemoryTrainingRepository{
trainings: make(map[ID]Training),
slugToID: make(map[string]ID),
ai: 1,
}
}
@ -35,7 +37,12 @@ func (r *InMemoryTrainingRepository) Create(training *Training) error {
}
}
if _, ok := r.slugToID[training.Slug]; ok {
return ErrTrainingWithSlugAlreadyExists
}
r.trainings[training.ID] = *training
r.slugToID[training.Slug] = training.ID
return nil
}
@ -50,6 +57,18 @@ func (r *InMemoryTrainingRepository) FindByID(id ID) (*Training, error) {
return &training, nil
}
func (r *InMemoryTrainingRepository) FindBySlug(slug string) (*Training, error) {
r.lock.RLock()
defer r.lock.RUnlock()
id, ok := r.slugToID[slug]
if !ok {
return nil, ErrTrainingNotFound
}
return r.FindByID(id)
}
func (r *InMemoryTrainingRepository) FindAll() ([]Training, error) {
r.lock.RLock()
defer r.lock.RUnlock()
@ -74,7 +93,16 @@ func (r *InMemoryTrainingRepository) Update(training *Training) error {
}
}
if _, ok := r.slugToID[training.Slug]; ok {
return ErrTrainingWithSlugAlreadyExists
}
r.trainings[training.ID] = *training
if r.trainings[training.ID].Slug != training.Slug {
delete(r.slugToID, r.trainings[training.ID].Slug)
r.slugToID[training.Slug] = training.ID
}
return nil
}
@ -87,6 +115,7 @@ func (r *InMemoryTrainingRepository) Delete(id ID) error {
return ErrTrainingNotFound
}
delete(r.slugToID, r.trainings[id].Slug)
delete(r.trainings, id)
return nil
}

View file

@ -4,7 +4,7 @@ import (
"context"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgxpool"
"gitlab.mareshq.com/hq/yggdrasil/pkg/slug"
slugpkg "gitlab.mareshq.com/hq/yggdrasil/pkg/slug"
"time"
)
@ -21,7 +21,7 @@ func (r *PostgresTrainingRepository) Create(training *Training) error {
defer cancel()
if training.Slug == "" {
training.Slug = slug.NewString(training.Name)
training.Slug = slugpkg.NewString(training.Name)
}
tx, txErr := r.pg.Begin(ctx)
@ -77,7 +77,7 @@ func (r *PostgresTrainingRepository) FindByID(id ID) (*Training, error) {
var training Training
err := r.pg.QueryRow(ctx, `
SELECT id, name, description, days
SELECT id, name, slug, description, days
FROM training.trainings
WHERE id = $1
`, id).Scan(&training.ID, &training.Name, &training.Slug, &training.Description, &training.Days)
@ -112,6 +112,51 @@ func (r *PostgresTrainingRepository) FindByID(id ID) (*Training, error) {
return &training, nil
}
func (r *PostgresTrainingRepository) FindBySlug(slug string) (*Training, error) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := slugpkg.Validate(slug); err != nil {
return nil, ErrTrainingNotFound
}
var training Training
err := r.pg.QueryRow(ctx, `
SELECT id, name, slug, description, days
FROM training.trainings
WHERE slug = $1
`, slug).Scan(&training.ID, &training.Name, &training.Slug, &training.Description, &training.Days)
if err != nil {
return nil, err
}
rows, err := r.pg.Query(ctx, `
SELECT amount, currency, type
FROM training.prices
WHERE training_id = $1
`, training.ID)
if err != nil {
return nil, err
}
defer rows.Close()
training.Pricing = make([]Price, 0)
training.Pricing, err = pgx.CollectRows[Price](rows, func(row pgx.CollectableRow) (Price, error) {
var price Price
err := row.Scan(&price.Amount, &price.Currency, &price.Type)
if err != nil {
return Price{}, err
}
return price, nil
})
if err != nil {
return nil, err
}
return &training, nil
}
func (r *PostgresTrainingRepository) FindAll() ([]Training, error) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
@ -157,9 +202,9 @@ func (r *PostgresTrainingRepository) Update(training *Training) error {
defer cancel()
if training.Slug == "" {
training.Slug = slug.NewString(training.Name)
training.Slug = slugpkg.NewString(training.Name)
} else {
slugValidateErr := slug.Validate(training.Slug)
slugValidateErr := slugpkg.Validate(training.Slug)
if slugValidateErr != nil {
return slugValidateErr
}

View file

@ -3,6 +3,7 @@ package training
type Repository interface {
Create(training *Training) error
FindByID(id ID) (*Training, error)
FindBySlug(slug string) (*Training, error)
FindAll() ([]Training, error)
Update(training *Training) error
Delete(id ID) error