Refactored Query class into Cursor class.
This commit is contained in:
parent
de5c078cec
commit
67b7f6b375
16
Rakefile
16
Rakefile
|
@ -14,11 +14,23 @@ include Config
|
|||
gem_command = "gem"
|
||||
gem_command = "gem1.9" if $0.match(/1\.9$/) # use gem1.9 if we used rake1.9
|
||||
|
||||
# NOTE: some of the tests assume Mongo is running
|
||||
# NOTE: the functional tests assume MongoDB is running.
|
||||
desc "Test the MongoDB Ruby driver."
|
||||
Rake::TestTask.new(:test) do |t|
|
||||
task :test do
|
||||
Rake::Task['test:unit'].invoke
|
||||
Rake::Task['test:functional'].invoke
|
||||
end
|
||||
|
||||
namespace :test do
|
||||
Rake::TestTask.new(:unit) do |t|
|
||||
t.test_files = FileList['test/unit/*_test.rb']
|
||||
t.verbose = true
|
||||
end
|
||||
|
||||
Rake::TestTask.new(:functional) do |t|
|
||||
t.test_files = FileList['test/test*.rb']
|
||||
t.verbose = true
|
||||
end
|
||||
end
|
||||
|
||||
desc "Generate documentation"
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
require 'mongo/types/binary'
|
||||
require 'mongo/types/code'
|
||||
require 'mongo/types/dbref'
|
||||
require 'mongo/types/objectid'
|
||||
require 'mongo/types/regexp_of_holding'
|
||||
|
||||
require 'mongo/util/conversions'
|
||||
require 'mongo/util/support'
|
||||
|
||||
require 'mongo/errors'
|
||||
require 'mongo/constants'
|
||||
|
|
|
@ -64,7 +64,7 @@ module Mongo
|
|||
# Return an array contining current profiling information from the
|
||||
# database.
|
||||
def profiling_info
|
||||
@db.query(Collection.new(@db, DB::SYSTEM_PROFILE_COLLECTION), Query.new({})).to_a
|
||||
Cursor.new(Collection.new(@db, DB::SYSTEM_PROFILE_COLLECTION), :selector => {}).to_a
|
||||
end
|
||||
|
||||
# Validate a named collection by raising an exception if there is a
|
||||
|
|
|
@ -14,8 +14,6 @@
|
|||
# limitations under the License.
|
||||
# ++
|
||||
|
||||
require 'mongo/query'
|
||||
|
||||
module Mongo
|
||||
|
||||
# A named collection of records in a database.
|
||||
|
@ -131,7 +129,8 @@ module Mongo
|
|||
end
|
||||
raise RuntimeError, "Unknown options [#{options.inspect}]" unless options.empty?
|
||||
|
||||
cursor = @db.query(self, Query.new(selector, fields, skip, limit, sort, hint, snapshot, timeout, @db.slave_ok?))
|
||||
cursor = Cursor.new(self, :selector => selector, :fields => fields, :skip => skip, :limit => limit,
|
||||
:order => sort, :hint => hint, :snapshot => snapshot, :timeout => timeout)
|
||||
if block_given?
|
||||
yield cursor
|
||||
cursor.close()
|
||||
|
|
|
@ -25,13 +25,29 @@ module Mongo
|
|||
|
||||
RESPONSE_HEADER_SIZE = 20
|
||||
|
||||
attr_reader :db, :collection, :query
|
||||
attr_reader :collection, :selector, :admin, :fields,
|
||||
:order, :hint, :snapshot, :timeout,
|
||||
:full_collection_name
|
||||
|
||||
# Create a new cursor.
|
||||
#
|
||||
# Should not be called directly by application developers.
|
||||
def initialize(db, collection, query, admin=false)
|
||||
@db, @collection, @query, @admin = db, collection, query, admin
|
||||
def initialize(collection, options={})
|
||||
@db = collection.db
|
||||
@collection = collection
|
||||
|
||||
@selector = convert_selector_for_query(options[:selector])
|
||||
@fields = convert_fields_for_query(options[:fields])
|
||||
@admin = options[:admin] || false
|
||||
@skip = options[:skip] || 0
|
||||
@limit = options[:limit] || 0
|
||||
@order = options[:order]
|
||||
@hint = options[:hint]
|
||||
@snapshot = options[:snapshot]
|
||||
@timeout = options[:timeout] || false
|
||||
@explain = options[:explain]
|
||||
|
||||
@full_collection_name = "#{@collection.db.name}.#{@collection.name}"
|
||||
@cache = []
|
||||
@closed = false
|
||||
@query_run = false
|
||||
|
@ -65,8 +81,8 @@ module Mongo
|
|||
# database error.
|
||||
def count
|
||||
command = OrderedHash["count", @collection.name,
|
||||
"query", @query.selector,
|
||||
"fields", @query.fields()]
|
||||
"query", @selector,
|
||||
"fields", @fields]
|
||||
response = @db.db_command(command)
|
||||
return response['n'].to_i if response['ok'] == 1
|
||||
return 0 if response['errmsg'] == "ns missing"
|
||||
|
@ -93,35 +109,39 @@ module Mongo
|
|||
order = key_or_list
|
||||
end
|
||||
|
||||
@query.order_by = order
|
||||
@order = order
|
||||
self
|
||||
end
|
||||
|
||||
# Limits the number of results to be returned by this cursor.
|
||||
# Returns the current number_to_return if no parameter is given.
|
||||
#
|
||||
# Raises InvalidOperation if this cursor has already been used.
|
||||
#
|
||||
# This method overrides any limit specified in the Collection#find method,
|
||||
# and only the last limit applied has an effect.
|
||||
def limit(number_to_return)
|
||||
def limit(number_to_return=nil)
|
||||
return @limit unless number_to_return
|
||||
check_modifiable
|
||||
raise ArgumentError, "limit requires an integer" unless number_to_return.is_a? Integer
|
||||
|
||||
@query.number_to_return = number_to_return
|
||||
@limit = number_to_return
|
||||
self
|
||||
end
|
||||
|
||||
# Skips the first +number_to_skip+ results of this cursor.
|
||||
# Returns the current number_to_skip if no parameter is given.
|
||||
#
|
||||
# Raises InvalidOperation if this cursor has already been used.
|
||||
#
|
||||
# This method overrides any skip specified in the Collection#find method,
|
||||
# and only the last skip applied has an effect.
|
||||
def skip(number_to_skip)
|
||||
def skip(number_to_skip=nil)
|
||||
return @skip unless number_to_skip
|
||||
check_modifiable
|
||||
raise ArgumentError, "skip requires an integer" unless number_to_skip.is_a? Integer
|
||||
|
||||
@query.number_to_skip = number_to_skip
|
||||
@skip = number_to_skip
|
||||
self
|
||||
end
|
||||
|
||||
|
@ -131,7 +151,7 @@ module Mongo
|
|||
# Iterating over an entire cursor will close it.
|
||||
def each
|
||||
num_returned = 0
|
||||
while more? && (@query.number_to_return <= 0 || num_returned < @query.number_to_return)
|
||||
while more? && (@limit <= 0 || num_returned < @limit)
|
||||
yield next_object()
|
||||
num_returned += 1
|
||||
end
|
||||
|
@ -148,7 +168,7 @@ module Mongo
|
|||
raise InvalidOperation, "can't call Cursor#to_a on a used cursor" if @query_run
|
||||
rows = []
|
||||
num_returned = 0
|
||||
while more? && (@query.number_to_return <= 0 || num_returned < @query.number_to_return)
|
||||
while more? && (@limit <= 0 || num_returned < @limit)
|
||||
rows << next_object()
|
||||
num_returned += 1
|
||||
end
|
||||
|
@ -157,16 +177,10 @@ module Mongo
|
|||
|
||||
# Returns an explain plan record for this cursor.
|
||||
def explain
|
||||
limit = @query.number_to_return
|
||||
@query.explain = true
|
||||
@query.number_to_return = -limit.abs
|
||||
|
||||
c = Cursor.new(@db, @collection, @query)
|
||||
c = Cursor.new(@collection, query_options_hash.merge(:limit => -@limit.abs, :explain => true))
|
||||
explanation = c.next_object
|
||||
c.close
|
||||
|
||||
@query.explain = false
|
||||
@query.number_to_return = limit
|
||||
explanation
|
||||
end
|
||||
|
||||
|
@ -194,8 +208,65 @@ module Mongo
|
|||
# Returns true if this cursor is closed, false otherwise.
|
||||
def closed?; @closed; end
|
||||
|
||||
# Returns an integer indicating which query options have been selected.
|
||||
# See http://www.mongodb.org/display/DOCS/Mongo+Wire+Protocol#MongoWireProtocol-Mongo::Constants::OPQUERY
|
||||
def query_opts
|
||||
timeout = @timeout ? 0 : Mongo::Constants::OP_QUERY_NO_CURSOR_TIMEOUT
|
||||
slave_ok = @db.slave_ok? ? Mongo::Constants::OP_QUERY_SLAVE_OK : 0
|
||||
slave_ok + timeout
|
||||
end
|
||||
|
||||
# Returns the query options set on this Cursor.
|
||||
def query_options_hash
|
||||
{ :selector => @selector,
|
||||
:fields => @fields,
|
||||
:admin => @admin,
|
||||
:skip => @skip_num,
|
||||
:limit => @limit_num,
|
||||
:order => @order,
|
||||
:hint => @hint,
|
||||
:snapshot => @snapshot,
|
||||
:timeout => @timeout }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Converts the +:fields+ parameter from a single field name or an array
|
||||
# of fields names to a hash, with the field names for keys and '1' for each
|
||||
# value.
|
||||
def convert_fields_for_query(fields)
|
||||
case fields
|
||||
when String, Symbol
|
||||
{fields => 1}
|
||||
when Array
|
||||
return nil if fields.length.zero?
|
||||
returning({}) do |hash|
|
||||
fields.each { |field| hash[field] = 1 }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Set query selector hash. If the selector is a Code or String object,
|
||||
# the selector will be used in a $where clause.
|
||||
# See http://www.mongodb.org/display/DOCS/Server-side+Code+Execution
|
||||
def convert_selector_for_query(selector)
|
||||
case selector
|
||||
when Hash
|
||||
selector
|
||||
when nil
|
||||
{}
|
||||
when String
|
||||
{"$where" => Code.new(selector)}
|
||||
when Code
|
||||
{"$where" => selector}
|
||||
end
|
||||
end
|
||||
|
||||
# Returns true if the query contains order, explain, hint, or snapshot.
|
||||
def query_contains_special_fields?
|
||||
@order || @explain || @hint || @snapshot
|
||||
end
|
||||
|
||||
def read_all
|
||||
read_message_header
|
||||
read_response_header
|
||||
|
@ -243,7 +314,7 @@ module Mongo
|
|||
end
|
||||
|
||||
# Internal method, not for general use. Return +true+ if there are
|
||||
# more records to retrieve. We do not check @query.number_to_return;
|
||||
# more records to retrieve. This methods does not check @limit;
|
||||
# #each is responsible for doing that.
|
||||
def more?
|
||||
num_remaining > 0
|
||||
|
@ -308,41 +379,40 @@ module Mongo
|
|||
|
||||
def construct_query_message(query)
|
||||
message = ByteBuffer.new
|
||||
message.put_int(query.query_opts)
|
||||
message.put_int(query_opts)
|
||||
db_name = @admin ? 'admin' : @db.name
|
||||
BSON.serialize_cstr(message, "#{db_name}.#{@collection.name}")
|
||||
message.put_int(query.number_to_skip)
|
||||
message.put_int(query.number_to_return)
|
||||
sel = query.selector
|
||||
if query.contains_special_fields
|
||||
sel = add_special_query_fields(sel, query)
|
||||
message.put_int(@skip)
|
||||
message.put_int(@limit)
|
||||
selector = @selector
|
||||
if query_contains_special_fields?
|
||||
selector = selector_with_special_query_fields
|
||||
end
|
||||
message.put_array(BSON.new.serialize(sel).to_a)
|
||||
message.put_array(BSON.new.serialize(query.fields).to_a) if query.fields
|
||||
message.put_array(BSON.new.serialize(selector).to_a)
|
||||
message.put_array(BSON.new.serialize(@fields).to_a) if @fields
|
||||
message
|
||||
end
|
||||
|
||||
def add_special_query_fields(sel, query)
|
||||
def selector_with_special_query_fields
|
||||
sel = OrderedHash.new
|
||||
sel['query'] = query.selector
|
||||
order_by = query.order_by
|
||||
sel['orderby'] = get_query_order_by(order_by) if order_by
|
||||
sel['$hint'] = query.hint if query.hint && query.hint.length > 0
|
||||
sel['$explain'] = true if query.explain
|
||||
sel['$snapshot'] = true if query.snapshot
|
||||
sel['query'] = @selector
|
||||
sel['orderby'] = formatted_order_clause if @order
|
||||
sel['$hint'] = @hint if @hint && @hint.length > 0
|
||||
sel['$explain'] = true if @explain
|
||||
sel['$snapshot'] = true if @snapshot
|
||||
sel
|
||||
end
|
||||
|
||||
def get_query_order_by(order_by)
|
||||
case order_by
|
||||
when String then string_as_sort_parameters(order_by)
|
||||
when Symbol then symbol_as_sort_parameters(order_by)
|
||||
when Array then array_as_sort_parameters(order_by)
|
||||
def formatted_order_clause
|
||||
case @order
|
||||
when String then string_as_sort_parameters(@order)
|
||||
when Symbol then symbol_as_sort_parameters(@order)
|
||||
when Array then array_as_sort_parameters(@order)
|
||||
when Hash # Should be an ordered hash, but this message doesn't care
|
||||
warn_if_deprecated(order_by)
|
||||
order_by
|
||||
warn_if_deprecated(@order)
|
||||
@order
|
||||
else
|
||||
raise InvalidSortValueError, "Illegal order_by, '#{query.order_by.class.name}'; must be String, Array, Hash, or OrderedHash"
|
||||
raise InvalidSortValueError, "Illegal order_by, '#{@order.class.name}'; must be String, Array, Hash, or OrderedHash"
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -351,7 +421,7 @@ module Mongo
|
|||
end
|
||||
|
||||
def close_cursor_if_query_complete
|
||||
close if @query.number_to_return > 0 && @n_received >= @query.number_to_return
|
||||
close if @limit > 0 && @n_received >= @limit
|
||||
end
|
||||
|
||||
def check_modifiable
|
||||
|
|
|
@ -18,7 +18,6 @@ require 'socket'
|
|||
require 'digest/md5'
|
||||
require 'thread'
|
||||
require 'mongo/collection'
|
||||
require 'mongo/query'
|
||||
require 'mongo/util/ordered_hash.rb'
|
||||
require 'mongo/admin'
|
||||
|
||||
|
@ -216,7 +215,7 @@ module Mongo
|
|||
def collections_info(coll_name=nil)
|
||||
selector = {}
|
||||
selector[:name] = full_collection_name(coll_name) if coll_name
|
||||
query(Collection.new(self, SYSTEM_NAMESPACE_COLLECTION), Query.new(selector))
|
||||
Cursor.new(Collection.new(self, SYSTEM_NAMESPACE_COLLECTION), :selector => selector)
|
||||
end
|
||||
|
||||
# Create a collection. If +strict+ is false, will return existing or
|
||||
|
@ -416,7 +415,7 @@ module Mongo
|
|||
def index_information(collection_name)
|
||||
sel = {:ns => full_collection_name(collection_name)}
|
||||
info = {}
|
||||
query(Collection.new(self, SYSTEM_INDEX_COLLECTION), Query.new(sel)).each { |index|
|
||||
Cursor.new(Collection.new(self, SYSTEM_INDEX_COLLECTION), :selector => sel).each { |index|
|
||||
info[index['name']] = index['key'].to_a
|
||||
}
|
||||
info
|
||||
|
@ -499,9 +498,8 @@ module Mongo
|
|||
end
|
||||
end
|
||||
|
||||
q = Query.new(selector)
|
||||
q.number_to_return = -1
|
||||
query(Collection.new(self, SYSTEM_COMMAND_COLLECTION), q, use_admin_db).next_object
|
||||
cursor = Cursor.new(Collection.new(self, SYSTEM_COMMAND_COLLECTION), :admin => use_admin_db, :limit => -1, :selector => selector)
|
||||
cursor.next_object
|
||||
end
|
||||
|
||||
def _synchronize &block
|
||||
|
|
|
@ -1,132 +0,0 @@
|
|||
# --
|
||||
# Copyright (C) 2008-2009 10gen Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# ++
|
||||
|
||||
require 'mongo/collection'
|
||||
require 'mongo/types/code'
|
||||
|
||||
module Mongo
|
||||
# Mongo documentation for query details.
|
||||
class Query
|
||||
|
||||
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).
|
||||
attr_accessor :hint
|
||||
attr_reader :selector # writer defined below
|
||||
|
||||
# sel :: A hash describing the query. See the Mongo docs for details.
|
||||
#
|
||||
# return_fields :: If not +nil+, a single field name or an array of
|
||||
# field names. Only those fields will be returned.
|
||||
# (Called :fields in calls to Collection#find.)
|
||||
#
|
||||
# number_to_skip :: Number of records to skip before returning
|
||||
# records. Default is 0.
|
||||
#
|
||||
# number_to_return :: Max number of records to return. (Called :limit
|
||||
# in calls to Collection#find.) Default is 0 (all
|
||||
# records).
|
||||
#
|
||||
# order_by :: If not +nil+, specifies record sort order. May be a
|
||||
# String, Hash, OrderedHash, or Array. If a string, the
|
||||
# results will be ordered by that field in ascending
|
||||
# order. If an array, it should be an array of field names
|
||||
# which will all be sorted in ascending order. If a hash,
|
||||
# it may be either a regular Hash or an OrderedHash. The
|
||||
# keys should be field names, and the values should be 1
|
||||
# (ascending) or -1 (descending). Note that if it is a
|
||||
# regular Hash then sorting by more than one field
|
||||
# probably will not be what you intend because key order
|
||||
# is not preserved. (order_by is called :sort in calls to
|
||||
# Collection#find.)
|
||||
# :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
|
||||
#
|
||||
# hint :: If not +nil+, specifies query hint fields. Must be either
|
||||
# +nil+ or a hash (preferably an OrderedHash). See Collection#hint.
|
||||
#
|
||||
# timeout :: When +true+ (default), the returned cursor will be subject to
|
||||
# the normal cursor timeout behavior of the mongod process.
|
||||
# When +false+, the returned cursor will never timeout. Care should
|
||||
# be taken to ensure that cursors with timeout disabled are properly closed.
|
||||
def initialize(sel={}, return_fields=nil, number_to_skip=0, number_to_return=0, order_by=nil, hint=nil, snapshot=nil, timeout=true, slave_ok=false)
|
||||
@number_to_skip, @number_to_return, @order_by, @hint, @snapshot, @timeout, @slave_ok =
|
||||
number_to_skip, number_to_return, order_by, hint, snapshot, timeout, slave_ok
|
||||
@explain = nil
|
||||
self.selector = sel
|
||||
self.fields = return_fields
|
||||
end
|
||||
|
||||
# Set query selector hash. If sel is Code/string, it will be used as a
|
||||
# $where clause. (See Mongo docs for details.)
|
||||
def selector=(sel)
|
||||
@selector = case sel
|
||||
when nil
|
||||
{}
|
||||
when Code
|
||||
{"$where" => sel}
|
||||
when String
|
||||
{"$where" => Code.new(sel)}
|
||||
when Hash
|
||||
sel
|
||||
end
|
||||
end
|
||||
|
||||
# Set fields to return. If +val+ is +nil+ or empty, all fields will be
|
||||
# returned.
|
||||
def fields=(val)
|
||||
@fields = val
|
||||
@fields = nil if @fields && @fields.empty?
|
||||
end
|
||||
|
||||
def fields
|
||||
case @fields
|
||||
when String
|
||||
{@fields => 1}
|
||||
when Array
|
||||
if @fields.length == 0
|
||||
nil
|
||||
else
|
||||
h = {}
|
||||
@fields.each { |field| h[field] = 1 }
|
||||
h
|
||||
end
|
||||
else # nil, anything else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def contains_special_fields
|
||||
@order_by || @explain || @hint || @snapshot
|
||||
end
|
||||
|
||||
# Returns an integer indicating which query options have been selected.
|
||||
# See http://www.mongodb.org/display/DOCS/Mongo+Wire+Protocol#MongoWireProtocol-Mongo::Constants::OPQUERY
|
||||
def query_opts
|
||||
timeout = @timeout ? 0 : Mongo::Constants::OP_QUERY_NO_CURSOR_TIMEOUT
|
||||
slave_ok = @slave_ok ? Mongo::Constants::OP_QUERY_SLAVE_OK : 0
|
||||
slave_ok + timeout
|
||||
end
|
||||
|
||||
def to_s
|
||||
"find(#{@selector.inspect})" + (@order_by ? ".sort(#{@order_by.inspect})" : "")
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,28 @@
|
|||
# --
|
||||
# Copyright (C) 2008-2009 10gen Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# ++
|
||||
|
||||
# A hash in which the order of keys are preserved.
|
||||
#
|
||||
# Under Ruby 1.9 and greater, this class has no added methods because Ruby's
|
||||
# Hash already keeps its keys ordered by order of insertion.
|
||||
class Object
|
||||
|
||||
def returning(value)
|
||||
yield value
|
||||
value
|
||||
end
|
||||
|
||||
end
|
|
@ -27,7 +27,6 @@ PACKAGE_FILES = ['README.rdoc', 'Rakefile', 'mongo-ruby-driver.gemspec',
|
|||
'lib/mongo/gridfs/grid_store.rb',
|
||||
'lib/mongo/gridfs.rb',
|
||||
'lib/mongo/errors.rb',
|
||||
'lib/mongo/query.rb',
|
||||
'lib/mongo/types/binary.rb',
|
||||
'lib/mongo/types/code.rb',
|
||||
'lib/mongo/types/dbref.rb',
|
||||
|
@ -37,6 +36,7 @@ PACKAGE_FILES = ['README.rdoc', 'Rakefile', 'mongo-ruby-driver.gemspec',
|
|||
'lib/mongo/util/byte_buffer.rb',
|
||||
'lib/mongo/util/conversions.rb',
|
||||
'lib/mongo/util/ordered_hash.rb',
|
||||
'lib/mongo/util/support.rb',
|
||||
'lib/mongo/util/xml_to_ruby.rb',
|
||||
'lib/mongo.rb']
|
||||
TEST_FILES = ['test/mongo-qa/_common.rb',
|
||||
|
|
|
@ -1,54 +0,0 @@
|
|||
# --
|
||||
# Copyright (C) 2008-2009 10gen Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# ++
|
||||
|
||||
$LOAD_PATH[0,0] = File.join(File.dirname(__FILE__), '..', 'lib')
|
||||
require 'mongo'
|
||||
require 'test/unit'
|
||||
|
||||
class TestQuery < Test::Unit::TestCase
|
||||
|
||||
include Mongo
|
||||
|
||||
def test_timeout_opcodes
|
||||
@timeout = true
|
||||
@query = Query.new({}, nil, 0, 0, nil, nil, nil, @timeout)
|
||||
assert_equal 0, @query.query_opts
|
||||
|
||||
|
||||
@timeout = false
|
||||
@query = Query.new({}, nil, 0, 0, nil, nil, nil, @timeout)
|
||||
assert_equal 16, @query.query_opts
|
||||
end
|
||||
|
||||
def test_slave_ok_opcodes
|
||||
@slave_ok = true
|
||||
@query = Query.new({}, nil, 0, 0, nil, nil, nil, true, @slave_ok)
|
||||
assert_equal 4, @query.query_opts
|
||||
|
||||
|
||||
@slave_ok = false
|
||||
@query = Query.new({}, nil, 0, 0, nil, nil, nil, true, @slave_ok)
|
||||
assert_equal 0, @query.query_opts
|
||||
end
|
||||
|
||||
def test_combined_opcodes
|
||||
@timeout = false
|
||||
@slave_ok = true
|
||||
@query = Query.new({}, nil, 0, 0, nil, nil, nil, @timeout, @slave_ok)
|
||||
assert_equal 20, @query.query_opts
|
||||
end
|
||||
|
||||
end
|
|
@ -24,19 +24,14 @@ class SlaveConnectionTest < Test::Unit::TestCase
|
|||
|
||||
def test_slave_ok_sent_to_queries
|
||||
@db = Connection.new(@@host, @@port, :slave_ok => true).db('ruby-mongo-demo')
|
||||
@coll = @db['test-collection']
|
||||
@cursor = @coll.find({})
|
||||
assert_equal true, @cursor.query.instance_variable_get(:@slave_ok)
|
||||
assert_equal true, @db.slave_ok?
|
||||
end
|
||||
else
|
||||
puts "Not connected to slave; skipping slave connection tests."
|
||||
|
||||
def test_slave_ok_false_on_queries
|
||||
@db = Connection.new(@@host, @@port).db('ruby-mongo-demo')
|
||||
@coll = @db['test-collection']
|
||||
@cursor = @coll.find({})
|
||||
assert_nil @cursor.query.instance_variable_get(:@slave_ok)
|
||||
assert !@db.slave_ok?
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
require 'test/test_helper'
|
||||
|
||||
class TestCursor < Test::Unit::TestCase
|
||||
|
||||
context "Cursor options" do
|
||||
setup do
|
||||
@db = stub(:name => "testing", :slave_ok? => false)
|
||||
@collection = stub(:db => @db, :name => "items")
|
||||
@cursor = Cursor.new(@collection)
|
||||
end
|
||||
|
||||
should "set admin to false" do
|
||||
assert_equal false, @cursor.admin
|
||||
|
||||
@cursor = Cursor.new(@collection, :admin => true)
|
||||
assert_equal true, @cursor.admin
|
||||
end
|
||||
|
||||
should "set selector" do
|
||||
assert @cursor.selector == {}
|
||||
|
||||
@cursor = Cursor.new(@collection, :selector => {:name => "Jones"})
|
||||
assert @cursor.selector == {:name => "Jones"}
|
||||
end
|
||||
|
||||
should "set fields" do
|
||||
assert_nil @cursor.fields
|
||||
|
||||
@cursor = Cursor.new(@collection, :fields => [:name, :date])
|
||||
assert @cursor.fields == {:name => 1, :date => 1}
|
||||
end
|
||||
|
||||
should "set limit" do
|
||||
assert_equal 0, @cursor.limit
|
||||
|
||||
@cursor = Cursor.new(@collection, :limit => 10)
|
||||
assert_equal 10, @cursor.limit
|
||||
end
|
||||
|
||||
|
||||
should "set skip" do
|
||||
assert_equal 0, @cursor.skip
|
||||
|
||||
@cursor = Cursor.new(@collection, :skip => 5)
|
||||
assert_equal 5, @cursor.skip
|
||||
end
|
||||
|
||||
should "set sort order" do
|
||||
assert_nil @cursor.order
|
||||
|
||||
@cursor = Cursor.new(@collection, :order => "last_name")
|
||||
assert_equal "last_name", @cursor.order
|
||||
end
|
||||
|
||||
should "set hint" do
|
||||
assert_nil @cursor.hint
|
||||
|
||||
@cursor = Cursor.new(@collection, :hint => "name")
|
||||
assert_equal "name", @cursor.hint
|
||||
end
|
||||
|
||||
should "cache full collection name" do
|
||||
assert_equal "testing.items", @cursor.full_collection_name
|
||||
end
|
||||
end
|
||||
|
||||
context "Query options" do
|
||||
should "test timeout true and slave_ok false" do
|
||||
@db = stub(:slave_ok? => false, :name => "testing")
|
||||
@collection = stub(:db => @db, :name => "items")
|
||||
@cursor = Cursor.new(@collection, :timeout => true)
|
||||
assert_equal 0, @cursor.query_opts
|
||||
end
|
||||
|
||||
should "test timeout false and slave_ok false" do
|
||||
@db = stub(:slave_ok? => false, :name => "testing")
|
||||
@collection = stub(:db => @db, :name => "items")
|
||||
@cursor = Cursor.new(@collection, :timeout => false)
|
||||
assert_equal 16, @cursor.query_opts
|
||||
end
|
||||
|
||||
should "set timeout true and slave_ok true" do
|
||||
@db = stub(:slave_ok? => true, :name => "testing")
|
||||
@collection = stub(:db => @db, :name => "items")
|
||||
@cursor = Cursor.new(@collection, :timeout => true)
|
||||
assert_equal 4, @cursor.query_opts
|
||||
end
|
||||
|
||||
should "set timeout false and slave_ok true" do
|
||||
@db = stub(:slave_ok? => true, :name => "testing")
|
||||
@collection = stub(:db => @db, :name => "items")
|
||||
@cursor = Cursor.new(@collection, :timeout => false)
|
||||
assert_equal 20, @cursor.query_opts
|
||||
end
|
||||
end
|
||||
|
||||
context "Query fields" do
|
||||
setup do
|
||||
@db = stub(:slave_ok? => true, :name => "testing")
|
||||
@collection = stub(:db => @db, :name => "items")
|
||||
end
|
||||
|
||||
should "when an array should return a hash with each key" do
|
||||
@cursor = Cursor.new(@collection, :fields => [:name, :age])
|
||||
result = @cursor.fields
|
||||
assert_equal result.keys, [:age, :name]
|
||||
assert result.values.all? {|v| v == 1}
|
||||
end
|
||||
|
||||
should "when a string, return a hash with just the key" do
|
||||
@cursor = Cursor.new(@collection, :fields => "name")
|
||||
result = @cursor.fields
|
||||
assert_equal result.keys.sort, ["name"]
|
||||
assert result.values.all? {|v| v == 1}
|
||||
end
|
||||
|
||||
should "return nil when neither hash nor string nor symbol" do
|
||||
@cursor = Cursor.new(@collection, :fields => 1234567)
|
||||
assert_nil @cursor.fields
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue