Skip to content

Commit

Permalink
Merge pull request #47246 from Shopify/support-joins-for-assoc-with-c…
Browse files Browse the repository at this point in the history
…omposite-foreign-key

Support joins for associations with composite foreign keys
  • Loading branch information
eileencodes committed Feb 13, 2023
2 parents 90f4b3d + 7c75e04 commit 75a1871
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 15 deletions.
10 changes: 7 additions & 3 deletions activerecord/lib/active_record/reflection.rb
Expand Up @@ -199,10 +199,14 @@ def join_scope(table, foreign_table, foreign_klass)

scope_chain_items.inject(klass_scope, &:merge!)

primary_key = join_primary_key
foreign_key = join_foreign_key
primary_key_column_names = Array(join_primary_key)
foreign_key_column_names = Array(join_foreign_key)

klass_scope.where!(table[primary_key].eq(foreign_table[foreign_key]))
primary_foreign_key_pairs = primary_key_column_names.zip(foreign_key_column_names)

primary_foreign_key_pairs.each do |primary_key_column_name, foreign_key_column_name|
klass_scope.where!(table[primary_key_column_name].eq(foreign_table[foreign_key_column_name]))
end

if klass.finder_needs_type_condition?
klass_scope.where!(klass.send(:type_condition, table))
Expand Down
Expand Up @@ -10,10 +10,12 @@
require "models/person"
require "models/tagging"
require "models/tag"
require "models/sharded/blog_post"
require "models/sharded/comment"

class InnerJoinAssociationTest < ActiveRecord::TestCase
fixtures :authors, :author_addresses, :essays, :posts, :comments, :categories, :categories_posts, :categorizations,
:taggings, :tags, :people
:taggings, :tags, :people, :sharded_comments, :sharded_blog_posts

def test_construct_finder_sql_applies_aliases_tables_on_association_conditions
result = Author.joins(:thinking_posts, :welcome_posts).first
Expand Down Expand Up @@ -212,4 +214,21 @@ def test_find_with_conditions_on_through_reflection
assert_equal 0, categories.first.special_categorizations.size
assert_equal 1, categories.second.special_categorizations.size
end

test "joins a belongs_to association with a composite foreign key" do
first_post_comments = Sharded::Comment.joins(:blog_post).where(blog_post: { title: "My first post!" }).to_a
expected_blog_post = sharded_blog_posts(:great_blog_post_one)

assert_not_empty comments
assert_equal(expected_blog_post.comments.to_a.sort, first_post_comments.sort)
end

test "joins a has_many association with a composite foreign key" do
blog_posts = Sharded::BlogPost.joins(:comments).where(comments: { body: "Your first blog post is great!" }).to_a

expected_comment = sharded_comments(:unique_comment_blog_post_one)

assert_not_empty blog_posts
assert_equal(expected_comment.blog_post, blog_posts.first)
end
end
10 changes: 5 additions & 5 deletions activerecord/test/cases/associations_test.rb
Expand Up @@ -131,7 +131,7 @@ def test_association_with_references

def test_belongs_to_a_model_with_composite_foreign_key_finds_associated_record
comment = sharded_comments(:great_comment_blog_post_one)
blog_post = sharded_blog_posts(:great_post_blog_one)
blog_post = sharded_blog_posts(:great_blog_post_one)

assert_equal(blog_post, comment.blog_post)
end
Expand All @@ -148,15 +148,15 @@ def test_belongs_to_a_model_with_composite_primary_key_uses_composite_pk_in_sql
end

def test_has_many_association_with_composite_foreign_key_loads_records
blog_post = sharded_blog_posts(:great_post_blog_one)
blog_post = sharded_blog_posts(:great_blog_post_one)

comments = blog_post.comments.to_a
assert_includes(comments, sharded_comments(:wow_comment_blog_post_one))
assert_includes(comments, sharded_comments(:great_comment_blog_post_one))
end

def test_model_with_composite_query_constraints_has_many_association_sql
blog_post = sharded_blog_posts(:great_post_blog_one)
blog_post = sharded_blog_posts(:great_blog_post_one)

sql = capture_sql do
blog_post.comments.to_a
Expand All @@ -167,7 +167,7 @@ def test_model_with_composite_query_constraints_has_many_association_sql
end

def test_append_composite_foreign_key_has_many_association
blog_post = sharded_blog_posts(:great_post_blog_one)
blog_post = sharded_blog_posts(:great_blog_post_one)
comment = Sharded::Comment.new(body: "Great post! :clap:")
comment.save
blog_post.comments << comment
Expand Down Expand Up @@ -206,7 +206,7 @@ def test_assign_composite_foreign_key_belongs_to_association
end

def test_append_composite_foreign_key_has_many_association_with_autosave
blog_post = sharded_blog_posts(:great_post_blog_one)
blog_post = sharded_blog_posts(:great_blog_post_one)
comment = Sharded::Comment.new(body: "Great post! :clap:")
blog_post.comments << comment

Expand Down
6 changes: 3 additions & 3 deletions activerecord/test/fixtures/sharded_blog_posts.yml
@@ -1,10 +1,10 @@
_fixture:
model_class: Sharded::BlogPost

great_post_blog_one:
great_blog_post_one:
title: "My first post!"
blog_id: <%= ActiveRecord::FixtureSet.identify(:sharded_blog_one) %>

great_post_blog_two:
title: "My first post!"
great_blog_post_two:
title: "My second post!"
blog_id: <%= ActiveRecord::FixtureSet.identify(:sharded_blog_two) %>
11 changes: 8 additions & 3 deletions activerecord/test/fixtures/sharded_comments.yml
Expand Up @@ -3,15 +3,20 @@ _fixture:

great_comment_blog_post_one:
body: "I really enjoyed the post!"
blog_post_id: <%= ActiveRecord::FixtureSet.identify(:great_post_blog_one) %>
blog_post_id: <%= ActiveRecord::FixtureSet.identify(:great_blog_post_one) %>
blog_id: <%= ActiveRecord::FixtureSet.identify(:sharded_blog_one) %>

wow_comment_blog_post_one:
body: "Wow!"
blog_post_id: <%= ActiveRecord::FixtureSet.identify(:great_post_blog_one) %>
blog_post_id: <%= ActiveRecord::FixtureSet.identify(:great_blog_post_one) %>
blog_id: <%= ActiveRecord::FixtureSet.identify(:sharded_blog_one) %>

unique_comment_blog_post_one:
body: "Your first blog post is great!"
blog_post_id: <%= ActiveRecord::FixtureSet.identify(:great_blog_post_one) %>
blog_id: <%= ActiveRecord::FixtureSet.identify(:sharded_blog_one) %>

great_comment_blog_post_two:
body: "I really enjoyed the post!"
blog_post_id: <%= ActiveRecord::FixtureSet.identify(:great_post_blog_two) %>
blog_post_id: <%= ActiveRecord::FixtureSet.identify(:great_blog_post_two) %>
blog_id: <%= ActiveRecord::FixtureSet.identify(:sharded_blog_two) %>

0 comments on commit 75a1871

Please sign in to comment.