File size: 8,063 Bytes
447d423 |
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 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 |
# crud.py (reemplaza la versión SQLAlchemy)
import os
import httpx
from dotenv import load_dotenv
from typing import Dict, Optional, List
from fastapi import HTTPException
load_dotenv()
SUPABASE_URL = os.getenv("SUPABASE_URL").rstrip("/")
SUPABASE_KEY = os.getenv("SUPABASE_KEY")
database_service_Key = os.getenv("database_service_Key")
TABLE = os.getenv("TABLE_NAME", "idioms")
HEADERS = {
"apikey": database_service_Key,
"Authorization": f"Bearer {database_service_Key}",
"Content-Type": "application/json",
"Accept": "application/json",
}
# helpers
async def _client():
return httpx.AsyncClient(timeout=30.0)
# CRUD
async def get_idioms(skip: int = 0, limit: int = 100000):
async with httpx.AsyncClient() as client:
url = f"{SUPABASE_URL}/rest/v1/{TABLE}?select=*&offset={skip}&limit={limit}"
print("Supabase GET URL:", url)
r = await client.get(url, headers=HEADERS)
print("Supabase GET status:", r.status_code)
print("Supabase GET response:", r.text)
r.raise_for_status()
return r.json()
async def get_all_idioms():
all_idioms = []
limit = 1000 # Supabase max per request
offset = 0
async with httpx.AsyncClient(timeout=60.0) as client:
while True:
url = f"{SUPABASE_URL}/rest/v1/{TABLE}?select=*&limit={limit}&offset={offset}"
r = await client.get(url, headers=HEADERS)
r.raise_for_status()
data = r.json()
if not data:
break
# ensure validation_count is a dict
for item in data:
if not isinstance(item.get("validation_count"), dict):
item["validation_count"] = {}
all_idioms.extend(data)
offset += limit
return all_idioms
async def get_idiom(idiom_id: str):
async with httpx.AsyncClient() as client:
try:
# Include both examples and meanings via foreign key embedding
url = (
f"{SUPABASE_URL}/rest/v1/{TABLE}?"
f"id=eq.{idiom_id}&"
f"select=*,"
f"idiom_meanings!idiom_meanings_idiom_id_fkey(*),"
f"examples!examples_idiom_id_fkey(*)"
)
print(f"Fetching idiom from Supabase: {url}") # debug
r = await client.get(url, headers=HEADERS)
print("HTTP status code:", r.status_code) # debug
r.raise_for_status()
data = r.json()
print("Raw data from Supabase:", data) # debug
except httpx.RequestError as e:
print("Request failed:", e)
raise HTTPException(status_code=500, detail=f"Supabase request failed: {e}")
except httpx.HTTPStatusError as e:
print("HTTP error:", e)
raise HTTPException(status_code=500, detail=f"Supabase HTTP error: {e}")
except Exception as e:
print("Unexpected error:", e)
raise HTTPException(status_code=500, detail=f"Unexpected error: {e}")
if not data:
print(f"No idiom found for id: {idiom_id}") # debug
return None
idiom = data[0]
if not isinstance(idiom, dict):
print(f"Unexpected data type for idiom: {type(idiom)}") # debug
raise ValueError(f"Expected dict, got: {type(idiom)}")
# --- Transform examples ---
raw_examples = idiom.get("examples") or []
idiom["examples"] = [
{
"id": ex.get("id"),
"source_text": ex.get("source_text") or "",
"source_language": ex.get("source_language") or idiom.get("language"),
"translations": json.loads(ex["translations"]) if isinstance(ex.get("translations"), str) else ex.get("translations") or [],
"dialect": ex.get("dialect"),
"url": ex.get("url"),
"source": ex.get("source"),
}
for ex in raw_examples
]
print(f"Found {len(idiom['examples'])} examples") # debug
# --- Transform meanings ---
raw_meanings = idiom.get("idiom_meanings") or []
print("Raw meanings data:", raw_meanings) # debug
idiom["meanings"] = [
{
"meaning_id": m.get("meaning_id"),
"idiom_id": m.get("idiom_id"),
"sense_number": m.get("sense_number"),
"register": m.get("register") or [],
"region": m.get("region") or [],
"definitions": m.get("definitions") or [],
"version": m.get("version"), # optional, if you need it
}
for m in raw_meanings
]
print("Transformed meanings data:", idiom["meanings"]) # debug
print(f"Found {len(idiom['meanings'])} meanings") # debug
return idiom
async def search_idioms(query: str = "", language: Optional[str] = None, skip: int = 0, limit: int = 50):
async with httpx.AsyncClient() as client:
# Compose select param to embed idiom_meanings
select_query = "*,idiom_meanings!idiom_meanings_idiom_id_fkey(*)"
url = (
f"{SUPABASE_URL}/rest/v1/{TABLE}"
f"?offset={skip}&limit={limit}&select={select_query}"
)
# Maintain partial text match on idiom column
if query:
url += f"&idiom=ilike.*{query}*"
# Maintain language filter if specified and not "all"
if language and language.lower() not in ("all", "*"):
url += f"&language=eq.{language}"
r = await client.get(url, headers=HEADERS)
r.raise_for_status()
data = r.json()
# Ensure validation_count is a dict
for item in data:
if not isinstance(item.get("validation_count"), dict):
item["validation_count"] = {}
# Transform embedded idiom_meanings to meanings field for UI use
raw_meanings = item.get("idiom_meanings") or []
item["meanings"] = [
{
"meaning_id": m.get("meaning_id"),
"idiom_id": m.get("idiom_id"),
"sense_number": m.get("sense_number"),
"register": m.get("register") or [],
"region": m.get("region") or [],
"definitions": m.get("definitions") or [],
"version": m.get("version"),
}
for m in raw_meanings
]
return data
async def create_idiom(item: dict):
async with httpx.AsyncClient() as client:
url = f"{SUPABASE_URL}/rest/v1/{TABLE}"
r = await client.post(url, json=item, headers=HEADERS)
r.raise_for_status() # fail if not 2xx
try:
data = r.json()
except ValueError:
# Supabase returned empty body, fallback to the original item
data = item
if isinstance(data, list) and data:
return data[0]
if isinstance(data, dict) and data:
return data
# final fallback
return item
async def update_idiom(idiom_id: str, item: dict):
async with httpx.AsyncClient() as client:
url = f"{SUPABASE_URL}/rest/v1/{TABLE}?id=eq.{idiom_id}"
r = await client.patch(url, json=item, headers=HEADERS)
if r.status_code not in (200, 204):
raise httpx.HTTPStatusError("Update failed", request=r.request, response=r)
# After patch, fetch the updated row
return await get_idiom(idiom_id)
async def delete_idiom(idiom_id: str):
async with httpx.AsyncClient() as client:
url = f"{SUPABASE_URL}/rest/v1/{TABLE}?id=eq.{idiom_id}"
r = await client.delete(url, headers=HEADERS)
if r.status_code not in (200, 204):
raise httpx.HTTPStatusError("Delete failed", request=r.request, response=r)
return {"status": "deleted"}
|