Channels, search and sync do no database work in their routes any more: reads go through catalog/queries, writes through catalog/service, and a live search's ingest is catalog/search. What a catalog route needs from Reader (a playlist's channels, a user's tag links, the feed projection of results) it asks reader/queries and reader/service. The scheduler and the runs page read channel titles and the work queue through catalog/queries. Catalog is fenced below its HTTP layer: its owner filters go through userscope, it reads no other unit's tables, and its ingest jobs commit only where they are named.
82 lines
2.6 KiB
Python
82 lines
2.6 KiB
Python
"""What a person types is a literal inside a LIKE pattern, never a wildcard (DB-lane).
|
|
|
|
`%` and `_` are LIKE wildcards. The feed's channel-name match and the live search's term fold both
|
|
built their pattern from the typed text as it was, so `my_channel` also matched `myXchannel`, and a
|
|
term already present as part of a longer word was never folded in.
|
|
"""
|
|
|
|
from datetime import datetime, timezone
|
|
|
|
from sqlalchemy import select
|
|
|
|
from app.catalog.models import Channel, Subscription, Video
|
|
from app.catalog.search import _fold_term
|
|
|
|
|
|
def _video(vid: str, ch: str, title: str, search_terms: str | None = None) -> Video:
|
|
return Video(
|
|
id=vid,
|
|
channel_id=ch,
|
|
published_at=datetime(2024, 1, 1, tzinfo=timezone.utc),
|
|
title=title,
|
|
is_short=False,
|
|
live_status="none",
|
|
via_search=False,
|
|
via_explore=False,
|
|
search_terms=search_terms,
|
|
)
|
|
|
|
|
|
def test_an_underscore_in_a_feed_search_matches_only_itself(db, as_user, make_user):
|
|
user = make_user()
|
|
db.add_all(
|
|
[
|
|
Channel(id="UCunder", title="build_log daily", subscriber_count=1),
|
|
Channel(id="UClookalike", title="buildXlog daily", subscriber_count=1),
|
|
]
|
|
)
|
|
db.add_all(
|
|
[
|
|
Subscription(user_id=user.id, channel_id=ch, priority=0, hidden=False)
|
|
for ch in ("UCunder", "UClookalike")
|
|
]
|
|
)
|
|
db.add_all(
|
|
[
|
|
_video("vidUnder", "UCunder", "Nothing in common"),
|
|
_video("vidLook", "UClookalike", "Nothing in common either"),
|
|
]
|
|
)
|
|
db.commit()
|
|
|
|
resp = as_user(user).get("/api/feed?q=build_log&show=all&limit=50")
|
|
|
|
assert resp.status_code == 200, resp.text
|
|
assert {it["id"] for it in resp.json()["items"]} == {"vidUnder"}
|
|
|
|
|
|
def test_a_term_is_folded_in_unless_it_is_already_a_whole_term(db):
|
|
db.add(Channel(id="UCfold", title="Fold", subscriber_count=1))
|
|
db.add_all(
|
|
[
|
|
_video("vidWord", "UCfold", "a", search_terms="category"),
|
|
_video("vidWild", "UCfold", "b", search_terms="catXdog"),
|
|
_video("vidHas", "UCfold", "c", search_terms="old cat_dog new"),
|
|
_video("vidNone", "UCfold", "d"),
|
|
]
|
|
)
|
|
db.commit()
|
|
|
|
_fold_term(db, ["vidWord", "vidWild", "vidHas", "vidNone"], "cat")
|
|
_fold_term(db, ["vidWild", "vidHas"], "cat_dog")
|
|
db.commit()
|
|
db.expire_all()
|
|
|
|
terms = dict(db.execute(select(Video.id, Video.search_terms)).all())
|
|
assert terms == {
|
|
"vidWord": "category cat",
|
|
"vidWild": "catXdog cat cat_dog",
|
|
"vidHas": "old cat_dog new cat",
|
|
"vidNone": "cat",
|
|
}
|