dbee-active_record 2.0.1 → 2.1.0.pre.alpha.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/.rubocop.yml +24 -9
- data/.ruby-version +1 -1
- data/.travis.yml +3 -7
- data/CHANGELOG.md +26 -0
- data/dbee-active_record.gemspec +13 -5
- data/exe/.gitkeep +0 -0
- data/lib/dbee/providers/active_record_provider/expression_builder.rb +47 -19
- data/lib/dbee/providers/active_record_provider/expression_builder/{constraint_maker.rb → constraint.rb} +11 -11
- data/lib/dbee/providers/active_record_provider/expression_builder/{order_maker.rb → order.rb} +8 -8
- data/lib/dbee/providers/active_record_provider/expression_builder/select.rb +71 -0
- data/lib/dbee/providers/active_record_provider/expression_builder/where.rb +91 -0
- data/lib/dbee/providers/active_record_provider/version.rb +1 -1
- data/spec/db_helper.rb +130 -14
- data/spec/dbee/providers/active_record_provider_spec.rb +102 -1
- data/spec/fixtures/active_record_snapshots/one_table_query_with_filters.yaml +24 -16
- data/spec/fixtures/active_record_snapshots/two_table_query_with_aggregation.yaml +71 -0
- data/spec/fixtures/active_record_snapshots/two_table_query_with_pivoting.yaml +88 -0
- data/spec/fixtures/models.yaml +20 -0
- metadata +30 -21
- data/lib/dbee/providers/active_record_provider/expression_builder/select_maker.rb +0 -33
- data/lib/dbee/providers/active_record_provider/expression_builder/where_maker.rb +0 -56
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 75d42ea7f3b391ad5014264a4b914339bf7dff8582aebe85c4c3180576ae7648
|
4
|
+
data.tar.gz: e63553d0dcc906a38b336767dfcf10bcc162807682ae866f4450a80185993b8e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f727e65305615a6e5b2450654ce4bb174674970be4b6855922035dac6bc8378862a003f0c1ec4677433d560dee4f5ca3b9094b57a4be8eae6a7d78720c805910
|
7
|
+
data.tar.gz: 21d91630d8ba8407550dcdd6d8a7aab9bc7dc52ad39679ed5b673f59263f2761e55505c61b8cafcc2ce09a31fee1571e58e9fffc76b24f1dd7a5d3d62e3b4ef7
|
data/.rubocop.yml
CHANGED
@@ -1,6 +1,20 @@
|
|
1
|
-
|
1
|
+
AllCops:
|
2
|
+
TargetRubyVersion: 2.5
|
3
|
+
|
4
|
+
Layout/LineLength:
|
2
5
|
Max: 100
|
3
6
|
|
7
|
+
Lint/RaiseException:
|
8
|
+
Enabled: True
|
9
|
+
|
10
|
+
Lint/StructNewOverride:
|
11
|
+
Enabled: True
|
12
|
+
|
13
|
+
Metrics/AbcSize:
|
14
|
+
Max: 16
|
15
|
+
Exclude:
|
16
|
+
- spec/db_helper.rb
|
17
|
+
|
4
18
|
Metrics/BlockLength:
|
5
19
|
ExcludedMethods:
|
6
20
|
- let
|
@@ -13,18 +27,19 @@ Metrics/BlockLength:
|
|
13
27
|
- spec/dbee/**/*
|
14
28
|
- dbee-active_record.gemspec
|
15
29
|
|
30
|
+
Metrics/ClassLength:
|
31
|
+
Max: 125
|
32
|
+
|
16
33
|
Metrics/MethodLength:
|
17
34
|
Max: 25
|
18
35
|
Exclude:
|
19
36
|
- spec/db_helper.rb
|
20
37
|
|
21
|
-
|
22
|
-
|
38
|
+
Style/HashEachMethods:
|
39
|
+
Enabled: True
|
23
40
|
|
24
|
-
|
25
|
-
|
26
|
-
Exclude:
|
27
|
-
- spec/db_helper.rb
|
41
|
+
Style/HashTransformKeys:
|
42
|
+
Enabled: True
|
28
43
|
|
29
|
-
|
30
|
-
|
44
|
+
Style/HashTransformValues:
|
45
|
+
Enabled: True
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.6.
|
1
|
+
2.6.6
|
data/.travis.yml
CHANGED
@@ -6,16 +6,12 @@ services:
|
|
6
6
|
- mysql
|
7
7
|
rvm:
|
8
8
|
# Build on the latest stable of all supported Rubies (https://www.ruby-lang.org/en/downloads/):
|
9
|
-
- 2.
|
10
|
-
- 2.
|
11
|
-
- 2.
|
9
|
+
- 2.5.8
|
10
|
+
- 2.6.6
|
11
|
+
- 2.7.1
|
12
12
|
env:
|
13
13
|
- AR_VERSION=5
|
14
14
|
- AR_VERSION=6
|
15
|
-
matrix:
|
16
|
-
exclude:
|
17
|
-
- rvm: 2.4.6
|
18
|
-
env: AR_VERSION=6
|
19
15
|
cache: bundler
|
20
16
|
before_script:
|
21
17
|
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,29 @@
|
|
1
|
+
# 2.1.0 (TBD)
|
2
|
+
|
3
|
+
### Additions:
|
4
|
+
|
5
|
+
* Implemented Dbee::Query::Field#aggregator
|
6
|
+
* Implemented Dbee::Query::Field#filters
|
7
|
+
|
8
|
+
### Changes:
|
9
|
+
|
10
|
+
* Bumped minimum Ruby version to 2.5
|
11
|
+
|
12
|
+
# 2.0.4 (February 13th, 2020)
|
13
|
+
|
14
|
+
* use Arel#in for Equal filters when there is more than one value
|
15
|
+
* use Arel#not_in for NotEqual filters when there are is than one value
|
16
|
+
|
17
|
+
# 2.0.3 (January 7th, 2020)
|
18
|
+
|
19
|
+
* Added/tested support for Dbee 2.0.3
|
20
|
+
* Added support for Ruby 2.6.5
|
21
|
+
|
22
|
+
# 2.0.2 (November 7th, 2019)
|
23
|
+
|
24
|
+
* Added/tested support for Dbee 2.0.2
|
25
|
+
* Added support for Ruby 2.3.8
|
26
|
+
|
1
27
|
# 2.0.1 (October 25th, 2019)
|
2
28
|
|
3
29
|
* Development dependency updates.
|
data/dbee-active_record.gemspec
CHANGED
@@ -15,11 +15,19 @@ Gem::Specification.new do |s|
|
|
15
15
|
s.email = ['mruggio@bluemarblepayroll.com']
|
16
16
|
s.files = `git ls-files`.split("\n")
|
17
17
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
-
s.
|
18
|
+
s.bindir = 'exe'
|
19
|
+
s.executables = []
|
19
20
|
s.homepage = 'https://github.com/bluemarblepayroll/dbee-active_record'
|
20
21
|
s.license = 'MIT'
|
22
|
+
s.metadata = {
|
23
|
+
'bug_tracker_uri' => 'https://github.com/bluemarblepayroll/dbee-active_record/issues',
|
24
|
+
'changelog_uri' => 'https://github.com/bluemarblepayroll/dbee-active_record/blob/master/CHANGELOG.md',
|
25
|
+
'documentation_uri' => 'https://www.rubydoc.info/gems/dbee-active_record',
|
26
|
+
'homepage_uri' => s.homepage,
|
27
|
+
'source_code_uri' => s.homepage
|
28
|
+
}
|
21
29
|
|
22
|
-
s.required_ruby_version = '>= 2.
|
30
|
+
s.required_ruby_version = '>= 2.5'
|
23
31
|
|
24
32
|
ar_version = ENV['AR_VERSION'] || ''
|
25
33
|
|
@@ -34,15 +42,15 @@ Gem::Specification.new do |s|
|
|
34
42
|
end
|
35
43
|
|
36
44
|
s.add_dependency('activerecord', activerecord_version)
|
37
|
-
s.add_dependency('dbee', '
|
45
|
+
s.add_dependency('dbee', '=2.1.0.pre.alpha')
|
38
46
|
|
39
47
|
s.add_development_dependency('guard-rspec', '~>4.7')
|
40
48
|
s.add_development_dependency('mysql2', '~>0.5')
|
41
49
|
s.add_development_dependency('pry', '~>0')
|
42
50
|
s.add_development_dependency('rake', '~> 13')
|
43
51
|
s.add_development_dependency('rspec', '~> 3.8')
|
44
|
-
s.add_development_dependency('rubocop', '~>0.
|
52
|
+
s.add_development_dependency('rubocop', '~>0.81.0')
|
45
53
|
s.add_development_dependency('simplecov', '~>0.17.0')
|
46
|
-
s.add_development_dependency('simplecov-console', '~>0.
|
54
|
+
s.add_development_dependency('simplecov-console', '~>0.7.0')
|
47
55
|
s.add_development_dependency('sqlite3', '~>1')
|
48
56
|
end
|
data/exe/.gitkeep
ADDED
File without changes
|
@@ -7,26 +7,24 @@
|
|
7
7
|
# LICENSE file in the root directory of this source tree.
|
8
8
|
#
|
9
9
|
|
10
|
-
require_relative 'expression_builder/
|
11
|
-
require_relative 'expression_builder/
|
12
|
-
require_relative 'expression_builder/
|
13
|
-
require_relative 'expression_builder/
|
10
|
+
require_relative 'expression_builder/constraint'
|
11
|
+
require_relative 'expression_builder/order'
|
12
|
+
require_relative 'expression_builder/select'
|
13
|
+
require_relative 'expression_builder/where'
|
14
14
|
|
15
15
|
module Dbee
|
16
16
|
module Providers
|
17
17
|
class ActiveRecordProvider
|
18
18
|
# This class can generate an Arel expression tree.
|
19
19
|
class ExpressionBuilder
|
20
|
-
extend Forwardable
|
21
|
-
|
22
20
|
class MissingConstraintError < StandardError; end
|
23
21
|
|
24
|
-
def_delegators :statement, :to_sql
|
25
|
-
|
26
22
|
def initialize(model, table_alias_maker, column_alias_maker)
|
27
23
|
@model = model
|
28
24
|
@table_alias_maker = table_alias_maker
|
29
25
|
@column_alias_maker = column_alias_maker
|
26
|
+
@requires_group_by = false
|
27
|
+
@group_by_columns = []
|
30
28
|
|
31
29
|
clear
|
32
30
|
end
|
@@ -49,13 +47,25 @@ module Dbee
|
|
49
47
|
self
|
50
48
|
end
|
51
49
|
|
50
|
+
def to_sql
|
51
|
+
if requires_group_by
|
52
|
+
@requires_group_by = false
|
53
|
+
statement.group(group_by_columns) unless group_by_columns.empty?
|
54
|
+
@group_by_columns = []
|
55
|
+
end
|
56
|
+
|
57
|
+
statement.to_sql
|
58
|
+
end
|
59
|
+
|
52
60
|
private
|
53
61
|
|
54
62
|
attr_reader :base_table,
|
55
63
|
:statement,
|
56
64
|
:model,
|
57
65
|
:table_alias_maker,
|
58
|
-
:column_alias_maker
|
66
|
+
:column_alias_maker,
|
67
|
+
:requires_group_by,
|
68
|
+
:group_by_columns
|
59
69
|
|
60
70
|
def tables
|
61
71
|
@tables ||= {}
|
@@ -70,7 +80,7 @@ module Dbee
|
|
70
80
|
|
71
81
|
key_path = filter.key_path
|
72
82
|
arel_column = key_paths_to_arel_columns[key_path]
|
73
|
-
predicate =
|
83
|
+
predicate = Where.instance.make(filter, arel_column)
|
74
84
|
|
75
85
|
build(statement.where(predicate))
|
76
86
|
|
@@ -82,22 +92,40 @@ module Dbee
|
|
82
92
|
|
83
93
|
key_path = sorter.key_path
|
84
94
|
arel_column = key_paths_to_arel_columns[key_path]
|
85
|
-
predicate =
|
95
|
+
predicate = Order.instance.make(sorter, arel_column)
|
86
96
|
|
87
97
|
build(statement.order(predicate))
|
88
98
|
|
89
99
|
self
|
90
100
|
end
|
91
101
|
|
102
|
+
def add_filter_key_paths(filters)
|
103
|
+
filters.each_with_object({}) do |filter, memo|
|
104
|
+
arel_key_column = add_key_path(filter.key_path)
|
105
|
+
|
106
|
+
memo[arel_key_column] = filter
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
92
110
|
def add_field(field)
|
93
|
-
add_key_path(field.key_path)
|
111
|
+
arel_value_column = add_key_path(field.key_path)
|
112
|
+
arel_key_columns_to_filters = add_filter_key_paths(field.filters)
|
94
113
|
|
95
|
-
|
96
|
-
|
97
|
-
|
114
|
+
predicate = Select.instance.make(
|
115
|
+
field,
|
116
|
+
arel_key_columns_to_filters,
|
117
|
+
arel_value_column,
|
118
|
+
column_alias_maker
|
119
|
+
)
|
98
120
|
|
99
121
|
build(statement.project(predicate))
|
100
122
|
|
123
|
+
if field.aggregator?
|
124
|
+
@requires_group_by = true
|
125
|
+
else
|
126
|
+
group_by_columns << arel_value_column
|
127
|
+
end
|
128
|
+
|
101
129
|
self
|
102
130
|
end
|
103
131
|
|
@@ -123,7 +151,7 @@ module Dbee
|
|
123
151
|
def table(name, model, previous_table)
|
124
152
|
table = make_table(model.table, name)
|
125
153
|
|
126
|
-
on =
|
154
|
+
on = Constraint.instance.make(model.constraints, table, previous_table)
|
127
155
|
|
128
156
|
raise MissingConstraintError, "for: #{name}" unless on
|
129
157
|
|
@@ -142,16 +170,16 @@ module Dbee
|
|
142
170
|
end
|
143
171
|
|
144
172
|
def add_key_path(key_path)
|
145
|
-
return if key_paths_to_arel_columns.key?(key_path)
|
173
|
+
return key_paths_to_arel_columns[key_path] if key_paths_to_arel_columns.key?(key_path)
|
146
174
|
|
147
175
|
ancestors = model.ancestors!(key_path.ancestor_names)
|
148
176
|
|
149
177
|
table = traverse_ancestors(ancestors)
|
150
178
|
|
151
179
|
arel_column = table[key_path.column_name]
|
152
|
-
key_paths_to_arel_columns[key_path] = arel_column
|
153
180
|
|
154
|
-
|
181
|
+
# Note that this returns arel_column
|
182
|
+
key_paths_to_arel_columns[key_path] = arel_column
|
155
183
|
end
|
156
184
|
|
157
185
|
def build(new_expression)
|
@@ -12,9 +12,19 @@ module Dbee
|
|
12
12
|
class ActiveRecordProvider
|
13
13
|
class ExpressionBuilder
|
14
14
|
# Can derive constraints for Arel table JOIN statements.
|
15
|
-
class
|
15
|
+
class Constraint
|
16
16
|
include Singleton
|
17
17
|
|
18
|
+
def make(constraints, table, previous_table)
|
19
|
+
constraints.inject(nil) do |memo, constraint|
|
20
|
+
method = CONSTRAINT_RESOLVERS[constraint.class]
|
21
|
+
|
22
|
+
raise ArgumentError, "constraint unhandled: #{constraint.class.name}" unless method
|
23
|
+
|
24
|
+
method.call(constraint, memo, table, previous_table)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
18
28
|
CONCAT_METHOD = lambda do |on, arel_column, value|
|
19
29
|
on ? on.and(arel_column.eq(value)) : arel_column.eq(value)
|
20
30
|
end
|
@@ -44,16 +54,6 @@ module Dbee
|
|
44
54
|
}.freeze
|
45
55
|
|
46
56
|
private_constant :CONSTRAINT_RESOLVERS
|
47
|
-
|
48
|
-
def make(constraints, table, previous_table)
|
49
|
-
constraints.inject(nil) do |memo, constraint|
|
50
|
-
method = CONSTRAINT_RESOLVERS[constraint.class]
|
51
|
-
|
52
|
-
raise ArgumentError, "constraint unhandled: #{constraint.class.name}" unless method
|
53
|
-
|
54
|
-
method.call(constraint, memo, table, previous_table)
|
55
|
-
end
|
56
|
-
end
|
57
57
|
end
|
58
58
|
end
|
59
59
|
end
|
data/lib/dbee/providers/active_record_provider/expression_builder/{order_maker.rb → order.rb}
RENAMED
@@ -12,16 +12,9 @@ module Dbee
|
|
12
12
|
class ActiveRecordProvider
|
13
13
|
class ExpressionBuilder
|
14
14
|
# Derives Arel#order predicates.
|
15
|
-
class
|
15
|
+
class Order
|
16
16
|
include Singleton
|
17
17
|
|
18
|
-
SORTER_EVALUATORS = {
|
19
|
-
Query::Sorters::Ascending => ->(column) { column },
|
20
|
-
Query::Sorters::Descending => ->(column) { column.desc }
|
21
|
-
}.freeze
|
22
|
-
|
23
|
-
private_constant :SORTER_EVALUATORS
|
24
|
-
|
25
18
|
def make(sorter, arel_column)
|
26
19
|
method = SORTER_EVALUATORS[sorter.class]
|
27
20
|
|
@@ -29,6 +22,13 @@ module Dbee
|
|
29
22
|
|
30
23
|
method.call(arel_column)
|
31
24
|
end
|
25
|
+
|
26
|
+
SORTER_EVALUATORS = {
|
27
|
+
Query::Sorters::Ascending => ->(column) { column },
|
28
|
+
Query::Sorters::Descending => ->(column) { column.desc }
|
29
|
+
}.freeze
|
30
|
+
|
31
|
+
private_constant :SORTER_EVALUATORS
|
32
32
|
end
|
33
33
|
end
|
34
34
|
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Copyright (c) 2019-present, Blue Marble Payroll, LLC
|
5
|
+
#
|
6
|
+
# This source code is licensed under the MIT license found in the
|
7
|
+
# LICENSE file in the root directory of this source tree.
|
8
|
+
#
|
9
|
+
|
10
|
+
module Dbee
|
11
|
+
module Providers
|
12
|
+
class ActiveRecordProvider
|
13
|
+
class ExpressionBuilder
|
14
|
+
# Derives Arel#project predicates.
|
15
|
+
class Select
|
16
|
+
include Singleton
|
17
|
+
|
18
|
+
def make(field, arel_key_nodes_to_filters, arel_value_node, alias_maker)
|
19
|
+
column_alias = quote(alias_maker.make(field.display))
|
20
|
+
predicate = expression(field, arel_key_nodes_to_filters, arel_value_node)
|
21
|
+
predicate = aggregate(field, predicate)
|
22
|
+
|
23
|
+
predicate.as(column_alias)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
AGGREGRATOR_EVALUATORS = {
|
29
|
+
nil => ->(arel_node) { arel_node },
|
30
|
+
Query::Field::Aggregator::AVE => ->(node) { Arel::Nodes::Avg.new([node]) },
|
31
|
+
Query::Field::Aggregator::COUNT => ->(node) { Arel::Nodes::Count.new([node]) },
|
32
|
+
Query::Field::Aggregator::MAX => ->(node) { Arel::Nodes::Max.new([node]) },
|
33
|
+
Query::Field::Aggregator::MIN => ->(node) { Arel::Nodes::Min.new([node]) },
|
34
|
+
Query::Field::Aggregator::SUM => ->(node) { Arel::Nodes::Sum.new([node]) }
|
35
|
+
}.freeze
|
36
|
+
|
37
|
+
private_constant :AGGREGRATOR_EVALUATORS
|
38
|
+
|
39
|
+
def quote(value)
|
40
|
+
ActiveRecord::Base.connection.quote(value)
|
41
|
+
end
|
42
|
+
|
43
|
+
def aggregate(field, predicate)
|
44
|
+
AGGREGRATOR_EVALUATORS[field.aggregator].call(predicate)
|
45
|
+
end
|
46
|
+
|
47
|
+
def expression(field, arel_key_nodes_to_filters, arel_value_node)
|
48
|
+
if field.filters?
|
49
|
+
case_statement = Arel::Nodes::Case.new
|
50
|
+
filter_predicate = make_filter_predicate(arel_key_nodes_to_filters)
|
51
|
+
|
52
|
+
case_statement.when(filter_predicate).then(arel_value_node)
|
53
|
+
else
|
54
|
+
arel_value_node
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def make_filter_predicate(arel_key_nodes_to_filters)
|
59
|
+
predicates = arel_key_nodes_to_filters.map do |arel_key_node, filter|
|
60
|
+
Where.instance.make(filter, arel_key_node)
|
61
|
+
end
|
62
|
+
|
63
|
+
predicates.inject(predicates.shift) do |memo, predicate|
|
64
|
+
memo.and(predicate)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Copyright (c) 2019-present, Blue Marble Payroll, LLC
|
5
|
+
#
|
6
|
+
# This source code is licensed under the MIT license found in the
|
7
|
+
# LICENSE file in the root directory of this source tree.
|
8
|
+
#
|
9
|
+
|
10
|
+
module Dbee
|
11
|
+
module Providers
|
12
|
+
class ActiveRecordProvider
|
13
|
+
class ExpressionBuilder
|
14
|
+
# Derives Arel#where predicates.
|
15
|
+
class Where
|
16
|
+
include Singleton
|
17
|
+
|
18
|
+
def make(filter, arel_column)
|
19
|
+
# If the filter has a value of nil, then simply return an IS NULL predicate
|
20
|
+
return make_is_null_predicate(arel_column) unless filter.value
|
21
|
+
|
22
|
+
values = Array(filter.value).flatten
|
23
|
+
|
24
|
+
# This logic helps ensure that if a null exists that it translates to an IS NULL
|
25
|
+
# predicate and does not get put into an in or not_in clause.
|
26
|
+
predicates = values.include?(nil) ? [make_is_null_predicate(arel_column)] : []
|
27
|
+
predicates += make_predicates(filter, arel_column, values - [nil])
|
28
|
+
|
29
|
+
# Chain all predicates together
|
30
|
+
predicates.inject(predicates.shift) do |memo, predicate|
|
31
|
+
memo.or(predicate)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
FILTER_EVALUATORS = {
|
38
|
+
Query::Filters::Contains => ->(node, val) { node.matches("%#{val}%") },
|
39
|
+
Query::Filters::Equals => ->(node, val) { node.eq(val) },
|
40
|
+
Query::Filters::GreaterThan => ->(node, val) { node.gt(val) },
|
41
|
+
Query::Filters::GreaterThanOrEqualTo => ->(node, val) { node.gteq(val) },
|
42
|
+
Query::Filters::LessThan => ->(node, val) { node.lt(val) },
|
43
|
+
Query::Filters::LessThanOrEqualTo => ->(node, val) { node.lteq(val) },
|
44
|
+
Query::Filters::NotContain => ->(node, val) { node.does_not_match("%#{val}%") },
|
45
|
+
Query::Filters::NotEquals => ->(node, val) { node.not_eq(val) },
|
46
|
+
Query::Filters::NotStartWith => ->(node, val) { node.does_not_match("#{val}%") },
|
47
|
+
Query::Filters::StartsWith => ->(node, val) { node.matches("#{val}%") }
|
48
|
+
}.freeze
|
49
|
+
|
50
|
+
private_constant :FILTER_EVALUATORS
|
51
|
+
|
52
|
+
def make_predicates(filter, arel_column, values)
|
53
|
+
if use_in?(filter, values)
|
54
|
+
[arel_column.in(values)]
|
55
|
+
elsif use_not_in?(filter, values)
|
56
|
+
[arel_column.not_in(values)]
|
57
|
+
else
|
58
|
+
make_or_predicates(filter, arel_column, values)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def use_in?(filter, values)
|
63
|
+
filter.is_a?(Query::Filters::Equals) && values.length > 1
|
64
|
+
end
|
65
|
+
|
66
|
+
def use_not_in?(filter, values)
|
67
|
+
filter.is_a?(Query::Filters::NotEquals) && values.length > 1
|
68
|
+
end
|
69
|
+
|
70
|
+
def make_or_predicates(filter, arel_column, values)
|
71
|
+
values.map do |value|
|
72
|
+
make_predicate(arel_column, filter.class, value)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def make_predicate(arel_column, filter_class, value)
|
77
|
+
method = FILTER_EVALUATORS[filter_class]
|
78
|
+
|
79
|
+
raise ArgumentError, "cannot compile filter: #{filter}" unless method
|
80
|
+
|
81
|
+
method.call(arel_column, value)
|
82
|
+
end
|
83
|
+
|
84
|
+
def make_is_null_predicate(arel_column)
|
85
|
+
make_predicate(arel_column, Query::Filters::Equals, nil)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|