File size: 12,593 Bytes
84d3b50
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
import gradio as gr
import os
from typing import List, Dict, Any
import pandas as pd
from dotenv import load_dotenv
from supabase import create_client, Client

# Load environment variables
load_dotenv()

class SupabaseConnection:
    def __init__(self):
        """Initialize Supabase client using API key"""
        self.url = "https://bnjblzcqaumctpehgoid.supabase.co"
        self.key = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImJuamJsemNxYXVtY3RwZWhnb2lkIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTgyOTA0OTQsImV4cCI6MjA3Mzg2NjQ5NH0.L4wPzuBj9dlSKpYxO1eDX-57KcP0mbNfN8stmTB-STM"
        
        try:
            self.supabase: Client = create_client(self.url, self.key)
            self.connection_status = "βœ… Supabase connection successful!"
        except Exception as e:
            self.supabase = None
            self.connection_status = f"❌ Supabase connection failed: {str(e)}"
    
    def test_connection(self) -> str:
        """Test the Supabase connection"""
        if not self.supabase:
            return self.connection_status
        
        try:
            # Try to fetch from a system table to test connection
            result = self.supabase.rpc('version').execute()
            return "βœ… Supabase connection is working!"
        except Exception as e:
            return f"❌ Connection test failed: {str(e)}"
    
    def get_tables(self) -> List[str]:
        """Get list of tables from the database"""
        if not self.supabase:
            return ["No connection"]
        
        try:
            # Get tables from information schema
            result = self.supabase.rpc('get_tables_list').execute()
            if result.data:
                return result.data
            else:
                # Fallback: try to get some common table names
                # This is a workaround since direct SQL queries might be limited
                return ["users", "posts", "profiles"]  # Common table names
        except Exception as e:
            return [f"Error: {str(e)}"]
    
    def get_table_data(self, table_name: str, limit: int = 100) -> pd.DataFrame:
        """Get data from a specific table"""
        if not self.supabase:
            return pd.DataFrame([{"Error": "No Supabase connection"}])
        
        if not table_name or table_name == "No connection":
            return pd.DataFrame([{"Message": "Please select a valid table"}])
        
        try:
            # Query the table
            result = self.supabase.table(table_name).select("*").limit(limit).execute()
            
            if result.data:
                return pd.DataFrame(result.data)
            else:
                return pd.DataFrame([{"Message": f"No data found in table '{table_name}'"}])
                
        except Exception as e:
            return pd.DataFrame([{"Error": f"Failed to query table '{table_name}': {str(e)}"}])
    
    def create_sample_table(self) -> str:
        """Create a sample table"""
        if not self.supabase:
            return "❌ No Supabase connection"
        
        try:
            # Note: Creating tables requires elevated permissions
            # This might not work with the anon key
            result = self.supabase.rpc('create_sample_table').execute()
            return "βœ… Sample table created successfully!"
        except Exception as e:
            return f"❌ Error creating table: {str(e)}. Note: Creating tables requires database admin permissions."
    
    def insert_sample_data(self, name: str, email: str, age: int) -> str:
        """Insert data into sample table"""
        if not self.supabase:
            return "❌ No Supabase connection"
        
        try:
            data = {
                "name": name,
                "email": email,
                "age": age
            }
            
            # Try to insert into a sample_data table
            result = self.supabase.table("sample_data").insert(data).execute()
            
            if result.data:
                return f"βœ… Successfully added: {name} ({email})"
            else:
                return "❌ Failed to insert data"
                
        except Exception as e:
            return f"❌ Error inserting data: {str(e)}"
    
    def execute_rpc_function(self, function_name: str, params: Dict[str, Any] = None) -> pd.DataFrame:
        """Execute a remote procedure call (RPC) function"""
        if not self.supabase:
            return pd.DataFrame([{"Error": "No Supabase connection"}])
        
        try:
            if params:
                result = self.supabase.rpc(function_name, params).execute()
            else:
                result = self.supabase.rpc(function_name).execute()
            
            if result.data:
                if isinstance(result.data, list):
                    return pd.DataFrame(result.data)
                else:
                    return pd.DataFrame([{"Result": result.data}])
            else:
                return pd.DataFrame([{"Message": f"RPC function '{function_name}' executed successfully (no data returned)"}])
                
        except Exception as e:
            return pd.DataFrame([{"Error": f"RPC function failed: {str(e)}"}])

# Initialize Supabase connection
try:
    db = SupabaseConnection()
    connection_status = db.connection_status
except Exception as e:
    db = None
    connection_status = f"❌ Failed to initialize Supabase: {str(e)}"

def refresh_tables():
    """Refresh the list of available tables"""
    if db:
        tables = db.get_tables()
        return gr.Dropdown(choices=tables, value=None)
    return gr.Dropdown(choices=["No connection"], value=None)

def view_table_data(table_name: str, limit: int):
    """View data from selected table"""
    if not db:
        return pd.DataFrame([{"Error": "No Supabase connection"}])
    
    return db.get_table_data(table_name, limit)

def create_table():
    """Create sample table"""
    if not db:
        return "❌ No Supabase connection"
    return db.create_sample_table()

def add_sample_data(name: str, email: str, age: int):
    """Add data to sample table"""
    if not db:
        return "❌ No Supabase connection"
    
    if not name or not email:
        return "❌ Name and email are required"
    
    if age < 0 or age > 150:
        return "❌ Please enter a valid age (0-150)"
    
    return db.insert_sample_data(name, email, age)

def execute_rpc_function(function_name: str, params_text: str = ""):
    """Execute RPC function"""
    if not db:
        return pd.DataFrame([{"Error": "No Supabase connection"}])
    
    if not function_name.strip():
        return pd.DataFrame([{"Message": "Please enter a function name"}])
    
    try:
        # Parse parameters if provided
        params = {}
        if params_text.strip():
            # Simple parameter parsing: key=value,key2=value2
            for param in params_text.split(','):
                if '=' in param:
                    key, value = param.split('=', 1)
                    params[key.strip()] = value.strip()
        
        return db.execute_rpc_function(function_name.strip(), params if params else None)
    except Exception as e:
        return pd.DataFrame([{"Error": f"Parameter parsing error: {str(e)}"}])

# Create Gradio interface
with gr.Blocks(title="Supabase Database Interface", theme=gr.themes.Soft()) as app:
    gr.Markdown("# πŸ—ƒοΈ Supabase Database Interface")
    gr.Markdown("Connect and interact with your Supabase database using the API")
    
    # Connection status
    with gr.Row():
        gr.Markdown(f"**Connection Status:** {connection_status}")
    
    with gr.Tabs():
        # Tab 1: View Tables
        with gr.Tab("πŸ“Š View Tables"):
            gr.Markdown("### Browse your database tables")
            
            with gr.Row():
                table_dropdown = gr.Dropdown(
                    choices=db.get_tables() if db else ["No connection"],
                    label="Select Table",
                    value=None
                )
                refresh_btn = gr.Button("πŸ”„ Refresh Tables", size="sm")
                
            with gr.Row():
                limit_slider = gr.Slider(
                    minimum=1, maximum=1000, value=100, step=1,
                    label="Number of rows to display"
                )
                
            view_btn = gr.Button("πŸ‘€ View Table Data", variant="primary")
            table_output = gr.Dataframe(label="Table Data")
            
            refresh_btn.click(refresh_tables, outputs=table_dropdown)
            view_btn.click(
                view_table_data,
                inputs=[table_dropdown, limit_slider],
                outputs=table_output
            )
        
        # Tab 2: Add Data
        with gr.Tab("βž• Add Data"):
            gr.Markdown("### Add data to your tables")
            
            create_table_btn = gr.Button("πŸ—οΈ Create Sample Table", variant="secondary")
            create_status = gr.Textbox(label="Table Creation Status", interactive=False)
            
            gr.Markdown("---")
            gr.Markdown("**Add record to sample_data table:**")
            
            with gr.Row():
                name_input = gr.Textbox(label="Name", placeholder="Enter name")
                email_input = gr.Textbox(label="Email", placeholder="Enter email")
                age_input = gr.Number(label="Age", value=25, minimum=0, maximum=150)
            
            add_btn = gr.Button("πŸ“ Add Record", variant="primary")
            add_status = gr.Textbox(label="Add Record Status", interactive=False)
            
            create_table_btn.click(create_table, outputs=create_status)
            add_btn.click(
                add_sample_data,
                inputs=[name_input, email_input, age_input],
                outputs=add_status
            )
        
        # Tab 3: RPC Functions
        with gr.Tab("πŸ”§ RPC Functions"):
            gr.Markdown("### Execute Remote Procedure Call (RPC) functions")
            gr.Markdown("⚠️ **Note:** RPC functions must be created in your Supabase database first.")
            
            function_input = gr.Textbox(
                label="Function Name",
                placeholder="e.g., get_user_count, hello_world",
                lines=1
            )
            
            params_input = gr.Textbox(
                label="Parameters (optional)",
                placeholder="param1=value1,param2=value2",
                lines=2
            )
            
            rpc_btn = gr.Button("▢️ Execute Function", variant="primary")
            rpc_output = gr.Dataframe(label="Function Results")
            
            # Example functions
            gr.Markdown("""
            **Example RPC Functions:**
            - `hello_world` - Simple test function
            - `get_tables_list` - Get list of tables
            - `version` - Get database version
            
            **Note:** These functions need to be created in your Supabase SQL editor first.
            """)
            
            rpc_btn.click(
                execute_rpc_function,
                inputs=[function_input, params_input],
                outputs=rpc_output
            )
        
        # Tab 4: Connection Info
        with gr.Tab("ℹ️ Connection Info"):
            gr.Markdown("### Supabase Connection Details")
            
            if db:
                gr.Markdown(f"""
                **Supabase URL:** `{db.url}`
                **Connection Type:** API Client (using anon key)
                **Status:** {db.connection_status}
                
                **Available Operations:**
                - βœ… Read data from tables
                - βœ… Insert data (if RLS policies allow)
                - βœ… Execute RPC functions
                - ❌ Create/modify tables (requires elevated permissions)
                
                **Note:** The anon key has limited permissions. For full database operations, you may need to use the service role key or enable Row Level Security (RLS) policies.
                """)
            else:
                gr.Markdown("❌ No connection established")
    
    gr.Markdown("---")
    gr.Markdown("πŸ’‘ **Tips:** This interface uses the Supabase API. Some operations may require specific permissions or RLS policies to be configured in your Supabase project.")

# Launch the app
if __name__ == "__main__":
    app.launch(
        server_name="0.0.0.0",
        server_port=7860,
        share=False
    )