mongo 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +15 -0
- data/Rakefile +1 -1
- data/lib/mongo.rb +6 -4
- data/lib/mongo/admin.rb +1 -1
- data/lib/mongo/collection.rb +11 -2
- data/lib/mongo/cursor.rb +53 -6
- data/lib/mongo/db.rb +31 -8
- data/lib/mongo/message/query_message.rb +3 -0
- data/lib/mongo/{binary.rb → types/binary.rb} +0 -0
- data/lib/mongo/{dbref.rb → types/dbref.rb} +0 -0
- data/lib/mongo/{objectid.rb → types/objectid.rb} +0 -0
- data/lib/mongo/types/regexp_of_holding.rb +44 -0
- data/lib/mongo/{undefined.rb → types/undefined.rb} +0 -0
- data/lib/mongo/util/bson.rb +34 -22
- data/lib/mongo/util/ordered_hash.rb +8 -0
- data/tests/test_bson.rb +20 -1
- data/tests/test_cursor.rb +63 -0
- data/tests/test_db_api.rb +4 -0
- metadata +8 -6
data/README.rdoc
CHANGED
@@ -49,6 +49,21 @@ be running, of course.
|
|
49
49
|
See also the test code, especially tests/test_db_api.rb.
|
50
50
|
|
51
51
|
|
52
|
+
= Notes
|
53
|
+
|
54
|
+
== String Encoding
|
55
|
+
|
56
|
+
The BSON ("Binary JSON") format used to communicate with Mongo requires that
|
57
|
+
strings be UTF-8 (http://en.wikipedia.org/wiki/UTF-8).
|
58
|
+
|
59
|
+
Ruby 1.9 has built-in character encoding support. All strings sent to Mongo
|
60
|
+
and received from Mongo are converted to UTF-8 when necessary, and strings
|
61
|
+
read from Mongo will have their character encodings set to UTF-8.
|
62
|
+
|
63
|
+
When used with Ruby 1.8, the bytes in each string are written to and read from
|
64
|
+
Mongo as-is. If the string is ASCII all is well, because ASCII is a subset of
|
65
|
+
UTF-8. If the string is not ASCII then it may not be a well-formed UTF-8 string.
|
66
|
+
|
52
67
|
= Testing
|
53
68
|
|
54
69
|
If you have the source code, you can run the tests.
|
data/Rakefile
CHANGED
@@ -7,7 +7,7 @@ require 'rake/gempackagetask'
|
|
7
7
|
require 'rake/contrib/rubyforgepublisher'
|
8
8
|
|
9
9
|
GEM = "mongo"
|
10
|
-
GEM_VERSION = '0.0.
|
10
|
+
GEM_VERSION = '0.0.4'
|
11
11
|
SUMMARY = 'Simple pure-Ruby driver for the 10gen Mongo DB'
|
12
12
|
DESCRIPTION = 'This is a simple pure-Ruby driver for the 10gen Mongo DB. For more information about Mongo, see http://www.mongodb.org.'
|
13
13
|
AUTHOR = 'Jim Menard'
|
data/lib/mongo.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
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
|
+
|
1
7
|
require 'mongo/mongo'
|
2
|
-
require 'mongo/objectid'
|
3
|
-
require 'mongo/dbref'
|
4
|
-
require 'mongo/binary'
|
5
|
-
require 'mongo/undefined'
|
6
8
|
require 'mongo/message'
|
7
9
|
require 'mongo/db'
|
8
10
|
require 'mongo/cursor'
|
data/lib/mongo/admin.rb
CHANGED
@@ -66,7 +66,7 @@ module XGen
|
|
66
66
|
# Return an array contining current profiling information from the
|
67
67
|
# database.
|
68
68
|
def profiling_info
|
69
|
-
@db.query(DB::SYSTEM_PROFILE_COLLECTION, Query.new({})).to_a
|
69
|
+
@db.query(Collection.new(@db, DB::SYSTEM_PROFILE_COLLECTION), Query.new({})).to_a
|
70
70
|
end
|
71
71
|
|
72
72
|
# Validate a named collection by raising an exception if there is a
|
data/lib/mongo/collection.rb
CHANGED
@@ -23,13 +23,22 @@ module XGen
|
|
23
23
|
# A named collection of records in a database.
|
24
24
|
class Collection
|
25
25
|
|
26
|
-
attr_reader :db, :name
|
26
|
+
attr_reader :db, :name, :hint_fields
|
27
27
|
|
28
28
|
def initialize(db, name)
|
29
29
|
@db = db
|
30
30
|
@name = name
|
31
31
|
end
|
32
32
|
|
33
|
+
# Set hint fields to use and return +self+. hint_fields may be a
|
34
|
+
# single field name or array of field names. May be +nil+. If no hint
|
35
|
+
# fields are specified, the ones in the collection are used if they
|
36
|
+
# exist.
|
37
|
+
def hint(hint_fields)
|
38
|
+
@hint_fileds = hint_fileds
|
39
|
+
self
|
40
|
+
end
|
41
|
+
|
33
42
|
# Return records that match a +selector+ hash. See Mongo docs for
|
34
43
|
# details.
|
35
44
|
#
|
@@ -47,7 +56,7 @@ module XGen
|
|
47
56
|
limit = options.delete(:limit) || 0
|
48
57
|
sort = options.delete(:sort)
|
49
58
|
raise RuntimeError, "Unknown options [#{options.inspect}]" unless options.empty?
|
50
|
-
@db.query(
|
59
|
+
@db.query(self, Query.new(selector, fields, offset, limit, sort))
|
51
60
|
end
|
52
61
|
|
53
62
|
# Insert +objects+, which are hashes. "<<" is aliased to this method.
|
data/lib/mongo/cursor.rb
CHANGED
@@ -29,12 +29,26 @@ module XGen
|
|
29
29
|
|
30
30
|
RESPONSE_HEADER_SIZE = 20
|
31
31
|
|
32
|
-
|
33
|
-
|
32
|
+
attr_reader :db, :collection, :query
|
33
|
+
|
34
|
+
def initialize(db, collection, query)
|
35
|
+
@db, @collection, @query = db, collection, query
|
36
|
+
@num_to_return = @query.number_to_return || 0
|
34
37
|
@cache = []
|
35
38
|
@closed = false
|
36
39
|
@can_call_to_a = true
|
37
|
-
|
40
|
+
@query_run = false
|
41
|
+
end
|
42
|
+
|
43
|
+
def closed?; @closed; end
|
44
|
+
|
45
|
+
# Set hint fields to use and return +self+. hint_fields may be a
|
46
|
+
# single field name or array of field names. May be +nil+. If no hint
|
47
|
+
# fields are specified, the ones in the collection are used if they
|
48
|
+
# exist.
|
49
|
+
def hint(hint_fields)
|
50
|
+
@hint_fields = hint_fields
|
51
|
+
self
|
38
52
|
end
|
39
53
|
|
40
54
|
# Return +true+ if there are more records to retrieve. We do not check
|
@@ -100,9 +114,20 @@ module XGen
|
|
100
114
|
@rows
|
101
115
|
end
|
102
116
|
|
117
|
+
# Returns an explain plan record.
|
118
|
+
def explain
|
119
|
+
sel = OrderedHash.new
|
120
|
+
sel['query'] = @query.selector
|
121
|
+
sel['$explain'] = true
|
122
|
+
c = Cursor.new(@db, @collection, Query.new(sel))
|
123
|
+
e = c.next_object
|
124
|
+
c.close
|
125
|
+
e
|
126
|
+
end
|
127
|
+
|
103
128
|
# Close the cursor.
|
104
129
|
def close
|
105
|
-
@db.send_to_db(
|
130
|
+
@db.send_to_db(KillCursorsMessage.new(@cursor_id)) if @cursor_id
|
106
131
|
@cache = []
|
107
132
|
@cursor_id = 0
|
108
133
|
@closed = true
|
@@ -146,6 +171,7 @@ module XGen
|
|
146
171
|
private
|
147
172
|
|
148
173
|
def next_object_on_wire
|
174
|
+
send_query_if_needed
|
149
175
|
# if @n_remaining is 0 but we have a non-zero cursor, there are more
|
150
176
|
# to fetch, so do a GetMore operation, but don't do it here - do it
|
151
177
|
# when someone pulls an object out of the cache and it's empty
|
@@ -154,8 +180,9 @@ module XGen
|
|
154
180
|
end
|
155
181
|
|
156
182
|
def refill_via_get_more
|
183
|
+
send_query_if_needed
|
157
184
|
return if @cursor_id == 0
|
158
|
-
@db.send_to_db(GetMoreMessage.new(@db.name, @collection, @cursor_id))
|
185
|
+
@db.send_to_db(GetMoreMessage.new(@db.name, @collection.name, @cursor_id))
|
159
186
|
read_all
|
160
187
|
end
|
161
188
|
|
@@ -170,6 +197,27 @@ module XGen
|
|
170
197
|
BSON.new(@db).deserialize(buf)
|
171
198
|
end
|
172
199
|
|
200
|
+
def send_query_if_needed
|
201
|
+
# Run query first time we request an object from the wire
|
202
|
+
unless @query_run
|
203
|
+
hints = @hint_fields || @collection.hint_fields
|
204
|
+
hints = [hints] if hints.kind_of?(String)
|
205
|
+
query = if hints
|
206
|
+
h = {}
|
207
|
+
hints.each { |field| h[field] = 1 }
|
208
|
+
sel = OrderedHash.new
|
209
|
+
sel['query'] = @query.selector
|
210
|
+
sel['$hint'] = h
|
211
|
+
Query.new(sel)
|
212
|
+
else
|
213
|
+
@query
|
214
|
+
end
|
215
|
+
@db.send_query_message(QueryMessage.new(@db.name, @collection.name, query))
|
216
|
+
@query_run = true
|
217
|
+
read_all
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
173
221
|
def to_s
|
174
222
|
"DBResponse(flags=#@result_flags, cursor_id=#@cursor_id, start=#@starting_from, n_returned=#@n_returned)"
|
175
223
|
end
|
@@ -177,4 +225,3 @@ module XGen
|
|
177
225
|
end
|
178
226
|
end
|
179
227
|
end
|
180
|
-
|
data/lib/mongo/db.rb
CHANGED
@@ -49,6 +49,8 @@ module XGen
|
|
49
49
|
# The name of the database.
|
50
50
|
attr_reader :name
|
51
51
|
|
52
|
+
attr_reader :host, :port
|
53
|
+
|
52
54
|
# The database's socket. For internal use only.
|
53
55
|
attr_reader :socket
|
54
56
|
|
@@ -82,7 +84,7 @@ module XGen
|
|
82
84
|
def collections_info(coll_name=nil)
|
83
85
|
selector = {}
|
84
86
|
selector[:name] = full_coll_name(coll_name) if coll_name
|
85
|
-
query(SYSTEM_NAMESPACE_COLLECTION, Query.new(selector))
|
87
|
+
query(Collection.new(self, SYSTEM_NAMESPACE_COLLECTION), Query.new(selector))
|
86
88
|
end
|
87
89
|
|
88
90
|
# Create a collection. If +strict+ is false, will return existing or
|
@@ -151,6 +153,20 @@ module XGen
|
|
151
153
|
ok?(doc) && is_master.kind_of?(Numeric) && is_master.to_i == 1
|
152
154
|
end
|
153
155
|
|
156
|
+
# Returns a string of the form "host:port" that points to the master
|
157
|
+
# database. Works even if this is the master database.
|
158
|
+
def master
|
159
|
+
doc = db_command(:ismaster => 1)
|
160
|
+
is_master = doc['ismaster']
|
161
|
+
raise "Error retrieving master database" unless ok?(doc) && is_master.kind_of?(Numeric)
|
162
|
+
case is_master.to_i
|
163
|
+
when 1
|
164
|
+
"#@host:#@port"
|
165
|
+
else
|
166
|
+
doc['remote']
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
154
170
|
# Close the connection to the database.
|
155
171
|
def close
|
156
172
|
@socket.close
|
@@ -161,12 +177,19 @@ module XGen
|
|
161
177
|
send_to_db(MsgMessage.new(msg))
|
162
178
|
end
|
163
179
|
|
164
|
-
#
|
165
|
-
#
|
166
|
-
|
180
|
+
# Returns a Cursor over the query results.
|
181
|
+
#
|
182
|
+
# Note that the query gets sent lazily; the cursor calls
|
183
|
+
# #send_query_message when needed. If the caller never requests an
|
184
|
+
# object from the cursor, the query never gets sent.
|
185
|
+
def query(collection, query)
|
186
|
+
Cursor.new(self, collection, query)
|
187
|
+
end
|
188
|
+
|
189
|
+
# Used by a Cursor to lazily send the query to the database.
|
190
|
+
def send_query_message(query_message)
|
167
191
|
@semaphore.synchronize {
|
168
|
-
send_to_db(
|
169
|
-
Cursor.new(self, collection_name, query.number_to_return)
|
192
|
+
send_to_db(query_message)
|
170
193
|
}
|
171
194
|
end
|
172
195
|
|
@@ -233,7 +256,7 @@ module XGen
|
|
233
256
|
# :ns :: Namespace; same as +collection_name+.
|
234
257
|
def index_information(collection_name)
|
235
258
|
sel = {:ns => full_coll_name(collection_name)}
|
236
|
-
query(SYSTEM_INDEX_COLLECTION, Query.new(sel)).collect { |row|
|
259
|
+
query(Collection.new(self, SYSTEM_INDEX_COLLECTION), Query.new(sel)).collect { |row|
|
237
260
|
h = {:name => row['name']}
|
238
261
|
raise "Name of index on return from db was nil. Coll = #{full_coll_name(collection_name)}" unless h[:name]
|
239
262
|
|
@@ -298,7 +321,7 @@ module XGen
|
|
298
321
|
|
299
322
|
q = Query.new(selector)
|
300
323
|
q.number_to_return = 1
|
301
|
-
query(SYSTEM_COMMAND_COLLECTION, q).next_object
|
324
|
+
query(Collection.new(self, SYSTEM_COMMAND_COLLECTION), q).next_object
|
302
325
|
end
|
303
326
|
|
304
327
|
end
|
@@ -8,8 +8,11 @@ module XGen
|
|
8
8
|
|
9
9
|
class QueryMessage < Message
|
10
10
|
|
11
|
+
attr_reader :query
|
12
|
+
|
11
13
|
def initialize(db_name, collection_name, query)
|
12
14
|
super(OP_QUERY)
|
15
|
+
@query = query
|
13
16
|
write_int(0)
|
14
17
|
write_string("#{db_name}.#{collection_name}")
|
15
18
|
write_int(query.number_to_skip)
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,44 @@
|
|
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
|
+
module XGen
|
18
|
+
module Mongo
|
19
|
+
module Driver
|
20
|
+
|
21
|
+
# A Regexp that can hold on to extra options and ignore them. Mongo
|
22
|
+
# regexes may contain option characters beyond 'i', 'm', and 'x'. (Note
|
23
|
+
# that Mongo only uses those three, but that regexes coming from other
|
24
|
+
# languages may store different option characters.)
|
25
|
+
#
|
26
|
+
# Note that you do not have to use this class at all if you wish to
|
27
|
+
# store regular expressions in Mongo. The Mongo and Ruby regex option
|
28
|
+
# flags are the same. Storing regexes is discouraged, in any case.
|
29
|
+
class RegexpOfHolding < Regexp
|
30
|
+
|
31
|
+
attr_accessor :extra_options_str
|
32
|
+
|
33
|
+
# +str+ and +options+ are the same as Regexp. +extra_options_str+
|
34
|
+
# contains all the other flags that were in Mongo but we do not use or
|
35
|
+
# understand.
|
36
|
+
def initialize(str, options, extra_options_str)
|
37
|
+
super(str, options)
|
38
|
+
@extra_options_str = extra_options_str
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
File without changes
|
data/lib/mongo/util/bson.rb
CHANGED
@@ -17,8 +17,11 @@
|
|
17
17
|
require 'base64'
|
18
18
|
require 'mongo/util/byte_buffer'
|
19
19
|
require 'mongo/util/ordered_hash'
|
20
|
-
require 'mongo/
|
21
|
-
require 'mongo/dbref'
|
20
|
+
require 'mongo/types/binary'
|
21
|
+
require 'mongo/types/dbref'
|
22
|
+
require 'mongo/types/objectid'
|
23
|
+
require 'mongo/types/regexp_of_holding'
|
24
|
+
require 'mongo/types/undefined'
|
22
25
|
|
23
26
|
# A BSON seralizer/deserializer.
|
24
27
|
class BSON
|
@@ -43,8 +46,18 @@ class BSON
|
|
43
46
|
NUMBER_INT = 16
|
44
47
|
MAXKEY = 127
|
45
48
|
|
49
|
+
if RUBY_VERSION >= '1.9'
|
50
|
+
def self.to_utf8(str)
|
51
|
+
str.encode("utf-8")
|
52
|
+
end
|
53
|
+
else
|
54
|
+
def self.to_utf8(str)
|
55
|
+
str # TODO punt for now
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
46
59
|
def self.serialize_cstr(buf, val)
|
47
|
-
buf.put_array(val.to_s.unpack("C*") + [0])
|
60
|
+
buf.put_array(to_utf8(val.to_s).unpack("C*") + [0])
|
48
61
|
end
|
49
62
|
|
50
63
|
def initialize(db=nil)
|
@@ -67,7 +80,7 @@ class BSON
|
|
67
80
|
obj.each {|k, v|
|
68
81
|
type = bson_type(v, k)
|
69
82
|
case type
|
70
|
-
when STRING, CODE
|
83
|
+
when STRING, CODE, SYMBOL
|
71
84
|
serialize_string_element(@buf, k, v, type)
|
72
85
|
when NUMBER, NUMBER_INT
|
73
86
|
serialize_number_element(@buf, k, v, type)
|
@@ -87,8 +100,6 @@ class BSON
|
|
87
100
|
serialize_null_element(@buf, k)
|
88
101
|
when REF
|
89
102
|
serialize_dbref_element(@buf, k, v)
|
90
|
-
when SYMBOL
|
91
|
-
serialize_symbol_element(@buf, k, v)
|
92
103
|
when BINARY
|
93
104
|
serialize_binary_element(@buf, k, v)
|
94
105
|
when UNDEFINED
|
@@ -118,6 +129,9 @@ class BSON
|
|
118
129
|
when STRING, CODE
|
119
130
|
key = deserialize_cstr(@buf)
|
120
131
|
doc[key] = deserialize_string_data(@buf)
|
132
|
+
when SYMBOL
|
133
|
+
key = deserialize_cstr(@buf)
|
134
|
+
doc[key] = deserialize_string_data(@buf).intern
|
121
135
|
when NUMBER
|
122
136
|
key = deserialize_cstr(@buf)
|
123
137
|
doc[key] = deserialize_number_data(@buf)
|
@@ -151,9 +165,6 @@ class BSON
|
|
151
165
|
when REF
|
152
166
|
key = deserialize_cstr(@buf)
|
153
167
|
doc[key] = deserialize_dbref_data(@buf, key, parent)
|
154
|
-
when SYMBOL
|
155
|
-
key = deserialize_cstr(@buf)
|
156
|
-
doc[key] = deserialize_symbol_data(@buf)
|
157
168
|
when BINARY
|
158
169
|
key = deserialize_cstr(@buf)
|
159
170
|
doc[key] = deserialize_binary_data(@buf)
|
@@ -170,6 +181,7 @@ class BSON
|
|
170
181
|
doc
|
171
182
|
end
|
172
183
|
|
184
|
+
# For debugging.
|
173
185
|
def hex_dump
|
174
186
|
str = ''
|
175
187
|
@buf.to_a.each_with_index { |b,i|
|
@@ -221,13 +233,18 @@ class BSON
|
|
221
233
|
options |= Regexp::IGNORECASE if options_str.include?('i')
|
222
234
|
options |= Regexp::MULTILINE if options_str.include?('m')
|
223
235
|
options |= Regexp::EXTENDED if options_str.include?('x')
|
224
|
-
|
236
|
+
options_str.gsub!(/[imx]/, '') # Now remove the three we understand
|
237
|
+
XGen::Mongo::Driver::RegexpOfHolding.new(str, options, options_str)
|
225
238
|
end
|
226
239
|
|
227
240
|
def deserialize_string_data(buf)
|
228
241
|
len = buf.get_int
|
229
242
|
bytes = buf.get(len)
|
230
|
-
bytes[0..-2].pack("C*")
|
243
|
+
str = bytes[0..-2].pack("C*")
|
244
|
+
if RUBY_VERSION >= '1.9'
|
245
|
+
str.force_encoding("utf-8")
|
246
|
+
end
|
247
|
+
str
|
231
248
|
end
|
232
249
|
|
233
250
|
def deserialize_oid_data(buf)
|
@@ -240,10 +257,6 @@ class BSON
|
|
240
257
|
XGen::Mongo::Driver::DBRef.new(parent, key, @db, ns, oid)
|
241
258
|
end
|
242
259
|
|
243
|
-
def deserialize_symbol_data(buf)
|
244
|
-
deserialize_cstr(buf).intern
|
245
|
-
end
|
246
|
-
|
247
260
|
def deserialize_binary_data(buf)
|
248
261
|
len = buf.get_int
|
249
262
|
bytes = buf.get(len)
|
@@ -268,12 +281,6 @@ class BSON
|
|
268
281
|
buf.put_array(val.object_id.to_a)
|
269
282
|
end
|
270
283
|
|
271
|
-
def serialize_symbol_element(buf, key, val)
|
272
|
-
buf.put(SYMBOL)
|
273
|
-
self.class.serialize_cstr(buf, key)
|
274
|
-
self.class.serialize_cstr(buf, val)
|
275
|
-
end
|
276
|
-
|
277
284
|
def serialize_binary_element(buf, key, val)
|
278
285
|
buf.put(BINARY)
|
279
286
|
self.class.serialize_cstr(buf, key)
|
@@ -342,7 +349,9 @@ class BSON
|
|
342
349
|
options_str << 'i' if ((options & Regexp::IGNORECASE) != 0)
|
343
350
|
options_str << 'm' if ((options & Regexp::MULTILINE) != 0)
|
344
351
|
options_str << 'x' if ((options & Regexp::EXTENDED) != 0)
|
345
|
-
|
352
|
+
options_str << val.extra_options_str if val.respond_to?(:extra_options_str)
|
353
|
+
# Must store option chars in alphabetical order
|
354
|
+
self.class.serialize_cstr(buf, options_str.split(//).sort.uniq.join)
|
346
355
|
end
|
347
356
|
|
348
357
|
def serialize_oid_element(buf, key, val)
|
@@ -379,6 +388,9 @@ class BSON
|
|
379
388
|
break if b == 0
|
380
389
|
chars << b.chr
|
381
390
|
end
|
391
|
+
if RUBY_VERSION >= '1.9'
|
392
|
+
chars.force_encoding("utf-8") # Mongo stores UTF-8
|
393
|
+
end
|
382
394
|
chars
|
383
395
|
end
|
384
396
|
|
@@ -15,8 +15,14 @@
|
|
15
15
|
# ++
|
16
16
|
|
17
17
|
# A hash in which the order of keys are preserved.
|
18
|
+
#
|
19
|
+
# Under Ruby 1.9 and greater, this class has no added methods because Ruby's
|
20
|
+
# Hash already keeps its keys ordered by order of insertion.
|
18
21
|
class OrderedHash < Hash
|
19
22
|
|
23
|
+
# We only need the body of this class if the RUBY_VERSION is before 1.9
|
24
|
+
if RUBY_VERSION < '1.9'
|
25
|
+
|
20
26
|
attr_accessor :ordered_keys
|
21
27
|
|
22
28
|
def keys
|
@@ -57,4 +63,6 @@ class OrderedHash < Hash
|
|
57
63
|
str << '}'
|
58
64
|
end
|
59
65
|
|
66
|
+
end # Ruby before 1.9
|
67
|
+
|
60
68
|
end
|
data/tests/test_bson.rb
CHANGED
@@ -59,7 +59,26 @@ class BSONTest < Test::Unit::TestCase
|
|
59
59
|
def test_regex
|
60
60
|
doc = {'doc' => /foobar/i}
|
61
61
|
@b.serialize(doc)
|
62
|
-
|
62
|
+
doc2 = @b.deserialize
|
63
|
+
assert_equal doc, doc2
|
64
|
+
|
65
|
+
r = doc2['doc']
|
66
|
+
assert_kind_of XGen::Mongo::Driver::RegexpOfHolding, r
|
67
|
+
assert_equal '', r.extra_options_str
|
68
|
+
|
69
|
+
r.extra_options_str << 'zywcab'
|
70
|
+
assert_equal 'zywcab', r.extra_options_str
|
71
|
+
|
72
|
+
b = BSON.new
|
73
|
+
doc = {'doc' => r}
|
74
|
+
b.serialize(doc)
|
75
|
+
doc2 = nil
|
76
|
+
doc2 = b.deserialize
|
77
|
+
assert_equal doc, doc2
|
78
|
+
|
79
|
+
r = doc2['doc']
|
80
|
+
assert_kind_of XGen::Mongo::Driver::RegexpOfHolding, r
|
81
|
+
assert_equal 'abcwyz', r.extra_options_str # must be sorted
|
63
82
|
end
|
64
83
|
|
65
84
|
def test_boolean
|
@@ -0,0 +1,63 @@
|
|
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
|
+
@coll.clear unless @coll == nil || @db.socket.closed?
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_explain
|
25
|
+
cursor = @coll.find('a' => 1)
|
26
|
+
explaination = cursor.explain
|
27
|
+
assert_not_nil explaination['cursor']
|
28
|
+
assert_kind_of Numeric, explaination['n']
|
29
|
+
assert_kind_of Numeric, explaination['millis']
|
30
|
+
assert_kind_of Numeric, explaination['nscanned']
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_close_no_query_sent
|
34
|
+
begin
|
35
|
+
cursor = @coll.find('a' => 1)
|
36
|
+
cursor.close
|
37
|
+
assert cursor.closed?
|
38
|
+
rescue => ex
|
39
|
+
fail ex.to_s
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_close_after_query_sent
|
44
|
+
begin
|
45
|
+
cursor = @coll.find('a' => 1)
|
46
|
+
cursor.next_object
|
47
|
+
cursor.close
|
48
|
+
assert cursor.closed?
|
49
|
+
rescue => ex
|
50
|
+
fail ex.to_s
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_hint
|
55
|
+
begin
|
56
|
+
cursor = @coll.find('a' => 1).hint('a')
|
57
|
+
assert_equal 1, cursor.to_a.size
|
58
|
+
rescue => ex
|
59
|
+
fail ex.to_s
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
data/tests/test_db_api.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mongo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jim Menard
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-01-
|
12
|
+
date: 2009-01-14 00:00:00 -05:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -25,11 +25,9 @@ files:
|
|
25
25
|
- bin/mongo_console
|
26
26
|
- bin/validate
|
27
27
|
- lib/mongo/admin.rb
|
28
|
-
- lib/mongo/binary.rb
|
29
28
|
- lib/mongo/collection.rb
|
30
29
|
- lib/mongo/cursor.rb
|
31
30
|
- lib/mongo/db.rb
|
32
|
-
- lib/mongo/dbref.rb
|
33
31
|
- lib/mongo/message/get_more_message.rb
|
34
32
|
- lib/mongo/message/insert_message.rb
|
35
33
|
- lib/mongo/message/kill_cursors_message.rb
|
@@ -42,9 +40,12 @@ files:
|
|
42
40
|
- lib/mongo/message/update_message.rb
|
43
41
|
- lib/mongo/message.rb
|
44
42
|
- lib/mongo/mongo.rb
|
45
|
-
- lib/mongo/objectid.rb
|
46
43
|
- lib/mongo/query.rb
|
47
|
-
- lib/mongo/
|
44
|
+
- lib/mongo/types/binary.rb
|
45
|
+
- lib/mongo/types/dbref.rb
|
46
|
+
- lib/mongo/types/objectid.rb
|
47
|
+
- lib/mongo/types/regexp_of_holding.rb
|
48
|
+
- lib/mongo/types/undefined.rb
|
48
49
|
- lib/mongo/util/bson.rb
|
49
50
|
- lib/mongo/util/byte_buffer.rb
|
50
51
|
- lib/mongo/util/ordered_hash.rb
|
@@ -53,6 +54,7 @@ files:
|
|
53
54
|
- tests/test_admin.rb
|
54
55
|
- tests/test_bson.rb
|
55
56
|
- tests/test_byte_buffer.rb
|
57
|
+
- tests/test_cursor.rb
|
56
58
|
- tests/test_db_api.rb
|
57
59
|
- tests/test_db_connection.rb
|
58
60
|
- tests/test_message.rb
|