Initial commit: invest-copilot app
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
import database
|
||||
"""Stock search endpoint — GET /api/v1/search."""
|
||||
|
||||
import logging
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, Query
|
||||
|
||||
from database import execute_query
|
||||
from schemas.stock import SearchResult
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
router = APIRouter(prefix="/search", tags=["stocks"])
|
||||
|
||||
|
||||
@router.get(
|
||||
"",
|
||||
summary="Search stocks by ticker or name",
|
||||
response_model=list[SearchResult],
|
||||
responses={400: {"description": "Invalid search query"}},
|
||||
)
|
||||
async def search_stocks(
|
||||
q: str = Query(..., min_length=1, max_length=50, description="Search query"),
|
||||
limit: int = Query(default=10, ge=1, le=50),
|
||||
):
|
||||
"""Search stocks by ticker symbol or company name.
|
||||
|
||||
Uses full-text search across stock_profiles table.
|
||||
"""
|
||||
like_pattern = f"{q}%"
|
||||
sql = """
|
||||
SELECT ticker, name, exchange, sector, market_cap
|
||||
FROM stock_profiles
|
||||
WHERE ticker ILIKE $1 OR name ILIKE $2
|
||||
ORDER BY
|
||||
CASE WHEN ticker ILIKE $1 THEN 0 ELSE 1 END,
|
||||
name
|
||||
LIMIT $3
|
||||
"""
|
||||
rows = await database.execute_query(sql, (like_pattern, f"%{q}%", limit))
|
||||
|
||||
results = []
|
||||
for row in rows:
|
||||
results.append(SearchResult(
|
||||
ticker=row["ticker"],
|
||||
name=row["name"],
|
||||
exchange=row["exchange"],
|
||||
sector=row["sector"],
|
||||
marketCap=float(row["market_cap"]) if row["market_cap"] else None,
|
||||
))
|
||||
|
||||
return results
|
||||
Reference in New Issue
Block a user