diff options
Diffstat (limited to 'lib/arel/algebra/relations/relation.rb')
-rw-r--r-- | lib/arel/algebra/relations/relation.rb | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb new file mode 100644 index 0000000000..9fdac26528 --- /dev/null +++ b/lib/arel/algebra/relations/relation.rb @@ -0,0 +1,136 @@ +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 |