Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
张重言
rails
提交
23cdecee
R
rails
项目概览
张重言
/
rails
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
rails
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
23cdecee
编写于
7月 30, 2019
作者:
R
Ryuta Kamizono
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Merge pull request #36805 from kamipo/user_supplied_joins_order_should_be_preserved
Preserve user supplied joins order as much as possible
上级
c6d751fc
变更
3
隐藏空白更改
内联
并排
Showing
3 changed file
with
65 addition
and
24 deletion
+65
-24
activerecord/CHANGELOG.md
activerecord/CHANGELOG.md
+6
-0
activerecord/lib/active_record/relation/query_methods.rb
activerecord/lib/active_record/relation/query_methods.rb
+30
-16
activerecord/test/cases/associations/inner_join_association_test.rb
...rd/test/cases/associations/inner_join_association_test.rb
+29
-8
未找到文件。
activerecord/CHANGELOG.md
浏览文件 @
23cdecee
*
Preserve user supplied joins order as much as possible.
Fixes #36761, #34328, #24281, #12953.
*Ryuta Kamizono*
*
Make the DATABASE_URL env variable only affect the primary connection. Add new env variables for multiple databases.
*John Crepezzi*, *Eileen Uchitelle*
...
...
activerecord/lib/active_record/relation/query_methods.rb
浏览文件 @
23cdecee
...
...
@@ -1095,26 +1095,44 @@ def valid_association_list(associations)
end
def
build_left_outer_joins
(
manager
,
outer_joins
,
aliases
)
buckets
=
{
association_join:
valid_association_list
(
outer_joins
)
}
buckets
=
Hash
.
new
{
|
h
,
k
|
h
[
k
]
=
[]
}
buckets
[
:association_join
]
=
valid_association_list
(
outer_joins
)
build_join_query
(
manager
,
buckets
,
Arel
::
Nodes
::
OuterJoin
,
aliases
)
end
def
build_joins
(
manager
,
joins
,
aliases
)
buckets
=
Hash
.
new
{
|
h
,
k
|
h
[
k
]
=
[]
}
unless
left_outer_joins_values
.
empty?
left_joins
=
valid_association_list
(
left_outer_joins_values
.
flatten
)
joins
.
unshift
construct_join_dependency
(
left_joins
,
Arel
::
Nodes
::
OuterJoin
)
buckets
[
:stashed_join
]
<<
construct_join_dependency
(
left_joins
,
Arel
::
Nodes
::
OuterJoin
)
end
buckets
=
joins
.
group_by
do
|
join
|
joins
.
map!
do
|
join
|
if
join
.
is_a?
(
String
)
table
.
create_string_join
(
Arel
.
sql
(
join
.
strip
))
unless
join
.
blank?
else
join
end
end
.
delete_if
(
&
:blank?
)
while
joins
.
first
.
is_a?
(
Arel
::
Nodes
::
Join
)
join_node
=
joins
.
shift
if
join_node
.
is_a?
(
Arel
::
Nodes
::
StringJoin
)
&&
!
buckets
[
:stashed_join
].
empty?
buckets
[
:join_node
]
<<
join_node
else
buckets
[
:leading_join
]
<<
join_node
end
end
joins
.
each
do
|
join
|
case
join
when
String
:string_join
when
Hash
,
Symbol
,
Array
:association_
join
buckets
[
:association_join
]
<<
join
when
ActiveRecord
::
Associations
::
JoinDependency
:stashed_
join
buckets
[
:stashed_join
]
<<
join
when
Arel
::
Nodes
::
Join
:join_node
buckets
[
:join_node
]
<<
join
else
raise
"unknown class: %s"
%
join
.
class
.
name
end
...
...
@@ -1124,25 +1142,21 @@ def build_joins(manager, joins, aliases)
end
def
build_join_query
(
manager
,
buckets
,
join_type
,
aliases
)
buckets
.
default
=
[]
association_joins
=
buckets
[
:association_join
]
stashed_joins
=
buckets
[
:stashed_join
]
leading_joins
=
buckets
[
:leading_join
].
tap
(
&
:uniq!
)
join_nodes
=
buckets
[
:join_node
].
tap
(
&
:uniq!
)
string_joins
=
buckets
[
:string_join
].
delete_if
(
&
:blank?
).
map!
(
&
:strip
).
tap
(
&
:uniq!
)
string_joins
.
map!
{
|
join
|
table
.
create_string_join
(
Arel
.
sql
(
join
))
}
join_sources
=
manager
.
join_sources
join_sources
.
concat
(
join_nodes
)
unless
join_node
s
.
empty?
join_sources
.
concat
(
leading_joins
)
unless
leading_join
s
.
empty?
unless
association_joins
.
empty?
&&
stashed_joins
.
empty?
alias_tracker
=
alias_tracker
(
join_nodes
+
string_join
s
,
aliases
)
alias_tracker
=
alias_tracker
(
leading_joins
+
join_node
s
,
aliases
)
join_dependency
=
construct_join_dependency
(
association_joins
,
join_type
)
join_sources
.
concat
(
join_dependency
.
join_constraints
(
stashed_joins
,
alias_tracker
))
end
join_sources
.
concat
(
string_joins
)
unless
string_join
s
.
empty?
join_sources
.
concat
(
join_nodes
)
unless
join_node
s
.
empty?
end
def
build_select
(
arel
)
...
...
activerecord/test/cases/associations/inner_join_association_test.rb
浏览文件 @
23cdecee
...
...
@@ -13,7 +13,7 @@
class
InnerJoinAssociationTest
<
ActiveRecord
::
TestCase
fixtures
:authors
,
:author_addresses
,
:essays
,
:posts
,
:comments
,
:categories
,
:categories_posts
,
:categorizations
,
:taggings
,
:tags
:taggings
,
:tags
,
:people
def
test_construct_finder_sql_applies_aliases_tables_on_association_conditions
result
=
Author
.
joins
(
:thinking_posts
,
:welcome_posts
).
to_a
...
...
@@ -36,16 +36,37 @@ def test_construct_finder_sql_does_not_table_name_collide_on_duplicate_associati
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
)
string_join
=
<<~
SQL
JOIN people agents_people ON agents_people.primary_contact_id = agents_people_2.id AND agents_people.id > agents_people_2.id
SQL
expected
=
people
(
:susan
)
assert_sql
(
/agents_people_2/i
)
do
assert_equal
[
expected
],
Person
.
joins
(
:agents
).
joins
(
string_join
)
end
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
)
agents
=
Person
.
arel_table
.
alias
(
"agents_people"
)
agents_2
=
Person
.
arel_table
.
alias
(
"agents_people_2"
)
constraint
=
agents
[
:primary_contact_id
].
eq
(
agents_2
[
:id
]).
and
(
agents
[
:id
].
gt
(
agents_2
[
:id
]))
expected
=
people
(
:susan
)
assert_sql
(
/agents_people_2/i
)
do
assert_equal
[
expected
],
Person
.
joins
(
:agents
).
joins
(
agents
.
create_join
(
agents
,
agents
.
create_on
(
constraint
)))
end
end
def
test_user_supplied_joins_order_should_be_preserved
string_join
=
<<~
SQL
JOIN people agents_people_2 ON agents_people_2.primary_contact_id = people.id
SQL
agents
=
Person
.
arel_table
.
alias
(
"agents_people"
)
agents_2
=
Person
.
arel_table
.
alias
(
"agents_people_2"
)
constraint
=
agents
[
:primary_contact_id
].
eq
(
agents_2
[
:id
]).
and
(
agents
[
:id
].
gt
(
agents_2
[
:id
]))
expected
=
people
(
:susan
)
assert_equal
[
expected
],
Person
.
joins
(
string_join
).
joins
(
agents
.
create_join
(
agents
,
agents
.
create_on
(
constraint
)))
end
def
test_construct_finder_sql_ignores_empty_joins_hash
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录