Permalink
Browse files

Collection delegates enslaved queries through find, find_one, map_reduce

  • Loading branch information...
durran committed Feb 10, 2010
1 parent ec3b0ae commit e5ef353ce07e1557d5a5527c5feba91c23a159cc
View
@@ -16,16 +16,7 @@ class Collection
# Example:
#
# <tt>collection.save({ :name => "Al" })</tt>
- proxy(:master, Collections::Operations::WRITE)
-
- # All read operations should be intelligently directed to either the master
- # or the slave, depending on where the read counter is and what it's
- # maximum was configured at.
- #
- # Example:
- #
- # <tt>collection.find({ :name => "Al" })</tt>
- proxy(:directed, (Collections::Operations::READ - [:find]))
+ proxy(:master, Collections::Operations::PROXIED)
# Determines where to send the next read query. If the slaves are not
# defined then send to master. If the read counter is under the configured
@@ -38,14 +29,9 @@ class Collection
# Return:
#
# Either a +Master+ or +Slaves+ collection.
- def directed
- if under_max_counter? || slaves.empty?
- @counter = @counter + 1
- master
- else
- @counter = 0
- slaves
- end
+ def directed(options = {})
+ enslave = options.delete(:enslave)
+ enslave ? slaves : master
end
# Find documents from the database given a selector and options.
@@ -59,35 +45,50 @@ def directed
#
# <tt>collection.find({ :test => "value" })</tt>
def find(selector = {}, options = {})
- cursor = Mongoid::Cursor.new(@klass, self, directed.find(selector, options))
+ cursor = Mongoid::Cursor.new(@klass, self, directed(options).find(selector, options))
if block_given?
yield cursor; cursor.close
else
cursor
end
end
+ # Find the first document from the database given a selector and options.
+ #
+ # Options:
+ #
+ # selector: A +Hash+ selector that is the query.
+ # options: The options to pass to the db.
+ #
+ # Example:
+ #
+ # <tt>collection.find_one({ :test => "value" })</tt>
+ def find_one(selector = {}, options = {})
+ directed(options).find_one(selector, options)
+ end
+
# Initialize a new Mongoid::Collection, setting up the master, slave, and
# name attributes. Masters will be used for writes, slaves for reads.
#
# Example:
#
# <tt>Mongoid::Collection.new(masters, slaves, "test")</tt>
def initialize(klass, name)
- @klass, @name, @counter = klass, name, 0
+ @klass, @name = klass, name
end
- # Return the object responsible for reading documents from the database.
- # This is usually the slave databases, but in their absence the master will
- # handle the task.
+ # Perform a map/reduce on the documents.
#
- # Example:
+ # Options:
#
- # <tt>collection.reader</tt>
- def slaves
- @slaves ||= Collections::Slaves.new(Mongoid.slaves, @name)
+ # map: The map javascript funcdtion.
+ # reduce: The reduce javascript function.
+ def map_reduce(map, reduce, options = {})
+ directed(options).map_reduce(map, reduce, options)
end
+ alias :mapreduce :map_reduce
+
# Return the object responsible for writes to the database. This will
# always return a collection associated with the Master DB.
#
@@ -98,9 +99,15 @@ def master
@master ||= Collections::Master.new(Mongoid.master, @name)
end
- protected
- def under_max_counter?
- @counter < Mongoid.max_successive_reads
+ # Return the object responsible for reading documents from the database.
+ # This is usually the slave databases, but in their absence the master will
+ # handle the task.
+ #
+ # Example:
+ #
+ # <tt>collection.reader</tt>
+ def slaves
+ @slaves ||= Collections::Slaves.new(Mongoid.slaves, @name)
end
end
end
@@ -34,6 +34,7 @@ module Operations #:nodoc:
# Convenience constant for getting back all collection operations.
ALL = (READ + WRITE)
+ PROXIED = ALL - [ :find, :find_one, :map_reduce, :mapreduce ]
end
end
end
@@ -9,7 +9,7 @@ module Optional
#
# <tt>criteria.enslave</tt>
def enslave
- @options.merge!(:enslaved => true); self
+ @options.merge!(:enslave => true); self
end
# Adds a criterion to the +Criteria+ that specifies additional options
@@ -40,73 +40,99 @@
end
end
- describe "#directed" do
+ describe "#find" do
+
+ before do
+ @cursor = stub.quacks_like(Mongoid::Cursor.allocate)
+ Mongoid::Cursor.expects(:new).with(Person, collection, @mongo_cursor).returns(@cursor)
+ end
- context "when the counter is less than the maximum" do
+ context "when no block supplied" do
before do
- collection.instance_variable_set(:@counter, 0)
+ master.expects(:find).with({ :test => "value" }, {}).returns(@mongo_cursor)
end
- it "delegates to the master" do
- collection.directed.should == master
+ it "finds return a cursor" do
+ collection.find({ :test => "value"}).should == @cursor
end
- it "increments the counter" do
- collection.directed
- collection.counter.should == 1
+ end
+
+ context "when a block is supplied" do
+
+ before do
+ master.expects(:find).with({ :test => "value" }, {}).returns(@mongo_cursor)
+ end
+
+ it "yields to the cursor and closes it" do
+ @cursor.expects(:close).returns(true)
+ collection.find({ :test => "value" }) do |cur|
+ cur.should == @cursor
+ end
end
end
- context "when the counter is at the max" do
+ context "when an enslave option exists" do
before do
- slaves.expects(:empty?).returns(false)
- collection.instance_variable_set(:@counter, 10)
+ @options = { :enslave => true }
+ slaves.expects(:find).with({ :test => "value" }, {}).returns(@mongo_cursor)
end
- it "delegates to the slave" do
- collection.directed.should == slaves
+ it "sends the query to the slave pool" do
+ collection.find({ :test => "value"}, @options).should == @cursor
end
- it "resets the counter" do
- collection.directed
- collection.counter.should == 0
+ it "deletes the enslave option" do
+ collection.find({ :test => "value"}, @options)
+ @options[:enslave].should be_nil
end
end
- context "when the slave does not exist" do
+ context "when an enslave option does not exist" do
before do
- collection.instance_variable_set(:@counter, 10)
- slaves.expects(:empty?).returns(true)
+ master.expects(:find).with({ :test => "value" }, {}).returns(@mongo_cursor)
end
- it "delegates to the master" do
- collection.directed.should == master
+ it "sends the query to the master" do
+ collection.find({ :test => "value"}).should == @cursor
end
end
end
- describe "#find" do
+ describe "#find_one" do
before do
- @cursor = stub.quacks_like(Mongoid::Cursor.allocate)
- master.expects(:find).with({ :test => "value" }, {}).returns(@mongo_cursor)
- Mongoid::Cursor.expects(:new).with(Person, collection, @mongo_cursor).returns(@cursor)
+ @person = stub
end
- it "finds are returns a cursor" do
- collection.find({ :test => "value"}).should == @cursor
+ context "when an enslave option exists" do
+
+ before do
+ @options = { :enslave => true }
+ slaves.expects(:find_one).with({ :test => "value" }, {}).returns(@person)
+ end
+
+ it "sends the query to the slave pool" do
+ collection.find_one({ :test => "value"}, @options).should == @person
+ end
+
+ it "deletes the enslave option" do
+ collection.find_one({ :test => "value"}, @options)
+ @options[:enslave].should be_nil
+ end
end
- context "when a block is supplied" do
+ context "when an enslave option does not exist" do
- it "yields to the cursor and closes it" do
- @cursor.expects(:close).returns(true)
- collection.find({ :test => "value" }) do |cur|
- cur.should == @cursor
- end
+ before do
+ master.expects(:find_one).with({ :test => "value" }, {}).returns(@person)
+ end
+
+ it "sends the query to the master" do
+ collection.find_one({ :test => "value"}).should == @person
end
end
end
@@ -11,7 +11,7 @@
it "sets the enslaved option on the criteria" do
@criteria.enslave
- @criteria.options[:enslaved].should be_true
+ @criteria.options[:enslave].should be_true
end
it "returns self" do

0 comments on commit e5ef353

Please sign in to comment.