activeset 0.3.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|