mirror of https://github.com/rails/rails
Merge pull request #45586 from eileencodes/check-for-cte-support
Fix cases where CTE's are not supported
This commit is contained in:
commit
e7633661b1
|
@ -326,6 +326,9 @@ module ActiveRecord
|
|||
|
||||
# Add a Common Table Expression (CTE) that you can then reference within another SELECT statement.
|
||||
#
|
||||
# Note: CTE's are only supported in MySQL for versions 8.0 and above. You will not be able to
|
||||
# use CTE's with MySQL 5.7.
|
||||
#
|
||||
# Post.with(posts_with_tags: Post.where("tags_count > ?", 0))
|
||||
# # => ActiveRecord::Relation
|
||||
# # WITH posts_with_tags AS (
|
||||
|
|
|
@ -394,30 +394,32 @@ class MergingDifferentRelationsTest < ActiveRecord::TestCase
|
|||
assert_equal dev.ratings, [rating_1]
|
||||
end
|
||||
|
||||
test "merging relation with common table expression" do
|
||||
posts_with_tags = Post.with(posts_with_tags: Post.where("tags_count > 0")).from("posts_with_tags AS posts")
|
||||
posts_with_comments = Post.where("legacy_comments_count > 0")
|
||||
relation = posts_with_comments.merge(posts_with_tags).order("posts.id")
|
||||
if ActiveRecord::Base.connection.supports_common_table_expressions?
|
||||
test "merging relation with common table expression" do
|
||||
posts_with_tags = Post.with(posts_with_tags: Post.where("tags_count > 0")).from("posts_with_tags AS posts")
|
||||
posts_with_comments = Post.where("legacy_comments_count > 0")
|
||||
relation = posts_with_comments.merge(posts_with_tags).order("posts.id")
|
||||
|
||||
assert_equal [1, 2, 7], relation.pluck(:id)
|
||||
end
|
||||
assert_equal [1, 2, 7], relation.pluck(:id)
|
||||
end
|
||||
|
||||
test "merging multiple relations with common table expression" do
|
||||
posts_with_tags = Post.with(posts_with_tags: Post.where("tags_count > 0"))
|
||||
posts_with_comments = Post.with(posts_with_comments: Post.where("legacy_comments_count > 0"))
|
||||
relation = posts_with_comments.merge(posts_with_tags)
|
||||
.joins("JOIN posts_with_tags pwt ON pwt.id = posts.id JOIN posts_with_comments pwc ON pwc.id = posts.id").order("posts.id")
|
||||
test "merging multiple relations with common table expression" do
|
||||
posts_with_tags = Post.with(posts_with_tags: Post.where("tags_count > 0"))
|
||||
posts_with_comments = Post.with(posts_with_comments: Post.where("legacy_comments_count > 0"))
|
||||
relation = posts_with_comments.merge(posts_with_tags)
|
||||
.joins("JOIN posts_with_tags pwt ON pwt.id = posts.id JOIN posts_with_comments pwc ON pwc.id = posts.id").order("posts.id")
|
||||
|
||||
assert_equal [1, 2, 7], relation.pluck(:id)
|
||||
end
|
||||
assert_equal [1, 2, 7], relation.pluck(:id)
|
||||
end
|
||||
|
||||
test "relation merger leaves to database to decide what to do when multiple CTEs with same alias are passed" do
|
||||
posts_with_tags = Post.with(popular_posts: Post.where("tags_count > 0"))
|
||||
posts_with_comments = Post.with(popular_posts: Post.where("legacy_comments_count > 0"))
|
||||
relation = posts_with_tags.merge(posts_with_comments).joins("JOIN popular_posts pp ON pp.id = posts.id")
|
||||
test "relation merger leaves to database to decide what to do when multiple CTEs with same alias are passed" do
|
||||
posts_with_tags = Post.with(popular_posts: Post.where("tags_count > 0"))
|
||||
posts_with_comments = Post.with(popular_posts: Post.where("legacy_comments_count > 0"))
|
||||
relation = posts_with_tags.merge(posts_with_comments).joins("JOIN popular_posts pp ON pp.id = posts.id")
|
||||
|
||||
assert_raises ActiveRecord::StatementInvalid do
|
||||
relation.load
|
||||
assert_raises ActiveRecord::StatementInvalid do
|
||||
relation.load
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -15,50 +15,58 @@ module ActiveRecord
|
|||
POSTS_WITH_TAGS_AND_COMMENTS = (POSTS_WITH_COMMENTS & POSTS_WITH_TAGS).sort.freeze
|
||||
POSTS_WITH_TAGS_AND_MULTIPLE_COMMENTS = (POSTS_WITH_MULTIPLE_COMMENTS & POSTS_WITH_TAGS).sort.freeze
|
||||
|
||||
def test_with_when_hash_is_passed_as_an_argument
|
||||
relation = Post
|
||||
.with(posts_with_comments: Post.where("legacy_comments_count > 0"))
|
||||
.from("posts_with_comments AS posts")
|
||||
if ActiveRecord::Base.connection.supports_common_table_expressions?
|
||||
def test_with_when_hash_is_passed_as_an_argument
|
||||
relation = Post
|
||||
.with(posts_with_comments: Post.where("legacy_comments_count > 0"))
|
||||
.from("posts_with_comments AS posts")
|
||||
|
||||
assert_equal POSTS_WITH_COMMENTS, relation.order(:id).pluck(:id)
|
||||
end
|
||||
assert_equal POSTS_WITH_COMMENTS, relation.order(:id).pluck(:id)
|
||||
end
|
||||
|
||||
def test_with_when_hash_with_multiple_elements_of_different_type_is_passed_as_an_argument
|
||||
cte_options = {
|
||||
posts_with_tags: Post.arel_table.project(Arel.star).where(Post.arel_table[:tags_count].gt(0)),
|
||||
posts_with_tags_and_comments: Arel.sql("SELECT * FROM posts_with_tags WHERE legacy_comments_count > 0"),
|
||||
"posts_with_tags_and_multiple_comments" => Post.where("legacy_comments_count > 1").from("posts_with_tags_and_comments AS posts")
|
||||
}
|
||||
relation = Post.with(cte_options).from("posts_with_tags_and_multiple_comments AS posts")
|
||||
def test_with_when_hash_with_multiple_elements_of_different_type_is_passed_as_an_argument
|
||||
cte_options = {
|
||||
posts_with_tags: Post.arel_table.project(Arel.star).where(Post.arel_table[:tags_count].gt(0)),
|
||||
posts_with_tags_and_comments: Arel.sql("SELECT * FROM posts_with_tags WHERE legacy_comments_count > 0"),
|
||||
"posts_with_tags_and_multiple_comments" => Post.where("legacy_comments_count > 1").from("posts_with_tags_and_comments AS posts")
|
||||
}
|
||||
relation = Post.with(cte_options).from("posts_with_tags_and_multiple_comments AS posts")
|
||||
|
||||
assert_equal POSTS_WITH_TAGS_AND_MULTIPLE_COMMENTS, relation.order(:id).pluck(:id)
|
||||
end
|
||||
assert_equal POSTS_WITH_TAGS_AND_MULTIPLE_COMMENTS, relation.order(:id).pluck(:id)
|
||||
end
|
||||
|
||||
def test_multiple_with_calls
|
||||
relation = Post
|
||||
.with(posts_with_tags: Post.where("tags_count > 0"))
|
||||
.from("posts_with_tags_and_comments AS posts")
|
||||
.with(posts_with_tags_and_comments: Arel.sql("SELECT * FROM posts_with_tags WHERE legacy_comments_count > 0"))
|
||||
def test_multiple_with_calls
|
||||
relation = Post
|
||||
.with(posts_with_tags: Post.where("tags_count > 0"))
|
||||
.from("posts_with_tags_and_comments AS posts")
|
||||
.with(posts_with_tags_and_comments: Arel.sql("SELECT * FROM posts_with_tags WHERE legacy_comments_count > 0"))
|
||||
|
||||
assert_equal POSTS_WITH_TAGS_AND_COMMENTS, relation.order(:id).pluck(:id)
|
||||
end
|
||||
assert_equal POSTS_WITH_TAGS_AND_COMMENTS, relation.order(:id).pluck(:id)
|
||||
end
|
||||
|
||||
def test_count_after_with_call
|
||||
relation = Post.with(posts_with_comments: Post.where("legacy_comments_count > 0"))
|
||||
def test_count_after_with_call
|
||||
relation = Post.with(posts_with_comments: Post.where("legacy_comments_count > 0"))
|
||||
|
||||
assert_equal Post.count, relation.count
|
||||
assert_equal POSTS_WITH_COMMENTS.size, relation.from("posts_with_comments AS posts").count
|
||||
assert_equal POSTS_WITH_COMMENTS.size, relation.joins("JOIN posts_with_comments ON posts_with_comments.id = posts.id").count
|
||||
end
|
||||
assert_equal Post.count, relation.count
|
||||
assert_equal POSTS_WITH_COMMENTS.size, relation.from("posts_with_comments AS posts").count
|
||||
assert_equal POSTS_WITH_COMMENTS.size, relation.joins("JOIN posts_with_comments ON posts_with_comments.id = posts.id").count
|
||||
end
|
||||
|
||||
def test_with_when_called_from_active_record_scope
|
||||
assert_equal POSTS_WITH_TAGS, Post.with_tags_cte.order(:id).pluck(:id)
|
||||
end
|
||||
def test_with_when_called_from_active_record_scope
|
||||
assert_equal POSTS_WITH_TAGS, Post.with_tags_cte.order(:id).pluck(:id)
|
||||
end
|
||||
|
||||
def test_with_when_invalid_params_are_passed
|
||||
assert_raise(ArgumentError) { Post.with }
|
||||
assert_raise(ArgumentError) { Post.with(posts_with_tags: nil).load }
|
||||
assert_raise(ArgumentError) { Post.with(posts_with_tags: [Post.where("tags_count > 0")]).load }
|
||||
def test_with_when_invalid_params_are_passed
|
||||
assert_raise(ArgumentError) { Post.with }
|
||||
assert_raise(ArgumentError) { Post.with(posts_with_tags: nil).load }
|
||||
assert_raise(ArgumentError) { Post.with(posts_with_tags: [Post.where("tags_count > 0")]).load }
|
||||
end
|
||||
else
|
||||
def test_common_table_expressions_are_unsupported
|
||||
assert_raises ActiveRecord::StatementInvalid do
|
||||
Post.with_tags_cte.order(:id).pluck(:id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue