kbaum-mongo 0.18.3p

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 (72) hide show
  1. data/LICENSE.txt +202 -0
  2. data/README.rdoc +339 -0
  3. data/Rakefile +138 -0
  4. data/bin/bson_benchmark.rb +59 -0
  5. data/bin/fail_if_no_c.rb +11 -0
  6. data/examples/admin.rb +42 -0
  7. data/examples/capped.rb +22 -0
  8. data/examples/cursor.rb +48 -0
  9. data/examples/gridfs.rb +88 -0
  10. data/examples/index_test.rb +126 -0
  11. data/examples/info.rb +31 -0
  12. data/examples/queries.rb +70 -0
  13. data/examples/simple.rb +24 -0
  14. data/examples/strict.rb +35 -0
  15. data/examples/types.rb +36 -0
  16. data/lib/mongo/collection.rb +609 -0
  17. data/lib/mongo/connection.rb +672 -0
  18. data/lib/mongo/cursor.rb +403 -0
  19. data/lib/mongo/db.rb +555 -0
  20. data/lib/mongo/exceptions.rb +66 -0
  21. data/lib/mongo/gridfs/chunk.rb +91 -0
  22. data/lib/mongo/gridfs/grid.rb +79 -0
  23. data/lib/mongo/gridfs/grid_file_system.rb +101 -0
  24. data/lib/mongo/gridfs/grid_io.rb +338 -0
  25. data/lib/mongo/gridfs/grid_store.rb +580 -0
  26. data/lib/mongo/gridfs.rb +25 -0
  27. data/lib/mongo/types/binary.rb +52 -0
  28. data/lib/mongo/types/code.rb +36 -0
  29. data/lib/mongo/types/dbref.rb +40 -0
  30. data/lib/mongo/types/min_max_keys.rb +58 -0
  31. data/lib/mongo/types/objectid.rb +180 -0
  32. data/lib/mongo/types/regexp_of_holding.rb +45 -0
  33. data/lib/mongo/util/bson_c.rb +18 -0
  34. data/lib/mongo/util/bson_ruby.rb +606 -0
  35. data/lib/mongo/util/byte_buffer.rb +222 -0
  36. data/lib/mongo/util/conversions.rb +87 -0
  37. data/lib/mongo/util/ordered_hash.rb +140 -0
  38. data/lib/mongo/util/server_version.rb +69 -0
  39. data/lib/mongo/util/support.rb +26 -0
  40. data/lib/mongo.rb +63 -0
  41. data/mongo-ruby-driver.gemspec +28 -0
  42. data/test/auxillary/autoreconnect_test.rb +42 -0
  43. data/test/binary_test.rb +15 -0
  44. data/test/bson_test.rb +427 -0
  45. data/test/byte_buffer_test.rb +81 -0
  46. data/test/chunk_test.rb +82 -0
  47. data/test/collection_test.rb +515 -0
  48. data/test/connection_test.rb +160 -0
  49. data/test/conversions_test.rb +120 -0
  50. data/test/cursor_test.rb +379 -0
  51. data/test/db_api_test.rb +780 -0
  52. data/test/db_connection_test.rb +16 -0
  53. data/test/db_test.rb +272 -0
  54. data/test/grid_file_system_test.rb +210 -0
  55. data/test/grid_io_test.rb +78 -0
  56. data/test/grid_store_test.rb +334 -0
  57. data/test/grid_test.rb +87 -0
  58. data/test/objectid_test.rb +125 -0
  59. data/test/ordered_hash_test.rb +172 -0
  60. data/test/replica/count_test.rb +34 -0
  61. data/test/replica/insert_test.rb +50 -0
  62. data/test/replica/pooled_insert_test.rb +54 -0
  63. data/test/replica/query_test.rb +39 -0
  64. data/test/slave_connection_test.rb +36 -0
  65. data/test/test_helper.rb +42 -0
  66. data/test/threading/test_threading_large_pool.rb +90 -0
  67. data/test/threading_test.rb +87 -0
  68. data/test/unit/collection_test.rb +61 -0
  69. data/test/unit/connection_test.rb +117 -0
  70. data/test/unit/cursor_test.rb +93 -0
  71. data/test/unit/db_test.rb +98 -0
  72. metadata +127 -0
data/lib/mongo/db.rb ADDED
@@ -0,0 +1,555 @@
1
+ # --
2
+ # Copyright (C) 2008-2010 10gen Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ # ++
16
+
17
+ require 'socket'
18
+ require 'timeout'
19
+ require 'digest/md5'
20
+ require 'thread'
21
+
22
+ module Mongo
23
+
24
+ # A MongoDB database.
25
+ class DB
26
+
27
+ SYSTEM_NAMESPACE_COLLECTION = "system.namespaces"
28
+ SYSTEM_INDEX_COLLECTION = "system.indexes"
29
+ SYSTEM_PROFILE_COLLECTION = "system.profile"
30
+ SYSTEM_USER_COLLECTION = "system.users"
31
+ SYSTEM_COMMAND_COLLECTION = "$cmd"
32
+
33
+ # Counter for generating unique request ids.
34
+ @@current_request_id = 0
35
+
36
+ # Strict mode enforces collection existence checks. When +true+,
37
+ # asking for a collection that does not exist, or trying to create a
38
+ # collection that already exists, raises an error.
39
+ #
40
+ # Strict mode is disabled by default, but enabled (+true+) at any time.
41
+ attr_writer :strict
42
+
43
+ # Returns the value of the +strict+ flag.
44
+ def strict?; @strict; end
45
+
46
+ # The name of the database.
47
+ attr_reader :name
48
+
49
+ # The Mongo::Connection instance connecting to the MongoDB server.
50
+ attr_reader :connection
51
+
52
+ # Instances of DB are normally obtained by calling Mongo#db.
53
+ #
54
+ # @param [String] db_name the database name.
55
+ # @param [Mongo::Connection] connection a connection object pointing to MongoDB. Note
56
+ # that databases are usually instantiated via the Connection class. See the examples below.
57
+ #
58
+ # @option options [Boolean] strict (False) If true, collections must exist to be accessed and must
59
+ # not exist to be created. See DB#collection and DB#create_collection.
60
+ #
61
+ # @option options [Object, #create_pk(doc)] pk (Mongo::ObjectID) A primary key factory object,
62
+ # which should take a hash and return a hash which merges the original hash with any primary key
63
+ # fields the factory wishes to inject. (NOTE: if the object already has a primary key,
64
+ # the factory should not inject a new key).
65
+ #
66
+ # @core databases constructor_details
67
+ def initialize(db_name, connection, options={})
68
+ @name = validate_db_name(db_name)
69
+ @connection = connection
70
+ @strict = options[:strict]
71
+ @pk_factory = options[:pk]
72
+ end
73
+
74
+ # Authenticate with the given username and password. Note that mongod
75
+ # must be started with the --auth option for authentication to be enabled.
76
+ #
77
+ # @param [String] username
78
+ # @param [String] password
79
+ #
80
+ # @return [Boolean]
81
+ #
82
+ # @raise [AuthenticationError]
83
+ #
84
+ # @core authenticate authenticate-instance_method
85
+ def authenticate(username, password)
86
+ doc = command(:getnonce => 1)
87
+ raise "error retrieving nonce: #{doc}" unless ok?(doc)
88
+ nonce = doc['nonce']
89
+
90
+ auth = OrderedHash.new
91
+ auth['authenticate'] = 1
92
+ auth['user'] = username
93
+ auth['nonce'] = nonce
94
+ auth['key'] = Digest::MD5.hexdigest("#{nonce}#{username}#{hash_password(username, password)}")
95
+ ok?(command(auth)) ||
96
+ raise(MongoDBError::AuthenticationError, "Failed to authenticate user '#{username}' on db '#{self.name}'")
97
+ end
98
+
99
+ # Adds a user to this database for use with authentication. If the user already
100
+ # exists in the system, the password will be updated.
101
+ #
102
+ # @param [String] username
103
+ # @param [String] password
104
+ #
105
+ # @return [Hash] an object representing the user.
106
+ def add_user(username, password)
107
+ users = self[SYSTEM_USER_COLLECTION]
108
+ user = users.find_one({:user => username}) || {:user => username}
109
+ user['pwd'] = hash_password(username, password)
110
+ users.save(user)
111
+ return user
112
+ end
113
+
114
+ # Remove the given user from this database. Returns false if the user
115
+ # doesn't exist in the system.
116
+ #
117
+ # @param [String] username
118
+ #
119
+ # @return [Boolean]
120
+ def remove_user(username)
121
+ if self[SYSTEM_USER_COLLECTION].find_one({:user => username})
122
+ self[SYSTEM_USER_COLLECTION].remove({:user => username}, :safe => true)
123
+ else
124
+ return false
125
+ end
126
+ end
127
+
128
+ # Deauthorizes use for this database for this connection.
129
+ #
130
+ # @raise [MongoDBError] if logging out fails.
131
+ #
132
+ # @return [Boolean]
133
+ def logout
134
+ doc = command(:logout => 1)
135
+ return true if ok?(doc)
136
+ raise MongoDBError, "error logging out: #{doc.inspect}"
137
+ end
138
+
139
+ # Get an array of collection names in this database.
140
+ #
141
+ # @return [Array]
142
+ def collection_names
143
+ names = collections_info.collect { |doc| doc['name'] || '' }
144
+ names = names.delete_if {|name| name.index(@name).nil? || name.index('$')}
145
+ names.map {|name| name.sub(@name + '.', '')}
146
+ end
147
+
148
+ # Get an array of Collection instances, one for each collection in this database.
149
+ #
150
+ # @return [Array<Mongo::Collection>]
151
+ def collections
152
+ collection_names.map do |collection_name|
153
+ Collection.new(self, collection_name)
154
+ end
155
+ end
156
+
157
+ # Get info on system namespaces (collections). This method returns
158
+ # a cursor which can be iterated over. For each collection, a hash
159
+ # will be yielded containing a 'name' string and, optionally, an 'options' hash.
160
+ #
161
+ # @param [String] coll_name return info for the specifed collection only.
162
+ #
163
+ # @return [Mongo::Cursor]
164
+ def collections_info(coll_name=nil)
165
+ selector = {}
166
+ selector[:name] = full_collection_name(coll_name) if coll_name
167
+ Cursor.new(Collection.new(self, SYSTEM_NAMESPACE_COLLECTION), :selector => selector)
168
+ end
169
+
170
+ # Create a collection.
171
+ #
172
+ # new collection. If +strict+ is true, will raise an error if
173
+ # collection +name+ already exists.
174
+ #
175
+ # @param [String] name the name of the new collection.
176
+ #
177
+ # @option options [Boolean] :capped (False) created a capped collection.
178
+ #
179
+ # @option options [Integer] :size (Nil) If +capped+ is +true+, specifies the maximum number of
180
+ # bytes for the capped collection. If +false+, specifies the number of bytes allocated
181
+ # for the initial extent of the collection.
182
+ #
183
+ # @option options [Integer] :max (Nil) If +capped+ is +true+, indicates the maximum number of records
184
+ # in a capped collection.
185
+ #
186
+ # @raise [MongoDBError] raised under two conditions: either we're in +strict+ mode and the collection
187
+ # already exists or collection creation fails on the server.
188
+ #
189
+ # @return [Mongo::Collection]
190
+ def create_collection(name, options={})
191
+ # Does the collection already exist?
192
+ if collection_names.include?(name)
193
+ if strict?
194
+ raise MongoDBError, "Collection #{name} already exists. Currently in strict mode."
195
+ else
196
+ return Collection.new(self, name)
197
+ end
198
+ end
199
+
200
+ # Create a new collection.
201
+ oh = OrderedHash.new
202
+ oh[:create] = name
203
+ doc = command(oh.merge(options || {}))
204
+ ok = doc['ok']
205
+ return Collection.new(self, name, @pk_factory) if ok.kind_of?(Numeric) && (ok.to_i == 1 || ok.to_i == 0)
206
+ raise MongoDBError, "Error creating collection: #{doc.inspect}"
207
+ end
208
+
209
+ # Get a collection by name.
210
+ #
211
+ # @param [String] name the collection name.
212
+ #
213
+ # @raise [MongoDBError] if collection does not already exist and we're in +strict+ mode.
214
+ #
215
+ # @return [Mongo::Collection]
216
+ def collection(name)
217
+ return Collection.new(self, name, @pk_factory) if !strict? || collection_names.include?(name)
218
+ raise MongoDBError, "Collection #{name} doesn't exist. Currently in strict mode."
219
+ end
220
+ alias_method :[], :collection
221
+
222
+ # Drop a collection by +name+.
223
+ #
224
+ # @param [String] name
225
+ #
226
+ # @return [Boolean] True on success or if the collection names doesn't exist.
227
+ def drop_collection(name)
228
+ return true unless collection_names.include?(name)
229
+
230
+ ok?(command(:drop => name))
231
+ end
232
+
233
+ # Get the error message from the most recently executed database
234
+ # operation for this connection.
235
+ #
236
+ # @return [String, Nil] either the text describing the error or nil if no
237
+ # error has occurred.
238
+ def error
239
+ doc = command(:getlasterror => 1)
240
+ raise MongoDBError, "error retrieving last error: #{doc}" unless ok?(doc)
241
+ doc['err']
242
+ end
243
+
244
+ # Get status information from the last operation on this connection.
245
+ #
246
+ # @return [Hash] a hash representing the status of the last db op.
247
+ def last_status
248
+ command(:getlasterror => 1)
249
+ end
250
+
251
+ # Return +true+ if an error was caused by the most recently executed
252
+ # database operation.
253
+ #
254
+ # @return [Boolean]
255
+ def error?
256
+ error != nil
257
+ end
258
+
259
+ # Get the most recent error to have occured on this database.
260
+ #
261
+ # This command only returns errors that have occured since the last call to
262
+ # DB#reset_error_history - returns +nil+ if there is no such error.
263
+ #
264
+ # @return [String, Nil] the text of the error or +nil+ if no error has occurred.
265
+ def previous_error
266
+ error = command(:getpreverror => 1)
267
+ if error["err"]
268
+ error
269
+ else
270
+ nil
271
+ end
272
+ end
273
+
274
+ # Reset the error history of this database
275
+ #
276
+ # Calls to DB#previous_error will only return errors that have occurred
277
+ # since the most recent call to this method.
278
+ #
279
+ # @return [Hash]
280
+ def reset_error_history
281
+ command(:reseterror => 1)
282
+ end
283
+
284
+ # @deprecated please use Collection#find to create queries.
285
+ #
286
+ # Returns a Cursor over the query results.
287
+ #
288
+ # Note that the query gets sent lazily; the cursor calls
289
+ # Connection#send_message when needed. If the caller never requests an
290
+ # object from the cursor, the query never gets sent.
291
+ def query(collection, query, admin=false)
292
+ Cursor.new(self, collection, query, admin)
293
+ end
294
+
295
+ # Dereference a DBRef, returning the document it points to.
296
+ #
297
+ # @param [Mongo::DBRef] dbref
298
+ #
299
+ # @return [Hash] the document indicated by the db reference.
300
+ #
301
+ # @see http://www.mongodb.org/display/DOCS/DB+Ref MongoDB DBRef spec.
302
+ def dereference(dbref)
303
+ collection(dbref.namespace).find_one("_id" => dbref.object_id)
304
+ end
305
+
306
+ # Evaluate a JavaScript expression in MongoDB.
307
+ #
308
+ # @param [String, Code] code a JavaScript expression to evaluate server-side.
309
+ # @param [Integer, Hash] args any additional argument to be passed to the +code+ expression when
310
+ # it's run on the server.
311
+ #
312
+ # @return [String] the return value of the function.
313
+ def eval(code, *args)
314
+ if not code.is_a? Code
315
+ code = Code.new(code)
316
+ end
317
+
318
+ oh = OrderedHash.new
319
+ oh[:$eval] = code
320
+ oh[:args] = args
321
+ doc = command(oh)
322
+ return doc['retval'] if ok?(doc)
323
+ raise OperationFailure, "eval failed: #{doc['errmsg']}"
324
+ end
325
+
326
+ # Rename a collection.
327
+ #
328
+ # @param [String] from original collection name.
329
+ # @param [String] to new collection name.
330
+ #
331
+ # @return [True] returns +true+ on success.
332
+ #
333
+ # @raise MongoDBError if there's an error renaming the collection.
334
+ def rename_collection(from, to)
335
+ oh = OrderedHash.new
336
+ oh[:renameCollection] = "#{@name}.#{from}"
337
+ oh[:to] = "#{@name}.#{to}"
338
+ doc = command(oh, true)
339
+ ok?(doc) || raise(MongoDBError, "Error renaming collection: #{doc.inspect}")
340
+ end
341
+
342
+ # Drop an index from a given collection. Normally called from
343
+ # Collection#drop_index or Collection#drop_indexes.
344
+ #
345
+ # @param [String] collection_name
346
+ # @param [String] index_name
347
+ #
348
+ # @return [True] returns +true+ on success.
349
+ #
350
+ # @raise MongoDBError if there's an error renaming the collection.
351
+ def drop_index(collection_name, index_name)
352
+ oh = OrderedHash.new
353
+ oh[:deleteIndexes] = collection_name
354
+ oh[:index] = index_name
355
+ doc = command(oh)
356
+ ok?(doc) || raise(MongoDBError, "Error with drop_index command: #{doc.inspect}")
357
+ end
358
+
359
+ # Get information on the indexes for the given collection.
360
+ # Normally called by Collection#index_information.
361
+ #
362
+ # @param [String] collection_name
363
+ #
364
+ # @return [Hash] keys are index names and the values are lists of [key, direction] pairs
365
+ # defining the index.
366
+ def index_information(collection_name)
367
+ sel = {:ns => full_collection_name(collection_name)}
368
+ info = {}
369
+ Cursor.new(Collection.new(self, SYSTEM_INDEX_COLLECTION), :selector => sel).each { |index|
370
+ info[index['name']] = index['key'].map {|k| k}
371
+ }
372
+ info
373
+ end
374
+
375
+ # Create a new index on the given collection.
376
+ # Normally called by Collection#create_index.
377
+ #
378
+ # @param [String] collection_name
379
+ # @param [String, Array] field_or_spec either either a single field name
380
+ # or an array of [field name, direction] pairs. Directions should be specified as
381
+ # Mongo::ASCENDING or Mongo::DESCENDING.
382
+ # @param [Boolean] unique if +true+, the created index will enforce a uniqueness constraint.
383
+ #
384
+ # @return [String] the name of the index created.
385
+ def create_index(collection_name, field_or_spec, unique=false)
386
+ self.collection(collection_name).create_index(field_or_spec, unique)
387
+ end
388
+
389
+ # Return +true+ if the supplied +doc+ contains an 'ok' field with the value 1.
390
+ #
391
+ # @param [Hash] doc
392
+ #
393
+ # @return [Boolean]
394
+ def ok?(doc)
395
+ ok = doc['ok']
396
+ ok.kind_of?(Numeric) && ok.to_i == 1
397
+ end
398
+
399
+ # Send a command to the database.
400
+ #
401
+ # Note: DB commands must start with the "command" key. For this reason,
402
+ # any selector containing more than one key must be an OrderedHash.
403
+ #
404
+ # It may be of interest hat a command in MongoDB is technically a kind of query
405
+ # that occurs on the system command collection ($cmd).
406
+ #
407
+ # @param [OrderedHash, Hash] selector an OrderedHash, or a standard Hash with just one
408
+ # key, specifying the command to be performed.
409
+ #
410
+ # @param [Boolean] admin If +true+, the command will be executed on the admin
411
+ # collection.
412
+ #
413
+ # @param [Boolean] check_response If +true+, will raise an exception if the
414
+ # command fails.
415
+ #
416
+ # @param [Socket] sock a socket to use. This is mainly for internal use.
417
+ #
418
+ # @return [Hash]
419
+ #
420
+ # @core commands command_instance-method
421
+ def command(selector, admin=false, check_response=false, sock=nil)
422
+ raise MongoArgumentError, "command must be given a selector" unless selector.is_a?(Hash) && !selector.empty?
423
+ if selector.class.eql?(Hash) && selector.keys.length > 1
424
+ raise MongoArgumentError, "DB#command requires an OrderedHash when hash contains multiple keys"
425
+ end
426
+
427
+ result = Cursor.new(system_command_collection, :admin => admin,
428
+ :limit => -1, :selector => selector, :socket => sock).next_document
429
+
430
+ if check_response && !ok?(result)
431
+ raise OperationFailure, "Database command '#{selector.keys.first}' failed."
432
+ else
433
+ result
434
+ end
435
+ end
436
+
437
+ # A shortcut returning db plus dot plus collection name.
438
+ #
439
+ # @param [String] collection_name
440
+ #
441
+ # @return [String]
442
+ def full_collection_name(collection_name)
443
+ "#{@name}.#{collection_name}"
444
+ end
445
+
446
+ # The primary key factory object (or +nil+).
447
+ #
448
+ # @return [Object, Nil]
449
+ def pk_factory
450
+ @pk_factory
451
+ end
452
+
453
+ # Specify a primary key factory if not already set.
454
+ #
455
+ # @raise [MongoArgumentError] if the primary key factory has already been set.
456
+ def pk_factory=(pk_factory)
457
+ if @pk_factory
458
+ raise MongoArgumentError, "Cannot change primary key factory once it's been set"
459
+ end
460
+
461
+ @pk_factory = pk_factory
462
+ end
463
+
464
+ # Return the current database profiling level. If profiling is enabled, you can
465
+ # get the results using DB#profiling_info.
466
+ #
467
+ # @return [Symbol] :off, :slow_only, or :all
468
+ #
469
+ # @core profiling profiling_level-instance_method
470
+ def profiling_level
471
+ oh = OrderedHash.new
472
+ oh[:profile] = -1
473
+ doc = command(oh)
474
+ raise "Error with profile command: #{doc.inspect}" unless ok?(doc) && doc['was'].kind_of?(Numeric)
475
+ case doc['was'].to_i
476
+ when 0
477
+ :off
478
+ when 1
479
+ :slow_only
480
+ when 2
481
+ :all
482
+ else
483
+ raise "Error: illegal profiling level value #{doc['was']}"
484
+ end
485
+ end
486
+
487
+ # Set this database's profiling level. If profiling is enabled, you can
488
+ # get the results using DB#profiling_info.
489
+ #
490
+ # @param [Symbol] level acceptable options are +:off+, +:slow_only+, or +:all+.
491
+ def profiling_level=(level)
492
+ oh = OrderedHash.new
493
+ oh[:profile] = case level
494
+ when :off
495
+ 0
496
+ when :slow_only
497
+ 1
498
+ when :all
499
+ 2
500
+ else
501
+ raise "Error: illegal profiling level value #{level}"
502
+ end
503
+ doc = command(oh)
504
+ ok?(doc) || raise(MongoDBError, "Error with profile command: #{doc.inspect}")
505
+ end
506
+
507
+ # Get the current profiling information.
508
+ #
509
+ # @return [Array] a list of documents containing profiling information.
510
+ def profiling_info
511
+ Cursor.new(Collection.new(self, DB::SYSTEM_PROFILE_COLLECTION), :selector => {}).to_a
512
+ end
513
+
514
+ # Validate a named collection.
515
+ #
516
+ # @param [String] name the collection name.
517
+ #
518
+ # @return [Hash] validation information.
519
+ #
520
+ # @raise [MongoDBError] if the command fails or there's a problem with the validation
521
+ # data, or if the collection is invalid.
522
+ def validate_collection(name)
523
+ doc = command(:validate => name)
524
+ raise MongoDBError, "Error with validate command: #{doc.inspect}" unless ok?(doc)
525
+ result = doc['result']
526
+ raise MongoDBError, "Error with validation data: #{doc.inspect}" unless result.kind_of?(String)
527
+ raise MongoDBError, "Error: invalid collection #{name}: #{doc.inspect}" if result =~ /\b(exception|corrupt)\b/i
528
+ doc
529
+ end
530
+
531
+ private
532
+
533
+ def hash_password(username, plaintext)
534
+ Digest::MD5.hexdigest("#{username}:mongo:#{plaintext}")
535
+ end
536
+
537
+ def system_command_collection
538
+ Collection.new(self, SYSTEM_COMMAND_COLLECTION)
539
+ end
540
+
541
+ def validate_db_name(db_name)
542
+ unless [String, Symbol].include?(db_name.class)
543
+ raise TypeError, "db_name must be a string or symbol"
544
+ end
545
+
546
+ [" ", ".", "$", "/", "\\"].each do |invalid_char|
547
+ if db_name.include? invalid_char
548
+ raise InvalidName, "database names cannot contain the character '#{invalid_char}'"
549
+ end
550
+ end
551
+ raise InvalidName, "database name cannot be the empty string" if db_name.empty?
552
+ db_name
553
+ end
554
+ end
555
+ end
@@ -0,0 +1,66 @@
1
+ # --
2
+ # Copyright (C) 2008-2010 10gen Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ # ++
16
+
17
+ module Mongo
18
+ # Generic Mongo Ruby Driver exception class.
19
+ class MongoRubyError < StandardError; end
20
+
21
+ # Raised when MongoDB itself has returned an error.
22
+ class MongoDBError < RuntimeError; end
23
+
24
+ # Raised when configuration options cause connections, queries, etc., to fail.
25
+ class ConfigurationError < MongoRubyError; end
26
+
27
+ # Raised with fatal errors to GridFS.
28
+ class GridError < MongoRubyError; end
29
+
30
+ # Raised when invalid arguments are sent to Mongo Ruby methods.
31
+ class MongoArgumentError < MongoRubyError; end
32
+
33
+ # Raised when given a string is not valid utf-8 (Ruby 1.8 only).
34
+ class InvalidStringEncoding < MongoRubyError; end
35
+
36
+ # Raised when attempting to initialize an invalid ObjectID.
37
+ class InvalidObjectID < MongoRubyError; end
38
+
39
+ # Raised on failures in connection to the database server.
40
+ class ConnectionError < MongoRubyError; end
41
+
42
+ # Raised on failures in connection to the database server.
43
+ class ConnectionTimeoutError < MongoRubyError; end
44
+
45
+ # Raised when trying to insert a document that exceeds the 4MB limit or
46
+ # when the document contains objects that can't be serialized as BSON.
47
+ class InvalidDocument < MongoDBError; end
48
+
49
+ # Raised when authentication fails.
50
+ class AuthenticationError < MongoDBError; end
51
+
52
+ # Raised when a database operation fails.
53
+ class OperationFailure < MongoDBError; end
54
+
55
+ # Raised when a connection operation fails.
56
+ class ConnectionFailure < MongoDBError; end
57
+
58
+ # Raised when a client attempts to perform an invalid operation.
59
+ class InvalidOperation < MongoDBError; end
60
+
61
+ # Raised when an invalid name is used.
62
+ class InvalidName < RuntimeError; end
63
+
64
+ # Raised when the client supplies an invalid value to sort by.
65
+ class InvalidSortValueError < MongoRubyError; end
66
+ end
@@ -0,0 +1,91 @@
1
+ # --
2
+ # Copyright (C) 2008-2010 10gen Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ # ++
16
+
17
+ require 'mongo/types/objectid'
18
+ require 'mongo/util/byte_buffer'
19
+ require 'mongo/util/ordered_hash'
20
+
21
+ module GridFS
22
+
23
+ # A chunk stores a portion of GridStore data.
24
+ # @deprecated
25
+ class Chunk
26
+
27
+ DEFAULT_CHUNK_SIZE = 1024 * 256
28
+
29
+ attr_reader :object_id, :chunk_number
30
+ attr_accessor :data
31
+
32
+ def initialize(file, mongo_object={})
33
+ @file = file
34
+ @object_id = mongo_object['_id'] || Mongo::ObjectID.new
35
+ @chunk_number = mongo_object['n'] || 0
36
+
37
+ @data = ByteBuffer.new
38
+ case mongo_object['data']
39
+ when String
40
+ mongo_object['data'].each_byte { |b| @data.put(b) }
41
+ when ByteBuffer
42
+ @data.put_array(mongo_object['data'].to_a)
43
+ when Array
44
+ @data.put_array(mongo_object['data'])
45
+ when nil
46
+ else
47
+ raise "illegal chunk format; data is #{mongo_object['data'] ? (' ' + mongo_object['data'].class.name) : 'nil'}"
48
+ end
49
+ @data.rewind
50
+ end
51
+
52
+ def pos; @data.position; end
53
+ def pos=(pos); @data.position = pos; end
54
+ def eof?; !@data.more?; end
55
+
56
+ def size; @data.size; end
57
+ alias_method :length, :size
58
+
59
+ def truncate
60
+ if @data.position < @data.length
61
+ curr_data = @data
62
+ @data = ByteBuffer.new
63
+ @data.put_array(curr_data.to_a[0...curr_data.position])
64
+ end
65
+ end
66
+
67
+ def getc
68
+ @data.more? ? @data.get : nil
69
+ end
70
+
71
+ def putc(byte)
72
+ @data.put(byte)
73
+ end
74
+
75
+ def save
76
+ coll = @file.chunk_collection
77
+ coll.remove({'_id' => @object_id})
78
+ coll.insert(to_mongo_object)
79
+ end
80
+
81
+ def to_mongo_object
82
+ h = OrderedHash.new
83
+ h['_id'] = @object_id
84
+ h['files_id'] = @file.files_id
85
+ h['n'] = @chunk_number
86
+ h['data'] = data
87
+ h
88
+ end
89
+
90
+ end
91
+ end