activeset 0.5.8 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +2 -0
- data/lib/.DS_Store +0 -0
- data/lib/active_set.rb +24 -26
- data/lib/active_set/.DS_Store +0 -0
- data/lib/active_set/adapter_activerecord.rb +58 -0
- data/lib/active_set/adapter_base.rb +14 -0
- data/lib/active_set/instruction.rb +66 -0
- data/lib/active_set/instructions.rb +34 -0
- data/lib/active_set/processor_base.rb +28 -0
- data/lib/active_set/processor_filter.rb +21 -0
- data/lib/active_set/processor_filter/active_record_adapter.rb +50 -0
- data/lib/active_set/processor_filter/enumerable_adapter.rb +21 -0
- data/lib/active_set/processor_paginate.rb +35 -0
- data/lib/active_set/{processors/paginate → processor_paginate}/active_record_adapter.rb +11 -13
- data/lib/active_set/{processors/paginate → processor_paginate}/enumerable_adapter.rb +10 -12
- data/lib/active_set/processor_sort.rb +19 -0
- data/lib/active_set/processor_sort/active_record_adapter.rb +50 -0
- data/lib/active_set/processor_sort/enumerable_adapter.rb +58 -0
- data/lib/active_set/{processors/transform_processor.rb → processor_transform.rb} +6 -6
- data/lib/active_set/{processors/transform → processor_transform}/csv_adapter.rb +11 -14
- data/lib/active_set/version.rb +1 -1
- data/lib/helpers/throws.rb +19 -0
- metadata +21 -19
- data/lib/active_set/instructions/base.rb +0 -37
- data/lib/active_set/instructions/entry.rb +0 -27
- data/lib/active_set/instructions/entry/keypath.rb +0 -65
- data/lib/active_set/instructions/entry/value.rb +0 -15
- data/lib/active_set/processors/base_adapter.rb +0 -17
- data/lib/active_set/processors/base_processor.rb +0 -22
- data/lib/active_set/processors/filter/active_record_adapter.rb +0 -78
- data/lib/active_set/processors/filter/enumerable_adapter.rb +0 -27
- data/lib/active_set/processors/filter_processor.rb +0 -18
- data/lib/active_set/processors/paginate_processor.rb +0 -36
- data/lib/active_set/processors/sort/active_record_adapter.rb +0 -55
- data/lib/active_set/processors/sort/enumerable_adapter.rb +0 -41
- data/lib/active_set/processors/sort_processor.rb +0 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8a2838aec338dd5f82088e61e90e37ad419a2039
|
4
|
+
data.tar.gz: 741731ac20fec572d99e2b7b62019af6116c89fc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 406349801340205ffc8035cc71540b8f03cfd89d67ef4c150b2c16fd94dc5838a16acdfee91dc5fd7c74b300fb4b5f39fbee79429b57c4411a2e9d87ee88a60b
|
7
|
+
data.tar.gz: 661719703c5b4b1fd8cee0459ef6e261fdf0094ea85dc855c96115ccaeda55bbb773d0eaf93edfc1d08f67544487dfc737d563b484dabfc608c8feafab49e0e5
|
data/CHANGELOG
CHANGED
data/lib/.DS_Store
ADDED
Binary file
|
data/lib/active_set.rb
CHANGED
@@ -2,67 +2,65 @@
|
|
2
2
|
|
3
3
|
require 'active_set/version'
|
4
4
|
|
5
|
-
require 'active_set/
|
6
|
-
require 'active_set/
|
7
|
-
require 'active_set/
|
8
|
-
require 'active_set/
|
5
|
+
require 'active_set/processor_filter'
|
6
|
+
require 'active_set/processor_sort'
|
7
|
+
require 'active_set/processor_paginate'
|
8
|
+
require 'active_set/processor_transform'
|
9
9
|
|
10
10
|
class ActiveSet
|
11
11
|
include Enumerable
|
12
12
|
|
13
|
-
attr_reader :set, :
|
13
|
+
attr_reader :set, :view, :instructions
|
14
14
|
|
15
|
-
def initialize(set,
|
15
|
+
def initialize(set, view: nil, instructions: {})
|
16
16
|
@set = set
|
17
|
+
@view = view || set
|
17
18
|
@instructions = instructions
|
18
|
-
@total_count = total_count || @set.count
|
19
19
|
end
|
20
20
|
|
21
21
|
def each(&block)
|
22
|
-
@
|
22
|
+
@view.each(&block)
|
23
23
|
end
|
24
24
|
|
25
25
|
def ==(other)
|
26
|
-
return @
|
27
|
-
@
|
26
|
+
return @view == other unless other.is_a?(ActiveSet)
|
27
|
+
@view == other.view
|
28
28
|
end
|
29
29
|
|
30
30
|
def method_missing(method_name, *args, &block)
|
31
|
-
@
|
31
|
+
@view.send(method_name, *args, &block) || super
|
32
32
|
end
|
33
33
|
|
34
34
|
def respond_to_missing?(method_name, include_private = false)
|
35
|
-
@
|
35
|
+
@view.respond_to?(method_name) || super
|
36
36
|
end
|
37
37
|
|
38
38
|
def filter(instructions)
|
39
|
-
filterer =
|
40
|
-
|
41
|
-
new_active_set(filtered_set, :filter, instructions, filtered_set.count)
|
39
|
+
filterer = Processor::Filter.new(@view, instructions)
|
40
|
+
reinitialize(filterer.process, :filter, instructions)
|
42
41
|
end
|
43
42
|
|
44
43
|
def sort(instructions)
|
45
|
-
sorter =
|
46
|
-
|
44
|
+
sorter = Processor::Sort.new(@view, instructions)
|
45
|
+
reinitialize(sorter.process, :sort, instructions)
|
47
46
|
end
|
48
47
|
|
49
48
|
def paginate(instructions)
|
50
|
-
paginater =
|
51
|
-
|
52
|
-
size: paginater.send(:page_size))
|
53
|
-
new_active_set(paginater.process, :paginate, full_instructions)
|
49
|
+
paginater = Processor::Paginate.new(@view, instructions)
|
50
|
+
reinitialize(paginater.process, :paginate, instructions)
|
54
51
|
end
|
55
52
|
|
56
53
|
def transform(instructions)
|
57
|
-
transformer =
|
54
|
+
transformer = Processor::Transform.new(@view, instructions)
|
58
55
|
transformer.process
|
59
56
|
end
|
60
57
|
|
61
58
|
private
|
62
59
|
|
63
|
-
def
|
64
|
-
self.class.new(set,
|
65
|
-
|
66
|
-
|
60
|
+
def reinitialize(processed_set, method, instructions)
|
61
|
+
self.class.new(@set,
|
62
|
+
view: processed_set,
|
63
|
+
instructions: @instructions.merge(
|
64
|
+
method => instructions))
|
67
65
|
end
|
68
66
|
end
|
Binary file
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative './adapter_base'
|
4
|
+
|
5
|
+
class ActiveSet
|
6
|
+
class Adapter::ActiveRecord < Adapter::Base
|
7
|
+
private
|
8
|
+
|
9
|
+
def can_query_with_active_record?
|
10
|
+
attribute_is_field?
|
11
|
+
end
|
12
|
+
|
13
|
+
def can_merge_with_active_record?
|
14
|
+
attribute_is_class_method? &&
|
15
|
+
attribute_is_method_with_params?
|
16
|
+
end
|
17
|
+
|
18
|
+
def arel_eager_load_associations
|
19
|
+
@set.eager_load(instruction.associations_hash)
|
20
|
+
end
|
21
|
+
|
22
|
+
def arel_column
|
23
|
+
arel_table[instruction.attribute]
|
24
|
+
end
|
25
|
+
|
26
|
+
def arel_table
|
27
|
+
Arel::Table.new(attribute_model.table_name)
|
28
|
+
end
|
29
|
+
|
30
|
+
def attribute_is_field?
|
31
|
+
return false unless attribute_model
|
32
|
+
|
33
|
+
attribute_model.attribute_names
|
34
|
+
.include?(instruction.attribute)
|
35
|
+
end
|
36
|
+
|
37
|
+
def attribute_is_class_method?
|
38
|
+
return false unless attribute_model
|
39
|
+
|
40
|
+
attribute_model.respond_to?(instruction.attribute)
|
41
|
+
end
|
42
|
+
|
43
|
+
def attribute_is_method_with_params?
|
44
|
+
return false unless attribute_model
|
45
|
+
|
46
|
+
attribute_model.method(instruction.attribute).arity != 0
|
47
|
+
end
|
48
|
+
|
49
|
+
def attribute_model
|
50
|
+
tmp_model = instruction.associations_array
|
51
|
+
.reduce(@set) do |obj, assoc|
|
52
|
+
obj.reflections[assoc.to_s]&.klass
|
53
|
+
end
|
54
|
+
# return tmp_model.klass if tmp_model.is_a?(ActiveRecord::Relation)
|
55
|
+
# tmp_model
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/core_ext/array/wrap'
|
4
|
+
|
5
|
+
class ActiveSet
|
6
|
+
class Instruction
|
7
|
+
attr_reader :keypath, :value
|
8
|
+
|
9
|
+
def initialize(keypath, value)
|
10
|
+
# `keypath` can be an Array (e.g. [:parent, :child, :grandchild])
|
11
|
+
# or a String (e.g. 'parent.child.grandchild')
|
12
|
+
@keypath = Array.wrap(keypath).map(&:to_s).flat_map { |x| x.split('.') }
|
13
|
+
@value = value
|
14
|
+
end
|
15
|
+
|
16
|
+
def attribute
|
17
|
+
attribute = @keypath.last
|
18
|
+
return attribute.sub(operator_regex, '') if attribute&.match operator_regex
|
19
|
+
|
20
|
+
attribute
|
21
|
+
end
|
22
|
+
|
23
|
+
def operator(default: '==')
|
24
|
+
attribute = @keypath.last
|
25
|
+
return attribute[operator_regex, 1] if attribute&.match operator_regex
|
26
|
+
|
27
|
+
default
|
28
|
+
end
|
29
|
+
|
30
|
+
def associations_array
|
31
|
+
return [] unless @keypath.any?
|
32
|
+
|
33
|
+
@keypath.slice(0, @keypath.length - 1)
|
34
|
+
end
|
35
|
+
|
36
|
+
def associations_hash
|
37
|
+
return {} unless @keypath.any?
|
38
|
+
|
39
|
+
associations_array.reverse.reduce({}) do |hash, association|
|
40
|
+
{ association => hash }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def value_for(item:)
|
45
|
+
resource_for(item: item).public_send(attribute)
|
46
|
+
rescue
|
47
|
+
nil
|
48
|
+
end
|
49
|
+
|
50
|
+
def resource_for(item:)
|
51
|
+
associations_array.reduce(item) do |resource, association|
|
52
|
+
return nil unless resource.respond_to? association
|
53
|
+
|
54
|
+
resource.public_send(association)
|
55
|
+
end
|
56
|
+
rescue
|
57
|
+
nil
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def operator_regex
|
63
|
+
/\((.*?)\)/
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../patches/core_ext/hash/flatten_keys'
|
4
|
+
require_relative './instruction'
|
5
|
+
|
6
|
+
class ActiveSet
|
7
|
+
class Instructions
|
8
|
+
include Enumerable
|
9
|
+
|
10
|
+
def initialize(hash)
|
11
|
+
@instructions = hash.flatten_keys.map do |keypath, value|
|
12
|
+
Instruction.new(keypath, value)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def each(&block)
|
17
|
+
@instructions.each(&block)
|
18
|
+
end
|
19
|
+
|
20
|
+
def method_missing(method_name, *args, &block)
|
21
|
+
@instructions.send(method_name, *args, &block) || super
|
22
|
+
end
|
23
|
+
|
24
|
+
def respond_to_missing?(method_name, include_private = false)
|
25
|
+
@instructions.respond_to?(method_name) || super
|
26
|
+
end
|
27
|
+
|
28
|
+
def get(key)
|
29
|
+
@instructions.find do |instruction|
|
30
|
+
instruction.attribute.to_s == key.to_s
|
31
|
+
end&.value
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative './instructions'
|
4
|
+
|
5
|
+
class ActiveSet
|
6
|
+
module Processor
|
7
|
+
class Base
|
8
|
+
attr_reader :set, :instructions, :adapters
|
9
|
+
|
10
|
+
def self.register_adapter(adapter, precedence = 0)
|
11
|
+
@adapters ||= []
|
12
|
+
@adapters.insert(precedence, adapter)
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(set, instructions)
|
16
|
+
@set = set
|
17
|
+
@instructions = Instructions.new(validate_instructions(instructions))
|
18
|
+
@adapters = self.class.instance_variable_get(:@adapters)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def validate_instructions(instructions)
|
24
|
+
instructions
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative './processor_base'
|
4
|
+
require_relative './processor_filter/enumerable_adapter'
|
5
|
+
require_relative './processor_filter/active_record_adapter'
|
6
|
+
|
7
|
+
class ActiveSet
|
8
|
+
class Processor::Filter < Processor::Base
|
9
|
+
def process
|
10
|
+
@instructions.reduce(@set) do |set, instruction|
|
11
|
+
adapters.each do |adapter|
|
12
|
+
result = adapter.new(set, [instruction]).process
|
13
|
+
break(result) if result
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
register_adapter(EnumerableAdapter)
|
19
|
+
register_adapter(ActiveRecordAdapter)
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../adapter_activerecord'
|
4
|
+
require_relative '../processor_base'
|
5
|
+
require_relative '../../helpers/throws'
|
6
|
+
|
7
|
+
class ActiveSet
|
8
|
+
class Processor::Filter < Processor::Base
|
9
|
+
class ActiveRecordAdapter < Adapter::ActiveRecord
|
10
|
+
def process
|
11
|
+
return false unless @set.respond_to?(:to_sql)
|
12
|
+
|
13
|
+
if can_query_with_active_record?
|
14
|
+
statement = arel_eager_load_associations
|
15
|
+
.where(arel_operation)
|
16
|
+
elsif can_merge_with_active_record?
|
17
|
+
statement = arel_eager_load_associations
|
18
|
+
.merge(attribute_model.public_send(instruction.attribute,
|
19
|
+
instruction.value))
|
20
|
+
else
|
21
|
+
return false
|
22
|
+
end
|
23
|
+
|
24
|
+
return false if throws?(ActiveRecord::StatementInvalid) { statement.load }
|
25
|
+
|
26
|
+
statement
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def instruction
|
32
|
+
@instructions.first
|
33
|
+
end
|
34
|
+
|
35
|
+
def arel_operation
|
36
|
+
Arel::Nodes::InfixOperation.new(arel_operator,
|
37
|
+
arel_column,
|
38
|
+
arel_value)
|
39
|
+
end
|
40
|
+
|
41
|
+
def arel_value
|
42
|
+
Arel.sql(ActiveRecord::Base.connection.quote(instruction.value))
|
43
|
+
end
|
44
|
+
|
45
|
+
def arel_operator
|
46
|
+
instruction.operator
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../adapter_base'
|
4
|
+
|
5
|
+
class ActiveSet
|
6
|
+
class Processor::Filter < Processor::Base
|
7
|
+
class EnumerableAdapter < Adapter::Base
|
8
|
+
def process
|
9
|
+
return false unless @set.respond_to? :select
|
10
|
+
|
11
|
+
@instructions.reduce(@set) do |set, instruction|
|
12
|
+
set.select do |item|
|
13
|
+
instruction.value_for(item: item)
|
14
|
+
.send(instruction.operator,
|
15
|
+
instruction.value)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative './processor_base'
|
4
|
+
require_relative './processor_paginate/enumerable_adapter'
|
5
|
+
require_relative './processor_paginate/active_record_adapter'
|
6
|
+
|
7
|
+
class ActiveSet
|
8
|
+
class Processor::Paginate < Processor::Base
|
9
|
+
def process
|
10
|
+
adapters.each do |adapter|
|
11
|
+
result = adapter.new(@set, @instructions).process
|
12
|
+
break(result) if result
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def validate_instructions(instructions)
|
19
|
+
{
|
20
|
+
page: (instructions[:page] ||
|
21
|
+
instructions['page'] ||
|
22
|
+
1).to_i,
|
23
|
+
size: (instructions[:size] ||
|
24
|
+
instructions['size'] ||
|
25
|
+
25).to_i,
|
26
|
+
outset: (instructions[:outset] ||
|
27
|
+
instructions['outset'] ||
|
28
|
+
0).to_i
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
register_adapter(EnumerableAdapter)
|
33
|
+
register_adapter(ActiveRecordAdapter)
|
34
|
+
end
|
35
|
+
end
|