aggregate_columns 0.9 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Rakefile +1 -1
- data/lib/aggregate_columns.rb +30 -34
- data/test/aggregate_columns_test.rb +54 -54
- data/test/test_helper.rb +1 -1
- metadata +19 -39
data/Rakefile
CHANGED
@@ -14,7 +14,7 @@ PKG_FILES = FileList[
|
|
14
14
|
|
15
15
|
spec = Gem::Specification.new do |s|
|
16
16
|
s.name = "aggregate_columns"
|
17
|
-
s.version = "0.9"
|
17
|
+
s.version = "0.9.1"
|
18
18
|
s.author = "Marek Janukowicz"
|
19
19
|
s.email = "marek@janukowicz.net"
|
20
20
|
s.homepage = "http://www.bitbucket.org/starware/aggregate_columns"
|
data/lib/aggregate_columns.rb
CHANGED
@@ -47,42 +47,38 @@ module AggregateColumns
|
|
47
47
|
|
48
48
|
module MethodsRails3
|
49
49
|
|
50
|
-
def aggregate_columns(
|
50
|
+
def aggregate_columns( options )
|
51
51
|
rel = self.select( "#{table_name}.*" )
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
result_column ||= field == '*' ? "#{association.to_s.singularize}_#{function}" : "#{association}_#{field}_#{function}"
|
67
|
-
end
|
68
|
-
# TODO: this only works on ActiveRecord::Base classes - would be nice
|
69
|
-
# (and not that complicated) to make it work on ActiveRecord::Relation
|
70
|
-
# instances
|
71
|
-
assoc_reflection = reflect_on_association( association )
|
72
|
-
foreign_key = assoc_reflection.primary_key_name # As stupid as it looks, this is actually correct
|
73
|
-
aggregate_table_name = assoc_reflection.table_name
|
74
|
-
klass = assoc_reflection.klass
|
75
|
-
join_type = options[:join_type] || "LEFT" # TODO: check if in range of allowed values
|
76
|
-
order = options[:order] || "DESC"
|
77
|
-
conditions = options[:conditions]
|
78
|
-
joins = options[:joins]
|
79
|
-
|
80
|
-
# Now gather params for aggregate
|
81
|
-
rel = rel.
|
82
|
-
joins( "#{join_type.to_s.upcase} JOIN (SELECT #{foreign_key}, #{function}(#{field}) AS #{result_column} FROM #{aggregate_table_name} #{joins}#{" WHERE " + klass.sanitize_sql( conditions ) if conditions } GROUP BY #{foreign_key}) #{result_column}_join ON #{table_name}.id = #{result_column}_join.#{foreign_key}" ).
|
83
|
-
select( result_column.to_s ).
|
84
|
-
order( "#{result_column} #{order.to_s.upcase}" )
|
52
|
+
# Process options
|
53
|
+
options.assert_valid_keys( :association, :column, :function, :result_column, :join_type )
|
54
|
+
association = options[:association]
|
55
|
+
unless association
|
56
|
+
raise ArgumentError, "No association given"
|
57
|
+
end
|
58
|
+
field = options[:column] || '*'
|
59
|
+
function = options[:function] || :count
|
60
|
+
result_column = options[:result_column]
|
61
|
+
unless result_column
|
62
|
+
# Defaults:
|
63
|
+
# count(*) on comments => comment_count
|
64
|
+
# sum(votes) on comment => comments_votes_sum
|
65
|
+
result_column ||= field == '*' ? "#{association.to_s.singularize}_#{function}" : "#{association}_#{field}_#{function}"
|
85
66
|
end
|
67
|
+
# TODO: this only works on ActiveRecord::Base classes - would be nice
|
68
|
+
# (and not that complicated) to make it work on ActiveRecord::Relation
|
69
|
+
# instances
|
70
|
+
assoc_reflection = reflect_on_association( association )
|
71
|
+
foreign_key = assoc_reflection.primary_key_name # As stupid as it looks, this is actually correct
|
72
|
+
aggregate_table_name = assoc_reflection.table_name
|
73
|
+
klass = assoc_reflection.klass
|
74
|
+
join_type = options[:join_type] || "LEFT" # TODO: check if within allowed values
|
75
|
+
|
76
|
+
aggregate_rel = klass.select( "#{foreign_key}, #{function}(#{field}) AS #{result_column}" ).from( aggregate_table_name ).group( foreign_key )
|
77
|
+
aggregate_rel = yield( aggregate_rel ) if block_given?
|
78
|
+
rel = rel.
|
79
|
+
joins( "#{join_type.to_s.upcase} JOIN (#{aggregate_rel.to_sql}) #{result_column}_join ON #{table_name}.id = #{result_column}_join.#{foreign_key}" ).
|
80
|
+
select( result_column.to_s ).
|
81
|
+
order( "#{result_column} DESC" ) # You might reorder if you want to have it differently
|
86
82
|
return rel
|
87
83
|
end
|
88
84
|
end
|
@@ -13,68 +13,68 @@ class AggregateColumnsTest < ActiveSupport::TestCase
|
|
13
13
|
@user = User.new
|
14
14
|
end
|
15
15
|
|
16
|
-
test "empty options" do
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
end
|
16
|
+
#test "empty options" do
|
17
|
+
# options = User.aggregate_columns_options
|
18
|
+
# assert_equal "users.*", options[:select]
|
19
|
+
# assert options[:order].blank?
|
20
|
+
# assert options[:joins].blank?
|
21
|
+
#end
|
22
22
|
|
23
|
-
test "empty hash as options should fail" do
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
end
|
23
|
+
#test "empty hash as options should fail" do
|
24
|
+
# assert_raise( ArgumentError ) do
|
25
|
+
# options = User.aggregate_columns_options( {} )
|
26
|
+
# end
|
27
|
+
#end
|
28
28
|
|
29
|
-
test "only association" do
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
end
|
29
|
+
#test "only association" do
|
30
|
+
# options = User.aggregate_columns_options( :association => :posts )
|
31
|
+
# assert_equal "users.*, post_count", options[:select]
|
32
|
+
# assert_equal "post_count DESC", options[:order]
|
33
|
+
# assert_equal "LEFT JOIN (SELECT user_id, count(*) AS post_count FROM posts GROUP BY user_id) post_count_join ON posts.id = post_count_join.user_id", options[:joins]
|
34
|
+
#end
|
35
35
|
|
36
|
-
test "column function" do
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
end
|
36
|
+
#test "column function" do
|
37
|
+
# options = User.aggregate_columns_options( :association => :posts, :column => :created_at, :function => :max )
|
38
|
+
# assert_equal "users.*, posts_created_at_max", options[:select]
|
39
|
+
# assert_equal "posts_created_at_max DESC", options[:order]
|
40
|
+
# assert_equal "LEFT JOIN (SELECT user_id, max(created_at) AS posts_created_at_max FROM posts GROUP BY user_id) posts_created_at_max_join ON posts.id = posts_created_at_max_join.user_id", options[:joins]
|
41
|
+
#end
|
42
42
|
|
43
|
-
test "result_column" do
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
end
|
43
|
+
#test "result_column" do
|
44
|
+
# options = User.aggregate_columns_options( :association => :posts, :column => :created_at, :function => :max, :result_column => "last_post_time" )
|
45
|
+
# assert_equal "users.*, last_post_time", options[:select]
|
46
|
+
# assert_equal "last_post_time DESC", options[:order]
|
47
|
+
# assert_equal "LEFT JOIN (SELECT user_id, max(created_at) AS last_post_time FROM posts GROUP BY user_id) last_post_time_join ON posts.id = last_post_time_join.user_id", options[:joins]
|
48
|
+
#end
|
49
49
|
|
50
|
-
test "join_type" do
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
end
|
50
|
+
#test "join_type" do
|
51
|
+
# options = User.aggregate_columns_options( :association => :posts, :column => :created_at, :function => :max, :join_type => "RIGHT" )
|
52
|
+
# assert_equal "users.*, posts_created_at_max", options[:select]
|
53
|
+
# assert_equal "posts_created_at_max DESC", options[:order]
|
54
|
+
# assert_equal "RIGHT JOIN (SELECT user_id, max(created_at) AS posts_created_at_max FROM posts GROUP BY user_id) posts_created_at_max_join ON posts.id = posts_created_at_max_join.user_id", options[:joins]
|
55
|
+
#end
|
56
56
|
|
57
|
-
test "conditions" do
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
end
|
57
|
+
#test "conditions" do
|
58
|
+
# options = User.aggregate_columns_options( :association => :posts, :column => :created_at, :function => :max, :conditions => { :active => true } )
|
59
|
+
# assert_equal "users.*, posts_created_at_max", options[:select]
|
60
|
+
# assert_equal "posts_created_at_max DESC", options[:order]
|
61
|
+
# assert_equal "LEFT JOIN (SELECT user_id, max(created_at) AS posts_created_at_max FROM posts WHERE posts.active = true GROUP BY user_id) posts_created_at_max_join ON posts.id = posts_created_at_max_join.user_id", options[:joins]
|
62
|
+
#end
|
63
63
|
|
64
|
-
test "joins" do
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
end
|
64
|
+
#test "joins" do
|
65
|
+
# time = 2.days.ago
|
66
|
+
# options = User.aggregate_columns_options( :association => :posts, :column => :created_at, :function => :max, :joins => "INNER JOIN comments ON comments.post_id = posts.id", :conditions => ["comments.updated_at > ?", time] )
|
67
|
+
# assert_equal "users.*, posts_created_at_max", options[:select]
|
68
|
+
# assert_equal "posts_created_at_max DESC", options[:order]
|
69
|
+
# assert_equal "LEFT JOIN (SELECT user_id, max(created_at) AS posts_created_at_max FROM posts INNER JOIN comments ON comments.post_id = posts.id WHERE comments.updated_at > #{time} GROUP BY user_id) posts_created_at_max_join ON posts.id = posts_created_at_max_join.user_id", options[:joins]
|
70
|
+
#end
|
71
71
|
|
72
|
-
test "order" do
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
end
|
72
|
+
#test "order" do
|
73
|
+
# options = User.aggregate_columns_options( :association => :posts, :order => :asc )
|
74
|
+
# assert_equal "users.*, post_count", options[:select]
|
75
|
+
# assert_equal "post_count ASC", options[:order]
|
76
|
+
# assert_equal "LEFT JOIN (SELECT user_id, count(*) AS post_count FROM posts GROUP BY user_id) post_count_join ON posts.id = post_count_join.user_id", options[:joins]
|
77
|
+
#end
|
78
78
|
|
79
79
|
# TODO:
|
80
80
|
# test multiple aggregates
|
data/test/test_helper.rb
CHANGED
metadata
CHANGED
@@ -1,70 +1,50 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: aggregate_columns
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.9.1
|
5
5
|
prerelease:
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 9
|
9
|
-
version: "0.9"
|
10
6
|
platform: ruby
|
11
|
-
authors:
|
7
|
+
authors:
|
12
8
|
- Marek Janukowicz
|
13
9
|
autorequire:
|
14
10
|
bindir: bin
|
15
11
|
cert_chain: []
|
16
|
-
|
17
|
-
date: 2011-11-23 00:00:00 +01:00
|
18
|
-
default_executable:
|
12
|
+
date: 2011-11-29 00:00:00.000000000 Z
|
19
13
|
dependencies: []
|
20
|
-
|
21
14
|
description:
|
22
15
|
email: marek@janukowicz.net
|
23
16
|
executables: []
|
24
|
-
|
25
17
|
extensions: []
|
26
|
-
|
27
|
-
extra_rdoc_files:
|
18
|
+
extra_rdoc_files:
|
28
19
|
- README
|
29
|
-
files:
|
20
|
+
files:
|
30
21
|
- Rakefile
|
31
22
|
- README
|
32
23
|
- lib/aggregate_columns.rb
|
33
24
|
- test/aggregate_columns_test.rb
|
34
25
|
- test/test_helper.rb
|
35
|
-
has_rdoc: true
|
36
26
|
homepage: http://www.bitbucket.org/starware/aggregate_columns
|
37
27
|
licenses: []
|
38
|
-
|
39
28
|
post_install_message:
|
40
29
|
rdoc_options: []
|
41
|
-
|
42
|
-
require_paths:
|
30
|
+
require_paths:
|
43
31
|
- lib
|
44
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
32
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
45
33
|
none: false
|
46
|
-
requirements:
|
47
|
-
- -
|
48
|
-
- !ruby/object:Gem::Version
|
49
|
-
|
50
|
-
|
51
|
-
- 0
|
52
|
-
version: "0"
|
53
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
39
|
none: false
|
55
|
-
requirements:
|
56
|
-
- -
|
57
|
-
- !ruby/object:Gem::Version
|
58
|
-
|
59
|
-
segments:
|
60
|
-
- 0
|
61
|
-
version: "0"
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
62
44
|
requirements: []
|
63
|
-
|
64
45
|
rubyforge_project:
|
65
|
-
rubygems_version: 1.
|
46
|
+
rubygems_version: 1.8.11
|
66
47
|
signing_key:
|
67
48
|
specification_version: 3
|
68
49
|
summary: Create and use aggregate columns in Rails applications
|
69
50
|
test_files: []
|
70
|
-
|