diff options
author | Ernie Miller <ernie@metautonomo.us> | 2010-04-09 19:52:43 -0400 |
---|---|---|
committer | Ernie Miller <ernie@metautonomo.us> | 2010-05-07 13:07:43 -0400 |
commit | bd473344000bd538d353e4bc6d20ca8fff2e4704 (patch) | |
tree | c2586b9dc543aa828dcbefd2769e7a1d7485280a /lib/arel/algebra | |
parent | 0433b054eebd5a53ff6c5f35383a6c0aed0015b2 (diff) | |
download | rails-bd473344000bd538d353e4bc6d20ca8fff2e4704.tar.gz rails-bd473344000bd538d353e4bc6d20ca8fff2e4704.tar.bz2 rails-bd473344000bd538d353e4bc6d20ca8fff2e4704.zip |
Support predicate complements and alternate not syntax (overload BasicObject#!)
Diffstat (limited to 'lib/arel/algebra')
-rw-r--r-- | lib/arel/algebra/attributes/attribute.rb | 4 | ||||
-rw-r--r-- | lib/arel/algebra/predicates.rb | 144 |
2 files changed, 124 insertions, 24 deletions
diff --git a/lib/arel/algebra/attributes/attribute.rb b/lib/arel/algebra/attributes/attribute.rb index 0266b38db3..640d6facde 100644 --- a/lib/arel/algebra/attributes/attribute.rb +++ b/lib/arel/algebra/attributes/attribute.rb @@ -104,12 +104,12 @@ module Arel ", :any => " def #{name}_any(*others) - Predicates::Any.new(Predicates::#{klass}, self, *others) + Predicates::Any.build(Predicates::#{klass}, self, *others) end ", :all => " def #{name}_all(*others) - Predicates::All.new(Predicates::#{klass}, self, *others) + Predicates::All.build(Predicates::#{klass}, self, *others) end " } 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 |