diff options
Diffstat (limited to 'activerecord/lib/active_record/relation')
5 files changed, 52 insertions, 41 deletions
diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb index 6bf3050af9..f613014f23 100644 --- a/activerecord/lib/active_record/relation/calculations.rb +++ b/activerecord/lib/active_record/relation/calculations.rb @@ -174,11 +174,26 @@ module ActiveRecord # # Person.pluck(:id) # SELECT people.id FROM people # Person.uniq.pluck(:role) # SELECT DISTINCT role FROM people - # Person.where(:confirmed => true).limit(5).pluck(:id) + # Person.where(:age => 21).limit(5).pluck(:id) # SELECT people.id FROM people WHERE people.age = 21 LIMIT 5 # def pluck(column_name) - klass.connection.select_all(select(column_name).arel).map! do |attributes| - klass.type_cast_attribute(attributes.keys.first, klass.initialize_attributes(attributes)) + key = column_name.to_s.split('.', 2).last + + if column_name.is_a?(Symbol) && column_names.include?(column_name.to_s) + column_name = "#{table_name}.#{column_name}" + end + + result = klass.connection.select_all(select(column_name).arel, nil, bind_values) + types = result.column_types.merge klass.column_types + column = types[key] + + result.map do |attributes| + value = klass.initialize_attributes(attributes)[key] + if column + column.type_cast value + else + value + end end end @@ -239,7 +254,8 @@ module ActiveRecord query_builder = relation.arel end - type_cast_calculated_value(@klass.connection.select_value(query_builder), column_for(column_name), operation) + result = @klass.connection.select_value(query_builder, nil, relation.bind_values) + type_cast_calculated_value(result, column_for(column_name), operation) end def execute_grouped_calculation(operation, column_name, distinct) #:nodoc: @@ -275,7 +291,7 @@ module ActiveRecord relation = except(:group).group(group.join(',')) relation.select_values = select_values - calculated_data = @klass.connection.select_all(relation) + calculated_data = @klass.connection.select_all(relation, nil, bind_values) if association key_ids = calculated_data.collect { |row| row[group_aliases.first] } @@ -283,7 +299,7 @@ module ActiveRecord key_records = Hash[key_records.map { |r| [r.id, r] }] end - ActiveSupport::OrderedHash[calculated_data.map do |row| + Hash[calculated_data.map do |row| key = group_columns.map { |aliaz, column| type_cast_calculated_value(row[aliaz], column) } diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb index f1ac421a50..2c74f4011d 100644 --- a/activerecord/lib/active_record/relation/finder_methods.rb +++ b/activerecord/lib/active_record/relation/finder_methods.rb @@ -200,7 +200,7 @@ module ActiveRecord relation = relation.where(table[primary_key].eq(id)) if id end - connection.select_value(relation, "#{name} Exists") ? true : false + connection.select_value(relation, "#{name} Exists", relation.bind_values) end protected @@ -208,7 +208,7 @@ module ActiveRecord def find_with_associations join_dependency = construct_join_dependency_for_association_find relation = construct_relation_for_association_find(join_dependency) - rows = connection.select_all(relation, 'SQL', relation.bind_values) + rows = connection.select_all(relation, 'SQL', relation.bind_values.dup) join_dependency.instantiate(rows) rescue ThrowResult [] @@ -290,7 +290,7 @@ module ActiveRecord r.assign_attributes(unprotected_attributes_for_create, :without_protection => true) end yield(record) if block_given? - record.save if match.instantiator == :create + record.send(match.save_method) if match.save_record? end record @@ -318,20 +318,10 @@ module ActiveRecord def find_one(id) id = id.id if ActiveRecord::Base === id - if IdentityMap.enabled? && where_values.blank? && - limit_value.blank? && order_values.blank? && - includes_values.blank? && preload_values.blank? && - readonly_value.nil? && joins_values.blank? && - !@klass.locking_enabled? && - record = IdentityMap.get(@klass, id) - return record - end - column = columns_hash[primary_key] - substitute = connection.substitute_at(column, @bind_values.length) relation = where(table[primary_key].eq(substitute)) - relation.bind_values = [[column, id]] + relation.bind_values += [[column, id]] record = relation.first unless record diff --git a/activerecord/lib/active_record/relation/predicate_builder.rb b/activerecord/lib/active_record/relation/predicate_builder.rb index 1d04e763f6..b40bf2b3cf 100644 --- a/activerecord/lib/active_record/relation/predicate_builder.rb +++ b/activerecord/lib/active_record/relation/predicate_builder.rb @@ -1,7 +1,7 @@ module ActiveRecord class PredicateBuilder # :nodoc: def self.build_from_hash(engine, attributes, default_table) - predicates = attributes.map do |column, value| + attributes.map do |column, value| table = default_table if value.is_a?(Hash) @@ -17,20 +17,18 @@ module ActiveRecord build(table[column.to_sym], value) end - end - predicates.flatten + end.flatten end def self.references(attributes) - references = attributes.map do |key, value| + attributes.map do |key, value| if value.is_a?(Hash) key else key = key.to_s key.split('.').first.to_sym if key.include?('.') end - end - references.compact + end.compact end private @@ -41,26 +39,27 @@ module ActiveRecord attribute.in(value.arel.ast) when Array, ActiveRecord::Associations::CollectionProxy values = value.to_a.map {|x| x.is_a?(ActiveRecord::Model) ? x.id : x} - ranges, values = values.partition {|v| v.is_a?(Range) || v.is_a?(Arel::Relation)} + ranges, values = values.partition {|v| v.is_a?(Range)} - array_predicates = ranges.map {|range| attribute.in(range)} - - if values.include?(nil) + values_predicate = if values.include?(nil) values = values.compact + case values.length when 0 - array_predicates << attribute.eq(nil) + attribute.eq(nil) when 1 - array_predicates << attribute.eq(values.first).or(attribute.eq(nil)) + attribute.eq(values.first).or(attribute.eq(nil)) else - array_predicates << attribute.in(values).or(attribute.eq(nil)) + attribute.in(values).or(attribute.eq(nil)) end else - array_predicates << attribute.in(values) + attribute.in(values) end - array_predicates.inject {|composite, predicate| composite.or(predicate)} - when Range, Arel::Relation + array_predicates = ranges.map { |range| attribute.in(range) } + array_predicates << values_predicate + array_predicates.inject { |composite, predicate| composite.or(predicate) } + when Range attribute.in(value) when ActiveRecord::Model attribute.eq(value.id) diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index b6d762c2e2..d737b34115 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -206,8 +206,8 @@ module ActiveRecord # Any subsequent condition chained to the returned relation will continue # generating an empty relation and will not fire any query to the database. # - # This is useful in scenarios where you need a chainable response to a method - # or a scope that could return zero results. + # Used in cases where a method or scope could return zero records but the + # result needs to be chainable. # # For example: # @@ -329,7 +329,7 @@ module ActiveRecord arel.having(*@having_values.uniq.reject{|h| h.blank?}) unless @having_values.empty? arel.take(connection.sanitize_limit(@limit_value)) if @limit_value - arel.skip(@offset_value) if @offset_value + arel.skip(@offset_value.to_i) if @offset_value arel.group(*@group_values.uniq.reject{|g| g.blank?}) unless @group_values.empty? diff --git a/activerecord/lib/active_record/relation/spawn_methods.rb b/activerecord/lib/active_record/relation/spawn_methods.rb index 7131aa29b6..03ba8c8628 100644 --- a/activerecord/lib/active_record/relation/spawn_methods.rb +++ b/activerecord/lib/active_record/relation/spawn_methods.rb @@ -22,15 +22,20 @@ module ActiveRecord end end - (Relation::MULTI_VALUE_METHODS - [:joins, :where, :order]).each do |method| + (Relation::MULTI_VALUE_METHODS - [:joins, :where, :order, :binds]).each do |method| value = r.send(:"#{method}_values") - merged_relation.send(:"#{method}_values=", merged_relation.send(:"#{method}_values") + value) if value.present? + next if value.empty? + + value += merged_relation.send(:"#{method}_values") + merged_relation.send :"#{method}_values=", value end merged_relation.joins_values += r.joins_values merged_wheres = @where_values + r.where_values + merged_binds = (@bind_values + r.bind_values).uniq(&:first) + unless @where_values.empty? # Remove duplicates, last one wins. seen = Hash.new { |h,table| h[table] = {} } @@ -47,6 +52,7 @@ module ActiveRecord end merged_relation.where_values = merged_wheres + merged_relation.bind_values = merged_binds (Relation::SINGLE_VALUE_METHODS - [:lock, :create_with, :reordering]).each do |method| value = r.send(:"#{method}_value") |