diff --git a/backend/app/api/datasources.py b/backend/app/api/datasources.py index 1f8215d..e544724 100644 --- a/backend/app/api/datasources.py +++ b/backend/app/api/datasources.py @@ -133,4 +133,7 @@ def test_datasource_connection( else: raise HTTPException(status_code=400, detail="Connection failed") except Exception as e: + import traceback + import sys + print(f"Datasource Test Error: {str(e)}\n{traceback.format_exc()}", file=sys.stderr) raise HTTPException(status_code=400, detail=f"Connection failed: {str(e)}") diff --git a/backend/app/connectors/factory.py b/backend/app/connectors/factory.py index 87da6da..53a199b 100644 --- a/backend/app/connectors/factory.py +++ b/backend/app/connectors/factory.py @@ -13,9 +13,17 @@ def _get_cached_connector(ds_type: str, config_json: str): config = json.loads(config_json) if ds_type in ["postgres", "postgresql", "supabase"]: - # Supabase is just postgres - db_url = config.get("connection_string") or \ - f"postgresql://{config.get('user')}:{config.get('password')}@{config.get('host')}:{config.get('port', 5432)}/{config.get('database')}" + db_url = config.get("connection_string") + if not db_url: + default_port = 6543 if ds_type == "supabase" else 5432 + port = config.get("port") or default_port + db_url = f"postgresql://{config.get('user')}:{config.get('password')}@{config.get('host')}:{port}/{config.get('database')}" + + if ds_type == "supabase" and "?" not in db_url: + db_url += "?sslmode=require" + elif ds_type == "supabase" and "sslmode=" not in db_url: + db_url += "&sslmode=require" + return PostgresConnector(db_url=db_url) elif ds_type == "sqlite": diff --git a/backend/app/connectors/postgres.py b/backend/app/connectors/postgres.py index a89bbfd..1f00ef3 100644 --- a/backend/app/connectors/postgres.py +++ b/backend/app/connectors/postgres.py @@ -69,6 +69,6 @@ class PostgresConnector: return True except Exception as e: print(f"PostgreSQL Connection Error: {e}") - return False + raise e postgres_connector = PostgresConnector() diff --git a/backend/dataclaw.db b/backend/dataclaw.db index d4f54d4..3c3f47d 100644 Binary files a/backend/dataclaw.db and b/backend/dataclaw.db differ diff --git a/frontend/src/components/DataSourceForm.tsx b/frontend/src/components/DataSourceForm.tsx index 6f02bab..849bd8a 100644 --- a/frontend/src/components/DataSourceForm.tsx +++ b/frontend/src/components/DataSourceForm.tsx @@ -93,9 +93,68 @@ export function DataSourceForm({ initialData, onSubmit, onTest, onCancel }: Data const renderConfigFields = () => { switch (type) { + case "supabase": + return ( +
+
+
+ + handleConfigChange("host", e.target.value)} + placeholder="aws-0-[region].pooler.supabase.com" + /> +
+
+ + handleConfigChange("port", parseInt(e.target.value))} + placeholder="6543" + /> +
+
+
+ + handleConfigChange("database", e.target.value)} + placeholder="postgres" + /> +
+
+ + handleConfigChange("user", e.target.value)} + placeholder="postgres.[project-ref]" + /> +
+
+ + handleConfigChange("password", e.target.value)} + placeholder="••••••" + /> +
+
+ 或者直接使用 Supabase 控制台提供的 Connection String (URI): +
+
+ + handleConfigChange("connection_string", e.target.value)} + placeholder="postgresql://postgres.[project-ref]:[password]@aws-0-[region].pooler.supabase.com:6543/postgres?sslmode=require" + /> +
+
+ ); case "postgres": case "postgresql": - case "supabase": case "mysql": case "sqlserver": case "oracle": diff --git a/frontend/src/pages/DataSources.tsx b/frontend/src/pages/DataSources.tsx index ed5102b..3d130cb 100644 --- a/frontend/src/pages/DataSources.tsx +++ b/frontend/src/pages/DataSources.tsx @@ -12,6 +12,7 @@ const SOURCE_TYPES = [ { id: "csv", name: "CSV Upload", icon: }, { id: "bigquery", name: "BigQuery", icon: }, { id: "postgres", name: "PostgreSQL", icon: }, + { id: "supabase", name: "Supabase", icon: }, { id: "mysql", name: "MySQL", icon: }, { id: "oracle", name: "Oracle", icon: }, { id: "sqlserver", name: "SQL Server", icon: },