from __future__ import annotations from typing import Any, Dict, Optional import httpx from app.config import settings class SupabaseRestClient: """轻量封装 Supabase RESTful API,兼容本地 sb_secret 密钥。""" def __init__(self) -> None: base_url = settings.supabase_url.rstrip("/") apikey = settings.supabase_anon_key or settings.supabase_service_role_key self.client = httpx.Client( base_url=f"{base_url}/rest/v1", headers={ "apikey": apikey, "Authorization": f"Bearer {settings.supabase_service_role_key}", }, timeout=10.0, ) def insert(self, table: str, payload: Dict[str, Any]) -> Dict[str, Any]: response = self.client.post( f"/{table}", json=payload, headers={"Prefer": "return=representation"}, ) response.raise_for_status() data = response.json() if isinstance(data, list): return data[0] return data def select_one(self, table: str, filters: Dict[str, Any]) -> Optional[Dict[str, Any]]: params = {key: f"eq.{value}" for key, value in filters.items()} params["select"] = "*" response = self.client.get(f"/{table}", params=params) response.raise_for_status() data = response.json() if isinstance(data, list) and data: return data[0] return None def select( self, table: str, filters: Optional[Dict[str, Any]] = None, *, columns: str = "*", order: Optional[str] = None, limit: Optional[int] = None, ) -> list[Dict[str, Any]]: params: Dict[str, Any] = {"select": columns} if filters: for key, value in filters.items(): params[key] = f"eq.{value}" if order: params["order"] = order if limit is not None: params["limit"] = limit response = self.client.get(f"/{table}", params=params) response.raise_for_status() data = response.json() if isinstance(data, list): return data if data: return [data] return [] def update(self, table: str, filters: Dict[str, Any], payload: Dict[str, Any]) -> None: params = {key: f"eq.{value}" for key, value in filters.items()} response = self.client.patch( f"/{table}", params=params, json=payload, headers={"Prefer": "return=minimal"}, ) response.raise_for_status() supabase_rest = SupabaseRestClient()