lucid-shopify 0.51.0 → 0.52.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: 0bde6faec2cf0c1f3aebaa448053cfd08de85aaf84886fc4dfac7ee54c9b16d4
4
- data.tar.gz: 9d88ca4bf4e318ecb84095c11e6ed4a7cf1466851a67bbbf9737f2be9c612040
3
+ metadata.gz: 507adadf48406a163883bd19d27f719b1e08c79449d62b02c3ed4489d34cf337
4
+ data.tar.gz: c9e9b5b1b9b07fce620b124739b572cac79eddc9a3a333fa89f662aa940f9e87
5
5
  SHA512:
6
- metadata.gz: 15792eae82caf1d7b9990a9c18c8ef4d38a5c1a42ce9b644e2628db014d38b9316fe6c3ecc007581a0c8022ba4e93c0763b1c1ddffc69a72e2a802da21966a34
7
- data.tar.gz: 9b85663e3679692a27ad2022527f101a4ac00586f044b85c3e68fae3851425c6c20d29cfa9ebe6ea55f3b45055642ad845f024d8e59ea2d7df20dd7a350fe19d
6
+ metadata.gz: 0a8301132bce1d3b8a11715eb9184cd948022edc1f509c270490d39d0923cf449dab1fb45eac7a6422c6b65794377c89697332fa285759e85aff5356cdb8a2f1
7
+ data.tar.gz: 7fafaa11ece1d2358468fad162a2ece4cfced8c1cc4525b67f065ac1e144c8043ff44dedfc9d3e760bd6301b760f9476721d5ff885368b033232c1ff86aef14d
data/README.md CHANGED
@@ -101,20 +101,24 @@ 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, <<~QUERY) do |product|
104
+ client.bulk(credentials).around do |&y|
105
+ db.transaction { y.() }
106
+ end.(<<~QUERY) do |product|
105
107
  {
106
108
  products {
107
109
  edges {
108
110
  node {
109
111
  id
110
- title
112
+ handle
111
113
  }
112
114
  }
113
115
  }
114
116
  }
115
117
  QUERY
116
- puts product['id']
117
- puts product['title']
118
+ db[:products].insert(
119
+ id: product['id'],
120
+ handle: product['handle'],
121
+ )
118
122
  end
119
123
 
120
124
 
@@ -13,102 +13,145 @@ module Lucid
13
13
  FailedOperationError = Class.new(OperationError)
14
14
  ObsoleteOperationError = Class.new(OperationError)
15
15
 
16
- # @param http [HTTP::Client]
17
- def initialize(http: Container[:http])
18
- @http = http
16
+ class Operation
17
+ include Dry::Initializer.define -> do
18
+ # @return [Client]
19
+ param :client
20
+ # @return [Credentials]
21
+ param :credentials
22
+ end
23
+
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.
27
+ #
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
+ # @param http [HTTP::Client]
52
+ #
53
+ # @yield [Hash] each parsed line of JSONL (streamed to limit memory usage)
54
+ def call(query, http: Container[:http], &block)
55
+ id = client.post_graphql(credentials, <<~QUERY)['data']['bulkOperationRunQuery']['bulkOperation']['id']
56
+ mutation {
57
+ bulkOperationRunQuery(
58
+ query: """
59
+ #{query}
60
+ """
61
+ ) {
62
+ bulkOperation {
63
+ id
64
+ }
65
+ userErrors {
66
+ field
67
+ message
68
+ }
69
+ }
70
+ }
71
+ QUERY
72
+
73
+ url = poll(id)
74
+
75
+ # TODO: Verify signature?
76
+
77
+ begin
78
+ file = Tempfile.new(mode: 0600)
79
+ body = http.get(url).body
80
+ until (chunk = body.readpartial).nil?
81
+ file.write(chunk)
82
+ end
83
+ file.rewind
84
+ call_around do
85
+ file.each_line do |line|
86
+ block.(JSON.parse(line))
87
+ end
88
+ end
89
+ ensure
90
+ file.close
91
+ file.unlink
92
+ end
93
+ end
94
+
95
+ # @param id [Integer] of the bulk operation
96
+ #
97
+ # @return [String] the download URL
98
+ private def poll(id)
99
+ op = client.post_graphql(credentials, <<~QUERY)['data']['currentBulkOperation']
100
+ {
101
+ currentBulkOperation {
102
+ id
103
+ status
104
+ url
105
+ }
106
+ }
107
+ QUERY
108
+
109
+ raise ObsoleteOperationError if op['id'] != id
110
+
111
+ case op['status']
112
+ when 'CANCELED'
113
+ raise CanceledOperationError
114
+ when 'EXPIRED'
115
+ raise ExpiredOperationError
116
+ when 'FAILED'
117
+ raise FailedOperationError
118
+ when 'COMPLETED'
119
+ op['url']
120
+ else
121
+ poll(id)
122
+ end
123
+ end
19
124
  end
20
125
 
21
126
  # @param client [Client]
22
127
  # @param credentials [Credentials]
23
- # @param query [String]
24
128
  #
25
- # @yield [String] each parsed line of JSONL (streamed to limit memory usage)
129
+ # @return [Operation]
26
130
  #
27
131
  # @example
28
- # bulk_request.(client, credentials, <<~QUERY)
132
+ # bulk_request.(client, credentials).around do |&y|
133
+ # db.transaction { y.() }
134
+ # end.(<<~QUERY) do |product|
29
135
  # {
30
136
  # products {
31
137
  # edges {
32
138
  # node {
33
139
  # id
34
140
  # handle
35
- # publishedAt
36
141
  # }
37
142
  # }
38
143
  # }
39
144
  # }
40
145
  # QUERY
41
- def call(client, credentials, query, &block)
146
+ # db[:products].insert(
147
+ # id: product['id'],
148
+ # handle: product['handle'],
149
+ # )
150
+ # end
151
+ def call(client, credentials)
42
152
  Shopify.assert_api_version!('2019-10')
43
153
 
44
- id = client.post_graphql(credentials, <<~QUERY)['data']['bulkOperationRunQuery']['bulkOperation']['id']
45
- mutation {
46
- bulkOperationRunQuery(
47
- query: """
48
- #{query}
49
- """
50
- ) {
51
- bulkOperation {
52
- id
53
- }
54
- userErrors {
55
- field
56
- message
57
- }
58
- }
59
- }
60
- QUERY
61
-
62
- url = poll(client, credentials, id)
63
-
64
- # TODO: Verify signature?
65
-
66
- begin
67
- file = Tempfile.new(mode: 0600)
68
- body = @http.get(url).body
69
- until (chunk = body.readpartial).nil?
70
- file.write(chunk)
71
- end
72
- file.rewind
73
- file.each_line do |line|
74
- block.call(JSON.parse(line))
75
- end
76
- ensure
77
- file.close
78
- file.unlink
79
- end
80
- end
81
-
82
- # @param client [Client]
83
- # @param credentials [Credentials]
84
- # @param id [Integer] of the bulk operation
85
- #
86
- # @return [String] the download URL
87
- private def poll(client, credentials, id)
88
- op = client.post_graphql(credentials, <<~QUERY)['data']['currentBulkOperation']
89
- {
90
- currentBulkOperation {
91
- id
92
- status
93
- url
94
- }
95
- }
96
- QUERY
97
-
98
- raise ObsoleteOperationError if op['id'] != id
99
-
100
- case op['status']
101
- when 'CANCELED'
102
- raise CanceledOperationError
103
- when 'EXPIRED'
104
- raise ExpiredOperationError
105
- when 'FAILED'
106
- raise FailedOperationError
107
- when 'COMPLETED'
108
- op['url']
109
- else
110
- poll(client, credentials, id)
111
- end
154
+ Operation.new(client, credentials)
112
155
  end
113
156
  end
114
157
  end
@@ -63,8 +63,8 @@ module Lucid
63
63
  end
64
64
 
65
65
  # @see BulkRequest#call
66
- def bulk(*args, &block)
67
- @bulk_request.(self, *args, &block)
66
+ def bulk(*args)
67
+ @bulk_request.(self, *args)
68
68
  end
69
69
 
70
70
  # @see DeleteRequest#initialize
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Lucid
4
4
  module Shopify
5
- VERSION = '0.51.0'
5
+ VERSION = '0.52.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.51.0
4
+ version: 0.52.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-02-19 00:00:00.000000000 Z
11
+ date: 2020-03-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dotenv
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '12.3'
33
+ version: '13.0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '12.3'
40
+ version: '13.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement