mongo 1.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/mongo.rb +4 -1
- data/lib/mongo/collection.rb +36 -21
- data/lib/mongo/connection.rb +24 -7
- data/lib/mongo/cursor.rb +11 -5
- data/lib/mongo/db.rb +21 -11
- data/lib/mongo/exceptions.rb +3 -0
- data/lib/mongo/gridfs/grid.rb +10 -6
- data/lib/mongo/gridfs/grid_ext.rb +36 -9
- data/lib/mongo/gridfs/grid_file_system.rb +10 -7
- data/lib/mongo/gridfs/grid_io.rb +10 -8
- data/lib/mongo/util/conversions.rb +3 -1
- data/lib/mongo/util/core_ext.rb +2 -0
- data/lib/mongo/util/server_version.rb +2 -0
- data/lib/mongo/util/support.rb +2 -0
- data/test/auxillary/1.4_features.rb +1 -1
- data/test/collection_test.rb +45 -2
- data/test/connection_test.rb +0 -1
- data/test/cursor_test.rb +0 -1
- data/test/db_api_test.rb +15 -6
- data/test/db_connection_test.rb +0 -1
- data/test/db_test.rb +18 -1
- data/test/grid_file_system_test.rb +9 -0
- data/test/grid_test.rb +9 -0
- data/test/test_helper.rb +9 -1
- metadata +10 -19
data/lib/mongo.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
1
3
|
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
4
|
|
3
5
|
module Mongo
|
4
|
-
VERSION = "1.0"
|
6
|
+
VERSION = "1.0.1"
|
5
7
|
end
|
6
8
|
|
7
9
|
module Mongo
|
@@ -40,6 +42,7 @@ require 'mongo/connection'
|
|
40
42
|
require 'mongo/cursor'
|
41
43
|
require 'mongo/db'
|
42
44
|
require 'mongo/exceptions'
|
45
|
+
require 'mongo/gridfs/grid_ext'
|
43
46
|
require 'mongo/gridfs/grid'
|
44
47
|
require 'mongo/gridfs/grid_io'
|
45
48
|
require 'mongo/gridfs/grid_file_system'
|
data/lib/mongo/collection.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
1
3
|
# --
|
2
4
|
# Copyright (C) 2008-2010 10gen Inc.
|
3
5
|
#
|
@@ -203,17 +205,22 @@ module Mongo
|
|
203
205
|
#
|
204
206
|
# @return [ObjectID] the _id of the saved document.
|
205
207
|
#
|
206
|
-
# @option opts [Boolean] :safe (+false+)
|
207
|
-
#
|
208
|
-
#
|
209
|
-
#
|
210
|
-
|
208
|
+
# @option opts [Boolean, Hash] :safe (+false+)
|
209
|
+
# run the operation in safe mode, which run a getlasterror command on the
|
210
|
+
# database to report any assertion. In addition, a hash can be provided to
|
211
|
+
# run an fsync and/or wait for replication of the save (>= 1.5.1). See the options
|
212
|
+
# for DB#error.
|
213
|
+
#
|
214
|
+
# @raise [OperationFailure] when :safe mode fails.
|
215
|
+
#
|
216
|
+
# @see DB#remove for options that can be passed to :safe.
|
217
|
+
def save(doc, opts={})
|
211
218
|
if doc.has_key?(:_id) || doc.has_key?('_id')
|
212
219
|
id = doc[:_id] || doc['_id']
|
213
|
-
update({:_id => id}, doc, :upsert => true, :safe =>
|
220
|
+
update({:_id => id}, doc, :upsert => true, :safe => opts[:safe])
|
214
221
|
id
|
215
222
|
else
|
216
|
-
insert(doc, :safe =>
|
223
|
+
insert(doc, :safe => opts[:safe])
|
217
224
|
end
|
218
225
|
end
|
219
226
|
|
@@ -226,10 +233,13 @@ module Mongo
|
|
226
233
|
# the _id of the inserted document or a list of _ids of all inserted documents.
|
227
234
|
# Note: the object may have been modified by the database's PK factory, if it has one.
|
228
235
|
#
|
229
|
-
# @option opts [Boolean] :safe (+false+)
|
230
|
-
#
|
231
|
-
#
|
232
|
-
#
|
236
|
+
# @option opts [Boolean, Hash] :safe (+false+)
|
237
|
+
# run the operation in safe mode, which run a getlasterror command on the
|
238
|
+
# database to report any assertion. In addition, a hash can be provided to
|
239
|
+
# run an fsync and/or wait for replication of the insert (>= 1.5.1). See the options
|
240
|
+
# for DB#error.
|
241
|
+
#
|
242
|
+
# @see DB#remove for options that can be passed to :safe.
|
233
243
|
#
|
234
244
|
# @core insert insert-instance_method
|
235
245
|
def insert(doc_or_docs, options={})
|
@@ -245,8 +255,11 @@ module Mongo
|
|
245
255
|
# @param [Hash] selector
|
246
256
|
# If specified, only matching documents will be removed.
|
247
257
|
#
|
248
|
-
# @option opts [Boolean] :safe
|
249
|
-
#
|
258
|
+
# @option opts [Boolean, Hash] :safe (+false+)
|
259
|
+
# run the operation in safe mode, which run a getlasterror command on the
|
260
|
+
# database to report any assertion. In addition, a hash can be provided to
|
261
|
+
# run an fsync and/or wait for replication of the remove (>= 1.5.1). See the options
|
262
|
+
# for DB#error.
|
250
263
|
#
|
251
264
|
# @example remove all documents from the 'users' collection:
|
252
265
|
# users.remove
|
@@ -260,6 +273,8 @@ module Mongo
|
|
260
273
|
# @raise [Mongo::OperationFailure] an exception will be raised iff safe mode is enabled
|
261
274
|
# and the operation fails.
|
262
275
|
#
|
276
|
+
# @see DB#remove for options that can be passed to :safe.
|
277
|
+
#
|
263
278
|
# @core remove remove-instance_method
|
264
279
|
def remove(selector={}, opts={})
|
265
280
|
# Initial byte is 0.
|
@@ -270,7 +285,7 @@ module Mongo
|
|
270
285
|
|
271
286
|
if opts[:safe]
|
272
287
|
@connection.send_message_with_safe_check(Mongo::Constants::OP_DELETE, message, @db.name,
|
273
|
-
"#{@db.name}['#{@name}'].remove(#{selector.inspect})")
|
288
|
+
"#{@db.name}['#{@name}'].remove(#{selector.inspect})", opts[:safe])
|
274
289
|
# the return value of send_message_with_safe_check isn't actually meaningful --
|
275
290
|
# only the fact that it didn't raise an error is -- so just return true
|
276
291
|
true
|
@@ -312,7 +327,7 @@ module Mongo
|
|
312
327
|
message.put_array(BSON::BSON_CODER.serialize(document, false, true).to_a)
|
313
328
|
if options[:safe]
|
314
329
|
@connection.send_message_with_safe_check(Mongo::Constants::OP_UPDATE, message, @db.name,
|
315
|
-
"#{@db.name}['#{@name}'].update(#{selector.inspect}, #{document.inspect})")
|
330
|
+
"#{@db.name}['#{@name}'].update(#{selector.inspect}, #{document.inspect})", options[:safe])
|
316
331
|
else
|
317
332
|
@connection.send_message(Mongo::Constants::OP_UPDATE, message,
|
318
333
|
"#{@db.name}['#{@name}'].update(#{selector.inspect}, #{document.inspect})")
|
@@ -360,7 +375,7 @@ module Mongo
|
|
360
375
|
# @core indexes create_index-instance_method
|
361
376
|
def create_index(spec, opts={})
|
362
377
|
opts.assert_valid_keys(:min, :max, :background, :unique, :dropDups)
|
363
|
-
field_spec = OrderedHash.new
|
378
|
+
field_spec = BSON::OrderedHash.new
|
364
379
|
if spec.is_a?(String) || spec.is_a?(Symbol)
|
365
380
|
field_spec[spec.to_s] = 1
|
366
381
|
elsif spec.is_a?(Array) && spec.all? {|field| field.is_a?(Array) }
|
@@ -432,7 +447,7 @@ module Mongo
|
|
432
447
|
#
|
433
448
|
# @core findandmodify find_and_modify-instance_method
|
434
449
|
def find_and_modify(opts={})
|
435
|
-
cmd = OrderedHash.new
|
450
|
+
cmd = BSON::OrderedHash.new
|
436
451
|
cmd[:findandmodify] = @name
|
437
452
|
cmd.merge!(opts)
|
438
453
|
cmd[:sort] = Mongo::Support.format_order_clause(opts[:sort]) if opts[:sort]
|
@@ -465,7 +480,7 @@ module Mongo
|
|
465
480
|
map = BSON::Code.new(map) unless map.is_a?(BSON::Code)
|
466
481
|
reduce = BSON::Code.new(reduce) unless reduce.is_a?(BSON::Code)
|
467
482
|
|
468
|
-
hash = OrderedHash.new
|
483
|
+
hash = BSON::OrderedHash.new
|
469
484
|
hash['mapreduce'] = self.name
|
470
485
|
hash['map'] = map
|
471
486
|
hash['reduce'] = reduce
|
@@ -557,7 +572,7 @@ module Mongo
|
|
557
572
|
# @return [Array] an array of distinct values.
|
558
573
|
def distinct(key, query=nil)
|
559
574
|
raise MongoArgumentError unless [String, Symbol].include?(key.class)
|
560
|
-
command = OrderedHash.new
|
575
|
+
command = BSON::OrderedHash.new
|
561
576
|
command[:distinct] = @name
|
562
577
|
command[:key] = key.to_s
|
563
578
|
command[:query] = query
|
@@ -639,7 +654,7 @@ module Mongo
|
|
639
654
|
when nil
|
640
655
|
nil
|
641
656
|
else
|
642
|
-
h = OrderedHash.new
|
657
|
+
h = BSON::OrderedHash.new
|
643
658
|
hint.to_a.each { |k| h[k] = 1 }
|
644
659
|
h
|
645
660
|
end
|
@@ -657,7 +672,7 @@ module Mongo
|
|
657
672
|
documents.each { |doc| message.put_array(BSON::BSON_CODER.serialize(doc, check_keys, true).to_a) }
|
658
673
|
if safe
|
659
674
|
@connection.send_message_with_safe_check(Mongo::Constants::OP_INSERT, message, @db.name,
|
660
|
-
"#{@db.name}['#{collection_name}'].insert(#{documents.inspect})")
|
675
|
+
"#{@db.name}['#{collection_name}'].insert(#{documents.inspect})", safe)
|
661
676
|
else
|
662
677
|
@connection.send_message(Mongo::Constants::OP_INSERT, message,
|
663
678
|
"#{@db.name}['#{collection_name}'].insert(#{documents.inspect})")
|
data/lib/mongo/connection.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
1
3
|
# --
|
2
4
|
# Copyright (C) 2008-2010 10gen Inc.
|
3
5
|
#
|
@@ -172,6 +174,9 @@ module Mongo
|
|
172
174
|
# specificed in the list of auths. This method is called automatically
|
173
175
|
# by DB#authenticate.
|
174
176
|
#
|
177
|
+
# Note: this method will not actually issue an authentication command. To do that,
|
178
|
+
# either run Connection#apply_saved_authentication or DB#authenticate.
|
179
|
+
#
|
175
180
|
# @param [String] db_name
|
176
181
|
# @param [String] username
|
177
182
|
# @param [String] password
|
@@ -266,7 +271,7 @@ module Mongo
|
|
266
271
|
# @param [String] username username for authentication against from_db (>=1.3.x).
|
267
272
|
# @param [String] password password for authentication against from_db (>=1.3.x).
|
268
273
|
def copy_database(from, to, from_host="localhost", username=nil, password=nil)
|
269
|
-
oh = OrderedHash.new
|
274
|
+
oh = BSON::OrderedHash.new
|
270
275
|
oh[:copydb] = 1
|
271
276
|
oh[:fromhost] = from_host
|
272
277
|
oh[:fromdb] = from
|
@@ -275,7 +280,7 @@ module Mongo
|
|
275
280
|
unless username && password
|
276
281
|
raise MongoArgumentError, "Both username and password must be supplied for authentication."
|
277
282
|
end
|
278
|
-
nonce_cmd = OrderedHash.new
|
283
|
+
nonce_cmd = BSON::OrderedHash.new
|
279
284
|
nonce_cmd[:copydbgetnonce] = 1
|
280
285
|
nonce_cmd[:fromhost] = from_host
|
281
286
|
result = self["admin"].command(nonce_cmd, true, true)
|
@@ -347,13 +352,17 @@ module Mongo
|
|
347
352
|
# @param [BSON::ByteBuffer] message a message to send to the database.
|
348
353
|
# @param [String] db_name the name of the database. used on call to get_last_error.
|
349
354
|
# @param [String] log_message text version of +message+ for logging.
|
355
|
+
# @param [Hash] last_error_params parameters to be sent to getLastError. See DB#error for
|
356
|
+
# available options.
|
357
|
+
#
|
358
|
+
# @see DB#error for valid last error params.
|
350
359
|
#
|
351
360
|
# @return [Array]
|
352
361
|
# An array whose indexes include [0] documents returned, [1] number of document received,
|
353
362
|
# and [3] a cursor_id.
|
354
|
-
def send_message_with_safe_check(operation, message, db_name, log_message=nil)
|
363
|
+
def send_message_with_safe_check(operation, message, db_name, log_message=nil, last_error_params=false)
|
355
364
|
message_with_headers = add_message_headers(operation, message)
|
356
|
-
message_with_check = last_error_message(db_name)
|
365
|
+
message_with_check = last_error_message(db_name, last_error_params)
|
357
366
|
@logger.debug(" MONGODB #{log_message || message}") if @logger
|
358
367
|
begin
|
359
368
|
sock = checkout
|
@@ -366,7 +375,7 @@ module Mongo
|
|
366
375
|
ensure
|
367
376
|
checkin(sock)
|
368
377
|
end
|
369
|
-
if num_received == 1 && error = docs[0]['err']
|
378
|
+
if num_received == 1 && (error = docs[0]['err'] || docs[0]['errmsg'])
|
370
379
|
raise Mongo::OperationFailure, error
|
371
380
|
end
|
372
381
|
[docs, num_received, cursor_id]
|
@@ -644,13 +653,21 @@ module Mongo
|
|
644
653
|
[docs, number_received, cursor_id]
|
645
654
|
end
|
646
655
|
|
647
|
-
|
656
|
+
# Constructs a getlasterror message. This method is used exclusively by
|
657
|
+
# Connection#send_message_with_safe_check.
|
658
|
+
def last_error_message(db_name, opts)
|
648
659
|
message = BSON::ByteBuffer.new
|
649
660
|
message.put_int(0)
|
650
661
|
BSON::BSON_RUBY.serialize_cstr(message, "#{db_name}.$cmd")
|
651
662
|
message.put_int(0)
|
652
663
|
message.put_int(-1)
|
653
|
-
|
664
|
+
cmd = BSON::OrderedHash.new
|
665
|
+
cmd[:getlasterror] = 1
|
666
|
+
if opts.is_a?(Hash)
|
667
|
+
opts.assert_valid_keys(:w, :wtimeout, :fsync)
|
668
|
+
cmd.merge!(opts)
|
669
|
+
end
|
670
|
+
message.put_array(BSON::BSON_CODER.serialize(cmd, false).unpack("C*"))
|
654
671
|
add_message_headers(Mongo::Constants::OP_QUERY, message)
|
655
672
|
end
|
656
673
|
|
data/lib/mongo/cursor.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
1
3
|
# Copyright (C) 2008-2010 10gen Inc.
|
2
4
|
#
|
3
5
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -94,7 +96,7 @@ module Mongo
|
|
94
96
|
#
|
95
97
|
# @raise [OperationFailure] on a database error.
|
96
98
|
def count
|
97
|
-
command = OrderedHash["count", @collection.name,
|
99
|
+
command = BSON::OrderedHash["count", @collection.name,
|
98
100
|
"query", @selector,
|
99
101
|
"fields", @fields]
|
100
102
|
response = @db.command(command)
|
@@ -299,10 +301,14 @@ module Mongo
|
|
299
301
|
selector
|
300
302
|
when nil
|
301
303
|
{}
|
302
|
-
when
|
303
|
-
|
304
|
-
|
304
|
+
when BSON::Code
|
305
|
+
warn "Collection#find will no longer take a JavaScript string in future versions. " +
|
306
|
+
"Please specify your $where query explicitly."
|
305
307
|
{"$where" => selector}
|
308
|
+
when String
|
309
|
+
warn "Collection#find will no longer take a JavaScript string in future versions. " +
|
310
|
+
"Please specify your $where query explicitly."
|
311
|
+
{"$where" => BSON::Code.new(selector)}
|
306
312
|
end
|
307
313
|
end
|
308
314
|
|
@@ -366,7 +372,7 @@ module Mongo
|
|
366
372
|
|
367
373
|
def construct_query_spec
|
368
374
|
return @selector if @selector.has_key?('$query')
|
369
|
-
spec = OrderedHash.new
|
375
|
+
spec = BSON::OrderedHash.new
|
370
376
|
spec['$query'] = @selector
|
371
377
|
spec['$orderby'] = Mongo::Support.format_order_clause(@order) if @order
|
372
378
|
spec['$hint'] = @hint if @hint && @hint.length > 0
|
data/lib/mongo/db.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
1
3
|
# --
|
2
4
|
# Copyright (C) 2008-2010 10gen Inc.
|
3
5
|
#
|
@@ -89,7 +91,7 @@ module Mongo
|
|
89
91
|
raise "error retrieving nonce: #{doc}" unless ok?(doc)
|
90
92
|
nonce = doc['nonce']
|
91
93
|
|
92
|
-
auth = OrderedHash.new
|
94
|
+
auth = BSON::OrderedHash.new
|
93
95
|
auth['authenticate'] = 1
|
94
96
|
auth['user'] = username
|
95
97
|
auth['nonce'] = nonce
|
@@ -212,7 +214,7 @@ module Mongo
|
|
212
214
|
end
|
213
215
|
|
214
216
|
# Create a new collection.
|
215
|
-
oh = OrderedHash.new
|
217
|
+
oh = BSON::OrderedHash.new
|
216
218
|
oh[:create] = name
|
217
219
|
doc = command(oh.merge(options || {}))
|
218
220
|
ok = doc['ok']
|
@@ -247,11 +249,19 @@ module Mongo
|
|
247
249
|
# Get the error message from the most recently executed database
|
248
250
|
# operation for this connection.
|
249
251
|
#
|
250
|
-
# @
|
252
|
+
# @option opts [Boolean] :fsync (false)
|
253
|
+
# @option opts [Integer] :w (nil)
|
254
|
+
# @option opts [Integer] :wtimeout (nil)
|
255
|
+
#
|
256
|
+
# @return [String, Nil] either the text describing an error or nil if no
|
251
257
|
# error has occurred.
|
252
|
-
def error
|
253
|
-
|
254
|
-
|
258
|
+
def error(opts={})
|
259
|
+
opts.assert_valid_keys(:w, :wtimeout, :fsync)
|
260
|
+
cmd = BSON::OrderedHash.new
|
261
|
+
cmd[:getlasterror] = 1
|
262
|
+
cmd.merge!(opts) unless opts.empty?
|
263
|
+
doc = command(cmd)
|
264
|
+
raise MongoDBError, "error retrieving last error: #{doc.inspect}" unless ok?(doc)
|
255
265
|
doc['err']
|
256
266
|
end
|
257
267
|
|
@@ -329,7 +339,7 @@ module Mongo
|
|
329
339
|
code = BSON::Code.new(code)
|
330
340
|
end
|
331
341
|
|
332
|
-
oh = OrderedHash.new
|
342
|
+
oh = BSON::OrderedHash.new
|
333
343
|
oh[:$eval] = code
|
334
344
|
oh[:args] = args
|
335
345
|
doc = command(oh)
|
@@ -346,7 +356,7 @@ module Mongo
|
|
346
356
|
#
|
347
357
|
# @raise MongoDBError if there's an error renaming the collection.
|
348
358
|
def rename_collection(from, to)
|
349
|
-
oh = OrderedHash.new
|
359
|
+
oh = BSON::OrderedHash.new
|
350
360
|
oh[:renameCollection] = "#{@name}.#{from}"
|
351
361
|
oh[:to] = "#{@name}.#{to}"
|
352
362
|
doc = command(oh, true)
|
@@ -363,7 +373,7 @@ module Mongo
|
|
363
373
|
#
|
364
374
|
# @raise MongoDBError if there's an error renaming the collection.
|
365
375
|
def drop_index(collection_name, index_name)
|
366
|
-
oh = OrderedHash.new
|
376
|
+
oh = BSON::OrderedHash.new
|
367
377
|
oh[:deleteIndexes] = collection_name
|
368
378
|
oh[:index] = index_name
|
369
379
|
doc = command(oh)
|
@@ -494,7 +504,7 @@ module Mongo
|
|
494
504
|
#
|
495
505
|
# @core profiling profiling_level-instance_method
|
496
506
|
def profiling_level
|
497
|
-
oh = OrderedHash.new
|
507
|
+
oh = BSON::OrderedHash.new
|
498
508
|
oh[:profile] = -1
|
499
509
|
doc = command(oh)
|
500
510
|
raise "Error with profile command: #{doc.inspect}" unless ok?(doc) && doc['was'].kind_of?(Numeric)
|
@@ -515,7 +525,7 @@ module Mongo
|
|
515
525
|
#
|
516
526
|
# @param [Symbol] level acceptable options are +:off+, +:slow_only+, or +:all+.
|
517
527
|
def profiling_level=(level)
|
518
|
-
oh = OrderedHash.new
|
528
|
+
oh = BSON::OrderedHash.new
|
519
529
|
oh[:profile] = case level
|
520
530
|
when :off
|
521
531
|
0
|
data/lib/mongo/exceptions.rb
CHANGED
data/lib/mongo/gridfs/grid.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
1
3
|
# --
|
2
4
|
# Copyright (C) 2008-2010 10gen Inc.
|
3
5
|
#
|
@@ -18,6 +20,8 @@ module Mongo
|
|
18
20
|
|
19
21
|
# Implementation of the MongoDB GridFS specification. A file store.
|
20
22
|
class Grid
|
23
|
+
include GridExt::InstanceMethods
|
24
|
+
|
21
25
|
DEFAULT_FS_NAME = 'fs'
|
22
26
|
|
23
27
|
# Initialize a new Grid instance, consisting of a MongoDB database
|
@@ -44,15 +48,15 @@ module Mongo
|
|
44
48
|
#
|
45
49
|
# @param [String, #read] data a string or io-like object to store.
|
46
50
|
#
|
47
|
-
# @
|
48
|
-
# @
|
49
|
-
# @
|
51
|
+
# @option opts [String] :filename (nil) a name for the file.
|
52
|
+
# @option opts [Hash] :metadata ({}) any additional data to store with the file.
|
53
|
+
# @option opts [ObjectID] :_id (ObjectID) a unique id for
|
50
54
|
# the file to be use in lieu of an automatically generated one.
|
51
|
-
# @
|
55
|
+
# @option opts [String] :content_type ('binary/octet-stream') If no content type is specified,
|
52
56
|
# the content type will may be inferred from the filename extension if the mime-types gem can be
|
53
57
|
# loaded. Otherwise, the content type 'binary/octet-stream' will be used.
|
54
|
-
# @
|
55
|
-
# @
|
58
|
+
# @option opts [Integer] (262144) :chunk_size size of file chunks in bytes.
|
59
|
+
# @option opts [Boolean] :safe (false) When safe mode is enabled, the chunks sent to the server
|
56
60
|
# will be validated using an md5 hash. If validation fails, an exception will be raised.
|
57
61
|
#
|
58
62
|
# @return [Mongo::ObjectID] the file's id.
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
1
3
|
# --
|
2
4
|
# Copyright (C) 2008-2010 10gen Inc.
|
3
5
|
#
|
@@ -15,16 +17,41 @@
|
|
15
17
|
# ++
|
16
18
|
|
17
19
|
module Mongo
|
18
|
-
module
|
19
|
-
|
20
|
-
def exists?(criteria)
|
21
|
-
BSON::ObjectID:
|
22
|
-
@files.find_one(query)
|
23
|
-
end
|
20
|
+
module GridExt
|
21
|
+
module InstanceMethods
|
24
22
|
|
25
|
-
|
26
|
-
|
23
|
+
# Check the existence of a file matching the given query selector.
|
24
|
+
#
|
25
|
+
# Note that this method can be used with both the Grid and GridFileSystem classes. Also
|
26
|
+
# keep in mind that if you're going to be performing lots of existence checks, you should
|
27
|
+
# keep an instance of Grid or GridFileSystem handy rather than instantiating for each existence
|
28
|
+
# check. Alternatively, simply keep a reference to the proper files collection and query that
|
29
|
+
# as needed. That's exactly how this methods works.
|
30
|
+
#
|
31
|
+
# @param [Hash] selector a query selector.
|
32
|
+
#
|
33
|
+
# @example
|
34
|
+
#
|
35
|
+
# # Check for the existence of a given filename
|
36
|
+
# @grid = GridFileSystem.new(@db)
|
37
|
+
# @grid.exist?(:filename => 'foo.txt')
|
38
|
+
#
|
39
|
+
# # Check for existence filename and content type
|
40
|
+
# @grid = GridFileSystem.new(@db)
|
41
|
+
# @grid.exist?(:filename => 'foo.txt', :content_type => 'image/jpg')
|
42
|
+
#
|
43
|
+
# # Check for existence by _id
|
44
|
+
# @grid = Grid.new(@db)
|
45
|
+
# @grid.exist?(:_id => BSON::ObjectID.from_string('4bddcd24beffd95a7db9b8c8'))
|
46
|
+
#
|
47
|
+
# # Check for existence by an arbitrary attribute.
|
48
|
+
# @grid = Grid.new(@db)
|
49
|
+
# @grid.exist?(:tags => {'$in' => ['nature', 'zen', 'photography']})
|
50
|
+
#
|
51
|
+
# @return [nil, Hash] either nil for the file's metadata as a hash.
|
52
|
+
def exist?(selector)
|
53
|
+
@files.find_one(selector)
|
54
|
+
end
|
27
55
|
end
|
28
|
-
|
29
56
|
end
|
30
57
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
1
3
|
# --
|
2
4
|
# Copyright (C) 2008-2010 10gen Inc.
|
3
5
|
#
|
@@ -19,8 +21,9 @@ module Mongo
|
|
19
21
|
# A file store built on the GridFS specification featuring
|
20
22
|
# an API and behavior similar to that of a traditional file system.
|
21
23
|
class GridFileSystem
|
24
|
+
include GridExt::InstanceMethods
|
22
25
|
|
23
|
-
# Initialize a new
|
26
|
+
# Initialize a new GridFileSystem instance, consisting of a MongoDB database
|
24
27
|
# and a filesystem prefix if not using the default.
|
25
28
|
#
|
26
29
|
# @param [Mongo::DB] db a MongoDB database.
|
@@ -51,17 +54,17 @@ module Mongo
|
|
51
54
|
# or writing to the file.
|
52
55
|
# @param [Hash] opts see GridIO#new
|
53
56
|
#
|
54
|
-
# @
|
55
|
-
# @
|
57
|
+
# @option opts [Hash] :metadata ({}) any additional data to store with the file.
|
58
|
+
# @option opts [ObjectID] :_id (ObjectID) a unique id for
|
56
59
|
# the file to be use in lieu of an automatically generated one.
|
57
|
-
# @
|
60
|
+
# @option opts [String] :content_type ('binary/octet-stream') If no content type is specified,
|
58
61
|
# the content type will may be inferred from the filename extension if the mime-types gem can be
|
59
62
|
# loaded. Otherwise, the content type 'binary/octet-stream' will be used.
|
60
|
-
# @
|
61
|
-
# @
|
63
|
+
# @option opts [Integer] (262144) :chunk_size size of file chunks in bytes.
|
64
|
+
# @option opts [Boolean] :delete_old (false) ensure that old versions of the file are deleted. This option
|
62
65
|
# only work in 'w' mode. Certain precautions must be taken when deleting GridFS files. See the notes under
|
63
66
|
# GridFileSystem#delete.
|
64
|
-
# @
|
67
|
+
# @option opts [Boolean] :safe (false) When safe mode is enabled, the chunks sent to the server
|
65
68
|
# will be validated using an md5 hash. If validation fails, an exception will be raised.
|
66
69
|
#
|
67
70
|
# @example
|
data/lib/mongo/gridfs/grid_io.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
1
3
|
# --
|
2
4
|
# Copyright (C) 2008-2010 10gen Inc.
|
3
5
|
#
|
@@ -43,14 +45,14 @@ module Mongo
|
|
43
45
|
# @option opts [Hash] :query a query selector used when opening the file in 'r' mode.
|
44
46
|
# @option opts [Hash] :query_opts any query options to be used when opening the file in 'r' mode.
|
45
47
|
# @option opts [String] :fs_name the file system prefix.
|
46
|
-
# @
|
47
|
-
# @
|
48
|
-
# @
|
48
|
+
# @option opts [Integer] (262144) :chunk_size size of file chunks in bytes.
|
49
|
+
# @option opts [Hash] :metadata ({}) any additional data to store with the file.
|
50
|
+
# @option opts [ObjectID] :_id (ObjectID) a unique id for
|
49
51
|
# the file to be use in lieu of an automatically generated one.
|
50
|
-
# @
|
52
|
+
# @option opts [String] :content_type ('binary/octet-stream') If no content type is specified,
|
51
53
|
# the content type will may be inferred from the filename extension if the mime-types gem can be
|
52
54
|
# loaded. Otherwise, the content type 'binary/octet-stream' will be used.
|
53
|
-
# @
|
55
|
+
# @option opts [Boolean] :safe (false) When safe mode is enabled, the chunks sent to the server
|
54
56
|
# will be validated using an md5 hash. If validation fails, an exception will be raised.
|
55
57
|
def initialize(files, chunks, filename, mode, opts={})
|
56
58
|
@files = files
|
@@ -197,7 +199,7 @@ module Mongo
|
|
197
199
|
private
|
198
200
|
|
199
201
|
def create_chunk(n)
|
200
|
-
chunk = OrderedHash.new
|
202
|
+
chunk = BSON::OrderedHash.new
|
201
203
|
chunk['_id'] = BSON::ObjectID.new
|
202
204
|
chunk['n'] = n
|
203
205
|
chunk['files_id'] = @files_id
|
@@ -319,7 +321,7 @@ module Mongo
|
|
319
321
|
end
|
320
322
|
|
321
323
|
def to_mongo_object
|
322
|
-
h = OrderedHash.new
|
324
|
+
h = BSON::OrderedHash.new
|
323
325
|
h['_id'] = @files_id
|
324
326
|
h['filename'] = @filename if @filename
|
325
327
|
h['contentType'] = @content_type
|
@@ -335,7 +337,7 @@ module Mongo
|
|
335
337
|
|
336
338
|
# Get a server-side md5 and validate against the client if running in safe mode.
|
337
339
|
def get_md5
|
338
|
-
md5_command = OrderedHash.new
|
340
|
+
md5_command = BSON::OrderedHash.new
|
339
341
|
md5_command['filemd5'] = @files_id
|
340
342
|
md5_command['root'] = @fs_name
|
341
343
|
@server_md5 = @files.db.command(md5_command)['md5']
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
1
3
|
# --
|
2
4
|
# Copyright (C) 2008-2010 10gen Inc.
|
3
5
|
#
|
@@ -31,7 +33,7 @@ module Mongo #:nodoc:
|
|
31
33
|
# <tt>array_as_sort_parameters([["field1", :asc], ["field2", :desc]])</tt> =>
|
32
34
|
# <tt>{ "field1" => 1, "field2" => -1}</tt>
|
33
35
|
def array_as_sort_parameters(value)
|
34
|
-
order_by = OrderedHash.new
|
36
|
+
order_by = BSON::OrderedHash.new
|
35
37
|
if value.first.is_a? Array
|
36
38
|
value.each do |param|
|
37
39
|
if (param.class.name == "String")
|
data/lib/mongo/util/core_ext.rb
CHANGED
data/lib/mongo/util/support.rb
CHANGED
@@ -150,7 +150,7 @@ class Features14Test < Test::Unit::TestCase
|
|
150
150
|
end
|
151
151
|
|
152
152
|
should "use geoNear command to return distances from a point" do
|
153
|
-
cmd = OrderedHash.new
|
153
|
+
cmd = BSON::OrderedHash.new
|
154
154
|
cmd['geoNear'] = 'places'
|
155
155
|
cmd['near'] = @empire_state
|
156
156
|
cmd['num'] = 6
|
data/test/collection_test.rb
CHANGED
@@ -115,6 +115,39 @@ class TestCollection < Test::Unit::TestCase
|
|
115
115
|
end
|
116
116
|
end
|
117
117
|
|
118
|
+
if @@version >= "1.5.1"
|
119
|
+
def test_safe_mode_with_advanced_safe_with_invalid_options
|
120
|
+
assert_raise_error ArgumentError, "Unknown key(s): wtime" do
|
121
|
+
@@test.insert({:foo => 1}, :safe => {:w => 2, :wtime => 1, :fsync => true})
|
122
|
+
end
|
123
|
+
assert_raise_error ArgumentError, "Unknown key(s): wtime" do
|
124
|
+
@@test.update({:foo => 1}, {:foo => 2}, :safe => {:w => 2, :wtime => 1, :fsync => true})
|
125
|
+
end
|
126
|
+
|
127
|
+
assert_raise_error ArgumentError, "Unknown key(s): wtime" do
|
128
|
+
@@test.remove({:foo => 2}, :safe => {:w => 2, :wtime => 1, :fsync => true})
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def test_safe_mode_with_w_failure
|
133
|
+
assert_raise_error OperationFailure, "timed out waiting for slaves" do
|
134
|
+
@@test.insert({:foo => 1}, :safe => {:w => 2, :wtimeout => 1, :fsync => true})
|
135
|
+
end
|
136
|
+
assert_raise_error OperationFailure, "timed out waiting for slaves" do
|
137
|
+
@@test.update({:foo => 1}, {:foo => 2}, :safe => {:w => 2, :wtimeout => 1, :fsync => true})
|
138
|
+
end
|
139
|
+
assert_raise_error OperationFailure, "timed out waiting for slaves" do
|
140
|
+
@@test.remove({:foo => 2}, :safe => {:w => 2, :wtimeout => 1, :fsync => true})
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def test_safe_mode_with_write_and_fsync
|
145
|
+
assert @@test.insert({:foo => 1}, :safe => {:w => 1, :wtimeout => 1, :fsync => true})
|
146
|
+
assert @@test.update({:foo => 1}, {:foo => 2}, :safe => {:w => 1, :wtimeout => 1, :fsync => true})
|
147
|
+
assert @@test.remove({:foo => 2}, :safe => {:w => 1, :wtimeout => 1, :fsync => true})
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
118
151
|
def test_update
|
119
152
|
id1 = @@test.save("x" => 5)
|
120
153
|
@@test.update({}, {"$inc" => {"x" => 1}})
|
@@ -272,6 +305,16 @@ class TestCollection < Test::Unit::TestCase
|
|
272
305
|
end
|
273
306
|
end
|
274
307
|
|
308
|
+
if @@version >= "1.5.1"
|
309
|
+
def test_fields_with_slice
|
310
|
+
@@test.save({:foo => [1, 2, 3, 4, 5, 6], :test => 'slice'})
|
311
|
+
|
312
|
+
doc = @@test.find_one({:test => 'slice'}, :fields => {'foo' => {'$slice' => [0, 3]}})
|
313
|
+
assert_equal [1, 2, 3], doc['foo']
|
314
|
+
@@test.remove
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
275
318
|
def test_find_one
|
276
319
|
id = @@test.save("hello" => "world", "foo" => "bar")
|
277
320
|
|
@@ -280,14 +323,14 @@ class TestCollection < Test::Unit::TestCase
|
|
280
323
|
assert_equal @@test.find_one(nil), @@test.find_one()
|
281
324
|
assert_equal @@test.find_one({}), @@test.find_one()
|
282
325
|
assert_equal @@test.find_one("hello" => "world"), @@test.find_one()
|
283
|
-
assert_equal @@test.find_one(OrderedHash["hello", "world"]), @@test.find_one()
|
326
|
+
assert_equal @@test.find_one(BSON::OrderedHash["hello", "world"]), @@test.find_one()
|
284
327
|
|
285
328
|
assert @@test.find_one(nil, :fields => ["hello"]).include?("hello")
|
286
329
|
assert !@@test.find_one(nil, :fields => ["foo"]).include?("hello")
|
287
330
|
assert_equal ["_id"], @@test.find_one(nil, :fields => []).keys()
|
288
331
|
|
289
332
|
assert_equal nil, @@test.find_one("hello" => "foo")
|
290
|
-
assert_equal nil, @@test.find_one(OrderedHash["hello", "foo"])
|
333
|
+
assert_equal nil, @@test.find_one(BSON::OrderedHash["hello", "foo"])
|
291
334
|
assert_equal nil, @@test.find_one(ObjectID.new)
|
292
335
|
|
293
336
|
assert_raise TypeError do
|
data/test/connection_test.rb
CHANGED
data/test/cursor_test.rb
CHANGED
data/test/db_api_test.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'test/test_helper'
|
2
2
|
|
3
|
-
# NOTE: assumes Mongo is running
|
4
3
|
class DBAPITest < Test::Unit::TestCase
|
5
4
|
include Mongo
|
6
5
|
include BSON
|
@@ -47,14 +46,14 @@ class DBAPITest < Test::Unit::TestCase
|
|
47
46
|
end
|
48
47
|
|
49
48
|
def test_save_ordered_hash
|
50
|
-
oh = OrderedHash.new
|
49
|
+
oh = BSON::OrderedHash.new
|
51
50
|
oh['a'] = -1
|
52
51
|
oh['b'] = 'foo'
|
53
52
|
|
54
53
|
oid = @@coll.save(oh)
|
55
54
|
assert_equal 'foo', @@coll.find_one(oid)['b']
|
56
55
|
|
57
|
-
oh = OrderedHash['a' => 1, 'b' => 'foo']
|
56
|
+
oh = BSON::OrderedHash['a' => 1, 'b' => 'foo']
|
58
57
|
oid = @@coll.save(oh)
|
59
58
|
assert_equal 'foo', @@coll.find_one(oid)['b']
|
60
59
|
end
|
@@ -188,7 +187,7 @@ class DBAPITest < Test::Unit::TestCase
|
|
188
187
|
|
189
188
|
# Sorting using ordered hash. You can use an unordered one, but then the
|
190
189
|
# order of the keys won't be guaranteed thus your sort won't make sense.
|
191
|
-
oh = OrderedHash.new
|
190
|
+
oh = BSON::OrderedHash.new
|
192
191
|
oh['a'] = -1
|
193
192
|
assert_raise InvalidSortValueError do
|
194
193
|
docs = @@coll.find({'a' => { '$lt' => 10 }}, :sort => oh).to_a
|
@@ -470,8 +469,18 @@ class DBAPITest < Test::Unit::TestCase
|
|
470
469
|
@@coll.insert('a' => 3)
|
471
470
|
|
472
471
|
assert_equal 3, @@coll.count
|
473
|
-
assert_equal 1, @@coll.find('$where' => Code.new('this.a > 2')).count()
|
474
|
-
assert_equal 2, @@coll.find('$where' => Code.new('this.a > i', {'i' => 1})).count()
|
472
|
+
assert_equal 1, @@coll.find('$where' => BSON::Code.new('this.a > 2')).count()
|
473
|
+
assert_equal 2, @@coll.find('$where' => BSON::Code.new('this.a > i', {'i' => 1})).count()
|
474
|
+
end
|
475
|
+
|
476
|
+
def test_implicit_where
|
477
|
+
@@coll.remove
|
478
|
+
@@coll.insert('a' => 2)
|
479
|
+
@@coll.insert('a' => 3)
|
480
|
+
|
481
|
+
assert_equal 2, @@coll.count
|
482
|
+
assert_equal 1, @@coll.find('this.a > 2').count()
|
483
|
+
assert_equal 2, @@coll.find(BSON::Code.new('this.a > z', {'z' => 1})).to_a.length
|
475
484
|
end
|
476
485
|
|
477
486
|
def test_eval
|
data/test/db_connection_test.rb
CHANGED
data/test/db_test.rb
CHANGED
@@ -10,7 +10,6 @@ class TestPKFactory
|
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
13
|
-
# NOTE: assumes Mongo is running
|
14
13
|
class DBTest < Test::Unit::TestCase
|
15
14
|
|
16
15
|
include Mongo
|
@@ -183,6 +182,24 @@ class DBTest < Test::Unit::TestCase
|
|
183
182
|
assert_nil @@db.previous_error
|
184
183
|
end
|
185
184
|
|
185
|
+
if @@version >= "1.5.1"
|
186
|
+
def test_failing_error_params
|
187
|
+
assert_raise_error Mongo::MongoDBError, "timed out waiting for slaves" do
|
188
|
+
@@db.error(:w => 2, :wtimeout => 10, :fsync => true)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def test_passing_error_params
|
193
|
+
assert_nil @@db.error(:w => 1, :wtimeout => 10, :fsync => true)
|
194
|
+
end
|
195
|
+
|
196
|
+
def test_invalid_error_params
|
197
|
+
assert_raise_error ArgumentError, "Unknown key(s): z" do
|
198
|
+
@@db.error(:z => 1, :wtimeout => 10, :fsync => true)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
186
203
|
def test_check_command_response
|
187
204
|
command = {:forceerror => 1}
|
188
205
|
assert_raise OperationFailure do
|
@@ -25,6 +25,15 @@ class GridFileSystemTest < Test::Unit::TestCase
|
|
25
25
|
@grid = GridFileSystem.new(@db)
|
26
26
|
end
|
27
27
|
|
28
|
+
should "return existence of the file" do
|
29
|
+
file = @grid.exist?(:filename => 'sample.file')
|
30
|
+
assert_equal 'sample.file', file['filename']
|
31
|
+
end
|
32
|
+
|
33
|
+
should "return nil if the file doesn't exist" do
|
34
|
+
assert_nil @grid.exist?(:filename => 'foo.file')
|
35
|
+
end
|
36
|
+
|
28
37
|
should "read sample data" do
|
29
38
|
data = @grid.open('sample.file', 'r') { |f| f.read }
|
30
39
|
assert_equal data.length, @chunks_data.length
|
data/test/grid_test.rb
CHANGED
@@ -22,6 +22,15 @@ class GridTest < Test::Unit::TestCase
|
|
22
22
|
@id = @grid.put(@data, :filename => 'sample', :metadata => {'app' => 'photos'})
|
23
23
|
end
|
24
24
|
|
25
|
+
should "check existence" do
|
26
|
+
file = @grid.exist?(:filename => 'sample')
|
27
|
+
assert_equal 'sample', file['filename']
|
28
|
+
end
|
29
|
+
|
30
|
+
should "return nil if it doesn't exist" do
|
31
|
+
assert_nil @grid.exist?(:metadata => 'foo')
|
32
|
+
end
|
33
|
+
|
25
34
|
should "retrieve the stored data" do
|
26
35
|
data = @grid.get(@id).data
|
27
36
|
assert_equal @data, data
|
data/test/test_helper.rb
CHANGED
@@ -23,7 +23,6 @@ require 'bson_ext/cbson' if ENV['C_EXT']
|
|
23
23
|
|
24
24
|
MONGO_TEST_DB = 'mongo-ruby-test'
|
25
25
|
|
26
|
-
# NOTE: most tests assume that MongoDB is running.
|
27
26
|
class Test::Unit::TestCase
|
28
27
|
include Mongo
|
29
28
|
include BSON
|
@@ -42,4 +41,13 @@ class Test::Unit::TestCase
|
|
42
41
|
end
|
43
42
|
end
|
44
43
|
end
|
44
|
+
|
45
|
+
def assert_raise_error(klass, message)
|
46
|
+
begin
|
47
|
+
yield
|
48
|
+
rescue => e
|
49
|
+
assert_equal klass, e.class
|
50
|
+
assert e.message.include?(message), "#{e.message} does not include #{message}."
|
51
|
+
end
|
52
|
+
end
|
45
53
|
end
|
metadata
CHANGED
@@ -1,11 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mongo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
segments:
|
6
|
-
- 1
|
7
|
-
- 0
|
8
|
-
version: "1.0"
|
4
|
+
version: 1.0.1
|
9
5
|
platform: ruby
|
10
6
|
authors:
|
11
7
|
- Jim Menard
|
@@ -15,22 +11,19 @@ autorequire:
|
|
15
11
|
bindir: bin
|
16
12
|
cert_chain: []
|
17
13
|
|
18
|
-
date: 2010-
|
14
|
+
date: 2010-05-07 00:00:00 -04:00
|
19
15
|
default_executable:
|
20
16
|
dependencies:
|
21
17
|
- !ruby/object:Gem::Dependency
|
22
18
|
name: bson
|
23
|
-
|
24
|
-
|
19
|
+
type: :runtime
|
20
|
+
version_requirement:
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
22
|
requirements:
|
26
23
|
- - "="
|
27
24
|
- !ruby/object:Gem::Version
|
28
|
-
|
29
|
-
|
30
|
-
- 0
|
31
|
-
version: "1.0"
|
32
|
-
type: :runtime
|
33
|
-
version_requirements: *id001
|
25
|
+
version: 1.0.1
|
26
|
+
version:
|
34
27
|
description: A Ruby driver for MongoDB. For more information about Mongo, see http://www.mongodb.org.
|
35
28
|
email: mongodb-dev@googlegroups.com
|
36
29
|
executables: []
|
@@ -85,20 +78,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
85
78
|
requirements:
|
86
79
|
- - ">="
|
87
80
|
- !ruby/object:Gem::Version
|
88
|
-
segments:
|
89
|
-
- 0
|
90
81
|
version: "0"
|
82
|
+
version:
|
91
83
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
92
84
|
requirements:
|
93
85
|
- - ">="
|
94
86
|
- !ruby/object:Gem::Version
|
95
|
-
segments:
|
96
|
-
- 0
|
97
87
|
version: "0"
|
88
|
+
version:
|
98
89
|
requirements: []
|
99
90
|
|
100
91
|
rubyforge_project:
|
101
|
-
rubygems_version: 1.3.
|
92
|
+
rubygems_version: 1.3.5
|
102
93
|
signing_key:
|
103
94
|
specification_version: 3
|
104
95
|
summary: Ruby driver for the MongoDB
|