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 +4 -4
- data/README.md +8 -4
- data/lib/lucid/shopify/bulk_request.rb +119 -76
- data/lib/lucid/shopify/client.rb +2 -2
- data/lib/lucid/shopify/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 507adadf48406a163883bd19d27f719b1e08c79449d62b02c3ed4489d34cf337
|
4
|
+
data.tar.gz: c9e9b5b1b9b07fce620b124739b572cac79eddc9a3a333fa89f662aa940f9e87
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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
|
-
|
112
|
+
handle
|
111
113
|
}
|
112
114
|
}
|
113
115
|
}
|
114
116
|
}
|
115
117
|
QUERY
|
116
|
-
|
117
|
-
|
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
|
-
|
17
|
-
|
18
|
-
|
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
|
-
# @
|
129
|
+
# @return [Operation]
|
26
130
|
#
|
27
131
|
# @example
|
28
|
-
# bulk_request.(client, credentials
|
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
|
-
|
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
|
-
|
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
|
data/lib/lucid/shopify/client.rb
CHANGED
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.
|
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
|
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: '
|
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: '
|
40
|
+
version: '13.0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rspec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|