aggregate_columns 0.9.8 → 0.9.9

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.
@@ -1,135 +1,14 @@
1
1
  module AggregateColumns
2
-
3
- module MethodsRails2
4
-
5
- def aggregate_columns_options( *aggregates )
6
- all_joins = []
7
- all_selects = ["#{table_name}.*"]
8
- all_orders = []
9
- aggregates.each do |options|
10
- # Process options
11
- options.assert_valid_keys( :association, :column, :function, :result_column, :join_type, :conditions, :joins, :order )
12
- association = options[:association]
13
- unless association
14
- raise ArgumentError, "No association given"
15
- end
16
- field = options[:column] || '*'
17
- function = options[:function] || :count
18
- result_column = options[:result_column]
19
- unless result_column
20
- # Defaults:
21
- # count(*) on comments => comment_count
22
- # sum(votes) on comment => comments_votes_sum
23
- result_column ||= field == '*' ? "#{association.to_s.singularize}_#{function}" : "#{association}_#{field}_#{function}"
24
- end
25
- assoc_reflection = reflect_on_association( association )
26
- foreign_key = assoc_reflection.primary_key_name # As stupid as it looks, this is actually correct
27
- table_name = assoc_reflection.table_name
28
- klass = assoc_reflection.klass
29
- join_type = options[:join_type] || "LEFT" # TODO: check if in range of allowed values
30
- order = options[:order] || "DESC"
31
- conditions = options[:conditions]
32
- joins = options[:joins]
33
-
34
- # Now gather params for aggregate
35
- all_joins << "#{join_type.to_s.upcase} JOIN (SELECT #{foreign_key}, #{function}(#{field}) AS #{result_column} FROM #{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}"
36
- all_selects << result_column.to_s
37
- all_orders << "#{result_column} #{order.to_s.upcase}"
38
- end
39
- return { :joins => all_joins.join( "\n" ), :select => all_selects.join( ', ' ), :order => all_orders.join( ', ' ) }
40
- end
41
-
42
- def aggregate_columns_scope( *aggregates )
43
- scoped( aggregate_columns_options( *aggregates ))
44
- end
45
-
46
- end
47
-
48
- module MethodsRails3
49
-
50
- def aggregate_columns( options )
51
- rel = self.select( "#{table_name}.*" )
52
- # Process options
53
- options.assert_valid_keys( :association, :column, :function, :result_column, :join_type, :expression )
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
- aggregate_expression = options[:expression]
61
- result_column = options[:result_column]
62
- unless aggregate_expression
63
- field = options[:column] || '*'
64
- function = options[:function] || :count
65
- aggregate_expression = "#{function}(#{field})"
66
- # Defaults:
67
- # count(*) on comments => comment_count
68
- # sum(votes) on comment => comments_votes_sum
69
- result_column ||= field == '*' ? "#{association.to_s.singularize}_#{function}" : "#{association}_#{field}_#{function}"
70
- end
71
- # TODO: this only works on ActiveRecord::Base classes - would be nice
72
- # (and not that complicated) to make it work on ActiveRecord::Relation
73
- # instances
74
- assoc_reflection = reflect_on_association( association )
75
- # TODO: this only handles single :through association
76
- through_reflection = assoc_reflection.through_reflection
77
- foreign_key = assoc_reflection.foreign_key
78
- aggregate_table_name = assoc_reflection.table_name
79
- klass = assoc_reflection.klass
80
- join_type = options[:join_type] # TODO: check if within allowed values
81
-
82
- # This is the reflection to use to "join" with main table
83
- join_reflection = through_reflection || assoc_reflection
84
- join_foreign_key = join_reflection.foreign_key
85
- aggregate_rel = klass.select( "#{aggregate_expression} AS #{result_column}" ).from( aggregate_table_name )
86
- if through_reflection
87
- aggregate_rel = aggregate_rel.joins( "INNER JOIN #{through_reflection.table_name} ON #{through_reflection.table_name}.id = #{aggregate_table_name}.#{assoc_reflection.foreign_key}" )
88
- end
89
-
90
- # TODO: this only handles :conditions and in a specific way - it should
91
- # really handle other options as well
92
- assoc_conditions = assoc_reflection.conditions.first.first
93
- if assoc_conditions
94
- aggregate_rel = aggregate_rel.where( klass.send( :sanitize_sql, assoc_conditions ))
95
- end
96
- if through_reflection
97
- through_conditions = through_reflection.conditions.first.first
98
- if through_conditions
99
- aggregate_rel = aggregate_rel.where( through_reflection.klass.send( :sanitize_sql, through_conditions ))
100
- end
101
- end
102
-
103
- if join_type
104
- aggregate_rel = aggregate_rel.select( join_foreign_key ).group( join_foreign_key )
105
- aggregate_rel = yield( aggregate_rel ) if block_given?
106
- rel = rel.
107
- joins( "#{join_type.to_s.upcase} JOIN (#{aggregate_rel.to_sql}) #{result_column}_join ON #{table_name}.id = #{result_column}_join.#{join_foreign_key}" ).
108
- select( result_column.to_s ).
109
- order( "#{result_column} DESC" ) # You might reorder if you want to have it differently
110
- else
111
- aggregate_rel = aggregate_rel.where( "#{table_name}.id = #{join_reflection.quoted_table_name}.#{join_reflection.foreign_key}" )
112
- aggregate_rel = yield( aggregate_rel ) if block_given?
113
- rel = rel.
114
- select( "(#{aggregate_rel.to_sql}) AS #{result_column}" ).
115
- order( "#{result_column} DESC" ) # You might reorder if you want to have it differently
116
- end
117
- return rel
118
- end
119
- end
120
-
121
2
  end
122
3
 
123
- if defined?( ActiveRecord::Relation ) # Rails 3
124
- ActiveRecord::Base.send( :extend, AggregateColumns::MethodsRails3 )
125
- else # Rails 2
4
+ case ActiveRecord::VERSION::MAJOR
5
+ when 2
6
+ require 'aggregate_columns/methods_rails_2'
126
7
  ActiveRecord::Base.send( :extend, AggregateColumns::MethodsRails2 )
8
+ when 3
9
+ require 'aggregate_columns/methods_rails_3'
10
+ ActiveRecord::Base.send( :extend, AggregateColumns::MethodsRails3 )
11
+ when 4
12
+ require 'aggregate_columns/methods_rails_4'
13
+ ActiveRecord::Base.send( :extend, AggregateColumns::MethodsRails4 )
127
14
  end
128
-
129
- ## Rails 2
130
- #if defined?( ActiveRecord::NamedScope )
131
- # ActiveRecord::Associations::AssociationCollection.send( :include, AggregateColumns::MethodsRails2 )
132
- # ActiveRecord::NamedScope::Scope.send( :include, AggregateColumns::MethodsRails2 )
133
- ## Rails 3
134
- #ActiveRecord::Associations::CollectionProxy.send( :include, AggregateColumns::Methods ) if defined?( ActiveRecord::Associations::CollectionProxy )
135
- #ActiveRecord::Relation.send( :include, AggregateColumns::Methods ) if defined?( ActiveRecord::Relation )
@@ -0,0 +1,47 @@
1
+ module AggregateColumns
2
+
3
+ module MethodsRails2
4
+
5
+ def aggregate_columns_options( *aggregates )
6
+ all_joins = []
7
+ all_selects = ["#{table_name}.*"]
8
+ all_orders = []
9
+ aggregates.each do |options|
10
+ # Process options
11
+ options.assert_valid_keys( :association, :column, :function, :result_column, :join_type, :conditions, :joins, :order )
12
+ association = options[:association]
13
+ unless association
14
+ raise ArgumentError, "No association given"
15
+ end
16
+ field = options[:column] || '*'
17
+ function = options[:function] || :count
18
+ result_column = options[:result_column]
19
+ unless result_column
20
+ # Defaults:
21
+ # count(*) on comments => comment_count
22
+ # sum(votes) on comment => comments_votes_sum
23
+ result_column ||= field == '*' ? "#{association.to_s.singularize}_#{function}" : "#{association}_#{field}_#{function}"
24
+ end
25
+ assoc_reflection = reflect_on_association( association )
26
+ foreign_key = assoc_reflection.primary_key_name # As stupid as it looks, this is actually correct
27
+ table_name = assoc_reflection.table_name
28
+ klass = assoc_reflection.klass
29
+ join_type = options[:join_type] || "LEFT" # TODO: check if in range of allowed values
30
+ order = options[:order] || "DESC"
31
+ conditions = options[:conditions]
32
+ joins = options[:joins]
33
+
34
+ # Now gather params for aggregate
35
+ all_joins << "#{join_type.to_s.upcase} JOIN (SELECT #{foreign_key}, #{function}(#{field}) AS #{result_column} FROM #{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}"
36
+ all_selects << result_column.to_s
37
+ all_orders << "#{result_column} #{order.to_s.upcase}"
38
+ end
39
+ return { :joins => all_joins.join( "\n" ), :select => all_selects.join( ', ' ), :order => all_orders.join( ', ' ) }
40
+ end
41
+
42
+ def aggregate_columns_scope( *aggregates )
43
+ scoped( aggregate_columns_options( *aggregates ))
44
+ end
45
+
46
+ end
47
+ end
@@ -0,0 +1,76 @@
1
+ module AggregateColumns
2
+
3
+ module MethodsRails3
4
+
5
+ def aggregate_columns( options )
6
+ rel = self.select( "#{table_name}.*" )
7
+ # Process options
8
+ options.assert_valid_keys( :association, :column, :function, :result_column, :join_type, :expression )
9
+ association = options[:association]
10
+ unless association
11
+ raise ArgumentError, "No association given"
12
+ end
13
+ #field = options[:column] || '*'
14
+ #function = options[:function] || :count
15
+ aggregate_expression = options[:expression]
16
+ result_column = options[:result_column]
17
+ unless aggregate_expression
18
+ field = options[:column] || '*'
19
+ function = options[:function] || :count
20
+ aggregate_expression = "#{function}(#{field})"
21
+ # Defaults:
22
+ # count(*) on comments => comment_count
23
+ # sum(votes) on comment => comments_votes_sum
24
+ result_column ||= field == '*' ? "#{association.to_s.singularize}_#{function}" : "#{association}_#{field}_#{function}"
25
+ end
26
+ # TODO: this only works on ActiveRecord::Base classes - would be nice
27
+ # (and not that complicated) to make it work on ActiveRecord::Relation
28
+ # instances
29
+ assoc_reflection = reflect_on_association( association )
30
+ # TODO: this only handles single :through association
31
+ through_reflection = assoc_reflection.through_reflection
32
+ foreign_key = assoc_reflection.foreign_key
33
+ aggregate_table_name = assoc_reflection.table_name
34
+ klass = assoc_reflection.klass
35
+ join_type = options[:join_type] # TODO: check if within allowed values
36
+
37
+ # This is the reflection to use to "join" with main table
38
+ join_reflection = through_reflection || assoc_reflection
39
+ join_foreign_key = join_reflection.foreign_key
40
+ aggregate_rel = klass.select( "#{aggregate_expression} AS #{result_column}" ).from( aggregate_table_name )
41
+ if through_reflection
42
+ aggregate_rel = aggregate_rel.joins( "INNER JOIN #{through_reflection.table_name} ON #{through_reflection.table_name}.id = #{aggregate_table_name}.#{assoc_reflection.foreign_key}" )
43
+ end
44
+
45
+ # TODO: this only handles :conditions and in a specific way - it should
46
+ # really handle other options as well
47
+ assoc_conditions = assoc_reflection.conditions.first.first
48
+ if assoc_conditions
49
+ aggregate_rel = aggregate_rel.where( klass.send( :sanitize_sql, assoc_conditions ))
50
+ end
51
+ if through_reflection
52
+ through_conditions = through_reflection.conditions.first.first
53
+ if through_conditions
54
+ aggregate_rel = aggregate_rel.where( through_reflection.klass.send( :sanitize_sql, through_conditions ))
55
+ end
56
+ end
57
+
58
+ if join_type
59
+ aggregate_rel = aggregate_rel.select( join_foreign_key ).group( join_foreign_key )
60
+ aggregate_rel = yield( aggregate_rel ) if block_given?
61
+ rel = rel.
62
+ joins( "#{join_type.to_s.upcase} JOIN (#{aggregate_rel.to_sql}) #{result_column}_join ON #{table_name}.id = #{result_column}_join.#{join_foreign_key}" ).
63
+ select( result_column.to_s ).
64
+ order( "#{result_column} DESC" ) # You might reorder if you want to have it differently
65
+ else
66
+ aggregate_rel = aggregate_rel.where( "#{table_name}.id = #{join_reflection.quoted_table_name}.#{join_reflection.foreign_key}" )
67
+ aggregate_rel = yield( aggregate_rel ) if block_given?
68
+ rel = rel.
69
+ select( "(#{aggregate_rel.to_sql}) AS #{result_column}" ).
70
+ order( "#{result_column} DESC" ) # You might reorder if you want to have it differently
71
+ end
72
+ return rel
73
+ end
74
+ end
75
+
76
+ end
@@ -0,0 +1,71 @@
1
+ module AggregateColumns
2
+
3
+ module MethodsRails4
4
+
5
+ def aggregate_columns( options )
6
+ rel = self.select( "#{table_name}.*" )
7
+ # Process options
8
+ options.assert_valid_keys( :association, :column, :function, :result_column, :join_type, :expression )
9
+ association = options[:association]
10
+ unless association
11
+ raise ArgumentError, "No association given"
12
+ end
13
+ #field = options[:column] || '*'
14
+ #function = options[:function] || :count
15
+ aggregate_expression = options[:expression]
16
+ result_column = options[:result_column]
17
+ unless aggregate_expression
18
+ field = options[:column] || '*'
19
+ function = options[:function] || :count
20
+ aggregate_expression = "#{function}(#{field})"
21
+ # Defaults:
22
+ # count(*) on comments => comment_count
23
+ # sum(votes) on comment => comments_votes_sum
24
+ result_column ||= field == '*' ? "#{association.to_s.singularize}_#{function}" : "#{association}_#{field}_#{function}"
25
+ end
26
+ # TODO: this only works on ActiveRecord::Base classes - would be nice
27
+ # (and not that complicated) to make it work on ActiveRecord::Relation
28
+ # instances
29
+ assoc_reflection = reflect_on_association( association )
30
+ # TODO: this only handles single :through association
31
+ through_reflection = assoc_reflection.through_reflection
32
+ foreign_key = assoc_reflection.foreign_key
33
+ aggregate_table_name = assoc_reflection.table_name
34
+ klass = assoc_reflection.klass
35
+ join_type = options[:join_type] # TODO: check if within allowed values
36
+
37
+ # This is the reflection to use to "join" with main table
38
+ join_reflection = through_reflection || assoc_reflection
39
+ join_foreign_key = join_reflection.foreign_key
40
+ aggregate_rel = klass.select( "#{aggregate_expression} AS #{result_column}" ).from( aggregate_table_name )
41
+ if through_reflection
42
+ aggregate_rel = aggregate_rel.joins( "INNER JOIN #{through_reflection.table_name} ON #{through_reflection.table_name}.id = #{aggregate_table_name}.#{assoc_reflection.foreign_key}" )
43
+ end
44
+
45
+ # TODO: I never needed this part, so it's completely untested
46
+ if assoc_reflection.scope
47
+ aggregate_rel = aggregate_rel.merge( assoc_reflection.scope )
48
+ end
49
+ if through_reflection && through_reflection.scope
50
+ aggregate_rel = aggregate_rel.merge( through_reflection.scope )
51
+ end
52
+
53
+ if join_type
54
+ aggregate_rel = aggregate_rel.select( join_foreign_key ).group( join_foreign_key )
55
+ aggregate_rel = yield( aggregate_rel ) if block_given?
56
+ rel = rel.
57
+ joins( "#{join_type.to_s.upcase} JOIN (#{aggregate_rel.to_sql}) #{result_column}_join ON #{table_name}.id = #{result_column}_join.#{join_foreign_key}" ).
58
+ select( result_column.to_s ).
59
+ order( "#{result_column} DESC" ) # You might reorder if you want to have it differently
60
+ else
61
+ aggregate_rel = aggregate_rel.where( "#{table_name}.id = #{join_reflection.quoted_table_name}.#{join_reflection.foreign_key}" )
62
+ aggregate_rel = yield( aggregate_rel ) if block_given?
63
+ rel = rel.
64
+ select( "(#{aggregate_rel.to_sql}) AS #{result_column}" ).
65
+ order( "#{result_column} DESC" ) # You might reorder if you want to have it differently
66
+ end
67
+ return rel
68
+ end
69
+ end
70
+
71
+ end
@@ -1,3 +1,3 @@
1
1
  module AggregateColumns
2
- VERSION = "0.9.8"
2
+ VERSION = "0.9.9"
3
3
  end
metadata CHANGED
@@ -1,113 +1,153 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: aggregate_columns
3
- version: !ruby/object:Gem::Version
4
- version: 0.9.8
3
+ version: !ruby/object:Gem::Version
4
+ hash: 41
5
5
  prerelease:
6
+ segments:
7
+ - 0
8
+ - 9
9
+ - 9
10
+ version: 0.9.9
6
11
  platform: ruby
7
- authors:
12
+ authors:
8
13
  - Marek Janukowicz/Starware
9
14
  autorequire:
10
15
  bindir: bin
11
16
  cert_chain: []
12
- date: 2012-02-02 00:00:00.000000000 Z
13
- dependencies:
14
- - !ruby/object:Gem::Dependency
17
+
18
+ date: 2014-12-12 00:00:00 +01:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
15
22
  name: activerecord
16
- requirement: &7078140 !ruby/object:Gem::Requirement
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
17
25
  none: false
18
- requirements:
19
- - - ! '>='
20
- - !ruby/object:Gem::Version
21
- version: '2'
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 7
30
+ segments:
31
+ - 2
32
+ version: "2"
22
33
  type: :runtime
23
- prerelease: false
24
- version_requirements: *7078140
25
- - !ruby/object:Gem::Dependency
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
26
36
  name: rake
27
- requirement: &7077260 !ruby/object:Gem::Requirement
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
28
39
  none: false
29
- requirements:
30
- - - ! '>='
31
- - !ruby/object:Gem::Version
32
- version: '0'
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 3
44
+ segments:
45
+ - 0
46
+ version: "0"
33
47
  type: :development
34
- prerelease: false
35
- version_requirements: *7077260
36
- - !ruby/object:Gem::Dependency
48
+ version_requirements: *id002
49
+ - !ruby/object:Gem::Dependency
37
50
  name: activerecord
38
- requirement: &7075460 !ruby/object:Gem::Requirement
51
+ prerelease: false
52
+ requirement: &id003 !ruby/object:Gem::Requirement
39
53
  none: false
40
- requirements:
41
- - - ! '>='
42
- - !ruby/object:Gem::Version
43
- version: '2'
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ hash: 7
58
+ segments:
59
+ - 2
60
+ version: "2"
44
61
  type: :development
45
- prerelease: false
46
- version_requirements: *7075460
47
- - !ruby/object:Gem::Dependency
62
+ version_requirements: *id003
63
+ - !ruby/object:Gem::Dependency
48
64
  name: activesupport
49
- requirement: &7073600 !ruby/object:Gem::Requirement
65
+ prerelease: false
66
+ requirement: &id004 !ruby/object:Gem::Requirement
50
67
  none: false
51
- requirements:
52
- - - ! '>='
53
- - !ruby/object:Gem::Version
54
- version: '2'
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ hash: 7
72
+ segments:
73
+ - 2
74
+ version: "2"
55
75
  type: :development
56
- prerelease: false
57
- version_requirements: *7073600
58
- - !ruby/object:Gem::Dependency
76
+ version_requirements: *id004
77
+ - !ruby/object:Gem::Dependency
59
78
  name: activerecord-nulldb-adapter
60
- requirement: &7072440 !ruby/object:Gem::Requirement
79
+ prerelease: false
80
+ requirement: &id005 !ruby/object:Gem::Requirement
61
81
  none: false
62
- requirements:
63
- - - =
64
- - !ruby/object:Gem::Version
82
+ requirements:
83
+ - - "="
84
+ - !ruby/object:Gem::Version
85
+ hash: 23
86
+ segments:
87
+ - 0
88
+ - 2
89
+ - 0
65
90
  version: 0.2.0
66
91
  type: :development
67
- prerelease: false
68
- version_requirements: *7072440
69
- description: ''
70
- email:
92
+ version_requirements: *id005
93
+ description: ""
94
+ email:
71
95
  - marek@janukowicz.net
72
96
  executables: []
97
+
73
98
  extensions: []
99
+
74
100
  extra_rdoc_files: []
75
- files:
101
+
102
+ files:
76
103
  - .hgignore
77
104
  - Gemfile
78
105
  - README
79
106
  - Rakefile
80
107
  - aggregate_columns.gemspec
81
108
  - lib/aggregate_columns.rb
109
+ - lib/aggregate_columns/methods_rails_2.rb
110
+ - lib/aggregate_columns/methods_rails_3.rb
111
+ - lib/aggregate_columns/methods_rails_4.rb
82
112
  - lib/aggregate_columns/version.rb
83
113
  - test/rails_2_test.rb
84
114
  - test/rails_3_test.rb
85
115
  - test/test_helper.rb
86
- homepage: ''
116
+ has_rdoc: true
117
+ homepage: ""
87
118
  licenses: []
119
+
88
120
  post_install_message:
89
121
  rdoc_options: []
90
- require_paths:
122
+
123
+ require_paths:
91
124
  - lib
92
- required_ruby_version: !ruby/object:Gem::Requirement
125
+ required_ruby_version: !ruby/object:Gem::Requirement
93
126
  none: false
94
- requirements:
95
- - - ! '>='
96
- - !ruby/object:Gem::Version
97
- version: '0'
98
- required_rubygems_version: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - ">="
129
+ - !ruby/object:Gem::Version
130
+ hash: 3
131
+ segments:
132
+ - 0
133
+ version: "0"
134
+ required_rubygems_version: !ruby/object:Gem::Requirement
99
135
  none: false
100
- requirements:
101
- - - ! '>='
102
- - !ruby/object:Gem::Version
103
- version: '0'
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ hash: 3
140
+ segments:
141
+ - 0
142
+ version: "0"
104
143
  requirements: []
144
+
105
145
  rubyforge_project:
106
- rubygems_version: 1.8.11
146
+ rubygems_version: 1.6.2
107
147
  signing_key:
108
148
  specification_version: 3
109
149
  summary: Create and use aggregate columns in Rails applications
110
- test_files:
150
+ test_files:
111
151
  - test/rails_2_test.rb
112
152
  - test/rails_3_test.rb
113
153
  - test/test_helper.rb