aggregate_columns 0.9.8 → 0.9.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -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