package training import ( "sync" "time" ) type InMemoryTrainingRepository struct { trainings map[ID]Training lock sync.RWMutex ai int } func NewInMemoryTrainingRepository() *InMemoryTrainingRepository { return &InMemoryTrainingRepository{ trainings: make(map[ID]Training), ai: 1, } } func (r *InMemoryTrainingRepository) Create(training *Training) error { r.lock.Lock() defer r.lock.Unlock() training.ID = r.ai r.ai++ r.trainings[training.ID] = *training return nil } func (r *InMemoryTrainingRepository) FindByID(id ID) (*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 ID) error { r.lock.Lock() defer r.lock.Unlock() _, ok := r.trainings[id] if !ok { return ErrTrainingNotFound } delete(r.trainings, id) return nil } type InMemoryDateRepository struct { trainingDates map[DateID]Date trainingToDates map[ID][]DateID lock sync.RWMutex ai int } func NewInMemoryDateRepository() *InMemoryDateRepository { return &InMemoryDateRepository{ trainingDates: make(map[DateID]Date), trainingToDates: make(map[ID][]DateID), ai: 1, } } func (r *InMemoryDateRepository) Create(trainingID ID, trainingDate *Date) error { r.lock.Lock() defer r.lock.Unlock() trainingDate.ID = r.ai r.ai++ trainingDate.trainingID = trainingID r.trainingDates[trainingDate.ID] = *trainingDate r.trainingToDates[trainingID] = append(r.trainingToDates[trainingID], trainingDate.ID) return nil } func (r *InMemoryDateRepository) FindByID(id DateID) (*Date, error) { r.lock.RLock() defer r.lock.RUnlock() date, ok := r.trainingDates[id] if !ok { return nil, ErrTrainingDateNotFound } return &date, nil } func (r *InMemoryDateRepository) FindAll() ([]Date, error) { r.lock.RLock() defer r.lock.RUnlock() dates := make([]Date, len(r.trainingDates)) for _, date := range r.trainingDates { dates = append(dates, date) } return dates, nil } func (r *InMemoryDateRepository) FindAllByTrainingID(trainingID ID) ([]Date, error) { r.lock.RLock() defer r.lock.RUnlock() dates := make([]Date, 0) for _, id := range r.trainingToDates[trainingID] { dates = append(dates, r.trainingDates[id]) } return dates, nil } func (r *InMemoryDateRepository) FindUpcomingByTrainingID(trainingID ID) ([]Date, error) { r.lock.RLock() defer r.lock.RUnlock() now := time.Now() var dates []Date for _, id := range r.trainingToDates[trainingID] { date := r.trainingDates[id] if date.Date.After(now) { dates = append(dates, date) } } return dates, nil } func (r *InMemoryDateRepository) Update(trainingDate *Date) 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 *InMemoryDateRepository) Delete(id DateID) 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 InMemoryAttendeeRepository struct { attendees map[AttendeeID]Attendee dateToAttendees map[DateID][]AttendeeID lock sync.RWMutex ai int } func NewInMemoryAttendeeRepository() *InMemoryAttendeeRepository { return &InMemoryAttendeeRepository{ attendees: make(map[AttendeeID]Attendee), dateToAttendees: make(map[DateID][]AttendeeID), ai: 1, } } func (r *InMemoryAttendeeRepository) Create(trainingDateID DateID, attendee *Attendee) error { r.lock.Lock() defer r.lock.Unlock() attendee.ID = r.ai r.ai++ attendee.trainingDateID = trainingDateID r.attendees[attendee.ID] = *attendee r.dateToAttendees[trainingDateID] = append(r.dateToAttendees[trainingDateID], attendee.ID) return nil } func (r *InMemoryAttendeeRepository) FindByID(id AttendeeID) (*Attendee, error) { r.lock.RLock() defer r.lock.RUnlock() attendee, ok := r.attendees[id] if !ok { return nil, ErrTrainingDateAttendeeNotFound } return &attendee, nil } func (r *InMemoryAttendeeRepository) FindAll() ([]Attendee, error) { r.lock.RLock() defer r.lock.RUnlock() attendees := make([]Attendee, len(r.attendees)) for _, attendee := range r.attendees { attendees = append(attendees, attendee) } return attendees, nil } func (r *InMemoryAttendeeRepository) FindAllByTrainingDateID(trainingDateID DateID) ([]Attendee, error) { r.lock.RLock() defer r.lock.RUnlock() attendees := make([]Attendee, 0) for _, id := range r.dateToAttendees[trainingDateID] { attendees = append(attendees, r.attendees[id]) } return attendees, nil } func (r *InMemoryAttendeeRepository) Update(attendee *Attendee) 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 *InMemoryAttendeeRepository) Delete(id AttendeeID) 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 }