Skip to content

Commit 985c6e0

Browse files
natikgadzhiFVidalCarneirolazebnyi
authored and
Erick Corona
committed
🐛 Source Linkedin Ads: fix changing next_page_token stopping criteria (test copy for #34166) (#37421)
Co-authored-by: FVidalCarneiro <[email protected]> Co-authored-by: Serhii Lazebnyi <[email protected]>
1 parent 74a6b55 commit 985c6e0

File tree

6 files changed

+29
-6
lines changed

6 files changed

+29
-6
lines changed

airbyte-integrations/connectors/source-linkedin-ads/metadata.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ data:
1111
connectorSubtype: api
1212
connectorType: source
1313
definitionId: 137ece28-5434-455c-8f34-69dc3782f451
14-
dockerImageTag: 1.0.0
14+
dockerImageTag: 1.0.1
1515
dockerRepository: airbyte/source-linkedin-ads
1616
documentationUrl: https://docs.airbyte.com/integrations/sources/linkedin-ads
1717
githubIssueLabel: source-linkedin-ads

airbyte-integrations/connectors/source-linkedin-ads/pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ requires = [ "poetry-core>=1.0.0",]
33
build-backend = "poetry.core.masonry.api"
44

55
[tool.poetry]
6-
version = "1.0.0"
6+
version = "1.0.1"
77
name = "source-linkedin-ads"
88
description = "Source implementation for Linkedin Ads."
99
authors = [ "Airbyte <[email protected]>",]

airbyte-integrations/connectors/source-linkedin-ads/source_linkedin_ads/analytics_streams.py

+12-1
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,18 @@ def next_page_token(self, response: requests.Response) -> Optional[Mapping[str,
213213
(See Restrictions: https://learn.microsoft.com/en-us/linkedin/marketing/integrations/ads-reporting/ads-reporting?view=li-lms-2023-09&tabs=http#restrictions)
214214
"""
215215
parsed_response = response.json()
216-
if len(parsed_response.get("elements")) < self.records_limit:
216+
is_elements_less_than_limit = len(parsed_response.get("elements")) < self.records_limit
217+
218+
# Note: The API might return fewer records than requested within the limits during pagination.
219+
# This behavior is documented at: https://github.com/airbytehq/airbyte/issues/34164
220+
paging_params = parsed_response.get("paging", {})
221+
is_end_of_records = (
222+
paging_params["total"] - paging_params["start"] <= self.records_limit
223+
if all(param in paging_params for param in ("total", "start"))
224+
else True
225+
)
226+
227+
if is_elements_less_than_limit and is_end_of_records:
217228
return None
218229
raise Exception(
219230
f"Limit {self.records_limit} elements exceeded. "

airbyte-integrations/connectors/source-linkedin-ads/source_linkedin_ads/streams.py

+13-2
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,20 @@ def next_page_token(self, response: requests.Response) -> Optional[Mapping[str,
7070
https://docs.microsoft.com/en-us/linkedin/shared/api-guide/concepts/pagination?context=linkedin/marketing/context
7171
"""
7272
parsed_response = response.json()
73-
if len(parsed_response.get("elements")) < self.records_limit:
73+
is_elements_less_than_limit = len(parsed_response.get("elements")) < self.records_limit
74+
75+
# Note: The API might return fewer records than requested within the limits during pagination.
76+
# This behavior is documented at: https://github.com/airbytehq/airbyte/issues/34164
77+
paging_params = parsed_response.get("paging", {})
78+
is_end_of_records = (
79+
paging_params["total"] - paging_params["start"] <= self.records_limit
80+
if all(param in paging_params for param in ("total", "start"))
81+
else True
82+
)
83+
84+
if is_elements_less_than_limit and is_end_of_records:
7485
return None
75-
return {"start": parsed_response.get("paging").get("start") + self.records_limit}
86+
return {"start": paging_params.get("start") + self.records_limit}
7687

7788
def request_headers(
7889
self, stream_state: Mapping[str, Any], stream_slice: Mapping[str, Any] = None, next_page_token: Mapping[str, Any] = None

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ def test_accounts(self):
161161
"response_json, expected",
162162
(
163163
({"elements": []}, None),
164-
({"elements": [{"data": []}] * 500, "paging": {"start": 0}}, {"start": 500}),
164+
({"elements": [{"data": []}] * 500, "paging": {"start": 0, "total": 600}}, {"start": 500}),
165165
),
166166
)
167167
def test_next_page_token(self, requests_mock, response_json, expected):

docs/integrations/sources/linkedin-ads.md

+1
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ After 5 unsuccessful attempts - the connector will stop the sync operation. In s
171171

172172
| Version | Date | Pull Request | Subject |
173173
|:--------|:-----------|:---------------------------------------------------------|:----------------------------------------------------------------------------------------------------------------|
174+
| 1.0.1 | 2024-03-28 | [34152](https://github.com/airbytehq/airbyte/pull/34152) | Proceed pagination if return less than expected |
174175
| 1.0.0 | 2024-04-10 | [36927](https://github.com/airbytehq/airbyte/pull/36927) | Update primary key for Analytics Streams |
175176
| 0.8.0 | 2024-03-19 | [36267](https://github.com/airbytehq/airbyte/pull/36267) | Pin airbyte-cdk version to `^0` |
176177
| 0.7.0 | 2024-02-20 | [35465](https://github.com/airbytehq/airbyte/pull/35465) | Per-error reporting and continue sync on stream failures |

0 commit comments

Comments
 (0)