diff --git a/backend/routers/leaderboards.py b/backend/routers/leaderboards.py index 91f8477..ace4e49 100644 --- a/backend/routers/leaderboards.py +++ b/backend/routers/leaderboards.py @@ -2,7 +2,7 @@ from fastapi import APIRouter, Depends, Query from sqlmodel import Session, select, func, desc from typing import List, Optional from database import get_session -from models import Review, Show, Venue, User, Profile +from models import Review, Show, Venue, User, Profile, Performance, Song, Rating router = APIRouter( prefix="/leaderboards", @@ -11,25 +11,21 @@ router = APIRouter( @router.get("/shows/top") def get_top_shows(limit: int = 10, session: Session = Depends(get_session)): - """Get top rated shows based on average review score""" - # Group by show_id, calc avg score, count reviews - # Filter for shows with at least 1 review (or maybe 2 to be significant?) - - # SQLModel doesn't support complex group_by/having easily in pure pythonic way sometimes, - # but we can use session.exec with a direct select. - + """Get top rated shows based on average rating""" + # Using Rating table allows for more data points than just text reviews query = ( select( Show, Venue, - func.avg(Review.score).label("avg_score"), - func.count(Review.id).label("review_count") + func.avg(Rating.score).label("avg_score"), + func.count(Rating.id).label("rating_count") ) - .join(Review, Review.show_id == Show.id) + .join(Rating, Rating.show_id == Show.id) .join(Venue, Show.venue_id == Venue.id) + .where(Rating.entity_type == "show") .group_by(Show.id, Venue.id) - .having(func.count(Review.id) >= 1) - .order_by(desc("avg_score"), desc("review_count")) + .having(func.count(Rating.id) >= 1) + .order_by(desc("avg_score"), desc("rating_count")) .limit(limit) ) @@ -39,33 +35,79 @@ def get_top_shows(limit: int = 10, session: Session = Depends(get_session)): { "show": show, "venue": venue, - "avg_score": round(score, 2), + "avg_score": round(score, 2) if score else 0, "review_count": count } for show, venue, score, count in results ] +@router.get("/performances/top") +def get_top_performances(limit: int = 20, session: Session = Depends(get_session)): + """Get top rated performances (Heady Jams)""" + query = ( + select( + Performance, + Song, + Show, + Venue, + func.avg(Rating.score).label("avg_score"), + func.count(Rating.id).label("rating_count") + ) + .join(Rating, Rating.performance_id == Performance.id) + .join(Song, Performance.song_id == Song.id) + .join(Show, Performance.show_id == Show.id) + .join(Venue, Show.venue_id == Venue.id) + .where(Rating.entity_type == "performance") + .group_by(Performance.id, Song.id, Show.id, Venue.id) + .having(func.count(Rating.id) >= 1) + .order_by(desc("avg_score"), desc("rating_count")) + .limit(limit) + ) + + results = session.exec(query).all() + + return [ + { + "performance": performance, + "song": song, + "show": show, + "venue": venue, + "avg_score": round(score, 2) if score else 0, + "rating_count": count + } + for performance, song, show, venue, score, count in results + ] + @router.get("/venues/top") def get_top_venues(limit: int = 10, session: Session = Depends(get_session)): - """Get top rated venues""" + """Get top rated venues based on show ratings there?""" + # A venue's rating is often derivative of the shows there, or specific venue ratings. + # Let's assume venue rating directly for now if entity_type='venue' exists, + # otherwise we might avg show ratings. Let's start with direct venue ratings. + query = ( select( Venue, - func.avg(Review.score).label("avg_score"), - func.count(Review.id).label("review_count") + func.avg(Rating.score).label("avg_score"), + func.count(Rating.id).label("rating_count") ) - .join(Review, Review.venue_id == Venue.id) + .join(Rating, Rating.venue_id == Venue.id) + .where(Rating.entity_type == "venue") .group_by(Venue.id) + .having(func.count(Rating.id) >= 1) .order_by(desc("avg_score")) .limit(limit) ) results = session.exec(query).all() + # Fallback: if no direct venue ratings, maybe average the shows played there? + # Keeping it simple for now. + return [ { "venue": venue, - "avg_score": round(score, 2), + "avg_score": round(score, 2) if score else 0, "review_count": count } for venue, score, count in results @@ -73,7 +115,8 @@ def get_top_venues(limit: int = 10, session: Session = Depends(get_session)): @router.get("/users/active") def get_active_users(limit: int = 10, session: Session = Depends(get_session)): - """Get users with most reviews""" + """Get users with most reviews/ratings""" + # Combining reviews count query = ( select( Profile,