shopify_api 14.4.0 → 14.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +7 -0
  3. data/Gemfile.lock +1 -1
  4. data/docs/usage/custom_apps.md +32 -1
  5. data/docs/usage/webhooks.md +3 -2
  6. data/lib/shopify_api/clients/graphql/client.rb +12 -2
  7. data/lib/shopify_api/clients/graphql/storefront.rb +10 -2
  8. data/lib/shopify_api/rest/base.rb +7 -1
  9. data/lib/shopify_api/rest/resources/2022_04/customer.rb +1 -0
  10. data/lib/shopify_api/rest/resources/2022_04/recurring_application_charge.rb +9 -0
  11. data/lib/shopify_api/rest/resources/2022_04/shop.rb +10 -0
  12. data/lib/shopify_api/rest/resources/2022_07/customer.rb +1 -0
  13. data/lib/shopify_api/rest/resources/2022_07/recurring_application_charge.rb +9 -0
  14. data/lib/shopify_api/rest/resources/2022_07/shop.rb +10 -0
  15. data/lib/shopify_api/rest/resources/2022_10/customer.rb +1 -0
  16. data/lib/shopify_api/rest/resources/2022_10/recurring_application_charge.rb +9 -0
  17. data/lib/shopify_api/rest/resources/2022_10/shop.rb +10 -0
  18. data/lib/shopify_api/rest/resources/2023_01/customer.rb +1 -0
  19. data/lib/shopify_api/rest/resources/2023_01/recurring_application_charge.rb +9 -0
  20. data/lib/shopify_api/rest/resources/2023_01/shop.rb +10 -0
  21. data/lib/shopify_api/rest/resources/2023_04/customer.rb +1 -0
  22. data/lib/shopify_api/rest/resources/2023_04/recurring_application_charge.rb +9 -0
  23. data/lib/shopify_api/rest/resources/2023_04/shop.rb +10 -0
  24. data/lib/shopify_api/rest/resources/2023_07/customer.rb +1 -0
  25. data/lib/shopify_api/rest/resources/2023_07/recurring_application_charge.rb +9 -0
  26. data/lib/shopify_api/rest/resources/2023_07/shop.rb +10 -0
  27. data/lib/shopify_api/rest/resources/2023_10/customer.rb +1 -0
  28. data/lib/shopify_api/rest/resources/2023_10/recurring_application_charge.rb +9 -0
  29. data/lib/shopify_api/rest/resources/2023_10/shop.rb +10 -0
  30. data/lib/shopify_api/rest/resources/2024_01/customer.rb +1 -0
  31. data/lib/shopify_api/rest/resources/2024_01/recurring_application_charge.rb +9 -0
  32. data/lib/shopify_api/rest/resources/2024_01/shop.rb +10 -0
  33. data/lib/shopify_api/rest/resources/2024_04/customer.rb +1 -0
  34. data/lib/shopify_api/rest/resources/2024_04/recurring_application_charge.rb +9 -0
  35. data/lib/shopify_api/rest/resources/2024_04/shop.rb +10 -0
  36. data/lib/shopify_api/rest/resources/2024_07/customer.rb +2 -0
  37. data/lib/shopify_api/rest/resources/2024_07/recurring_application_charge.rb +8 -0
  38. data/lib/shopify_api/rest/resources/2024_07/shop.rb +10 -0
  39. data/lib/shopify_api/utils/attributes_comparator.rb +21 -4
  40. data/lib/shopify_api/version.rb +1 -1
  41. data/sorbet/rbi/shims/hash.rb +3 -0
  42. metadata +4 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cc6cb9b900f3eba7d192c4d5091308edeaff8245517254af586192f72f57417c
4
- data.tar.gz: bb86d0654b8aa58ce70c017707ac700cb51094467608119d75d2235942483d85
3
+ metadata.gz: 8b9b61bc6316148fcd2d905384def067e31b4fca5265bb1327a7502020ee6104
4
+ data.tar.gz: b3971fadf5e0159a68953fee0883be0a6fb5f366d0a25f39201cc6c134caa0bb
5
5
  SHA512:
6
- metadata.gz: d7a256c3ce166b787b5a21d228fe25d73fc2ea1f0bbe2fca6896c3c07bae3300336c1c2efc7943d7a0096cdfd99bd0938d81fe1c097a39b2ef2f9ee931edbea2
7
- data.tar.gz: 42c03e72834f764f6435c7f81286ef45502a36819ce4647eb6a346eb48e349d6f6f59dd5913bef591d4a45ae95e339d6bea9c016109d9d6bec0c077fc86bf29c
6
+ metadata.gz: 845bcdfac189ab0b17a07540c7cad3ba3621bbc83622d16b32a143f37eaaf9909499beb8791a2f0a0b6726e8283f833c5f1702ae804bbe38393ee5d6fa0fef67
7
+ data.tar.gz: f0216976a29a1b59ab8bf89316d3ccc9b3cbda4a42b81490cb5e25af19d9cf2b2b196484397816decdde75065f387e1f9bfddd5d82a42c110be8f13654c6f8d9
data/CHANGELOG.md CHANGED
@@ -4,6 +4,13 @@ Note: For changes to the API, see https://shopify.dev/changelog?filter=api
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ ## 14.5.0
8
+
9
+ - [#1327](https://github.com/Shopify/shopify-api-ruby/pull/1327) Support `?debug=true` parameter in GraphQL client requests
10
+ - [#1308](https://github.com/Shopify/shopify-api-ruby/pull/1308) Support hash_with_indifferent_access when creating REST objects from Shopify responses. Closes #1296
11
+ - [#1332](https://github.com/Shopify/shopify-api-ruby/pull/1332) Fixed an issue where `Customer` REST API PUT requests didn't send all of the fields in the `email_marketing_consent` attribute
12
+ - [#1335](https://github.com/Shopify/shopify-api-ruby/pull/1335) Add back the `current` methods for `Shop` and `RecurringApplicationCharge` resources
13
+
7
14
  ## 14.4.0
8
15
 
9
16
  - [#1325](https://github.com/Shopify/shopify-api-ruby/pull/1325) Add support for 2024-07 API version
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- shopify_api (14.4.0)
4
+ shopify_api (14.5.0)
5
5
  activesupport
6
6
  concurrent-ruby
7
7
  hash_diff
@@ -53,6 +53,15 @@ def configure_app
53
53
  access_token: "the_token_for_your_custom_app_found_in_admin"
54
54
  )
55
55
 
56
+ ShopifyAPI::Context.setup(
57
+ api_key: "<api-key>",
58
+ api_secret_key: "<api-secret-key>",
59
+ scope: "read_orders,read_products,etc",
60
+ is_embedded: true, # Set to true if you are building an embedded app
61
+ api_version: "2024-01", # The version of the API you would like to use
62
+ is_private: true, # Set to true if you have an existing private app
63
+ )
64
+
56
65
  # Activate session to be used in all API calls
57
66
  # session must be type `ShopifyAPI::Auth::Session`
58
67
  ShopifyAPI::Context.activate_session(session)
@@ -62,9 +71,31 @@ end
62
71
  def make_api_request
63
72
  # 1. Create API client without session information
64
73
  # The graphql_client will use `ShopifyAPI::Context.active_session` when making API calls
65
- graphql_client = ShopifyAPI::Clients::Graphql::Admin.new
74
+ # you can set the api version for your GraphQL client to override the api version in ShopifyAPI::Context
75
+ graphql_client = ShopifyAPI::Clients::Graphql::Admin.new(api_version: "2024-07")
66
76
 
67
77
  # 2. Use API client to make queries
78
+ # Graphql
79
+ query = <<~QUERY
80
+ {
81
+ products(first: 10) {
82
+ edges {
83
+ cursor
84
+ node {
85
+ id
86
+ title
87
+ onlineStoreUrl
88
+ }
89
+ }
90
+ }
91
+ }
92
+ QUERY
93
+
94
+ response = graphql_client.query(query: query)
95
+
96
+ # Use REST resources to make authenticated API call
97
+ product_count = ShopifyAPI::Product.count
98
+
68
99
  ...
69
100
  end
70
101
 
@@ -21,8 +21,9 @@ module WebhookHandler
21
21
  extend ShopifyAPI::Webhooks::WebhookHandler
22
22
 
23
23
  class << self
24
- def handle_webhook(data:)
25
- puts "Received webhook! topic: #{data.topic} shop: #{data.shop} body: #{data.body} webhook_id: #{data.webhook_id} api_version: #{data.api_version"
24
+ def handle(data:)
25
+ puts "Received webhook! topic: #{data.topic} shop: #{data.shop} body: #{data.body} webhook_id: #{data.webhook_id} api_version: #{data.api_version}"
26
+ perform_later(topic: data.topic, shop_domain: data.shop, webhook: data.body)
26
27
  end
27
28
  end
28
29
  end
@@ -29,14 +29,24 @@ module ShopifyAPI
29
29
  headers: T.nilable(T::Hash[T.any(Symbol, String), T.untyped]),
30
30
  tries: Integer,
31
31
  response_as_struct: T.nilable(T::Boolean),
32
+ debug: T::Boolean,
32
33
  ).returns(HttpResponse)
33
34
  end
34
- def query(query:, variables: nil, headers: nil, tries: 1, response_as_struct: Context.response_as_struct)
35
+ def query(
36
+ query:,
37
+ variables: nil,
38
+ headers: nil,
39
+ tries: 1,
40
+ response_as_struct: Context.response_as_struct,
41
+ debug: false
42
+ )
35
43
  body = { query: query, variables: variables }
44
+ search_params = debug ? "?debug=true" : ""
45
+
36
46
  @http_client.request(
37
47
  HttpRequest.new(
38
48
  http_method: :post,
39
- path: "#{@api_version}/graphql.json",
49
+ path: "#{@api_version}/graphql.json#{search_params}",
40
50
  body: body,
41
51
  query: nil,
42
52
  extra_headers: headers,
@@ -46,12 +46,20 @@ module ShopifyAPI
46
46
  headers: T.nilable(T::Hash[T.any(Symbol, String), T.untyped]),
47
47
  tries: Integer,
48
48
  response_as_struct: T.nilable(T::Boolean),
49
+ debug: T::Boolean,
49
50
  ).returns(HttpResponse)
50
51
  end
51
- def query(query:, variables: nil, headers: {}, tries: 1, response_as_struct: Context.response_as_struct)
52
+ def query(
53
+ query:,
54
+ variables: nil,
55
+ headers: {},
56
+ tries: 1,
57
+ response_as_struct: Context.response_as_struct,
58
+ debug: false
59
+ )
52
60
  T.must(headers).merge!({ @storefront_auth_header => @storefront_access_token })
53
61
  super(query: query, variables: variables, headers: headers, tries: tries,
54
- response_as_struct: response_as_struct)
62
+ response_as_struct: response_as_struct, debug: debug)
55
63
  end
56
64
  end
57
65
  end
@@ -2,6 +2,7 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "active_support/inflector"
5
+ require "active_support/core_ext/hash/indifferent_access"
5
6
 
6
7
  module ShopifyAPI
7
8
  module Rest
@@ -16,6 +17,7 @@ module ShopifyAPI
16
17
  @paths = T.let([], T::Array[T::Hash[Symbol, T.any(T::Array[Symbol], String, Symbol)]])
17
18
  @custom_prefix = T.let(nil, T.nilable(String))
18
19
  @read_only_attributes = T.let([], T.nilable(T::Array[Symbol]))
20
+ @atomic_hash_attributes = T.let([], T::Array[Symbol])
19
21
  @aliased_properties = T.let({}, T::Hash[String, String])
20
22
 
21
23
  sig { returns(T::Hash[Symbol, T.untyped]) }
@@ -61,6 +63,9 @@ module ShopifyAPI
61
63
  sig { returns(T::Hash[Symbol, T::Class[T.anything]]) }
62
64
  attr_reader :has_one
63
65
 
66
+ sig { returns(T.nilable(T::Array[Symbol])) }
67
+ attr_reader :atomic_hash_attributes
68
+
64
69
  sig { returns(T.nilable(T::Hash[T.any(Symbol, String), String])) }
65
70
  attr_accessor :headers
66
71
 
@@ -248,7 +253,7 @@ module ShopifyAPI
248
253
  def create_instances_from_response(response:, session:)
249
254
  objects = []
250
255
 
251
- body = T.cast(response.body, T::Hash[String, T.untyped])
256
+ body = T.cast(response.body, T::Hash[String, T.untyped]).with_indifferent_access
252
257
 
253
258
  response_names = json_response_body_names
254
259
 
@@ -417,6 +422,7 @@ module ShopifyAPI
417
422
  ShopifyAPI::Utils::AttributesComparator.compare(
418
423
  stringified_updatable_attributes,
419
424
  stringified_new_attributes,
425
+ atomic_hash_attributes: self.class.atomic_hash_attributes || [],
420
426
  )
421
427
  end
422
428
 
@@ -55,6 +55,7 @@ module ShopifyAPI
55
55
  metafield: Metafield
56
56
  }, T::Hash[Symbol, Class])
57
57
  @has_many = T.let({}, T::Hash[Symbol, Class])
58
+ @atomic_hash_attributes = [:email_marketing_consent]
58
59
  @paths = T.let([
59
60
  {http_method: :delete, operation: :delete, ids: [:id], path: "customers/<id>.json"},
60
61
  {http_method: :get, operation: :count, ids: [], path: "customers/count.json"},
@@ -149,6 +149,15 @@ module ShopifyAPI
149
149
  T.cast(response, T::Array[RecurringApplicationCharge])
150
150
  end
151
151
 
152
+ sig do
153
+ params(session: Auth::Session)
154
+ .returns(T.nilable(RecurringApplicationCharge))
155
+ end
156
+ def current(session: ShopifyAPI::Context.active_session)
157
+ charges = all(session: session)
158
+ charges.select { |charge| charge.status == "active" }.first
159
+ end
160
+
152
161
  end
153
162
 
154
163
  sig do
@@ -216,6 +216,16 @@ module ShopifyAPI
216
216
  T.cast(response, T::Array[Shop])
217
217
  end
218
218
 
219
+ sig do
220
+ params(
221
+ fields: T.untyped,
222
+ session: Auth::Session,
223
+ ).returns(T.nilable(Shop))
224
+ end
225
+ def current(fields: nil, session: ShopifyAPI::Context.active_session)
226
+ all(session: session, fields: fields).first
227
+ end
228
+
219
229
  end
220
230
 
221
231
  end
@@ -55,6 +55,7 @@ module ShopifyAPI
55
55
  metafield: Metafield
56
56
  }, T::Hash[Symbol, Class])
57
57
  @has_many = T.let({}, T::Hash[Symbol, Class])
58
+ @atomic_hash_attributes = [:email_marketing_consent]
58
59
  @paths = T.let([
59
60
  {http_method: :delete, operation: :delete, ids: [:id], path: "customers/<id>.json"},
60
61
  {http_method: :get, operation: :count, ids: [], path: "customers/count.json"},
@@ -149,6 +149,15 @@ module ShopifyAPI
149
149
  T.cast(response, T::Array[RecurringApplicationCharge])
150
150
  end
151
151
 
152
+ sig do
153
+ params(session: Auth::Session)
154
+ .returns(T.nilable(RecurringApplicationCharge))
155
+ end
156
+ def current(session: ShopifyAPI::Context.active_session)
157
+ charges = all(session: session)
158
+ charges.select { |charge| charge.status == "active" }.first
159
+ end
160
+
152
161
  end
153
162
 
154
163
  sig do
@@ -216,6 +216,16 @@ module ShopifyAPI
216
216
  T.cast(response, T::Array[Shop])
217
217
  end
218
218
 
219
+ sig do
220
+ params(
221
+ fields: T.untyped,
222
+ session: Auth::Session,
223
+ ).returns(T.nilable(Shop))
224
+ end
225
+ def current(fields: nil, session: ShopifyAPI::Context.active_session)
226
+ all(session: session, fields: fields).first
227
+ end
228
+
219
229
  end
220
230
 
221
231
  end
@@ -55,6 +55,7 @@ module ShopifyAPI
55
55
  metafield: Metafield
56
56
  }, T::Hash[Symbol, Class])
57
57
  @has_many = T.let({}, T::Hash[Symbol, Class])
58
+ @atomic_hash_attributes = [:email_marketing_consent]
58
59
  @paths = T.let([
59
60
  {http_method: :delete, operation: :delete, ids: [:id], path: "customers/<id>.json"},
60
61
  {http_method: :get, operation: :count, ids: [], path: "customers/count.json"},
@@ -149,6 +149,15 @@ module ShopifyAPI
149
149
  T.cast(response, T::Array[RecurringApplicationCharge])
150
150
  end
151
151
 
152
+ sig do
153
+ params(session: Auth::Session)
154
+ .returns(T.nilable(RecurringApplicationCharge))
155
+ end
156
+ def current(session: ShopifyAPI::Context.active_session)
157
+ charges = all(session: session)
158
+ charges.select { |charge| charge.status == "active" }.first
159
+ end
160
+
152
161
  end
153
162
 
154
163
  sig do
@@ -216,6 +216,16 @@ module ShopifyAPI
216
216
  T.cast(response, T::Array[Shop])
217
217
  end
218
218
 
219
+ sig do
220
+ params(
221
+ fields: T.untyped,
222
+ session: Auth::Session,
223
+ ).returns(T.nilable(Shop))
224
+ end
225
+ def current(fields: nil, session: ShopifyAPI::Context.active_session)
226
+ all(session: session, fields: fields).first
227
+ end
228
+
219
229
  end
220
230
 
221
231
  end
@@ -55,6 +55,7 @@ module ShopifyAPI
55
55
  metafield: Metafield
56
56
  }, T::Hash[Symbol, Class])
57
57
  @has_many = T.let({}, T::Hash[Symbol, Class])
58
+ @atomic_hash_attributes = [:email_marketing_consent]
58
59
  @paths = T.let([
59
60
  {http_method: :delete, operation: :delete, ids: [:id], path: "customers/<id>.json"},
60
61
  {http_method: :get, operation: :count, ids: [], path: "customers/count.json"},
@@ -149,6 +149,15 @@ module ShopifyAPI
149
149
  T.cast(response, T::Array[RecurringApplicationCharge])
150
150
  end
151
151
 
152
+ sig do
153
+ params(session: Auth::Session)
154
+ .returns(T.nilable(RecurringApplicationCharge))
155
+ end
156
+ def current(session: ShopifyAPI::Context.active_session)
157
+ charges = all(session: session)
158
+ charges.select { |charge| charge.status == "active" }.first
159
+ end
160
+
152
161
  end
153
162
 
154
163
  sig do
@@ -216,6 +216,16 @@ module ShopifyAPI
216
216
  T.cast(response, T::Array[Shop])
217
217
  end
218
218
 
219
+ sig do
220
+ params(
221
+ fields: T.untyped,
222
+ session: Auth::Session,
223
+ ).returns(T.nilable(Shop))
224
+ end
225
+ def current(fields: nil, session: ShopifyAPI::Context.active_session)
226
+ all(session: session, fields: fields).first
227
+ end
228
+
219
229
  end
220
230
 
221
231
  end
@@ -55,6 +55,7 @@ module ShopifyAPI
55
55
  metafield: Metafield
56
56
  }, T::Hash[Symbol, Class])
57
57
  @has_many = T.let({}, T::Hash[Symbol, Class])
58
+ @atomic_hash_attributes = [:email_marketing_consent]
58
59
  @paths = T.let([
59
60
  {http_method: :delete, operation: :delete, ids: [:id], path: "customers/<id>.json"},
60
61
  {http_method: :get, operation: :count, ids: [], path: "customers/count.json"},
@@ -149,6 +149,15 @@ module ShopifyAPI
149
149
  T.cast(response, T::Array[RecurringApplicationCharge])
150
150
  end
151
151
 
152
+ sig do
153
+ params(session: Auth::Session)
154
+ .returns(T.nilable(RecurringApplicationCharge))
155
+ end
156
+ def current(session: ShopifyAPI::Context.active_session)
157
+ charges = all(session: session)
158
+ charges.select { |charge| charge.status == "active" }.first
159
+ end
160
+
152
161
  end
153
162
 
154
163
  sig do
@@ -216,6 +216,16 @@ module ShopifyAPI
216
216
  T.cast(response, T::Array[Shop])
217
217
  end
218
218
 
219
+ sig do
220
+ params(
221
+ fields: T.untyped,
222
+ session: Auth::Session,
223
+ ).returns(T.nilable(Shop))
224
+ end
225
+ def current(fields: nil, session: ShopifyAPI::Context.active_session)
226
+ all(session: session, fields: fields).first
227
+ end
228
+
219
229
  end
220
230
 
221
231
  end
@@ -55,6 +55,7 @@ module ShopifyAPI
55
55
  metafield: Metafield
56
56
  }, T::Hash[Symbol, Class])
57
57
  @has_many = T.let({}, T::Hash[Symbol, Class])
58
+ @atomic_hash_attributes = [:email_marketing_consent]
58
59
  @paths = T.let([
59
60
  {http_method: :delete, operation: :delete, ids: [:id], path: "customers/<id>.json"},
60
61
  {http_method: :get, operation: :count, ids: [], path: "customers/count.json"},
@@ -149,6 +149,15 @@ module ShopifyAPI
149
149
  T.cast(response, T::Array[RecurringApplicationCharge])
150
150
  end
151
151
 
152
+ sig do
153
+ params(session: Auth::Session)
154
+ .returns(T.nilable(RecurringApplicationCharge))
155
+ end
156
+ def current(session: ShopifyAPI::Context.active_session)
157
+ charges = all(session: session)
158
+ charges.select { |charge| charge.status == "active" }.first
159
+ end
160
+
152
161
  end
153
162
 
154
163
  sig do
@@ -216,6 +216,16 @@ module ShopifyAPI
216
216
  T.cast(response, T::Array[Shop])
217
217
  end
218
218
 
219
+ sig do
220
+ params(
221
+ fields: T.untyped,
222
+ session: Auth::Session,
223
+ ).returns(T.nilable(Shop))
224
+ end
225
+ def current(fields: nil, session: ShopifyAPI::Context.active_session)
226
+ all(session: session, fields: fields).first
227
+ end
228
+
219
229
  end
220
230
 
221
231
  end
@@ -55,6 +55,7 @@ module ShopifyAPI
55
55
  metafield: Metafield
56
56
  }, T::Hash[Symbol, Class])
57
57
  @has_many = T.let({}, T::Hash[Symbol, Class])
58
+ @atomic_hash_attributes = [:email_marketing_consent]
58
59
  @paths = T.let([
59
60
  {http_method: :delete, operation: :delete, ids: [:id], path: "customers/<id>.json"},
60
61
  {http_method: :get, operation: :count, ids: [], path: "customers/count.json"},
@@ -149,6 +149,15 @@ module ShopifyAPI
149
149
  T.cast(response, T::Array[RecurringApplicationCharge])
150
150
  end
151
151
 
152
+ sig do
153
+ params(session: Auth::Session)
154
+ .returns(T.nilable(RecurringApplicationCharge))
155
+ end
156
+ def current(session: ShopifyAPI::Context.active_session)
157
+ charges = all(session: session)
158
+ charges.select { |charge| charge.status == "active" }.first
159
+ end
160
+
152
161
  end
153
162
 
154
163
  sig do
@@ -216,6 +216,16 @@ module ShopifyAPI
216
216
  T.cast(response, T::Array[Shop])
217
217
  end
218
218
 
219
+ sig do
220
+ params(
221
+ fields: T.untyped,
222
+ session: Auth::Session,
223
+ ).returns(T.nilable(Shop))
224
+ end
225
+ def current(fields: nil, session: ShopifyAPI::Context.active_session)
226
+ all(session: session, fields: fields).first
227
+ end
228
+
219
229
  end
220
230
 
221
231
  end
@@ -55,6 +55,7 @@ module ShopifyAPI
55
55
  metafield: Metafield
56
56
  }, T::Hash[Symbol, Class])
57
57
  @has_many = T.let({}, T::Hash[Symbol, Class])
58
+ @atomic_hash_attributes = [:email_marketing_consent]
58
59
  @paths = T.let([
59
60
  {http_method: :delete, operation: :delete, ids: [:id], path: "customers/<id>.json"},
60
61
  {http_method: :get, operation: :count, ids: [], path: "customers/count.json"},
@@ -149,6 +149,15 @@ module ShopifyAPI
149
149
  T.cast(response, T::Array[RecurringApplicationCharge])
150
150
  end
151
151
 
152
+ sig do
153
+ params(session: Auth::Session)
154
+ .returns(T.nilable(RecurringApplicationCharge))
155
+ end
156
+ def current(session: ShopifyAPI::Context.active_session)
157
+ charges = all(session: session)
158
+ charges.select { |charge| charge.status == "active" }.first
159
+ end
160
+
152
161
  end
153
162
 
154
163
  sig do
@@ -216,6 +216,16 @@ module ShopifyAPI
216
216
  T.cast(response, T::Array[Shop])
217
217
  end
218
218
 
219
+ sig do
220
+ params(
221
+ fields: T.untyped,
222
+ session: Auth::Session,
223
+ ).returns(T.nilable(Shop))
224
+ end
225
+ def current(fields: nil, session: ShopifyAPI::Context.active_session)
226
+ all(session: session, fields: fields).first
227
+ end
228
+
219
229
  end
220
230
 
221
231
  end
@@ -55,6 +55,7 @@ module ShopifyAPI
55
55
  metafield: Metafield
56
56
  }, T::Hash[Symbol, Class])
57
57
  @has_many = T.let({}, T::Hash[Symbol, Class])
58
+ @atomic_hash_attributes = [:email_marketing_consent]
58
59
  @paths = T.let([
59
60
  {http_method: :delete, operation: :delete, ids: [:id], path: "customers/<id>.json"},
60
61
  {http_method: :get, operation: :count, ids: [], path: "customers/count.json"},
@@ -149,6 +149,15 @@ module ShopifyAPI
149
149
  T.cast(response, T::Array[RecurringApplicationCharge])
150
150
  end
151
151
 
152
+ sig do
153
+ params(session: Auth::Session)
154
+ .returns(T.nilable(RecurringApplicationCharge))
155
+ end
156
+ def current(session: ShopifyAPI::Context.active_session)
157
+ charges = all(session: session)
158
+ charges.select { |charge| charge.status == "active" }.first
159
+ end
160
+
152
161
  end
153
162
 
154
163
  sig do
@@ -216,6 +216,16 @@ module ShopifyAPI
216
216
  T.cast(response, T::Array[Shop])
217
217
  end
218
218
 
219
+ sig do
220
+ params(
221
+ fields: T.untyped,
222
+ session: Auth::Session,
223
+ ).returns(T.nilable(Shop))
224
+ end
225
+ def current(fields: nil, session: ShopifyAPI::Context.active_session)
226
+ all(session: session, fields: fields).first
227
+ end
228
+
219
229
  end
220
230
 
221
231
  end
@@ -22,6 +22,7 @@ module ShopifyAPI
22
22
  @accepts_marketing_updated_at = T.let(nil, T.nilable(String))
23
23
  @addresses = T.let(nil, T.nilable(T::Array[T.untyped]))
24
24
  @created_at = T.let(nil, T.nilable(String))
25
+
25
26
  @currency = T.let(nil, T.nilable(String))
26
27
  @default_address = T.let(nil, T.nilable(T::Hash[T.untyped, T.untyped]))
27
28
  @email = T.let(nil, T.nilable(String))
@@ -55,6 +56,7 @@ module ShopifyAPI
55
56
  metafield: Metafield
56
57
  }, T::Hash[Symbol, Class])
57
58
  @has_many = T.let({}, T::Hash[Symbol, Class])
59
+ @atomic_hash_attributes = [:email_marketing_consent]
58
60
  @paths = T.let([
59
61
  {http_method: :delete, operation: :delete, ids: [:id], path: "customers/<id>.json"},
60
62
  {http_method: :get, operation: :count, ids: [], path: "customers/count.json"},
@@ -149,6 +149,14 @@ module ShopifyAPI
149
149
  T.cast(response, T::Array[RecurringApplicationCharge])
150
150
  end
151
151
 
152
+ sig do
153
+ params(session: Auth::Session)
154
+ .returns(T.nilable(RecurringApplicationCharge))
155
+ end
156
+ def current(session: ShopifyAPI::Context.active_session)
157
+ charges = all(session: session)
158
+ charges.select { |charge| charge.status == "active" }.first
159
+ end
152
160
  end
153
161
 
154
162
  sig do
@@ -216,6 +216,16 @@ module ShopifyAPI
216
216
  T.cast(response, T::Array[Shop])
217
217
  end
218
218
 
219
+ sig do
220
+ params(
221
+ fields: T.untyped,
222
+ session: Auth::Session,
223
+ ).returns(T.nilable(Shop))
224
+ end
225
+ def current(fields: nil, session: ShopifyAPI::Context.active_session)
226
+ all(session: session, fields: fields).first
227
+ end
228
+
219
229
  end
220
230
 
221
231
  end
@@ -13,9 +13,10 @@ module ShopifyAPI
13
13
  params(
14
14
  original_attributes: T::Hash[String, T.untyped],
15
15
  updated_attributes: T::Hash[String, T.untyped],
16
+ atomic_hash_attributes: T::Array[Symbol],
16
17
  ).returns(T::Hash[String, T.untyped])
17
18
  end
18
- def compare(original_attributes, updated_attributes)
19
+ def compare(original_attributes, updated_attributes, atomic_hash_attributes: [])
19
20
  attributes_diff = HashDiff::Comparison.new(
20
21
  original_attributes,
21
22
  updated_attributes,
@@ -24,6 +25,7 @@ module ShopifyAPI
24
25
  update_value = build_update_value(
25
26
  attributes_diff,
26
27
  reference_values: updated_attributes,
28
+ atomic_hash_attributes: atomic_hash_attributes,
27
29
  )
28
30
 
29
31
  update_value
@@ -34,9 +36,10 @@ module ShopifyAPI
34
36
  diff: T::Hash[String, T.untyped],
35
37
  path: T::Array[String],
36
38
  reference_values: T::Hash[String, T.untyped],
39
+ atomic_hash_attributes: T::Array[Symbol],
37
40
  ).returns(T::Hash[String, T.untyped])
38
41
  end
39
- def build_update_value(diff, path: [], reference_values: {})
42
+ def build_update_value(diff, path: [], reference_values: {}, atomic_hash_attributes: [])
40
43
  new_hash = {}
41
44
 
42
45
  diff.each do |key, value|
@@ -49,7 +52,19 @@ module ShopifyAPI
49
52
  if has_numbered_key && ref_value.is_a?(Array)
50
53
  new_hash[key] = ref_value
51
54
  else
52
- new_value = build_update_value(value, path: current_path, reference_values: reference_values)
55
+ new_value = build_update_value(
56
+ value,
57
+ path: current_path,
58
+ reference_values: reference_values,
59
+ atomic_hash_attributes: atomic_hash_attributes,
60
+ )
61
+
62
+ atomic_update = atomic_hash_attributes.include?(key.to_sym)
63
+
64
+ # If the key is in atomic_hash_attributes, we use the entire reference value
65
+ # so we update the hash as a whole.
66
+ if !new_value.empty? && !ref_value.empty? && atomic_update
67
+ new_hash[key] = ref_value
53
68
 
54
69
  # Only add to new_hash if the user intentionally updates
55
70
  # to empty value like `{}` or `[]`. For example:
@@ -70,7 +85,9 @@ module ShopifyAPI
70
85
  # new_hash = {}
71
86
  #
72
87
  # new_hash is empty because nothing changes
73
- new_hash[key] = new_value if !new_value.empty? || ref_value.empty?
88
+ elsif !new_value.empty? || ref_value.empty?
89
+ new_hash[key] = new_value
90
+ end
74
91
  end
75
92
  elsif value != HashDiff::NO_VALUE
76
93
  new_hash[key] = value
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module ShopifyAPI
5
- VERSION = "14.4.0"
5
+ VERSION = "14.5.0"
6
6
  end
@@ -0,0 +1,3 @@
1
+ class Hash
2
+ def with_indifferent_access; end
3
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shopify_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 14.4.0
4
+ version: 14.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shopify
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-07-02 00:00:00.000000000 Z
11
+ date: 2024-08-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -1058,6 +1058,7 @@ files:
1058
1058
  - sorbet/rbi/gems/yard@0.9.27.rbi
1059
1059
  - sorbet/rbi/gems/zeitwerk@2.5.4.rbi
1060
1060
  - sorbet/rbi/shims/fakefs.rbi
1061
+ - sorbet/rbi/shims/hash.rb
1061
1062
  - sorbet/rbi/shims/openssl.rb
1062
1063
  - sorbet/rbi/todo.rbi
1063
1064
  - sorbet/tapioca/config.yml
@@ -1083,7 +1084,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
1083
1084
  - !ruby/object:Gem::Version
1084
1085
  version: '0'
1085
1086
  requirements: []
1086
- rubygems_version: 3.5.14
1087
+ rubygems_version: 3.5.17
1087
1088
  signing_key:
1088
1089
  specification_version: 4
1089
1090
  summary: The gem for accessing the Shopify API