Files
rengine/shared/services/asset_query/errors.py
T
Yogesh OjhaandClaude Opus 5 d41a66deb9 refactor(query): one builder for a query the parser refused
Eleven call sites across six services each spelled the same
QueryError(message=..., hint=..., start=..., end=...) so the UI could
underline the query in place. errors.py already owned the other half
of that vocabulary, query_error_for(DBAPIError); syntax_error() is its
counterpart and the services call it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DafWxfoWZXVDgr9KroJBDZ
2026-09-16 08:45:15 +05:30

37 lines
1.2 KiB
Python

from __future__ import annotations
from sqlalchemy.exc import DBAPIError
from shared.models.asset_query import QueryError
from .ast import QuerySyntaxError
STATEMENT_TIMEOUT = "SET LOCAL statement_timeout = '20s'"
NO_JIT = "SET LOCAL jit = off"
QUERY_SQLSTATES = {
"2201B": (
"Invalid regular expression.",
"PostgreSQL regular expression syntax applies.",
),
"2201G": ("Invalid regular expression.", None),
"57014": ("The search timed out.", "Add a field filter."),
"22003": ("A number is out of range.", None),
"22P02": ("A value has the wrong type.", None),
"54000": ("A search term is too long to index.", None),
}
def query_error_for(exc: DBAPIError) -> QueryError | None:
sqlstate = getattr(exc.orig, "sqlstate", None) or getattr(exc.orig, "pgcode", None)
known = QUERY_SQLSTATES.get(str(sqlstate))
if known is None:
return None
message, hint = known
return QueryError(message=message, hint=hint)
def syntax_error(exc: QuerySyntaxError) -> QueryError:
"""What the UI underlines in place of the query it could not parse."""
return QueryError(message=exc.message, hint=exc.hint, start=exc.start, end=exc.end)