From 6311975fb3c02f50730fd1e11b8dba8dd9c05306 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Fri, 13 Apr 2012 15:59:47 +0100 Subject: use a hash to store relation values --- activerecord/lib/active_record/relation.rb | 27 +++++----- .../lib/active_record/relation/calculations.rb | 10 ++-- .../lib/active_record/relation/finder_methods.rb | 14 ++--- .../lib/active_record/relation/query_methods.rb | 61 +++++++++++++++------- activerecord/test/cases/relation_test.rb | 14 ++--- 5 files changed, 74 insertions(+), 52 deletions(-) diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index 4ed78bcbef..7918d08cf0 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -29,11 +29,7 @@ module ActiveRecord @implicit_readonly = nil @loaded = false @default_scoped = false - - SINGLE_VALUE_METHODS.each {|v| instance_variable_set(:"@#{v}_value", nil)} - MULTI_VALUE_METHODS.each {|v| instance_variable_set(:"@#{v}_values", [])} - - @create_with_value = {} + @values = {} end def insert(values) @@ -84,7 +80,8 @@ module ActiveRecord end def initialize_copy(other) - @bind_values = @bind_values.dup + @values = @values.dup + @values[:bind] = @values[:bind].dup if @values[:bind] reset end @@ -174,17 +171,17 @@ module ActiveRecord default_scoped = with_default_scope if default_scoped.equal?(self) - @records = eager_loading? ? find_with_associations : @klass.find_by_sql(arel, @bind_values) + @records = eager_loading? ? find_with_associations : @klass.find_by_sql(arel, bind_values) - preload = @preload_values - preload += @includes_values unless eager_loading? + preload = preload_values + preload += includes_values unless eager_loading? preload.each do |associations| ActiveRecord::Associations::Preloader.new(@records, associations).run end # @readonly_value is true only if set explicitly. @implicit_readonly is true if there # are JOINS and no explicit SELECT. - readonly = @readonly_value.nil? ? @implicit_readonly : @readonly_value + readonly = readonly_value.nil? ? @implicit_readonly : readonly_value @records.each { |record| record.readonly! } if readonly else @records = default_scoped.to_a @@ -224,7 +221,7 @@ module ActiveRecord if block_given? to_a.many? { |*block_args| yield(*block_args) } else - @limit_value ? to_a.many? : size > 1 + limit_value ? to_a.many? : size > 1 end end @@ -460,7 +457,7 @@ module ActiveRecord end def to_sql - @to_sql ||= klass.connection.to_sql(arel, @bind_values.dup) + @to_sql ||= klass.connection.to_sql(arel, bind_values.dup) end def where_values_hash @@ -482,8 +479,8 @@ module ActiveRecord def eager_loading? @should_eager_load ||= - @eager_load_values.any? || - @includes_values.any? && (joined_includes_values.any? || references_eager_loaded_tables?) + eager_load_values.any? || + includes_values.any? && (joined_includes_values.any? || references_eager_loaded_tables?) end # Joins that are also marked for preloading. In which case we should just eager load them. @@ -491,7 +488,7 @@ module ActiveRecord # represent the same association, but that aren't matched by this. Also, we could have # nested hashes which partially match, e.g. { :a => :b } & { :a => [:b, :c] } def joined_includes_values - @includes_values & @joins_values + includes_values & joins_values end def ==(other) diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb index f613014f23..6bb2c7af81 100644 --- a/activerecord/lib/active_record/relation/calculations.rb +++ b/activerecord/lib/active_record/relation/calculations.rb @@ -216,7 +216,7 @@ module ActiveRecord distinct = nil if column_name =~ /\s*DISTINCT\s+/i end - if @group_values.any? + if group_values.any? execute_grouped_calculation(operation, column_name, distinct) else execute_simple_calculation(operation, column_name, distinct) @@ -259,7 +259,7 @@ module ActiveRecord end def execute_grouped_calculation(operation, column_name, distinct) #:nodoc: - group_attr = @group_values + 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.foreign_key : group_attr) @@ -282,7 +282,7 @@ module ActiveRecord operation, distinct).as(aggregate_alias) ] - select_values += @select_values unless @having_values.empty? + select_values += select_values unless having_values.empty? select_values.concat group_fields.zip(group_aliases).map { |field,aliaz| "#{field} AS #{aliaz}" @@ -347,8 +347,8 @@ module ActiveRecord end def select_for_count - if @select_values.present? - select = @select_values.join(", ") + if select_values.present? + select = select_values.join(", ") select if select !~ /[,*]/ end end diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb index 52061a2286..87f6822a3d 100644 --- a/activerecord/lib/active_record/relation/finder_methods.rb +++ b/activerecord/lib/active_record/relation/finder_methods.rb @@ -236,12 +236,12 @@ module ActiveRecord end def construct_join_dependency_for_association_find - including = (@eager_load_values + @includes_values).uniq + including = (eager_load_values + includes_values).uniq ActiveRecord::Associations::JoinDependency.new(@klass, including, []) end def construct_relation_for_association_calculations - including = (@eager_load_values + @includes_values).uniq + including = (eager_load_values + includes_values).uniq join_dependency = ActiveRecord::Associations::JoinDependency.new(@klass, including, arel.froms.first) relation = except(:includes, :eager_load, :preload) apply_join_dependency(relation, join_dependency) @@ -340,7 +340,7 @@ module ActiveRecord id = id.id if ActiveRecord::Base === id column = columns_hash[primary_key] - substitute = connection.substitute_at(column, @bind_values.length) + substitute = connection.substitute_at(column, bind_values.length) relation = where(table[primary_key].eq(substitute)) relation.bind_values += [[column, id]] record = relation.first @@ -358,15 +358,15 @@ module ActiveRecord result = where(table[primary_key].in(ids)).all expected_size = - if @limit_value && ids.size > @limit_value - @limit_value + if limit_value && ids.size > limit_value + limit_value else ids.size end # 11 ids with limit 3, offset 9 should give 2 results. - if @offset_value && (ids.size - @offset_value < expected_size) - expected_size = ids.size - @offset_value + if offset_value && (ids.size - offset_value < expected_size) + expected_size = ids.size - offset_value end if result.size == expected_size diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index 6b7e03f9f7..855477eaed 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -5,12 +5,37 @@ module ActiveRecord module QueryMethods extend ActiveSupport::Concern - attr_accessor :includes_values, :eager_load_values, :preload_values, - :select_values, :group_values, :order_values, :joins_values, - :where_values, :having_values, :bind_values, - :limit_value, :offset_value, :lock_value, :readonly_value, :create_with_value, - :from_value, :reordering_value, :reverse_order_value, - :uniq_value, :references_values, :extending_values + Relation::MULTI_VALUE_METHODS.each do |name| + class_eval <<-CODE, __FILE__, __LINE__ + 1 + def #{name}_values # def select_values + @values[:#{name}] || [] # @values[:select] || [] + end # end + # + def #{name}_values=(values) # def select_values=(values) + @values[:#{name}] = values # @values[:select] = values + end # end + CODE + end + + (Relation::SINGLE_VALUE_METHODS - [:create_with]).each do |name| + class_eval <<-CODE, __FILE__, __LINE__ + 1 + def #{name}_value # def readonly_value + @values[:#{name}] # @values[:readonly] + end # end + # + def #{name}_value=(value) # def readonly_value=(value) + @values[:#{name}] = value # @values[:readonly] = value + end # end + CODE + end + + def create_with_value + @values[:create_with] || {} + end + + def create_with_value=(value) + @values[:create_with] = value + end alias extensions extending_values @@ -372,26 +397,26 @@ module ActiveRecord def build_arel arel = table.from table - build_joins(arel, @joins_values) unless @joins_values.empty? + build_joins(arel, joins_values) unless joins_values.empty? - collapse_wheres(arel, (@where_values - ['']).uniq) + collapse_wheres(arel, (where_values - ['']).uniq) - arel.having(*@having_values.uniq.reject{|h| h.blank?}) unless @having_values.empty? + 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.to_i) if @offset_value + arel.take(connection.sanitize_limit(limit_value)) if limit_value + arel.skip(offset_value.to_i) if offset_value - arel.group(*@group_values.uniq.reject{|g| g.blank?}) unless @group_values.empty? + arel.group(*group_values.uniq.reject{|g| g.blank?}) unless group_values.empty? - order = @order_values - order = reverse_sql_order(order) if @reverse_order_value + order = order_values + order = reverse_sql_order(order) if reverse_order_value arel.order(*order.uniq.reject{|o| o.blank?}) unless order.empty? - build_select(arel, @select_values.uniq) + build_select(arel, select_values.uniq) - arel.distinct(@uniq_value) - arel.from(@from_value) if @from_value - arel.lock(@lock_value) if @lock_value + arel.distinct(uniq_value) + arel.from(from_value) if from_value + arel.lock(lock_value) if lock_value arel end diff --git a/activerecord/test/cases/relation_test.rb b/activerecord/test/cases/relation_test.rb index 633654a961..c636284b8f 100644 --- a/activerecord/test/cases/relation_test.rb +++ b/activerecord/test/cases/relation_test.rb @@ -43,19 +43,19 @@ module ActiveRecord relation = Relation.new :a, :b assert_equal({}, relation.where_values_hash) - relation.where_values << :hello + relation.where! :hello assert_equal({}, relation.where_values_hash) end def test_has_values relation = Relation.new Post, Post.arel_table - relation.where_values << relation.table[:id].eq(10) + relation.where! relation.table[:id].eq(10) assert_equal({:id => 10}, relation.where_values_hash) end def test_values_wrong_table relation = Relation.new Post, Post.arel_table - relation.where_values << Comment.arel_table[:id].eq(10) + relation.where! Comment.arel_table[:id].eq(10) assert_equal({}, relation.where_values_hash) end @@ -64,7 +64,7 @@ module ActiveRecord left = relation.table[:id].eq(10) right = relation.table[:id].eq(10) combine = left.and right - relation.where_values << combine + relation.where! combine assert_equal({}, relation.where_values_hash) end @@ -87,7 +87,7 @@ module ActiveRecord def test_create_with_value_with_wheres relation = Relation.new Post, Post.arel_table - relation.where_values << relation.table[:id].eq(10) + relation.where! relation.table[:id].eq(10) relation.create_with_value = {:hello => 'world'} assert_equal({:hello => 'world', :id => 10}, relation.scope_for_create) end @@ -97,7 +97,7 @@ module ActiveRecord relation = Relation.new Post, Post.arel_table assert_equal({}, relation.scope_for_create) - relation.where_values << relation.table[:id].eq(10) + relation.where! relation.table[:id].eq(10) assert_equal({}, relation.scope_for_create) relation.create_with_value = {:hello => 'world'} @@ -111,7 +111,7 @@ module ActiveRecord def test_eager_load_values relation = Relation.new :a, :b - relation.eager_load_values << :b + relation.eager_load! :b assert relation.eager_loading? end -- cgit v1.2.3