1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
|
# frozen_string_literal: true
require "cases/helper"
require "models/post"
require "models/comment"
require "models/author"
require "models/essay"
require "models/category"
require "models/categorization"
require "models/person"
require "models/tagging"
require "models/tag"
class InnerJoinAssociationTest < ActiveRecord::TestCase
fixtures :authors, :author_addresses, :essays, :posts, :comments, :categories, :categories_posts, :categorizations,
:taggings, :tags
def test_construct_finder_sql_applies_aliases_tables_on_association_conditions
result = Author.joins(:thinking_posts, :welcome_posts).to_a
assert_equal authors(:david), result.first
end
def test_construct_finder_sql_does_not_table_name_collide_on_duplicate_associations
assert_nothing_raised do
sql = Person.joins(agents: { agents: :agents }).joins(agents: { agents: { primary_contact: :agents } }).to_sql
assert_match(/agents_people_4/i, sql)
end
end
def test_construct_finder_sql_does_not_table_name_collide_on_duplicate_associations_with_left_outer_joins
sql = Person.joins(agents: :agents).left_outer_joins(agents: :agents).to_sql
assert_match(/agents_people_2/i, sql)
assert_match(/INNER JOIN/i, sql)
assert_no_match(/agents_people_4/i, sql)
assert_no_match(/LEFT OUTER JOIN/i, sql)
end
def test_construct_finder_sql_does_not_table_name_collide_with_string_joins
sql = Person.joins(:agents).joins("JOIN people agents_people ON agents_people.primary_contact_id = people.id").to_sql
assert_match(/agents_people_2/i, sql)
end
def test_construct_finder_sql_does_not_table_name_collide_with_aliased_joins
people = Person.arel_table
agents = people.alias("agents_people")
constraint = agents[:primary_contact_id].eq(people[:id])
sql = Person.joins(:agents).joins(agents.create_join(agents, agents.create_on(constraint))).to_sql
assert_match(/agents_people_2/i, sql)
end
def test_construct_finder_sql_ignores_empty_joins_hash
sql = Author.joins({}).to_sql
assert_no_match(/JOIN/i, sql)
end
def test_construct_finder_sql_ignores_empty_joins_array
sql = Author.joins([]).to_sql
assert_no_match(/JOIN/i, sql)
end
def test_join_conditions_added_to_join_clause
sql = Author.joins(:essays).to_sql
assert_match(/writer_type.*?=.*?Author/i, sql)
assert_no_match(/WHERE/i, sql)
end
def test_join_association_conditions_support_string_and_arel_expressions
assert_equal 0, Author.joins(:welcome_posts_with_one_comment).count
assert_equal 1, Author.joins(:welcome_posts_with_comments).count
end
def test_join_conditions_allow_nil_associations
authors = Author.includes(:essays).where(essays: { id: nil })
assert_equal 2, authors.count
end
def test_find_with_implicit_inner_joins_without_select_does_not_imply_readonly
authors = Author.joins(:posts)
assert_not authors.empty?, "expected authors to be non-empty"
assert authors.none?(&:readonly?), "expected no authors to be readonly"
end
def test_find_with_implicit_inner_joins_honors_readonly_with_select
authors = Author.joins(:posts).select("authors.*").to_a
assert_not authors.empty?, "expected authors to be non-empty"
assert authors.all? { |a| !a.readonly? }, "expected no authors to be readonly"
end
def test_find_with_implicit_inner_joins_honors_readonly_false
authors = Author.joins(:posts).readonly(false).to_a
assert_not authors.empty?, "expected authors to be non-empty"
assert authors.all? { |a| !a.readonly? }, "expected no authors to be readonly"
end
def test_find_with_implicit_inner_joins_does_not_set_associations
authors = Author.joins(:posts).select("authors.*").to_a
assert_not authors.empty?, "expected authors to be non-empty"
assert authors.all? { |a| !a.instance_variable_defined?(:@posts) }, "expected no authors to have the @posts association loaded"
end
def test_count_honors_implicit_inner_joins
real_count = Author.all.to_a.sum { |a| a.posts.count }
assert_equal real_count, Author.joins(:posts).count, "plain inner join count should match the number of referenced posts records"
end
def test_calculate_honors_implicit_inner_joins
real_count = Author.all.to_a.sum { |a| a.posts.count }
assert_equal real_count, Author.joins(:posts).calculate(:count, "authors.id"), "plain inner join count should match the number of referenced posts records"
end
def test_calculate_honors_implicit_inner_joins_and_distinct_and_conditions
real_count = Author.all.to_a.select { |a| a.posts.any? { |p| p.title.start_with?("Welcome") } }.length
authors_with_welcoming_post_titles = Author.all.merge!(joins: :posts, where: "posts.title like 'Welcome%'").distinct.calculate(:count, "authors.id")
assert_equal real_count, authors_with_welcoming_post_titles, "inner join and conditions should have only returned authors posting titles starting with 'Welcome'"
end
def test_find_with_sti_join
scope = Post.joins(:special_comments).where(id: posts(:sti_comments).id)
# The join should match SpecialComment and its subclasses only
assert_empty scope.where("comments.type" => "Comment")
assert_not_empty scope.where("comments.type" => "SpecialComment")
assert_not_empty scope.where("comments.type" => "SubSpecialComment")
end
def test_find_with_conditions_on_reflection
assert_not_empty posts(:welcome).comments
assert Post.joins(:nonexistent_comments).where(id: posts(:welcome).id).empty? # [sic!]
end
def test_find_with_conditions_on_through_reflection
assert_not_empty posts(:welcome).tags
assert_empty Post.joins(:misc_tags).where(id: posts(:welcome).id)
end
test "the default scope of the target is applied when joining associations" do
author = Author.create! name: "Jon"
author.categorizations.create!
author.categorizations.create! special: true
assert_equal [author], Author.where(id: author).joins(:special_categorizations)
end
test "the default scope of the target is correctly aliased when joining associations" do
author = Author.create! name: "Jon"
author.categories.create! name: "Not Special"
author.special_categories.create! name: "Special"
categories = author.categories.includes(:special_categorizations).references(:special_categorizations).to_a
assert_equal 2, categories.size
end
test "the correct records are loaded when including an aliased association" do
author = Author.create! name: "Jon"
author.categories.create! name: "Not Special"
author.special_categories.create! name: "Special"
categories = author.categories.eager_load(:special_categorizations).order(:name).to_a
assert_equal 0, categories.first.special_categorizations.size
assert_equal 1, categories.second.special_categorizations.size
end
end
|