Moved hint call from Cursor into Collection#find options and Query#initialize

parameter.
This commit is contained in:
Jim Menard 2009-01-29 07:15:59 -05:00
parent 086fbaf6e5
commit b3bc2c41e2
6 changed files with 63 additions and 51 deletions

View File

@ -23,27 +23,18 @@ module XGen
# A named collection of records in a database. # A named collection of records in a database.
class Collection class Collection
attr_reader :db, :name, :hint_fields attr_reader :db, :name, :hint
def initialize(db, name) def initialize(db, name)
@db = db @db = db
@name = name @name = name
end end
# Set hint fields to use and return +self+. hint_fields may be a # Set hint fields to use and return +self+. hint may be a
# single field name, array of field names, or a hash whose keys will # single field name, array of field names, or a hash whose keys will
# become the hint field names. May be +nil+. # become the hint field names. May be +nil+.
def hint(hint_fields) def hint=(hint)
@hint_fields = case hint_fields @hint = normalize_hint_fields(hint)
when String
[hint_fields]
when Hash
hint_fields.keys
when nil
nil
else
hint_fields.to_a
end
self self
end end
@ -57,14 +48,21 @@ module XGen
# :sort :: Either hash of field names as keys and 1/-1 as values; 1 == # :sort :: Either hash of field names as keys and 1/-1 as values; 1 ==
# ascending, -1 == descending, or array of field names (all # ascending, -1 == descending, or array of field names (all
# assumed to be sorted in ascending order). # assumed to be sorted in ascending order).
# :hint :: See #hint. This option overrides the collection-wide value.
def find(selector={}, options={}) def find(selector={}, options={})
fields = options.delete(:fields) fields = options.delete(:fields)
fields = nil if fields && fields.empty? fields = nil if fields && fields.empty?
offset = options.delete(:offset) || 0 offset = options.delete(:offset) || 0
limit = options.delete(:limit) || 0 limit = options.delete(:limit) || 0
sort = options.delete(:sort) sort = options.delete(:sort)
hint = options.delete(:hint)
if hint
hint = normalize_hint_fields(hint)
else
hint = @hint
end
raise RuntimeError, "Unknown options [#{options.inspect}]" unless options.empty? raise RuntimeError, "Unknown options [#{options.inspect}]" unless options.empty?
@db.query(self, Query.new(selector, fields, offset, limit, sort)) @db.query(self, Query.new(selector, fields, offset, limit, sort, hint))
end end
# Insert +objects+, which are hashes. "<<" is aliased to this method. # Insert +objects+, which are hashes. "<<" is aliased to this method.
@ -154,6 +152,20 @@ module XGen
@db.count(@name, selector || {}) @db.count(@name, selector || {})
end end
protected
def normalize_hint_fields(hint)
case hint
when String
[hint]
when Hash
hint.keys
when nil
nil
else
hint.to_a
end
end
end end
end end
end end

View File

@ -42,24 +42,6 @@ module XGen
def closed?; @closed; end def closed?; @closed; end
# Set hint fields to use and return +self+. hint_fields may be a
# single field name, array of field names, or a hash whose keys will
# become the hint field names. May be +nil+. If no hint fields are
# specified, the ones in the collection are used if they exist.
def hint(hint_fields)
@hint_fields = case hint_fields
when String
[hint_fields]
when Hash
hint_fields.keys
when nil
nil
else
hint_fields.to_a
end
self
end
# Return +true+ if there are more records to retrieve. We do not check # Return +true+ if there are more records to retrieve. We do not check
# @num_to_return; #each is responsible for doing that. # @num_to_return; #each is responsible for doing that.
def more? def more?
@ -223,12 +205,8 @@ module XGen
def send_query_if_needed def send_query_if_needed
# Run query first time we request an object from the wire # Run query first time we request an object from the wire
unless @query_run unless @query_run
hints = @hint_fields || @collection.hint_fields
old_hints = @query.hint_fields
@query.hint_fields = hints
@db.send_query_message(QueryMessage.new(@db.name, @collection.name, @query)) @db.send_query_message(QueryMessage.new(@db.name, @collection.name, @query))
@query_run = true @query_run = true
@query.hint_fields = old_hints
read_all read_all
end end
end end

View File

@ -44,9 +44,9 @@ module XGen
raise "illegal order_by: is a #{query.order_by.class.name}, must be String, Array, Hash, or OrderedHash" raise "illegal order_by: is a #{query.order_by.class.name}, must be String, Array, Hash, or OrderedHash"
end end
end end
if query.hint_fields && query.hint_fields.length > 0 if query.hint && query.hint.length > 0
hints = OrderedHash.new hints = OrderedHash.new
query.hint_fields.each { |hf| hints[hf] = 1 } query.hint.each { |hf| hints[hf] = 1 }
sel['$hint'] = hints sel['$hint'] = hints
end end
if query.explain if query.explain

View File

@ -29,7 +29,7 @@ module XGen
# If true, $explain will be set in QueryMessage that uses this query. # If true, $explain will be set in QueryMessage that uses this query.
attr_accessor :explain attr_accessor :explain
# Either +nil+ or an array of hint field names. # Either +nil+ or an array of hint field names.
attr_accessor :hint_fields attr_accessor :hint
attr_reader :selector # writer defined below attr_reader :selector # writer defined below
# sel :: A hash describing the query. See the Mongo docs for details. # sel :: A hash describing the query. See the Mongo docs for details.
@ -58,8 +58,12 @@ module XGen
# probably will not be what you intend because key order # probably will not be what you intend because key order
# is not preserved. (order_by is called :sort in calls to # is not preserved. (order_by is called :sort in calls to
# Collection#find.) # Collection#find.)
def initialize(sel={}, return_fields=nil, number_to_skip=0, number_to_return=0, order_by=nil) #
@number_to_skip, @number_to_return, @order_by = number_to_skip, number_to_return, order_by # hint :: If not +nil+, specifies query hint fields. 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
self.selector = sel self.selector = sel
self.fields = return_fields self.fields = return_fields
end end
@ -102,7 +106,7 @@ module XGen
end end
def contains_special_fields def contains_special_fields
(@order_by != nil && @order_by.length > 0) || @explain || @hint_fields (@order_by != nil && @order_by.length > 0) || @explain || @hint
end end
end end
end end

View File

@ -54,13 +54,4 @@ class CursorTest < Test::Unit::TestCase
end end
end end
def test_hint
begin
cursor = @coll.find('a' => 1).hint('a')
assert_equal 1, cursor.to_a.size
rescue => ex
fail ex.to_s
end
end
end end

View File

@ -372,4 +372,31 @@ class DBAPITest < Test::Unit::TestCase
assert_equal "#{@db.host}:#{@db.port}", @db.master assert_equal "#{@db.host}:#{@db.port}", @db.master
end end
def test_hint
begin
assert_nil @coll.hint
assert_equal 1, @coll.find({'a' => 1}, :hint => 'a').to_a.size
assert_equal 1, @coll.find({'a' => 1}, :hint => ['a']).to_a.size
assert_equal 1, @coll.find({'a' => 1}, :hint => {'a' => 1}).to_a.size
@coll.hint = 'a'
assert_equal ['a'], @coll.hint
assert_equal 1, @coll.find('a' => 1).to_a.size
@coll.hint = ['a']
assert_equal ['a'], @coll.hint
assert_equal 1, @coll.find('a' => 1).to_a.size
@coll.hint = {'a' => 1}
assert_equal ['a'], @coll.hint
assert_equal 1, @coll.find('a' => 1).to_a.size
@coll.hint = nil
assert_nil @coll.hint
assert_equal 1, @coll.find('a' => 1).to_a.size
rescue => ex
fail ex.to_s
end
end
end end