From 1d9b011a790cb707c172d17a54a675be54210cd2 Mon Sep 17 00:00:00 2001 From: Artem Inzhyyants Date: Mon, 23 Oct 2023 17:37:37 +0200 Subject: [PATCH 01/14] Source Bing Ads: remove vcrpy caching --- .../connectors/source-bing-ads/metadata.yaml | 2 +- .../connectors/source-bing-ads/setup.py | 2 +- .../source-bing-ads/source_bing_ads/cache.py | 42 ------------------- .../source-bing-ads/source_bing_ads/source.py | 11 +---- 4 files changed, 3 insertions(+), 54 deletions(-) delete mode 100644 airbyte-integrations/connectors/source-bing-ads/source_bing_ads/cache.py diff --git a/airbyte-integrations/connectors/source-bing-ads/metadata.yaml b/airbyte-integrations/connectors/source-bing-ads/metadata.yaml index c67f82b4b936..23af3dbb0312 100644 --- a/airbyte-integrations/connectors/source-bing-ads/metadata.yaml +++ b/airbyte-integrations/connectors/source-bing-ads/metadata.yaml @@ -16,7 +16,7 @@ data: connectorSubtype: api connectorType: source definitionId: 47f25999-dd5e-4636-8c39-e7cea2453331 - dockerImageTag: 1.0.2 + dockerImageTag: 1.1.0 dockerRepository: airbyte/source-bing-ads documentationUrl: https://docs.airbyte.com/integrations/sources/bing-ads githubIssueLabel: source-bing-ads diff --git a/airbyte-integrations/connectors/source-bing-ads/setup.py b/airbyte-integrations/connectors/source-bing-ads/setup.py index c342863f078e..ad3e2ee1a218 100644 --- a/airbyte-integrations/connectors/source-bing-ads/setup.py +++ b/airbyte-integrations/connectors/source-bing-ads/setup.py @@ -5,7 +5,7 @@ from setuptools import find_packages, setup -MAIN_REQUIREMENTS = ["airbyte-cdk", "bingads~=13.0.13", "vcrpy==4.1.1", "backoff==1.10.0", "pendulum==2.1.2", "urllib3<2.0"] +MAIN_REQUIREMENTS = ["airbyte-cdk", "bingads~=13.0.13", "urllib3<2.0"] TEST_REQUIREMENTS = [ "requests-mock~=1.9.3", diff --git a/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/cache.py b/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/cache.py deleted file mode 100644 index 52736e8ee945..000000000000 --- a/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/cache.py +++ /dev/null @@ -1,42 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -import contextlib -import tempfile - -import vcr - - -def _matcher(r1: vcr.request.Request, r2: vcr.request.Request) -> None: - """ - Defines algorithm to compare two bing ads requests. - Makes sure that uri, body and headers are equal in both requests - """ - assert r1.uri == r2.uri and r1.body == r2.body and r1.headers == r2.headers - - -class VcrCache: - """ - VcrPy wrapper to cache bing ads requests, and to be able to reuse results in other streams - """ - - def __init__(self) -> None: - self._vcr = vcr.VCR() - self._vcr.register_matcher("default", _matcher) - # Register default matcher - self._vcr.match_on = ["default"] - - self._cache_file = tempfile.NamedTemporaryFile() - # Init inmemory cache file with empty data - self._cache_file.write(b"interactions: []") - self._cache_file.flush() - self._cache_file.close() - - @contextlib.contextmanager - def use_cassette(self) -> None: - """ - Implements use_cassette method wrapper which uses in-memory temporary file for caching and yaml format for serialization - """ - with self._vcr.use_cassette(self._cache_file.name, record_mode="new_episodes", serializer="yaml"): - yield diff --git a/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/source.py b/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/source.py index 7d32cb18b6ce..fc481cb68b18 100644 --- a/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/source.py +++ b/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/source.py @@ -15,7 +15,6 @@ from airbyte_cdk.sources.streams import Stream from bingads.service_client import ServiceClient from bingads.v13.reporting.reporting_service_manager import ReportingServiceManager -from source_bing_ads.cache import VcrCache from source_bing_ads.client import Client from source_bing_ads.reports import ( ALL_CONVERSION_FIELDS, @@ -31,13 +30,9 @@ ) from suds import sudsobject -CACHE: VcrCache = VcrCache() - class BingAdsStream(Stream, ABC): primary_key: Optional[Union[str, List[str], List[List[str]]]] = None - # indicates whether stream should cache incoming responses via VcrCache - use_cache: bool = False def __init__(self, client: Client, config: Mapping[str, Any]) -> None: super().__init__() @@ -120,11 +115,7 @@ def send_request(self, params: Mapping[str, Any], customer_id: str, account_id: "params": params, } request = self.client.request(**request_kwargs) - if self.use_cache: - with CACHE.use_cassette(): - return request - else: - return request + return request def read_records( self, From 70e9c359eda5ef1d2e986ef897b977f4a0e9a15d Mon Sep 17 00:00:00 2001 From: Artem Inzhyyants Date: Mon, 23 Oct 2023 17:45:58 +0200 Subject: [PATCH 02/14] Source Bing Ads: refactor --- .../source-bing-ads/source_bing_ads/source.py | 824 +---------------- .../source_bing_ads/streams.py | 831 ++++++++++++++++++ 2 files changed, 833 insertions(+), 822 deletions(-) create mode 100644 airbyte-integrations/connectors/source-bing-ads/source_bing_ads/streams.py diff --git a/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/source.py b/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/source.py index fc481cb68b18..42012caf12f6 100644 --- a/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/source.py +++ b/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/source.py @@ -3,834 +3,14 @@ # -import ssl -import time -from abc import ABC, abstractmethod -from typing import Any, Iterable, List, Mapping, MutableMapping, Optional, Tuple, Union -from urllib.error import URLError +from typing import Any, List, Mapping, Tuple from airbyte_cdk import AirbyteLogger from airbyte_cdk.models import SyncMode from airbyte_cdk.sources import AbstractSource from airbyte_cdk.sources.streams import Stream -from bingads.service_client import ServiceClient -from bingads.v13.reporting.reporting_service_manager import ReportingServiceManager from source_bing_ads.client import Client -from source_bing_ads.reports import ( - ALL_CONVERSION_FIELDS, - ALL_REVENUE_FIELDS, - AVERAGE_FIELDS, - BUDGET_FIELDS, - CONVERSION_FIELDS, - HISTORICAL_FIELDS, - LOW_QUALITY_FIELDS, - REVENUE_FIELDS, - PerformanceReportsMixin, - ReportsMixin, -) -from suds import sudsobject - - -class BingAdsStream(Stream, ABC): - primary_key: Optional[Union[str, List[str], List[List[str]]]] = None - - def __init__(self, client: Client, config: Mapping[str, Any]) -> None: - super().__init__() - self.client = client - self.config = config - - @property - @abstractmethod - def data_field(self) -> str: - """ - Specifies root object name in a stream response - """ - pass - - @property - @abstractmethod - def service_name(self) -> str: - """ - Specifies bing ads service name for a current stream - """ - pass - - @property - @abstractmethod - def operation_name(self) -> str: - """ - Specifies operation name to use for a current stream - """ - pass - - @property - @abstractmethod - def additional_fields(self) -> Optional[str]: - """ - Specifies which additional fields to fetch for a current stream. - Expected format: field names separated by space - """ - pass - - @property - def _service(self) -> Union[ServiceClient, ReportingServiceManager]: - return self.client.get_service(service_name=self.service_name) - - @property - def _user_id(self) -> int: - return self._get_user_id() - - # TODO remove once Microsoft support confirm their SSL certificates are always valid... - def _get_user_id(self, number_of_retries=10): - """""" - try: - return self._service.GetUser().User.Id - except URLError as error: - if isinstance(error.reason, ssl.SSLError): - self.logger.warn("SSL certificate error, retrying...") - if number_of_retries > 0: - time.sleep(1) - return self._get_user_id(number_of_retries - 1) - else: - raise error - - def next_page_token(self, response: sudsobject.Object, **kwargs: Mapping[str, Any]) -> Optional[Mapping[str, Any]]: - """ - Default method for streams that don't support pagination - """ - return None - - def parse_response(self, response: sudsobject.Object, **kwargs) -> Iterable[Mapping]: - if response is not None and hasattr(response, self.data_field): - yield from self.client.asdict(response)[self.data_field] - - yield from [] - - def send_request(self, params: Mapping[str, Any], customer_id: str, account_id: str = None) -> Mapping[str, Any]: - request_kwargs = { - "service_name": self.service_name, - "customer_id": customer_id, - "account_id": account_id, - "operation_name": self.operation_name, - "params": params, - } - request = self.client.request(**request_kwargs) - return request - - def read_records( - self, - sync_mode: SyncMode, - stream_slice: Mapping[str, Any] = None, - stream_state: Mapping[str, Any] = None, - **kwargs: Mapping[str, Any], - ) -> Iterable[Mapping[str, Any]]: - stream_state = stream_state or {} - next_page_token = None - account_id = str(stream_slice.get("account_id")) if stream_slice else None - customer_id = str(stream_slice.get("customer_id")) if stream_slice else None - - while True: - params = self.request_params( - stream_state=stream_state, - stream_slice=stream_slice, - next_page_token=next_page_token, - account_id=account_id, - ) - response = self.send_request(params, customer_id=customer_id, account_id=account_id) - for record in self.parse_response(response): - yield record - - next_page_token = self.next_page_token(response, current_page_token=next_page_token) - if not next_page_token: - break - - yield from [] - - -class Accounts(BingAdsStream): - """ - Searches for accounts that the current authenticated user can access. - API doc: https://docs.microsoft.com/en-us/advertising/customer-management-service/searchaccounts?view=bingads-13 - Account schema: https://docs.microsoft.com/en-us/advertising/customer-management-service/advertiseraccount?view=bingads-13 - Stream caches incoming responses to be able to reuse this data in Campaigns stream - """ - - primary_key = "Id" - # Stream caches incoming responses to avoid duplicated http requests - use_cache: bool = True - data_field: str = "AdvertiserAccount" - service_name: str = "CustomerManagementService" - operation_name: str = "SearchAccounts" - additional_fields: str = "TaxCertificate AccountMode" - # maximum page size - page_size_limit: int = 1000 - - def next_page_token(self, response: sudsobject.Object, current_page_token: Optional[int]) -> Optional[Mapping[str, Any]]: - current_page_token = current_page_token or 0 - if response is not None and hasattr(response, self.data_field): - return None if self.page_size_limit > len(response[self.data_field]) else current_page_token + 1 - else: - return None - - def request_params( - self, - next_page_token: Mapping[str, Any] = None, - **kwargs: Mapping[str, Any], - ) -> MutableMapping[str, Any]: - predicates = { - "Predicate": [ - { - "Field": "UserId", - "Operator": "Equals", - "Value": self._user_id, - } - ] - } - - paging = self._service.factory.create("ns5:Paging") - paging.Index = next_page_token or 0 - paging.Size = self.page_size_limit - return { - "PageInfo": paging, - "Predicates": predicates, - "ReturnAdditionalFields": self.additional_fields, - } - - -class Campaigns(BingAdsStream): - """ - Gets the campaigns for all provided accounts. - API doc: https://docs.microsoft.com/en-us/advertising/campaign-management-service/getcampaignsbyaccountid?view=bingads-13 - Campaign schema: https://docs.microsoft.com/en-us/advertising/campaign-management-service/campaign?view=bingads-13 - Stream caches incoming responses to be able to reuse this data in AdGroups stream - """ - - primary_key = "Id" - # Stream caches incoming responses to avoid duplicated http requests - use_cache: bool = True - data_field: str = "Campaign" - service_name: str = "CampaignManagement" - operation_name: str = "GetCampaignsByAccountId" - additional_fields: Iterable[str] = [ - "AdScheduleUseSearcherTimeZone", - "BidStrategyId", - "CpvCpmBiddingScheme", - "DynamicDescriptionSetting", - "DynamicFeedSetting", - "MaxConversionValueBiddingScheme", - "MultimediaAdsBidAdjustment", - "TargetImpressionShareBiddingScheme", - "TargetSetting", - "VerifiedTrackingSetting", - ] - campaign_types: Iterable[str] = ["Audience", "DynamicSearchAds", "Search", "Shopping"] - - def request_params( - self, - stream_slice: Mapping[str, Any] = None, - **kwargs: Mapping[str, Any], - ) -> MutableMapping[str, Any]: - return { - "AccountId": stream_slice["account_id"], - "CampaignType": " ".join(self.campaign_types), - "ReturnAdditionalFields": " ".join(self.additional_fields), - } - - def stream_slices( - self, - **kwargs: Mapping[str, Any], - ) -> Iterable[Optional[Mapping[str, Any]]]: - for account in Accounts(self.client, self.config).read_records(SyncMode.full_refresh): - yield {"account_id": account["Id"], "customer_id": account["ParentCustomerId"]} - - yield from [] - - -class AdGroups(BingAdsStream): - """ - Gets the ad groups for all provided accounts. - API doc: https://docs.microsoft.com/en-us/advertising/campaign-management-service/getadgroupsbycampaignid?view=bingads-13 - AdGroup schema: https://docs.microsoft.com/en-us/advertising/campaign-management-service/adgroup?view=bingads-13 - Stream caches incoming responses to be able to reuse this data in Ads stream - """ - - primary_key = "Id" - # Stream caches incoming responses to avoid duplicated http requests - use_cache: bool = True - data_field: str = "AdGroup" - service_name: str = "CampaignManagement" - operation_name: str = "GetAdGroupsByCampaignId" - additional_fields: str = "AdGroupType AdScheduleUseSearcherTimeZone CpmBid CpvBid MultimediaAdsBidAdjustment" - - def request_params( - self, - stream_slice: Mapping[str, Any] = None, - **kwargs: Mapping[str, Any], - ) -> MutableMapping[str, Any]: - return {"CampaignId": stream_slice["campaign_id"], "ReturnAdditionalFields": self.additional_fields} - - def stream_slices( - self, - **kwargs: Mapping[str, Any], - ) -> Iterable[Optional[Mapping[str, Any]]]: - campaigns = Campaigns(self.client, self.config) - for account in Accounts(self.client, self.config).read_records(SyncMode.full_refresh): - for campaign in campaigns.read_records( - sync_mode=SyncMode.full_refresh, stream_slice={"account_id": account["Id"], "customer_id": account["ParentCustomerId"]} - ): - yield {"campaign_id": campaign["Id"], "account_id": account["Id"], "customer_id": account["ParentCustomerId"]} - - yield from [] - - -class Ads(BingAdsStream): - """ - Retrieves the ads for all provided accounts. - API doc: https://docs.microsoft.com/en-us/advertising/campaign-management-service/getadsbyadgroupid?view=bingads-13 - Ad schema: https://docs.microsoft.com/en-us/advertising/campaign-management-service/ad?view=bingads-13 - """ - - primary_key = "Id" - data_field: str = "Ad" - service_name: str = "CampaignManagement" - operation_name: str = "GetAdsByAdGroupId" - additional_fields: str = "ImpressionTrackingUrls Videos LongHeadlines" - ad_types: Iterable[str] = [ - "Text", - "Image", - "Product", - "AppInstall", - "ExpandedText", - "DynamicSearch", - "ResponsiveAd", - "ResponsiveSearch", - ] - - def request_params( - self, - stream_slice: Mapping[str, Any] = None, - **kwargs: Mapping[str, Any], - ) -> MutableMapping[str, Any]: - return { - "AdGroupId": stream_slice["ad_group_id"], - "AdTypes": {"AdType": self.ad_types}, - "ReturnAdditionalFields": self.additional_fields, - } - - def stream_slices( - self, - **kwargs: Mapping[str, Any], - ) -> Iterable[Optional[Mapping[str, Any]]]: - ad_groups = AdGroups(self.client, self.config) - for slice in ad_groups.stream_slices(sync_mode=SyncMode.full_refresh): - for ad_group in ad_groups.read_records(sync_mode=SyncMode.full_refresh, stream_slice=slice): - yield {"ad_group_id": ad_group["Id"], "account_id": slice["account_id"], "customer_id": slice["customer_id"]} - yield from [] - - -class BudgetSummaryReport(ReportsMixin, BingAdsStream): - data_field: str = "" - service_name: str = "ReportingService" - report_name: str = "BudgetSummaryReport" - operation_name: str = "download_report" - additional_fields: str = "" - report_aggregation = None - cursor_field = "Date" - report_schema_name = "budget_summary_report" - primary_key = "Date" - - report_columns = [ - "AccountName", - "AccountNumber", - "AccountId", - "CampaignName", - "CampaignId", - "Date", - "MonthlyBudget", - "DailySpend", - "MonthToDateSpend", - ] - - -class CampaignPerformanceReport(PerformanceReportsMixin, BingAdsStream): - data_field: str = "" - service_name: str = "ReportingService" - report_name: str = "CampaignPerformanceReport" - operation_name: str = "download_report" - additional_fields: str = "" - cursor_field = "TimePeriod" - report_schema_name = "campaign_performance_report" - primary_key = [ - "AccountId", - "CampaignId", - "TimePeriod", - "CurrencyCode", - "AdDistribution", - "DeviceType", - "Network", - "DeliveredMatchType", - "DeviceOS", - "TopVsOther", - "BidMatchType", - ] - - report_columns = [ - *primary_key, - "AccountName", - "CampaignName", - "CampaignType", - "CampaignStatus", - "CampaignLabels", - "Impressions", - "Clicks", - "Ctr", - "Spend", - "CostPerConversion", - "QualityScore", - "AdRelevance", - "LandingPageExperience", - "PhoneImpressions", - "PhoneCalls", - "Ptr", - "Assists", - "ReturnOnAdSpend", - "CostPerAssist", - "CustomParameters", - "ViewThroughConversions", - "AllCostPerConversion", - "AllReturnOnAdSpend", - *ALL_CONVERSION_FIELDS, - *ALL_REVENUE_FIELDS, - *AVERAGE_FIELDS, - *CONVERSION_FIELDS, - *LOW_QUALITY_FIELDS, - *REVENUE_FIELDS, - *BUDGET_FIELDS, - ] - - -class CampaignPerformanceReportHourly(CampaignPerformanceReport): - report_aggregation = "Hourly" - - -class CampaignPerformanceReportDaily(CampaignPerformanceReport): - report_aggregation = "Daily" - report_columns = [ - *CampaignPerformanceReport.report_columns, - *HISTORICAL_FIELDS, - ] - - -class CampaignPerformanceReportWeekly(CampaignPerformanceReport): - report_aggregation = "Weekly" - report_columns = [ - *CampaignPerformanceReport.report_columns, - *HISTORICAL_FIELDS, - ] - - -class CampaignPerformanceReportMonthly(CampaignPerformanceReport): - report_aggregation = "Monthly" - report_columns = [ - *CampaignPerformanceReport.report_columns, - *HISTORICAL_FIELDS, - ] - - -class AdPerformanceReport(PerformanceReportsMixin, BingAdsStream): - data_field: str = "" - service_name: str = "ReportingService" - report_name: str = "AdPerformanceReport" - operation_name: str = "download_report" - additional_fields: str = "" - cursor_field = "TimePeriod" - report_schema_name = "ad_performance_report" - primary_key = [ - "AccountId", - "CampaignId", - "AdGroupId", - "AdId", - "TimePeriod", - "CurrencyCode", - "AdDistribution", - "DeviceType", - "Language", - "Network", - "DeviceOS", - "TopVsOther", - "BidMatchType", - "DeliveredMatchType", - ] - - report_columns = [ - *primary_key, - "AccountName", - "CampaignName", - "CampaignType", - "AdGroupName", - "Impressions", - "Clicks", - "Ctr", - "Spend", - "CostPerConversion", - "DestinationUrl", - "Assists", - "ReturnOnAdSpend", - "CostPerAssist", - "CustomParameters", - "FinalAppUrl", - "AdDescription", - "AdDescription2", - "ViewThroughConversions", - "ViewThroughConversionsQualified", - "AllCostPerConversion", - "AllReturnOnAdSpend", - *CONVERSION_FIELDS, - *AVERAGE_FIELDS, - *ALL_CONVERSION_FIELDS, - *ALL_REVENUE_FIELDS, - *REVENUE_FIELDS, - ] - - -class AdPerformanceReportHourly(AdPerformanceReport): - report_aggregation = "Hourly" - - -class AdPerformanceReportDaily(AdPerformanceReport): - report_aggregation = "Daily" - - -class AdPerformanceReportWeekly(AdPerformanceReport): - report_aggregation = "Weekly" - - -class AdPerformanceReportMonthly(AdPerformanceReport): - report_aggregation = "Monthly" - - -class AdGroupPerformanceReport(PerformanceReportsMixin, BingAdsStream): - data_field: str = "" - service_name: str = "ReportingService" - report_name: str = "AdGroupPerformanceReport" - operation_name: str = "download_report" - additional_fields: str = "" - cursor_field = "TimePeriod" - report_schema_name = "ad_group_performance_report" - - primary_key = [ - "AccountId", - "CampaignId", - "AdGroupId", - "TimePeriod", - "CurrencyCode", - "AdDistribution", - "DeviceType", - "Network", - "DeliveredMatchType", - "DeviceOS", - "TopVsOther", - "BidMatchType", - "Language", - ] - - report_columns = [ - *primary_key, - "AccountName", - "CampaignName", - "CampaignType", - "AdGroupName", - "AdGroupType", - "Impressions", - "Clicks", - "Ctr", - "Spend", - "CostPerConversion", - "QualityScore", - "ExpectedCtr", - "AdRelevance", - "LandingPageExperience", - "PhoneImpressions", - "PhoneCalls", - "Ptr", - "Assists", - "CostPerAssist", - "CustomParameters", - "FinalUrlSuffix", - "ViewThroughConversions", - "AllCostPerConversion", - "AllReturnOnAdSpend", - *ALL_CONVERSION_FIELDS, - *ALL_REVENUE_FIELDS, - *AVERAGE_FIELDS, - *CONVERSION_FIELDS, - *REVENUE_FIELDS, - ] - - -class AdGroupPerformanceReportHourly(AdGroupPerformanceReport): - report_aggregation = "Hourly" - - -class AdGroupPerformanceReportDaily(AdGroupPerformanceReport): - report_aggregation = "Daily" - report_columns = [ - *AdGroupPerformanceReport.report_columns, - *HISTORICAL_FIELDS, - ] - - -class AdGroupPerformanceReportWeekly(AdGroupPerformanceReport): - report_aggregation = "Weekly" - report_columns = [ - *AdGroupPerformanceReport.report_columns, - *HISTORICAL_FIELDS, - ] - - -class AdGroupPerformanceReportMonthly(AdGroupPerformanceReport): - report_aggregation = "Monthly" - report_columns = [ - *AdGroupPerformanceReport.report_columns, - *HISTORICAL_FIELDS, - ] - - -class KeywordPerformanceReport(PerformanceReportsMixin, BingAdsStream): - data_field: str = "" - service_name: str = "ReportingService" - report_name: str = "KeywordPerformanceReport" - operation_name: str = "download_report" - additional_fields: str = "" - cursor_field = "TimePeriod" - report_schema_name = "keyword_performance_report" - primary_key = [ - "AccountId", - "CampaignId", - "AdGroupId", - "KeywordId", - "AdId", - "TimePeriod", - "CurrencyCode", - "DeliveredMatchType", - "AdDistribution", - "DeviceType", - "Language", - "Network", - "DeviceOS", - "TopVsOther", - "BidMatchType", - ] - - report_columns = [ - *primary_key, - "AccountName", - "CampaignName", - "AdGroupName", - "Keyword", - "KeywordStatus", - "Impressions", - "Clicks", - "Ctr", - "CurrentMaxCpc", - "Spend", - "CostPerConversion", - "QualityScore", - "ExpectedCtr", - "AdRelevance", - "LandingPageExperience", - "QualityImpact", - "Assists", - "ReturnOnAdSpend", - "CostPerAssist", - "CustomParameters", - "FinalAppUrl", - "Mainline1Bid", - "MainlineBid", - "FirstPageBid", - "FinalUrlSuffix", - "ViewThroughConversions", - "ViewThroughConversionsQualified", - "AllCostPerConversion", - "AllReturnOnAdSpend", - *CONVERSION_FIELDS, - *AVERAGE_FIELDS, - *ALL_CONVERSION_FIELDS, - *ALL_REVENUE_FIELDS, - *REVENUE_FIELDS, - ] - - -class KeywordPerformanceReportHourly(KeywordPerformanceReport): - report_aggregation = "Hourly" - - -class KeywordPerformanceReportDaily(KeywordPerformanceReport): - report_aggregation = "Daily" - report_columns = [ - *KeywordPerformanceReport.report_columns, - *HISTORICAL_FIELDS, - ] - - -class KeywordPerformanceReportWeekly(KeywordPerformanceReport): - report_aggregation = "Weekly" - - -class KeywordPerformanceReportMonthly(KeywordPerformanceReport): - report_aggregation = "Monthly" - - -class GeographicPerformanceReport(PerformanceReportsMixin, BingAdsStream): - data_field: str = "" - service_name: str = "ReportingService" - report_name: str = "GeographicPerformanceReport" - operation_name: str = "download_report" - additional_fields: str = "" - cursor_field = "TimePeriod" - report_schema_name = "geographic_performance_report" - - # Need to override the primary key here because the one inherited from the PerformanceReportsMixin - # is incorrect for the geographic performance reports - primary_key = None - - report_columns = [ - "AccountId", - "CampaignId", - "AdGroupId", - "TimePeriod", - "Country", - "CurrencyCode", - "DeliveredMatchType", - "AdDistribution", - "DeviceType", - "Language", - "Network", - "DeviceOS", - "TopVsOther", - "BidMatchType", - "MetroArea", - "State", - "City", - "AdGroupName", - "Ctr", - "ProximityTargetLocation", - "Radius", - "Assists", - "ReturnOnAdSpend", - "CostPerAssist", - "LocationType", - "MostSpecificLocation", - "AccountStatus", - "CampaignStatus", - "AdGroupStatus", - "County", - "PostalCode", - "LocationId", - "BaseCampaignId", - "AllCostPerConversion", - "AllReturnOnAdSpend", - "ViewThroughConversions", - "Goal", - "GoalType", - "AbsoluteTopImpressionRatePercent", - "TopImpressionRatePercent", - "AllConversionsQualified", - "ViewThroughConversionsQualified", - "Neighborhood", - "ViewThroughRevenue", - "CampaignType", - "AssetGroupId", - "AssetGroupName", - "AssetGroupStatus", - "Clicks", - "Spend", - "Impressions", - "CostPerConversion", - "AccountName", - "AccountNumber", - "CampaignName", - *CONVERSION_FIELDS, - *AVERAGE_FIELDS, - *ALL_CONVERSION_FIELDS, - *ALL_REVENUE_FIELDS, - *REVENUE_FIELDS, - ] - - -class GeographicPerformanceReportHourly(GeographicPerformanceReport): - report_aggregation = "Hourly" - - -class GeographicPerformanceReportDaily(GeographicPerformanceReport): - report_aggregation = "Daily" - - -class GeographicPerformanceReportWeekly(GeographicPerformanceReport): - report_aggregation = "Weekly" - - -class GeographicPerformanceReportMonthly(GeographicPerformanceReport): - report_aggregation = "Monthly" - - -class AccountPerformanceReport(PerformanceReportsMixin, BingAdsStream): - data_field: str = "" - service_name: str = "ReportingService" - report_name: str = "AccountPerformanceReport" - operation_name: str = "download_report" - additional_fields: str = "" - cursor_field = "TimePeriod" - report_schema_name = "account_performance_report" - primary_key = [ - "AccountId", - "TimePeriod", - "CurrencyCode", - "AdDistribution", - "DeviceType", - "Network", - "DeliveredMatchType", - "DeviceOS", - "TopVsOther", - "BidMatchType", - ] - - report_columns = [ - *primary_key, - "AccountName", - "AccountNumber", - "PhoneImpressions", - "PhoneCalls", - "Clicks", - "Ctr", - "Spend", - "Impressions", - "CostPerConversion", - "Ptr", - "Assists", - "ReturnOnAdSpend", - "CostPerAssist", - *AVERAGE_FIELDS, - *CONVERSION_FIELDS, - *LOW_QUALITY_FIELDS, - *REVENUE_FIELDS, - ] - - -class AccountPerformanceReportHourly(AccountPerformanceReport): - report_aggregation = "Hourly" - - -class AccountPerformanceReportDaily(AccountPerformanceReport): - report_aggregation = "Daily" - - -class AccountPerformanceReportWeekly(AccountPerformanceReport): - report_aggregation = "Weekly" - - -class AccountPerformanceReportMonthly(AccountPerformanceReport): - report_aggregation = "Monthly" +from source_bing_ads.streams import Accounts, AdGroups, Ads, BudgetSummaryReport, Campaigns class SourceBingAds(AbstractSource): diff --git a/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/streams.py b/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/streams.py new file mode 100644 index 000000000000..12247c72451a --- /dev/null +++ b/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/streams.py @@ -0,0 +1,831 @@ +# +# Copyright (c) 2023 Airbyte, Inc., all rights reserved. +# + + +import ssl +import time +from abc import ABC, abstractmethod +from typing import Any, Iterable, List, Mapping, MutableMapping, Optional, Union +from urllib.error import URLError + +from airbyte_cdk.models import SyncMode +from airbyte_cdk.sources.streams import Stream +from bingads.service_client import ServiceClient +from bingads.v13.reporting.reporting_service_manager import ReportingServiceManager +from source_bing_ads.client import Client +from source_bing_ads.reports import ( + ALL_CONVERSION_FIELDS, + ALL_REVENUE_FIELDS, + AVERAGE_FIELDS, + BUDGET_FIELDS, + CONVERSION_FIELDS, + HISTORICAL_FIELDS, + LOW_QUALITY_FIELDS, + REVENUE_FIELDS, + PerformanceReportsMixin, + ReportsMixin, +) +from suds import sudsobject + + +class BingAdsStream(Stream, ABC): + primary_key: Optional[Union[str, List[str], List[List[str]]]] = None + + def __init__(self, client: Client, config: Mapping[str, Any]) -> None: + super().__init__() + self.client = client + self.config = config + + @property + @abstractmethod + def data_field(self) -> str: + """ + Specifies root object name in a stream response + """ + pass + + @property + @abstractmethod + def service_name(self) -> str: + """ + Specifies bing ads service name for a current stream + """ + pass + + @property + @abstractmethod + def operation_name(self) -> str: + """ + Specifies operation name to use for a current stream + """ + pass + + @property + @abstractmethod + def additional_fields(self) -> Optional[str]: + """ + Specifies which additional fields to fetch for a current stream. + Expected format: field names separated by space + """ + pass + + @property + def _service(self) -> Union[ServiceClient, ReportingServiceManager]: + return self.client.get_service(service_name=self.service_name) + + @property + def _user_id(self) -> int: + return self._get_user_id() + + # TODO remove once Microsoft support confirm their SSL certificates are always valid... + def _get_user_id(self, number_of_retries=10): + """""" + try: + return self._service.GetUser().User.Id + except URLError as error: + if isinstance(error.reason, ssl.SSLError): + self.logger.warn("SSL certificate error, retrying...") + if number_of_retries > 0: + time.sleep(1) + return self._get_user_id(number_of_retries - 1) + else: + raise error + + def next_page_token(self, response: sudsobject.Object, **kwargs: Mapping[str, Any]) -> Optional[Mapping[str, Any]]: + """ + Default method for streams that don't support pagination + """ + return None + + def parse_response(self, response: sudsobject.Object, **kwargs) -> Iterable[Mapping]: + if response is not None and hasattr(response, self.data_field): + yield from self.client.asdict(response)[self.data_field] + + yield from [] + + def send_request(self, params: Mapping[str, Any], customer_id: str, account_id: str = None) -> Mapping[str, Any]: + request_kwargs = { + "service_name": self.service_name, + "customer_id": customer_id, + "account_id": account_id, + "operation_name": self.operation_name, + "params": params, + } + request = self.client.request(**request_kwargs) + return request + + def read_records( + self, + sync_mode: SyncMode, + stream_slice: Mapping[str, Any] = None, + stream_state: Mapping[str, Any] = None, + **kwargs: Mapping[str, Any], + ) -> Iterable[Mapping[str, Any]]: + stream_state = stream_state or {} + next_page_token = None + account_id = str(stream_slice.get("account_id")) if stream_slice else None + customer_id = str(stream_slice.get("customer_id")) if stream_slice else None + + while True: + params = self.request_params( + stream_state=stream_state, + stream_slice=stream_slice, + next_page_token=next_page_token, + account_id=account_id, + ) + response = self.send_request(params, customer_id=customer_id, account_id=account_id) + for record in self.parse_response(response): + yield record + + next_page_token = self.next_page_token(response, current_page_token=next_page_token) + if not next_page_token: + break + + yield from [] + + +class Accounts(BingAdsStream): + """ + Searches for accounts that the current authenticated user can access. + API doc: https://docs.microsoft.com/en-us/advertising/customer-management-service/searchaccounts?view=bingads-13 + Account schema: https://docs.microsoft.com/en-us/advertising/customer-management-service/advertiseraccount?view=bingads-13 + Stream caches incoming responses to be able to reuse this data in Campaigns stream + """ + + primary_key = "Id" + # Stream caches incoming responses to avoid duplicated http requests + use_cache: bool = True + data_field: str = "AdvertiserAccount" + service_name: str = "CustomerManagementService" + operation_name: str = "SearchAccounts" + additional_fields: str = "TaxCertificate AccountMode" + # maximum page size + page_size_limit: int = 1000 + + def next_page_token(self, response: sudsobject.Object, current_page_token: Optional[int]) -> Optional[Mapping[str, Any]]: + current_page_token = current_page_token or 0 + if response is not None and hasattr(response, self.data_field): + return None if self.page_size_limit > len(response[self.data_field]) else current_page_token + 1 + else: + return None + + def request_params( + self, + next_page_token: Mapping[str, Any] = None, + **kwargs: Mapping[str, Any], + ) -> MutableMapping[str, Any]: + predicates = { + "Predicate": [ + { + "Field": "UserId", + "Operator": "Equals", + "Value": self._user_id, + } + ] + } + + paging = self._service.factory.create("ns5:Paging") + paging.Index = next_page_token or 0 + paging.Size = self.page_size_limit + return { + "PageInfo": paging, + "Predicates": predicates, + "ReturnAdditionalFields": self.additional_fields, + } + + +class Campaigns(BingAdsStream): + """ + Gets the campaigns for all provided accounts. + API doc: https://docs.microsoft.com/en-us/advertising/campaign-management-service/getcampaignsbyaccountid?view=bingads-13 + Campaign schema: https://docs.microsoft.com/en-us/advertising/campaign-management-service/campaign?view=bingads-13 + Stream caches incoming responses to be able to reuse this data in AdGroups stream + """ + + primary_key = "Id" + # Stream caches incoming responses to avoid duplicated http requests + use_cache: bool = True + data_field: str = "Campaign" + service_name: str = "CampaignManagement" + operation_name: str = "GetCampaignsByAccountId" + additional_fields: Iterable[str] = [ + "AdScheduleUseSearcherTimeZone", + "BidStrategyId", + "CpvCpmBiddingScheme", + "DynamicDescriptionSetting", + "DynamicFeedSetting", + "MaxConversionValueBiddingScheme", + "MultimediaAdsBidAdjustment", + "TargetImpressionShareBiddingScheme", + "TargetSetting", + "VerifiedTrackingSetting", + ] + campaign_types: Iterable[str] = ["Audience", "DynamicSearchAds", "Search", "Shopping"] + + def request_params( + self, + stream_slice: Mapping[str, Any] = None, + **kwargs: Mapping[str, Any], + ) -> MutableMapping[str, Any]: + return { + "AccountId": stream_slice["account_id"], + "CampaignType": " ".join(self.campaign_types), + "ReturnAdditionalFields": " ".join(self.additional_fields), + } + + def stream_slices( + self, + **kwargs: Mapping[str, Any], + ) -> Iterable[Optional[Mapping[str, Any]]]: + for account in Accounts(self.client, self.config).read_records(SyncMode.full_refresh): + yield {"account_id": account["Id"], "customer_id": account["ParentCustomerId"]} + + yield from [] + + +class AdGroups(BingAdsStream): + """ + Gets the ad groups for all provided accounts. + API doc: https://docs.microsoft.com/en-us/advertising/campaign-management-service/getadgroupsbycampaignid?view=bingads-13 + AdGroup schema: https://docs.microsoft.com/en-us/advertising/campaign-management-service/adgroup?view=bingads-13 + Stream caches incoming responses to be able to reuse this data in Ads stream + """ + + primary_key = "Id" + # Stream caches incoming responses to avoid duplicated http requests + use_cache: bool = True + data_field: str = "AdGroup" + service_name: str = "CampaignManagement" + operation_name: str = "GetAdGroupsByCampaignId" + additional_fields: str = "AdGroupType AdScheduleUseSearcherTimeZone CpmBid CpvBid MultimediaAdsBidAdjustment" + + def request_params( + self, + stream_slice: Mapping[str, Any] = None, + **kwargs: Mapping[str, Any], + ) -> MutableMapping[str, Any]: + return {"CampaignId": stream_slice["campaign_id"], "ReturnAdditionalFields": self.additional_fields} + + def stream_slices( + self, + **kwargs: Mapping[str, Any], + ) -> Iterable[Optional[Mapping[str, Any]]]: + campaigns = Campaigns(self.client, self.config) + for account in Accounts(self.client, self.config).read_records(SyncMode.full_refresh): + for campaign in campaigns.read_records( + sync_mode=SyncMode.full_refresh, stream_slice={"account_id": account["Id"], "customer_id": account["ParentCustomerId"]} + ): + yield {"campaign_id": campaign["Id"], "account_id": account["Id"], "customer_id": account["ParentCustomerId"]} + + yield from [] + + +class Ads(BingAdsStream): + """ + Retrieves the ads for all provided accounts. + API doc: https://docs.microsoft.com/en-us/advertising/campaign-management-service/getadsbyadgroupid?view=bingads-13 + Ad schema: https://docs.microsoft.com/en-us/advertising/campaign-management-service/ad?view=bingads-13 + """ + + primary_key = "Id" + data_field: str = "Ad" + service_name: str = "CampaignManagement" + operation_name: str = "GetAdsByAdGroupId" + additional_fields: str = "ImpressionTrackingUrls Videos LongHeadlines" + ad_types: Iterable[str] = [ + "Text", + "Image", + "Product", + "AppInstall", + "ExpandedText", + "DynamicSearch", + "ResponsiveAd", + "ResponsiveSearch", + ] + + def request_params( + self, + stream_slice: Mapping[str, Any] = None, + **kwargs: Mapping[str, Any], + ) -> MutableMapping[str, Any]: + return { + "AdGroupId": stream_slice["ad_group_id"], + "AdTypes": {"AdType": self.ad_types}, + "ReturnAdditionalFields": self.additional_fields, + } + + def stream_slices( + self, + **kwargs: Mapping[str, Any], + ) -> Iterable[Optional[Mapping[str, Any]]]: + ad_groups = AdGroups(self.client, self.config) + for slice in ad_groups.stream_slices(sync_mode=SyncMode.full_refresh): + for ad_group in ad_groups.read_records(sync_mode=SyncMode.full_refresh, stream_slice=slice): + yield {"ad_group_id": ad_group["Id"], "account_id": slice["account_id"], "customer_id": slice["customer_id"]} + yield from [] + + +class BudgetSummaryReport(ReportsMixin, BingAdsStream): + data_field: str = "" + service_name: str = "ReportingService" + report_name: str = "BudgetSummaryReport" + operation_name: str = "download_report" + additional_fields: str = "" + report_aggregation = None + cursor_field = "Date" + report_schema_name = "budget_summary_report" + primary_key = "Date" + + report_columns = [ + "AccountName", + "AccountNumber", + "AccountId", + "CampaignName", + "CampaignId", + "Date", + "MonthlyBudget", + "DailySpend", + "MonthToDateSpend", + ] + + +class CampaignPerformanceReport(PerformanceReportsMixin, BingAdsStream): + data_field: str = "" + service_name: str = "ReportingService" + report_name: str = "CampaignPerformanceReport" + operation_name: str = "download_report" + additional_fields: str = "" + cursor_field = "TimePeriod" + report_schema_name = "campaign_performance_report" + primary_key = [ + "AccountId", + "CampaignId", + "TimePeriod", + "CurrencyCode", + "AdDistribution", + "DeviceType", + "Network", + "DeliveredMatchType", + "DeviceOS", + "TopVsOther", + "BidMatchType", + ] + + report_columns = [ + *primary_key, + "AccountName", + "CampaignName", + "CampaignType", + "CampaignStatus", + "CampaignLabels", + "Impressions", + "Clicks", + "Ctr", + "Spend", + "CostPerConversion", + "QualityScore", + "AdRelevance", + "LandingPageExperience", + "PhoneImpressions", + "PhoneCalls", + "Ptr", + "Assists", + "ReturnOnAdSpend", + "CostPerAssist", + "CustomParameters", + "ViewThroughConversions", + "AllCostPerConversion", + "AllReturnOnAdSpend", + *ALL_CONVERSION_FIELDS, + *ALL_REVENUE_FIELDS, + *AVERAGE_FIELDS, + *CONVERSION_FIELDS, + *LOW_QUALITY_FIELDS, + *REVENUE_FIELDS, + *BUDGET_FIELDS, + ] + + +class CampaignPerformanceReportHourly(CampaignPerformanceReport): + report_aggregation = "Hourly" + + +class CampaignPerformanceReportDaily(CampaignPerformanceReport): + report_aggregation = "Daily" + report_columns = [ + *CampaignPerformanceReport.report_columns, + *HISTORICAL_FIELDS, + ] + + +class CampaignPerformanceReportWeekly(CampaignPerformanceReport): + report_aggregation = "Weekly" + report_columns = [ + *CampaignPerformanceReport.report_columns, + *HISTORICAL_FIELDS, + ] + + +class CampaignPerformanceReportMonthly(CampaignPerformanceReport): + report_aggregation = "Monthly" + report_columns = [ + *CampaignPerformanceReport.report_columns, + *HISTORICAL_FIELDS, + ] + + +class AdPerformanceReport(PerformanceReportsMixin, BingAdsStream): + data_field: str = "" + service_name: str = "ReportingService" + report_name: str = "AdPerformanceReport" + operation_name: str = "download_report" + additional_fields: str = "" + cursor_field = "TimePeriod" + report_schema_name = "ad_performance_report" + primary_key = [ + "AccountId", + "CampaignId", + "AdGroupId", + "AdId", + "TimePeriod", + "CurrencyCode", + "AdDistribution", + "DeviceType", + "Language", + "Network", + "DeviceOS", + "TopVsOther", + "BidMatchType", + "DeliveredMatchType", + ] + + report_columns = [ + *primary_key, + "AccountName", + "CampaignName", + "CampaignType", + "AdGroupName", + "Impressions", + "Clicks", + "Ctr", + "Spend", + "CostPerConversion", + "DestinationUrl", + "Assists", + "ReturnOnAdSpend", + "CostPerAssist", + "CustomParameters", + "FinalAppUrl", + "AdDescription", + "AdDescription2", + "ViewThroughConversions", + "ViewThroughConversionsQualified", + "AllCostPerConversion", + "AllReturnOnAdSpend", + *CONVERSION_FIELDS, + *AVERAGE_FIELDS, + *ALL_CONVERSION_FIELDS, + *ALL_REVENUE_FIELDS, + *REVENUE_FIELDS, + ] + + +class AdPerformanceReportHourly(AdPerformanceReport): + report_aggregation = "Hourly" + + +class AdPerformanceReportDaily(AdPerformanceReport): + report_aggregation = "Daily" + + +class AdPerformanceReportWeekly(AdPerformanceReport): + report_aggregation = "Weekly" + + +class AdPerformanceReportMonthly(AdPerformanceReport): + report_aggregation = "Monthly" + + +class AdGroupPerformanceReport(PerformanceReportsMixin, BingAdsStream): + data_field: str = "" + service_name: str = "ReportingService" + report_name: str = "AdGroupPerformanceReport" + operation_name: str = "download_report" + additional_fields: str = "" + cursor_field = "TimePeriod" + report_schema_name = "ad_group_performance_report" + + primary_key = [ + "AccountId", + "CampaignId", + "AdGroupId", + "TimePeriod", + "CurrencyCode", + "AdDistribution", + "DeviceType", + "Network", + "DeliveredMatchType", + "DeviceOS", + "TopVsOther", + "BidMatchType", + "Language", + ] + + report_columns = [ + *primary_key, + "AccountName", + "CampaignName", + "CampaignType", + "AdGroupName", + "AdGroupType", + "Impressions", + "Clicks", + "Ctr", + "Spend", + "CostPerConversion", + "QualityScore", + "ExpectedCtr", + "AdRelevance", + "LandingPageExperience", + "PhoneImpressions", + "PhoneCalls", + "Ptr", + "Assists", + "CostPerAssist", + "CustomParameters", + "FinalUrlSuffix", + "ViewThroughConversions", + "AllCostPerConversion", + "AllReturnOnAdSpend", + *ALL_CONVERSION_FIELDS, + *ALL_REVENUE_FIELDS, + *AVERAGE_FIELDS, + *CONVERSION_FIELDS, + *REVENUE_FIELDS, + ] + + +class AdGroupPerformanceReportHourly(AdGroupPerformanceReport): + report_aggregation = "Hourly" + + +class AdGroupPerformanceReportDaily(AdGroupPerformanceReport): + report_aggregation = "Daily" + report_columns = [ + *AdGroupPerformanceReport.report_columns, + *HISTORICAL_FIELDS, + ] + + +class AdGroupPerformanceReportWeekly(AdGroupPerformanceReport): + report_aggregation = "Weekly" + report_columns = [ + *AdGroupPerformanceReport.report_columns, + *HISTORICAL_FIELDS, + ] + + +class AdGroupPerformanceReportMonthly(AdGroupPerformanceReport): + report_aggregation = "Monthly" + report_columns = [ + *AdGroupPerformanceReport.report_columns, + *HISTORICAL_FIELDS, + ] + + +class KeywordPerformanceReport(PerformanceReportsMixin, BingAdsStream): + data_field: str = "" + service_name: str = "ReportingService" + report_name: str = "KeywordPerformanceReport" + operation_name: str = "download_report" + additional_fields: str = "" + cursor_field = "TimePeriod" + report_schema_name = "keyword_performance_report" + primary_key = [ + "AccountId", + "CampaignId", + "AdGroupId", + "KeywordId", + "AdId", + "TimePeriod", + "CurrencyCode", + "DeliveredMatchType", + "AdDistribution", + "DeviceType", + "Language", + "Network", + "DeviceOS", + "TopVsOther", + "BidMatchType", + ] + + report_columns = [ + *primary_key, + "AccountName", + "CampaignName", + "AdGroupName", + "Keyword", + "KeywordStatus", + "Impressions", + "Clicks", + "Ctr", + "CurrentMaxCpc", + "Spend", + "CostPerConversion", + "QualityScore", + "ExpectedCtr", + "AdRelevance", + "LandingPageExperience", + "QualityImpact", + "Assists", + "ReturnOnAdSpend", + "CostPerAssist", + "CustomParameters", + "FinalAppUrl", + "Mainline1Bid", + "MainlineBid", + "FirstPageBid", + "FinalUrlSuffix", + "ViewThroughConversions", + "ViewThroughConversionsQualified", + "AllCostPerConversion", + "AllReturnOnAdSpend", + *CONVERSION_FIELDS, + *AVERAGE_FIELDS, + *ALL_CONVERSION_FIELDS, + *ALL_REVENUE_FIELDS, + *REVENUE_FIELDS, + ] + + +class KeywordPerformanceReportHourly(KeywordPerformanceReport): + report_aggregation = "Hourly" + + +class KeywordPerformanceReportDaily(KeywordPerformanceReport): + report_aggregation = "Daily" + report_columns = [ + *KeywordPerformanceReport.report_columns, + *HISTORICAL_FIELDS, + ] + + +class KeywordPerformanceReportWeekly(KeywordPerformanceReport): + report_aggregation = "Weekly" + + +class KeywordPerformanceReportMonthly(KeywordPerformanceReport): + report_aggregation = "Monthly" + + +class GeographicPerformanceReport(PerformanceReportsMixin, BingAdsStream): + data_field: str = "" + service_name: str = "ReportingService" + report_name: str = "GeographicPerformanceReport" + operation_name: str = "download_report" + additional_fields: str = "" + cursor_field = "TimePeriod" + report_schema_name = "geographic_performance_report" + + # Need to override the primary key here because the one inherited from the PerformanceReportsMixin + # is incorrect for the geographic performance reports + primary_key = None + + report_columns = [ + "AccountId", + "CampaignId", + "AdGroupId", + "TimePeriod", + "Country", + "CurrencyCode", + "DeliveredMatchType", + "AdDistribution", + "DeviceType", + "Language", + "Network", + "DeviceOS", + "TopVsOther", + "BidMatchType", + "MetroArea", + "State", + "City", + "AdGroupName", + "Ctr", + "ProximityTargetLocation", + "Radius", + "Assists", + "ReturnOnAdSpend", + "CostPerAssist", + "LocationType", + "MostSpecificLocation", + "AccountStatus", + "CampaignStatus", + "AdGroupStatus", + "County", + "PostalCode", + "LocationId", + "BaseCampaignId", + "AllCostPerConversion", + "AllReturnOnAdSpend", + "ViewThroughConversions", + "Goal", + "GoalType", + "AbsoluteTopImpressionRatePercent", + "TopImpressionRatePercent", + "AllConversionsQualified", + "ViewThroughConversionsQualified", + "Neighborhood", + "ViewThroughRevenue", + "CampaignType", + "AssetGroupId", + "AssetGroupName", + "AssetGroupStatus", + "Clicks", + "Spend", + "Impressions", + "CostPerConversion", + "AccountName", + "AccountNumber", + "CampaignName", + *CONVERSION_FIELDS, + *AVERAGE_FIELDS, + *ALL_CONVERSION_FIELDS, + *ALL_REVENUE_FIELDS, + *REVENUE_FIELDS, + ] + + +class GeographicPerformanceReportHourly(GeographicPerformanceReport): + report_aggregation = "Hourly" + + +class GeographicPerformanceReportDaily(GeographicPerformanceReport): + report_aggregation = "Daily" + + +class GeographicPerformanceReportWeekly(GeographicPerformanceReport): + report_aggregation = "Weekly" + + +class GeographicPerformanceReportMonthly(GeographicPerformanceReport): + report_aggregation = "Monthly" + + +class AccountPerformanceReport(PerformanceReportsMixin, BingAdsStream): + data_field: str = "" + service_name: str = "ReportingService" + report_name: str = "AccountPerformanceReport" + operation_name: str = "download_report" + additional_fields: str = "" + cursor_field = "TimePeriod" + report_schema_name = "account_performance_report" + primary_key = [ + "AccountId", + "TimePeriod", + "CurrencyCode", + "AdDistribution", + "DeviceType", + "Network", + "DeliveredMatchType", + "DeviceOS", + "TopVsOther", + "BidMatchType", + ] + + report_columns = [ + *primary_key, + "AccountName", + "AccountNumber", + "PhoneImpressions", + "PhoneCalls", + "Clicks", + "Ctr", + "Spend", + "Impressions", + "CostPerConversion", + "Ptr", + "Assists", + "ReturnOnAdSpend", + "CostPerAssist", + *AVERAGE_FIELDS, + *CONVERSION_FIELDS, + *LOW_QUALITY_FIELDS, + *REVENUE_FIELDS, + ] + + +class AccountPerformanceReportHourly(AccountPerformanceReport): + report_aggregation = "Hourly" + + +class AccountPerformanceReportDaily(AccountPerformanceReport): + report_aggregation = "Daily" + + +class AccountPerformanceReportWeekly(AccountPerformanceReport): + report_aggregation = "Weekly" + + +class AccountPerformanceReportMonthly(AccountPerformanceReport): + report_aggregation = "Monthly" From c08a6796a303fe26383de7ea4da4474de9e25ece Mon Sep 17 00:00:00 2001 From: Artem Inzhyyants Date: Tue, 24 Oct 2023 11:43:40 +0200 Subject: [PATCH 03/14] Source Bing Ads: add new stream AgeGenderAudienceReport --- .../source_bing_ads/reports.py | 2 +- .../schemas/age_gender_audience_report.json | 108 ++++++++++++++++++ .../source-bing-ads/source_bing_ads/source.py | 68 +++++++---- .../source_bing_ads/streams.py | 68 ++++++++++- docs/integrations/sources/bing-ads.md | 7 +- 5 files changed, 230 insertions(+), 23 deletions(-) create mode 100644 airbyte-integrations/connectors/source-bing-ads/source_bing_ads/schemas/age_gender_audience_report.json diff --git a/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/reports.py b/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/reports.py index b3cd1c5bf47d..0b33fc4e64f4 100644 --- a/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/reports.py +++ b/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/reports.py @@ -348,7 +348,7 @@ def get_start_date(self, stream_state: Mapping[str, Any] = None, account_id: str if self.config.get("lookback_window"): # Datetime subtract won't work with days = 0 - # it'll output an AirbuteError + # it'll output an AirbyteError return start_date.subtract(days=self.config["lookback_window"]) else: return start_date diff --git a/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/schemas/age_gender_audience_report.json b/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/schemas/age_gender_audience_report.json new file mode 100644 index 000000000000..a01c1d27e384 --- /dev/null +++ b/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/schemas/age_gender_audience_report.json @@ -0,0 +1,108 @@ +{ + "$schema": "https://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "AccountId": { + "type": ["null", "integer"] + }, + "AgeGroup": { + "type": ["null", "string"] + }, + "Gender": { + "type": ["null", "string"] + }, + "TimePeriod": { + "type": ["null", "string"] + }, + "AllConversions": { + "type": ["null", "integer"] + }, + "AccountName": { + "type": ["null", "string"] + }, + "AccountNumber": { + "type": ["null", "string"] + }, + "CampaignName": { + "type": ["null", "string"] + }, + "CampaignId": { + "type": ["null", "integer"] + }, + "AdGroupName": { + "type": ["null", "string"] + }, + "AdGroupId": { + "type": ["null", "integer"] + }, + "AdDistribution": { + "type": ["null", "string"] + }, + "Impressions": { + "type": ["null", "integer"] + }, + "Clicks": { + "type": ["null", "integer"] + }, + "Conversions": { + "type": ["null", "number"] + }, + "Spend": { + "type": ["null", "number"] + }, + "Revenue": { + "type": ["null", "number"] + }, + "ExtendedCost": { + "type": ["null", "string"] + }, + "Assists": { + "type": ["null", "integer"] + }, + "Language": { + "type": ["null", "string"] + }, + "AccountStatus": { + "type": ["null", "string"] + }, + "CampaignStatus": { + "type": ["null", "string"] + }, + "AdGroupStatus": { + "type": ["null", "string"] + }, + "BaseCampaignId": { + "type": ["null", "string"] + }, + "AllRevenue": { + "type": ["null", "number"] + }, + "ViewThroughConversions": { + "type": ["null", "integer"] + }, + "Goal": { + "type": ["null", "string"] + }, + "GoalType": { + "type": ["null", "string"] + }, + "AbsoluteTopImpressionRatePercent": { + "type": ["null", "number"] + }, + "TopImpressionRatePercent": { + "type": ["null", "string"] + }, + "ConversionsQualified": { + "type": ["null", "number"] + }, + "AllConversionsQualified": { + "type": ["null", "string"] + }, + "ViewThroughConversionsQualified": { + "type": ["null", "number"] + }, + "ViewThroughRevenue": { + "type": ["null", "string"] + } + } +} diff --git a/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/source.py b/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/source.py index 42012caf12f6..10c0ed8fc856 100644 --- a/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/source.py +++ b/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/source.py @@ -1,8 +1,7 @@ # # Copyright (c) 2023 Airbyte, Inc., all rights reserved. # - - +from itertools import product from typing import Any, List, Mapping, Tuple from airbyte_cdk import AirbyteLogger @@ -10,7 +9,41 @@ from airbyte_cdk.sources import AbstractSource from airbyte_cdk.sources.streams import Stream from source_bing_ads.client import Client -from source_bing_ads.streams import Accounts, AdGroups, Ads, BudgetSummaryReport, Campaigns +from source_bing_ads.streams import ( + AccountPerformanceReportDaily, + AccountPerformanceReportHourly, + AccountPerformanceReportMonthly, + AccountPerformanceReportWeekly, + Accounts, + AdGroupPerformanceReportDaily, + AdGroupPerformanceReportHourly, + AdGroupPerformanceReportMonthly, + AdGroupPerformanceReportWeekly, + AdGroups, + AdPerformanceReportDaily, + AdPerformanceReportHourly, + AdPerformanceReportMonthly, + AdPerformanceReportWeekly, + Ads, + AgeGenderAudienceReportDaily, + AgeGenderAudienceReportHourly, + AgeGenderAudienceReportMonthly, + AgeGenderAudienceReportWeekly, + BudgetSummaryReport, + CampaignPerformanceReportDaily, + CampaignPerformanceReportHourly, + CampaignPerformanceReportMonthly, + CampaignPerformanceReportWeekly, + Campaigns, + GeographicPerformanceReportDaily, + GeographicPerformanceReportHourly, + GeographicPerformanceReportMonthly, + GeographicPerformanceReportWeekly, + KeywordPerformanceReportDaily, + KeywordPerformanceReportHourly, + KeywordPerformanceReportMonthly, + KeywordPerformanceReportWeekly, +) class SourceBingAds(AbstractSource): @@ -29,16 +62,6 @@ def check_connection(self, logger: AirbyteLogger, config: Mapping[str, Any]) -> except Exception as error: return False, error - def get_report_streams(self, aggregation_type: str) -> List[Stream]: - return [ - globals()[f"AccountPerformanceReport{aggregation_type}"], - globals()[f"KeywordPerformanceReport{aggregation_type}"], - globals()[f"AdGroupPerformanceReport{aggregation_type}"], - globals()[f"AdPerformanceReport{aggregation_type}"], - globals()[f"CampaignPerformanceReport{aggregation_type}"], - globals()[f"GeographicPerformanceReport{aggregation_type}"], - ] - def streams(self, config: Mapping[str, Any]) -> List[Stream]: client = Client(**config) streams = [ @@ -46,13 +69,18 @@ def streams(self, config: Mapping[str, Any]) -> List[Stream]: AdGroups(client, config), Ads(client, config), Campaigns(client, config), + BudgetSummaryReport(client, config), ] - streams.append(BudgetSummaryReport(client, config)) - - streams.extend([c(client, config) for c in self.get_report_streams("Hourly")]) - streams.extend([c(client, config) for c in self.get_report_streams("Daily")]) - streams.extend([c(client, config) for c in self.get_report_streams("Weekly")]) - streams.extend([c(client, config) for c in self.get_report_streams("Monthly")]) - + reports = ( + "AgeGenderAudienceReport", + "AccountPerformanceReport", + "KeywordPerformanceReport", + "AdGroupPerformanceReport", + "AdPerformanceReport", + "CampaignPerformanceReport", + "GeographicPerformanceReport", + ) + report_aggregation = ("Hourly", "Daily", "Weekly", "Monthly") + streams.extend([eval(f"{report}{aggregation}")(client, config) for (report, aggregation) in product(reports, report_aggregation)]) return streams diff --git a/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/streams.py b/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/streams.py index 12247c72451a..45d190909419 100644 --- a/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/streams.py +++ b/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/streams.py @@ -507,7 +507,7 @@ class AdPerformanceReportMonthly(AdPerformanceReport): report_aggregation = "Monthly" -class AdGroupPerformanceReport(PerformanceReportsMixin, BingAdsStream): +class AdGroupPerformanceReport(PerformanceReportsMixin, BingAdsStream, ABC): data_field: str = "" service_name: str = "ReportingService" report_name: str = "AdGroupPerformanceReport" @@ -829,3 +829,69 @@ class AccountPerformanceReportWeekly(AccountPerformanceReport): class AccountPerformanceReportMonthly(AccountPerformanceReport): report_aggregation = "Monthly" + + +class AgeGenderAudienceReport(PerformanceReportsMixin, BingAdsStream, ABC): + data_field: str = "" + service_name: str = "ReportingService" + report_name: str = "AgeGenderAudienceReport" + operation_name: str = "download_report" + additional_fields: str = "" + cursor_field = "TimePeriod" + report_schema_name = "age_gender_audience_report" + primary_key = [ + "AgeGroup", + "Gender", + "TimePeriod", + "AccountId", + ] + + report_columns = [ + *primary_key, + "AllConversions", + "AccountName", + "AccountNumber", + "CampaignName", + "CampaignId", + "AdGroupName", + "AdGroupId", + "AdDistribution", + "Impressions", + "Clicks", + "Conversions", + "Spend", + "Revenue", + "ExtendedCost", + "Assists", + "Language", + "AccountStatus", + "CampaignStatus", + "AdGroupStatus", + "BaseCampaignId", + "AllRevenue", + "ViewThroughConversions", + "Goal", + "GoalType", + "AbsoluteTopImpressionRatePercent", + "TopImpressionRatePercent", + "ConversionsQualified", + "AllConversionsQualified", + "ViewThroughConversionsQualified", + "ViewThroughRevenue", + ] + + +class AgeGenderAudienceReportHourly(AgeGenderAudienceReport): + report_aggregation = "Hourly" + + +class AgeGenderAudienceReportDaily(AgeGenderAudienceReport): + report_aggregation = "Daily" + + +class AgeGenderAudienceReportWeekly(AgeGenderAudienceReport): + report_aggregation = "Weekly" + + +class AgeGenderAudienceReportMonthly(AgeGenderAudienceReport): + report_aggregation = "Monthly" diff --git a/docs/integrations/sources/bing-ads.md b/docs/integrations/sources/bing-ads.md index 22f510cd8155..eb27f73c25e2 100644 --- a/docs/integrations/sources/bing-ads.md +++ b/docs/integrations/sources/bing-ads.md @@ -93,6 +93,10 @@ The Bing Ads source connector supports the following streams. For more informati - [ad_performance_report_daily](https://docs.microsoft.com/en-us/advertising/reporting-service/adperformancereportrequest?view=bingads-13) - [ad_performance_report_weekly](https://docs.microsoft.com/en-us/advertising/reporting-service/adperformancereportrequest?view=bingads-13) - [ad_performance_report_monthly](https://docs.microsoft.com/en-us/advertising/reporting-service/adperformancereportrequest?view=bingads-13) +- [age_gender_audience_report_hourly](https://learn.microsoft.com/en-us/advertising/reporting-service/agegenderaudiencereportrequest?view=bingads-13) +- [age_gender_audience_report_daily](https://learn.microsoft.com/en-us/advertising/reporting-service/agegenderaudiencereportrequest?view=bingads-13) +- [age_gender_audience_report_weekly](https://learn.microsoft.com/en-us/advertising/reporting-service/agegenderaudiencereportrequest?view=bingads-13) +- [age_gender_audience_report_monthly](https://learn.microsoft.com/en-us/advertising/reporting-service/agegenderaudiencereportrequest?view=bingads-13) - [geographic_performance_report_hourly](https://learn.microsoft.com/en-us/advertising/reporting-service/geographicperformancereportrequest?view=bingads-13) - [geographic_performance_report_daily](https://learn.microsoft.com/en-us/advertising/reporting-service/geographicperformancereportrequest?view=bingads-13) - [geographic_performance_report_weekly](https://learn.microsoft.com/en-us/advertising/reporting-service/geographicperformancereportrequest?view=bingads-13) @@ -123,7 +127,8 @@ The Bing Ads API limits the number of requests for all Microsoft Advertising cli | Version | Date | Pull Request | Subject | |:--------|:-----------|:---------------------------------------------------------------------------------------------------------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------| -| 1.0.2 | 2023-10-19 | [31599](https://github.com/airbytehq/airbyte/pull/31599) | Base image migration: remove Dockerfile and use the python-connector-base image | +| 1.1.0 | 2023-10-24 | [31712](https://github.com/airbytehq/airbyte/pull/31712) | Add new stream: AgeGenderAudienceReport (daily, hourly, weekly, monthly) | +| 1.0.2 | 2023-10-19 | [31599](https://github.com/airbytehq/airbyte/pull/31599) | Base image migration: remove Dockerfile and use the python-connector-base image | | 1.0.1 | 2023-10-16 | [31432](https://github.com/airbytehq/airbyte/pull/31432) | Remove primary keys from the geographic performance reports - complete what was missed in version 1.0.0 | | 1.0.0 | 2023-10-11 | [31277](https://github.com/airbytehq/airbyte/pull/31277) | Remove primary keys from the geographic performance reports. | | 0.2.3 | 2023-09-28 | [30834](https://github.com/airbytehq/airbyte/pull/30834) | Wrap auth error with the config error. | From 7d730d3ac4a1dc795f3baa80d443caa4c95c2d97 Mon Sep 17 00:00:00 2001 From: Artem Inzhyyants Date: Tue, 24 Oct 2023 11:45:18 +0200 Subject: [PATCH 04/14] Source Bing Ads: flake ignore --- .../connectors/source-bing-ads/source_bing_ads/source.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/source.py b/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/source.py index 10c0ed8fc856..eb9368fc0f0a 100644 --- a/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/source.py +++ b/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/source.py @@ -9,7 +9,7 @@ from airbyte_cdk.sources import AbstractSource from airbyte_cdk.sources.streams import Stream from source_bing_ads.client import Client -from source_bing_ads.streams import ( +from source_bing_ads.streams import ( # noqa: F401 AccountPerformanceReportDaily, AccountPerformanceReportHourly, AccountPerformanceReportMonthly, From d8e17ed11351e6d7a7fc30b6e0133652bd80960d Mon Sep 17 00:00:00 2001 From: Artem Inzhyyants Date: Tue, 24 Oct 2023 11:52:33 +0200 Subject: [PATCH 05/14] Source Bing Ads: update unit tests --- .../connectors/source-bing-ads/unit_tests/test_source.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/airbyte-integrations/connectors/source-bing-ads/unit_tests/test_source.py b/airbyte-integrations/connectors/source-bing-ads/unit_tests/test_source.py index 23a53d6ac78e..f97f1d7a7588 100644 --- a/airbyte-integrations/connectors/source-bing-ads/unit_tests/test_source.py +++ b/airbyte-integrations/connectors/source-bing-ads/unit_tests/test_source.py @@ -8,7 +8,7 @@ import pytest import source_bing_ads from airbyte_cdk.models import SyncMode -from source_bing_ads.source import AccountPerformanceReportMonthly, Accounts, AdGroups, Ads, Campaigns, SourceBingAds +from source_bing_ads.streams import AccountPerformanceReportMonthly, Accounts, AdGroups, Ads, Campaigns, SourceBingAds @pytest.fixture(name="config") @@ -27,7 +27,7 @@ def logger_mock_fixture(): @patch.object(source_bing_ads.source, "Client") def test_streams_config_based(mocked_client, config): streams = SourceBingAds().streams(config) - assert len(streams) == 29 + assert len(streams) == 33 @patch.object(source_bing_ads.source, "Client") From a76f249368b45b340576ff1a0109754e8c0f6076 Mon Sep 17 00:00:00 2001 From: Artem Inzhyyants Date: Tue, 24 Oct 2023 11:52:59 +0200 Subject: [PATCH 06/14] Source Bing Ads: update unit tests --- .../connectors/source-bing-ads/unit_tests/test_reports.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/airbyte-integrations/connectors/source-bing-ads/unit_tests/test_reports.py b/airbyte-integrations/connectors/source-bing-ads/unit_tests/test_reports.py index 8763c1ea8bcf..2b3fd6dd38e3 100644 --- a/airbyte-integrations/connectors/source-bing-ads/unit_tests/test_reports.py +++ b/airbyte-integrations/connectors/source-bing-ads/unit_tests/test_reports.py @@ -9,12 +9,12 @@ import pytest from bingads.v13.internal.reporting.row_report_iterator import _RowReportRecord, _RowValues from source_bing_ads.reports import PerformanceReportsMixin, ReportsMixin -from source_bing_ads.source import ( +from source_bing_ads.source import SourceBingAds +from source_bing_ads.streams import ( GeographicPerformanceReportDaily, GeographicPerformanceReportHourly, GeographicPerformanceReportMonthly, GeographicPerformanceReportWeekly, - SourceBingAds, ) From 0a61de1d46903eb90b56bf43c6eb131bc69ca193 Mon Sep 17 00:00:00 2001 From: Artem Inzhyyants Date: Tue, 24 Oct 2023 12:04:51 +0200 Subject: [PATCH 07/14] Source Bing Ads: update unit tests --- .../connectors/source-bing-ads/unit_tests/test_source.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/airbyte-integrations/connectors/source-bing-ads/unit_tests/test_source.py b/airbyte-integrations/connectors/source-bing-ads/unit_tests/test_source.py index f97f1d7a7588..9f8435077bce 100644 --- a/airbyte-integrations/connectors/source-bing-ads/unit_tests/test_source.py +++ b/airbyte-integrations/connectors/source-bing-ads/unit_tests/test_source.py @@ -8,7 +8,8 @@ import pytest import source_bing_ads from airbyte_cdk.models import SyncMode -from source_bing_ads.streams import AccountPerformanceReportMonthly, Accounts, AdGroups, Ads, Campaigns, SourceBingAds +from source_bing_ads.source import SourceBingAds +from source_bing_ads.streams import AccountPerformanceReportMonthly, Accounts, AdGroups, Ads, Campaigns @pytest.fixture(name="config") From 9ecbb29f49590f71022b74537878ee3f47ae446d Mon Sep 17 00:00:00 2001 From: Artem Inzhyyants Date: Tue, 24 Oct 2023 12:27:14 +0200 Subject: [PATCH 08/14] Source Bing Ads: fix primary keys; update schema --- .../schemas/age_gender_audience_report.json | 2 +- .../source_bing_ads/streams.py | 47 ++++++------------- 2 files changed, 16 insertions(+), 33 deletions(-) diff --git a/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/schemas/age_gender_audience_report.json b/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/schemas/age_gender_audience_report.json index a01c1d27e384..73e0f9873fda 100644 --- a/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/schemas/age_gender_audience_report.json +++ b/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/schemas/age_gender_audience_report.json @@ -87,7 +87,7 @@ "type": ["null", "string"] }, "AbsoluteTopImpressionRatePercent": { - "type": ["null", "number"] + "type": ["null", "string"] }, "TopImpressionRatePercent": { "type": ["null", "string"] diff --git a/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/streams.py b/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/streams.py index 45d190909419..3e65a6ab3af9 100644 --- a/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/streams.py +++ b/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/streams.py @@ -13,6 +13,8 @@ from airbyte_cdk.sources.streams import Stream from bingads.service_client import ServiceClient from bingads.v13.reporting.reporting_service_manager import ReportingServiceManager + +from airbyte_cdk.sources.utils.transform import TransformConfig, TypeTransformer from source_bing_ads.client import Client from source_bing_ads.reports import ( ALL_CONVERSION_FIELDS, @@ -832,6 +834,7 @@ class AccountPerformanceReportMonthly(AccountPerformanceReport): class AgeGenderAudienceReport(PerformanceReportsMixin, BingAdsStream, ABC): + transformer: TypeTransformer = TypeTransformer(TransformConfig.DefaultSchemaNormalization) data_field: str = "" service_name: str = "ReportingService" report_name: str = "AgeGenderAudienceReport" @@ -844,42 +847,22 @@ class AgeGenderAudienceReport(PerformanceReportsMixin, BingAdsStream, ABC): "Gender", "TimePeriod", "AccountId", - ] - - report_columns = [ - *primary_key, - "AllConversions", - "AccountName", - "AccountNumber", - "CampaignName", "CampaignId", - "AdGroupName", - "AdGroupId", - "AdDistribution", - "Impressions", - "Clicks", - "Conversions", - "Spend", - "Revenue", - "ExtendedCost", - "Assists", "Language", - "AccountStatus", - "CampaignStatus", - "AdGroupStatus", - "BaseCampaignId", - "AllRevenue", - "ViewThroughConversions", - "Goal", - "GoalType", - "AbsoluteTopImpressionRatePercent", - "TopImpressionRatePercent", - "ConversionsQualified", - "AllConversionsQualified", - "ViewThroughConversionsQualified", - "ViewThroughRevenue", + "AdDistribution" ] + @property + def report_columns(self): + return list(self.get_json_schema().get("properties", {}).keys()) + + def parse_response(self, response: sudsobject.Object, **kwargs: Mapping[str, Any]) -> Iterable[Mapping]: + if response is not None: + for row in response.report_records: + yield {column: row.value(column) if row.value(column) else None for column in self.report_columns} + + yield from [] + class AgeGenderAudienceReportHourly(AgeGenderAudienceReport): report_aggregation = "Hourly" From b7c53f4ab6aaf4575b80e8d3a3a8bd371453604f Mon Sep 17 00:00:00 2001 From: Artem Inzhyyants Date: Tue, 24 Oct 2023 12:34:36 +0200 Subject: [PATCH 09/14] Source Bing Ads: format file --- .../source-bing-ads/source_bing_ads/streams.py | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/streams.py b/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/streams.py index 3e65a6ab3af9..89ccf41f48d9 100644 --- a/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/streams.py +++ b/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/streams.py @@ -11,10 +11,9 @@ from airbyte_cdk.models import SyncMode from airbyte_cdk.sources.streams import Stream +from airbyte_cdk.sources.utils.transform import TransformConfig, TypeTransformer from bingads.service_client import ServiceClient from bingads.v13.reporting.reporting_service_manager import ReportingServiceManager - -from airbyte_cdk.sources.utils.transform import TransformConfig, TypeTransformer from source_bing_ads.client import Client from source_bing_ads.reports import ( ALL_CONVERSION_FIELDS, @@ -842,15 +841,7 @@ class AgeGenderAudienceReport(PerformanceReportsMixin, BingAdsStream, ABC): additional_fields: str = "" cursor_field = "TimePeriod" report_schema_name = "age_gender_audience_report" - primary_key = [ - "AgeGroup", - "Gender", - "TimePeriod", - "AccountId", - "CampaignId", - "Language", - "AdDistribution" - ] + primary_key = ["AgeGroup", "Gender", "TimePeriod", "AccountId", "CampaignId", "Language", "AdDistribution"] @property def report_columns(self): From b8e5c36c7946b2684189b11a92009a8bcb977ce0 Mon Sep 17 00:00:00 2001 From: Artem Inzhyyants Date: Tue, 24 Oct 2023 13:02:14 +0200 Subject: [PATCH 10/14] Source Bing Ads: update CAT tests --- .../acceptance-test-config.yml | 4 +- .../integration_tests/configured_catalog.json | 40 +++++++++++++++++++ ...ted_records.txt => expected_records.jsonl} | 14 +++++++ .../schemas/age_gender_audience_report.json | 6 +-- 4 files changed, 60 insertions(+), 4 deletions(-) rename airbyte-integrations/connectors/source-bing-ads/integration_tests/{expected_records.txt => expected_records.jsonl} (71%) diff --git a/airbyte-integrations/connectors/source-bing-ads/acceptance-test-config.yml b/airbyte-integrations/connectors/source-bing-ads/acceptance-test-config.yml index 3df7cace96bf..5bad38935091 100644 --- a/airbyte-integrations/connectors/source-bing-ads/acceptance-test-config.yml +++ b/airbyte-integrations/connectors/source-bing-ads/acceptance-test-config.yml @@ -19,7 +19,7 @@ acceptance_tests: tests: - config_path: secrets/config.json expect_records: - path: "integration_tests/expected_records.txt" + path: "integration_tests/expected_records.jsonl" extra_records: yes empty_streams: - name: account_performance_report_hourly @@ -34,6 +34,8 @@ acceptance_tests: bypass_reason: "Hourly reports are disabled, because sync is too long" - name: geographic_performance_report_hourly bypass_reason: "Hourly reports are disabled, because sync is too long" + - name: age_gender_audience_report_hourly + bypass_reason: "Hourly reports are disabled, because sync is too long" timeout_seconds: 900 full_refresh: tests: diff --git a/airbyte-integrations/connectors/source-bing-ads/integration_tests/configured_catalog.json b/airbyte-integrations/connectors/source-bing-ads/integration_tests/configured_catalog.json index 651e4da746e5..8d48603892d8 100644 --- a/airbyte-integrations/connectors/source-bing-ads/integration_tests/configured_catalog.json +++ b/airbyte-integrations/connectors/source-bing-ads/integration_tests/configured_catalog.json @@ -265,6 +265,46 @@ "sync_mode": "incremental", "cursor_field": ["TimePeriod"], "destination_sync_mode": "append" + }, + { + "stream": { + "name": "age_gender_audience_report_daily", + "json_schema": {}, + "supported_sync_modes": ["incremental", "full_refresh"] + }, + "sync_mode": "incremental", + "cursor_field": ["TimePeriod"], + "destination_sync_mode": "append" + }, + { + "stream": { + "name": "age_gender_audience_report_weekly", + "json_schema": {}, + "supported_sync_modes": ["incremental", "full_refresh"] + }, + "sync_mode": "incremental", + "cursor_field": ["TimePeriod"], + "destination_sync_mode": "append" + }, + { + "stream": { + "name": "age_gender_audience_report_hourly", + "json_schema": {}, + "supported_sync_modes": ["incremental", "full_refresh"] + }, + "sync_mode": "incremental", + "cursor_field": ["TimePeriod"], + "destination_sync_mode": "append" + }, + { + "stream": { + "name": "age_gender_audience_report_monthly", + "json_schema": {}, + "supported_sync_modes": ["incremental", "full_refresh"] + }, + "sync_mode": "incremental", + "cursor_field": ["TimePeriod"], + "destination_sync_mode": "append" } ] } diff --git a/airbyte-integrations/connectors/source-bing-ads/integration_tests/expected_records.txt b/airbyte-integrations/connectors/source-bing-ads/integration_tests/expected_records.jsonl similarity index 71% rename from airbyte-integrations/connectors/source-bing-ads/integration_tests/expected_records.txt rename to airbyte-integrations/connectors/source-bing-ads/integration_tests/expected_records.jsonl index 5b3c841b8abd..15b209c448ad 100644 --- a/airbyte-integrations/connectors/source-bing-ads/integration_tests/expected_records.txt +++ b/airbyte-integrations/connectors/source-bing-ads/integration_tests/expected_records.jsonl @@ -21,3 +21,17 @@ {"stream": "geographic_performance_report_daily", "data": {"AccountId": 180278106, "CampaignId": 413444833, "AdGroupId": 1352400325389092, "TimePeriod": "2021-06-09", "Country": "Australia", "CurrencyCode": "USD", "DeliveredMatchType": "Broad", "AdDistribution": "Search", "DeviceType": "Computer", "Language": "English", "Network": "Syndicated search partners", "DeviceOS": "Windows", "TopVsOther": "Syndicated search partners - Top", "BidMatchType": "Broad", "MetroArea": null, "State": "New South Wales", "City": null, "AdGroupName": "Airbyte", "Ctr": 0.0, "ProximityTargetLocation": null, "Radius": "0", "Assists": 0, "ReturnOnAdSpend": null, "CostPerAssist": null, "LocationType": "Physical location", "MostSpecificLocation": "2000", "AccountStatus": "Active", "CampaignStatus": "Paused", "AdGroupStatus": "Active", "County": null, "PostalCode": "2000", "LocationId": "122395", "BaseCampaignId": "413444833", "AllCostPerConversion": null, "AllReturnOnAdSpend": null, "ViewThroughConversions": 0, "Goal": null, "GoalType": null, "AbsoluteTopImpressionRatePercent": 0.0, "TopImpressionRatePercent": "100.00%", "AllConversionsQualified": "0.00", "ViewThroughConversionsQualified": null, "Neighborhood": null, "ViewThroughRevenue": "0.00", "CampaignType": "Search & content", "AssetGroupId": null, "AssetGroupName": null, "AssetGroupStatus": null, "Clicks": 0, "Spend": 0.0, "Impressions": 1, "CostPerConversion": null, "AccountName": "Daxtarity Inc.", "AccountNumber": "F149GKV5", "CampaignName": "Test 2", "Conversions": 0.0, "ConversionRate": null, "ConversionsQualified": 0.0, "AverageCpc": 0.0, "AveragePosition": 0.0, "AverageCpm": 0.0, "AllConversions": 0, "AllConversionRate": null, "AllRevenue": 0.0, "AllRevenuePerConversion": null, "Revenue": 0.0, "RevenuePerConversion": null, "RevenuePerAssist": null}, "emitted_at": 1695825623738} {"stream": "geographic_performance_report_weekly", "data": {"AccountId": 180278106, "CampaignId": 413444833, "AdGroupId": 1352400325389092, "TimePeriod": "2021-06-06", "Country": "Australia", "CurrencyCode": "USD", "DeliveredMatchType": "Broad", "AdDistribution": "Search", "DeviceType": "Computer", "Language": "English", "Network": "Bing and Yahoo! search", "DeviceOS": "Windows", "TopVsOther": "Bing and Yahoo! search - Other", "BidMatchType": "Broad", "MetroArea": null, "State": "New South Wales", "City": null, "AdGroupName": "Airbyte", "Ctr": 0.0, "ProximityTargetLocation": null, "Radius": "0", "Assists": 0, "ReturnOnAdSpend": null, "CostPerAssist": null, "LocationType": "Physical location", "MostSpecificLocation": "New South Wales", "AccountStatus": "Active", "CampaignStatus": "Paused", "AdGroupStatus": "Active", "County": null, "PostalCode": null, "LocationId": "4048", "BaseCampaignId": "413444833", "AllCostPerConversion": null, "AllReturnOnAdSpend": null, "ViewThroughConversions": 0, "Goal": null, "GoalType": null, "AbsoluteTopImpressionRatePercent": 0.0, "TopImpressionRatePercent": "0.00%", "AllConversionsQualified": "0.00", "ViewThroughConversionsQualified": null, "Neighborhood": null, "ViewThroughRevenue": "0.00", "CampaignType": "Search & content", "AssetGroupId": null, "AssetGroupName": null, "AssetGroupStatus": null, "Clicks": 0, "Spend": 0.0, "Impressions": 1, "CostPerConversion": null, "AccountName": "Daxtarity Inc.", "AccountNumber": "F149GKV5", "CampaignName": "Test 2", "Conversions": 0.0, "ConversionRate": null, "ConversionsQualified": 0.0, "AverageCpc": 0.0, "AveragePosition": 0.0, "AverageCpm": 0.0, "AllConversions": 0, "AllConversionRate": null, "AllRevenue": 0.0, "AllRevenuePerConversion": null, "Revenue": 0.0, "RevenuePerConversion": null, "RevenuePerAssist": null}, "emitted_at": 1695825558741} {"stream": "geographic_performance_report_monthly", "data": {"AccountId": 180278106, "CampaignId": 413444833, "AdGroupId": 1352400325389092, "TimePeriod": "2021-06-01", "Country": "United Arab Emirates", "CurrencyCode": "USD", "DeliveredMatchType": "Broad", "AdDistribution": "Search", "DeviceType": "Computer", "Language": "English", "Network": "Bing and Yahoo! search", "DeviceOS": "Windows", "TopVsOther": "Bing and Yahoo! search - Top", "BidMatchType": "Broad", "MetroArea": null, "State": null, "City": null, "AdGroupName": "Airbyte", "Ctr": 0.0, "ProximityTargetLocation": null, "Radius": "0", "Assists": 0, "ReturnOnAdSpend": null, "CostPerAssist": null, "LocationType": "Physical location", "MostSpecificLocation": "United Arab Emirates", "AccountStatus": "Active", "CampaignStatus": "Paused", "AdGroupStatus": "Active", "County": null, "PostalCode": null, "LocationId": "218", "BaseCampaignId": "413444833", "AllCostPerConversion": null, "AllReturnOnAdSpend": null, "ViewThroughConversions": 0, "Goal": null, "GoalType": null, "AbsoluteTopImpressionRatePercent": 0.0, "TopImpressionRatePercent": "100.00%", "AllConversionsQualified": "0.00", "ViewThroughConversionsQualified": null, "Neighborhood": null, "ViewThroughRevenue": "0.00", "CampaignType": "Search & content", "AssetGroupId": null, "AssetGroupName": null, "AssetGroupStatus": null, "Clicks": 0, "Spend": 0.0, "Impressions": 1, "CostPerConversion": null, "AccountName": "Daxtarity Inc.", "AccountNumber": "F149GKV5", "CampaignName": "Test 2", "Conversions": 0.0, "ConversionRate": null, "ConversionsQualified": 0.0, "AverageCpc": 0.0, "AveragePosition": 0.0, "AverageCpm": 0.0, "AllConversions": 0, "AllConversionRate": null, "AllRevenue": 0.0, "AllRevenuePerConversion": null, "Revenue": 0.0, "RevenuePerConversion": null, "RevenuePerAssist": null}, "emitted_at": 1695825503003} +{"stream":"age_gender_audience_report_daily","data":{"AccountId":180278106,"AgeGroup":"50-64","Gender":"Female","TimePeriod":"2021-07-29","AllConversions":0,"AccountName":"Daxtarity Inc.","AccountNumber":"F149GKV5","CampaignName":"Test 2","CampaignId":413444833,"AdGroupName":"Airbyte","AdGroupId":1352400325389092,"AdDistribution":"Search","Impressions":1,"Clicks":0,"Conversions":0.0,"Spend":0.0,"Revenue":0.0,"ExtendedCost":0.0,"Assists":0,"Language":"English","AccountStatus":"Active","CampaignStatus":"Paused","AdGroupStatus":"Active","BaseCampaignId":"413444833","AllRevenue":0.0,"ViewThroughConversions":0,"Goal":null,"GoalType":null,"AbsoluteTopImpressionRatePercent":"100.00%","TopImpressionRatePercent":"100.00%","ConversionsQualified":0.0,"AllConversionsQualified":0.0,"ViewThroughConversionsQualified":null,"ViewThroughRevenue":0.0},"emitted_at":1698144719344} +{"stream":"age_gender_audience_report_daily","data":{"AccountId":180278106,"AgeGroup":"65+","Gender":"Unknown","TimePeriod":"2021-06-13","AllConversions":0,"AccountName":"Daxtarity Inc.","AccountNumber":"F149GKV5","CampaignName":"Test 2","CampaignId":413444833,"AdGroupName":"Airbyte","AdGroupId":1352400325389092,"AdDistribution":"Search","Impressions":2,"Clicks":0,"Conversions":0.0,"Spend":0.0,"Revenue":0.0,"ExtendedCost":0.0,"Assists":0,"Language":"English","AccountStatus":"Active","CampaignStatus":"Paused","AdGroupStatus":"Active","BaseCampaignId":"413444833","AllRevenue":0.0,"ViewThroughConversions":0,"Goal":null,"GoalType":null,"AbsoluteTopImpressionRatePercent":"0.00%","TopImpressionRatePercent":"100.00%","ConversionsQualified":0.0,"AllConversionsQualified":0.0,"ViewThroughConversionsQualified":null,"ViewThroughRevenue":0.0},"emitted_at":1698144719348} +{"stream":"age_gender_audience_report_daily","data":{"AccountId":180278106,"AgeGroup":"65+","Gender":"Male","TimePeriod":"2021-06-09","AllConversions":0,"AccountName":"Daxtarity Inc.","AccountNumber":"F149GKV5","CampaignName":"Test 2","CampaignId":413444833,"AdGroupName":"Airbyte","AdGroupId":1352400325389092,"AdDistribution":"Search","Impressions":1,"Clicks":0,"Conversions":0.0,"Spend":0.0,"Revenue":0.0,"ExtendedCost":0.0,"Assists":0,"Language":"English","AccountStatus":"Active","CampaignStatus":"Paused","AdGroupStatus":"Active","BaseCampaignId":"413444833","AllRevenue":0.0,"ViewThroughConversions":0,"Goal":null,"GoalType":null,"AbsoluteTopImpressionRatePercent":"0.00%","TopImpressionRatePercent":"0.00%","ConversionsQualified":0.0,"AllConversionsQualified":0.0,"ViewThroughConversionsQualified":null,"ViewThroughRevenue":0.0},"emitted_at":1698144719350} +{"stream":"age_gender_audience_report_weekly","data":{"AccountId":180278106,"AgeGroup":"Unknown","Gender":"Female","TimePeriod":"2021-07-18","AllConversions":0,"AccountName":"Daxtarity Inc.","AccountNumber":"F149GKV5","CampaignName":"Test 2","CampaignId":413444833,"AdGroupName":"Airbyte","AdGroupId":1352400325389092,"AdDistribution":"Search","Impressions":1,"Clicks":0,"Conversions":0.0,"Spend":0.0,"Revenue":0.0,"ExtendedCost":0.0,"Assists":0,"Language":"English","AccountStatus":"Active","CampaignStatus":"Paused","AdGroupStatus":"Active","BaseCampaignId":"413444833","AllRevenue":0.0,"ViewThroughConversions":0,"Goal":null,"GoalType":null,"AbsoluteTopImpressionRatePercent":"0.00%","TopImpressionRatePercent":"0.00%","ConversionsQualified":0.0,"AllConversionsQualified":0.0,"ViewThroughConversionsQualified":null,"ViewThroughRevenue":0.0},"emitted_at":1698144728984} +{"stream":"age_gender_audience_report_weekly","data":{"AccountId":180278106,"AgeGroup":"18-24","Gender":"Unknown","TimePeriod":"2021-06-06","AllConversions":0,"AccountName":"Daxtarity Inc.","AccountNumber":"F149GKV5","CampaignName":"Test 2","CampaignId":413444833,"AdGroupName":"Airbyte","AdGroupId":1352400325389092,"AdDistribution":"Search","Impressions":5,"Clicks":0,"Conversions":0.0,"Spend":0.0,"Revenue":0.0,"ExtendedCost":0.0,"Assists":0,"Language":"English","AccountStatus":"Active","CampaignStatus":"Paused","AdGroupStatus":"Active","BaseCampaignId":"413444833","AllRevenue":0.0,"ViewThroughConversions":0,"Goal":null,"GoalType":null,"AbsoluteTopImpressionRatePercent":"20.00%","TopImpressionRatePercent":"80.00%","ConversionsQualified":0.0,"AllConversionsQualified":0.0,"ViewThroughConversionsQualified":null,"ViewThroughRevenue":0.0},"emitted_at":1698144728986} +{"stream":"age_gender_audience_report_weekly","data":{"AccountId":180278106,"AgeGroup":"50-64","Gender":"Male","TimePeriod":"2021-07-25","AllConversions":0,"AccountName":"Daxtarity Inc.","AccountNumber":"F149GKV5","CampaignName":"Test 2","CampaignId":413444833,"AdGroupName":"Airbyte","AdGroupId":1352400325389092,"AdDistribution":"Audience","Impressions":2,"Clicks":0,"Conversions":0.0,"Spend":0.0,"Revenue":0.0,"ExtendedCost":0.0,"Assists":0,"Language":"German","AccountStatus":"Active","CampaignStatus":"Paused","AdGroupStatus":"Active","BaseCampaignId":"413444833","AllRevenue":0.0,"ViewThroughConversions":0,"Goal":null,"GoalType":null,"AbsoluteTopImpressionRatePercent":"0.00%","TopImpressionRatePercent":"0.00%","ConversionsQualified":0.0,"AllConversionsQualified":0.0,"ViewThroughConversionsQualified":null,"ViewThroughRevenue":0.0},"emitted_at":1698144729135} +{"stream":"age_gender_audience_report_weekly","data":{"AccountId":180278106,"AgeGroup":"50-64","Gender":"Female","TimePeriod":"2021-06-06","AllConversions":0,"AccountName":"Daxtarity Inc.","AccountNumber":"F149GKV5","CampaignName":"Test 2","CampaignId":413444833,"AdGroupName":"Airbyte","AdGroupId":1352400325389092,"AdDistribution":"Search","Impressions":3,"Clicks":0,"Conversions":0.0,"Spend":0.0,"Revenue":0.0,"ExtendedCost":0.0,"Assists":0,"Language":"English","AccountStatus":"Active","CampaignStatus":"Paused","AdGroupStatus":"Active","BaseCampaignId":"413444833","AllRevenue":0.0,"ViewThroughConversions":0,"Goal":null,"GoalType":null,"AbsoluteTopImpressionRatePercent":"0.00%","TopImpressionRatePercent":"33.33%","ConversionsQualified":0.0,"AllConversionsQualified":0.0,"ViewThroughConversionsQualified":null,"ViewThroughRevenue":0.0},"emitted_at":1698144729136} +{"stream":"age_gender_audience_report_weekly","data":{"AccountId":180278106,"AgeGroup":"65+","Gender":"Unknown","TimePeriod":"2021-06-13","AllConversions":0,"AccountName":"Daxtarity Inc.","AccountNumber":"F149GKV5","CampaignName":"Test 2","CampaignId":413444833,"AdGroupName":"Airbyte","AdGroupId":1352400325389092,"AdDistribution":"Search","Impressions":2,"Clicks":0,"Conversions":0.0,"Spend":0.0,"Revenue":0.0,"ExtendedCost":0.0,"Assists":0,"Language":"English","AccountStatus":"Active","CampaignStatus":"Paused","AdGroupStatus":"Active","BaseCampaignId":"413444833","AllRevenue":0.0,"ViewThroughConversions":0,"Goal":null,"GoalType":null,"AbsoluteTopImpressionRatePercent":"0.00%","TopImpressionRatePercent":"100.00%","ConversionsQualified":0.0,"AllConversionsQualified":0.0,"ViewThroughConversionsQualified":null,"ViewThroughRevenue":0.0},"emitted_at":1698144729143} +{"stream":"age_gender_audience_report_weekly","data":{"AccountId":180278106,"AgeGroup":"65+","Gender":"Male","TimePeriod":"2021-07-11","AllConversions":0,"AccountName":"Daxtarity Inc.","AccountNumber":"F149GKV5","CampaignName":"Test 2","CampaignId":413444833,"AdGroupName":"Airbyte","AdGroupId":1352400325389092,"AdDistribution":"Search","Impressions":1,"Clicks":0,"Conversions":0.0,"Spend":0.0,"Revenue":0.0,"ExtendedCost":0.0,"Assists":0,"Language":"English","AccountStatus":"Active","CampaignStatus":"Paused","AdGroupStatus":"Active","BaseCampaignId":"413444833","AllRevenue":0.0,"ViewThroughConversions":0,"Goal":null,"GoalType":null,"AbsoluteTopImpressionRatePercent":"0.00%","TopImpressionRatePercent":"0.00%","ConversionsQualified":0.0,"AllConversionsQualified":0.0,"ViewThroughConversionsQualified":null,"ViewThroughRevenue":0.0},"emitted_at":1698144729150} +{"stream":"age_gender_audience_report_monthly","data":{"AccountId":180278106,"AgeGroup":"Unknown","Gender":"Unknown","TimePeriod":"2021-06-01","AllConversions":0,"AccountName":"Daxtarity Inc.","AccountNumber":"F149GKV5","CampaignName":"Test 2","CampaignId":413444833,"AdGroupName":"Airbyte","AdGroupId":1352400325389092,"AdDistribution":"Search","Impressions":8750,"Clicks":81,"Conversions":0.0,"Spend":14.76,"Revenue":0.0,"ExtendedCost":0.0,"Assists":0,"Language":"English","AccountStatus":"Active","CampaignStatus":"Paused","AdGroupStatus":"Active","BaseCampaignId":"413444833","AllRevenue":0.0,"ViewThroughConversions":0,"Goal":null,"GoalType":null,"AbsoluteTopImpressionRatePercent":"9.16%","TopImpressionRatePercent":"80.29%","ConversionsQualified":0.0,"AllConversionsQualified":0.0,"ViewThroughConversionsQualified":null,"ViewThroughRevenue":0.0},"emitted_at":1698144746067} +{"stream":"age_gender_audience_report_monthly","data":{"AccountId":180278106,"AgeGroup":"18-24","Gender":"Unknown","TimePeriod":"2021-08-01","AllConversions":0,"AccountName":"Daxtarity Inc.","AccountNumber":"F149GKV5","CampaignName":"Test 2","CampaignId":413444833,"AdGroupName":"Airbyte","AdGroupId":1352400325389092,"AdDistribution":"Search","Impressions":1,"Clicks":0,"Conversions":0.0,"Spend":0.0,"Revenue":0.0,"ExtendedCost":0.0,"Assists":0,"Language":"Thai","AccountStatus":"Active","CampaignStatus":"Paused","AdGroupStatus":"Active","BaseCampaignId":"413444833","AllRevenue":0.0,"ViewThroughConversions":0,"Goal":null,"GoalType":null,"AbsoluteTopImpressionRatePercent":"0.00%","TopImpressionRatePercent":"0.00%","ConversionsQualified":0.0,"AllConversionsQualified":0.0,"ViewThroughConversionsQualified":null,"ViewThroughRevenue":0.0},"emitted_at":1698144746150} +{"stream":"age_gender_audience_report_monthly","data":{"AccountId":180278106,"AgeGroup":"50-64","Gender":"Female","TimePeriod":"2021-07-01","AllConversions":0,"AccountName":"Daxtarity Inc.","AccountNumber":"F149GKV5","CampaignName":"Test 2","CampaignId":413444833,"AdGroupName":"Airbyte","AdGroupId":1352400325389092,"AdDistribution":"Search","Impressions":3,"Clicks":0,"Conversions":0.0,"Spend":0.0,"Revenue":0.0,"ExtendedCost":0.0,"Assists":0,"Language":"English","AccountStatus":"Active","CampaignStatus":"Paused","AdGroupStatus":"Active","BaseCampaignId":"413444833","AllRevenue":0.0,"ViewThroughConversions":0,"Goal":null,"GoalType":null,"AbsoluteTopImpressionRatePercent":"33.33%","TopImpressionRatePercent":"33.33%","ConversionsQualified":0.0,"AllConversionsQualified":0.0,"ViewThroughConversionsQualified":null,"ViewThroughRevenue":0.0},"emitted_at":1698144746216} +{"stream":"age_gender_audience_report_monthly","data":{"AccountId":180278106,"AgeGroup":"65+","Gender":"Unknown","TimePeriod":"2021-06-01","AllConversions":0,"AccountName":"Daxtarity Inc.","AccountNumber":"F149GKV5","CampaignName":"Test 2","CampaignId":413444833,"AdGroupName":"Airbyte","AdGroupId":1352400325389092,"AdDistribution":"Search","Impressions":2,"Clicks":0,"Conversions":0.0,"Spend":0.0,"Revenue":0.0,"ExtendedCost":0.0,"Assists":0,"Language":"English","AccountStatus":"Active","CampaignStatus":"Paused","AdGroupStatus":"Active","BaseCampaignId":"413444833","AllRevenue":0.0,"ViewThroughConversions":0,"Goal":null,"GoalType":null,"AbsoluteTopImpressionRatePercent":"0.00%","TopImpressionRatePercent":"100.00%","ConversionsQualified":0.0,"AllConversionsQualified":0.0,"ViewThroughConversionsQualified":null,"ViewThroughRevenue":0.0},"emitted_at":1698144746217} +{"stream":"age_gender_audience_report_monthly","data":{"AccountId":180278106,"AgeGroup":"65+","Gender":"Male","TimePeriod":"2021-07-01","AllConversions":0,"AccountName":"Daxtarity Inc.","AccountNumber":"F149GKV5","CampaignName":"Test 2","CampaignId":413444833,"AdGroupName":"Airbyte","AdGroupId":1352400325389092,"AdDistribution":"Search","Impressions":2,"Clicks":0,"Conversions":0.0,"Spend":0.0,"Revenue":0.0,"ExtendedCost":0.0,"Assists":0,"Language":"English","AccountStatus":"Active","CampaignStatus":"Paused","AdGroupStatus":"Active","BaseCampaignId":"413444833","AllRevenue":0.0,"ViewThroughConversions":0,"Goal":null,"GoalType":null,"AbsoluteTopImpressionRatePercent":"0.00%","TopImpressionRatePercent":"0.00%","ConversionsQualified":0.0,"AllConversionsQualified":0.0,"ViewThroughConversionsQualified":null,"ViewThroughRevenue":0.0},"emitted_at":1698144746220} diff --git a/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/schemas/age_gender_audience_report.json b/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/schemas/age_gender_audience_report.json index 73e0f9873fda..c07a3e631b1d 100644 --- a/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/schemas/age_gender_audience_report.json +++ b/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/schemas/age_gender_audience_report.json @@ -54,7 +54,7 @@ "type": ["null", "number"] }, "ExtendedCost": { - "type": ["null", "string"] + "type": ["null", "number"] }, "Assists": { "type": ["null", "integer"] @@ -96,13 +96,13 @@ "type": ["null", "number"] }, "AllConversionsQualified": { - "type": ["null", "string"] + "type": ["null", "number"] }, "ViewThroughConversionsQualified": { "type": ["null", "number"] }, "ViewThroughRevenue": { - "type": ["null", "string"] + "type": ["null", "number"] } } } From 1ea45e4aea37c38eb6b49a5f6be3cd347d04895a Mon Sep 17 00:00:00 2001 From: Artem Inzhyyants Date: Tue, 24 Oct 2023 14:12:42 +0200 Subject: [PATCH 11/14] Source Bing Ads: update CAT tests + use typetransformer --- .../acceptance-test-config.yml | 2 -- .../source_bing_ads/reports.py | 25 ++++++++----------- .../source_bing_ads/streams.py | 9 ------- 3 files changed, 10 insertions(+), 26 deletions(-) diff --git a/airbyte-integrations/connectors/source-bing-ads/acceptance-test-config.yml b/airbyte-integrations/connectors/source-bing-ads/acceptance-test-config.yml index 5bad38935091..93c9b1886d27 100644 --- a/airbyte-integrations/connectors/source-bing-ads/acceptance-test-config.yml +++ b/airbyte-integrations/connectors/source-bing-ads/acceptance-test-config.yml @@ -9,8 +9,6 @@ acceptance_tests: - config_path: secrets/config.json connection: tests: - - config_path: secrets/config_old.json - status: succeed - config_path: secrets/config.json status: succeed - config_path: integration_tests/invalid_config.json diff --git a/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/reports.py b/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/reports.py index 0b33fc4e64f4..a63e94bbba1d 100644 --- a/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/reports.py +++ b/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/reports.py @@ -11,6 +11,7 @@ from airbyte_cdk.models import SyncMode from airbyte_cdk.sources.streams.core import package_name_from_class from airbyte_cdk.sources.utils.schema_helpers import ResourceSchemaLoader +from airbyte_cdk.sources.utils.transform import TransformConfig, TypeTransformer from bingads.service_client import ServiceClient from bingads.v13.internal.reporting.row_report import _RowReport from bingads.v13.internal.reporting.row_report_iterator import _RowReportRecord @@ -149,6 +150,7 @@ class ReportsMixin(ABC): timeout: int = 300000 report_file_format: str = "Csv" + transformer: TypeTransformer = TypeTransformer(TransformConfig.DefaultSchemaNormalization) primary_key: List[str] = ["TimePeriod", "Network", "DeviceType"] @property @@ -296,25 +298,18 @@ def parse_response(self, response: sudsobject.Object, **kwargs: Mapping[str, Any yield from [] - def get_column_value(self, row: _RowReportRecord, column: str) -> Union[str, None, int, float]: + @staticmethod + def get_column_value(row: _RowReportRecord, column: str) -> Union[str, None, int, float]: """ - Reads field value from row and transforms string type field to numeric if possible + Reads field value from row and transforms: + 1. empty values to logical None + 2. Percent values to numeric string e.g. "12.25%" -> "12.25" """ value = row.value(column) - if value == "": + if not value or value == "--": return None - - if value is not None and column in REPORT_FIELD_TYPES: - if REPORT_FIELD_TYPES[column] == "integer": - value = 0 if value == "--" else int(value.replace(",", "")) - elif REPORT_FIELD_TYPES[column] == "number": - if value == "--": - value = 0.0 - else: - if "%" in value: - value = float(value.replace("%", "").replace(",", "")) / 100 - else: - value = float(value.replace(",", "")) + if "%" in value: + value = value.replace("%", "") return value diff --git a/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/streams.py b/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/streams.py index 89ccf41f48d9..2855dbf71cff 100644 --- a/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/streams.py +++ b/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/streams.py @@ -11,7 +11,6 @@ from airbyte_cdk.models import SyncMode from airbyte_cdk.sources.streams import Stream -from airbyte_cdk.sources.utils.transform import TransformConfig, TypeTransformer from bingads.service_client import ServiceClient from bingads.v13.reporting.reporting_service_manager import ReportingServiceManager from source_bing_ads.client import Client @@ -833,7 +832,6 @@ class AccountPerformanceReportMonthly(AccountPerformanceReport): class AgeGenderAudienceReport(PerformanceReportsMixin, BingAdsStream, ABC): - transformer: TypeTransformer = TypeTransformer(TransformConfig.DefaultSchemaNormalization) data_field: str = "" service_name: str = "ReportingService" report_name: str = "AgeGenderAudienceReport" @@ -847,13 +845,6 @@ class AgeGenderAudienceReport(PerformanceReportsMixin, BingAdsStream, ABC): def report_columns(self): return list(self.get_json_schema().get("properties", {}).keys()) - def parse_response(self, response: sudsobject.Object, **kwargs: Mapping[str, Any]) -> Iterable[Mapping]: - if response is not None: - for row in response.report_records: - yield {column: row.value(column) if row.value(column) else None for column in self.report_columns} - - yield from [] - class AgeGenderAudienceReportHourly(AgeGenderAudienceReport): report_aggregation = "Hourly" From 7682351f7bfec3d9762838882e8e8f3604371a28 Mon Sep 17 00:00:00 2001 From: Artem Inzhyyants Date: Tue, 24 Oct 2023 15:17:26 +0200 Subject: [PATCH 12/14] Source Bing Ads: update schema + expected records --- .../integration_tests/expected_records.jsonl | 58 ++++++++----------- .../schemas/age_gender_audience_report.json | 4 +- 2 files changed, 26 insertions(+), 36 deletions(-) diff --git a/airbyte-integrations/connectors/source-bing-ads/integration_tests/expected_records.jsonl b/airbyte-integrations/connectors/source-bing-ads/integration_tests/expected_records.jsonl index 15b209c448ad..8931bda81a05 100644 --- a/airbyte-integrations/connectors/source-bing-ads/integration_tests/expected_records.jsonl +++ b/airbyte-integrations/connectors/source-bing-ads/integration_tests/expected_records.jsonl @@ -1,37 +1,27 @@ {"stream":"ad_groups","data":{"AdRotation":null,"AudienceAdsBidAdjustment":null,"BiddingScheme":{"Type":"InheritFromParent","InheritedBidStrategyType":"EnhancedCpc"},"CpcBid":{"Amount":0.05},"EndDate":null,"FinalUrlSuffix":null,"ForwardCompatibilityMap":null,"Id":1357897480389129,"Language":null,"Name":"Data Integration Tool","Network":"OwnedAndOperatedAndSyndicatedSearch","PrivacyStatus":null,"Settings":null,"StartDate":{"Day":4,"Month":12,"Year":2020},"Status":"Paused","TrackingUrlTemplate":null,"UrlCustomParameters":null,"AdScheduleUseSearcherTimeZone":false,"AdGroupType":"SearchStandard","CpvBid":{"Amount":null},"CpmBid":{"Amount":null}},"emitted_at":1675189566179} {"stream":"ads","data":{"AdFormatPreference":"All","DevicePreference":0,"EditorialStatus":"ActiveLimited","FinalAppUrls":null,"FinalMobileUrls":{"string":["https://airbyte.io"]},"FinalUrlSuffix":null,"FinalUrls":{"string":["https://airbyte.io"]},"ForwardCompatibilityMap":null,"Id":84525295496190,"Status":"Active","TrackingUrlTemplate":null,"Type":"ResponsiveSearch","UrlCustomParameters":null,"Descriptions":{"AssetLink":[{"Asset":{"Id":10239221964468,"Name":null,"Type":"TextAsset","Text":"Open data integration for modern data teams"},"AssetPerformanceLabel":"Learning","EditorialStatus":"Active","PinnedField":null},{"Asset":{"Id":10239221964466,"Name":null,"Type":"TextAsset","Text":"Get your data pipelines running in minutes. With pre-built or custom connectors"},"AssetPerformanceLabel":"Learning","EditorialStatus":"Active","PinnedField":null}]},"Domain":"airbyte.io","Headlines":{"AssetLink":[{"Asset":{"Id":10239221964471,"Name":null,"Type":"TextAsset","Text":"Data Integration Tool"},"AssetPerformanceLabel":"Learning","EditorialStatus":"Active","PinnedField":null},{"Asset":{"Id":10239221964469,"Name":null,"Type":"TextAsset","Text":"1,000+ Members"},"AssetPerformanceLabel":"Learning","EditorialStatus":"Active","PinnedField":null},{"Asset":{"Id":10239221964467,"Name":null,"Type":"TextAsset","Text":"Data Management Software"},"AssetPerformanceLabel":"Learning","EditorialStatus":"Active","PinnedField":null}]},"Path1":null,"Path2":null},"emitted_at":1675189577521} {"stream":"campaigns","data":{"AudienceAdsBidAdjustment":0,"BiddingScheme":{"Type":"EnhancedCpc"},"BudgetType":"DailyBudgetStandard","DailyBudget":0.1,"ExperimentId":null,"FinalUrlSuffix":null,"ForwardCompatibilityMap":null,"Id":407519039,"MultimediaAdsBidAdjustment":40,"Name":"integration-test-campaign","Status":"Paused","SubType":null,"TimeZone":"Arizona","TrackingUrlTemplate":null,"UrlCustomParameters":null,"CampaignType":"Search","Settings":{"Setting":[{"Type":"TargetSetting","Details":{"TargetSettingDetail":[{"CriterionTypeGroup":"Audience","TargetAndBid":false}]}}]},"BudgetId":null,"Languages":{"string":["English"]},"AdScheduleUseSearcherTimeZone":false},"emitted_at":1675189585409} -{"stream": "accounts", "data": {"BillToCustomerId": 251186883, "CurrencyCode": "USD", "AccountFinancialStatus": "ClearFinancialStatus", "Id": 180278106, "Language": "English", "LastModifiedByUserId": 0, "LastModifiedTime": "2023-08-11T03:26:10.277000", "Name": "Daxtarity Inc.", "Number": "F149GKV5", "ParentCustomerId": 251186883, "PaymentMethodId": 138188746, "PaymentMethodType": "CreditCard", "PrimaryUserId": 138225488, "AccountLifeCycleStatus": "Active", "TimeStamp": "AAAAAH1yyMo=", "TimeZone": "Arizona", "PauseReason": null, "ForwardCompatibilityMap": null, "LinkedAgencies": null, "SalesHouseCustomerId": null, "TaxInformation": null, "BackUpPaymentInstrumentId": null, "BillingThresholdAmount": null, "BusinessAddress": {"City": "San Francisco", "CountryCode": "US", "Id": 149004358, "Line1": "350 29th avenue", "Line2": null, "Line3": null, "Line4": null, "PostalCode": "94121", "StateOrProvince": "CA", "TimeStamp": null, "BusinessName": "Daxtarity Inc."}, "AutoTagType": "Inactive", "SoldToPaymentInstrumentId": null, "AccountMode": "Expert"}, "emitted_at": 1692381691611} -{"stream":"account_performance_report_daily", "data":{"AccountId": 180278106, "TimePeriod": "2021-08-03", "CurrencyCode": "USD", "AdDistribution": "Search", "DeviceType": "Tablet", "Network": "Syndicated search partners", "DeliveredMatchType": "Exact", "DeviceOS": "Android", "TopVsOther": "Syndicated search partners - Other", "BidMatchType": "Broad", "AccountName": "Daxtarity Inc.", "AccountNumber": "F149GKV5", "PhoneImpressions": 0, "PhoneCalls": 0, "Clicks": 0, "Ctr": 0.0, "Spend": 0.0, "Impressions": 1, "CostPerConversion": null, "Ptr": null, "Assists": 0, "ReturnOnAdSpend": null, "CostPerAssist": null, "AverageCpc": 0.0, "AveragePosition": 0.0, "AverageCpm": 0.0, "Conversions": 0.0, "ConversionRate": null, "ConversionsQualified": 0.0, "LowQualityClicks": 0, "LowQualityClicksPercent": null, "LowQualityImpressions": 0, "LowQualitySophisticatedClicks": 0, "LowQualityConversions": 0, "LowQualityConversionRate": null, "Revenue": 0.0, "RevenuePerConversion": null, "RevenuePerAssist": null}, "emitted_at": 1679944835117} -{"stream":"account_performance_report_weekly", "data": {"AccountId": 180278106, "TimePeriod": "2021-08-01", "CurrencyCode": "USD", "AdDistribution": "Search", "DeviceType": "Tablet", "Network": "Syndicated search partners", "DeliveredMatchType": "Broad", "DeviceOS": "Android", "TopVsOther": "Syndicated search partners - Top", "BidMatchType": "Broad", "AccountName": "Daxtarity Inc.", "AccountNumber": "F149GKV5", "PhoneImpressions": 0, "PhoneCalls": 0, "Clicks": 0, "Ctr": 0.0, "Spend": 0.0, "Impressions": 1, "CostPerConversion": null, "Ptr": null, "Assists": 0, "ReturnOnAdSpend": null, "CostPerAssist": null, "AverageCpc": 0.0, "AveragePosition": 0.0, "AverageCpm": 0.0, "Conversions": 0.0, "ConversionRate": null, "ConversionsQualified": 0.0, "LowQualityClicks": 0, "LowQualityClicksPercent": null, "LowQualityImpressions": 1, "LowQualitySophisticatedClicks": 0, "LowQualityConversions": 0, "LowQualityConversionRate": null, "Revenue": 0.0, "RevenuePerConversion": null, "RevenuePerAssist": null}, "emitted_at": 1679944953111} -{"stream":"account_performance_report_monthly", "data": {"AccountId": 180278106, "TimePeriod": "2021-08-01", "CurrencyCode": "USD", "AdDistribution": "Search", "DeviceType": "Tablet", "Network": "Syndicated search partners", "DeliveredMatchType": "Broad", "DeviceOS": "Android", "TopVsOther": "Syndicated search partners - Top", "BidMatchType": "Broad", "AccountName": "Daxtarity Inc.", "AccountNumber": "F149GKV5", "PhoneImpressions": 0, "PhoneCalls": 0, "Clicks": 0, "Ctr": 0.0, "Spend": 0.0, "Impressions": 1, "CostPerConversion": null, "Ptr": null, "Assists": 0, "ReturnOnAdSpend": null, "CostPerAssist": null, "AverageCpc": 0.0, "AveragePosition": 0.0, "AverageCpm": 0.0, "Conversions": 0.0, "ConversionRate": null, "ConversionsQualified": 0.0, "LowQualityClicks": 0, "LowQualityClicksPercent": null, "LowQualityImpressions": 1, "LowQualitySophisticatedClicks": 0, "LowQualityConversions": 0, "LowQualityConversionRate": null, "Revenue": 0.0, "RevenuePerConversion": null, "RevenuePerAssist": null}, "emitted_at": 1679945438344} -{"stream":"ad_group_performance_report_daily", "data": {"AccountId": 180278106, "CampaignId": 413444833, "AdGroupId": 1352400325389092, "TimePeriod": "2021-08-03", "CurrencyCode": "USD", "AdDistribution": "Search", "DeviceType": "Tablet", "Network": "Syndicated search partners", "DeliveredMatchType": "Exact", "DeviceOS": "Android", "TopVsOther": "Syndicated search partners - Other", "BidMatchType": "Broad", "Language": "English", "AccountName": "Daxtarity Inc.", "CampaignName": "Test 2", "CampaignType": "Search & content", "AdGroupName": "Airbyte", "AdGroupType": "Standard", "Impressions": 1, "Clicks": 0, "Ctr": 0.0, "Spend": 0.0, "CostPerConversion": null, "QualityScore": 0.0, "ExpectedCtr": "--", "AdRelevance": 0.0, "LandingPageExperience": 0.0, "PhoneImpressions": 0, "PhoneCalls": 0, "Ptr": null, "Assists": 0, "CostPerAssist": null, "CustomParameters": null, "FinalUrlSuffix": null, "ViewThroughConversions": 0, "AllCostPerConversion": null, "AllReturnOnAdSpend": null, "AllConversions": 0, "AllConversionRate": null, "AllRevenue": 0.0, "AllRevenuePerConversion": null, "AverageCpc": 0.0, "AveragePosition": 0.0, "AverageCpm": 0.0, "Conversions": 0.0, "ConversionRate": null, "ConversionsQualified": 0.0, "Revenue": 0.0, "RevenuePerConversion": null, "RevenuePerAssist": null, "HistoricalQualityScore": 8.0, "HistoricalExpectedCtr": 2.0, "HistoricalAdRelevance": 3.0, "HistoricalLandingPageExperience": 3.0}, "emitted_at": 1679950558186} -{"stream":"ad_group_performance_report_weekly", "data": {"AccountId": 180278106, "CampaignId": 413444833, "AdGroupId": 1352400325389092, "TimePeriod": "2021-08-01", "CurrencyCode": "USD", "AdDistribution": "Search", "DeviceType": "Tablet", "Network": "Syndicated search partners", "DeliveredMatchType": "Broad", "DeviceOS": "Android", "TopVsOther": "Syndicated search partners - Top", "BidMatchType": "Broad", "Language": "English", "AccountName": "Daxtarity Inc.", "CampaignName": "Test 2", "CampaignType": "Search & content", "AdGroupName": "Airbyte", "AdGroupType": "Standard", "Impressions": 1, "Clicks": 0, "Ctr": 0.0, "Spend": 0.0, "CostPerConversion": null, "QualityScore": 0.0, "ExpectedCtr": "--", "AdRelevance": 0.0, "LandingPageExperience": 0.0, "PhoneImpressions": 0, "PhoneCalls": 0, "Ptr": null, "Assists": 0, "CostPerAssist": null, "CustomParameters": null, "FinalUrlSuffix": null, "ViewThroughConversions": 0, "AllCostPerConversion": null, "AllReturnOnAdSpend": null, "AllConversions": 0, "AllConversionRate": null, "AllRevenue": 0.0, "AllRevenuePerConversion": null, "AverageCpc": 0.0, "AveragePosition": 0.0, "AverageCpm": 0.0, "Conversions": 0.0, "ConversionRate": null, "ConversionsQualified": 0.0, "Revenue": 0.0, "RevenuePerConversion": null, "RevenuePerAssist": null, "HistoricalQualityScore": 8.0, "HistoricalExpectedCtr": 2.0, "HistoricalAdRelevance": 3.0, "HistoricalLandingPageExperience": 3.0}, "emitted_at": 1679945714359} -{"stream":"ad_group_performance_report_monthly", "data": {"AccountId": 180278106, "CampaignId": 413444833, "AdGroupId": 1352400325389092, "TimePeriod": "2021-08-01", "CurrencyCode": "USD", "AdDistribution": "Search", "DeviceType": "Tablet", "Network": "Syndicated search partners", "DeliveredMatchType": "Broad", "DeviceOS": "Android", "TopVsOther": "Syndicated search partners - Top", "BidMatchType": "Broad", "Language": "English", "AccountName": "Daxtarity Inc.", "CampaignName": "Test 2", "CampaignType": "Search & content", "AdGroupName": "Airbyte", "AdGroupType": "Standard", "Impressions": 1, "Clicks": 0, "Ctr": 0.0, "Spend": 0.0, "CostPerConversion": null, "QualityScore": 0.0, "ExpectedCtr": "--", "AdRelevance": 0.0, "LandingPageExperience": 0.0, "PhoneImpressions": 0, "PhoneCalls": 0, "Ptr": null, "Assists": 0, "CostPerAssist": null, "CustomParameters": null, "FinalUrlSuffix": null, "ViewThroughConversions": 0, "AllCostPerConversion": null, "AllReturnOnAdSpend": null, "AllConversions": 0, "AllConversionRate": null, "AllRevenue": 0.0, "AllRevenuePerConversion": null, "AverageCpc": 0.0, "AveragePosition": 0.0, "AverageCpm": 0.0, "Conversions": 0.0, "ConversionRate": null, "ConversionsQualified": 0.0, "Revenue": 0.0, "RevenuePerConversion": null, "RevenuePerAssist": null, "HistoricalQualityScore": 8.0, "HistoricalExpectedCtr": 2.0, "HistoricalAdRelevance": 3.0, "HistoricalLandingPageExperience": 3.0}, "emitted_at": 1679945656700} -{"stream": "ad_performance_report_daily", "data": {"AccountId": 180278106, "CampaignId": 413444833, "AdGroupId": 1352400325389092, "AdId": 84525295496190, "TimePeriod": "2021-08-03", "CurrencyCode": "USD", "AdDistribution": "Search", "DeviceType": "Tablet", "Language": "English", "Network": "Syndicated search partners", "DeviceOS": "Android", "TopVsOther": "Syndicated search partners - Other", "BidMatchType": "Broad", "DeliveredMatchType": "Exact", "AccountName": "Daxtarity Inc.", "CampaignName": "Test 2", "CampaignType": "Search & content", "AdGroupName": "Airbyte", "Impressions": 1, "Clicks": 0, "Ctr": 0.0, "Spend": 0.0, "CostPerConversion": null, "DestinationUrl": null, "Assists": 0, "ReturnOnAdSpend": null, "CostPerAssist": null, "CustomParameters": null, "FinalAppUrl": null, "AdDescription": null, "AdDescription2": null, "ViewThroughConversions": 0, "ViewThroughConversionsQualified": null, "AllCostPerConversion": null, "AllReturnOnAdSpend": null, "Conversions": 0.0, "ConversionRate": null, "ConversionsQualified": 0.0, "AverageCpc": 0.0, "AveragePosition": 0.0, "AverageCpm": 0.0, "AllConversions": 0, "AllConversionRate": null, "AllRevenue": 0.0, "AllRevenuePerConversion": null, "Revenue": 0.0, "RevenuePerConversion": null, "RevenuePerAssist": null}, "emitted_at": 1679950716583} -{"stream": "ad_performance_report_weekly", "data": {"AccountId": 180278106, "CampaignId": 413444833, "AdGroupId": 1352400325389092, "AdId": 84525295496190, "TimePeriod": "2021-08-01", "CurrencyCode": "USD", "AdDistribution": "Search", "DeviceType": "Tablet", "Language": "English", "Network": "Syndicated search partners", "DeviceOS": "Android", "TopVsOther": "Syndicated search partners - Other", "BidMatchType": "Broad", "DeliveredMatchType": "Phrase", "AccountName": "Daxtarity Inc.", "CampaignName": "Test 2", "CampaignType": "Search & content", "AdGroupName": "Airbyte", "Impressions": 1, "Clicks": 0, "Ctr": 0.0, "Spend": 0.0, "CostPerConversion": null, "DestinationUrl": null, "Assists": 0, "ReturnOnAdSpend": null, "CostPerAssist": null, "CustomParameters": null, "FinalAppUrl": null, "AdDescription": null, "AdDescription2": null, "ViewThroughConversions": 0, "ViewThroughConversionsQualified": null, "AllCostPerConversion": null, "AllReturnOnAdSpend": null, "Conversions": 0.0, "ConversionRate": null, "ConversionsQualified": 0.0, "AverageCpc": 0.0, "AveragePosition": 0.0, "AverageCpm": 0.0, "AllConversions": 0, "AllConversionRate": null, "AllRevenue": 0.0, "AllRevenuePerConversion": null, "Revenue": 0.0, "RevenuePerConversion": null, "RevenuePerAssist": null}, "emitted_at": 1679950767960} -{"stream": "ad_performance_report_monthly", "data": {"AccountId": 180278106, "CampaignId": 413444833, "AdGroupId": 1352400325389092, "AdId": 84525295496190, "TimePeriod": "2021-08-01", "CurrencyCode": "USD", "AdDistribution": "Search", "DeviceType": "Tablet", "Language": "English", "Network": "Syndicated search partners", "DeviceOS": "Android", "TopVsOther": "Syndicated search partners - Other", "BidMatchType": "Broad", "DeliveredMatchType": "Phrase", "AccountName": "Daxtarity Inc.", "CampaignName": "Test 2", "CampaignType": "Search & content", "AdGroupName": "Airbyte", "Impressions": 1, "Clicks": 0, "Ctr": 0.0, "Spend": 0.0, "CostPerConversion": null, "DestinationUrl": null, "Assists": 0, "ReturnOnAdSpend": null, "CostPerAssist": null, "CustomParameters": null, "FinalAppUrl": null, "AdDescription": null, "AdDescription2": null, "ViewThroughConversions": 0, "ViewThroughConversionsQualified": null, "AllCostPerConversion": null, "AllReturnOnAdSpend": null, "Conversions": 0.0, "ConversionRate": null, "ConversionsQualified": 0.0, "AverageCpc": 0.0, "AveragePosition": 0.0, "AverageCpm": 0.0, "AllConversions": 0, "AllConversionRate": null, "AllRevenue": 0.0, "AllRevenuePerConversion": null, "Revenue": 0.0, "RevenuePerConversion": null, "RevenuePerAssist": null}, "emitted_at": 1679950813350} -{"stream":"budget_summary_report","data":{"AccountName":"Daxtarity Inc.","AccountNumber":"F149GKV5","AccountId":180278106,"CampaignName":"Test 2","CampaignId":413444833,"Date":"6/9/2021","MonthlyBudget":22.8,"DailySpend":0.71,"MonthToDateSpend":0.71},"emitted_at":1675189738185} -{"stream": "campaign_performance_report_daily", "data": {"AccountId": 180278106, "CampaignId": 413444833, "TimePeriod": "2021-06-09", "CurrencyCode": "USD", "AdDistribution": "Search", "DeviceType": "Computer", "Network": "Bing and Yahoo! search", "DeliveredMatchType": "Exact", "DeviceOS": "Windows", "TopVsOther": "Bing and Yahoo! search - Top", "BidMatchType": "Broad", "AccountName": "Daxtarity Inc.", "CampaignName": "Test 2", "CampaignType": "Search & content", "CampaignStatus": "Paused", "CampaignLabels": "integration-test-label;another label;what a new label", "Impressions": 1, "Clicks": 0, "Ctr": 0.0, "Spend": 0.0, "CostPerConversion": null, "QualityScore": 0.0, "AdRelevance": 0.0, "LandingPageExperience": 0.0, "PhoneImpressions": 0, "PhoneCalls": 0, "Ptr": null, "Assists": 0, "ReturnOnAdSpend": null, "CostPerAssist": null, "CustomParameters": null, "ViewThroughConversions": 0, "AllCostPerConversion": null, "AllReturnOnAdSpend": null, "AllConversions": 0, "AllConversionRate": null, "AllRevenue": 0.0, "AllRevenuePerConversion": null, "AverageCpc": 0.0, "AveragePosition": 0.0, "AverageCpm": 0.0, "Conversions": 0.0, "ConversionRate": null, "ConversionsQualified": 0.0, "LowQualityClicks": 0, "LowQualityClicksPercent": null, "LowQualityImpressions": 2, "LowQualitySophisticatedClicks": 0, "LowQualityConversions": 0, "LowQualityConversionRate": null, "Revenue": 0.0, "RevenuePerConversion": null, "RevenuePerAssist": null, "BudgetName": null, "BudgetStatus": null, "BudgetAssociationStatus": "Current", "HistoricalQualityScore": 8.0, "HistoricalExpectedCtr": 2.0, "HistoricalAdRelevance": 3.0, "HistoricalLandingPageExperience": 3.0}, "emitted_at": 1683583446923} -{"stream": "campaign_performance_report_weekly", "data": {"AccountId": 180278106, "CampaignId": 413444833, "TimePeriod": "2021-07-04", "CurrencyCode": "USD", "AdDistribution": "Search", "DeviceType": "Smartphone", "Network": "Syndicated search partners", "DeliveredMatchType": "Broad", "DeviceOS": "iOS", "TopVsOther": "Syndicated search partners - Other", "BidMatchType": "Broad", "AccountName": "Daxtarity Inc.", "CampaignName": "Test 2", "CampaignType": "Search & content", "CampaignStatus": "Paused", "CampaignLabels": "integration-test-label;another label;what a new label", "Impressions": 5, "Clicks": 0, "Ctr": 0.0, "Spend": 0.0, "CostPerConversion": null, "QualityScore": 0.0, "AdRelevance": 0.0, "LandingPageExperience": 0.0, "PhoneImpressions": 0, "PhoneCalls": 0, "Ptr": null, "Assists": 0, "ReturnOnAdSpend": null, "CostPerAssist": null, "CustomParameters": null, "ViewThroughConversions": 0, "AllCostPerConversion": null, "AllReturnOnAdSpend": null, "AllConversions": 0, "AllConversionRate": null, "AllRevenue": 0.0, "AllRevenuePerConversion": null, "AverageCpc": 0.0, "AveragePosition": 0.0, "AverageCpm": 0.0, "Conversions": 0.0, "ConversionRate": null, "ConversionsQualified": 0.0, "LowQualityClicks": 0, "LowQualityClicksPercent": null, "LowQualityImpressions": 0, "LowQualitySophisticatedClicks": 0, "LowQualityConversions": 0, "LowQualityConversionRate": null, "Revenue": 0.0, "RevenuePerConversion": null, "RevenuePerAssist": null, "BudgetName": null, "BudgetStatus": null, "BudgetAssociationStatus": "Current", "HistoricalQualityScore": 8.0, "HistoricalExpectedCtr": 2.0, "HistoricalAdRelevance": 3.0, "HistoricalLandingPageExperience": 3.0}, "emitted_at": 1683583674907} -{"stream": "campaign_performance_report_monthly", "data": {"AccountId": 180278106, "CampaignId": 413444833, "TimePeriod": "2021-06-01", "CurrencyCode": "USD", "AdDistribution": "Search", "DeviceType": "Computer", "Network": "Bing and Yahoo! search", "DeliveredMatchType": "Exact", "DeviceOS": "Windows", "TopVsOther": "Bing and Yahoo! search - Top", "BidMatchType": "Broad", "AccountName": "Daxtarity Inc.", "CampaignName": "Test 2", "CampaignType": "Search & content", "CampaignStatus": "Paused", "CampaignLabels": "integration-test-label;another label;what a new label", "Impressions": 11, "Clicks": 0, "Ctr": 0.0, "Spend": 0.0, "CostPerConversion": null, "QualityScore": 0.0, "AdRelevance": 0.0, "LandingPageExperience": 0.0, "PhoneImpressions": 0, "PhoneCalls": 0, "Ptr": null, "Assists": 0, "ReturnOnAdSpend": null, "CostPerAssist": null, "CustomParameters": null, "ViewThroughConversions": 0, "AllCostPerConversion": null, "AllReturnOnAdSpend": null, "AllConversions": 0, "AllConversionRate": null, "AllRevenue": 0.0, "AllRevenuePerConversion": null, "AverageCpc": 0.0, "AveragePosition": 0.0, "AverageCpm": 0.0, "Conversions": 0.0, "ConversionRate": null, "ConversionsQualified": 0.0, "LowQualityClicks": 0, "LowQualityClicksPercent": null, "LowQualityImpressions": 30, "LowQualitySophisticatedClicks": 0, "LowQualityConversions": 0, "LowQualityConversionRate": null, "Revenue": 0.0, "RevenuePerConversion": null, "RevenuePerAssist": null, "BudgetName": null, "BudgetStatus": null, "BudgetAssociationStatus": "Current", "HistoricalQualityScore": 8.0, "HistoricalExpectedCtr": 2.0, "HistoricalAdRelevance": 3.0, "HistoricalLandingPageExperience": 3.0}, "emitted_at": 1683583743890} -{"stream": "keyword_performance_report_daily", "data": {"AccountId": 180278106, "CampaignId": 413444833, "AdGroupId": 1352400325389092, "KeywordId": 84525593559629, "AdId": 84525295496190, "TimePeriod": "2021-08-03", "CurrencyCode": "USD", "DeliveredMatchType": "Broad", "AdDistribution": "Search", "DeviceType": "Smartphone", "Language": "English", "Network": "Syndicated search partners", "DeviceOS": "Android", "TopVsOther": "Syndicated search partners - Top", "BidMatchType": "Broad", "AccountName": "Daxtarity Inc.", "CampaignName": "Test 2", "AdGroupName": "Airbyte", "Keyword": "data integration tools", "KeywordStatus": "Active", "Impressions": 1, "Clicks": 0, "Ctr": 0.0, "CurrentMaxCpc": 0.11, "Spend": 0.0, "CostPerConversion": null, "QualityScore": 0.0, "ExpectedCtr": "--", "AdRelevance": 0.0, "LandingPageExperience": 0.0, "QualityImpact": 0.0, "Assists": 0, "ReturnOnAdSpend": null, "CostPerAssist": null, "CustomParameters": null, "FinalAppUrl": null, "Mainline1Bid": null, "MainlineBid": null, "FirstPageBid": null, "FinalUrlSuffix": null, "ViewThroughConversions": 0, "ViewThroughConversionsQualified": null, "AllCostPerConversion": null, "AllReturnOnAdSpend": null, "Conversions": 0.0, "ConversionRate": null, "ConversionsQualified": 0.0, "AverageCpc": 0.0, "AveragePosition": 0.0, "AverageCpm": 0.0, "AllConversions": 0, "AllConversionRate": null, "AllRevenue": 0.0, "AllRevenuePerConversion": null, "Revenue": 0.0, "RevenuePerConversion": null, "RevenuePerAssist": null, "HistoricalQualityScore": 8.0, "HistoricalExpectedCtr": 2.0, "HistoricalAdRelevance": 3.0, "HistoricalLandingPageExperience": 3.0}, "emitted_at": 1679951505600} -{"stream": "keyword_performance_report_weekly", "data": {"AccountId": 180278106, "CampaignId": 413444833, "AdGroupId": 1352400325389092, "KeywordId": 84525593559629, "AdId": 84525295496190, "TimePeriod": "2021-08-01", "CurrencyCode": "USD", "DeliveredMatchType": "Broad", "AdDistribution": "Search", "DeviceType": "Tablet", "Language": "English", "Network": "Syndicated search partners", "DeviceOS": "Android", "TopVsOther": "Syndicated search partners - Top", "BidMatchType": "Broad", "AccountName": "Daxtarity Inc.", "CampaignName": "Test 2", "AdGroupName": "Airbyte", "Keyword": "data integration tools", "KeywordStatus": "Active", "Impressions": 1, "Clicks": 0, "Ctr": 0.0, "CurrentMaxCpc": 0.11, "Spend": 0.0, "CostPerConversion": null, "QualityScore": 0.0, "ExpectedCtr": "--", "AdRelevance": 0.0, "LandingPageExperience": 0.0, "QualityImpact": 0.0, "Assists": 0, "ReturnOnAdSpend": null, "CostPerAssist": null, "CustomParameters": null, "FinalAppUrl": null, "Mainline1Bid": null, "MainlineBid": null, "FirstPageBid": null, "FinalUrlSuffix": null, "ViewThroughConversions": 0, "ViewThroughConversionsQualified": null, "AllCostPerConversion": null, "AllReturnOnAdSpend": null, "Conversions": 0.0, "ConversionRate": null, "ConversionsQualified": 0.0, "AverageCpc": 0.0, "AveragePosition": 0.0, "AverageCpm": 0.0, "AllConversions": 0, "AllConversionRate": null, "AllRevenue": 0.0, "AllRevenuePerConversion": null, "Revenue": 0.0, "RevenuePerConversion": null, "RevenuePerAssist": null}, "emitted_at": 1679951543951} -{"stream": "keyword_performance_report_monthly", "data": {"AccountId": 180278106, "CampaignId": 413444833, "AdGroupId": 1352400325389092, "KeywordId": 84525593559629, "AdId": 84525295496190, "TimePeriod": "2021-08-01", "CurrencyCode": "USD", "DeliveredMatchType": "Broad", "AdDistribution": "Search", "DeviceType": "Tablet", "Language": "English", "Network": "Syndicated search partners", "DeviceOS": "Android", "TopVsOther": "Syndicated search partners - Top", "BidMatchType": "Broad", "AccountName": "Daxtarity Inc.", "CampaignName": "Test 2", "AdGroupName": "Airbyte", "Keyword": "data integration tools", "KeywordStatus": "Active", "Impressions": 1, "Clicks": 0, "Ctr": 0.0, "CurrentMaxCpc": 0.11, "Spend": 0.0, "CostPerConversion": null, "QualityScore": 0.0, "ExpectedCtr": "--", "AdRelevance": 0.0, "LandingPageExperience": 0.0, "QualityImpact": 0.0, "Assists": 0, "ReturnOnAdSpend": null, "CostPerAssist": null, "CustomParameters": null, "FinalAppUrl": null, "Mainline1Bid": null, "MainlineBid": null, "FirstPageBid": null, "FinalUrlSuffix": null, "ViewThroughConversions": 0, "ViewThroughConversionsQualified": null, "AllCostPerConversion": null, "AllReturnOnAdSpend": null, "Conversions": 0.0, "ConversionRate": null, "ConversionsQualified": 0.0, "AverageCpc": 0.0, "AveragePosition": 0.0, "AverageCpm": 0.0, "AllConversions": 0, "AllConversionRate": null, "AllRevenue": 0.0, "AllRevenuePerConversion": null, "Revenue": 0.0, "RevenuePerConversion": null, "RevenuePerAssist": null}, "emitted_at": 1679951588461} -{"stream": "geographic_performance_report_daily", "data": {"AccountId": 180278106, "CampaignId": 413444833, "AdGroupId": 1352400325389092, "TimePeriod": "2021-06-09", "Country": "Australia", "CurrencyCode": "USD", "DeliveredMatchType": "Broad", "AdDistribution": "Search", "DeviceType": "Computer", "Language": "English", "Network": "Syndicated search partners", "DeviceOS": "Windows", "TopVsOther": "Syndicated search partners - Top", "BidMatchType": "Broad", "MetroArea": null, "State": "New South Wales", "City": null, "AdGroupName": "Airbyte", "Ctr": 0.0, "ProximityTargetLocation": null, "Radius": "0", "Assists": 0, "ReturnOnAdSpend": null, "CostPerAssist": null, "LocationType": "Physical location", "MostSpecificLocation": "2000", "AccountStatus": "Active", "CampaignStatus": "Paused", "AdGroupStatus": "Active", "County": null, "PostalCode": "2000", "LocationId": "122395", "BaseCampaignId": "413444833", "AllCostPerConversion": null, "AllReturnOnAdSpend": null, "ViewThroughConversions": 0, "Goal": null, "GoalType": null, "AbsoluteTopImpressionRatePercent": 0.0, "TopImpressionRatePercent": "100.00%", "AllConversionsQualified": "0.00", "ViewThroughConversionsQualified": null, "Neighborhood": null, "ViewThroughRevenue": "0.00", "CampaignType": "Search & content", "AssetGroupId": null, "AssetGroupName": null, "AssetGroupStatus": null, "Clicks": 0, "Spend": 0.0, "Impressions": 1, "CostPerConversion": null, "AccountName": "Daxtarity Inc.", "AccountNumber": "F149GKV5", "CampaignName": "Test 2", "Conversions": 0.0, "ConversionRate": null, "ConversionsQualified": 0.0, "AverageCpc": 0.0, "AveragePosition": 0.0, "AverageCpm": 0.0, "AllConversions": 0, "AllConversionRate": null, "AllRevenue": 0.0, "AllRevenuePerConversion": null, "Revenue": 0.0, "RevenuePerConversion": null, "RevenuePerAssist": null}, "emitted_at": 1695825623738} -{"stream": "geographic_performance_report_weekly", "data": {"AccountId": 180278106, "CampaignId": 413444833, "AdGroupId": 1352400325389092, "TimePeriod": "2021-06-06", "Country": "Australia", "CurrencyCode": "USD", "DeliveredMatchType": "Broad", "AdDistribution": "Search", "DeviceType": "Computer", "Language": "English", "Network": "Bing and Yahoo! search", "DeviceOS": "Windows", "TopVsOther": "Bing and Yahoo! search - Other", "BidMatchType": "Broad", "MetroArea": null, "State": "New South Wales", "City": null, "AdGroupName": "Airbyte", "Ctr": 0.0, "ProximityTargetLocation": null, "Radius": "0", "Assists": 0, "ReturnOnAdSpend": null, "CostPerAssist": null, "LocationType": "Physical location", "MostSpecificLocation": "New South Wales", "AccountStatus": "Active", "CampaignStatus": "Paused", "AdGroupStatus": "Active", "County": null, "PostalCode": null, "LocationId": "4048", "BaseCampaignId": "413444833", "AllCostPerConversion": null, "AllReturnOnAdSpend": null, "ViewThroughConversions": 0, "Goal": null, "GoalType": null, "AbsoluteTopImpressionRatePercent": 0.0, "TopImpressionRatePercent": "0.00%", "AllConversionsQualified": "0.00", "ViewThroughConversionsQualified": null, "Neighborhood": null, "ViewThroughRevenue": "0.00", "CampaignType": "Search & content", "AssetGroupId": null, "AssetGroupName": null, "AssetGroupStatus": null, "Clicks": 0, "Spend": 0.0, "Impressions": 1, "CostPerConversion": null, "AccountName": "Daxtarity Inc.", "AccountNumber": "F149GKV5", "CampaignName": "Test 2", "Conversions": 0.0, "ConversionRate": null, "ConversionsQualified": 0.0, "AverageCpc": 0.0, "AveragePosition": 0.0, "AverageCpm": 0.0, "AllConversions": 0, "AllConversionRate": null, "AllRevenue": 0.0, "AllRevenuePerConversion": null, "Revenue": 0.0, "RevenuePerConversion": null, "RevenuePerAssist": null}, "emitted_at": 1695825558741} -{"stream": "geographic_performance_report_monthly", "data": {"AccountId": 180278106, "CampaignId": 413444833, "AdGroupId": 1352400325389092, "TimePeriod": "2021-06-01", "Country": "United Arab Emirates", "CurrencyCode": "USD", "DeliveredMatchType": "Broad", "AdDistribution": "Search", "DeviceType": "Computer", "Language": "English", "Network": "Bing and Yahoo! search", "DeviceOS": "Windows", "TopVsOther": "Bing and Yahoo! search - Top", "BidMatchType": "Broad", "MetroArea": null, "State": null, "City": null, "AdGroupName": "Airbyte", "Ctr": 0.0, "ProximityTargetLocation": null, "Radius": "0", "Assists": 0, "ReturnOnAdSpend": null, "CostPerAssist": null, "LocationType": "Physical location", "MostSpecificLocation": "United Arab Emirates", "AccountStatus": "Active", "CampaignStatus": "Paused", "AdGroupStatus": "Active", "County": null, "PostalCode": null, "LocationId": "218", "BaseCampaignId": "413444833", "AllCostPerConversion": null, "AllReturnOnAdSpend": null, "ViewThroughConversions": 0, "Goal": null, "GoalType": null, "AbsoluteTopImpressionRatePercent": 0.0, "TopImpressionRatePercent": "100.00%", "AllConversionsQualified": "0.00", "ViewThroughConversionsQualified": null, "Neighborhood": null, "ViewThroughRevenue": "0.00", "CampaignType": "Search & content", "AssetGroupId": null, "AssetGroupName": null, "AssetGroupStatus": null, "Clicks": 0, "Spend": 0.0, "Impressions": 1, "CostPerConversion": null, "AccountName": "Daxtarity Inc.", "AccountNumber": "F149GKV5", "CampaignName": "Test 2", "Conversions": 0.0, "ConversionRate": null, "ConversionsQualified": 0.0, "AverageCpc": 0.0, "AveragePosition": 0.0, "AverageCpm": 0.0, "AllConversions": 0, "AllConversionRate": null, "AllRevenue": 0.0, "AllRevenuePerConversion": null, "Revenue": 0.0, "RevenuePerConversion": null, "RevenuePerAssist": null}, "emitted_at": 1695825503003} -{"stream":"age_gender_audience_report_daily","data":{"AccountId":180278106,"AgeGroup":"50-64","Gender":"Female","TimePeriod":"2021-07-29","AllConversions":0,"AccountName":"Daxtarity Inc.","AccountNumber":"F149GKV5","CampaignName":"Test 2","CampaignId":413444833,"AdGroupName":"Airbyte","AdGroupId":1352400325389092,"AdDistribution":"Search","Impressions":1,"Clicks":0,"Conversions":0.0,"Spend":0.0,"Revenue":0.0,"ExtendedCost":0.0,"Assists":0,"Language":"English","AccountStatus":"Active","CampaignStatus":"Paused","AdGroupStatus":"Active","BaseCampaignId":"413444833","AllRevenue":0.0,"ViewThroughConversions":0,"Goal":null,"GoalType":null,"AbsoluteTopImpressionRatePercent":"100.00%","TopImpressionRatePercent":"100.00%","ConversionsQualified":0.0,"AllConversionsQualified":0.0,"ViewThroughConversionsQualified":null,"ViewThroughRevenue":0.0},"emitted_at":1698144719344} -{"stream":"age_gender_audience_report_daily","data":{"AccountId":180278106,"AgeGroup":"65+","Gender":"Unknown","TimePeriod":"2021-06-13","AllConversions":0,"AccountName":"Daxtarity Inc.","AccountNumber":"F149GKV5","CampaignName":"Test 2","CampaignId":413444833,"AdGroupName":"Airbyte","AdGroupId":1352400325389092,"AdDistribution":"Search","Impressions":2,"Clicks":0,"Conversions":0.0,"Spend":0.0,"Revenue":0.0,"ExtendedCost":0.0,"Assists":0,"Language":"English","AccountStatus":"Active","CampaignStatus":"Paused","AdGroupStatus":"Active","BaseCampaignId":"413444833","AllRevenue":0.0,"ViewThroughConversions":0,"Goal":null,"GoalType":null,"AbsoluteTopImpressionRatePercent":"0.00%","TopImpressionRatePercent":"100.00%","ConversionsQualified":0.0,"AllConversionsQualified":0.0,"ViewThroughConversionsQualified":null,"ViewThroughRevenue":0.0},"emitted_at":1698144719348} -{"stream":"age_gender_audience_report_daily","data":{"AccountId":180278106,"AgeGroup":"65+","Gender":"Male","TimePeriod":"2021-06-09","AllConversions":0,"AccountName":"Daxtarity Inc.","AccountNumber":"F149GKV5","CampaignName":"Test 2","CampaignId":413444833,"AdGroupName":"Airbyte","AdGroupId":1352400325389092,"AdDistribution":"Search","Impressions":1,"Clicks":0,"Conversions":0.0,"Spend":0.0,"Revenue":0.0,"ExtendedCost":0.0,"Assists":0,"Language":"English","AccountStatus":"Active","CampaignStatus":"Paused","AdGroupStatus":"Active","BaseCampaignId":"413444833","AllRevenue":0.0,"ViewThroughConversions":0,"Goal":null,"GoalType":null,"AbsoluteTopImpressionRatePercent":"0.00%","TopImpressionRatePercent":"0.00%","ConversionsQualified":0.0,"AllConversionsQualified":0.0,"ViewThroughConversionsQualified":null,"ViewThroughRevenue":0.0},"emitted_at":1698144719350} -{"stream":"age_gender_audience_report_weekly","data":{"AccountId":180278106,"AgeGroup":"Unknown","Gender":"Female","TimePeriod":"2021-07-18","AllConversions":0,"AccountName":"Daxtarity Inc.","AccountNumber":"F149GKV5","CampaignName":"Test 2","CampaignId":413444833,"AdGroupName":"Airbyte","AdGroupId":1352400325389092,"AdDistribution":"Search","Impressions":1,"Clicks":0,"Conversions":0.0,"Spend":0.0,"Revenue":0.0,"ExtendedCost":0.0,"Assists":0,"Language":"English","AccountStatus":"Active","CampaignStatus":"Paused","AdGroupStatus":"Active","BaseCampaignId":"413444833","AllRevenue":0.0,"ViewThroughConversions":0,"Goal":null,"GoalType":null,"AbsoluteTopImpressionRatePercent":"0.00%","TopImpressionRatePercent":"0.00%","ConversionsQualified":0.0,"AllConversionsQualified":0.0,"ViewThroughConversionsQualified":null,"ViewThroughRevenue":0.0},"emitted_at":1698144728984} -{"stream":"age_gender_audience_report_weekly","data":{"AccountId":180278106,"AgeGroup":"18-24","Gender":"Unknown","TimePeriod":"2021-06-06","AllConversions":0,"AccountName":"Daxtarity Inc.","AccountNumber":"F149GKV5","CampaignName":"Test 2","CampaignId":413444833,"AdGroupName":"Airbyte","AdGroupId":1352400325389092,"AdDistribution":"Search","Impressions":5,"Clicks":0,"Conversions":0.0,"Spend":0.0,"Revenue":0.0,"ExtendedCost":0.0,"Assists":0,"Language":"English","AccountStatus":"Active","CampaignStatus":"Paused","AdGroupStatus":"Active","BaseCampaignId":"413444833","AllRevenue":0.0,"ViewThroughConversions":0,"Goal":null,"GoalType":null,"AbsoluteTopImpressionRatePercent":"20.00%","TopImpressionRatePercent":"80.00%","ConversionsQualified":0.0,"AllConversionsQualified":0.0,"ViewThroughConversionsQualified":null,"ViewThroughRevenue":0.0},"emitted_at":1698144728986} -{"stream":"age_gender_audience_report_weekly","data":{"AccountId":180278106,"AgeGroup":"50-64","Gender":"Male","TimePeriod":"2021-07-25","AllConversions":0,"AccountName":"Daxtarity Inc.","AccountNumber":"F149GKV5","CampaignName":"Test 2","CampaignId":413444833,"AdGroupName":"Airbyte","AdGroupId":1352400325389092,"AdDistribution":"Audience","Impressions":2,"Clicks":0,"Conversions":0.0,"Spend":0.0,"Revenue":0.0,"ExtendedCost":0.0,"Assists":0,"Language":"German","AccountStatus":"Active","CampaignStatus":"Paused","AdGroupStatus":"Active","BaseCampaignId":"413444833","AllRevenue":0.0,"ViewThroughConversions":0,"Goal":null,"GoalType":null,"AbsoluteTopImpressionRatePercent":"0.00%","TopImpressionRatePercent":"0.00%","ConversionsQualified":0.0,"AllConversionsQualified":0.0,"ViewThroughConversionsQualified":null,"ViewThroughRevenue":0.0},"emitted_at":1698144729135} -{"stream":"age_gender_audience_report_weekly","data":{"AccountId":180278106,"AgeGroup":"50-64","Gender":"Female","TimePeriod":"2021-06-06","AllConversions":0,"AccountName":"Daxtarity Inc.","AccountNumber":"F149GKV5","CampaignName":"Test 2","CampaignId":413444833,"AdGroupName":"Airbyte","AdGroupId":1352400325389092,"AdDistribution":"Search","Impressions":3,"Clicks":0,"Conversions":0.0,"Spend":0.0,"Revenue":0.0,"ExtendedCost":0.0,"Assists":0,"Language":"English","AccountStatus":"Active","CampaignStatus":"Paused","AdGroupStatus":"Active","BaseCampaignId":"413444833","AllRevenue":0.0,"ViewThroughConversions":0,"Goal":null,"GoalType":null,"AbsoluteTopImpressionRatePercent":"0.00%","TopImpressionRatePercent":"33.33%","ConversionsQualified":0.0,"AllConversionsQualified":0.0,"ViewThroughConversionsQualified":null,"ViewThroughRevenue":0.0},"emitted_at":1698144729136} -{"stream":"age_gender_audience_report_weekly","data":{"AccountId":180278106,"AgeGroup":"65+","Gender":"Unknown","TimePeriod":"2021-06-13","AllConversions":0,"AccountName":"Daxtarity Inc.","AccountNumber":"F149GKV5","CampaignName":"Test 2","CampaignId":413444833,"AdGroupName":"Airbyte","AdGroupId":1352400325389092,"AdDistribution":"Search","Impressions":2,"Clicks":0,"Conversions":0.0,"Spend":0.0,"Revenue":0.0,"ExtendedCost":0.0,"Assists":0,"Language":"English","AccountStatus":"Active","CampaignStatus":"Paused","AdGroupStatus":"Active","BaseCampaignId":"413444833","AllRevenue":0.0,"ViewThroughConversions":0,"Goal":null,"GoalType":null,"AbsoluteTopImpressionRatePercent":"0.00%","TopImpressionRatePercent":"100.00%","ConversionsQualified":0.0,"AllConversionsQualified":0.0,"ViewThroughConversionsQualified":null,"ViewThroughRevenue":0.0},"emitted_at":1698144729143} -{"stream":"age_gender_audience_report_weekly","data":{"AccountId":180278106,"AgeGroup":"65+","Gender":"Male","TimePeriod":"2021-07-11","AllConversions":0,"AccountName":"Daxtarity Inc.","AccountNumber":"F149GKV5","CampaignName":"Test 2","CampaignId":413444833,"AdGroupName":"Airbyte","AdGroupId":1352400325389092,"AdDistribution":"Search","Impressions":1,"Clicks":0,"Conversions":0.0,"Spend":0.0,"Revenue":0.0,"ExtendedCost":0.0,"Assists":0,"Language":"English","AccountStatus":"Active","CampaignStatus":"Paused","AdGroupStatus":"Active","BaseCampaignId":"413444833","AllRevenue":0.0,"ViewThroughConversions":0,"Goal":null,"GoalType":null,"AbsoluteTopImpressionRatePercent":"0.00%","TopImpressionRatePercent":"0.00%","ConversionsQualified":0.0,"AllConversionsQualified":0.0,"ViewThroughConversionsQualified":null,"ViewThroughRevenue":0.0},"emitted_at":1698144729150} -{"stream":"age_gender_audience_report_monthly","data":{"AccountId":180278106,"AgeGroup":"Unknown","Gender":"Unknown","TimePeriod":"2021-06-01","AllConversions":0,"AccountName":"Daxtarity Inc.","AccountNumber":"F149GKV5","CampaignName":"Test 2","CampaignId":413444833,"AdGroupName":"Airbyte","AdGroupId":1352400325389092,"AdDistribution":"Search","Impressions":8750,"Clicks":81,"Conversions":0.0,"Spend":14.76,"Revenue":0.0,"ExtendedCost":0.0,"Assists":0,"Language":"English","AccountStatus":"Active","CampaignStatus":"Paused","AdGroupStatus":"Active","BaseCampaignId":"413444833","AllRevenue":0.0,"ViewThroughConversions":0,"Goal":null,"GoalType":null,"AbsoluteTopImpressionRatePercent":"9.16%","TopImpressionRatePercent":"80.29%","ConversionsQualified":0.0,"AllConversionsQualified":0.0,"ViewThroughConversionsQualified":null,"ViewThroughRevenue":0.0},"emitted_at":1698144746067} -{"stream":"age_gender_audience_report_monthly","data":{"AccountId":180278106,"AgeGroup":"18-24","Gender":"Unknown","TimePeriod":"2021-08-01","AllConversions":0,"AccountName":"Daxtarity Inc.","AccountNumber":"F149GKV5","CampaignName":"Test 2","CampaignId":413444833,"AdGroupName":"Airbyte","AdGroupId":1352400325389092,"AdDistribution":"Search","Impressions":1,"Clicks":0,"Conversions":0.0,"Spend":0.0,"Revenue":0.0,"ExtendedCost":0.0,"Assists":0,"Language":"Thai","AccountStatus":"Active","CampaignStatus":"Paused","AdGroupStatus":"Active","BaseCampaignId":"413444833","AllRevenue":0.0,"ViewThroughConversions":0,"Goal":null,"GoalType":null,"AbsoluteTopImpressionRatePercent":"0.00%","TopImpressionRatePercent":"0.00%","ConversionsQualified":0.0,"AllConversionsQualified":0.0,"ViewThroughConversionsQualified":null,"ViewThroughRevenue":0.0},"emitted_at":1698144746150} -{"stream":"age_gender_audience_report_monthly","data":{"AccountId":180278106,"AgeGroup":"50-64","Gender":"Female","TimePeriod":"2021-07-01","AllConversions":0,"AccountName":"Daxtarity Inc.","AccountNumber":"F149GKV5","CampaignName":"Test 2","CampaignId":413444833,"AdGroupName":"Airbyte","AdGroupId":1352400325389092,"AdDistribution":"Search","Impressions":3,"Clicks":0,"Conversions":0.0,"Spend":0.0,"Revenue":0.0,"ExtendedCost":0.0,"Assists":0,"Language":"English","AccountStatus":"Active","CampaignStatus":"Paused","AdGroupStatus":"Active","BaseCampaignId":"413444833","AllRevenue":0.0,"ViewThroughConversions":0,"Goal":null,"GoalType":null,"AbsoluteTopImpressionRatePercent":"33.33%","TopImpressionRatePercent":"33.33%","ConversionsQualified":0.0,"AllConversionsQualified":0.0,"ViewThroughConversionsQualified":null,"ViewThroughRevenue":0.0},"emitted_at":1698144746216} -{"stream":"age_gender_audience_report_monthly","data":{"AccountId":180278106,"AgeGroup":"65+","Gender":"Unknown","TimePeriod":"2021-06-01","AllConversions":0,"AccountName":"Daxtarity Inc.","AccountNumber":"F149GKV5","CampaignName":"Test 2","CampaignId":413444833,"AdGroupName":"Airbyte","AdGroupId":1352400325389092,"AdDistribution":"Search","Impressions":2,"Clicks":0,"Conversions":0.0,"Spend":0.0,"Revenue":0.0,"ExtendedCost":0.0,"Assists":0,"Language":"English","AccountStatus":"Active","CampaignStatus":"Paused","AdGroupStatus":"Active","BaseCampaignId":"413444833","AllRevenue":0.0,"ViewThroughConversions":0,"Goal":null,"GoalType":null,"AbsoluteTopImpressionRatePercent":"0.00%","TopImpressionRatePercent":"100.00%","ConversionsQualified":0.0,"AllConversionsQualified":0.0,"ViewThroughConversionsQualified":null,"ViewThroughRevenue":0.0},"emitted_at":1698144746217} -{"stream":"age_gender_audience_report_monthly","data":{"AccountId":180278106,"AgeGroup":"65+","Gender":"Male","TimePeriod":"2021-07-01","AllConversions":0,"AccountName":"Daxtarity Inc.","AccountNumber":"F149GKV5","CampaignName":"Test 2","CampaignId":413444833,"AdGroupName":"Airbyte","AdGroupId":1352400325389092,"AdDistribution":"Search","Impressions":2,"Clicks":0,"Conversions":0.0,"Spend":0.0,"Revenue":0.0,"ExtendedCost":0.0,"Assists":0,"Language":"English","AccountStatus":"Active","CampaignStatus":"Paused","AdGroupStatus":"Active","BaseCampaignId":"413444833","AllRevenue":0.0,"ViewThroughConversions":0,"Goal":null,"GoalType":null,"AbsoluteTopImpressionRatePercent":"0.00%","TopImpressionRatePercent":"0.00%","ConversionsQualified":0.0,"AllConversionsQualified":0.0,"ViewThroughConversionsQualified":null,"ViewThroughRevenue":0.0},"emitted_at":1698144746220} +{"stream":"accounts","data":{"BillToCustomerId":251186883,"CurrencyCode":"USD","AccountFinancialStatus":"ClearFinancialStatus","Id":180278106,"Language":"English","LastModifiedByUserId":0,"LastModifiedTime":"2023-08-11T03:26:10.277000","Name":"Daxtarity Inc.","Number":"F149GKV5","ParentCustomerId":251186883,"PaymentMethodId":138188746,"PaymentMethodType":"CreditCard","PrimaryUserId":138225488,"AccountLifeCycleStatus":"Active","TimeStamp":"AAAAAH1yyMo=","TimeZone":"Arizona","PauseReason":null,"ForwardCompatibilityMap":null,"LinkedAgencies":null,"SalesHouseCustomerId":null,"TaxInformation":null,"BackUpPaymentInstrumentId":null,"BillingThresholdAmount":null,"BusinessAddress":{"City":"San Francisco","CountryCode":"US","Id":149004358,"Line1":"350 29th avenue","Line2":null,"Line3":null,"Line4":null,"PostalCode":"94121","StateOrProvince":"CA","TimeStamp":null,"BusinessName":"Daxtarity Inc."},"AutoTagType":"Inactive","SoldToPaymentInstrumentId":null,"AccountMode":"Expert"},"emitted_at":1698149762546} +{"stream":"account_performance_report_daily","data":{"AccountId":180278106,"TimePeriod":"2021-06-09","CurrencyCode":"USD","AdDistribution":"Search","DeviceType":"Smartphone","Network":"Bing and Yahoo! search","DeliveredMatchType":"Broad","DeviceOS":"Android","TopVsOther":"Bing and Yahoo! search - Top","BidMatchType":"Broad","AccountName":"Daxtarity Inc.","AccountNumber":"F149GKV5","PhoneImpressions":0,"PhoneCalls":0,"Clicks":0,"Ctr":0.0,"Spend":0.0,"Impressions":3,"CostPerConversion":null,"Ptr":null,"Assists":0,"ReturnOnAdSpend":null,"CostPerAssist":null,"AverageCpc":0.0,"AveragePosition":0.0,"AverageCpm":0.0,"Conversions":0.0,"ConversionRate":null,"ConversionsQualified":0.0,"LowQualityClicks":0,"LowQualityClicksPercent":null,"LowQualityImpressions":0,"LowQualitySophisticatedClicks":0,"LowQualityConversions":0,"LowQualityConversionRate":null,"Revenue":0.0,"RevenuePerConversion":null,"RevenuePerAssist":null},"emitted_at":1698149775393} +{"stream":"account_performance_report_weekly","data":{"AccountId":180278106,"TimePeriod":"2021-06-06","CurrencyCode":"USD","AdDistribution":"Search","DeviceType":"Computer","Network":"Bing and Yahoo! search","DeliveredMatchType":"Exact","DeviceOS":"Windows","TopVsOther":"Bing and Yahoo! search - Other","BidMatchType":"Broad","AccountName":"Daxtarity Inc.","AccountNumber":"F149GKV5","PhoneImpressions":0,"PhoneCalls":0,"Clicks":0,"Ctr":null,"Spend":0.0,"Impressions":0,"CostPerConversion":null,"Ptr":null,"Assists":0,"ReturnOnAdSpend":null,"CostPerAssist":null,"AverageCpc":0.0,"AveragePosition":0.0,"AverageCpm":0.0,"Conversions":0.0,"ConversionRate":null,"ConversionsQualified":0.0,"LowQualityClicks":0,"LowQualityClicksPercent":null,"LowQualityImpressions":7,"LowQualitySophisticatedClicks":0,"LowQualityConversions":0,"LowQualityConversionRate":null,"Revenue":0.0,"RevenuePerConversion":null,"RevenuePerAssist":null},"emitted_at":1698149785273} +{"stream":"account_performance_report_monthly","data":{"AccountId":180278106,"TimePeriod":"2021-06-01","CurrencyCode":"USD","AdDistribution":"Search","DeviceType":"Computer","Network":"Bing and Yahoo! search","DeliveredMatchType":"Exact","DeviceOS":"Windows","TopVsOther":"Bing and Yahoo! search - Top","BidMatchType":"Broad","AccountName":"Daxtarity Inc.","AccountNumber":"F149GKV5","PhoneImpressions":0,"PhoneCalls":0,"Clicks":0,"Ctr":0.0,"Spend":0.0,"Impressions":11,"CostPerConversion":null,"Ptr":null,"Assists":0,"ReturnOnAdSpend":null,"CostPerAssist":null,"AverageCpc":0.0,"AveragePosition":0.0,"AverageCpm":0.0,"Conversions":0.0,"ConversionRate":null,"ConversionsQualified":0.0,"LowQualityClicks":0,"LowQualityClicksPercent":null,"LowQualityImpressions":30,"LowQualitySophisticatedClicks":0,"LowQualityConversions":0,"LowQualityConversionRate":null,"Revenue":0.0,"RevenuePerConversion":null,"RevenuePerAssist":null},"emitted_at":1698149794340} +{"stream":"ad_group_performance_report_daily","data":{"AccountId":180278106,"CampaignId":413444833,"AdGroupId":1352400325389092,"TimePeriod":"2021-06-09","CurrencyCode":"USD","AdDistribution":"Search","DeviceType":"Computer","Network":"Bing and Yahoo! search","DeliveredMatchType":"Phrase","DeviceOS":"Windows","TopVsOther":"Bing and Yahoo! search - Top","BidMatchType":"Broad","Language":"English","AccountName":"Daxtarity Inc.","CampaignName":"Test 2","CampaignType":"Search & content","AdGroupName":"Airbyte","AdGroupType":"Standard","Impressions":1,"Clicks":0,"Ctr":0.0,"Spend":0.0,"CostPerConversion":null,"QualityScore":null,"ExpectedCtr":null,"AdRelevance":null,"LandingPageExperience":null,"PhoneImpressions":0,"PhoneCalls":0,"Ptr":null,"Assists":0,"CostPerAssist":null,"CustomParameters":null,"FinalUrlSuffix":null,"ViewThroughConversions":0,"AllCostPerConversion":null,"AllReturnOnAdSpend":null,"AllConversions":0,"AllConversionRate":null,"AllRevenue":0.0,"AllRevenuePerConversion":null,"AverageCpc":0.0,"AveragePosition":0.0,"AverageCpm":0.0,"Conversions":0.0,"ConversionRate":null,"ConversionsQualified":0.0,"Revenue":0.0,"RevenuePerConversion":null,"RevenuePerAssist":null,"HistoricalQualityScore":8.0,"HistoricalExpectedCtr":2.0,"HistoricalAdRelevance":3.0,"HistoricalLandingPageExperience":3.0},"emitted_at":1698149811393} +{"stream":"ad_group_performance_report_weekly","data":{"AccountId":180278106,"CampaignId":413444833,"AdGroupId":1352400325389092,"TimePeriod":"2021-06-06","CurrencyCode":"USD","AdDistribution":"Search","DeviceType":"Computer","Network":"Bing and Yahoo! search","DeliveredMatchType":"Phrase","DeviceOS":"Windows","TopVsOther":"Bing and Yahoo! search - Top","BidMatchType":"Broad","Language":"English","AccountName":"Daxtarity Inc.","CampaignName":"Test 2","CampaignType":"Search & content","AdGroupName":"Airbyte","AdGroupType":"Standard","Impressions":1,"Clicks":0,"Ctr":0.0,"Spend":0.0,"CostPerConversion":null,"QualityScore":null,"ExpectedCtr":null,"AdRelevance":null,"LandingPageExperience":null,"PhoneImpressions":0,"PhoneCalls":0,"Ptr":null,"Assists":0,"CostPerAssist":null,"CustomParameters":null,"FinalUrlSuffix":null,"ViewThroughConversions":0,"AllCostPerConversion":null,"AllReturnOnAdSpend":null,"AllConversions":0,"AllConversionRate":null,"AllRevenue":0.0,"AllRevenuePerConversion":null,"AverageCpc":0.0,"AveragePosition":0.0,"AverageCpm":0.0,"Conversions":0.0,"ConversionRate":null,"ConversionsQualified":0.0,"Revenue":0.0,"RevenuePerConversion":null,"RevenuePerAssist":null,"HistoricalQualityScore":8.0,"HistoricalExpectedCtr":2.0,"HistoricalAdRelevance":3.0,"HistoricalLandingPageExperience":3.0},"emitted_at":1698149821559} +{"stream":"ad_group_performance_report_monthly","data":{"AccountId":180278106,"CampaignId":413444833,"AdGroupId":1352400325389092,"TimePeriod":"2021-06-01","CurrencyCode":"USD","AdDistribution":"Search","DeviceType":"Computer","Network":"Bing and Yahoo! search","DeliveredMatchType":"Exact","DeviceOS":"Windows","TopVsOther":"Bing and Yahoo! search - Other","BidMatchType":"Broad","Language":"German","AccountName":"Daxtarity Inc.","CampaignName":"Test 2","CampaignType":"Search & content","AdGroupName":"Airbyte","AdGroupType":"Standard","Impressions":1,"Clicks":0,"Ctr":0.0,"Spend":0.0,"CostPerConversion":null,"QualityScore":null,"ExpectedCtr":null,"AdRelevance":null,"LandingPageExperience":null,"PhoneImpressions":0,"PhoneCalls":0,"Ptr":null,"Assists":0,"CostPerAssist":null,"CustomParameters":null,"FinalUrlSuffix":null,"ViewThroughConversions":0,"AllCostPerConversion":null,"AllReturnOnAdSpend":null,"AllConversions":0,"AllConversionRate":null,"AllRevenue":0.0,"AllRevenuePerConversion":null,"AverageCpc":0.0,"AveragePosition":0.0,"AverageCpm":0.0,"Conversions":0.0,"ConversionRate":null,"ConversionsQualified":0.0,"Revenue":0.0,"RevenuePerConversion":null,"RevenuePerAssist":null,"HistoricalQualityScore":8.0,"HistoricalExpectedCtr":2.0,"HistoricalAdRelevance":3.0,"HistoricalLandingPageExperience":3.0},"emitted_at":1698149830886} +{"stream":"ad_performance_report_daily","data":{"AccountId":180278106,"CampaignId":413444833,"AdGroupId":1352400325389092,"AdId":84525295496190,"TimePeriod":"2021-06-09","CurrencyCode":"USD","AdDistribution":"Search","DeviceType":"Computer","Language":"English","Network":"Bing and Yahoo! search","DeviceOS":"Unknown","TopVsOther":"Bing and Yahoo! search - Other","BidMatchType":"Broad","DeliveredMatchType":"Broad","AccountName":"Daxtarity Inc.","CampaignName":"Test 2","CampaignType":"Search & content","AdGroupName":"Airbyte","Impressions":2,"Clicks":0,"Ctr":0.0,"Spend":0.0,"CostPerConversion":null,"DestinationUrl":null,"Assists":0,"ReturnOnAdSpend":null,"CostPerAssist":null,"CustomParameters":null,"FinalAppUrl":null,"AdDescription":null,"AdDescription2":null,"ViewThroughConversions":0,"ViewThroughConversionsQualified":null,"AllCostPerConversion":null,"AllReturnOnAdSpend":null,"Conversions":0.0,"ConversionRate":null,"ConversionsQualified":0.0,"AverageCpc":0.0,"AveragePosition":0.0,"AverageCpm":0.0,"AllConversions":0,"AllConversionRate":null,"AllRevenue":0.0,"AllRevenuePerConversion":null,"Revenue":0.0,"RevenuePerConversion":null,"RevenuePerAssist":null},"emitted_at":1698149848147} +{"stream":"ad_performance_report_weekly","data":{"AccountId":180278106,"CampaignId":413444833,"AdGroupId":1352400325389092,"AdId":84525295496190,"TimePeriod":"2021-06-06","CurrencyCode":"USD","AdDistribution":"Search","DeviceType":"Computer","Language":"German","Network":"Syndicated search partners","DeviceOS":"Unknown","TopVsOther":"Syndicated search partners - Other","BidMatchType":"Broad","DeliveredMatchType":"Broad","AccountName":"Daxtarity Inc.","CampaignName":"Test 2","CampaignType":"Search & content","AdGroupName":"Airbyte","Impressions":1,"Clicks":0,"Ctr":0.0,"Spend":0.0,"CostPerConversion":null,"DestinationUrl":null,"Assists":0,"ReturnOnAdSpend":null,"CostPerAssist":null,"CustomParameters":null,"FinalAppUrl":null,"AdDescription":null,"AdDescription2":null,"ViewThroughConversions":0,"ViewThroughConversionsQualified":null,"AllCostPerConversion":null,"AllReturnOnAdSpend":null,"Conversions":0.0,"ConversionRate":null,"ConversionsQualified":0.0,"AverageCpc":0.0,"AveragePosition":0.0,"AverageCpm":0.0,"AllConversions":0,"AllConversionRate":null,"AllRevenue":0.0,"AllRevenuePerConversion":null,"Revenue":0.0,"RevenuePerConversion":null,"RevenuePerAssist":null},"emitted_at":1698149858191} +{"stream":"ad_performance_report_monthly","data":{"AccountId":180278106,"CampaignId":413444833,"AdGroupId":1352400325389092,"AdId":84525295496190,"TimePeriod":"2021-06-01","CurrencyCode":"USD","AdDistribution":"Search","DeviceType":"Computer","Language":"German","Network":"Bing and Yahoo! search","DeviceOS":"Windows","TopVsOther":"Bing and Yahoo! search - Other","BidMatchType":"Broad","DeliveredMatchType":"Exact","AccountName":"Daxtarity Inc.","CampaignName":"Test 2","CampaignType":"Search & content","AdGroupName":"Airbyte","Impressions":1,"Clicks":0,"Ctr":0.0,"Spend":0.0,"CostPerConversion":null,"DestinationUrl":null,"Assists":0,"ReturnOnAdSpend":null,"CostPerAssist":null,"CustomParameters":null,"FinalAppUrl":null,"AdDescription":null,"AdDescription2":null,"ViewThroughConversions":0,"ViewThroughConversionsQualified":null,"AllCostPerConversion":null,"AllReturnOnAdSpend":null,"Conversions":0.0,"ConversionRate":null,"ConversionsQualified":0.0,"AverageCpc":0.0,"AveragePosition":0.0,"AverageCpm":0.0,"AllConversions":0,"AllConversionRate":null,"AllRevenue":0.0,"AllRevenuePerConversion":null,"Revenue":0.0,"RevenuePerConversion":null,"RevenuePerAssist":null},"emitted_at":1698149867383} +{"stream":"budget_summary_report","data":{"AccountName":"Daxtarity Inc.","AccountNumber":"F149GKV5","AccountId":180278106,"CampaignName":"Test 2","CampaignId":413444833,"Date":"6/10/2021","MonthlyBudget":22.8,"DailySpend":0.74,"MonthToDateSpend":1.45},"emitted_at":1698149948646} +{"stream":"campaign_performance_report_daily","data":{"AccountId":180278106,"CampaignId":413444833,"TimePeriod":"2021-06-09","CurrencyCode":"USD","AdDistribution":"Search","DeviceType":"Computer","Network":"Bing and Yahoo! search","DeliveredMatchType":"Exact","DeviceOS":"Windows","TopVsOther":"Bing and Yahoo! search - Other","BidMatchType":"Broad","AccountName":"Daxtarity Inc.","CampaignName":"Test 2","CampaignType":"Search & content","CampaignStatus":"Paused","CampaignLabels":"integration-test-label;another label;what a new label","Impressions":0,"Clicks":0,"Ctr":null,"Spend":0.0,"CostPerConversion":null,"QualityScore":null,"AdRelevance":null,"LandingPageExperience":null,"PhoneImpressions":0,"PhoneCalls":0,"Ptr":null,"Assists":0,"ReturnOnAdSpend":null,"CostPerAssist":null,"CustomParameters":null,"ViewThroughConversions":0,"AllCostPerConversion":null,"AllReturnOnAdSpend":null,"AllConversions":0,"AllConversionRate":null,"AllRevenue":0.0,"AllRevenuePerConversion":null,"AverageCpc":0.0,"AveragePosition":0.0,"AverageCpm":0.0,"Conversions":0.0,"ConversionRate":null,"ConversionsQualified":0.0,"LowQualityClicks":0,"LowQualityClicksPercent":null,"LowQualityImpressions":6,"LowQualitySophisticatedClicks":0,"LowQualityConversions":0,"LowQualityConversionRate":null,"Revenue":0.0,"RevenuePerConversion":null,"RevenuePerAssist":null,"BudgetName":null,"BudgetStatus":null,"BudgetAssociationStatus":"Current","HistoricalQualityScore":8.0,"HistoricalExpectedCtr":2.0,"HistoricalAdRelevance":3.0,"HistoricalLandingPageExperience":3.0},"emitted_at":1698149965377} +{"stream":"campaign_performance_report_weekly","data":{"AccountId":180278106,"CampaignId":413444833,"TimePeriod":"2021-06-06","CurrencyCode":"USD","AdDistribution":"Search","DeviceType":"Computer","Network":"Bing and Yahoo! search","DeliveredMatchType":"Phrase","DeviceOS":"Unknown","TopVsOther":"Bing and Yahoo! search - Top","BidMatchType":"Broad","AccountName":"Daxtarity Inc.","CampaignName":"Test 2","CampaignType":"Search & content","CampaignStatus":"Paused","CampaignLabels":"integration-test-label;another label;what a new label","Impressions":0,"Clicks":0,"Ctr":null,"Spend":0.0,"CostPerConversion":null,"QualityScore":null,"AdRelevance":null,"LandingPageExperience":null,"PhoneImpressions":0,"PhoneCalls":0,"Ptr":null,"Assists":0,"ReturnOnAdSpend":null,"CostPerAssist":null,"CustomParameters":null,"ViewThroughConversions":0,"AllCostPerConversion":null,"AllReturnOnAdSpend":null,"AllConversions":0,"AllConversionRate":null,"AllRevenue":0.0,"AllRevenuePerConversion":null,"AverageCpc":0.0,"AveragePosition":0.0,"AverageCpm":0.0,"Conversions":0.0,"ConversionRate":null,"ConversionsQualified":0.0,"LowQualityClicks":0,"LowQualityClicksPercent":null,"LowQualityImpressions":3,"LowQualitySophisticatedClicks":0,"LowQualityConversions":0,"LowQualityConversionRate":null,"Revenue":0.0,"RevenuePerConversion":null,"RevenuePerAssist":null,"BudgetName":null,"BudgetStatus":null,"BudgetAssociationStatus":"Current","HistoricalQualityScore":8.0,"HistoricalExpectedCtr":2.0,"HistoricalAdRelevance":3.0,"HistoricalLandingPageExperience":3.0},"emitted_at":1698149976036} +{"stream":"campaign_performance_report_monthly","data":{"AccountId":180278106,"CampaignId":413444833,"TimePeriod":"2021-06-01","CurrencyCode":"USD","AdDistribution":"Search","DeviceType":"Computer","Network":"Bing and Yahoo! search","DeliveredMatchType":"Exact","DeviceOS":"Windows","TopVsOther":"Bing and Yahoo! search - Top","BidMatchType":"Broad","AccountName":"Daxtarity Inc.","CampaignName":"Test 2","CampaignType":"Search & content","CampaignStatus":"Paused","CampaignLabels":"integration-test-label;another label;what a new label","Impressions":11,"Clicks":0,"Ctr":0.0,"Spend":0.0,"CostPerConversion":null,"QualityScore":null,"AdRelevance":null,"LandingPageExperience":null,"PhoneImpressions":0,"PhoneCalls":0,"Ptr":null,"Assists":0,"ReturnOnAdSpend":null,"CostPerAssist":null,"CustomParameters":null,"ViewThroughConversions":0,"AllCostPerConversion":null,"AllReturnOnAdSpend":null,"AllConversions":0,"AllConversionRate":null,"AllRevenue":0.0,"AllRevenuePerConversion":null,"AverageCpc":0.0,"AveragePosition":0.0,"AverageCpm":0.0,"Conversions":0.0,"ConversionRate":null,"ConversionsQualified":0.0,"LowQualityClicks":0,"LowQualityClicksPercent":null,"LowQualityImpressions":30,"LowQualitySophisticatedClicks":0,"LowQualityConversions":0,"LowQualityConversionRate":null,"Revenue":0.0,"RevenuePerConversion":null,"RevenuePerAssist":null,"BudgetName":null,"BudgetStatus":null,"BudgetAssociationStatus":"Current","HistoricalQualityScore":8.0,"HistoricalExpectedCtr":2.0,"HistoricalAdRelevance":3.0,"HistoricalLandingPageExperience":3.0},"emitted_at":1698149985116} +{"stream":"keyword_performance_report_daily","data":{"AccountId":180278106,"CampaignId":413444833,"AdGroupId":1352400325389092,"KeywordId":84525593559627,"AdId":84525295496190,"TimePeriod":"2021-06-14","CurrencyCode":"USD","DeliveredMatchType":"Broad","AdDistribution":"Search","DeviceType":"Smartphone","Language":"English","Network":"Syndicated search partners","DeviceOS":"Android","TopVsOther":"Syndicated search partners - Top","BidMatchType":"Broad","AccountName":"Daxtarity Inc.","CampaignName":"Test 2","AdGroupName":"Airbyte","Keyword":"big data integration tools","KeywordStatus":"Active","Impressions":1,"Clicks":0,"Ctr":0.0,"CurrentMaxCpc":0.11,"Spend":0.0,"CostPerConversion":null,"QualityScore":null,"ExpectedCtr":null,"AdRelevance":null,"LandingPageExperience":null,"QualityImpact":0.0,"Assists":0,"ReturnOnAdSpend":null,"CostPerAssist":null,"CustomParameters":null,"FinalAppUrl":null,"Mainline1Bid":null,"MainlineBid":null,"FirstPageBid":null,"FinalUrlSuffix":null,"ViewThroughConversions":0,"ViewThroughConversionsQualified":null,"AllCostPerConversion":null,"AllReturnOnAdSpend":null,"Conversions":0.0,"ConversionRate":null,"ConversionsQualified":0.0,"AverageCpc":0.0,"AveragePosition":0.0,"AverageCpm":0.0,"AllConversions":0,"AllConversionRate":null,"AllRevenue":0.0,"AllRevenuePerConversion":null,"Revenue":0.0,"RevenuePerConversion":null,"RevenuePerAssist":null,"HistoricalQualityScore":7.0,"HistoricalExpectedCtr":2.0,"HistoricalAdRelevance":2.0,"HistoricalLandingPageExperience":3.0},"emitted_at":1698150002220} +{"stream":"keyword_performance_report_weekly","data":{"AccountId":180278106,"CampaignId":413444833,"AdGroupId":1352400325389092,"KeywordId":84525593559627,"AdId":84525295496190,"TimePeriod":"2021-06-13","CurrencyCode":"USD","DeliveredMatchType":"Broad","AdDistribution":"Search","DeviceType":"Smartphone","Language":"English","Network":"Syndicated search partners","DeviceOS":"iOS","TopVsOther":"Syndicated search partners - Top","BidMatchType":"Broad","AccountName":"Daxtarity Inc.","CampaignName":"Test 2","AdGroupName":"Airbyte","Keyword":"big data integration tools","KeywordStatus":"Active","Impressions":10,"Clicks":0,"Ctr":0.0,"CurrentMaxCpc":0.11,"Spend":0.0,"CostPerConversion":null,"QualityScore":null,"ExpectedCtr":null,"AdRelevance":null,"LandingPageExperience":null,"QualityImpact":0.0,"Assists":0,"ReturnOnAdSpend":null,"CostPerAssist":null,"CustomParameters":null,"FinalAppUrl":null,"Mainline1Bid":null,"MainlineBid":null,"FirstPageBid":null,"FinalUrlSuffix":null,"ViewThroughConversions":0,"ViewThroughConversionsQualified":null,"AllCostPerConversion":null,"AllReturnOnAdSpend":null,"Conversions":0.0,"ConversionRate":null,"ConversionsQualified":0.0,"AverageCpc":0.0,"AveragePosition":0.0,"AverageCpm":0.0,"AllConversions":0,"AllConversionRate":null,"AllRevenue":0.0,"AllRevenuePerConversion":null,"Revenue":0.0,"RevenuePerConversion":null,"RevenuePerAssist":null},"emitted_at":1698150013239} +{"stream":"keyword_performance_report_monthly","data":{"AccountId":180278106,"CampaignId":413444833,"AdGroupId":1352400325389092,"KeywordId":84525593559629,"AdId":84525295496190,"TimePeriod":"2021-08-01","CurrencyCode":"USD","DeliveredMatchType":"Broad","AdDistribution":"Search","DeviceType":"Tablet","Language":"English","Network":"Syndicated search partners","DeviceOS":"Android","TopVsOther":"Syndicated search partners - Top","BidMatchType":"Broad","AccountName":"Daxtarity Inc.","CampaignName":"Test 2","AdGroupName":"Airbyte","Keyword":"data integration tools","KeywordStatus":"Active","Impressions":1,"Clicks":0,"Ctr":0.0,"CurrentMaxCpc":0.11,"Spend":0.0,"CostPerConversion":null,"QualityScore":null,"ExpectedCtr":null,"AdRelevance":null,"LandingPageExperience":null,"QualityImpact":0.0,"Assists":0,"ReturnOnAdSpend":null,"CostPerAssist":null,"CustomParameters":null,"FinalAppUrl":null,"Mainline1Bid":null,"MainlineBid":null,"FirstPageBid":null,"FinalUrlSuffix":null,"ViewThroughConversions":0,"ViewThroughConversionsQualified":null,"AllCostPerConversion":null,"AllReturnOnAdSpend":null,"Conversions":0.0,"ConversionRate":null,"ConversionsQualified":0.0,"AverageCpc":0.0,"AveragePosition":0.0,"AverageCpm":0.0,"AllConversions":0,"AllConversionRate":null,"AllRevenue":0.0,"AllRevenuePerConversion":null,"Revenue":0.0,"RevenuePerConversion":null,"RevenuePerAssist":null},"emitted_at":1698150022983} +{"stream":"geographic_performance_report_daily","data":{"AccountId":180278106,"CampaignId":413444833,"AdGroupId":1352400325389092,"TimePeriod":"2021-06-09","Country":"United Kingdom","CurrencyCode":"USD","DeliveredMatchType":"Broad","AdDistribution":"Search","DeviceType":"Computer","Language":"English","Network":"Syndicated search partners","DeviceOS":"Unknown","TopVsOther":"Syndicated search partners - Top","BidMatchType":"Broad","MetroArea":"London","State":"England","City":"London","AdGroupName":"Airbyte","Ctr":0.0,"ProximityTargetLocation":null,"Radius":"0","Assists":0,"ReturnOnAdSpend":null,"CostPerAssist":null,"LocationType":"Physical location","MostSpecificLocation":"SE13","AccountStatus":"Active","CampaignStatus":"Paused","AdGroupStatus":"Active","County":null,"PostalCode":"SE13","LocationId":"132401","BaseCampaignId":"413444833","AllCostPerConversion":null,"AllReturnOnAdSpend":null,"ViewThroughConversions":0,"Goal":null,"GoalType":null,"AbsoluteTopImpressionRatePercent":0.0,"TopImpressionRatePercent":"100.00","AllConversionsQualified":"0.00","ViewThroughConversionsQualified":null,"Neighborhood":null,"ViewThroughRevenue":"0.00","CampaignType":"Search & content","AssetGroupId":null,"AssetGroupName":null,"AssetGroupStatus":null,"Clicks":0,"Spend":0.0,"Impressions":1,"CostPerConversion":null,"AccountName":"Daxtarity Inc.","AccountNumber":"F149GKV5","CampaignName":"Test 2","Conversions":0.0,"ConversionRate":null,"ConversionsQualified":0.0,"AverageCpc":0.0,"AveragePosition":0.0,"AverageCpm":0.0,"AllConversions":0,"AllConversionRate":null,"AllRevenue":0.0,"AllRevenuePerConversion":null,"Revenue":0.0,"RevenuePerConversion":null,"RevenuePerAssist":null},"emitted_at":1698153346893} +{"stream":"geographic_performance_report_weekly","data":{"AccountId":180278106,"CampaignId":413444833,"AdGroupId":1352400325389092,"TimePeriod":"2021-06-06","Country":"Australia","CurrencyCode":"USD","DeliveredMatchType":"Broad","AdDistribution":"Search","DeviceType":"Computer","Language":"English","Network":"Bing and Yahoo! search","DeviceOS":"Windows","TopVsOther":"Bing and Yahoo! search - Other","BidMatchType":"Broad","MetroArea":null,"State":"New South Wales","City":null,"AdGroupName":"Airbyte","Ctr":0.0,"ProximityTargetLocation":null,"Radius":"0","Assists":0,"ReturnOnAdSpend":null,"CostPerAssist":null,"LocationType":"Physical location","MostSpecificLocation":"New South Wales","AccountStatus":"Active","CampaignStatus":"Paused","AdGroupStatus":"Active","County":null,"PostalCode":null,"LocationId":"4048","BaseCampaignId":"413444833","AllCostPerConversion":null,"AllReturnOnAdSpend":null,"ViewThroughConversions":0,"Goal":null,"GoalType":null,"AbsoluteTopImpressionRatePercent":0.0,"TopImpressionRatePercent":"0.00","AllConversionsQualified":"0.00","ViewThroughConversionsQualified":null,"Neighborhood":null,"ViewThroughRevenue":"0.00","CampaignType":"Search & content","AssetGroupId":null,"AssetGroupName":null,"AssetGroupStatus":null,"Clicks":0,"Spend":0.0,"Impressions":1,"CostPerConversion":null,"AccountName":"Daxtarity Inc.","AccountNumber":"F149GKV5","CampaignName":"Test 2","Conversions":0.0,"ConversionRate":null,"ConversionsQualified":0.0,"AverageCpc":0.0,"AveragePosition":0.0,"AverageCpm":0.0,"AllConversions":0,"AllConversionRate":null,"AllRevenue":0.0,"AllRevenuePerConversion":null,"Revenue":0.0,"RevenuePerConversion":null,"RevenuePerAssist":null},"emitted_at":1698149877247} +{"stream":"geographic_performance_report_monthly","data":{"AccountId":180278106,"CampaignId":413444833,"AdGroupId":1352400325389092,"TimePeriod":"2021-06-01","Country":"United Arab Emirates","CurrencyCode":"USD","DeliveredMatchType":"Broad","AdDistribution":"Search","DeviceType":"Computer","Language":"English","Network":"Bing and Yahoo! search","DeviceOS":"Windows","TopVsOther":"Bing and Yahoo! search - Other","BidMatchType":"Broad","MetroArea":null,"State":null,"City":null,"AdGroupName":"Airbyte","Ctr":0.0,"ProximityTargetLocation":null,"Radius":"0","Assists":0,"ReturnOnAdSpend":null,"CostPerAssist":null,"LocationType":"Physical location","MostSpecificLocation":"United Arab Emirates","AccountStatus":"Active","CampaignStatus":"Paused","AdGroupStatus":"Active","County":null,"PostalCode":null,"LocationId":"218","BaseCampaignId":"413444833","AllCostPerConversion":null,"AllReturnOnAdSpend":null,"ViewThroughConversions":0,"Goal":null,"GoalType":null,"AbsoluteTopImpressionRatePercent":0.0,"TopImpressionRatePercent":"0.00","AllConversionsQualified":"0.00","ViewThroughConversionsQualified":null,"Neighborhood":null,"ViewThroughRevenue":"0.00","CampaignType":"Search & content","AssetGroupId":null,"AssetGroupName":null,"AssetGroupStatus":null,"Clicks":0,"Spend":0.0,"Impressions":1,"CostPerConversion":null,"AccountName":"Daxtarity Inc.","AccountNumber":"F149GKV5","CampaignName":"Test 2","Conversions":0.0,"ConversionRate":null,"ConversionsQualified":0.0,"AverageCpc":0.0,"AveragePosition":0.0,"AverageCpm":0.0,"AllConversions":0,"AllConversionRate":null,"AllRevenue":0.0,"AllRevenuePerConversion":null,"Revenue":0.0,"RevenuePerConversion":null,"RevenuePerAssist":null},"emitted_at":1698149915741} +{"stream":"age_gender_audience_report_daily","data":{"AccountId":180278106,"AgeGroup":"Unknown","Gender":"Unknown","TimePeriod":"2021-06-09","AllConversions":0,"AccountName":"Daxtarity Inc.","AccountNumber":"F149GKV5","CampaignName":"Test 2","CampaignId":413444833,"AdGroupName":"Airbyte","AdGroupId":1352400325389092,"AdDistribution":"Search","Impressions":250,"Clicks":1,"Conversions":0.0,"Spend":0.3,"Revenue":0.0,"ExtendedCost":0.0,"Assists":0,"Language":"English","AccountStatus":"Active","CampaignStatus":"Paused","AdGroupStatus":"Active","BaseCampaignId":"413444833","AllRevenue":0.0,"ViewThroughConversions":0,"Goal":null,"GoalType":null,"AbsoluteTopImpressionRatePercent":9.64,"TopImpressionRatePercent":91.16,"ConversionsQualified":0.0,"AllConversionsQualified":0.0,"ViewThroughConversionsQualified":null,"ViewThroughRevenue":0.0},"emitted_at":1698150031605} +{"stream":"age_gender_audience_report_weekly","data":{"AccountId":180278106,"AgeGroup":"Unknown","Gender":"Female","TimePeriod":"2021-07-18","AllConversions":0,"AccountName":"Daxtarity Inc.","AccountNumber":"F149GKV5","CampaignName":"Test 2","CampaignId":413444833,"AdGroupName":"Airbyte","AdGroupId":1352400325389092,"AdDistribution":"Search","Impressions":1,"Clicks":0,"Conversions":0.0,"Spend":0.0,"Revenue":0.0,"ExtendedCost":0.0,"Assists":0,"Language":"English","AccountStatus":"Active","CampaignStatus":"Paused","AdGroupStatus":"Active","BaseCampaignId":"413444833","AllRevenue":0.0,"ViewThroughConversions":0,"Goal":null,"GoalType":null,"AbsoluteTopImpressionRatePercent":0.00,"TopImpressionRatePercent":0.0,"ConversionsQualified":0.0,"AllConversionsQualified":0.0,"ViewThroughConversionsQualified":null,"ViewThroughRevenue":0.0},"emitted_at":1698144728984} +{"stream":"age_gender_audience_report_weekly","data":{"AccountId":180278106,"AgeGroup":"18-24","Gender":"Unknown","TimePeriod":"2021-06-06","AllConversions":0,"AccountName":"Daxtarity Inc.","AccountNumber":"F149GKV5","CampaignName":"Test 2","CampaignId":413444833,"AdGroupName":"Airbyte","AdGroupId":1352400325389092,"AdDistribution":"Search","Impressions":5,"Clicks":0,"Conversions":0.0,"Spend":0.0,"Revenue":0.0,"ExtendedCost":0.0,"Assists":0,"Language":"English","AccountStatus":"Active","CampaignStatus":"Paused","AdGroupStatus":"Active","BaseCampaignId":"413444833","AllRevenue":0.0,"ViewThroughConversions":0,"Goal":null,"GoalType":null,"AbsoluteTopImpressionRatePercent":20.00,"TopImpressionRatePercent":80.0,"ConversionsQualified":0.0,"AllConversionsQualified":0.0,"ViewThroughConversionsQualified":null,"ViewThroughRevenue":0.0},"emitted_at":1698144728986} +{"stream":"age_gender_audience_report_monthly","data":{"AccountId":180278106,"AgeGroup":"50-64","Gender":"Female","TimePeriod":"2021-07-01","AllConversions":0,"AccountName":"Daxtarity Inc.","AccountNumber":"F149GKV5","CampaignName":"Test 2","CampaignId":413444833,"AdGroupName":"Airbyte","AdGroupId":1352400325389092,"AdDistribution":"Search","Impressions":3,"Clicks":0,"Conversions":0.0,"Spend":0.0,"Revenue":0.0,"ExtendedCost":0.0,"Assists":0,"Language":"English","AccountStatus":"Active","CampaignStatus":"Paused","AdGroupStatus":"Active","BaseCampaignId":"413444833","AllRevenue":0.0,"ViewThroughConversions":0,"Goal":null,"GoalType":null,"AbsoluteTopImpressionRatePercent":33.33,"TopImpressionRatePercent":33.33,"ConversionsQualified":0.0,"AllConversionsQualified":0.0,"ViewThroughConversionsQualified":null,"ViewThroughRevenue":0.0},"emitted_at":1698144746216} diff --git a/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/schemas/age_gender_audience_report.json b/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/schemas/age_gender_audience_report.json index c07a3e631b1d..29b9b94cb932 100644 --- a/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/schemas/age_gender_audience_report.json +++ b/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/schemas/age_gender_audience_report.json @@ -87,10 +87,10 @@ "type": ["null", "string"] }, "AbsoluteTopImpressionRatePercent": { - "type": ["null", "string"] + "type": ["null", "number"] }, "TopImpressionRatePercent": { - "type": ["null", "string"] + "type": ["null", "number"] }, "ConversionsQualified": { "type": ["null", "number"] From 7edf7d28a3771a834f4e52f1eca3f5709cb2ecb0 Mon Sep 17 00:00:00 2001 From: Artem Inzhyyants Date: Tue, 24 Oct 2023 15:38:50 +0200 Subject: [PATCH 13/14] Source Bing Ads: update unit test + CAT description --- .../connectors/source-bing-ads/acceptance-test-config.yml | 2 +- .../connectors/source-bing-ads/unit_tests/test_reports.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/airbyte-integrations/connectors/source-bing-ads/acceptance-test-config.yml b/airbyte-integrations/connectors/source-bing-ads/acceptance-test-config.yml index 93c9b1886d27..09d73faa0dbe 100644 --- a/airbyte-integrations/connectors/source-bing-ads/acceptance-test-config.yml +++ b/airbyte-integrations/connectors/source-bing-ads/acceptance-test-config.yml @@ -33,7 +33,7 @@ acceptance_tests: - name: geographic_performance_report_hourly bypass_reason: "Hourly reports are disabled, because sync is too long" - name: age_gender_audience_report_hourly - bypass_reason: "Hourly reports are disabled, because sync is too long" + bypass_reason: "Empty report; hourly data fetched is limited to 180 days" timeout_seconds: 900 full_refresh: tests: diff --git a/airbyte-integrations/connectors/source-bing-ads/unit_tests/test_reports.py b/airbyte-integrations/connectors/source-bing-ads/unit_tests/test_reports.py index 2b3fd6dd38e3..1e9e500b8757 100644 --- a/airbyte-integrations/connectors/source-bing-ads/unit_tests/test_reports.py +++ b/airbyte-integrations/connectors/source-bing-ads/unit_tests/test_reports.py @@ -48,11 +48,11 @@ def test_get_column_value(): record = _RowReportRecord(row_values) test_report = TestReport() - assert test_report.get_column_value(record, "AccountId") == 33 - assert test_report.get_column_value(record, "AverageCpc") == 11.5 - assert test_report.get_column_value(record, "AdGroupId") == 0 + assert test_report.get_column_value(record, "AccountId") == "33" + assert test_report.get_column_value(record, "AverageCpc") == "11.5" + assert test_report.get_column_value(record, "AdGroupId") == None assert test_report.get_column_value(record, "AccountName") == "123456789" - assert test_report.get_column_value(record, "Spend") == 1.203 + assert test_report.get_column_value(record, "Spend") == "120.3" def test_get_updated_state_init_state(): From b2c833bf39f7a3743da62ae516a5cd33a0ed520e Mon Sep 17 00:00:00 2001 From: Artem Inzhyyants Date: Tue, 24 Oct 2023 17:01:22 +0200 Subject: [PATCH 14/14] Source Bing Ads: update unit test --- .../connectors/source-bing-ads/unit_tests/test_reports.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/airbyte-integrations/connectors/source-bing-ads/unit_tests/test_reports.py b/airbyte-integrations/connectors/source-bing-ads/unit_tests/test_reports.py index 1e9e500b8757..034a83f524b0 100644 --- a/airbyte-integrations/connectors/source-bing-ads/unit_tests/test_reports.py +++ b/airbyte-integrations/connectors/source-bing-ads/unit_tests/test_reports.py @@ -50,7 +50,7 @@ def test_get_column_value(): test_report = TestReport() assert test_report.get_column_value(record, "AccountId") == "33" assert test_report.get_column_value(record, "AverageCpc") == "11.5" - assert test_report.get_column_value(record, "AdGroupId") == None + assert test_report.get_column_value(record, "AdGroupId") is None assert test_report.get_column_value(record, "AccountName") == "123456789" assert test_report.get_column_value(record, "Spend") == "120.3"