]> git.openstreetmap.org Git - rails.git/blob - vendor/gems/composite_primary_keys-2.2.2/lib/composite_primary_keys/calculations.rb
Merge branch 'master' into terms
[rails.git] / vendor / gems / composite_primary_keys-2.2.2 / lib / composite_primary_keys / calculations.rb
1 module CompositePrimaryKeys
2   module ActiveRecord
3     module Calculations
4       def self.append_features(base)
5         super
6         base.send(:extend, ClassMethods)
7       end
8
9       module ClassMethods
10         def construct_calculation_sql(operation, column_name, options) #:nodoc:
11           operation = operation.to_s.downcase
12           options = options.symbolize_keys
13
14           scope           = scope(:find)
15           merged_includes = merge_includes(scope ? scope[:include] : [], options[:include])
16           aggregate_alias = column_alias_for(operation, column_name)
17           use_workaround  = !connection.supports_count_distinct? && options[:distinct] && operation.to_s.downcase == 'count'
18           join_dependency = nil
19
20           if merged_includes.any? && operation.to_s.downcase == 'count'
21             options[:distinct] = true
22             use_workaround  = !connection.supports_count_distinct?
23             column_name = options[:select] || primary_key.map{ |part| "#{quoted_table_name}.#{connection.quote_column_name(part)}"}.join(',')
24           end
25
26           sql  = "SELECT #{operation}(#{'DISTINCT ' if options[:distinct]}#{column_name}) AS #{aggregate_alias}"
27
28           # A (slower) workaround if we're using a backend, like sqlite, that doesn't support COUNT DISTINCT.
29           sql = "SELECT COUNT(*) AS #{aggregate_alias}" if use_workaround
30
31           sql << ", #{connection.quote_column_name(options[:group_field])} AS #{options[:group_alias]}" if options[:group]
32           sql << " FROM (SELECT DISTINCT #{column_name}" if use_workaround
33           sql << " FROM #{quoted_table_name} "
34           if merged_includes.any?
35             join_dependency = ::ActiveRecord::Associations::ClassMethods::JoinDependency.new(self, merged_includes, options[:joins])
36             sql << join_dependency.join_associations.collect{|join| join.association_join }.join
37           end
38
39           add_joins!(sql, options[:joins], scope)
40           add_conditions!(sql, options[:conditions], scope)
41           add_limited_ids_condition!(sql, options, join_dependency) if \
42             join_dependency &&
43             !using_limitable_reflections?(join_dependency.reflections) &&
44             ((scope && scope[:limit]) || options[:limit])
45
46           if options[:group]
47             group_key = connection.adapter_name == 'FrontBase' ?  :group_alias : :group_field
48             sql << " GROUP BY #{connection.quote_column_name(options[group_key])} "
49           end
50
51           if options[:group] && options[:having]
52             # FrontBase requires identifiers in the HAVING clause and chokes on function calls
53             if connection.adapter_name == 'FrontBase'
54               options[:having].downcase!
55               options[:having].gsub!(/#{operation}\s*\(\s*#{column_name}\s*\)/, aggregate_alias)
56             end
57
58             sql << " HAVING #{options[:having]} "
59           end
60
61           sql << " ORDER BY #{options[:order]} " if options[:order]
62           add_limit!(sql, options, scope)
63           sql << ') w1' if use_workaround # assign a dummy table name as required for postgresql
64           sql
65         end
66       end
67     end
68   end
69 end