aboutsummaryrefslogblamecommitdiffstats
path: root/lib/arel/algebra/relations/relation.rb
blob: 2ce3fdcce87115115fb8e5a0ae5cd22964155c10 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
           
                

                      
               
                 
       
 

                       
       
 


                      
 


                          
                      
                                       
         
 
               
                                

         
                      
 
                   
                                                            
                           
                   
                                              
                     
                                                             

              
           

         
                                          
                                       
         
 
                                                                                      
                                                   



                                                                                                                           

         

                       
         
 
                     
                          
                                                 


                               
                                                      


                  
                                           

           
                      
 
                                                                        
                           
                                                           


           
                    
 



                              
                                             
                                  
                                                  

                    

                                       
         
 
                                            
                                                
         
 
                                                      
                                                      
                                                                                     

           
 





                                                          


                                                                    
                                                               


                                  
 


                                              
       
                               
 

                                         
                                         


                                         
                                                 

                                         
                                         

                             
     
   
module Arel
  class Relation
    attr_reader :count

    def session
      Session.new
    end

    def call
      engine.read(self)
    end

    def bind(relation)
      self
    end

    module Enumerable
      include ::Enumerable

      def each(&block)
        session.read(self).each(&block)
      end

      def first
        session.read(self).first
      end
    end
    include Enumerable

    module Operable
      def join(other_relation = nil, join_class = InnerJoin)
        case other_relation
        when String
          StringJoin.new(self, other_relation)
        when Relation
          JoinOperation.new(join_class, self, other_relation)
        else
          self
        end
      end

      def outer_join(other_relation = nil)
        join(other_relation, OuterJoin)
      end

      [:where, :project, :order, :take, :skip, :group, :from].each do |operation_name|
        class_eval <<-OPERATION, __FILE__, __LINE__
          def #{operation_name}(*arguments, &block)
            arguments.all?(&:blank?) && !block_given?? self : #{operation_name.to_s.classify}.new(self, *arguments, &block)
          end
        OPERATION
      end

      def alias
        Alias.new(self)
      end

      module Writable
        def insert(record)
          session.create Insert.new(self, record)
        end

        def update(assignments)
          session.update Update.new(self, assignments)
        end

        def delete
          session.delete Deletion.new(self)
        end
      end
      include Writable

      JoinOperation = Struct.new(:join_class, :relation1, :relation2) do
        def on(*predicates)
          join_class.new(relation1, relation2, *predicates)
        end
      end
    end
    include Operable

    module AttributeAccessable
      def [](index)
        case index
        when Symbol, String
          find_attribute_matching_name(index)
        when Attribute, Expression
          find_attribute_matching_attribute(index)
        when ::Array
          # TESTME
          index.collect { |i| self[i] }
        end
      end

      def find_attribute_matching_name(name)
        attributes.detect { |a| a.named?(name) }
      end

      def find_attribute_matching_attribute(attribute)
        matching_attributes(attribute).max do |a1, a2|
          (a1.original_attribute / attribute) <=> (a2.original_attribute / attribute)
        end
      end

      def position_of(attribute)
        (@position_of ||= Hash.new do |h, attribute|
          h[attribute] = attributes.index(self[attribute])
        end)[attribute]
      end

      private
      def matching_attributes(attribute)
        (@matching_attributes ||= attributes.inject({}) do |hash, a|
          (hash[a.is_a?(Value) ? a.value : a.root] ||= []) << a
          hash
        end)[attribute.root] || []
      end

      def has_attribute?(attribute)
        !matching_attributes(attribute).empty?
      end
    end
    include AttributeAccessable

    module DefaultOperations
      def attributes;             []  end
      def wheres;                 []  end
      def orders;                 []  end
      def inserts;                []  end
      def groupings;              []  end
      def joins(formatter = nil); nil end # FIXME
      def taken;                  nil end
      def skipped;                nil end
      def sources;                []  end
    end
    include DefaultOperations
  end
end