activerecord-filter 6.0.0.7 → 6.1.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f04e35c30cfd4a96db7ba90fa1221a808121bacde16bdb70080e105274ae33d5
4
- data.tar.gz: 5aabf016e7b0cec65b87b09f191fd0da5eb55b0f48cdf94cf4f1727b2c0867af
3
+ metadata.gz: 02d2dcb9fb2f2fce2bcd28836c71fda9835fafcf85917a2dc0ce7366e7ce2446
4
+ data.tar.gz: f48abf819e7b5229f3b16176eb93a04d95190358d68267ddf9228590422e5ecf
5
5
  SHA512:
6
- metadata.gz: af710f6e3adfd0b3dab81c34a9ae1b2578e9d6047f81c0fed362e30dd97a06ee110eb189eb670bd3e0875792196a36f574e35051585aef37ec0eaca4b4849b69
7
- data.tar.gz: 869eab8791079a03a395f45ce510d31f05fb0399914ab6996cf8ef4ff4f3450da6a70941cd6068c24a193d4923ac12a539aea4620f16da292c9ae610b77a4419
6
+ metadata.gz: d9ee89bb0e6352d38c0fc2455074c904ceb2ab665495b7f7fdf3c30434ac1576fd778b417cecd2ecf1028437e170927b512ec470ffedabe513672aaf1c273e1e
7
+ data.tar.gz: 2d8014c494e72c3f77f9b7c4c6021713b90de72218c6929ffc28b848ab5491f75ce32091acbe55f5e136e87b2dbbf32266de6b14fb3547d6a98273217bd0fbf8
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
- # ActiveRecord::filter
1
+ # ActiveRecord::Filter
2
2
 
3
- `ActiveRecord::filter` provides and easy way to accept user input and filter a query by the input.
3
+ `ActiveRecord::Filter` provides and easy way to accept user input and filter a query by the input.
4
4
 
5
5
  Installtion
6
6
  -----------
@@ -73,6 +73,9 @@ String columns:
73
73
  Property.filter(name: {like: 'nam%'}).to_sql
74
74
  # => "... WHERE properties.name LIKE 'nam%' ..."
75
75
 
76
+ Property.filter(name: {ilike: 'nam%'}).to_sql
77
+ # => "... WHERE properties.name ILIKE 'nam%' ..."
78
+
76
79
  Property.filter(name: {ts_match: 'name'}).to_sql
77
80
  # => "... WHERE to_tsvector("properties"."name") @@ to_tsquery('name') ..."
78
81
  ```
@@ -125,6 +128,6 @@ It can also sort on relations:
125
128
 
126
129
  ```ruby
127
130
  Photo.filter(property: {name: 'Empire State'}).to_sql
128
- # => "... INNER JOIN properties ON properties.id = photos.property_id ...
131
+ # => "... LEFT OUTER JOIN properties ON properties.id = photos.property_id ...
129
132
  # => "... WHERE properties.name = 'Empire State'"
130
- ```
133
+ ```
@@ -4,6 +4,20 @@ require 'arel/extensions'
4
4
  class ActiveRecord::UnkownFilterError < NoMethodError
5
5
  end
6
6
 
7
+ class ActiveRecord::Associations::AliasTracker
8
+
9
+ def initialize(connection, aliases)
10
+ @aliases = aliases
11
+ @connection = connection
12
+ @relation_trail = {}
13
+ end
14
+
15
+ def aliased_table_for_relation(trail, arel_table, &block)
16
+ @relation_trail[trail] ||= aliased_table_for(arel_table, &block)
17
+ end
18
+
19
+ end
20
+
7
21
  module ActiveRecord::Filter
8
22
 
9
23
  delegate :filter, :filter_for, to: :all
@@ -60,16 +74,21 @@ module ActiveRecord
60
74
  elsif reflection = klass._reflections[key.to_s]
61
75
  if value.is_a?(Hash)
62
76
  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}")
77
+ value = value.dup
78
+ join_klass = value.delete(:as).safe_constantize
79
+ right_table = join_klass.arel_table
66
80
  left_table = reflection.active_record.arel_table
67
81
 
68
82
  on = right_table[join_klass.primary_key].
69
83
  eq(left_table[reflection.foreign_key]).
70
84
  and(left_table[reflection.foreign_type].eq(join_klass.name))
71
85
 
72
- left_table.join(right_table, Arel::Nodes::OuterJoin).on(on).join_sources
86
+ cross_boundry_joins = join_klass.left_outer_joins(ActiveRecord::PredicateBuilder.filter_joins(join_klass, value).flatten).send(:build_joins, [])
87
+
88
+ [
89
+ left_table.join(right_table, Arel::Nodes::OuterJoin).on(on).join_sources,
90
+ cross_boundry_joins
91
+ ]
73
92
  else
74
93
  {
75
94
  key => build_filter_joins(reflection.klass, value, [], custom)
@@ -84,7 +103,7 @@ module ActiveRecord
84
103
  elsif value != true && value != false && value != 'true' && value != 'false' && !value.nil?
85
104
  relations << key
86
105
  end
87
- elsif !klass.columns_hash.has_key?(key.to_s) && key.to_s.ends_with?('_ids') && reflection = klass._reflections[key.to_s.gsub(/_ids$/, 's')]
106
+ elsif !klass.columns_hash.has_key?(key.to_s) && key.to_s.end_with?('_ids') && reflection = klass._reflections[key.to_s.gsub(/_ids$/, 's')]
88
107
  relations << reflection.name
89
108
  elsif reflection = 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 }
90
109
  reflection = klass._reflections[klass._reflections[reflection.name.to_s].send(:delegate_reflection).options[:through].to_s]
@@ -142,7 +161,7 @@ module ActiveRecord
142
161
  expand_filter_for_column(key, column, value, relation_trail)
143
162
  elsif relation = klass.reflect_on_association(key)
144
163
  expand_filter_for_relationship(relation, value, relation_trail, alias_tracker)
145
- elsif key.to_s.ends_with?('_ids') && relation = klass.reflect_on_association(key.to_s.gsub(/_ids$/, 's'))
164
+ elsif key.to_s.end_with?('_ids') && relation = klass.reflect_on_association(key.to_s.gsub(/_ids$/, 's'))
146
165
  expand_filter_for_relationship(relation, {id: value}, relation_trail, alias_tracker)
147
166
  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 }
148
167
  expand_filter_for_join_table(relation, value, relation_trail, alias_tracker)
@@ -160,7 +179,7 @@ module ActiveRecord
160
179
  end
161
180
 
162
181
  def expand_filter_for_column(key, column, value, relation_trail)
163
- attribute = table.arel_attribute(column.name)
182
+ attribute = table.arel_table[column.name]
164
183
  relation_trail.each do |rt|
165
184
  attribute = Arel::Attributes::Relation.new(attribute, rt)
166
185
  end
@@ -196,13 +215,13 @@ module ActiveRecord
196
215
  def expand_filter_for_arel_attribute(column, attribute, key, value)
197
216
  case key.to_sym
198
217
  when :contains
199
- attribute.contains(column.array ? Array(value) : value)
218
+ attribute.contains(Arel::Nodes::Casted.new(column.array ? Array(value) : value, attribute))
200
219
  when :contained_by
201
- attribute.contained_by(column.array ? Array(value) : value)
220
+ attribute.contained_by(Arel::Nodes::Casted.new(column.array ? Array(value) : value, attribute))
202
221
  when :equal_to, :eq
203
222
  attribute.eq(value)
204
223
  when :excludes
205
- attribute.excludes(Array(value))
224
+ attribute.excludes(Arel::Nodes::Casted.new(column.array ? Array(value) : value, attribute))
206
225
  when :greater_than, :gt
207
226
  attribute.gt(value)
208
227
  when :greater_than_or_equal_to, :gteq, :gte
@@ -238,14 +257,16 @@ module ActiveRecord
238
257
  attribute.lt(value)
239
258
  when :less_than_or_equal_to, :lteq, :lte
240
259
  attribute.lteq(value)
241
- when :like, :ilike
242
- attribute.matches(value)
260
+ when :like
261
+ attribute.matches(value, nil, true)
262
+ when :ilike
263
+ attribute.matches(value, nil, false)
243
264
  when :not, :not_equal, :neq
244
265
  attribute.not_eq(value)
245
266
  when :not_in
246
267
  attribute.not_in(value)
247
268
  when :overlaps
248
- attribute.overlaps(value)
269
+ attribute.overlaps(Arel::Nodes::Casted.new(column.array ? Array(value) : value, attribute))
249
270
  when :not_overlaps
250
271
  attribute.not_overlaps(value)
251
272
  when :ts_match
@@ -277,14 +298,14 @@ module ActiveRecord
277
298
  if value == true || value == 'true'
278
299
  counter_cache_column_name = relation.counter_cache_column || "#{relation.plural_name}_count"
279
300
  if relation.active_record.column_names.include?(counter_cache_column_name.to_s)
280
- return table.arel_attribute(counter_cache_column_name.to_sym).gt(0)
301
+ return table.arel_table[counter_cache_column_name.to_sym].gt(0)
281
302
  else
282
303
  raise "Not Supported: #{relation.name}"
283
304
  end
284
305
  elsif value == false || value == 'false'
285
306
  counter_cache_column_name = relation.counter_cache_column || "#{relation.plural_name}_count"
286
307
  if relation.active_record.column_names.include?(counter_cache_column_name.to_s)
287
- return table.arel_attribute(counter_cache_column_name.to_sym).eq(0)
308
+ return table.arel_table[counter_cache_column_name.to_sym].eq(0)
288
309
  else
289
310
  raise "Not Supported: #{relation.name}"
290
311
  end
@@ -292,33 +313,31 @@ module ActiveRecord
292
313
 
293
314
  when :belongs_to
294
315
  if value == true || value == 'true'
295
- return table.arel_attribute(relation.foreign_key).not_eq(nil)
316
+ return table.arel_table[relation.foreign_key].not_eq(nil)
296
317
  elsif value == false || value == 'false' || value.nil?
297
- return table.arel_attribute(relation.foreign_key).eq(nil)
318
+ return table.arel_table[relation.foreign_key].eq(nil)
298
319
  end
299
320
  end
300
321
 
301
- builder = if relation.polymorphic?
322
+ if relation.polymorphic?
302
323
  value = value.dup
303
324
  klass = value.delete(:as).safe_constantize
304
325
 
305
- self.class.new(TableMetadata.new(
306
- klass,
307
- Arel::Table.new("#{klass.table_name}_as_#{relation.name}", type_caster: klass.type_caster),
326
+ builder = self.class.new(TableMetadata.new(
327
+ klass,
328
+ alias_tracker.aliased_table_for_relation(relation_trail + ["#{klass.table_name}_as_#{relation.name}"], klass.arel_table) { klass.arel_table.name },
308
329
  relation
309
330
  ))
331
+ builder.build_from_filter_hash(value, relation_trail + ["#{klass.table_name}_as_#{relation.name}"], alias_tracker)
310
332
  else
311
- self.class.new(TableMetadata.new(
333
+ builder = self.class.new(TableMetadata.new(
312
334
  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
- ),
335
+ alias_tracker.aliased_table_for_relation(relation_trail + [relation.name], relation.klass.arel_table) { relation.alias_candidate(table.arel_table.name || relation.klass.arel_table) },
318
336
  relation
319
337
  ))
338
+ builder.build_from_filter_hash(value, relation_trail + [relation.name], alias_tracker)
320
339
  end
321
- builder.build_from_filter_hash(value, relation_trail + [relation.name], alias_tracker)
340
+
322
341
  end
323
342
 
324
343
 
@@ -326,11 +345,7 @@ module ActiveRecord
326
345
  relation = relation.active_record._reflections[relation.active_record._reflections[relation.name.to_s].send(:delegate_reflection).options[:through].to_s]
327
346
  builder = self.class.new(TableMetadata.new(
328
347
  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
- ),
348
+ alias_tracker.aliased_table_for_relation(relation_trail + [relation.name], relation.klass.arel_table) { relation.alias_candidate(table.arel_table.name || relation.klass.arel_table) },
334
349
  relation
335
350
  ))
336
351
  builder.build_from_filter_hash(value, relation_trail + [relation.name], alias_tracker)
@@ -417,14 +432,14 @@ class ActiveRecord::Relation
417
432
  @filter_clause_factory ||= FilterClauseFactory.new(klass, predicate_builder)
418
433
  end
419
434
 
420
- def build_arel(aliases)
435
+ def build_arel(aliases = nil)
421
436
  arel = super
422
437
  my_alias_tracker = ActiveRecord::Associations::AliasTracker.create(connection, table.name, [])
423
438
  build_filters(arel, my_alias_tracker)
424
439
  arel
425
440
  end
426
441
 
427
- def build_filters(manager, aliases)
442
+ def build_filters(manager, alias_tracker)
428
443
  @filters.each do |filters|
429
444
  manager.where(filter_clause_factory.build(filters, alias_tracker).ast)
430
445
  end
@@ -1,5 +1,5 @@
1
1
  module ActiveRecord
2
2
  module Filter
3
- VERSION = '6.0.0.7'
3
+ VERSION = '6.1.0.2'
4
4
  end
5
5
  end
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.7
4
+ version: 6.1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jon Bracy
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-06-26 00:00:00.000000000 Z
11
+ date: 2021-07-14 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.1.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.1.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.8
33
+ version: 6.1.0
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.8
40
+ version: 6.1.0
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.1.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.1.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.1.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.1.0
153
153
  - !ruby/object:Gem::Dependency
154
154
  name: faker
155
155
  requirement: !ruby/object:Gem::Requirement
@@ -211,7 +211,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
211
211
  - !ruby/object:Gem::Version
212
212
  version: '0'
213
213
  requirements: []
214
- rubygems_version: 3.1.2
214
+ rubygems_version: 3.2.3
215
215
  signing_key:
216
216
  specification_version: 4
217
217
  summary: A safe way to accept user parameters and query against your ActiveRecord