1
0
Fork 0

feat: add postgres repository for training

This commit is contained in:
Vojtěch Mareš 2024-06-23 10:35:38 +02:00
parent 8c277ef692
commit ff7e320481
Signed by: vojtech.mares
GPG key ID: C6827B976F17240D
19 changed files with 1277 additions and 414 deletions

View file

@ -0,0 +1,270 @@
package training
import (
"sync"
"time"
)
type InMemoryTrainingRepository struct {
trainings map[TrainingID]Training
lock sync.RWMutex
}
func NewInMemoryTrainingRepository() *InMemoryTrainingRepository {
return &InMemoryTrainingRepository{
trainings: make(map[TrainingID]Training),
}
}
func (r *InMemoryTrainingRepository) Create(training *Training) error {
r.lock.Lock()
defer r.lock.Unlock()
training.ID = NewTrainingID()
r.trainings[training.ID] = *training
return nil
}
func (r *InMemoryTrainingRepository) FindByID(id TrainingID) (*Training, error) {
r.lock.RLock()
defer r.lock.RUnlock()
training, ok := r.trainings[id]
if !ok {
return nil, ErrTrainingNotFound
}
return &training, nil
}
func (r *InMemoryTrainingRepository) FindAll() ([]Training, error) {
r.lock.RLock()
defer r.lock.RUnlock()
trainings := make([]Training, 0, len(r.trainings))
for _, training := range r.trainings {
trainings = append(trainings, training)
}
return trainings, nil
}
func (r *InMemoryTrainingRepository) Update(training *Training) error {
r.lock.Lock()
defer r.lock.Unlock()
r.trainings[training.ID] = *training
return nil
}
func (r *InMemoryTrainingRepository) Delete(id TrainingID) error {
r.lock.Lock()
defer r.lock.Unlock()
_, ok := r.trainings[id]
if !ok {
return ErrTrainingNotFound
}
delete(r.trainings, id)
return nil
}
type InMemoryTrainingDateRepository struct {
trainingDates map[TrainingDateID]TrainingDate
trainingToDates map[TrainingID][]TrainingDateID
lock sync.RWMutex
}
func NewInMemoryTrainingDateRepository() *InMemoryTrainingDateRepository {
return &InMemoryTrainingDateRepository{
trainingDates: make(map[TrainingDateID]TrainingDate),
trainingToDates: make(map[TrainingID][]TrainingDateID),
}
}
func (r *InMemoryTrainingDateRepository) Create(trainingID TrainingID, trainingDate *TrainingDate) error {
r.lock.Lock()
defer r.lock.Unlock()
trainingDate.ID = NewTrainingDateID()
trainingDate.trainingID = trainingID
r.trainingDates[trainingDate.ID] = *trainingDate
r.trainingToDates[trainingID] = append(r.trainingToDates[trainingID], trainingDate.ID)
return nil
}
func (r *InMemoryTrainingDateRepository) FindByID(id TrainingDateID) (*TrainingDate, error) {
r.lock.RLock()
defer r.lock.RUnlock()
date, ok := r.trainingDates[id]
if !ok {
return nil, ErrTrainingDateNotFound
}
return &date, nil
}
func (r *InMemoryTrainingDateRepository) FindAll() ([]TrainingDate, error) {
r.lock.RLock()
defer r.lock.RUnlock()
dates := make([]TrainingDate, len(r.trainingDates))
for _, date := range r.trainingDates {
dates = append(dates, date)
}
return dates, nil
}
func (r *InMemoryTrainingDateRepository) FindAllByTrainingID(trainingID TrainingID) ([]TrainingDate, error) {
r.lock.RLock()
defer r.lock.RUnlock()
dates := make([]TrainingDate, 0)
for _, id := range r.trainingToDates[trainingID] {
dates = append(dates, r.trainingDates[id])
}
return dates, nil
}
func (r *InMemoryTrainingDateRepository) FindUpcomingByTrainingID(trainingID TrainingID) ([]TrainingDate, error) {
r.lock.RLock()
defer r.lock.RUnlock()
now := time.Now()
var dates []TrainingDate
for _, id := range r.trainingToDates[trainingID] {
date := r.trainingDates[id]
if date.Date.After(now) {
dates = append(dates, date)
}
}
return dates, nil
}
func (r *InMemoryTrainingDateRepository) Update(trainingDate *TrainingDate) error {
r.lock.Lock()
defer r.lock.Unlock()
oldDate := r.trainingDates[trainingDate.ID]
trainingDate.trainingID = oldDate.trainingID
r.trainingDates[trainingDate.ID] = *trainingDate
return nil
}
func (r *InMemoryTrainingDateRepository) Delete(id TrainingDateID) error {
r.lock.Lock()
defer r.lock.Unlock()
date, ok := r.trainingDates[id]
if !ok {
return ErrTrainingDateNotFound
}
delete(r.trainingDates, id)
dates := r.trainingToDates[date.trainingID]
for idx, d := range dates {
if d == id {
r.trainingToDates[date.trainingID] = append(dates[:idx], dates[idx+1:]...)
break
}
}
return nil
}
type InMemoryTrainingDateAttendeeRepository struct {
attendees map[TrainingDateAttendeeID]TrainingDateAttendee
dateToAttendees map[TrainingDateID][]TrainingDateAttendeeID
lock sync.RWMutex
}
func NewInMemoryTrainingDateAttendeeRepository() *InMemoryTrainingDateAttendeeRepository {
return &InMemoryTrainingDateAttendeeRepository{
attendees: make(map[TrainingDateAttendeeID]TrainingDateAttendee),
dateToAttendees: make(map[TrainingDateID][]TrainingDateAttendeeID),
}
}
func (r *InMemoryTrainingDateAttendeeRepository) Create(trainingDateID TrainingDateID, attendee *TrainingDateAttendee) error {
r.lock.Lock()
defer r.lock.Unlock()
attendee.ID = NewTrainingDateAttendeeID()
attendee.trainingDateID = trainingDateID
r.attendees[attendee.ID] = *attendee
r.dateToAttendees[trainingDateID] = append(r.dateToAttendees[trainingDateID], attendee.ID)
return nil
}
func (r *InMemoryTrainingDateAttendeeRepository) FindByID(id TrainingDateAttendeeID) (*TrainingDateAttendee, error) {
r.lock.RLock()
defer r.lock.RUnlock()
attendee, ok := r.attendees[id]
if !ok {
return nil, ErrTrainingDateAttendeeNotFound
}
return &attendee, nil
}
func (r *InMemoryTrainingDateAttendeeRepository) FindAll() ([]TrainingDateAttendee, error) {
r.lock.RLock()
defer r.lock.RUnlock()
attendees := make([]TrainingDateAttendee, len(r.attendees))
for _, attendee := range r.attendees {
attendees = append(attendees, attendee)
}
return attendees, nil
}
func (r *InMemoryTrainingDateAttendeeRepository) FindAllByTrainingDateID(trainingDateID TrainingDateID) ([]TrainingDateAttendee, error) {
r.lock.RLock()
defer r.lock.RUnlock()
attendees := make([]TrainingDateAttendee, 0)
for _, id := range r.dateToAttendees[trainingDateID] {
attendees = append(attendees, r.attendees[id])
}
return attendees, nil
}
func (r *InMemoryTrainingDateAttendeeRepository) Update(attendee *TrainingDateAttendee) error {
r.lock.Lock()
defer r.lock.Unlock()
oldAttendee := r.attendees[attendee.ID]
attendee.trainingDateID = oldAttendee.trainingDateID
r.attendees[attendee.ID] = *attendee
return nil
}
func (r *InMemoryTrainingDateAttendeeRepository) Delete(id TrainingDateAttendeeID) error {
r.lock.Lock()
defer r.lock.Unlock()
attendee, ok := r.attendees[id]
if !ok {
return ErrTrainingDateAttendeeNotFound
}
delete(r.attendees, id)
attendees := r.dateToAttendees[attendee.trainingDateID]
for idx, a := range attendees {
if a == id {
r.dateToAttendees[attendee.trainingDateID] = append(attendees[:idx], attendees[idx+1:]...)
break
}
}
return nil
}

View file

@ -1,11 +1,11 @@
package training
import (
"github.com/shopspring/decimal"
"gitlab.mareshq.com/hq/yggdrasil/internal/money"
"time"
"github.com/google/uuid"
"github.com/shopspring/decimal"
"gitlab.mareshq.com/hq/yggdrasil/internal/money"
)
type TrainingID = uuid.UUID
@ -19,7 +19,7 @@ type Training struct {
Name string
Days int8
Description string
Pricing []TrainingPrice
Pricing []TrainingPrice `db:"-"`
}
type TrainingPrice struct {
@ -44,15 +44,16 @@ func NewTrainingDateID() TrainingDateID {
type TrainingDate struct {
trainingID TrainingID
ID TrainingDateID
Date time.Time
StartTime time.Time
Days int8
IsOnline bool
Location string
Address string
Capacity int8
Price money.Price
ID TrainingDateID
Date time.Time
StartTime time.Time
Days int8
IsOnline bool
Location string
Address string
Capacity int8
PriceAmount decimal.Decimal `db:"price_amount"`
PriceCurrency money.Currency `db:"price_currency"`
}
type TrainingDateAttendeeID = uuid.UUID
@ -64,14 +65,15 @@ func NewTrainingDateAttendeeID() TrainingDateAttendeeID {
type TrainingDateAttendee struct {
trainingDateID TrainingDateID
ID TrainingDateAttendeeID
Name string
Email string
Phone string
Company string
Position string
Bill money.Price
IsStudent bool
HasPaid bool
HasAttended bool
ID TrainingDateAttendeeID
Name string
Email string
Phone string
Company string
Position string
IsStudent bool
HasPaid bool
HasAttended bool
BillAmount decimal.Decimal `db:"bill_amount"`
BillCurrency money.Currency `db:"bill_currency"`
}

View file

@ -0,0 +1,561 @@
package training
import (
"context"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgxpool"
"time"
)
type PostgresTrainingRepository struct {
pg *pgxpool.Pool
}
func NewPostgresTrainingRepository(pg *pgxpool.Pool) *PostgresTrainingRepository {
return &PostgresTrainingRepository{pg: pg}
}
func (r *PostgresTrainingRepository) Create(training *Training) error {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
training.ID = NewTrainingID()
tx, err := r.pg.Begin(ctx)
if err != nil {
return err
}
_, err = tx.Exec(ctx, `
INSERT INTO training.trainings (id, name, description, days)
VALUES ($1, $2, $3, $4)
`, training.ID, training.Name, training.Description, training.Days)
if err != nil {
return err
}
queryBatch := &pgx.Batch{}
for _, price := range training.Pricing {
queryBatch.Queue(`
INSERT INTO training.prices (training_id, amount, currency, type)
VALUES ($1, $2, $3, $4)
`, training.ID, price.Amount, price.Currency, price.Type)
}
batch := tx.SendBatch(ctx, queryBatch)
defer func() {
if e := batch.Close(); e != nil {
err = e
}
if err != nil {
_ = tx.Rollback(ctx)
} else {
if e := tx.Commit(ctx); e != nil {
err = e
}
}
}()
_, err = batch.Exec()
if err != nil {
return err
}
return nil
}
func (r *PostgresTrainingRepository) FindByID(id TrainingID) (*Training, error) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
var training Training
err := r.pg.QueryRow(ctx, `
SELECT id, name, description, days
FROM training.trainings
WHERE id = $1
`, id).Scan(&training.ID, &training.Name, &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
`, id)
if err != nil {
return nil, err
}
defer rows.Close()
training.Pricing = make([]TrainingPrice, 0)
training.Pricing, err = pgx.CollectRows[TrainingPrice](rows, func(row pgx.CollectableRow) (TrainingPrice, error) {
var price TrainingPrice
err := row.Scan(&price.Amount, &price.Currency, &price.Type)
if err != nil {
return TrainingPrice{}, 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()
rows, err := r.pg.Query(ctx, `
SELECT *
FROM training.trainings
`)
if err != nil {
return nil, err
}
defer rows.Close()
trainings, err := pgx.CollectRows(rows, func(row pgx.CollectableRow) (Training, error) {
var training Training
scanErr := row.Scan(&training.ID, &training.Name, &training.Description, &training.Days)
if scanErr != nil {
return Training{}, scanErr
}
priceRows, queryErr := r.pg.Query(ctx, `SELECT amount, currency, type FROM training.prices WHERE training_id = $1`, training.ID)
if queryErr != nil {
return Training{}, queryErr
}
training.Pricing, scanErr = pgx.CollectRows(priceRows, pgx.RowToStructByName[TrainingPrice])
if scanErr != nil {
return Training{}, scanErr
}
return training, nil
})
if err != nil {
return nil, err
}
return trainings, nil
}
func (r *PostgresTrainingRepository) Update(training *Training) error {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
tx, err := r.pg.Begin(ctx)
if err != nil {
return err
}
_, err = tx.Exec(ctx, `
UPDATE training.trainings
SET name = $1, description = $2, days = $3
WHERE id = $4
`, training.Name, training.Description, training.Days, training.ID)
if err != nil {
return err
}
queryBatch := &pgx.Batch{}
for _, price := range training.Pricing {
queryBatch.Queue(`
INSERT INTO training.prices (training_id, amount, currency, type)
VALUES ($1, $2, $3, $4)
`, training.ID, price.Amount, price.Currency, price.Type)
}
batch := tx.SendBatch(ctx, queryBatch)
defer func() {
if e := batch.Close(); e != nil {
err = e
}
if err != nil {
_ = tx.Rollback(ctx)
} else {
if e := tx.Commit(ctx); e != nil {
err = e
}
}
}()
_, err = batch.Exec()
if err != nil {
return err
}
return nil
}
func (r *PostgresTrainingRepository) Delete(id TrainingID) error {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
tx, err := r.pg.Begin(ctx)
if err != nil {
return err
}
_, err = tx.Exec(context.Background(), `
DELETE FROM training.prices
WHERE training_id = $1
`, id)
if err != nil {
return err
}
_, err = tx.Exec(context.Background(), `
DELETE FROM training.trainings
WHERE id = $1
`, id)
if err != nil {
return err
}
err = tx.Commit(ctx)
if err != nil {
return err
}
return nil
}
type PostgresTrainingDateRepository struct {
pg *pgxpool.Pool
}
func NewPostgresTrainingDateRepository(pg *pgxpool.Pool) *PostgresTrainingDateRepository {
return &PostgresTrainingDateRepository{pg: pg}
}
func (r *PostgresTrainingDateRepository) Create(trainingID TrainingID, trainingDate *TrainingDate) error {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
trainingDate.ID = NewTrainingDateID()
_, err := r.pg.Exec(ctx, `
INSERT INTO training.dates (id, training_id, date, start_time, days, is_online, location, address, capacity, price_amount, price_currency)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)`,
trainingDate.ID,
trainingID,
trainingDate.Date,
trainingDate.StartTime,
trainingDate.Days,
trainingDate.IsOnline,
trainingDate.Location,
trainingDate.Address,
trainingDate.Capacity,
trainingDate.PriceAmount,
trainingDate.PriceCurrency,
)
if err != nil {
return err
}
return nil
}
func (r *PostgresTrainingDateRepository) FindByID(id TrainingDateID) (*TrainingDate, error) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
var trainingDate TrainingDate
err := r.pg.QueryRow(ctx, `SELECT * FROM training.dates WHERE id = $1`, id).
Scan(
&trainingDate.ID,
&trainingDate.trainingID,
&trainingDate.Date,
&trainingDate.StartTime,
&trainingDate.Days,
&trainingDate.IsOnline,
&trainingDate.Location,
&trainingDate.Address,
&trainingDate.Capacity,
&trainingDate.PriceAmount,
&trainingDate.PriceCurrency,
)
if err != nil {
return nil, err
}
return &trainingDate, nil
}
func (r *PostgresTrainingDateRepository) FindAll() ([]TrainingDate, error) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
rows, err := r.pg.Query(ctx, `SELECT * FROM training.dates`)
if err != nil {
return nil, err
}
defer rows.Close()
var trainingDates []TrainingDate
for rows.Next() {
var trainingDate TrainingDate
err := rows.Scan(
&trainingDate.ID,
&trainingDate.trainingID,
&trainingDate.Date,
&trainingDate.StartTime,
&trainingDate.Days,
&trainingDate.IsOnline,
&trainingDate.Location,
&trainingDate.Address,
&trainingDate.Capacity,
&trainingDate.PriceAmount,
&trainingDate.PriceCurrency,
)
if err != nil {
return nil, err
}
trainingDates = append(trainingDates, trainingDate)
}
return trainingDates, nil
}
func (r *PostgresTrainingDateRepository) FindAllByTrainingID(trainingID TrainingID) ([]TrainingDate, error) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
rows, err := r.pg.Query(ctx, `SELECT * FROM training.dates WHERE training_id = $1`, trainingID)
if err != nil {
return nil, err
}
defer rows.Close()
var trainingDates []TrainingDate
for rows.Next() {
var trainingDate TrainingDate
err := rows.Scan(
&trainingDate.ID,
&trainingDate.trainingID,
&trainingDate.Date,
&trainingDate.StartTime,
&trainingDate.Days,
&trainingDate.IsOnline,
&trainingDate.Location,
&trainingDate.Address,
&trainingDate.Capacity,
&trainingDate.PriceAmount,
&trainingDate.PriceCurrency,
)
if err != nil {
return nil, err
}
trainingDates = append(trainingDates, trainingDate)
}
return trainingDates, nil
}
func (r *PostgresTrainingDateRepository) FindUpcomingByTrainingID(trainingID TrainingID) ([]TrainingDate, error) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
rows, err := r.pg.Query(ctx, `
SELECT * FROM training.dates
WHERE training_id = $1 AND date > $2
`, trainingID, time.Now())
if err != nil {
return nil, err
}
defer rows.Close()
var trainingDates []TrainingDate
for rows.Next() {
var trainingDate TrainingDate
err := rows.Scan(
&trainingDate.ID,
&trainingDate.trainingID,
&trainingDate.Date,
&trainingDate.StartTime,
&trainingDate.Days,
&trainingDate.IsOnline,
&trainingDate.Location,
&trainingDate.Address,
&trainingDate.Capacity,
&trainingDate.PriceAmount,
&trainingDate.PriceCurrency,
)
if err != nil {
return nil, err
}
trainingDates = append(trainingDates, trainingDate)
}
return trainingDates, nil
}
func (r *PostgresTrainingDateRepository) Update(trainingDate *TrainingDate) error {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
_, err := r.pg.Exec(ctx, `
UPDATE training.dates
SET date = $1, start_time = $2, days = $3, is_online = $4, location = $5, address = $6, capacity = $7, price_amount = $8, price_currency = $9
WHERE id = $10
`, trainingDate.Date, trainingDate.StartTime, trainingDate.Days, trainingDate.IsOnline, trainingDate.Location, trainingDate.Address, trainingDate.Capacity, trainingDate.PriceAmount, trainingDate.PriceCurrency, trainingDate.ID)
if err != nil {
return err
}
return nil
}
func (r *PostgresTrainingDateRepository) Delete(id TrainingDateID) error {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
_, err := r.pg.Exec(ctx, `DELETE FROM training.dates WHERE id = $1`, id)
if err != nil {
return err
}
return nil
}
type PostgresTrainingDateAttendeeRepository struct {
pg *pgxpool.Pool
}
func NewPostgresTrainingDateAttendeeRepository(pg *pgxpool.Pool) *PostgresTrainingDateAttendeeRepository {
return &PostgresTrainingDateAttendeeRepository{pg: pg}
}
func (r *PostgresTrainingDateAttendeeRepository) Create(trainingDateID TrainingDateID, attendee *TrainingDateAttendee) error {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
attendee.ID = NewTrainingDateAttendeeID()
_, err := r.pg.Exec(ctx, `
INSERT INTO training.date_attendees (id, date_id, name, email, phone, company, position, is_student, has_paid, has_attended, bill_amount, bill_currency)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
`, attendee.ID, trainingDateID, attendee.Name, attendee.Email, attendee.Phone, attendee.Company, attendee.Position, attendee.IsStudent, attendee.HasPaid, attendee.HasAttended, attendee.BillAmount, attendee.BillCurrency)
if err != nil {
return err
}
return nil
}
func (r *PostgresTrainingDateAttendeeRepository) FindByID(id TrainingDateAttendeeID) (*TrainingDateAttendee, error) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
var attendee TrainingDateAttendee
err := r.pg.QueryRow(ctx, `
SELECT id, date_id, name, email, phone, company, position, is_student, has_paid, has_attended, bill_amount, bill_currency
FROM training.date_attendees
WHERE id = $1
`, id).Scan(&attendee.ID, &attendee.trainingDateID, &attendee.Name, &attendee.Email, &attendee.Phone, &attendee.Company, &attendee.Position, &attendee.IsStudent, &attendee.HasPaid, &attendee.HasAttended, &attendee.BillAmount, &attendee.BillCurrency)
if err != nil {
return nil, err
}
return &attendee, nil
}
func (r *PostgresTrainingDateAttendeeRepository) FindAll() ([]TrainingDateAttendee, error) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
rows, err := r.pg.Query(ctx, `
SELECT id, date_id, name, email, phone, company, position, is_student, has_paid, has_attended, bill_amount, bill_currency
FROM training.date_attendees
`)
if err != nil {
return nil, err
}
defer rows.Close()
var attendees []TrainingDateAttendee
for rows.Next() {
var attendee TrainingDateAttendee
err := rows.Scan(&attendee.ID, &attendee.trainingDateID, &attendee.Name, &attendee.Email, &attendee.Phone, &attendee.Company, &attendee.Position, &attendee.IsStudent, &attendee.HasPaid, &attendee.HasAttended, &attendee.BillAmount, &attendee.BillCurrency)
if err != nil {
return nil, err
}
attendees = append(attendees, attendee)
}
return attendees, nil
}
func (r *PostgresTrainingDateAttendeeRepository) FindAllByTrainingDateID(trainingDateID TrainingDateID) ([]TrainingDateAttendee, error) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
rows, err := r.pg.Query(ctx, `
SELECT id, date_id, name, email, phone, company, position, is_student, has_paid, has_attended, bill_amount, bill_currency
FROM training.date_attendees
WHERE date_id = $1
`, trainingDateID)
if err != nil {
return nil, err
}
defer rows.Close()
var attendees []TrainingDateAttendee
for rows.Next() {
var attendee TrainingDateAttendee
err := rows.Scan(&attendee.ID, &attendee.trainingDateID, &attendee.Name, &attendee.Email, &attendee.Phone, &attendee.Company, &attendee.Position, &attendee.IsStudent, &attendee.HasPaid, &attendee.HasAttended, &attendee.BillAmount, &attendee.BillCurrency)
if err != nil {
return nil, err
}
attendees = append(attendees, attendee)
}
return attendees, nil
}
func (r *PostgresTrainingDateAttendeeRepository) Update(attendee *TrainingDateAttendee) error {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
_, err := r.pg.Exec(ctx, `
UPDATE training.date_attendees
SET name = $1, email = $2, phone = $3, company = $4, position = $5, is_student = $6, has_paid = $7, has_attended = $8, bill_amount = $9, bill_currency = $10
WHERE id = $10
`, attendee.Name, attendee.Email, attendee.Phone, attendee.Company, attendee.Position, attendee.IsStudent, attendee.HasPaid, attendee.HasAttended, attendee.BillAmount, attendee.BillCurrency, attendee.ID)
if err != nil {
return err
}
return nil
}
func (r *PostgresTrainingDateAttendeeRepository) Delete(id TrainingDateAttendeeID) error {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
_, err := r.pg.Exec(ctx, `DELETE FROM training.date_attendees WHERE id = $1`, id)
if err != nil {
return err
}
return nil
}

View file

@ -1,10 +1,5 @@
package training
import (
"sync"
"time"
)
type TrainingRepository interface {
Create(training *Training) error
FindByID(id TrainingID) (*Training, error)
@ -13,69 +8,6 @@ type TrainingRepository interface {
Delete(id TrainingID) error
}
type InMemoryTrainingRepository struct {
trainings map[TrainingID]Training
lock sync.RWMutex
}
func NewInMemoryTrainingRepository() *InMemoryTrainingRepository {
return &InMemoryTrainingRepository{
trainings: make(map[TrainingID]Training),
}
}
func (r *InMemoryTrainingRepository) Create(training *Training) error {
r.lock.Lock()
defer r.lock.Unlock()
training.ID = NewTrainingID()
r.trainings[training.ID] = *training
return nil
}
func (r *InMemoryTrainingRepository) FindByID(id TrainingID) (*Training, error) {
r.lock.RLock()
defer r.lock.RUnlock()
training, ok := r.trainings[id]
if !ok {
return nil, ErrTrainingNotFound
}
return &training, nil
}
func (r *InMemoryTrainingRepository) FindAll() ([]Training, error) {
r.lock.RLock()
defer r.lock.RUnlock()
trainings := make([]Training, 0, len(r.trainings))
for _, training := range r.trainings {
trainings = append(trainings, training)
}
return trainings, nil
}
func (r *InMemoryTrainingRepository) Update(training *Training) error {
r.lock.Lock()
defer r.lock.Unlock()
r.trainings[training.ID] = *training
return nil
}
func (r *InMemoryTrainingRepository) Delete(id TrainingID) error {
r.lock.Lock()
defer r.lock.Unlock()
_, ok := r.trainings[id]
if !ok {
return ErrTrainingNotFound
}
delete(r.trainings, id)
return nil
}
type TrainingDateRepository interface {
Create(trainingID TrainingID, trainingDate *TrainingDate) error
FindByID(id TrainingDateID) (*TrainingDate, error)
@ -86,114 +18,6 @@ type TrainingDateRepository interface {
Delete(id TrainingDateID) error
}
type InMemoryTrainingDateRepository struct {
trainingDates map[TrainingDateID]TrainingDate
trainingToDates map[TrainingID][]TrainingDateID
lock sync.RWMutex
}
func NewInMemoryTrainingDateRepository() *InMemoryTrainingDateRepository {
return &InMemoryTrainingDateRepository{
trainingDates: make(map[TrainingDateID]TrainingDate),
trainingToDates: make(map[TrainingID][]TrainingDateID),
}
}
func (r *InMemoryTrainingDateRepository) Create(trainingID TrainingID, trainingDate *TrainingDate) error {
r.lock.Lock()
defer r.lock.Unlock()
trainingDate.ID = NewTrainingDateID()
trainingDate.trainingID = trainingID
r.trainingDates[trainingDate.ID] = *trainingDate
r.trainingToDates[trainingID] = append(r.trainingToDates[trainingID], trainingDate.ID)
return nil
}
func (r *InMemoryTrainingDateRepository) FindByID(id TrainingDateID) (*TrainingDate, error) {
r.lock.RLock()
defer r.lock.RUnlock()
date, ok := r.trainingDates[id]
if !ok {
return nil, ErrTrainingDateNotFound
}
return &date, nil
}
func (r *InMemoryTrainingDateRepository) FindAll() ([]TrainingDate, error) {
r.lock.RLock()
defer r.lock.RUnlock()
dates := make([]TrainingDate, len(r.trainingDates))
for _, date := range r.trainingDates {
dates = append(dates, date)
}
return dates, nil
}
func (r *InMemoryTrainingDateRepository) FindAllByTrainingID(trainingID TrainingID) ([]TrainingDate, error) {
r.lock.RLock()
defer r.lock.RUnlock()
dates := make([]TrainingDate, 0)
for _, id := range r.trainingToDates[trainingID] {
dates = append(dates, r.trainingDates[id])
}
return dates, nil
}
func (r *InMemoryTrainingDateRepository) FindUpcomingByTrainingID(trainingID TrainingID) ([]TrainingDate, error) {
r.lock.RLock()
defer r.lock.RUnlock()
now := time.Now()
var dates []TrainingDate
for _, id := range r.trainingToDates[trainingID] {
date := r.trainingDates[id]
if date.Date.After(now) {
dates = append(dates, date)
}
}
return dates, nil
}
func (r *InMemoryTrainingDateRepository) Update(trainingDate *TrainingDate) error {
r.lock.Lock()
defer r.lock.Unlock()
oldDate := r.trainingDates[trainingDate.ID]
trainingDate.trainingID = oldDate.trainingID
r.trainingDates[trainingDate.ID] = *trainingDate
return nil
}
func (r *InMemoryTrainingDateRepository) Delete(id TrainingDateID) error {
r.lock.Lock()
defer r.lock.Unlock()
date, ok := r.trainingDates[id]
if !ok {
return ErrTrainingDateNotFound
}
delete(r.trainingDates, id)
dates := r.trainingToDates[date.trainingID]
for idx, d := range dates {
if d == id {
r.trainingToDates[date.trainingID] = append(dates[:idx], dates[idx+1:]...)
break
}
}
return nil
}
type TrainingDateAttendeeRepository interface {
Create(trainingDateID TrainingDateID, attendee *TrainingDateAttendee) error
FindByID(id TrainingDateAttendeeID) (*TrainingDateAttendee, error)
@ -202,96 +26,3 @@ type TrainingDateAttendeeRepository interface {
Update(attendee *TrainingDateAttendee) error
Delete(id TrainingDateAttendeeID) error
}
type InMemoryTrainingDateAttendeeRepository struct {
attendees map[TrainingDateAttendeeID]TrainingDateAttendee
dateToAttendees map[TrainingDateID][]TrainingDateAttendeeID
lock sync.RWMutex
}
func NewInMemoryTrainingDateAttendeeRepository() *InMemoryTrainingDateAttendeeRepository {
return &InMemoryTrainingDateAttendeeRepository{
attendees: make(map[TrainingDateAttendeeID]TrainingDateAttendee),
dateToAttendees: make(map[TrainingDateID][]TrainingDateAttendeeID),
}
}
func (r *InMemoryTrainingDateAttendeeRepository) Create(trainingDateID TrainingDateID, attendee *TrainingDateAttendee) error {
r.lock.Lock()
defer r.lock.Unlock()
attendee.ID = NewTrainingDateAttendeeID()
attendee.trainingDateID = trainingDateID
r.attendees[attendee.ID] = *attendee
r.dateToAttendees[trainingDateID] = append(r.dateToAttendees[trainingDateID], attendee.ID)
return nil
}
func (r *InMemoryTrainingDateAttendeeRepository) FindByID(id TrainingDateAttendeeID) (*TrainingDateAttendee, error) {
r.lock.RLock()
defer r.lock.RUnlock()
attendee, ok := r.attendees[id]
if !ok {
return nil, ErrTrainingDateAttendeeNotFound
}
return &attendee, nil
}
func (r *InMemoryTrainingDateAttendeeRepository) FindAll() ([]TrainingDateAttendee, error) {
r.lock.RLock()
defer r.lock.RUnlock()
attendees := make([]TrainingDateAttendee, len(r.attendees))
for _, attendee := range r.attendees {
attendees = append(attendees, attendee)
}
return attendees, nil
}
func (r *InMemoryTrainingDateAttendeeRepository) FindAllByTrainingDateID(trainingDateID TrainingDateID) ([]TrainingDateAttendee, error) {
r.lock.RLock()
defer r.lock.RUnlock()
attendees := make([]TrainingDateAttendee, 0)
for _, id := range r.dateToAttendees[trainingDateID] {
attendees = append(attendees, r.attendees[id])
}
return attendees, nil
}
func (r *InMemoryTrainingDateAttendeeRepository) Update(attendee *TrainingDateAttendee) error {
r.lock.Lock()
defer r.lock.Unlock()
oldAttendee := r.attendees[attendee.ID]
attendee.trainingDateID = oldAttendee.trainingDateID
r.attendees[attendee.ID] = *attendee
return nil
}
func (r *InMemoryTrainingDateAttendeeRepository) Delete(id TrainingDateAttendeeID) error {
r.lock.Lock()
defer r.lock.Unlock()
attendee, ok := r.attendees[id]
if !ok {
return ErrTrainingDateAttendeeNotFound
}
delete(r.attendees, id)
attendees := r.dateToAttendees[attendee.trainingDateID]
for idx, a := range attendees {
if a == id {
r.dateToAttendees[attendee.trainingDateID] = append(attendees[:idx], attendees[idx+1:]...)
break
}
}
return nil
}