feat(api): song search endpoint and PATCH /songs/{id}
GET /bands/{id}/songs/search — filter by title (ILIKE), tags (contains
all), key, BPM range, session_id. All params optional and composable.
PATCH /songs/{id} — update title, status, notes, tags, key, BPM.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import uuid
|
||||
from typing import Any
|
||||
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.orm import selectinload
|
||||
@@ -41,6 +42,43 @@ class SongRepository(BaseRepository[Song]):
|
||||
result = await self.session.execute(stmt)
|
||||
return result.scalar_one_or_none()
|
||||
|
||||
async def search(
|
||||
self,
|
||||
band_id: uuid.UUID,
|
||||
q: str | None = None,
|
||||
tags: list[str] | None = None,
|
||||
key: str | None = None,
|
||||
bpm_min: float | None = None,
|
||||
bpm_max: float | None = None,
|
||||
session_id: uuid.UUID | None = None,
|
||||
) -> list[Song]:
|
||||
from sqlalchemy import cast, func
|
||||
from sqlalchemy.dialects.postgresql import ARRAY
|
||||
from sqlalchemy import Text
|
||||
|
||||
stmt = (
|
||||
select(Song)
|
||||
.where(Song.band_id == band_id)
|
||||
.options(selectinload(Song.versions))
|
||||
.order_by(Song.updated_at.desc())
|
||||
)
|
||||
if q:
|
||||
stmt = stmt.where(Song.title.ilike(f"%{q}%"))
|
||||
if tags:
|
||||
# songs.tags must contain ALL requested tags
|
||||
stmt = stmt.where(Song.tags.contains(cast(tags, ARRAY(Text))))
|
||||
if key:
|
||||
stmt = stmt.where(func.lower(Song.global_key) == key.lower())
|
||||
if bpm_min is not None:
|
||||
stmt = stmt.where(Song.global_bpm >= bpm_min)
|
||||
if bpm_max is not None:
|
||||
stmt = stmt.where(Song.global_bpm <= bpm_max)
|
||||
if session_id is not None:
|
||||
stmt = stmt.where(Song.session_id == session_id)
|
||||
|
||||
result = await self.session.execute(stmt)
|
||||
return list(result.scalars().all())
|
||||
|
||||
async def next_version_number(self, song_id: uuid.UUID) -> int:
|
||||
from sqlalchemy import func
|
||||
|
||||
|
||||
Reference in New Issue
Block a user