aboutsummaryrefslogtreecommitdiffstats
path: root/lib/arel/algebra/predicates.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/arel/algebra/predicates.rb')
-rw-r--r--lib/arel/algebra/predicates.rb144
1 files changed, 122 insertions, 22 deletions
diff --git a/lib/arel/algebra/predicates.rb b/lib/arel/algebra/predicates.rb
index be80f2a987..2da37af2e7 100644
--- a/lib/arel/algebra/predicates.rb
+++ b/lib/arel/algebra/predicates.rb
@@ -9,32 +9,52 @@ module Arel
And.new(self, other_predicate)
end
- def not
+ def complement
Not.new(self)
end
+
+ def not
+ complement
+ end
+
+ if respond_to?('!') # Nice! We're running Ruby 1.9 and can override the inherited BasicObject#!
+ def empty? # Need to define empty? to keep Object#blank? from going haywire
+ false
+ end
+
+ define_method('!') do
+ self.complement
+ end
+ end
end
class Polyadic < Predicate
- attributes :operator, :operand1, :additional_operands
+ attributes :predicates
- def initialize(operator, operand1, *additional_operands)
- @operator = operator
- @operand1 = operand1
- @additional_operands = additional_operands.uniq
+ def initialize(*predicates)
+ @predicates = predicates
+ end
+
+ # Build a Polyadic predicate based on:
+ # * <tt>operator</tt> - The Predicate subclass that defines the type of operation
+ # (LessThan, Equality, etc)
+ # * <tt>operand1</tt> - The left-hand operand (normally an Arel::Attribute)
+ # * <tt>additional_operands</tt> - All possible right-hand operands
+ def self.build(operator, operand1, *additional_operands)
+ new(
+ *additional_operands.uniq.inject([]) do |predicates, operand|
+ predicates << operator.new(operand1, operand)
+ end
+ )
end
def ==(other)
- self.class === other and
- @operator == operator and
- @operand1 == other.operand1 and
- same_elements?(@additional_operands, other.additional_operands)
+ same_elements?(@predicates, other.predicates)
end
def bind(relation)
self.class.new(
- operator,
- operand1.find_correlate_in(relation),
- *additional_operands.map {|o| o.find_correlate_in(relation)}
+ *predicates.map {|p| p.find_correlate_in(relation)}
)
end
@@ -49,6 +69,18 @@ module Arel
end
end
+ class Any < Polyadic
+ def complement
+ All.new(*predicates.map {|p| p.complement})
+ end
+ end
+
+ class All < Polyadic
+ def complement
+ Any.new(*predicates.map {|p| p.complement})
+ end
+ end
+
class Unary < Predicate
attributes :operand
deriving :initialize, :==
@@ -57,6 +89,12 @@ module Arel
self.class.new(operand.find_correlate_in(relation))
end
end
+
+ class Not < Unary
+ def complement
+ operand
+ end
+ end
class Binary < Predicate
attributes :operand1, :operand2
@@ -72,6 +110,20 @@ module Arel
self.class.new(operand1.find_correlate_in(relation), operand2.find_correlate_in(relation))
end
end
+
+ class CompoundPredicate < Binary; end
+
+ class And < CompoundPredicate
+ def complement
+ Or.new(operand1.complement, operand2.complement)
+ end
+ end
+
+ class Or < CompoundPredicate
+ def complement
+ And.new(operand1.complement, operand2.complement)
+ end
+ end
class Equality < Binary
def ==(other)
@@ -79,16 +131,64 @@ module Arel
((operand1 == other.operand1 and operand2 == other.operand2) or
(operand1 == other.operand2 and operand2 == other.operand1))
end
+
+ def complement
+ Inequality.new(operand1, operand2)
+ end
end
- class Inequality < Equality; end
- class GreaterThanOrEqualTo < Binary; end
- class GreaterThan < Binary; end
- class LessThanOrEqualTo < Binary; end
- class LessThan < Binary; end
- class Match < Binary; end
- class NotMatch < Binary; end
- class In < Binary; end
- class NotIn < Binary; end
+ class Inequality < Equality
+ def complement
+ Equality.new(operand1, operand2)
+ end
+ end
+
+ class GreaterThanOrEqualTo < Binary
+ def complement
+ LessThan.new(operand1, operand2)
+ end
+ end
+
+ class GreaterThan < Binary
+ def complement
+ LessThanOrEqualTo.new(operand1, operand2)
+ end
+ end
+
+ class LessThanOrEqualTo < Binary
+ def complement
+ GreaterThan.new(operand1, operand2)
+ end
+ end
+
+ class LessThan < Binary
+ def complement
+ GreaterThanOrEqualTo.new(operand1, operand2)
+ end
+ end
+
+ class Match < Binary
+ def complement
+ NotMatch.new(operand1, operand2)
+ end
+ end
+
+ class NotMatch < Binary
+ def complement
+ Match.new(operand1, operand2)
+ end
+ end
+
+ class In < Binary
+ def complement
+ NotIn.new(operand1, operand2)
+ end
+ end
+
+ class NotIn < Binary
+ def complement
+ In.new(operand1, operand2)
+ end
+ end
end
end