From 0aba33ca8d0b09d11bb66e90b58e85a284330d80 Mon Sep 17 00:00:00 2001 From: Jonas Linter Date: Wed, 22 Oct 2025 08:22:25 +0200 Subject: [PATCH] Campaign missing from db when running campaign_insights --- src/meta_api_grabber/database.py | 35 +++++++++++++++++++++++ src/meta_api_grabber/scheduled_grabber.py | 12 ++++++-- 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/src/meta_api_grabber/database.py b/src/meta_api_grabber/database.py index e18a174..f823cfd 100644 --- a/src/meta_api_grabber/database.py +++ b/src/meta_api_grabber/database.py @@ -296,6 +296,7 @@ class TimescaleDBClient: account_id: str, data: Dict[str, Any], date_preset: str = "today", + cache_metadata: bool = True, ): """ Insert campaign-level insights data. @@ -306,7 +307,18 @@ class TimescaleDBClient: account_id: Ad account ID data: Insights data dictionary from Meta API date_preset: Date preset used + cache_metadata: If True, automatically cache campaign metadata from insights data """ + # Cache campaign metadata if requested and available in the insights data + if cache_metadata and data.get("campaign_name"): + await self.upsert_campaign( + campaign_id=campaign_id, + account_id=account_id, + campaign_name=data["campaign_name"], + status=None, # Not available in insights response + objective=None, # Not available in insights response + ) + query = """ INSERT INTO campaign_insights ( time, campaign_id, account_id, impressions, clicks, spend, reach, @@ -362,6 +374,7 @@ class TimescaleDBClient: account_id: str, data: Dict[str, Any], date_preset: str = "today", + cache_metadata: bool = True, ): """ Insert ad set level insights data. @@ -373,7 +386,29 @@ class TimescaleDBClient: account_id: Ad account ID data: Insights data dictionary from Meta API date_preset: Date preset used + cache_metadata: If True, automatically cache adset/campaign metadata from insights data """ + # Cache metadata if requested and available in the insights data + if cache_metadata: + # First ensure campaign exists (adset references campaign) + # We don't have campaign name in adset insights, so only create if needed + await self.upsert_campaign( + campaign_id=campaign_id, + account_id=account_id, + campaign_name='Unknown', # Campaign name not in adset insights + status=None, + objective=None, + ) + + # Then cache adset metadata if available + if data.get("adset_name"): + await self.upsert_adset( + adset_id=adset_id, + campaign_id=campaign_id, + adset_name=data["adset_name"], + status=None, # Not available in insights response + ) + query = """ INSERT INTO adset_insights ( time, adset_id, campaign_id, account_id, impressions, clicks, spend, reach, diff --git a/src/meta_api_grabber/scheduled_grabber.py b/src/meta_api_grabber/scheduled_grabber.py index 5093987..54b791c 100644 --- a/src/meta_api_grabber/scheduled_grabber.py +++ b/src/meta_api_grabber/scheduled_grabber.py @@ -503,7 +503,7 @@ class ScheduledInsightsGrabber: # Get account timezone from database account_timezone = await self._get_account_timezone(account_id) - # Store insights + # Store insights (metadata is automatically cached from insights data) count = 0 for insight in insights: campaign_id = insight.get('campaign_id') @@ -514,12 +514,14 @@ class ScheduledInsightsGrabber: date_start_str = insight_dict.get("date_start") timestamp = self._compute_timestamp(date_start_str, account_timezone) + # Insert insights - metadata is automatically cached from the insights data await self.db.insert_campaign_insights( time=timestamp, campaign_id=campaign_id, account_id=account_id, data=insight_dict, date_preset=date_preset, + cache_metadata=True, # Automatically cache campaign name from insights ) count += 1 @@ -572,7 +574,7 @@ class ScheduledInsightsGrabber: # Get account timezone from database account_timezone = await self._get_account_timezone(account_id) - # Store insights + # Store insights (metadata is automatically cached from insights data) count = 0 for insight in insights: adset_id = insight.get('adset_id') @@ -584,6 +586,7 @@ class ScheduledInsightsGrabber: date_start_str = insight_dict.get("date_start") timestamp = self._compute_timestamp(date_start_str, account_timezone) + # Insert insights - metadata is automatically cached from the insights data await self.db.insert_adset_insights( time=timestamp, adset_id=adset_id, @@ -591,6 +594,7 @@ class ScheduledInsightsGrabber: account_id=account_id, data=insight_dict, date_preset=date_preset, + cache_metadata=True, # Automatically cache adset/campaign from insights ) count += 1 @@ -601,7 +605,9 @@ class ScheduledInsightsGrabber: Run a single collection cycle for all ad accounts. Args: - cache_metadata: Whether to refresh metadata cache + cache_metadata: Whether to fetch and cache full metadata (status, objective, etc.) + from separate API calls. Campaign/adset names are always cached + automatically from insights data to prevent foreign key violations. """ print("\n" + "="*60) print(f"COLLECTION CYCLE - {datetime.now().isoformat()}")