fediversion/backend/routers/search.py
fullsizemalt b4cddf41ea feat: Initialize Fediversion multi-band platform
- Fork elmeg-demo codebase for multi-band support
- Add data importer infrastructure with base class
- Create band-specific importers:
  - phish.py: Phish.net API v5
  - grateful_dead.py: Grateful Stats API
  - setlistfm.py: Dead & Company, Billy Strings (Setlist.fm)
- Add spec-kit configuration for Gemini
- Update README with supported bands and architecture
2025-12-28 12:39:28 -08:00

122 lines
3.6 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
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 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,
"nicknames": nicknames,
"performances": performances,
"reviews": reviews,
"comments": comments
}