Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 277 lines (248 sloc) 14.659 kB
99307b9 @dhh Added calculations: Base.count, Base.average, Base.sum, Base.minimum,…
dhh authored
1 module ActiveRecord
fed7d33 @dhh Fixed documentation
dhh authored
2 module Calculations #:nodoc:
4251662 @technoweenie Allow all calculations to take the :include option, not just COUNT (c…
technoweenie authored
3 CALCULATIONS_OPTIONS = [:conditions, :joins, :order, :select, :group, :having, :distinct, :limit, :offset, :include]
99307b9 @dhh Added calculations: Base.count, Base.average, Base.sum, Base.minimum,…
dhh authored
4 def self.included(base)
5 base.extend(ClassMethods)
6 end
7
8 module ClassMethods
a413056 @technoweenie Fix and properly document/test count(column_name) usage. Closes #8999…
technoweenie authored
9 # Count operates using three different approaches.
99307b9 @dhh Added calculations: Base.count, Base.average, Base.sum, Base.minimum,…
dhh authored
10 #
11 # * Count all: By not passing any parameters to count, it will return a count of all the rows for the model.
64092de @fxn Improve documentation coverage and markup
fxn authored
12 # * Count using column: By passing a column name to count, it will return a count of all the rows for the model with supplied column present
99307b9 @dhh Added calculations: Base.count, Base.average, Base.sum, Base.minimum,…
dhh authored
13 # * Count using options will find the row count matched by the options used.
14 #
a413056 @technoweenie Fix and properly document/test count(column_name) usage. Closes #8999…
technoweenie authored
15 # The third approach, count using options, accepts an option hash as the only parameter. The options are:
99307b9 @dhh Added calculations: Base.count, Base.average, Base.sum, Base.minimum,…
dhh authored
16 #
17 # * <tt>:conditions</tt>: An SQL fragment like "administrator = 1" or [ "user_name = ?", username ]. See conditions in the intro.
9661395 Remove references to nonexistent :joins documentation. Closes #10498 …
Marcel Molina authored
18 # * <tt>:joins</tt>: Either an SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id" (rarely needed)
64092de @fxn Improve documentation coverage and markup
fxn authored
19 # or named associations in the same form used for the <tt>:include</tt> option, which will perform an INNER JOIN on the associated table(s).
7143d80 Smattering of grammatical fixes to documentation. Closes #10083 [BobS…
Marcel Molina authored
20 # If the value is a string, then the records will be returned read-only since they will have attributes that do not correspond to the table's columns.
64092de @fxn Improve documentation coverage and markup
fxn authored
21 # Pass <tt>:readonly => false</tt> to override.
99307b9 @dhh Added calculations: Base.count, Base.average, Base.sum, Base.minimum,…
dhh authored
22 # * <tt>:include</tt>: Named associations that should be loaded alongside using LEFT OUTER JOINs. The symbols named refer
7143d80 Smattering of grammatical fixes to documentation. Closes #10083 [BobS…
Marcel Molina authored
23 # to already defined associations. When using named associations, count returns the number of DISTINCT items for the model you're counting.
99307b9 @dhh Added calculations: Base.count, Base.average, Base.sum, Base.minimum,…
dhh authored
24 # See eager loading under Associations.
a8d085a @dhh Make calculations typecasty! (closes #4016) [Rick Olson]
dhh authored
25 # * <tt>:order</tt>: An SQL fragment like "created_at DESC, name" (really only used with GROUP BY calculations).
26 # * <tt>:group</tt>: An attribute name by which the result should be grouped. Uses the GROUP BY SQL-clause.
7143d80 Smattering of grammatical fixes to documentation. Closes #10083 [BobS…
Marcel Molina authored
27 # * <tt>:select</tt>: By default, this is * as in SELECT * FROM, but can be changed if you, for example, want to do a join but not
a8d085a @dhh Make calculations typecasty! (closes #4016) [Rick Olson]
dhh authored
28 # include the joined columns.
29 # * <tt>:distinct</tt>: Set this to true to make this a distinct calculation, such as SELECT COUNT(DISTINCT posts.id) ...
99307b9 @dhh Added calculations: Base.count, Base.average, Base.sum, Base.minimum,…
dhh authored
30 #
31 # Examples for counting all:
32 # Person.count # returns the total count of all people
33 #
a413056 @technoweenie Fix and properly document/test count(column_name) usage. Closes #8999…
technoweenie authored
34 # Examples for counting by column:
35 # Person.count(:age) # returns the total count of all people whose age is present in database
36 #
99307b9 @dhh Added calculations: Base.count, Base.average, Base.sum, Base.minimum,…
dhh authored
37 # Examples for count with options:
38 # Person.count(:conditions => "age > 26")
39 # Person.count(:conditions => "age > 26 AND job.salary > 60000", :include => :job) # because of the named association, it finds the DISTINCT count using LEFT OUTER JOIN.
b6171e7 @jeremy SQLite: count(distinct) queries supported in >= 3.2.6, fix calculatio…
jeremy authored
40 # Person.count(:conditions => "age > 26 AND job.salary > 60000", :joins => "LEFT JOIN jobs on jobs.person_id = person.id") # finds the number of rows matching the conditions and joins.
99307b9 @dhh Added calculations: Base.count, Base.average, Base.sum, Base.minimum,…
dhh authored
41 # Person.count('id', :conditions => "age > 26") # Performs a COUNT(id)
42 # Person.count(:all, :conditions => "age > 26") # Performs a COUNT(*) (:all is an alias for '*')
43 #
64092de @fxn Improve documentation coverage and markup
fxn authored
44 # Note: <tt>Person.count(:all)</tt> will not work because it will use <tt>:all</tt> as the condition. Use Person.count instead.
99307b9 @dhh Added calculations: Base.count, Base.average, Base.sum, Base.minimum,…
dhh authored
45 def count(*args)
872c5f4 @technoweenie Remove deprecated count(conditions=nil, joins=nil) usage. Closes #89…
technoweenie authored
46 calculate(:count, *construct_count_options_from_args(*args))
99307b9 @dhh Added calculations: Base.count, Base.average, Base.sum, Base.minimum,…
dhh authored
47 end
48
98dc582 @lifo Merge docrails.
lifo authored
49 # Calculates the average value on a given column. The value is returned as a float. See +calculate+ for examples with options.
99307b9 @dhh Added calculations: Base.count, Base.average, Base.sum, Base.minimum,…
dhh authored
50 #
51 # Person.average('age')
52 def average(column_name, options = {})
53 calculate(:avg, column_name, options)
54 end
55
98dc582 @lifo Merge docrails.
lifo authored
56 # Calculates the minimum value on a given column. The value is returned with the same data type of the column. See +calculate+ for examples with options.
99307b9 @dhh Added calculations: Base.count, Base.average, Base.sum, Base.minimum,…
dhh authored
57 #
58 # Person.minimum('age')
59 def minimum(column_name, options = {})
60 calculate(:min, column_name, options)
61 end
62
98dc582 @lifo Merge docrails.
lifo authored
63 # Calculates the maximum value on a given column. The value is returned with the same data type of the column. See +calculate+ for examples with options.
99307b9 @dhh Added calculations: Base.count, Base.average, Base.sum, Base.minimum,…
dhh authored
64 #
65 # Person.maximum('age')
66 def maximum(column_name, options = {})
67 calculate(:max, column_name, options)
68 end
69
98dc582 @lifo Merge docrails.
lifo authored
70 # Calculates the sum of values on a given column. The value is returned with the same data type of the column. See +calculate+ for examples with options.
99307b9 @dhh Added calculations: Base.count, Base.average, Base.sum, Base.minimum,…
dhh authored
71 #
456ddc6 @dhh Doc fix (closes #4014) [thijs@fngtps.com]
dhh authored
72 # Person.sum('age')
99307b9 @dhh Added calculations: Base.count, Base.average, Base.sum, Base.minimum,…
dhh authored
73 def sum(column_name, options = {})
4210d85 Ensure Associations#sum returns 0 when no rows are returned. [#295 st…
Jonathan Viney authored
74 calculate(:sum, column_name, options)
99307b9 @dhh Added calculations: Base.count, Base.average, Base.sum, Base.minimum,…
dhh authored
75 end
76
7143d80 Smattering of grammatical fixes to documentation. Closes #10083 [BobS…
Marcel Molina authored
77 # This calculates aggregate values in the given column. Methods for count, sum, average, minimum, and maximum have been added as shortcuts.
64092de @fxn Improve documentation coverage and markup
fxn authored
78 # Options such as <tt>:conditions</tt>, <tt>:order</tt>, <tt>:group</tt>, <tt>:having</tt>, and <tt>:joins</tt> can be passed to customize the query.
99307b9 @dhh Added calculations: Base.count, Base.average, Base.sum, Base.minimum,…
dhh authored
79 #
80 # There are two basic forms of output:
81 # * Single aggregate value: The single value is type cast to Fixnum for COUNT, Float for AVG, and the given column's type for everything else.
64092de @fxn Improve documentation coverage and markup
fxn authored
82 # * Grouped values: This returns an ordered hash of the values and groups them by the <tt>:group</tt> option. It takes either a column name, or the name
99307b9 @dhh Added calculations: Base.count, Base.average, Base.sum, Base.minimum,…
dhh authored
83 # of a belongs_to association.
84 #
85 # values = Person.maximum(:age, :group => 'last_name')
86 # puts values["Drake"]
87 # => 43
88 #
89 # drake = Family.find_by_last_name('Drake')
90 # values = Person.maximum(:age, :group => :family) # Person belongs_to :family
91 # puts values[drake]
92 # => 43
93 #
94 # values.each do |family, max_age|
95 # ...
96 # end
97 #
a8d085a @dhh Make calculations typecasty! (closes #4016) [Rick Olson]
dhh authored
98 # Options:
9450262 Standardize on using hyphens rather than colons to separate option na…
Marcel Molina authored
99 # * <tt>:conditions</tt> - An SQL fragment like "administrator = 1" or [ "user_name = ?", username ]. See conditions in the intro.
ee6b607 Document how the :include option can be used in Calculations::calcula…
Marcel Molina authored
100 # * <tt>:include</tt>: Eager loading, see Associations for details. Since calculations don't load anything, the purpose of this is to access fields on joined tables in your conditions, order, or group clauses.
9450262 Standardize on using hyphens rather than colons to separate option na…
Marcel Molina authored
101 # * <tt>:joins</tt> - An SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id". (Rarely needed).
a8d085a @dhh Make calculations typecasty! (closes #4016) [Rick Olson]
dhh authored
102 # The records will be returned read-only since they will have attributes that do not correspond to the table's columns.
9450262 Standardize on using hyphens rather than colons to separate option na…
Marcel Molina authored
103 # * <tt>:order</tt> - An SQL fragment like "created_at DESC, name" (really only used with GROUP BY calculations).
104 # * <tt>:group</tt> - An attribute name by which the result should be grouped. Uses the GROUP BY SQL-clause.
105 # * <tt>:select</tt> - By default, this is * as in SELECT * FROM, but can be changed if you for example want to do a join, but not
a8d085a @dhh Make calculations typecasty! (closes #4016) [Rick Olson]
dhh authored
106 # include the joined columns.
9450262 Standardize on using hyphens rather than colons to separate option na…
Marcel Molina authored
107 # * <tt>:distinct</tt> - Set this to true to make this a distinct calculation, such as SELECT COUNT(DISTINCT posts.id) ...
a8d085a @dhh Make calculations typecasty! (closes #4016) [Rick Olson]
dhh authored
108 #
99307b9 @dhh Added calculations: Base.count, Base.average, Base.sum, Base.minimum,…
dhh authored
109 # Examples:
110 # Person.calculate(:count, :all) # The same as Person.count
111 # Person.average(:age) # SELECT AVG(age) FROM people...
112 # Person.minimum(:age, :conditions => ['last_name != ?', 'Drake']) # Selects the minimum age for everyone with a last name other than 'Drake'
113 # Person.minimum(:age, :having => 'min(age) > 17', :group => :last_name) # Selects the minimum age for any family without any minors
9e45586 @dhh Ensure that you can still do expressions in calculations (closes #113…
dhh authored
114 # Person.sum("2 * age")
99307b9 @dhh Added calculations: Base.count, Base.average, Base.sum, Base.minimum,…
dhh authored
115 def calculate(operation, column_name, options = {})
a8d085a @dhh Make calculations typecasty! (closes #4016) [Rick Olson]
dhh authored
116 validate_calculation_options(operation, options)
117 column_name = options[:select] if options[:select]
ad9f678 @dhh Compatibility patches for calculations
dhh authored
118 column_name = '*' if column_name == :all
a8d085a @dhh Make calculations typecasty! (closes #4016) [Rick Olson]
dhh authored
119 column = column_for column_name
4251662 @technoweenie Allow all calculations to take the :include option, not just COUNT (c…
technoweenie authored
120 catch :invalid_query do
121 if options[:group]
122 return execute_grouped_calculation(operation, column_name, column, options)
123 else
124 return execute_simple_calculation(operation, column_name, column, options)
125 end
99307b9 @dhh Added calculations: Base.count, Base.average, Base.sum, Base.minimum,…
dhh authored
126 end
4251662 @technoweenie Allow all calculations to take the :include option, not just COUNT (c…
technoweenie authored
127 0
99307b9 @dhh Added calculations: Base.count, Base.average, Base.sum, Base.minimum,…
dhh authored
128 end
129
130 protected
872c5f4 @technoweenie Remove deprecated count(conditions=nil, joins=nil) usage. Closes #89…
technoweenie authored
131 def construct_count_options_from_args(*args)
df7b746 @technoweenie Fix the HasManyAssociation#count method so it uses the new ActiveReco…
technoweenie authored
132 options = {}
133 column_name = :all
a413056 @technoweenie Fix and properly document/test count(column_name) usage. Closes #8999…
technoweenie authored
134
a0bf019 @jeremy Deprecation: count class method should be called with an options hash…
jeremy authored
135 # We need to handle
136 # count()
a413056 @technoweenie Fix and properly document/test count(column_name) usage. Closes #8999…
technoweenie authored
137 # count(:column_name=:all)
a0bf019 @jeremy Deprecation: count class method should be called with an options hash…
jeremy authored
138 # count(options={})
139 # count(column_name=:all, options={})
a413056 @technoweenie Fix and properly document/test count(column_name) usage. Closes #8999…
technoweenie authored
140 case args.size
141 when 1
142 args[0].is_a?(Hash) ? options = args[0] : column_name = args[0]
143 when 2
872c5f4 @technoweenie Remove deprecated count(conditions=nil, joins=nil) usage. Closes #89…
technoweenie authored
144 column_name, options = args
145 else
a413056 @technoweenie Fix and properly document/test count(column_name) usage. Closes #8999…
technoweenie authored
146 raise ArgumentError, "Unexpected parameters passed to count(): #{args.inspect}"
872c5f4 @technoweenie Remove deprecated count(conditions=nil, joins=nil) usage. Closes #89…
technoweenie authored
147 end if args.size > 0
a413056 @technoweenie Fix and properly document/test count(column_name) usage. Closes #8999…
technoweenie authored
148
df7b746 @technoweenie Fix the HasManyAssociation#count method so it uses the new ActiveReco…
technoweenie authored
149 [column_name, options]
150 end
a0bf019 @jeremy Deprecation: count class method should be called with an options hash…
jeremy authored
151
4251662 @technoweenie Allow all calculations to take the :include option, not just COUNT (c…
technoweenie authored
152 def construct_calculation_sql(operation, column_name, options) #:nodoc:
b6171e7 @jeremy SQLite: count(distinct) queries supported in >= 3.2.6, fix calculatio…
jeremy authored
153 operation = operation.to_s.downcase
154 options = options.symbolize_keys
155
37adea6 @dhh Address shortcomings of changeset [8054] [protocool]
dhh authored
156 scope = scope(:find)
4251662 @technoweenie Allow all calculations to take the :include option, not just COUNT (c…
technoweenie authored
157 merged_includes = merge_includes(scope ? scope[:include] : [], options[:include])
158 aggregate_alias = column_alias_for(operation, column_name)
9e45586 @dhh Ensure that you can still do expressions in calculations (closes #113…
dhh authored
159 column_name = "#{connection.quote_table_name(table_name)}.#{column_name}" if column_names.include?(column_name.to_s)
4251662 @technoweenie Allow all calculations to take the :include option, not just COUNT (c…
technoweenie authored
160
b6171e7 @jeremy SQLite: count(distinct) queries supported in >= 3.2.6, fix calculatio…
jeremy authored
161 if operation == 'count'
162 if merged_includes.any?
163 options[:distinct] = true
8f74527 @NZKoz Escape table names during calculation queries. [wesley.moxam, Koz] Cl…
NZKoz authored
164 column_name = options[:select] || [connection.quote_table_name(table_name), primary_key] * '.'
b6171e7 @jeremy SQLite: count(distinct) queries supported in >= 3.2.6, fix calculatio…
jeremy authored
165 end
166
167 if options[:distinct]
168 use_workaround = !connection.supports_count_distinct?
169 end
4251662 @technoweenie Allow all calculations to take the :include option, not just COUNT (c…
technoweenie authored
170 end
171
50538fb @NZKoz Don't double include DISTINCT when the user has already specified it.…
NZKoz authored
172 if options[:distinct] && column_name.to_s !~ /\s*DISTINCT\s+/i
173 distinct = 'DISTINCT '
174 end
175 sql = "SELECT #{operation}(#{distinct}#{column_name}) AS #{aggregate_alias}"
4251662 @technoweenie Allow all calculations to take the :include option, not just COUNT (c…
technoweenie authored
176
177 # A (slower) workaround if we're using a backend, like sqlite, that doesn't support COUNT DISTINCT.
178 sql = "SELECT COUNT(*) AS #{aggregate_alias}" if use_workaround
b6171e7 @jeremy SQLite: count(distinct) queries supported in >= 3.2.6, fix calculatio…
jeremy authored
179
fed7d33 @dhh Fixed documentation
dhh authored
180 sql << ", #{options[:group_field]} AS #{options[:group_alias]}" if options[:group]
55622e0 @fcheung Avoid adding two DISTINCT statements to queries in sqlite 2.
fcheung authored
181 sql << " FROM (SELECT #{distinct}#{column_name}" if use_workaround
8f74527 @NZKoz Escape table names during calculation queries. [wesley.moxam, Koz] Cl…
NZKoz authored
182 sql << " FROM #{connection.quote_table_name(table_name)} "
4251662 @technoweenie Allow all calculations to take the :include option, not just COUNT (c…
technoweenie authored
183 if merged_includes.any?
37adea6 @dhh Address shortcomings of changeset [8054] [protocool]
dhh authored
184 join_dependency = ActiveRecord::Associations::ClassMethods::JoinDependency.new(self, merged_includes, options[:joins])
4251662 @technoweenie Allow all calculations to take the :include option, not just COUNT (c…
technoweenie authored
185 sql << join_dependency.join_associations.collect{|join| join.association_join }.join
186 end
fed7d33 @dhh Fixed documentation
dhh authored
187 add_joins!(sql, options, scope)
188 add_conditions!(sql, options[:conditions], scope)
4251662 @technoweenie Allow all calculations to take the :include option, not just COUNT (c…
technoweenie authored
189 add_limited_ids_condition!(sql, options, join_dependency) if join_dependency && !using_limitable_reflections?(join_dependency.reflections) && ((scope && scope[:limit]) || options[:limit])
0dc53a8 When grouping, use the appropriate option key. [Marcel Molina Jr.]
Marcel Molina authored
190
191 if options[:group]
b6171e7 @jeremy SQLite: count(distinct) queries supported in >= 3.2.6, fix calculatio…
jeremy authored
192 group_key = connection.adapter_name == 'FrontBase' ? :group_alias : :group_field
0dc53a8 When grouping, use the appropriate option key. [Marcel Molina Jr.]
Marcel Molina authored
193 sql << " GROUP BY #{options[group_key]} "
194 end
b2c0ddf Add support for FrontBase (http://www.frontbase.com/) with a new adap…
Marcel Molina authored
195
196 if options[:group] && options[:having]
197 # FrontBase requires identifiers in the HAVING clause and chokes on function calls
b6171e7 @jeremy SQLite: count(distinct) queries supported in >= 3.2.6, fix calculatio…
jeremy authored
198 if connection.adapter_name == 'FrontBase'
b2c0ddf Add support for FrontBase (http://www.frontbase.com/) with a new adap…
Marcel Molina authored
199 options[:having].downcase!
200 options[:having].gsub!(/#{operation}\s*\(\s*#{column_name}\s*\)/, aggregate_alias)
201 end
b6171e7 @jeremy SQLite: count(distinct) queries supported in >= 3.2.6, fix calculatio…
jeremy authored
202
b2c0ddf Add support for FrontBase (http://www.frontbase.com/) with a new adap…
Marcel Molina authored
203 sql << " HAVING #{options[:having]} "
204 end
205
f106e2c @technoweenie Fix bug where calculations with long alias names return null. [Rick]
technoweenie authored
206 sql << " ORDER BY #{options[:order]} " if options[:order]
4251662 @technoweenie Allow all calculations to take the :include option, not just COUNT (c…
technoweenie authored
207 add_limit!(sql, options, scope)
208 sql << ')' if use_workaround
9466211 @technoweenie fix calculations for the Oracle Adapter (closes #4626) [Michael Schoen]
technoweenie authored
209 sql
fed7d33 @dhh Fixed documentation
dhh authored
210 end
99307b9 @dhh Added calculations: Base.count, Base.average, Base.sum, Base.minimum,…
dhh authored
211
4251662 @technoweenie Allow all calculations to take the :include option, not just COUNT (c…
technoweenie authored
212 def execute_simple_calculation(operation, column_name, column, options) #:nodoc:
213 value = connection.select_value(construct_calculation_sql(operation, column_name, options))
fed7d33 @dhh Fixed documentation
dhh authored
214 type_cast_calculated_value(value, column, operation)
99307b9 @dhh Added calculations: Base.count, Base.average, Base.sum, Base.minimum,…
dhh authored
215 end
216
4251662 @technoweenie Allow all calculations to take the :include option, not just COUNT (c…
technoweenie authored
217 def execute_grouped_calculation(operation, column_name, column, options) #:nodoc:
fed7d33 @dhh Fixed documentation
dhh authored
218 group_attr = options[:group].to_s
219 association = reflect_on_association(group_attr.to_sym)
220 associated = association && association.macro == :belongs_to # only count belongs_to associations
5bbc461 @jeremy Fix calculations on associations with custom :foreign_key. Closes #81…
jeremy authored
221 group_field = associated ? association.primary_key_name : group_attr
fed7d33 @dhh Fixed documentation
dhh authored
222 group_alias = column_alias_for(group_field)
223 group_column = column_for group_field
4251662 @technoweenie Allow all calculations to take the :include option, not just COUNT (c…
technoweenie authored
224 sql = construct_calculation_sql(operation, column_name, options.merge(:group_field => group_field, :group_alias => group_alias))
fed7d33 @dhh Fixed documentation
dhh authored
225 calculated_data = connection.select_all(sql)
4251662 @technoweenie Allow all calculations to take the :include option, not just COUNT (c…
technoweenie authored
226 aggregate_alias = column_alias_for(operation, column_name)
fed7d33 @dhh Fixed documentation
dhh authored
227
228 if association
229 key_ids = calculated_data.collect { |row| row[group_alias] }
230 key_records = association.klass.base_class.find(key_ids)
231 key_records = key_records.inject({}) { |hsh, r| hsh.merge(r.id => r) }
232 end
233
325cb12 @technoweenie Namespaced OrderedHash so the Rails implementation does not clash wit…
technoweenie authored
234 calculated_data.inject(ActiveSupport::OrderedHash.new) do |all, row|
b05fc40 @jeremy Calculations support non-numeric foreign keys. Closes #8154.
jeremy authored
235 key = type_cast_calculated_value(row[group_alias], group_column)
236 key = key_records[key] if associated
fed7d33 @dhh Fixed documentation
dhh authored
237 value = row[aggregate_alias]
57c613a @jeremy Ruby 1.9 compat: calculations don't assume array implementation of or…
jeremy authored
238 all[key] = type_cast_calculated_value(value, column, operation)
239 all
fed7d33 @dhh Fixed documentation
dhh authored
240 end
99307b9 @dhh Added calculations: Base.count, Base.average, Base.sum, Base.minimum,…
dhh authored
241 end
242
243 private
fed7d33 @dhh Fixed documentation
dhh authored
244 def validate_calculation_options(operation, options = {})
4251662 @technoweenie Allow all calculations to take the :include option, not just COUNT (c…
technoweenie authored
245 options.assert_valid_keys(CALCULATIONS_OPTIONS)
fed7d33 @dhh Fixed documentation
dhh authored
246 end
ad9f678 @dhh Compatibility patches for calculations
dhh authored
247
98dc582 @lifo Merge docrails.
lifo authored
248 # Converts the given keys to the value that the database adapter returns as
249 # a usable column name:
250 #
251 # column_alias_for("users.id") # => "users_id"
252 # column_alias_for("sum(id)") # => "sum_id"
253 # column_alias_for("count(distinct users.id)") # => "count_distinct_users_id"
254 # column_alias_for("count(*)") # => "count_all"
255 # column_alias_for("count", "id") # => "count_id"
fed7d33 @dhh Fixed documentation
dhh authored
256 def column_alias_for(*keys)
f106e2c @technoweenie Fix bug where calculations with long alias names return null. [Rick]
technoweenie authored
257 connection.table_alias_for(keys.join(' ').downcase.gsub(/\*/, 'all').gsub(/\W+/, ' ').strip.gsub(/ +/, '_'))
fed7d33 @dhh Fixed documentation
dhh authored
258 end
99307b9 @dhh Added calculations: Base.count, Base.average, Base.sum, Base.minimum,…
dhh authored
259
fed7d33 @dhh Fixed documentation
dhh authored
260 def column_for(field)
261 field_name = field.to_s.split('.').last
262 columns.detect { |c| c.name.to_s == field_name }
263 end
a8d085a @dhh Make calculations typecasty! (closes #4016) [Rick Olson]
dhh authored
264
fed7d33 @dhh Fixed documentation
dhh authored
265 def type_cast_calculated_value(value, column, operation = nil)
266 operation = operation.to_s.downcase
267 case operation
bd75a72 @lifo Ensure AR#sum result is typecasted properly
lifo authored
268 when 'count' then value.to_i
269 when 'sum' then value =~ /\./ ? value.to_f : value.to_i
270 when 'avg' then value && value.to_f
fed7d33 @dhh Fixed documentation
dhh authored
271 else column ? column.type_cast(value) : value
272 end
99307b9 @dhh Added calculations: Base.count, Base.average, Base.sum, Base.minimum,…
dhh authored
273 end
274 end
275 end
445cb5c @NZKoz Add support for :include to with_scope [andrew@redlinesoftware.com]
NZKoz authored
276 end
Something went wrong with that request. Please try again.