Commit Graph

235 Commits

Author SHA1 Message Date
Anmol Arora
2a65310890 Clear ActiveRecord object memoized by take 2019-08-20 00:54:03 +05:30
Ryuta Kamizono
c81af6ae72 Enable Layout/EmptyLinesAroundAccessModifier cop
We sometimes say "✂️ newline after `private`" in a code review (e.g.
https://github.com/rails/rails/pull/18546#discussion_r23188776,
https://github.com/rails/rails/pull/34832#discussion_r244847195).

Now `Layout/EmptyLinesAroundAccessModifier` cop have new enforced style
`EnforcedStyle: only_before` (https://github.com/rubocop-hq/rubocop/pull/7059).

That cop and enforced style will reduce the our code review cost.
2019-06-13 12:00:45 +09:00
Ryuta Kamizono
82a54be0c6 Fall back to type casting from the connection adapter
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
```
2019-05-21 23:41:13 +09:00
Ryuta Kamizono
5d858b5d3e Fix sliced IN clauses to be grouped
Follow up of #35838.

And also this refactors `in_clause_length` handling is entirely
integrated in Arel visitor.
2019-04-24 13:35:42 +09:00
Ryuta Kamizono
12a9664ff6 Deprecate where.not working as NOR and will be changed to NAND in Rails 6.1
`where.not` with polymorphic association is partly fixed incidentally at
213796f (refer #33493, #26207, #17010, #16983, #14161), and I've added
test case e9ba12f to avoid lose that fix accidentally in the future.

In Rails 5.2, `where.not(polymorphic: object)` works as expected as
NAND, but `where.not(polymorphic_type: object.class.polymorphic_name,
polymorphic_id: object.id)` still unexpectedly works as NOR.

To will make `where.not` working desiredly as NAND in Rails 6.1, this
deprecates `where.not` working as NOR. If people want to continue NOR
conditions, we'd encourage to them to `where.not` each conditions
manually.

```ruby
all = [treasures(:diamond), treasures(:sapphire), cars(:honda), treasures(:sapphire)]
assert_equal all, PriceEstimate.all.map(&:estimate_of)
```

In Rails 6.0:

```ruby
sapphire = treasures(:sapphire)

nor = all.reject { |e|
  e.estimate_of_type == sapphire.class.polymorphic_name
}.reject { |e|
  e.estimate_of_id == sapphire.id
}
assert_equal [cars(:honda)], nor

without_sapphire = PriceEstimate.where.not(
  estimate_of_type: sapphire.class.polymorphic_name, estimate_of_id: sapphire.id
)
assert_equal nor, without_sapphire.map(&:estimate_of)
```

In Rails 6.1:

```ruby
sapphire = treasures(:sapphire)

nand = all - [sapphire]
assert_equal [treasures(:diamond), cars(:honda)], nand

without_sapphire = PriceEstimate.where.not(
  estimate_of_type: sapphire.class.polymorphic_name, estimate_of_id: sapphire.id
)
assert_equal nand, without_sapphire.map(&:estimate_of)
```

Resolves #31209.
2019-04-19 13:49:31 +09:00
Ryuta Kamizono
824ea8d06f Add missing touch_all delegation to relation
Follow up of #31513.
2019-04-05 16:13:40 +09:00
Ryuta Kamizono
8f05035b7e Stash left_joins into joins to deduplicate redundant LEFT JOIN
Originally the `JoinDependency` has the deduplication for eager loading
(LEFT JOIN). This re-uses that deduplication for `left_joins`.

And also, This makes left join order into part of joins, i.e.:

Before:

```
association joins -> stash joins (eager loading, etc) -> string joins -> left joins
```

After:

```
association joins -> stash joins (eager loading, left joins, etc) -> string joins
```

Now string joins are able to refer left joins.

Fixes #34325.
Fixes #34332.
Fixes #34536.
2019-04-05 06:40:53 +09:00
Ryuta Kamizono
6e43a207c6 Revert unused code and re-using query annotation for update_all and delete_all
This partly reverts #35617.

#35617 includes unused code (for `InsertStatement`) and re-using query
annotation for `update_all` and `delete_all`, which has not been
discussed yet.

If a relation has any annotation, I think it is mostly for SELECT query,
so re-using annotation by default is not always desired behavior for me.

We should discuss about desired behavior before publishing the
implementation.
2019-04-01 15:04:11 +09:00
Matt Yoho
f41825809c Add Relation#annotate for SQL commenting
This patch has two main portions:

1. Add SQL comment support to Arel via Arel::Nodes::Comment.
2. Implement a Relation#annotate method on top of that.

== Adding SQL comment support

Adds a new Arel::Nodes::Comment node that represents an optional SQL
comment and teachers the relevant visitors how to handle it.

Comment nodes may be added to the basic CRUD statement nodes and set
through any of the four (Select|Insert|Update|Delete)Manager objects.

For example:

    manager = Arel::UpdateManager.new
    manager.table table
    manager.comment("annotation")
    manager.to_sql # UPDATE "users" /* annotation */

This new node type will be used by ActiveRecord::Relation to enable
query annotation via SQL comments.

== Implementing the Relation#annotate method

Implements `ActiveRecord::Relation#annotate`, which accepts a comment
string that will be appeneded to any queries generated by the relation.

Some examples:

    relation = Post.where(id: 123).annotate("metadata string")
    relation.first
    # SELECT "posts".* FROM "posts" WHERE "posts"."id" = 123
    # LIMIT 1 /* metadata string */

    class Tag < ActiveRecord::Base
      scope :foo_annotated, -> { annotate("foo") }
    end
    Tag.foo_annotated.annotate("bar").first
    # SELECT "tags".* FROM "tags" LIMIT 1 /* foo */ /* bar */

Also wires up the plumbing so this works with `#update_all` and
`#delete_all` as well.

This feature is useful for instrumentation and general analysis of
queries generated at runtime.
2019-03-21 20:30:56 -07:00
Ryuta Kamizono
8309706239 Delegate only query method to relation as with except
I've found the skewness of delegation methods between `except` and
`only` in a88b6f2.

The `only` method is closely similar with `except` as `SpawnMethods`.

e056b9bfb0/activerecord/lib/active_record/relation/spawn_methods.rb (L53-L67)

It is preferable both behaves the same way.
2019-03-07 19:11:43 +09:00
Ryuta Kamizono
a88b6f257b Refactor AR::Querying to extract QUERYING_METHODS list
This makes to ease testing `QUERYING_METHODS`.
2019-03-07 18:30:41 +09:00
Abhay Nikam
82b0ff03b1 Fixed reselect throwing NoMethodError on ActiveRecord. 2019-03-03 22:25:10 +05:30
Yasuo Honda
417c251928 Oracle database can run delete statement with order by andfetch first n rows only
Since https://github.com/rails/arel/pull/337 Oracle adapter uses better
top N query using `fetch first n rows only`, which can remove this
unless condition.

* This commit passes with Oracle database
```ruby
$ ARCONN=oracle bin/test test/cases/relation/delete_all_test.rb -n test_delete_all_with_order_and_limit_deletes_subset_only
Using oracle
Run options: -n test_delete_all_with_order_and_limit_deletes_subset_only --seed 1081

.

Finished in 8.068626s, 0.1239 runs/s, 0.6197 assertions/s.
1 runs, 5 assertions, 0 failures, 0 errors, 0 skips
$
```

* SQL statement includes `ORDER BY` and `FETCH FIRST n ROWS ONLY`

```sql
  Post Destroy (12.5ms)  DELETE FROM "POSTS" WHERE "POSTS"."ID" IN (SELECT "POSTS"."ID" FROM "POSTS" WHERE "POSTS"."AUTHOR_ID" = :a1 ORDER BY "POSTS"."ID" ASC FETCH FIRST :a2 ROWS ONLY)  [["author_id", 1], ["LIMIT", 1]]
```
2019-03-03 05:38:09 +00:00
Andrew White
0c4bf982e8
Merge pull request #33611 from willianveiga/feature/reselect-method
Add reselect method
2019-03-01 08:33:01 +00:00
Ryuta Kamizono
66d40abff5
Merge pull request #35352 from kamipo/update_all_doesnt_care_optimistic_locking
Ensure `update_all` series doesn't care optimistic locking
2019-02-25 20:49:07 +09:00
Ryuta Kamizono
1d8fad6f90 Ensure update_all series cares about optimistic locking
Incrementing the lock version invalidates any other process's optimistic
lock, which is the desired outcome: the record no longer looks the same
as it did when they loaded it.
2019-02-25 20:14:56 +09:00
Ryuta Kamizono
a99e00452b Remove duplicated protected params definitions
Use "support/stubs/strong_parameters" instead.
2019-02-24 19:50:53 +09:00
Ryuta Kamizono
357cd23d3a Don't allow where with non numeric string matches to 0 values
This is a follow-up of #35310.

Currently `Topic.find_by(id: "not-a-number")` matches to a `id = 0`
record. That is considered as silently leaking information.

If non numeric string is given to find by an integer column, it should
not be matched to any record.

Related #12793.
2019-02-20 22:00:56 +09:00
Abhay Nikam
002f55e795 Add delegation tests for delete_by and destroy_by methods 2019-02-20 09:30:31 +05:30
Ryuta Kamizono
b09d8f6bb3 Don't allow where with invalid value matches to nil values
That is considered as silently leaking information.
If type casting doesn't return any actual value, it should not be
matched to any record.

Fixes #33624.
Closes #33946.
2019-02-18 16:57:10 +09:00
Ryuta Kamizono
311f001167 Fix order with custom attributes
This follows up 0ee96d13de29680e148ccb8e5b68025f29fd091c.
2019-02-17 02:44:37 +09:00
Ryuta Kamizono
0f3e8e1ebb Relation no longer respond to Arel methods
This follows up d97980a16d76ad190042b4d8578109714e9c53d0.
2019-02-06 04:58:45 +09:00
Ryuta Kamizono
31ffbf8d50 All of queries should return correct result even if including large number
Currently several queries cannot return correct result due to incorrect
`RangeError` handling.

First example:

```ruby
assert_equal true, Topic.where(id: [1, 9223372036854775808]).exists?
assert_equal true, Topic.where.not(id: 9223372036854775808).exists?
```

The first example is obviously to be true, but currently it returns
false.

Second example:

```ruby
assert_equal topics(:first), Topic.where(id: 1..9223372036854775808).find(1)
```

The second example also should return the object, but currently it
raises `RecordNotFound`.

It can be seen from the examples, the queries including large number
assuming empty result is not always correct.

Therefore, This change handles `RangeError` to generate executable SQL
instead of raising `RangeError` to users to always return correct
result. By this change, it is no longer raised `RangeError` to users.
2019-01-18 16:01:07 +09:00
Rafael Mendonça França
d97980a16d
Remove delegation of missing methods in a relation to arel 2019-01-17 16:08:32 -05:00
Ryuta Kamizono
892e38c78e Enable Style/RedundantBegin cop to avoid newly adding redundant begin block
Currently we sometimes find a redundant begin block in code review
(e.g. https://github.com/rails/rails/pull/33604#discussion_r209784205).

I'd like to enable `Style/RedundantBegin` cop to avoid that, since
rescue/else/ensure are allowed inside do/end blocks in Ruby 2.5
(https://bugs.ruby-lang.org/issues/12906), so we'd probably meets with
that situation than before.
2018-12-21 06:12:42 +09:00
Dmytro Shteflyuk
b5302d5a82 Arel: Implemented DB-aware NULL-safe comparison (#34451)
* Arel: Implemented DB-aware NULL-safe comparison

* Fixed where clause inversion for NULL-safe comparison

* Renaming "null_safe_eq" to "is_not_distinct_from", "null_safe_not_eq" to "is_distinct_from"

[Dmytro Shteflyuk + Rafael Mendonça França]
2018-11-15 14:49:55 -05:00
Willian Gustavo Veiga
2d4df1349e Merge branch 'master' into feature/reselect-method 2018-10-02 12:57:37 -03:00
Bogdan Gusiev
d76e3e1280 Bugfix ActiveRecord::Relation#merge special case of from clause
When one relation is merged into another that has a different base class
merging `from_clause` causes invalid SQL to be generated
2018-09-28 11:46:40 +03:00
Ryuta Kamizono
d681adbbb5 Use table name qualified column name for update counters
MySQL supports JOINs to UPDATE, so if column name isn't qualified by
table name, it would cause an ambiguous error:

```
Mysql2::Error: Column 'integer' in field list is ambiguous: UPDATE `pets` INNER JOIN `toys` ON `toys`.`pet_id` = `pets`.`pet_id` SET `integer` = COALESCE(`integer`, 0) + 1 WHERE `toys`.`name` = ?
```
2018-09-16 08:57:09 +09:00
Ryuta Kamizono
68d6c1353a Extract {update,delete}_all_test.rb from persistence_test.rb and relations_test.rb
`persistence_test.rb` and `relations_test.rb` have too many lines, so
I'd like to extract relation around tests to dedicated files before
newly test added.
2018-09-16 08:41:08 +09:00
Kevin Deisz
7c9751d7fe
Permit list usage cleanup and clearer documentation 2018-08-27 09:51:46 -04:00
Kevin Deisz
0efecd913c
Convert remaining usage of whitelist and blacklist 2018-08-24 16:16:41 -04:00
Ryuta Kamizono
96cd16bdee Fix merging relation that order including ?
The `Relation::Merger` has a problem that order values would be merged
as nested array.

That was caused an issue #33664 since if array value is passed to
`order` and first element in the array includes `?`, the array is
regarded as a prepared statement and bind variables.

https://api.rubyonrails.org/classes/ActiveRecord/Sanitization/ClassMethods.html#method-i-sanitize_sql_for_order

Just merging that as splat args like other values would fix the issue.

Fixes #33664.
2018-08-21 00:01:38 +09:00
Willian Gustavo Veiga
00c50c2b59 Add reselect method 2018-08-13 22:19:39 -03:00
Kazuhiro Sera
52919f3d13 Fix the obvious typos detected by github.com/client9/misspell 2018-08-08 21:55:46 +09:00
Graham Turner
bc62f2a3be get_value needs to be a public method
Adds test case for failing issue

Moves set_value back to protected
2018-04-25 06:29:03 -04:00
James Williams
28ef2de229 Fix relation merging with skip_query_cache! 2018-04-19 09:42:55 -06:00
Lachlan Sylvester
115bbdac2b don't check for immutability when setting skip_preloading as it doesn't effect the arel and the arel may already be generated by fresh_when 2018-04-12 10:17:31 +10:00
Ryuta Kamizono
a481603480 Add QueryingMethodsDelegationTest to cover query methods delegation
It makes to ease to detect a future regression as long as the methods
are covered by this test.
2018-03-22 03:12:03 +09:00
Lachlan Sylvester
d04a32fe67 Only preload misses on multifetch cache 2018-03-06 14:10:45 +11:00
Matthew Draper
a2a752d102
Merge pull request #31133 from mohsen-alizadeh/sanitize_empty_and_nil_parameters_passed_to_select
sanitize empty and nil parameters to select #31059
2018-02-11 19:37:10 +10:30
Daniel Colson
82c39e1a0b Use assert_empty and assert_not_empty 2018-01-25 23:32:59 -05:00
Daniel Colson
94333a4c31 Use assert_predicate and assert_not_predicate 2018-01-25 23:32:59 -05:00
Daniel Colson
211adb47e7 Change refute to assert_not 2018-01-25 23:32:58 -05:00
Daniel Colson
6928950def Avoid passing unnecessary arguments to relation
Most of the time the table and predicate_builder
passed to Relation.new are exactly the
arel_table and predicate builder of the
given klass. This uses klass.arel_table
and klass.predicate_builder as the defaults,
so we don't have to pass them in most cases.

This does change the signaure of both Relation and
AssocationRelation. Are we ok with that?
2018-01-24 16:49:35 -05:00
Mehmet Emin INAC
899a801413
Fix relation merger issue with left_outer_joins 2018-01-15 16:06:00 +01:00
Yasuo Honda
6c6c3fa166 Suppress warning: BigDecimal.new is deprecated in activerecord
`BigDecimal.new` has been deprecated in BigDecimal 1.3.3
 which will be a default for Ruby 2.5.

Refer 533737338d

```
$ cd rails/activerecord/
$ git grep -l BigDecimal.new | grep \.rb | xargs sed -i -e "s/BigDecimal.new/BigDecimal/g"
```

- Changes made only to Active Record. Will apply the same change to
other module once this commit is merged.

- The following deprecation has not been addressed because it has been
reported at `ActiveRecord::Result.new`. `ActiveRecord::Result.ancestors`
did not show `BigDecimal`.

* Not addressed

```ruby
/path/to/rails/activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb:34:
warning: BigDecimal.new is deprecated
```

* database_statements.rb:34

```ruby
ActiveRecord::Result.new(result.fields, result.to_a) if result
```

* ActiveRecord::Result.ancestors

```ruby
[ActiveRecord::Result,
 Enumerable,
 ActiveSupport::ToJsonWithActiveSupportEncoder,
 Object,
 Metaclass::ObjectMethods,
 Mocha::ObjectMethods,
 PP::ObjectMixin,
 ActiveSupport::Dependencies::Loadable,
 ActiveSupport::Tryable,
 JSON::Ext::Generator::GeneratorMethods::Object,
 Kernel,
 BasicObject]
```

This commit has been tested with these Ruby and BigDecimal versions

- ruby 2.5 and bigdecimal 1.3.3

```
$ ruby -v
ruby 2.5.0dev (2017-12-14 trunk 61217) [x86_64-linux]
$ gem list |grep bigdecimal
bigdecimal (default: 1.3.3, default: 1.3.2)
```

- ruby 2.4 and bigdecimal 1.3.0

```
$ ruby -v
ruby 2.4.2p198 (2017-09-14 revision 59899) [x86_64-linux-gnu]
$ gem list |grep bigdecimal
bigdecimal (default: 1.3.0)
```

- ruby 2.3 and bigdecimal 1.2.8

```
$ ruby -v
ruby 2.3.5p376 (2017-09-14 revision 59905) [x86_64-linux]
$ gem list |grep -i bigdecimal
bigdecimal (1.2.8)
```

- ruby 2.2 and bigdecimal 1.2.6
```
$ ruby -v
ruby 2.2.8p477 (2017-09-14 revision 59906) [x86_64-linux]
$ gem list |grep bigdecimal
bigdecimal (1.2.6)
```
2017-12-13 21:29:06 +00:00
Mohsen Alizadeh
ccbba22938 add test case to relation select 2017-12-03 15:16:52 +03:30
Yasuo Honda
aaed081e08 Address random test_or_with_bind_params failures
Reported at https://travis-ci.org/rails/rails/jobs/274370258

- `Post.find([1, 2])` generates this query below:
```sql
SELECT "posts".* FROM "posts" WHERE "posts"."id" IN ($1, $2)  [["id", 1], ["id", 2]]
```

- `Post.where(id: 1).or(Post.where(id: 2)).to_a` generates this query below:
```sql
SELECT "posts".* FROM "posts" WHERE ("posts"."id" = $1 OR "posts"."id" = $2)  [["id", 1], ["id", 2]]
```

Most of the time these two queries return the same result but the order of records are not guaranteed
from SQL point of view then added `sort` before comparing them.
2017-09-13 22:55:13 +00:00
Matthew Draper
7721f23e86 Merge pull request #30377 from keepcosmos/delegate-missing-methods
Delegate :rindex, :slice, :rotate(missing) to 'records'
2017-08-31 15:49:47 +09:30