actionset 0.8.1 → 0.11.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/.rubocop.yml +5 -5
- data/.ruby-version +1 -1
- data/.travis.yml +1 -1
- data/CHANGELOG +67 -0
- data/Gemfile.lock +134 -126
- data/README.md +26 -0
- data/Rakefile +8 -1
- data/actionset.gemspec +2 -2
- data/lib/action_set.rb +8 -23
- data/lib/action_set/attribute_value.rb +7 -1
- data/lib/action_set/filter_instructions.rb +72 -0
- data/lib/action_set/helpers/helper_methods.rb +2 -1
- data/lib/action_set/helpers/pagination/record_description_for_helper.rb +20 -0
- data/lib/action_set/helpers/pagination/record_first_for_helper.rb +20 -0
- data/lib/action_set/helpers/pagination/record_last_for_helper.rb +26 -0
- data/lib/action_set/helpers/pagination/record_range_for_helper.rb +25 -0
- data/lib/action_set/helpers/pagination/record_size_for_helper.rb +9 -0
- data/lib/action_set/helpers/pagination/total_pages_for_helper.rb +3 -1
- data/lib/action_set/sort_instructions.rb +44 -0
- data/lib/active_set.rb +25 -2
- data/lib/active_set/active_record_set_instruction.rb +33 -32
- data/lib/active_set/attribute_instruction.rb +3 -3
- data/lib/active_set/enumerable_set_instruction.rb +13 -24
- data/lib/active_set/filtering/active_record/operators.rb +280 -0
- data/lib/active_set/filtering/active_record/query_column.rb +35 -0
- data/lib/active_set/filtering/active_record/query_value.rb +47 -0
- data/lib/active_set/filtering/active_record/set_instruction.rb +29 -0
- data/lib/active_set/filtering/active_record/strategy.rb +87 -0
- data/lib/active_set/filtering/constants.rb +349 -0
- data/lib/active_set/filtering/enumerable/operators.rb +308 -0
- data/lib/active_set/filtering/enumerable/set_instruction.rb +98 -0
- data/lib/active_set/filtering/enumerable/strategy.rb +90 -0
- data/lib/active_set/filtering/operation.rb +5 -8
- data/lib/active_set/paginating/active_record_strategy.rb +0 -2
- data/lib/active_set/sorting/active_record_strategy.rb +27 -3
- data/lib/active_set/sorting/enumerable_strategy.rb +12 -2
- data/lib/active_set/sorting/operation.rb +1 -2
- data/lib/helpers/flatten_keys_of.rb +53 -0
- data/lib/helpers/transform_to_sortable_numeric.rb +3 -3
- metadata +26 -13
- data/lib/active_set/filtering/active_record_strategy.rb +0 -85
- data/lib/active_set/filtering/enumerable_strategy.rb +0 -79
- data/lib/helpers/throws.rb +0 -19
- data/lib/patches/core_ext/hash/flatten_keys.rb +0 -58
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative '../attribute_instruction'
|
4
|
-
require_relative './
|
5
|
-
require_relative './
|
4
|
+
require_relative './enumerable/strategy'
|
5
|
+
require_relative './active_record/strategy'
|
6
6
|
|
7
7
|
class ActiveSet
|
8
8
|
module Filtering
|
@@ -12,14 +12,12 @@ class ActiveSet
|
|
12
12
|
@instructions_hash = instructions_hash
|
13
13
|
end
|
14
14
|
|
15
|
-
# rubocop:disable Metrics/MethodLength
|
16
15
|
def execute
|
17
|
-
attribute_instructions = @instructions_hash
|
18
|
-
.flatten_keys
|
16
|
+
attribute_instructions = flatten_keys_of(@instructions_hash)
|
19
17
|
.map { |k, v| AttributeInstruction.new(k, v) }
|
20
18
|
|
21
19
|
activerecord_filtered_set = attribute_instructions.reduce(@set) do |set, attribute_instruction|
|
22
|
-
maybe_set_or_false =
|
20
|
+
maybe_set_or_false = ActiveRecord::Strategy.new(set, attribute_instruction).execute
|
23
21
|
next set unless maybe_set_or_false
|
24
22
|
|
25
23
|
attribute_instruction.processed = true
|
@@ -29,14 +27,13 @@ class ActiveSet
|
|
29
27
|
return activerecord_filtered_set if attribute_instructions.all?(&:processed?)
|
30
28
|
|
31
29
|
attribute_instructions.reject(&:processed?).reduce(activerecord_filtered_set) do |set, attribute_instruction|
|
32
|
-
maybe_set_or_false =
|
30
|
+
maybe_set_or_false = Enumerable::Strategy.new(set, attribute_instruction).execute
|
33
31
|
next set unless maybe_set_or_false
|
34
32
|
|
35
33
|
attribute_instruction.processed = true
|
36
34
|
maybe_set_or_false
|
37
35
|
end
|
38
36
|
end
|
39
|
-
# rubocop:enable Metrics/MethodLength
|
40
37
|
|
41
38
|
def operation_instructions
|
42
39
|
@instructions_hash.symbolize_keys
|
@@ -10,8 +10,6 @@ class ActiveSet
|
|
10
10
|
|
11
11
|
def execute
|
12
12
|
return false unless @set.respond_to? :to_sql
|
13
|
-
return @set.none if @set.length <= @operation_instructions[:size] &&
|
14
|
-
@operation_instructions[:page] > 1
|
15
13
|
|
16
14
|
@set.limit(@operation_instructions[:size]).offset(page_offset)
|
17
15
|
end
|
@@ -41,17 +41,23 @@ class ActiveSet
|
|
41
41
|
private
|
42
42
|
|
43
43
|
# https://stackoverflow.com/a/44912964/2884386
|
44
|
-
#
|
44
|
+
# When ActiveSet.configuration.on_asc_sort_nils_come == :last
|
45
|
+
# null values to be sorted as if larger than any non-null value.
|
45
46
|
# ASC => [-2, -1, 1, 2, nil]
|
46
47
|
# DESC => [nil, 2, 1, -1, -2]
|
48
|
+
# Otherwise sort nulls as if smaller than any non-null value.
|
49
|
+
# ASC => [nil, -2, -1, 1, 2]
|
50
|
+
# DESC => [2, 1, -1, -2, nil]
|
47
51
|
def order_operation_for(set_instruction)
|
48
52
|
attribute_model = set_instruction.attribute_model
|
49
53
|
|
50
54
|
arel_column = set_instruction.arel_column
|
51
55
|
arel_direction = direction_operator(set_instruction.value)
|
52
|
-
nil_sorter = arel_column.send(arel_direction == :asc ? :eq : :not_eq, nil)
|
53
56
|
|
54
|
-
attribute_model.order(
|
57
|
+
attribute_model.order(Arel.sql(nil_sorter_for(set_instruction.arel_table,
|
58
|
+
set_instruction.arel_column_name,
|
59
|
+
arel_direction)))
|
60
|
+
.order(arel_column.send(arel_direction))
|
55
61
|
end
|
56
62
|
|
57
63
|
def direction_operator(direction)
|
@@ -59,6 +65,24 @@ class ActiveSet
|
|
59
65
|
|
60
66
|
:asc
|
61
67
|
end
|
68
|
+
|
69
|
+
def nil_sorter_for(model, column, direction)
|
70
|
+
"CASE WHEN #{model.table_name}.#{column} IS NULL #{nil_sorter_then_statement(direction)}"
|
71
|
+
end
|
72
|
+
|
73
|
+
def nil_sorter_then_statement(direction)
|
74
|
+
first = 'THEN 0 ELSE 1 END'
|
75
|
+
last = 'THEN 1 ELSE 0 END'
|
76
|
+
if ActiveSet.configuration.on_asc_sort_nils_come == :last
|
77
|
+
return last if direction == :asc
|
78
|
+
|
79
|
+
return first
|
80
|
+
else
|
81
|
+
return first if direction == :asc
|
82
|
+
|
83
|
+
return last
|
84
|
+
end
|
85
|
+
end
|
62
86
|
end
|
63
87
|
end
|
64
88
|
end
|
@@ -21,11 +21,15 @@ class ActiveSet
|
|
21
21
|
value_for_comparison = sortable_numeric_for(set_instruction, item)
|
22
22
|
direction_multiplier = direction_multiplier(set_instruction.value)
|
23
23
|
|
24
|
-
#
|
24
|
+
# When ActiveSet.configuration.on_asc_sort_nils_come == :last
|
25
|
+
# null values to be sorted as if larger than any non-null value.
|
25
26
|
# ASC => [-2, -1, 1, 2, nil]
|
26
27
|
# DESC => [nil, 2, 1, -1, -2]
|
28
|
+
# Otherwise sort nulls as if smaller than any non-null value.
|
29
|
+
# ASC => [nil, -2, -1, 1, 2]
|
30
|
+
# DESC => [2, 1, -1, -2, nil]
|
27
31
|
if value_for_comparison.nil?
|
28
|
-
[direction_multiplier, 0]
|
32
|
+
[direction_multiplier * nil_sorter, 0]
|
29
33
|
else
|
30
34
|
[0, value_for_comparison * direction_multiplier]
|
31
35
|
end
|
@@ -44,6 +48,12 @@ class ActiveSet
|
|
44
48
|
|
45
49
|
1
|
46
50
|
end
|
51
|
+
|
52
|
+
def nil_sorter
|
53
|
+
return 1 if ActiveSet.configuration.on_asc_sort_nils_come == :last
|
54
|
+
|
55
|
+
-1
|
56
|
+
end
|
47
57
|
end
|
48
58
|
end
|
49
59
|
end
|
@@ -13,8 +13,7 @@ class ActiveSet
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def execute
|
16
|
-
attribute_instructions = @instructions_hash
|
17
|
-
.flatten_keys
|
16
|
+
attribute_instructions = flatten_keys_of(@instructions_hash)
|
18
17
|
.map { |k, v| AttributeInstruction.new(k, v) }
|
19
18
|
|
20
19
|
activerecord_strategy = ActiveRecordStrategy.new(@set, attribute_instructions)
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/core_ext/array/wrap'
|
4
|
+
|
5
|
+
# Returns a flat hash where all nested keys are flattened into an array of keys.
|
6
|
+
#
|
7
|
+
# hash = { key: 'value', nested: { key: 'nested_value' }, array: [0, 1, 2] }
|
8
|
+
# flatten_keys_of(hash)
|
9
|
+
# => { [:key]=>"value", [:nested, :key]=>"nested_value", [:array]=>[0, 1, 2] }
|
10
|
+
#
|
11
|
+
# Can also pass a Proc to change how nested keys are flattened:
|
12
|
+
# flatten_keys_of(hash, flattener: ->(*keys) { keys.join('.') })
|
13
|
+
# => { "key"=>"value", "nested.key"=>"nested_value", "array"=>[0, 1, 2] }
|
14
|
+
# flatten_keys_of(hash, flattener: ->(*keys) { keys.join('-') })
|
15
|
+
# => { "key"=>"value", "nested-key"=>"nested_value", "array"=>[0, 1, 2] }
|
16
|
+
# flatten_keys_of(hash, flattener: ->(*keys) { keys.map(&:to_s).reduce { |memo, key| memo + "[#{key}]" } })
|
17
|
+
# => { "key"=>"value", "nested[key]"=>"nested_value", "array"=>[0, 1, 2] }
|
18
|
+
#
|
19
|
+
# Can also determine if array values should be flattened as well:
|
20
|
+
# hash = { person: { age: '28', siblings: ['Tom', 'Sally'] } }
|
21
|
+
# flatten_keys_of(hash, flatten_arrays: true)
|
22
|
+
# => { [:key]=>"value", [:nested, :key]=>"nested_value", [:array, 0]=>0, [:array, 1]=>1, [:array, 2]=>2 }
|
23
|
+
# flatten_keys_of(hash, flattener: ->(*keys) { keys.join('.') }, flatten_arrays: true)
|
24
|
+
# => { "key"=>"value", "nested.key"=>"nested_value", "array.0"=>0, "array.1"=>1, "array.2"=>2 }
|
25
|
+
|
26
|
+
# refactored from https://stackoverflow.com/a/23861946/2884386
|
27
|
+
def flatten_keys_of(input, keys = [], output = {}, flattener: ->(*k) { k }, flatten_arrays: false)
|
28
|
+
if input.is_a?(Hash)
|
29
|
+
input.each do |key, value|
|
30
|
+
flatten_keys_of(
|
31
|
+
value,
|
32
|
+
keys + Array.wrap(key),
|
33
|
+
output,
|
34
|
+
flattener: flattener,
|
35
|
+
flatten_arrays: flatten_arrays
|
36
|
+
)
|
37
|
+
end
|
38
|
+
elsif input.is_a?(Array) && flatten_arrays
|
39
|
+
input.each_with_index do |value, index|
|
40
|
+
flatten_keys_of(
|
41
|
+
value,
|
42
|
+
keys + Array.wrap(index),
|
43
|
+
output,
|
44
|
+
flattener: flattener,
|
45
|
+
flatten_arrays: flatten_arrays
|
46
|
+
)
|
47
|
+
end
|
48
|
+
else
|
49
|
+
return output.merge!(flattener.call(*keys) => input)
|
50
|
+
end
|
51
|
+
|
52
|
+
output
|
53
|
+
end
|
@@ -13,7 +13,7 @@
|
|
13
13
|
# transform_to_sortable_numeric(Date.new(2000, 12, 25))
|
14
14
|
# => 977720400000
|
15
15
|
|
16
|
-
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/
|
16
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
17
17
|
def transform_to_sortable_numeric(value)
|
18
18
|
# https://www.justinweiss.com/articles/4-simple-memoization-patterns-in-ruby-and-one-gem/#and-what-about-parameters
|
19
19
|
@sortable_numeric ||= Hash.new do |h, key|
|
@@ -35,8 +35,7 @@ def transform_to_sortable_numeric(value)
|
|
35
35
|
end
|
36
36
|
@sortable_numeric[value]
|
37
37
|
end
|
38
|
-
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/
|
39
|
-
# rubocop:enable Style/AsciiComments
|
38
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
40
39
|
|
41
40
|
def string_to_sortable_numeric(string)
|
42
41
|
string # 'aB09ü'
|
@@ -46,6 +45,7 @@ def string_to_sortable_numeric(string)
|
|
46
45
|
.reduce(&:concat) # "097.066048057252"
|
47
46
|
.to_r # (24266512014313/250000000000)
|
48
47
|
end
|
48
|
+
# rubocop:enable Style/AsciiComments
|
49
49
|
|
50
50
|
def time_to_sortable_numeric(time)
|
51
51
|
# https://stackoverflow.com/a/30604935/2884386
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: actionset
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.11.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stephen Margheim
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-04-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -142,14 +142,14 @@ dependencies:
|
|
142
142
|
requirements:
|
143
143
|
- - "~>"
|
144
144
|
- !ruby/object:Gem::Version
|
145
|
-
version: 5.
|
145
|
+
version: 5.2.0
|
146
146
|
type: :development
|
147
147
|
prerelease: false
|
148
148
|
version_requirements: !ruby/object:Gem::Requirement
|
149
149
|
requirements:
|
150
150
|
- - "~>"
|
151
151
|
- !ruby/object:Gem::Version
|
152
|
-
version: 5.
|
152
|
+
version: 5.2.0
|
153
153
|
- !ruby/object:Gem::Dependency
|
154
154
|
name: rake
|
155
155
|
requirement: !ruby/object:Gem::Requirement
|
@@ -259,6 +259,7 @@ files:
|
|
259
259
|
- config.ru
|
260
260
|
- lib/action_set.rb
|
261
261
|
- lib/action_set/attribute_value.rb
|
262
|
+
- lib/action_set/filter_instructions.rb
|
262
263
|
- lib/action_set/helpers/export/path_for_helper.rb
|
263
264
|
- lib/action_set/helpers/helper_methods.rb
|
264
265
|
- lib/action_set/helpers/pagination/current_page_description_for_helper.rb
|
@@ -270,6 +271,11 @@ files:
|
|
270
271
|
- lib/action_set/helpers/pagination/page_size_for_helper.rb
|
271
272
|
- lib/action_set/helpers/pagination/path_for_helper.rb
|
272
273
|
- lib/action_set/helpers/pagination/prev_page_link_for_helper.rb
|
274
|
+
- lib/action_set/helpers/pagination/record_description_for_helper.rb
|
275
|
+
- lib/action_set/helpers/pagination/record_first_for_helper.rb
|
276
|
+
- lib/action_set/helpers/pagination/record_last_for_helper.rb
|
277
|
+
- lib/action_set/helpers/pagination/record_range_for_helper.rb
|
278
|
+
- lib/action_set/helpers/pagination/record_size_for_helper.rb
|
273
279
|
- lib/action_set/helpers/pagination/total_pages_for_helper.rb
|
274
280
|
- lib/action_set/helpers/params/current_helper.rb
|
275
281
|
- lib/action_set/helpers/params/form_for_object_helper.rb
|
@@ -279,6 +285,7 @@ files:
|
|
279
285
|
- lib/action_set/helpers/sort/link_for_helper.rb
|
280
286
|
- lib/action_set/helpers/sort/next_direction_for_helper.rb
|
281
287
|
- lib/action_set/helpers/sort/path_for_helper.rb
|
288
|
+
- lib/action_set/sort_instructions.rb
|
282
289
|
- lib/active_set.rb
|
283
290
|
- lib/active_set/active_record_set_instruction.rb
|
284
291
|
- lib/active_set/attribute_instruction.rb
|
@@ -286,8 +293,15 @@ files:
|
|
286
293
|
- lib/active_set/enumerable_set_instruction.rb
|
287
294
|
- lib/active_set/exporting/csv_strategy.rb
|
288
295
|
- lib/active_set/exporting/operation.rb
|
289
|
-
- lib/active_set/filtering/
|
290
|
-
- lib/active_set/filtering/
|
296
|
+
- lib/active_set/filtering/active_record/operators.rb
|
297
|
+
- lib/active_set/filtering/active_record/query_column.rb
|
298
|
+
- lib/active_set/filtering/active_record/query_value.rb
|
299
|
+
- lib/active_set/filtering/active_record/set_instruction.rb
|
300
|
+
- lib/active_set/filtering/active_record/strategy.rb
|
301
|
+
- lib/active_set/filtering/constants.rb
|
302
|
+
- lib/active_set/filtering/enumerable/operators.rb
|
303
|
+
- lib/active_set/filtering/enumerable/set_instruction.rb
|
304
|
+
- lib/active_set/filtering/enumerable/strategy.rb
|
291
305
|
- lib/active_set/filtering/operation.rb
|
292
306
|
- lib/active_set/paginating/active_record_strategy.rb
|
293
307
|
- lib/active_set/paginating/enumerable_strategy.rb
|
@@ -295,15 +309,14 @@ files:
|
|
295
309
|
- lib/active_set/sorting/active_record_strategy.rb
|
296
310
|
- lib/active_set/sorting/enumerable_strategy.rb
|
297
311
|
- lib/active_set/sorting/operation.rb
|
298
|
-
- lib/helpers/
|
312
|
+
- lib/helpers/flatten_keys_of.rb
|
299
313
|
- lib/helpers/transform_to_sortable_numeric.rb
|
300
|
-
- lib/patches/core_ext/hash/flatten_keys.rb
|
301
314
|
- pagination.png
|
302
315
|
homepage: https://github.com/fractaledmind/actionset
|
303
316
|
licenses:
|
304
317
|
- MIT
|
305
318
|
metadata: {}
|
306
|
-
post_install_message:
|
319
|
+
post_install_message:
|
307
320
|
rdoc_options: []
|
308
321
|
require_paths:
|
309
322
|
- lib
|
@@ -318,9 +331,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
318
331
|
- !ruby/object:Gem::Version
|
319
332
|
version: '0'
|
320
333
|
requirements: []
|
321
|
-
rubyforge_project:
|
322
|
-
rubygems_version: 2.6.
|
323
|
-
signing_key:
|
334
|
+
rubyforge_project:
|
335
|
+
rubygems_version: 2.6.14.4
|
336
|
+
signing_key:
|
324
337
|
specification_version: 4
|
325
338
|
summary: A toolkit for working with collections.
|
326
339
|
test_files: []
|
@@ -1,85 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative '../active_record_set_instruction'
|
4
|
-
require 'active_support/core_ext/module/delegation'
|
5
|
-
|
6
|
-
class ActiveSet
|
7
|
-
module Filtering
|
8
|
-
class ActiveRecordStrategy
|
9
|
-
delegate :attribute_model,
|
10
|
-
:arel_column,
|
11
|
-
:arel_operator,
|
12
|
-
:arel_value,
|
13
|
-
:arel_type,
|
14
|
-
:initial_relation,
|
15
|
-
:attribute,
|
16
|
-
to: :@set_instruction
|
17
|
-
|
18
|
-
def initialize(set, attribute_instruction)
|
19
|
-
@set = set
|
20
|
-
@attribute_instruction = attribute_instruction
|
21
|
-
@set_instruction = ActiveRecordSetInstruction.new(attribute_instruction, set)
|
22
|
-
end
|
23
|
-
|
24
|
-
def execute
|
25
|
-
return false unless @set.respond_to? :to_sql
|
26
|
-
|
27
|
-
if execute_filter_operation?
|
28
|
-
statement = filter_operation
|
29
|
-
elsif execute_intersect_operation?
|
30
|
-
begin
|
31
|
-
statement = intersect_operation
|
32
|
-
rescue ArgumentError # thrown if merging a non-ActiveRecord::Relation
|
33
|
-
return false
|
34
|
-
end
|
35
|
-
else
|
36
|
-
return false
|
37
|
-
end
|
38
|
-
|
39
|
-
statement
|
40
|
-
end
|
41
|
-
|
42
|
-
private
|
43
|
-
|
44
|
-
def execute_filter_operation?
|
45
|
-
return false unless attribute_model
|
46
|
-
return false unless attribute_model.respond_to?(:attribute_names)
|
47
|
-
return false unless attribute_model.attribute_names.include?(attribute)
|
48
|
-
|
49
|
-
true
|
50
|
-
end
|
51
|
-
|
52
|
-
def execute_intersect_operation?
|
53
|
-
return false unless attribute_model
|
54
|
-
return false unless attribute_model.respond_to?(attribute)
|
55
|
-
return false if attribute_model.method(attribute).arity.zero?
|
56
|
-
|
57
|
-
true
|
58
|
-
end
|
59
|
-
|
60
|
-
def filter_operation
|
61
|
-
initial_relation
|
62
|
-
.where(
|
63
|
-
arel_column.send(
|
64
|
-
arel_operator,
|
65
|
-
arel_value
|
66
|
-
)
|
67
|
-
)
|
68
|
-
end
|
69
|
-
|
70
|
-
def intersect_operation
|
71
|
-
# NOTE: If merging relations that contain duplicate column conditions,
|
72
|
-
# the second condition will replace the first.
|
73
|
-
# e.g. Thing.where(id: [1,2]).merge(Thing.where(id: [2,3]))
|
74
|
-
# => [Thing<2>, Thing<3>] NOT [Thing<2>]
|
75
|
-
initial_relation
|
76
|
-
.merge(
|
77
|
-
attribute_model.public_send(
|
78
|
-
attribute,
|
79
|
-
arel_value
|
80
|
-
)
|
81
|
-
)
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
@@ -1,79 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative '../enumerable_set_instruction'
|
4
|
-
require 'active_support/core_ext/module/delegation'
|
5
|
-
|
6
|
-
class ActiveSet
|
7
|
-
module Filtering
|
8
|
-
class EnumerableStrategy
|
9
|
-
delegate :attribute_instance,
|
10
|
-
:attribute_class,
|
11
|
-
:attribute_value,
|
12
|
-
:attribute_value_for,
|
13
|
-
:operator,
|
14
|
-
:attribute,
|
15
|
-
to: :@set_instruction
|
16
|
-
|
17
|
-
def initialize(set, attribute_instruction)
|
18
|
-
@set = set
|
19
|
-
@attribute_instruction = attribute_instruction
|
20
|
-
@set_instruction = EnumerableSetInstruction.new(attribute_instruction, set)
|
21
|
-
end
|
22
|
-
|
23
|
-
def execute
|
24
|
-
return false unless @set.respond_to? :select
|
25
|
-
|
26
|
-
if execute_filter_operation?
|
27
|
-
set = filter_operation
|
28
|
-
elsif execute_intersect_operation?
|
29
|
-
begin
|
30
|
-
set = intersect_operation
|
31
|
-
rescue TypeError # thrown if intersecting with a non-Array
|
32
|
-
return false
|
33
|
-
end
|
34
|
-
else
|
35
|
-
return false
|
36
|
-
end
|
37
|
-
|
38
|
-
set
|
39
|
-
end
|
40
|
-
|
41
|
-
private
|
42
|
-
|
43
|
-
def execute_filter_operation?
|
44
|
-
return false unless attribute_instance
|
45
|
-
return false unless attribute_instance.respond_to?(attribute)
|
46
|
-
return false if attribute_instance.method(attribute).arity.positive?
|
47
|
-
|
48
|
-
true
|
49
|
-
end
|
50
|
-
|
51
|
-
def execute_intersect_operation?
|
52
|
-
return false unless attribute_class
|
53
|
-
return false unless attribute_class.respond_to?(attribute)
|
54
|
-
return false if attribute_class.method(attribute).arity.zero?
|
55
|
-
|
56
|
-
true
|
57
|
-
end
|
58
|
-
|
59
|
-
def filter_operation
|
60
|
-
@set.select do |item|
|
61
|
-
attribute_value_for(item)
|
62
|
-
.public_send(
|
63
|
-
operator,
|
64
|
-
attribute_value
|
65
|
-
)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
def intersect_operation
|
70
|
-
other_set = attribute_class
|
71
|
-
.public_send(
|
72
|
-
attribute,
|
73
|
-
attribute_value
|
74
|
-
)
|
75
|
-
@set & other_set
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|