lucid-shopify 0.51.0 → 0.52.0

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.
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