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"}