Skip to content

feat: adicionar handler Meta Ad Library#54

Merged
magroski merged 2 commits into
mainfrom
feature/sc-76058/meta-ad-library-handler
Apr 22, 2026
Merged

feat: adicionar handler Meta Ad Library#54
magroski merged 2 commits into
mainfrom
feature/sc-76058/meta-ad-library-handler

Conversation

@patrickadeelino
Copy link
Copy Markdown
Collaborator

@patrickadeelino patrickadeelino commented Apr 20, 2026

Contexto

Handler para consultar dados públicos da Meta Ad Library via `https://graph.facebook.com/<api_version>/ads_archive`. Parte da story SC-76058, que entrega o conector `meta_ad_library` no Data Agent com token gerenciado pela Talentify.

O que foi implementado

  • Handler `meta_ad_library` com tabela `ads` expondo os principais campos públicos da API: dados criativos, janela de entrega, page info, métricas best-effort de impressões/gastos e distribuição demográfica/regional.
  • Paginação por cursor (`after`) com suporte a `LIMIT` e filtros temporais traduzidos para `ad_delivery_date_min`/`ad_delivery_date_max`.
  • Sanitização de `ad_snapshot_url`: URLs internas do Facebook que continham `access_token` na query string são convertidas para links públicos da Ad Library (`/ads/library/?id=<ad_id>`), eliminando vazamento de token nas respostas do agente.
  • Correção de LIMIT com filtros locais: quando a query inclui filtros que o MindsDB aplica localmente (ex: `WHERE page_name = 'X'`), o handler usa `DEFAULT_PAGE_SIZE` em vez do LIMIT SQL para buscar uma amostra suficiente da API antes do filtro local. Sem essa correção, `LIMIT 5` com `WHERE page_name` retornava 0 linhas.
  • Defaults sensatos: `api_version=v24.0`, `ad_type=ALL`, `ad_active_status=ALL`, `ad_reached_countries=["ALL"]`.

Arquitetura e decisões

O token é passado via `connection_data` — sem OAuth na V1. O handler lê `access_token` de `connection_data` e o injeta nas requests à API da Meta. No lado do `mktplace`, o token é gerenciado pela plataforma e nunca exposto ao usuário final (ver PR correspondente no mktplace).

A lógica de "não pré-limitar quando há filtros locais pendentes" fica em `ads_table.py` após `_build_request_params`, verificando se o conjunto de condições originais ainda tem filtros não traduzidos para a API.

Correções pós-review

  • `_request()`: substituído `assert self.session is not None` por `RuntimeError` explícito — `assert` é eliminado com a flag `-O` do Python, deixando um `AttributeError` opaco no lugar de uma mensagem legível.
  • `_extract_delivery_date_bounds()`: removido `NOT_BETWEEN` do check inicial de operadores. O operador não tem mapeamento para os parâmetros `ad_delivery_date_min`/`max` da API da Meta e nunca marcava `condition.applied = True` — comportamento correto mas acidental. Agora cai explicitamente para filtragem local do MindsDB.
  • `_coerce_to_list()`: colapsados os branches idênticos de `list` e `tuple` em um único `isinstance(value, (list, tuple))`.
  • Teste adicionado: `test_check_connection_fails_when_no_search_scope` cobre o caminho de 400 da API quando nenhum `search_page_ids` nem `search_terms` é fornecido na `connection_data`.

Pontos de atenção

  • Campos de métricas (`impressions`, `spend`, `estimated_audience_size`, `delivery_by_region`, `demographic_distribution`) são best-effort — a Meta não os retorna para todos os anúncios, dependendo do tipo e dos limiares de privacidade.
  • Testes unitários: 12 passed.

patrickadeelino and others added 2 commits April 20, 2026 14:45
… Library

- Substitui `assert self.session is not None` por RuntimeError explícito em
  `_request()` — assert é eliminado com flag -O do Python, deixando um
  AttributeError opaco no lugar de uma mensagem legível
- Remove NOT_BETWEEN do check inicial de `_extract_delivery_date_bounds()`:
  o operador não tem mapeamento para os parâmetros da API da Meta e nunca
  marcava `condition.applied = True`, comportamento correto mas acidental;
  agora cai no branch else, retorna None no _coerce_date e é ignorado
  explicitamente, ficando para filtragem local do MindsDB
- Colapsa os branches idênticos de list/tuple em `_coerce_to_list()` em um
  único isinstance(value, (list, tuple))
- Adiciona test_check_connection_fails_when_no_search_scope: cobre o caminho
  de 400 da API da Meta quando nenhum search_page_ids nem search_terms é
  fornecido na connection_data

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@patrickadeelino patrickadeelino marked this pull request as ready for review April 22, 2026 14:54
@magroski magroski merged commit f0fe705 into main Apr 22, 2026
1 check failed
@magroski magroski deleted the feature/sc-76058/meta-ad-library-handler branch April 22, 2026 15:26
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.

2 participants