Merge branch 'master' of github.com:mongodb/mongo-ruby-driver

This commit is contained in:
Mike Dirolf 2009-12-17 09:47:29 -05:00
commit f9fb823c53
29 changed files with 193 additions and 200 deletions

View File

@ -47,11 +47,13 @@ Les Hill, leshill on github
* OrderedHash#each returns self * OrderedHash#each returns self
Sean Cribbs, seancribbs on github Sean Cribbs, seancribbs on github
* Modify standard_benchmark to allow profiling * Modified standard_benchmark to allow profiling
* c ext for faster ObjectID creation
Sunny Hirai Sunny Hirai
* Suggested hashcode fix for Mongo::ObjectID * Suggested hashcode fix for Mongo::ObjectID
* Noted index ordering bug. * Noted index ordering bug.
* GridFS performance boost
Christos Trochalakis Christos Trochalakis
* Added map/reduce helper * Added map/reduce helper

View File

@ -8,7 +8,7 @@
0.18 2009-11-25 0.18 2009-11-25
* Connections now support connection pooling. See http://api.mongodb.org/ruby/0.18/classes/Mongo/Connection.html#M000158 * Connections now support connection pooling. See http://api.mongodb.org/ruby/0.18/classes/Mongo/Connection.html#M000158
* Deprecated :auto_reconnect option on connection; if the driver fails to * Deprecated :auto_reconnect option on connection; if the driver fails to
connect, it will automatically try to reconnect on the subsequent operation. connect, it will automatically try to reconnect on the subsequent operation.
See http://www.mongodb.org/display/DOCS/Replica+Pairs+in+Ruby See http://www.mongodb.org/display/DOCS/Replica+Pairs+in+Ruby
* Added Collection#map_reduce helper (Christos Trochalakis) * Added Collection#map_reduce helper (Christos Trochalakis)
* Deprecated DB#db_command in favor of DB#command. * Deprecated DB#db_command in favor of DB#command.

View File

@ -13,7 +13,7 @@ Here is a quick code sample. See the MongoDB Ruby Tutorial
@coll = db.collection('test') @coll = db.collection('test')
@coll.remove @coll.remove
3.times do |i| 3.times do |i|
@coll.insert({'a' => i+1}) @coll.insert({'a' => i+1})
end end
puts "There are #{@coll.count()} records. Here they are:" puts "There are #{@coll.count()} records. Here they are:"
@ -254,7 +254,7 @@ Random cursor fun facts:
= Testing = Testing
If you have the source code, you can run the tests. There's a separate rake task for testing with If you have the source code, you can run the tests. There's a separate rake task for testing with
the mongo_ext c extension enabled. the mongo_ext c extension enabled.
$ rake test:c $ rake test:c

View File

@ -1,26 +0,0 @@
$LOAD_PATH[0,0] = File.join(File.dirname(__FILE__), '..', 'lib')
require 'mongo'
db = Mongo::Connection.new({:left => ["localhost", 27017], :right => ["localhost", 27018]}, nil, :auto_reconnect => true).db("ruby_test")
db['test'].clear
10.times do |i|
db['test'].save("x" => i)
end
while true do
begin
exit() if not db['test'].count() == 10
x = 0
db['test'].find().each do |doc|
x += doc['x']
end
exit() if not x == 45
print "."
STDOUT.flush
sleep 1
rescue
sleep 1
end
end

View File

@ -2,7 +2,7 @@
require 'rubygems' require 'rubygems'
require 'mongo' require 'mongo'
require 'mongo/gridfs' require 'mongo/gridfs'
require 'benchmark' #require 'ruby-prof'
include Mongo include Mongo
include GridFS include GridFS
@ -15,10 +15,15 @@ length = sample_data.length
mb = length / 1048576.0 mb = length / 1048576.0
t1 = Time.now t1 = Time.now
#RubyProf.start
GridStore.open(db, 'mongodb.pdf', 'w') do |f| GridStore.open(db, 'mongodb.pdf', 'w') do |f|
f.write(sample_data) f.write(sample_data)
end end
#result = RubyProf.stop
puts "Write: #{mb / (Time.now - t1)} mb/s" puts "Write: #{mb / (Time.now - t1)} mb/s"
#printer = RubyProf::FlatPrinter.new(result)
#printer.print(STDOUT, 0)
t1 = Time.now t1 = Time.now
GridStore.open(db, 'mongodb.pdf', 'r') do |f| GridStore.open(db, 'mongodb.pdf', 'r') do |f|

View File

@ -33,14 +33,14 @@ array = cursor.to_a
cursor.each { |row| pp row } cursor.each { |row| pp row }
# You can get the next object # You can get the next object
first_object = coll.find().next_object first_object = coll.find().next_document
# next_object returns nil if there are no more objects that match # next_document returns nil if there are no more objects that match
cursor = coll.find() cursor = coll.find()
obj = cursor.next_object obj = cursor.next_document
while obj while obj
pp obj pp obj
obj = cursor.next_object obj = cursor.next_document
end end
# Destroy the collection # Destroy the collection

View File

@ -30,6 +30,6 @@ coll.insert('array' => [1, 2, 3],
'null' => nil, 'null' => nil,
'symbol' => :zildjian) 'symbol' => :zildjian)
pp coll.find().next_object pp coll.find().next_document
coll.clear coll.clear

View File

@ -459,6 +459,7 @@ static void write_doc(buffer_t buffer, VALUE hash, VALUE check_keys) {
// make sure that length doesn't exceed 4MB // make sure that length doesn't exceed 4MB
if (length > 4 * 1024 * 1024) { if (length > 4 * 1024 * 1024) {
buffer_free(buffer);
rb_raise(InvalidDocument, "Document too large: BSON documents are limited to 4MB."); rb_raise(InvalidDocument, "Document too large: BSON documents are limited to 4MB.");
return; return;
} }

View File

@ -21,7 +21,7 @@ begin
warn " You can install the extension as follows:\n gem install mongo_ext\n" warn " You can install the extension as follows:\n gem install mongo_ext\n"
warn " If you continue to receive this message after installing, make sure that the" warn " If you continue to receive this message after installing, make sure that the"
warn " mongo_ext gem is in your load path and that the mongo_ext and mongo gems are of the same version.\n" warn " mongo_ext gem is in your load path and that the mongo_ext and mongo gems are of the same version.\n"
end end
require 'mongo/types/binary' require 'mongo/types/binary'
require 'mongo/types/code' require 'mongo/types/code'

View File

@ -59,8 +59,7 @@ module Mongo
raise "Error with profile command: #{doc.inspect}" unless @db.ok?(doc) raise "Error with profile command: #{doc.inspect}" unless @db.ok?(doc)
end end
# Return an array contining current profiling information from the # Returns an array containing current profiling information.
# database.
def profiling_info def profiling_info
Cursor.new(Collection.new(@db, DB::SYSTEM_PROFILE_COLLECTION), :selector => {}).to_a Cursor.new(Collection.new(@db, DB::SYSTEM_PROFILE_COLLECTION), :selector => {}).to_a
end end

View File

@ -158,7 +158,7 @@ module Mongo
else else
raise TypeError, "spec_or_object_id must be an instance of ObjectID or Hash, or nil" raise TypeError, "spec_or_object_id must be an instance of ObjectID or Hash, or nil"
end end
find(spec, options.merge(:limit => -1)).next_object find(spec, options.merge(:limit => -1)).next_document
end end
# Save a document in this collection. # Save a document in this collection.
@ -497,7 +497,7 @@ EOS
# 'create' will be the collection name. For the other possible keys # 'create' will be the collection name. For the other possible keys
# and values, see DB#create_collection. # and values, see DB#create_collection.
def options def options
@db.collections_info(@name).next_object()['options'] @db.collections_info(@name).next_document['options']
end end
# Get the number of documents in this collection. # Get the number of documents in this collection.
@ -526,7 +526,7 @@ EOS
private private
# Sends an Mongo::Constants::OP_INSERT message to the database. # Sends a Mongo::Constants::OP_INSERT message to the database.
# Takes an array of +documents+, an optional +collection_name+, and a # Takes an array of +documents+, an optional +collection_name+, and a
# +check_keys+ setting. # +check_keys+ setting.
def insert_documents(documents, collection_name=@name, check_keys=true, safe=false) def insert_documents(documents, collection_name=@name, check_keys=true, safe=false)

View File

@ -33,10 +33,10 @@ module Mongo
attr_reader :logger, :size, :host, :port, :nodes, :sockets, :checked_out, :reserved_connections attr_reader :logger, :size, :host, :port, :nodes, :sockets, :checked_out, :reserved_connections
def slave_ok? def slave_ok?
@slave_ok @slave_ok
end end
# Counter for generating unique request ids. # Counter for generating unique request ids.
@@current_request_id = 0 @@current_request_id = 0
@ -45,7 +45,7 @@ module Mongo
# #
# == Connecting # == Connecting
# If connecting to just one server, you may specify whether connection to slave is permitted. # If connecting to just one server, you may specify whether connection to slave is permitted.
# #
# In all cases, the default host is "localhost" and the default port, is 27017. # In all cases, the default host is "localhost" and the default port, is 27017.
# #
# When specifying a pair, pair_or_host, is a hash with two keys: :left and :right. Each key maps to either # When specifying a pair, pair_or_host, is a hash with two keys: :left and :right. Each key maps to either
@ -69,13 +69,13 @@ module Mongo
# :timeout :: When all of the connections to the pool are checked out, # :timeout :: When all of the connections to the pool are checked out,
# this is the number of seconds to wait for a new connection # this is the number of seconds to wait for a new connection
# to be released before throwing an exception. # to be released before throwing an exception.
# #
# #
# === Examples: # === Examples:
# #
# # localhost, 27017 # # localhost, 27017
# Connection.new # Connection.new
# #
# # localhost, 27017 # # localhost, 27017
# Connection.new("localhost") # Connection.new("localhost")
# #
@ -85,9 +85,9 @@ module Mongo
# # localhost, 3000, where this node may be a slave # # localhost, 3000, where this node may be a slave
# Connection.new("localhost", 3000, :slave_ok => true) # Connection.new("localhost", 3000, :slave_ok => true)
# #
# # A pair of servers. The driver will always talk to master. # # A pair of servers. The driver will always talk to master.
# # On connection errors, Mongo::ConnectionFailure will be raised. # # On connection errors, Mongo::ConnectionFailure will be raised.
# # See http://www.mongodb.org/display/DOCS/Replica+Pairs+in+Ruby # # See http://www.mongodb.org/display/DOCS/Replica+Pairs+in+Ruby
# Connection.new({:left => ["db1.example.com", 27017], # Connection.new({:left => ["db1.example.com", 27017],
# :right => ["db2.example.com", 27017]}) # :right => ["db2.example.com", 27017]})
# #
@ -100,7 +100,7 @@ module Mongo
# Host and port of current master. # Host and port of current master.
@host = @port = nil @host = @port = nil
# Lock for request ids. # Lock for request ids.
@id_lock = Mutex.new @id_lock = Mutex.new
@ -123,7 +123,7 @@ module Mongo
if options[:auto_reconnect] if options[:auto_reconnect]
warn(":auto_reconnect is deprecated. see http://www.mongodb.org/display/DOCS/Replica+Pairs+in+Ruby") warn(":auto_reconnect is deprecated. see http://www.mongodb.org/display/DOCS/Replica+Pairs+in+Ruby")
end end
# Slave ok can be true only if one node is specified # Slave ok can be true only if one node is specified
@slave_ok = options[:slave_ok] && @nodes.length == 1 @slave_ok = options[:slave_ok] && @nodes.length == 1
@logger = options[:logger] || nil @logger = options[:logger] || nil
@ -177,7 +177,7 @@ module Mongo
# Increments and returns the next available request id. # Increments and returns the next available request id.
def get_request_id def get_request_id
request_id = '' request_id = ''
@id_lock.synchronize do @id_lock.synchronize do
request_id = @@current_request_id += 1 request_id = @@current_request_id += 1
end end
request_id request_id
@ -196,7 +196,7 @@ module Mongo
## Connections and pooling ## ## Connections and pooling ##
# Sends a message to MongoDB. # Sends a message to MongoDB.
# #
# Takes a MongoDB opcode, +operation+, a message of class ByteBuffer, # Takes a MongoDB opcode, +operation+, a message of class ByteBuffer,
@ -234,7 +234,7 @@ module Mongo
# Sends a message to the database and waits for the response. # Sends a message to the database and waits for the response.
# #
# Takes a MongoDB opcode, +operation+, a message of class ByteBuffer, # Takes a MongoDB opcode, +operation+, a message of class ByteBuffer,
# +message+, and an optional formatted +log_message+. This method # +message+, and an optional formatted +log_message+. This method
# also takes an options socket for internal use with #connect_to_master. # also takes an options socket for internal use with #connect_to_master.
def receive_message(operation, message, log_message=nil, socket=nil) def receive_message(operation, message, log_message=nil, socket=nil)
packed_message = add_message_headers(operation, message).to_s packed_message = add_message_headers(operation, message).to_s
@ -275,7 +275,7 @@ module Mongo
socket.close if socket socket.close if socket
false false
end end
end end
raise ConnectionFailure, "failed to connect to any given host:port" unless socket raise ConnectionFailure, "failed to connect to any given host:port" unless socket
end end
@ -291,7 +291,7 @@ module Mongo
sock.close sock.close
end end
@host = @port = nil @host = @port = nil
@sockets.clear @sockets.clear
@checked_out.clear @checked_out.clear
@reserved_connections.clear @reserved_connections.clear
end end
@ -312,7 +312,7 @@ module Mongo
# Return a socket to the pool. # Return a socket to the pool.
def checkin(socket) def checkin(socket)
@connection_mutex.synchronize do @connection_mutex.synchronize do
@reserved_connections.delete Thread.current.object_id @reserved_connections.delete Thread.current.object_id
@checked_out.delete(socket) @checked_out.delete(socket)
@queue.signal @queue.signal
@ -328,7 +328,7 @@ module Mongo
Thread.list.each do |thread| Thread.list.each do |thread|
keys.delete(thread.object_id) if thread.alive? keys.delete(thread.object_id) if thread.alive?
end end
keys.each do |key| keys.each do |key|
next unless @reserved_connections.has_key?(key) next unless @reserved_connections.has_key?(key)
checkin(@reserved_connections[key]) checkin(@reserved_connections[key])
@ -366,10 +366,10 @@ module Mongo
# pool size has not been exceeded. Otherwise, wait for the next # pool size has not been exceeded. Otherwise, wait for the next
# available socket. # available socket.
def obtain_socket def obtain_socket
@connection_mutex.synchronize do @connection_mutex.synchronize do
connect_to_master if !connected? connect_to_master if !connected?
loop do loop do
socket = if @checked_out.size < @sockets.size socket = if @checked_out.size < @sockets.size
checkout_existing_socket checkout_existing_socket
elsif @sockets.size < @size elsif @sockets.size < @size
@ -401,9 +401,9 @@ module Mongo
if RUBY_VERSION >= '1.9' if RUBY_VERSION >= '1.9'
# Ruby 1.9's Condition Variables don't support timeouts yet; # Ruby 1.9's Condition Variables don't support timeouts yet;
# until they do, we'll make do with this hack. # until they do, we'll make do with this hack.
def wait def wait
Timeout.timeout(@timeout) do Timeout.timeout(@timeout) do
@queue.wait @queue.wait
end end
end end
@ -424,7 +424,7 @@ module Mongo
header.put_array(receive_message_on_socket(16, sock).unpack("C*")) header.put_array(receive_message_on_socket(16, sock).unpack("C*"))
unless header.size == STANDARD_HEADER_SIZE unless header.size == STANDARD_HEADER_SIZE
raise "Short read for DB response header: " + raise "Short read for DB response header: " +
"expected #{STANDARD_HEADER_SIZE} bytes, saw #{header.size}" "expected #{STANDARD_HEADER_SIZE} bytes, saw #{header.size}"
end end
header.rewind header.rewind
size = header.get_int size = header.get_int
@ -473,7 +473,7 @@ module Mongo
message.put_array(BSON.serialize({:getlasterror => 1}, false).unpack("C*")) message.put_array(BSON.serialize({:getlasterror => 1}, false).unpack("C*"))
add_message_headers(Mongo::Constants::OP_QUERY, message) add_message_headers(Mongo::Constants::OP_QUERY, message)
end end
# Prepares a message for transmission to MongoDB by # Prepares a message for transmission to MongoDB by
# constructing a valid message header. # constructing a valid message header.
def add_message_headers(operation, message) def add_message_headers(operation, message)
@ -494,7 +494,7 @@ module Mongo
end end
# Low-level method for sending a message on a socket. # Low-level method for sending a message on a socket.
# Requires a packed message and an available socket, # Requires a packed message and an available socket,
def send_message_on_socket(packed_message, socket) def send_message_on_socket(packed_message, socket)
begin begin
socket.send(packed_message, 0) socket.send(packed_message, 0)
@ -537,7 +537,7 @@ module Mongo
[['localhost', DEFAULT_PORT]] [['localhost', DEFAULT_PORT]]
end end
end end
# Turns an array containing a host name string and a # Turns an array containing a host name string and a
# port number integer into a [host, port] pair array. # port number integer into a [host, port] pair array.
def pair_val_to_connection(a) def pair_val_to_connection(a)

View File

@ -1,8 +1,8 @@
module Mongo module Mongo
module Constants module Constants
OP_REPLY = 1 OP_REPLY = 1
OP_MSG = 1000 OP_MSG = 1000
OP_UPDATE = 2001 OP_UPDATE = 2001
OP_INSERT = 2002 OP_INSERT = 2002
OP_QUERY = 2004 OP_QUERY = 2004
OP_GET_MORE = 2005 OP_GET_MORE = 2005

View File

@ -19,7 +19,7 @@ module Mongo
include Mongo::Conversions include Mongo::Conversions
include Enumerable include Enumerable
attr_reader :collection, :selector, :admin, :fields, attr_reader :collection, :selector, :admin, :fields,
:order, :hint, :snapshot, :timeout, :order, :hint, :snapshot, :timeout,
:full_collection_name :full_collection_name
@ -49,19 +49,17 @@ module Mongo
@query_run = false @query_run = false
end end
# Return the next object or nil if there are no more. Raises an error # Return the next document or nil if there are no more.
# if necessary. def next_document
def next_object
refill_via_get_more if num_remaining == 0 refill_via_get_more if num_remaining == 0
o = @cache.shift doc = @cache.shift
if o && o['$err'] if doc && doc['$err']
err = o['$err'] err = doc['$err']
# If the server has stopped being the master (e.g., it's one of a # If the server has stopped being the master (e.g., it's one of a
# pair but it has died or something like that) then we close that # pair but it has died or something like that) then we close that
# connection. If the db has auto connect option and a pair of # connection. The next request will re-open on master server.
# servers, next request will re-open on master server.
if err == "not master" if err == "not master"
raise ConnectionFailure, err raise ConnectionFailure, err
@connection.close @connection.close
@ -70,12 +68,17 @@ module Mongo
raise OperationFailure, err raise OperationFailure, err
end end
o doc
end end
# Get the size of the results set for this query. def next_object
warn "Cursor#next_object is deprecated; please use Cursor#next_document instead."
next_document
end
# Get the size of the result set for this query.
# #
# Returns the number of objects in the results set for this query. Does # Returns the number of objects in the result set for this query. Does
# not take limit and skip into account. Raises OperationFailure on a # not take limit and skip into account. Raises OperationFailure on a
# database error. # database error.
def count def count
@ -88,17 +91,17 @@ module Mongo
raise OperationFailure, "Count failed: #{response['errmsg']}" raise OperationFailure, "Count failed: #{response['errmsg']}"
end end
# Sort this cursor's result # Sort this cursor's results.
# #
# Takes either a single key and a direction, or an array of [key, # Takes either a single key and a direction, or an array of [key,
# direction] pairs. Directions should be specified as Mongo::ASCENDING # direction] pairs. Directions should be specified as Mongo::ASCENDING / Mongo::DESCENDING
# or Mongo::DESCENDING (or :ascending or :descending) (or :asc or :desc). # (or :ascending / :descending, :asc / :desc).
# #
# Raises InvalidOperation if this cursor has already been used. Raises # Raises InvalidOperation if this cursor has already been used. Raises
# InvalidSortValueError if specified order is invalid. # InvalidSortValueError if the specified order is invalid.
# #
# This method overrides any sort order specified in the Collection#find # This method overrides any sort order specified in the Collection#find
# method, and only the last sort applied has an effect # method, and only the last sort applied has an effect.
def sort(key_or_list, direction=nil) def sort(key_or_list, direction=nil)
check_modifiable check_modifiable
@ -130,7 +133,7 @@ module Mongo
# Skips the first +number_to_skip+ results of this cursor. # Skips the first +number_to_skip+ results of this cursor.
# Returns the current number_to_skip if no parameter is given. # Returns the current number_to_skip if no parameter is given.
# #
# Raises InvalidOperation if this cursor has already been used. # Raises InvalidOperation if this cursor has already been used.
# #
# This method overrides any skip specified in the Collection#find method, # This method overrides any skip specified in the Collection#find method,
@ -151,15 +154,15 @@ module Mongo
def each def each
num_returned = 0 num_returned = 0
while more? && (@limit <= 0 || num_returned < @limit) while more? && (@limit <= 0 || num_returned < @limit)
yield next_object() yield next_document
num_returned += 1 num_returned += 1
end end
end end
# Return all of the documents in this cursor as an array of hashes. # Return all of the documents in this cursor as an array of hashes.
# #
# Raises InvalidOperation if this cursor has already been used (including # Raises InvalidOperation if this cursor has already been used or if
# any previous calls to this method). # this methods has already been called on the cursor.
# #
# Use of this method is discouraged - iterating over a cursor is much # Use of this method is discouraged - iterating over a cursor is much
# more efficient in most cases. # more efficient in most cases.
@ -168,22 +171,22 @@ module Mongo
rows = [] rows = []
num_returned = 0 num_returned = 0
while more? && (@limit <= 0 || num_returned < @limit) while more? && (@limit <= 0 || num_returned < @limit)
rows << next_object() rows << next_document
num_returned += 1 num_returned += 1
end end
rows rows
end end
# Returns an explain plan record for this cursor. # Returns an explain plan document for this cursor.
def explain def explain
c = Cursor.new(@collection, query_options_hash.merge(:limit => -@limit.abs, :explain => true)) c = Cursor.new(@collection, query_options_hash.merge(:limit => -@limit.abs, :explain => true))
explanation = c.next_object explanation = c.next_document
c.close c.close
explanation explanation
end end
# Close the cursor. # Closes the cursor.
# #
# Note: if a cursor is read until exhausted (read until Mongo::Constants::OP_QUERY or # Note: if a cursor is read until exhausted (read until Mongo::Constants::OP_QUERY or
# Mongo::Constants::OP_GETMORE returns zero for the cursor id), there is no need to # Mongo::Constants::OP_GETMORE returns zero for the cursor id), there is no need to
@ -211,20 +214,20 @@ module Mongo
# See http://www.mongodb.org/display/DOCS/Mongo+Wire+Protocol#MongoWireProtocol-Mongo::Constants::OPQUERY # See http://www.mongodb.org/display/DOCS/Mongo+Wire+Protocol#MongoWireProtocol-Mongo::Constants::OPQUERY
def query_opts def query_opts
timeout = @timeout ? 0 : Mongo::Constants::OP_QUERY_NO_CURSOR_TIMEOUT timeout = @timeout ? 0 : Mongo::Constants::OP_QUERY_NO_CURSOR_TIMEOUT
slave_ok = @connection.slave_ok? ? Mongo::Constants::OP_QUERY_SLAVE_OK : 0 slave_ok = @connection.slave_ok? ? Mongo::Constants::OP_QUERY_SLAVE_OK : 0
slave_ok + timeout slave_ok + timeout
end end
# Returns the query options set on this Cursor. # Returns the query options for this Cursor.
def query_options_hash def query_options_hash
{ :selector => @selector, { :selector => @selector,
:fields => @fields, :fields => @fields,
:admin => @admin, :admin => @admin,
:skip => @skip_num, :skip => @skip_num,
:limit => @limit_num, :limit => @limit_num,
:order => @order, :order => @order,
:hint => @hint, :hint => @hint,
:snapshot => @snapshot, :snapshot => @snapshot,
:timeout => @timeout } :timeout => @timeout }
end end
@ -245,7 +248,7 @@ module Mongo
end end
end end
# Set query selector hash. If the selector is a Code or String object, # Set the query selector hash. If the selector is a Code or String object,
# the selector will be used in a $where clause. # the selector will be used in a $where clause.
# See http://www.mongodb.org/display/DOCS/Server-side+Code+Execution # See http://www.mongodb.org/display/DOCS/Server-side+Code+Execution
def convert_selector_for_query(selector) def convert_selector_for_query(selector)
@ -266,20 +269,21 @@ module Mongo
@order || @explain || @hint || @snapshot @order || @explain || @hint || @snapshot
end end
# Return a number of documents remaining for this cursor.
def num_remaining def num_remaining
refill_via_get_more if @cache.length == 0 refill_via_get_more if @cache.length == 0
@cache.length @cache.length
end end
# Internal method, not for general use. Return +true+ if there are # Internal method, not for general use. Return +true+ if there are
# more records to retrieve. This methods does not check @limit; # more records to retrieve. This method does not check @limit;
# #each is responsible for doing that. # Cursor#each is responsible for doing that.
def more? def more?
num_remaining > 0 num_remaining > 0
end end
def refill_via_get_more def refill_via_get_more
return if send_query_if_needed || @cursor_id.zero? return if send_initial_query || @cursor_id.zero?
message = ByteBuffer.new message = ByteBuffer.new
# Reserved. # Reserved.
message.put_int(0) message.put_int(0)
@ -290,7 +294,7 @@ module Mongo
# Number of results to return; db decides for now. # Number of results to return; db decides for now.
message.put_int(0) message.put_int(0)
# Cursor id. # Cursor id.
message.put_long(@cursor_id) message.put_long(@cursor_id)
results, @n_received, @cursor_id = @connection.receive_message(Mongo::Constants::OP_GET_MORE, message, "cursor.get_more()", @socket) results, @n_received, @cursor_id = @connection.receive_message(Mongo::Constants::OP_GET_MORE, message, "cursor.get_more()", @socket)
@ -299,13 +303,13 @@ module Mongo
end end
# Run query the first time we request an object from the wire # Run query the first time we request an object from the wire
def send_query_if_needed def send_initial_query
if @query_run if @query_run
false false
else else
message = construct_query_message message = construct_query_message
results, @n_received, @cursor_id = @connection.receive_message(Mongo::Constants::OP_QUERY, message, results, @n_received, @cursor_id = @connection.receive_message(Mongo::Constants::OP_QUERY, message,
(query_log_message if @connection.logger), @socket) (query_log_message if @connection.logger), @socket)
@cache += results @cache += results
@query_run = true @query_run = true
close_cursor_if_query_complete close_cursor_if_query_complete
@ -331,7 +335,7 @@ module Mongo
def query_log_message def query_log_message
"#{@admin ? 'admin' : @db.name}.#{@collection.name}.find(#{@selector.inspect}, #{@fields ? @fields.inspect : '{}'})" + "#{@admin ? 'admin' : @db.name}.#{@collection.name}.find(#{@selector.inspect}, #{@fields ? @fields.inspect : '{}'})" +
"#{@skip != 0 ? ('.skip(' + @skip.to_s + ')') : ''}#{@limit != 0 ? ('.limit(' + @limit.to_s + ')') : ''}" "#{@skip != 0 ? ('.skip(' + @skip.to_s + ')') : ''}#{@limit != 0 ? ('.limit(' + @limit.to_s + ')') : ''}"
end end
def selector_with_special_query_fields def selector_with_special_query_fields
@ -349,7 +353,7 @@ module Mongo
when String, Symbol then string_as_sort_parameters(@order) when String, Symbol then string_as_sort_parameters(@order)
when Array then array_as_sort_parameters(@order) when Array then array_as_sort_parameters(@order)
else else
raise InvalidSortValueError, "Illegal sort clause, '#{@order.class.name}'; must be of the form " + raise InvalidSortValueError, "Illegal sort clause, '#{@order.class.name}'; must be of the form " +
"[['field1', '(ascending|descending)'], ['field2', '(ascending|descending)']]" "[['field1', '(ascending|descending)'], ['field2', '(ascending|descending)']]"
end end
end end

View File

@ -48,7 +48,7 @@ module Mongo
# The Mongo::Connection instance connecting to the MongoDB server. # The Mongo::Connection instance connecting to the MongoDB server.
attr_reader :connection attr_reader :connection
# An array of [host, port] pairs. # An array of [host, port] pairs.
attr_reader :nodes attr_reader :nodes
@ -316,7 +316,7 @@ module Mongo
def create_index(collection_name, field_or_spec, unique=false) def create_index(collection_name, field_or_spec, unique=false)
self.collection(collection_name).create_index(field_or_spec, unique) self.collection(collection_name).create_index(field_or_spec, unique)
end end
# Return +true+ if +doc+ contains an 'ok' field with the value 1. # Return +true+ if +doc+ contains an 'ok' field with the value 1.
def ok?(doc) def ok?(doc)
ok = doc['ok'] ok = doc['ok']
@ -334,9 +334,9 @@ module Mongo
end end
cursor = Cursor.new(Collection.new(self, SYSTEM_COMMAND_COLLECTION), :admin => use_admin_db, :limit => -1, :selector => selector, :socket => sock) cursor = Cursor.new(Collection.new(self, SYSTEM_COMMAND_COLLECTION), :admin => use_admin_db, :limit => -1, :selector => selector, :socket => sock)
cursor.next_object cursor.next_document
end end
# Sends a command to the database. # Sends a command to the database.
# #
# :selector (required) :: An OrderedHash, or a standard Hash with just one # :selector (required) :: An OrderedHash, or a standard Hash with just one
@ -352,12 +352,12 @@ module Mongo
# any selector containing more than one key must be an OrderedHash. # any selector containing more than one key must be an OrderedHash.
def command(selector, admin=false, check_response=false, sock=nil) def command(selector, admin=false, check_response=false, sock=nil)
raise MongoArgumentError, "command must be given a selector" unless selector.is_a?(Hash) && !selector.empty? raise MongoArgumentError, "command must be given a selector" unless selector.is_a?(Hash) && !selector.empty?
if selector.class.eql?(Hash) && selector.keys.length > 1 if selector.class.eql?(Hash) && selector.keys.length > 1
raise MongoArgumentError, "DB#command requires an OrderedHash when hash contains multiple keys" raise MongoArgumentError, "DB#command requires an OrderedHash when hash contains multiple keys"
end end
result = Cursor.new(system_command_collection, :admin => admin, result = Cursor.new(system_command_collection, :admin => admin,
:limit => -1, :selector => selector, :socket => sock).next_object :limit => -1, :selector => selector, :socket => sock).next_document
if check_response && !ok?(result) if check_response && !ok?(result)
raise OperationFailure, "Database command '#{selector.keys.first}' failed." raise OperationFailure, "Database command '#{selector.keys.first}' failed."

View File

@ -73,7 +73,7 @@ module GridFS
class << self class << self
def exist?(db, name, root_collection=DEFAULT_ROOT_COLLECTION) def exist?(db, name, root_collection=DEFAULT_ROOT_COLLECTION)
db.collection("#{root_collection}.files").find({'filename' => name}).next_object != nil db.collection("#{root_collection}.files").find({'filename' => name}).next_document != nil
end end
def open(db, name, mode, options={}) def open(db, name, mode, options={})
@ -94,12 +94,12 @@ module GridFS
} }
end end
# List the contains of all GridFS files stored in the given db and # List the contents of all GridFS files stored in the given db and
# root collection. # root collection.
# #
# :db :: the database to use # :db :: the database to use
# #
# :root_collection :: the root collection to use # :root_collection :: the root collection to use. If not specified, will use default root collection.
def list(db, root_collection=DEFAULT_ROOT_COLLECTION) def list(db, root_collection=DEFAULT_ROOT_COLLECTION)
db.collection("#{root_collection}.files").find().map { |f| db.collection("#{root_collection}.files").find().map { |f|
f['filename'] f['filename']
@ -148,7 +148,7 @@ module GridFS
@db, @filename, @mode = db, name, mode @db, @filename, @mode = db, name, mode
@root = options[:root] || DEFAULT_ROOT_COLLECTION @root = options[:root] || DEFAULT_ROOT_COLLECTION
doc = collection.find({'filename' => @filename}).next_object doc = collection.find({'filename' => @filename}).next_document
if doc if doc
@files_id = doc['_id'] @files_id = doc['_id']
@content_type = doc['contentType'] @content_type = doc['contentType']
@ -495,7 +495,7 @@ module GridFS
end end
def nth_chunk(n) def nth_chunk(n)
mongo_chunk = chunk_collection.find({'files_id' => @files_id, 'n' => n}).next_object mongo_chunk = chunk_collection.find({'files_id' => @files_id, 'n' => n}).next_document
Chunk.new(self, mongo_chunk || {}) Chunk.new(self, mongo_chunk || {})
end end

View File

@ -18,6 +18,7 @@ module Mongo
# JavaScript code to be evaluated by MongoDB # JavaScript code to be evaluated by MongoDB
class Code < String class Code < String
# Hash mapping identifiers to their values # Hash mapping identifiers to their values
attr_accessor :scope attr_accessor :scope

View File

@ -25,7 +25,7 @@ module Mongo
# Implements comparable. # Implements comparable.
def <=>(new) def <=>(new)
local, new = self.to_a, to_array(new) local, new = self.to_a, to_array(new)
for n in 0...local.size do for n in 0...local.size do
break if elements_include_mods?(local[n], new[n]) break if elements_include_mods?(local[n], new[n])
if local[n] < new[n].to_i if local[n] < new[n].to_i
result = -1 result = -1
@ -52,10 +52,10 @@ module Mongo
# Returns true if any elements include mod symbols (-, +) # Returns true if any elements include mod symbols (-, +)
def elements_include_mods?(*elements) def elements_include_mods?(*elements)
elements.any? { |n| n =~ /[\-\+]/ } elements.any? { |n| n =~ /[\-\+]/ }
end end
# Converts argument to an array of integers, # Converts argument to an array of integers,
# appending any mods as the final element. # appending any mods as the final element.
def to_array(version) def to_array(version)
array = version.split(".").map {|n| (n =~ /^\d+$/) ? n.to_i : n } array = version.split(".").map {|n| (n =~ /^\d+$/) ? n.to_i : n }

View File

@ -1,5 +1,5 @@
require 'lib/mongo' require 'lib/mongo'
VERSION_HEADER = File.open(File.join(File.dirname(__FILE__), 'ext', 'cbson', 'version.h'), "r") VERSION_HEADER = File.open(File.join(File.dirname(__FILE__), 'ext', 'cbson', 'version.h'), "r")
VERSION = VERSION_HEADER.read.scan(/VERSION\s+"(\d+\.\d+(\.\d+)?)\"/)[0][0] VERSION = VERSION_HEADER.read.scan(/VERSION\s+"(\d+\.\d+(\.\d+)?)\"/)[0][0]
Gem::Specification.new do |s| Gem::Specification.new do |s|
s.name = 'mongo_ext' s.name = 'mongo_ext'

View File

@ -6,8 +6,8 @@ require 'test/test_helper'
# NOTE: this test should be run only if a replica pair is running. # NOTE: this test should be run only if a replica pair is running.
class ReplicaPairCountTest < Test::Unit::TestCase class ReplicaPairCountTest < Test::Unit::TestCase
include Mongo include Mongo
def setup def setup
@conn = Mongo::Connection.new({:left => ["localhost", 27017], :right => ["localhost", 27018]}, nil) @conn = Mongo::Connection.new({:left => ["localhost", 27017], :right => ["localhost", 27018]}, nil)
@db = @conn.db('mongo-ruby-test') @db = @conn.db('mongo-ruby-test')
@db.drop_collection("test-pairs") @db.drop_collection("test-pairs")
@ -24,7 +24,7 @@ class ReplicaPairCountTest < Test::Unit::TestCase
puts "Please disconnect the current master." puts "Please disconnect the current master."
gets gets
rescue_connection_failure do rescue_connection_failure do
@coll.insert({:a => 30}, :safe => true) @coll.insert({:a => 30}, :safe => true)
end end
@coll.insert({:a => 40}, :safe => true) @coll.insert({:a => 40}, :safe => true)

View File

@ -6,8 +6,8 @@ require 'test/test_helper'
# NOTE: this test should be run only if a replica pair is running. # NOTE: this test should be run only if a replica pair is running.
class ReplicaPairInsertTest < Test::Unit::TestCase class ReplicaPairInsertTest < Test::Unit::TestCase
include Mongo include Mongo
def setup def setup
@conn = Mongo::Connection.new({:left => ["localhost", 27017], :right => ["localhost", 27018]}, nil) @conn = Mongo::Connection.new({:left => ["localhost", 27017], :right => ["localhost", 27018]}, nil)
@db = @conn.db('mongo-ruby-test') @db = @conn.db('mongo-ruby-test')
@db.drop_collection("test-pairs") @db.drop_collection("test-pairs")
@ -19,7 +19,7 @@ class ReplicaPairInsertTest < Test::Unit::TestCase
puts "Please disconnect the current master." puts "Please disconnect the current master."
gets gets
rescue_connection_failure do rescue_connection_failure do
@coll.save({:a => 30}, :safe => true) @coll.save({:a => 30}, :safe => true)
end end
@ -28,12 +28,12 @@ class ReplicaPairInsertTest < Test::Unit::TestCase
@coll.save({:a => 60}, :safe => true) @coll.save({:a => 60}, :safe => true)
@coll.save({:a => 70}, :safe => true) @coll.save({:a => 70}, :safe => true)
puts "Please reconnect the old master to make sure that the new master " + puts "Please reconnect the old master to make sure that the new master " +
"has synced with the previous master. Note: this may have happened already." "has synced with the previous master. Note: this may have happened already."
gets gets
results = [] results = []
rescue_connection_failure do rescue_connection_failure do
@coll.find.each {|r| results << r} @coll.find.each {|r| results << r}
[20, 30, 40, 50, 60, 70].each do |a| [20, 30, 40, 50, 60, 70].each do |a|
assert results.any? {|r| r['a'] == a}, "Could not find record for a => #{a}" assert results.any? {|r| r['a'] == a}, "Could not find record for a => #{a}"

View File

@ -6,8 +6,8 @@ require 'test/test_helper'
# NOTE: this test should be run only if a replica pair is running. # NOTE: this test should be run only if a replica pair is running.
class ReplicaPairPooledInsertTest < Test::Unit::TestCase class ReplicaPairPooledInsertTest < Test::Unit::TestCase
include Mongo include Mongo
def setup def setup
@conn = Mongo::Connection.new({:left => ["localhost", 27017], :right => ["localhost", 27018]}, nil, :pool_size => 10, :timeout => 5) @conn = Mongo::Connection.new({:left => ["localhost", 27017], :right => ["localhost", 27018]}, nil, :pool_size => 10, :timeout => 5)
@db = @conn.db('mongo-ruby-test') @db = @conn.db('mongo-ruby-test')
@db.drop_collection("test-pairs") @db.drop_collection("test-pairs")
@ -22,22 +22,22 @@ class ReplicaPairPooledInsertTest < Test::Unit::TestCase
threads = [] threads = []
10.times do |i| 10.times do |i|
threads[i] = Thread.new do threads[i] = Thread.new do
rescue_connection_failure do rescue_connection_failure do
@coll.save({:a => i}, :safe => true) @coll.save({:a => i}, :safe => true)
end end
end end
end end
puts "Please reconnect the old master to make sure that the new master " + puts "Please reconnect the old master to make sure that the new master " +
"has synced with the previous master. Note: this may have happened already." + "has synced with the previous master. Note: this may have happened already." +
"Note also that when connection with multiple threads, you may need to wait a few seconds" + "Note also that when connection with multiple threads, you may need to wait a few seconds" +
"after restarting the old master so that all the data has had a chance to sync." + "after restarting the old master so that all the data has had a chance to sync." +
"This is a case of eventual consistency." "This is a case of eventual consistency."
gets gets
results = [] results = []
rescue_connection_failure do rescue_connection_failure do
@coll.find.each {|r| results << r} @coll.find.each {|r| results << r}
expected_results.each do |a| expected_results.each do |a|
assert results.any? {|r| r['a'] == a}, "Could not find record for a => #{a}" assert results.any? {|r| r['a'] == a}, "Could not find record for a => #{a}"

View File

@ -6,8 +6,8 @@ require 'test/test_helper'
# NOTE: this test should be run only if a replica pair is running. # NOTE: this test should be run only if a replica pair is running.
class ReplicaPairQueryTest < Test::Unit::TestCase class ReplicaPairQueryTest < Test::Unit::TestCase
include Mongo include Mongo
def setup def setup
@conn = Mongo::Connection.new({:left => ["localhost", 27017], :right => ["localhost", 27018]}, nil) @conn = Mongo::Connection.new({:left => ["localhost", 27017], :right => ["localhost", 27018]}, nil)
@db = @conn.db('mongo-ruby-test') @db = @conn.db('mongo-ruby-test')
@db.drop_collection("test-pairs") @db.drop_collection("test-pairs")
@ -28,7 +28,7 @@ class ReplicaPairQueryTest < Test::Unit::TestCase
gets gets
results = [] results = []
rescue_connection_failure do rescue_connection_failure do
@coll.find.each {|r| results << r} @coll.find.each {|r| results << r}
[20, 30, 40].each do |a| [20, 30, 40].each do |a|
assert results.any? {|r| r['a'] == a}, "Could not find record for a => #{a}" assert results.any? {|r| r['a'] == a}, "Could not find record for a => #{a}"

View File

@ -359,12 +359,12 @@ class TestCollection < Test::Unit::TestCase
@@test.save(:foo => i) @@test.save(:foo => i)
end end
assert_equal 5, @@test.find({}, :skip => 5).next_object()["foo"] assert_equal 5, @@test.find({}, :skip => 5).next_document()["foo"]
assert_equal nil, @@test.find({}, :skip => 10).next_object() assert_equal nil, @@test.find({}, :skip => 10).next_document()
assert_equal 5, @@test.find({}, :limit => 5).to_a.length assert_equal 5, @@test.find({}, :limit => 5).to_a.length
assert_equal 3, @@test.find({}, :skip => 3, :limit => 5).next_object()["foo"] assert_equal 3, @@test.find({}, :skip => 3, :limit => 5).next_document()["foo"]
assert_equal 5, @@test.find({}, :skip => 3, :limit => 5).to_a.length assert_equal 5, @@test.find({}, :skip => 3, :limit => 5).to_a.length
end end

View File

@ -54,8 +54,8 @@ class TestConnection < Test::Unit::TestCase
def test_copy_database def test_copy_database
@mongo.db('old').collection('copy-test').insert('a' => 1) @mongo.db('old').collection('copy-test').insert('a' => 1)
@mongo.copy_database('old', 'new') @mongo.copy_database('old', 'new')
old_object = @mongo.db('old').collection('copy-test').find.next_object old_object = @mongo.db('old').collection('copy-test').find.next_document
new_object = @mongo.db('new').collection('copy-test').find.next_object new_object = @mongo.db('new').collection('copy-test').find.next_document
assert_equal old_object, new_object assert_equal old_object, new_object
end end

View File

@ -58,33 +58,40 @@ class CursorTest < Test::Unit::TestCase
assert_equal 0, @@db['acollectionthatdoesn'].count() assert_equal 0, @@db['acollectionthatdoesn'].count()
end end
def test_next_object_deprecation
@@coll.remove
@@coll.insert({"a" => 1})
assert_equal 1, @@coll.find().next_object["a"]
end
def test_sort def test_sort
@@coll.remove @@coll.remove
5.times{|x| @@coll.insert({"a" => x}) } 5.times{|x| @@coll.insert({"a" => x}) }
assert_kind_of Cursor, @@coll.find().sort(:a, 1) assert_kind_of Cursor, @@coll.find().sort(:a, 1)
assert_equal 0, @@coll.find().sort(:a, 1).next_object["a"] assert_equal 0, @@coll.find().sort(:a, 1).next_document["a"]
assert_equal 4, @@coll.find().sort(:a, -1).next_object["a"] assert_equal 4, @@coll.find().sort(:a, -1).next_document["a"]
assert_equal 0, @@coll.find().sort([["a", :asc]]).next_object["a"] assert_equal 0, @@coll.find().sort([["a", :asc]]).next_document["a"]
assert_kind_of Cursor, @@coll.find().sort([[:a, -1], [:b, 1]]) assert_kind_of Cursor, @@coll.find().sort([[:a, -1], [:b, 1]])
assert_equal 4, @@coll.find().sort(:a, 1).sort(:a, -1).next_object["a"] assert_equal 4, @@coll.find().sort(:a, 1).sort(:a, -1).next_document["a"]
assert_equal 0, @@coll.find().sort(:a, -1).sort(:a, 1).next_object["a"] assert_equal 0, @@coll.find().sort(:a, -1).sort(:a, 1).next_document["a"]
cursor = @@coll.find() cursor = @@coll.find()
cursor.next_object() cursor.next_document
assert_raise InvalidOperation do assert_raise InvalidOperation do
cursor.sort(["a"]) cursor.sort(["a"])
end end
assert_raise InvalidSortValueError do assert_raise InvalidSortValueError do
@@coll.find().sort(:a, 25).next_object @@coll.find().sort(:a, 25).next_document
end end
assert_raise InvalidSortValueError do assert_raise InvalidSortValueError do
@@coll.find().sort(25).next_object @@coll.find().sort(25).next_document
end end
end end
@ -106,7 +113,7 @@ class CursorTest < Test::Unit::TestCase
end end
cursor = @@coll.find() cursor = @@coll.find()
firstResult = cursor.next_object() firstResult = cursor.next_document
assert_raise InvalidOperation, "Cannot modify the query once it has been run or closed." do assert_raise InvalidOperation, "Cannot modify the query once it has been run or closed." do
cursor.limit(1) cursor.limit(1)
end end
@ -140,7 +147,7 @@ class CursorTest < Test::Unit::TestCase
end end
cursor = @@coll.find() cursor = @@coll.find()
firstResult = cursor.next_object() firstResult = cursor.next_document
assert_raise InvalidOperation, "Cannot modify the query once it has been run or closed." do assert_raise InvalidOperation, "Cannot modify the query once it has been run or closed." do
cursor.skip(1) cursor.skip(1)
end end
@ -233,7 +240,7 @@ class CursorTest < Test::Unit::TestCase
def test_close_after_query_sent def test_close_after_query_sent
begin begin
cursor = @@coll.find('a' => 1) cursor = @@coll.find('a' => 1)
cursor.next_object cursor.next_document
cursor.close cursor.close
assert cursor.closed? assert cursor.closed?
rescue => ex rescue => ex
@ -267,7 +274,7 @@ class CursorTest < Test::Unit::TestCase
10.times do |i| 10.times do |i|
a = @@coll.find() a = @@coll.find()
a.next_object() a.next_document
a.close() a.close()
end end
@ -277,7 +284,7 @@ class CursorTest < Test::Unit::TestCase
@@db.command("cursorInfo" => 1)["byLocation_size"]) @@db.command("cursorInfo" => 1)["byLocation_size"])
a = @@coll.find() a = @@coll.find()
a.next_object() a.next_document
assert_not_equal(client_cursors, assert_not_equal(client_cursors,
@@db.command("cursorInfo" => 1)["clientCursors_size"]) @@db.command("cursorInfo" => 1)["clientCursors_size"])
@ -291,7 +298,7 @@ class CursorTest < Test::Unit::TestCase
assert_equal(by_location, assert_equal(by_location,
@@db.command("cursorInfo" => 1)["byLocation_size"]) @@db.command("cursorInfo" => 1)["byLocation_size"])
a = @@coll.find({}, :limit => 10).next_object() a = @@coll.find({}, :limit => 10).next_document
assert_equal(client_cursors, assert_equal(client_cursors,
@@db.command("cursorInfo" => 1)["clientCursors_size"]) @@db.command("cursorInfo" => 1)["clientCursors_size"])
@ -299,7 +306,7 @@ class CursorTest < Test::Unit::TestCase
@@db.command("cursorInfo" => 1)["byLocation_size"]) @@db.command("cursorInfo" => 1)["byLocation_size"])
@@coll.find() do |cursor| @@coll.find() do |cursor|
cursor.next_object() cursor.next_document
end end
assert_equal(client_cursors, assert_equal(client_cursors,
@ -308,7 +315,7 @@ class CursorTest < Test::Unit::TestCase
@@db.command("cursorInfo" => 1)["byLocation_size"]) @@db.command("cursorInfo" => 1)["byLocation_size"])
@@coll.find() { |cursor| @@coll.find() { |cursor|
cursor.next_object() cursor.next_document
} }
assert_equal(client_cursors, assert_equal(client_cursors,

View File

@ -2,26 +2,26 @@ require 'test/test_helper'
class ConnectionTest < Test::Unit::TestCase class ConnectionTest < Test::Unit::TestCase
context "Basic operations: " do context "Basic operations: " do
setup do setup do
@logger = mock() @logger = mock()
end end
should "send update message" do should "send update message" do
@conn = Connection.new('localhost', 27017, :logger => @logger, :connect => false) @conn = Connection.new('localhost', 27017, :logger => @logger, :connect => false)
@db = @conn['testing'] @db = @conn['testing']
@coll = @db.collection('books') @coll = @db.collection('books')
@conn.expects(:send_message).with do |op, msg, log| @conn.expects(:send_message).with do |op, msg, log|
op == 2001 && log.include?("db.books.update") op == 2001 && log.include?("db.books.update")
end end
@coll.update({}, {:title => 'Moby Dick'}) @coll.update({}, {:title => 'Moby Dick'})
end end
should "send insert message" do should "send insert message" do
@conn = Connection.new('localhost', 27017, :logger => @logger, :connect => false) @conn = Connection.new('localhost', 27017, :logger => @logger, :connect => false)
@db = @conn['testing'] @db = @conn['testing']
@coll = @db.collection('books') @coll = @db.collection('books')
@conn.expects(:send_message).with do |op, msg, log| @conn.expects(:send_message).with do |op, msg, log|
op == 2002 && log.include?("db.books.insert") op == 2002 && log.include?("db.books.insert")
end end
@coll.insert({:title => 'Moby Dick'}) @coll.insert({:title => 'Moby Dick'})
@ -49,4 +49,4 @@ class ConnectionTest < Test::Unit::TestCase
end end
end end

View File

@ -2,15 +2,15 @@ require 'test/test_helper'
class TestCursor < Test::Unit::TestCase class TestCursor < Test::Unit::TestCase
context "Cursor options" do context "Cursor options" do
setup do setup do
@connection = stub(:class => Connection) @connection = stub(:class => Connection)
@db = stub(:name => "testing", :slave_ok? => false, :connection => @connection) @db = stub(:name => "testing", :slave_ok? => false, :connection => @connection)
@collection = stub(:db => @db, :name => "items") @collection = stub(:db => @db, :name => "items")
@cursor = Cursor.new(@collection) @cursor = Cursor.new(@collection)
end end
should "set admin to false" do should "set admin to false" do
assert_equal false, @cursor.admin assert_equal false, @cursor.admin
@cursor = Cursor.new(@collection, :admin => true) @cursor = Cursor.new(@collection, :admin => true)
@ -60,35 +60,35 @@ class TestCursor < Test::Unit::TestCase
assert_equal "name", @cursor.hint assert_equal "name", @cursor.hint
end end
should "cache full collection name" do should "cache full collection name" do
assert_equal "testing.items", @cursor.full_collection_name assert_equal "testing.items", @cursor.full_collection_name
end end
end end
context "Query fields" do context "Query fields" do
setup do setup do
@connection = stub(:class => Collection) @connection = stub(:class => Collection)
@db = stub(:slave_ok? => true, :name => "testing", :connection => @connection) @db = stub(:slave_ok? => true, :name => "testing", :connection => @connection)
@collection = stub(:db => @db, :name => "items") @collection = stub(:db => @db, :name => "items")
end end
should "when an array should return a hash with each key" do should "when an array should return a hash with each key" do
@cursor = Cursor.new(@collection, :fields => [:name, :age]) @cursor = Cursor.new(@collection, :fields => [:name, :age])
result = @cursor.fields result = @cursor.fields
assert_equal result.keys.sort{|a,b| a.to_s <=> b.to_s}, [:age, :name].sort{|a,b| a.to_s <=> b.to_s} assert_equal result.keys.sort{|a,b| a.to_s <=> b.to_s}, [:age, :name].sort{|a,b| a.to_s <=> b.to_s}
assert result.values.all? {|v| v == 1} assert result.values.all? {|v| v == 1}
end end
should "when a string, return a hash with just the key" do should "when a string, return a hash with just the key" do
@cursor = Cursor.new(@collection, :fields => "name") @cursor = Cursor.new(@collection, :fields => "name")
result = @cursor.fields result = @cursor.fields
assert_equal result.keys.sort, ["name"] assert_equal result.keys.sort, ["name"]
assert result.values.all? {|v| v == 1} assert result.values.all? {|v| v == 1}
end end
should "return nil when neither hash nor string nor symbol" do should "return nil when neither hash nor string nor symbol" do
@cursor = Cursor.new(@collection, :fields => 1234567) @cursor = Cursor.new(@collection, :fields => 1234567)
assert_nil @cursor.fields assert_nil @cursor.fields
end end
end end
end end

View File

@ -11,8 +11,8 @@ class DBTest < Test::Unit::TestCase
message = db.add_message_headers(Mongo::Constants::OP_INSERT, message) message = db.add_message_headers(Mongo::Constants::OP_INSERT, message)
end end
context "DB commands" do context "DB commands" do
setup do setup do
@conn = stub() @conn = stub()
@db = DB.new("testing", @conn) @db = DB.new("testing", @conn)
@collection = mock() @collection = mock()
@ -20,30 +20,30 @@ class DBTest < Test::Unit::TestCase
end end
should "raise an error if given a hash with more than one key" do should "raise an error if given a hash with more than one key" do
assert_raise MongoArgumentError do assert_raise MongoArgumentError do
@db.command(:buildinfo => 1, :somekey => 1) @db.command(:buildinfo => 1, :somekey => 1)
end end
end end
should "raise an error if the selector is omitted" do should "raise an error if the selector is omitted" do
assert_raise MongoArgumentError do assert_raise MongoArgumentError do
@db.command({}, true) @db.command({}, true)
end end
end end
should "create the proper cursor" do should "create the proper cursor" do
@cursor = mock(:next_object => {"ok" => 1}) @cursor = mock(:next_document => {"ok" => 1})
Cursor.expects(:new).with(@collection, :admin => true, Cursor.expects(:new).with(@collection, :admin => true,
:limit => -1, :selector => {:buildinfo => 1}, :socket => nil).returns(@cursor) :limit => -1, :selector => {:buildinfo => 1}, :socket => nil).returns(@cursor)
command = {:buildinfo => 1} command = {:buildinfo => 1}
@db.command(command, true) @db.command(command, true)
end end
should "raise an error when the command fails" do should "raise an error when the command fails" do
@cursor = mock(:next_object => {"ok" => 0}) @cursor = mock(:next_document => {"ok" => 0})
Cursor.expects(:new).with(@collection, :admin => true, Cursor.expects(:new).with(@collection, :admin => true,
:limit => -1, :selector => {:buildinfo => 1}, :socket => nil).returns(@cursor) :limit => -1, :selector => {:buildinfo => 1}, :socket => nil).returns(@cursor)
assert_raise OperationFailure do assert_raise OperationFailure do
command = {:buildinfo => 1} command = {:buildinfo => 1}
@db.command(command, true, true) @db.command(command, true, true)
end end
@ -51,4 +51,4 @@ class DBTest < Test::Unit::TestCase
end end
end end