Spaces:
Running
Running
File size: 4,862 Bytes
9aab9db | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 | """
Supabase database client
"""
from typing import Any, Dict, List, Optional
from contextlib import asynccontextmanager
from supabase import create_client, Client
from postgrest.exceptions import APIError
from app.config import settings
from app.utils.logging import get_logger
logger = get_logger("database")
class DatabaseClient:
"""Supabase database client wrapper"""
_instance = None
_client: Optional[Client] = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
def connect(self) -> Client:
"""Initialize Supabase client"""
if self._client is None:
try:
self._client = create_client(
settings.supabase_url,
settings.supabase_service_key or settings.supabase_key
)
logger.info("Supabase client initialized")
except Exception as e:
logger.error("Failed to initialize Supabase client", error=str(e))
raise
return self._client
@property
def client(self) -> Client:
"""Get Supabase client"""
if self._client is None:
return self.connect()
return self._client
@property
def table(self):
"""Get table builder"""
return self.client.table
async def fetch_one(
self,
table: str,
filters: Optional[Dict[str, Any]] = None
) -> Optional[Dict[str, Any]]:
"""Fetch single record"""
try:
query = self.table(table)
if filters:
for key, value in filters.items():
query = query.eq(key, value)
result = await query.execute()
if result.data and len(result.data) > 0:
return result.data[0]
return None
except Exception as e:
logger.error(f"Error fetching from {table}", error=str(e))
return None
async def fetch_many(
self,
table: str,
filters: Optional[Dict[str, Any]] = None,
order_by: Optional[str] = None,
ascending: bool = True,
limit: int = 100,
offset: int = 0
) -> List[Dict[str, Any]]:
"""Fetch multiple records"""
try:
query = self.table(table)
if filters:
for key, value in filters.items():
query = query.eq(key, value)
if order_by:
query = query.order(order_by, desc=not ascending)
result = await query.limit(limit).offset(offset).execute()
return result.data or []
except Exception as e:
logger.error(f"Error fetching from {table}", error=str(e))
return []
async def insert(
self,
table: str,
data: Dict[str, Any] | List[Dict[str, Any]]
) -> Optional[Dict[str, Any] | List[Dict[str, Any]]]:
"""Insert record(s)"""
try:
result = await self.table(table).insert(data).execute()
return result.data
except Exception as e:
logger.error(f"Error inserting into {table}", error=str(e))
return None
async def update(
self,
table: str,
data: Dict[str, Any],
filters: Dict[str, Any]
) -> Optional[List[Dict[str, Any]]]:
"""Update record(s)"""
try:
query = self.table(table)
for key, value in filters.items():
query = query.eq(key, value)
result = await query.update(data).execute()
return result.data
except Exception as e:
logger.error(f"Error updating {table}", error=str(e))
return None
async def delete(
self,
table: str,
filters: Dict[str, Any]
) -> bool:
"""Delete record(s)"""
try:
query = self.table(table)
for key, value in filters.items():
query = query.eq(key, value)
await query.delete().execute()
return True
except Exception as e:
logger.error(f"Error deleting from {table}", error=str(e))
return False
async def rpc(
self,
function_name: str,
params: Optional[Dict[str, Any]] = None
) -> Any:
"""Call stored procedure"""
try:
result = await self.client.rpc(function_name, params or {}).execute()
return result.data
except Exception as e:
logger.error(f"Error calling RPC {function_name}", error=str(e))
return None
# Global database instance
db = DatabaseClient()
|