lhs 6.7.2 → 6.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -0
- data/lib/lhs/complex.rb +180 -0
- data/lib/lhs/concerns/record/chainable.rb +93 -31
- data/lib/lhs/concerns/record/first.rb +4 -4
- data/lib/lhs/concerns/record/request.rb +16 -4
- data/lib/lhs/record.rb +0 -1
- data/lib/lhs/version.rb +1 -1
- data/spec/complex/merge_spec.rb +180 -0
- data/spec/record/includes_spec.rb +20 -4
- metadata +5 -3
- data/lib/lhs/concerns/record/includes.rb +0 -47
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 49f6aad4dc7d9f73ffaabcc3d433b4ea1e22aa9b
|
4
|
+
data.tar.gz: 9b913652093f6587c121d8e8e2da7ddbf8633ae5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6a97f63461df816e36ac3ca2f837db9b330702683a0a320747f39258b3aa6b73ed6c3d37d7f5c2e014a9db9007ce774c58d1f52d0a0bf4d206e3880f41863ae5
|
7
|
+
data.tar.gz: 71c16105809625cd8c2b598f1d8e5934cb7d0152bb067ed904ca41db1604838d5997f36dea4dbbc225d32d578743447067e189f5673e0210ec95254d8328008a
|
data/.rubocop.yml
CHANGED
data/lib/lhs/complex.rb
ADDED
@@ -0,0 +1,180 @@
|
|
1
|
+
# Complex is the main data structure for includes:
|
2
|
+
# Can be for example :place, [:place, :customer],
|
3
|
+
# [{ places: [:customer] }, { places: { customer: :contract }}]
|
4
|
+
# and so on
|
5
|
+
class LHS::Complex
|
6
|
+
|
7
|
+
# Merge an array of complex that is created
|
8
|
+
# when chaining includes/references and
|
9
|
+
# reducing values is required for further handling
|
10
|
+
def self.merge(data)
|
11
|
+
result = []
|
12
|
+
data.flatten.uniq.each do |datum|
|
13
|
+
result = merge_first_level!(result, datum)
|
14
|
+
end
|
15
|
+
reduce!(result)
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.reduce!(array)
|
19
|
+
array.flatten!
|
20
|
+
array.uniq!
|
21
|
+
return array.first if array.length == 1
|
22
|
+
reduce_symbols!(array)
|
23
|
+
return nil if array.blank?
|
24
|
+
array
|
25
|
+
end
|
26
|
+
private_class_method :reduce!
|
27
|
+
|
28
|
+
def self.reduce_symbols!(array)
|
29
|
+
array.each do |element|
|
30
|
+
if element.is_a?(Symbol)
|
31
|
+
array.each do |other_element|
|
32
|
+
array.delete(element) if other_element.is_a?(Hash) && other_element.key?(element)
|
33
|
+
array.delete(element) if other_element.is_a?(Array) && other_element.include?(element)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
private_class_method :reduce_symbols!
|
39
|
+
|
40
|
+
# Merging the addition into the base array (first level)
|
41
|
+
def self.merge_first_level!(base, addition)
|
42
|
+
return [addition] if base.empty?
|
43
|
+
base.each do |element|
|
44
|
+
merge_multi_level!(base, element, addition)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
private_class_method :merge_first_level!
|
48
|
+
|
49
|
+
# Merge nested complex (addition) into
|
50
|
+
# an hash or an array (element) of the parent
|
51
|
+
def self.merge_multi_level!(parent, element, addition, key = nil)
|
52
|
+
return if element == addition
|
53
|
+
if addition.is_a?(Symbol) && element.is_a?(Hash)
|
54
|
+
merge_symbol_into_hash!(parent, element, addition, key)
|
55
|
+
elsif addition.is_a?(Symbol) && element.is_a?(Array)
|
56
|
+
merge_symbol_into_array!(parent, element, addition, key)
|
57
|
+
elsif addition.is_a?(Symbol) && element.is_a?(Symbol)
|
58
|
+
add_symbol_to_parent!(parent, element, addition, key)
|
59
|
+
elsif addition.is_a?(Hash) && element.is_a?(Symbol)
|
60
|
+
merge_hash_into_symbol!(parent, element, addition, key)
|
61
|
+
elsif addition.is_a?(Hash) && element.is_a?(Hash)
|
62
|
+
merge_hash_into_hash!(parent, element, addition, key)
|
63
|
+
elsif addition.is_a?(Hash) && element.is_a?(Array)
|
64
|
+
merge_hash_into_array!(element, addition)
|
65
|
+
elsif addition.is_a?(Array) && element.is_a?(Symbol)
|
66
|
+
merge_array_into_symbol!(parent, element, addition, key)
|
67
|
+
elsif addition.is_a?(Array) && element.is_a?(Hash)
|
68
|
+
merge_array_into_hash!(parent, element, addition, key)
|
69
|
+
elsif addition.is_a?(Array) && element.is_a?(Array)
|
70
|
+
merge_array_into_array!(parent, element, addition, key)
|
71
|
+
else
|
72
|
+
raise "Can't merge that complex: #{addition} -> #{parent} (#{element})#{key ? " for #{key}" : ''}"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
private_class_method :merge_multi_level!
|
76
|
+
|
77
|
+
def self.merge_symbol_into_hash!(parent, element, addition, key = nil)
|
78
|
+
return if element.key?(addition)
|
79
|
+
if parent.is_a?(Array)
|
80
|
+
parent.push(addition)
|
81
|
+
reduce!(parent)
|
82
|
+
elsif parent.is_a?(Hash)
|
83
|
+
parent[key] = reduce!([element, addition])
|
84
|
+
else
|
85
|
+
raise "Can't merge that complex: #{addition} -> #{parent} (#{element})#{key ? " for #{key}" : ''}"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
private_class_method :merge_symbol_into_hash!
|
89
|
+
|
90
|
+
def self.merge_symbol_into_array!(_parent, element, addition, _key = nil)
|
91
|
+
return if element.include?(addition)
|
92
|
+
element.push(addition)
|
93
|
+
reduce!(element)
|
94
|
+
end
|
95
|
+
private_class_method :merge_symbol_into_array!
|
96
|
+
|
97
|
+
def self.merge_hash_into_symbol!(parent, element, addition, key = nil)
|
98
|
+
parent.delete(element) if addition.key?(element)
|
99
|
+
if parent.is_a?(Array)
|
100
|
+
merge_hash_into_array!(parent, addition)
|
101
|
+
elsif parent.is_a?(Hash)
|
102
|
+
if addition.key?(element)
|
103
|
+
parent[key] = addition
|
104
|
+
else
|
105
|
+
parent[key] = reduce!([element, addition])
|
106
|
+
end
|
107
|
+
else
|
108
|
+
raise "Can't merge that complex: #{addition} -> #{parent} (#{element})"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
private_class_method :merge_hash_into_symbol!
|
112
|
+
|
113
|
+
def self.merge_array_into_symbol!(parent, element, addition, key = nil)
|
114
|
+
addition.unshift(element)
|
115
|
+
reduce!(addition)
|
116
|
+
parent[key] = addition
|
117
|
+
end
|
118
|
+
private_class_method :merge_array_into_symbol!
|
119
|
+
|
120
|
+
def self.merge_hash_into_hash!(parent, element, addition, _key = nil)
|
121
|
+
addition.keys.each do |key|
|
122
|
+
if element[key]
|
123
|
+
parent.delete(addition)
|
124
|
+
merge_multi_level!(element, element[key], addition[key], key)
|
125
|
+
else
|
126
|
+
parent.delete(addition)
|
127
|
+
element[key] = addition[key]
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
private_class_method :merge_hash_into_hash!
|
132
|
+
|
133
|
+
def self.merge_array_into_hash!(parent, element, addition, key = nil)
|
134
|
+
addition.each do |element_to_add|
|
135
|
+
merge_multi_level!(parent, element, element_to_add, key)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
private_class_method :merge_array_into_hash!
|
139
|
+
|
140
|
+
def self.merge_array_into_array!(_parent, element, addition, _key = nil)
|
141
|
+
addition.each do |element_to_add|
|
142
|
+
merge_multi_level!(element, element, element_to_add)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
private_class_method :merge_array_into_array!
|
146
|
+
|
147
|
+
def self.merge_hash_into_array!(array, addition)
|
148
|
+
array.each do |element|
|
149
|
+
next unless element.is_a?(Hash)
|
150
|
+
element.keys.each do |key|
|
151
|
+
next unless addition.key?(key)
|
152
|
+
return merge_multi_level!(element, element[key], addition[key], key)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
array.push(addition)
|
156
|
+
reduce!(array)
|
157
|
+
end
|
158
|
+
private_class_method :merge_hash_into_array!
|
159
|
+
|
160
|
+
def self.add_symbol_to_parent!(parent, element, addition, key = nil)
|
161
|
+
if parent.is_a?(Array)
|
162
|
+
unless parent.include?(addition)
|
163
|
+
parent.push(addition)
|
164
|
+
reduce!(parent)
|
165
|
+
end
|
166
|
+
elsif parent.is_a?(Hash)
|
167
|
+
add_symbol_to_hash_parent!(parent, element, addition, key)
|
168
|
+
else
|
169
|
+
raise "Can't merge that complex: #{addition} -> #{parent} (#{element})"
|
170
|
+
end
|
171
|
+
end
|
172
|
+
private_class_method :add_symbol_to_parent!
|
173
|
+
|
174
|
+
def self.add_symbol_to_hash_parent!(parent, element, addition, key)
|
175
|
+
return if parent[key] == addition
|
176
|
+
return if parent[key].is_a?(Array) && parent[key].include?(addition)
|
177
|
+
parent[key] = reduce!([element, addition])
|
178
|
+
end
|
179
|
+
private_class_method :add_symbol_to_hash_parent!
|
180
|
+
end
|
@@ -34,20 +34,27 @@ class LHS::Record
|
|
34
34
|
def handle(error_class, handler)
|
35
35
|
Chain.new(self, ErrorHandling.new(error_class => handler))
|
36
36
|
end
|
37
|
+
|
38
|
+
def includes(*args)
|
39
|
+
Chain.new(self, Include.new(Chain.unfold(args)))
|
40
|
+
end
|
41
|
+
|
42
|
+
def references(*args)
|
43
|
+
Chain.new(self, Reference.new(Chain.unfold(args)))
|
44
|
+
end
|
37
45
|
end
|
38
46
|
|
39
47
|
# Link: A part of a chain
|
40
48
|
class Link
|
41
|
-
def initialize(hash = nil)
|
42
|
-
@hash = hash
|
43
|
-
end
|
44
49
|
|
45
|
-
|
46
|
-
|
50
|
+
attr_reader :data
|
51
|
+
|
52
|
+
def initialize(data = nil)
|
53
|
+
@data = data
|
47
54
|
end
|
48
55
|
|
49
|
-
def
|
50
|
-
@
|
56
|
+
def [](parameter)
|
57
|
+
@data[parameter]
|
51
58
|
end
|
52
59
|
end
|
53
60
|
|
@@ -63,16 +70,25 @@ class LHS::Record
|
|
63
70
|
class Pagination < Link
|
64
71
|
end
|
65
72
|
|
73
|
+
# Include: Part of the chain that will be used to include linked resources
|
74
|
+
class Include < Link
|
75
|
+
end
|
76
|
+
|
77
|
+
# Reference: Part of the chain that will be used to pass options to requests
|
78
|
+
# made to include linked resources
|
79
|
+
class Reference < Link
|
80
|
+
end
|
81
|
+
|
66
82
|
# ErrorHandling: Catch and resolve errors when resolving the chain
|
67
83
|
class ErrorHandling < Link
|
68
84
|
delegate :call, to: :handler
|
69
85
|
|
70
86
|
def handler
|
71
|
-
@
|
87
|
+
@data.values.first
|
72
88
|
end
|
73
89
|
|
74
90
|
def class
|
75
|
-
@
|
91
|
+
@data.keys.first
|
76
92
|
end
|
77
93
|
end
|
78
94
|
|
@@ -91,6 +107,10 @@ class LHS::Record
|
|
91
107
|
|
92
108
|
attr_accessor :_links
|
93
109
|
|
110
|
+
def self.unfold(args)
|
111
|
+
args.size == 1 ? args[0] : args
|
112
|
+
end
|
113
|
+
|
94
114
|
def initialize(record_class, link, record = nil)
|
95
115
|
@record_class = record_class
|
96
116
|
@record = record
|
@@ -98,46 +118,46 @@ class LHS::Record
|
|
98
118
|
end
|
99
119
|
|
100
120
|
def create(data = {})
|
101
|
-
@record_class.create(data,
|
121
|
+
@record_class.create(data, resolved_options)
|
102
122
|
end
|
103
123
|
|
104
124
|
def create!(data = {})
|
105
|
-
@record_class.create!(data,
|
125
|
+
@record_class.create!(data, resolved_options)
|
106
126
|
end
|
107
127
|
|
108
128
|
def save!(options = nil)
|
109
129
|
options ||= {}
|
110
|
-
@record.save!(
|
130
|
+
@record.save!(resolved_options.merge(options))
|
111
131
|
end
|
112
132
|
|
113
133
|
def save(options = nil)
|
114
134
|
options ||= {}
|
115
|
-
@record.save(
|
135
|
+
@record.save(resolved_options.merge(options))
|
116
136
|
end
|
117
137
|
|
118
138
|
def destroy(options = nil)
|
119
139
|
options ||= {}
|
120
140
|
options = options.respond_to?(:to_h) ? options : { id: options }
|
121
141
|
if @record
|
122
|
-
@record.destroy(
|
142
|
+
@record.destroy(resolved_options.merge(options))
|
123
143
|
else
|
124
|
-
@record_class.destroy(options,
|
144
|
+
@record_class.destroy(options, resolved_options)
|
125
145
|
end
|
126
146
|
end
|
127
147
|
|
128
148
|
def update(data = {}, options = nil)
|
129
149
|
options ||= {}
|
130
|
-
@record.update(data,
|
150
|
+
@record.update(data, resolved_options.merge(options))
|
131
151
|
end
|
132
152
|
|
133
153
|
def update!(data = {}, options = nil)
|
134
154
|
options ||= {}
|
135
|
-
@record.update!(data,
|
155
|
+
@record.update!(data, resolved_options.merge(options))
|
136
156
|
end
|
137
157
|
|
138
158
|
def valid?(options = nil)
|
139
159
|
options ||= {}
|
140
|
-
@record.valid?(
|
160
|
+
@record.valid?(resolved_options.merge(options))
|
141
161
|
end
|
142
162
|
alias validate valid?
|
143
163
|
|
@@ -166,18 +186,28 @@ class LHS::Record
|
|
166
186
|
push ErrorHandling.new(error_class => handler)
|
167
187
|
end
|
168
188
|
|
189
|
+
def includes(*args)
|
190
|
+
push Include.new(Chain.unfold(args))
|
191
|
+
end
|
192
|
+
|
193
|
+
def references(*args)
|
194
|
+
push Reference.new(Chain.unfold(args))
|
195
|
+
end
|
196
|
+
|
169
197
|
def find(*args)
|
170
|
-
|
171
|
-
options = options.merge(error_handler: chain_error_handler) if chain_error_handler.any?
|
172
|
-
@record_class.find(*args.push(options))
|
198
|
+
@record_class.find(*args.push(resolved_options))
|
173
199
|
end
|
174
200
|
|
175
201
|
def find_by(params = {})
|
176
|
-
@record_class.find_by(params,
|
202
|
+
@record_class.find_by(params, resolved_options)
|
177
203
|
end
|
178
204
|
|
179
205
|
def find_by!(params = {})
|
180
|
-
@record_class.find_by!(params,
|
206
|
+
@record_class.find_by!(params, resolved_options)
|
207
|
+
end
|
208
|
+
|
209
|
+
def first!
|
210
|
+
@record_class.first!(resolved_options)
|
181
211
|
end
|
182
212
|
|
183
213
|
# Returns a hash of where conditions
|
@@ -195,6 +225,16 @@ class LHS::Record
|
|
195
225
|
chain_pagination
|
196
226
|
end
|
197
227
|
|
228
|
+
# Returns a hash of include conditions
|
229
|
+
def includes_values
|
230
|
+
chain_includes
|
231
|
+
end
|
232
|
+
|
233
|
+
# Returns a hash of reference options
|
234
|
+
def references_values
|
235
|
+
chain_references
|
236
|
+
end
|
237
|
+
|
198
238
|
protected
|
199
239
|
|
200
240
|
def method_missing(name, *args, &block)
|
@@ -209,14 +249,20 @@ class LHS::Record
|
|
209
249
|
end
|
210
250
|
|
211
251
|
def resolve
|
212
|
-
options = chain_options
|
213
|
-
options = options.merge(params: chain_parameters.merge(chain_pagination))
|
214
|
-
options = options.merge(error_handler: chain_error_handler) if chain_error_handler.any?
|
215
252
|
@resolved ||= @record_class.new(
|
216
|
-
@record_class.request(
|
253
|
+
@record_class.request(resolved_options)
|
217
254
|
)
|
218
255
|
end
|
219
256
|
|
257
|
+
def resolved_options
|
258
|
+
options = chain_options
|
259
|
+
options = options.merge(params: chain_parameters.merge(chain_pagination))
|
260
|
+
options = options.merge(error_handler: chain_error_handler) if chain_error_handler.present?
|
261
|
+
options = options.merge(including: chain_includes) if chain_includes.present?
|
262
|
+
options = options.merge(referencing: chain_references) if chain_references.present?
|
263
|
+
options
|
264
|
+
end
|
265
|
+
|
220
266
|
private
|
221
267
|
|
222
268
|
def push(link)
|
@@ -226,11 +272,11 @@ class LHS::Record
|
|
226
272
|
end
|
227
273
|
|
228
274
|
def chain_parameters
|
229
|
-
merge_links
|
275
|
+
merge_links(_links.select { |link| link.is_a? Parameter })
|
230
276
|
end
|
231
277
|
|
232
278
|
def chain_options
|
233
|
-
merge_links
|
279
|
+
merge_links(_links.select { |link| link.is_a? Option })
|
234
280
|
end
|
235
281
|
|
236
282
|
def chain_error_handler
|
@@ -241,6 +287,22 @@ class LHS::Record
|
|
241
287
|
resolve_pagination _links.select { |link| link.is_a? Pagination }
|
242
288
|
end
|
243
289
|
|
290
|
+
def chain_includes
|
291
|
+
LHS::Complex.merge(
|
292
|
+
_links
|
293
|
+
.select { |link| link.is_a?(Include) && link.data.present? }
|
294
|
+
.map { |link| link.data }
|
295
|
+
)
|
296
|
+
end
|
297
|
+
|
298
|
+
def chain_references
|
299
|
+
LHS::Complex.merge(
|
300
|
+
_links
|
301
|
+
.select { |link| link.is_a?(Reference) && link.data.present? }
|
302
|
+
.map { |link| link.data }
|
303
|
+
)
|
304
|
+
end
|
305
|
+
|
244
306
|
def resolve_pagination(links)
|
245
307
|
return {} if links.empty?
|
246
308
|
page = 1
|
@@ -259,8 +321,8 @@ class LHS::Record
|
|
259
321
|
def merge_links(links)
|
260
322
|
hash = {}
|
261
323
|
links.each do |link|
|
262
|
-
next if link.
|
263
|
-
hash.deep_merge!(link.
|
324
|
+
next if link.data.blank?
|
325
|
+
hash.deep_merge!(link.data)
|
264
326
|
end
|
265
327
|
hash
|
266
328
|
end
|
@@ -6,12 +6,12 @@ class LHS::Record
|
|
6
6
|
extend ActiveSupport::Concern
|
7
7
|
|
8
8
|
module ClassMethods
|
9
|
-
def first
|
10
|
-
find_by
|
9
|
+
def first(options = nil)
|
10
|
+
find_by({}, options)
|
11
11
|
end
|
12
12
|
|
13
|
-
def first!
|
14
|
-
find_by!
|
13
|
+
def first!(options = nil)
|
14
|
+
find_by!({}, options)
|
15
15
|
end
|
16
16
|
end
|
17
17
|
end
|
@@ -93,10 +93,13 @@ class LHS::Record
|
|
93
93
|
|
94
94
|
def handle_includes(includes, data, references = {})
|
95
95
|
references ||= {}
|
96
|
+
references = [references] if includes.is_a?(Array) && !references.is_a?(Array)
|
96
97
|
if includes.is_a? Hash
|
97
98
|
includes.each { |included, sub_includes| handle_include(included, data, sub_includes, references[included]) }
|
98
99
|
elsif includes.is_a? Array
|
99
|
-
includes.
|
100
|
+
includes.each_with_index do |included, index|
|
101
|
+
handle_includes(included, data, references[index])
|
102
|
+
end
|
100
103
|
else
|
101
104
|
handle_include(includes, data, nil, references[includes])
|
102
105
|
end
|
@@ -123,7 +126,7 @@ class LHS::Record
|
|
123
126
|
record = record_for_options(options) || self
|
124
127
|
options = convert_options_to_endpoints(options) if record_for_options(options)
|
125
128
|
expanded_data = begin
|
126
|
-
record.
|
129
|
+
record.request(options)
|
127
130
|
rescue LHC::NotFound
|
128
131
|
LHS::Data.new({}, data, record)
|
129
132
|
end
|
@@ -163,7 +166,12 @@ class LHS::Record
|
|
163
166
|
record = record_for_options(options) || self
|
164
167
|
options = convert_options_to_endpoints(options) if record_for_options(options)
|
165
168
|
begin
|
166
|
-
|
169
|
+
if options.is_a?(Array)
|
170
|
+
options.each { |options| options.merge!(including: sub_includes) if sub_includes.present? }
|
171
|
+
elsif sub_includes.present?
|
172
|
+
options.merge!(including: sub_includes)
|
173
|
+
end
|
174
|
+
record.request(options)
|
167
175
|
rescue LHC::NotFound
|
168
176
|
LHS::Data.new({}, data, record)
|
169
177
|
end
|
@@ -185,9 +193,11 @@ class LHS::Record
|
|
185
193
|
data = LHC.request(options.compact).map do |response|
|
186
194
|
LHS::Data.new(response.body, nil, self, response.request)
|
187
195
|
end
|
196
|
+
including = LHS::Complex.merge options.compact.map { |options| options.delete(:including) }.compact
|
197
|
+
referencing = LHS::Complex.merge options.compact.map { |options| options.delete(:referencing) }.compact
|
188
198
|
data = restore_with_nils(data, locate_nils(options)) # nil objects in data provide location information for mapping
|
189
199
|
data = LHS::Data.new(data, nil, self)
|
190
|
-
handle_includes(including, data, referencing) if including && !data.empty?
|
200
|
+
handle_includes(including, data, referencing) if including.present? && !data.empty?
|
191
201
|
data
|
192
202
|
end
|
193
203
|
|
@@ -260,6 +270,8 @@ class LHS::Record
|
|
260
270
|
|
261
271
|
def single_request(options)
|
262
272
|
options ||= {}
|
273
|
+
including = options.delete(:including)
|
274
|
+
referencing = options.delete(:referencing)
|
263
275
|
options = options.dup
|
264
276
|
endpoint = find_endpoint(options[:params])
|
265
277
|
response = LHC.request(process_options(options, endpoint))
|
data/lib/lhs/record.rb
CHANGED
data/lib/lhs/version.rb
CHANGED
@@ -0,0 +1,180 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
describe LHS::Complex do
|
4
|
+
context 'first level' do
|
5
|
+
context 'merges symbols into/with X' do
|
6
|
+
it 'merges symbols into hash' do
|
7
|
+
expect(LHS::Complex.merge([
|
8
|
+
{ entries: :contract },
|
9
|
+
:entries
|
10
|
+
])).to eq(entries: :contract)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'merges symbols into array' do
|
14
|
+
expect(LHS::Complex.merge([
|
15
|
+
[:contracts],
|
16
|
+
:entries
|
17
|
+
])).to eq([:contracts, :entries])
|
18
|
+
expect(LHS::Complex.merge([
|
19
|
+
[:entries],
|
20
|
+
:entries
|
21
|
+
])).to eq(:entries)
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'merges symbols with symbols' do
|
25
|
+
expect(LHS::Complex.merge([
|
26
|
+
:contracts,
|
27
|
+
:entries
|
28
|
+
])).to eq([:contracts, :entries])
|
29
|
+
expect(LHS::Complex.merge([
|
30
|
+
:entries,
|
31
|
+
:entries
|
32
|
+
])).to eq(:entries)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'merges arrays into/with X' do
|
37
|
+
it 'merges arrays into an hash' do
|
38
|
+
expect(LHS::Complex.merge([
|
39
|
+
{ entries: :contract },
|
40
|
+
[:entries]
|
41
|
+
])).to eq(entries: :contract)
|
42
|
+
expect(LHS::Complex.merge([
|
43
|
+
{ entries: :contract },
|
44
|
+
[:products]
|
45
|
+
])).to eq([{ entries: :contract }, :products])
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'merges arrays into an arrays' do
|
49
|
+
expect(LHS::Complex.merge([
|
50
|
+
[:entries],
|
51
|
+
[:entries]
|
52
|
+
])).to eq(:entries)
|
53
|
+
expect(LHS::Complex.merge([
|
54
|
+
[:entries],
|
55
|
+
[:products]
|
56
|
+
])).to eq([:entries, :products])
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'merges arrays into an symbols' do
|
60
|
+
expect(LHS::Complex.merge([
|
61
|
+
:entries,
|
62
|
+
[:entries]
|
63
|
+
])).to eq(:entries)
|
64
|
+
expect(LHS::Complex.merge([
|
65
|
+
:entries,
|
66
|
+
[:products]
|
67
|
+
])).to eq([:entries, :products])
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'merges hashes into/with X' do
|
72
|
+
it 'merges hash into an hash' do
|
73
|
+
expect(LHS::Complex.merge([
|
74
|
+
{ entries: :contract },
|
75
|
+
{ entries: :products }
|
76
|
+
])).to eq(entries: [:contract, :products])
|
77
|
+
expect(LHS::Complex.merge([
|
78
|
+
{ entries: :contract },
|
79
|
+
{ entries: :contract }
|
80
|
+
])).to eq(entries: :contract)
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'merges hash into an array' do
|
84
|
+
expect(LHS::Complex.merge([
|
85
|
+
[:entries],
|
86
|
+
{ entries: :products }
|
87
|
+
])).to eq(entries: :products)
|
88
|
+
expect(LHS::Complex.merge([
|
89
|
+
[{ entries: :contract }],
|
90
|
+
{ entries: :contract }
|
91
|
+
])).to eq(entries: :contract)
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'merges hash into a symbol' do
|
95
|
+
expect(LHS::Complex.merge([
|
96
|
+
:entries,
|
97
|
+
{ entries: :products }
|
98
|
+
])).to eq(entries: :products)
|
99
|
+
expect(LHS::Complex.merge([
|
100
|
+
:products,
|
101
|
+
{ entries: :contract }
|
102
|
+
])).to eq([:products, { entries: :contract }])
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
context 'merges array into/with X' do
|
107
|
+
it 'merges array into hash' do
|
108
|
+
expect(LHS::Complex.merge([
|
109
|
+
{ entries: :contract },
|
110
|
+
[:entries, :products]
|
111
|
+
])).to eq([{ entries: :contract }, :products])
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'merges array into array' do
|
115
|
+
expect(LHS::Complex.merge([
|
116
|
+
[:contracts],
|
117
|
+
[:entries, :products, :contracts]
|
118
|
+
])).to eq([:contracts, :entries, :products])
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'merges array with symbols' do
|
122
|
+
expect(LHS::Complex.merge([
|
123
|
+
:contracts,
|
124
|
+
[:entries, :products]
|
125
|
+
])).to eq([:contracts, :entries, :products])
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
context 'multi-level' do
|
131
|
+
it 'merges a complex multi-level example' do
|
132
|
+
expect(LHS::Complex.merge([
|
133
|
+
:contracts,
|
134
|
+
[:entries, products: { content_ads: :address }],
|
135
|
+
products: { content_ads: { place: :location } }
|
136
|
+
])).to eq([
|
137
|
+
:contracts,
|
138
|
+
:entries,
|
139
|
+
products: { content_ads: [:address, { place: :location }] }
|
140
|
+
])
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'merges another complex multi-level example' do
|
144
|
+
expect(LHS::Complex.merge([
|
145
|
+
[entries: :content_ads, products: :price],
|
146
|
+
[:entries, products: { content_ads: :address }],
|
147
|
+
[entries: { content_ads: :owner }, products: [{ price: :region }, :image, { content_ads: :owner }]]
|
148
|
+
])).to eq(
|
149
|
+
entries: { content_ads: :owner },
|
150
|
+
products: [{ content_ads: [:address, :owner] }, { price: :region }, :image]
|
151
|
+
)
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'merges another complex multi-level example' do
|
155
|
+
expect(LHS::Complex.merge([
|
156
|
+
{ entries: :products },
|
157
|
+
{ entries: [:customer, :contracts] }
|
158
|
+
])).to eq(
|
159
|
+
entries: [:products, :customer, :contracts]
|
160
|
+
)
|
161
|
+
end
|
162
|
+
|
163
|
+
it 'merges another complex multi-level example' do
|
164
|
+
expect(LHS::Complex.merge([
|
165
|
+
{ entries: { customer: :contracts } },
|
166
|
+
{ entries: [:customer, :content_ads] }
|
167
|
+
])).to eq(
|
168
|
+
entries: [{ customer: :contracts }, :content_ads]
|
169
|
+
)
|
170
|
+
end
|
171
|
+
|
172
|
+
it 'reduces properly' do
|
173
|
+
expect(LHS::Complex.merge([
|
174
|
+
[:entries, :place, :content_ads], [{ place: :content_ads }], { content_ads: :place }
|
175
|
+
])).to eq(
|
176
|
+
[:entries, { place: :content_ads, content_ads: :place }]
|
177
|
+
)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
@@ -366,11 +366,17 @@ describe LHS::Record do
|
|
366
366
|
before(:each) do
|
367
367
|
class Customer < LHS::Record
|
368
368
|
endpoint ':datastore/customers/:id'
|
369
|
+
endpoint ':datastore/customers'
|
369
370
|
end
|
370
371
|
|
371
372
|
class Place < LHS::Record
|
372
373
|
endpoint ':datastore/places'
|
373
374
|
end
|
375
|
+
|
376
|
+
stub_request(:get, "#{datastore}/places?forwarded_params=123")
|
377
|
+
.to_return(body: {
|
378
|
+
'items' => [{ id: 1 }]
|
379
|
+
}.to_json)
|
374
380
|
end
|
375
381
|
|
376
382
|
it 'forwards includes options to requests made for those includes' do
|
@@ -380,15 +386,25 @@ describe LHS::Record do
|
|
380
386
|
'href' => "#{datastore}/places"
|
381
387
|
}
|
382
388
|
}.to_json)
|
383
|
-
stub_request(:get, "#{datastore}/places?forwarded_params=123")
|
384
|
-
.to_return(body: {
|
385
|
-
'items' => [{ id: 1 }]
|
386
|
-
}.to_json)
|
387
389
|
customer = Customer
|
388
390
|
.includes(:places)
|
389
391
|
.references(places: { params: { forwarded_params: 123 } })
|
390
392
|
.find(1)
|
391
393
|
expect(customer.places.first.id).to eq 1
|
392
394
|
end
|
395
|
+
|
396
|
+
it 'is chain-able' do
|
397
|
+
stub_request(:get, "#{datastore}/customers?name=Steve")
|
398
|
+
.to_return(body: [
|
399
|
+
'places' => {
|
400
|
+
'href' => "#{datastore}/places"
|
401
|
+
}
|
402
|
+
].to_json)
|
403
|
+
customers = Customer
|
404
|
+
.where(name: 'Steve')
|
405
|
+
.references(places: { params: { forwarded_params: 123 } })
|
406
|
+
.includes(:places)
|
407
|
+
expect(customers.first.places.first.id).to eq 1
|
408
|
+
end
|
393
409
|
end
|
394
410
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lhs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 6.
|
4
|
+
version: 6.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- https://github.com/local-ch/lhs/graphs/contributors
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-11-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: lhc
|
@@ -178,6 +178,7 @@ files:
|
|
178
178
|
- lhs.gemspec
|
179
179
|
- lib/lhs.rb
|
180
180
|
- lib/lhs/collection.rb
|
181
|
+
- lib/lhs/complex.rb
|
181
182
|
- lib/lhs/concerns/collection/internal_collection.rb
|
182
183
|
- lib/lhs/concerns/data/equality.rb
|
183
184
|
- lib/lhs/concerns/data/json.rb
|
@@ -198,7 +199,6 @@ files:
|
|
198
199
|
- lib/lhs/concerns/record/find.rb
|
199
200
|
- lib/lhs/concerns/record/find_by.rb
|
200
201
|
- lib/lhs/concerns/record/first.rb
|
201
|
-
- lib/lhs/concerns/record/includes.rb
|
202
202
|
- lib/lhs/concerns/record/mapping.rb
|
203
203
|
- lib/lhs/concerns/record/model.rb
|
204
204
|
- lib/lhs/concerns/record/pagination.rb
|
@@ -221,6 +221,7 @@ files:
|
|
221
221
|
- spec/collection/meta_data_spec.rb
|
222
222
|
- spec/collection/respond_to_spec.rb
|
223
223
|
- spec/collection/without_object_items_spec.rb
|
224
|
+
- spec/complex/merge_spec.rb
|
224
225
|
- spec/data/collection_spec.rb
|
225
226
|
- spec/data/equality_spec.rb
|
226
227
|
- spec/data/inspect_spec.rb
|
@@ -371,6 +372,7 @@ test_files:
|
|
371
372
|
- spec/collection/meta_data_spec.rb
|
372
373
|
- spec/collection/respond_to_spec.rb
|
373
374
|
- spec/collection/without_object_items_spec.rb
|
375
|
+
- spec/complex/merge_spec.rb
|
374
376
|
- spec/data/collection_spec.rb
|
375
377
|
- spec/data/equality_spec.rb
|
376
378
|
- spec/data/inspect_spec.rb
|
@@ -1,47 +0,0 @@
|
|
1
|
-
require 'active_support'
|
2
|
-
|
3
|
-
class LHS::Record
|
4
|
-
|
5
|
-
module Includes
|
6
|
-
extend ActiveSupport::Concern
|
7
|
-
|
8
|
-
included do
|
9
|
-
cattr_accessor :including, :referencing
|
10
|
-
end
|
11
|
-
|
12
|
-
module ClassMethods
|
13
|
-
def includes(*args)
|
14
|
-
class_clone_factory(args).tap do |class_clone|
|
15
|
-
class_clone.including = unfold_args(args)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
def references(*args)
|
20
|
-
class_clone_factory(args).tap do |class_clone|
|
21
|
-
class_clone.referencing = unfold_args(args)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
def without_including
|
26
|
-
class_clone_factory(rand.to_s.gsub(/\D/, '')).tap do |class_clone|
|
27
|
-
class_clone.including = nil
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
private
|
32
|
-
|
33
|
-
def unfold_args(args)
|
34
|
-
args.size == 1 ? args[0] : args
|
35
|
-
end
|
36
|
-
|
37
|
-
def class_clone_factory(args)
|
38
|
-
name = "#{self}#{args.object_id}"
|
39
|
-
constant = Object.const_set(name.demodulize, self.dup) # rubocop:disable Style/RedundantSelf
|
40
|
-
class_clone = constant
|
41
|
-
class_clone.endpoints = endpoints
|
42
|
-
class_clone.mapping = mapping
|
43
|
-
class_clone
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|