mongo 1.0.3 → 1.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY +17 -0
- data/lib/mongo.rb +12 -5
- data/lib/mongo/collection.rb +13 -3
- data/lib/mongo/connection.rb +22 -6
- data/lib/mongo/cursor.rb +17 -16
- data/lib/mongo/db.rb +39 -41
- data/lib/mongo/gridfs/grid.rb +3 -2
- data/lib/mongo/gridfs/grid_io.rb +7 -0
- data/test/collection_test.rb +19 -2
- data/test/cursor_fail_test.rb +76 -0
- data/test/cursor_message_test.rb +32 -0
- data/test/cursor_test.rb +25 -1
- data/test/db_api_test.rb +1 -1
- data/test/db_test.rb +9 -1
- data/test/grid_io_test.rb +1 -3
- data/test/grid_test.rb +6 -0
- data/test/unit/connection_test.rb +7 -0
- data/test/unit/cursor_test.rb +0 -7
- data/test/unit/db_test.rb +5 -5
- metadata +7 -5
data/HISTORY
CHANGED
@@ -1,3 +1,20 @@
|
|
1
|
+
1.0.4 2010-7-13
|
2
|
+
|
3
|
+
* Removed deprecated
|
4
|
+
- Cursor admin option
|
5
|
+
- DB#query
|
6
|
+
- DB#create_index (use Collection#create_index)
|
7
|
+
- DB#command only takes hash options now
|
8
|
+
* j2bson executable (neomantra)
|
9
|
+
* Fixed bson_ext compilation on Solaris (slyphon)
|
10
|
+
* System JS helpers (neovintage)
|
11
|
+
* Use one mutex per thread on pooled connections (cremes)
|
12
|
+
* Check for CursorNotFound response flag
|
13
|
+
* MapReduce can return raw command output using :raw
|
14
|
+
* BSON::OrderedHash equality with other Ruby hashes (Ryan Angilly)
|
15
|
+
* Fix for broken Socket.send with large payloads (Frédéric De Jaeger)
|
16
|
+
* Lots of minor improvements. See commmits.
|
17
|
+
|
1
18
|
1.0.3 2010-6-15
|
2
19
|
|
3
20
|
* Optimiztion for BSON::OrderedHash
|
data/lib/mongo.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
4
4
|
|
5
5
|
module Mongo
|
6
|
-
VERSION = "1.0.
|
6
|
+
VERSION = "1.0.4"
|
7
7
|
end
|
8
8
|
|
9
9
|
module Mongo
|
@@ -21,11 +21,18 @@ module Mongo
|
|
21
21
|
OP_DELETE = 2006
|
22
22
|
OP_KILL_CURSORS = 2007
|
23
23
|
|
24
|
-
OP_QUERY_TAILABLE = 2
|
25
|
-
OP_QUERY_SLAVE_OK =
|
26
|
-
|
24
|
+
OP_QUERY_TAILABLE = 2 ** 1
|
25
|
+
OP_QUERY_SLAVE_OK = 2 ** 2
|
26
|
+
OP_QUERY_OPLOG_REPLAY = 2 ** 3
|
27
|
+
OP_QUERY_NO_CURSOR_TIMEOUT = 2 ** 4
|
28
|
+
OP_QUERY_AWAIT_DATA = 2 ** 5
|
29
|
+
OP_QUERY_EXHAUST = 2 ** 6
|
30
|
+
|
31
|
+
REPLY_CURSOR_NOT_FOUND = 2 ** 0
|
32
|
+
REPLY_QUERY_FAILURE = 2 ** 1
|
33
|
+
REPLY_SHARD_CONFIG_STALE = 2 ** 2
|
34
|
+
REPLY_AWAIT_CAPABLE = 2 ** 3
|
27
35
|
end
|
28
|
-
|
29
36
|
end
|
30
37
|
|
31
38
|
require 'bson'
|
data/lib/mongo/collection.rb
CHANGED
@@ -157,7 +157,8 @@ module Mongo
|
|
157
157
|
raise RuntimeError, "Unknown options [#{opts.inspect}]" unless opts.empty?
|
158
158
|
|
159
159
|
cursor = Cursor.new(self, :selector => selector, :fields => fields, :skip => skip, :limit => limit,
|
160
|
-
|
160
|
+
:order => sort, :hint => hint, :snapshot => snapshot, :timeout => timeout, :batch_size => batch_size)
|
161
|
+
|
161
162
|
if block_given?
|
162
163
|
yield cursor
|
163
164
|
cursor.close()
|
@@ -470,6 +471,8 @@ module Mongo
|
|
470
471
|
# @option opts [String] :out (nil) the name of the output collection. If specified, the collection will not be treated as temporary.
|
471
472
|
# @option opts [Boolean] :keeptemp (false) if true, the generated collection will be persisted. default is false.
|
472
473
|
# @option opts [Boolean ] :verbose (false) if true, provides statistics on job execution time.
|
474
|
+
# @options opts [Boolean] :raw (false) if true, return the raw result object from the map_reduce command, and not
|
475
|
+
# the instantiated collection that's returned by default.
|
473
476
|
#
|
474
477
|
# @return [Collection] a collection containing the results of the operation.
|
475
478
|
#
|
@@ -477,8 +480,10 @@ module Mongo
|
|
477
480
|
#
|
478
481
|
# @core mapreduce map_reduce-instance_method
|
479
482
|
def map_reduce(map, reduce, opts={})
|
483
|
+
opts.assert_valid_keys(:query, :sort, :limit, :finalize, :keeptemp, :verbose, :raw)
|
480
484
|
map = BSON::Code.new(map) unless map.is_a?(BSON::Code)
|
481
485
|
reduce = BSON::Code.new(reduce) unless reduce.is_a?(BSON::Code)
|
486
|
+
raw = opts.delete(:raw)
|
482
487
|
|
483
488
|
hash = BSON::OrderedHash.new
|
484
489
|
hash['mapreduce'] = self.name
|
@@ -487,10 +492,15 @@ module Mongo
|
|
487
492
|
hash.merge! opts
|
488
493
|
|
489
494
|
result = @db.command(hash)
|
490
|
-
unless result
|
495
|
+
unless Mongo::Support.ok?(result)
|
491
496
|
raise Mongo::OperationFailure, "map-reduce failed: #{result['errmsg']}"
|
492
497
|
end
|
493
|
-
|
498
|
+
|
499
|
+
if raw
|
500
|
+
result
|
501
|
+
else
|
502
|
+
@db[result["result"]]
|
503
|
+
end
|
494
504
|
end
|
495
505
|
alias :mapreduce :map_reduce
|
496
506
|
|
data/lib/mongo/connection.rb
CHANGED
@@ -32,7 +32,7 @@ module Mongo
|
|
32
32
|
STANDARD_HEADER_SIZE = 16
|
33
33
|
RESPONSE_HEADER_SIZE = 20
|
34
34
|
|
35
|
-
MONGODB_URI_MATCHER = /(([.\w\d]+):([\w\d]+)@)?([-.\w\d]+)(:([\w\d]+))?(\/([-\d\w]+))?/
|
35
|
+
MONGODB_URI_MATCHER = /(([-_.\w\d]+):([-_\w\d]+)@)?([-.\w\d]+)(:([\w\d]+))?(\/([-\d\w]+))?/
|
36
36
|
MONGODB_URI_SPEC = "mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/database]"
|
37
37
|
|
38
38
|
attr_reader :logger, :size, :host, :port, :nodes, :auths, :sockets, :checked_out
|
@@ -97,7 +97,11 @@ module Mongo
|
|
97
97
|
|
98
98
|
# Mutex for synchronizing pool access
|
99
99
|
@connection_mutex = Mutex.new
|
100
|
-
|
100
|
+
|
101
|
+
|
102
|
+
# Create a mutex when a new key, in this case a socket,
|
103
|
+
# is added to the hash.
|
104
|
+
@safe_mutexes = Hash.new { |h, k| h[k] = Mutex.new }
|
101
105
|
|
102
106
|
# Condition variable for signal and wait
|
103
107
|
@queue = ConditionVariable.new
|
@@ -368,7 +372,7 @@ module Mongo
|
|
368
372
|
sock = checkout
|
369
373
|
packed_message = message_with_headers.append!(message_with_check).to_s
|
370
374
|
docs = num_received = cursor_id = ''
|
371
|
-
@
|
375
|
+
@safe_mutexes[sock].synchronize do
|
372
376
|
send_message_on_socket(packed_message, sock)
|
373
377
|
docs, num_received, cursor_id = receive(sock)
|
374
378
|
end
|
@@ -398,7 +402,7 @@ module Mongo
|
|
398
402
|
sock = socket || checkout
|
399
403
|
|
400
404
|
result = ''
|
401
|
-
@
|
405
|
+
@safe_mutexes[sock].synchronize do
|
402
406
|
send_message_on_socket(packed_message, sock)
|
403
407
|
result = receive(sock)
|
404
408
|
end
|
@@ -632,13 +636,22 @@ module Mongo
|
|
632
636
|
"expected #{RESPONSE_HEADER_SIZE} bytes, saw #{header_buf.length}"
|
633
637
|
end
|
634
638
|
header_buf.rewind
|
635
|
-
|
639
|
+
check_response_flags(header_buf.get_int)
|
636
640
|
cursor_id = header_buf.get_long
|
637
641
|
starting_from = header_buf.get_int
|
638
642
|
number_remaining = header_buf.get_int
|
639
643
|
[number_remaining, cursor_id]
|
640
644
|
end
|
641
645
|
|
646
|
+
def check_response_flags(flags)
|
647
|
+
if flags & Mongo::Constants::REPLY_CURSOR_NOT_FOUND != 0
|
648
|
+
raise Mongo::OperationFailure, "Query response returned CURSOR_NOT_FOUND. " +
|
649
|
+
"Either an invalid cursor was specified, or the cursor may have timed out on the server."
|
650
|
+
elsif flags & Mongo::Constants::REPLY_QUERY_FAILURE != 0
|
651
|
+
# Getting odd failures when a exception is raised here.
|
652
|
+
end
|
653
|
+
end
|
654
|
+
|
642
655
|
def read_documents(number_received, cursor_id, sock)
|
643
656
|
docs = []
|
644
657
|
number_remaining = number_received
|
@@ -696,7 +709,10 @@ module Mongo
|
|
696
709
|
# Requires a packed message and an available socket,
|
697
710
|
def send_message_on_socket(packed_message, socket)
|
698
711
|
begin
|
699
|
-
|
712
|
+
while packed_message.size > 0
|
713
|
+
byte_sent = socket.send(packed_message, 0)
|
714
|
+
packed_message.slice!(0, byte_sent)
|
715
|
+
end
|
700
716
|
rescue => ex
|
701
717
|
close
|
702
718
|
raise ConnectionFailure, "Operation failed with the following exception: #{ex}"
|
data/lib/mongo/cursor.rb
CHANGED
@@ -21,9 +21,9 @@ module Mongo
|
|
21
21
|
include Mongo::Conversions
|
22
22
|
include Enumerable
|
23
23
|
|
24
|
-
attr_reader :collection, :selector, :
|
24
|
+
attr_reader :collection, :selector, :fields,
|
25
25
|
:order, :hint, :snapshot, :timeout,
|
26
|
-
:full_collection_name
|
26
|
+
:full_collection_name, :batch_size
|
27
27
|
|
28
28
|
# Create a new cursor.
|
29
29
|
#
|
@@ -40,10 +40,6 @@ module Mongo
|
|
40
40
|
|
41
41
|
@selector = convert_selector_for_query(options[:selector])
|
42
42
|
@fields = convert_fields_for_query(options[:fields])
|
43
|
-
if options[:admin]
|
44
|
-
warn "The admin option to Cursor#new has been deprecated. The cursor should now be passed the admin collection explicitly."
|
45
|
-
end
|
46
|
-
@admin = options[:admin] || false
|
47
43
|
@skip = options[:skip] || 0
|
48
44
|
@limit = options[:limit] || 0
|
49
45
|
@order = options[:order]
|
@@ -237,7 +233,7 @@ module Mongo
|
|
237
233
|
message = BSON::ByteBuffer.new([0, 0, 0, 0])
|
238
234
|
message.put_int(1)
|
239
235
|
message.put_long(@cursor_id)
|
240
|
-
@connection.send_message(Mongo::Constants::OP_KILL_CURSORS, message, "cursor.close")
|
236
|
+
@connection.send_message(Mongo::Constants::OP_KILL_CURSORS, message, "cursor.close #{@cursor_id}")
|
241
237
|
end
|
242
238
|
@cursor_id = 0
|
243
239
|
@closed = true
|
@@ -255,10 +251,11 @@ module Mongo
|
|
255
251
|
# @see http://www.mongodb.org/display/DOCS/Mongo+Wire+Protocol#MongoWireProtocol-Mongo::Constants::OPQUERY
|
256
252
|
# The MongoDB wire protocol.
|
257
253
|
def query_opts
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
254
|
+
opts = 0
|
255
|
+
opts |= Mongo::Constants::OP_QUERY_NO_CURSOR_TIMEOUT unless @timeout
|
256
|
+
opts |= Mongo::Constants::OP_QUERY_SLAVE_OK if @connection.slave_ok?
|
257
|
+
opts |= Mongo::Constants::OP_QUERY_TAILABLE if @tailable
|
258
|
+
opts
|
262
259
|
end
|
263
260
|
|
264
261
|
# Get the query options for this Cursor.
|
@@ -275,6 +272,12 @@ module Mongo
|
|
275
272
|
:timeout => @timeout }
|
276
273
|
end
|
277
274
|
|
275
|
+
# Clean output for inspect.
|
276
|
+
def inspect
|
277
|
+
"<Mongo::Cursor:0x#{object_id.to_s(16)} namespace='#{@db.name}.#{@collection.name}' " +
|
278
|
+
"@selector=#{@selector.inspect}>"
|
279
|
+
end
|
280
|
+
|
278
281
|
private
|
279
282
|
|
280
283
|
# Convert the +:fields+ parameter from a single field name or an array
|
@@ -325,8 +328,7 @@ module Mongo
|
|
325
328
|
message = BSON::ByteBuffer.new([0, 0, 0, 0])
|
326
329
|
|
327
330
|
# DB name.
|
328
|
-
|
329
|
-
BSON::BSON_RUBY.serialize_cstr(message, "#{db_name}.#{@collection.name}")
|
331
|
+
BSON::BSON_RUBY.serialize_cstr(message, "#{@db.name}.#{@collection.name}")
|
330
332
|
|
331
333
|
# Number of results to return.
|
332
334
|
message.put_int(@batch_size)
|
@@ -356,8 +358,7 @@ module Mongo
|
|
356
358
|
def construct_query_message
|
357
359
|
message = BSON::ByteBuffer.new
|
358
360
|
message.put_int(query_opts)
|
359
|
-
|
360
|
-
BSON::BSON_RUBY.serialize_cstr(message, "#{db_name}.#{@collection.name}")
|
361
|
+
BSON::BSON_RUBY.serialize_cstr(message, "#{@db.name}.#{@collection.name}")
|
361
362
|
message.put_int(@skip)
|
362
363
|
message.put_int(@limit)
|
363
364
|
spec = query_contains_special_fields? ? construct_query_spec : @selector
|
@@ -367,7 +368,7 @@ module Mongo
|
|
367
368
|
end
|
368
369
|
|
369
370
|
def query_log_message
|
370
|
-
"#{@
|
371
|
+
"#{@db.name}['#{@collection.name}'].find(#{@selector.inspect}, #{@fields ? @fields.inspect : '{}'})" +
|
371
372
|
"#{@skip != 0 ? ('.skip(' + @skip.to_s + ')') : ''}#{@limit != 0 ? ('.limit(' + @limit.to_s + ')') : ''}" +
|
372
373
|
"#{@order ? ('.sort(' + @order.inspect + ')') : ''}"
|
373
374
|
end
|
data/lib/mongo/db.rb
CHANGED
@@ -29,6 +29,7 @@ module Mongo
|
|
29
29
|
SYSTEM_INDEX_COLLECTION = "system.indexes"
|
30
30
|
SYSTEM_PROFILE_COLLECTION = "system.profile"
|
31
31
|
SYSTEM_USER_COLLECTION = "system.users"
|
32
|
+
SYSTEM_JS_COLLECTION = "system.js"
|
32
33
|
SYSTEM_COMMAND_COLLECTION = "$cmd"
|
33
34
|
|
34
35
|
# Counter for generating unique request ids.
|
@@ -106,6 +107,36 @@ module Mongo
|
|
106
107
|
end
|
107
108
|
end
|
108
109
|
|
110
|
+
# Adds a stored Javascript function to the database which can executed
|
111
|
+
# server-side in map_reduce, db.eval and $where clauses.
|
112
|
+
#
|
113
|
+
# @param [String] function_name
|
114
|
+
# @param [String] code
|
115
|
+
#
|
116
|
+
# @return [String] the function name saved to the database
|
117
|
+
def add_stored_function(function_name, code)
|
118
|
+
self[SYSTEM_JS_COLLECTION].save(
|
119
|
+
{
|
120
|
+
"_id" => function_name,
|
121
|
+
:value => BSON::Code.new(code)
|
122
|
+
}
|
123
|
+
)
|
124
|
+
end
|
125
|
+
|
126
|
+
# Removes stored Javascript function from the database. Returns
|
127
|
+
# false if the function does not exist
|
128
|
+
#
|
129
|
+
# @param [String] function_name
|
130
|
+
#
|
131
|
+
# @return [Boolean]
|
132
|
+
def remove_stored_function(function_name)
|
133
|
+
if self[SYSTEM_JS_COLLECTION].find_one({"_id" => function_name})
|
134
|
+
self[SYSTEM_JS_COLLECTION].remove({"_id" => function_name}, :safe => true)
|
135
|
+
else
|
136
|
+
return false
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
109
140
|
# Adds a user to this database for use with authentication. If the user already
|
110
141
|
# exists in the system, the password will be updated.
|
111
142
|
#
|
@@ -238,7 +269,7 @@ module Mongo
|
|
238
269
|
#
|
239
270
|
# @param [String] name
|
240
271
|
#
|
241
|
-
# @return [Boolean]
|
272
|
+
# @return [Boolean] +true+ on success or +false+ if the collection name doesn't exist.
|
242
273
|
def drop_collection(name)
|
243
274
|
return true unless collection_names.include?(name)
|
244
275
|
|
@@ -304,17 +335,6 @@ module Mongo
|
|
304
335
|
command(:reseterror => 1)
|
305
336
|
end
|
306
337
|
|
307
|
-
# @deprecated please use Collection#find to create queries.
|
308
|
-
#
|
309
|
-
# Returns a Cursor over the query results.
|
310
|
-
#
|
311
|
-
# Note that the query gets sent lazily; the cursor calls
|
312
|
-
# Connection#send_message when needed. If the caller never requests an
|
313
|
-
# object from the cursor, the query never gets sent.
|
314
|
-
def query(collection, query, admin=false)
|
315
|
-
Cursor.new(self, collection, query, admin)
|
316
|
-
end
|
317
|
-
|
318
338
|
# Dereference a DBRef, returning the document it points to.
|
319
339
|
#
|
320
340
|
# @param [Mongo::DBRef] dbref
|
@@ -375,7 +395,7 @@ module Mongo
|
|
375
395
|
oh = BSON::OrderedHash.new
|
376
396
|
oh[:deleteIndexes] = collection_name
|
377
397
|
oh[:index] = index_name
|
378
|
-
doc = command(oh)
|
398
|
+
doc = command(oh, :check_response => false)
|
379
399
|
ok?(doc) || raise(MongoDBError, "Error with drop_index command: #{doc.inspect}")
|
380
400
|
end
|
381
401
|
|
@@ -403,23 +423,6 @@ module Mongo
|
|
403
423
|
self.command({:dbstats => 1})
|
404
424
|
end
|
405
425
|
|
406
|
-
# Create a new index on the given collection.
|
407
|
-
# Normally called by Collection#create_index.
|
408
|
-
#
|
409
|
-
# @param [String] collection_name
|
410
|
-
# @param [String, Array] field_or_spec either either a single field name
|
411
|
-
# or an array of [field name, direction] pairs. Directions should be specified as
|
412
|
-
# Mongo::ASCENDING or Mongo::DESCENDING.
|
413
|
-
# @param [Boolean] unique if +true+, the created index will enforce a uniqueness constraint.
|
414
|
-
#
|
415
|
-
# @return [String] the name of the index created.
|
416
|
-
#
|
417
|
-
# @deprecated
|
418
|
-
def create_index(collection_name, field_or_spec, unique=false)
|
419
|
-
warn "DB#create_index is now deprecated. Please use Collection#create_index instead."
|
420
|
-
self.collection(collection_name).create_index(field_or_spec, :unique => unique)
|
421
|
-
end
|
422
|
-
|
423
426
|
# Return +true+ if the supplied +doc+ contains an 'ok' field with the value 1.
|
424
427
|
#
|
425
428
|
# @param [Hash] doc
|
@@ -453,24 +456,19 @@ module Mongo
|
|
453
456
|
#
|
454
457
|
# @core commands command_instance-method
|
455
458
|
def command(selector, opts={}, old_check_response=false, old_sock=nil)
|
456
|
-
|
457
|
-
|
458
|
-
sock = opts[:sock]
|
459
|
-
else
|
460
|
-
warn "The options passed to DB#command should now be passed as hash keys; the admin option has been deprecated."
|
461
|
-
admin = opts
|
462
|
-
check_response = old_check_response
|
463
|
-
sock = old_sock
|
464
|
-
end
|
459
|
+
check_response = opts[:check_response].nil? ? true : opts[:check_response]
|
460
|
+
sock = opts[:sock]
|
465
461
|
raise MongoArgumentError, "command must be given a selector" unless selector.is_a?(Hash) && !selector.empty?
|
466
462
|
if selector.keys.length > 1 && RUBY_VERSION < '1.9' && selector.class != BSON::OrderedHash
|
467
463
|
raise MongoArgumentError, "DB#command requires an OrderedHash when hash contains multiple keys"
|
468
464
|
end
|
469
465
|
|
470
|
-
result = Cursor.new(system_command_collection,
|
466
|
+
result = Cursor.new(system_command_collection,
|
471
467
|
:limit => -1, :selector => selector, :socket => sock).next_document
|
472
468
|
|
473
|
-
if result.nil?
|
469
|
+
if result.nil?
|
470
|
+
raise OperationFailure, "Database command '#{selector.keys.first}' failed: returned null."
|
471
|
+
elsif (check_response && !ok?(result))
|
474
472
|
raise OperationFailure, "Database command '#{selector.keys.first}' failed: #{result.inspect}"
|
475
473
|
else
|
476
474
|
result
|
data/lib/mongo/gridfs/grid.rb
CHANGED
@@ -41,10 +41,11 @@ module Mongo
|
|
41
41
|
@chunks.create_index([['files_id', Mongo::ASCENDING], ['n', Mongo::ASCENDING]], :unique => true)
|
42
42
|
end
|
43
43
|
|
44
|
-
# Store a file in the file store.
|
44
|
+
# Store a file in the file store. This method is designed only for writing new files;
|
45
|
+
# if you need to update a given file, first delete it using #Grid#delete.
|
45
46
|
#
|
46
47
|
# Note that arbitary metadata attributes can be saved to the file by passing
|
47
|
-
# them
|
48
|
+
# them in as options.
|
48
49
|
#
|
49
50
|
# @param [String, #read] data a string or io-like object to store.
|
50
51
|
#
|
data/lib/mongo/gridfs/grid_io.rb
CHANGED
@@ -315,11 +315,18 @@ module Mongo
|
|
315
315
|
@aliases = opts.delete(:aliases) if opts[:aliases]
|
316
316
|
@file_length = 0
|
317
317
|
opts.each {|k, v| self[k] = v}
|
318
|
+
check_existing_file if @safe
|
318
319
|
|
319
320
|
@current_chunk = create_chunk(0)
|
320
321
|
@file_position = 0
|
321
322
|
end
|
322
323
|
|
324
|
+
def check_existing_file
|
325
|
+
if @files.find_one('_id' => @files_id)
|
326
|
+
raise GridError, "Attempting to overwrite with Grid#put. You must delete the file first."
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
323
330
|
def to_mongo_object
|
324
331
|
h = BSON::OrderedHash.new
|
325
332
|
h['_id'] = @files_id
|
data/test/collection_test.rb
CHANGED
@@ -393,7 +393,7 @@ class TestCollection < Test::Unit::TestCase
|
|
393
393
|
assert c.closed?
|
394
394
|
end
|
395
395
|
|
396
|
-
if @@version
|
396
|
+
if @@version > "1.1.1"
|
397
397
|
def test_map_reduce
|
398
398
|
@@test << { "user_id" => 1 }
|
399
399
|
@@test << { "user_id" => 2 }
|
@@ -429,6 +429,23 @@ class TestCollection < Test::Unit::TestCase
|
|
429
429
|
assert res.find_one({"_id" => 2})
|
430
430
|
assert res.find_one({"_id" => 3})
|
431
431
|
end
|
432
|
+
|
433
|
+
def test_map_reduce_with_raw_response
|
434
|
+
m = Code.new("function() { emit(this.user_id, 1); }")
|
435
|
+
r = Code.new("function(k,vals) { return 1; }")
|
436
|
+
res = @@test.map_reduce(m, r, :raw => true)
|
437
|
+
assert res["result"]
|
438
|
+
assert res["counts"]
|
439
|
+
assert res["timeMillis"]
|
440
|
+
end
|
441
|
+
|
442
|
+
def test_allows_only_valid_keys
|
443
|
+
m = Code.new("function() { emit(this.user_id, 1); }")
|
444
|
+
r = Code.new("function(k,vals) { return 1; }")
|
445
|
+
assert_raise ArgumentError do
|
446
|
+
@@test.map_reduce(m, r, :foo => true)
|
447
|
+
end
|
448
|
+
end
|
432
449
|
end
|
433
450
|
|
434
451
|
if @@version > "1.3.0"
|
@@ -686,7 +703,7 @@ class TestCollection < Test::Unit::TestCase
|
|
686
703
|
assert_nil cursor.next_document
|
687
704
|
end
|
688
705
|
|
689
|
-
should "" do
|
706
|
+
should "fail tailable cursor on a non-capped collection" do
|
690
707
|
col = @@db['regular-collection']
|
691
708
|
col.insert({:a => 1000})
|
692
709
|
tail = Cursor.new(col, :tailable => true, :order => [['$natural', 1]])
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'test/test_helper'
|
2
|
+
require 'logger'
|
3
|
+
|
4
|
+
class CursorTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
include Mongo
|
7
|
+
|
8
|
+
@@connection = Connection.new(ENV['MONGO_RUBY_DRIVER_HOST'] || 'localhost',
|
9
|
+
ENV['MONGO_RUBY_DRIVER_PORT'] || Connection::DEFAULT_PORT)
|
10
|
+
@@db = @@connection.db(MONGO_TEST_DB)
|
11
|
+
@@coll = @@db.collection('test')
|
12
|
+
@@version = @@connection.server_version
|
13
|
+
|
14
|
+
def setup
|
15
|
+
@@coll.remove
|
16
|
+
@@coll.insert('a' => 1) # collection not created until it's used
|
17
|
+
@@coll_full_name = "#{MONGO_TEST_DB}.test"
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_refill_via_get_more
|
21
|
+
assert_equal 1, @@coll.count
|
22
|
+
1000.times { |i|
|
23
|
+
assert_equal 1 + i, @@coll.count
|
24
|
+
@@coll.insert('a' => i)
|
25
|
+
}
|
26
|
+
|
27
|
+
assert_equal 1001, @@coll.count
|
28
|
+
count = 0
|
29
|
+
@@coll.find.each { |obj|
|
30
|
+
count += obj['a']
|
31
|
+
}
|
32
|
+
assert_equal 1001, @@coll.count
|
33
|
+
|
34
|
+
# do the same thing again for debugging
|
35
|
+
assert_equal 1001, @@coll.count
|
36
|
+
count2 = 0
|
37
|
+
@@coll.find.each { |obj|
|
38
|
+
count2 += obj['a']
|
39
|
+
}
|
40
|
+
assert_equal 1001, @@coll.count
|
41
|
+
|
42
|
+
assert_equal count, count2
|
43
|
+
assert_equal 499501, count
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_refill_via_get_more_alt_coll
|
47
|
+
coll = @@db.collection('test-alt-coll')
|
48
|
+
coll.remove
|
49
|
+
coll.insert('a' => 1) # collection not created until it's used
|
50
|
+
assert_equal 1, coll.count
|
51
|
+
|
52
|
+
1000.times { |i|
|
53
|
+
assert_equal 1 + i, coll.count
|
54
|
+
coll.insert('a' => i)
|
55
|
+
}
|
56
|
+
|
57
|
+
assert_equal 1001, coll.count
|
58
|
+
count = 0
|
59
|
+
coll.find.each { |obj|
|
60
|
+
count += obj['a']
|
61
|
+
}
|
62
|
+
assert_equal 1001, coll.count
|
63
|
+
|
64
|
+
# do the same thing again for debugging
|
65
|
+
assert_equal 1001, coll.count
|
66
|
+
count2 = 0
|
67
|
+
coll.find.each { |obj|
|
68
|
+
count2 += obj['a']
|
69
|
+
}
|
70
|
+
assert_equal 1001, coll.count
|
71
|
+
|
72
|
+
assert_equal count, count2
|
73
|
+
assert_equal 499501, count
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'test/test_helper'
|
2
|
+
require 'logger'
|
3
|
+
|
4
|
+
class CursorTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
include Mongo
|
7
|
+
|
8
|
+
@@connection = Connection.new(ENV['MONGO_RUBY_DRIVER_HOST'] || 'localhost',
|
9
|
+
ENV['MONGO_RUBY_DRIVER_PORT'] || Connection::DEFAULT_PORT)
|
10
|
+
@@db = @@connection.db(MONGO_TEST_DB)
|
11
|
+
@@coll = @@db.collection('test')
|
12
|
+
@@version = @@connection.server_version
|
13
|
+
|
14
|
+
def setup
|
15
|
+
@@coll.remove
|
16
|
+
@@coll.insert('a' => 1) # collection not created until it's used
|
17
|
+
@@coll_full_name = "#{MONGO_TEST_DB}.test"
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_cursor_invalid
|
21
|
+
100.times do |n|
|
22
|
+
@@coll.insert({:a => "HELLO" * 50000})
|
23
|
+
end
|
24
|
+
|
25
|
+
cursor = @@coll.find({}, :batch_size => 50)
|
26
|
+
cursor.next_document
|
27
|
+
p @@db.command("cursorInfo" => 1)
|
28
|
+
cursor.close
|
29
|
+
p @@db.command("cursorInfo" => 1)
|
30
|
+
cursor.next_document
|
31
|
+
end
|
32
|
+
end
|
data/test/cursor_test.rb
CHANGED
@@ -17,6 +17,13 @@ class CursorTest < Test::Unit::TestCase
|
|
17
17
|
@@coll_full_name = "#{MONGO_TEST_DB}.test"
|
18
18
|
end
|
19
19
|
|
20
|
+
def test_inspect
|
21
|
+
selector = {:a => 1}
|
22
|
+
cursor = @@coll.find(selector)
|
23
|
+
assert_equal "<Mongo::Cursor:0x#{cursor.object_id.to_s(16)} namespace='#{@@db.name}.#{@@coll.name}' " +
|
24
|
+
"@selector=#{selector.inspect}>", cursor.inspect
|
25
|
+
end
|
26
|
+
|
20
27
|
def test_explain
|
21
28
|
cursor = @@coll.find('a' => 1)
|
22
29
|
explaination = cursor.explain
|
@@ -130,7 +137,7 @@ class CursorTest < Test::Unit::TestCase
|
|
130
137
|
@@coll.save({:t => 't2'})
|
131
138
|
@@coll.save({:t => 't2'})
|
132
139
|
|
133
|
-
assert_equal 3, @@coll.find({'_id' => {'$gt' => t1_id
|
140
|
+
assert_equal 3, @@coll.find({'_id' => {'$gt' => t1_id, '$lt' => t2_id}}).count
|
134
141
|
@@coll.find({'_id' => {'$gt' => t2_id}}).each do |doc|
|
135
142
|
assert_equal 't2', doc['t']
|
136
143
|
end
|
@@ -389,4 +396,21 @@ class CursorTest < Test::Unit::TestCase
|
|
389
396
|
|
390
397
|
assert_equal false, cursor.has_next?
|
391
398
|
end
|
399
|
+
|
400
|
+
def test_cursor_invalid
|
401
|
+
@@coll.remove
|
402
|
+
1000.times do |n|
|
403
|
+
@@coll.insert({:a => n})
|
404
|
+
end
|
405
|
+
|
406
|
+
cursor = @@coll.find({})
|
407
|
+
cursor.next_document
|
408
|
+
cursor.close
|
409
|
+
|
410
|
+
assert_raise_error(Mongo::OperationFailure, "CURSOR_NOT_FOUND") do
|
411
|
+
999.times do
|
412
|
+
cursor.next_document
|
413
|
+
end
|
414
|
+
end
|
415
|
+
end
|
392
416
|
end
|
data/test/db_api_test.rb
CHANGED
@@ -289,7 +289,7 @@ class DBAPITest < Test::Unit::TestCase
|
|
289
289
|
def test_index_create_with_symbol
|
290
290
|
assert_equal @@coll.index_information.length, 1
|
291
291
|
|
292
|
-
name = @@
|
292
|
+
name = @@coll.create_index([['a', 1]])
|
293
293
|
info = @@db.index_information(@@coll.name)
|
294
294
|
assert_equal name, "a_1"
|
295
295
|
assert_equal @@coll.index_information, info
|
data/test/db_test.rb
CHANGED
@@ -230,7 +230,7 @@ class DBTest < Test::Unit::TestCase
|
|
230
230
|
def test_text_port_number_raises_no_errors
|
231
231
|
conn = Connection.new(@@host, @@port.to_s)
|
232
232
|
db = conn[MONGO_TEST_DB]
|
233
|
-
|
233
|
+
db.collection('users').remove
|
234
234
|
end
|
235
235
|
|
236
236
|
def test_user_management
|
@@ -247,6 +247,14 @@ class DBTest < Test::Unit::TestCase
|
|
247
247
|
assert !@@db.remove_user("joe")
|
248
248
|
end
|
249
249
|
|
250
|
+
def test_stored_function_management
|
251
|
+
@@db.add_stored_function("sum", "function (x, y) { return x + y; }")
|
252
|
+
assert_equal @@db.eval("return sum(2,3);"), 5
|
253
|
+
assert @@db.remove_stored_function("sum")
|
254
|
+
assert_raise OperationFailure do
|
255
|
+
@@db.eval("return sum(2,3);")
|
256
|
+
end
|
257
|
+
end
|
250
258
|
|
251
259
|
if @@version >= "1.3.5"
|
252
260
|
def test_db_stats
|
data/test/grid_io_test.rb
CHANGED
@@ -52,9 +52,7 @@ class GridIOTest < Test::Unit::TestCase
|
|
52
52
|
|
53
53
|
should "raise an exception when check fails" do
|
54
54
|
io = File.open(File.join(File.dirname(__FILE__), 'data', 'sample_file.pdf'), 'r')
|
55
|
-
db
|
56
|
-
db.stubs(:command).returns({'md5' => '12345'})
|
57
|
-
@files.expects(:db).returns(db)
|
55
|
+
@db.stubs(:command).returns({'md5' => '12345'})
|
58
56
|
file = GridIO.new(@files, @chunks, 'bigfile', 'w', :safe => true)
|
59
57
|
file.write(io)
|
60
58
|
assert_raise GridMD5Failure do
|
data/test/grid_test.rb
CHANGED
@@ -27,6 +27,12 @@ class GridTest < Test::Unit::TestCase
|
|
27
27
|
assert_equal 'sample', file['filename']
|
28
28
|
end
|
29
29
|
|
30
|
+
should "not be able to overwrite an exising file" do
|
31
|
+
assert_raise GridError do
|
32
|
+
@grid.put(@data, :filename => 'sample', :_id => @id, :safe => true)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
30
36
|
should "return nil if it doesn't exist" do
|
31
37
|
assert_nil @grid.exist?(:metadata => 'foo')
|
32
38
|
end
|
@@ -88,6 +88,13 @@ class ConnectionTest < Test::Unit::TestCase
|
|
88
88
|
assert_equal auth_hash, @conn.auths[1]
|
89
89
|
end
|
90
90
|
|
91
|
+
should "parse a uri with a hyphen & underscore in the username or password" do
|
92
|
+
@conn = Connection.from_uri("mongodb://hyphen-user_name:p-s_s@localhost:27017/db", :connect => false)
|
93
|
+
assert_equal ['localhost', 27017], @conn.nodes[0]
|
94
|
+
auth_hash = { 'db_name' => 'db', 'username' => 'hyphen-user_name', "password" => 'p-s_s' }
|
95
|
+
assert_equal auth_hash, @conn.auths[0]
|
96
|
+
end
|
97
|
+
|
91
98
|
should "attempt to connect" do
|
92
99
|
TCPSocket.stubs(:new).returns(new_mock_socket)
|
93
100
|
@conn = Connection.from_uri("mongodb://localhost", :connect => false)
|
data/test/unit/cursor_test.rb
CHANGED
@@ -9,13 +9,6 @@ class CursorTest < Test::Unit::TestCase
|
|
9
9
|
@cursor = Cursor.new(@collection)
|
10
10
|
end
|
11
11
|
|
12
|
-
should "set admin to false" do
|
13
|
-
assert_equal false, @cursor.admin
|
14
|
-
|
15
|
-
@cursor = Cursor.new(@collection, :admin => true)
|
16
|
-
assert_equal true, @cursor.admin
|
17
|
-
end
|
18
|
-
|
19
12
|
should "set selector" do
|
20
13
|
assert @cursor.selector == {}
|
21
14
|
|
data/test/unit/db_test.rb
CHANGED
@@ -31,25 +31,25 @@ class DBTest < Test::Unit::TestCase
|
|
31
31
|
|
32
32
|
should "raise an error if the selector is omitted" do
|
33
33
|
assert_raise MongoArgumentError do
|
34
|
-
@db.command({}, true)
|
34
|
+
@db.command({}, :check_response => true)
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
38
|
should "create the proper cursor" do
|
39
39
|
@cursor = mock(:next_document => {"ok" => 1})
|
40
|
-
Cursor.expects(:new).with(@collection,
|
40
|
+
Cursor.expects(:new).with(@collection,
|
41
41
|
:limit => -1, :selector => {:buildinfo => 1}, :socket => nil).returns(@cursor)
|
42
42
|
command = {:buildinfo => 1}
|
43
|
-
@db.command(command, true)
|
43
|
+
@db.command(command, :check_response => true)
|
44
44
|
end
|
45
45
|
|
46
46
|
should "raise an error when the command fails" do
|
47
47
|
@cursor = mock(:next_document => {"ok" => 0})
|
48
|
-
Cursor.expects(:new).with(@collection,
|
48
|
+
Cursor.expects(:new).with(@collection,
|
49
49
|
:limit => -1, :selector => {:buildinfo => 1}, :socket => nil).returns(@cursor)
|
50
50
|
assert_raise OperationFailure do
|
51
51
|
command = {:buildinfo => 1}
|
52
|
-
@db.command(command,
|
52
|
+
@db.command(command, :check_response => true)
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 1
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: 1.0.
|
8
|
+
- 4
|
9
|
+
version: 1.0.4
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Jim Menard
|
@@ -16,7 +16,7 @@ autorequire:
|
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
18
|
|
19
|
-
date: 2010-
|
19
|
+
date: 2010-07-13 00:00:00 -04:00
|
20
20
|
default_executable:
|
21
21
|
dependencies:
|
22
22
|
- !ruby/object:Gem::Dependency
|
@@ -29,8 +29,8 @@ dependencies:
|
|
29
29
|
segments:
|
30
30
|
- 1
|
31
31
|
- 0
|
32
|
-
-
|
33
|
-
version: 1.0.
|
32
|
+
- 4
|
33
|
+
version: 1.0.4
|
34
34
|
type: :runtime
|
35
35
|
version_requirements: *id001
|
36
36
|
description: A Ruby driver for MongoDB. For more information about Mongo, see http://www.mongodb.org.
|
@@ -112,6 +112,8 @@ test_files:
|
|
112
112
|
- test/collection_test.rb
|
113
113
|
- test/connection_test.rb
|
114
114
|
- test/conversions_test.rb
|
115
|
+
- test/cursor_fail_test.rb
|
116
|
+
- test/cursor_message_test.rb
|
115
117
|
- test/cursor_test.rb
|
116
118
|
- test/db_api_test.rb
|
117
119
|
- test/db_connection_test.rb
|