mongo 0.18.3 → 0.19

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. data/README.rdoc +41 -50
  2. data/Rakefile +14 -4
  3. data/examples/gridfs.rb +25 -70
  4. data/lib/mongo.rb +4 -2
  5. data/lib/mongo/collection.rb +70 -89
  6. data/lib/mongo/connection.rb +203 -43
  7. data/lib/mongo/cursor.rb +7 -7
  8. data/lib/mongo/db.rb +61 -18
  9. data/lib/mongo/exceptions.rb +7 -1
  10. data/lib/mongo/gridfs.rb +8 -1
  11. data/lib/mongo/gridfs/chunk.rb +2 -1
  12. data/lib/mongo/gridfs/grid.rb +90 -0
  13. data/lib/mongo/gridfs/grid_file_system.rb +113 -0
  14. data/lib/mongo/gridfs/grid_io.rb +339 -0
  15. data/lib/mongo/gridfs/grid_store.rb +43 -18
  16. data/lib/mongo/types/binary.rb +5 -1
  17. data/lib/mongo/types/code.rb +1 -1
  18. data/lib/mongo/types/dbref.rb +3 -1
  19. data/lib/mongo/types/min_max_keys.rb +1 -1
  20. data/lib/mongo/types/objectid.rb +16 -55
  21. data/lib/mongo/types/regexp_of_holding.rb +1 -1
  22. data/lib/mongo/util/bson_c.rb +2 -2
  23. data/lib/mongo/util/bson_ruby.rb +22 -11
  24. data/lib/mongo/util/byte_buffer.rb +1 -1
  25. data/lib/mongo/util/conversions.rb +1 -1
  26. data/lib/mongo/util/ordered_hash.rb +6 -1
  27. data/lib/mongo/util/server_version.rb +1 -1
  28. data/lib/mongo/util/support.rb +1 -1
  29. data/mongo-ruby-driver.gemspec +1 -1
  30. data/test/auxillary/authentication_test.rb +68 -0
  31. data/test/auxillary/autoreconnect_test.rb +41 -0
  32. data/test/binary_test.rb +15 -0
  33. data/test/{test_bson.rb → bson_test.rb} +63 -6
  34. data/test/{test_byte_buffer.rb → byte_buffer_test.rb} +0 -0
  35. data/test/{test_chunk.rb → chunk_test.rb} +0 -0
  36. data/test/{test_collection.rb → collection_test.rb} +35 -39
  37. data/test/{test_connection.rb → connection_test.rb} +33 -3
  38. data/test/{test_conversions.rb → conversions_test.rb} +0 -0
  39. data/test/{test_cursor.rb → cursor_test.rb} +0 -7
  40. data/test/{test_db_api.rb → db_api_test.rb} +3 -6
  41. data/test/{test_db_connection.rb → db_connection_test.rb} +0 -0
  42. data/test/{test_db.rb → db_test.rb} +33 -15
  43. data/test/grid_file_system_test.rb +210 -0
  44. data/test/grid_io_test.rb +78 -0
  45. data/test/{test_grid_store.rb → grid_store_test.rb} +33 -2
  46. data/test/grid_test.rb +87 -0
  47. data/test/{test_objectid.rb → objectid_test.rb} +2 -33
  48. data/test/{test_ordered_hash.rb → ordered_hash_test.rb} +4 -0
  49. data/test/{test_slave_connection.rb → slave_connection_test.rb} +0 -0
  50. data/test/test_helper.rb +2 -2
  51. data/test/{test_threading.rb → threading_test.rb} +0 -0
  52. data/test/unit/collection_test.rb +12 -3
  53. data/test/unit/connection_test.rb +85 -24
  54. data/test/unit/cursor_test.rb +1 -2
  55. data/test/unit/db_test.rb +70 -69
  56. metadata +27 -23
  57. data/bin/objectid_benchmark.rb +0 -23
  58. data/bin/perf.rb +0 -30
  59. data/lib/mongo/admin.rb +0 -95
  60. data/lib/mongo/util/xml_to_ruby.rb +0 -112
  61. data/test/test_admin.rb +0 -67
  62. data/test/test_round_trip.rb +0 -114
data/README.rdoc CHANGED
@@ -9,15 +9,15 @@ Here's a quick code sample. See the MongoDB Ruby Tutorial
9
9
  require 'mongo'
10
10
  include Mongo
11
11
 
12
- @db = Connection.new.db('sample-db')
13
- @coll = db.collection('test')
12
+ db = Connection.new.db('sample-db')
13
+ coll = db.collection('test')
14
14
 
15
- @coll.remove
15
+ coll.remove
16
16
  3.times do |i|
17
- @coll.insert({'a' => i+1})
17
+ coll.insert({'a' => i+1})
18
18
  end
19
- puts "There are #{@coll.count()} records. Here they are:"
20
- @coll.find().each { |doc| puts doc.inspect }
19
+ puts "There are #{coll.count()} records. Here they are:"
20
+ coll.find().each { |doc| puts doc.inspect }
21
21
 
22
22
  = Installation
23
23
 
@@ -25,7 +25,6 @@ The driver's gems are hosted on Gemcutter[http://gemcutter.org]. If you haven't
25
25
  installed a gem from Gemcutter before, you'll need to set up Gemcutter first:
26
26
 
27
27
  $ gem install gemcutter
28
- $ gem tumble
29
28
 
30
29
  Once you've installed Gemcutter, install the mongo gem as follows:
31
30
 
@@ -70,40 +69,51 @@ Here's how to start MongoDB and run the "simple.rb" example:
70
69
 
71
70
  See also the test code, especially test/test_db_api.rb.
72
71
 
73
- = GridStore
72
+ = GridFS
74
73
 
75
- The GridStore class is a Ruby implementation of MongoDB's GridFS file storage
76
- system. An instance of GridStore is like an IO object. See the RDocs for
77
- details, and see examples/gridfs.rb for code that uses many of the GridStore
78
- features (metadata, content type, rewind/seek/tell, etc).
74
+ Note: The GridStore class has been deprecated. Use either the Grid or GridFileSystem
75
+ classes to take advantage of GridFS.
79
76
 
80
- Note that the GridStore class is not automatically required when you require
81
- 'mongo'. You also need to require 'mongo/gridfs'
77
+ The Ruby driver include two abstractions for storing large files: Grid and GridFileSystem.
78
+ The Grid class is a Ruby implementation of MongoDB's GridFS file storage
79
+ specification. GridFileSystem is essentailly the same, but provides a more filesystem-like API
80
+ and assumes that filenames are unique.
82
81
 
83
- Example code:
82
+ An instance of both classes represents an individual file store. See the API reference
83
+ for details, and see examples/gridfs.rb for code that uses many of the Grid
84
+ features (metadata, content type, seek, tell, etc).
84
85
 
85
- include GridFS
86
+ Examples:
87
+ include Mongo
88
+
89
+ # Get a database
90
+ db = Mongo::Connection.new.db('app-db')
86
91
 
87
- # Store the text "Hello, world!" in the grid store.
88
- GridStore.open(database, 'filename', 'w') do |f|
89
- f.puts "Hello, world!"
92
+ # GridFileSystem. Store the text "Hello, world!" in the fs.
93
+ fs = GridFileSystem.new(db)
94
+ fs.open('filename', 'w') do |f|
95
+ f.write "Hello, world!"
90
96
  end
91
97
 
92
- # Output "Hello, world!"
93
- GridStore.open(database, 'filename', 'r') do |f|
98
+ # GridFileSystem. Output "Hello, world!"
99
+ fs = GridFileSystem.new(db)
100
+ fs.open('filename', 'r') do |f|
94
101
  puts f.read
95
102
  end
96
103
 
97
- # Add text to the grid store.
98
- GridStore.open(database, 'filename', 'w+') do |f|
99
- f.puts "But wait, there's more!"
100
- end
104
+ # Write a file on disk to the Grid
105
+ file = File.open('image.jpg')
106
+ grid = Grid.new(db)
107
+ id = grid.put(file)
101
108
 
102
- # Retrieve everything, outputting "Hello, world!\nBut wait, there's more!\n"
103
- GridStore.open(database, 'filename', 'r') do |f|
104
- puts f.read
105
- end
109
+ # Retrieve the file
110
+ file = grid.get(id)
111
+ file.read
106
112
 
113
+ # Get all the file's metata
114
+ file.filename
115
+ file.content_type
116
+ file.metadata
107
117
 
108
118
  = Notes
109
119
 
@@ -294,8 +304,7 @@ It's also possible to test replica pairs with connection pooling:
294
304
 
295
305
  ===Shoulda and Mocha
296
306
 
297
- All tests now require shoulda and mocha. You can install these gems as
298
- follows:
307
+ Running the test suite requires shoulda and mocha. You can install them as follows:
299
308
 
300
309
  $ gem install shoulda
301
310
  $ gem install mocha
@@ -305,23 +314,6 @@ can override the default host (localhost) and port (Connection::DEFAULT_PORT) by
305
314
  using the environment variables MONGO_RUBY_DRIVER_HOST and
306
315
  MONGO_RUBY_DRIVER_PORT.
307
316
 
308
- The project mongo-qa (http://github.com/mongodb/mongo-qa) contains many more
309
- Mongo driver tests that are language independent. To run thoses tests as part
310
- of the "rake test" task, download the code "next to" this directory. So, after
311
- installing the mongo-qa code you would have these two directories next to each
312
- other:
313
-
314
- $ ls
315
- mongo-qa
316
- mongo-ruby-driver
317
- $ rake test
318
-
319
- The tests run just fine if the mongo-qa directory is not there.
320
-
321
- Additionally, the script bin/validate is used by the mongo-qa project's
322
- validator script.
323
-
324
-
325
317
  = Documentation
326
318
 
327
319
  This documentation is available online at http://api.mongodb.org/ruby. You can
@@ -342,7 +334,7 @@ See CREDITS.
342
334
 
343
335
  = License
344
336
 
345
- Copyright 2008-2009 10gen Inc.
337
+ Copyright 2008-2010 10gen Inc.
346
338
 
347
339
  Licensed under the Apache License, Version 2.0 (the "License");
348
340
  you may not use this file except in compliance with the License.
@@ -355,4 +347,3 @@ See CREDITS.
355
347
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
356
348
  See the License for the specific language governing permissions and
357
349
  limitations under the License.
358
-
data/Rakefile CHANGED
@@ -47,7 +47,7 @@ namespace :test do
47
47
  end
48
48
 
49
49
  Rake::TestTask.new(:functional) do |t|
50
- t.test_files = FileList['test/test*.rb']
50
+ t.test_files = FileList['test/*_test.rb']
51
51
  t.verbose = true
52
52
  end
53
53
 
@@ -76,6 +76,16 @@ namespace :test do
76
76
  t.verbose = true
77
77
  end
78
78
 
79
+ Rake::TestTask.new(:auto_reconnect) do |t|
80
+ t.test_files = FileList['test/auxillary/autoreconnect_test.rb']
81
+ t.verbose = true
82
+ end
83
+
84
+ Rake::TestTask.new(:authentication) do |t|
85
+ t.test_files = FileList['test/auxillary/authentication_test.rb']
86
+ t.verbose = true
87
+ end
88
+
79
89
  task :drop_databases do |t|
80
90
  puts "Dropping test database..."
81
91
  require File.join(File.dirname(__FILE__), 'lib', 'mongo')
@@ -96,10 +106,10 @@ end
96
106
 
97
107
  desc "Generate YARD documentation"
98
108
  task :ydoc do
99
- version = eval(File.read("mongo-ruby-driver.gemspec")).version
100
- out = File.join('ydoc', version.to_s)
109
+ require File.join(File.dirname(__FILE__), 'lib', 'mongo')
110
+ out = File.join('ydoc', Mongo::VERSION)
101
111
  FileUtils.rm_rf('ydoc')
102
- system "yardoc lib/**/*.rb lib/mongo/**/*.rb -o #{out} --title MongoRuby-#{version}"
112
+ system "yardoc lib/**/*.rb lib/mongo/**/*.rb -e docs/yard_ext.rb -p docs/templates -o #{out} --title MongoRuby-#{Mongo::VERSION}"
103
113
  end
104
114
 
105
115
  desc "Publish documentation to mongo.rubyforge.org"
data/examples/gridfs.rb CHANGED
@@ -1,10 +1,10 @@
1
1
  $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ def assert
3
+ raise "Failed!" unless yield
4
+ end
2
5
 
3
6
  require 'mongo'
4
- require 'mongo/gridfs'
5
-
6
7
  include Mongo
7
- include GridFS
8
8
 
9
9
  host = ENV['MONGO_RUBY_DRIVER_HOST'] || 'localhost'
10
10
  port = ENV['MONGO_RUBY_DRIVER_PORT'] || Connection::DEFAULT_PORT
@@ -12,77 +12,32 @@ port = ENV['MONGO_RUBY_DRIVER_PORT'] || Connection::DEFAULT_PORT
12
12
  puts "Connecting to #{host}:#{port}"
13
13
  db = Connection.new(host, port).db('ruby-mongo-examples')
14
14
 
15
- def dump(db, fname)
16
- GridStore.open(db, fname, 'r') { |f| puts f.read }
17
- end
18
-
19
- # Write a new file
20
- GridStore.open(db, 'foobar', 'w') { |f| f.write("hello, world!") }
21
-
22
- # Read it and print out the contents
23
- dump(db, 'foobar')
24
-
25
- # Append more data
26
- GridStore.open(db, 'foobar', 'w+') { |f| f.write("\n"); f.puts "line two" }
27
- dump(db, 'foobar')
15
+ data = "hello, world!"
28
16
 
29
- # Overwrite
30
- GridStore.open(db, 'foobar', 'w') { |f| f.puts "hello, sailor!" }
31
- dump(db, 'foobar')
17
+ grid = Grid.new(db)
32
18
 
33
- # File existence tests
34
- puts "File 'foobar' exists: #{GridStore.exist?(db, 'foobar')}"
35
- puts "File 'does-not-exist' exists: #{GridStore.exist?(db, 'does-not-exist')}"
19
+ # Write a new file. data can be a string or an io object responding to #read.
20
+ id = grid.put(data, 'hello.txt')
36
21
 
37
- # Read with offset (uses seek)
38
- puts GridStore.read(db, 'foobar', 6, 7)
22
+ # Read it and print out the contents
23
+ file = grid.get(id)
24
+ puts file.read
39
25
 
40
- # Rewind/seek/tell
41
- GridStore.open(db, 'foobar', 'w') { |f|
42
- f.write "hello, world!"
43
- f.rewind
44
- f.write "xyzzz"
45
- puts f.tell # => 5
46
- f.seek(4)
47
- f.write('y')
48
- }
49
- dump(db, 'foobar') # => 'xyzzy'
26
+ # Delete the file
27
+ grid.delete(id)
50
28
 
51
- # Unlink (delete)
52
- GridStore.unlink(db, 'foobar')
53
- puts "File 'foobar' exists after delete: #{GridStore.exist?(db, 'foobar')}"
29
+ begin
30
+ grid.get(id)
31
+ rescue => e
32
+ assert {e.class == Mongo::GridError}
33
+ end
54
34
 
55
35
  # Metadata
56
- GridStore.open(db, 'foobar', 'w') { |f| f.write("hello, world!") }
57
- GridStore.open(db, 'foobar', 'r') { |f|
58
- puts f.content_type
59
- puts f.upload_date
60
- puts f.chunk_size
61
- puts f.metadata.inspect
62
- }
63
-
64
- # Add some metadata; change content type
65
- GridStore.open(db, 'foobar', 'w+') { |f|
66
- f.content_type = 'text/xml'
67
- f.metadata = {'a' => 1}
68
- }
69
- # Print it
70
- GridStore.open(db, 'foobar', 'r') { |f|
71
- puts f.content_type
72
- puts f.upload_date
73
- puts f.chunk_size
74
- puts f.metadata.inspect
75
- }
76
-
77
- # You can also set metadata when initially writing the file. Setting :root
78
- # means that the file and its chunks are stored in a different root
79
- # collection: instead of gridfs.files and gridfs.chunks, here we use
80
- # my_files.files and my_files.chunks.
81
- GridStore.open(db, 'foobar', 'w',
82
- :content_type => 'text/plain',
83
- :metadata => {'a' => 1},
84
- :chunk_size => 1024 * 4,
85
- :root => 'my_files') { |f|
86
- f.puts 'hello, world'
87
- }
88
-
36
+ id = grid.put(data, 'hello.txt', :content_type => 'text/plain', :metadata => {'name' => 'hello'})
37
+ file = grid.get(id)
38
+
39
+ p file.content_type
40
+ p file.metadata.inspect
41
+ p file.chunk_size
42
+ p file.file_length
43
+ p file.data
data/lib/mongo.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
2
 
3
3
  module Mongo
4
- VERSION = "0.18.3"
4
+ VERSION = "0.19"
5
5
  end
6
6
 
7
7
  begin
@@ -52,10 +52,12 @@ require 'mongo/util/conversions'
52
52
  require 'mongo/util/server_version'
53
53
  require 'mongo/util/bson_ruby'
54
54
 
55
- require 'mongo/admin'
56
55
  require 'mongo/collection'
57
56
  require 'mongo/connection'
58
57
  require 'mongo/cursor'
59
58
  require 'mongo/db'
60
59
  require 'mongo/exceptions'
61
60
  require 'mongo/gridfs'
61
+ require 'mongo/gridfs/grid'
62
+ require 'mongo/gridfs/grid_io'
63
+ require 'mongo/gridfs/grid_file_system'
@@ -1,5 +1,5 @@
1
1
  # --
2
- # Copyright (C) 2008-2009 10gen Inc.
2
+ # Copyright (C) 2008-2010 10gen Inc.
3
3
  #
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
5
5
  # you may not use this file except in compliance with the License.
@@ -33,6 +33,8 @@ module Mongo
33
33
  # if collection name is not a string or symbol
34
34
  #
35
35
  # @return [Collection]
36
+ #
37
+ # @core collections constructor_details
36
38
  def initialize(db, name, pk_factory=nil)
37
39
  case name
38
40
  when Symbol, String
@@ -126,6 +128,8 @@ module Mongo
126
128
  #
127
129
  # @raise [RuntimeError]
128
130
  # if given unknown options
131
+ #
132
+ # @core find find-instance_method
129
133
  def find(selector={}, opts={})
130
134
  fields = opts.delete(:fields)
131
135
  fields = ["_id"] if fields && fields.empty?
@@ -221,6 +225,8 @@ module Mongo
221
225
  # If true, check that the save succeeded. OperationFailure
222
226
  # will be raised on an error. Note that a safe check requires an extra
223
227
  # round-trip to the database.
228
+ #
229
+ # @core insert insert-instance_method
224
230
  def insert(doc_or_docs, options={})
225
231
  doc_or_docs = [doc_or_docs] unless doc_or_docs.is_a?(Array)
226
232
  doc_or_docs.collect! { |doc| @pk_factory.create_pk(doc) }
@@ -248,15 +254,17 @@ module Mongo
248
254
  #
249
255
  # @raise [Mongo::OperationFailure] an exception will be raised iff safe mode is enabled
250
256
  # and the operation fails.
257
+ #
258
+ # @core remove remove-instance_method
251
259
  def remove(selector={}, opts={})
252
260
  # Initial byte is 0.
253
261
  message = ByteBuffer.new([0, 0, 0, 0])
254
262
  BSON_RUBY.serialize_cstr(message, "#{@db.name}.#{@name}")
255
263
  message.put_int(0)
256
- message.put_array(BSON.serialize(selector, false).to_a)
264
+ message.put_array(BSON.serialize(selector, false, true).to_a)
257
265
 
258
266
  if opts[:safe]
259
- @connection.send_message_with_safe_check(Mongo::Constants::OP_DELETE, message,
267
+ @connection.send_message_with_safe_check(Mongo::Constants::OP_DELETE, message, @db.name,
260
268
  "db.#{@db.name}.remove(#{selector.inspect})")
261
269
  # the return value of send_message_with_safe_check isn't actually meaningful --
262
270
  # only the fact that it didn't raise an error is -- so just return true
@@ -285,6 +293,8 @@ module Mongo
285
293
  # If true, check that the save succeeded. OperationFailure
286
294
  # will be raised on an error. Note that a safe check requires an extra
287
295
  # round-trip to the database.
296
+ #
297
+ # @core update update-instance_method
288
298
  def update(selector, document, options={})
289
299
  # Initial byte is 0.
290
300
  message = ByteBuffer.new([0, 0, 0, 0])
@@ -293,8 +303,8 @@ module Mongo
293
303
  update_options += 1 if options[:upsert]
294
304
  update_options += 2 if options[:multi]
295
305
  message.put_int(update_options)
296
- message.put_array(BSON.serialize(selector, false).to_a)
297
- message.put_array(BSON.serialize(document, false).to_a)
306
+ message.put_array(BSON.serialize(selector, false, true).to_a)
307
+ message.put_array(BSON.serialize(document, false, true).to_a)
298
308
  if options[:safe]
299
309
  @connection.send_message_with_safe_check(Mongo::Constants::OP_UPDATE, message, @db.name,
300
310
  "db.#{@name}.update(#{selector.inspect}, #{document.inspect})")
@@ -313,6 +323,8 @@ module Mongo
313
323
  # @param [Boolean] unique if true, this index will enforce a uniqueness constraint.
314
324
  #
315
325
  # @return [String] the name of the index created.
326
+ #
327
+ # @core indexes create_index-instance_method
316
328
  def create_index(field_or_spec, unique=false)
317
329
  field_h = OrderedHash.new
318
330
  if field_or_spec.is_a?(String) || field_or_spec.is_a?(Symbol)
@@ -326,18 +338,26 @@ module Mongo
326
338
  :ns => "#{@db.name}.#{@name}",
327
339
  :key => field_h,
328
340
  :unique => unique }
329
- insert_documents([sel], Mongo::DB::SYSTEM_INDEX_COLLECTION, false)
341
+ begin
342
+ insert_documents([sel], Mongo::DB::SYSTEM_INDEX_COLLECTION, false, true)
343
+ rescue Mongo::OperationFailure
344
+ raise Mongo::OperationFailure, "Failed to create index #{sel.inspect}."
345
+ end
330
346
  name
331
347
  end
332
348
 
333
349
  # Drop a specified index.
334
350
  #
335
351
  # @param [String] name
352
+ #
353
+ # @core indexes
336
354
  def drop_index(name)
337
355
  @db.drop_index(@name, name)
338
356
  end
339
357
 
340
358
  # Drop all indexes.
359
+ #
360
+ # @core indexes
341
361
  def drop_indexes
342
362
 
343
363
  # Note: calling drop_indexes with no args will drop them all.
@@ -369,6 +389,8 @@ module Mongo
369
389
  # @return [Collection] a collection containing the results of the operation.
370
390
  #
371
391
  # @see http://www.mongodb.org/display/DOCS/MapReduce Offical MongoDB map/reduce documentation.
392
+ #
393
+ # @core mapreduce map_reduce-instance_method
372
394
  def map_reduce(map, reduce, opts={})
373
395
  map = Code.new(map) unless map.is_a?(Code)
374
396
  reduce = Code.new(reduce) unless reduce.is_a?(Code)
@@ -397,100 +419,57 @@ module Mongo
397
419
  # @param [String, Code] finalize :: optional. a JavaScript function that receives and modifies
398
420
  # each of the resultant grouped objects. Available only when group is run
399
421
  # with command set to true.
400
- # @param [Boolean] command if true, run the group as a command instead of in an
401
- # eval. Note: Running group as eval has been DEPRECATED.
422
+ # @param [Nil] deprecated this param in a placeholder for a deprecated param. It will be removed
423
+ # in the next release.
402
424
  #
403
425
  # @return [Array] the grouped items.
404
- def group(key, condition, initial, reduce, command=false, finalize=nil)
426
+ def group(key, condition, initial, reduce, finalize=nil, deprecated=nil)
405
427
 
406
- if command
428
+ # Warn of changed API post eval deprecation.
429
+ if finalize == true || finalize == false || deprecated
430
+ warn "The API for Collection#group has changed. 'Finalize' is now the fifth parameter, " +
431
+ "since it's no longer necessary to specify whether #group is run as a command. " +
432
+ "See http://api.mongodb.org/ruby/current/Mongo/Collection.html#group-instance_method for details."
433
+ end
407
434
 
408
- reduce = Code.new(reduce) unless reduce.is_a?(Code)
435
+ reduce = Code.new(reduce) unless reduce.is_a?(Code)
409
436
 
410
- group_command = {
411
- "group" => {
412
- "ns" => @name,
413
- "$reduce" => reduce,
414
- "cond" => condition,
415
- "initial" => initial
416
- }
437
+ group_command = {
438
+ "group" => {
439
+ "ns" => @name,
440
+ "$reduce" => reduce,
441
+ "cond" => condition,
442
+ "initial" => initial
417
443
  }
444
+ }
418
445
 
419
- unless key.nil?
420
- if key.is_a? Array
421
- key_type = "key"
422
- key_value = {}
423
- key.each { |k| key_value[k] = 1 }
424
- else
425
- key_type = "$keyf"
426
- key_value = key.is_a?(Code) ? key : Code.new(key)
427
- end
428
-
429
- group_command["group"][key_type] = key_value
430
- end
431
-
432
- # only add finalize if specified
433
- if finalize
434
- finalize = Code.new(finalize) unless finalize.is_a?(Code)
435
- group_command['group']['finalize'] = finalize
436
- end
437
-
438
- result = @db.command group_command
439
-
440
- if result["ok"] == 1
441
- return result["retval"]
446
+ unless key.nil?
447
+ if key.is_a? Array
448
+ key_type = "key"
449
+ key_value = {}
450
+ key.each { |k| key_value[k] = 1 }
442
451
  else
443
- raise OperationFailure, "group command failed: #{result['errmsg']}"
452
+ key_type = "$keyf"
453
+ key_value = key.is_a?(Code) ? key : Code.new(key)
444
454
  end
445
455
 
446
- else
447
-
448
- warn "Collection#group must now be run as a command; you can do this by passing 'true' as the command argument."
449
-
450
- raise OperationFailure, ":finalize can be specified only when " +
451
- "group is run as a command (set command param to true)" if finalize
456
+ group_command["group"][key_type] = key_value
457
+ end
452
458
 
453
- raise OperationFailure, "key must be an array of fields to group by. If you want to pass a key function,
454
- run group as a command by passing 'true' as the command argument." unless key.is_a? Array || key.nil?
459
+ # only add finalize if specified
460
+ # check to see if users have sent the finalizer as the last argument.
461
+ finalize = deprecated if deprecated.is_a?(String) || deprecated.is_a?(Code)
462
+ finalize = Code.new(finalize) if finalize.is_a?(String)
463
+ if finalize.is_a?(Code)
464
+ group_command['group']['finalize'] = finalize
465
+ end
455
466
 
456
- case reduce
457
- when Code
458
- scope = reduce.scope
459
- else
460
- scope = {}
461
- end
462
- scope.merge!({
463
- "ns" => @name,
464
- "keys" => key,
465
- "condition" => condition,
466
- "initial" => initial })
467
-
468
- group_function = <<EOS
469
- function () {
470
- var c = db[ns].find(condition);
471
- var map = new Map();
472
- var reduce_function = #{reduce};
473
- while (c.hasNext()) {
474
- var obj = c.next();
475
-
476
- var key = {};
477
- for (var i = 0; i < keys.length; i++) {
478
- var k = keys[i];
479
- key[k] = obj[k];
480
- }
467
+ result = @db.command group_command
481
468
 
482
- var aggObj = map.get(key);
483
- if (aggObj == null) {
484
- var newObj = Object.extend({}, key);
485
- aggObj = Object.extend(newObj, initial);
486
- map.put(key, aggObj);
487
- }
488
- reduce_function(obj, aggObj);
489
- }
490
- return {"result": map.values()};
491
- }
492
- EOS
493
- @db.eval(Code.new(group_function, scope))["result"]
469
+ if result["ok"] == 1
470
+ result["retval"]
471
+ else
472
+ raise OperationFailure, "group command failed: #{result['errmsg']}"
494
473
  end
495
474
  end
496
475
 
@@ -534,7 +513,7 @@ EOS
534
513
  # Note: If operating in auth mode, the client must be authorized as an admin to
535
514
  # perform this operation.
536
515
  #
537
- # @param [String ] new_name the new name for this collection
516
+ # @param [String] new_name the new name for this collection
538
517
  #
539
518
  # @raise [InvalidName] if +new_name+ is an invalid collection name.
540
519
  def rename(new_name)
@@ -562,6 +541,8 @@ EOS
562
541
  # Get information on the indexes for this collection.
563
542
  #
564
543
  # @return [Hash] a hash where the keys are index names.
544
+ #
545
+ # @core indexes
565
546
  def index_information
566
547
  @db.index_information(@name)
567
548
  end
@@ -609,7 +590,7 @@ EOS
609
590
  # Initial byte is 0.
610
591
  message = ByteBuffer.new([0, 0, 0, 0])
611
592
  BSON_RUBY.serialize_cstr(message, "#{@db.name}.#{collection_name}")
612
- documents.each { |doc| message.put_array(BSON.serialize(doc, check_keys).to_a) }
593
+ documents.each { |doc| message.put_array(BSON.serialize(doc, check_keys, true).to_a) }
613
594
  if safe
614
595
  @connection.send_message_with_safe_check(Mongo::Constants::OP_INSERT, message, @db.name,
615
596
  "db.#{collection_name}.insert(#{documents.inspect})")