airbyte-source-google-ads 4.1.3__tar.gz → 4.1.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (16) hide show
  1. {airbyte_source_google_ads-4.1.3 → airbyte_source_google_ads-4.1.4}/PKG-INFO +2 -2
  2. {airbyte_source_google_ads-4.1.3 → airbyte_source_google_ads-4.1.4}/pyproject.toml +2 -2
  3. {airbyte_source_google_ads-4.1.3 → airbyte_source_google_ads-4.1.4}/source_google_ads/components.py +12 -0
  4. {airbyte_source_google_ads-4.1.3 → airbyte_source_google_ads-4.1.4}/source_google_ads/manifest.yaml +129 -45
  5. {airbyte_source_google_ads-4.1.3 → airbyte_source_google_ads-4.1.4}/README.md +0 -0
  6. {airbyte_source_google_ads-4.1.3 → airbyte_source_google_ads-4.1.4}/source_google_ads/__init__.py +0 -0
  7. {airbyte_source_google_ads-4.1.3 → airbyte_source_google_ads-4.1.4}/source_google_ads/config_migrations.py +0 -0
  8. {airbyte_source_google_ads-4.1.3 → airbyte_source_google_ads-4.1.4}/source_google_ads/google_ads.py +0 -0
  9. {airbyte_source_google_ads-4.1.3 → airbyte_source_google_ads-4.1.4}/source_google_ads/models.py +0 -0
  10. {airbyte_source_google_ads-4.1.3 → airbyte_source_google_ads-4.1.4}/source_google_ads/run.py +0 -0
  11. {airbyte_source_google_ads-4.1.3 → airbyte_source_google_ads-4.1.4}/source_google_ads/schemas/customer_client.json +0 -0
  12. {airbyte_source_google_ads-4.1.3 → airbyte_source_google_ads-4.1.4}/source_google_ads/schemas/service_accounts.json +0 -0
  13. {airbyte_source_google_ads-4.1.3 → airbyte_source_google_ads-4.1.4}/source_google_ads/source.py +0 -0
  14. {airbyte_source_google_ads-4.1.3 → airbyte_source_google_ads-4.1.4}/source_google_ads/spec.json +0 -0
  15. {airbyte_source_google_ads-4.1.3 → airbyte_source_google_ads-4.1.4}/source_google_ads/streams.py +0 -0
  16. {airbyte_source_google_ads-4.1.3 → airbyte_source_google_ads-4.1.4}/source_google_ads/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: airbyte-source-google-ads
3
- Version: 4.1.3
3
+ Version: 4.1.4
4
4
  Summary: Source implementation for Google Ads.
5
5
  Home-page: https://airbyte.com
6
6
  License: Elv2
@@ -11,7 +11,7 @@ Classifier: License :: Other/Proprietary License
11
11
  Classifier: Programming Language :: Python :: 3
12
12
  Classifier: Programming Language :: Python :: 3.10
13
13
  Classifier: Programming Language :: Python :: 3.11
14
- Requires-Dist: airbyte-cdk (>=7.4.1,<8.0.0)
14
+ Requires-Dist: airbyte-cdk (>=7.5.1.post3.dev19705070276,<8.0.0)
15
15
  Requires-Dist: google-ads (==27.0.0)
16
16
  Requires-Dist: pendulum (<3.0.0)
17
17
  Requires-Dist: protobuf (==4.25.2)
@@ -3,7 +3,7 @@ requires = [ "poetry-core>=1.0.0",]
3
3
  build-backend = "poetry.core.masonry.api"
4
4
 
5
5
  [tool.poetry]
6
- version = "4.1.3"
6
+ version = "4.1.4"
7
7
  name = "airbyte-source-google-ads"
8
8
  description = "Source implementation for Google Ads."
9
9
  authors = [ "Airbyte <contact@airbyte.io>",]
@@ -20,7 +20,7 @@ python = "^3.10,<3.12"
20
20
  google-ads = "==27.0.0"
21
21
  protobuf = "==4.25.2"
22
22
  pendulum = "<3.0.0"
23
- airbyte-cdk = "^7.4.1"
23
+ airbyte-cdk = "^7.5.1.post3.dev19705070276"
24
24
 
25
25
  [tool.poetry.scripts]
26
26
  source-google-ads = "source_google_ads.run:run"
@@ -697,6 +697,7 @@ class CustomGAQueryHttpRequester(HttpRequester):
697
697
  def __post_init__(self, parameters: Mapping[str, Any]):
698
698
  super().__post_init__(parameters=parameters)
699
699
  self.query = GAQL.parse(parameters.get("query"))
700
+ self.stream_response = True
700
701
 
701
702
  @staticmethod
702
703
  def is_metrics_in_custom_query(query: GAQL) -> bool:
@@ -761,6 +762,17 @@ class CustomGAQueryHttpRequester(HttpRequester):
761
762
  return self.query[from_index + 4 :].strip()
762
763
 
763
764
 
765
+ class CustomGAQueryClickViewHttpRequester(CustomGAQueryHttpRequester):
766
+ @staticmethod
767
+ def _insert_segments_date_expr(query: GAQL, start_date: str, end_date: str) -> GAQL:
768
+ if "segments.date" not in query.fields:
769
+ query = query.append_field("segments.date")
770
+ condition = f"segments.date ='{start_date}'"
771
+ if query.where:
772
+ return query.set_where(query.where + " AND " + condition)
773
+ return query.set_where(condition)
774
+
775
+
764
776
  @dataclass()
765
777
  class CustomGAQuerySchemaLoader(SchemaLoader):
766
778
  """
@@ -65,27 +65,15 @@ definitions:
65
65
  field_path:
66
66
  - results
67
67
 
68
- cursor_paginator:
69
- type: DefaultPaginator
70
- pagination_strategy:
71
- type: CursorPagination
72
- cursor_value: "{{ response.get('nextPageToken', '') }}"
73
- stop_condition: "{{ response.get('nextPageToken', '') is none }}"
74
- page_token_option:
75
- type: RequestOption
76
- inject_into: body_json
77
- field_path: ["page_token"]
78
-
79
68
  base_retriever:
80
69
  type: SimpleRetriever
81
70
  requester:
82
71
  $ref: "#/definitions/stream_requester"
83
72
  record_selector:
84
73
  $ref: "#/definitions/base_selector"
85
- paginator:
86
- $ref: "#/definitions/cursor_paginator"
87
74
  decoder:
88
- type: JsonDecoder
75
+ type: CustomDecoder
76
+ class_name: "source_google_ads.components.GoogleAdsStreamingDecoder"
89
77
 
90
78
  stream_base:
91
79
  type: DeclarativeStream
@@ -199,7 +187,7 @@ definitions:
199
187
  $ref: "#/schemas"
200
188
  authenticator:
201
189
  $ref: "#/definitions/authenticator"
202
- url_base: "https://googleads.googleapis.com/v20/{{ stream_partition['customer_id'] }}/googleAds:search"
190
+ url_base: "https://googleads.googleapis.com/v20/{{ stream_partition['customer_id'] }}/googleAds:searchStream"
203
191
  http_method: POST
204
192
  error_handler:
205
193
  $ref: "#/definitions/base_error_handler"
@@ -224,7 +212,7 @@ definitions:
224
212
  incremental_stream:
225
213
  $ref: "#/definitions/incremental_stream_base"
226
214
  $parameters:
227
- url_base: "https://googleads.googleapis.com/v20/{{ stream_partition['parent_slice']['customer_id'] }}/googleAds:search"
215
+ url_base: "https://googleads.googleapis.com/v20/{{ stream_partition['parent_slice']['customer_id'] }}/googleAds:searchStream"
228
216
  retriever:
229
217
  type: CustomRetriever
230
218
  class_name: "source_google_ads.components.CriterionRetriever"
@@ -240,8 +228,6 @@ definitions:
240
228
  http_method: POST
241
229
  error_handler:
242
230
  $ref: "#/definitions/base_error_handler"
243
- paginator:
244
- $ref: "#/definitions/cursor_paginator"
245
231
  record_selector:
246
232
  type: RecordSelector
247
233
  extractor:
@@ -297,8 +283,6 @@ definitions:
297
283
  $ref: "#/definitions/base_requester"
298
284
  url_base: "https://googleads.googleapis.com/v20/customers:listAccessibleCustomers"
299
285
  http_method: GET
300
- paginator:
301
- type: NoPagination
302
286
  record_selector:
303
287
  extractor:
304
288
  type: CustomRecordExtractor
@@ -422,11 +406,6 @@ definitions:
422
406
  parent_key: "clientCustomer"
423
407
  partition_field: "customer_id"
424
408
  stream: "#/definitions/customer_client"
425
- decoder:
426
- type: CustomDecoder
427
- class_name: "source_google_ads.components.GoogleAdsStreamingDecoder"
428
- paginator:
429
- type: NoPagination
430
409
  transformations:
431
410
  - type: CustomTransformation
432
411
  class_name: "source_google_ads.components.KeysToSnakeCaseGoogleAdsTransformation"
@@ -487,13 +466,6 @@ definitions:
487
466
 
488
467
  ad_group_ad_stream:
489
468
  $ref: "#/definitions/incremental_stream_base"
490
- retriever:
491
- $ref: "#/definitions/incremental_stream_base/retriever"
492
- paginator:
493
- type: NoPagination
494
- decoder:
495
- type: CustomDecoder
496
- class_name: "source_google_ads.components.GoogleAdsStreamingDecoder"
497
469
  name: ad_group_ad
498
470
  primary_key:
499
471
  - ad_group.id
@@ -665,12 +637,10 @@ definitions:
665
637
  $ref: "#/schemas/click_view"
666
638
  authenticator:
667
639
  $ref: "#/definitions/authenticator"
668
- url_base: "https://googleads.googleapis.com/v20/{{ stream_partition['customer_id'] }}/googleAds:search"
640
+ url_base: "https://googleads.googleapis.com/v20/{{ stream_partition['customer_id'] }}/googleAds:searchStream"
669
641
  http_method: POST
670
642
  error_handler:
671
643
  $ref: "#/definitions/base_error_handler"
672
- paginator:
673
- $ref: "#/definitions/cursor_paginator"
674
644
  incremental_sync:
675
645
  type: DatetimeBasedCursor
676
646
  cursor_field: segments.date
@@ -859,8 +829,6 @@ definitions:
859
829
  error_handler:
860
830
  $ref: "#/definitions/base_error_handler"
861
831
  name: change_status
862
- paginator:
863
- $ref: "#/definitions/cursor_paginator"
864
832
  pagination_reset:
865
833
  type: PaginationReset
866
834
  action: SPLIT_USING_CURSOR
@@ -1030,14 +998,6 @@ definitions:
1030
998
  )
1031
999
  }}
1032
1000
  create_or_update: true
1033
- - type: ComponentMappingDefinition
1034
- field_path:
1035
- - retriever
1036
- - requester
1037
- - $parameters
1038
- - query
1039
- value: "{{ components_values.get('query', None) }}"
1040
- create_or_update: true
1041
1001
  - type: ComponentMappingDefinition
1042
1002
  field_path:
1043
1003
  - retriever
@@ -1085,6 +1045,130 @@ definitions:
1085
1045
  )
1086
1046
  }}
1087
1047
  create_or_update: true
1048
+ - type: ComponentMappingDefinition
1049
+ field_path:
1050
+ - incremental_sync
1051
+ - step
1052
+ value: "P1D"
1053
+ condition: >-
1054
+ {{
1055
+ (
1056
+ (
1057
+ components_values.get('query', '').count('segments.date') == 1
1058
+ and (components_values.get('query') | regex_search('(?i)(\\bSELECT\\b[\\s\\S]*?segments\\.date[\\s\\S]*?\\bFROM\\b)'))
1059
+ )
1060
+ or
1061
+ (
1062
+ components_values.get('query', '').count('segments.date') == 2
1063
+ and (components_values.get('query') | regex_search('(?i)(\\bSELECT\\b[\\s\\S]*?segments\\.date[\\s\\S]*?\\bFROM\\b)'))
1064
+ and (components_values.get('query') | regex_search('(?i)(\\bORDER\\s+BY\\b[\\s\\S]*?segments\\.date)'))
1065
+ )
1066
+ ) and components_values.get('query', '') | regex_search('(?i)(\\bFROM\\s+click_view\\b)')
1067
+ }}
1068
+ create_or_update: true
1069
+ - type: ComponentMappingDefinition
1070
+ field_path:
1071
+ - incremental_sync
1072
+ - start_datetime
1073
+ value: >-
1074
+ {
1075
+ "type": "MinMaxDatetime",
1076
+ "datetime": "{{ max(config.get('start_date', day_delta(-90, format='%Y-%m-%d')), day_delta(-90, format='%Y-%m-%d')) }}",
1077
+ "datetime_format": "%Y-%m-%d"
1078
+ }
1079
+ condition: >-
1080
+ {{
1081
+ (
1082
+ (
1083
+ components_values.get('query', '').count('segments.date') == 1
1084
+ and (components_values.get('query') | regex_search('(?i)(\\bSELECT\\b[\\s\\S]*?segments\\.date[\\s\\S]*?\\bFROM\\b)'))
1085
+ )
1086
+ or
1087
+ (
1088
+ components_values.get('query', '').count('segments.date') == 2
1089
+ and (components_values.get('query') | regex_search('(?i)(\\bSELECT\\b[\\s\\S]*?segments\\.date[\\s\\S]*?\\bFROM\\b)'))
1090
+ and (components_values.get('query') | regex_search('(?i)(\\bORDER\\s+BY\\b[\\s\\S]*?segments\\.date)'))
1091
+ )
1092
+ ) and components_values.get('query', '') | regex_search('(?i)(\\bFROM\\s+click_view\\b)')
1093
+ }}
1094
+ create_or_update: true
1095
+ - type: ComponentMappingDefinition
1096
+ field_path:
1097
+ - incremental_sync
1098
+ - end_datetime
1099
+ value: >-
1100
+ {
1101
+ "type": "MinMaxDatetime",
1102
+ "datetime": "{{ format_datetime((str_to_datetime(config.get('end_date')) if config.get('end_date') else now_utc()) + duration('P1D'), '%Y-%m-%d') }}",
1103
+ "datetime_format": "%Y-%m-%d"
1104
+ }
1105
+ condition: >-
1106
+ {{
1107
+ (
1108
+ (
1109
+ components_values.get('query', '').count('segments.date') == 1
1110
+ and (components_values.get('query') | regex_search('(?i)(\\bSELECT\\b[\\s\\S]*?segments\\.date[\\s\\S]*?\\bFROM\\b)'))
1111
+ )
1112
+ or
1113
+ (
1114
+ components_values.get('query', '').count('segments.date') == 2
1115
+ and (components_values.get('query') | regex_search('(?i)(\\bSELECT\\b[\\s\\S]*?segments\\.date[\\s\\S]*?\\bFROM\\b)'))
1116
+ and (components_values.get('query') | regex_search('(?i)(\\bORDER\\s+BY\\b[\\s\\S]*?segments\\.date)'))
1117
+ )
1118
+ ) and components_values.get('query', '') | regex_search('(?i)(\\bFROM\\s+click_view\\b)')
1119
+ }}
1120
+ create_or_update: true
1121
+ - type: ComponentMappingDefinition
1122
+ field_path:
1123
+ - incremental_sync
1124
+ - cursor_granularity
1125
+ value: P1D
1126
+ condition: >-
1127
+ {{
1128
+ (
1129
+ (
1130
+ components_values.get('query', '').count('segments.date') == 1
1131
+ and (components_values.get('query') | regex_search('(?i)(\\bSELECT\\b[\\s\\S]*?segments\\.date[\\s\\S]*?\\bFROM\\b)'))
1132
+ )
1133
+ or
1134
+ (
1135
+ components_values.get('query', '').count('segments.date') == 2
1136
+ and (components_values.get('query') | regex_search('(?i)(\\bSELECT\\b[\\s\\S]*?segments\\.date[\\s\\S]*?\\bFROM\\b)'))
1137
+ and (components_values.get('query') | regex_search('(?i)(\\bORDER\\s+BY\\b[\\s\\S]*?segments\\.date)'))
1138
+ )
1139
+ ) and components_values.get('query', '') | regex_search('(?i)(\\bFROM\\s+click_view\\b)')
1140
+ }}
1141
+ create_or_update: true
1142
+ - type: ComponentMappingDefinition
1143
+ field_path:
1144
+ - retriever
1145
+ - requester
1146
+ - class_name
1147
+ value: "source_google_ads.components.CustomGAQueryClickViewHttpRequester"
1148
+ condition: >-
1149
+ {{
1150
+ (
1151
+ (
1152
+ components_values.get('query', '').count('segments.date') == 1
1153
+ and (components_values.get('query') | regex_search('(?i)(\\bSELECT\\b[\\s\\S]*?segments\\.date[\\s\\S]*?\\bFROM\\b)'))
1154
+ )
1155
+ or
1156
+ (
1157
+ components_values.get('query', '').count('segments.date') == 2
1158
+ and (components_values.get('query') | regex_search('(?i)(\\bSELECT\\b[\\s\\S]*?segments\\.date[\\s\\S]*?\\bFROM\\b)'))
1159
+ and (components_values.get('query') | regex_search('(?i)(\\bORDER\\s+BY\\b[\\s\\S]*?segments\\.date)'))
1160
+ )
1161
+ ) and components_values.get('query', '') | regex_search('(?i)(\\bFROM\\s+click_view\\b)')
1162
+ }}
1163
+ create_or_update: true
1164
+ - type: ComponentMappingDefinition
1165
+ field_path:
1166
+ - retriever
1167
+ - requester
1168
+ - $parameters
1169
+ - query
1170
+ value: "{{ components_values.get('query', None) }}"
1171
+ create_or_update: true
1088
1172
  - type: ComponentMappingDefinition
1089
1173
  field_path:
1090
1174
  - retriever