From a55501f2ea8f54fbc620ca7f0c8ac514aed94731 Mon Sep 17 00:00:00 2001 From: Deeman Date: Mon, 2 Mar 2026 07:35:33 +0100 Subject: [PATCH] feat(core): add count_where() helper, compress admin COUNT queries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task 2/6: Adds count_where(table_where, params) to core.py that compresses the fetch_one + null-check COUNT(*) pattern. Applied across admin/routes.py — dashboard stats shrinks from ~75 to ~25 lines, plus 10 more call sites compressed. Co-Authored-By: Claude Opus 4.6 --- web/src/padelnomics/admin/routes.py | 150 ++++++++-------------------- web/src/padelnomics/core.py | 9 ++ 2 files changed, 50 insertions(+), 109 deletions(-) diff --git a/web/src/padelnomics/admin/routes.py b/web/src/padelnomics/admin/routes.py index 71fd52b..c55d3c3 100644 --- a/web/src/padelnomics/admin/routes.py +++ b/web/src/padelnomics/admin/routes.py @@ -28,6 +28,7 @@ from ..auth.routes import role_required from ..core import ( EMAIL_ADDRESSES, config, + count_where, csrf_protect, execute, fetch_all, @@ -91,8 +92,7 @@ async def _inject_admin_sidebar_data(): """Load unread inbox count for sidebar badge on every admin page.""" from quart import g try: - row = await fetch_one("SELECT COUNT(*) as cnt FROM inbound_emails WHERE is_read = 0") - g.admin_unread_count = row["cnt"] if row else 0 + g.admin_unread_count = await count_where("inbound_emails WHERE is_read = 0") except Exception: logger.exception("Failed to load admin sidebar unread count") g.admin_unread_count = 0 @@ -114,76 +114,32 @@ async def get_dashboard_stats() -> dict: now = utcnow() today = now.date().isoformat() week_ago = (now - timedelta(days=7)).strftime("%Y-%m-%d %H:%M:%S") - users_total = await fetch_one("SELECT COUNT(*) as count FROM users WHERE deleted_at IS NULL") - users_today = await fetch_one( - "SELECT COUNT(*) as count FROM users WHERE created_at >= ? AND deleted_at IS NULL", - (today,) - ) - users_week = await fetch_one( - "SELECT COUNT(*) as count FROM users WHERE created_at >= ? AND deleted_at IS NULL", - (week_ago,) - ) - subs = await fetch_one( - "SELECT COUNT(*) as count FROM subscriptions WHERE status = 'active'" + # Two queries that aren't simple COUNT(*) — keep as fetch_one + planner_row = await fetch_one( + "SELECT COUNT(DISTINCT user_id) AS n FROM scenarios WHERE deleted_at IS NULL" ) - - tasks_pending = await fetch_one("SELECT COUNT(*) as count FROM tasks WHERE status = 'pending'") - tasks_failed = await fetch_one("SELECT COUNT(*) as count FROM tasks WHERE status = 'failed'") - - # Lead funnel stats - leads_total = await fetch_one( - "SELECT COUNT(*) as count FROM lead_requests WHERE lead_type = 'quote'" - ) - leads_new = await fetch_one( - "SELECT COUNT(*) as count FROM lead_requests WHERE status = 'new' AND lead_type = 'quote'" - ) - leads_verified = await fetch_one( - "SELECT COUNT(*) as count FROM lead_requests WHERE verified_at IS NOT NULL AND lead_type = 'quote'" - ) - leads_unlocked = await fetch_one( - "SELECT COUNT(*) as count FROM lead_requests WHERE unlock_count > 0 AND lead_type = 'quote'" - ) - - # Planner users - planner_users = await fetch_one( - "SELECT COUNT(DISTINCT user_id) as count FROM scenarios WHERE deleted_at IS NULL" - ) - - # Supplier stats - suppliers_claimed = await fetch_one( - "SELECT COUNT(*) as count FROM suppliers WHERE claimed_by IS NOT NULL" - ) - suppliers_growth = await fetch_one( - "SELECT COUNT(*) as count FROM suppliers WHERE tier = 'growth'" - ) - suppliers_pro = await fetch_one( - "SELECT COUNT(*) as count FROM suppliers WHERE tier = 'pro'" - ) - total_credits_spent = await fetch_one( - "SELECT COALESCE(SUM(ABS(delta)), 0) as total FROM credit_ledger WHERE delta < 0" - ) - leads_unlocked_by_suppliers = await fetch_one( - "SELECT COUNT(*) as count FROM lead_forwards" + credits_row = await fetch_one( + "SELECT COALESCE(SUM(ABS(delta)), 0) AS n FROM credit_ledger WHERE delta < 0" ) return { - "users_total": users_total["count"] if users_total else 0, - "users_today": users_today["count"] if users_today else 0, - "users_week": users_week["count"] if users_week else 0, - "active_subscriptions": subs["count"] if subs else 0, - "tasks_pending": tasks_pending["count"] if tasks_pending else 0, - "tasks_failed": tasks_failed["count"] if tasks_failed else 0, - "leads_total": leads_total["count"] if leads_total else 0, - "leads_new": leads_new["count"] if leads_new else 0, - "leads_verified": leads_verified["count"] if leads_verified else 0, - "leads_unlocked": leads_unlocked["count"] if leads_unlocked else 0, - "planner_users": planner_users["count"] if planner_users else 0, - "suppliers_claimed": suppliers_claimed["count"] if suppliers_claimed else 0, - "suppliers_growth": suppliers_growth["count"] if suppliers_growth else 0, - "suppliers_pro": suppliers_pro["count"] if suppliers_pro else 0, - "total_credits_spent": total_credits_spent["total"] if total_credits_spent else 0, - "leads_unlocked_by_suppliers": leads_unlocked_by_suppliers["count"] if leads_unlocked_by_suppliers else 0, + "users_total": await count_where("users WHERE deleted_at IS NULL"), + "users_today": await count_where("users WHERE created_at >= ? AND deleted_at IS NULL", (today,)), + "users_week": await count_where("users WHERE created_at >= ? AND deleted_at IS NULL", (week_ago,)), + "active_subscriptions": await count_where("subscriptions WHERE status = 'active'"), + "tasks_pending": await count_where("tasks WHERE status = 'pending'"), + "tasks_failed": await count_where("tasks WHERE status = 'failed'"), + "leads_total": await count_where("lead_requests WHERE lead_type = 'quote'"), + "leads_new": await count_where("lead_requests WHERE status = 'new' AND lead_type = 'quote'"), + "leads_verified": await count_where("lead_requests WHERE verified_at IS NOT NULL AND lead_type = 'quote'"), + "leads_unlocked": await count_where("lead_requests WHERE unlock_count > 0 AND lead_type = 'quote'"), + "planner_users": planner_row["n"] if planner_row else 0, + "suppliers_claimed": await count_where("suppliers WHERE claimed_by IS NOT NULL"), + "suppliers_growth": await count_where("suppliers WHERE tier = 'growth'"), + "suppliers_pro": await count_where("suppliers WHERE tier = 'pro'"), + "total_credits_spent": credits_row["n"] if credits_row else 0, + "leads_unlocked_by_suppliers": await count_where("lead_forwards WHERE 1=1"), } @@ -446,10 +402,7 @@ async def get_leads( params.append(f"-{days} days") where = " AND ".join(wheres) - count_row = await fetch_one( - f"SELECT COUNT(*) as cnt FROM lead_requests WHERE {where}", tuple(params) - ) - total = count_row["cnt"] if count_row else 0 + total = await count_where(f"lead_requests WHERE {where}", tuple(params)) offset = (page - 1) * per_page rows = await fetch_all( @@ -929,13 +882,10 @@ async def get_suppliers_list( async def get_supplier_stats() -> dict: """Get aggregate supplier stats for the admin list header.""" - claimed = await fetch_one("SELECT COUNT(*) as cnt FROM suppliers WHERE claimed_by IS NOT NULL") - growth = await fetch_one("SELECT COUNT(*) as cnt FROM suppliers WHERE tier = 'growth'") - pro = await fetch_one("SELECT COUNT(*) as cnt FROM suppliers WHERE tier = 'pro'") return { - "claimed": claimed["cnt"] if claimed else 0, - "growth": growth["cnt"] if growth else 0, - "pro": pro["cnt"] if pro else 0, + "claimed": await count_where("suppliers WHERE claimed_by IS NOT NULL"), + "growth": await count_where("suppliers WHERE tier = 'growth'"), + "pro": await count_where("suppliers WHERE tier = 'pro'"), } @@ -1017,11 +967,7 @@ async def supplier_detail(supplier_id: int): (supplier_id,), ) - enquiry_row = await fetch_one( - "SELECT COUNT(*) as cnt FROM supplier_enquiries WHERE supplier_id = ?", - (supplier_id,), - ) - enquiry_count = enquiry_row["cnt"] if enquiry_row else 0 + enquiry_count = await count_where("supplier_enquiries WHERE supplier_id = ?", (supplier_id,)) # Email activity timeline — correlate by contact_email (no FK) timeline = [] @@ -1239,7 +1185,6 @@ _PRODUCT_CATEGORIES = [ @role_required("admin") async def billing_products(): """Read-only overview of Paddle products, subscriptions, and revenue proxies.""" - active_subs_row = await fetch_one("SELECT COUNT(*) as cnt FROM subscriptions WHERE status = 'active'") mrr_row = await fetch_one( """SELECT COALESCE(SUM( CASE WHEN pp.key LIKE '%_yearly' THEN pp.price_cents / 12 @@ -1249,14 +1194,12 @@ async def billing_products(): JOIN paddle_products pp ON s.plan = pp.key WHERE s.status = 'active' AND pp.billing_type = 'subscription'""" ) - active_boosts_row = await fetch_one("SELECT COUNT(*) as cnt FROM supplier_boosts WHERE status = 'active'") - bp_exports_row = await fetch_one("SELECT COUNT(*) as cnt FROM business_plan_exports WHERE status = 'completed'") stats = { - "active_subs": (active_subs_row or {}).get("cnt", 0), + "active_subs": await count_where("subscriptions WHERE status = 'active'"), "mrr_cents": (mrr_row or {}).get("total_cents", 0), - "active_boosts": (active_boosts_row or {}).get("cnt", 0), - "bp_exports": (bp_exports_row or {}).get("cnt", 0), + "active_boosts": await count_where("supplier_boosts WHERE status = 'active'"), + "bp_exports": await count_where("business_plan_exports WHERE status = 'completed'"), } products_rows = await fetch_all("SELECT * FROM paddle_products ORDER BY key") @@ -1342,23 +1285,18 @@ async def get_email_log( async def get_email_stats() -> dict: """Aggregate email stats for the list header.""" - total = await fetch_one("SELECT COUNT(*) as cnt FROM email_log") - delivered = await fetch_one("SELECT COUNT(*) as cnt FROM email_log WHERE last_event = 'delivered'") - bounced = await fetch_one("SELECT COUNT(*) as cnt FROM email_log WHERE last_event = 'bounced'") today = utcnow().date().isoformat() - sent_today = await fetch_one("SELECT COUNT(*) as cnt FROM email_log WHERE created_at >= ?", (today,)) return { - "total": total["cnt"] if total else 0, - "delivered": delivered["cnt"] if delivered else 0, - "bounced": bounced["cnt"] if bounced else 0, - "sent_today": sent_today["cnt"] if sent_today else 0, + "total": await count_where("email_log WHERE 1=1"), + "delivered": await count_where("email_log WHERE last_event = 'delivered'"), + "bounced": await count_where("email_log WHERE last_event = 'bounced'"), + "sent_today": await count_where("email_log WHERE created_at >= ?", (today,)), } async def get_unread_count() -> int: """Count unread inbound emails.""" - row = await fetch_one("SELECT COUNT(*) as cnt FROM inbound_emails WHERE is_read = 0") - return row["cnt"] if row else 0 + return await count_where("inbound_emails WHERE is_read = 0") @bp.route("/emails") @@ -1824,11 +1762,7 @@ async def template_detail(slug: str): columns = await get_table_columns(config["data_table"]) sample_rows = await fetch_template_data(config["data_table"], limit=10) - # Count generated articles - row = await fetch_one( - "SELECT COUNT(*) as cnt FROM articles WHERE template_slug = ?", (slug,), - ) - generated_count = row["cnt"] if row else 0 + generated_count = await count_where("articles WHERE template_slug = ?", (slug,)) return await render_template( "admin/template_detail.html", @@ -1959,8 +1893,8 @@ async def _query_scenarios(search: str, country: str, venue_type: str) -> tuple[ f"SELECT * FROM published_scenarios WHERE {where} ORDER BY created_at DESC LIMIT 500", tuple(params), ) - total_row = await fetch_one("SELECT COUNT(*) as cnt FROM published_scenarios") - return rows, (total_row["cnt"] if total_row else 0) + total = await count_where("published_scenarios WHERE 1=1") + return rows, total @bp.route("/scenarios") @@ -2927,11 +2861,9 @@ _CSV_IMPORT_LIMIT = 500 # guard against huge uploads async def get_follow_up_due_count() -> int: """Count pipeline suppliers with follow_up_at <= today.""" - row = await fetch_one( - """SELECT COUNT(*) as cnt FROM suppliers - WHERE outreach_status IS NOT NULL AND follow_up_at <= date('now')""" + return await count_where( + "suppliers WHERE outreach_status IS NOT NULL AND follow_up_at <= date('now')" ) - return row["cnt"] if row else 0 async def get_outreach_pipeline() -> dict: diff --git a/web/src/padelnomics/core.py b/web/src/padelnomics/core.py index 19f9438..ed5c905 100644 --- a/web/src/padelnomics/core.py +++ b/web/src/padelnomics/core.py @@ -192,6 +192,15 @@ async def fetch_all(sql: str, params: tuple = ()) -> list[dict]: return [dict(row) for row in rows] +async def count_where(table_where: str, params: tuple = ()) -> int: + """Count rows matching a condition. Compresses the fetch_one + null-check pattern. + + Usage: await count_where("users WHERE deleted_at IS NULL") + """ + row = await fetch_one(f"SELECT COUNT(*) AS n FROM {table_where}", params) + return row["n"] if row else 0 + + async def execute(sql: str, params: tuple = ()) -> int: """Execute SQL and return lastrowid.""" db = await get_db()