106 lines
2.9 KiB
Go
106 lines
2.9 KiB
Go
package courses
|
|
|
|
import (
|
|
"Yimaru-Backend/internal/domain"
|
|
"Yimaru-Backend/internal/ports"
|
|
"Yimaru-Backend/internal/services/programs"
|
|
"context"
|
|
"errors"
|
|
|
|
"github.com/jackc/pgx/v5"
|
|
)
|
|
|
|
var ErrCourseNotFound = errors.New("course not found")
|
|
|
|
type Service struct {
|
|
courses ports.CourseStore
|
|
programs ports.ProgramStore
|
|
}
|
|
|
|
func NewService(courses ports.CourseStore, programs ports.ProgramStore) *Service {
|
|
return &Service{courses: courses, programs: programs}
|
|
}
|
|
|
|
func (s *Service) Create(ctx context.Context, programID int64, input domain.CreateCourseInput) (domain.Course, error) {
|
|
if _, err := s.programs.GetProgramByID(ctx, programID); err != nil {
|
|
if errors.Is(err, pgx.ErrNoRows) {
|
|
return domain.Course{}, programs.ErrProgramNotFound
|
|
}
|
|
return domain.Course{}, err
|
|
}
|
|
return s.courses.CreateCourse(ctx, programID, input)
|
|
}
|
|
|
|
func (s *Service) GetByID(ctx context.Context, id int64) (domain.Course, error) {
|
|
c, err := s.courses.GetCourseByID(ctx, id)
|
|
if err != nil {
|
|
if errors.Is(err, pgx.ErrNoRows) {
|
|
return domain.Course{}, ErrCourseNotFound
|
|
}
|
|
return domain.Course{}, err
|
|
}
|
|
return c, nil
|
|
}
|
|
|
|
func (s *Service) ListByProgram(ctx context.Context, programID int64, limit, offset int32) ([]domain.Course, int64, error) {
|
|
if _, err := s.programs.GetProgramByID(ctx, programID); err != nil {
|
|
if errors.Is(err, pgx.ErrNoRows) {
|
|
return nil, 0, programs.ErrProgramNotFound
|
|
}
|
|
return nil, 0, err
|
|
}
|
|
if limit <= 0 {
|
|
limit = 20
|
|
}
|
|
if limit > 200 {
|
|
limit = 200
|
|
}
|
|
if offset < 0 {
|
|
offset = 0
|
|
}
|
|
return s.courses.ListCoursesByProgramID(ctx, programID, limit, offset)
|
|
}
|
|
|
|
func (s *Service) Update(ctx context.Context, id int64, input domain.UpdateCourseInput) (domain.Course, error) {
|
|
c, err := s.courses.UpdateCourse(ctx, id, input)
|
|
if err != nil {
|
|
if errors.Is(err, pgx.ErrNoRows) {
|
|
return domain.Course{}, ErrCourseNotFound
|
|
}
|
|
return domain.Course{}, err
|
|
}
|
|
return c, nil
|
|
}
|
|
|
|
func (s *Service) Delete(ctx context.Context, id int64) error {
|
|
if _, err := s.courses.GetCourseByID(ctx, id); err != nil {
|
|
if errors.Is(err, pgx.ErrNoRows) {
|
|
return ErrCourseNotFound
|
|
}
|
|
return err
|
|
}
|
|
return s.courses.DeleteCourse(ctx, id)
|
|
}
|
|
|
|
// ReorderInProgram sets course sort_order under a program. ordered must list every course id in that program
|
|
// exactly once (e.g. from GET /programs/{id}/courses) in the desired order.
|
|
func (s *Service) ReorderInProgram(ctx context.Context, programID int64, ordered []int64) error {
|
|
if _, err := s.programs.GetProgramByID(ctx, programID); err != nil {
|
|
if errors.Is(err, pgx.ErrNoRows) {
|
|
return programs.ErrProgramNotFound
|
|
}
|
|
return err
|
|
}
|
|
expected, err := s.courses.ListCourseIDsByProgram(ctx, programID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := domain.ValidateReorderPermutation(ordered, expected); err != nil {
|
|
return err
|
|
}
|
|
if len(ordered) == 0 {
|
|
return nil
|
|
}
|
|
return s.courses.ReorderCoursesInProgram(ctx, programID, ordered)
|
|
}
|