e_plat 0.2.4 → 0.4.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 +633 -135
- data/lib/active_resource/connection_error.rb +29 -0
- data/lib/active_resource/formats.rb +27 -0
- data/lib/current.rb +7 -0
- data/lib/e_plat/client/default_request_args.rb +27 -3
- data/lib/e_plat/client.rb +114 -87
- data/lib/e_plat/connection.rb +4 -0
- data/lib/e_plat/errors/missing_session_error.rb +1 -1
- data/lib/e_plat/mapping/base.rb +119 -12
- data/lib/e_plat/mapping/bigcommerce/v_3/metafield.rb +62 -0
- data/lib/e_plat/mapping/bigcommerce/v_3/order/billing_address.rb +14 -0
- data/lib/e_plat/mapping/bigcommerce/v_3/order/line_item.rb +85 -0
- data/lib/e_plat/mapping/bigcommerce/v_3/order/shipping_address.rb +73 -0
- data/lib/e_plat/mapping/bigcommerce/v_3/order.rb +160 -0
- data/lib/e_plat/mapping/bigcommerce/v_3/product/image.rb +12 -12
- data/lib/e_plat/mapping/bigcommerce/v_3/product/variant.rb +1 -1
- data/lib/e_plat/mapping/bigcommerce/v_3/script_tag.rb +78 -0
- data/lib/e_plat/mapping/bigcommerce/v_3/shop.rb +11 -6
- data/lib/e_plat/mapping/bigcommerce/v_3/webhook.rb +54 -0
- data/lib/e_plat/mapping/request_body_root.rb +38 -0
- data/lib/e_plat/mapping/shopify/v_2024_01/metafield.rb +26 -0
- data/lib/e_plat/mapping/shopify/v_2024_01/order/billing_address.rb +14 -0
- data/lib/e_plat/mapping/shopify/v_2024_01/order/shipping_address.rb +30 -0
- data/lib/e_plat/mapping/shopify/{v_2022_07/product.rb → v_2024_01/order.rb} +3 -3
- data/lib/e_plat/mapping/shopify/{v_2022_07 → v_2024_01}/product/image.rb +1 -1
- data/lib/e_plat/mapping/shopify/{v_2022_07 → v_2024_01}/product/variant.rb +2 -1
- data/lib/e_plat/mapping/shopify/v_2024_01/product.rb +26 -0
- data/lib/e_plat/mapping/shopify/v_2024_01/script_tag.rb +26 -0
- data/lib/e_plat/mapping/shopify/{v_2022_07 → v_2024_01}/shop.rb +1 -1
- data/lib/e_plat/mapping/shopify/v_2024_01/webhook.rb +29 -0
- data/lib/e_plat/mapping/virtual_collection/base.rb +14 -0
- data/lib/e_plat/mapping/virtual_collection/bigcommerce/order_line_items.rb +297 -0
- data/lib/e_plat/mapping.rb +3 -3
- data/lib/e_plat/resource/attribute_interface.rb +28 -28
- data/lib/e_plat/resource/base.rb +107 -68
- data/lib/e_plat/resource/collection.rb +92 -0
- data/lib/e_plat/resource/concerns/aliases.rb +102 -18
- data/lib/e_plat/resource/concerns/dirty.rb +54 -0
- data/lib/e_plat/resource/concerns/metafieldable.rb +43 -0
- data/lib/e_plat/resource/concerns/overwrite_instance_methods.rb +108 -6
- data/lib/e_plat/resource/concerns/overwrite_request_methods.rb +73 -37
- data/lib/e_plat/resource/countable.rb +43 -0
- data/lib/e_plat/resource/metafield.rb +70 -0
- data/lib/e_plat/resource/order/Consignment.rb +8 -0
- data/lib/e_plat/resource/order/billing_address.rb +6 -0
- data/lib/e_plat/resource/order/fulfillment.rb +1 -0
- data/lib/e_plat/resource/order/line_item.rb +1 -0
- data/lib/e_plat/resource/order/shipping_address.rb +44 -0
- data/lib/e_plat/resource/order/shipping_line.rb +15 -14
- data/lib/e_plat/resource/order.rb +32 -0
- data/lib/e_plat/resource/paginated/link_headers.rb +42 -0
- data/lib/e_plat/resource/paginated/link_params.rb +26 -0
- data/lib/e_plat/resource/product/image.rb +6 -0
- data/lib/e_plat/resource/product/option.rb +1 -0
- data/lib/e_plat/resource/product/variant.rb +8 -12
- data/lib/e_plat/resource/product.rb +8 -2
- data/lib/e_plat/resource/script_tag.rb +56 -0
- data/lib/e_plat/resource/shop.rb +17 -13
- data/lib/e_plat/resource/shopify_only/recurring_application_charge/usage_charge.rb +32 -0
- data/lib/e_plat/resource/shopify_only/recurring_application_charge.rb +47 -0
- data/lib/e_plat/resource/webhook.rb +50 -0
- data/lib/e_plat/session.rb +14 -14
- data/lib/e_plat/type_coercer.rb +15 -17
- data/lib/e_plat/types.rb +1 -1
- data/lib/e_plat/version.rb +1 -1
- data/lib/e_plat.rb +4 -4
- metadata +51 -19
- data/lib/e_plat/resource/order/customer.rb +0 -37
- data/lib/e_plat/session_state.rb +0 -25
@@ -0,0 +1,92 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module EPlat
|
4
|
+
class Collection < ActiveResource::Collection
|
5
|
+
|
6
|
+
def initialize(parsed = {})
|
7
|
+
super parsed
|
8
|
+
end
|
9
|
+
|
10
|
+
def next_page?
|
11
|
+
return unless pagination_available?
|
12
|
+
@next_url.present?
|
13
|
+
end
|
14
|
+
|
15
|
+
def previous_page?
|
16
|
+
return unless pagination_available?
|
17
|
+
@previous_url.present?
|
18
|
+
end
|
19
|
+
|
20
|
+
def next_page_info
|
21
|
+
return unless pagination_available?
|
22
|
+
extract_page_info(@next_url)
|
23
|
+
end
|
24
|
+
|
25
|
+
def previous_page_info
|
26
|
+
return unless pagination_available?
|
27
|
+
extract_page_info(@previous_url)
|
28
|
+
end
|
29
|
+
|
30
|
+
def fetch_next_page
|
31
|
+
return unless pagination_available?
|
32
|
+
fetch_page(@next_url)
|
33
|
+
end
|
34
|
+
|
35
|
+
def fetch_previous_page
|
36
|
+
return unless pagination_available?
|
37
|
+
fetch_page(@previous_url)
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def fetch_page(url)
|
44
|
+
return [] unless url.present?
|
45
|
+
url = "#{ resource_class.collection_path }#{ url }" if client.bigcommerce?
|
46
|
+
|
47
|
+
resource_class.all(from: url)
|
48
|
+
end
|
49
|
+
|
50
|
+
def pagination_links
|
51
|
+
case client.platform
|
52
|
+
when :shopify
|
53
|
+
@pagination_links ||= EPlat::Paginated::LinkHeaders.new(
|
54
|
+
(full_response&.headers&.to_h || {})[:link]
|
55
|
+
)
|
56
|
+
when :bigcommerce
|
57
|
+
response = JSON.parse(full_response.body)
|
58
|
+
return unless response.is_a? Hash
|
59
|
+
link_params = response.dig('meta', 'pagination', 'links')
|
60
|
+
return unless link_params.present?
|
61
|
+
|
62
|
+
@pagination_links ||= EPlat::Paginated::LinkParams.new(
|
63
|
+
link_params
|
64
|
+
)
|
65
|
+
else
|
66
|
+
raise "Unknown platform"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def pagination_available?
|
71
|
+
@next_url = pagination_links&.next_link&.url&.to_s
|
72
|
+
@previous_url = pagination_links&.previous_link&.url&.to_s
|
73
|
+
|
74
|
+
@next_url.present? or @previous_url.present?
|
75
|
+
end
|
76
|
+
|
77
|
+
def extract_page_info(url)
|
78
|
+
return unless url.present?
|
79
|
+
|
80
|
+
query_params = URI.decode_www_form(URI(url).query).to_h
|
81
|
+
query_params[client.pagination_param]
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
def client
|
88
|
+
Current.e_plat_session
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
end
|
@@ -3,6 +3,7 @@ module EPlat
|
|
3
3
|
module Concerns
|
4
4
|
module Aliases
|
5
5
|
extend ActiveSupport::Concern
|
6
|
+
|
6
7
|
attr_accessor :type_coercer
|
7
8
|
|
8
9
|
def add_aliases!(aliases, type_schema)
|
@@ -14,20 +15,27 @@ module EPlat
|
|
14
15
|
args = action.values.first
|
15
16
|
e_plat_key = args[:e_plat_key]
|
16
17
|
native_key = args[:native_key]
|
17
|
-
|
18
|
+
@is_virtual = args[:virtual_collection]
|
19
|
+
|
18
20
|
case action_name
|
19
21
|
when :alias_attribute
|
20
22
|
add_to_instance! alias_mapped_getter(e_plat_key, native_key, proc: args[:custom_e_plat_getter])
|
21
23
|
add_to_instance! alias_mapped_setter(e_plat_key, native_key, proc: args[:custom_native_setter])
|
24
|
+
# puts alias_mapped_setter(e_plat_key, native_key, proc: args[:custom_native_setter]) if e_plat_key == 'variant_id'
|
22
25
|
processed << e_plat_key
|
23
26
|
end
|
24
27
|
end
|
25
28
|
|
26
29
|
type_schema.each do |e_plat_key, type|
|
27
30
|
next if processed.include?(e_plat_key)
|
28
|
-
add_to_instance! mapped_getter(e_plat_key)
|
31
|
+
add_to_instance! mapped_getter(e_plat_key), @is_virtual
|
29
32
|
end
|
30
33
|
|
34
|
+
native_keys.each do |native_key|
|
35
|
+
next if processed.include?(native_key)
|
36
|
+
|
37
|
+
add_to_instance! native_setter(native_key), @is_virtual
|
38
|
+
end
|
31
39
|
end
|
32
40
|
|
33
41
|
|
@@ -39,7 +47,7 @@ module EPlat
|
|
39
47
|
|
40
48
|
<<-STRING
|
41
49
|
def #{ e_plat_key }
|
42
|
-
current_value =
|
50
|
+
current_value = #{ native_key_path(native_key) }
|
43
51
|
#{ proc_line }
|
44
52
|
type_coercer.type_value!('#{ e_plat_key }', current_value)
|
45
53
|
end
|
@@ -50,10 +58,15 @@ module EPlat
|
|
50
58
|
proc_line = (proc) ? "new_value = #{ proc.strip }.call(new_value)" : nil
|
51
59
|
|
52
60
|
<<-STRING
|
53
|
-
def #{
|
61
|
+
def #{e_plat_key}=(value)
|
54
62
|
new_value = value
|
55
63
|
#{proc_line}
|
56
|
-
|
64
|
+
|
65
|
+
unless new_value == #{ native_key_path(native_key) }
|
66
|
+
#{ native_key_path(native_key) } = new_value
|
67
|
+
attribute_will_change!('#{e_plat_key}')
|
68
|
+
#{ nested_attribute_will_change(native_key) if native_key&.include?('[') }
|
69
|
+
end
|
57
70
|
end
|
58
71
|
STRING
|
59
72
|
end
|
@@ -66,11 +79,77 @@ module EPlat
|
|
66
79
|
STRING
|
67
80
|
end
|
68
81
|
|
69
|
-
def
|
82
|
+
def native_setter(native_key)
|
83
|
+
<<-STRING
|
84
|
+
def #{native_key}=(value)
|
85
|
+
super
|
86
|
+
attribute_will_change!('#{native_key}')
|
87
|
+
end
|
88
|
+
STRING
|
89
|
+
end
|
90
|
+
|
91
|
+
def native_key_path(native_key)
|
92
|
+
segments = native_key.split(/[\[\]]+/).reject(&:empty?)
|
93
|
+
path_code = @is_virtual ? "self.mapping.virtual_collection.resource" : "self"
|
94
|
+
|
95
|
+
segments.each do |segment|
|
96
|
+
if segment.match(/^\d+$/) # Check if the segment is a number (array index)
|
97
|
+
path_code += "[#{segment}]"
|
98
|
+
else
|
99
|
+
path_code += ".#{segment}"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
path_code
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
# ".send('#{ native_key_parent }').attribute_will_change!('#{ native_key }')"
|
108
|
+
|
109
|
+
def add_to_instance!(meta_programming_string, is_virtual=false)
|
110
|
+
# puts meta_programming_string if meta_programming_string.include?('note')
|
111
|
+
|
70
112
|
self.instance_eval { eval meta_programming_string }
|
71
113
|
end
|
72
|
-
|
73
|
-
|
114
|
+
|
115
|
+
# doesn't support two indexes in a row. i.e. [0][0]
|
116
|
+
def nested_attribute_will_change(native_key) # "[consignments][0][shipping][0][line_items][0][variant_id]"
|
117
|
+
ref_object = @is_virtual ? "mapping.virtual_collection.resource" : "self"
|
118
|
+
parts = native_key.scan(/(\w+)|(\d+)/).flatten.compact # ["consignments", "0", "shipping", "0", "line_items", "0", "variant_id"]
|
119
|
+
|
120
|
+
method_chain = ""
|
121
|
+
change_statements = []
|
122
|
+
|
123
|
+
first_attribute = parts.find { |part| !is_index?(part) }
|
124
|
+
if first_attribute
|
125
|
+
change_statements << "#{ref_object}.attribute_will_change!('#{first_attribute}')"
|
126
|
+
end
|
127
|
+
|
128
|
+
parts.each_with_index do |part, index|
|
129
|
+
method_chain += is_index?(part) ? "[#{part}]" : ".#{part}"
|
130
|
+
|
131
|
+
next_call = parts[index + 1]
|
132
|
+
attribute_key = is_index?(next_call) ? parts[index + 2] : next_call
|
133
|
+
next if (is_index?(part) && next_call && attribute_key.nil?) or !is_index?(part)
|
134
|
+
|
135
|
+
change_statement = "#{ref_object}#{method_chain}.attribute_will_change!('#{attribute_key}')"
|
136
|
+
change_statements << change_statement
|
137
|
+
end
|
138
|
+
|
139
|
+
<<-STRING
|
140
|
+
attribute_will_change!('#{parts.last}')
|
141
|
+
#{change_statements.join("\n")}
|
142
|
+
STRING
|
143
|
+
end
|
144
|
+
|
145
|
+
|
146
|
+
def is_index?(part)
|
147
|
+
part&.match?(/\d+/)
|
148
|
+
end
|
149
|
+
|
150
|
+
|
151
|
+
|
152
|
+
|
74
153
|
|
75
154
|
# Requires an array of hashes which each contain a single :alias_attribute entry.
|
76
155
|
# This will expose e_plat_key getter and setter methods that interact with the
|
@@ -82,19 +161,24 @@ module EPlat
|
|
82
161
|
# Like the below example, optional stringified procs can be passed in to respect the e_plat or native interfaces version of the value. e.g. enums
|
83
162
|
#
|
84
163
|
# {
|
85
|
-
# alias_attribute: {native_key: "
|
164
|
+
# alias_attribute: {native_key: "description", e_plat_key: "body_html"}
|
165
|
+
# }, {
|
166
|
+
# alias_attribute: {
|
167
|
+
# native_key: "description",
|
168
|
+
# e_plat_key: "body_html",
|
169
|
+
# custom_e_plat_getter: "-> (value) { value&.gsub(' ', '-') }",
|
170
|
+
# custom_native_setter: "-> (value) { value&.gsub('-', ' ') }"
|
171
|
+
# }
|
172
|
+
# }, {
|
173
|
+
# existing_entry: {native_key: "id", e_plat_key: "id"}
|
86
174
|
# },
|
87
175
|
# {
|
88
|
-
#
|
89
|
-
# custom_e_plat_getter: "-> (value) {
|
90
|
-
# {'preorder'=>'active', 'available' => 'active', 'disabled' => 'draft'}[value] || value
|
91
|
-
# }",
|
92
|
-
# custom_native_setter: "-> (value) {
|
93
|
-
# {'available' => 'active', 'disabled' => 'draft'}.invert[value] || value
|
94
|
-
# }" #invert will merge new duped keys
|
95
|
-
# }
|
176
|
+
# alias_attribute: {native_key: "billing_address[email]", e_plat_key: "email"}
|
96
177
|
# }
|
97
|
-
|
178
|
+
# {
|
179
|
+
# alias_attribute: {native_key: "[nested][deeply][in][2][attribute]", e_plat_key: "hey"}
|
180
|
+
# }
|
181
|
+
#
|
98
182
|
end
|
99
183
|
end
|
100
184
|
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module EPlat
|
2
|
+
module Concerns
|
3
|
+
module Dirty
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
# manages the self.changed_attributes hash
|
6
|
+
# this is important for the as_json method, which will only include changed attributes when updating an existing resource
|
7
|
+
# only supports native attributes
|
8
|
+
|
9
|
+
included do
|
10
|
+
def changed_attributes
|
11
|
+
@changed_attributes ||= {}
|
12
|
+
end
|
13
|
+
|
14
|
+
def attribute_will_change!(attr)
|
15
|
+
changed_attributes[attr] = read_attribute(attr)
|
16
|
+
|
17
|
+
native_keys.include?(attr) ? e_plat_attribute_will_change!(attr) : native_attribute_will_change!(attr)
|
18
|
+
end
|
19
|
+
|
20
|
+
def attribute_changed?(attr)
|
21
|
+
changed_attributes.include?(attr)
|
22
|
+
end
|
23
|
+
|
24
|
+
def read_attribute(attr)
|
25
|
+
self.send(attr)
|
26
|
+
end
|
27
|
+
|
28
|
+
def reload!
|
29
|
+
try(:super)
|
30
|
+
changed_attributes.clear
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def native_attribute_will_change!(eplat_attr)
|
37
|
+
key = self.mapping.native_key_to(eplat_attr)
|
38
|
+
return unless key && self.respond_to?(key)
|
39
|
+
|
40
|
+
changed_attributes[key] = send(key)
|
41
|
+
end
|
42
|
+
|
43
|
+
def e_plat_attribute_will_change!(native_attr)
|
44
|
+
key = self.mapping.e_plat_key_to(native_attr)
|
45
|
+
return unless key && self.respond_to?(key)
|
46
|
+
|
47
|
+
changed_attributes[key] = send(key)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module EPlat
|
4
|
+
module Concerns
|
5
|
+
module Metafieldable #< ActiveResource::CustomMethods
|
6
|
+
|
7
|
+
def metafields(**options)
|
8
|
+
options.merge!(resource: self.class.collection_name, resource_id: id)
|
9
|
+
|
10
|
+
Metafield.find(:all,
|
11
|
+
from: current_resources_metafield_path,
|
12
|
+
params: options
|
13
|
+
)
|
14
|
+
end
|
15
|
+
|
16
|
+
def find_metafield(id)
|
17
|
+
metafields.find { |m| m.id == id }
|
18
|
+
end
|
19
|
+
|
20
|
+
def add_metafield(metafield)
|
21
|
+
raise ArgumentError, "You can only add metafields to a resource that has been saved" if new?
|
22
|
+
|
23
|
+
metafield.owner_id = id
|
24
|
+
metafield.owner_resource = self.class.element_name
|
25
|
+
metafield.save
|
26
|
+
metafield
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def current_resources_metafield_path
|
33
|
+
uri = URI.parse(element_path)
|
34
|
+
uri.path = uri.path.gsub(".json", "/metafields.json")
|
35
|
+
uri.path += "/metafields" if uri.path.exclude?("json")
|
36
|
+
uri.path.gsub!('v2', 'v3') if client.bigcommerce? # metafield uses v3 API, even though orders are only available in v2
|
37
|
+
|
38
|
+
uri.to_s
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -1,11 +1,113 @@
|
|
1
1
|
module EPlat
|
2
2
|
module Concerns
|
3
|
-
module OverwriteInstanceMethods
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
module OverwriteInstanceMethods
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
def to_json(options = {})
|
7
|
+
#add this option here so root is added at the top of the JSON, as_json to every nested resource
|
8
|
+
root_at_top_of_json = self.mapping.include_root_in_request_body?(self)
|
9
|
+
options[:root] = self.element_name if root_at_top_of_json
|
10
|
+
|
11
|
+
super(options)
|
7
12
|
end
|
8
|
-
|
13
|
+
|
14
|
+
def as_json(options = {})
|
15
|
+
full_json = super(options)
|
16
|
+
return {} if read_only?
|
17
|
+
|
18
|
+
if mapping.class.virtual_collections.present?
|
19
|
+
virtual_keys = mapping.class.virtual_collections.map{|c| c[:name]}.map(&:to_s)
|
20
|
+
|
21
|
+
full_json.reject!{|key, value| virtual_keys.include?(key) } # not needed in JSON, as it's just a proxy for setting the real attributes
|
22
|
+
end
|
23
|
+
|
24
|
+
return full_json if new_record? # new records request with all attributes
|
25
|
+
|
26
|
+
request_json =
|
27
|
+
if include_root_in_json or options[:root].present?
|
28
|
+
{ element_name => select_changed_attributes_and_collection_keys(full_json[element_name]) }
|
29
|
+
else
|
30
|
+
select_changed_attributes_and_collection_keys(full_json)
|
31
|
+
end
|
32
|
+
|
33
|
+
if top_level_resource? # then check that any present collections have all entries represented with atleast an ID, so they're not removed
|
34
|
+
hash_without_root(request_json).each do |key, value|
|
35
|
+
next unless arrayOfPresentHashes?(value)
|
36
|
+
|
37
|
+
hash_without_root(request_json)[key].filter!(&:present?)
|
38
|
+
hash_without_root(request_json)[key] += unrepresented_collection_ids(key, value).map{ |id| { "id" => id } }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
add_root_if_needed(request_json, options[:root]).reject do |k,v|
|
43
|
+
if v.is_a?(Array)
|
44
|
+
v.reject(&:empty?).empty?
|
45
|
+
else
|
46
|
+
v.nil? || v.blank?
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Create and return a class definition for a resource inside the current resource
|
52
|
+
def create_resource_for(resource_name)
|
53
|
+
resource = Class.new(EPlat::Base) # <- this line changed
|
54
|
+
resource.prefix = self.class.prefix
|
55
|
+
resource.site = self.class.site
|
56
|
+
self.class.const_set(resource_name, resource)
|
57
|
+
|
58
|
+
resource
|
59
|
+
end
|
60
|
+
|
61
|
+
def create
|
62
|
+
self.attributes = mapping.via_native_attributes_where_possible(attributes)
|
63
|
+
super
|
64
|
+
end
|
65
|
+
|
66
|
+
def update
|
67
|
+
self.attributes = mapping.via_native_attributes_where_possible(attributes)
|
68
|
+
super
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def select_changed_attributes_and_collection_keys(json)
|
75
|
+
sanitised_json = json.dup
|
76
|
+
|
77
|
+
sanitised_json.select!{|key, value| changed_attributes.has_key?(key.to_s) || arrayOfPresentHashes?(value) }
|
78
|
+
|
79
|
+
if sanitised_json.present? # then we'll add an ID so that the resource can be updated
|
80
|
+
sanitised_json['id'] = json['id'] if json['id'] && client.can_update_nested_resources?
|
81
|
+
end
|
82
|
+
|
83
|
+
sanitised_json || {}
|
84
|
+
end
|
85
|
+
|
86
|
+
def arrayOfPresentHashes?(value)
|
87
|
+
value.is_a?(Array) && value.first.is_a?(Hash) && value.first.present?
|
88
|
+
end
|
89
|
+
|
90
|
+
def unrepresented_collection_ids(key, arrayOfHashes)
|
91
|
+
return [] unless client.can_update_nested_resources?
|
92
|
+
|
93
|
+
all_instance_ids = try(key)&.map(&:id) || []
|
94
|
+
represented_instance_ids = arrayOfHashes.map{|item| item["id"] }
|
95
|
+
|
96
|
+
all_instance_ids.compact - represented_instance_ids.compact
|
97
|
+
end
|
98
|
+
|
99
|
+
def hash_without_root(json)
|
100
|
+
self.include_root_in_json ? json[self.element_name] : json
|
101
|
+
end
|
102
|
+
|
103
|
+
def add_root_if_needed(json, root)
|
104
|
+
if root and !json.has_key?(root)
|
105
|
+
{ root => json }
|
106
|
+
else
|
107
|
+
json
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
9
111
|
end
|
10
112
|
end
|
11
|
-
end
|
113
|
+
end
|
@@ -1,50 +1,86 @@
|
|
1
1
|
module EPlat
|
2
2
|
module Concerns
|
3
|
-
module OverwriteRequestMethods
|
3
|
+
module OverwriteRequestMethods
|
4
4
|
|
5
|
-
def
|
6
|
-
|
7
|
-
arguments.second[:params].merge!(client.send "#{element_name}_default_find_args") if arguments.second
|
8
|
-
arguments.second[:params].merge!(mapping.to_native_keys arguments.second[:params]) if arguments.second
|
9
|
-
|
10
|
-
super
|
5
|
+
def self.included(base)
|
6
|
+
base.extend ClassMethods
|
11
7
|
end
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
def find(*arguments)
|
11
|
+
initialize_singleton!
|
12
|
+
|
13
|
+
if arguments.second && arguments.second[:params]
|
14
|
+
arguments.second[:params].merge!(client.try("#{element_name}_default_request_args") || {})
|
15
|
+
arguments.second[:params] = mapping.via_native_attributes_where_possible(arguments.second[:params])
|
16
|
+
else
|
17
|
+
arguments << {params: (client.try("#{element_name}_default_request_args") || {}) }
|
18
|
+
end
|
19
|
+
|
20
|
+
super
|
21
|
+
end
|
22
|
+
|
23
|
+
def find_by(params)
|
24
|
+
find(:all, params: params)&.first
|
25
|
+
end
|
26
|
+
|
27
|
+
def instantiate_collection(collection, original_params = {}, prefix_options = {})
|
28
|
+
collection = collection["data"] if collection.is_a?(Hash) && collection["data"]
|
29
|
+
super
|
30
|
+
end
|
31
|
+
|
32
|
+
def new(attributes, persisted = false)
|
33
|
+
initialize_singleton!
|
34
|
+
|
35
|
+
self.mapping = EPlat::Mapping.new_instance(specifc_mapping: specifc_mapping_name, resource: nil)
|
36
|
+
|
37
|
+
if attributes[mapping.native_top_key]
|
38
|
+
attributes = attributes.send(*top_key_method(mapping.native_top_key))
|
39
|
+
end
|
40
|
+
attributes = attributes.with_defaults(mapping.class::DEFAULT_VALUES)
|
41
|
+
|
42
|
+
super
|
43
|
+
end
|
44
|
+
|
45
|
+
def create(attributes = {})
|
46
|
+
initialize_singleton!
|
47
|
+
attributes = mapping.via_native_attributes_where_possible(attributes)
|
48
|
+
|
49
|
+
super
|
50
|
+
end
|
51
|
+
|
52
|
+
def update(attributes = {})
|
53
|
+
initialize_singleton!
|
54
|
+
attributes = mapping.via_native_attributes_where_possible(attributes)
|
55
|
+
|
56
|
+
super
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
39
61
|
def top_key_method(top_key)
|
40
62
|
(top_key == :itself) ? top_key : [:[], top_key]
|
41
63
|
end
|
42
|
-
|
64
|
+
|
43
65
|
def specifc_mapping_name
|
44
66
|
class_constant_string = self.name.gsub("EPlat::", "")
|
45
|
-
"EPlat::Mapping::#{
|
67
|
+
"EPlat::Mapping::#{client.platform.capitalize}::V#{client.api_version.camelize}::#{class_constant_string}"
|
46
68
|
end
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
def collection_path(options = {})
|
73
|
+
options = options.merge client.try("#{element_name}_default_request_args") || {}
|
74
|
+
|
75
|
+
super(options)
|
76
|
+
end
|
77
|
+
|
78
|
+
def element_path(options = {})
|
79
|
+
options = options.merge client.try("#{element_name}_default_request_args") || {}
|
80
|
+
|
81
|
+
super(options)
|
82
|
+
end
|
47
83
|
|
48
84
|
end
|
49
85
|
end
|
50
|
-
end
|
86
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module EPlat
|
4
|
+
module Countable
|
5
|
+
|
6
|
+
def count(options = {})
|
7
|
+
initialize_singleton!
|
8
|
+
|
9
|
+
if counts_via_meta_data?
|
10
|
+
raw_data = connection.get(collection_path, headers)
|
11
|
+
data_hash = ActiveSupport::JSON.decode(raw_data.body)
|
12
|
+
data = data_hash.dig("meta", "pagination", "total")
|
13
|
+
elsif count_key_next_to_root?
|
14
|
+
raw = get(:count, options)
|
15
|
+
data = JSON.parse raw.full_response.body
|
16
|
+
else
|
17
|
+
data = get(:count, options)
|
18
|
+
end
|
19
|
+
|
20
|
+
count =
|
21
|
+
case data
|
22
|
+
when Hash then data["count"]
|
23
|
+
else data
|
24
|
+
end
|
25
|
+
|
26
|
+
Integer(count)
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def counts_via_meta_data?
|
33
|
+
return false unless client.bigcommerce?
|
34
|
+
|
35
|
+
self == EPlat::Product or self == EPlat::Product::Variant
|
36
|
+
end
|
37
|
+
|
38
|
+
def count_key_next_to_root?
|
39
|
+
client.bigcommerce? && self == EPlat::Order
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|