mongo 1.0 → 1.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. data/LICENSE.txt +1 -13
  2. data/{README.rdoc → README.md} +129 -149
  3. data/Rakefile +94 -58
  4. data/bin/mongo_console +21 -0
  5. data/docs/1.0_UPGRADE.md +21 -0
  6. data/docs/CREDITS.md +123 -0
  7. data/docs/FAQ.md +112 -0
  8. data/docs/GridFS.md +158 -0
  9. data/docs/HISTORY.md +185 -0
  10. data/docs/REPLICA_SETS.md +75 -0
  11. data/docs/TUTORIAL.md +247 -0
  12. data/docs/WRITE_CONCERN.md +28 -0
  13. data/lib/mongo/collection.rb +225 -105
  14. data/lib/mongo/connection.rb +374 -315
  15. data/lib/mongo/cursor.rb +122 -77
  16. data/lib/mongo/db.rb +109 -85
  17. data/lib/mongo/exceptions.rb +6 -0
  18. data/lib/mongo/gridfs/grid.rb +19 -11
  19. data/lib/mongo/gridfs/grid_ext.rb +36 -9
  20. data/lib/mongo/gridfs/grid_file_system.rb +15 -9
  21. data/lib/mongo/gridfs/grid_io.rb +49 -16
  22. data/lib/mongo/gridfs/grid_io_fix.rb +38 -0
  23. data/lib/mongo/repl_set_connection.rb +290 -0
  24. data/lib/mongo/util/conversions.rb +3 -1
  25. data/lib/mongo/util/core_ext.rb +17 -4
  26. data/lib/mongo/util/pool.rb +125 -0
  27. data/lib/mongo/util/server_version.rb +2 -0
  28. data/lib/mongo/util/support.rb +12 -0
  29. data/lib/mongo/util/uri_parser.rb +71 -0
  30. data/lib/mongo.rb +23 -7
  31. data/{mongo-ruby-driver.gemspec → mongo.gemspec} +9 -7
  32. data/test/auxillary/1.4_features.rb +2 -2
  33. data/test/auxillary/authentication_test.rb +1 -1
  34. data/test/auxillary/autoreconnect_test.rb +1 -1
  35. data/test/{slave_connection_test.rb → auxillary/slave_connection_test.rb} +6 -6
  36. data/test/bson/binary_test.rb +15 -0
  37. data/test/bson/bson_test.rb +537 -0
  38. data/test/bson/byte_buffer_test.rb +190 -0
  39. data/test/bson/hash_with_indifferent_access_test.rb +38 -0
  40. data/test/bson/json_test.rb +17 -0
  41. data/test/bson/object_id_test.rb +141 -0
  42. data/test/bson/ordered_hash_test.rb +197 -0
  43. data/test/collection_test.rb +195 -15
  44. data/test/connection_test.rb +93 -56
  45. data/test/conversions_test.rb +1 -1
  46. data/test/cursor_fail_test.rb +75 -0
  47. data/test/cursor_message_test.rb +43 -0
  48. data/test/cursor_test.rb +93 -32
  49. data/test/db_api_test.rb +28 -55
  50. data/test/db_connection_test.rb +2 -3
  51. data/test/db_test.rb +45 -40
  52. data/test/grid_file_system_test.rb +14 -6
  53. data/test/grid_io_test.rb +36 -7
  54. data/test/grid_test.rb +54 -10
  55. data/test/replica_sets/connect_test.rb +84 -0
  56. data/test/replica_sets/count_test.rb +35 -0
  57. data/test/{replica → replica_sets}/insert_test.rb +17 -14
  58. data/test/replica_sets/pooled_insert_test.rb +55 -0
  59. data/test/replica_sets/query_secondaries.rb +80 -0
  60. data/test/replica_sets/query_test.rb +41 -0
  61. data/test/replica_sets/replication_ack_test.rb +64 -0
  62. data/test/replica_sets/rs_test_helper.rb +29 -0
  63. data/test/safe_test.rb +68 -0
  64. data/test/support/hash_with_indifferent_access.rb +199 -0
  65. data/test/support/keys.rb +45 -0
  66. data/test/support_test.rb +19 -0
  67. data/test/test_helper.rb +53 -15
  68. data/test/threading/{test_threading_large_pool.rb → threading_with_large_pool_test.rb} +2 -2
  69. data/test/threading_test.rb +2 -2
  70. data/test/tools/repl_set_manager.rb +241 -0
  71. data/test/tools/test.rb +13 -0
  72. data/test/unit/collection_test.rb +70 -7
  73. data/test/unit/connection_test.rb +18 -39
  74. data/test/unit/cursor_test.rb +7 -8
  75. data/test/unit/db_test.rb +14 -17
  76. data/test/unit/grid_test.rb +49 -0
  77. data/test/unit/pool_test.rb +9 -0
  78. data/test/unit/repl_set_connection_test.rb +82 -0
  79. data/test/unit/safe_test.rb +125 -0
  80. metadata +132 -51
  81. data/bin/bson_benchmark.rb +0 -59
  82. data/bin/fail_if_no_c.rb +0 -11
  83. data/examples/admin.rb +0 -43
  84. data/examples/capped.rb +0 -22
  85. data/examples/cursor.rb +0 -48
  86. data/examples/gridfs.rb +0 -44
  87. data/examples/index_test.rb +0 -126
  88. data/examples/info.rb +0 -31
  89. data/examples/queries.rb +0 -70
  90. data/examples/simple.rb +0 -24
  91. data/examples/strict.rb +0 -35
  92. data/examples/types.rb +0 -36
  93. data/test/replica/count_test.rb +0 -34
  94. data/test/replica/pooled_insert_test.rb +0 -54
  95. data/test/replica/query_test.rb +0 -39
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
  #
@@ -27,6 +29,7 @@ module Mongo
27
29
  SYSTEM_INDEX_COLLECTION = "system.indexes"
28
30
  SYSTEM_PROFILE_COLLECTION = "system.profile"
29
31
  SYSTEM_USER_COLLECTION = "system.users"
32
+ SYSTEM_JS_COLLECTION = "system.js"
30
33
  SYSTEM_COMMAND_COLLECTION = "$cmd"
31
34
 
32
35
  # Counter for generating unique request ids.
@@ -42,12 +45,15 @@ module Mongo
42
45
  # Returns the value of the +strict+ flag.
43
46
  def strict?; @strict; end
44
47
 
45
- # The name of the database.
46
- attr_reader :name
48
+ # The name of the database and the local safe option.
49
+ attr_reader :name, :safe
47
50
 
48
51
  # The Mongo::Connection instance connecting to the MongoDB server.
49
52
  attr_reader :connection
50
53
 
54
+ # The length of time that Collection.ensure_index should cache index calls
55
+ attr_accessor :cache_time
56
+
51
57
  # Instances of DB are normally obtained by calling Mongo#db.
52
58
  #
53
59
  # @param [String] db_name the database name.
@@ -57,17 +63,26 @@ module Mongo
57
63
  # @option options [Boolean] :strict (False) If true, collections must exist to be accessed and must
58
64
  # not exist to be created. See DB#collection and DB#create_collection.
59
65
  #
60
- # @option options [Object, #create_pk(doc)] :pk (Mongo::ObjectID) A primary key factory object,
66
+ # @option options [Object, #create_pk(doc)] :pk (Mongo::ObjectId) A primary key factory object,
61
67
  # which should take a hash and return a hash which merges the original hash with any primary key
62
68
  # fields the factory wishes to inject. (NOTE: if the object already has a primary key,
63
69
  # the factory should not inject a new key).
64
70
  #
71
+ # @option options [Boolean, Hash] :safe (false) Set the default safe-mode options
72
+ # propogated to Collection objects instantiated off of this DB. If no
73
+ # value is provided, the default value set on this instance's Connection object will be used. This
74
+ # default can be overridden upon instantiation of any collection by explicity setting a :safe value
75
+ # on initialization
76
+ # @option options [Integer] :cache_time (300) Set the time that all ensure_index calls should cache the command.
77
+ #
65
78
  # @core databases constructor_details
66
79
  def initialize(db_name, connection, options={})
67
80
  @name = Mongo::Support.validate_db_name(db_name)
68
81
  @connection = connection
69
82
  @strict = options[:strict]
70
83
  @pk_factory = options[:pk]
84
+ @safe = options.has_key?(:safe) ? options[:safe] : @connection.safe
85
+ @cache_time = options[:cache_time] || 300 #5 minutes.
71
86
  end
72
87
 
73
88
  # Authenticate with the given username and password. Note that mongod
@@ -85,16 +100,16 @@ module Mongo
85
100
  #
86
101
  # @core authenticate authenticate-instance_method
87
102
  def authenticate(username, password, save_auth=true)
88
- doc = command(:getnonce => 1)
103
+ doc = command({:getnonce => 1}, :check_response => false)
89
104
  raise "error retrieving nonce: #{doc}" unless ok?(doc)
90
105
  nonce = doc['nonce']
91
106
 
92
- auth = OrderedHash.new
107
+ auth = BSON::OrderedHash.new
93
108
  auth['authenticate'] = 1
94
109
  auth['user'] = username
95
110
  auth['nonce'] = nonce
96
111
  auth['key'] = Mongo::Support.auth_key(username, password, nonce)
97
- if ok?(command(auth))
112
+ if ok?(self.command(auth, :check_response => false))
98
113
  if save_auth
99
114
  @connection.add_auth(@name, username, password)
100
115
  end
@@ -104,6 +119,36 @@ module Mongo
104
119
  end
105
120
  end
106
121
 
122
+ # Adds a stored Javascript function to the database which can executed
123
+ # server-side in map_reduce, db.eval and $where clauses.
124
+ #
125
+ # @param [String] function_name
126
+ # @param [String] code
127
+ #
128
+ # @return [String] the function name saved to the database
129
+ def add_stored_function(function_name, code)
130
+ self[SYSTEM_JS_COLLECTION].save(
131
+ {
132
+ "_id" => function_name,
133
+ :value => BSON::Code.new(code)
134
+ }
135
+ )
136
+ end
137
+
138
+ # Removes stored Javascript function from the database. Returns
139
+ # false if the function does not exist
140
+ #
141
+ # @param [String] function_name
142
+ #
143
+ # @return [Boolean]
144
+ def remove_stored_function(function_name)
145
+ if self[SYSTEM_JS_COLLECTION].find_one({"_id" => function_name})
146
+ self[SYSTEM_JS_COLLECTION].remove({"_id" => function_name}, :safe => true)
147
+ else
148
+ return false
149
+ end
150
+ end
151
+
107
152
  # Adds a user to this database for use with authentication. If the user already
108
153
  # exists in the system, the password will be updated.
109
154
  #
@@ -212,24 +257,29 @@ module Mongo
212
257
  end
213
258
 
214
259
  # Create a new collection.
215
- oh = OrderedHash.new
260
+ oh = BSON::OrderedHash.new
216
261
  oh[:create] = name
217
262
  doc = command(oh.merge(options || {}))
218
- ok = doc['ok']
219
- return Collection.new(self, name, @pk_factory) if ok.kind_of?(Numeric) && (ok.to_i == 1 || ok.to_i == 0)
263
+ return Collection.new(self, name, :pk => @pk_factory) if ok?(doc)
220
264
  raise MongoDBError, "Error creating collection: #{doc.inspect}"
221
265
  end
222
266
 
223
267
  # Get a collection by name.
224
268
  #
225
269
  # @param [String] name the collection name.
270
+ # @param [Hash] options any valid options that can me passed to Collection#new.
226
271
  #
227
272
  # @raise [MongoDBError] if collection does not already exist and we're in +strict+ mode.
228
273
  #
229
274
  # @return [Mongo::Collection]
230
- def collection(name)
231
- return Collection.new(self, name, @pk_factory) if !strict? || collection_names.include?(name)
232
- raise Mongo::MongoDBError, "Collection #{name} doesn't exist. Currently in strict mode."
275
+ def collection(name, options={})
276
+ if strict? && !collection_names.include?(name)
277
+ raise Mongo::MongoDBError, "Collection #{name} doesn't exist. Currently in strict mode."
278
+ else
279
+ options[:safe] = options.has_key?(:safe) ? options[:safe] : @safe
280
+ options.merge!(:pk => @pk_factory) unless options[:pk]
281
+ Collection.new(self, name, options)
282
+ end
233
283
  end
234
284
  alias_method :[], :collection
235
285
 
@@ -237,29 +287,29 @@ module Mongo
237
287
  #
238
288
  # @param [String] name
239
289
  #
240
- # @return [Boolean] True on success or if the collection names doesn't exist.
290
+ # @return [Boolean] +true+ on success or +false+ if the collection name doesn't exist.
241
291
  def drop_collection(name)
242
292
  return true unless collection_names.include?(name)
243
293
 
244
294
  ok?(command(:drop => name))
245
295
  end
246
296
 
247
- # Get the error message from the most recently executed database
248
- # operation for this connection.
297
+ # Run the getlasterror command with the specified replication options.
249
298
  #
250
- # @return [String, Nil] either the text describing the error or nil if no
251
- # error has occurred.
252
- def error
253
- doc = command(:getlasterror => 1)
254
- raise MongoDBError, "error retrieving last error: #{doc}" unless ok?(doc)
255
- doc['err']
256
- end
257
-
258
- # Get status information from the last operation on this connection.
299
+ # @option opts [Boolean] :fsync (false)
300
+ # @option opts [Integer] :w (nil)
301
+ # @option opts [Integer] :wtimeout (nil)
302
+ #
303
+ # @return [Hash] the entire response to getlasterror.
259
304
  #
260
- # @return [Hash] a hash representing the status of the last db op.
261
- def last_status
262
- command(:getlasterror => 1)
305
+ # @raise [MongoDBError] if the operation fails.
306
+ def get_last_error(opts={})
307
+ cmd = BSON::OrderedHash.new
308
+ cmd[:getlasterror] = 1
309
+ cmd.merge!(opts)
310
+ doc = command(cmd, :check_response => false)
311
+ raise MongoDBError, "error retrieving last error: #{doc.inspect}" unless ok?(doc)
312
+ doc
263
313
  end
264
314
 
265
315
  # Return +true+ if an error was caused by the most recently executed
@@ -267,7 +317,7 @@ module Mongo
267
317
  #
268
318
  # @return [Boolean]
269
319
  def error?
270
- error != nil
320
+ get_last_error['err'] != nil
271
321
  end
272
322
 
273
323
  # Get the most recent error to have occured on this database.
@@ -295,17 +345,6 @@ module Mongo
295
345
  command(:reseterror => 1)
296
346
  end
297
347
 
298
- # @deprecated please use Collection#find to create queries.
299
- #
300
- # Returns a Cursor over the query results.
301
- #
302
- # Note that the query gets sent lazily; the cursor calls
303
- # Connection#send_message when needed. If the caller never requests an
304
- # object from the cursor, the query never gets sent.
305
- def query(collection, query, admin=false)
306
- Cursor.new(self, collection, query, admin)
307
- end
308
-
309
348
  # Dereference a DBRef, returning the document it points to.
310
349
  #
311
350
  # @param [Mongo::DBRef] dbref
@@ -329,12 +368,11 @@ module Mongo
329
368
  code = BSON::Code.new(code)
330
369
  end
331
370
 
332
- oh = OrderedHash.new
371
+ oh = BSON::OrderedHash.new
333
372
  oh[:$eval] = code
334
- oh[:args] = args
373
+ oh[:args] = args
335
374
  doc = command(oh)
336
- return doc['retval'] if ok?(doc)
337
- raise OperationFailure, "eval failed: #{doc['errmsg']}"
375
+ doc['retval']
338
376
  end
339
377
 
340
378
  # Rename a collection.
@@ -343,13 +381,13 @@ module Mongo
343
381
  # @param [String] to new collection name.
344
382
  #
345
383
  # @return [True] returns +true+ on success.
346
- #
384
+ #
347
385
  # @raise MongoDBError if there's an error renaming the collection.
348
386
  def rename_collection(from, to)
349
- oh = OrderedHash.new
387
+ oh = BSON::OrderedHash.new
350
388
  oh[:renameCollection] = "#{@name}.#{from}"
351
389
  oh[:to] = "#{@name}.#{to}"
352
- doc = command(oh, true)
390
+ doc = DB.new('admin', @connection).command(oh, :check_response => false)
353
391
  ok?(doc) || raise(MongoDBError, "Error renaming collection: #{doc.inspect}")
354
392
  end
355
393
 
@@ -363,10 +401,10 @@ module Mongo
363
401
  #
364
402
  # @raise MongoDBError if there's an error renaming the collection.
365
403
  def drop_index(collection_name, index_name)
366
- oh = OrderedHash.new
404
+ oh = BSON::OrderedHash.new
367
405
  oh[:deleteIndexes] = collection_name
368
406
  oh[:index] = index_name
369
- doc = command(oh)
407
+ doc = command(oh, :check_response => false)
370
408
  ok?(doc) || raise(MongoDBError, "Error with drop_index command: #{doc.inspect}")
371
409
  end
372
410
 
@@ -386,7 +424,6 @@ module Mongo
386
424
  info
387
425
  end
388
426
 
389
-
390
427
  # Return stats on this database. Uses MongoDB's dbstats command.
391
428
  #
392
429
  # @return [Hash]
@@ -394,31 +431,13 @@ module Mongo
394
431
  self.command({:dbstats => 1})
395
432
  end
396
433
 
397
- # Create a new index on the given collection.
398
- # Normally called by Collection#create_index.
399
- #
400
- # @param [String] collection_name
401
- # @param [String, Array] field_or_spec either either a single field name
402
- # or an array of [field name, direction] pairs. Directions should be specified as
403
- # Mongo::ASCENDING or Mongo::DESCENDING.
404
- # @param [Boolean] unique if +true+, the created index will enforce a uniqueness constraint.
405
- #
406
- # @return [String] the name of the index created.
407
- #
408
- # @deprecated
409
- def create_index(collection_name, field_or_spec, unique=false)
410
- warn "DB#create_index is now deprecated. Please use Collection#create_index instead."
411
- self.collection(collection_name).create_index(field_or_spec, :unique => unique)
412
- end
413
-
414
434
  # Return +true+ if the supplied +doc+ contains an 'ok' field with the value 1.
415
435
  #
416
436
  # @param [Hash] doc
417
437
  #
418
438
  # @return [Boolean]
419
439
  def ok?(doc)
420
- ok = doc['ok']
421
- ok.kind_of?(Numeric) && ok.to_i == 1
440
+ Mongo::Support.ok?(doc)
422
441
  end
423
442
 
424
443
  # Send a command to the database.
@@ -431,29 +450,34 @@ module Mongo
431
450
  # to see how it works.
432
451
  #
433
452
  # @param [OrderedHash, Hash] selector an OrderedHash, or a standard Hash with just one
434
- # key, specifying the command to be performed.
453
+ # key, specifying the command to be performed. In Ruby 1.9, OrderedHash isn't necessary since
454
+ # hashes are ordered by default.
435
455
  #
436
- # @param [Boolean] admin If +true+, the command will be executed on the admin
437
- # collection.
438
- #
439
- # @param [Boolean] check_response If +true+, will raise an exception if the
456
+ # @option opts [Boolean] :check_response (true) If +true+, raises an exception if the
440
457
  # command fails.
441
- #
442
- # @param [Socket] sock a socket to use. This is mainly for internal use.
458
+ # @option opts [Socket] :sock a socket to use for sending the command. This is mainly for internal use.
443
459
  #
444
460
  # @return [Hash]
445
461
  #
446
462
  # @core commands command_instance-method
447
- def command(selector, admin=false, check_response=false, sock=nil)
463
+ def command(selector, opts={})
464
+ check_response = opts.fetch(:check_response, true)
465
+ sock = opts[:sock]
448
466
  raise MongoArgumentError, "command must be given a selector" unless selector.is_a?(Hash) && !selector.empty?
449
- if selector.class.eql?(Hash) && selector.keys.length > 1
467
+ if selector.keys.length > 1 && RUBY_VERSION < '1.9' && selector.class != BSON::OrderedHash
450
468
  raise MongoArgumentError, "DB#command requires an OrderedHash when hash contains multiple keys"
451
469
  end
452
470
 
453
- result = Cursor.new(system_command_collection, :admin => admin,
454
- :limit => -1, :selector => selector, :socket => sock).next_document
471
+ begin
472
+ result = Cursor.new(system_command_collection,
473
+ :limit => -1, :selector => selector, :socket => sock).next_document
474
+ rescue OperationFailure => ex
475
+ raise OperationFailure, "Database command '#{selector.keys.first}' failed: #{ex.message}"
476
+ end
455
477
 
456
- if check_response && !ok?(result)
478
+ if result.nil?
479
+ raise OperationFailure, "Database command '#{selector.keys.first}' failed: returned null."
480
+ elsif (check_response && !ok?(result))
457
481
  raise OperationFailure, "Database command '#{selector.keys.first}' failed: #{result.inspect}"
458
482
  else
459
483
  result
@@ -494,9 +518,9 @@ module Mongo
494
518
  #
495
519
  # @core profiling profiling_level-instance_method
496
520
  def profiling_level
497
- oh = OrderedHash.new
521
+ oh = BSON::OrderedHash.new
498
522
  oh[:profile] = -1
499
- doc = command(oh)
523
+ doc = command(oh, :check_response => false)
500
524
  raise "Error with profile command: #{doc.inspect}" unless ok?(doc) && doc['was'].kind_of?(Numeric)
501
525
  case doc['was'].to_i
502
526
  when 0
@@ -515,7 +539,7 @@ module Mongo
515
539
  #
516
540
  # @param [Symbol] level acceptable options are +:off+, +:slow_only+, or +:all+.
517
541
  def profiling_level=(level)
518
- oh = OrderedHash.new
542
+ oh = BSON::OrderedHash.new
519
543
  oh[:profile] = case level
520
544
  when :off
521
545
  0
@@ -526,7 +550,7 @@ module Mongo
526
550
  else
527
551
  raise "Error: illegal profiling level value #{level}"
528
552
  end
529
- doc = command(oh)
553
+ doc = command(oh, :check_response => false)
530
554
  ok?(doc) || raise(MongoDBError, "Error with profile command: #{doc.inspect}")
531
555
  end
532
556
 
@@ -546,7 +570,7 @@ module Mongo
546
570
  # @raise [MongoDBError] if the command fails or there's a problem with the validation
547
571
  # data, or if the collection is invalid.
548
572
  def validate_collection(name)
549
- doc = command(:validate => name)
573
+ doc = command({:validate => name}, :check_response => false)
550
574
  raise MongoDBError, "Error with validate command: #{doc.inspect}" unless ok?(doc)
551
575
  result = doc['result']
552
576
  raise MongoDBError, "Error with validation data: #{doc.inspect}" unless result.kind_of?(String)
@@ -1,3 +1,6 @@
1
+ # encoding: UTF-8
2
+
3
+ #
1
4
  # --
2
5
  # Copyright (C) 2008-2010 10gen Inc.
3
6
  #
@@ -39,6 +42,9 @@ module Mongo
39
42
  # Raised on failures in connection to the database server.
40
43
  class ConnectionError < MongoRubyError; end
41
44
 
45
+ # Raised on failures in connection to the database server.
46
+ class ReplicaSetConnectionError < ConnectionError; end
47
+
42
48
  # Raised on failures in connection to the database server.
43
49
  class ConnectionTimeoutError < MongoRubyError; end
44
50
 
@@ -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
@@ -34,30 +38,34 @@ module Mongo
34
38
  @chunks = @db["#{fs_name}.chunks"]
35
39
  @fs_name = fs_name
36
40
 
37
- @chunks.create_index([['files_id', Mongo::ASCENDING], ['n', Mongo::ASCENDING]], :unique => true)
41
+ # Ensure indexes only if not connected to slave.
42
+ unless db.connection.slave_ok?
43
+ @chunks.create_index([['files_id', Mongo::ASCENDING], ['n', Mongo::ASCENDING]], :unique => true)
44
+ end
38
45
  end
39
46
 
40
- # Store a file in the file store.
47
+ # Store a file in the file store. This method is designed only for writing new files;
48
+ # if you need to update a given file, first delete it using Grid#delete.
41
49
  #
42
50
  # Note that arbitary metadata attributes can be saved to the file by passing
43
- # them is as options.
51
+ # them in as options.
44
52
  #
45
53
  # @param [String, #read] data a string or io-like object to store.
46
54
  #
47
- # @options opts [String] :filename (nil) a name for the file.
48
- # @options opts [Hash] :metadata ({}) any additional data to store with the file.
49
- # @options opts [ObjectID] :_id (ObjectID) a unique id for
55
+ # @option opts [String] :filename (nil) a name for the file.
56
+ # @option opts [Hash] :metadata ({}) any additional data to store with the file.
57
+ # @option opts [ObjectId] :_id (ObjectId) a unique id for
50
58
  # the file to be use in lieu of an automatically generated one.
51
- # @options opts [String] :content_type ('binary/octet-stream') If no content type is specified,
59
+ # @option opts [String] :content_type ('binary/octet-stream') If no content type is specified,
52
60
  # the content type will may be inferred from the filename extension if the mime-types gem can be
53
61
  # loaded. Otherwise, the content type 'binary/octet-stream' will be used.
54
- # @options opts [Integer] (262144) :chunk_size size of file chunks in bytes.
55
- # @options opts [Boolean] :safe (false) When safe mode is enabled, the chunks sent to the server
62
+ # @option opts [Integer] (262144) :chunk_size size of file chunks in bytes.
63
+ # @option opts [Boolean] :safe (false) When safe mode is enabled, the chunks sent to the server
56
64
  # will be validated using an md5 hash. If validation fails, an exception will be raised.
57
65
  #
58
- # @return [Mongo::ObjectID] the file's id.
66
+ # @return [Mongo::ObjectId] the file's id.
59
67
  def put(data, opts={})
60
- filename = opts[:filename]
68
+ filename = opts.delete :filename
61
69
  opts.merge!(default_grid_io_opts)
62
70
  file = GridIO.new(@files, @chunks, filename, 'w', opts=opts)
63
71
  file.write(data)
@@ -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 ClassMethods
19
-
20
- def exists?(criteria)
21
- BSON::ObjectID:
22
- @files.find_one(query)
23
- end
20
+ module GridExt
21
+ module InstanceMethods
24
22
 
25
- def list(query={})
26
- @files.find(query)
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 Grid instance, consisting of a MongoDB database
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.
@@ -36,8 +39,11 @@ module Mongo
36
39
 
37
40
  @default_query_opts = {:sort => [['filename', 1], ['uploadDate', -1]], :limit => 1}
38
41
 
39
- @files.create_index([['filename', 1], ['uploadDate', -1]])
40
- @chunks.create_index([['files_id', Mongo::ASCENDING], ['n', Mongo::ASCENDING]], :unique => true)
42
+ # Ensure indexes only if not connected to slave.
43
+ unless db.connection.slave_ok?
44
+ @files.create_index([['filename', 1], ['uploadDate', -1]])
45
+ @chunks.create_index([['files_id', Mongo::ASCENDING], ['n', Mongo::ASCENDING]], :unique => true)
46
+ end
41
47
  end
42
48
 
43
49
  # Open a file for reading or writing. Note that the options for this method only apply
@@ -51,17 +57,17 @@ module Mongo
51
57
  # or writing to the file.
52
58
  # @param [Hash] opts see GridIO#new
53
59
  #
54
- # @options opts [Hash] :metadata ({}) any additional data to store with the file.
55
- # @options opts [ObjectID] :_id (ObjectID) a unique id for
60
+ # @option opts [Hash] :metadata ({}) any additional data to store with the file.
61
+ # @option opts [ObjectId] :_id (ObjectId) a unique id for
56
62
  # the file to be use in lieu of an automatically generated one.
57
- # @options opts [String] :content_type ('binary/octet-stream') If no content type is specified,
63
+ # @option opts [String] :content_type ('binary/octet-stream') If no content type is specified,
58
64
  # the content type will may be inferred from the filename extension if the mime-types gem can be
59
65
  # loaded. Otherwise, the content type 'binary/octet-stream' will be used.
60
- # @options opts [Integer] (262144) :chunk_size size of file chunks in bytes.
61
- # @options opts [Boolean] :delete_old (false) ensure that old versions of the file are deleted. This option
66
+ # @option opts [Integer] (262144) :chunk_size size of file chunks in bytes.
67
+ # @option opts [Boolean] :delete_old (false) ensure that old versions of the file are deleted. This option
62
68
  # only work in 'w' mode. Certain precautions must be taken when deleting GridFS files. See the notes under
63
69
  # GridFileSystem#delete.
64
- # @options opts [Boolean] :safe (false) When safe mode is enabled, the chunks sent to the server
70
+ # @option opts [Boolean] :safe (false) When safe mode is enabled, the chunks sent to the server
65
71
  # will be validated using an md5 hash. If validation fails, an exception will be raised.
66
72
  #
67
73
  # @example