fediversion/backend/routers/search.py
fullsizemalt 18b102558d
Some checks failed
Deploy Fediversion / deploy (push) Failing after 1s
feat: redesign band hub page and populate song stats
2025-12-31 14:29:35 -08:00

150 lines
4.5 KiB
Python

from typing import List, Optional
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlmodel import Session, select, col
from sqlalchemy.orm import selectinload
from database import get_session
from models import Show, Song, Venue, Tour, Group, Performance, PerformanceNickname, Comment, Review, Vertical, SongCanon
router = APIRouter(prefix="/search", tags=["search"])
@router.get("/")
def global_search(
q: str,
session: Session = Depends(get_session),
limit: int = 5
):
if len(q) < 2:
return {}
q_str = f"%{q}%"
# Search Canonical Songs (The Hub)
canonical_songs = session.exec(
select(SongCanon)
.where(col(SongCanon.title).ilike(q_str))
.limit(limit)
).all()
# Search Songs (Artist Versions)
songs_raw = session.exec(
select(Song)
.options(selectinload(Song.vertical))
.where(col(Song.title).ilike(q_str))
.limit(limit)
).all()
# Serialize songs with vertical info
songs = []
for s in songs_raw:
songs.append({
"id": s.id,
"title": s.title,
"slug": s.slug,
"original_artist": s.original_artist,
"vertical": {"name": s.vertical.name, "slug": s.vertical.slug} if s.vertical else None
})
# Search Venues
venues = session.exec(
select(Venue)
.where(col(Venue.name).ilike(q_str))
.limit(limit)
).all()
# Search Tours
tours = session.exec(
select(Tour)
.where(col(Tour.name).ilike(q_str))
.limit(limit)
).all()
# Search Groups
groups = session.exec(
select(Group)
.where(col(Group.name).ilike(q_str))
.limit(limit)
).all()
# Search Verticals (Bands)
verticals = session.exec(
select(Vertical)
.where(col(Vertical.name).ilike(q_str))
.limit(limit)
).all()
# Search Nicknames
nicknames_raw = session.exec(
select(PerformanceNickname)
.options(
selectinload(PerformanceNickname.performance)
.selectinload(Performance.song),
selectinload(PerformanceNickname.performance)
.selectinload(Performance.show)
)
.where(col(PerformanceNickname.nickname).ilike(q_str))
.where(PerformanceNickname.status == "approved")
.limit(limit)
).all()
# Serialize nicknames with nested data
nicknames = []
for n in nicknames_raw:
nicknames.append({
"id": n.id,
"nickname": n.nickname,
"description": n.description,
"performance": {
"id": n.performance.id if n.performance else None,
"song": {"id": n.performance.song.id, "title": n.performance.song.title} if n.performance and n.performance.song else None,
"show": {"slug": n.performance.show.slug, "date": str(n.performance.show.date.date()) if n.performance.show else None} if n.performance and n.performance.show else None
} if n.performance else None
})
# Search Performances by notes
performances_raw = session.exec(
select(Performance)
.options(selectinload(Performance.song), selectinload(Performance.show))
.where(col(Performance.notes).ilike(q_str))
.limit(limit)
).all()
# Serialize performances with nested song/show data
performances = []
for p in performances_raw:
performances.append({
"id": p.id,
"slug": p.slug,
"notes": p.notes,
"song": {"id": p.song.id, "title": p.song.title, "slug": p.song.slug} if p.song else None,
"show": {"slug": p.show.slug, "date": str(p.show.date.date()) if p.show else None} if p.show else None
})
# Search Reviews
reviews = session.exec(
select(Review)
.where(
(col(Review.blurb).ilike(q_str)) |
(col(Review.content).ilike(q_str))
)
.limit(limit)
).all()
# Search Comments
comments = session.exec(
select(Comment)
.where(col(Comment.content).ilike(q_str))
.limit(limit)
).all()
return {
"canonical_songs": canonical_songs,
"songs": songs,
"venues": venues,
"tours": tours,
"groups": groups,
"verticals": verticals,
"nicknames": nicknames,
"performances": performances,
"reviews": reviews,
"comments": comments
}