diff --git a/app.py b/app.py index 713f4ac..2ed69df 100644 --- a/app.py +++ b/app.py @@ -18,46 +18,38 @@ async def market_context() -> dict: Market app context processor. - menu_items: direct DB query via glue layer - - cart_count/cart_total: direct DB query (same shared DB) + - cart_count/cart_total: via cart service (shared DB) """ from shared.infrastructure.context import base_context - from glue.services.navigation import get_navigation_tree + from shared.services.navigation import get_navigation_tree from shared.infrastructure.cart_identity import current_cart_identity - from models.market import CartItem - from sqlalchemy.orm import selectinload + from shared.services.registry import services ctx = await base_context() ctx["menu_items"] = await get_navigation_tree(g.s) - # Cart data: query shared DB directly (avoids stale cross-app API responses) + # Cart data via service (replaces direct CartItem query) ident = current_cart_identity() - cart_filters = [CartItem.deleted_at.is_(None)] - if ident["user_id"] is not None: - cart_filters.append(CartItem.user_id == ident["user_id"]) - else: - cart_filters.append(CartItem.session_id == ident["session_id"]) - - cart_result = await g.s.execute( - select(CartItem) - .where(*cart_filters) - .options(selectinload(CartItem.product)) + summary = await services.cart.cart_summary( + g.s, user_id=ident["user_id"], session_id=ident["session_id"], ) - cart_items = cart_result.scalars().all() - - from bp.cart.services import total - ctx["cart"] = list(cart_items) - ctx["cart_count"] = sum(ci.quantity for ci in cart_items) - ctx["cart_total"] = total(cart_items) or 0 + ctx["cart"] = summary.items + ctx["cart_count"] = summary.count + ctx["cart_total"] = float(summary.total) return ctx def create_app() -> "Quart": from models.market_place import MarketPlace - from shared.models.ghost_content import Post + from services import register_domain_services - app = create_base_app("market", context_fn=market_context) + app = create_base_app( + "market", + context_fn=market_context, + domain_services_fn=register_domain_services, + ) # App-specific templates override shared templates app_templates = str(Path(__file__).resolve().parent / "templates") @@ -100,12 +92,8 @@ def create_app() -> "Quart": if not post_slug or not market_slug: return - # Load post by slug - post = ( - await g.s.execute( - select(Post).where(Post.slug == post_slug) - ) - ).scalar_one_or_none() + # Load post by slug via blog service + post = await services.blog.get_post_by_slug(g.s, post_slug) if not post: abort(404) @@ -147,23 +135,22 @@ def create_app() -> "Quart": # --- Root route: market listing --- @app.get("/") async def markets_listing(): - rows = ( - await g.s.execute( - select(MarketPlace, Post) - .join( - Post, - (MarketPlace.container_type == "page") - & (MarketPlace.container_id == Post.id), - ) - .where(MarketPlace.deleted_at.is_(None)) - .order_by(MarketPlace.name) - ) - ).all() + result = await g.s.execute( + select(MarketPlace) + .where(MarketPlace.deleted_at.is_(None), MarketPlace.container_type == "page") + .order_by(MarketPlace.name) + ) + all_markets = result.scalars().all() - # Attach the joined post to each market for template access + # Resolve page posts via blog service + post_ids = list({m.container_id for m in all_markets}) + posts_by_id = { + p.id: p + for p in await services.blog.get_posts_by_ids(g.s, post_ids) + } markets = [] - for market, post in rows: - market.page = post + for market in all_markets: + market.page = posts_by_id.get(market.container_id) markets.append(market) html = await render_template( diff --git a/services/__init__.py b/services/__init__.py new file mode 100644 index 0000000..6a531a1 --- /dev/null +++ b/services/__init__.py @@ -0,0 +1,26 @@ +"""Market app service registration.""" +from __future__ import annotations + + +def register_domain_services() -> None: + """Register services for the market app. + + Market owns: Product, CartItem, MarketPlace, NavTop, NavSub, + Listing, ProductImage. + Standard deployment registers all 4 services as real DB impls + (shared DB). For composable deployments, swap non-owned services + with stubs from shared.services.stubs. + """ + from shared.services.registry import services + from shared.services.blog_impl import SqlBlogService + from shared.services.calendar_impl import SqlCalendarService + from shared.services.market_impl import SqlMarketService + from shared.services.cart_impl import SqlCartService + + services.market = SqlMarketService() + if not services.has("blog"): + services.blog = SqlBlogService() + if not services.has("calendar"): + services.calendar = SqlCalendarService() + if not services.has("cart"): + services.cart = SqlCartService() diff --git a/shared b/shared index ea7dc97..70b1c7d 160000 --- a/shared +++ b/shared @@ -1 +1 @@ -Subproject commit ea7dc9723a8f86b82b42ee9631fca096d0ec11bb +Subproject commit 70b1c7de1007f1759a20a5d17eaab83f96d26b72