aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorErnie Miller <ernie@metautonomo.us>2010-03-30 15:32:39 -0400
committerErnie Miller <ernie@metautonomo.us>2010-05-07 13:07:21 -0400
commit0433b054eebd5a53ff6c5f35383a6c0aed0015b2 (patch)
treeed07230cd0f1e033138f89e103bb2ce4cb6d6f7a
parent0afcfa27c9f386ca7c190cd1f66db1cdd9971f3b (diff)
downloadrails-0433b054eebd5a53ff6c5f35383a6c0aed0015b2.tar.gz
rails-0433b054eebd5a53ff6c5f35383a6c0aed0015b2.tar.bz2
rails-0433b054eebd5a53ff6c5f35383a6c0aed0015b2.zip
Tests for notmatches and notin, and fixes for issues found in tests
-rw-r--r--lib/arel/algebra/predicates.rb23
-rw-r--r--lib/arel/engines/memory/predicates.rb53
-rw-r--r--lib/arel/engines/sql/predicates.rb6
-rw-r--r--spec/relations/join_spec.rb6
-rw-r--r--spec/relations/relation_spec.rb2
-rw-r--r--spec/shared/relation_spec.rb37
6 files changed, 106 insertions, 21 deletions
diff --git a/lib/arel/algebra/predicates.rb b/lib/arel/algebra/predicates.rb
index 43606139b0..be80f2a987 100644
--- a/lib/arel/algebra/predicates.rb
+++ b/lib/arel/algebra/predicates.rb
@@ -14,19 +14,28 @@ module Arel
end
end
- class Grouped < Predicate
- attributes :operator, :operand1, :operands2
+ class Polyadic < Predicate
+ attributes :operator, :operand1, :additional_operands
- def initialize(operator, operand1, *operands2)
+ def initialize(operator, operand1, *additional_operands)
@operator = operator
@operand1 = operand1
- @operands2 = operands2.uniq
+ @additional_operands = additional_operands.uniq
end
def ==(other)
self.class === other and
+ @operator == operator and
@operand1 == other.operand1 and
- same_elements?(@operands2, other.operands2)
+ same_elements?(@additional_operands, other.additional_operands)
+ end
+
+ def bind(relation)
+ self.class.new(
+ operator,
+ operand1.find_correlate_in(relation),
+ *additional_operands.map {|o| o.find_correlate_in(relation)}
+ )
end
private
@@ -43,6 +52,10 @@ module Arel
class Unary < Predicate
attributes :operand
deriving :initialize, :==
+
+ def bind(relation)
+ self.class.new(operand.find_correlate_in(relation))
+ end
end
class Binary < Predicate
diff --git a/lib/arel/engines/memory/predicates.rb b/lib/arel/engines/memory/predicates.rb
index d0963e2f74..c0ee862626 100644
--- a/lib/arel/engines/memory/predicates.rb
+++ b/lib/arel/engines/memory/predicates.rb
@@ -5,6 +5,49 @@ module Arel
operand1.eval(row).send(operator, operand2.eval(row))
end
end
+
+ class Unary < Predicate
+ def eval(row)
+ operand.eval(row).send(operator)
+ end
+ end
+
+ class Not < Unary
+ def operator; '!' end
+ end
+
+ class CompoundPredicate < Binary
+ def eval(row)
+ eval "operand1.eval(row) #{operator} operand2.eval(row)"
+ end
+ end
+
+ class Or < CompoundPredicate
+ def operator; :or end
+ end
+
+ class And < CompoundPredicate
+ def operator; :and end
+ end
+
+ class GroupedPredicate < Polyadic
+ def eval(row)
+ group = additional_operands.inject([]) do |results, operand|
+ results << operator.new(operand1, operand)
+ end
+ group.send(compounder) do |operation|
+ operation.eval(row)
+ end
+ end
+ end
+
+ class Any < GroupedPredicate
+ def compounder; :any? end
+ end
+
+ class All < GroupedPredicate
+ def compounder; :all? end
+ end
class Equality < Binary
def operator; :== end
@@ -37,16 +80,20 @@ module Arel
end
class NotMatch < Binary
- def operator; :!~ end
+ def eval(row)
+ operand1.eval(row) !~ operand2.eval(row)
+ end
end
class In < Binary
- def operator; :include? end
+ def eval(row)
+ operand2.eval(row).include?(operand1.eval(row))
+ end
end
class NotIn < Binary
def eval(row)
- !(operand1.eval(row).include?(operand2.eval(row)))
+ !(operand2.eval(row).include?(operand1.eval(row)))
end
end
end
diff --git a/lib/arel/engines/sql/predicates.rb b/lib/arel/engines/sql/predicates.rb
index 29bc74c605..b459168620 100644
--- a/lib/arel/engines/sql/predicates.rb
+++ b/lib/arel/engines/sql/predicates.rb
@@ -30,11 +30,11 @@ module Arel
def predicate_sql; "AND" end
end
- class GroupedPredicate < Grouped
+ class GroupedPredicate < Polyadic
def to_sql(formatter = nil)
"(" +
- operands2.inject([]) { |predicates, operand|
- predicates << operator.new(operand1, operand).to_sql
+ additional_operands.inject([]) { |predicates, operand|
+ predicates << operator.new(operand1, operand).to_sql(formatter)
}.join(" #{predicate_sql} ") +
")"
end
diff --git a/spec/relations/join_spec.rb b/spec/relations/join_spec.rb
index 47e468a9f9..3894d175e8 100644
--- a/spec/relations/join_spec.rb
+++ b/spec/relations/join_spec.rb
@@ -13,6 +13,7 @@ describe "Arel" do
r.attribute :id, Arel::Attributes::Integer
r.attribute :owner_id, Arel::Attributes::Integer
+ r.attribute :name, Arel::Attributes::String
r.attribute :age, Arel::Attributes::Integer
end
end
@@ -28,9 +29,10 @@ describe "Arel" do
8.times do |i|
thing_id = owner_id * 8 + i
age = 2 * thing_id
+ name = "Name#{thing_id}"
- @thing.insert([thing_id, owner_id, age])
- @expected << Arel::Row.new(@relation, [thing_id, owner_id, age, owner_id])
+ @thing.insert([thing_id, owner_id, name, age])
+ @expected << Arel::Row.new(@relation, [thing_id, owner_id, name, age, owner_id])
end
end
end
diff --git a/spec/relations/relation_spec.rb b/spec/relations/relation_spec.rb
index 808ddf1444..0381f8759d 100644
--- a/spec/relations/relation_spec.rb
+++ b/spec/relations/relation_spec.rb
@@ -14,7 +14,7 @@ describe "Arel" do
describe "Relation" do
before :all do
- @expected = (1..20).map { |i| @relation.insert([i, nil, 2 * i]) }
+ @expected = (1..20).map { |i| @relation.insert([i, "Name#{i}", 2 * i]) }
end
it_should_behave_like 'A Relation'
diff --git a/spec/shared/relation_spec.rb b/spec/shared/relation_spec.rb
index 1407dddb2a..dabbde2dd5 100644
--- a/spec/shared/relation_spec.rb
+++ b/spec/shared/relation_spec.rb
@@ -35,7 +35,7 @@ share_examples_for 'A Relation' do
@relation.where(@relation[:age].eq(@pivot[@relation[:age]])).should have_rows(expected)
end
- it "finds rows with a not predicate" do
+ it "finds rows with a noteq predicate" do
expected = @expected.select { |r| r[@relation[:age]] != @pivot[@relation[:age]] }
@relation.where(@relation[:age].noteq(@pivot[@relation[:age]])).should have_rows(expected)
end
@@ -60,17 +60,40 @@ share_examples_for 'A Relation' do
@relation.where(@relation[:age].gteq(@pivot[@relation[:age]])).should have_rows(expected)
end
- it "finds rows with a matches predicate"
+ it "finds rows with a matches predicate" do
+ expected = @expected.select { |r| r[@relation[:name]] =~ /#{@pivot[@relation[:name]]}/ }
+ @relation.where(@relation[:name].matches(/#{@pivot[@relation[:name]]}/)).should have_rows(expected)
+ end
- it "finds rows with a not matches predicate"
+ it "finds rows with a not matches predicate" do
+ expected = @expected.select { |r| r[@relation[:name]] !~ /#{@pivot[@relation[:name]]}/ }
+ @relation.where(@relation[:name].notmatches(/#{@pivot[@relation[:name]]}/)).should have_rows(expected)
+ end
it "finds rows with an in predicate" do
- pending
- set = @expected[1..(@expected.length/2+1)]
- @relation.all(:id.in => set.map { |r| r.id }).should have_resources(set)
+ expected = @expected.select {|r| r[@relation[:age]] >=3 && r[@relation[:age]] <= 20}
+ @relation.where(@relation[:age].in(3..20)).should have_rows(expected)
end
- it "finds rows with a not in predicate"
+ it "finds rows with a not in predicate" do
+ expected = @expected.select {|r| !(r[@relation[:age]] >=3 && r[@relation[:age]] <= 20)}
+ @relation.where(@relation[:age].notin(3..20)).should have_rows(expected)
+ end
+
+ it "finds rows with a not predicate" do
+ expected = @expected.select {|r| !(r[@relation[:age]] >= 3 && r[@relation[:age]] <= 20)}
+ @relation.where(@relation[:age].in(3..20).not).should have_rows(expected)
+ end
+
+ it "finds rows with a grouped predicate of class Any" do
+ expected = @expected.select {|r| [2,4,8,16].include?(r[@relation[:age]])}
+ @relation.where(@relation[:age].in_any([2,4], [8, 16])).should have_rows(expected)
+ end
+
+ it "finds rows with a grouped predicate of class All" do
+ expected = @expected.select {|r| r[@relation[:name]] =~ /Name/ && r[@relation[:name]] =~ /1/}
+ @relation.where(@relation[:name].matches_all(/Name/, /1/)).should have_rows(expected)
+ end
end
describe "#order" do