diff options
Diffstat (limited to 'activerecord/lib/active_record/relation')
6 files changed, 46 insertions, 35 deletions
diff --git a/activerecord/lib/active_record/relation/batches.rb b/activerecord/lib/active_record/relation/batches.rb index b41e935ed5..359af9820f 100644 --- a/activerecord/lib/active_record/relation/batches.rb +++ b/activerecord/lib/active_record/relation/batches.rb @@ -65,7 +65,7 @@ module ActiveRecord batch_size = options.delete(:batch_size) || 1000 relation = relation.except(:order).order(batch_order).limit(batch_size) - records = relation.where(primary_key.gteq(start)).all + records = relation.where(table[primary_key].gteq(start)).all while records.any? yield records @@ -73,7 +73,7 @@ module ActiveRecord break if records.size < batch_size if primary_key_offset = records.last.id - records = relation.where(primary_key.gt(primary_key_offset)).to_a + records = relation.where(table[primary_key].gt(primary_key_offset)).to_a else raise "Primary key not included in the custom select clause" end @@ -83,7 +83,7 @@ module ActiveRecord private def batch_order - "#{@klass.table_name}.#{@klass.primary_key} ASC" + "#{table_name}.#{primary_key} ASC" end end end diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb index fd45bb24dd..abc4c54109 100644 --- a/activerecord/lib/active_record/relation/calculations.rb +++ b/activerecord/lib/active_record/relation/calculations.rb @@ -168,7 +168,7 @@ module ActiveRecord unless arel.ast.grep(Arel::Nodes::OuterJoin).empty? distinct = true - column_name = @klass.primary_key if column_name == :all + column_name = primary_key if column_name == :all end distinct = nil if column_name =~ /\s*DISTINCT\s+/i @@ -211,7 +211,7 @@ module ActiveRecord group_attr = @group_values association = @klass.reflect_on_association(group_attr.first.to_sym) associated = group_attr.size == 1 && association && association.macro == :belongs_to # only count belongs_to associations - group_fields = Array(associated ? association.primary_key_name : group_attr) + group_fields = Array(associated ? association.foreign_key : group_attr) group_aliases = group_fields.map { |field| column_alias_for(field) } group_columns = group_aliases.zip(group_fields).map { |aliaz,field| [aliaz, column_for(field)] @@ -282,15 +282,11 @@ module ActiveRecord end def type_cast_calculated_value(value, column, operation = nil) - if value.is_a?(String) || value.nil? - case operation - when 'count' then value.to_i - when 'sum' then type_cast_using_column(value || '0', column) - when 'average' then value.try(:to_d) - else type_cast_using_column(value, column) - end - else - type_cast_using_column(value, column) + case operation + when 'count' then value.to_i + when 'sum' then type_cast_using_column(value || '0', column) + when 'average' then value.respond_to?(:to_d) ? value.to_d : value + else type_cast_using_column(value, column) end end diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb index 8bc28c06cb..7f32e5538e 100644 --- a/activerecord/lib/active_record/relation/finder_methods.rb +++ b/activerecord/lib/active_record/relation/finder_methods.rb @@ -19,7 +19,7 @@ module ActiveRecord # # All approaches accept an options hash as their last parameter. # - # ==== Parameters + # ==== Options # # * <tt>:conditions</tt> - An SQL fragment like "administrator = 1", <tt>["user_name = ?", username]</tt>, # or <tt>["user_name = :user_name", { :user_name => user_name }]</tt>. See conditions in the intro. @@ -171,13 +171,13 @@ module ActiveRecord def exists?(id = nil) id = id.id if ActiveRecord::Base === id - relation = select(primary_key).limit(1) + relation = select("1").limit(1) case id when Array, Hash relation = relation.where(id) else - relation = relation.where(primary_key.eq(id)) if id + relation = relation.where(table[primary_key].eq(id)) if id end relation.first ? true : false @@ -188,7 +188,8 @@ module ActiveRecord def find_with_associations including = (@eager_load_values + @includes_values).uniq join_dependency = ActiveRecord::Associations::ClassMethods::JoinDependency.new(@klass, including, []) - rows = construct_relation_for_association_find(join_dependency).to_a + relation = construct_relation_for_association_find(join_dependency) + rows = connection.select_all(relation.to_sql, 'SQL', relation.bind_values) join_dependency.instantiate(rows) rescue ThrowResult [] @@ -225,10 +226,10 @@ module ActiveRecord def construct_limited_ids_condition(relation) orders = relation.order_values - values = @klass.connection.distinct("#{@klass.connection.quote_table_name @klass.table_name}.#{@klass.primary_key}", orders) + values = @klass.connection.distinct("#{@klass.connection.quote_table_name table_name}.#{primary_key}", orders) - ids_array = relation.select(values).collect {|row| row[@klass.primary_key]} - ids_array.empty? ? raise(ThrowResult) : primary_key.in(ids_array) + ids_array = relation.select(values).collect {|row| row[primary_key]} + ids_array.empty? ? raise(ThrowResult) : table[primary_key].in(ids_array) end def find_by_attributes(match, attributes, *args) @@ -290,24 +291,24 @@ module ActiveRecord def find_one(id) id = id.id if ActiveRecord::Base === id - column = columns_hash[primary_key.name.to_s] + column = columns_hash[primary_key] substitute = connection.substitute_for(column, @bind_values) - relation = where(primary_key.eq(substitute)) + relation = where(table[primary_key].eq(substitute)) relation.bind_values = [[column, id]] record = relation.first unless record conditions = arel.where_sql conditions = " [#{conditions}]" if conditions - raise RecordNotFound, "Couldn't find #{@klass.name} with #{@klass.primary_key}=#{id}#{conditions}" + raise RecordNotFound, "Couldn't find #{@klass.name} with #{primary_key}=#{id}#{conditions}" end record end def find_some(ids) - result = where(primary_key.in(ids)).all + result = where(table[primary_key].in(ids)).all expected_size = if @limit_value && ids.size > @limit_value diff --git a/activerecord/lib/active_record/relation/predicate_builder.rb b/activerecord/lib/active_record/relation/predicate_builder.rb index 70d84619a1..61d9974570 100644 --- a/activerecord/lib/active_record/relation/predicate_builder.rb +++ b/activerecord/lib/active_record/relation/predicate_builder.rb @@ -15,18 +15,18 @@ module ActiveRecord table = Arel::Table.new(table_name, :engine => engine) end - attribute = table[column] || Arel::Attribute.new(table, column) + attribute = table[column.to_sym] case value when Array, ActiveRecord::Associations::AssociationCollection, ActiveRecord::Relation values = value.to_a.map { |x| - x.respond_to?(:quoted_id) ? x.quoted_id : x + x.is_a?(ActiveRecord::Base) ? x.id : x } attribute.in(values) when Range, Arel::Relation attribute.in(value) when ActiveRecord::Base - attribute.eq(Arel.sql(value.quoted_id)) + attribute.eq(value.id) when Class # FIXME: I think we need to deprecate this behavior attribute.eq(value.name) diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index 0ab55ae864..6a905b8588 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -128,7 +128,7 @@ module ActiveRecord def create_with(value) relation = clone - relation.create_with_value = value + relation.create_with_value = value && (@create_with_value || {}).merge(value) relation end @@ -152,7 +152,7 @@ module ActiveRecord order_clause = arel.order_clauses order = order_clause.empty? ? - "#{@klass.table_name}.#{@klass.primary_key} DESC" : + "#{table_name}.#{primary_key} DESC" : reverse_sql_order(order_clause).join(', ') except(:order).order(Arel.sql(order)) @@ -171,7 +171,7 @@ module ActiveRecord arel.having(*@having_values.uniq.reject{|h| h.blank?}) unless @having_values.empty? - arel.take(@limit_value) if @limit_value + arel.take(connection.sanitize_limit(@limit_value)) if @limit_value arel.skip(@offset_value) 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 5acf3ec83a..4150e36a9a 100644 --- a/activerecord/lib/active_record/relation/spawn_methods.rb +++ b/activerecord/lib/active_record/relation/spawn_methods.rb @@ -46,21 +46,28 @@ module ActiveRecord merged_relation.where_values = merged_wheres - (Relation::SINGLE_VALUE_METHODS - [:lock]).each do |method| + (Relation::SINGLE_VALUE_METHODS - [:lock, :create_with]).each do |method| value = r.send(:"#{method}_value") merged_relation.send(:"#{method}_value=", value) unless value.nil? end merged_relation.lock_value = r.lock_value unless merged_relation.lock_value + merged_relation = merged_relation.create_with(r.create_with_value) if r.create_with_value + # Apply scope extension modules merged_relation.send :apply_modules, r.extensions merged_relation end - alias :& :merge - + # Removes from the query the condition(s) specified in +skips+. + # + # Example: + # + # Post.order('id asc').except(:order) # discards the order condition + # Post.where('id > 10').order('id asc').except(:where) # discards the where condition but keeps the order + # def except(*skips) result = self.class.new(@klass, table) @@ -75,6 +82,13 @@ module ActiveRecord result end + # Removes any condition from the query other than the one(s) specified in +onlies+. + # + # Example: + # + # Post.order('id asc').only(:where) # discards the order condition + # Post.order('id asc').only(:where, :order) # uses the specified order + # def only(*onlies) result = self.class.new(@klass, table) @@ -98,7 +112,7 @@ module ActiveRecord options.assert_valid_keys(VALID_FIND_OPTIONS) finders = options.dup - finders.delete_if { |key, value| value.nil? } + finders.delete_if { |key, value| value.nil? && key != :limit } ([:joins, :select, :group, :order, :having, :limit, :offset, :from, :lock, :readonly] & finders.keys).each do |finder| relation = relation.send(finder, finders[finder]) |