Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
张重言
rails
提交
d5994ee4
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,发现更多精彩内容 >>
提交
d5994ee4
编写于
3月 03, 2011
作者:
J
John Mileham
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Change behavior of count(:limit => x, :offset => y) to limit/offset before counting.
上级
1db4969d
变更
3
显示空白变更内容
内联
并排
Showing
3 changed file
with
80 addition
and
25 deletion
+80
-25
activerecord/lib/active_record/relation/calculations.rb
activerecord/lib/active_record/relation/calculations.rb
+26
-14
activerecord/test/cases/calculations_test.rb
activerecord/test/cases/calculations_test.rb
+26
-11
activerecord/test/cases/relations_test.rb
activerecord/test/cases/relations_test.rb
+28
-0
未找到文件。
activerecord/lib/active_record/relation/calculations.rb
浏览文件 @
d5994ee4
...
...
@@ -183,10 +183,13 @@ def perform_calculation(operation, column_name, options = {})
end
end
def
aggregate_column
(
column_name
)
def
aggregate_column
(
column_name
,
subquery_alias
=
nil
)
if
@klass
.
column_names
.
include?
(
column_name
.
to_s
)
Arel
::
Attribute
.
new
(
@klass
.
unscoped
.
table
,
column_name
)
Arel
::
Attribute
.
new
(
subquery_alias
||
@klass
.
unscoped
.
table
,
column_name
)
else
if
subquery_alias
&&
(
split_name
=
column_name
.
to_s
.
split
(
"."
)).
length
>
1
column_name
=
split_name
.
last
end
Arel
.
sql
(
column_name
==
:all
?
"*"
:
column_name
.
to_s
)
end
end
...
...
@@ -196,24 +199,22 @@ def operation_over_aggregate_column(column, operation, distinct)
end
def
execute_simple_calculation
(
operation
,
column_name
,
distinct
)
#:nodoc:
column
=
aggregate_column
(
column_name
)
# Postgresql doesn't like ORDER BY when there are no GROUP BY
relation
=
except
(
:order
)
if
operation
==
"count"
&&
(
relation
.
limit_value
||
relation
.
offset_value
)
# Shortcut when limit is zero.
return
0
if
relation
.
limit_value
==
0
query_builder
=
build_count_subquery
(
relation
,
column_name
,
distinct
)
else
column
=
aggregate_column
(
column_name
)
select_value
=
operation_over_aggregate_column
(
column
,
operation
,
distinct
)
relation
.
select_values
=
[
select_value
]
query_builder
=
relation
.
arel
if
operation
==
"count"
limit
=
relation
.
limit_value
offset
=
relation
.
offset_value
unless
limit
&&
offset
query_builder
.
limit
=
nil
query_builder
.
offset
=
nil
end
end
type_cast_calculated_value
(
@klass
.
connection
.
select_value
(
query_builder
.
to_sql
),
column_for
(
column_name
),
operation
)
...
...
@@ -312,5 +313,16 @@ def select_for_count
select
if
select
!~
/(,|\*)/
end
end
def
build_count_subquery
(
relation
,
column_name
,
distinct
)
# Arel doesn't do subqueries
subquery_alias
=
arel_table
.
alias
(
"subquery_for_count"
)
aliased_column
=
aggregate_column
(
column_name
,
subquery_alias
)
select_value
=
operation_over_aggregate_column
(
aliased_column
,
'count'
,
distinct
)
relation
.
select_values
=
[(
column_name
==
:all
?
1
:
aggregate_column
(
column_name
))]
subquery_sql
=
"(
#{
relation
.
arel
.
to_sql
}
)
#{
subquery_alias
.
name
}
"
subquery_alias
.
relation
.
select_manager
.
project
(
select_value
).
from
(
subquery_sql
)
end
end
end
activerecord/test/cases/calculations_test.rb
浏览文件 @
d5994ee4
...
...
@@ -109,27 +109,42 @@ def test_should_limit_calculation_with_offset
assert_equal
[
2
,
6
],
c
.
keys
.
compact
end
def
test_limit_with_offset_is_kept
def
test_limit_should_apply_before_count
accounts
=
Account
.
limit
(
3
).
where
(
'firm_id IS NOT NULL'
)
assert_equal
3
,
accounts
.
count
(
:firm_id
)
assert_equal
3
,
accounts
.
select
(
:firm_id
).
count
end
def
test_count_should_shortcut_with_limit_zero
accounts
=
Account
.
limit
(
0
)
assert_no_queries
{
assert_equal
0
,
accounts
.
count
}
end
def
test_limit_is_kept
return
if
current_adapter?
(
:OracleAdapter
)
queries
=
assert_sql
{
Account
.
limit
(
1
).
offset
(
1
).
count
}
queries
=
assert_sql
{
Account
.
limit
(
1
).
count
}
assert_equal
1
,
queries
.
length
assert_match
(
/LIMIT/
,
queries
.
first
)
assert_match
(
/OFFSET/
,
queries
.
first
)
end
def
test_offset_without_limit_removes_offset
def
test_offset_is_kept
return
if
current_adapter?
(
:OracleAdapter
)
queries
=
assert_sql
{
Account
.
offset
(
1
).
count
}
assert_equal
1
,
queries
.
length
assert_no_match
(
/LIMIT/
,
queries
.
first
)
assert_no_match
(
/OFFSET/
,
queries
.
first
)
assert_match
(
/OFFSET/
,
queries
.
first
)
end
def
test_limit_without_offset_removes_limit
queries
=
assert_sql
{
Account
.
limit
(
1
).
count
}
def
test_limit_with_offset_is_kept
return
if
current_adapter?
(
:OracleAdapter
)
queries
=
assert_sql
{
Account
.
limit
(
1
).
offset
(
1
).
count
}
assert_equal
1
,
queries
.
length
assert_
no_
match
(
/LIMIT/
,
queries
.
first
)
assert_
no_
match
(
/OFFSET/
,
queries
.
first
)
assert_match
(
/LIMIT/
,
queries
.
first
)
assert_match
(
/OFFSET/
,
queries
.
first
)
end
def
test_no_limit_no_offset
...
...
activerecord/test/cases/relations_test.rb
浏览文件 @
d5994ee4
...
...
@@ -666,6 +666,34 @@ def test_size
assert_no_queries
{
assert_equal
5
,
best_posts
.
size
}
end
def
test_size_with_limit
posts
=
Post
.
limit
(
6
)
assert_queries
(
1
)
{
assert_equal
6
,
posts
.
size
}
assert
!
posts
.
loaded?
best_posts
=
posts
.
where
(
:comments_count
=>
0
)
best_posts
.
to_a
# force load
assert_no_queries
{
assert_equal
5
,
best_posts
.
size
}
end
def
test_size_with_zero_limit
posts
=
Post
.
limit
(
0
)
assert_no_queries
{
assert_equal
0
,
posts
.
size
}
assert
!
posts
.
loaded?
posts
.
to_a
# force load
assert_no_queries
{
assert_equal
0
,
posts
.
size
}
end
def
test_empty_with_zero_limit
posts
=
Post
.
limit
(
0
)
assert_no_queries
{
assert_equal
true
,
posts
.
empty?
}
assert
!
posts
.
loaded?
end
def
test_count_complex_chained_relations
posts
=
Post
.
select
(
'comments_count'
).
where
(
'id is not null'
).
group
(
"author_id"
).
where
(
"comments_count > 0"
)
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录