forked from retoor/devplacepy
feat: add author-username search to feed/gists/projects listings and partial-index migration
Extend `database.text_search_clause` with an `author_field` parameter that resolves username matches to user UIDs, enabling author-username search across the three public listings (`/feed`, `/gists`, `/projects`). Update the corresponding API docs and README route descriptions to reflect the new search scope. Add six partial indexes (`idx_comments_target_live`, `idx_votes_target_live`, `idx_reactions_target_live`, `idx_gists_live_created`, `idx_projects_live_created`, `idx_attachments_user_created_live`) to optimize filtered queries on non-deleted rows. Introduce a hot-settings cache (`_hot_settings`) with a 2-second TTL for `maintenance_mode`, `rate_limit_per_minute`, and `rate_limit_window_seconds`, plus a periodic rate-limit store sweep (`_sweep_rate_limit_store`) to evict stale IP entries every 60 seconds. Add `GZipMiddleware` to the FastAPI app for response compression.
This commit is contained in:
@@ -522,3 +522,75 @@ def test_load_comments_drops_blocked_author(local_db):
|
||||
|
||||
others = load_comments("post", post_uid, None)
|
||||
assert len(others) == 1
|
||||
|
||||
|
||||
def test_get_uids_by_username_match_returns_matching_uids(local_db):
|
||||
from devplacepy.database import get_uids_by_username_match
|
||||
|
||||
target = generate_uid()
|
||||
get_table("users").insert(
|
||||
{
|
||||
"uid": target,
|
||||
"username": "searchablehero",
|
||||
"created_at": _now_db_helpers(),
|
||||
}
|
||||
)
|
||||
assert target in get_uids_by_username_match("searchablehero")
|
||||
assert target in get_uids_by_username_match("hablehe")
|
||||
assert get_uids_by_username_match("") == []
|
||||
|
||||
|
||||
def test_text_search_clause_matches_author_username(local_db):
|
||||
from devplacepy.database import text_search_clause
|
||||
|
||||
author = generate_uid()
|
||||
get_table("users").insert(
|
||||
{
|
||||
"uid": author,
|
||||
"username": "authorquery",
|
||||
"created_at": _now_db_helpers(),
|
||||
}
|
||||
)
|
||||
post_uid = _post(author, title="unrelated title", content="unrelated body")
|
||||
posts = get_table("posts")
|
||||
|
||||
clause = text_search_clause(
|
||||
posts, "authorquery", ("title", "content"), author_field="user_uid"
|
||||
)
|
||||
assert clause is not None
|
||||
rows = list(posts.find(clause, deleted_at=None))
|
||||
assert post_uid in {r["uid"] for r in rows}
|
||||
|
||||
|
||||
def test_text_search_clause_without_author_field_ignores_username(local_db):
|
||||
from devplacepy.database import text_search_clause
|
||||
|
||||
author = generate_uid()
|
||||
get_table("users").insert(
|
||||
{
|
||||
"uid": author,
|
||||
"username": "lonelyauthor",
|
||||
"created_at": _now_db_helpers(),
|
||||
}
|
||||
)
|
||||
_post(author, title="nothing here", content="nothing here either")
|
||||
posts = get_table("posts")
|
||||
|
||||
clause = text_search_clause(posts, "lonelyauthor", ("title", "content"))
|
||||
rows = list(posts.find(clause, deleted_at=None)) if clause is not None else []
|
||||
assert all(r["user_uid"] != author for r in rows)
|
||||
|
||||
|
||||
def test_text_search_clause_still_matches_text_fields(local_db):
|
||||
from devplacepy.database import text_search_clause
|
||||
|
||||
author = _user_db_helpers()
|
||||
post_uid = _post(author, title="distinctivekeyword", content="body text")
|
||||
posts = get_table("posts")
|
||||
|
||||
clause = text_search_clause(
|
||||
posts, "distinctivekeyword", ("title", "content"), author_field="user_uid"
|
||||
)
|
||||
assert clause is not None
|
||||
rows = list(posts.find(clause, deleted_at=None))
|
||||
assert post_uid in {r["uid"] for r in rows}
|
||||
|
||||
@@ -14,7 +14,7 @@ from devplacepy.services.deepsearch.store import VectorStore
|
||||
|
||||
|
||||
def _patch_pipeline(monkeypatch, pages):
|
||||
async def fake_plan(query, api_key):
|
||||
async def fake_plan(query, api_key, emit=lambda frame: None):
|
||||
return [query, f"{query} overview"]
|
||||
|
||||
async def fake_search(queries, emit=lambda frame: None):
|
||||
|
||||
Reference in New Issue
Block a user