mongodb-mongo 0.6.3 → 0.6.4
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +13 -2
- data/bin/standard_benchmark +1 -1
- data/examples/types.rb +2 -2
- data/lib/mongo/cursor.rb +17 -5
- data/lib/mongo/db.rb +11 -1
- data/lib/mongo/message/message_header.rb +8 -2
- data/lib/mongo/mongo.rb +4 -9
- data/lib/mongo/query.rb +5 -2
- data/lib/mongo/types/code.rb +34 -0
- data/lib/mongo/types/dbref.rb +4 -4
- data/lib/mongo/util/bson.rb +152 -92
- data/lib/mongo/util/byte_buffer.rb +15 -3
- data/lib/mongo/util/ordered_hash.rb +6 -0
- data/lib/mongo/util/xml_to_ruby.rb +4 -2
- data/mongo-ruby-driver.gemspec +2 -1
- data/tests/test_admin.rb +7 -0
- data/tests/test_bson.rb +13 -5
- data/tests/test_cursor.rb +52 -0
- data/tests/test_db.rb +1 -1
- data/tests/test_db_api.rb +47 -0
- data/tests/test_mongo.rb +1 -1
- data/tests/test_ordered_hash.rb +27 -0
- data/tests/test_round_trip.rb +2 -2
- metadata +2 -1
data/Rakefile
CHANGED
@@ -4,7 +4,10 @@ require 'fileutils'
|
|
4
4
|
require 'rake'
|
5
5
|
require 'rake/testtask'
|
6
6
|
require 'rake/gempackagetask'
|
7
|
-
|
7
|
+
begin
|
8
|
+
require 'rake/contrib/rubyforgepublisher'
|
9
|
+
rescue LoadError
|
10
|
+
end
|
8
11
|
|
9
12
|
# NOTE: some of the tests assume Mongo is running
|
10
13
|
Rake::TestTask.new do |t|
|
@@ -23,7 +26,15 @@ task :publish => [:rdoc] do
|
|
23
26
|
Rake::RubyForgePublisher.new(GEM, RUBYFORGE_USER).upload
|
24
27
|
end
|
25
28
|
|
26
|
-
|
29
|
+
desc "Compile the extension"
|
30
|
+
task :compile do
|
31
|
+
cd 'ext/cbson'
|
32
|
+
ruby 'extconf.rb'
|
33
|
+
sh 'make'
|
34
|
+
cp 'cbson.bundle', '../../lib/mongo/ext/cbson.bundle'
|
35
|
+
end
|
36
|
+
|
37
|
+
namespace :gem do
|
27
38
|
|
28
39
|
desc "Install the gem locally"
|
29
40
|
task :install do
|
data/bin/standard_benchmark
CHANGED
@@ -64,7 +64,7 @@ benchmark('insert (medium, no index)', insert, PER_TRIAL, db, 'medium_none', MED
|
|
64
64
|
benchmark('insert (large, no index)', insert, PER_TRIAL, db, 'large_none', LARGE)
|
65
65
|
|
66
66
|
index_on_x = Proc.new { |coll, object|
|
67
|
-
coll.create_index('
|
67
|
+
coll.create_index('x')
|
68
68
|
}
|
69
69
|
benchmark('insert (small, indexed)', insert, PER_TRIAL, db, 'small_index', SMALL, index_on_x)
|
70
70
|
benchmark('insert (medium, indexed)', insert, PER_TRIAL, db, 'medium_index', MEDIUM, index_on_x)
|
data/examples/types.rb
CHANGED
@@ -25,8 +25,8 @@ coll.insert('array' => [1, 2, 3],
|
|
25
25
|
'float' => 33.33333,
|
26
26
|
'regex' => /foobar/i,
|
27
27
|
'boolean' => true,
|
28
|
-
'$where' => 'this.x == 3',
|
29
|
-
'dbref' => DBRef.new(
|
28
|
+
'$where' => Code.new('this.x == 3'),
|
29
|
+
'dbref' => DBRef.new(coll.name, ObjectID.new),
|
30
30
|
|
31
31
|
# NOTE: the undefined type is not saved to the database properly. This is a
|
32
32
|
# Mongo bug. However, the undefined type may go away completely.
|
data/lib/mongo/cursor.rb
CHANGED
@@ -18,6 +18,9 @@ require 'mongo/message'
|
|
18
18
|
require 'mongo/util/byte_buffer'
|
19
19
|
require 'mongo/util/bson'
|
20
20
|
|
21
|
+
require 'logger'
|
22
|
+
LOG = Logger.new('recv_file.log', 'daily')
|
23
|
+
|
21
24
|
module XGen
|
22
25
|
module Mongo
|
23
26
|
module Driver
|
@@ -160,12 +163,15 @@ module XGen
|
|
160
163
|
end
|
161
164
|
|
162
165
|
def read_message_header
|
163
|
-
MessageHeader.new.read_header(@db
|
166
|
+
MessageHeader.new.read_header(@db)
|
164
167
|
end
|
165
168
|
|
166
169
|
def read_response_header
|
167
170
|
header_buf = ByteBuffer.new
|
168
|
-
|
171
|
+
read = @db.receive_full(RESPONSE_HEADER_SIZE)
|
172
|
+
header_buf.put_array(read.unpack("C*"))
|
173
|
+
LOG.debug "resp head: #{read.inspect}\n"
|
174
|
+
raise "BAD SIZE" unless read.length == RESPONSE_HEADER_SIZE
|
169
175
|
raise "Short read for DB response header; expected #{RESPONSE_HEADER_SIZE} bytes, saw #{header_buf.length}" unless header_buf.length == RESPONSE_HEADER_SIZE
|
170
176
|
header_buf.rewind
|
171
177
|
@result_flags = header_buf.get_int
|
@@ -200,13 +206,19 @@ module XGen
|
|
200
206
|
|
201
207
|
def object_from_stream
|
202
208
|
buf = ByteBuffer.new
|
203
|
-
|
209
|
+
read1 = @db.receive_full(4)
|
210
|
+
buf.put_array(read1.unpack("C*"))
|
211
|
+
LOG.debug "size: #{read1.inspect}\n"
|
212
|
+
raise "BAD SIZE" unless read1.length == 4
|
204
213
|
buf.rewind
|
205
214
|
size = buf.get_int
|
206
|
-
|
215
|
+
read2 = @db.receive_full(size - 4)
|
216
|
+
buf.put_array(read2.unpack("C*"), 4)
|
217
|
+
LOG.debug "body: #{read2.inspect}\n"
|
218
|
+
raise "BAD SIZE" unless read2.length == size - 4
|
207
219
|
@n_remaining -= 1
|
208
220
|
buf.rewind
|
209
|
-
BSON.new
|
221
|
+
BSON.new.deserialize(buf)
|
210
222
|
end
|
211
223
|
|
212
224
|
def send_query_if_needed
|
data/lib/mongo/db.rb
CHANGED
@@ -143,7 +143,7 @@ module XGen
|
|
143
143
|
@semaphore.lock if semaphore_is_locked
|
144
144
|
|
145
145
|
break if @slave_ok || is_master
|
146
|
-
rescue => ex
|
146
|
+
rescue SocketError, SystemCallError, IOError => ex
|
147
147
|
close if @socket
|
148
148
|
end
|
149
149
|
@socket
|
@@ -301,6 +301,16 @@ module XGen
|
|
301
301
|
@socket != nil
|
302
302
|
end
|
303
303
|
|
304
|
+
def receive_full(length)
|
305
|
+
message = ""
|
306
|
+
while message.length < length do
|
307
|
+
chunk = @socket.recv(length - message.length)
|
308
|
+
raise "connection closed" unless chunk.length > 0
|
309
|
+
message += chunk
|
310
|
+
end
|
311
|
+
message
|
312
|
+
end
|
313
|
+
|
304
314
|
# Send a MsgMessage to the database.
|
305
315
|
def send_message(msg)
|
306
316
|
send_to_db(MsgMessage.new(msg))
|
@@ -16,6 +16,9 @@
|
|
16
16
|
|
17
17
|
require 'mongo/util/byte_buffer'
|
18
18
|
|
19
|
+
require 'logger'
|
20
|
+
LOG = Logger.new('recv_file.log', 'daily')
|
21
|
+
|
19
22
|
module XGen
|
20
23
|
module Mongo
|
21
24
|
module Driver
|
@@ -28,9 +31,12 @@ module XGen
|
|
28
31
|
@buf = ByteBuffer.new
|
29
32
|
end
|
30
33
|
|
31
|
-
def read_header(
|
34
|
+
def read_header(db)
|
32
35
|
@buf.rewind
|
33
|
-
|
36
|
+
read = db.receive_full(HEADER_SIZE)
|
37
|
+
@buf.put_array(read.unpack("C*"))
|
38
|
+
LOG.debug "header: #{read.inspect}\n"
|
39
|
+
raise "BAD SIZE" unless read.length == HEADER_SIZE
|
34
40
|
raise "Short read for DB response header: expected #{HEADER_SIZE} bytes, saw #{@buf.size}" unless @buf.size == HEADER_SIZE
|
35
41
|
@buf.rewind
|
36
42
|
@size = @buf.get_int
|
data/lib/mongo/mongo.rb
CHANGED
@@ -34,7 +34,7 @@ module XGen
|
|
34
34
|
# and :right. Each key maps to either
|
35
35
|
# * a server name, in which case port is DEFAULT_PORT
|
36
36
|
# * a port number, in which case server is "localhost"
|
37
|
-
# * an array containing a server name and a port number in
|
37
|
+
# * an array containing a server name and a port number in that order
|
38
38
|
#
|
39
39
|
# +options+ are passed on to each DB instance:
|
40
40
|
#
|
@@ -127,8 +127,8 @@ module XGen
|
|
127
127
|
|
128
128
|
protected
|
129
129
|
|
130
|
-
# Turns an array containing
|
131
|
-
#
|
130
|
+
# Turns an array containing a host name string and a
|
131
|
+
# port number integer into a [host, port] pair array.
|
132
132
|
def pair_val_to_connection(a)
|
133
133
|
case a
|
134
134
|
when nil
|
@@ -138,12 +138,7 @@ module XGen
|
|
138
138
|
when Integer
|
139
139
|
['localhost', a]
|
140
140
|
when Array
|
141
|
-
|
142
|
-
connection[0] = a[0] if a[0].kind_of?(String)
|
143
|
-
connection[0] = a[1] if a[1].kind_of?(String)
|
144
|
-
connection[1] = a[0] if a[0].kind_of?(Integer)
|
145
|
-
connection[1] = a[1] if a[1].kind_of?(Integer)
|
146
|
-
connection
|
141
|
+
a
|
147
142
|
end
|
148
143
|
end
|
149
144
|
|
data/lib/mongo/query.rb
CHANGED
@@ -16,6 +16,7 @@
|
|
16
16
|
|
17
17
|
require 'mongo/collection'
|
18
18
|
require 'mongo/message'
|
19
|
+
require 'mongo/types/code'
|
19
20
|
|
20
21
|
module XGen
|
21
22
|
module Mongo
|
@@ -70,14 +71,16 @@ module XGen
|
|
70
71
|
self.fields = return_fields
|
71
72
|
end
|
72
73
|
|
73
|
-
# Set query selector hash. If sel is
|
74
|
+
# Set query selector hash. If sel is Code/string, it will be used as a
|
74
75
|
# $where clause. (See Mongo docs for details.)
|
75
76
|
def selector=(sel)
|
76
77
|
@selector = case sel
|
77
78
|
when nil
|
78
79
|
{}
|
79
|
-
when
|
80
|
+
when Code
|
80
81
|
{"$where" => sel}
|
82
|
+
when String
|
83
|
+
{"$where" => Code.new(sel)}
|
81
84
|
when Hash
|
82
85
|
sel
|
83
86
|
end
|
@@ -0,0 +1,34 @@
|
|
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
|
+
|
17
|
+
module XGen
|
18
|
+
module Mongo
|
19
|
+
module Driver
|
20
|
+
|
21
|
+
# JavaScript code to be evaluated by MongoDB
|
22
|
+
class Code < String
|
23
|
+
# Hash mapping identifiers to their values
|
24
|
+
attr_accessor :scope
|
25
|
+
|
26
|
+
def initialize(code, scope={})
|
27
|
+
super(code)
|
28
|
+
@scope = scope
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/mongo/types/dbref.rb
CHANGED
@@ -20,11 +20,11 @@ module XGen
|
|
20
20
|
|
21
21
|
class DBRef
|
22
22
|
|
23
|
-
attr_reader :
|
23
|
+
attr_reader :namespace, :object_id
|
24
24
|
|
25
|
-
def initialize(
|
26
|
-
@
|
27
|
-
|
25
|
+
def initialize(namespace, object_id)
|
26
|
+
@namespace, @object_id =
|
27
|
+
namespace, object_id
|
28
28
|
end
|
29
29
|
|
30
30
|
def to_s
|
data/lib/mongo/util/bson.rb
CHANGED
@@ -62,9 +62,7 @@ class BSON
|
|
62
62
|
buf.put_array(to_utf8(val.to_s).unpack("C*") + [0])
|
63
63
|
end
|
64
64
|
|
65
|
-
def initialize(
|
66
|
-
# db is only needed during deserialization when the data contains a DBRef
|
67
|
-
@db = db
|
65
|
+
def initialize()
|
68
66
|
@buf = ByteBuffer.new
|
69
67
|
end
|
70
68
|
|
@@ -72,27 +70,34 @@ class BSON
|
|
72
70
|
@buf.to_a
|
73
71
|
end
|
74
72
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
73
|
+
begin
|
74
|
+
require 'mongo/ext/cbson'
|
75
|
+
def serialize(obj)
|
76
|
+
@buf = ByteBuffer.new(CBson.serialize(obj))
|
77
|
+
end
|
78
|
+
rescue LoadError
|
79
|
+
def serialize(obj)
|
80
|
+
raise "Document is null" unless obj
|
81
|
+
|
82
|
+
@buf.rewind
|
83
|
+
# put in a placeholder for the total size
|
84
|
+
@buf.put_int(0)
|
85
|
+
|
86
|
+
# Write key/value pairs. Always write _id first if it exists.
|
87
|
+
oid = obj['_id'] || obj[:_id]
|
88
|
+
serialize_key_value('_id', oid) if oid
|
89
|
+
obj.each {|k, v| serialize_key_value(k, v) unless k == '_id' || k == :_id }
|
90
|
+
|
91
|
+
serialize_eoo_element(@buf)
|
92
|
+
@buf.put_int(@buf.size, 0)
|
93
|
+
self
|
94
|
+
end
|
90
95
|
end
|
91
96
|
|
92
97
|
def serialize_key_value(k, v)
|
93
|
-
type = bson_type(v
|
98
|
+
type = bson_type(v)
|
94
99
|
case type
|
95
|
-
when STRING,
|
100
|
+
when STRING, SYMBOL
|
96
101
|
serialize_string_element(@buf, k, v, type)
|
97
102
|
when NUMBER, NUMBER_INT
|
98
103
|
serialize_number_element(@buf, k, v, type)
|
@@ -117,76 +122,92 @@ class BSON
|
|
117
122
|
when UNDEFINED
|
118
123
|
serialize_undefined_element(@buf, k)
|
119
124
|
when CODE_W_SCOPE
|
120
|
-
|
121
|
-
raise "unimplemented type #{type}"
|
125
|
+
serialize_code_w_scope(@buf, k, v)
|
122
126
|
else
|
123
127
|
raise "unhandled type #{type}"
|
124
128
|
end
|
125
129
|
end
|
126
130
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
@buf.get_int # eat message size
|
133
|
-
doc = OrderedHash.new
|
134
|
-
while @buf.more?
|
135
|
-
type = @buf.get
|
136
|
-
case type
|
137
|
-
when STRING, CODE
|
138
|
-
key = deserialize_cstr(@buf)
|
139
|
-
doc[key] = deserialize_string_data(@buf)
|
140
|
-
when SYMBOL
|
141
|
-
key = deserialize_cstr(@buf)
|
142
|
-
doc[key] = deserialize_string_data(@buf).intern
|
143
|
-
when NUMBER
|
144
|
-
key = deserialize_cstr(@buf)
|
145
|
-
doc[key] = deserialize_number_data(@buf)
|
146
|
-
when NUMBER_INT
|
147
|
-
key = deserialize_cstr(@buf)
|
148
|
-
doc[key] = deserialize_number_int_data(@buf)
|
149
|
-
when OID
|
150
|
-
key = deserialize_cstr(@buf)
|
151
|
-
doc[key] = deserialize_oid_data(@buf)
|
152
|
-
when ARRAY
|
153
|
-
key = deserialize_cstr(@buf)
|
154
|
-
doc[key] = deserialize_array_data(@buf, doc)
|
155
|
-
when REGEX
|
156
|
-
key = deserialize_cstr(@buf)
|
157
|
-
doc[key] = deserialize_regex_data(@buf)
|
158
|
-
when OBJECT
|
159
|
-
key = deserialize_cstr(@buf)
|
160
|
-
doc[key] = deserialize_object_data(@buf, doc)
|
161
|
-
when BOOLEAN
|
162
|
-
key = deserialize_cstr(@buf)
|
163
|
-
doc[key] = deserialize_boolean_data(@buf)
|
164
|
-
when DATE
|
165
|
-
key = deserialize_cstr(@buf)
|
166
|
-
doc[key] = deserialize_date_data(@buf)
|
167
|
-
when NULL
|
168
|
-
key = deserialize_cstr(@buf)
|
169
|
-
doc[key] = nil
|
170
|
-
when UNDEFINED
|
171
|
-
key = deserialize_cstr(@buf)
|
172
|
-
doc[key] = Undefined.new
|
173
|
-
when REF
|
174
|
-
key = deserialize_cstr(@buf)
|
175
|
-
doc[key] = deserialize_dbref_data(@buf, key, parent)
|
176
|
-
when BINARY
|
177
|
-
key = deserialize_cstr(@buf)
|
178
|
-
doc[key] = deserialize_binary_data(@buf)
|
179
|
-
when CODE_W_SCOPE
|
180
|
-
# TODO CODE_W_SCOPE unimplemented; may be removed
|
181
|
-
raise "unimplemented type #{type}"
|
182
|
-
when EOO
|
183
|
-
break
|
131
|
+
begin
|
132
|
+
require 'mongo/ext/cbson'
|
133
|
+
def deserialize(buf=nil)
|
134
|
+
if buf.is_a? String
|
135
|
+
@buf = ByteBuffer.new(buf) if buf
|
184
136
|
else
|
185
|
-
|
137
|
+
@buf = ByteBuffer.new(buf.to_a) if buf
|
186
138
|
end
|
139
|
+
@buf.rewind
|
140
|
+
CBson.deserialize(@buf.to_s)
|
141
|
+
end
|
142
|
+
rescue LoadError
|
143
|
+
def deserialize(buf=nil)
|
144
|
+
# If buf is nil, use @buf, assumed to contain already-serialized BSON.
|
145
|
+
# This is only true during testing.
|
146
|
+
if buf.is_a? String
|
147
|
+
@buf = ByteBuffer.new(buf) if buf
|
148
|
+
else
|
149
|
+
@buf = ByteBuffer.new(buf.to_a) if buf
|
150
|
+
end
|
151
|
+
@buf.rewind
|
152
|
+
@buf.get_int # eat message size
|
153
|
+
doc = OrderedHash.new
|
154
|
+
while @buf.more?
|
155
|
+
type = @buf.get
|
156
|
+
case type
|
157
|
+
when STRING, CODE
|
158
|
+
key = deserialize_cstr(@buf)
|
159
|
+
doc[key] = deserialize_string_data(@buf)
|
160
|
+
when SYMBOL
|
161
|
+
key = deserialize_cstr(@buf)
|
162
|
+
doc[key] = deserialize_string_data(@buf).intern
|
163
|
+
when NUMBER
|
164
|
+
key = deserialize_cstr(@buf)
|
165
|
+
doc[key] = deserialize_number_data(@buf)
|
166
|
+
when NUMBER_INT
|
167
|
+
key = deserialize_cstr(@buf)
|
168
|
+
doc[key] = deserialize_number_int_data(@buf)
|
169
|
+
when OID
|
170
|
+
key = deserialize_cstr(@buf)
|
171
|
+
doc[key] = deserialize_oid_data(@buf)
|
172
|
+
when ARRAY
|
173
|
+
key = deserialize_cstr(@buf)
|
174
|
+
doc[key] = deserialize_array_data(@buf)
|
175
|
+
when REGEX
|
176
|
+
key = deserialize_cstr(@buf)
|
177
|
+
doc[key] = deserialize_regex_data(@buf)
|
178
|
+
when OBJECT
|
179
|
+
key = deserialize_cstr(@buf)
|
180
|
+
doc[key] = deserialize_object_data(@buf)
|
181
|
+
when BOOLEAN
|
182
|
+
key = deserialize_cstr(@buf)
|
183
|
+
doc[key] = deserialize_boolean_data(@buf)
|
184
|
+
when DATE
|
185
|
+
key = deserialize_cstr(@buf)
|
186
|
+
doc[key] = deserialize_date_data(@buf)
|
187
|
+
when NULL
|
188
|
+
key = deserialize_cstr(@buf)
|
189
|
+
doc[key] = nil
|
190
|
+
when UNDEFINED
|
191
|
+
key = deserialize_cstr(@buf)
|
192
|
+
doc[key] = Undefined.new
|
193
|
+
when REF
|
194
|
+
key = deserialize_cstr(@buf)
|
195
|
+
doc[key] = deserialize_dbref_data(@buf)
|
196
|
+
when BINARY
|
197
|
+
key = deserialize_cstr(@buf)
|
198
|
+
doc[key] = deserialize_binary_data(@buf)
|
199
|
+
when CODE_W_SCOPE
|
200
|
+
key = deserialize_cstr(@buf)
|
201
|
+
doc[key] = deserialize_code_w_scope_data(@buf)
|
202
|
+
when EOO
|
203
|
+
break
|
204
|
+
else
|
205
|
+
raise "Unknown type #{type}, key = #{key}"
|
206
|
+
end
|
207
|
+
end
|
208
|
+
@buf.rewind
|
209
|
+
doc
|
187
210
|
end
|
188
|
-
@buf.rewind
|
189
|
-
doc
|
190
211
|
end
|
191
212
|
|
192
213
|
# For debugging.
|
@@ -221,14 +242,14 @@ class BSON
|
|
221
242
|
buf.get_int
|
222
243
|
end
|
223
244
|
|
224
|
-
def deserialize_object_data(buf
|
245
|
+
def deserialize_object_data(buf)
|
225
246
|
size = buf.get_int
|
226
247
|
buf.position -= 4
|
227
|
-
BSON.new(
|
248
|
+
BSON.new().deserialize(buf.get(size))
|
228
249
|
end
|
229
250
|
|
230
|
-
def deserialize_array_data(buf
|
231
|
-
h = deserialize_object_data(buf
|
251
|
+
def deserialize_array_data(buf)
|
252
|
+
h = deserialize_object_data(buf)
|
232
253
|
a = []
|
233
254
|
h.each { |k, v| a[k.to_i] = v }
|
234
255
|
a
|
@@ -248,21 +269,42 @@ class BSON
|
|
248
269
|
def deserialize_string_data(buf)
|
249
270
|
len = buf.get_int
|
250
271
|
bytes = buf.get(len)
|
251
|
-
str = bytes[0..-2]
|
272
|
+
str = bytes[0..-2]
|
273
|
+
if str.respond_to? "pack"
|
274
|
+
str = str.pack("C*")
|
275
|
+
end
|
252
276
|
if RUBY_VERSION >= '1.9'
|
253
277
|
str.force_encoding("utf-8")
|
254
278
|
end
|
255
279
|
str
|
256
280
|
end
|
257
281
|
|
282
|
+
def deserialize_code_w_scope_data(buf)
|
283
|
+
buf.get_int
|
284
|
+
len = buf.get_int
|
285
|
+
code = buf.get(len)[0..-2]
|
286
|
+
if code.respond_to? "pack"
|
287
|
+
code = code.pack("C*")
|
288
|
+
end
|
289
|
+
if RUBY_VERSION >= '1.9'
|
290
|
+
code.force_encoding("utf-8")
|
291
|
+
end
|
292
|
+
|
293
|
+
scope_size = buf.get_int
|
294
|
+
buf.position -= 4
|
295
|
+
scope = BSON.new().deserialize(buf.get(scope_size))
|
296
|
+
|
297
|
+
Code.new(code, scope)
|
298
|
+
end
|
299
|
+
|
258
300
|
def deserialize_oid_data(buf)
|
259
301
|
ObjectID.new(buf.get(12))
|
260
302
|
end
|
261
303
|
|
262
|
-
def deserialize_dbref_data(buf
|
304
|
+
def deserialize_dbref_data(buf)
|
263
305
|
ns = deserialize_string_data(buf)
|
264
306
|
oid = deserialize_oid_data(buf)
|
265
|
-
DBRef.new(
|
307
|
+
DBRef.new(ns, oid)
|
266
308
|
end
|
267
309
|
|
268
310
|
def deserialize_binary_data(buf)
|
@@ -391,6 +433,23 @@ class BSON
|
|
391
433
|
buf.position = end_pos
|
392
434
|
end
|
393
435
|
|
436
|
+
def serialize_code_w_scope(buf, key, val)
|
437
|
+
buf.put(CODE_W_SCOPE)
|
438
|
+
self.class.serialize_cstr(buf, key)
|
439
|
+
|
440
|
+
# Make a hole for the length
|
441
|
+
len_pos = buf.position
|
442
|
+
buf.put_int(0)
|
443
|
+
|
444
|
+
buf.put_int(val.length + 1)
|
445
|
+
self.class.serialize_cstr(buf, val)
|
446
|
+
buf.put_array(BSON.new.serialize(val.scope).to_a)
|
447
|
+
|
448
|
+
end_pos = buf.position
|
449
|
+
buf.put_int(end_pos - len_pos, len_pos)
|
450
|
+
buf.position = end_pos
|
451
|
+
end
|
452
|
+
|
394
453
|
def deserialize_cstr(buf)
|
395
454
|
chars = ""
|
396
455
|
while true
|
@@ -404,7 +463,7 @@ class BSON
|
|
404
463
|
chars
|
405
464
|
end
|
406
465
|
|
407
|
-
def bson_type(o
|
466
|
+
def bson_type(o)
|
408
467
|
case o
|
409
468
|
when nil
|
410
469
|
NULL
|
@@ -414,9 +473,10 @@ class BSON
|
|
414
473
|
NUMBER
|
415
474
|
when ByteBuffer
|
416
475
|
BINARY
|
476
|
+
when Code
|
477
|
+
CODE_W_SCOPE
|
417
478
|
when String
|
418
|
-
|
419
|
-
key == "$where" ? CODE : STRING
|
479
|
+
STRING
|
420
480
|
when Array
|
421
481
|
ARRAY
|
422
482
|
when Regexp
|
@@ -100,7 +100,11 @@ class ByteBuffer
|
|
100
100
|
if one_byte
|
101
101
|
@buf[start]
|
102
102
|
else
|
103
|
-
@buf
|
103
|
+
if @buf.respond_to? "unpack"
|
104
|
+
@buf[start, len].unpack("C*")
|
105
|
+
else
|
106
|
+
@buf[start, len]
|
107
|
+
end
|
104
108
|
end
|
105
109
|
end
|
106
110
|
|
@@ -135,11 +139,19 @@ class ByteBuffer
|
|
135
139
|
end
|
136
140
|
|
137
141
|
def to_a
|
138
|
-
@buf
|
142
|
+
if @buf.respond_to? "unpack"
|
143
|
+
@buf.unpack("C*")
|
144
|
+
else
|
145
|
+
@buf
|
146
|
+
end
|
139
147
|
end
|
140
148
|
|
141
149
|
def to_s
|
142
|
-
@buf.pack
|
150
|
+
if @buf.respond_to? "pack"
|
151
|
+
@buf.pack("C*")
|
152
|
+
else
|
153
|
+
@buf
|
154
|
+
end
|
143
155
|
end
|
144
156
|
|
145
157
|
def dump
|
@@ -42,8 +42,10 @@ class XMLToRuby
|
|
42
42
|
e.text.to_i
|
43
43
|
when 'number'
|
44
44
|
e.text.to_f
|
45
|
-
when 'string'
|
45
|
+
when 'string'
|
46
46
|
e.text.to_s
|
47
|
+
when 'code'
|
48
|
+
Code.new(e.text.to_s)
|
47
49
|
when 'binary'
|
48
50
|
bin = Binary.new
|
49
51
|
decoded = Base64.decode64(e.text.to_s)
|
@@ -99,7 +101,7 @@ class XMLToRuby
|
|
99
101
|
def dbref_to_ruby(elements)
|
100
102
|
ns = elements['ns'].text
|
101
103
|
oid_str = elements['oid'].text
|
102
|
-
DBRef.new(
|
104
|
+
DBRef.new(ns, ObjectID.from_string(oid_str))
|
103
105
|
end
|
104
106
|
|
105
107
|
end
|
data/mongo-ruby-driver.gemspec
CHANGED
@@ -35,6 +35,7 @@ PACKAGE_FILES = ['README.rdoc', 'Rakefile', 'mongo-ruby-driver.gemspec',
|
|
35
35
|
'lib/mongo/mongo.rb',
|
36
36
|
'lib/mongo/query.rb',
|
37
37
|
'lib/mongo/types/binary.rb',
|
38
|
+
'lib/mongo/types/code.rb',
|
38
39
|
'lib/mongo/types/dbref.rb',
|
39
40
|
'lib/mongo/types/objectid.rb',
|
40
41
|
'lib/mongo/types/regexp_of_holding.rb',
|
@@ -74,7 +75,7 @@ TEST_FILES = ['tests/mongo-qa/_common.rb',
|
|
74
75
|
|
75
76
|
Gem::Specification.new do |s|
|
76
77
|
s.name = 'mongo'
|
77
|
-
s.version = '0.6.
|
78
|
+
s.version = '0.6.4'
|
78
79
|
s.platform = Gem::Platform::RUBY
|
79
80
|
s.summary = 'Simple pure-Ruby driver for the 10gen Mongo DB'
|
80
81
|
s.description = 'A pure-Ruby driver for the 10gen Mongo DB. For more information about Mongo, see http://www.mongodb.org.'
|
data/tests/test_admin.rb
CHANGED
@@ -33,6 +33,13 @@ class AdminTest < Test::Unit::TestCase
|
|
33
33
|
assert_equal :slow_only, @admin.profiling_level
|
34
34
|
@admin.profiling_level = :off
|
35
35
|
assert_equal :off, @admin.profiling_level
|
36
|
+
@admin.profiling_level = :all
|
37
|
+
assert_equal :all, @admin.profiling_level
|
38
|
+
begin
|
39
|
+
@admin.profiling_level = :medium
|
40
|
+
fail "shouldn't be able to do this"
|
41
|
+
rescue
|
42
|
+
end
|
36
43
|
end
|
37
44
|
|
38
45
|
def test_profiling_info
|
data/tests/test_bson.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
$LOAD_PATH[0,0] = File.join(File.dirname(__FILE__), '..', 'lib')
|
2
2
|
require 'mongo'
|
3
|
+
require 'mongo/util/ordered_hash'
|
3
4
|
require 'test/unit'
|
4
5
|
|
5
6
|
class BSONTest < Test::Unit::TestCase
|
@@ -16,14 +17,11 @@ class BSONTest < Test::Unit::TestCase
|
|
16
17
|
def test_string
|
17
18
|
doc = {'doc' => 'hello, world'}
|
18
19
|
@b.serialize(doc)
|
19
|
-
assert_equal @b.to_a, [0x1b, 0x00, 0x00, 0x00, 0x02, ?d, ?o, ?c, 0x00, 0x0D,
|
20
|
-
0x00, 0x00, 0x00, ?h, ?e, ?l, ?l, ?o, ","[0], " "[0],
|
21
|
-
?w, ?o, ?r, ?l, ?d, 0x00, 0x00]
|
22
20
|
assert_equal doc, @b.deserialize
|
23
21
|
end
|
24
22
|
|
25
23
|
def test_code
|
26
|
-
doc = {'$where' => 'this.a.b < this.b'}
|
24
|
+
doc = {'$where' => Code.new('this.a.b < this.b')}
|
27
25
|
@b.serialize(doc)
|
28
26
|
assert_equal doc, @b.deserialize
|
29
27
|
end
|
@@ -40,6 +38,16 @@ class BSONTest < Test::Unit::TestCase
|
|
40
38
|
assert_equal doc, @b.deserialize
|
41
39
|
end
|
42
40
|
|
41
|
+
def test_ordered_hash
|
42
|
+
doc = OrderedHash.new
|
43
|
+
doc["b"] = 1
|
44
|
+
doc["a"] = 2
|
45
|
+
doc["c"] = 3
|
46
|
+
doc["d"] = 4
|
47
|
+
@b.serialize(doc)
|
48
|
+
assert_equal doc, @b.deserialize
|
49
|
+
end
|
50
|
+
|
43
51
|
def test_object
|
44
52
|
doc = {'doc' => {'age' => 42, 'name' => 'Spongebob', 'shoe_size' => 9.5}}
|
45
53
|
@b.serialize(doc)
|
@@ -100,7 +108,7 @@ class BSONTest < Test::Unit::TestCase
|
|
100
108
|
def test_dbref
|
101
109
|
oid = ObjectID.new
|
102
110
|
doc = {}
|
103
|
-
doc['dbref'] = DBRef.new(
|
111
|
+
doc['dbref'] = DBRef.new('namespace', oid)
|
104
112
|
@b.serialize(doc)
|
105
113
|
doc2 = @b.deserialize
|
106
114
|
assert_equal 'namespace', doc2['dbref'].namespace
|
data/tests/test_cursor.rb
CHANGED
@@ -40,6 +40,58 @@ class CursorTest < Test::Unit::TestCase
|
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
+
def test_refill_via_get_more
|
44
|
+
1000.times { |i|
|
45
|
+
@@coll.insert('a' => i)
|
46
|
+
}
|
47
|
+
|
48
|
+
assert_equal 1001, @@coll.count
|
49
|
+
count = 0
|
50
|
+
@@coll.find.each { |obj|
|
51
|
+
count += obj['a']
|
52
|
+
}
|
53
|
+
assert_equal 1001, @@coll.count
|
54
|
+
|
55
|
+
# do the same thing again for debugging
|
56
|
+
assert_equal 1001, @@coll.count
|
57
|
+
count2 = 0
|
58
|
+
@@coll.find.each { |obj|
|
59
|
+
count2 += obj['a']
|
60
|
+
}
|
61
|
+
assert_equal 1001, @@coll.count
|
62
|
+
|
63
|
+
assert_equal count, count2
|
64
|
+
assert_equal 499501, count
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_refill_via_get_more_alt_coll
|
68
|
+
coll = @@db.collection('test-alt-coll')
|
69
|
+
coll.clear
|
70
|
+
coll.insert('a' => 1) # collection not created until it's used
|
71
|
+
|
72
|
+
1000.times { |i|
|
73
|
+
coll.insert('a' => i)
|
74
|
+
}
|
75
|
+
|
76
|
+
assert_equal 1001, coll.count
|
77
|
+
count = 0
|
78
|
+
coll.find.each { |obj|
|
79
|
+
count += obj['a']
|
80
|
+
}
|
81
|
+
assert_equal 1001, coll.count
|
82
|
+
|
83
|
+
# do the same thing again for debugging
|
84
|
+
assert_equal 1001, coll.count
|
85
|
+
count2 = 0
|
86
|
+
coll.find.each { |obj|
|
87
|
+
count2 += obj['a']
|
88
|
+
}
|
89
|
+
assert_equal 1001, coll.count
|
90
|
+
|
91
|
+
assert_equal count, count2
|
92
|
+
assert_equal 499501, count
|
93
|
+
end
|
94
|
+
|
43
95
|
def test_close_after_query_sent
|
44
96
|
begin
|
45
97
|
cursor = @@coll.find('a' => 1)
|
data/tests/test_db.rb
CHANGED
@@ -56,7 +56,7 @@ class DBTest < Test::Unit::TestCase
|
|
56
56
|
@@db = Mongo.new({:left => "this-should-fail", :right => [@@host, @@port]}).db('ruby-mongo-test')
|
57
57
|
assert @@db.connected?
|
58
58
|
ensure
|
59
|
-
@@db = Mongo.new(@@host, @@port) unless @@db.connected?
|
59
|
+
@@db = Mongo.new(@@host, @@port).db('ruby-mongo-test') unless @@db.connected?
|
60
60
|
@@users = @@db.collection('system.users')
|
61
61
|
end
|
62
62
|
|
data/tests/test_db_api.rb
CHANGED
@@ -233,6 +233,12 @@ class DBAPITest < Test::Unit::TestCase
|
|
233
233
|
assert !@@db.collection_names.include?(@@coll_full_name)
|
234
234
|
end
|
235
235
|
|
236
|
+
def test_other_drop
|
237
|
+
assert @@db.collection_names.include?(@@coll_full_name)
|
238
|
+
@@coll.drop
|
239
|
+
assert !@@db.collection_names.include?(@@coll_full_name)
|
240
|
+
end
|
241
|
+
|
236
242
|
def test_collection_names
|
237
243
|
names = @@db.collection_names
|
238
244
|
assert names.length >= 1
|
@@ -277,6 +283,7 @@ class DBAPITest < Test::Unit::TestCase
|
|
277
283
|
def test_index_information
|
278
284
|
name = @@db.create_index(@@coll.name, 'a')
|
279
285
|
list = @@db.index_information(@@coll.name)
|
286
|
+
assert_equal @@coll.index_information, list
|
280
287
|
assert_equal 1, list.length
|
281
288
|
|
282
289
|
info = list[0]
|
@@ -368,6 +375,37 @@ class DBAPITest < Test::Unit::TestCase
|
|
368
375
|
@@db.strict = false
|
369
376
|
@@db.drop_collection('foobar')
|
370
377
|
end
|
378
|
+
|
379
|
+
# Now we're not in strict mode - should succeed
|
380
|
+
@@db.create_collection('foobar')
|
381
|
+
@@db.create_collection('foobar')
|
382
|
+
@@db.drop_collection('foobar')
|
383
|
+
end
|
384
|
+
|
385
|
+
def test_replace
|
386
|
+
assert_equal @@coll.count, 1
|
387
|
+
assert_equal @@coll.find_first["a"], 1
|
388
|
+
|
389
|
+
@@coll.replace({"a" => 1}, {"a" => 2})
|
390
|
+
assert_equal @@coll.count, 1
|
391
|
+
assert_equal @@coll.find_first["a"], 2
|
392
|
+
|
393
|
+
@@coll.replace({"b" => 1}, {"a" => 3})
|
394
|
+
assert_equal @@coll.count, 1
|
395
|
+
assert_equal @@coll.find_first["a"], 2
|
396
|
+
end
|
397
|
+
|
398
|
+
def test_repsert
|
399
|
+
assert_equal @@coll.count, 1
|
400
|
+
assert_equal @@coll.find_first["a"], 1
|
401
|
+
|
402
|
+
@@coll.repsert({"a" => 1}, {"a" => 2})
|
403
|
+
assert_equal @@coll.count, 1
|
404
|
+
assert_equal @@coll.find_first["a"], 2
|
405
|
+
|
406
|
+
@@coll.repsert({"b" => 1}, {"a" => 3})
|
407
|
+
assert_equal @@coll.count, 2
|
408
|
+
assert @@coll.find_first({"a" => 3})
|
371
409
|
end
|
372
410
|
|
373
411
|
def test_to_a
|
@@ -404,6 +442,15 @@ class DBAPITest < Test::Unit::TestCase
|
|
404
442
|
assert_equal "#{@@db.host}:#{@@db.port}", @@db.master
|
405
443
|
end
|
406
444
|
|
445
|
+
def test_where
|
446
|
+
@@coll.insert('a' => 2)
|
447
|
+
@@coll.insert('a' => 3)
|
448
|
+
|
449
|
+
assert_equal 3, @@coll.count
|
450
|
+
assert_equal 1, @@coll.find('$where' => Code.new('this.a > 2')).count
|
451
|
+
assert_equal 2, @@coll.find('$where' => Code.new('this.a > i', {'i' => 1})).count
|
452
|
+
end
|
453
|
+
|
407
454
|
def test_hint
|
408
455
|
name = @@coll.create_index('a')
|
409
456
|
begin
|
data/tests/test_mongo.rb
CHANGED
@@ -64,7 +64,7 @@ class MongoTest < Test::Unit::TestCase
|
|
64
64
|
assert_equal ['localhost', Mongo::DEFAULT_PORT], pair[0]
|
65
65
|
assert_equal ['bar', Mongo::DEFAULT_PORT], pair[1]
|
66
66
|
|
67
|
-
db = Mongo.new({:right => [
|
67
|
+
db = Mongo.new({:right => ['foo', 123], :left => 'bar'})
|
68
68
|
pair = db.instance_variable_get('@pair')
|
69
69
|
assert_equal 2, pair.length
|
70
70
|
assert_equal ['bar', Mongo::DEFAULT_PORT], pair[0]
|
data/tests/test_ordered_hash.rb
CHANGED
@@ -16,6 +16,33 @@ class OrderedHashTest < Test::Unit::TestCase
|
|
16
16
|
assert_equal [], OrderedHash.new.keys
|
17
17
|
end
|
18
18
|
|
19
|
+
def test_equality
|
20
|
+
a = OrderedHash.new
|
21
|
+
a['x'] = 1
|
22
|
+
a['y'] = 2
|
23
|
+
|
24
|
+
b = OrderedHash.new
|
25
|
+
b['y'] = 2
|
26
|
+
b['x'] = 1
|
27
|
+
|
28
|
+
c = OrderedHash.new
|
29
|
+
c['x'] = 1
|
30
|
+
c['y'] = 2
|
31
|
+
|
32
|
+
d = OrderedHash.new
|
33
|
+
d['x'] = 2
|
34
|
+
d['y'] = 3
|
35
|
+
|
36
|
+
e = OrderedHash.new
|
37
|
+
e['z'] = 1
|
38
|
+
e['y'] = 2
|
39
|
+
|
40
|
+
assert_equal a, c
|
41
|
+
assert_not_equal a, b
|
42
|
+
assert_not_equal a, d
|
43
|
+
assert_not_equal a, e
|
44
|
+
end
|
45
|
+
|
19
46
|
def test_order_preserved
|
20
47
|
assert_equal @ordered_keys, @oh.keys
|
21
48
|
end
|
data/tests/test_round_trip.rb
CHANGED
@@ -93,9 +93,9 @@ EOS
|
|
93
93
|
# Turn those BSON bytes back into a Ruby object.
|
94
94
|
#
|
95
95
|
# We're passing a nil db to the contructor here, but that's OK because
|
96
|
-
# the BSON
|
96
|
+
# the BSON DBRef bytes don't contain the db object in any case, and we
|
97
97
|
# don't care what the database is.
|
98
|
-
obj_from_bson = BSON.new
|
98
|
+
obj_from_bson = BSON.new.deserialize(ByteBuffer.new(bson_from_ruby))
|
99
99
|
assert_kind_of OrderedHash, obj_from_bson
|
100
100
|
|
101
101
|
# Turn that Ruby object into BSON and compare it to the original BSON
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mongodb-mongo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jim Menard
|
@@ -61,6 +61,7 @@ files:
|
|
61
61
|
- lib/mongo/mongo.rb
|
62
62
|
- lib/mongo/query.rb
|
63
63
|
- lib/mongo/types/binary.rb
|
64
|
+
- lib/mongo/types/code.rb
|
64
65
|
- lib/mongo/types/dbref.rb
|
65
66
|
- lib/mongo/types/objectid.rb
|
66
67
|
- lib/mongo/types/regexp_of_holding.rb
|