aboutsummaryrefslogtreecommitdiffstats
path: root/lib/arel/algebra
diff options
context:
space:
mode:
authorBryan Helmkamp <bryan@brynary.com>2009-05-17 14:31:04 -0400
committerBryan Helmkamp <bryan@brynary.com>2009-05-17 14:31:04 -0400
commit7032a50297fce4d7724d1735e81e5df5fd919e71 (patch)
treec52333abcc7a1454ea6ada7fe5e31e054f4e9540 /lib/arel/algebra
parentbdca9ed42ffea10aa6989ea3ecebedb424fa01ed (diff)
downloadrails-7032a50297fce4d7724d1735e81e5df5fd919e71.tar.gz
rails-7032a50297fce4d7724d1735e81e5df5fd919e71.tar.bz2
rails-7032a50297fce4d7724d1735e81e5df5fd919e71.zip
reorganized file structures
Conflicts: lib/arel.rb lib/arel/arel.rb lib/arel/engines/memory/predicates.rb lib/arel/engines/memory/relations/array.rb lib/arel/engines/sql/relations/table.rb
Diffstat (limited to 'lib/arel/algebra')
-rw-r--r--lib/arel/algebra/extensions.rb4
-rw-r--r--lib/arel/algebra/extensions/array.rb5
-rw-r--r--lib/arel/algebra/extensions/class.rb37
-rw-r--r--lib/arel/algebra/extensions/hash.rb7
-rw-r--r--lib/arel/algebra/extensions/object.rb15
-rw-r--r--lib/arel/algebra/extensions/pathname.rb5
-rw-r--r--lib/arel/algebra/predicates.rb45
-rw-r--r--lib/arel/algebra/primitives.rb4
-rw-r--r--lib/arel/algebra/primitives/attribute.rb133
-rw-r--r--lib/arel/algebra/primitives/expression.rb31
-rw-r--r--lib/arel/algebra/primitives/value.rb19
-rw-r--r--lib/arel/algebra/relations.rb15
-rw-r--r--lib/arel/algebra/relations/operations/alias.rb7
-rw-r--r--lib/arel/algebra/relations/operations/group.rb15
-rw-r--r--lib/arel/algebra/relations/operations/join.rb41
-rw-r--r--lib/arel/algebra/relations/operations/order.rb16
-rw-r--r--lib/arel/algebra/relations/operations/project.rb19
-rw-r--r--lib/arel/algebra/relations/operations/skip.rb10
-rw-r--r--lib/arel/algebra/relations/operations/take.rb10
-rw-r--r--lib/arel/algebra/relations/operations/where.rb16
-rw-r--r--lib/arel/algebra/relations/relation.rb134
-rw-r--r--lib/arel/algebra/relations/utilities/compound.rb18
-rw-r--r--lib/arel/algebra/relations/utilities/externalization.rb24
-rw-r--r--lib/arel/algebra/relations/utilities/nil.rb7
-rw-r--r--lib/arel/algebra/relations/writes/delete.rb10
-rw-r--r--lib/arel/algebra/relations/writes/insert.rb14
-rw-r--r--lib/arel/algebra/relations/writes/update.rb14
27 files changed, 675 insertions, 0 deletions
diff --git a/lib/arel/algebra/extensions.rb b/lib/arel/algebra/extensions.rb
new file mode 100644
index 0000000000..5338fee989
--- /dev/null
+++ b/lib/arel/algebra/extensions.rb
@@ -0,0 +1,4 @@
+require 'arel/algebra/extensions/object'
+require 'arel/algebra/extensions/class'
+require 'arel/algebra/extensions/array'
+require 'arel/algebra/extensions/hash'
diff --git a/lib/arel/algebra/extensions/array.rb b/lib/arel/algebra/extensions/array.rb
new file mode 100644
index 0000000000..5b6d6d6abd
--- /dev/null
+++ b/lib/arel/algebra/extensions/array.rb
@@ -0,0 +1,5 @@
+class Array
+ def to_hash
+ Hash[*flatten]
+ end
+end \ No newline at end of file
diff --git a/lib/arel/algebra/extensions/class.rb b/lib/arel/algebra/extensions/class.rb
new file mode 100644
index 0000000000..f37898e7d7
--- /dev/null
+++ b/lib/arel/algebra/extensions/class.rb
@@ -0,0 +1,37 @@
+class Class
+ def attributes(*attrs)
+ @attributes = attrs
+ attr_reader *attrs
+ end
+
+ def deriving(*methods)
+ methods.each { |m| derive m }
+ end
+
+ def derive(method_name)
+ methods = {
+ :initialize => "
+ def #{method_name}(#{@attributes.join(',')})
+ #{@attributes.collect { |a| "@#{a} = #{a}" }.join("\n")}
+ end
+ ",
+ :== => "
+ def ==(other)
+ #{name} === other &&
+ #{@attributes.collect { |a| "@#{a} == other.#{a}" }.join(" &&\n")}
+ end
+ "
+ }
+ class_eval methods[method_name], __FILE__, __LINE__
+ end
+
+ def hash_on(delegatee)
+ define_method :eql? do |other|
+ self == other
+ end
+
+ define_method :hash do
+ @hash ||= delegatee.hash
+ end
+ end
+end \ No newline at end of file
diff --git a/lib/arel/algebra/extensions/hash.rb b/lib/arel/algebra/extensions/hash.rb
new file mode 100644
index 0000000000..7472b5aa73
--- /dev/null
+++ b/lib/arel/algebra/extensions/hash.rb
@@ -0,0 +1,7 @@
+class Hash
+ def bind(relation)
+ inject({}) do |bound, (key, value)|
+ bound.merge(key.bind(relation) => value.bind(relation))
+ end
+ end
+end \ No newline at end of file
diff --git a/lib/arel/algebra/extensions/object.rb b/lib/arel/algebra/extensions/object.rb
new file mode 100644
index 0000000000..d626407dcb
--- /dev/null
+++ b/lib/arel/algebra/extensions/object.rb
@@ -0,0 +1,15 @@
+class Object
+ def bind(relation)
+ Arel::Value.new(self, relation)
+ end
+
+ def find_correlate_in(relation)
+ bind(relation)
+ end
+
+ def metaclass
+ class << self
+ self
+ end
+ end
+end
diff --git a/lib/arel/algebra/extensions/pathname.rb b/lib/arel/algebra/extensions/pathname.rb
new file mode 100644
index 0000000000..2f7e2733e7
--- /dev/null
+++ b/lib/arel/algebra/extensions/pathname.rb
@@ -0,0 +1,5 @@
+class Pathname
+ def /(path)
+ (self + path).expand_path
+ end
+end \ No newline at end of file
diff --git a/lib/arel/algebra/predicates.rb b/lib/arel/algebra/predicates.rb
new file mode 100644
index 0000000000..f83101306e
--- /dev/null
+++ b/lib/arel/algebra/predicates.rb
@@ -0,0 +1,45 @@
+module Arel
+ class Predicate
+ end
+
+ class Binary < Predicate
+ attributes :operand1, :operand2
+ deriving :initialize
+
+ def ==(other)
+ self.class === other and
+ @operand1 == other.operand1 and
+ @operand2 == other.operand2
+ end
+
+ def bind(relation)
+ self.class.new(operand1.find_correlate_in(relation), operand2.find_correlate_in(relation))
+ end
+ end
+
+ class Equality < Binary
+ def ==(other)
+ Equality === other and
+ ((operand1 == other.operand1 and operand2 == other.operand2) or
+ (operand1 == other.operand2 and operand2 == other.operand1))
+ end
+ end
+
+ class GreaterThanOrEqualTo < Binary
+ end
+
+ class GreaterThan < Binary
+ end
+
+ class LessThanOrEqualTo < Binary
+ end
+
+ class LessThan < Binary
+ end
+
+ class Match < Binary
+ end
+
+ class In < Binary
+ end
+end \ No newline at end of file
diff --git a/lib/arel/algebra/primitives.rb b/lib/arel/algebra/primitives.rb
new file mode 100644
index 0000000000..a4c3169e0b
--- /dev/null
+++ b/lib/arel/algebra/primitives.rb
@@ -0,0 +1,4 @@
+require 'arel/algebra/primitives/attribute'
+require 'arel/algebra/primitives/value'
+require 'arel/algebra/primitives/expression'
+
diff --git a/lib/arel/algebra/primitives/attribute.rb b/lib/arel/algebra/primitives/attribute.rb
new file mode 100644
index 0000000000..5e216770e4
--- /dev/null
+++ b/lib/arel/algebra/primitives/attribute.rb
@@ -0,0 +1,133 @@
+require 'set'
+
+module Arel
+ class Attribute
+ attributes :relation, :name, :alias, :ancestor
+ deriving :==
+ delegate :engine, :christener, :to => :relation
+
+ def initialize(relation, name, options = {})
+ @relation, @name, @alias, @ancestor = relation, name, options[:alias], options[:ancestor]
+ end
+
+ def named?(hypothetical_name)
+ (@alias || name).to_s == hypothetical_name.to_s
+ end
+
+ def aggregation?
+ false
+ end
+
+ module Transformations
+ def self.included(klass)
+ klass.send :alias_method, :eql?, :==
+ end
+
+ def hash
+ @hash ||= history.size + name.hash + relation.hash
+ end
+
+ def as(aliaz = nil)
+ Attribute.new(relation, name, :alias => aliaz, :ancestor => self)
+ end
+
+ def bind(new_relation)
+ relation == new_relation ? self : Attribute.new(new_relation, name, :alias => @alias, :ancestor => self)
+ end
+
+ def to_attribute
+ self
+ end
+ end
+ include Transformations
+
+ module Congruence
+ def history
+ @history ||= [self] + (ancestor ? ancestor.history : [])
+ end
+
+ def join?
+ relation.join?
+ end
+
+ def root
+ history.last
+ end
+
+ def original_relation
+ @original_relation ||= original_attribute.relation
+ end
+
+ def original_attribute
+ @original_attribute ||= history.detect { |a| !a.join? }
+ end
+
+ def find_correlate_in(relation)
+ relation[self] || self
+ end
+
+ def descends_from?(other)
+ history.include?(other)
+ end
+
+ def /(other)
+ other ? (history & other.history).size : 0
+ end
+ end
+ include Congruence
+
+ module Predications
+ def eq(other)
+ Equality.new(self, other)
+ end
+
+ def lt(other)
+ LessThan.new(self, other)
+ end
+
+ def lteq(other)
+ LessThanOrEqualTo.new(self, other)
+ end
+
+ def gt(other)
+ GreaterThan.new(self, other)
+ end
+
+ def gteq(other)
+ GreaterThanOrEqualTo.new(self, other)
+ end
+
+ def matches(regexp)
+ Match.new(self, regexp)
+ end
+
+ def in(array)
+ In.new(self, array)
+ end
+ end
+ include Predications
+
+ module Expressions
+ def count(distinct = false)
+ distinct ? Expression.new(self, "DISTINCT").count : Expression.new(self, "COUNT")
+ end
+
+ def sum
+ Expression.new(self, "SUM")
+ end
+
+ def maximum
+ Expression.new(self, "MAX")
+ end
+
+ def minimum
+ Expression.new(self, "MIN")
+ end
+
+ def average
+ Expression.new(self, "AVG")
+ end
+ end
+ include Expressions
+ end
+end
diff --git a/lib/arel/algebra/primitives/expression.rb b/lib/arel/algebra/primitives/expression.rb
new file mode 100644
index 0000000000..b67a5e1f8e
--- /dev/null
+++ b/lib/arel/algebra/primitives/expression.rb
@@ -0,0 +1,31 @@
+module Arel
+ class Expression < Attribute
+ attributes :attribute, :function_sql, :alias, :ancestor
+ deriving :==
+ delegate :relation, :to => :attribute
+ alias_method :name, :alias
+
+ def initialize(attribute, function_sql, aliaz = nil, ancestor = nil)
+ @attribute, @function_sql, @alias, @ancestor = attribute, function_sql, aliaz, ancestor
+ end
+
+ def aggregation?
+ true
+ end
+
+ module Transformations
+ def as(aliaz)
+ Expression.new(attribute, function_sql, aliaz, self)
+ end
+
+ def bind(new_relation)
+ new_relation == relation ? self : Expression.new(attribute.bind(new_relation), function_sql, @alias, self)
+ end
+
+ def to_attribute
+ Attribute.new(relation, @alias, :ancestor => self)
+ end
+ end
+ include Transformations
+ end
+end
diff --git a/lib/arel/algebra/primitives/value.rb b/lib/arel/algebra/primitives/value.rb
new file mode 100644
index 0000000000..91c4045507
--- /dev/null
+++ b/lib/arel/algebra/primitives/value.rb
@@ -0,0 +1,19 @@
+module Arel
+ class Value
+ attributes :value, :relation
+ deriving :initialize, :==
+ delegate :inclusion_predicate_sql, :equality_predicate_sql, :to => :value
+
+ def bind(relation)
+ Value.new(value, relation)
+ end
+
+ def aggregation?
+ false
+ end
+
+ def to_attribute
+ value
+ end
+ end
+end
diff --git a/lib/arel/algebra/relations.rb b/lib/arel/algebra/relations.rb
new file mode 100644
index 0000000000..03f04d2459
--- /dev/null
+++ b/lib/arel/algebra/relations.rb
@@ -0,0 +1,15 @@
+require 'arel/algebra/relations/relation'
+require 'arel/algebra/relations/utilities/compound'
+require 'arel/algebra/relations/utilities/nil'
+require 'arel/algebra/relations/utilities/externalization'
+require 'arel/algebra/relations/writes/delete'
+require 'arel/algebra/relations/writes/update'
+require 'arel/algebra/relations/writes/insert'
+require 'arel/algebra/relations/operations/alias'
+require 'arel/algebra/relations/operations/group'
+require 'arel/algebra/relations/operations/join'
+require 'arel/algebra/relations/operations/order'
+require 'arel/algebra/relations/operations/project'
+require 'arel/algebra/relations/operations/where'
+require 'arel/algebra/relations/operations/skip'
+require 'arel/algebra/relations/operations/take' \ No newline at end of file
diff --git a/lib/arel/algebra/relations/operations/alias.rb b/lib/arel/algebra/relations/operations/alias.rb
new file mode 100644
index 0000000000..67837f6a75
--- /dev/null
+++ b/lib/arel/algebra/relations/operations/alias.rb
@@ -0,0 +1,7 @@
+module Arel
+ class Alias < Compound
+ attributes :relation
+ deriving :initialize
+ alias_method :==, :equal?
+ end
+end \ No newline at end of file
diff --git a/lib/arel/algebra/relations/operations/group.rb b/lib/arel/algebra/relations/operations/group.rb
new file mode 100644
index 0000000000..04fd9fea62
--- /dev/null
+++ b/lib/arel/algebra/relations/operations/group.rb
@@ -0,0 +1,15 @@
+module Arel
+ class Group < Compound
+ attributes :relation, :groupings
+ deriving :==
+
+ def initialize(relation, *groupings, &block)
+ @relation = relation
+ @groupings = (groupings + (block_given?? [yield(relatoin)] : [])).collect { |g| g.bind(relation) }
+ end
+
+ def externalizable?
+ true
+ end
+ end
+end \ No newline at end of file
diff --git a/lib/arel/algebra/relations/operations/join.rb b/lib/arel/algebra/relations/operations/join.rb
new file mode 100644
index 0000000000..8e19254378
--- /dev/null
+++ b/lib/arel/algebra/relations/operations/join.rb
@@ -0,0 +1,41 @@
+module Arel
+ class Join < Relation
+ attributes :join_sql, :relation1, :relation2, :predicates
+ deriving :==
+ delegate :engine, :name, :to => :relation1
+ hash_on :relation1
+
+ def initialize(join_sql, relation1, relation2 = Nil.instance, *predicates)
+ @join_sql, @relation1, @relation2, @predicates = join_sql, relation1, relation2, predicates
+ end
+
+ def attributes
+ @attributes ||= (relation1.externalize.attributes +
+ relation2.externalize.attributes).collect { |a| a.bind(self) }
+ end
+
+ def wheres
+ # TESTME bind to self?
+ relation1.externalize.wheres
+ end
+
+ def ons
+ @ons ||= @predicates.collect { |p| p.bind(self) }
+ end
+
+ # TESTME
+ def externalizable?
+ relation1.externalizable? or relation2.externalizable?
+ end
+
+ def join?
+ true
+ end
+ end
+
+ class Relation
+ def join?
+ false
+ end
+ end
+end
diff --git a/lib/arel/algebra/relations/operations/order.rb b/lib/arel/algebra/relations/operations/order.rb
new file mode 100644
index 0000000000..05af3fde4d
--- /dev/null
+++ b/lib/arel/algebra/relations/operations/order.rb
@@ -0,0 +1,16 @@
+module Arel
+ class Order < Compound
+ attributes :relation, :orderings
+ deriving :==
+
+ def initialize(relation, *orderings, &block)
+ @relation = relation
+ @orderings = (orderings + (block_given?? [yield(relation)] : [])).collect { |o| o.bind(relation) }
+ end
+
+ # TESTME
+ def orders
+ (orderings + relation.orders).collect { |o| o.bind(self) }
+ end
+ end
+end \ No newline at end of file
diff --git a/lib/arel/algebra/relations/operations/project.rb b/lib/arel/algebra/relations/operations/project.rb
new file mode 100644
index 0000000000..5507ea3163
--- /dev/null
+++ b/lib/arel/algebra/relations/operations/project.rb
@@ -0,0 +1,19 @@
+module Arel
+ class Project < Compound
+ attributes :relation, :projections
+ deriving :==
+
+ def initialize(relation, *projections, &block)
+ @relation = relation
+ @projections = (projections + (block_given?? [yield(relation)] : [])).collect { |p| p.bind(relation) }
+ end
+
+ def attributes
+ @attributes ||= projections.collect { |p| p.bind(self) }
+ end
+
+ def externalizable?
+ attributes.any?(&:aggregation?) or relation.externalizable?
+ end
+ end
+end
diff --git a/lib/arel/algebra/relations/operations/skip.rb b/lib/arel/algebra/relations/operations/skip.rb
new file mode 100644
index 0000000000..930e4c94ea
--- /dev/null
+++ b/lib/arel/algebra/relations/operations/skip.rb
@@ -0,0 +1,10 @@
+module Arel
+ class Skip < Compound
+ attributes :relation, :skipped
+ deriving :initialize, :==
+
+ def externalizable?
+ true
+ end
+ end
+end \ No newline at end of file
diff --git a/lib/arel/algebra/relations/operations/take.rb b/lib/arel/algebra/relations/operations/take.rb
new file mode 100644
index 0000000000..2fd3fdf635
--- /dev/null
+++ b/lib/arel/algebra/relations/operations/take.rb
@@ -0,0 +1,10 @@
+module Arel
+ class Take < Compound
+ attributes :relation, :taken
+ deriving :initialize, :==
+
+ def externalizable?
+ true
+ end
+ end
+end \ No newline at end of file
diff --git a/lib/arel/algebra/relations/operations/where.rb b/lib/arel/algebra/relations/operations/where.rb
new file mode 100644
index 0000000000..608aaeb4b7
--- /dev/null
+++ b/lib/arel/algebra/relations/operations/where.rb
@@ -0,0 +1,16 @@
+module Arel
+ class Where < Compound
+ attributes :relation, :predicate
+ deriving :==
+
+ def initialize(relation, *predicates, &block)
+ predicate = block_given?? yield(relation) : predicates.shift
+ @relation = predicates.empty?? relation : Where.new(relation, *predicates)
+ @predicate = predicate.bind(@relation)
+ end
+
+ def wheres
+ @wheres ||= (relation.wheres + [predicate]).collect { |p| p.bind(self) }
+ end
+ end
+end
diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb
new file mode 100644
index 0000000000..20badaf165
--- /dev/null
+++ b/lib/arel/algebra/relations/relation.rb
@@ -0,0 +1,134 @@
+module Arel
+ class Relation
+ attr_reader :count
+
+ def session
+ Session.new
+ end
+
+ def call
+ engine.read(self)
+ end
+
+ def bind(relation)
+ self
+ end
+
+ def root
+ 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_type = "INNER JOIN")
+ case other_relation
+ when String
+ Join.new(other_relation, self)
+ when Relation
+ JoinOperation.new(join_type, self, other_relation)
+ else
+ self
+ end
+ end
+
+ def outer_join(other_relation = nil)
+ join(other_relation, "LEFT OUTER JOIN")
+ end
+
+ [:where, :project, :order, :take, :skip, :group].each do |operation_name|
+ operation = <<-OPERATION
+ def #{operation_name}(*arguments, &block)
+ arguments.all?(&:blank?) && !block_given?? self : #{operation_name.to_s.classify}.new(self, *arguments, &block)
+ end
+ OPERATION
+ class_eval operation, __FILE__, __LINE__
+ end
+
+ def alias
+ Alias.new(self)
+ end
+
+ module Writable
+ def insert(record)
+ session.create Insert.new(self, record); self
+ 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_sql, :relation1, :relation2) do
+ def on(*predicates)
+ Join.new(join_sql, 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
+ 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
+
+ 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
diff --git a/lib/arel/algebra/relations/utilities/compound.rb b/lib/arel/algebra/relations/utilities/compound.rb
new file mode 100644
index 0000000000..e33b8dbf14
--- /dev/null
+++ b/lib/arel/algebra/relations/utilities/compound.rb
@@ -0,0 +1,18 @@
+module Arel
+ class Compound < Relation
+ attr_reader :relation
+ hash_on :relation
+ delegate :joins, :join?, :inserts, :taken, :skipped, :name, :externalizable?,
+ :column_for, :engine, :table, :table_sql, :array,
+ :to => :relation
+
+ [:attributes, :wheres, :groupings, :orders].each do |operation_name|
+ operation = <<-OPERATION
+ def #{operation_name}
+ @#{operation_name} ||= relation.#{operation_name}.collect { |o| o.bind(self) }
+ end
+ OPERATION
+ class_eval operation, __FILE__, __LINE__
+ end
+ end
+end
diff --git a/lib/arel/algebra/relations/utilities/externalization.rb b/lib/arel/algebra/relations/utilities/externalization.rb
new file mode 100644
index 0000000000..bd067f2304
--- /dev/null
+++ b/lib/arel/algebra/relations/utilities/externalization.rb
@@ -0,0 +1,24 @@
+module Arel
+ class Externalization < Compound
+ attributes :relation
+ deriving :initialize, :==
+
+ def wheres
+ []
+ end
+
+ def attributes
+ @attributes ||= relation.attributes.collect(&:to_attribute).collect { |a| a.bind(self) }
+ end
+ end
+
+ class Relation
+ def externalize
+ @externalized ||= externalizable?? Externalization.new(self) : self
+ end
+
+ def externalizable?
+ false
+ end
+ end
+end
diff --git a/lib/arel/algebra/relations/utilities/nil.rb b/lib/arel/algebra/relations/utilities/nil.rb
new file mode 100644
index 0000000000..6a9d678c45
--- /dev/null
+++ b/lib/arel/algebra/relations/utilities/nil.rb
@@ -0,0 +1,7 @@
+require 'singleton'
+
+module Arel
+ class Nil < Relation
+ include Singleton
+ end
+end
diff --git a/lib/arel/algebra/relations/writes/delete.rb b/lib/arel/algebra/relations/writes/delete.rb
new file mode 100644
index 0000000000..a94067c7fa
--- /dev/null
+++ b/lib/arel/algebra/relations/writes/delete.rb
@@ -0,0 +1,10 @@
+module Arel
+ class Deletion < Compound
+ attributes :relation
+ deriving :initialize, :==
+
+ def call
+ engine.delete(self)
+ end
+ end
+end
diff --git a/lib/arel/algebra/relations/writes/insert.rb b/lib/arel/algebra/relations/writes/insert.rb
new file mode 100644
index 0000000000..6d85e9769a
--- /dev/null
+++ b/lib/arel/algebra/relations/writes/insert.rb
@@ -0,0 +1,14 @@
+module Arel
+ class Insert < Compound
+ attributes :relation, :record
+ deriving :==
+
+ def initialize(relation, record)
+ @relation, @record = relation, record.bind(relation)
+ end
+
+ def call
+ engine.create(self)
+ end
+ end
+end
diff --git a/lib/arel/algebra/relations/writes/update.rb b/lib/arel/algebra/relations/writes/update.rb
new file mode 100644
index 0000000000..e647218a80
--- /dev/null
+++ b/lib/arel/algebra/relations/writes/update.rb
@@ -0,0 +1,14 @@
+module Arel
+ class Update < Compound
+ attributes :relation, :assignments
+ deriving :==
+
+ def initialize(relation, assignments)
+ @relation, @assignments = relation, assignments
+ end
+
+ def call
+ engine.update(self)
+ end
+ end
+end