This repository has been archived on 2026-02-24. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
market/scrape/persist_snapshot/save_nav.py
giles 478636f799 feat: decouple market from shared_lib, add app-owned models
Phase 1-3 of decoupling:
- path_setup.py adds project root to sys.path
- Market-owned models in market/models/ (market, market_place)
- All imports updated: shared.infrastructure, shared.db, shared.browser, etc.
- MarketPlace uses container_type/container_id instead of post_id FK

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 12:46:32 +00:00

111 lines
3.1 KiB
Python

# at top of persist_snapshot.py:
from datetime import datetime
from sqlalchemy import (
select, tuple_
)
from typing import Dict
from models.market import (
NavTop,
NavSub,
)
from shared.db.session import get_session
async def save_nav(nav: Dict) -> None:
async with get_session() as session:
await _save_nav(session, nav)
await session.commit()
async def _save_nav(session, nav: Dict, market_id=None) -> None:
print('===================SAVE NAV========================')
print(nav)
now = datetime.utcnow()
incoming_top_slugs = set()
incoming_sub_keys = set() # (top_slug, sub_slug)
# First pass: collect slugs
for label, data in (nav.get("cats") or {}).items():
top_slug = (data or {}).get("slug")
if not top_slug:
continue
incoming_top_slugs.add(top_slug)
for s in (data.get("subs") or []):
sub_slug = s.get("slug")
if sub_slug:
incoming_sub_keys.add((top_slug, sub_slug))
# Soft-delete stale NavSub entries
# This requires joining NavTop to access top_slug
subs_to_delete = await session.execute(
select(NavSub)
.join(NavTop, NavSub.top_id == NavTop.id)
.where(
NavSub.deleted_at.is_(None),
~tuple_(NavTop.slug, NavSub.slug).in_(incoming_sub_keys)
)
)
for sub in subs_to_delete.scalars():
sub.deleted_at = now
# Soft-delete stale NavTop entries
tops_to_delete = await session.execute(
select(NavTop)
.where(
NavTop.deleted_at.is_(None),
~NavTop.slug.in_(incoming_top_slugs)
)
)
for top in tops_to_delete.scalars():
top.deleted_at = now
await session.flush()
# Upsert NavTop and NavSub
for label, data in (nav.get("cats") or {}).items():
top_slug = (data or {}).get("slug")
if not top_slug:
continue
res = await session.execute(
select(NavTop).where(NavTop.slug == top_slug)
)
top = res.scalar_one_or_none()
if top:
top.label = label
top.deleted_at = None
if market_id is not None and top.market_id is None:
top.market_id = market_id
else:
top = NavTop(label=label, slug=top_slug, market_id=market_id)
session.add(top)
await session.flush()
for s in (data.get("subs") or []):
sub_slug = s.get("slug")
if not sub_slug:
continue
sub_label = s.get("label")
sub_href = s.get("href")
res_sub = await session.execute(
select(NavSub).where(
NavSub.slug == sub_slug,
NavSub.top_id == top.id
)
)
sub = res_sub.scalar_one_or_none()
if sub:
sub.label = sub_label
sub.href = sub_href
sub.deleted_at = None
else:
session.add(NavSub(top_id=top.id, label=sub_label, slug=sub_slug, href=sub_href))