diff options
Diffstat (limited to 'activerecord/lib/active_record/relation/query_methods.rb')
-rw-r--r-- | activerecord/lib/active_record/relation/query_methods.rb | 91 |
1 files changed, 49 insertions, 42 deletions
diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index 0a4c119849..51a39be065 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -162,52 +162,57 @@ module ActiveRecord @arel ||= build_arel end - def custom_join_sql(*joins) - arel = table.select_manager + def build_arel + arel = table.from table - joins.each do |join| - next if join.blank? + build_joins(arel, @joins_values) unless @joins_values.empty? - @implicit_readonly = true + collapse_wheres(arel, (@where_values - ['']).uniq) - case join - when Array - join = Arel.sql(join.join(' ')) if array_of_strings?(join) - when String - join = Arel.sql(join) - end + arel.having(*@having_values.uniq.reject{|h| h.blank?}) unless @having_values.empty? - arel.join(join) - end + arel.take(@limit_value) if @limit_value + arel.skip(@offset_value) if @offset_value - arel.joins(arel) - end + arel.group(*@group_values.uniq.reject{|g| g.blank?}) unless @group_values.empty? - def build_arel - arel = table + arel.order(*@order_values.uniq.reject{|o| o.blank?}) unless @order_values.empty? - arel = build_joins(arel, @joins_values) unless @joins_values.empty? + build_select(arel, @select_values.uniq) - arel = collapse_wheres(arel, (@where_values - ['']).uniq) + arel.from(@from_value) if @from_value + arel.lock(@lock_value) if @lock_value - arel = arel.having(*@having_values.uniq.reject{|h| h.blank?}) unless @having_values.empty? + arel + end - arel = arel.take(@limit_value) if @limit_value - arel = arel.skip(@offset_value) if @offset_value + private - arel = arel.group(*@group_values.uniq.reject{|g| g.blank?}) unless @group_values.empty? + def custom_join_ast(table, joins) + joins = joins.reject { |join| join.blank? } - arel = arel.order(*@order_values.uniq.reject{|o| o.blank?}) unless @order_values.empty? + return if joins.empty? - arel = build_select(arel, @select_values.uniq) + @implicit_readonly = true - arel = arel.from(@from_value) if @from_value - arel = arel.lock(@lock_value) if @lock_value + joins.map! do |join| + case join + when Array + join = Arel.sql(join.join(' ')) if array_of_strings?(join) + when String + join = Arel.sql(join) + end + join + end - arel - end + head = table.create_string_join(table, joins.shift) - private + joins.inject(head) do |ast, join| + ast.right = table.create_string_join(ast.right, join) + end + + head + end def collapse_wheres(arel, wheres) equalities = wheres.grep(Arel::Nodes::Equality) @@ -220,14 +225,13 @@ module ActiveRecord test = eqls.inject(eqls.shift) do |memo, expr| memo.or(expr) end - arel = arel.where(test) + arel.where(test) end (wheres - equalities).each do |where| where = Arel.sql(where) if String === where - arel = arel.where(Arel::Nodes::Grouping.new(where)) + arel.where(Arel::Nodes::Grouping.new(where)) end - arel end def build_where(opts, other = []) @@ -242,31 +246,34 @@ module ActiveRecord end end - def build_joins(relation, joins) - association_joins = [] - + def build_joins(manager, joins) joins = joins.map {|j| j.respond_to?(:strip) ? j.strip : j}.uniq - joins.each do |join| - association_joins << join if [Hash, Array, Symbol].include?(join.class) && !array_of_strings?(join) + association_joins = joins.find_all do |join| + [Hash, Array, Symbol].include?(join.class) && !array_of_strings?(join) end stashed_association_joins = joins.grep(ActiveRecord::Associations::ClassMethods::JoinDependency::JoinAssociation) non_association_joins = (joins - association_joins - stashed_association_joins) - custom_joins = custom_join_sql(*non_association_joins) + join_ast = custom_join_ast(manager.froms.first, non_association_joins) - join_dependency = ActiveRecord::Associations::ClassMethods::JoinDependency.new(@klass, association_joins, custom_joins) + join_dependency = ActiveRecord::Associations::ClassMethods::JoinDependency.new(@klass, association_joins, join_ast) join_dependency.graft(*stashed_association_joins) @implicit_readonly = true unless association_joins.empty? && stashed_association_joins.empty? + # FIXME: refactor this to build an AST join_dependency.join_associations.each do |association| - relation = association.join_to(relation) + association.join_to(manager) end - relation.join(custom_joins) + return manager unless join_ast + + join_ast.left = manager.froms.first + manager.from join_ast + manager end def build_select(arel, selects) |