Merge pull request #31966 from kg8m/fix_limited_ids_for

Use column alias of primary_key in limited_ids_for
This commit is contained in:
Ryuta Kamizono 2018-02-28 00:46:52 +09:00
commit 6717d6027c
6 changed files with 30 additions and 17 deletions

@ -1,5 +1,13 @@
## Rails 6.0.0.alpha (Unreleased) ## ## Rails 6.0.0.alpha (Unreleased) ##
* Fix `#columsn_for_distinct` of MySQL and PostgreSQL to make
`ActiveRecord::FinderMethods#limited_ids_for` use correct primary key values
even if `ORDER BY` columns include other table's primary key.
Fixes #28364.
*Takumi Kagiyama*
* Make `reflection.klass` raise if `polymorphic?` not to be misused. * Make `reflection.klass` raise if `polymorphic?` not to be misused.
Fixes #31876. Fixes #31876.

@ -513,7 +513,7 @@ def columns_for_distinct(columns, orders) # :nodoc:
s.gsub(/\s+(?:ASC|DESC)\b/i, "") s.gsub(/\s+(?:ASC|DESC)\b/i, "")
}.reject(&:blank?).map.with_index { |column, i| "#{column} AS alias_#{i}" } }.reject(&:blank?).map.with_index { |column, i| "#{column} AS alias_#{i}" }
[super, *order_columns].join(", ") (order_columns << super).join(", ")
end end
def strict_mode? def strict_mode?

@ -583,7 +583,7 @@ def columns_for_distinct(columns, orders) #:nodoc:
.gsub(/\s+NULLS\s+(?:FIRST|LAST)\b/i, "") .gsub(/\s+NULLS\s+(?:FIRST|LAST)\b/i, "")
}.reject(&:blank?).map.with_index { |column, i| "#{column} AS alias_#{i}" } }.reject(&:blank?).map.with_index { |column, i| "#{column} AS alias_#{i}" }
[super, *order_columns].join(", ") (order_columns << super).join(", ")
end end
def update_table_definition(table_name, base) # :nodoc: def update_table_definition(table_name, base) # :nodoc:

@ -25,25 +25,25 @@ def test_columns_for_distinct_zero_orders
end end
def test_columns_for_distinct_one_order def test_columns_for_distinct_one_order
assert_equal "posts.id, posts.created_at AS alias_0", assert_equal "posts.created_at AS alias_0, posts.id",
@conn.columns_for_distinct("posts.id", ["posts.created_at desc"]) @conn.columns_for_distinct("posts.id", ["posts.created_at desc"])
end end
def test_columns_for_distinct_few_orders def test_columns_for_distinct_few_orders
assert_equal "posts.id, posts.created_at AS alias_0, posts.position AS alias_1", assert_equal "posts.created_at AS alias_0, posts.position AS alias_1, posts.id",
@conn.columns_for_distinct("posts.id", ["posts.created_at desc", "posts.position asc"]) @conn.columns_for_distinct("posts.id", ["posts.created_at desc", "posts.position asc"])
end end
def test_columns_for_distinct_with_case def test_columns_for_distinct_with_case
assert_equal( assert_equal(
"posts.id, CASE WHEN author.is_active THEN UPPER(author.name) ELSE UPPER(author.email) END AS alias_0", "CASE WHEN author.is_active THEN UPPER(author.name) ELSE UPPER(author.email) END AS alias_0, posts.id",
@conn.columns_for_distinct("posts.id", @conn.columns_for_distinct("posts.id",
["CASE WHEN author.is_active THEN UPPER(author.name) ELSE UPPER(author.email) END"]) ["CASE WHEN author.is_active THEN UPPER(author.name) ELSE UPPER(author.email) END"])
) )
end end
def test_columns_for_distinct_blank_not_nil_orders def test_columns_for_distinct_blank_not_nil_orders
assert_equal "posts.id, posts.created_at AS alias_0", assert_equal "posts.created_at AS alias_0, posts.id",
@conn.columns_for_distinct("posts.id", ["posts.created_at desc", "", " "]) @conn.columns_for_distinct("posts.id", ["posts.created_at desc", "", " "])
end end
@ -52,7 +52,7 @@ def test_columns_for_distinct_with_arel_order
def order.to_sql def order.to_sql
"posts.created_at desc" "posts.created_at desc"
end end
assert_equal "posts.id, posts.created_at AS alias_0", assert_equal "posts.created_at AS alias_0, posts.id",
@conn.columns_for_distinct("posts.id", [order]) @conn.columns_for_distinct("posts.id", [order])
end end

@ -263,25 +263,25 @@ def test_columns_for_distinct_zero_orders
end end
def test_columns_for_distinct_one_order def test_columns_for_distinct_one_order
assert_equal "posts.id, posts.created_at AS alias_0", assert_equal "posts.created_at AS alias_0, posts.id",
@connection.columns_for_distinct("posts.id", ["posts.created_at desc"]) @connection.columns_for_distinct("posts.id", ["posts.created_at desc"])
end end
def test_columns_for_distinct_few_orders def test_columns_for_distinct_few_orders
assert_equal "posts.id, posts.created_at AS alias_0, posts.position AS alias_1", assert_equal "posts.created_at AS alias_0, posts.position AS alias_1, posts.id",
@connection.columns_for_distinct("posts.id", ["posts.created_at desc", "posts.position asc"]) @connection.columns_for_distinct("posts.id", ["posts.created_at desc", "posts.position asc"])
end end
def test_columns_for_distinct_with_case def test_columns_for_distinct_with_case
assert_equal( assert_equal(
"posts.id, CASE WHEN author.is_active THEN UPPER(author.name) ELSE UPPER(author.email) END AS alias_0", "CASE WHEN author.is_active THEN UPPER(author.name) ELSE UPPER(author.email) END AS alias_0, posts.id",
@connection.columns_for_distinct("posts.id", @connection.columns_for_distinct("posts.id",
["CASE WHEN author.is_active THEN UPPER(author.name) ELSE UPPER(author.email) END"]) ["CASE WHEN author.is_active THEN UPPER(author.name) ELSE UPPER(author.email) END"])
) )
end end
def test_columns_for_distinct_blank_not_nil_orders def test_columns_for_distinct_blank_not_nil_orders
assert_equal "posts.id, posts.created_at AS alias_0", assert_equal "posts.created_at AS alias_0, posts.id",
@connection.columns_for_distinct("posts.id", ["posts.created_at desc", "", " "]) @connection.columns_for_distinct("posts.id", ["posts.created_at desc", "", " "])
end end
@ -290,23 +290,23 @@ def test_columns_for_distinct_with_arel_order
def order.to_sql def order.to_sql
"posts.created_at desc" "posts.created_at desc"
end end
assert_equal "posts.id, posts.created_at AS alias_0", assert_equal "posts.created_at AS alias_0, posts.id",
@connection.columns_for_distinct("posts.id", [order]) @connection.columns_for_distinct("posts.id", [order])
end end
def test_columns_for_distinct_with_nulls def test_columns_for_distinct_with_nulls
assert_equal "posts.title, posts.updater_id AS alias_0", @connection.columns_for_distinct("posts.title", ["posts.updater_id desc nulls first"]) assert_equal "posts.updater_id AS alias_0, posts.title", @connection.columns_for_distinct("posts.title", ["posts.updater_id desc nulls first"])
assert_equal "posts.title, posts.updater_id AS alias_0", @connection.columns_for_distinct("posts.title", ["posts.updater_id desc nulls last"]) assert_equal "posts.updater_id AS alias_0, posts.title", @connection.columns_for_distinct("posts.title", ["posts.updater_id desc nulls last"])
end end
def test_columns_for_distinct_without_order_specifiers def test_columns_for_distinct_without_order_specifiers
assert_equal "posts.title, posts.updater_id AS alias_0", assert_equal "posts.updater_id AS alias_0, posts.title",
@connection.columns_for_distinct("posts.title", ["posts.updater_id"]) @connection.columns_for_distinct("posts.title", ["posts.updater_id"])
assert_equal "posts.title, posts.updater_id AS alias_0", assert_equal "posts.updater_id AS alias_0, posts.title",
@connection.columns_for_distinct("posts.title", ["posts.updater_id nulls last"]) @connection.columns_for_distinct("posts.title", ["posts.updater_id nulls last"])
assert_equal "posts.title, posts.updater_id AS alias_0", assert_equal "posts.updater_id AS alias_0, posts.title",
@connection.columns_for_distinct("posts.title", ["posts.updater_id nulls first"]) @connection.columns_for_distinct("posts.title", ["posts.updater_id nulls first"])
end end

@ -1189,6 +1189,11 @@ def test_find_with_order_on_included_associations_with_construct_finder_sql_for_
order("author_addresses_authors.id DESC").limit(3).to_a.size order("author_addresses_authors.id DESC").limit(3).to_a.size
end end
def test_find_with_eager_loading_collection_and_ordering_by_collection_primary_key
assert_equal Post.first, Post.eager_load(comments: :ratings).
order("posts.id, ratings.id, comments.id").first
end
def test_find_with_nil_inside_set_passed_for_one_attribute def test_find_with_nil_inside_set_passed_for_one_attribute
client_of = Company. client_of = Company.
where(client_of: [2, 1, nil], where(client_of: [2, 1, nil],