mongo 0.15.1 → 0.16

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 (63) hide show
  1. data/LICENSE.txt +202 -0
  2. data/README.rdoc +15 -2
  3. data/Rakefile +17 -3
  4. data/bin/autoreconnect.rb +26 -0
  5. data/bin/fail_if_no_c.rb +11 -0
  6. data/lib/mongo.rb +9 -2
  7. data/lib/mongo/admin.rb +1 -1
  8. data/lib/mongo/collection.rb +86 -25
  9. data/lib/mongo/connection.rb +11 -0
  10. data/lib/mongo/constants.rb +15 -0
  11. data/lib/mongo/cursor.rb +176 -36
  12. data/lib/mongo/db.rb +84 -97
  13. data/lib/mongo/errors.rb +7 -1
  14. data/lib/mongo/types/objectid.rb +5 -0
  15. data/lib/mongo/util/byte_buffer.rb +12 -0
  16. data/lib/mongo/util/server_version.rb +69 -0
  17. data/lib/mongo/{message.rb → util/support.rb} +7 -4
  18. data/mongo-ruby-driver.gemspec +9 -86
  19. data/test/test_admin.rb +2 -2
  20. data/test/test_bson.rb +14 -0
  21. data/test/test_byte_buffer.rb +14 -0
  22. data/test/test_chunk.rb +4 -4
  23. data/test/test_collection.rb +107 -17
  24. data/test/test_connection.rb +13 -4
  25. data/test/test_cursor.rb +17 -14
  26. data/test/test_db.rb +7 -7
  27. data/test/test_db_api.rb +31 -19
  28. data/test/test_db_connection.rb +1 -1
  29. data/test/test_grid_store.rb +8 -8
  30. data/test/test_helper.rb +25 -0
  31. data/test/test_objectid.rb +11 -1
  32. data/test/test_slave_connection.rb +37 -0
  33. data/test/test_threading.rb +1 -1
  34. data/test/unit/cursor_test.rb +122 -0
  35. metadata +26 -46
  36. data/bin/mongo_console +0 -21
  37. data/bin/run_test_script +0 -19
  38. data/bin/standard_benchmark +0 -109
  39. data/lib/mongo/message/get_more_message.rb +0 -32
  40. data/lib/mongo/message/insert_message.rb +0 -37
  41. data/lib/mongo/message/kill_cursors_message.rb +0 -31
  42. data/lib/mongo/message/message.rb +0 -80
  43. data/lib/mongo/message/message_header.rb +0 -45
  44. data/lib/mongo/message/msg_message.rb +0 -29
  45. data/lib/mongo/message/opcodes.rb +0 -27
  46. data/lib/mongo/message/query_message.rb +0 -69
  47. data/lib/mongo/message/remove_message.rb +0 -37
  48. data/lib/mongo/message/update_message.rb +0 -38
  49. data/lib/mongo/query.rb +0 -118
  50. data/test/mongo-qa/admin +0 -26
  51. data/test/mongo-qa/capped +0 -22
  52. data/test/mongo-qa/count1 +0 -18
  53. data/test/mongo-qa/dbs +0 -22
  54. data/test/mongo-qa/find +0 -10
  55. data/test/mongo-qa/find1 +0 -15
  56. data/test/mongo-qa/gridfs_in +0 -16
  57. data/test/mongo-qa/gridfs_out +0 -17
  58. data/test/mongo-qa/indices +0 -49
  59. data/test/mongo-qa/remove +0 -25
  60. data/test/mongo-qa/stress1 +0 -35
  61. data/test/mongo-qa/test1 +0 -11
  62. data/test/mongo-qa/update +0 -18
  63. data/test/test_message.rb +0 -35
@@ -15,6 +15,12 @@
15
15
  # Exceptions raised by the MongoDB driver.
16
16
 
17
17
  module Mongo
18
+ # Generic Mongo Ruby Driver exception class.
19
+ class MongoRubyError < StandardError; end
20
+
21
+ # Raised when configuration options cause connections, queries, etc., to fail.
22
+ class ConfigurationError < MongoRubyError; end
23
+
18
24
  # Raised when a database operation fails.
19
25
  class OperationFailure < RuntimeError; end
20
26
 
@@ -25,5 +31,5 @@ module Mongo
25
31
  class InvalidName < RuntimeError; end
26
32
 
27
33
  # Raised when the client supplies an invalid value to sort by.
28
- class InvalidSortValueError < RuntimeError; end
34
+ class InvalidSortValueError < MongoRubyError; end
29
35
  end
@@ -42,6 +42,11 @@ module Mongo
42
42
  str && str.length == len && match == str
43
43
  end
44
44
 
45
+ # Adds a primary key to the given document if needed.
46
+ def self.create_pk(doc)
47
+ doc[:_id] || doc['_id'] ? doc : doc.merge!(:_id => self.new)
48
+ end
49
+
45
50
  # +data+ is an array of bytes. If nil, a new id will be generated.
46
51
  def initialize(data=nil)
47
52
  @data = data || generate
@@ -54,6 +54,18 @@ class ByteBuffer
54
54
  end
55
55
  alias_method :length, :size
56
56
 
57
+ # Appends a second ByteBuffer object, +buffer+, to the current buffer.
58
+ def append!(buffer)
59
+ @buf = @buf + buffer.to_a
60
+ self
61
+ end
62
+
63
+ # Prepends a second ByteBuffer object, +buffer+, to the current buffer.
64
+ def prepend!(buffer)
65
+ @buf = buffer.to_a + @buf
66
+ self
67
+ end
68
+
57
69
  def put(byte, offset=nil)
58
70
  @cursor = offset if offset
59
71
  @buf[@cursor] = byte
@@ -0,0 +1,69 @@
1
+ # --
2
+ # Copyright (C) 2008-2009 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
+ module Mongo
17
+ # Simple class for comparing server versions.
18
+ class ServerVersion
19
+ include Comparable
20
+
21
+ def initialize(version)
22
+ @version = version
23
+ end
24
+
25
+ # Implements comparable.
26
+ def <=>(new)
27
+ local, new = self.to_a, to_array(new)
28
+ for n in 0...local.size do
29
+ break if elements_include_mods?(local[n], new[n])
30
+ if local[n] < new[n].to_i
31
+ result = -1
32
+ break;
33
+ elsif local[n] > new[n].to_i
34
+ result = 1
35
+ break;
36
+ end
37
+ end
38
+ result || 0
39
+ end
40
+
41
+ # Return an array representation of this server version.
42
+ def to_a
43
+ to_array(@version)
44
+ end
45
+
46
+ # Return a string representation of this server version.
47
+ def to_s
48
+ @version
49
+ end
50
+
51
+ private
52
+
53
+ # Returns true if any elements include mod symbols (-, +)
54
+ def elements_include_mods?(*elements)
55
+ elements.any? { |n| n =~ /[\-\+]/ }
56
+ end
57
+
58
+ # Converts argument to an array of integers,
59
+ # appending any mods as the final element.
60
+ def to_array(version)
61
+ array = version.split(".").map {|n| (n =~ /^\d+$/) ? n.to_i : n }
62
+ if array.last =~ /(\d+)([\-\+])/
63
+ array[array.length-1] = $1.to_i
64
+ array << $2
65
+ end
66
+ array
67
+ end
68
+ end
69
+ end
@@ -13,8 +13,11 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
  # ++
16
+ class Object
16
17
 
17
- %w(get_more_message insert_message kill_cursors_message message_header
18
- msg_message query_message remove_message update_message).each { |f|
19
- require "mongo/message/#{f}"
20
- }
18
+ def returning(value)
19
+ yield value
20
+ value
21
+ end
22
+
23
+ end
@@ -1,99 +1,22 @@
1
- # We need to list all of the included files because we aren't allowed to use
2
- # Dir[...] in the github sandbox.
3
- PACKAGE_FILES = ['README.rdoc', 'Rakefile', 'mongo-ruby-driver.gemspec',
4
- 'bin/bson_benchmark.rb',
5
- 'bin/mongo_console',
6
- 'bin/run_test_script',
7
- 'bin/standard_benchmark',
8
- 'examples/admin.rb',
9
- 'examples/benchmarks.rb',
10
- 'examples/blog.rb',
11
- 'examples/capped.rb',
12
- 'examples/cursor.rb',
13
- 'examples/gridfs.rb',
14
- 'examples/index_test.rb',
15
- 'examples/info.rb',
16
- 'examples/queries.rb',
17
- 'examples/simple.rb',
18
- 'examples/strict.rb',
19
- 'examples/types.rb',
20
- 'lib/mongo/admin.rb',
21
- 'lib/mongo/collection.rb',
22
- 'lib/mongo/connection.rb',
23
- 'lib/mongo/cursor.rb',
24
- 'lib/mongo/db.rb',
25
- 'lib/mongo/gridfs/chunk.rb',
26
- 'lib/mongo/gridfs/grid_store.rb',
27
- 'lib/mongo/gridfs.rb',
28
- 'lib/mongo/errors.rb',
29
- 'lib/mongo/message/get_more_message.rb',
30
- 'lib/mongo/message/insert_message.rb',
31
- 'lib/mongo/message/kill_cursors_message.rb',
32
- 'lib/mongo/message/message.rb',
33
- 'lib/mongo/message/message_header.rb',
34
- 'lib/mongo/message/msg_message.rb',
35
- 'lib/mongo/message/opcodes.rb',
36
- 'lib/mongo/message/query_message.rb',
37
- 'lib/mongo/message/remove_message.rb',
38
- 'lib/mongo/message/update_message.rb',
39
- 'lib/mongo/message.rb',
40
- 'lib/mongo/query.rb',
41
- 'lib/mongo/types/binary.rb',
42
- 'lib/mongo/types/code.rb',
43
- 'lib/mongo/types/dbref.rb',
44
- 'lib/mongo/types/objectid.rb',
45
- 'lib/mongo/types/regexp_of_holding.rb',
46
- 'lib/mongo/util/bson.rb',
47
- 'lib/mongo/util/byte_buffer.rb',
48
- 'lib/mongo/util/conversions.rb',
49
- 'lib/mongo/util/ordered_hash.rb',
50
- 'lib/mongo/util/xml_to_ruby.rb',
51
- 'lib/mongo.rb']
52
- TEST_FILES = ['test/mongo-qa/_common.rb',
53
- 'test/mongo-qa/admin',
54
- 'test/mongo-qa/capped',
55
- 'test/mongo-qa/count1',
56
- 'test/mongo-qa/dbs',
57
- 'test/mongo-qa/find',
58
- 'test/mongo-qa/find1',
59
- 'test/mongo-qa/gridfs_in',
60
- 'test/mongo-qa/gridfs_out',
61
- 'test/mongo-qa/indices',
62
- 'test/mongo-qa/remove',
63
- 'test/mongo-qa/stress1',
64
- 'test/mongo-qa/test1',
65
- 'test/mongo-qa/update',
66
- 'test/test_admin.rb',
67
- 'test/test_bson.rb',
68
- 'test/test_byte_buffer.rb',
69
- 'test/test_chunk.rb',
70
- 'test/test_collection.rb',
71
- 'test/test_connection.rb',
72
- 'test/test_conversions.rb',
73
- 'test/test_cursor.rb',
74
- 'test/test_db.rb',
75
- 'test/test_db_api.rb',
76
- 'test/test_db_connection.rb',
77
- 'test/test_grid_store.rb',
78
- 'test/test_message.rb',
79
- 'test/test_objectid.rb',
80
- 'test/test_ordered_hash.rb',
81
- 'test/test_threading.rb',
82
- 'test/test_round_trip.rb']
1
+ require "lib/mongo"
83
2
 
84
3
  Gem::Specification.new do |s|
85
4
  s.name = 'mongo'
86
5
 
87
- # be sure to change this constant in lib/mongo.rb as well
88
- s.version = '0.15.1'
6
+ s.version = Mongo::VERSION
89
7
 
90
8
  s.platform = Gem::Platform::RUBY
91
9
  s.summary = 'Ruby driver for the MongoDB'
92
10
  s.description = 'A Ruby driver for MongoDB. For more information about Mongo, see http://www.mongodb.org.'
93
11
 
94
12
  s.require_paths = ['lib']
95
- s.files = PACKAGE_FILES
96
- s.test_files = TEST_FILES
13
+
14
+ s.files = ['README.rdoc', 'Rakefile', 'mongo-ruby-driver.gemspec', 'LICENSE.txt']
15
+ s.files += Dir['lib/**/*.rb'] + Dir['examples/**/*.rb'] + Dir['bin/**/*.rb']
16
+ s.test_files = Dir['test/**/*.rb']
17
+
18
+ s.has_rdoc = true
19
+ s.test_files = Dir['test/**/*.rb']
97
20
 
98
21
  s.has_rdoc = true
99
22
  s.rdoc_options = ['--main', 'README.rdoc', '--inline-source']
@@ -13,7 +13,7 @@ class AdminTest < Test::Unit::TestCase
13
13
 
14
14
  def setup
15
15
  # Insert some data to make sure the database itself exists.
16
- @@coll.clear
16
+ @@coll.remove
17
17
  @r1 = @@coll.insert('a' => 1) # collection not created until it's used
18
18
  @@coll_full_name = 'ruby-mongo-test.test'
19
19
  @admin = @@db.admin
@@ -21,7 +21,7 @@ class AdminTest < Test::Unit::TestCase
21
21
 
22
22
  def teardown
23
23
  @admin.profiling_level = :off
24
- @@coll.clear if @@coll
24
+ @@coll.remove if @@coll
25
25
  @@db.error
26
26
  end
27
27
 
@@ -265,4 +265,18 @@ class BSONTest < Test::Unit::TestCase
265
265
  assert val.keys.include?(:_id)
266
266
  end
267
267
 
268
+ # note we only test for _id here because in the general case we will
269
+ # write duplicates for :key and "key". _id is a special case because
270
+ # we call has_key? to check for it's existance rather than just iterating
271
+ # over it like we do for the rest of the keys. thus, things like
272
+ # HashWithIndifferentAccess can cause problems for _id but not for other
273
+ # keys. rather than require rails to test with HWIA directly, we do this
274
+ # somewhat hacky test.
275
+ def test_no_duplicate_id
276
+ dup = {"_id" => "foo", :_id => "foo"}
277
+ one = {"_id" => "foo"}
278
+
279
+ assert_equal @b.serialize(one).to_a, @b.serialize(dup).to_a
280
+ end
281
+
268
282
  end
@@ -66,4 +66,18 @@ class ByteBufferTest < Test::Unit::TestCase
66
66
  assert_equal 4, @buf.position
67
67
  end
68
68
 
69
+ def test_prepend_byte_buffer
70
+ @buf.put_int(4)
71
+ new_buf = ByteBuffer.new([5, 0, 0, 0])
72
+ @buf.prepend!(new_buf)
73
+ assert_equal [5, 0, 0, 0, 4, 0, 0, 0], @buf.to_a
74
+ end
75
+
76
+ def test_append_byte_buffer
77
+ @buf.put_int(4)
78
+ new_buf = ByteBuffer.new([5, 0, 0, 0])
79
+ @buf.append!(new_buf)
80
+ assert_equal [4, 0, 0, 0, 5, 0, 0, 0], @buf.to_a
81
+ end
82
+
69
83
  end
@@ -14,16 +14,16 @@ class ChunkTest < Test::Unit::TestCase
14
14
  @@chunks = @@db.collection('gridfs.chunks')
15
15
 
16
16
  def setup
17
- @@chunks.clear
18
- @@files.clear
17
+ @@chunks.remove
18
+ @@files.remove
19
19
 
20
20
  @f = GridStore.new(@@db, 'foobar', 'w')
21
21
  @c = @f.instance_variable_get('@curr_chunk')
22
22
  end
23
23
 
24
24
  def teardown
25
- @@chunks.clear
26
- @@files.clear
25
+ @@chunks.remove
26
+ @@files.remove
27
27
  @@db.error
28
28
  end
29
29
 
@@ -14,22 +14,33 @@
14
14
  # limitations under the License.
15
15
  # ++
16
16
 
17
- $LOAD_PATH[0,0] = File.join(File.dirname(__FILE__), '..', 'lib')
18
- require 'mongo'
19
- require 'test/unit'
20
-
21
- # NOTE: assumes Mongo is running
17
+ require 'test/test_helper'
22
18
  class TestCollection < Test::Unit::TestCase
23
- include Mongo
24
-
25
- @@db = Connection.new(ENV['MONGO_RUBY_DRIVER_HOST'] || 'localhost',
26
- ENV['MONGO_RUBY_DRIVER_PORT'] || Connection::DEFAULT_PORT).db('ruby-mongo-test')
19
+ @@connection = Connection.new(ENV['MONGO_RUBY_DRIVER_HOST'] || 'localhost', ENV['MONGO_RUBY_DRIVER_PORT'] || Connection::DEFAULT_PORT)
20
+ @@db = @@connection.db('ruby-mongo-test')
27
21
  @@test = @@db.collection("test")
22
+ @@version = @@connection.server_version
28
23
 
29
24
  def setup
30
25
  @@test.drop()
31
26
  end
32
27
 
28
+ def test_optional_pk_factory
29
+ @coll_default_pk = @@db.collection('stuff')
30
+ assert_equal Mongo::ObjectID, @coll_default_pk.pk_factory
31
+ @coll_default_pk = @@db.create_collection('more-stuff')
32
+ assert_equal Mongo::ObjectID, @coll_default_pk.pk_factory
33
+
34
+ # Create a db with a pk_factory.
35
+ @db = Connection.new(ENV['MONGO_RUBY_DRIVER_HOST'] || 'localhost',
36
+ ENV['MONGO_RUBY_DRIVER_PORT'] || Connection::DEFAULT_PORT).db('ruby-mongo-test', :pk => Object.new)
37
+ @coll = @db.collection('coll-with-pk')
38
+ assert @coll.pk_factory.is_a?(Object)
39
+
40
+ @coll = @db.create_collection('created_coll_with_pk')
41
+ assert @coll.pk_factory.is_a?(Object)
42
+ end
43
+
33
44
  def test_collection
34
45
  assert_raise InvalidName do
35
46
  @@db["te$t"]
@@ -43,7 +54,7 @@ class TestCollection < Test::Unit::TestCase
43
54
  assert_equal @@db["test"]["foo"].name(), @@db.collection("test.foo").name()
44
55
  assert_equal @@db["test"]["foo"].name(), @@db["test.foo"].name()
45
56
 
46
- @@db["test"]["foo"].clear
57
+ @@db["test"]["foo"].remove
47
58
  @@db["test"]["foo"].insert("x" => 5)
48
59
  assert_equal 5, @@db.collection("test.foo").find_one()["x"]
49
60
  end
@@ -79,15 +90,33 @@ class TestCollection < Test::Unit::TestCase
79
90
  assert_equal 2, @@test.find_one()["count"]
80
91
  end
81
92
 
82
- def test_safe_update
83
- @@test.create_index("x")
84
- @@test.insert("x" => 5)
93
+ if @@version < "1.1.3"
94
+ def test_safe_update
95
+ @@test.create_index("x")
96
+ @@test.insert("x" => 5)
85
97
 
86
- @@test.update({}, {"$inc" => {"x" => 1}})
87
- assert @@db.error?
98
+ @@test.update({}, {"$inc" => {"x" => 1}})
99
+ assert @@db.error?
88
100
 
89
- assert_raise OperationFailure do
90
- @@test.update({}, {"$inc" => {"x" => 1}}, :safe => true)
101
+ # Can't change an index.
102
+ assert_raise OperationFailure do
103
+ @@test.update({}, {"$inc" => {"x" => 1}}, :safe => true)
104
+ end
105
+ end
106
+ else
107
+ def test_safe_update
108
+ @@test.create_index("x", true)
109
+ @@test.insert("x" => 5)
110
+ @@test.insert("x" => 10)
111
+
112
+ # Can update an indexed collection.
113
+ @@test.update({}, {"$inc" => {"x" => 1}})
114
+ assert !@@db.error?
115
+
116
+ # Can't duplicate an index.
117
+ assert_raise OperationFailure do
118
+ @@test.update({}, {"x" => 10}, :safe => true, :upsert => true)
119
+ end
91
120
  end
92
121
  end
93
122
 
@@ -112,6 +141,35 @@ class TestCollection < Test::Unit::TestCase
112
141
  assert_equal 2, @@test.count
113
142
  end
114
143
 
144
+ # Note: #size is just an alias for #count.
145
+ def test_size
146
+ @@test.drop
147
+
148
+ assert_equal 0, @@test.count
149
+ assert_equal @@test.size, @@test.count
150
+ @@test.save("x" => 1)
151
+ @@test.save("x" => 2)
152
+ assert_equal @@test.size, @@test.count
153
+ end
154
+
155
+ def test_no_timeout_option
156
+ @@test.drop
157
+
158
+ assert_raise ArgumentError, "Timeout can be set to false only when #find is invoked with a block." do
159
+ @@test.find({}, :timeout => false)
160
+ end
161
+
162
+ @@test.find({}, :timeout => false) do |cursor|
163
+ assert_equal 0, cursor.count
164
+ end
165
+
166
+ @@test.save("x" => 1)
167
+ @@test.save("x" => 2)
168
+ @@test.find({}, :timeout => false) do |cursor|
169
+ assert_equal 2, cursor.count
170
+ end
171
+ end
172
+
115
173
  def test_find_one
116
174
  id = @@test.save("hello" => "world", "foo" => "bar")
117
175
 
@@ -278,5 +336,37 @@ class TestCollection < Test::Unit::TestCase
278
336
  # assert_equal 1, @@test.group([], {}, {"count" => 0},
279
337
  # Code.new(reduce_function,
280
338
  # {"inc_value" => 0.5}), true)[0]["count"]
339
+ end
340
+
341
+ context "A collection with two records" do
342
+ setup do
343
+ @collection = @@db.collection('test-collection')
344
+ @collection.insert({:name => "Jones"})
345
+ @collection.insert({:name => "Smith"})
346
+ end
347
+
348
+ should "have two records" do
349
+ assert_equal 2, @collection.size
350
+ end
351
+
352
+ should "remove the two records" do
353
+ @collection.remove()
354
+ assert_equal 0, @collection.size
355
+ end
356
+
357
+ should "remove all records if an empty document is specified" do
358
+ @collection.remove({})
359
+ assert_equal 0, @collection.find.count
360
+ end
361
+
362
+ should "remove all records if deprecated clear is used" do
363
+ @collection.clear
364
+ assert_equal 0, @collection.find.count
365
+ end
366
+
367
+ should "remove only matching records" do
368
+ @collection.remove({:name => "Jones"})
369
+ assert_equal 1, @collection.size
370
+ end
281
371
  end
282
372
  end