airbyte-source-shopify 3.0.13.dev202512232215__py3-none-any.whl → 3.0.14.dev202512192257__py3-none-any.whl
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.
- {airbyte_source_shopify-3.0.13.dev202512232215.dist-info → airbyte_source_shopify-3.0.14.dev202512192257.dist-info}/METADATA +1 -1
- {airbyte_source_shopify-3.0.13.dev202512232215.dist-info → airbyte_source_shopify-3.0.14.dev202512192257.dist-info}/RECORD +8 -7
- source_shopify/schemas/deleted_products.json +27 -0
- source_shopify/scopes.py +1 -0
- source_shopify/source.py +2 -0
- source_shopify/streams/streams.py +95 -4
- {airbyte_source_shopify-3.0.13.dev202512232215.dist-info → airbyte_source_shopify-3.0.14.dev202512192257.dist-info}/WHEEL +0 -0
- {airbyte_source_shopify-3.0.13.dev202512232215.dist-info → airbyte_source_shopify-3.0.14.dev202512192257.dist-info}/entry_points.txt +0 -0
|
@@ -14,6 +14,7 @@ source_shopify/schemas/custom_collections.json,sha256=ElDY1y_G_VFPOGr9ipU022AZDW
|
|
|
14
14
|
source_shopify/schemas/customer_address.json,sha256=kLKylul_xK7eO_aduvDddj078k8aQLM4JtUEpa5Tp_8,2628
|
|
15
15
|
source_shopify/schemas/customer_journey_summary.json,sha256=GlZmIqFeR1x84DwgwMo28HQ8QseImkhvYxLSNRkUmwg,12733
|
|
16
16
|
source_shopify/schemas/customers.json,sha256=pywejBEtvMnRHvvnJQhfA8NlCBjELv7XuMlKdpS4cZI,10233
|
|
17
|
+
source_shopify/schemas/deleted_products.json,sha256=7TbqrABNDg9ZFAeLJCPe2Z5jtk9QGbJDuoSKofGd1lg,773
|
|
17
18
|
source_shopify/schemas/discount_codes.json,sha256=YxGptdpjXwM46fmzs5zoi3m96xAWKXrfllC_oIZW0vo,3730
|
|
18
19
|
source_shopify/schemas/disputes.json,sha256=Uvzy1Gi954cLxij6H0Vbz0OWS6GS10YaJI4DJfY2x8I,1775
|
|
19
20
|
source_shopify/schemas/draft_orders.json,sha256=3NaZt9Qk4mY8VO9pB5UBzw3GZibL8MvI0z_tlnMsdBI,24211
|
|
@@ -49,7 +50,7 @@ source_shopify/schemas/shop.json,sha256=vEGiTvEYX7qnMq06MRVBycqih49h49xjTNC6gJux
|
|
|
49
50
|
source_shopify/schemas/smart_collections.json,sha256=kv7dINsvgzJ0RyKfFNKjU0apdNDXwQaHfnNZfQsshcU,2009
|
|
50
51
|
source_shopify/schemas/tender_transactions.json,sha256=U8fdT-eflycEPzYSpBDiB0lp9wxmJHgioHTrICflh78,2006
|
|
51
52
|
source_shopify/schemas/transactions.json,sha256=vbwscH3UcAtbSsC70mBka4oNaFR4S3S6IFBmzR7t37U,10226
|
|
52
|
-
source_shopify/scopes.py,sha256=
|
|
53
|
+
source_shopify/scopes.py,sha256=78f9QL3PJZ9UDx1gIWzNwx5fYJE9OB3vPi9RahB_kFw,6533
|
|
53
54
|
source_shopify/shopify_graphql/bulk/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
54
55
|
source_shopify/shopify_graphql/bulk/exceptions.py,sha256=4dj7Za4xIfwL-zf8joT9svF_RSoGlE3GviMiIl1e1rs,2532
|
|
55
56
|
source_shopify/shopify_graphql/bulk/job.py,sha256=c3Cg70_Io9jTD-rU-5MvjHaPmJCtcpeqEYnRtFECGOo,28673
|
|
@@ -58,13 +59,13 @@ source_shopify/shopify_graphql/bulk/record.py,sha256=X6VGngugv7a_S8UEeDo121BkdCV
|
|
|
58
59
|
source_shopify/shopify_graphql/bulk/retry.py,sha256=R5rSJJE8D5zcj6mN-OmmNO2aFZEIdjAlWclDDVW5KPI,2626
|
|
59
60
|
source_shopify/shopify_graphql/bulk/status.py,sha256=RmuQ2XsYL3iRCpVGxea9F1wXGmbwasDCSXjaTyL4LMA,328
|
|
60
61
|
source_shopify/shopify_graphql/bulk/tools.py,sha256=nUQ2ZmPTKJNJdfLToR6KJtLKcJFCChSifkAOvwg0Vss,4065
|
|
61
|
-
source_shopify/source.py,sha256=
|
|
62
|
+
source_shopify/source.py,sha256=oikoM-VPNk62zlmeAQR59PMxfuXq2s42N7zaqLM6_lo,8575
|
|
62
63
|
source_shopify/spec.json,sha256=ITYWiQ-NrI5VISk5qmUQhp9ChUE2FV18d8xzVzPwvAg,6144
|
|
63
64
|
source_shopify/streams/base_streams.py,sha256=k_4uLaLADLRTUcSmP8uA_830uuzRvnqUaCVGcb0Zpd8,42625
|
|
64
|
-
source_shopify/streams/streams.py,sha256
|
|
65
|
+
source_shopify/streams/streams.py,sha256=F_otpKWbwn4Xn_wYVIdPF1MVjaOGke3BlvPG336Ip28,18105
|
|
65
66
|
source_shopify/transform.py,sha256=mn0htL812_90zc_YszGQa0hHcIZQpYYdmk8IqpZm5TI,4685
|
|
66
67
|
source_shopify/utils.py,sha256=DSqEchu-MQJ7zust7CNfqOkGIv9OSR-5UUsuD-bsDa8,16224
|
|
67
|
-
airbyte_source_shopify-3.0.
|
|
68
|
-
airbyte_source_shopify-3.0.
|
|
69
|
-
airbyte_source_shopify-3.0.
|
|
70
|
-
airbyte_source_shopify-3.0.
|
|
68
|
+
airbyte_source_shopify-3.0.14.dev202512192257.dist-info/METADATA,sha256=YtLc8y1hLx7E1BjYCj3XvskFi68Pvkzl5qHOnaf4nkU,5314
|
|
69
|
+
airbyte_source_shopify-3.0.14.dev202512192257.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
|
70
|
+
airbyte_source_shopify-3.0.14.dev202512192257.dist-info/entry_points.txt,sha256=SyTwKSsPk9MCdPf01saWpnp8hcmZOgBssVcSIvMbBeQ,57
|
|
71
|
+
airbyte_source_shopify-3.0.14.dev202512192257.dist-info/RECORD,,
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": ["object", "null"],
|
|
3
|
+
"additionalProperties": true,
|
|
4
|
+
"properties": {
|
|
5
|
+
"id": {
|
|
6
|
+
"description": "The unique identifier of the deleted product.",
|
|
7
|
+
"type": ["null", "integer"]
|
|
8
|
+
},
|
|
9
|
+
"deleted_at": {
|
|
10
|
+
"description": "The date and time when the product was deleted.",
|
|
11
|
+
"type": ["null", "string"],
|
|
12
|
+
"format": "date-time"
|
|
13
|
+
},
|
|
14
|
+
"deleted_message": {
|
|
15
|
+
"description": "Message related to the deletion of the product.",
|
|
16
|
+
"type": ["null", "string"]
|
|
17
|
+
},
|
|
18
|
+
"deleted_description": {
|
|
19
|
+
"description": "Description of the reason for deletion.",
|
|
20
|
+
"type": ["null", "string"]
|
|
21
|
+
},
|
|
22
|
+
"shop_url": {
|
|
23
|
+
"description": "The URL of the shop where the product was listed.",
|
|
24
|
+
"type": ["null", "string"]
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
source_shopify/scopes.py
CHANGED
|
@@ -37,6 +37,7 @@ SCOPES_MAPPING: Mapping[str, set[str]] = {
|
|
|
37
37
|
"MetafieldDraftOrders": ("read_draft_orders",),
|
|
38
38
|
# SCOPE: read_products
|
|
39
39
|
"Products": ("read_products",),
|
|
40
|
+
"DeletedProducts": ("read_products",),
|
|
40
41
|
"MetafieldProducts": ("read_products",),
|
|
41
42
|
"ProductImages": ("read_products",),
|
|
42
43
|
"MetafieldProductImages": ("read_products",),
|
source_shopify/source.py
CHANGED
|
@@ -27,6 +27,7 @@ from .streams.streams import (
|
|
|
27
27
|
CustomerAddress,
|
|
28
28
|
CustomerJourneySummary,
|
|
29
29
|
Customers,
|
|
30
|
+
DeletedProducts,
|
|
30
31
|
DiscountCodes,
|
|
31
32
|
Disputes,
|
|
32
33
|
DraftOrders,
|
|
@@ -211,6 +212,7 @@ class SourceShopify(AbstractSource):
|
|
|
211
212
|
PriceRules(config),
|
|
212
213
|
ProductImages(config),
|
|
213
214
|
Products(config),
|
|
215
|
+
DeletedProducts(config),
|
|
214
216
|
ProductVariants(config),
|
|
215
217
|
Shop(config),
|
|
216
218
|
SmartCollections(config),
|
|
@@ -135,6 +135,100 @@ class Products(IncrementalShopifyGraphQlBulkStream):
|
|
|
135
135
|
bulk_query: Product = Product
|
|
136
136
|
|
|
137
137
|
|
|
138
|
+
class DeletedProducts(IncrementalShopifyStream):
|
|
139
|
+
"""
|
|
140
|
+
Stream for fetching deleted products using the Shopify GraphQL Events API.
|
|
141
|
+
This stream queries events with action:destroy and subject_type:Product to get deleted product records.
|
|
142
|
+
https://shopify.dev/docs/api/admin-graphql/latest/queries/events
|
|
143
|
+
"""
|
|
144
|
+
|
|
145
|
+
data_field = "graphql"
|
|
146
|
+
cursor_field = "deleted_at"
|
|
147
|
+
http_method = "POST"
|
|
148
|
+
filter_field = None
|
|
149
|
+
|
|
150
|
+
_page_cursor: Optional[str] = None
|
|
151
|
+
|
|
152
|
+
EVENTS_QUERY = """
|
|
153
|
+
query GetDeletedProductEvents($first: Int!, $after: String, $query: String) {
|
|
154
|
+
events(first: $first, after: $after, query: $query, sortKey: CREATED_AT) {
|
|
155
|
+
pageInfo {
|
|
156
|
+
hasNextPage
|
|
157
|
+
endCursor
|
|
158
|
+
}
|
|
159
|
+
nodes {
|
|
160
|
+
... on BasicEvent {
|
|
161
|
+
id
|
|
162
|
+
createdAt
|
|
163
|
+
message
|
|
164
|
+
subjectId
|
|
165
|
+
subjectType
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
"""
|
|
171
|
+
|
|
172
|
+
@property
|
|
173
|
+
def url_base(self) -> str:
|
|
174
|
+
return f"https://{self.config['shop']}.myshopify.com/admin/api/{self.config['api_version']}/graphql.json"
|
|
175
|
+
|
|
176
|
+
def path(self, **kwargs) -> str:
|
|
177
|
+
return ""
|
|
178
|
+
|
|
179
|
+
def request_params(
|
|
180
|
+
self, stream_state: Mapping[str, Any] = None, next_page_token: Mapping[str, Any] = None, **kwargs
|
|
181
|
+
) -> MutableMapping[str, Any]:
|
|
182
|
+
return {}
|
|
183
|
+
|
|
184
|
+
def request_body_json(
|
|
185
|
+
self,
|
|
186
|
+
stream_state: Optional[Mapping[str, Any]] = None,
|
|
187
|
+
stream_slice: Optional[Mapping[str, Any]] = None,
|
|
188
|
+
next_page_token: Optional[Mapping[str, Any]] = None,
|
|
189
|
+
) -> Optional[Mapping[str, Any]]:
|
|
190
|
+
query_filter = "action:destroy AND subject_type:Product"
|
|
191
|
+
if stream_state and stream_state.get(self.cursor_field):
|
|
192
|
+
state_value = stream_state[self.cursor_field]
|
|
193
|
+
query_filter += f" AND created_at:>'{state_value}'"
|
|
194
|
+
|
|
195
|
+
variables = {
|
|
196
|
+
"first": 250,
|
|
197
|
+
"query": query_filter,
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if next_page_token and next_page_token.get("cursor"):
|
|
201
|
+
variables["after"] = next_page_token["cursor"]
|
|
202
|
+
|
|
203
|
+
return {
|
|
204
|
+
"query": self.EVENTS_QUERY,
|
|
205
|
+
"variables": variables,
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
def next_page_token(self, response: requests.Response) -> Optional[Mapping[str, Any]]:
|
|
209
|
+
json_response = response.json()
|
|
210
|
+
page_info = json_response.get("data", {}).get("events", {}).get("pageInfo", {})
|
|
211
|
+
if page_info.get("hasNextPage"):
|
|
212
|
+
return {"cursor": page_info.get("endCursor")}
|
|
213
|
+
return None
|
|
214
|
+
|
|
215
|
+
def parse_response(self, response: requests.Response, **kwargs) -> Iterable[Mapping]:
|
|
216
|
+
json_response = response.json()
|
|
217
|
+
events = json_response.get("data", {}).get("events", {}).get("nodes", [])
|
|
218
|
+
for event in events:
|
|
219
|
+
if event.get("subjectType") == "Product" and event.get("subjectId"):
|
|
220
|
+
subject_id = event.get("subjectId", "")
|
|
221
|
+
product_id = int(subject_id.split("/")[-1]) if "/" in subject_id else None
|
|
222
|
+
if product_id:
|
|
223
|
+
yield {
|
|
224
|
+
"id": product_id,
|
|
225
|
+
"deleted_at": event.get("createdAt"),
|
|
226
|
+
"deleted_message": event.get("message"),
|
|
227
|
+
"deleted_description": None,
|
|
228
|
+
"shop_url": self.config.get("shop"),
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
|
|
138
232
|
class MetafieldProducts(IncrementalShopifyGraphQlBulkStream):
|
|
139
233
|
parent_stream_class = Products
|
|
140
234
|
bulk_query: MetafieldProduct = MetafieldProduct
|
|
@@ -407,10 +501,7 @@ class Countries(HttpSubStream, FullRefreshShopifyGraphQlBulkStream):
|
|
|
407
501
|
stream_slice: Optional[Mapping[str, Any]] = None,
|
|
408
502
|
next_page_token: Optional[Mapping[str, Any]] = None,
|
|
409
503
|
) -> Optional[Mapping[str, Any]]:
|
|
410
|
-
|
|
411
|
-
if not profile_location_groups:
|
|
412
|
-
return None
|
|
413
|
-
location_group_id = profile_location_groups[0]["locationGroup"]["id"]
|
|
504
|
+
location_group_id = stream_slice["parent"]["profile_location_groups"][0]["locationGroup"]["id"]
|
|
414
505
|
return {
|
|
415
506
|
"query": self.query(location_group_id=location_group_id, location_group_zones_cursor=self._sub_page_cursor).get(
|
|
416
507
|
query_args={
|
|
File without changes
|