Skip to content

Commit 2e7ee75

Browse files
Source GoogleAds: add end_date to config (#8669)
* GoogleAds add end_date to config * Update script following review comments * Add unit test * Solve conflicts * Solve conflicts in MR * Update test_google_ads.py Instanciate IncrementalGoogleAdsStream in tests + add missing line between functions * Update test_source.py remove extra hashtag * Update tests with missing params * Add missing time_zone param * merge user code * run format * revert unit test stream count * remove error log file * bump connector version * run seed file Co-authored-by: Marcos Marx <[email protected]>
1 parent 20d6009 commit 2e7ee75

File tree

10 files changed

+153
-6
lines changed

10 files changed

+153
-6
lines changed

airbyte-config/init/src/main/resources/config/STANDARD_SOURCE_DEFINITION/253487c0-2246-43ba-a21f-5116b20a2c50.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"sourceDefinitionId": "253487c0-2246-43ba-a21f-5116b20a2c50",
33
"name": "Google Ads",
44
"dockerRepository": "airbyte/source-google-ads",
5-
"dockerImageTag": "0.1.21",
5+
"dockerImageTag": "0.1.23",
66
"documentationUrl": "https://docs.airbyte.io/integrations/sources/google-ads",
77
"icon": "google-adwords.svg"
88
}

airbyte-config/init/src/main/resources/seed/source_definitions.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@
245245
- name: Google Ads
246246
sourceDefinitionId: 253487c0-2246-43ba-a21f-5116b20a2c50
247247
dockerRepository: airbyte/source-google-ads
248-
dockerImageTag: 0.1.22
248+
dockerImageTag: 0.1.23
249249
documentationUrl: https://docs.airbyte.io/integrations/sources/google-ads
250250
icon: google-adwords.svg
251251
sourceType: api

airbyte-config/init/src/main/resources/seed/source_specs.yaml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2308,7 +2308,7 @@
23082308
supportsNormalization: false
23092309
supportsDBT: false
23102310
supported_destination_sync_modes: []
2311-
- dockerImage: "airbyte/source-google-ads:0.1.22"
2311+
- dockerImage: "airbyte/source-google-ads:0.1.23"
23122312
spec:
23132313
documentationUrl: "https://docs.airbyte.com/integrations/sources/google-ads"
23142314
connectionSpecification:
@@ -2383,6 +2383,15 @@
23832383
examples:
23842384
- "2017-01-25"
23852385
order: 2
2386+
end_date:
2387+
type: "string"
2388+
title: "End Date"
2389+
description: "UTC date and time in the format 2017-01-25. Any data after\
2390+
\ this date will not be replicated."
2391+
pattern: "^[0-9]{4}-[0-9]{2}-[0-9]{2}$"
2392+
examples:
2393+
- "2017-01-30"
2394+
order: 6
23862395
custom_queries:
23872396
type: "array"
23882397
title: "Custom GAQL Queries (Optional)"

airbyte-integrations/connectors/source-google-ads/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,5 @@ RUN pip install .
1313

1414
ENTRYPOINT ["python", "/airbyte/integration_code/main.py"]
1515

16-
LABEL io.airbyte.version=0.1.22
16+
LABEL io.airbyte.version=0.1.23
1717
LABEL io.airbyte.name=airbyte/source-google-ads

airbyte-integrations/connectors/source-google-ads/source_google_ads/source.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,13 @@ def streams(self, config: Mapping[str, Any]) -> List[Stream]:
9090
google_api = GoogleAds(credentials=self.get_credentials(config), customer_id=config["customer_id"])
9191
account_info = self.get_account_info(google_api)
9292
time_zone = self.get_time_zone(account_info)
93+
end_date = config.get("end_date")
9394
incremental_stream_config = dict(
94-
api=google_api, conversion_window_days=config["conversion_window_days"], start_date=config["start_date"], time_zone=time_zone
95+
api=google_api,
96+
conversion_window_days=config["conversion_window_days"],
97+
start_date=config["start_date"],
98+
time_zone=time_zone,
99+
end_date=end_date,
95100
)
96101

97102
streams = [

airbyte-integrations/connectors/source-google-ads/source_google_ads/spec.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,14 @@
6363
"examples": ["2017-01-25"],
6464
"order": 2
6565
},
66+
"end_date": {
67+
"type": "string",
68+
"title": "End Date",
69+
"description": "UTC date and time in the format 2017-01-25. Any data after this date will not be replicated.",
70+
"pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$",
71+
"examples": ["2017-01-30"],
72+
"order": 6
73+
},
6674
"custom_queries": {
6775
"type": "array",
6876
"title": "Custom GAQL Queries (Optional)",

airbyte-integrations/connectors/source-google-ads/source_google_ads/streams.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,18 +71,21 @@ class IncrementalGoogleAdsStream(GoogleAdsStream, ABC):
7171
primary_key = None
7272
range_days = 15 # date range is set to 15 days, because for conversion_window_days default value is 14. Range less than 15 days will break the integration tests.
7373

74-
def __init__(self, start_date: str, conversion_window_days: int, time_zone: [pendulum.timezone, str], **kwargs):
74+
def __init__(self, start_date: str, conversion_window_days: int, time_zone: [pendulum.timezone, str], end_date: str = None, **kwargs):
7575
self.conversion_window_days = conversion_window_days
7676
self._start_date = start_date
7777
self.time_zone = time_zone
78+
self._end_date = end_date
7879
super().__init__(**kwargs)
7980

8081
def stream_slices(self, stream_state: Mapping[str, Any] = None, **kwargs) -> Iterable[Optional[Mapping[str, any]]]:
8182
stream_state = stream_state or {}
8283
start_date = stream_state.get(self.cursor_field) or self._start_date
84+
end_date = self._end_date
8385

8486
return chunk_date_range(
8587
start_date=start_date,
88+
end_date=end_date,
8689
conversion_window=self.conversion_window_days,
8790
field=self.cursor_field,
8891
days_of_data_storage=self.days_of_data_storage,

airbyte-integrations/connectors/source-google-ads/unit_tests/test_google_ads.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,3 +177,65 @@ def test_parse_single_result():
177177
date = "2001-01-01"
178178
response = GoogleAds.parse_single_result(SAMPLE_SCHEMA, MockedDateSegment(date))
179179
assert response == response
180+
181+
182+
# Add a sample config with date parameters
183+
SAMPLE_CONFIG_WITH_DATE = {
184+
"credentials": {
185+
"developer_token": "developer_token",
186+
"client_id": "client_id",
187+
"client_secret": "client_secret",
188+
"refresh_token": "refresh_token",
189+
},
190+
"customer_id": "customer_id",
191+
"start_date": "2021-11-01",
192+
"end_date": "2021-11-15",
193+
}
194+
195+
196+
def test_get_date_params_with_date():
197+
# Please note that this is equal to inputted stream_slice start date + 1 day
198+
mock_start_date = SAMPLE_CONFIG_WITH_DATE["start_date"]
199+
mock_end_date = SAMPLE_CONFIG_WITH_DATE["end_date"]
200+
incremental_stream_config = dict(
201+
start_date=mock_start_date,
202+
end_date=mock_end_date,
203+
conversion_window_days=0,
204+
time_zone="local",
205+
api=MockGoogleAdsClient(SAMPLE_CONFIG_WITH_DATE),
206+
)
207+
start_date, end_date = IncrementalGoogleAdsStream(**incremental_stream_config).get_date_params(
208+
stream_slice={"segments.date": "2021-10-31"}, cursor_field="segments.date", end_date=pendulum.parse("2021-11-15")
209+
)
210+
assert mock_start_date == start_date and mock_end_date == end_date
211+
212+
213+
SAMPLE_CONFIG_WITHOUT_END_DATE = {
214+
"credentials": {
215+
"developer_token": "developer_token",
216+
"client_id": "client_id",
217+
"client_secret": "client_secret",
218+
"refresh_token": "refresh_token",
219+
},
220+
"customer_id": "customer_id",
221+
"start_date": "2021-11-01",
222+
}
223+
224+
225+
def test_get_date_params_without_end_date():
226+
# Please note that this is equal to inputted stream_slice start date + 1 day
227+
mock_start_date = SAMPLE_CONFIG_WITHOUT_END_DATE["start_date"]
228+
mock_end_date = "2021-11-30"
229+
incremental_stream_config = dict(
230+
start_date=mock_start_date,
231+
end_date=mock_end_date,
232+
conversion_window_days=0,
233+
time_zone="local",
234+
api=MockGoogleAdsClient(SAMPLE_CONFIG_WITHOUT_END_DATE),
235+
)
236+
start_date, end_date = IncrementalGoogleAdsStream(**incremental_stream_config).get_date_params(
237+
stream_slice={"segments.date": "2021-10-31"}, cursor_field="segments.date"
238+
)
239+
assert mock_start_date == start_date
240+
# There is a Google limitation where we capture only a 15-day date range
241+
assert end_date == "2021-11-15"

airbyte-integrations/connectors/source-google-ads/unit_tests/test_source.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,30 @@
22
# Copyright (c) 2021 Airbyte, Inc., all rights reserved.
33
#
44

5+
import pendulum
56
import pytest
67
from source_google_ads.custom_query_stream import CustomQuery
78
from source_google_ads.google_ads import GoogleAds
89
from source_google_ads.source import SourceGoogleAds
910
from source_google_ads.streams import AdGroupAdReport, chunk_date_range
1011

1112

13+
# Test chunck date range without end date
14+
def test_chunk_date_range_without_end_date():
15+
start_date_str = pendulum.now().subtract(days=5).to_date_string()
16+
conversion_window = 0
17+
field = "date"
18+
response = chunk_date_range(
19+
start_date=start_date_str, conversion_window=conversion_window, field=field, end_date=None, days_of_data_storage=None, range_days=1
20+
)
21+
start_date = pendulum.parse(start_date_str)
22+
expected_response = []
23+
while start_date < pendulum.now():
24+
expected_response.append({field: start_date.to_date_string()})
25+
start_date = start_date.add(days=1)
26+
assert expected_response == response
27+
28+
1229
def test_chunk_date_range():
1330
start_date = "2021-03-04"
1431
end_date = "2021-05-04"
@@ -102,6 +119,24 @@ def get_instance_from_config(config, query):
102119
return instance
103120

104121

122+
# get he instance with a config
123+
def get_instance_from_config_with_end_date(config, query):
124+
start_date = "2021-03-04"
125+
end_date = "2021-04-04"
126+
conversion_window_days = 14
127+
google_api = GoogleAds(credentials=config["credentials"], customer_id=config["customer_id"])
128+
129+
instance = CustomQuery(
130+
api=google_api,
131+
conversion_window_days=conversion_window_days,
132+
start_date=start_date,
133+
end_date=end_date,
134+
time_zone="local",
135+
custom_query_config={"query": query, "table_name": "whatever_table"},
136+
)
137+
return instance
138+
139+
105140
@pytest.mark.parametrize(
106141
"query, fields",
107142
[
@@ -244,6 +279,30 @@ def test_get_json_schema_parse_query(config):
244279
assert set(schema_keys) == set(final_fields) # test 1
245280

246281

282+
# Test get json schema when start and end date are provided in the config file
283+
def test_get_json_schema_parse_query_with_end_date(config):
284+
query = """
285+
SELECT
286+
campaign.accessible_bidding_strategy,
287+
segments.ad_destination_type,
288+
campaign.start_date,
289+
campaign.end_date
290+
FROM campaign
291+
"""
292+
final_fields = [
293+
"campaign.accessible_bidding_strategy",
294+
"segments.ad_destination_type",
295+
"campaign.start_date",
296+
"campaign.end_date",
297+
"segments.date",
298+
]
299+
300+
instance = get_instance_from_config_with_end_date(config=config, query=query)
301+
final_schema = instance.get_json_schema()
302+
schema_keys = final_schema["properties"]
303+
assert set(schema_keys) == set(final_fields) # test 1
304+
305+
247306
def test_google_type_conversion(config):
248307
"""
249308
query may be invalid (fields incompatibility did not checked).

docs/integrations/sources/google-ads.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ This source is constrained by whatever API limits are set for the Google Ads tha
102102

103103
| Version | Date | Pull Request | Subject |
104104
| :--- | :--- | :--- | :--- |
105+
| `0.1.23` | 2022-01-25 | [8669](https://github.com/airbytehq/airbyte/pull/8669) | Add end date parameter in spec. |
105106
| `0.1.22` | 2022-01-24 | [9608](https://github.com/airbytehq/airbyte/pull/9608) | Reduce stream slice date range. |
106107
| `0.1.21` | 2021-12-28 | [9149](https://github.com/airbytehq/airbyte/pull/9149) | Update title and description |
107108
| `0.1.20` | 2021-12-22 | [9071](https://github.com/airbytehq/airbyte/pull/9071) | Fix: Keyword schema enum |

0 commit comments

Comments
 (0)