refactor: wrap bare errors with context in anime package
This commit is contained in:
@@ -35,17 +35,19 @@ type browseQuery struct {
|
||||
func producerQueryParams(c *gin.Context) (string, int, int, error) {
|
||||
q := strings.TrimSpace(c.Query("q"))
|
||||
|
||||
page, err := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||||
rawPage := c.DefaultQuery("page", "1")
|
||||
page, err := strconv.Atoi(rawPage)
|
||||
if err != nil {
|
||||
return "", 0, 0, fmt.Errorf("invalid page")
|
||||
return "", 0, 0, fmt.Errorf("invalid page %q: %w", rawPage, err)
|
||||
}
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
|
||||
limit, err := strconv.Atoi(c.DefaultQuery("limit", "50"))
|
||||
rawLimit := c.DefaultQuery("limit", "50")
|
||||
limit, err := strconv.Atoi(rawLimit)
|
||||
if err != nil {
|
||||
return "", 0, 0, fmt.Errorf("invalid limit")
|
||||
return "", 0, 0, fmt.Errorf("invalid limit %q: %w", rawLimit, err)
|
||||
}
|
||||
if limit < 1 || limit > 12 {
|
||||
limit = 12
|
||||
@@ -137,8 +139,11 @@ func parseBrowseQuery(c *gin.Context) (browseQuery, error) {
|
||||
studioID := 0
|
||||
if raw := strings.TrimSpace(c.Query("studio")); raw != "" {
|
||||
id, err := strconv.Atoi(raw)
|
||||
if err != nil || id < 0 {
|
||||
return browseQuery{}, fmt.Errorf("invalid studio id")
|
||||
if err != nil {
|
||||
return browseQuery{}, fmt.Errorf("invalid studio id %q: %w", raw, err)
|
||||
}
|
||||
if id < 0 {
|
||||
return browseQuery{}, fmt.Errorf("invalid studio id %d", id)
|
||||
}
|
||||
studioID = id
|
||||
}
|
||||
@@ -147,16 +152,17 @@ func parseBrowseQuery(c *gin.Context) (browseQuery, error) {
|
||||
for _, g := range c.QueryArray("genres") {
|
||||
id, err := strconv.Atoi(g)
|
||||
if err != nil {
|
||||
return browseQuery{}, fmt.Errorf("invalid genre id")
|
||||
return browseQuery{}, fmt.Errorf("invalid genre id %q: %w", g, err)
|
||||
}
|
||||
if id > 0 {
|
||||
genres = append(genres, id)
|
||||
}
|
||||
}
|
||||
|
||||
page, err := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||||
rawPage := c.DefaultQuery("page", "1")
|
||||
page, err := strconv.Atoi(rawPage)
|
||||
if err != nil {
|
||||
return browseQuery{}, fmt.Errorf("invalid page")
|
||||
return browseQuery{}, fmt.Errorf("invalid page %q: %w", rawPage, err)
|
||||
}
|
||||
if page < 1 {
|
||||
page = 1
|
||||
|
||||
@@ -2,6 +2,7 @@ package recommendations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"mal/integrations/jikan"
|
||||
"mal/internal/domain"
|
||||
"mal/internal/observability"
|
||||
@@ -35,7 +36,7 @@ func (e engine) getTopPicksForYou(ctx context.Context, userID string, resultLimi
|
||||
|
||||
watchlist, err := e.repo.GetUserWatchList(ctx, userID)
|
||||
if err != nil {
|
||||
return domain.CatalogSectionData{}, err
|
||||
return domain.CatalogSectionData{}, fmt.Errorf("get user watchlist for %q: %w", userID, err)
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
@@ -46,17 +47,17 @@ func (e engine) getTopPicksForYou(ctx context.Context, userID string, resultLimi
|
||||
|
||||
seedAnimes, err := e.fetchSeedAnimes(ctx, seedPool)
|
||||
if err != nil {
|
||||
return domain.CatalogSectionData{}, err
|
||||
return domain.CatalogSectionData{}, fmt.Errorf("fetch seed animes: %w", err)
|
||||
}
|
||||
|
||||
profile := buildTasteProfile(now, seedPool, seedAnimes)
|
||||
store := newCandidateStore(watchlist)
|
||||
|
||||
if err := e.collectCollaborativeCandidates(ctx, seedPool, store); err != nil {
|
||||
return domain.CatalogSectionData{}, err
|
||||
return domain.CatalogSectionData{}, fmt.Errorf("collect collaborative candidates: %w", err)
|
||||
}
|
||||
if err := e.collectProfileSearchCandidates(ctx, profile, store); err != nil {
|
||||
return domain.CatalogSectionData{}, err
|
||||
return domain.CatalogSectionData{}, fmt.Errorf("collect profile search candidates: %w", err)
|
||||
}
|
||||
|
||||
ranked := store.ranked()
|
||||
@@ -66,7 +67,7 @@ func (e engine) getTopPicksForYou(ctx context.Context, userID string, resultLimi
|
||||
|
||||
candidates, err := e.scoreRankedCandidates(ctx, now, profile, ranked, resultLimit)
|
||||
if err != nil {
|
||||
return domain.CatalogSectionData{}, err
|
||||
return domain.CatalogSectionData{}, fmt.Errorf("score ranked candidates: %w", err)
|
||||
}
|
||||
|
||||
return domain.CatalogSectionData{
|
||||
@@ -83,7 +84,7 @@ func (e engine) fetchSeedAnimes(ctx context.Context, seedPool []recommendationSe
|
||||
g.Go(func() error {
|
||||
anime, err := e.jikan.GetAnimeByID(ctx, seed.animeID)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("get seed anime %d: %w", seed.animeID, err)
|
||||
}
|
||||
seedAnimes[i] = anime
|
||||
return nil
|
||||
@@ -91,7 +92,7 @@ func (e engine) fetchSeedAnimes(ctx context.Context, seedPool []recommendationSe
|
||||
}
|
||||
|
||||
if err := g.Wait(); err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("wait for seed anime fetches: %w", err)
|
||||
}
|
||||
|
||||
return seedAnimes, nil
|
||||
@@ -131,7 +132,10 @@ func (e engine) collectCollaborativeCandidates(ctx context.Context, seedPool []r
|
||||
})
|
||||
}
|
||||
|
||||
return g.Wait()
|
||||
if err := g.Wait(); err != nil {
|
||||
return fmt.Errorf("wait for collaborative candidate fetches: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e engine) collectProfileSearchCandidates(ctx context.Context, profile userTasteProfile, store *candidateStore) error {
|
||||
@@ -183,7 +187,10 @@ func (e engine) collectProfileSearchCandidates(ctx context.Context, profile user
|
||||
})
|
||||
}
|
||||
|
||||
return g.Wait()
|
||||
if err := g.Wait(); err != nil {
|
||||
return fmt.Errorf("wait for profile search candidate fetches: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e engine) scoreRankedCandidates(
|
||||
@@ -233,7 +240,7 @@ func (e engine) scoreRankedCandidates(
|
||||
}
|
||||
|
||||
if err := g.Wait(); err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("wait for candidate scoring: %w", err)
|
||||
}
|
||||
|
||||
sort.Slice(candidates, func(i, j int) bool {
|
||||
|
||||
@@ -15,14 +15,19 @@ type reviewsQuery struct {
|
||||
}
|
||||
|
||||
func parseReviewsQuery(c *gin.Context) (reviewsQuery, error) {
|
||||
id, err := strconv.Atoi(c.Param("id"))
|
||||
if err != nil || id <= 0 {
|
||||
return reviewsQuery{}, fmt.Errorf("invalid anime id")
|
||||
rawID := c.Param("id")
|
||||
id, err := strconv.Atoi(rawID)
|
||||
if err != nil {
|
||||
return reviewsQuery{}, fmt.Errorf("invalid anime id %q: %w", rawID, err)
|
||||
}
|
||||
if id <= 0 {
|
||||
return reviewsQuery{}, fmt.Errorf("invalid anime id %d", id)
|
||||
}
|
||||
|
||||
page, err := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||||
rawPage := c.DefaultQuery("page", "1")
|
||||
page, err := strconv.Atoi(rawPage)
|
||||
if err != nil {
|
||||
return reviewsQuery{}, fmt.Errorf("invalid page")
|
||||
return reviewsQuery{}, fmt.Errorf("invalid page %q: %w", rawPage, err)
|
||||
}
|
||||
if page < 1 {
|
||||
page = 1
|
||||
|
||||
@@ -47,19 +47,25 @@ func (s *animeService) GetCatalogSection(ctx context.Context, userID string, sec
|
||||
case "Popular":
|
||||
res, err = s.jikan.GetTopAnime(gCtx, 1)
|
||||
}
|
||||
return err
|
||||
if err != nil {
|
||||
return fmt.Errorf("get catalog section %q: %w", section, err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if userID != "" && section == "Continue" {
|
||||
g.Go(func() error {
|
||||
var err error
|
||||
cw, err = s.repo.GetContinueWatchingEntries(gCtx, userID)
|
||||
return err
|
||||
if err != nil {
|
||||
return fmt.Errorf("get continue watching entries for %q: %w", userID, err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
if err := g.Wait(); err != nil {
|
||||
return domain.CatalogSectionData{}, err
|
||||
return domain.CatalogSectionData{}, fmt.Errorf("wait for catalog section %q: %w", section, err)
|
||||
}
|
||||
|
||||
animes := wrapAnimes(res.Animes)
|
||||
@@ -300,7 +306,7 @@ func (s *animeService) GetRandomAnime(ctx context.Context) (domain.Anime, error)
|
||||
return domain.Anime{Anime: res.Animes[r.Intn(len(res.Animes))]}, nil
|
||||
}
|
||||
|
||||
return domain.Anime{}, err
|
||||
return domain.Anime{}, fmt.Errorf("get random anime: %w", err)
|
||||
}
|
||||
|
||||
func (s *animeService) GetAllEpisodes(ctx context.Context, id int) ([]domain.EpisodeData, error) {
|
||||
|
||||
Reference in New Issue
Block a user