From 32fbb70f100d0d6f9800020ef519a09a0852ae47 Mon Sep 17 00:00:00 2001 From: Ernie Miller Date: Thu, 25 Mar 2010 20:18:36 -0400 Subject: Add grouped predicates (_any/_all) and refactored predication method definitions --- lib/arel/algebra/attributes/attribute.rb | 72 +++++++++++++++----------------- lib/arel/algebra/predicates.rb | 26 ++++++++++++ lib/arel/engines/sql/predicates.rb | 18 ++++++++ 3 files changed, 78 insertions(+), 38 deletions(-) (limited to 'lib') diff --git a/lib/arel/algebra/attributes/attribute.rb b/lib/arel/algebra/attributes/attribute.rb index d9ea588128..5689d69b02 100644 --- a/lib/arel/algebra/attributes/attribute.rb +++ b/lib/arel/algebra/attributes/attribute.rb @@ -82,48 +82,44 @@ module Arel include Congruence module Predications - def eq(other) - Predicates::Equality.new(self, other) - end - - def not(other) - Predicates::Not.new(self, other) - end - - def lt(other) - Predicates::LessThan.new(self, other) - end - - def lteq(other) - Predicates::LessThanOrEqualTo.new(self, other) - end - - def gt(other) - Predicates::GreaterThan.new(self, other) - end - - def gteq(other) - Predicates::GreaterThanOrEqualTo.new(self, other) - end - - def matches(regexp) - Predicates::Match.new(self, regexp) - end - - def notmatches(regexp) - Predicates::NotMatch.new(self, regexp) - end + methods = { + :eq => "Equality", + :not => "Not", + :lt => "LessThan", + :lteq => "LessThanOrEqualTo", + :gt => "GreaterThan", + :gteq => "GreaterThanOrEqualTo", + :matches => "Match", + :notmatches => "NotMatch", + :in => "In", + :notin => "NotIn" + } - def in(array) - if array.is_a?(Range) && array.exclude_end? - [Predicates::GreaterThanOrEqualTo.new(self, array.begin), Predicates::LessThan.new(self, array.end)] - else - Predicates::In.new(self, array) + def self.predication(name, klass) + methods = { + :operator => " + def #{name}(other) + Predicates::#{klass}.new(self, other) + end + ", + :any => " + def #{name}_any(*others) + Predicates::Any.new(Predicates::#{klass}, self, *others) + end + ", + :all => " + def #{name}_all(*others) + Predicates::All.new(Predicates::#{klass}, self, *others) + end + " + } + [:operator, :any, :all].each do |method_name| + module_eval methods[method_name], __FILE__, __LINE__ end end - def notin(array) - Predicates::NotIn.new(self, array) + methods.each_pair do |method_name, class_name| + predication(method_name, class_name) end end include Predications diff --git a/lib/arel/algebra/predicates.rb b/lib/arel/algebra/predicates.rb index 05a1de983d..ea1f771abb 100644 --- a/lib/arel/algebra/predicates.rb +++ b/lib/arel/algebra/predicates.rb @@ -9,6 +9,32 @@ module Arel And.new(self, other_predicate) end end + + class Grouped < Predicate + attributes :operator, :operand1, :operands2 + + def initialize(operator, operand1, *operands2) + @operator = operator + @operand1 = operand1 + @operands2 = operands2.uniq + end + + def ==(other) + self.class === other and + @operand1 == other.operand1 and + same_elements?(@operands2, other.operands2) + end + + private + + def same_elements?(a1, a2) + [:select, :inject, :size].each do |m| + return false unless [a1, a2].each {|a| a.respond_to?(m) } + end + a1.inject({}) { |h,e| h[e] = a1.select { |i| i == e }.size; h } == + a2.inject({}) { |h,e| h[e] = a2.select { |i| i == e }.size; h } + end + end class Binary < Predicate attributes :operand1, :operand2 diff --git a/lib/arel/engines/sql/predicates.rb b/lib/arel/engines/sql/predicates.rb index e9a068fb13..53bac7a2ca 100644 --- a/lib/arel/engines/sql/predicates.rb +++ b/lib/arel/engines/sql/predicates.rb @@ -19,6 +19,24 @@ module Arel class And < CompoundPredicate def predicate_sql; "AND" end end + + class GroupedPredicate < Grouped + def to_sql(formatter = nil) + "(" + + operands2.inject([]) { |predicates, operand| + predicates << operator.new(operand1, operand).to_sql + }.join(" #{predicate_sql} ") + + ")" + end + end + + class Any < GroupedPredicate + def predicate_sql; "OR" end + end + + class All < GroupedPredicate + def predicate_sql; "AND" end + end class Equality < Binary def predicate_sql -- cgit v1.2.3