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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 68d9eea1eeef7f8711bc52a5f502889db86060f3
4
- data.tar.gz: ace1d44c61822943f8d388abb1ca0729a539bd56
3
+ metadata.gz: 49f6aad4dc7d9f73ffaabcc3d433b4ea1e22aa9b
4
+ data.tar.gz: 9b913652093f6587c121d8e8e2da7ddbf8633ae5
5
5
  SHA512:
6
- metadata.gz: 036a2f4aec3cdba0aab5c5291187725740df70c8613e1651f9b371ef5f17e3908cc57465f461ea3bc1fa4fa873c746c3ec75488571052abb26ba06ea13891ce2
7
- data.tar.gz: 0e307ed787e902e0b0b0c37f3665965ef52c8d1909d55cc3f6e95c0a66fe2ba38859b36482ecc275f407bad9f84b00e937b2f4e6f016bd1e33d1fc55eb286e88
6
+ metadata.gz: 6a97f63461df816e36ac3ca2f837db9b330702683a0a320747f39258b3aa6b73ed6c3d37d7f5c2e014a9db9007ce774c58d1f52d0a0bf4d206e3880f41863ae5
7
+ data.tar.gz: 71c16105809625cd8c2b598f1d8e5934cb7d0152bb067ed904ca41db1604838d5997f36dea4dbbc225d32d578743447067e189f5673e0210ec95254d8328008a
data/.rubocop.yml CHANGED
@@ -6,6 +6,9 @@ inherit_from:
6
6
  Lint/IneffectiveAccessModifier:
7
7
  Enabled: false
8
8
 
9
+ Lint/ShadowingOuterLocalVariable:
10
+ Enabled: false
11
+
9
12
  RSpec/DescribedClass:
10
13
  Enabled: false
11
14
 
@@ -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
- def [](parameter)
46
- @hash[parameter]
50
+ attr_reader :data
51
+
52
+ def initialize(data = nil)
53
+ @data = data
47
54
  end
48
55
 
49
- def to_hash
50
- @hash
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
- @hash.values.first
87
+ @data.values.first
72
88
  end
73
89
 
74
90
  def class
75
- @hash.keys.first
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, chain_options)
121
+ @record_class.create(data, resolved_options)
102
122
  end
103
123
 
104
124
  def create!(data = {})
105
- @record_class.create!(data, chain_options)
125
+ @record_class.create!(data, resolved_options)
106
126
  end
107
127
 
108
128
  def save!(options = nil)
109
129
  options ||= {}
110
- @record.save!(chain_options.merge(options))
130
+ @record.save!(resolved_options.merge(options))
111
131
  end
112
132
 
113
133
  def save(options = nil)
114
134
  options ||= {}
115
- @record.save(chain_options.merge(options))
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(chain_options.merge(options))
142
+ @record.destroy(resolved_options.merge(options))
123
143
  else
124
- @record_class.destroy(options, chain_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, chain_options.merge(options))
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, chain_options.merge(options))
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?(chain_options.merge(options))
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
- options = chain_options
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, chain_options)
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, chain_options)
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(options)
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 _links.select { |link| link.is_a? Parameter }
275
+ merge_links(_links.select { |link| link.is_a? Parameter })
230
276
  end
231
277
 
232
278
  def chain_options
233
- merge_links _links.select { |link| link.is_a? Option }
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.to_hash.blank?
263
- hash.deep_merge!(link.to_hash)
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.each { |included| handle_includes(included, data, references[included]) }
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.without_including.request(options)
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
- record.includes(sub_includes).request(options)
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
@@ -12,7 +12,6 @@ class LHS::Record
12
12
  include Find
13
13
  include FindBy
14
14
  include First
15
- include Includes
16
15
  include Inspect
17
16
  include Mapping
18
17
  include Model
data/lib/lhs/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module LHS
2
- VERSION = "6.7.2"
2
+ VERSION = "6.8.0"
3
3
  end
@@ -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.7.2
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-10-28 00:00:00.000000000 Z
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