feat(training): add Repository.FindBySlug() method
This commit is contained in:
parent
fe38dd6683
commit
e0594892d5
4 changed files with 84 additions and 8 deletions
|
|
@ -6,4 +6,5 @@ var (
|
||||||
ErrTrainingNotFound = errors.New("training not found")
|
ErrTrainingNotFound = errors.New("training not found")
|
||||||
ErrTrainingDateNotFound = errors.New("training date not found")
|
ErrTrainingDateNotFound = errors.New("training date not found")
|
||||||
ErrTrainingDateAttendeeNotFound = errors.New("training date attendee not found")
|
ErrTrainingDateAttendeeNotFound = errors.New("training date attendee not found")
|
||||||
|
ErrTrainingWithSlugAlreadyExists = errors.New("training with slug already exists")
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import (
|
||||||
|
|
||||||
type InMemoryTrainingRepository struct {
|
type InMemoryTrainingRepository struct {
|
||||||
trainings map[ID]Training
|
trainings map[ID]Training
|
||||||
|
slugToID map[string]ID
|
||||||
lock sync.RWMutex
|
lock sync.RWMutex
|
||||||
ai int
|
ai int
|
||||||
}
|
}
|
||||||
|
|
@ -15,6 +16,7 @@ type InMemoryTrainingRepository struct {
|
||||||
func NewInMemoryTrainingRepository() *InMemoryTrainingRepository {
|
func NewInMemoryTrainingRepository() *InMemoryTrainingRepository {
|
||||||
return &InMemoryTrainingRepository{
|
return &InMemoryTrainingRepository{
|
||||||
trainings: make(map[ID]Training),
|
trainings: make(map[ID]Training),
|
||||||
|
slugToID: make(map[string]ID),
|
||||||
ai: 1,
|
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.trainings[training.ID] = *training
|
||||||
|
r.slugToID[training.Slug] = training.ID
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -50,6 +57,18 @@ func (r *InMemoryTrainingRepository) FindByID(id ID) (*Training, error) {
|
||||||
return &training, nil
|
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) {
|
func (r *InMemoryTrainingRepository) FindAll() ([]Training, error) {
|
||||||
r.lock.RLock()
|
r.lock.RLock()
|
||||||
defer r.lock.RUnlock()
|
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
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -87,6 +115,7 @@ func (r *InMemoryTrainingRepository) Delete(id ID) error {
|
||||||
return ErrTrainingNotFound
|
return ErrTrainingNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
|
delete(r.slugToID, r.trainings[id].Slug)
|
||||||
delete(r.trainings, id)
|
delete(r.trainings, id)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/jackc/pgx/v5"
|
"github.com/jackc/pgx/v5"
|
||||||
"github.com/jackc/pgx/v5/pgxpool"
|
"github.com/jackc/pgx/v5/pgxpool"
|
||||||
"gitlab.mareshq.com/hq/yggdrasil/pkg/slug"
|
slugpkg "gitlab.mareshq.com/hq/yggdrasil/pkg/slug"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -21,7 +21,7 @@ func (r *PostgresTrainingRepository) Create(training *Training) error {
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if training.Slug == "" {
|
if training.Slug == "" {
|
||||||
training.Slug = slug.NewString(training.Name)
|
training.Slug = slugpkg.NewString(training.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
tx, txErr := r.pg.Begin(ctx)
|
tx, txErr := r.pg.Begin(ctx)
|
||||||
|
|
@ -77,7 +77,7 @@ func (r *PostgresTrainingRepository) FindByID(id ID) (*Training, error) {
|
||||||
|
|
||||||
var training Training
|
var training Training
|
||||||
err := r.pg.QueryRow(ctx, `
|
err := r.pg.QueryRow(ctx, `
|
||||||
SELECT id, name, description, days
|
SELECT id, name, slug, description, days
|
||||||
FROM training.trainings
|
FROM training.trainings
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
`, id).Scan(&training.ID, &training.Name, &training.Slug, &training.Description, &training.Days)
|
`, 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
|
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) {
|
func (r *PostgresTrainingRepository) FindAll() ([]Training, error) {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
@ -157,9 +202,9 @@ func (r *PostgresTrainingRepository) Update(training *Training) error {
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if training.Slug == "" {
|
if training.Slug == "" {
|
||||||
training.Slug = slug.NewString(training.Name)
|
training.Slug = slugpkg.NewString(training.Name)
|
||||||
} else {
|
} else {
|
||||||
slugValidateErr := slug.Validate(training.Slug)
|
slugValidateErr := slugpkg.Validate(training.Slug)
|
||||||
if slugValidateErr != nil {
|
if slugValidateErr != nil {
|
||||||
return slugValidateErr
|
return slugValidateErr
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package training
|
||||||
type Repository interface {
|
type Repository interface {
|
||||||
Create(training *Training) error
|
Create(training *Training) error
|
||||||
FindByID(id ID) (*Training, error)
|
FindByID(id ID) (*Training, error)
|
||||||
|
FindBySlug(slug string) (*Training, error)
|
||||||
FindAll() ([]Training, error)
|
FindAll() ([]Training, error)
|
||||||
Update(training *Training) error
|
Update(training *Training) error
|
||||||
Delete(id ID) error
|
Delete(id ID) error
|
||||||
|
|
|
||||||
Reference in a new issue