Skip to content

Conversation

@ZdenekSrotyr
Copy link
Contributor

@ZdenekSrotyr ZdenekSrotyr commented Dec 19, 2025

fix(SUPPORT-14107): robust action breakdown detection and DSL parsing

Summary

Fixes Facebook Ads V2 action breakdown queries that were producing empty columns in output. The root cause was threefold:

  1. Fragile action breakdown detection in output_parser.py that only worked with string parameters containing exact substring matches
  2. Missing DSL parameter parsing in page_loader.py - sync insights queries using DSL syntax weren't sending required parameters to Facebook API
  3. Missing account_id in output when explicit fields are specified in DSL (Facebook API doesn't return it automatically)

Changes in output_parser.py:

  • Added _is_action_breakdown_query() helper that properly handles:
    • String parameters (query string format like action_breakdowns=action_type)
    • Dict parameters
    • DSL-style fields string (.action_breakdowns(action_type) syntax)
  • Uses urllib.parse.parse_qs for proper query string parsing with fallback
  • Refactored _copy_common_fields(extended=True) to follow Clojure V1 approach: copy ALL scalar fields from original_row instead of maintaining an explicit field list
  • Simplified _populate_action_row() to copy all fields from action data (Clojure approach)
  • Removed _has_action_reaction_breakdown() helper - action_reaction is now included automatically if present in data
  • Added account_id derivation from page_id in _create_base_row() for Ads accounts (strips act_ prefix)

Changes in page_loader.py:

  • Replaced individual DSL handlers with a generic regex extractor that automatically forwards any .X(Y) pattern as X=Y parameter
  • Only special handling for:
    • since/until: date conversion via get_past_date()
    • metric: comma-separated list normalization
  • All other params (level, action_breakdowns, date_preset, period, time_increment, etc.) pass through directly
  • Extracts {field1,field2,...}fields=field1,field2,... via regex
  • Future-proof: any new DSL pattern automatically gets forwarded without code changes

Updates since last revision

Added account_id fallback - Test job 152495554 failed with "Missing columns: account_id" because Facebook API doesn't return account_id when explicit fields are specified in DSL. Following Clojure approach: derive account_id from the query context (page_id) by stripping the act_ prefix for Ads accounts.

Review & Testing Checklist for Human

  • Re-test with actual customer config (project 15170) - previous tests failed. Must verify sync query now produces expected columns including account_id
  • Verify account_id format is correct - the fix strips act_ prefix (e.g., act_123456123456). Confirm this matches what the output mapping/schema expects
  • Verify regex handles edge cases - the pattern [^)]+ won't handle nested parentheses. Check for configs where DSL values might contain ) characters
  • Verify no regression for Facebook Pages and Instagram - this component serves all three (FB Ads, Pages, IG). The account_id derivation only triggers when page_id starts with act_
  • Test async queries still work - page_loader.py changes only affect _build_params() used by sync queries

Recommended test plan:

  1. Deploy new branch tag to test config in project 15170
  2. Run the customer's sync extraction query with action_breakdowns=action_type
  3. Verify output table has populated values for: account_id, ad_name, clicks, impressions, spend, reach
  4. Run a basic Facebook Pages or Instagram query to verify no regression
  5. Run an async insights query to verify no regression

Notes

Link to Devin run: https://app.devin.ai/sessions/d820bdbb1686427f81b3777a37f3fc2d
Requested by: [email protected] (@ZdenekSrotyr)

- Add _is_action_breakdown_query() helper that handles both string and dict parameters
- Add _has_action_reaction_breakdown() helper for action_reaction specific detection
- Use urllib.parse.parse_qs for proper query string parsing with fallback
- Support DSL-style fields string (.action_breakdowns() syntax)
- Add missing fields to _copy_common_fields(extended=True): ad_name, adset_name, impressions, clicks, spend, reach

This fixes the issue where action breakdown queries were not properly detected
when parameters were in different formats, causing empty columns in output.

Co-Authored-By: [email protected] <[email protected]>
@devin-ai-integration
Copy link
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

devin-ai-integration bot and others added 4 commits December 19, 2025 12:11
…elds

Instead of maintaining an explicit list of fields to copy, follow the
Clojure V1 approach: when extended=True, copy ALL scalar fields from
original_row to action rows.

This is simpler, more flexible, and automatically includes any new
fields that Facebook API returns without code changes.

Co-Authored-By: [email protected] <[email protected]>
- Remove _has_action_reaction_breakdown() helper entirely
- Remove DSL detection from _is_action_breakdown_query()
- Simplify _populate_action_row() to copy all fields from action data
- action_reaction is now included automatically if present in data

Co-Authored-By: [email protected] <[email protected]>
Customer config uses DSL-style fields (e.g., insights.action_breakdowns(action_type))
which requires DSL detection to properly route output to action rows.
Without this, output mapping fails with missing columns error.

Co-Authored-By: [email protected] <[email protected]>
Add parsing for DSL patterns in sync insights queries:
- .level(X) -> level=X
- .action_breakdowns(X) -> action_breakdowns=X
- .date_preset(X) -> date_preset=X
- .time_increment(X) -> time_increment=X
- {field1,field2,...} -> fields=field1,field2,...

Without this, sync queries using DSL syntax don't send the
required parameters to Facebook API, resulting in missing columns.

Co-Authored-By: [email protected] <[email protected]>
@devin-ai-integration devin-ai-integration bot changed the title fix(SUPPORT-14107): robust action breakdown detection and missing fields fix(SUPPORT-14107): robust action breakdown detection and DSL parsing Dec 19, 2025
devin-ai-integration bot and others added 2 commits December 19, 2025 14:17
Replace individual .X() handlers with generic regex extractor that
automatically forwards any .X(Y) pattern as X=Y parameter.

Only special handling for:
- since/until: date conversion via get_past_date()
- metric: comma-separated list normalization

Any new DSL pattern (e.g. .filtering(), .breakdowns()) will be
automatically forwarded without code changes.

query.parameters still overrides DSL-derived values (existing behavior).

Co-Authored-By: [email protected] <[email protected]>
Facebook API doesn't return account_id when explicit fields are specified
in DSL. Following Clojure approach: derive account_id from the query
context (page_id) instead of relying on API response.

For Ads accounts (page_id starts with 'act_'), strip the prefix to get
the numeric account_id that output mapping expects.

Co-Authored-By: [email protected] <[email protected]>
@devin-ai-integration
Copy link
Contributor

Merged into PR #23

@devin-ai-integration devin-ai-integration bot deleted the devin/SUPPORT-14107-1766145867-minimal-fix branch December 19, 2025 15:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant