mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2026-08-29 22:17:14 +00:00
refactor(search): split error classes and build_permission_filter out of _query.py
_query.py mixed three unrelated responsibilities: the SearchQueryError family (paperless's public error-surface API, re-exported by __init__.py), the actual query rewrite/parse/emit/blend pipeline, and build_permission_filter, which has nothing to do with query parsing and is consumed only by _backend.py. - New _errors.py: SearchQueryError, InvalidDateQuery, InvalidNumberQuery, MultipleSearchQueryErrors, search_query_error_messages. _query.py now imports these instead of defining them. - build_permission_filter moves to _backend.py, next to its one caller (TantivyBackend._build_permission_filter). - __init__.py re-exports the error classes from _errors.py instead of _query.py; the package's public API (documents.search import ...) is unchanged for every caller going through it (views.py etc.). _query.py now reads top-to-bottom as rewrite -> parse -> emit -> blend, matching what parse_user_query's own docstring already claimed the file was.
This commit is contained in:
committed by
stumpylog
parent
bf7eec7168
commit
ddf8287072
@@ -0,0 +1,54 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from collections.abc import Sequence
|
||||
|
||||
|
||||
class SearchQueryError(ValueError):
|
||||
"""
|
||||
Base for user-fixable search query errors.
|
||||
|
||||
Carries a message safe to surface to the user (no internal details). The
|
||||
view layer catches this and returns an HTTP 400, so any future subclass
|
||||
gets the same treatment.
|
||||
"""
|
||||
|
||||
|
||||
class InvalidDateQuery(SearchQueryError):
|
||||
"""Raised when a date field value or range bound cannot be parsed."""
|
||||
|
||||
def __init__(self, field: str | None, value: str | None) -> None:
|
||||
self.field = field
|
||||
self.value = value
|
||||
super().__init__(f"Invalid date value {value!r} for field {field!r}.")
|
||||
|
||||
|
||||
class InvalidNumberQuery(SearchQueryError):
|
||||
"""Raised when a numeric field value or range bound cannot be parsed."""
|
||||
|
||||
def __init__(self, field: str | None, value: str | None) -> None:
|
||||
self.field = field
|
||||
self.value = value
|
||||
super().__init__(f"Invalid numeric value {value!r} for field {field!r}.")
|
||||
|
||||
|
||||
class MultipleSearchQueryErrors(SearchQueryError):
|
||||
"""Aggregates every user-fixable error from one parse, not just the first."""
|
||||
|
||||
def __init__(self, errors: Sequence[SearchQueryError]) -> None:
|
||||
self.errors = tuple(errors)
|
||||
super().__init__("; ".join(str(e) for e in self.errors))
|
||||
|
||||
|
||||
def search_query_error_messages(e: SearchQueryError) -> list[str]:
|
||||
"""The user-facing message list for a SearchQueryError.
|
||||
|
||||
Every offending value's message, not just the first, so the user can
|
||||
fix them all in one round-trip. Shared by every view that maps
|
||||
SearchQueryError to an HTTP 400.
|
||||
"""
|
||||
if isinstance(e, MultipleSearchQueryErrors):
|
||||
return [str(sub) for sub in e.errors]
|
||||
return [str(e)]
|
||||
Reference in New Issue
Block a user