activeset 0.6.5 → 0.7.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.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +0 -6
  4. data/CHANGELOG +5 -0
  5. data/README.md +58 -6
  6. data/activeset.gemspec +8 -8
  7. data/bin/console +14 -0
  8. data/lib/.DS_Store +0 -0
  9. data/lib/active_set.rb +28 -21
  10. data/lib/active_set/{instruction.rb → attribute_instruction.rb} +12 -8
  11. data/lib/active_set/column_instruction.rb +44 -0
  12. data/lib/active_set/exporting/operation.rb +66 -0
  13. data/lib/active_set/filtering/operation.rb +190 -0
  14. data/lib/active_set/paginating/operation.rb +102 -0
  15. data/lib/active_set/sorting/operation.rb +144 -0
  16. data/lib/helpers/throws.rb +2 -2
  17. data/lib/helpers/transform_to_sortable_numeric.rb +36 -0
  18. data/lib/patches/core_ext/hash/flatten_keys.rb +43 -14
  19. metadata +55 -39
  20. data/lib/active_set/.DS_Store +0 -0
  21. data/lib/active_set/adapter_activerecord.rb +0 -58
  22. data/lib/active_set/adapter_base.rb +0 -14
  23. data/lib/active_set/instructions.rb +0 -42
  24. data/lib/active_set/processor_base.rb +0 -28
  25. data/lib/active_set/processor_filter.rb +0 -21
  26. data/lib/active_set/processor_filter/active_record_adapter.rb +0 -50
  27. data/lib/active_set/processor_filter/enumerable_adapter.rb +0 -21
  28. data/lib/active_set/processor_paginate.rb +0 -35
  29. data/lib/active_set/processor_paginate/active_record_adapter.rb +0 -37
  30. data/lib/active_set/processor_paginate/enumerable_adapter.rb +0 -39
  31. data/lib/active_set/processor_sort.rb +0 -19
  32. data/lib/active_set/processor_sort/active_record_adapter.rb +0 -27
  33. data/lib/active_set/processor_sort/active_record_operation.rb +0 -55
  34. data/lib/active_set/processor_sort/enumerable_adapter.rb +0 -58
  35. data/lib/active_set/processor_transform.rb +0 -30
  36. data/lib/active_set/processor_transform/csv_adapter.rb +0 -77
  37. data/lib/active_set/version.rb +0 -5
Binary file
@@ -1,58 +0,0 @@
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
@@ -1,14 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class ActiveSet
4
- module Adapter
5
- class Base
6
- attr_accessor :instruction
7
-
8
- def initialize(set, instructions)
9
- @set = set
10
- @instructions = instructions
11
- end
12
- end
13
- end
14
- end
@@ -1,42 +0,0 @@
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
- # :nocov:
21
- def method_missing(method_name, *args, &block)
22
- @instructions.send(method_name, *args, &block) || super
23
- end
24
- # :nocov:
25
-
26
- # :nocov:
27
- def respond_to_missing?(method_name, include_private = false)
28
- @instructions.respond_to?(method_name) || super
29
- end
30
- # :nocov:
31
-
32
- def associations_hash
33
- @instructions.reduce({}) { |h, i| h.merge(i.associations_hash) }
34
- end
35
-
36
- def get(key)
37
- @instructions.find do |instruction|
38
- instruction.attribute.to_s == key.to_s
39
- end&.value
40
- end
41
- end
42
- end
@@ -1,28 +0,0 @@
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
@@ -1,21 +0,0 @@
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
@@ -1,50 +0,0 @@
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(default: '=')
47
- end
48
- end
49
- end
50
- end
@@ -1,21 +0,0 @@
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
@@ -1,35 +0,0 @@
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
@@ -1,37 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../adapter_base'
4
- require_relative '../processor_base'
5
-
6
- class ActiveSet
7
- class Processor::Paginate < Processor::Base
8
- class ActiveRecordAdapter < Adapter::Base
9
- def process
10
- return false unless @set.respond_to? :to_sql
11
- return @set.none if @set.length <= page_size && page_number > 1
12
-
13
- @set.limit(page_size).offset(page_offset)
14
- end
15
-
16
- private
17
-
18
- def page_offset
19
- return 0 if page_number == 1
20
-
21
- page_size * (page_number - 1)
22
- end
23
-
24
- def page_size
25
- @instructions.get('size').to_i
26
- end
27
-
28
- def page_number
29
- num = @instructions.get('page').to_i
30
- return 1 if (num - 1).negative?
31
- return 1 if (num - 1).zero?
32
-
33
- num
34
- end
35
- end
36
- end
37
- end
@@ -1,39 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../adapter_base'
4
- require_relative '../processor_base'
5
-
6
- class ActiveSet
7
- class Processor::Paginate < Processor::Base
8
- class EnumerableAdapter < Adapter::Base
9
- def process
10
- return [] if @set.count <= page_size && page_number > 1
11
-
12
- @set[page_start..page_end] || []
13
- end
14
-
15
- private
16
-
17
- def page_start
18
- return 0 if page_number == 1
19
-
20
- page_size * (page_number - 1)
21
- end
22
-
23
- def page_end
24
- return page_start if page_size == 1
25
-
26
- page_start + page_size - 1
27
- end
28
-
29
- def page_size
30
- @instructions.get('size').to_i
31
- end
32
-
33
- def page_number
34
- num = @instructions.get('page').to_i
35
- (num.to_i - 1).negative? ? 0 : num
36
- end
37
- end
38
- end
39
- end
@@ -1,19 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative './processor_base'
4
- require_relative './processor_sort/enumerable_adapter'
5
- require_relative './processor_sort/active_record_adapter'
6
-
7
- class ActiveSet
8
- class Processor::Sort < 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
- register_adapter(EnumerableAdapter)
17
- register_adapter(ActiveRecordAdapter)
18
- end
19
- end
@@ -1,27 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../adapter_activerecord'
4
- require_relative '../processor_base'
5
- require_relative '../../helpers/throws'
6
- require_relative './active_record_operation'
7
-
8
- class ActiveSet
9
- class Processor::Sort < Processor::Base
10
- class ActiveRecordAdapter < Adapter::ActiveRecord
11
- def process
12
- return false unless @set.respond_to?(:to_sql)
13
-
14
- @instructions.reduce(@set.eager_load(@instructions.associations_hash)) do |set, instruction|
15
- ar_operation = ActiveRecordOperation.new(instruction, @set.klass)
16
- return false unless ar_operation.attribute_is_field?
17
-
18
- statement = set.merge(ar_operation.operation)
19
-
20
- return false if throws?(ActiveRecord::StatementInvalid) { statement.load }
21
-
22
- statement
23
- end
24
- end
25
- end
26
- end
27
- end
@@ -1,55 +0,0 @@
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::Sort < Processor::Base
9
- class ActiveRecordOperation
10
- def initialize(instruction, klass)
11
- @instruction = instruction
12
- @klass = klass
13
- end
14
-
15
- def operation
16
- attribute_model.order(column.send(validate_direction(@instruction.value)))
17
- end
18
-
19
- def attribute_is_field?
20
- return false unless attribute_model
21
-
22
- attribute_model.attribute_names
23
- .include?(@instruction.attribute)
24
- end
25
-
26
- def case_insensitive?
27
- @instruction.operator.to_s.downcase == 'i'
28
- end
29
-
30
- def column
31
- column = table[@instruction.attribute]
32
- case_insensitive? ? column.lower : column
33
- end
34
-
35
- def table
36
- Arel::Table.new(attribute_model.table_name)
37
- end
38
-
39
- def validate_direction(direction)
40
- return 'desc' if direction.to_s.downcase.start_with? 'desc'
41
-
42
- 'asc'
43
- end
44
-
45
- def attribute_model
46
- tmp_model = @instruction.associations_array
47
- .reduce(@klass) do |obj, assoc|
48
- obj.reflections[assoc.to_s]&.klass
49
- end
50
- # return tmp_model.klass if tmp_model.is_a?(ActiveRecord::Relation)
51
- # tmp_model
52
- end
53
- end
54
- end
55
- end