Permalink
Browse files

Merge pull request #1594 from i0rek/typecast

Typecast $or and $and conditions.
  • Loading branch information...
2 parents 72fb250 + 7c0755c commit 3b70df6aa3a1b8a7b0612195fb9585446dc2fe85 @durran durran committed Jan 15, 2012
Showing with 112 additions and 35 deletions.
  1. +22 −4 lib/mongoid/criterion/selector.rb
  2. +90 −31 spec/unit/mongoid/criterion/selector_spec.rb
@@ -85,11 +85,29 @@ def inspect
# @since 1.0.0
def try_to_typecast(key, value)
access = key.to_s
- if !fields.has_key?(access) && !aliased_fields.has_key?(access)
- return value
+ if field = fields[key.to_s] || fields[aliased_fields[key.to_s]]
+ typecast_value_for(field, value)
+ elsif proper_and_or_value?(key, value)
+ handle_and_or_value(value)
+ else
+ value
+ end
+ end
+
+ def proper_and_or_value?(key, value)
+ ["$and", "$or"].include?(key) &&
+ value.is_a?(Array) &&
+ value.all?{ |e| e.is_a?(Hash) }
+ end
+
+ def handle_and_or_value(values)
+ [].tap do |result|
+ values.map do |value|
+ value.each do |key, value|
+ result.push key => try_to_typecast(key, value)
+ end
+ end
end
- field = fields[access] || fields[aliased_fields[access]]
- typecast_value_for(field, value)
end
# Get the typecast value for the defined field.
@@ -6,6 +6,14 @@
stub(:type => Integer, :localized? => false)
end
+ let(:klass) do
+ Class.new
+ end
+
+ let(:selector) do
+ Mongoid::Criterion::Selector.new(klass)
+ end
+
describe "#initialize" do
let(:klass) do
@@ -24,14 +32,6 @@
describe "#[]=" do
- let(:klass) do
- Class.new
- end
-
- let(:selector) do
- Mongoid::Criterion::Selector.new(klass)
- end
-
it "should store the values provided" do
klass.stubs(:fields).returns({})
klass.stubs(:aliased_fields).returns({})
@@ -91,15 +91,6 @@
end
describe "#update" do
-
- let(:klass) do
- Class.new
- end
-
- let(:selector) do
- Mongoid::Criterion::Selector.new(klass)
- end
-
it "should typecast values when possible" do
klass.stubs(:fields).returns({"age" => field})
klass.stubs(:aliased_fields).returns({})
@@ -110,15 +101,6 @@
end
describe "#merge!" do
-
- let(:klass) do
- Class.new
- end
-
- let(:selector) do
- Mongoid::Criterion::Selector.new(klass)
- end
-
it "should typecast values when possible" do
klass.stubs(:fields).returns({"age" => field})
klass.stubs(:aliased_fields).returns({})
@@ -129,13 +111,37 @@
end
describe "#try_to_typecast" do
+ context "when the key is $or or $and" do
+ let(:value) { { "age" => "45" } }
- let(:klass) do
- Class.new
- end
+ before do
+ klass.stubs(:fields).returns({})
+ klass.stubs(:aliased_fields).returns({})
+ end
+
+ context "when the value is not an array" do
+ it "returns the value" do
+ selector.expects(:typecast_value_for).with(field, value["age"]).never
+ selector.send(:try_to_typecast, "$or", value).should == value
+ end
+ end
- let(:selector) do
- Mongoid::Criterion::Selector.new(klass)
+ context "when the value is an array containing hashes" do
+ context "when the keys are not declared" do
+ it "returns the array" do
+ selector.expects(:typecast_value_for).with(field, value["time"]).never
+ selector.send(:try_to_typecast, "$or", [value]).should == [value]
+ end
+ end
+
+ context "when the keys are declared" do
+ it "returns the typecasted array" do
+ klass.stubs(:fields).returns({"age" => field})
+ field.expects(:selection).with("45").returns(45).once
+ selector.send(:try_to_typecast, "$or", [value]).should == ["age" => 45]
+ end
+ end
+ end
end
context "when the key is not a declared field" do
@@ -157,6 +163,59 @@
end
end
+ describe "#proper_and_or_value" do
+ before do
+ klass.stubs(:fields).returns({})
+ klass.stubs(:aliased_fields).returns({})
+ end
+
+ context "when the key is not $or or $and" do
+ it "returns false" do
+ selector.send(:proper_and_or_value?, "fubar", nil).should be_false
+ end
+ end
+
+ context "when the key is $or or $and" do
+ context "when the value is not an array" do
+ it "returns false" do
+ selector.send(:proper_and_or_value?, "$or", nil).should be_false
+ end
+ end
+
+ context "when the value is an array" do
+ context "when the entries are no hashes" do
+ it "returns false" do
+ selector.send(:proper_and_or_value?, "$or", [nil]).should be_false
+ end
+ end
+
+ context "when the array is empty" do
+ it "returns true" do
+ selector.send(:proper_and_or_value?, "$or", []).should be_true
+ end
+ end
+
+ context "when the entries are hashes" do
+ it "returns true" do
+ selector.send(:proper_and_or_value?, "$or", [{}]).should be_true
+ end
+ end
+ end
+ end
+ end
+
+ describe "#handle_and_or_value" do
+ before do
+ klass.stubs(:fields).returns({})
+ klass.stubs(:aliased_fields).returns({})
+ end
+
+ it "tries to typecast every entry" do
+ selector.expects(:try_to_typecast).with("age", "45").once
+ selector.send(:handle_and_or_value, [{"age" => "45"}])
+ end
+ end
+
describe "#typecast_value_for" do
let(:field) { stub(:type => Integer) }
let(:selector) { Mongoid::Criterion::Selector.allocate }

0 comments on commit 3b70df6

Please sign in to comment.