activeset 0.3.0 → 0.3.1
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/CHANGELOG +6 -0
- data/lib/active_set/instructions/base.rb +26 -0
- data/lib/active_set/instructions/entry.rb +26 -0
- data/lib/active_set/instructions/entry/keypath.rb +58 -0
- data/lib/active_set/instructions/entry/value.rb +15 -0
- data/lib/active_set/processors/base_adapter.rb +5 -6
- data/lib/active_set/processors/base_processor.rb +14 -11
- data/lib/active_set/processors/filter/active_record_adapter.rb +10 -10
- data/lib/active_set/processors/filter/enumerable_adapter.rb +3 -3
- data/lib/active_set/processors/filter_processor.rb +1 -4
- data/lib/active_set/processors/paginate/enumerable_adapter.rb +2 -2
- data/lib/active_set/processors/paginate_processor.rb +7 -3
- data/lib/active_set/processors/sort/active_record_adapter.rb +13 -13
- data/lib/active_set/processors/sort/enumerable_adapter.rb +3 -3
- data/lib/active_set/processors/sort_processor.rb +1 -4
- data/lib/active_set/version.rb +1 -1
- data/lib/patches/core_ext/hash/flatten_keys.rb +3 -1
- metadata +6 -3
- data/lib/active_set/structure/path.rb +0 -54
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fc73d4a0f511ddca2d0c895b7867816dc571102f
|
4
|
+
data.tar.gz: 02ac9b548790d30b2dac78a372b3ccc091769ed2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 029232215b1cd1280f1b75757198bce5e97aa2e64603f2fa5c51aef8304407c7b56e1b0928a0e09fac080c9de272b00716842d94ad122a99f97d8f5337a1d58b
|
7
|
+
data.tar.gz: e73777713e06505233491977d66b4f48966e3ce5a50b4b99dcc242f00db13349e10ac3166a6ac5fff0da0cfcad02fffcf61359cba737b6e20c63d8694df8216a
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
v 0.3.1
|
2
|
+
- Implement an Instructions object layer for handling the hashes passed into Processors
|
3
|
+
v 0.3.0
|
4
|
+
- remove the typecasting functionality
|
5
|
+
- bug fixes
|
6
|
+
- improved specs
|
1
7
|
v 0.2.0
|
2
8
|
- allows for filtering and sorting enumerable collections via associated attributes
|
3
9
|
v 0.1.0
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative './entry'
|
4
|
+
|
5
|
+
class ActiveSet
|
6
|
+
class Instructions
|
7
|
+
attr_reader :hash
|
8
|
+
|
9
|
+
def initialize(hash)
|
10
|
+
@hash = hash
|
11
|
+
@flattened_hash = hash.flatten_keys
|
12
|
+
end
|
13
|
+
|
14
|
+
def process_adapter(set:, adapter:)
|
15
|
+
@flattened_hash.reject { |_, v| v.blank? }
|
16
|
+
.reduce(set) do |inner_set, (keypath, value)|
|
17
|
+
instruction = Entry.new(keypath, value)
|
18
|
+
adapter.new(instruction).process(inner_set)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def get(keypath)
|
23
|
+
@hash.dig(*keypath)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/core_ext/module/delegation'
|
4
|
+
|
5
|
+
require_relative 'entry/keypath'
|
6
|
+
require_relative 'entry/value'
|
7
|
+
|
8
|
+
class ActiveSet
|
9
|
+
class Instructions
|
10
|
+
class Entry
|
11
|
+
attr_reader :keypath
|
12
|
+
|
13
|
+
delegate :attribute, :operator, :associations_array, :associations_hash, :value_for, :resource_for,
|
14
|
+
to: :keypath
|
15
|
+
|
16
|
+
def initialize(keypath, value)
|
17
|
+
@keypath = KeyPath.new(keypath)
|
18
|
+
@value = Value.new(value)
|
19
|
+
end
|
20
|
+
|
21
|
+
def value
|
22
|
+
@value.raw
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/core_ext/array/wrap'
|
4
|
+
require 'active_support/core_ext/object/try'
|
5
|
+
|
6
|
+
class ActiveSet
|
7
|
+
class Instructions
|
8
|
+
class Entry
|
9
|
+
class KeyPath
|
10
|
+
attr_reader :path
|
11
|
+
|
12
|
+
def initialize(path)
|
13
|
+
# `path` can be an Array (e.g. [:parent, :child, :grandchild])
|
14
|
+
# or a String (e.g. 'parent.child.grandchild')
|
15
|
+
@path = path.is_a?(String) ? path.split('.') : Array.wrap(path).map(&:to_s)
|
16
|
+
end
|
17
|
+
|
18
|
+
def attribute
|
19
|
+
attribute = @path.last
|
20
|
+
return attribute.sub(operator_regex, '') if attribute.match operator_regex
|
21
|
+
attribute
|
22
|
+
end
|
23
|
+
|
24
|
+
def operator
|
25
|
+
attribute = @path.last
|
26
|
+
return attribute[operator_regex, 1] if attribute.match operator_regex
|
27
|
+
'=='
|
28
|
+
end
|
29
|
+
|
30
|
+
def associations_array
|
31
|
+
@path.slice(0, @path.length - 1)
|
32
|
+
end
|
33
|
+
|
34
|
+
def associations_hash
|
35
|
+
associations_array.reverse.reduce({}) { |a, e| { e => a } }
|
36
|
+
end
|
37
|
+
|
38
|
+
def value_for(item:)
|
39
|
+
resource_for(item: item).send(attribute)
|
40
|
+
rescue
|
41
|
+
nil
|
42
|
+
end
|
43
|
+
|
44
|
+
def resource_for(item:)
|
45
|
+
associations_array.reduce(item, :try)
|
46
|
+
rescue
|
47
|
+
nil
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def operator_regex
|
53
|
+
/\((.*?)\)/
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -1,10 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
@value = value
|
3
|
+
class ActiveSet
|
4
|
+
class BaseAdapter
|
5
|
+
def initialize(instruction)
|
6
|
+
@instruction = instruction
|
7
|
+
end
|
9
8
|
end
|
10
9
|
end
|
@@ -1,19 +1,22 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'patches/core_ext/hash/flatten_keys'
|
4
|
+
require_relative '../instructions/base'
|
4
5
|
|
5
|
-
class
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
class ActiveSet
|
7
|
+
class BaseProcessor
|
8
|
+
def self.queue_adapter(adapter)
|
9
|
+
@adapters ||= []
|
10
|
+
@adapters |= [adapter]
|
11
|
+
end
|
10
12
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
13
|
+
def initialize(set, instructions)
|
14
|
+
@set = set
|
15
|
+
@instructions = Instructions.new(instructions)
|
16
|
+
end
|
15
17
|
|
16
|
-
|
17
|
-
|
18
|
+
def adapters
|
19
|
+
self.class.instance_variable_get(:@adapters)
|
20
|
+
end
|
18
21
|
end
|
19
22
|
end
|
@@ -19,34 +19,34 @@ class ActiveSet
|
|
19
19
|
def attribute_is_field?
|
20
20
|
return false unless attribute_model
|
21
21
|
attribute_model.attribute_names
|
22
|
-
.include?(@
|
22
|
+
.include?(@instruction.attribute)
|
23
23
|
end
|
24
24
|
|
25
25
|
def query
|
26
|
-
@set.includes(@
|
27
|
-
.references(@
|
26
|
+
@set.includes(@instruction.associations_hash)
|
27
|
+
.references(@instruction.associations_hash)
|
28
28
|
.where(arel_operation)
|
29
29
|
end
|
30
30
|
|
31
31
|
def arel_operation
|
32
|
-
Arel::Nodes::InfixOperation.new(@
|
32
|
+
Arel::Nodes::InfixOperation.new(@instruction.operator,
|
33
33
|
arel_column,
|
34
34
|
arel_value)
|
35
35
|
end
|
36
36
|
|
37
37
|
def attribute_model
|
38
|
-
@
|
39
|
-
|
40
|
-
|
41
|
-
|
38
|
+
@instruction.associations_array
|
39
|
+
.reduce(@set) do |obj, assoc|
|
40
|
+
obj.reflections[assoc.to_s]&.klass
|
41
|
+
end
|
42
42
|
end
|
43
43
|
|
44
44
|
def arel_column
|
45
|
-
arel_table[@
|
45
|
+
arel_table[@instruction.attribute]
|
46
46
|
end
|
47
47
|
|
48
48
|
def arel_value
|
49
|
-
Arel.sql(ActiveRecord::Base.connection.quote(@value))
|
49
|
+
Arel.sql(ActiveRecord::Base.connection.quote(@instruction.value))
|
50
50
|
end
|
51
51
|
|
52
52
|
def arel_table
|
@@ -7,7 +7,7 @@ class ActiveSet
|
|
7
7
|
class EnumerableAdapter < BaseAdapter
|
8
8
|
def process(set)
|
9
9
|
set.select do |item|
|
10
|
-
value_for(item).send(@
|
10
|
+
value_for(item).send(@instruction.operator,
|
11
11
|
passed_value)
|
12
12
|
end
|
13
13
|
end
|
@@ -15,11 +15,11 @@ class ActiveSet
|
|
15
15
|
private
|
16
16
|
|
17
17
|
def value_for(item)
|
18
|
-
convert_datetime_values_to_integer(@
|
18
|
+
convert_datetime_values_to_integer(@instruction.value_for(item: item))
|
19
19
|
end
|
20
20
|
|
21
21
|
def passed_value
|
22
|
-
convert_datetime_values_to_integer(@value)
|
22
|
+
convert_datetime_values_to_integer(@instruction.value)
|
23
23
|
end
|
24
24
|
|
25
25
|
def convert_datetime_values_to_integer(value)
|
@@ -13,10 +13,7 @@ class ActiveSet
|
|
13
13
|
|
14
14
|
def process
|
15
15
|
adapters.reduce(@set) do |outer_set, adapter|
|
16
|
-
@
|
17
|
-
.reduce(outer_set) do |inner_set, (keypath, value)|
|
18
|
-
adapter.new(keypath, value).process(inner_set)
|
19
|
-
end
|
16
|
+
@instructions.process_adapter(set: outer_set, adapter: adapter)
|
20
17
|
end
|
21
18
|
end
|
22
19
|
end
|
@@ -7,7 +7,7 @@ class ActiveSet
|
|
7
7
|
class PaginateProcessor < BaseProcessor
|
8
8
|
def process
|
9
9
|
return @set if @set.count < pagesize
|
10
|
-
adapter.new(
|
10
|
+
adapter.new(instruction).process(@set)
|
11
11
|
end
|
12
12
|
|
13
13
|
private
|
@@ -16,12 +16,16 @@ class ActiveSet
|
|
16
16
|
EnumerableAdapter
|
17
17
|
end
|
18
18
|
|
19
|
+
def instruction
|
20
|
+
Instructions::Entry.new(page_number, pagesize)
|
21
|
+
end
|
22
|
+
|
19
23
|
def page_number
|
20
|
-
@
|
24
|
+
@instructions.get(:page) || 1
|
21
25
|
end
|
22
26
|
|
23
27
|
def pagesize
|
24
|
-
@
|
28
|
+
@instructions.get(:size) || 25
|
25
29
|
end
|
26
30
|
end
|
27
31
|
end
|
@@ -11,8 +11,8 @@ class ActiveSet
|
|
11
11
|
return @set unless @set.respond_to? :to_sql
|
12
12
|
return @set unless attribute_is_field?
|
13
13
|
|
14
|
-
@set.includes(@
|
15
|
-
.references(@
|
14
|
+
@set.includes(@instruction.associations_hash)
|
15
|
+
.references(@instruction.associations_hash)
|
16
16
|
.merge(arel_operation)
|
17
17
|
end
|
18
18
|
|
@@ -21,32 +21,32 @@ class ActiveSet
|
|
21
21
|
def attribute_is_field?
|
22
22
|
return false unless attribute_model
|
23
23
|
attribute_model.attribute_names
|
24
|
-
.include?(@
|
25
|
-
end
|
26
|
-
|
27
|
-
def case_insensitive?
|
28
|
-
@structure_path.operator.to_s == 'i'
|
24
|
+
.include?(@instruction.attribute)
|
29
25
|
end
|
30
26
|
|
31
27
|
def arel_operation
|
32
28
|
column = case_insensitive? ? arel_column.lower : arel_column
|
33
|
-
attribute_model.order(column.send(@value))
|
29
|
+
attribute_model.order(column.send(@instruction.value))
|
34
30
|
end
|
35
31
|
|
36
32
|
def attribute_model
|
37
|
-
@
|
38
|
-
|
39
|
-
|
40
|
-
|
33
|
+
@instruction.associations_array
|
34
|
+
.reduce(@set) do |obj, assoc|
|
35
|
+
obj.reflections[assoc.to_s]&.klass
|
36
|
+
end
|
41
37
|
end
|
42
38
|
|
43
39
|
def arel_column
|
44
|
-
arel_table[@
|
40
|
+
arel_table[@instruction.attribute]
|
45
41
|
end
|
46
42
|
|
47
43
|
def arel_table
|
48
44
|
Arel::Table.new(attribute_model.table_name)
|
49
45
|
end
|
46
|
+
|
47
|
+
def case_insensitive?
|
48
|
+
@instruction.operator.to_s == 'i'
|
49
|
+
end
|
50
50
|
end
|
51
51
|
end
|
52
52
|
end
|
@@ -8,9 +8,9 @@ class ActiveSet
|
|
8
8
|
class EnumerableAdapter < BaseAdapter
|
9
9
|
def process(set)
|
10
10
|
set.sort_by do |item|
|
11
|
-
attribute_value = @
|
11
|
+
attribute_value = @instruction.value_for(item: item)
|
12
12
|
case_insensitive?(attribute_value) ? insensify(attribute_value) : attribute_value
|
13
|
-
end.tap { |c| c.reverse! if @value.to_s == 'desc' }
|
13
|
+
end.tap { |c| c.reverse! if @instruction.value.to_s == 'desc' }
|
14
14
|
end
|
15
15
|
|
16
16
|
private
|
@@ -19,7 +19,7 @@ class ActiveSet
|
|
19
19
|
# Cannot sort pure Booleans or Nils, so we _must_ cast to Strings
|
20
20
|
return true if value.is_a?(TrueClass) || value.is_a?(FalseClass)
|
21
21
|
return true if value.is_a?(NilClass)
|
22
|
-
@
|
22
|
+
@instruction.operator.to_s == 'i'
|
23
23
|
end
|
24
24
|
|
25
25
|
def insensify(value)
|
@@ -13,10 +13,7 @@ class ActiveSet
|
|
13
13
|
|
14
14
|
def process
|
15
15
|
adapters.reduce(@set) do |outer_set, adapter|
|
16
|
-
@
|
17
|
-
.reduce(outer_set) do |inner_set, (keypath, value)|
|
18
|
-
adapter.new(keypath, value).process(inner_set)
|
19
|
-
end
|
16
|
+
@instructions.process_adapter(set: outer_set, adapter: adapter)
|
20
17
|
end
|
21
18
|
end
|
22
19
|
end
|
data/lib/active_set/version.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'active_support/core_ext/array/wrap'
|
4
|
+
|
3
5
|
class Hash
|
4
6
|
# Returns a flat hash where all nested keys are collapsed into a an array of keys.
|
5
7
|
#
|
@@ -24,7 +26,7 @@ class Hash
|
|
24
26
|
|
25
27
|
def _flatten_keys(h, keys = [], res = {})
|
26
28
|
return res.merge!(keys => h) unless h.is_a? Hash
|
27
|
-
h.each { |k, r| _flatten_keys(r, keys +
|
29
|
+
h.each { |k, r| _flatten_keys(r, keys + Array.wrap(k), res) }
|
28
30
|
res
|
29
31
|
end
|
30
32
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activeset
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stephen Margheim
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-09-
|
11
|
+
date: 2017-09-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -171,6 +171,10 @@ files:
|
|
171
171
|
- bin/setup
|
172
172
|
- config.ru
|
173
173
|
- lib/active_set.rb
|
174
|
+
- lib/active_set/instructions/base.rb
|
175
|
+
- lib/active_set/instructions/entry.rb
|
176
|
+
- lib/active_set/instructions/entry/keypath.rb
|
177
|
+
- lib/active_set/instructions/entry/value.rb
|
174
178
|
- lib/active_set/processors/base_adapter.rb
|
175
179
|
- lib/active_set/processors/base_processor.rb
|
176
180
|
- lib/active_set/processors/filter/active_record_adapter.rb
|
@@ -181,7 +185,6 @@ files:
|
|
181
185
|
- lib/active_set/processors/sort/active_record_adapter.rb
|
182
186
|
- lib/active_set/processors/sort/enumerable_adapter.rb
|
183
187
|
- lib/active_set/processors/sort_processor.rb
|
184
|
-
- lib/active_set/structure/path.rb
|
185
188
|
- lib/active_set/version.rb
|
186
189
|
- lib/patches/core_ext/hash/flatten_keys.rb
|
187
190
|
homepage: https://github.com/fractaledmind/activeset
|
@@ -1,54 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'active_support/core_ext/array/wrap'
|
4
|
-
require 'active_support/core_ext/object/try'
|
5
|
-
|
6
|
-
module Structure
|
7
|
-
class Path
|
8
|
-
attr_reader :path
|
9
|
-
|
10
|
-
def initialize(path)
|
11
|
-
# `path` can be an Array (e.g. [:parent, :child, :grandchild])
|
12
|
-
# or a String (e.g. 'parent.child.grandchild')
|
13
|
-
@path = path.is_a?(String) ? path.split('.') : Array.wrap(path).map(&:to_s)
|
14
|
-
end
|
15
|
-
|
16
|
-
def attribute
|
17
|
-
attribute = @path.last
|
18
|
-
return attribute.sub(operator_regex, '') if attribute.match operator_regex
|
19
|
-
attribute
|
20
|
-
end
|
21
|
-
|
22
|
-
def operator
|
23
|
-
attribute = @path.last
|
24
|
-
return attribute[operator_regex, 1] if attribute.match operator_regex
|
25
|
-
'=='
|
26
|
-
end
|
27
|
-
|
28
|
-
def to_a
|
29
|
-
@path.slice(0, @path.length - 1)
|
30
|
-
end
|
31
|
-
|
32
|
-
def to_h
|
33
|
-
to_a.reverse.reduce({}) { |a, e| { e => a } }
|
34
|
-
end
|
35
|
-
|
36
|
-
def value_for(item:)
|
37
|
-
resource_for(item: item).send(attribute)
|
38
|
-
rescue
|
39
|
-
nil
|
40
|
-
end
|
41
|
-
|
42
|
-
def resource_for(item:)
|
43
|
-
to_a.reduce(item, :try)
|
44
|
-
rescue
|
45
|
-
nil
|
46
|
-
end
|
47
|
-
|
48
|
-
private
|
49
|
-
|
50
|
-
def operator_regex
|
51
|
-
/\((.*?)\)/
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|