feat(backend): Add Heady Jams to leaderboards and optimize queries
Some checks are pending
Deploy Elmeg / deploy (push) Waiting to run
Some checks are pending
Deploy Elmeg / deploy (push) Waiting to run
This commit is contained in:
parent
5c53fbc497
commit
6407c19a29
1 changed files with 63 additions and 20 deletions
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue