mongodb-mongo 0.1.3

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 (48) hide show
  1. data/README.rdoc +216 -0
  2. data/Rakefile +54 -0
  3. data/bin/mongo_console +21 -0
  4. data/bin/validate +51 -0
  5. data/examples/benchmarks.rb +38 -0
  6. data/examples/blog.rb +76 -0
  7. data/examples/index_test.rb +128 -0
  8. data/examples/simple.rb +17 -0
  9. data/lib/mongo/admin.rb +86 -0
  10. data/lib/mongo/collection.rb +161 -0
  11. data/lib/mongo/cursor.rb +230 -0
  12. data/lib/mongo/db.rb +399 -0
  13. data/lib/mongo/message/get_more_message.rb +21 -0
  14. data/lib/mongo/message/insert_message.rb +19 -0
  15. data/lib/mongo/message/kill_cursors_message.rb +20 -0
  16. data/lib/mongo/message/message.rb +68 -0
  17. data/lib/mongo/message/message_header.rb +34 -0
  18. data/lib/mongo/message/msg_message.rb +17 -0
  19. data/lib/mongo/message/opcodes.rb +16 -0
  20. data/lib/mongo/message/query_message.rb +67 -0
  21. data/lib/mongo/message/remove_message.rb +20 -0
  22. data/lib/mongo/message/update_message.rb +21 -0
  23. data/lib/mongo/message.rb +4 -0
  24. data/lib/mongo/mongo.rb +98 -0
  25. data/lib/mongo/query.rb +110 -0
  26. data/lib/mongo/types/binary.rb +34 -0
  27. data/lib/mongo/types/dbref.rb +37 -0
  28. data/lib/mongo/types/objectid.rb +137 -0
  29. data/lib/mongo/types/regexp_of_holding.rb +44 -0
  30. data/lib/mongo/types/undefined.rb +31 -0
  31. data/lib/mongo/util/bson.rb +431 -0
  32. data/lib/mongo/util/byte_buffer.rb +163 -0
  33. data/lib/mongo/util/ordered_hash.rb +68 -0
  34. data/lib/mongo/util/xml_to_ruby.rb +102 -0
  35. data/lib/mongo.rb +12 -0
  36. data/mongo-ruby-driver.gemspec +62 -0
  37. data/tests/test_admin.rb +60 -0
  38. data/tests/test_bson.rb +135 -0
  39. data/tests/test_byte_buffer.rb +69 -0
  40. data/tests/test_cursor.rb +66 -0
  41. data/tests/test_db.rb +85 -0
  42. data/tests/test_db_api.rb +354 -0
  43. data/tests/test_db_connection.rb +17 -0
  44. data/tests/test_message.rb +35 -0
  45. data/tests/test_objectid.rb +98 -0
  46. data/tests/test_ordered_hash.rb +85 -0
  47. data/tests/test_round_trip.rb +116 -0
  48. metadata +100 -0
@@ -0,0 +1,102 @@
1
+ # --
2
+ # Copyright (C) 2008-2009 10gen Inc.
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify it
5
+ # under the terms of the GNU Affero General Public License, version 3, as
6
+ # published by the Free Software Foundation.
7
+ #
8
+ # This program is distributed in the hope that it will be useful, but WITHOUT
9
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
11
+ # for more details.
12
+ #
13
+ # You should have received a copy of the GNU Affero General Public License
14
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
15
+ # ++
16
+
17
+ require 'rexml/document'
18
+ require 'mongo'
19
+
20
+ # Converts a .xson file (an XML file that describes a Mongo-type document) to
21
+ # an OrderedHash.
22
+ class XMLToRuby
23
+
24
+ include XGen::Mongo::Driver
25
+
26
+ def xml_to_ruby(io)
27
+ doc = REXML::Document.new(io)
28
+ doc_to_ruby(doc.root.elements['doc'])
29
+ end
30
+
31
+ protected
32
+
33
+ def element_to_ruby(e)
34
+ type = e.name
35
+ child = e.elements[1]
36
+ case type
37
+ when 'oid'
38
+ ObjectID.from_string(e.text)
39
+ when 'ref'
40
+ dbref_to_ruby(e.elements)
41
+ when 'int'
42
+ e.text.to_i
43
+ when 'number'
44
+ e.text.to_f
45
+ when 'string', 'code'
46
+ e.text.to_s
47
+ when 'binary'
48
+ Base64.decode64(e.text.to_s).to_mongo_binary
49
+ when 'symbol'
50
+ e.text.to_s.intern
51
+ when 'boolean'
52
+ e.text.to_s == 'true'
53
+ when 'array'
54
+ array_to_ruby(e.elements)
55
+ when 'date'
56
+ Time.at(e.text.to_f / 1000.0)
57
+ when 'regex'
58
+ regex_to_ruby(e.elements)
59
+ when 'null'
60
+ nil
61
+ when 'undefined'
62
+ Undefined.new
63
+ when 'doc'
64
+ doc_to_ruby(e)
65
+ else
66
+ raise "Unknown type #{type} in element with name #{e.attributes['name']}"
67
+ end
68
+ end
69
+
70
+ def doc_to_ruby(element)
71
+ oh = OrderedHash.new
72
+ element.elements.each { |e| oh[e.attributes['name']] = element_to_ruby(e) }
73
+ oh
74
+ end
75
+
76
+ def array_to_ruby(elements)
77
+ a = []
78
+ elements.each { |e|
79
+ index_str = e.attributes['name']
80
+ a[index_str.to_i] = element_to_ruby(e)
81
+ }
82
+ a
83
+ end
84
+
85
+ def regex_to_ruby(elements)
86
+ pattern = elements['pattern'].text
87
+ options_str = elements['options'].text || ''
88
+
89
+ options = 0
90
+ options |= Regexp::IGNORECASE if options_str.include?('i')
91
+ options |= Regexp::MULTILINE if options_str.include?('m')
92
+ options |= Regexp::EXTENDED if options_str.include?('x')
93
+ Regexp.new(pattern, options)
94
+ end
95
+
96
+ def dbref_to_ruby(elements)
97
+ ns = elements['ns'].text
98
+ oid_str = elements['oid'].text
99
+ DBRef.new(nil, nil, nil, ns, ObjectID.from_string(oid_str))
100
+ end
101
+
102
+ end
data/lib/mongo.rb ADDED
@@ -0,0 +1,12 @@
1
+ require 'mongo/types/binary'
2
+ require 'mongo/types/dbref'
3
+ require 'mongo/types/objectid'
4
+ require 'mongo/types/regexp_of_holding'
5
+ require 'mongo/types/undefined'
6
+
7
+ require 'mongo/mongo'
8
+ require 'mongo/message'
9
+ require 'mongo/db'
10
+ require 'mongo/cursor'
11
+ require 'mongo/collection'
12
+ require 'mongo/admin'
@@ -0,0 +1,62 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'mongo'
3
+ s.version = '0.1.3'
4
+ s.platform = Gem::Platform::RUBY
5
+ s.summary = 'Simple pure-Ruby driver for the 10gen Mongo DB'
6
+ s.description = 'A pure-Ruby driver for the 10gen Mongo DB. For more information about Mongo, see http://www.mongodb.org.'
7
+
8
+ s.require_paths = ['lib']
9
+
10
+ s.files = ['bin/mongo_console', 'bin/validate',
11
+ 'examples/benchmarks.rb',
12
+ 'examples/blog.rb',
13
+ 'examples/index_test.rb',
14
+ 'examples/simple.rb',
15
+ 'lib/mongo.rb',
16
+ 'lib/mongo/admin.rb',
17
+ 'lib/mongo/collection.rb',
18
+ 'lib/mongo/cursor.rb',
19
+ 'lib/mongo/db.rb',
20
+ 'lib/mongo/message/get_more_message.rb',
21
+ 'lib/mongo/message/insert_message.rb',
22
+ 'lib/mongo/message/kill_cursors_message.rb',
23
+ 'lib/mongo/message/message.rb',
24
+ 'lib/mongo/message/message_header.rb',
25
+ 'lib/mongo/message/msg_message.rb',
26
+ 'lib/mongo/message/opcodes.rb',
27
+ 'lib/mongo/message/query_message.rb',
28
+ 'lib/mongo/message/remove_message.rb',
29
+ 'lib/mongo/message/update_message.rb',
30
+ 'lib/mongo/message.rb',
31
+ 'lib/mongo/mongo.rb',
32
+ 'lib/mongo/query.rb',
33
+ 'lib/mongo/types/binary.rb',
34
+ 'lib/mongo/types/dbref.rb',
35
+ 'lib/mongo/types/objectid.rb',
36
+ 'lib/mongo/types/regexp_of_holding.rb',
37
+ 'lib/mongo/types/undefined.rb',
38
+ 'lib/mongo/util/bson.rb',
39
+ 'lib/mongo/util/byte_buffer.rb',
40
+ 'lib/mongo/util/ordered_hash.rb',
41
+ 'lib/mongo/util/xml_to_ruby.rb',
42
+ 'README.rdoc', 'Rakefile', 'mongo-ruby-driver.gemspec']
43
+ s.test_files = ['tests/test_admin.rb',
44
+ 'tests/test_bson.rb',
45
+ 'tests/test_byte_buffer.rb',
46
+ 'tests/test_cursor.rb',
47
+ 'tests/test_db.rb',
48
+ 'tests/test_db_api.rb',
49
+ 'tests/test_db_connection.rb',
50
+ 'tests/test_message.rb',
51
+ 'tests/test_objectid.rb',
52
+ 'tests/test_ordered_hash.rb',
53
+ 'tests/test_round_trip.rb']
54
+
55
+ s.has_rdoc = true
56
+ s.rdoc_options = ['--main', 'README.rdoc', '--inline-source']
57
+ s.extra_rdoc_files = ['README.rdoc']
58
+
59
+ s.author = 'Jim Menard'
60
+ s.email = 'jim@10gen.com'
61
+ s.homepage = 'http://www.mongodb.org'
62
+ end
@@ -0,0 +1,60 @@
1
+ $LOAD_PATH[0,0] = File.join(File.dirname(__FILE__), '..', 'lib')
2
+ require 'mongo'
3
+ require 'test/unit'
4
+
5
+ # NOTE: assumes Mongo is running
6
+ class AdminTest < Test::Unit::TestCase
7
+
8
+ include XGen::Mongo::Driver
9
+
10
+ def setup
11
+ host = ENV['MONGO_RUBY_DRIVER_HOST'] || 'localhost'
12
+ port = ENV['MONGO_RUBY_DRIVER_PORT'] || Mongo::DEFAULT_PORT
13
+ @db = Mongo.new(host, port).db('ruby-mongo-test')
14
+ # Insert some data to make sure the database itself exists.
15
+ @coll = @db.collection('test')
16
+ @coll.clear
17
+ @r1 = @coll.insert('a' => 1) # collection not created until it's used
18
+ @coll_full_name = 'ruby-mongo-test.test'
19
+ @admin = @db.admin
20
+ end
21
+
22
+ def teardown
23
+ if @db.connected?
24
+ @admin.profiling_level = :off
25
+ @coll.clear if @coll
26
+ @db.close
27
+ end
28
+ end
29
+
30
+ def test_default_profiling_level
31
+ assert_equal :off, @admin.profiling_level
32
+ end
33
+
34
+ def test_change_profiling_level
35
+ @admin.profiling_level = :slow_only
36
+ assert_equal :slow_only, @admin.profiling_level
37
+ @admin.profiling_level = :off
38
+ assert_equal :off, @admin.profiling_level
39
+ end
40
+
41
+ def test_profiling_info
42
+ # Perform at least one query while profiling so we have something to see.
43
+ @admin.profiling_level = :all
44
+ @coll.find()
45
+ @admin.profiling_level = :off
46
+
47
+ info = @admin.profiling_info
48
+ assert_kind_of Array, info
49
+ assert info.length >= 1
50
+ first = info.first
51
+ assert_kind_of String, first['info']
52
+ assert_kind_of Time, first['ts']
53
+ assert_kind_of Numeric, first['millis']
54
+ end
55
+
56
+ def test_validate_collection
57
+ assert @admin.validate_collection(@coll.name)
58
+ end
59
+
60
+ end
@@ -0,0 +1,135 @@
1
+ $LOAD_PATH[0,0] = File.join(File.dirname(__FILE__), '..', 'lib')
2
+ require 'mongo'
3
+ require 'test/unit'
4
+
5
+ class BSONTest < Test::Unit::TestCase
6
+
7
+ include XGen::Mongo::Driver
8
+
9
+ def setup
10
+ # We don't pass a DB to the constructor, even though we are about to test
11
+ # deserialization. This means that when we deserialize, any DBRefs will
12
+ # have nil @db ivars. That's fine for now.
13
+ @b = BSON.new
14
+ end
15
+
16
+ def test_string
17
+ doc = {'doc' => 'hello, world'}
18
+ @b.serialize(doc)
19
+ assert_equal doc, @b.deserialize
20
+ end
21
+
22
+ def test_code
23
+ doc = {'$where' => 'this.a.b < this.b'}
24
+ @b.serialize(doc)
25
+ assert_equal doc, @b.deserialize
26
+ end
27
+
28
+ def test_number
29
+ doc = {'doc' => 41.99}
30
+ @b.serialize(doc)
31
+ assert_equal doc, @b.deserialize
32
+ end
33
+
34
+ def test_int
35
+ doc = {'doc' => 42}
36
+ @b.serialize(doc)
37
+ assert_equal doc, @b.deserialize
38
+ end
39
+
40
+ def test_object
41
+ doc = {'doc' => {'age' => 42, 'name' => 'Spongebob', 'shoe_size' => 9.5}}
42
+ @b.serialize(doc)
43
+ assert_equal doc, @b.deserialize
44
+ end
45
+
46
+ def test_oid
47
+ doc = {'doc' => ObjectID.new}
48
+ @b.serialize(doc)
49
+ assert_equal doc, @b.deserialize
50
+ end
51
+
52
+ def test_array
53
+ doc = {'doc' => [1, 2, 'a', 'b']}
54
+ @b.serialize(doc)
55
+ assert_equal doc, @b.deserialize
56
+ end
57
+
58
+ def test_regex
59
+ doc = {'doc' => /foobar/i}
60
+ @b.serialize(doc)
61
+ doc2 = @b.deserialize
62
+ assert_equal doc, doc2
63
+
64
+ r = doc2['doc']
65
+ assert_kind_of XGen::Mongo::Driver::RegexpOfHolding, r
66
+ assert_equal '', r.extra_options_str
67
+
68
+ r.extra_options_str << 'zywcab'
69
+ assert_equal 'zywcab', r.extra_options_str
70
+
71
+ b = BSON.new
72
+ doc = {'doc' => r}
73
+ b.serialize(doc)
74
+ doc2 = nil
75
+ doc2 = b.deserialize
76
+ assert_equal doc, doc2
77
+
78
+ r = doc2['doc']
79
+ assert_kind_of XGen::Mongo::Driver::RegexpOfHolding, r
80
+ assert_equal 'abcwyz', r.extra_options_str # must be sorted
81
+ end
82
+
83
+ def test_boolean
84
+ doc = {'doc' => true}
85
+ @b.serialize(doc)
86
+ assert_equal doc, @b.deserialize
87
+ end
88
+
89
+ def test_date
90
+ doc = {'date' => Time.now}
91
+ @b.serialize(doc)
92
+ doc2 = @b.deserialize
93
+ # Mongo only stores seconds, so comparing raw Time objects will fail
94
+ # because the fractional seconds will be different.
95
+ assert_equal doc['date'].to_i, doc2['date'].to_i
96
+ end
97
+
98
+ def test_null
99
+ end
100
+
101
+ def test_dbref
102
+ oid = ObjectID.new
103
+ doc = {}
104
+ doc['dbref'] = DBRef.new(doc, 'dbref', nil, 'namespace', oid)
105
+ @b.serialize(doc)
106
+ doc2 = @b.deserialize
107
+ assert_equal 'namespace', doc2['dbref'].namespace
108
+ assert_equal oid, doc2['dbref'].object_id
109
+ end
110
+
111
+ def test_symbol
112
+ doc = {'sym' => :foo}
113
+ @b.serialize(doc)
114
+ doc2 = @b.deserialize
115
+ assert_equal :foo, doc2['sym']
116
+ end
117
+
118
+ def test_binary
119
+ bin = 'binstring'.to_mongo_binary
120
+ assert_kind_of Binary, bin
121
+
122
+ doc = {'bin' => bin}
123
+ @b.serialize(doc)
124
+ doc2 = @b.deserialize
125
+ assert_equal 'binstring', doc2['bin']
126
+ end
127
+
128
+ def test_undefined
129
+ doc = {'undef' => Undefined.new}
130
+ @b.serialize(doc)
131
+ doc2 = @b.deserialize
132
+ assert_kind_of Undefined, doc2['undef']
133
+ end
134
+
135
+ end
@@ -0,0 +1,69 @@
1
+ $LOAD_PATH[0,0] = File.join(File.dirname(__FILE__), '..', 'lib')
2
+ require 'mongo'
3
+ require 'test/unit'
4
+
5
+ class ByteBufferTest < Test::Unit::TestCase
6
+
7
+ def setup
8
+ @buf = ByteBuffer.new
9
+ end
10
+
11
+ def test_nil_get_returns_one_byte
12
+ @buf.put_array([1, 2, 3, 4])
13
+ @buf.rewind
14
+ assert_equal 1, @buf.get
15
+ end
16
+
17
+ def test_one_get_returns_array_length_one
18
+ @buf.put_array([1, 2, 3, 4])
19
+ @buf.rewind
20
+ assert_equal [1], @buf.get(1)
21
+ end
22
+
23
+ def test_zero_get_returns_empty_array
24
+ @buf.put_array([1, 2, 3, 4])
25
+ @buf.rewind
26
+ assert_equal [], @buf.get(0)
27
+ end
28
+
29
+ def test_empty
30
+ assert_equal 0, @buf.length
31
+ end
32
+
33
+ def test_length
34
+ @buf.put_int 3
35
+ assert_equal 4, @buf.length
36
+ end
37
+
38
+ def test_default_order
39
+ assert_equal :little_endian, @buf.order
40
+ end
41
+
42
+ def test_long_length
43
+ @buf.put_long 1027
44
+ assert_equal 8, @buf.length
45
+ end
46
+
47
+ def test_get_long
48
+ @buf.put_long 1027
49
+ @buf.rewind
50
+ assert_equal 1027, @buf.get_long
51
+ end
52
+
53
+ def test_get_double
54
+ @buf.put_double 41.2
55
+ @buf.rewind
56
+ assert_equal 41.2, @buf.get_double
57
+ end
58
+
59
+ def test_rewrite
60
+ @buf.put_int(0)
61
+ @buf.rewind
62
+ @buf.put_int(1027)
63
+ assert_equal 4, @buf.length
64
+ @buf.rewind
65
+ assert_equal 1027, @buf.get_int
66
+ assert_equal 4, @buf.position
67
+ end
68
+
69
+ end
@@ -0,0 +1,66 @@
1
+ $LOAD_PATH[0,0] = File.join(File.dirname(__FILE__), '..', 'lib')
2
+ require 'mongo'
3
+ require 'test/unit'
4
+
5
+ # NOTE: assumes Mongo is running
6
+ class CursorTest < Test::Unit::TestCase
7
+
8
+ include XGen::Mongo::Driver
9
+
10
+ def setup
11
+ host = ENV['MONGO_RUBY_DRIVER_HOST'] || 'localhost'
12
+ port = ENV['MONGO_RUBY_DRIVER_PORT'] || Mongo::DEFAULT_PORT
13
+ @db = Mongo.new(host, port).db('ruby-mongo-test')
14
+ @coll = @db.collection('test')
15
+ @coll.clear
16
+ @r1 = @coll.insert('a' => 1) # collection not created until it's used
17
+ @coll_full_name = 'ruby-mongo-test.test'
18
+ end
19
+
20
+ def teardown
21
+ if @db.connected?
22
+ @coll.clear if @coll
23
+ @db.close
24
+ end
25
+ end
26
+
27
+ def test_explain
28
+ cursor = @coll.find('a' => 1)
29
+ explaination = cursor.explain
30
+ assert_not_nil explaination['cursor']
31
+ assert_kind_of Numeric, explaination['n']
32
+ assert_kind_of Numeric, explaination['millis']
33
+ assert_kind_of Numeric, explaination['nscanned']
34
+ end
35
+
36
+ def test_close_no_query_sent
37
+ begin
38
+ cursor = @coll.find('a' => 1)
39
+ cursor.close
40
+ assert cursor.closed?
41
+ rescue => ex
42
+ fail ex.to_s
43
+ end
44
+ end
45
+
46
+ def test_close_after_query_sent
47
+ begin
48
+ cursor = @coll.find('a' => 1)
49
+ cursor.next_object
50
+ cursor.close
51
+ assert cursor.closed?
52
+ rescue => ex
53
+ fail ex.to_s
54
+ end
55
+ end
56
+
57
+ def test_hint
58
+ begin
59
+ cursor = @coll.find('a' => 1).hint('a')
60
+ assert_equal 1, cursor.to_a.size
61
+ rescue => ex
62
+ fail ex.to_s
63
+ end
64
+ end
65
+
66
+ end
data/tests/test_db.rb ADDED
@@ -0,0 +1,85 @@
1
+ $LOAD_PATH[0,0] = File.join(File.dirname(__FILE__), '..', 'lib')
2
+ require 'mongo'
3
+ require 'test/unit'
4
+
5
+ class TestPKFactory
6
+ def create_pk(row)
7
+ row['_id'] ||= XGen::Mongo::Driver::ObjectID.new
8
+ row
9
+ end
10
+ end
11
+
12
+ # NOTE: assumes Mongo is running
13
+ class DBTest < Test::Unit::TestCase
14
+
15
+ include XGen::Mongo::Driver
16
+
17
+ def setup
18
+ @host = ENV['MONGO_RUBY_DRIVER_HOST'] || 'localhost'
19
+ @port = ENV['MONGO_RUBY_DRIVER_PORT'] || Mongo::DEFAULT_PORT
20
+ @db = Mongo.new(@host, @port).db('ruby-mongo-test')
21
+ end
22
+
23
+ def teardown
24
+ if @db.connected?
25
+ @db.close
26
+ end
27
+ end
28
+
29
+ def test_close
30
+ @db.close
31
+ assert !@db.connected?
32
+ begin
33
+ @db.collection('test').insert('a' => 1)
34
+ fail "expected 'NilClass' exception"
35
+ rescue => ex
36
+ assert_match /NilClass/, ex.to_s
37
+ end
38
+ end
39
+
40
+ def test_full_coll_name
41
+ coll = @db.collection('test')
42
+ assert_equal 'ruby-mongo-test.test', @db.full_coll_name(coll.name)
43
+ end
44
+
45
+ def test_master
46
+ # Doesn't really test anything since we probably only have one database
47
+ # during this test.
48
+ @db.switch_to_master
49
+ assert @db.connected?
50
+ end
51
+
52
+ def test_array
53
+ @db.close
54
+ @db = Mongo.new([["nosuch.example.com"], [@host, @port]]).db('ruby-mongo-test')
55
+ assert @db.connected?
56
+ end
57
+
58
+ def test_pk_factory
59
+ db = Mongo.new(@host, @port).db('ruby-mongo-test', :pk => TestPKFactory.new)
60
+ coll = db.collection('test')
61
+ coll.clear
62
+
63
+ obj = coll.insert('name' => 'Fred', 'age' => 42)
64
+ row = coll.find({'name' => 'Fred'}, :limit => 1).next_object
65
+ assert_equal obj, row
66
+
67
+ oid = XGen::Mongo::Driver::ObjectID.new
68
+ obj = coll.insert('_id' => oid, 'name' => 'Barney', 'age' => 41)
69
+ row = coll.find({'name' => 'Barney'}, :limit => 1).next_object
70
+ assert_equal obj, row
71
+
72
+ coll.clear
73
+ end
74
+
75
+ def test_pk_factory_reset
76
+ @db.pk_factory = Object.new # first time
77
+ begin
78
+ @db.pk_factory = Object.new
79
+ fail "error: expected exception"
80
+ rescue => ex
81
+ assert_match /can not change PK factory/, ex.to_s
82
+ end
83
+ end
84
+
85
+ end