Yimaru-BackEnd/internal/services/modules/service.go

112 lines
3.1 KiB
Go

package modules
import (
"Yimaru-Backend/internal/domain"
"Yimaru-Backend/internal/ports"
"Yimaru-Backend/internal/services/courses"
"context"
"errors"
"github.com/jackc/pgx/v5"
)
var ErrModuleNotFound = errors.New("module not found")
type Service struct {
modules ports.ModuleStore
courses ports.CourseStore
}
func NewService(modules ports.ModuleStore, courses ports.CourseStore) *Service {
return &Service{modules: modules, courses: courses}
}
func (s *Service) getCourseOrErr(ctx context.Context, courseID int64) (domain.Course, error) {
c, err := s.courses.GetCourseByID(ctx, courseID)
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
return domain.Course{}, courses.ErrCourseNotFound
}
return domain.Course{}, err
}
return c, nil
}
// Create loads the course and stores program_id from it (parent program is not taken from the URL).
func (s *Service) Create(ctx context.Context, courseID int64, input domain.CreateModuleInput) (domain.Module, error) {
c, err := s.getCourseOrErr(ctx, courseID)
if err != nil {
return domain.Module{}, err
}
return s.modules.CreateModule(ctx, c.ProgramID, courseID, input)
}
func (s *Service) GetByID(ctx context.Context, id int64) (domain.Module, error) {
m, err := s.modules.GetModuleByID(ctx, id)
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
return domain.Module{}, ErrModuleNotFound
}
return domain.Module{}, err
}
return m, nil
}
// ListByCourse loads the course and lists modules for its program_id and course_id.
func (s *Service) ListByCourse(ctx context.Context, courseID int64, limit, offset int32) ([]domain.Module, int64, error) {
c, err := s.getCourseOrErr(ctx, courseID)
if err != nil {
return nil, 0, err
}
if limit <= 0 {
limit = 20
}
if limit > 200 {
limit = 200
}
if offset < 0 {
offset = 0
}
return s.modules.ListModulesByProgramAndCourse(ctx, c.ProgramID, courseID, limit, offset)
}
func (s *Service) Update(ctx context.Context, id int64, input domain.UpdateModuleInput) (domain.Module, error) {
m, err := s.modules.UpdateModule(ctx, id, input)
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
return domain.Module{}, ErrModuleNotFound
}
return domain.Module{}, err
}
return m, nil
}
func (s *Service) Delete(ctx context.Context, id int64) error {
if _, err := s.modules.GetModuleByID(ctx, id); err != nil {
if errors.Is(err, pgx.ErrNoRows) {
return ErrModuleNotFound
}
return err
}
return s.modules.DeleteModule(ctx, id)
}
// ReorderInCourse sets module sort_order under a course. ordered must list every module id in that course
// exactly once (e.g. from GET /courses/{id}/modules) in the desired order.
func (s *Service) ReorderInCourse(ctx context.Context, courseID int64, ordered []int64) error {
if _, err := s.getCourseOrErr(ctx, courseID); err != nil {
return err
}
expected, err := s.modules.ListModuleIDsByCourse(ctx, courseID)
if err != nil {
return err
}
if err := domain.ValidateReorderPermutation(ordered, expected); err != nil {
return err
}
if len(ordered) == 0 {
return nil
}
return s.modules.ReorderModulesInCourse(ctx, courseID, ordered)
}