lhs 6.7.2 → 6.8.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 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