130 lines
3.8 KiB
Python
130 lines
3.8 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
|
|
|
|
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
|
|
}
|