mongo 0.20.1 → 1.0

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.
@@ -35,7 +35,6 @@ The driver also requires the BSON gem:
35
35
  $ gem install bson
36
36
 
37
37
  And for a significant performance boost, you'll want to install the C extensions:
38
- extensions:
39
38
 
40
39
  $ gem install bson_ext
41
40
 
@@ -9,13 +9,14 @@ host = ENV['MONGO_RUBY_DRIVER_HOST'] || 'localhost'
9
9
  port = ENV['MONGO_RUBY_DRIVER_PORT'] || Connection::DEFAULT_PORT
10
10
 
11
11
  puts "Connecting to #{host}:#{port}"
12
- db = Mongo::Connection.new(host, port).db('ruby-mongo-examples')
12
+ con = Mongo::Connection.new(host, port)
13
+ db = con.db('ruby-mongo-examples')
13
14
  coll = db.create_collection('test')
14
15
 
15
16
  # Erase all records from collection, if any
16
17
  coll.remove
17
18
 
18
- admin = db.admin
19
+ admin = con['admin']
19
20
 
20
21
  # Profiling level set/get
21
22
  puts "Profiling level: #{admin.profiling_level}"
@@ -34,7 +35,7 @@ pp admin.profiling_info
34
35
 
35
36
  # Validate returns a hash if all is well and
36
37
  # raises an exception if there is a problem.
37
- info = admin.validate_collection(coll.name)
38
+ info = db.validate_collection(coll.name)
38
39
  puts "valid = #{info['ok']}"
39
40
  puts info['result']
40
41
 
@@ -24,7 +24,7 @@ p db.collection_names
24
24
  p db.collections_info
25
25
 
26
26
  # Index information
27
- db.create_index('test', 'a')
27
+ coll.create_index('a')
28
28
  p db.index_information('test')
29
29
 
30
30
  # Destroy the collection
@@ -1,7 +1,7 @@
1
1
  $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
2
 
3
3
  module Mongo
4
- VERSION = "0.20.1"
4
+ VERSION = "1.0"
5
5
  end
6
6
 
7
7
  module Mongo
@@ -19,8 +19,11 @@ module Mongo
19
19
  OP_DELETE = 2006
20
20
  OP_KILL_CURSORS = 2007
21
21
 
22
+ OP_QUERY_TAILABLE = 2
22
23
  OP_QUERY_SLAVE_OK = 4
23
24
  OP_QUERY_NO_CURSOR_TIMEOUT = 16
25
+
26
+ DEFAULT_BATCH_SIZE = 100
24
27
  end
25
28
 
26
29
  end
@@ -120,6 +120,8 @@ module Mongo
120
120
  # @option opts [Boolean] :snapshot ('false') if true, snapshot mode will be used for this query.
121
121
  # Snapshot mode assures no duplicates are returned, or objects missed, which were preset at both the start and
122
122
  # end of the query's execution. For details see http://www.mongodb.org/display/DOCS/How+to+do+Snapshotting+in+the+Mongo+Database
123
+ # @option opts [Boolean] :batch_size (100) the number of documents to returned by the database per GETMORE operation. A value of 0
124
+ # will let the database server decide how many results to returns. This option can be ignored for most use cases.
123
125
  # @option opts [Boolean] :timeout ('true') when +true+, the returned cursor will be subject to
124
126
  # the normal cursor timeout behavior of the mongod process. When +false+, the returned cursor will never timeout. Note
125
127
  # that disabling timeout will only work when #find is invoked with a block. This is to prevent any inadvertant failure to
@@ -140,6 +142,7 @@ module Mongo
140
142
  sort = opts.delete(:sort)
141
143
  hint = opts.delete(:hint)
142
144
  snapshot = opts.delete(:snapshot)
145
+ batch_size = opts.delete(:batch_size)
143
146
  if opts[:timeout] == false && !block_given?
144
147
  raise ArgumentError, "Timeout can be set to false only when #find is invoked with a block."
145
148
  end
@@ -152,7 +155,7 @@ module Mongo
152
155
  raise RuntimeError, "Unknown options [#{opts.inspect}]" unless opts.empty?
153
156
 
154
157
  cursor = Cursor.new(self, :selector => selector, :fields => fields, :skip => skip, :limit => limit,
155
- :order => sort, :hint => hint, :snapshot => snapshot, :timeout => timeout)
158
+ :order => sort, :hint => hint, :snapshot => snapshot, :timeout => timeout, :batch_size => batch_size)
156
159
  if block_given?
157
160
  yield cursor
158
161
  cursor.close()
@@ -330,9 +333,6 @@ module Mongo
330
333
  # Also note that it is permissible to create compound indexes that include a geospatial index as
331
334
  # long as the geospatial index comes first.
332
335
  #
333
- # @param [Boolean] unique if true, this index will enforce a uniqueness constraint. DEPRECATED. Future
334
- # versions of this driver will specify the uniqueness constraint using a hash param.
335
- #
336
336
  # @option opts [Boolean] :unique (false) if true, this index will enforce a uniqueness constraint.
337
337
  # @option opts [Boolean] :background (false) indicate that the index should be built in the background. This
338
338
  # feature is only available in MongoDB >= 1.3.2.
@@ -359,32 +359,36 @@ module Mongo
359
359
  #
360
360
  # @core indexes create_index-instance_method
361
361
  def create_index(spec, opts={})
362
- opts.assert_valid_keys(:min, :max, :background, :unique, :dropDups) if opts.is_a?(Hash)
362
+ opts.assert_valid_keys(:min, :max, :background, :unique, :dropDups)
363
363
  field_spec = OrderedHash.new
364
364
  if spec.is_a?(String) || spec.is_a?(Symbol)
365
365
  field_spec[spec.to_s] = 1
366
366
  elsif spec.is_a?(Array) && spec.all? {|field| field.is_a?(Array) }
367
- spec.each { |f| field_spec[f[0].to_s] = f[1] }
367
+ spec.each do |f|
368
+ if [Mongo::ASCENDING, Mongo::DESCENDING, Mongo::GEO2D].include?(f[1])
369
+ field_spec[f[0].to_s] = f[1]
370
+ else
371
+ raise MongoArgumentError, "Invalid index field #{f[1].inspect}; " +
372
+ "should be one of Mongo::ASCENDING (1), Mongo::DESCENDING (-1) or Mongo::GEO2D ('2d')."
373
+ end
374
+ end
368
375
  else
369
376
  raise MongoArgumentError, "Invalid index specification #{spec.inspect}; " +
370
377
  "should be either a string, symbol, or an array of arrays."
371
378
  end
372
379
 
373
380
  name = generate_index_name(field_spec)
374
- if opts == true || opts == false
375
- warn "For Collection#create_index, the method for specifying a unique index has changed." +
376
- "Please pass :unique => true to the method instead."
377
- end
378
- sel = {
381
+
382
+ selector = {
379
383
  :name => name,
380
384
  :ns => "#{@db.name}.#{@name}",
381
- :key => field_spec,
382
- :unique => (opts == true ? true : false) }
383
- sel.merge!(opts) if opts.is_a?(Hash)
385
+ :key => field_spec
386
+ }
387
+ selector.merge!(opts)
384
388
  begin
385
- response = insert_documents([sel], Mongo::DB::SYSTEM_INDEX_COLLECTION, false, true)
389
+ response = insert_documents([selector], Mongo::DB::SYSTEM_INDEX_COLLECTION, false, true)
386
390
  rescue Mongo::OperationFailure
387
- raise Mongo::OperationFailure, "Failed to create index #{sel.inspect} with the following errors: #{response}"
391
+ raise Mongo::OperationFailure, "Failed to create index #{selector.inspect} with the following errors: #{response}"
388
392
  end
389
393
  name
390
394
  end
@@ -118,11 +118,11 @@ module Mongo
118
118
  # @param opts Takes the same options as Connection.new
119
119
  #
120
120
  # @example
121
- # Connection.new([["db1.example.com", 27017],
121
+ # Connection.paired([["db1.example.com", 27017],
122
122
  # ["db2.example.com", 27017]])
123
123
  #
124
124
  # @example
125
- # Connection.new([["db1.example.com", 27017],
125
+ # Connection.paired([["db1.example.com", 27017],
126
126
  # ["db2.example.com", 27017]],
127
127
  # :pool_size => 20, :timeout => 5)
128
128
  #
@@ -47,6 +47,8 @@ module Mongo
47
47
  @timeout = options[:timeout] || false
48
48
  @explain = options[:explain]
49
49
  @socket = options[:socket]
50
+ @tailable = options[:tailable] || false
51
+ @batch_size = options[:batch_size] || Mongo::Constants::DEFAULT_BATCH_SIZE
50
52
 
51
53
  @full_collection_name = "#{@collection.db.name}.#{@collection.name}"
52
54
  @cache = []
@@ -250,7 +252,8 @@ module Mongo
250
252
  def query_opts
251
253
  timeout = @timeout ? 0 : Mongo::Constants::OP_QUERY_NO_CURSOR_TIMEOUT
252
254
  slave_ok = @connection.slave_ok? ? Mongo::Constants::OP_QUERY_SLAVE_OK : 0
253
- slave_ok + timeout
255
+ tailable = @tailable ? Mongo::Constants::OP_QUERY_TAILABLE : 0
256
+ slave_ok + timeout + tailable
254
257
  end
255
258
 
256
259
  # Get the query options for this Cursor.
@@ -317,8 +320,8 @@ module Mongo
317
320
  db_name = @admin ? 'admin' : @db.name
318
321
  BSON::BSON_RUBY.serialize_cstr(message, "#{db_name}.#{@collection.name}")
319
322
 
320
- # Number of results to return; db decides for now.
321
- message.put_int(100)
323
+ # Number of results to return.
324
+ message.put_int(@batch_size)
322
325
 
323
326
  # Cursor id.
324
327
  message.put_long(@cursor_id)
@@ -404,8 +404,11 @@ module Mongo
404
404
  # @param [Boolean] unique if +true+, the created index will enforce a uniqueness constraint.
405
405
  #
406
406
  # @return [String] the name of the index created.
407
+ #
408
+ # @deprecated
407
409
  def create_index(collection_name, field_or_spec, unique=false)
408
- self.collection(collection_name).create_index(field_or_spec, unique)
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)
409
412
  end
410
413
 
411
414
  # Return +true+ if the supplied +doc+ contains an 'ok' field with the value 1.
@@ -39,6 +39,9 @@ module Mongo
39
39
 
40
40
  # Store a file in the file store.
41
41
  #
42
+ # Note that arbitary metadata attributes can be saved to the file by passing
43
+ # them is as options.
44
+ #
42
45
  # @param [String, #read] data a string or io-like object to store.
43
46
  #
44
47
  # @options opts [String] :filename (nil) a name for the file.
@@ -53,14 +56,8 @@ module Mongo
53
56
  # will be validated using an md5 hash. If validation fails, an exception will be raised.
54
57
  #
55
58
  # @return [Mongo::ObjectID] the file's id.
56
- def put(data, opts={}, old_opts={})
57
- if opts.is_a?(String)
58
- warn "The filename is now optional. Please pass the filename as a hash option: Grid#put(data, :filename => 'file.jpg')."
59
- filename = opts
60
- opts = old_opts
61
- else
62
- filename = opts[:filename]
63
- end
59
+ def put(data, opts={})
60
+ filename = opts[:filename]
64
61
  opts.merge!(default_grid_io_opts)
65
62
  file = GridIO.new(@files, @chunks, filename, 'w', opts=opts)
66
63
  file.write(data)
@@ -0,0 +1,30 @@
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
+ module ClassMethods
19
+
20
+ def exists?(criteria)
21
+ BSON::ObjectID:
22
+ @files.find_one(query)
23
+ end
24
+
25
+ def list(query={})
26
+ @files.find(query)
27
+ end
28
+
29
+ end
30
+ end
@@ -43,6 +43,9 @@ module Mongo
43
43
  # Open a file for reading or writing. Note that the options for this method only apply
44
44
  # when opening in 'w' mode.
45
45
  #
46
+ # Note that arbitary metadata attributes can be saved to the file by passing
47
+ # them is as options.
48
+ #
46
49
  # @param [String] filename the name of the file.
47
50
  # @param [String] mode either 'r' or 'w' for reading from
48
51
  # or writing to the file.
@@ -105,7 +108,7 @@ module Mongo
105
108
  # Delete the file with the given filename. Note that this will delete
106
109
  # all versions of the file.
107
110
  #
108
- # Note that deleting a GridFS file can result in read errors if another process
111
+ # Be careful with this. Deleting a GridFS file can result in read errors if another process
109
112
  # is attempting to read a file while it's being deleted. While the odds for this
110
113
  # kind of race condition are small, it's important to be aware of.
111
114
  #
@@ -165,7 +165,7 @@ class TestCollection < Test::Unit::TestCase
165
165
  end
166
166
  else
167
167
  def test_safe_update
168
- @@test.create_index("x", true)
168
+ @@test.create_index("x", :unique => true)
169
169
  @@test.insert("x" => 5)
170
170
  @@test.insert("x" => 10)
171
171
 
@@ -182,7 +182,7 @@ class TestCollection < Test::Unit::TestCase
182
182
  end
183
183
 
184
184
  def test_safe_save
185
- @@test.create_index("hello", true)
185
+ @@test.create_index("hello", :unique => true)
186
186
 
187
187
  @@test.save("hello" => "world")
188
188
  @@test.save("hello" => "world")
@@ -558,7 +558,7 @@ class TestCollection < Test::Unit::TestCase
558
558
  end
559
559
 
560
560
  should "create a unique index" do
561
- @collection.create_index([['a', Mongo::ASCENDING]], true)
561
+ @collection.create_index([['a', Mongo::ASCENDING]], :unique => true)
562
562
  assert @collection.index_information['a_1']['unique'] == true
563
563
  end
564
564
 
@@ -577,6 +577,12 @@ class TestCollection < Test::Unit::TestCase
577
577
  end
578
578
  end
579
579
 
580
+ should "enforce proper index types" do
581
+ assert_raise MongoArgumentError do
582
+ @collection.create_index([['c', 'blah']])
583
+ end
584
+ end
585
+
580
586
  should "generate indexes in the proper order" do
581
587
  @collection.expects(:insert_documents) do |sel, coll, safe|
582
588
  assert_equal 'b_1_a_1', sel[:name]
@@ -594,4 +600,42 @@ class TestCollection < Test::Unit::TestCase
594
600
  end
595
601
  end
596
602
  end
603
+
604
+ context "Capped collections" do
605
+ setup do
606
+ @@db.drop_collection('log')
607
+ @capped = @@db.create_collection('log', :capped => true, :size => 1024)
608
+
609
+ 10.times { |n| @capped.insert({:n => n}) }
610
+ end
611
+
612
+ should "find using a standard cursor" do
613
+ cursor = @capped.find
614
+ 10.times do
615
+ assert cursor.next_document
616
+ end
617
+ assert_nil cursor.next_document
618
+ @capped.insert({:n => 100})
619
+ assert_nil cursor.next_document
620
+ end
621
+
622
+ should "" do
623
+ col = @@db['regular-collection']
624
+ col.insert({:a => 1000})
625
+ tail = Cursor.new(col, :tailable => true, :order => [['$natural', 1]])
626
+ assert_raise OperationFailure do
627
+ tail.next_document
628
+ end
629
+ end
630
+
631
+ should "find using a tailable cursor" do
632
+ tail = Cursor.new(@capped, :tailable => true, :order => [['$natural', 1]])
633
+ 10.times do
634
+ assert tail.next_document
635
+ end
636
+ assert_nil tail.next_document
637
+ @capped.insert({:n => 100})
638
+ assert tail.next_document
639
+ end
640
+ end
597
641
  end
@@ -275,7 +275,7 @@ class DBAPITest < Test::Unit::TestCase
275
275
  def test_index_information
276
276
  assert_equal @@coll.index_information.length, 1
277
277
 
278
- name = @@db.create_index(@@coll.name, 'a')
278
+ name = @@coll.create_index('a')
279
279
  info = @@db.index_information(@@coll.name)
280
280
  assert_equal name, "a_1"
281
281
  assert_equal @@coll.index_information, info
@@ -303,7 +303,7 @@ class DBAPITest < Test::Unit::TestCase
303
303
  end
304
304
 
305
305
  def test_multiple_index_cols
306
- name = @@db.create_index(@@coll.name, [['a', DESCENDING], ['b', ASCENDING], ['c', DESCENDING]])
306
+ name = @@coll.create_index([['a', DESCENDING], ['b', ASCENDING], ['c', DESCENDING]])
307
307
  info = @@db.index_information(@@coll.name)
308
308
  assert_equal 2, info.length
309
309
 
@@ -315,7 +315,7 @@ class DBAPITest < Test::Unit::TestCase
315
315
  end
316
316
 
317
317
  def test_multiple_index_cols_with_symbols
318
- name = @@db.create_index(@@coll.name, [[:a, DESCENDING], [:b, ASCENDING], [:c, DESCENDING]])
318
+ name = @@coll.create_index([[:a, DESCENDING], [:b, ASCENDING], [:c, DESCENDING]])
319
319
  info = @@db.index_information(@@coll.name)
320
320
  assert_equal 2, info.length
321
321
 
@@ -338,7 +338,7 @@ class DBAPITest < Test::Unit::TestCase
338
338
 
339
339
  @@db.drop_collection("blah")
340
340
  test = @@db.collection("blah")
341
- test.create_index("hello", unique=true)
341
+ test.create_index("hello", :unique => true)
342
342
 
343
343
  test.insert("hello" => "world")
344
344
  test.insert("hello" => "mike")
@@ -357,7 +357,7 @@ class DBAPITest < Test::Unit::TestCase
357
357
 
358
358
  @@db.drop_collection("blah")
359
359
  test = @@db.collection("blah")
360
- test.create_index("hello.a", unique=true)
360
+ test.create_index("hello.a", :unique => true)
361
361
 
362
362
  test.insert("hello" => {"a" => 4, "b" => 5})
363
363
  test.insert("hello" => {"a" => 7, "b" => 2})
@@ -19,7 +19,7 @@ class GridTest < Test::Unit::TestCase
19
19
  setup do
20
20
  @data = "GRIDDATA" * 50000
21
21
  @grid = Grid.new(@db, 'test-fs')
22
- @id = @grid.put(@data, 'sample', :metadata => {'app' => 'photos'})
22
+ @id = @grid.put(@data, :filename => 'sample', :metadata => {'app' => 'photos'})
23
23
  end
24
24
 
25
25
  should "retrieve the stored data" do
@@ -58,7 +58,7 @@ class GridTest < Test::Unit::TestCase
58
58
  end
59
59
 
60
60
  should "store the file with the old filename api" do
61
- id = @grid.put(@data, 'sample', :metadata => @metadata)
61
+ id = @grid.put(@data, :filename => 'sample', :metadata => @metadata)
62
62
  file = @grid.get(id)
63
63
  assert_equal 'sample', file.filename
64
64
  assert_equal @metadata, file.metadata
@@ -106,7 +106,7 @@ class GridTest < Test::Unit::TestCase
106
106
  context "Storing data with a length of zero" do
107
107
  setup do
108
108
  @grid = Grid.new(@db, 'test-fs')
109
- @id = @grid.put('', 'sample', :metadata => {'app' => 'photos'})
109
+ @id = @grid.put('', :filename => 'sample', :metadata => {'app' => 'photos'})
110
110
  end
111
111
 
112
112
  should "return the zero length" do
@@ -119,7 +119,7 @@ class GridTest < Test::Unit::TestCase
119
119
  setup do
120
120
  def read_and_write_stream(filename, read_length, opts={})
121
121
  io = File.open(File.join(File.dirname(__FILE__), 'data', filename), 'r')
122
- id = @grid.put(io, filename + read_length.to_s, opts)
122
+ id = @grid.put(io, opts.merge!(:filename => filename + read_length.to_s))
123
123
  file = @grid.get(id)
124
124
  io.rewind
125
125
  data = io.read
@@ -19,7 +19,7 @@ class TestThreadingLargePool < Test::Unit::TestCase
19
19
  @duplicate.insert("test" => "update")
20
20
  @unique.insert("test" => "insert")
21
21
  @unique.insert("test" => "update")
22
- @unique.create_index("test", true)
22
+ @unique.create_index("test", :unique => true)
23
23
  end
24
24
 
25
25
  def test_safe_update
@@ -17,7 +17,7 @@ class TestThreading < Test::Unit::TestCase
17
17
  @duplicate.insert("test" => "update")
18
18
  @unique.insert("test" => "insert")
19
19
  @unique.insert("test" => "update")
20
- @unique.create_index("test", true)
20
+ @unique.create_index("test", :unique => true)
21
21
  end
22
22
 
23
23
  def test_safe_update
metadata CHANGED
@@ -3,10 +3,9 @@ name: mongo
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
- - 0
7
- - 20
8
6
  - 1
9
- version: 0.20.1
7
+ - 0
8
+ version: "1.0"
10
9
  platform: ruby
11
10
  authors:
12
11
  - Jim Menard
@@ -16,7 +15,7 @@ autorequire:
16
15
  bindir: bin
17
16
  cert_chain: []
18
17
 
19
- date: 2010-04-07 00:00:00 -04:00
18
+ date: 2010-04-29 00:00:00 -04:00
20
19
  default_executable:
21
20
  dependencies:
22
21
  - !ruby/object:Gem::Dependency
@@ -27,10 +26,9 @@ dependencies:
27
26
  - - "="
28
27
  - !ruby/object:Gem::Version
29
28
  segments:
30
- - 0
31
- - 20
32
29
  - 1
33
- version: 0.20.1
30
+ - 0
31
+ version: "1.0"
34
32
  type: :runtime
35
33
  version_requirements: *id001
36
34
  description: A Ruby driver for MongoDB. For more information about Mongo, see http://www.mongodb.org.
@@ -53,6 +51,7 @@ files:
53
51
  - lib/mongo/db.rb
54
52
  - lib/mongo/exceptions.rb
55
53
  - lib/mongo/gridfs/grid.rb
54
+ - lib/mongo/gridfs/grid_ext.rb
56
55
  - lib/mongo/gridfs/grid_file_system.rb
57
56
  - lib/mongo/gridfs/grid_io.rb
58
57
  - lib/mongo/util/conversions.rb