diff --git a/backend/internal/core/episode/ports.go b/backend/internal/core/episode/ports.go new file mode 100644 index 0000000..6a5518b --- /dev/null +++ b/backend/internal/core/episode/ports.go @@ -0,0 +1,12 @@ +package episode + +import "context" + +// UseCases captures the inbound port for episode-related interactions. +type UseCases interface { + GetCurrent(ctx context.Context) (Episode, error) + SetCurrent(ctx context.Context, id int64, start string) (Episode, error) + MoveToArchive(ctx context.Context, ids []int64) (MoveResult, error) + ListAll(ctx context.Context) ([]Episode, error) + Delete(ctx context.Context, id int64) error +} diff --git a/backend/internal/http/handlers.go b/backend/internal/http/handlers.go index 96dfd4b..fa34e73 100644 --- a/backend/internal/http/handlers.go +++ b/backend/internal/http/handlers.go @@ -7,12 +7,11 @@ import ( "time" "watch-party-backend/internal/core/episode" - "watch-party-backend/internal/service" "github.com/gin-gonic/gin" ) -func NewRouter(svc service.EpisodeService) *gin.Engine { +func NewRouter(svc episode.UseCases) *gin.Engine { r := gin.New() r.Use(gin.Logger(), gin.Recovery()) @@ -54,7 +53,7 @@ func timeHandler(c *gin.Context) { // @Failure 404 {object} HTTPError "no current row found" // @Failure 500 {object} HTTPError "query failed" // @Router /api/v1/current [get] -func getCurrentHandler(svc service.EpisodeService) gin.HandlerFunc { +func getCurrentHandler(svc episode.UseCases) gin.HandlerFunc { return func(c *gin.Context) { cur, err := svc.GetCurrent(c.Request.Context()) if err != nil { @@ -81,7 +80,7 @@ func getCurrentHandler(svc service.EpisodeService) gin.HandlerFunc { // @Failure 404 {object} HTTPError "id not found" // @Failure 500 {object} HTTPError "update failed" // @Router /api/v1/current [post] -func setCurrentHandler(svc service.EpisodeService) gin.HandlerFunc { +func setCurrentHandler(svc episode.UseCases) gin.HandlerFunc { return func(c *gin.Context) { var req SetCurrentReq if err := c.ShouldBindJSON(&req); err != nil { @@ -117,7 +116,7 @@ func setCurrentHandler(svc service.EpisodeService) gin.HandlerFunc { // @Failure 400 {object} HTTPError "empty ids" // @Failure 500 {object} HTTPError "move failed" // @Router /api/v1/archive [post] -func moveToArchiveHandler(svc service.EpisodeService) gin.HandlerFunc { +func moveToArchiveHandler(svc episode.UseCases) gin.HandlerFunc { return func(c *gin.Context) { var req MoveReq if err := c.ShouldBindJSON(&req); err != nil { @@ -158,7 +157,7 @@ func moveToArchiveHandler(svc service.EpisodeService) gin.HandlerFunc { // @Success 200 {array} CurrentResponse // @Failure 500 {object} HTTPError "list failed" // @Router /api/v1/shows [get] -func listShowsHandler(svc service.EpisodeService) gin.HandlerFunc { +func listShowsHandler(svc episode.UseCases) gin.HandlerFunc { return func(c *gin.Context) { items, err := svc.ListAll(c.Request.Context()) if err != nil { @@ -180,7 +179,7 @@ func listShowsHandler(svc service.EpisodeService) gin.HandlerFunc { // @Failure 404 {object} HTTPError "id not found" // @Failure 500 {object} HTTPError "delete failed" // @Router /api/v1/shows [delete] -func deleteShowsHandler(svc service.EpisodeService) gin.HandlerFunc { +func deleteShowsHandler(svc episode.UseCases) gin.HandlerFunc { return func(c *gin.Context) { idStr := c.Query("id") id, err := strconv.ParseInt(idStr, 10, 64) diff --git a/backend/internal/http/handlers_test.go b/backend/internal/http/handlers_test.go index 28a6031..6ee5e80 100644 --- a/backend/internal/http/handlers_test.go +++ b/backend/internal/http/handlers_test.go @@ -11,12 +11,11 @@ import ( "watch-party-backend/internal/core/episode" httpapi "watch-party-backend/internal/http" - "watch-party-backend/internal/service" "github.com/gin-gonic/gin" ) -// ---- fake service implementing service.EpisodeService ---- +// ---- fake service implementing episode.UseCases ---- type fakeSvc struct { cur episode.Episode @@ -55,7 +54,7 @@ func (f *fakeSvc) Delete(ctx context.Context, id int64) error { // ---- helpers ---- -func newRouterWithSvc(svc service.EpisodeService) *gin.Engine { +func newRouterWithSvc(svc episode.UseCases) *gin.Engine { gin.SetMode(gin.TestMode) return httpapi.NewRouter(svc) } diff --git a/backend/internal/service/episode_service.go b/backend/internal/service/episode_service.go index 4de7f94..fc160f8 100644 --- a/backend/internal/service/episode_service.go +++ b/backend/internal/service/episode_service.go @@ -8,29 +8,22 @@ import ( "watch-party-backend/internal/core/episode" ) -type EpisodeService interface { - GetCurrent(ctx context.Context) (episode.Episode, error) - SetCurrent(ctx context.Context, id int64, start string) (episode.Episode, error) - MoveToArchive(ctx context.Context, ids []int64) (episode.MoveResult, error) - ListAll(ctx context.Context) ([]episode.Episode, error) - Delete(ctx context.Context, id int64) error -} - -type episodeService struct { +// Service implements the episode.UseCases port. +type Service struct { repo episode.Repository } -func NewEpisodeService(r episode.Repository) EpisodeService { - return &episodeService{repo: r} +func NewEpisodeService(r episode.Repository) *Service { + return &Service{repo: r} } -func (s *episodeService) ListAll(ctx context.Context) ([]episode.Episode, error) { +func (s *Service) ListAll(ctx context.Context) ([]episode.Episode, error) { c, cancel := context.WithTimeout(ctx, 5*time.Second) defer cancel() return s.repo.ListAll(c) } -func (s *episodeService) GetCurrent(ctx context.Context) (episode.Episode, error) { +func (s *Service) GetCurrent(ctx context.Context) (episode.Episode, error) { c, cancel := context.WithTimeout(ctx, 3*time.Second) defer cancel() return s.repo.GetCurrent(c) @@ -38,7 +31,7 @@ func (s *episodeService) GetCurrent(ctx context.Context) (episode.Episode, error var hhmmss = regexp.MustCompile(`^(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d$`) -func (s *episodeService) SetCurrent(ctx context.Context, id int64, start string) (episode.Episode, error) { +func (s *Service) SetCurrent(ctx context.Context, id int64, start string) (episode.Episode, error) { if !hhmmss.MatchString(start) { return episode.Episode{}, episode.ErrInvalidStartTime } @@ -50,7 +43,7 @@ func (s *episodeService) SetCurrent(ctx context.Context, id int64, start string) return s.repo.GetCurrent(c) } -func (s *episodeService) MoveToArchive(ctx context.Context, ids []int64) (episode.MoveResult, error) { +func (s *Service) MoveToArchive(ctx context.Context, ids []int64) (episode.MoveResult, error) { uniq := make([]int64, 0, len(ids)) seen := make(map[int64]struct{}, len(ids)) for _, id := range ids { @@ -68,7 +61,7 @@ func (s *episodeService) MoveToArchive(ctx context.Context, ids []int64) (episod return s.repo.MoveToArchive(c, uniq) } -func (s *episodeService) Delete(ctx context.Context, id int64) error { +func (s *Service) Delete(ctx context.Context, id int64) error { c, cancel := context.WithTimeout(ctx, 5*time.Second) defer cancel() return s.repo.Delete(c, id)