diff --git a/lib/mongo/collection.rb b/lib/mongo/collection.rb index 790065a..6203889 100644 --- a/lib/mongo/collection.rb +++ b/lib/mongo/collection.rb @@ -67,6 +67,11 @@ module XGen # ascending, -1 == descending, or array of field names (all # assumed to be sorted in ascending order). # :hint :: See #hint. This option overrides the collection-wide value. + # :snapshot :: If true, snapshot mode will be used for this query. + # Snapshot mode assures no duplicates are returned, or + # objects missed, which were preset at both the start and + # end of the query's execution. For details see + # http://www.mongodb.org/display/DOCS/How+to+do+Snapshotting+in+the+Mongo+Database def find(selector={}, options={}) fields = options.delete(:fields) fields = nil if fields && fields.empty? @@ -74,13 +79,14 @@ module XGen limit = options.delete(:limit) || 0 sort = options.delete(:sort) hint = options.delete(:hint) + snapshot = options.delete(:snapshot) if hint hint = normalize_hint_fields(hint) else hint = @hint # assumed to be normalized already end raise RuntimeError, "Unknown options [#{options.inspect}]" unless options.empty? - @db.query(self, Query.new(selector, fields, offset, limit, sort, hint)) + @db.query(self, Query.new(selector, fields, offset, limit, sort, hint, snapshot)) end # Find the first record that matches +selector+. See #find. diff --git a/lib/mongo/message/query_message.rb b/lib/mongo/message/query_message.rb index 4ff561e..d5316b9 100644 --- a/lib/mongo/message/query_message.rb +++ b/lib/mongo/message/query_message.rb @@ -62,7 +62,7 @@ module XGen end sel['$hint'] = query.hint if query.hint && query.hint.length > 0 sel['$explain'] = true if query.explain - + sel['$snapshot'] = true if query.snapshot end write_doc(sel) write_doc(query.fields) if query.fields diff --git a/lib/mongo/query.rb b/lib/mongo/query.rb index ef12f10..9e9a017 100644 --- a/lib/mongo/query.rb +++ b/lib/mongo/query.rb @@ -26,7 +26,7 @@ module XGen # Mongo documentation for query details. class Query - attr_accessor :number_to_skip, :number_to_return, :order_by + attr_accessor :number_to_skip, :number_to_return, :order_by, :snapshot # If true, $explain will be set in QueryMessage that uses this query. attr_accessor :explain # Either +nil+ or a hash (preferably an OrderedHash). @@ -63,9 +63,9 @@ module XGen # hint :: If not +nil+, specifies query hint fields. Must be either # +nil+ or a hash (preferably an OrderedHash). See # Collection#hint. - def initialize(sel={}, return_fields=nil, number_to_skip=0, number_to_return=0, order_by=nil, hint=nil) - @number_to_skip, @number_to_return, @order_by, @hint = - number_to_skip, number_to_return, order_by, hint + def initialize(sel={}, return_fields=nil, number_to_skip=0, number_to_return=0, order_by=nil, hint=nil, snapshot=nil) + @number_to_skip, @number_to_return, @order_by, @hint, @snapshot = + number_to_skip, number_to_return, order_by, hint, snapshot @explain = nil self.selector = sel self.fields = return_fields @@ -111,7 +111,7 @@ module XGen end def contains_special_fields - (@order_by != nil && @order_by.length > 0) || @explain || @hint + (@order_by != nil && @order_by.length > 0) || @explain || @hint || @snapshot end end end diff --git a/tests/test_db_api.rb b/tests/test_db_api.rb index 876445a..d70be14 100644 --- a/tests/test_db_api.rb +++ b/tests/test_db_api.rb @@ -781,6 +781,14 @@ class DBAPITest < Test::Unit::TestCase assert_equal 0, b.count() end + # doesn't really test functionality, just that the option is set correctly + def test_snapshot + @@db.collection("test").find({}, :snapshot => true).to_a + assert_raise RuntimeError do + @@db.collection("test").find({}, :snapshot => true, :sort => 'a').to_a + end + end + # TODO this test fails with error message "Undefed Before end of object" # That is a database error. The undefined type may go away.