QueryQuest / src /queryquest /web /render.py
mohamedgamal04
QueryQuest — Hugging Face Spaces deploy (Docker)
0cac9cf
Raw
History Blame Contribute Delete
3.03 kB
"""Render an EngineResult as chat-ready markdown.
Kept pure (no Chainlit imports) so the Chainlit handler stays trivial and the
formatting is unit-testable on its own.
Author: mohamedgamal04
"""
from __future__ import annotations
import re
from ..core.models import EngineResult, StatementResult
ROW_LIMIT = 50
def _cell(value: object) -> str:
"""Render one cell, escaping pipes so the markdown table stays intact."""
if value is None:
return ""
return str(value).replace("|", "\\|").replace("\n", " ")
def _markdown_table(columns: list[str], rows: list[dict]) -> str:
"""Build a markdown table from preview columns and row dicts."""
if not columns:
columns = list(rows[0].keys()) if rows else []
if not columns:
return "_(no columns)_"
header = "| " + " | ".join(_cell(column) for column in columns) + " |"
separator = "| " + " | ".join("---" for _ in columns) + " |"
lines = [header, separator]
for row in rows[:ROW_LIMIT]:
lines.append("| " + " | ".join(_cell(row.get(column)) for column in columns) + " |")
return "\n".join(lines)
def _render_statement(statement: StatementResult) -> str:
"""Render a single statement's outcome."""
if statement.error is not None:
return f"❌ **Refused/failed:** {statement.error}\n\n```sql\n{statement.sql}\n```"
if statement.kind == "select":
if statement.row_count == 0:
if re.search(r"\bjoin\b", statement.sql, flags=re.IGNORECASE):
return (
"⚠️ The join matched no rows — the two sheets likely share no "
"matching key column, so there is nothing to join on."
)
return "ℹ️ The query ran but matched no rows. Check the filter or column values."
table = _markdown_table(statement.columns, statement.rows)
if statement.truncated:
table += f"\n\n_Showing first {len(statement.rows)} of {statement.row_count} rows._"
return table
return f"✏️ **{statement.kind.upper()}** affected {statement.row_count} row(s)."
def format_result_markdown(result: EngineResult) -> str:
"""Turn an EngineResult into a single markdown message for the chat UI."""
if result.error is not None:
return f"⚠️ {result.error}"
parts: list[str] = []
if result.explanation:
parts.append(result.explanation)
for statement in result.statements:
parts.append(_render_statement(statement))
if result.wrote_back and result.writeback_targets:
saved = "\n".join(
f"💾 Saved **{target.affected_rows}** row(s) to `{target.file_path.name}` "
f"(sheet `{target.sheet_name}`)."
for target in result.writeback_targets
)
parts.append(saved)
elif result.writeback_targets and not result.wrote_back:
parts.append("⚠️ Changes were **not** saved to disk.")
if not parts:
return "_(no output)_"
return "\n\n".join(parts)