aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/relation/predicate_builder
Commit message (Collapse)AuthorAgeFilesLines
* Remove unused `predicate_builder` for `BasicObjectHandler` and `RangeHandler`Ryuta Kamizono2016-07-022-16/+0
|
* Reuse a result of `table.associated_table(column)` in ↵Ryuta Kamizono2016-05-281-2/+3
| | | | `AssociationQueryHandler.value_for`
* Fixed `where` for polymorphic associations when passed an array containing ↵Philippe Huibonhoa2016-02-162-0/+67
| | | | | | | | | | | | | | | | | different types. When passing in an array of different types of objects to `where`, it would only take into account the class of the first object in the array. PriceEstimate.where(estimate_of: [Treasure.find(1), Car.find(2)]) # => SELECT "price_estimates".* FROM "price_estimates" WHERE ("price_estimates"."estimate_of_type" = 'Treasure' AND "price_estimates"."estimate_of_id" IN (1, 2)) This is fixed to properly look for any records matching both type and id: PriceEstimate.where(estimate_of: [Treasure.find(1), Car.find(2)]) # => SELECT "price_estimates".* FROM "price_estimates" WHERE (("price_estimates"."estimate_of_type" = 'Treasure' AND "price_estimates"."estimate_of_id" = 1) OR ("price_estimates"."estimate_of_type" = 'Car' AND "price_estimates"."estimate_of_id" = 2))
* Extract a Relation#arel_attributeMatthew Draper2016-02-041-1/+1
|
* Defer Arel attribute lookup to the model classMatthew Draper2016-02-041-1/+1
| | | | | This still isn't as separated as I'd like, but it at least moves most of the burden of alias mapping in one place.
* Use bind parameters for ranges in where clausesSean Griffin2016-01-211-1/+17
| | | | | | | | | | | | | | This is a similar case to wanting ot use bind params for limit and offset. Right now passing a range grows the amount of prepared statements in an unbounded fashion. We could avoid using prepared statements in that case, similar to what we do with arrays, but there's a known number of variants for ranges. This ends up duplicating some of the logic from Arel for how to handle potentially infinite ranges, and that behavior may be removed from Arel in the future. Fixes #23074
* Reduce calls to stringify_keys.Guo Xiang Tan2015-09-071-2/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Stackprof output truncated. ``` TOTAL (pct) SAMPLES (pct) FRAME 23 (4.7%) 12 (2.4%) Hash#transform_keys 11 (2.2%) 11 (2.2%) block in Hash#transform_keys 30 (6.1%) 7 (1.4%) Hash#stringify_keys ``` Benchmark Script: ``` begin require 'bundler/inline' rescue LoadError => e $stderr.puts 'Bundler version 1.10 or later is required. Please update your Bundler' raise e end gemfile(true) do source 'https://rubygems.org' gem 'rails', path: '~/rails' # master against ref "f1f0a3f8d99aef8aacfa81ceac3880dcac03ca06" gem 'arel', github: 'rails/arel', branch: 'master' gem 'rack', github: 'rack/rack', branch: 'master' gem 'sass' gem 'sprockets-rails', github: 'rails/sprockets-rails', branch: 'master' gem 'sprockets', github: 'rails/sprockets', branch: 'master' gem 'pg' gem 'benchmark-ips' end require 'active_record' require 'benchmark/ips' ActiveRecord::Base.establish_connection('postgres://postgres@localhost:5432/rubybench') ActiveRecord::Migration.verbose = false ActiveRecord::Schema.define do create_table :users, force: true do |t| t.string :name, :email t.timestamps null: false end end class User < ActiveRecord::Base; end attributes = { name: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", email: "foobar@email.com", } 1000.times { User.create!(attributes) } Benchmark.ips(5, 3) do |x| x.report('where with hash') { User.where(name: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.") } x.report('where with string') { User.where("users.name = ?", "Lorem ipsum dolor sit amet, consectetur adipiscing elit.") } x.compare! end key = if RUBY_VERSION < '2.2' :total_allocated_object else :total_allocated_objects end before = GC.stat[key] User.where(name: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.") after = GC.stat[key] puts "Total Allocated Object: #{after - before}" ``` Before: ``` Calculating ------------------------------------- where with hash 2.796k i/100ms where with string 4.338k i/100ms ------------------------------------------------- where with hash 29.177k (± 1.5%) i/s - 148.188k where with string 47.419k (± 2.8%) i/s - 238.590k Comparison: where with string: 47419.0 i/s where with hash: 29176.6 i/s - 1.63x slower Total Allocated Object: 85 ``` After: ``` Calculating ------------------------------------- where with hash 2.895k i/100ms where with string 4.416k i/100ms ------------------------------------------------- where with hash 30.758k (± 2.0%) i/s - 156.330k where with string 47.708k (± 2.6%) i/s - 238.464k Comparison: where with string: 47707.9 i/s where with hash: 30757.7 i/s - 1.55x slower Total Allocated Object: 84 ```
* Respect custom primary keys for associations in `Relation#where`Sean Griffin2015-02-041-1/+21
| | | | | | | | | | While we query the proper columns, we go through normal handling for converting the value to a primitive which assumes it should use the table's primary key. If the association specifies a different value (and we know that we're working with an association), we should use the custom primary key instead. Fixes #18813.
* Remove unneeded requiresRafael Mendonça França2015-01-041-2/+0
| | | | These requires were added only to change deprecation message
* Rely on the injectable type caster for `arel_table`Sean Griffin2014-12-293-23/+1
| | | | | | | This API will require much less consuming code to change to accomodate the removal of automatic type casting from Arel. As long as the predicates are constructed using the `arel_table` off of an AR subclass, there will be no changes that need to happen.
* Eagerly cast array values passed to the predicate builderSean Griffin2014-12-261-1/+6
| | | | | | | | Part of a larger refactoring to remove type casting from Arel. /cc @mrgilman [Sean Griffin & Melanie Gilman]
* Eagerly cast range values in the predicate builderSean Griffin2014-12-261-0/+24
| | | | | | | | | A custom object is required for this, as you cannot build a range object out of `Arel::Nodes::Quoted` objects. Depends on the changes introduced in https://github.com/rails/arel/commit/cf03bd45e39def057a2f63e42a3391b7d750dece /cc @mrgilman
* Perform casting of single values within the predicate builderSean Griffin2014-12-263-2/+27
| | | | | | | | | | | As part of the larger refactoring to remove type casting from Arel, we need to do the casting of values eagerly. The predicate builder is the closest place that knows about the Active Record class, and can therefore have the type information. /cc @mrgilman [Sean Griffin & Melanie Gilman]
* Remove `klass` and `arel_table` as a dependency of `PredicateBuilder`Sean Griffin2014-12-261-6/+7
| | | | | | | | | | | | | | | This class cares far too much about the internals of other parts of Active Record. This is an attempt to break out a meaningful object which represents the needs of the predicate builder. I'm not fully satisfied with the name, but the general concept is an object which represents a table, the associations to/from that table, and the types associated with it. Many of these exist at the `ActiveRecord::Base` class level, not as properties of the table itself, hence the need for another object. Currently it provides these by holding a reference to the class, but that will likely change in the future. This allows the predicate builder to remain wholy concerned with building predicates. /cc @mrgilman
* Refactor association handling in `PredicateBuilder`Sean Griffin2014-12-261-0/+57
| | | | | | | | | | I'm attempting to remove `klass` as a dependency of the predicate builder, in favor of an object that better represents what we're using it for. The only part of this which doesn't fit nicely into that picture is the check for an association being polymorphic. Since I'm not yet sure what that is going to look like, I've moved this logic into another class in an attempt to separate things that will change from things that won't.
* Re-use the predicate builder in the `ArrayHandler`Sean Griffin2014-12-261-3/+11
| | | | | | | | | | This reduces the number of places which will need to care about single value or range specific logic as we introduce type casting. The array handler is only responsible for producing `in` statements. /cc @mrgilman [Sean Griffin & Melanie Gilman]
* Change `PredicateBuilder` handler methods to instance methodsSean Griffin2014-12-264-0/+46
| | | | | | | | | | | | This will allow us to pass the predicate builder into the constructor of these handlers. The procs had to be changed to objects, because the `PredicateBuilder` needs to be marshalable. If we ever decide to make `register_handler` part of the public API, we should come up with a better solution which allows procs. /cc @mrgilman [Sean Griffin & Melanie Gilman]
* Add missing `:nodoc:`Sean Griffin2014-12-261-1/+1
| | | | | We're accidentally documenting `PredicateBuilder` and `ArrayHandler` since there's a constant which is missing `# :nodoc:`
* Remove deprecated behavior allowing nested arrays as query valuesMelanie Gilman2014-12-041-10/+0
|
* Pass the `SelectManager`, rather than the AST when querying w/ RelationSean Griffin2014-11-021-1/+1
| | | | | | Arel specifically handles `SelectManager`, with the same logic we're currently performing. The AST is `Enumerable`, which Arel looks for separately now.
* Use `#between`, rather than `#in` for passing Ranges to ArelSean Griffin2014-10-301-1/+1
| | | | Passing ranges to `#in` has been deprecated in Arel.
* let's warn with heredocsXavier Noria2014-10-281-3/+8
| | | | | | | | | | | | The current style for warning messages without newlines uses concatenation of string literals with manual trailing spaces where needed. Heredocs have better readability, and with `squish` we can still produce a single line. This is a similar use case to the one that motivated defining `strip_heredoc`, heredocs are super clean.
* Fix query with nested array in Active RecordCristian Bica2014-09-061-4/+12
| | | | | | | | `User.where(id: [[1,2],3])` was equal to `User.where(id:[1, 2, 3])` in Rails 4.1.x but because of some refactoring in Arel this stopped working in 4.2.0. This fixes it in Rails. [Dan Olson & Cristian Bica]
* Allow empty arrays in where predicatesSean Griffin2014-05-261-0/+2
|
* Refactor the handling of arrays in where predicatesSean Griffin2014-05-261-11/+14
| | | | | | Simplifies the code slightly, isolates non-nil non-range values into a single array, which will make it easier to do things like apply type casting to them in the future.
* Add ability to specify how a class is converted to Arel predicatesgrif2013-07-282-0/+42
This adds the ability for rails apps or gems to have granular control over how a domain object is converted to sql. One simple use case would be to add support for Regexp. Another simple case would be something like the following: class DateRange < Struct.new(:start, :end) def include?(date) (start..end).cover?(date) end end class DateRangePredicate def call(attribute, range) attribute.in(range.start..range.end) end end ActiveRecord::PredicateBuilder.register_handler(DateRange, DateRangePredicate.new) More complex cases might include taking a currency object and converting it from EUR to USD before performing the query. By moving the existing handlers to this format, we were also able to nicely refactor a rather nasty method in PredicateBuilder.