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].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.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 end include DefaultOperations end end