mongodb-mongo 0.6.3 → 0.6.4

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.
data/Rakefile CHANGED
@@ -4,7 +4,10 @@ require 'fileutils'
4
4
  require 'rake'
5
5
  require 'rake/testtask'
6
6
  require 'rake/gempackagetask'
7
- require 'rake/contrib/rubyforgepublisher'
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
- namespace :gem do
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
@@ -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('foo', 'x') # TODO fix this in the driver!!
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', # special case of string
29
- 'dbref' => DBRef.new(nil, 'dbref', db, coll.name, ObjectID.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.socket)
166
+ MessageHeader.new.read_header(@db)
164
167
  end
165
168
 
166
169
  def read_response_header
167
170
  header_buf = ByteBuffer.new
168
- header_buf.put_array(@db.socket.recv(RESPONSE_HEADER_SIZE).unpack("C*"))
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
- buf.put_array(@db.socket.recv(4).unpack("C*"))
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
- buf.put_array(@db.socket.recv(size-4).unpack("C*"), 4)
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(@db).deserialize(buf)
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(socket)
34
+ def read_header(db)
32
35
  @buf.rewind
33
- @buf.put_array(socket.recv(HEADER_SIZE).unpack("C*"))
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 either order
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 an optional host name string and an
131
- # optional port number integer into a [host, port] pair array.
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
- connection = ['localhost', DEFAULT_PORT]
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 a string, it will be used as a
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 String
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
@@ -20,11 +20,11 @@ module XGen
20
20
 
21
21
  class DBRef
22
22
 
23
- attr_reader :parent, :field_name, :db, :namespace, :object_id
23
+ attr_reader :namespace, :object_id
24
24
 
25
- def initialize(parent, field_name, db, namespace, object_id)
26
- @parent, @field_name, @db, @namespace, @object_id =
27
- parent, field_name, db, namespace, object_id
25
+ def initialize(namespace, object_id)
26
+ @namespace, @object_id =
27
+ namespace, object_id
28
28
  end
29
29
 
30
30
  def to_s
@@ -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(db=nil)
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
- def serialize(obj)
76
- raise "Document is null" unless obj
77
-
78
- @buf.rewind
79
- # put in a placeholder for the total size
80
- @buf.put_int(0)
81
-
82
- # Write key/value pairs. Always write _id first if it exists.
83
- oid = obj['_id'] || obj[:_id]
84
- serialize_key_value('_id', oid) if oid
85
- obj.each {|k, v| serialize_key_value(k, v) unless k == '_id' || k == :_id }
86
-
87
- serialize_eoo_element(@buf)
88
- @buf.put_int(@buf.size, 0)
89
- self
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, k)
98
+ type = bson_type(v)
94
99
  case type
95
- when STRING, CODE, SYMBOL
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
- # TODO CODE_W_SCOPE unimplemented; may be removed
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
- def deserialize(buf=nil, parent=nil)
128
- # If buf is nil, use @buf, assumed to contain already-serialized BSON.
129
- # This is only true during testing.
130
- @buf = ByteBuffer.new(buf.to_a) if buf
131
- @buf.rewind
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
- raise "Unknown type #{type}, key = #{key}"
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, parent)
245
+ def deserialize_object_data(buf)
225
246
  size = buf.get_int
226
247
  buf.position -= 4
227
- BSON.new(@db).deserialize(buf.get(size), parent)
248
+ BSON.new().deserialize(buf.get(size))
228
249
  end
229
250
 
230
- def deserialize_array_data(buf, parent)
231
- h = deserialize_object_data(buf, parent)
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].pack("C*")
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, key, parent)
304
+ def deserialize_dbref_data(buf)
263
305
  ns = deserialize_string_data(buf)
264
306
  oid = deserialize_oid_data(buf)
265
- DBRef.new(parent, key, @db, ns, oid)
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, key)
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
- # magic awful stuff - the DB requires that a where clause is sent as CODE
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[start, len]
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("C*")
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
@@ -35,6 +35,12 @@ class OrderedHash < Hash
35
35
  super(key, value)
36
36
  end
37
37
 
38
+ def ==(other)
39
+ !other.nil? &&
40
+ keys == other.keys &&
41
+ values == other.values
42
+ end
43
+
38
44
  def each
39
45
  @ordered_keys ||= []
40
46
  @ordered_keys.each { |k| yield k, self[k] }
@@ -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', 'code'
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(nil, nil, nil, ns, ObjectID.from_string(oid_str))
104
+ DBRef.new(ns, ObjectID.from_string(oid_str))
103
105
  end
104
106
 
105
107
  end
@@ -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.3'
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(doc, 'dbref', nil, 'namespace', oid)
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 => [123, 'foo'], :left => 'bar'})
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]
@@ -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
@@ -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 DBFef bytes don't contain the db object in any case, and we
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(nil).deserialize(ByteBuffer.new(bson_from_ruby))
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.3
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