lucid-shopify 0.57.0 → 0.60.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7c1fdb1699b2550ff42c9e707fca8a483281910066b4454c0a46472325f9ac9b
4
- data.tar.gz: fb18e1fa4164cc1753bdeae3cb6c7b7c1120fe4437faf8d270ca9b3e547a4e61
3
+ metadata.gz: a2000b0881f8f32a1ae28c1e81f75c4e10c99fb386e090087c930835453a7c20
4
+ data.tar.gz: 871ddf85d10f96e5f03c253436d4fb49f76da54ed0e1bca68428fa2ae4cd095e
5
5
  SHA512:
6
- metadata.gz: 1bcf5b74b4bd51e62df057b9280208439a376109497845794dddc78d2523ce92cc5f7dedc7385e1fc61d74d234f39db0c71f41fdeb8a3e6a98fc0a27f7788f0a
7
- data.tar.gz: 78c4ec7ec01c43338f17fc5b25129285e2a28371da9afb20c8bedbd47ec5ae5379954d66f834b4740159d69a32110cfc48f27e7eabab101a6fca36e4ac260ac8
6
+ metadata.gz: 17cbb58d6af88ebe841ff7ad8d2217512a7a11c78f40763a9061ef85e4e132d0334cce964235eed844d7d231a2657107ac3a493a091b6b2aba360d8f4042f925
7
+ data.tar.gz: bfebbb6f59bb8592827a6b3264c00bef9d3839e9236628d4e8eb91da30af9cc032e15500d389f366d4c8c7b967b8bbe75612d28d3de8658e3124fc13d1495661
data/README.md CHANGED
@@ -101,9 +101,7 @@ Since API version 2019-10, Shopify has offered an API for bulk requests (using
101
101
  the GraphQL API). The gem wraps this API, by writing the result to a temporary
102
102
  file and yielding each line of the result to limit memory usage.
103
103
 
104
- client.bulk(credentials).around do |&y|
105
- db.transaction { y.() }
106
- end.(<<~QUERY) do |product|
104
+ client.bulk(credentials, <<~QUERY) do |products|
107
105
  {
108
106
  products {
109
107
  edges {
@@ -115,12 +113,19 @@ file and yielding each line of the result to limit memory usage.
115
113
  }
116
114
  }
117
115
  QUERY
118
- db[:products].insert(
119
- id: product['id'],
120
- handle: product['handle'],
121
- )
116
+ db.transaction do
117
+ products.each do |product|
118
+ db[:products].insert(
119
+ id: product['id'],
120
+ handle: product['handle'],
121
+ )
122
+ end
123
+ end
122
124
  end
123
125
 
126
+ Bulk requests are limited to one per shop at any one time. Calling a new bulk
127
+ request via lucid-shopify will cancel any request in progress for the shop.
128
+
124
129
 
125
130
  ### Pagination
126
131
 
@@ -19,59 +19,35 @@ module Lucid
19
19
  param :client
20
20
  # @return [Credentials]
21
21
  param :credentials
22
+ # @return [String]
23
+ param :id
22
24
  end
23
25
 
24
- # Set a block which is called after the file is downloaded, and around
25
- # the line by line iteration in {#call}. The block must yield control
26
- # back to the caller.
26
+ # Wait for the operation to complete, then download the JSONL result
27
+ # data which is yielded as an {Enumerator} to the block. The data is
28
+ # streamed and parsed line by line to limit memory usage.
27
29
  #
28
- # @return [self]
29
- #
30
- # @example
31
- # operation.around do |&y|
32
- # puts 'Before iteration'
33
- # y.()
34
- # ensure
35
- # puts 'After iteration'
36
- # end
37
- def around(&block)
38
- @around = block
39
-
40
- self
41
- end
42
-
43
- # Call the block set by {#around}.
44
- #
45
- # @yield inside the wrapper block
46
- private def call_around(&block)
47
- @around.respond_to?(:call) ? @around.(&block) : block.()
48
- end
49
-
50
- # @param query [String] the GraphQL query
51
30
  # @param delay [Integer] delay between polling requests in seconds
52
31
  # @param http [HTTP::Client]
53
32
  #
54
- # @yield [Hash] each parsed line of JSONL (streamed to limit memory usage)
55
- def call(query, delay: 1, http: Container[:http], &block)
56
- id = client.post_graphql(credentials, <<~QUERY)['data']['bulkOperationRunQuery']['bulkOperation']['id']
57
- mutation {
58
- bulkOperationRunQuery(
59
- query: """
60
- #{query}
61
- """
62
- ) {
63
- bulkOperation {
64
- id
65
- }
66
- userErrors {
67
- field
68
- message
69
- }
70
- }
71
- }
72
- QUERY
73
-
74
- url = poll(id, delay: delay)
33
+ # @yield [Enumerator<Hash>] yields each parsed line of JSONL
34
+ def call(delay: 1, http: Container[:http], &block)
35
+ url = loop do
36
+ status, url = poll
37
+
38
+ case status
39
+ when 'CANCELED'
40
+ raise CanceledOperationError
41
+ when 'EXPIRED'
42
+ raise ExpiredOperationError
43
+ when 'FAILED'
44
+ raise FailedOperationError
45
+ when 'COMPLETED'
46
+ break url
47
+ else
48
+ sleep(delay)
49
+ end
50
+ end
75
51
 
76
52
  return if url.nil?
77
53
 
@@ -84,22 +60,38 @@ module Lucid
84
60
  file.write(chunk)
85
61
  end
86
62
  file.rewind
87
- call_around do
88
- file.each_line do |line|
89
- block.(JSON.parse(line))
90
- end
91
- end
63
+ block.(Enumerator.new do |y|
64
+ file.each_line { |line| y << JSON.parse(line) }
65
+ end)
92
66
  ensure
93
67
  file.close
94
68
  file.unlink
95
69
  end
96
70
  end
97
71
 
98
- # @param id [Integer] of the bulk operation
99
- # @param delay [Integer]
100
- #
101
- # @return [String, nil] the download URL, or nil if the result data is empty
102
- private def poll(id, delay:)
72
+ # Cancel the bulk operation.
73
+ def cancel
74
+ client.post_graphql(credentials, <<~QUERY)
75
+ mutation {
76
+ bulkOperationCancel(id: "#{id}") {
77
+ userErrors {
78
+ field
79
+ message
80
+ }
81
+ }
82
+ }
83
+ QUERY
84
+
85
+ loop do
86
+ status, _ = poll
87
+
88
+ break unless status == 'CANCELING'
89
+ end
90
+ end
91
+
92
+ # @return [Array(String, String | nil)] the operation status and the
93
+ # download URL, or nil if the result data is empty
94
+ private def poll
103
95
  op = client.post_graphql(credentials, <<~QUERY)['data']['currentBulkOperation']
104
96
  {
105
97
  currentBulkOperation {
@@ -112,32 +104,23 @@ module Lucid
112
104
 
113
105
  raise ObsoleteOperationError if op['id'] != id
114
106
 
115
- case op['status']
116
- when 'CANCELED'
117
- raise CanceledOperationError
118
- when 'EXPIRED'
119
- raise ExpiredOperationError
120
- when 'FAILED'
121
- raise FailedOperationError
122
- when 'COMPLETED'
123
- op['url']
124
- else
125
- sleep(delay)
126
-
127
- poll(id, delay: delay)
128
- end
107
+ [
108
+ op['status'],
109
+ op['url'],
110
+ ]
129
111
  end
130
112
  end
131
113
 
114
+ # Create and start a new bulk operation via the GraphQL API.
115
+ #
132
116
  # @param client [Client]
133
117
  # @param credentials [Credentials]
118
+ # @param query [String] the GraphQL query
134
119
  #
135
120
  # @return [Operation]
136
121
  #
137
122
  # @example
138
- # bulk_request.(client, credentials).around do |&y|
139
- # db.transaction { y.() }
140
- # end.(<<~QUERY) do |product|
123
+ # bulk_request.(client, credentials, <<~QUERY).() do |products|
141
124
  # {
142
125
  # products {
143
126
  # edges {
@@ -149,15 +132,49 @@ module Lucid
149
132
  # }
150
133
  # }
151
134
  # QUERY
152
- # db[:products].insert(
153
- # id: product['id'],
154
- # handle: product['handle'],
155
- # )
135
+ # db.transaction do
136
+ # products.each do |product|
137
+ # db[:products].insert(
138
+ # id: product['id'],
139
+ # handle: product['handle'],
140
+ # )
141
+ # end
142
+ # end
156
143
  # end
157
- def call(client, credentials)
144
+ def call(client, credentials, query)
158
145
  Shopify.assert_api_version!('2019-10')
159
146
 
160
- Operation.new(client, credentials)
147
+ op = client.post_graphql(credentials, <<~QUERY)['data']['currentBulkOperation']
148
+ {
149
+ currentBulkOperation {
150
+ id
151
+ status
152
+ url
153
+ }
154
+ }
155
+ QUERY
156
+
157
+ Operation.new(client, credentials, op['id']).cancel if op && op['status'] == 'RUNNING'
158
+
159
+ id = client.post_graphql(credentials, <<~QUERY)['data']['bulkOperationRunQuery']['bulkOperation']['id']
160
+ mutation {
161
+ bulkOperationRunQuery(
162
+ query: """
163
+ #{query}
164
+ """
165
+ ) {
166
+ bulkOperation {
167
+ id
168
+ }
169
+ userErrors {
170
+ field
171
+ message
172
+ }
173
+ }
174
+ }
175
+ QUERY
176
+
177
+ Operation.new(client, credentials, id)
161
178
  end
162
179
  end
163
180
  end
@@ -62,9 +62,15 @@ module Lucid
62
62
  AuthenticatedClient.new(self, credentials)
63
63
  end
64
64
 
65
+ # If called with a block, calls {BulkRequest::Operation#call} immediately,
66
+ # else, returns the {BulkRequest::Operation}.
67
+ #
65
68
  # @see BulkRequest#call
66
- def bulk(*args)
67
- @bulk_request.(self, *args)
69
+ # @see BulkRequest::Operation#call
70
+ def bulk(*args, &block)
71
+ op = @bulk_request.(self, *args)
72
+
73
+ block ? op.(&block) : op
68
74
  end
69
75
 
70
76
  # @see DeleteRequest#initialize
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Lucid
4
4
  module Shopify
5
- VERSION = '0.57.0'
5
+ VERSION = '0.60.0'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lucid-shopify
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.57.0
4
+ version: 0.60.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kelsey Judson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-03-15 00:00:00.000000000 Z
11
+ date: 2020-03-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dotenv