refactor(adapters): accept SharedTableProtocol; replace thread-local Store pattern with clone()
This commit is contained in:
parent
9d8b627fe1
commit
80ac13e69f
3 changed files with 28 additions and 7 deletions
|
|
@ -22,7 +22,7 @@ _SHOPPING_API_INTER_REQUEST_DELAY = 0.5 # seconds between successive calls
|
|||
_SELLER_ENRICH_TTL_HOURS = 24 # skip re-enrichment within this window
|
||||
|
||||
from app.db.models import Listing, MarketComp, Seller
|
||||
from app.db.store import Store
|
||||
from app.db.protocol import SharedTableProtocol
|
||||
from app.platforms import PlatformAdapter, SearchFilters
|
||||
from app.platforms.ebay.auth import EbayTokenManager
|
||||
from app.platforms.ebay.normaliser import normalise_listing, normalise_seller
|
||||
|
|
@ -67,7 +67,7 @@ BROWSE_BASE = {
|
|||
|
||||
|
||||
class EbayAdapter(PlatformAdapter):
|
||||
def __init__(self, token_manager: EbayTokenManager, shared_store: Store, env: str = "production"):
|
||||
def __init__(self, token_manager: EbayTokenManager, shared_store: SharedTableProtocol, env: str = "production"):
|
||||
self._tokens = token_manager
|
||||
self._store = shared_store
|
||||
self._env = env
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ log = logging.getLogger(__name__)
|
|||
from bs4 import BeautifulSoup
|
||||
|
||||
from app.db.models import Listing, MarketComp, Seller
|
||||
from app.db.store import Store
|
||||
from app.db.protocol import SharedTableProtocol
|
||||
from app.platforms import PlatformAdapter, SearchFilters
|
||||
|
||||
EBAY_SEARCH_URL = "https://www.ebay.com/sch/i.html"
|
||||
|
|
@ -286,7 +286,7 @@ class ScrapedEbayAdapter(PlatformAdapter):
|
|||
category_history) cause TrustScorer to set score_is_partial=True.
|
||||
"""
|
||||
|
||||
def __init__(self, shared_store: Store, delay: float = 1.0):
|
||||
def __init__(self, shared_store: SharedTableProtocol, delay: float = 1.0):
|
||||
self._store = shared_store
|
||||
self._delay = delay
|
||||
|
||||
|
|
@ -374,8 +374,6 @@ class ScrapedEbayAdapter(PlatformAdapter):
|
|||
Does not raise — failures per-seller are silently skipped so the main
|
||||
search response is never blocked.
|
||||
"""
|
||||
db_path = self._store._db_path # capture for thread-local Store creation
|
||||
|
||||
def _enrich_one(item: tuple[str, str]) -> None:
|
||||
seller_id, listing_id = item
|
||||
try:
|
||||
|
|
@ -388,7 +386,7 @@ class ScrapedEbayAdapter(PlatformAdapter):
|
|||
)
|
||||
if age_days is None and fb_count is None:
|
||||
return # nothing new to write
|
||||
thread_store = Store(db_path)
|
||||
thread_store = self._store.clone()
|
||||
seller = thread_store.get_seller("ebay", seller_id)
|
||||
if not seller:
|
||||
log.warning("BTF enrich: seller %s not found in DB", seller_id)
|
||||
|
|
|
|||
|
|
@ -14,3 +14,26 @@ def test_store_clone_returns_new_instance(tmp_path):
|
|||
assert isinstance(clone, Store)
|
||||
assert clone is not s
|
||||
assert clone._db_path == db
|
||||
|
||||
|
||||
def test_ebay_adapter_accepts_protocol():
|
||||
from app.platforms.ebay.adapter import EbayAdapter
|
||||
import tempfile
|
||||
import pathlib
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
s = Store(pathlib.Path(tmp) / "t.db")
|
||||
adapter = EbayAdapter(token_manager=MagicMock(), shared_store=s)
|
||||
assert adapter._store is s
|
||||
|
||||
|
||||
def test_scraped_adapter_no_db_path_ref():
|
||||
from app.platforms.ebay.scraper import ScrapedEbayAdapter
|
||||
import tempfile
|
||||
import pathlib
|
||||
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
s = Store(pathlib.Path(tmp) / "t.db")
|
||||
adapter = ScrapedEbayAdapter(shared_store=s)
|
||||
assert not hasattr(adapter, '_db_path_ref')
|
||||
|
|
|
|||
Loading…
Reference in a new issue