SPB Git

spb/findata

Public
2.3 KB · 55 lines python
1from __future__ import annotations23import time45from fastapi import APIRouter, Depends, Request6from findata_core.config import get_settings7from findata_ingest.reader import dataset_views, run_sql8from pydantic import BaseModel, Field910from findata_api import auth as A11from findata_api import metrics as M12from findata_api.errors import ApiError13from findata_api.ratelimit import record_usage1415router = APIRouter(prefix="/query", tags=["query"])161718class QueryIn(BaseModel):19    sql: str = Field(..., max_length=20000)20    max_rows: int = Field(1000, ge=1, le=100_000)212223@router.post("")24def query(body: QueryIn, request: Request, p: A.Principal = Depends(A.require("query"))):25    s = get_settings()26    views = dataset_views()27    t0 = time.monotonic()28    try:29        tbl, meta = run_sql(body.sql, min(body.max_rows, s.query_max_rows), s.query_timeout_seconds, views)30    except ValueError as e:31        raise ApiError(400, "query_rejected", str(e)) from None32    except TimeoutError as e:33        raise ApiError(408, "query_timeout", str(e)) from None34    except Exception as e:35        raise ApiError(400, "query_error", str(e)[:500]) from None36    rows = tbl.to_pylist()37    for r in rows:38        for k, v in r.items():39            if hasattr(v, "isoformat"):40                r[k] = v.isoformat()41    M.ROWS.labels("query").inc(len(rows))42    record_usage(p.label, rows=len(rows))43    A.audit(request, "query.sql", None, rows=len(rows), ms=int((time.monotonic() - t0) * 1000), sql=body.sql[:500])44    return {"columns": [{"name": f.name, "type": str(f.type)} for f in tbl.schema], "rows": rows,45            "meta": {**meta, "rows": len(rows), "elapsed_ms": int((time.monotonic() - t0) * 1000),46                     "views": sorted(views), "engine": "duckdb (read-only, sandboxed, 1 statement)"}}474849@router.get("/views")50def views(p: A.Principal = Depends(A.require("query"))):51    v = dataset_views()52    return {"views": [{"name": k, "files": len(paths)} for k, paths in sorted(v.items())],53            "examples": ["SELECT symbol_as_reported, count(*) bars FROM market_bars_stock_1m_raw GROUP BY 1 ORDER BY 2 DESC LIMIT 20",54                         "SELECT session_date, min(low) lo, max(high) hi, sum(volume) vol FROM market_bars_stock_1m_raw WHERE symbol_as_reported='AAPL' GROUP BY 1 ORDER BY 1"]}55
Files · ee1dcbcefcb46b74e2ae222c3c00dc318d19817f
Menu

Theme