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 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 Songs songs = session.exec( select(Song) .where(col(Song.title).ilike(q_str)) .limit(limit) ).all() # 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 { "songs": songs, "venues": venues, "tours": tours, "groups": groups, "verticals": verticals, "nicknames": nicknames, "performances": performances, "reviews": reviews, "comments": comments }