// officeHour package repositories import ( "database/sql" "fmt" "officeHours/config" "officeHours/models" ) type OfficeHourRepo struct { db *sql.DB roomRepo *RoomRepo tutorRepo *TutorRepo courseRepo *CourseRepo config config.Config } func NewOfficeHourRepo(db *sql.DB, roomRepo *RoomRepo, tutorRepo *TutorRepo, courseRepo *CourseRepo, conf config.Config) *OfficeHourRepo { return &OfficeHourRepo{ db: db, roomRepo: roomRepo, tutorRepo: tutorRepo, courseRepo: courseRepo, config: conf, } } func (r *OfficeHourRepo) GetAll(activeOnly bool) ([]models.OfficeHour, error) { var rows *sql.Rows var err error if activeOnly { rows, err = r.db.Query("SELECT * FROM officeHour WHERE active") } else { rows, err = r.db.Query("SELECT * FROM officeHour") } if err != nil { return nil, fmt.Errorf("Error getting all officeHours from database: %s", err.Error()) } defer rows.Close() return r.getFromRows(rows) } func (r *OfficeHourRepo) FindByCourse(course models.Course, activeOnly bool) ([]models.OfficeHour, error) { var rows *sql.Rows var err error if activeOnly { rows, err = r.db.Query("SELECT * FROM officeHour WHERE course=? and active", course.Id) } else { rows, err = r.db.Query("SELECT * FROM officeHour WHERE course=?", course.Id) } if err != nil { return nil, fmt.Errorf("Error getting officeHours by course from database: %s", err.Error()) } defer rows.Close() return r.getFromRows(rows) } func (r *OfficeHourRepo) FindByRoom(room models.Room, activeOnly bool) ([]models.OfficeHour, error) { var rows *sql.Rows var err error if activeOnly { rows, err = r.db.Query("SELECT * FROM officeHour WHERE room=? AND active", room.Id) } else { rows, err = r.db.Query("SELECT * FROM officeHour WHERE room=?", room.Id) } if err != nil { return nil, fmt.Errorf("Error getting officeHours by room from database: %s", err.Error()) } defer rows.Close() return r.getFromRows(rows) } func (r *OfficeHourRepo) FindById(id int) (models.OfficeHour, error) { return r.getFromRow(r.db.QueryRow("SELECT * FROM officeHour WHERE id=?", id)) } func (r *OfficeHourRepo) Add(officeHour models.OfficeHour) (id int, err error) { // Find correct tutor or add if not existent r.tutorRepo.Add(officeHour.Tutor) officeHour.Tutor, err = r.tutorRepo.FindByNameAndEmail(officeHour.Tutor.Name, officeHour.Tutor.Email) if err != nil { return 0, err } //Don't add identical officeHours officeHours, err := r.FindByCourse(officeHour.Course, false) if err != nil { return 0, err } for _, oldOfficeHour := range officeHours { if officeHour.Tutor == oldOfficeHour.Tutor && officeHour.Date == oldOfficeHour.Date && officeHour.Room == oldOfficeHour.Room && // officeHour.Course == oldOfficeHour.Course && already filtered above officeHour.Info == oldOfficeHour.Info && officeHour.Active == oldOfficeHour.Active && officeHour.Duration == oldOfficeHour.Duration { return oldOfficeHour.Id, nil } } sqlResult, err := r.db.Exec("INSERT INTO `officeHour` (tutor, day, hour, minute, room, course, week, info, active, duration) VALUES (?,?,?,?,?,?,?,?,?,?)", officeHour.Tutor.Id, officeHour.Date.Day, officeHour.Date.Hour, officeHour.Date.Minute, officeHour.Room.Id, officeHour.Course.Id, officeHour.Date.Week, officeHour.Info, officeHour.Active, officeHour.Duration) id64, _ := sqlResult.LastInsertId() return int(id64), err } func (r *OfficeHourRepo) Delete(officeHour models.OfficeHour) error { _, err := r.db.Exec("DELETE FROM officeHour WHERE id=?", officeHour.Id) if err != nil { return fmt.Errorf("Error deleting officeHour from database: %s", err.Error()) } return nil } func (r *OfficeHourRepo) getFromRow(row *sql.Row) (models.OfficeHour, error) { var officeHour models.OfficeHour var week, day, hour, minute, tutorId, courseId, roomId int err := row.Scan(&officeHour.Id, &tutorId, &day, &hour, &minute, &roomId, &courseId, &week, &officeHour.Info, &officeHour.Active, &officeHour.Duration) if err != nil { return models.OfficeHour{}, fmt.Errorf("Error getting single officeHours row from database: %s", err.Error()) } officeHour.Date = models.Date{Week: week, Day: day, Hour: hour, Minute: minute} officeHour.Room, _ = r.roomRepo.FindById(roomId) officeHour.Tutor, _ = r.tutorRepo.FindById(tutorId) officeHour.Course, _ = r.courseRepo.FindById(courseId) return officeHour, nil } func (r *OfficeHourRepo) getFromRows(rows *sql.Rows) ([]models.OfficeHour, error) { var officeHours []models.OfficeHour for rows.Next() { var officeHour models.OfficeHour var week, day, hour, minute, tutorId, roomId, courseId int if err := rows.Scan(&officeHour.Id, &tutorId, &day, &hour, &minute, &roomId, &courseId, &week, &officeHour.Info, &officeHour.Active, &officeHour.Duration); err != nil { return officeHours, fmt.Errorf("Error getting multiple officeHour rows from database: %s", err.Error()) } officeHour.Date = models.Date{Week: week, Day: day, Hour: hour, Minute: minute} officeHour.Room, _ = r.roomRepo.FindById(roomId) officeHour.Tutor, _ = r.tutorRepo.FindById(tutorId) officeHour.Course, _ = r.courseRepo.FindById(courseId) officeHours = append(officeHours, officeHour) } return officeHours, nil } func (r *OfficeHourRepo) NumberByTimeSpanAndRoom(date models.Date, duration int, room models.Room, activeOnly bool) (int, error) { var rows *sql.Rows var err error if activeOnly { rows, err = r.db.Query("SELECT * FROM officeHour WHERE room=? AND day =? AND active", room.Id, date.Day) } else { rows, err = r.db.Query("SELECT * FROM officeHour WHERE room=?", room.Id) } if err != nil { return 0, fmt.Errorf("Error getting officeHours by timespan and room from database: %s", err.Error()) } defer rows.Close() officeHours, err := r.getFromRows(rows) if err != nil { return 0, err } var count int // iterate over all points in the new officehour to get the maximum parallel officehours for minute := 0; minute < duration; minute += r.config.Date.MinuteGranularity { var minuteCount int = 0 for _, officeHour := range officeHours { // increase count if officehour starts before this point in time and ends later if models.DateLess(officeHour.Date, models.GetEndDate(date, minute, false)) && models.DateLess(models.GetEndDate(date, minute, false), models.GetEndDate(officeHour.Date, officeHour.Duration, false)) { minuteCount += 1 } } if minuteCount > count { count = minuteCount } } return count, nil } func (r *OfficeHourRepo) AllowedAt(date models.Date, duration int, room models.Room, activeOnly bool) (bool, error) { numberOfOfficeHours, err := r.NumberByTimeSpanAndRoom(date, duration, room, activeOnly) if err != nil { return false, err } return numberOfOfficeHours < room.MaxOccupy, nil }