feat(campaigns): add PostgreSQL campaign repository
Adds CampaignRepository with list/get/create/update/delete for campaigns plus add_event/list_events for the audit trail, following the existing postgres_repo.py connection pattern. Replaces the brief's two bare `assert created/updated is not None` checks with explicit RuntimeError raises so the guard survives python -O.
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Row mapping for the campaign repository."""
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from adclaw.campaigns.repo import campaign_from_row
|
||||
|
||||
|
||||
def _row(**overrides):
|
||||
row = {
|
||||
"id": "camp_1",
|
||||
"company_id": "maskanx",
|
||||
"name": "Lead gen",
|
||||
"status": "draft",
|
||||
"origin": "maskanx",
|
||||
"objective": "OUTCOME_LEADS",
|
||||
"ad_account_id": "act_1",
|
||||
"budget": {"daily_budget": 10000},
|
||||
"guardrails": {"max_cost_per_lead": 150},
|
||||
"targeting": {"age_min": 25},
|
||||
"advanced": {},
|
||||
"channels": ["facebook"],
|
||||
"schedule": {},
|
||||
"meta_campaign_id": None,
|
||||
"sync_status": "not_synced",
|
||||
"sync_error": None,
|
||||
"approved_by": None,
|
||||
"created_at": datetime(2026, 8, 1, tzinfo=timezone.utc),
|
||||
"updated_at": datetime(2026, 8, 1, tzinfo=timezone.utc),
|
||||
}
|
||||
row.update(overrides)
|
||||
return row
|
||||
|
||||
|
||||
def test_campaign_from_row_maps_all_fields():
|
||||
spec = campaign_from_row(_row())
|
||||
assert spec.id == "camp_1"
|
||||
assert spec.budget["daily_budget"] == 10000
|
||||
assert spec.guardrails["max_cost_per_lead"] == 150
|
||||
assert spec.channels == ["facebook"]
|
||||
assert spec.sync_status == "not_synced"
|
||||
|
||||
|
||||
def test_campaign_from_row_defaults_null_json_to_empty():
|
||||
spec = campaign_from_row(
|
||||
_row(budget=None, guardrails=None, targeting=None, advanced=None,
|
||||
channels=None, schedule=None),
|
||||
)
|
||||
assert spec.budget == {}
|
||||
assert spec.guardrails == {}
|
||||
assert spec.targeting == {}
|
||||
assert spec.advanced == {}
|
||||
assert spec.channels == []
|
||||
assert spec.schedule == {}
|
||||
Reference in New Issue
Block a user