activerecord-filter 6.0.0.2 → 6.0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +77 -30
- data/lib/active_record/filter.rb +123 -74
- data/lib/active_record/filter/version.rb +1 -1
- metadata +14 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f04e35c30cfd4a96db7ba90fa1221a808121bacde16bdb70080e105274ae33d5
|
4
|
+
data.tar.gz: 5aabf016e7b0cec65b87b09f191fd0da5eb55b0f48cdf94cf4f1727b2c0867af
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: af710f6e3adfd0b3dab81c34a9ae1b2578e9d6047f81c0fed362e30dd97a06ee110eb189eb670bd3e0875792196a36f574e35051585aef37ec0eaca4b4849b69
|
7
|
+
data.tar.gz: 869eab8791079a03a395f45ce510d31f05fb0399914ab6996cf8ef4ff4f3450da6a70941cd6068c24a193d4923ac12a539aea4620f16da292c9ae610b77a4419
|
data/README.md
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
Installtion
|
6
6
|
-----------
|
7
7
|
|
8
|
-
- Add `gem 'activerecord-filter', require: 'active_record/filter'
|
8
|
+
- Add `gem 'activerecord-filter', require: 'active_record/filter'`
|
9
9
|
- Run `bundle install`
|
10
10
|
|
11
11
|
Examples
|
@@ -14,48 +14,89 @@ Examples
|
|
14
14
|
Normal columns:
|
15
15
|
|
16
16
|
```ruby
|
17
|
-
Property.filter(:
|
18
|
-
|
17
|
+
Property.filter(id: 5).to_sql
|
18
|
+
Property.filter(id: {eq: 5}).to_sql
|
19
|
+
Property.filter(id: {equal_to: 5}).to_sql
|
20
|
+
# => "... WHERE properties.id = 5 ..."
|
19
21
|
|
20
|
-
Property.filter(:
|
21
|
-
|
22
|
+
Property.filter(id: {not: 5}).to_sql
|
23
|
+
Property.filter(id: {neq: 5}).to_sql
|
24
|
+
Property.filter(id: {not_equal: 5}).to_sql
|
25
|
+
# => "... WHERE properties.id != 5 ..."
|
22
26
|
|
23
|
-
Property.filter(:
|
24
|
-
# => "...WHERE properties.id
|
27
|
+
Property.filter(id: [5, 10, 15]).to_sql
|
28
|
+
# => "... WHERE properties.id IN (5, 10, 15) ..."
|
25
29
|
|
26
|
-
Property.filter(:
|
27
|
-
# => "...WHERE properties.id
|
30
|
+
Property.filter(id: {in: [5, 10, 15]}).to_sql
|
31
|
+
# => "... WHERE properties.id IN (5, 10, 15) ..."
|
28
32
|
|
29
|
-
Property.filter(:
|
30
|
-
# => "...WHERE properties.id
|
33
|
+
Property.filter(id: {not_in: [5, 10, 15]}).to_sql
|
34
|
+
# => "... WHERE properties.id NOT IN (5, 10, 15) ..."
|
31
35
|
|
32
|
-
Property.filter(:
|
33
|
-
|
36
|
+
Property.filter(id: {gt: 5}).to_sql
|
37
|
+
Property.filter(id: {greater_than: 5}).to_sql
|
38
|
+
# => "... WHERE properties.id > 5 ..."
|
34
39
|
|
35
|
-
Property.filter(:
|
36
|
-
|
40
|
+
Property.filter(id: {gte: 5}).to_sql
|
41
|
+
Property.filter(id: {gteq: 5}).to_sql
|
42
|
+
Property.filter(id: {greater_than_or_equal_to: 5}).to_sql
|
43
|
+
# => "... WHERE properties.id >= 5 ..."
|
37
44
|
|
38
|
-
Property.filter(:
|
39
|
-
|
45
|
+
Property.filter(id: {lt: 5}).to_sql
|
46
|
+
Property.filter(id: {less_than: 5}).to_sql
|
47
|
+
# => "... WHERE properties.id < 5 ..."
|
40
48
|
|
41
|
-
Property.filter(:
|
42
|
-
|
49
|
+
Property.filter(id: {lte: 5}).to_sql
|
50
|
+
Property.filter(id: {lteq: 5}).to_sql
|
51
|
+
Property.filter(id: {less_than_or_equal_to: 5}).to_sql
|
52
|
+
# => "... WHERE properties.id <= 5 ..."
|
53
|
+
|
54
|
+
Property.filter(address_id: nil).to_sql
|
55
|
+
# => "... WHERE properties.address_id IS NULL ..."
|
56
|
+
|
57
|
+
Property.filter(address_id: false).to_sql
|
58
|
+
# => "... WHERE properties.address_id IS NULL ..."
|
59
|
+
|
60
|
+
Property.filter(boolean_column: false).to_sql
|
61
|
+
# => "... WHERE properties.boolean_column = FALSE ..."
|
62
|
+
|
63
|
+
Property.filter(address_id: true).to_sql
|
64
|
+
# => "... WHERE properties.address_id IS NOT NULL ..."
|
65
|
+
|
66
|
+
Property.filter(boolean_column: true).to_sql
|
67
|
+
# => "... WHERE properties.boolean_column = TRUE ..."
|
68
|
+
```
|
69
|
+
|
70
|
+
String columns:
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
Property.filter(name: {like: 'nam%'}).to_sql
|
74
|
+
# => "... WHERE properties.name LIKE 'nam%' ..."
|
75
|
+
|
76
|
+
Property.filter(name: {ts_match: 'name'}).to_sql
|
77
|
+
# => "... WHERE to_tsvector("properties"."name") @@ to_tsquery('name') ..."
|
43
78
|
```
|
44
79
|
|
45
80
|
It can also work with array columns:
|
46
81
|
|
47
82
|
```ruby
|
48
|
-
Property.filter(:
|
83
|
+
Property.filter(tags: 'Skyscraper').to_sql
|
49
84
|
# => "...WHERE properties.tags = '{'Skyscraper'}'..."
|
50
85
|
|
51
|
-
Property.filter(:
|
52
|
-
# => "...WHERE
|
86
|
+
Property.filter(tags: ['Skyscraper', 'Brick']).to_sql
|
87
|
+
# => "...WHERE properties.tags = '{"Skyscraper", "Brick"}'..."
|
88
|
+
|
89
|
+
Property.filter(tags: {overlaps: ['Skyscraper', 'Brick']}).to_sql
|
90
|
+
# => "...WHERE properties.tags && '{"Skyscraper", "Brick"}'..."
|
91
|
+
|
92
|
+
Property.filter(tags: {contains: ['Skyscraper', 'Brick']}).to_sql
|
93
|
+
# => "...WHERE accounts.tags @> '{"Skyscraper", "Brick"}'..."
|
53
94
|
|
54
|
-
Property.filter(:
|
55
|
-
# => "...WHERE
|
95
|
+
Property.filter(tags: {excludes: ['Skyscraper', 'Brick']}).to_sql
|
96
|
+
# => "...WHERE NOT (accounts.tags @> '{"Skyscraper", "Brick"}')..."
|
56
97
|
|
57
|
-
Property.filter(:
|
58
|
-
# => "...WHERE accounts.tags
|
98
|
+
Property.filter(tags: {contained_by: ['Skyscraper', 'Brick']}).to_sql
|
99
|
+
# => "...WHERE accounts.tags <@ '{"Skyscraper", "Brick"}'..."
|
59
100
|
```
|
60
101
|
|
61
102
|
And JSON columns:
|
@@ -70,6 +111,12 @@ Property.filter(metadata: { contains: { key: 'value' } }).to_sql
|
|
70
111
|
Property.filter(metadata: { has_key: 'key' }).to_sql
|
71
112
|
# => "...WHERE "properties"."metadata" ? 'key'..."
|
72
113
|
|
114
|
+
Property.filter(metadata: { has_keys: ['key1', 'key2'] }).to_sql
|
115
|
+
# => "...WHERE "properties"."metadata" ?& array['key1', 'key2']..."
|
116
|
+
|
117
|
+
Property.filter(metadata: { has_any_key: ['key1', 'key2'] }).to_sql
|
118
|
+
# => "...WHERE "properties"."metadata" ?| array['key1', 'key2']..."
|
119
|
+
|
73
120
|
Property.filter("metadata.key": { eq: 'value' }).to_sql
|
74
121
|
# => "...WHERE "properties"."metadata" #> '{key}' = 'value'..."
|
75
122
|
```
|
@@ -77,7 +124,7 @@ Property.filter("metadata.key": { eq: 'value' }).to_sql
|
|
77
124
|
It can also sort on relations:
|
78
125
|
|
79
126
|
```ruby
|
80
|
-
Photo.filter(:
|
81
|
-
# => "...INNER JOIN properties ON properties.id = photos.property_id
|
82
|
-
# => "
|
83
|
-
```
|
127
|
+
Photo.filter(property: {name: 'Empire State'}).to_sql
|
128
|
+
# => "... INNER JOIN properties ON properties.id = photos.property_id ...
|
129
|
+
# => "... WHERE properties.name = 'Empire State'"
|
130
|
+
```
|
data/lib/active_record/filter.rb
CHANGED
@@ -7,23 +7,23 @@ end
|
|
7
7
|
module ActiveRecord::Filter
|
8
8
|
|
9
9
|
delegate :filter, :filter_for, to: :all
|
10
|
-
|
10
|
+
|
11
11
|
def inherited(subclass)
|
12
12
|
super
|
13
13
|
subclass.instance_variable_set('@filters', HashWithIndifferentAccess.new)
|
14
14
|
end
|
15
|
-
|
15
|
+
|
16
16
|
def filters
|
17
17
|
@filters
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
20
|
def filter_on(name, dependent_joins=nil, &block)
|
21
21
|
@filters[name.to_s] = {
|
22
22
|
joins: dependent_joins,
|
23
23
|
block: block
|
24
24
|
}
|
25
25
|
end
|
26
|
-
|
26
|
+
|
27
27
|
end
|
28
28
|
|
29
29
|
module ActiveRecord
|
@@ -33,7 +33,7 @@ module ActiveRecord
|
|
33
33
|
custom = []
|
34
34
|
[build_filter_joins(klass, filters, [], custom), custom]
|
35
35
|
end
|
36
|
-
|
36
|
+
|
37
37
|
def self.build_filter_joins(klass, filters, relations=[], custom=[])
|
38
38
|
if filters.is_a?(Array)
|
39
39
|
filters.each { |f| build_filter_joins(klass, f, relations, custom) }.compact
|
@@ -41,7 +41,7 @@ module ActiveRecord
|
|
41
41
|
filters.each do |key, value|
|
42
42
|
if klass.filters.has_key?(key.to_sym)
|
43
43
|
js = klass.filters.dig(key.to_sym, :joins)
|
44
|
-
|
44
|
+
|
45
45
|
if js.is_a?(Array)
|
46
46
|
js.each do |j|
|
47
47
|
if j.is_a?(String)
|
@@ -59,9 +59,28 @@ module ActiveRecord
|
|
59
59
|
end
|
60
60
|
elsif reflection = klass._reflections[key.to_s]
|
61
61
|
if value.is_a?(Hash)
|
62
|
-
relations <<
|
63
|
-
|
64
|
-
|
62
|
+
relations << if reflection.polymorphic?
|
63
|
+
join_klass = value[:as].safe_constantize
|
64
|
+
|
65
|
+
right_table = join_klass.arel_table.alias("#{join_klass.table_name}_as_#{reflection.name}")
|
66
|
+
left_table = reflection.active_record.arel_table
|
67
|
+
|
68
|
+
on = right_table[join_klass.primary_key].
|
69
|
+
eq(left_table[reflection.foreign_key]).
|
70
|
+
and(left_table[reflection.foreign_type].eq(join_klass.name))
|
71
|
+
|
72
|
+
left_table.join(right_table, Arel::Nodes::OuterJoin).on(on).join_sources
|
73
|
+
else
|
74
|
+
{
|
75
|
+
key => build_filter_joins(reflection.klass, value, [], custom)
|
76
|
+
}
|
77
|
+
end
|
78
|
+
elsif value.is_a?(Array)
|
79
|
+
value.each do |v|
|
80
|
+
relations << {
|
81
|
+
key => build_filter_joins(reflection.klass, v, [], custom)
|
82
|
+
}
|
83
|
+
end
|
65
84
|
elsif value != true && value != false && value != 'true' && value != 'false' && !value.nil?
|
66
85
|
relations << key
|
67
86
|
end
|
@@ -73,17 +92,17 @@ module ActiveRecord
|
|
73
92
|
end
|
74
93
|
end
|
75
94
|
end
|
76
|
-
|
95
|
+
|
77
96
|
relations
|
78
97
|
end
|
79
|
-
|
80
|
-
def build_from_filter_hash(attributes)
|
98
|
+
|
99
|
+
def build_from_filter_hash(attributes, relation_trail, alias_tracker)
|
81
100
|
if attributes.is_a?(Array)
|
82
|
-
node = build_from_filter_hash(attributes.shift)
|
101
|
+
node = build_from_filter_hash(attributes.shift, relation_trail, alias_tracker)
|
83
102
|
|
84
103
|
n = attributes.shift(2)
|
85
104
|
while !n.empty?
|
86
|
-
n[1] = build_from_filter_hash(n[1])
|
105
|
+
n[1] = build_from_filter_hash(n[1], relation_trail, alias_tracker)
|
87
106
|
if n[0] == 'AND'
|
88
107
|
if node.is_a?(Arel::Nodes::And)
|
89
108
|
node.children.push(n[1])
|
@@ -92,39 +111,46 @@ module ActiveRecord
|
|
92
111
|
end
|
93
112
|
elsif n[0] == 'OR'
|
94
113
|
node = Arel::Nodes::Grouping.new(node).or(Arel::Nodes::Grouping.new(n[1]))
|
114
|
+
elsif !n[0].is_a?(String)
|
115
|
+
n[0] = build_from_filter_hash(n[0], relation_trail, alias_tracker)
|
116
|
+
if node.is_a?(Arel::Nodes::And)
|
117
|
+
node.children.push(n[0])
|
118
|
+
else
|
119
|
+
node = node.and(n[0])
|
120
|
+
end
|
95
121
|
else
|
96
122
|
raise 'lll'
|
97
123
|
end
|
98
124
|
n = attributes.shift(2)
|
99
125
|
end
|
100
|
-
|
126
|
+
|
101
127
|
node
|
102
128
|
elsif attributes.is_a?(Hash)
|
103
|
-
expand_from_filter_hash(attributes)
|
129
|
+
expand_from_filter_hash(attributes, relation_trail, alias_tracker)
|
104
130
|
else
|
105
|
-
expand_from_filter_hash({id: attributes})
|
131
|
+
expand_from_filter_hash({id: attributes}, relation_trail, alias_tracker)
|
106
132
|
end
|
107
133
|
end
|
108
|
-
|
109
|
-
def expand_from_filter_hash(attributes)
|
134
|
+
|
135
|
+
def expand_from_filter_hash(attributes, relation_trail, alias_tracker)
|
110
136
|
klass = table.send(:klass)
|
111
|
-
|
137
|
+
|
112
138
|
children = attributes.flat_map do |key, value|
|
113
139
|
if custom_filter = klass.filters[key]
|
114
|
-
self.instance_exec(klass, table, key, value, &custom_filter[:block])
|
140
|
+
self.instance_exec(klass, table, key, value, relation_trail, alias_tracker, &custom_filter[:block])
|
115
141
|
elsif column = klass.columns_hash[key.to_s] || klass.columns_hash[key.to_s.split('.').first]
|
116
|
-
expand_filter_for_column(key, column, value)
|
142
|
+
expand_filter_for_column(key, column, value, relation_trail)
|
117
143
|
elsif relation = klass.reflect_on_association(key)
|
118
|
-
expand_filter_for_relationship(relation, value)
|
144
|
+
expand_filter_for_relationship(relation, value, relation_trail, alias_tracker)
|
119
145
|
elsif key.to_s.ends_with?('_ids') && relation = klass.reflect_on_association(key.to_s.gsub(/_ids$/, 's'))
|
120
|
-
expand_filter_for_relationship(relation, {id: value})
|
146
|
+
expand_filter_for_relationship(relation, {id: value}, relation_trail, alias_tracker)
|
121
147
|
elsif relation = klass.reflect_on_all_associations(:has_and_belongs_to_many).find {|r| r.join_table == key.to_s && value.keys.first.to_s == r.association_foreign_key.to_s }
|
122
|
-
expand_filter_for_join_table(relation, value)
|
148
|
+
expand_filter_for_join_table(relation, value, relation_trail, alias_tracker)
|
123
149
|
else
|
124
150
|
raise ActiveRecord::UnkownFilterError.new("Unkown filter \"#{key}\" for #{klass}.")
|
125
151
|
end
|
126
152
|
end
|
127
|
-
|
153
|
+
|
128
154
|
children.compact!
|
129
155
|
if children.size > 1
|
130
156
|
Arel::Nodes::And.new(children)
|
@@ -132,20 +158,11 @@ module ActiveRecord
|
|
132
158
|
children.first
|
133
159
|
end
|
134
160
|
end
|
135
|
-
|
136
|
-
def expand_filter_for_column(key, column, value)
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
# Arel::Nodes::TableAlias, would like to go back to it one day
|
141
|
-
attribute = if klass = table.send(:klass)
|
142
|
-
if Arel::Nodes::TableAlias === table.send(:arel_table)
|
143
|
-
klass.arel_attribute(column.name, table.send(:arel_table).left)
|
144
|
-
else
|
145
|
-
klass.arel_attribute(column.name, table.send(:arel_table))
|
146
|
-
end
|
147
|
-
else
|
148
|
-
table.send(:arel_table)[column.name]
|
161
|
+
|
162
|
+
def expand_filter_for_column(key, column, value, relation_trail)
|
163
|
+
attribute = table.arel_attribute(column.name)
|
164
|
+
relation_trail.each do |rt|
|
165
|
+
attribute = Arel::Attributes::Relation.new(attribute, rt)
|
149
166
|
end
|
150
167
|
|
151
168
|
if column.type == :json || column.type == :jsonb
|
@@ -153,7 +170,7 @@ module ActiveRecord
|
|
153
170
|
names.shift
|
154
171
|
attribute = attribute.dig(names)
|
155
172
|
end
|
156
|
-
|
173
|
+
|
157
174
|
if value.is_a?(Hash)
|
158
175
|
nodes = value.map do |subkey, subvalue|
|
159
176
|
expand_filter_for_arel_attribute(column, attribute, subkey, subvalue)
|
@@ -173,9 +190,9 @@ module ActiveRecord
|
|
173
190
|
else
|
174
191
|
raise ActiveRecord::UnkownFilterError.new("Unkown type for #{column}. (type #{value.class})")
|
175
192
|
end
|
176
|
-
|
193
|
+
|
177
194
|
end
|
178
|
-
|
195
|
+
|
179
196
|
def expand_filter_for_arel_attribute(column, attribute, key, value)
|
180
197
|
case key.to_sym
|
181
198
|
when :contains
|
@@ -206,7 +223,7 @@ module ActiveRecord
|
|
206
223
|
# elsif # EWKT
|
207
224
|
# elsif # WKT
|
208
225
|
# end
|
209
|
-
|
226
|
+
|
210
227
|
# TODO us above if to determin if SRID sent
|
211
228
|
geometry_value = if value.is_a?(Hash)
|
212
229
|
Arel::Nodes::NamedFunction.new('ST_SetSRID', [Arel::Nodes::NamedFunction.new('ST_GeomFromGeoJSON', [Arel::Nodes.build_quoted(JSON.generate(subvalue))]), 4326])
|
@@ -250,11 +267,11 @@ module ActiveRecord
|
|
250
267
|
raise "Not Supported value for within: #{value.inspect}"
|
251
268
|
end
|
252
269
|
else
|
253
|
-
raise "Not Supported: #{key.to_sym}"
|
270
|
+
raise "Not Supported: #{key.to_sym} on column \"#{column.name}\" of type #{column.type}"
|
254
271
|
end
|
255
272
|
end
|
256
|
-
|
257
|
-
def expand_filter_for_relationship(relation, value)
|
273
|
+
|
274
|
+
def expand_filter_for_relationship(relation, value, relation_trail, alias_tracker)
|
258
275
|
case relation.macro
|
259
276
|
when :has_many
|
260
277
|
if value == true || value == 'true'
|
@@ -272,6 +289,7 @@ module ActiveRecord
|
|
272
289
|
raise "Not Supported: #{relation.name}"
|
273
290
|
end
|
274
291
|
end
|
292
|
+
|
275
293
|
when :belongs_to
|
276
294
|
if value == true || value == 'true'
|
277
295
|
return table.arel_attribute(relation.foreign_key).not_eq(nil)
|
@@ -279,16 +297,43 @@ module ActiveRecord
|
|
279
297
|
return table.arel_attribute(relation.foreign_key).eq(nil)
|
280
298
|
end
|
281
299
|
end
|
282
|
-
|
283
|
-
builder =
|
284
|
-
|
300
|
+
|
301
|
+
builder = if relation.polymorphic?
|
302
|
+
value = value.dup
|
303
|
+
klass = value.delete(:as).safe_constantize
|
304
|
+
|
305
|
+
self.class.new(TableMetadata.new(
|
306
|
+
klass,
|
307
|
+
Arel::Table.new("#{klass.table_name}_as_#{relation.name}", type_caster: klass.type_caster),
|
308
|
+
relation
|
309
|
+
))
|
310
|
+
else
|
311
|
+
self.class.new(TableMetadata.new(
|
312
|
+
relation.klass,
|
313
|
+
alias_tracker.aliased_table_for(
|
314
|
+
relation.table_name,
|
315
|
+
relation.alias_candidate(table.send(:arel_table).name),
|
316
|
+
relation.klass.type_caster
|
317
|
+
),
|
318
|
+
relation
|
319
|
+
))
|
320
|
+
end
|
321
|
+
builder.build_from_filter_hash(value, relation_trail + [relation.name], alias_tracker)
|
285
322
|
end
|
286
|
-
|
287
|
-
def expand_filter_for_join_table(relation, value)
|
288
|
-
relation = relation.active_record._reflections[relation.active_record._reflections[relation.name.to_s].send(:delegate_reflection).options[:through].to_s]
|
289
323
|
|
290
|
-
|
291
|
-
|
324
|
+
|
325
|
+
def expand_filter_for_join_table(relation, value, relation_trail, alias_tracker)
|
326
|
+
relation = relation.active_record._reflections[relation.active_record._reflections[relation.name.to_s].send(:delegate_reflection).options[:through].to_s]
|
327
|
+
builder = self.class.new(TableMetadata.new(
|
328
|
+
relation.klass,
|
329
|
+
alias_tracker.aliased_table_for(
|
330
|
+
relation.table_name,
|
331
|
+
relation.alias_candidate(table.send(:arel_table).name),
|
332
|
+
relation.klass.type_caster
|
333
|
+
),
|
334
|
+
relation
|
335
|
+
))
|
336
|
+
builder.build_from_filter_hash(value, relation_trail + [relation.name], alias_tracker)
|
292
337
|
end
|
293
338
|
|
294
339
|
end
|
@@ -303,18 +348,13 @@ module ActiveRecord
|
|
303
348
|
@predicate_builder = predicate_builder
|
304
349
|
end
|
305
350
|
|
306
|
-
def build(filters)
|
351
|
+
def build(filters, alias_tracker)
|
307
352
|
if filters.is_a?(Hash) || filters.is_a?(Array)
|
308
|
-
|
309
|
-
# attributes = klass.send(:expand_hash_conditions_for_aggregates, attributes)
|
310
|
-
# attributes.stringify_keys!
|
311
|
-
#
|
312
|
-
# attributes, binds = predicate_builder.create_binds(attributes)
|
313
|
-
parts = [predicate_builder.build_from_filter_hash(filters)]
|
353
|
+
parts = [predicate_builder.build_from_filter_hash(filters, [], alias_tracker)]
|
314
354
|
else
|
315
355
|
raise ArgumentError, "Unsupported argument type: #{filters.inspect} (#{filters.class})"
|
316
356
|
end
|
317
|
-
|
357
|
+
|
318
358
|
WhereClause.new(parts)
|
319
359
|
end
|
320
360
|
|
@@ -332,12 +372,12 @@ class ActiveRecord::Relation
|
|
332
372
|
@filters = []
|
333
373
|
super
|
334
374
|
end
|
335
|
-
|
375
|
+
|
336
376
|
def initialize_copy(other)
|
337
377
|
@filters = @filters.deep_dup
|
338
378
|
super
|
339
379
|
end
|
340
|
-
|
380
|
+
|
341
381
|
def clean_filters(value)
|
342
382
|
if value.class.name == 'ActionController::Parameters'.freeze
|
343
383
|
value.to_unsafe_h
|
@@ -350,34 +390,43 @@ class ActiveRecord::Relation
|
|
350
390
|
|
351
391
|
def filter(filters)
|
352
392
|
filters = clean_filters(filters)
|
353
|
-
|
393
|
+
|
354
394
|
if filters.nil? || filters.empty?
|
355
395
|
self
|
356
396
|
else
|
357
397
|
spawn.filter!(filters)
|
358
398
|
end
|
359
399
|
end
|
360
|
-
|
400
|
+
|
361
401
|
def filter!(filters)
|
362
402
|
js = ActiveRecord::PredicateBuilder.filter_joins(klass, filters)
|
363
|
-
js.each
|
403
|
+
js.flatten.each do |j|
|
404
|
+
if j.is_a?(String)
|
405
|
+
joins!(j)
|
406
|
+
elsif j.is_a?(Arel::Nodes::Join)
|
407
|
+
joins!(j)
|
408
|
+
elsif j.present?
|
409
|
+
left_outer_joins!(j)
|
410
|
+
end
|
411
|
+
end
|
364
412
|
@filters << filters
|
365
413
|
self
|
366
414
|
end
|
367
|
-
|
415
|
+
|
368
416
|
def filter_clause_factory
|
369
417
|
@filter_clause_factory ||= FilterClauseFactory.new(klass, predicate_builder)
|
370
418
|
end
|
371
|
-
|
419
|
+
|
372
420
|
def build_arel(aliases)
|
373
421
|
arel = super
|
374
|
-
|
422
|
+
my_alias_tracker = ActiveRecord::Associations::AliasTracker.create(connection, table.name, [])
|
423
|
+
build_filters(arel, my_alias_tracker)
|
375
424
|
arel
|
376
425
|
end
|
377
|
-
|
378
|
-
def build_filters(manager)
|
426
|
+
|
427
|
+
def build_filters(manager, aliases)
|
379
428
|
@filters.each do |filters|
|
380
|
-
manager.where(filter_clause_factory.build(filters).ast)
|
429
|
+
manager.where(filter_clause_factory.build(filters, alias_tracker).ast)
|
381
430
|
end
|
382
431
|
end
|
383
432
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord-filter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 6.0.0.
|
4
|
+
version: 6.0.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jon Bracy
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-06-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -16,28 +16,28 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 6.0.0
|
19
|
+
version: 6.0.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 6.0.0
|
26
|
+
version: 6.0.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: arel-extensions
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 6.0.0
|
33
|
+
version: 6.0.0.8
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 6.0.0
|
40
|
+
version: 6.0.0.8
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: pg
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -58,14 +58,14 @@ dependencies:
|
|
58
58
|
requirements:
|
59
59
|
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: 6.0.0
|
61
|
+
version: 6.0.0
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: 6.0.0
|
68
|
+
version: 6.0.0
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: bundler
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -142,14 +142,14 @@ dependencies:
|
|
142
142
|
requirements:
|
143
143
|
- - ">="
|
144
144
|
- !ruby/object:Gem::Version
|
145
|
-
version: 6.0.0
|
145
|
+
version: 6.0.0
|
146
146
|
type: :development
|
147
147
|
prerelease: false
|
148
148
|
version_requirements: !ruby/object:Gem::Requirement
|
149
149
|
requirements:
|
150
150
|
- - ">="
|
151
151
|
- !ruby/object:Gem::Version
|
152
|
-
version: 6.0.0
|
152
|
+
version: 6.0.0
|
153
153
|
- !ruby/object:Gem::Dependency
|
154
154
|
name: faker
|
155
155
|
requirement: !ruby/object:Gem::Requirement
|
@@ -194,7 +194,7 @@ homepage: https://github.com/malomalo/activerecord-filter
|
|
194
194
|
licenses:
|
195
195
|
- MIT
|
196
196
|
metadata: {}
|
197
|
-
post_install_message:
|
197
|
+
post_install_message:
|
198
198
|
rdoc_options:
|
199
199
|
- "--main"
|
200
200
|
- README.md
|
@@ -211,8 +211,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
211
211
|
- !ruby/object:Gem::Version
|
212
212
|
version: '0'
|
213
213
|
requirements: []
|
214
|
-
rubygems_version: 3.
|
215
|
-
signing_key:
|
214
|
+
rubygems_version: 3.1.2
|
215
|
+
signing_key:
|
216
216
|
specification_version: 4
|
217
217
|
summary: A safe way to accept user parameters and query against your ActiveRecord
|
218
218
|
Models
|