package training import ( "sync" "time" ) type TrainingRepository interface { Create(training *Training) error FindByID(id TrainingID) (*Training, error) FindAll() ([]Training, error) Update(training *Training) error 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) FindAll() ([]TrainingDate, error) FindAllByTrainingID(trainingID TrainingID) ([]TrainingDate, error) FindUpcomingByTrainingID(trainingID TrainingID) ([]TrainingDate, error) Update(trainingDate *TrainingDate) error 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) FindAll() ([]TrainingDateAttendee, error) FindAllByTrainingDateID(trainingDateID TrainingDateID) ([]TrainingDateAttendee, error) 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 }