activerecord-filter 6.0.0.1 → 6.0.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: '09bb100ef828af898f984d813b053e52af5c0264e1f5991eb62062d641dce71d'
4
- data.tar.gz: 97fbdfccc6e9dff58be2d37cb4a17cc292c458c4d60610d5d5e31330d4c516d7
3
+ metadata.gz: 3f64c71b3f52eecc00c0e0ba35bc824466a756ec0781ee87fae30b2cde539a34
4
+ data.tar.gz: c4efd0dd23d922090881e9f07ce2e091551795b6e21975fa76a92d07b5101799
5
5
  SHA512:
6
- metadata.gz: 6d13276e0475e34a6232804118693ffa8e103f5bc34fa781a5a31444da88f968e17c8a81dc37753539681968605c3cbd79f16ef88ded994cb8a7db577c0f2f4a
7
- data.tar.gz: 772aff1eba3e010a77783ba6e3a40942b20bd4f5a7d4a7c218e31780ac211e9ec6a7fe4b9810b802277f801c9b00cd8434873096e5b62573a6f8f8d4b6789a86
6
+ metadata.gz: 432f672949da926119e4d06ffbcc105daaf06dddae7d2f08349b1c6b950f8002b3fb839caf191b41da2afaa0139028e135136640c7a9fbb2b0aa8224fe55dff2
7
+ data.tar.gz: 42503928c6ff4ef0cd83e56b6c7258b480d87236da66db61fa79603da351788a7b201eb0d63f2a14bebb35b9377ee841adc55e513130e2885f61f1fd27a15782
data/README.md CHANGED
@@ -56,8 +56,24 @@ Property.filter(:tags => {overlaps: ['Skyscraper', 'Brick']}).to_sql
56
56
 
57
57
  Property.filter(:tags => {contains: ['Skyscraper', 'Brick']}).to_sql
58
58
  # => "...WHERE accounts.tags @> '{"Skyscraper", "Brick"}')..."
59
+ ```
60
+
61
+ And JSON columns:
62
+
63
+ ```ruby
64
+ Property.filter(metadata: { eq: { key: 'value' } }).to_sql
65
+ # => "...WHERE "properties"."metadata" = '{\"key\":\"value\"}'..."
59
66
 
67
+ Property.filter(metadata: { contains: { key: 'value' } }).to_sql
68
+ # => "...WHERE "properties"."metadata" @> '{\"key\":\"value\"}'..."
69
+
70
+ Property.filter(metadata: { has_key: 'key' }).to_sql
71
+ # => "...WHERE "properties"."metadata" ? 'key'..."
72
+
73
+ Property.filter("metadata.key": { eq: 'value' }).to_sql
74
+ # => "...WHERE "properties"."metadata" #> '{key}' = 'value'..."
60
75
  ```
76
+
61
77
  It can also sort on relations:
62
78
 
63
79
  ```ruby
@@ -77,13 +77,13 @@ module ActiveRecord
77
77
  relations
78
78
  end
79
79
 
80
- def build_from_filter_hash(attributes, join_dependency)
80
+ def build_from_filter_hash(attributes)
81
81
  if attributes.is_a?(Array)
82
- node = build_from_filter_hash(attributes.shift, join_dependency)
82
+ node = build_from_filter_hash(attributes.shift)
83
83
 
84
84
  n = attributes.shift(2)
85
85
  while !n.empty?
86
- n[1] = build_from_filter_hash(n[1], join_dependency)
86
+ n[1] = build_from_filter_hash(n[1])
87
87
  if n[0] == 'AND'
88
88
  if node.is_a?(Arel::Nodes::And)
89
89
  node.children.push(n[1])
@@ -100,26 +100,26 @@ module ActiveRecord
100
100
 
101
101
  node
102
102
  elsif attributes.is_a?(Hash)
103
- expand_from_filter_hash(attributes, join_dependency)
103
+ expand_from_filter_hash(attributes)
104
104
  else
105
- expand_from_filter_hash({id: attributes}, join_dependency)
105
+ expand_from_filter_hash({id: attributes})
106
106
  end
107
107
  end
108
108
 
109
- def expand_from_filter_hash(attributes, join_dependency)
109
+ def expand_from_filter_hash(attributes)
110
110
  klass = table.send(:klass)
111
111
 
112
112
  children = attributes.flat_map do |key, value|
113
113
  if custom_filter = klass.filters[key]
114
- self.instance_exec(klass, table, key, value, join_dependency, &custom_filter[:block])
114
+ self.instance_exec(klass, table, key, value, &custom_filter[:block])
115
115
  elsif column = klass.columns_hash[key.to_s] || klass.columns_hash[key.to_s.split('.').first]
116
116
  expand_filter_for_column(key, column, value)
117
117
  elsif relation = klass.reflect_on_association(key)
118
- expand_filter_for_relationship(relation, value, join_dependency)
118
+ expand_filter_for_relationship(relation, value)
119
119
  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}, join_dependency)
120
+ expand_filter_for_relationship(relation, {id: value})
121
121
  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, join_dependency)
122
+ expand_filter_for_join_table(relation, value)
123
123
  else
124
124
  raise ActiveRecord::UnkownFilterError.new("Unkown filter \"#{key}\" for #{klass}.")
125
125
  end
@@ -133,17 +133,21 @@ module ActiveRecord
133
133
  end
134
134
  end
135
135
 
136
- def convert_filter_value(column, value)
137
- caster = table.send(:klass).attribute_types[column.name]
138
- if value.is_a?(Array) && !column.array
139
- value.map {|v| caster.cast(v) }
136
+ def expand_filter_for_column(key, column, value)
137
+ # Not sure why
138
+ # activerecord/lib/active_record/table_metadata.rb#arel_attribute
139
+ # doesn't work here, something's not working with a
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
140
147
  else
141
- caster.cast(value)
148
+ table.send(:arel_table)[column.name]
142
149
  end
143
- end
144
-
145
- def expand_filter_for_column(key, column, value)
146
- attribute = table.arel_attribute(column.name)
150
+
147
151
  if column.type == :json || column.type == :jsonb
148
152
  names = key.to_s.split('.')
149
153
  names.shift
@@ -162,9 +166,9 @@ module ActiveRecord
162
166
  elsif value == false || value == 'false'
163
167
  column.type == :boolean ? attribute.eq(false) : attribute.eq(nil)
164
168
  elsif value.is_a?(Array) && !column.array
165
- attribute.in(convert_filter_value(column, value))
169
+ attribute.in(value)
166
170
  elsif column.type != :json && column.type != :jsonb
167
- converted_value = convert_filter_value(column, column.array ? Array(value) : value)
171
+ converted_value = column.array ? Array(value) : value
168
172
  attribute.eq(converted_value)
169
173
  else
170
174
  raise ActiveRecord::UnkownFilterError.new("Unkown type for #{column}. (type #{value.class})")
@@ -175,17 +179,17 @@ module ActiveRecord
175
179
  def expand_filter_for_arel_attribute(column, attribute, key, value)
176
180
  case key.to_sym
177
181
  when :contains
178
- attribute.contains(column.array ? convert_filter_value(column, Array(value)) : convert_filter_value(column, value))
182
+ attribute.contains(column.array ? Array(value) : value)
179
183
  when :contained_by
180
- attribute.contained_by(column.array ? convert_filter_value(column, Array(value)) : convert_filter_value(column, value))
184
+ attribute.contained_by(column.array ? Array(value) : value)
181
185
  when :equal_to, :eq
182
- attribute.eq(convert_filter_value(column, value))
186
+ attribute.eq(value)
183
187
  when :excludes
184
- attribute.excludes(convert_filter_value(column, Array(value)))
188
+ attribute.excludes(Array(value))
185
189
  when :greater_than, :gt
186
- attribute.gt(convert_filter_value(column, value))
190
+ attribute.gt(value)
187
191
  when :greater_than_or_equal_to, :gteq, :gte
188
- attribute.gteq(convert_filter_value(column, value))
192
+ attribute.gteq(value)
189
193
  when :has_key
190
194
  attribute.has_key(value)
191
195
  when :has_keys
@@ -193,7 +197,7 @@ module ActiveRecord
193
197
  when :has_any_key
194
198
  attribute.has_any_key(*Array(value).map { |x| Arel::Nodes.build_quoted(x) })
195
199
  when :in
196
- attribute.in(convert_filter_value(column, value))
200
+ attribute.in(value)
197
201
  when :intersects
198
202
  # geometry_value = if value.is_a?(Hash) # GeoJSON
199
203
  # Arel::Nodes::NamedFunction.new('ST_GeomFromGeoJSON', [JSON.generate(value)])
@@ -214,24 +218,24 @@ module ActiveRecord
214
218
 
215
219
  Arel::Nodes::NamedFunction.new('ST_Intersects', [attribute, geometry_value])
216
220
  when :less_than, :lt
217
- attribute.lt(convert_filter_value(column, value))
221
+ attribute.lt(value)
218
222
  when :less_than_or_equal_to, :lteq, :lte
219
- attribute.lteq(convert_filter_value(column, value))
223
+ attribute.lteq(value)
220
224
  when :like, :ilike
221
- attribute.matches(convert_filter_value(column, value))
225
+ attribute.matches(value)
222
226
  when :not, :not_equal, :neq
223
- attribute.not_eq(convert_filter_value(column, value))
227
+ attribute.not_eq(value)
224
228
  when :not_in
225
- attribute.not_in(convert_filter_value(column, value))
229
+ attribute.not_in(value)
226
230
  when :overlaps
227
- attribute.overlaps(convert_filter_value(column, value))
231
+ attribute.overlaps(value)
228
232
  when :not_overlaps
229
- attribute.not_overlaps(convert_filter_value(column, value))
233
+ attribute.not_overlaps(value)
230
234
  when :ts_match
231
235
  if value.is_a?(Array)
232
- attribute.ts_query(*convert_filter_value(column, value))
236
+ attribute.ts_query(*value)
233
237
  else
234
- attribute.ts_query(convert_filter_value(column, value))
238
+ attribute.ts_query(value)
235
239
  end
236
240
  when :within
237
241
  if value.is_a?(String)
@@ -250,7 +254,7 @@ module ActiveRecord
250
254
  end
251
255
  end
252
256
 
253
- def expand_filter_for_relationship(relation, value, join_dependency)
257
+ def expand_filter_for_relationship(relation, value)
254
258
  case relation.macro
255
259
  when :has_many
256
260
  if value == true || value == 'true'
@@ -276,27 +280,15 @@ module ActiveRecord
276
280
  end
277
281
  end
278
282
 
279
-
280
-
281
283
  builder = associated_predicate_builder(relation.name.to_sym)
282
-
283
- if join_dependency
284
- join_dependency = join_dependency.children.find { |c| c.reflection.name == relation.name }
285
- builder.send(:table).instance_variable_set(:@arel_table, join_dependency.tables.first)
286
- end
287
-
288
- builder.build_from_filter_hash(value, join_dependency)
284
+ builder.build_from_filter_hash(value)
289
285
  end
290
286
 
291
- def expand_filter_for_join_table(relation, value, join_dependency)
287
+ def expand_filter_for_join_table(relation, value)
292
288
  relation = relation.active_record._reflections[relation.active_record._reflections[relation.name.to_s].send(:delegate_reflection).options[:through].to_s]
293
289
 
294
290
  builder = associated_predicate_builder(relation.name.to_sym)
295
- if join_dependency
296
- join_dependency = join_dependency.children.find { |c| c.reflection.name == relation.name }
297
- builder.send(:table).instance_variable_set(:@arel_table, join_dependency.tables.first)
298
- end
299
- builder.build_from_filter_hash(value, join_dependency)
291
+ builder.build_from_filter_hash(value)
300
292
  end
301
293
 
302
294
  end
@@ -311,14 +303,14 @@ module ActiveRecord
311
303
  @predicate_builder = predicate_builder
312
304
  end
313
305
 
314
- def build(filters, join_dependency)
306
+ def build(filters)
315
307
  if filters.is_a?(Hash) || filters.is_a?(Array)
316
308
  # attributes = predicate_builder.resolve_column_aliases(filters)
317
309
  # attributes = klass.send(:expand_hash_conditions_for_aggregates, attributes)
318
310
  # attributes.stringify_keys!
319
311
  #
320
312
  # attributes, binds = predicate_builder.create_binds(attributes)
321
- parts = [predicate_builder.build_from_filter_hash(filters, join_dependency)]
313
+ parts = [predicate_builder.build_from_filter_hash(filters)]
322
314
  else
323
315
  raise ArgumentError, "Unsupported argument type: #{filters.inspect} (#{filters.class})"
324
316
  end
@@ -338,7 +330,6 @@ class ActiveRecord::Relation
338
330
 
339
331
  def initialize(klass, table: klass.arel_table, predicate_builder: klass.predicate_builder, values: {})
340
332
  @filters = []
341
- @join_dependency = nil
342
333
  super
343
334
  end
344
335
 
@@ -369,9 +360,7 @@ class ActiveRecord::Relation
369
360
 
370
361
  def filter!(filters)
371
362
  js = ActiveRecord::PredicateBuilder.filter_joins(klass, filters)
372
- js.each do |j|
373
- joins!(j) if j.present?
374
- end
363
+ js.each { |j| joins!(j) if j.present? }
375
364
  @filters << filters
376
365
  self
377
366
  end
@@ -385,45 +374,10 @@ class ActiveRecord::Relation
385
374
  build_filters(arel)
386
375
  arel
387
376
  end
388
-
389
- def build_join_query(manager, buckets, join_type, aliases)
390
- buckets.default = []
391
-
392
- association_joins = buckets[:association_join]
393
- stashed_joins = buckets[:stashed_join]
394
- join_nodes = buckets[:join_node].uniq
395
- string_joins = buckets[:string_join].map(&:strip).uniq
396
-
397
- join_list = join_nodes + convert_join_strings_to_ast(string_joins)
398
- alias_tracker = alias_tracker(join_list, aliases)
399
-
400
- join_dependency = ActiveRecord::Associations::JoinDependency.new(
401
- klass, table, association_joins
402
- )
403
-
404
- joins = join_dependency.join_constraints(stashed_joins, join_type, alias_tracker)
405
- joins.each { |join| manager.from(join) }
406
- # join_infos = join_dependency.join_constraints stashed_association_joins, join_type
407
-
408
- # join_infos.each do |info|
409
- # info.joins.each { |join| manager.from(join) }
410
- # manager.bind_values.concat info.binds
411
- # end
412
-
413
- # manager.join_sources.concat(join_list)
414
-
415
- manager.join_sources.concat(join_list)
416
-
417
- if klass.connection.class.name != 'ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter'
418
- @join_dependency = join_dependency
419
- end
420
-
421
- alias_tracker.aliases
422
- end
423
377
 
424
378
  def build_filters(manager)
425
379
  @filters.each do |filters|
426
- manager.where(filter_clause_factory.build(filters, @join_dependency&.send(:join_root)).ast)
380
+ manager.where(filter_clause_factory.build(filters).ast)
427
381
  end
428
382
  end
429
383
 
@@ -1,5 +1,5 @@
1
1
  module ActiveRecord
2
2
  module Filter
3
- VERSION = '6.0.0.1'
3
+ VERSION = '6.0.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.1
4
+ version: 6.0.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: 2019-06-11 00:00:00.000000000 Z
11
+ date: 2019-08-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 6.0.0.rc1
19
+ version: 6.0.0.rc2
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.rc1
26
+ version: 6.0.0.rc2
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: arel-extensions
29
29
  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.rc1
61
+ version: 6.0.0.rc2
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.rc1
68
+ version: 6.0.0.rc2
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.rc1
145
+ version: 6.0.0.rc2
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.rc1
152
+ version: 6.0.0.rc2
153
153
  - !ruby/object:Gem::Dependency
154
154
  name: faker
155
155
  requirement: !ruby/object:Gem::Requirement