feat(backend): search finds word prefixes, earlier versions and deleted messages, with filters and cursor paging
This commit is contained in:
1 parent
42b4e1d7e6
commit
d45c96c259
5 files changed
+377
-88
No files matched your search
@@ -1,23 +1,48 @@
|
||||
from datetime import datetime
|
||||
from datetime import UTC, datetime, timedelta
|
||||
from typing import Literal
|
||||
|
||||
from pydantic import BaseModel
|
||||
from pydantic import BaseModel, field_validator
|
||||
|
||||
DEFAULT_LIMIT = 50
|
||||
MAX_LIMIT = 500
|
||||
|
||||
_EPOCH = datetime(1970, 1, 1, tzinfo=UTC)
|
||||
_MICROSECOND = timedelta(microseconds=1)
|
||||
|
||||
ChatKind = Literal["private", "group", "channel"]
|
||||
HitSource = Literal["text", "stt", "version"]
|
||||
|
||||
|
||||
def encode_cursor(date: datetime, chat_id: int, message_id: int) -> str:
|
||||
return f"{(date - _EPOCH) // _MICROSECOND}_{chat_id}_{message_id}"
|
||||
|
||||
|
||||
def decode_cursor(cursor: str) -> tuple[datetime, int, int]:
|
||||
micros, chat_id, message_id = (int(part) for part in cursor.split("_"))
|
||||
return _EPOCH + micros * _MICROSECOND, chat_id, message_id
|
||||
|
||||
|
||||
class SearchFilters(BaseModel):
|
||||
account_id: int
|
||||
query: str | None = None
|
||||
chat_id: int | None = None
|
||||
sender_id: int | None = None
|
||||
kind: ChatKind | None = None
|
||||
has_media: bool | None = None
|
||||
deleted: bool | None = None
|
||||
edited: bool | None = None
|
||||
date_from: datetime | None = None
|
||||
date_to: datetime | None = None
|
||||
regex: str | None = None
|
||||
cursor: str | None = None
|
||||
limit: int = DEFAULT_LIMIT
|
||||
offset: int = 0
|
||||
|
||||
@field_validator("cursor")
|
||||
@classmethod
|
||||
def _valid_cursor(cls, value: str | None) -> str | None:
|
||||
if value is not None:
|
||||
decode_cursor(value)
|
||||
return value
|
||||
|
||||
|
||||
class SearchHit(BaseModel):
|
||||
@@ -26,5 +51,17 @@ class SearchHit(BaseModel):
|
||||
date: datetime
|
||||
sender_id: int | None
|
||||
text: str | None
|
||||
source: Literal["text", "stt"]
|
||||
has_media: bool
|
||||
media_kind: str | None
|
||||
edited_at: datetime | None
|
||||
deleted_at: datetime | None
|
||||
source: HitSource
|
||||
extracted_text: str | None
|
||||
version_text: str | None
|
||||
version_at: datetime | None
|
||||
|
||||
|
||||
class SearchPage(BaseModel):
|
||||
hits: list[SearchHit]
|
||||
next_cursor: str | None
|
||||
terms: list[str]
|
||||
Reference in new issue
Block a user