| Commit message (Collapse) | Author | Age | Files | Lines |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Unfortunately, a11a8ff had no effect as long as using bind param, and
was not tested.
This ensures making the intent of a11a8ff, which fall back to type
casting from the connection adapter.
Fixes #35205.
```
% ARCONN=postgresql bundle exec ruby -w -Itest test/cases/relation/where_test.rb -n test_type_casting_nested_joins
Using postgresql
Run options: -n test_type_casting_nested_joins --seed 55730
# Running:
E
Error:
ActiveRecord::WhereTest#test_type_casting_nested_joins:
ActiveRecord::StatementInvalid: PG::InvalidTextRepresentation: ERROR: invalid input syntax for integer: "2-foo"
rails test test/cases/relation/where_test.rb:30
Finished in 0.245778s, 4.0687 runs/s, 0.0000 assertions/s.
1 runs, 0 assertions, 0 failures, 1 errors, 0 skips
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
If we want to get alias resolved attribute finally, we can use
`attribute_alias` directly.
For that purpose, avoiding redundant `attribute_alias?` makes alias
attribute access 40% faster.
https://gist.github.com/kamipo/e427f080a27b46f50bc508fae3612a0e
Before (2c0729d8):
```
Warming up --------------------------------------
user['id'] 102.668k i/100ms
user['new_id'] 80.660k i/100ms
user['name'] 99.368k i/100ms
user['new_name'] 81.626k i/100ms
Calculating -------------------------------------
user['id'] 1.431M (± 4.0%) i/s - 7.187M in 5.031985s
user['new_id'] 1.042M (± 4.2%) i/s - 5.243M in 5.039858s
user['name'] 1.406M (± 5.6%) i/s - 7.055M in 5.036743s
user['new_name'] 1.074M (± 3.6%) i/s - 5.387M in 5.024152s
```
After (this change):
```
Warming up --------------------------------------
user['id'] 109.775k i/100ms
user['new_id'] 103.303k i/100ms
user['name'] 105.988k i/100ms
user['new_name'] 99.618k i/100ms
Calculating -------------------------------------
user['id'] 1.520M (± 6.7%) i/s - 7.574M in 5.011496s
user['new_id'] 1.485M (± 6.2%) i/s - 7.438M in 5.036252s
user['name'] 1.538M (± 5.4%) i/s - 7.737M in 5.049765s
user['new_name'] 1.516M (± 4.6%) i/s - 7.571M in 5.007293s
```
|
| |
|
|
|
|
|
|
|
| |
With #31615 `type_for_attribute` accepts either
a symbol as well as a string. `has_attribute?` and `attribute_alias`
also accept either. Since these methods call `to_s` on the argument,
we no longer need to do that at the call site.
|
|
|
|
|
|
|
|
|
| |
Follow up of #31724.
If `composed_of` objects have multiple mappings, array predicate handler
can not correctly handle the expanded condition.
We need to handle it like polymorphic association objects.
|
|
|
|
|
|
|
| |
`association_primary_key` in `TableMetadata`
Because `join_primary_key` is called by `join_keys` and it is to
abstract calling `association_primary_key`.
|
| |
|
|
|
|
|
|
| |
has many association wrong set of primary key and foreign key are selected.
Changed code to use 'join' primary key and foreign key over 'association' primary key and foreign key.
|
| |
|
|
|
|
|
| |
This reverts commit 3420a14590c0e6915d8b6c242887f74adb4120f9, reversing
changes made to afb66a5a598ce4ac74ad84b125a5abf046dcf5aa.
|
| |
|
|
|
|
| |
Avoids a NoMethodError when table_name is a symbol instead of a string.
|
| |
|
|\
| |
| | |
Add `Type.default_value` and use it everywhere for internal
|
| |
| |
| |
| | |
For reduce instantiating `Type::Value`.
|
|/
|
|
| |
Follow up to #26301.
|
|
|
|
|
|
| |
If handled as an associated predicate even though a table has the
column, will generate invalid SQL by valid column name treated as a
table name.
|
| |
|
|
|
|
|
|
|
| |
`AssociationQueryHandler` requires `association` initialized
`TableMetadata` even if `table_name == arel_table.name`.
Fixes #25689.
|
|
|
|
| |
Fixes #25128
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Benchmark Script Used:
```
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 single') { User.where(name: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.") }
x.report('where with string single') { User.where("users.name = ?", "Lorem ipsum dolor sit amet, consectetur adipiscing elit.") }
x.report('where with hash double') { User.where(name: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", email: "foobar@email.com") }
x.report('where with string double') { User.where("users.name = ? AND users.email = ?", "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", "foobar@email.com") }
x.compare!
end
```
Before:
```
Calculating -------------------------------------
where with hash single
3.300k i/100ms
where with string single
4.965k i/100ms
where with hash double
2.594k i/100ms
where with string double
4.400k i/100ms
-------------------------------------------------
where with hash single
35.161k (± 1.2%) i/s - 178.200k
where with string single
53.368k (± 2.9%) i/s - 268.110k
where with hash double
27.364k (± 1.1%) i/s - 137.482k
where with string double
46.876k (± 2.1%) i/s - 237.600k
Comparison:
where with string single: 53368.1 i/s
where with string double: 46875.5 i/s - 1.14x slower
where with hash single: 35160.8 i/s - 1.52x slower
where with hash double: 27364.0 i/s - 1.95x slower
```
After:
```
Calculating -------------------------------------
where with hash single
3.403k i/100ms
where with string single
5.167k i/100ms
where with hash double
2.659k i/100ms
where with string double
4.597k i/100ms
-------------------------------------------------
where with hash single
36.410k (± 1.3%) i/s - 183.762k
where with string single
55.009k (± 2.6%) i/s - 279.018k
where with hash double
27.951k (± 1.4%) i/s - 140.927k
where with string double
48.362k (± 2.6%) i/s - 243.641k
Comparison:
where with string single: 55008.6 i/s
where with string double: 48361.5 i/s - 1.14x slower
where with hash single: 36410.1 i/s - 1.51x slower
where with hash double: 27950.9 i/s - 1.97x slower
```
|
|
|
|
| |
Related with #20418
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
With this change, we will always assume the association name is the same
as the table it's referencing. This is subtly different than treating
the hash key passed to `where` as the table name, as it still allows the
class referenced by the association to provide additional type
information.
After exploring several possible solutions to the ambiguity problem, I
do not think there is a short term answer that will maintain backwards
compatibility.
This change will make it so the following code does not work:
class User
has_many :approved_posts, -> { where(approved: true) }, class_name: "Post"
end
User.where(approved_posts: { id: 1 })
But prevents potential ambiguity and collision as demonstrated in [this
gist](https://gist.github.com/senny/1ae4d8ea7b0e269ed7a0).
Unfortunately, truely solving this requires significantly
re-architecting this code, so that what is currently represented as an
`Arel::Attribute` is instead another data structure that also references
the association it is representing, so we can identify the proper table
name for aliasing when we construct the final tree.
While I'd still like to accomplish that in the long run, I don't think
I'll be able to get there in time for Rails 5 (since I'm not full time
OSS any more, and this is several weeks worth of work). I'm hoping to
achieve this for Rails 5.1.
Fixes #20308
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
|
| |
The column is primarily used for type casting, which we're trying to
separate from the idea of a column. Since what we really need is the
combination of a name, type, and value, let's use the object that we
already have to represent that concept, rather than this tuple. No
consumers of the bind values have been changed, only the producers
(outside of tests which care too much about internals). This is
*finally* possible since the bind values are now produced from a
reasonable number of lcoations.
|
|
|
|
|
|
|
|
|
|
|
|
| |
This removes the need to duplicate much of the logic in `WhereClause`
and `PredicateBuilder`, simplifies the code, removes the need for the
connection adapter to be continuously passed around, and removes one
place that cares about the internal representation of `bind_values`
Part of the larger refactoring to change how binds are represented
internally
[Sean Griffin & anthonynavarre]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This will allow all types which require no additional handling to use
prepared statements. Specifically, this will allow for `true`, `false`,
`Date`, `Time`, and any custom PG type to use prepared statements. This
also revealed another source of nil columns in bind params, and an
inconsistency in their use.
The specific inconsistency comes from a nested query coming from a
through association, where one of the inversed associations is not
bi-directional.
The stop-gap is to simply construct the column at the site it is being
used. This should simply go away on its own once we use `Attribute` to
represent them instead, since we already have all of the information we
need.
|
|
|
|
|
|
| |
I'm looking to introduce a `WhereClause` class to handle most of this
logic, and this method will eventually move over to there. However, this
intermediate refactoring should make that easier to do.
|
| |
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
There are several valid cases where right now we can't determine the
association's class in a call to `where`. In these cases, we can fall
back to casting by looking up the column from the connection adapter
(which is what happens right now when we fall through to Arel)
This is ugly, and since we're trying to separate the concept of a type
from a column, I'd like to remove it in the future. The problem
basically comes down to this:
Liquid.joins(molecules: :electrons)
.where("molecules.name" => "something", "electrons.name" => "something")
The hash in this case will turn into:
{
molecules: { name: "something" },
electrons: { name: "something" },
}
What we actually need is:
{
molecules: {
name: "something",
electrons: { name: "something" },
}
}
/cc @mrgilman
|
|
|
|
|
|
|
|
|
|
|
| |
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]
|
|
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
|