mongo 0.18.2 → 0.18.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +37 -28
- data/Rakefile +19 -0
- data/bin/objectid_benchmark.rb +23 -0
- data/examples/admin.rb +7 -6
- data/examples/capped.rb +3 -4
- data/examples/cursor.rb +4 -3
- data/examples/gridfs.rb +3 -2
- data/examples/index_test.rb +10 -9
- data/examples/info.rb +3 -2
- data/examples/queries.rb +3 -2
- data/examples/simple.rb +3 -2
- data/examples/strict.rb +2 -1
- data/examples/types.rb +4 -3
- data/lib/mongo.rb +29 -12
- data/lib/mongo/admin.rb +17 -2
- data/lib/mongo/collection.rb +230 -169
- data/lib/mongo/connection.rb +136 -91
- data/lib/mongo/cursor.rb +68 -40
- data/lib/mongo/db.rb +247 -123
- data/lib/mongo/{errors.rb → exceptions.rb} +6 -5
- data/lib/mongo/gridfs.rb +6 -0
- data/lib/mongo/gridfs/grid_store.rb +142 -94
- data/lib/mongo/types/binary.rb +11 -1
- data/lib/mongo/types/code.rb +6 -1
- data/lib/mongo/types/dbref.rb +7 -2
- data/lib/mongo/types/min_max_keys.rb +58 -0
- data/lib/mongo/types/objectid.rb +76 -20
- data/lib/mongo/types/regexp_of_holding.rb +5 -0
- data/lib/mongo/util/bson_ruby.rb +36 -2
- data/lib/mongo/util/byte_buffer.rb +18 -2
- data/lib/mongo/util/conversions.rb +6 -5
- data/lib/mongo/util/ordered_hash.rb +3 -1
- data/lib/mongo/util/support.rb +3 -0
- data/lib/mongo/util/xml_to_ruby.rb +7 -0
- data/test/test_bson.rb +48 -0
- data/test/test_collection.rb +13 -0
- data/test/test_connection.rb +35 -0
- data/test/test_conversions.rb +1 -1
- data/test/test_cursor.rb +37 -5
- data/test/test_db.rb +51 -2
- data/test/test_db_api.rb +4 -7
- data/test/test_grid_store.rb +10 -0
- data/test/test_objectid.rb +16 -2
- data/test/test_ordered_hash.rb +14 -0
- data/test/threading/test_threading_large_pool.rb +4 -4
- data/test/unit/db_test.rb +43 -0
- metadata +5 -7
- data/examples/benchmarks.rb +0 -42
- data/examples/blog.rb +0 -76
- data/lib/mongo/constants.rb +0 -15
- data/test/mongo-qa/_common.rb +0 -8
data/lib/mongo/connection.rb
CHANGED
@@ -20,11 +20,10 @@ require 'thread'
|
|
20
20
|
|
21
21
|
module Mongo
|
22
22
|
|
23
|
-
#
|
23
|
+
# Instantiates and manages connections to MongoDB.
|
24
24
|
class Connection
|
25
25
|
|
26
|
-
#
|
27
|
-
# a ConnectionError is raised.
|
26
|
+
# Abort connections if a ConnectionError is raised.
|
28
27
|
Thread.abort_on_exception = true
|
29
28
|
|
30
29
|
DEFAULT_PORT = 27017
|
@@ -33,70 +32,59 @@ module Mongo
|
|
33
32
|
|
34
33
|
attr_reader :logger, :size, :host, :port, :nodes, :sockets, :checked_out
|
35
34
|
|
36
|
-
def slave_ok?
|
37
|
-
@slave_ok
|
38
|
-
end
|
39
|
-
|
40
35
|
# Counter for generating unique request ids.
|
41
36
|
@@current_request_id = 0
|
42
37
|
|
43
|
-
#
|
38
|
+
# Create a connection to MongoDB. Specify either one or a pair of servers,
|
44
39
|
# along with a maximum connection pool size and timeout.
|
45
40
|
#
|
46
|
-
# == Connecting
|
47
41
|
# If connecting to just one server, you may specify whether connection to slave is permitted.
|
42
|
+
# In all cases, the default host is "localhost" and the default port is 27017.
|
48
43
|
#
|
49
|
-
#
|
50
|
-
#
|
51
|
-
# When specifying a pair, pair_or_host, is a hash with two keys: :left and :right. Each key maps to either
|
44
|
+
# When specifying a pair, +pair_or_host+, is a hash with two keys: :left and :right. Each key maps to either
|
52
45
|
# * a server name, in which case port is 27017,
|
53
46
|
# * a port number, in which case the server is "localhost", or
|
54
47
|
# * an array containing [server_name, port_number]
|
55
48
|
#
|
56
|
-
# === Options
|
57
|
-
#
|
58
|
-
# :slave_ok :: Defaults to +false+. Must be set to +true+ when connecting
|
59
|
-
# to a single, slave node.
|
60
|
-
#
|
61
|
-
# :logger :: Optional Logger instance to which driver usage information
|
62
|
-
# will be logged.
|
63
|
-
#
|
64
|
-
# :auto_reconnect :: DEPRECATED. See http://www.mongodb.org/display/DOCS/Replica+Pairs+in+Ruby
|
65
|
-
#
|
66
|
-
# :pool_size :: The maximum number of socket connections that can be opened
|
67
|
-
# that can be opened to the database.
|
68
|
-
#
|
69
|
-
# :timeout :: When all of the connections to the pool are checked out,
|
70
|
-
# this is the number of seconds to wait for a new connection
|
71
|
-
# to be released before throwing an exception.
|
72
|
-
#
|
73
49
|
# Note that there are a few issues when using connection pooling with Ruby 1.9 on Windows. These
|
74
50
|
# should be resolved in the next release.
|
75
51
|
#
|
76
|
-
#
|
52
|
+
# @param [String, Hash] pair_or_host See explanation above.
|
53
|
+
# @param [Integer] port specify a port number here if only one host is being specified. Leave nil if
|
54
|
+
# specifying a pair of servers in +pair_or_host+.
|
77
55
|
#
|
78
|
-
#
|
79
|
-
#
|
56
|
+
# @option options [Boolean] :slave_ok (false) Must be set to +true+ when connecting
|
57
|
+
# to a single, slave node.
|
58
|
+
# @option options [Logger, #debug] :logger (nil) Logger instance to receive driver operation log.
|
59
|
+
# @option options [Boolean] :auto_reconnect DEPRECATED. See http://www.mongodb.org/display/DOCS/Replica+Pairs+in+Ruby
|
60
|
+
# @option options [Integer] :pool_size (1) The maximum number of socket connections that can be opened to the database.
|
61
|
+
# @option options [Float] :timeout (5.0) When all of the connections to the pool are checked out,
|
62
|
+
# this is the number of seconds to wait for a new connection to be released before throwing an exception.
|
80
63
|
#
|
81
|
-
# # localhost, 27017
|
82
|
-
# Connection.new("localhost")
|
83
64
|
#
|
84
|
-
#
|
85
|
-
#
|
65
|
+
# @example localhost, 27017
|
66
|
+
# Connection.new
|
86
67
|
#
|
87
|
-
#
|
88
|
-
#
|
68
|
+
# @example localhost, 27017
|
69
|
+
# Connection.new("localhost")
|
89
70
|
#
|
90
|
-
#
|
91
|
-
#
|
92
|
-
#
|
93
|
-
#
|
71
|
+
# @example localhost, 3000, max 5 connections, with max 5 seconds of wait time.
|
72
|
+
# Connection.new("localhost", 3000, :pool_size => 5, :timeout => 5)
|
73
|
+
#
|
74
|
+
# @example localhost, 3000, where this node may be a slave
|
75
|
+
# Connection.new("localhost", 3000, :slave_ok => true)
|
76
|
+
#
|
77
|
+
# @example A pair of servers. The driver will always talk to master.
|
78
|
+
# # On connection errors, Mongo::ConnectionFailure will be raised.
|
79
|
+
# Connection.new({:left => ["db1.example.com", 27017],
|
94
80
|
# :right => ["db2.example.com", 27017]})
|
95
81
|
#
|
96
|
-
#
|
97
|
-
#
|
98
|
-
#
|
99
|
-
#
|
82
|
+
# @example A pair of servers with connection pooling enabled. Note the nil param placeholder for port.
|
83
|
+
# Connection.new({:left => ["db1.example.com", 27017],
|
84
|
+
# :right => ["db2.example.com", 27017]}, nil,
|
85
|
+
# :pool_size => 20, :timeout => 5)
|
86
|
+
#
|
87
|
+
# @see http://www.mongodb.org/display/DOCS/Replica+Pairs+in+Ruby Replica pairs in Ruby
|
100
88
|
def initialize(pair_or_host=nil, port=nil, options={})
|
101
89
|
@nodes = format_pair(pair_or_host, port)
|
102
90
|
|
@@ -124,7 +112,7 @@ module Mongo
|
|
124
112
|
warn(":auto_reconnect is deprecated. see http://www.mongodb.org/display/DOCS/Replica+Pairs+in+Ruby")
|
125
113
|
end
|
126
114
|
|
127
|
-
#
|
115
|
+
# slave_ok can be true only if one node is specified
|
128
116
|
@slave_ok = options[:slave_ok] && @nodes.length == 1
|
129
117
|
@logger = options[:logger] || nil
|
130
118
|
@options = options
|
@@ -133,8 +121,10 @@ module Mongo
|
|
133
121
|
connect_to_master if should_connect
|
134
122
|
end
|
135
123
|
|
136
|
-
#
|
137
|
-
# disk.
|
124
|
+
# Return a hash with all database names
|
125
|
+
# and their respective sizes on disk.
|
126
|
+
#
|
127
|
+
# @return [Hash]
|
138
128
|
def database_info
|
139
129
|
doc = self['admin'].command(:listDatabases => 1)
|
140
130
|
returning({}) do |info|
|
@@ -142,39 +132,57 @@ module Mongo
|
|
142
132
|
end
|
143
133
|
end
|
144
134
|
|
145
|
-
#
|
135
|
+
# Return an array of database names.
|
136
|
+
#
|
137
|
+
# @return [Array]
|
146
138
|
def database_names
|
147
139
|
database_info.keys
|
148
140
|
end
|
149
141
|
|
150
|
-
#
|
151
|
-
# See DB#new for
|
142
|
+
# Return a database with the given name.
|
143
|
+
# See DB#new for valid options hash parameters.
|
144
|
+
#
|
145
|
+
# @param [String] db_name a valid database name.
|
146
|
+
#
|
147
|
+
# @return [Mongo::DB]
|
152
148
|
def db(db_name, options={})
|
153
149
|
DB.new(db_name, self, options.merge(:logger => @logger))
|
154
150
|
end
|
155
151
|
|
156
|
-
#
|
152
|
+
# Shortcut for returning a database. Use DB#db to accept options.
|
153
|
+
#
|
154
|
+
# @param [String] db_name a valid database name.
|
155
|
+
#
|
156
|
+
# @return [Mongo::DB]
|
157
157
|
def [](db_name)
|
158
158
|
DB.new(db_name, self, :logger => @logger)
|
159
159
|
end
|
160
160
|
|
161
|
-
#
|
161
|
+
# Drop a database.
|
162
|
+
#
|
163
|
+
# @param [String] name name of an existing database.
|
162
164
|
def drop_database(name)
|
163
165
|
self[name].command(:dropDatabase => 1)
|
164
166
|
end
|
165
167
|
|
166
|
-
#
|
168
|
+
# Copy the database +from+ on the local server to +to+ on the specified +host+.
|
167
169
|
# +host+ defaults to 'localhost' if no value is provided.
|
168
|
-
|
170
|
+
#
|
171
|
+
# @param [String] from name of the database to copy from.
|
172
|
+
# @param [String] to name of the database to copy to.
|
173
|
+
# @param [String] from_host host of the 'from' database.
|
174
|
+
def copy_database(from, to, from_host="localhost")
|
169
175
|
oh = OrderedHash.new
|
170
176
|
oh[:copydb] = 1
|
171
|
-
oh[:fromhost] =
|
177
|
+
oh[:fromhost] = from_host
|
172
178
|
oh[:fromdb] = from
|
173
179
|
oh[:todb] = to
|
174
180
|
self["admin"].command(oh)
|
175
181
|
end
|
176
182
|
|
177
|
-
#
|
183
|
+
# Increment and return the next available request id.
|
184
|
+
#
|
185
|
+
# return [Integer]
|
178
186
|
def get_request_id
|
179
187
|
request_id = ''
|
180
188
|
@id_lock.synchronize do
|
@@ -183,51 +191,75 @@ module Mongo
|
|
183
191
|
request_id
|
184
192
|
end
|
185
193
|
|
186
|
-
#
|
194
|
+
# Get the build information for the current connection.
|
195
|
+
#
|
196
|
+
# @return [Hash]
|
187
197
|
def server_info
|
188
198
|
db("admin").command({:buildinfo => 1}, {:admin => true, :check_response => true})
|
189
199
|
end
|
190
200
|
|
191
|
-
#
|
192
|
-
#
|
201
|
+
# Get the build version of the current server.
|
202
|
+
#
|
203
|
+
# @return [Mongo::ServerVersion]
|
204
|
+
# object allowing easy comparability of version.
|
193
205
|
def server_version
|
194
206
|
ServerVersion.new(server_info["version"])
|
195
207
|
end
|
196
208
|
|
209
|
+
# Is it okay to connect to a slave?
|
210
|
+
#
|
211
|
+
# @return [Boolean]
|
212
|
+
def slave_ok?
|
213
|
+
@slave_ok
|
214
|
+
end
|
215
|
+
|
197
216
|
|
198
217
|
## Connections and pooling ##
|
199
218
|
|
200
|
-
#
|
219
|
+
# Send a message to MongoDB, adding the necessary headers.
|
201
220
|
#
|
202
|
-
#
|
203
|
-
#
|
204
|
-
#
|
221
|
+
# @param [Integer] operation a MongoDB opcode.
|
222
|
+
# @param [ByteBuffer] message a message to send to the database.
|
223
|
+
# @param [String] log_message text version of +message+ for logging.
|
224
|
+
#
|
225
|
+
# @return [True]
|
205
226
|
def send_message(operation, message, log_message=nil)
|
206
227
|
@logger.debug(" MONGODB #{log_message || message}") if @logger
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
228
|
+
begin
|
229
|
+
packed_message = add_message_headers(operation, message).to_s
|
230
|
+
socket = checkout
|
231
|
+
send_message_on_socket(packed_message, socket)
|
232
|
+
ensure
|
233
|
+
checkin(socket)
|
234
|
+
end
|
211
235
|
end
|
212
236
|
|
213
237
|
# Sends a message to the database, waits for a response, and raises
|
214
238
|
# an exception if the operation has failed.
|
215
239
|
#
|
216
|
-
#
|
217
|
-
#
|
218
|
-
#
|
240
|
+
# @param [Integer] operation a MongoDB opcode.
|
241
|
+
# @param [ByteBuffer] message a message to send to the database.
|
242
|
+
# @param [String] db_name the name of the database. used on call to get_last_error.
|
243
|
+
# @param [String] log_message text version of +message+ for logging.
|
244
|
+
#
|
245
|
+
# @return [Array]
|
246
|
+
# An array whose indexes include [0] documents returned, [1] number of document received,
|
247
|
+
# and [3] a cursor_id.
|
219
248
|
def send_message_with_safe_check(operation, message, db_name, log_message=nil)
|
220
249
|
message_with_headers = add_message_headers(operation, message)
|
221
250
|
message_with_check = last_error_message(db_name)
|
222
251
|
@logger.debug(" MONGODB #{log_message || message}") if @logger
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
252
|
+
begin
|
253
|
+
sock = checkout
|
254
|
+
packed_message = message_with_headers.append!(message_with_check).to_s
|
255
|
+
docs = num_received = cursor_id = ''
|
256
|
+
@safe_mutex.synchronize do
|
257
|
+
send_message_on_socket(packed_message, sock)
|
258
|
+
docs, num_received, cursor_id = receive(sock)
|
259
|
+
end
|
260
|
+
ensure
|
261
|
+
checkin(sock)
|
229
262
|
end
|
230
|
-
checkin(sock)
|
231
263
|
if num_received == 1 && error = docs[0]['err']
|
232
264
|
raise Mongo::OperationFailure, error
|
233
265
|
end
|
@@ -236,25 +268,35 @@ module Mongo
|
|
236
268
|
|
237
269
|
# Sends a message to the database and waits for the response.
|
238
270
|
#
|
239
|
-
#
|
240
|
-
#
|
241
|
-
#
|
271
|
+
# @param [Integer] operation a MongoDB opcode.
|
272
|
+
# @param [ByteBuffer] message a message to send to the database.
|
273
|
+
# @param [String] log_message text version of +message+ for logging.
|
274
|
+
# @param [Socket] socket a socket to use in lieu of checking out a new one.
|
275
|
+
#
|
276
|
+
# @return [Array]
|
277
|
+
# An array whose indexes include [0] documents returned, [1] number of document received,
|
278
|
+
# and [3] a cursor_id.
|
242
279
|
def receive_message(operation, message, log_message=nil, socket=nil)
|
243
280
|
packed_message = add_message_headers(operation, message).to_s
|
244
281
|
@logger.debug(" MONGODB #{log_message || message}") if @logger
|
245
|
-
|
282
|
+
begin
|
283
|
+
sock = socket || checkout
|
246
284
|
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
285
|
+
result = ''
|
286
|
+
@safe_mutex.synchronize do
|
287
|
+
send_message_on_socket(packed_message, sock)
|
288
|
+
result = receive(sock)
|
289
|
+
end
|
290
|
+
ensure
|
291
|
+
checkin(sock)
|
251
292
|
end
|
252
|
-
checkin(sock)
|
253
293
|
result
|
254
294
|
end
|
255
295
|
|
256
|
-
#
|
257
|
-
# If successful, sets
|
296
|
+
# Create a new socket and attempt to connect to master.
|
297
|
+
# If successful, sets host and port to master and returns the socket.
|
298
|
+
#
|
299
|
+
# @raise [ConnectionFailure] if unable to connect to any host or port.
|
258
300
|
def connect_to_master
|
259
301
|
close
|
260
302
|
@host = @port = nil
|
@@ -286,7 +328,7 @@ module Mongo
|
|
286
328
|
end
|
287
329
|
|
288
330
|
# Are we connected to MongoDB? This is determined by checking whether
|
289
|
-
#
|
331
|
+
# host and port have values, since they're set to nil on calls to #close.
|
290
332
|
def connected?
|
291
333
|
@host && @port
|
292
334
|
end
|
@@ -361,6 +403,9 @@ module Mongo
|
|
361
403
|
return socket if socket
|
362
404
|
|
363
405
|
# Otherwise, wait
|
406
|
+
if @logger
|
407
|
+
@logger.warn "Waiting for available connection; #{@checked_out.size} of #{@size} connections checked out."
|
408
|
+
end
|
364
409
|
@queue.wait(@connection_mutex)
|
365
410
|
end
|
366
411
|
end
|
data/lib/mongo/cursor.rb
CHANGED
@@ -25,7 +25,10 @@ module Mongo
|
|
25
25
|
|
26
26
|
# Create a new cursor.
|
27
27
|
#
|
28
|
-
#
|
28
|
+
# Note: cursors are created when executing queries using [Collection#find] and other
|
29
|
+
# similar methods. Application developers shouldn't have to create cursors manually.
|
30
|
+
#
|
31
|
+
# @return [Cursor]
|
29
32
|
def initialize(collection, options={})
|
30
33
|
@db = collection.db
|
31
34
|
@collection = collection
|
@@ -49,7 +52,9 @@ module Mongo
|
|
49
52
|
@query_run = false
|
50
53
|
end
|
51
54
|
|
52
|
-
#
|
55
|
+
# Get the next document specified the cursor options.
|
56
|
+
#
|
57
|
+
# @return [Hash, Nil] the next document or Nil if no documents remain.
|
53
58
|
def next_document
|
54
59
|
refill_via_get_more if num_remaining == 0
|
55
60
|
doc = @cache.shift
|
@@ -71,6 +76,7 @@ module Mongo
|
|
71
76
|
doc
|
72
77
|
end
|
73
78
|
|
79
|
+
# @deprecated use Cursor#next_document instead.
|
74
80
|
def next_object
|
75
81
|
warn "Cursor#next_object is deprecated; please use Cursor#next_document instead."
|
76
82
|
next_document
|
@@ -78,9 +84,10 @@ module Mongo
|
|
78
84
|
|
79
85
|
# Get the size of the result set for this query.
|
80
86
|
#
|
81
|
-
#
|
82
|
-
#
|
83
|
-
#
|
87
|
+
# @return [Integer] the number of objects in the result set for this query. Does
|
88
|
+
# not take limit and skip into account.
|
89
|
+
#
|
90
|
+
# @raise [OperationFailure] on a database error.
|
84
91
|
def count
|
85
92
|
command = OrderedHash["count", @collection.name,
|
86
93
|
"query", @selector,
|
@@ -93,15 +100,16 @@ module Mongo
|
|
93
100
|
|
94
101
|
# Sort this cursor's results.
|
95
102
|
#
|
96
|
-
# Takes either a single key and a direction, or an array of [key,
|
97
|
-
# direction] pairs. Directions should be specified as Mongo::ASCENDING / Mongo::DESCENDING
|
98
|
-
# (or :ascending / :descending, :asc / :desc).
|
99
|
-
#
|
100
|
-
# Raises InvalidOperation if this cursor has already been used. Raises
|
101
|
-
# InvalidSortValueError if the specified order is invalid.
|
102
|
-
#
|
103
103
|
# This method overrides any sort order specified in the Collection#find
|
104
104
|
# method, and only the last sort applied has an effect.
|
105
|
+
#
|
106
|
+
# @param [Symbol, Array] key_or_list either 1) a key to sort by or 2)
|
107
|
+
# an array of [key, direction] pairs to sort by. Direction should
|
108
|
+
# be specified as Mongo::ASCENDING (or :ascending / :asc) or Mongo::DESCENDING (or :descending / :desc)
|
109
|
+
#
|
110
|
+
# @raise [InvalidOperation] if this cursor has already been used.
|
111
|
+
#
|
112
|
+
# @raise [InvalidSortValueError] if the specified order is invalid.
|
105
113
|
def sort(key_or_list, direction=nil)
|
106
114
|
check_modifiable
|
107
115
|
|
@@ -115,13 +123,14 @@ module Mongo
|
|
115
123
|
self
|
116
124
|
end
|
117
125
|
|
118
|
-
#
|
119
|
-
# Returns the current number_to_return if no parameter is given.
|
120
|
-
#
|
121
|
-
# Raises InvalidOperation if this cursor has already been used.
|
126
|
+
# Limit the number of results to be returned by this cursor.
|
122
127
|
#
|
123
128
|
# This method overrides any limit specified in the Collection#find method,
|
124
129
|
# and only the last limit applied has an effect.
|
130
|
+
#
|
131
|
+
# @return [Integer] the current number_to_return if no parameter is given.
|
132
|
+
#
|
133
|
+
# @raise [InvalidOperation] if this cursor has already been used.
|
125
134
|
def limit(number_to_return=nil)
|
126
135
|
return @limit unless number_to_return
|
127
136
|
check_modifiable
|
@@ -134,10 +143,12 @@ module Mongo
|
|
134
143
|
# Skips the first +number_to_skip+ results of this cursor.
|
135
144
|
# Returns the current number_to_skip if no parameter is given.
|
136
145
|
#
|
137
|
-
# Raises InvalidOperation if this cursor has already been used.
|
138
|
-
#
|
139
146
|
# This method overrides any skip specified in the Collection#find method,
|
140
147
|
# and only the last skip applied has an effect.
|
148
|
+
#
|
149
|
+
# @return [Integer]
|
150
|
+
#
|
151
|
+
# @raise [InvalidOperation] if this cursor has already been used.
|
141
152
|
def skip(number_to_skip=nil)
|
142
153
|
return @skip unless number_to_skip
|
143
154
|
check_modifiable
|
@@ -151,6 +162,13 @@ module Mongo
|
|
151
162
|
# block.
|
152
163
|
#
|
153
164
|
# Iterating over an entire cursor will close it.
|
165
|
+
#
|
166
|
+
# @yield passes each document to a block for processing.
|
167
|
+
#
|
168
|
+
# @example if 'comments' represents a collection of comments:
|
169
|
+
# comments.find.each do |doc|
|
170
|
+
# puts doc['user']
|
171
|
+
# end
|
154
172
|
def each
|
155
173
|
num_returned = 0
|
156
174
|
while more? && (@limit <= 0 || num_returned < @limit)
|
@@ -159,13 +177,15 @@ module Mongo
|
|
159
177
|
end
|
160
178
|
end
|
161
179
|
|
162
|
-
#
|
180
|
+
# Receive all the documents from this cursor as an array of hashes.
|
163
181
|
#
|
164
|
-
#
|
165
|
-
#
|
182
|
+
# Note: use of this method is discouraged - in most cases, it's much more
|
183
|
+
# efficient to retrieve documents as you need them by iterating over the cursor.
|
166
184
|
#
|
167
|
-
#
|
168
|
-
#
|
185
|
+
# @return [Array] an array of documents.
|
186
|
+
#
|
187
|
+
# @raise [InvalidOperation] if this cursor has already been used or if
|
188
|
+
# this method has already been called on the cursor.
|
169
189
|
def to_a
|
170
190
|
raise InvalidOperation, "can't call Cursor#to_a on a used cursor" if @query_run
|
171
191
|
rows = []
|
@@ -177,7 +197,9 @@ module Mongo
|
|
177
197
|
rows
|
178
198
|
end
|
179
199
|
|
180
|
-
#
|
200
|
+
# Get the explain plan for this cursor.
|
201
|
+
#
|
202
|
+
# @return [Hash] a document containing the explain plan for this cursor.
|
181
203
|
def explain
|
182
204
|
c = Cursor.new(@collection, query_options_hash.merge(:limit => -@limit.abs, :explain => true))
|
183
205
|
explanation = c.next_document
|
@@ -186,19 +208,19 @@ module Mongo
|
|
186
208
|
explanation
|
187
209
|
end
|
188
210
|
|
189
|
-
#
|
211
|
+
# Close the cursor.
|
190
212
|
#
|
191
213
|
# Note: if a cursor is read until exhausted (read until Mongo::Constants::OP_QUERY or
|
192
214
|
# Mongo::Constants::OP_GETMORE returns zero for the cursor id), there is no need to
|
193
|
-
# close it
|
215
|
+
# close it manually.
|
216
|
+
#
|
217
|
+
# Note also: Collection#find takes an optional block argument which can be used to
|
218
|
+
# ensure that your cursors get closed.
|
194
219
|
#
|
195
|
-
#
|
196
|
-
# ensure that your cursors get closed. See the documentation for
|
197
|
-
# Collection#find for details.
|
220
|
+
# @return [True]
|
198
221
|
def close
|
199
222
|
if @cursor_id
|
200
|
-
message = ByteBuffer.new
|
201
|
-
message.put_int(0)
|
223
|
+
message = ByteBuffer.new([0, 0, 0, 0])
|
202
224
|
message.put_int(1)
|
203
225
|
message.put_long(@cursor_id)
|
204
226
|
@connection.send_message(Mongo::Constants::OP_KILL_CURSORS, message, "cursor.close()")
|
@@ -207,18 +229,26 @@ module Mongo
|
|
207
229
|
@closed = true
|
208
230
|
end
|
209
231
|
|
210
|
-
#
|
232
|
+
# Is this cursor closed?
|
233
|
+
#
|
234
|
+
# @return [Boolean]
|
211
235
|
def closed?; @closed; end
|
212
236
|
|
213
237
|
# Returns an integer indicating which query options have been selected.
|
214
|
-
#
|
238
|
+
#
|
239
|
+
# @return [Integer]
|
240
|
+
#
|
241
|
+
# @see http://www.mongodb.org/display/DOCS/Mongo+Wire+Protocol#MongoWireProtocol-Mongo::Constants::OPQUERY
|
242
|
+
# The MongoDB wire protocol.
|
215
243
|
def query_opts
|
216
244
|
timeout = @timeout ? 0 : Mongo::Constants::OP_QUERY_NO_CURSOR_TIMEOUT
|
217
245
|
slave_ok = @connection.slave_ok? ? Mongo::Constants::OP_QUERY_SLAVE_OK : 0
|
218
246
|
slave_ok + timeout
|
219
247
|
end
|
220
248
|
|
221
|
-
#
|
249
|
+
# Get the query options for this Cursor.
|
250
|
+
#
|
251
|
+
# @return [Hash]
|
222
252
|
def query_options_hash
|
223
253
|
{ :selector => @selector,
|
224
254
|
:fields => @fields,
|
@@ -233,7 +263,7 @@ module Mongo
|
|
233
263
|
|
234
264
|
private
|
235
265
|
|
236
|
-
#
|
266
|
+
# Convert the +:fields+ parameter from a single field name or an array
|
237
267
|
# of fields names to a hash, with the field names for keys and '1' for each
|
238
268
|
# value.
|
239
269
|
def convert_fields_for_query(fields)
|
@@ -284,9 +314,7 @@ module Mongo
|
|
284
314
|
|
285
315
|
def refill_via_get_more
|
286
316
|
return if send_initial_query || @cursor_id.zero?
|
287
|
-
message = ByteBuffer.new
|
288
|
-
# Reserved.
|
289
|
-
message.put_int(0)
|
317
|
+
message = ByteBuffer.new([0, 0, 0, 0])
|
290
318
|
|
291
319
|
# DB name.
|
292
320
|
db_name = @admin ? 'admin' : @db.name
|
@@ -328,8 +356,8 @@ module Mongo
|
|
328
356
|
if query_contains_special_fields?
|
329
357
|
selector = selector_with_special_query_fields
|
330
358
|
end
|
331
|
-
message.put_array(BSON.serialize(selector, false).
|
332
|
-
message.put_array(BSON.serialize(@fields, false).
|
359
|
+
message.put_array(BSON.serialize(selector, false).to_a)
|
360
|
+
message.put_array(BSON.serialize(@fields, false).to_a) if @fields
|
333
361
|
message
|
334
362
|
end
|
335
363
|
|