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 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