Spaces:
Paused
Paused
Commit ·
a8fd301
1
Parent(s): d6a01c7
fix: harden route parsing, column dedup, and column name access
Browse files- Normalize QU route output (strip/lowercase) before validation
- Fix column name deduplication to handle suffix collisions
(e.g., 'Score_A', 'Score_A', 'Score_A_2' no longer produces duplicates)
- Use defensive .get() for column name access in SQL result formatting
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- src/query_engine.py +2 -0
- src/sql_ingest.py +11 -8
- src/sql_retriever.py +1 -1
src/query_engine.py
CHANGED
|
@@ -162,6 +162,8 @@ def _parse_qu_result(raw: str, original_query: str) -> dict:
|
|
| 162 |
search_query = parsed.get("search_query", original_query)
|
| 163 |
display_query = parsed.get("display_query", original_query)
|
| 164 |
route = parsed.get("route", "vector")
|
|
|
|
|
|
|
| 165 |
if route not in ("sql", "vector", "both"):
|
| 166 |
route = "vector"
|
| 167 |
sql_query = parsed.get("sql_query") if route in ("sql", "both") else None
|
|
|
|
| 162 |
search_query = parsed.get("search_query", original_query)
|
| 163 |
display_query = parsed.get("display_query", original_query)
|
| 164 |
route = parsed.get("route", "vector")
|
| 165 |
+
if isinstance(route, str):
|
| 166 |
+
route = route.strip().lower()
|
| 167 |
if route not in ("sql", "vector", "both"):
|
| 168 |
route = "vector"
|
| 169 |
sql_query = parsed.get("sql_query") if route in ("sql", "both") else None
|
src/sql_ingest.py
CHANGED
|
@@ -499,15 +499,18 @@ def _ingest_tables(
|
|
| 499 |
|
| 500 |
# Infer column types, collect samples and stats
|
| 501 |
safe_headers = [_sanitize_column_name(h) for h in headers]
|
| 502 |
-
# Deduplicate:
|
| 503 |
-
|
|
|
|
|
|
|
|
|
|
| 504 |
for i, name in enumerate(safe_headers):
|
| 505 |
-
|
| 506 |
-
|
| 507 |
-
|
| 508 |
-
|
| 509 |
-
|
| 510 |
-
|
| 511 |
col_types = []
|
| 512 |
col_samples = []
|
| 513 |
col_stats = []
|
|
|
|
| 499 |
|
| 500 |
# Infer column types, collect samples and stats
|
| 501 |
safe_headers = [_sanitize_column_name(h) for h in headers]
|
| 502 |
+
# Deduplicate: ensure all column names are unique after sanitization.
|
| 503 |
+
# Checks every name against all previously assigned names,
|
| 504 |
+
# handling both same-name collisions and suffix collisions
|
| 505 |
+
# (e.g., 'Score_A', 'Score_A', 'Score_A_2' won't produce duplicates).
|
| 506 |
+
used: set[str] = set()
|
| 507 |
for i, name in enumerate(safe_headers):
|
| 508 |
+
if name.lower() in used:
|
| 509 |
+
suffix = 2
|
| 510 |
+
while f"{name}_{suffix}".lower() in used:
|
| 511 |
+
suffix += 1
|
| 512 |
+
safe_headers[i] = f"{name}_{suffix}"
|
| 513 |
+
used.add(safe_headers[i].lower())
|
| 514 |
col_types = []
|
| 515 |
col_samples = []
|
| 516 |
col_stats = []
|
src/sql_retriever.py
CHANGED
|
@@ -93,7 +93,7 @@ def format_sql_results_as_context(
|
|
| 93 |
if table_desc:
|
| 94 |
parts.append(f"Dataset description: {table_desc}\n")
|
| 95 |
col_descs = {
|
| 96 |
-
c
|
| 97 |
for c in table_info.get("columns", [])
|
| 98 |
}
|
| 99 |
desc_lines = [f" {name}: {desc}" for name, desc in col_descs.items() if desc]
|
|
|
|
| 93 |
if table_desc:
|
| 94 |
parts.append(f"Dataset description: {table_desc}\n")
|
| 95 |
col_descs = {
|
| 96 |
+
c.get("name", "unknown"): c.get("description", "")
|
| 97 |
for c in table_info.get("columns", [])
|
| 98 |
}
|
| 99 |
desc_lines = [f" {name}: {desc}" for name, desc in col_descs.items() if desc]
|