mongo 0.15.1 → 0.16

Sign up to get free protection for your applications and to get access to all the features.
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