mongodb-mongo 0.13 → 0.14

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.
@@ -314,10 +314,17 @@ module Mongo
314
314
  keys.each do |k|
315
315
  hash[k] = 1
316
316
  end
317
+
318
+ case reduce
319
+ when Code
320
+ else
321
+ reduce = Code.new(reduce)
322
+ end
323
+
317
324
  result = @db.db_command({"group" =>
318
325
  {
319
326
  "ns" => @name,
320
- "$reduce" => Code.new(reduce),
327
+ "$reduce" => reduce,
321
328
  "key" => hash,
322
329
  "cond" => condition,
323
330
  "initial" => initial}})
@@ -327,6 +334,19 @@ module Mongo
327
334
  raise OperationFailure, "group command failed: #{result['errmsg']}"
328
335
  end
329
336
  end
337
+
338
+ case reduce
339
+ when Code
340
+ scope = reduce.scope
341
+ else
342
+ scope = {}
343
+ end
344
+ scope.merge!({
345
+ "ns" => @name,
346
+ "keys" => keys,
347
+ "condition" => condition,
348
+ "initial" => initial })
349
+
330
350
  group_function = <<EOS
331
351
  function () {
332
352
  var c = db[ns].find(condition);
@@ -352,13 +372,7 @@ function () {
352
372
  return {"result": map.values()};
353
373
  }
354
374
  EOS
355
- return @db.eval(Code.new(group_function,
356
- {
357
- "ns" => @name,
358
- "keys" => keys,
359
- "condition" => condition,
360
- "initial" => initial
361
- }))["result"]
375
+ return @db.eval(Code.new(group_function, scope))["result"]
362
376
  end
363
377
 
364
378
  # Rename this collection.
@@ -108,16 +108,6 @@ module Mongo
108
108
  database_info.keys
109
109
  end
110
110
 
111
- # Not implemented.
112
- def clone_database(from)
113
- raise "not implemented"
114
- end
115
-
116
- # Not implemented.
117
- def copy_database(from_host, from_db, to_db)
118
- raise "not implemented"
119
- end
120
-
121
111
  # Drops the database +name+.
122
112
  def drop_database(name)
123
113
  single_db_command(name, :dropDatabase => 1)
data/lib/mongo/cursor.rb CHANGED
@@ -66,7 +66,8 @@ module Mongo
66
66
  # database error.
67
67
  def count
68
68
  command = OrderedHash["count", @collection.name,
69
- "query", @query.selector]
69
+ "query", @query.selector,
70
+ "fields", @query.fields()]
70
71
  response = @db.db_command(command)
71
72
  return response['n'].to_i if response['ok'] == 1
72
73
  return 0 if response['errmsg'] == "ns missing"
data/lib/mongo/db.rb CHANGED
@@ -154,11 +154,11 @@ module Mongo
154
154
  is_master = master?
155
155
  @semaphore.lock if semaphore_is_locked
156
156
 
157
- break if @slave_ok || is_master
157
+ @slave_ok || is_master
158
158
  rescue SocketError, SystemCallError, IOError => ex
159
159
  close if @socket
160
+ false
160
161
  end
161
- @socket
162
162
  }
163
163
  raise "error: failed to connect to any given host:port" unless @socket
164
164
  end
@@ -15,61 +15,26 @@
15
15
  # ++
16
16
 
17
17
  require 'mutex_m'
18
- require 'mongo/util/byte_buffer'
18
+ require 'socket'
19
+ require 'digest/md5'
19
20
 
20
21
  module Mongo
21
22
 
22
- # Implementation of the Babble OID. Object ids are not required by
23
- # Mongo, but they make certain operations more efficient.
24
- #
25
- # The driver does not automatically assign ids to records that are
26
- # inserted. (An upcoming feature will allow you to give an id "factory"
27
- # to a database and/or a collection.)
28
- #
29
- # 12 bytes
30
- # ---
31
- # 0 time
32
- # 1
33
- # 2
34
- # 3
35
- # 4 machine
36
- # 5
37
- # 6
38
- # 7 pid
39
- # 8
40
- # 9 inc
41
- # 10
42
- # 11
23
+ # Representation of an ObjectId for Mongo.
43
24
  class ObjectID
44
-
45
- MACHINE = ( val = rand(0x1000000); [val & 0xff, (val >> 8) & 0xff, (val >> 16) & 0xff] )
46
- PID = ( val = rand(0x10000); [val & 0xff, (val >> 8) & 0xff]; )
47
-
48
- # The string representation of an OID is different than its internal
49
- # and BSON byte representations. The BYTE_ORDER here maps
50
- # internal/BSON byte position (the index in BYTE_ORDER) to the
51
- # position of the two hex characters representing that byte in the
52
- # string representation. For example, the 0th BSON byte corresponds to
53
- # the (0-based) 7th pair of hex chars in the string.
25
+ # This is the legacy byte ordering for Babble. Versions of the Ruby
26
+ # driver prior to 0.14 used this byte ordering when converting ObjectID
27
+ # instances to and from strings. If you have string representations of
28
+ # ObjectIDs using the legacy byte ordering make sure to use the
29
+ # to_s_legacy and from_string_legacy methods, or convert your strings
30
+ # with ObjectID#legacy_string_convert
54
31
  BYTE_ORDER = [7, 6, 5, 4, 3, 2, 1, 0, 11, 10, 9, 8]
55
32
 
56
33
  LOCK = Object.new
57
34
  LOCK.extend Mutex_m
58
35
 
59
- @@index_time = Time.new.to_i
60
36
  @@index = 0
61
37
 
62
- # Given a string representation of an ObjectID, return a new ObjectID
63
- # with that value.
64
- def self.from_string(str)
65
- raise "illegal ObjectID format" unless legal?(str)
66
- data = []
67
- BYTE_ORDER.each_with_index { |string_position, data_index|
68
- data[data_index] = str[string_position * 2, 2].to_i(16)
69
- }
70
- self.new(data)
71
- end
72
-
73
38
  def self.legal?(str)
74
39
  len = BYTE_ORDER.length * 2
75
40
  str =~ /([0-9a-f]+)/i
@@ -78,9 +43,8 @@ module Mongo
78
43
  end
79
44
 
80
45
  # +data+ is an array of bytes. If nil, a new id will be generated.
81
- # The time +t+ is only used for testing; leave it nil.
82
- def initialize(data=nil, t=nil)
83
- @data = data || generate_id(t)
46
+ def initialize(data=nil)
47
+ @data = data || generate
84
48
  end
85
49
 
86
50
  def eql?(other)
@@ -92,7 +56,42 @@ module Mongo
92
56
  @data.dup
93
57
  end
94
58
 
59
+ # Given a string representation of an ObjectID, return a new ObjectID
60
+ # with that value.
61
+ def self.from_string(str)
62
+ raise "illegal ObjectID format" unless legal?(str)
63
+ data = []
64
+ 12.times do |i|
65
+ data[i] = str[i * 2, 2].to_i(16)
66
+ end
67
+ self.new(data)
68
+ end
69
+
70
+ # Create a new ObjectID given a string representation of an ObjectID
71
+ # using the legacy byte ordering. This method may eventually be
72
+ # removed. If you are not sure that you need this method you should be
73
+ # using the regular from_string.
74
+ def self.from_string_legacy(str)
75
+ raise "illegal ObjectID format" unless legal?(str)
76
+ data = []
77
+ BYTE_ORDER.each_with_index { |string_position, data_index|
78
+ data[data_index] = str[string_position * 2, 2].to_i(16)
79
+ }
80
+ self.new(data)
81
+ end
82
+
95
83
  def to_s
84
+ str = ' ' * 24
85
+ 12.times do |i|
86
+ str[i * 2, 2] = '%02x' % @data[i]
87
+ end
88
+ str
89
+ end
90
+
91
+ # Get a string representation of this ObjectID using the legacy byte
92
+ # ordering. This method may eventually be removed. If you are not sure
93
+ # that you need this method you should be using the regular to_s.
94
+ def to_s_legacy
96
95
  str = ' ' * 24
97
96
  BYTE_ORDER.each_with_index { |string_position, data_index|
98
97
  str[string_position * 2, 2] = '%02x' % @data[data_index]
@@ -100,34 +99,43 @@ module Mongo
100
99
  str
101
100
  end
102
101
 
103
- # (Would normally be private, but isn't so we can test it.)
104
- def generate_id(t=nil)
105
- t ||= Time.new.to_i
106
- buf = ByteBuffer.new
107
- buf.put_int(t & 0xffffffff)
108
- buf.put_array(MACHINE)
109
- buf.put_array(PID)
110
- i = index_for_time(t)
111
- buf.put(i & 0xff)
112
- buf.put((i >> 8) & 0xff)
113
- buf.put((i >> 16) & 0xff)
114
-
115
- buf.rewind
116
- buf.to_a.dup
102
+ # Convert a string representation of an ObjectID using the legacy byte
103
+ # ordering to the proper byte ordering. This method may eventually be
104
+ # removed. If you are not sure that you need this method it is probably
105
+ # unnecessary.
106
+ def self.legacy_string_convert(str)
107
+ legacy = ' ' * 24
108
+ BYTE_ORDER.each_with_index do |legacy_pos, pos|
109
+ legacy[legacy_pos * 2, 2] = str[pos * 2, 2]
110
+ end
111
+ legacy
112
+ end
113
+
114
+ private
115
+
116
+ def generate
117
+ oid = ''
118
+
119
+ # 4 bytes current time
120
+ time = Time.new.to_i
121
+ oid += [time].pack("N")
122
+
123
+ # 3 bytes machine
124
+ oid += Digest::MD5.digest(Socket.gethostname)[0, 3]
125
+
126
+ # 2 bytes pid
127
+ oid += [Process.pid % 0xFFFF].pack("n")
128
+
129
+ # 3 bytes inc
130
+ oid += [get_inc].pack("N")[1, 3]
131
+
132
+ oid.unpack("C12")
117
133
  end
118
134
 
119
- # (Would normally be private, but isn't so we can test it.)
120
- def index_for_time(t)
135
+ def get_inc
121
136
  LOCK.mu_synchronize {
122
- if t != @@index_time
123
- @@index = 0
124
- @@index_time = t
125
- end
126
- retval = @@index
127
- @@index += 1
128
- retval
137
+ @@index = (@@index + 1) % 0xFFFFFF
129
138
  }
130
139
  end
131
-
132
140
  end
133
141
  end
@@ -83,7 +83,7 @@ TEST_FILES = ['test/mongo-qa/_common.rb',
83
83
 
84
84
  Gem::Specification.new do |s|
85
85
  s.name = 'mongo'
86
- s.version = '0.13'
86
+ s.version = '0.14'
87
87
  s.platform = Gem::Platform::RUBY
88
88
  s.summary = 'Ruby driver for the 10gen Mongo DB'
89
89
  s.description = 'A Ruby driver for the 10gen Mongo DB. For more information about Mongo, see http://www.mongodb.org.'
@@ -177,5 +177,44 @@ class TestCollection < Test::Unit::TestCase
177
177
  end
178
178
  assert c.closed?
179
179
  end
180
- end
181
180
 
181
+ def test_save_symbol_find_string
182
+ @@test.save(:foo => :mike)
183
+
184
+ assert_equal :mike, @@test.find_one(:foo => :mike)["foo"]
185
+ assert_equal :mike, @@test.find_one("foo" => :mike)["foo"]
186
+ assert_equal nil, @@test.find_one(:foo => "mike")
187
+ assert_equal nil, @@test.find_one("foo" => "mike")
188
+ end
189
+
190
+ def test_group_with_scope
191
+ @@test.save("a" => 1)
192
+ @@test.save("b" => 1)
193
+
194
+ reduce_function = "function (obj, prev) { prev.count += inc_value; }"
195
+
196
+ assert_equal 2, @@test.group([], {}, {"count" => 0},
197
+ Code.new(reduce_function,
198
+ {"inc_value" => 1}))[0]["count"]
199
+
200
+ # TODO enable these tests when SERVER-262 is fixed
201
+
202
+ # assert_equal 2, @@test.group([], {}, {"count" => 0},
203
+ # Code.new(reduce_function,
204
+ # {"inc_value" => 1}), true)[0]["count"]
205
+
206
+ assert_equal 4, @@test.group([], {}, {"count" => 0},
207
+ Code.new(reduce_function,
208
+ {"inc_value" => 2}))[0]["count"]
209
+ # assert_equal 4, @@test.group([], {}, {"count" => 0},
210
+ # Code.new(reduce_function,
211
+ # {"inc_value" => 2}), true)[0]["count"]
212
+
213
+ assert_equal 1, @@test.group([], {}, {"count" => 0},
214
+ Code.new(reduce_function,
215
+ {"inc_value" => 0.5}))[0]["count"]
216
+ # assert_equal 1, @@test.group([], {}, {"count" => 0},
217
+ # Code.new(reduce_function,
218
+ # {"inc_value" => 0.5}), true)[0]["count"]
219
+ end
220
+ end
data/test/test_cursor.rb CHANGED
@@ -220,4 +220,14 @@ class CursorTest < Test::Unit::TestCase
220
220
  assert_equal(by_location,
221
221
  @@db.db_command("cursorInfo" => 1)["byLocation_size"])
222
222
  end
223
+
224
+ def test_count_with_fields
225
+ @@coll.clear
226
+ @@coll.save("x" => 1)
227
+
228
+ @@coll.find({}, :fields => ["a"]).each do |doc|
229
+ fail "shouldn't have any results here"
230
+ end
231
+ assert_equal(0, @@coll.find({}, :fields => ["a"]).count())
232
+ end
223
233
  end
@@ -7,41 +7,19 @@ class ObjectIDTest < Test::Unit::TestCase
7
7
  include Mongo
8
8
 
9
9
  def setup
10
- @t = 42
11
- @o = ObjectID.new(nil, @t)
12
- end
13
-
14
- def test_index_for_time
15
- t = 99
16
- assert_equal 0, @o.index_for_time(t)
17
- assert_equal 1, @o.index_for_time(t)
18
- assert_equal 2, @o.index_for_time(t)
19
- t = 100
20
- assert_equal 0, @o.index_for_time(t)
21
- end
22
-
23
- def test_time_bytes
24
- a = @o.to_a
25
- assert_equal @t, a[0]
26
- 3.times { |i| assert_equal 0, a[i+1] }
27
-
28
- t = 43
29
- o = ObjectID.new(nil, t)
30
- a = o.to_a
31
- assert_equal t, a[0]
32
- 3.times { |i| assert_equal 0, a[i+1] }
33
- assert_equal 1, o.index_for_time(t) # 0 was used for o
10
+ @o = ObjectID.new()
34
11
  end
35
12
 
36
13
  def test_different
37
- o2 = ObjectID.new(nil, @t)
38
- assert @o.to_a != o2.to_a
14
+ a = ObjectID.new
15
+ b = ObjectID.new
16
+ assert_not_equal a.to_a, b.to_a
17
+ assert_not_equal a, b
39
18
  end
40
19
 
41
20
  def test_eql?
42
21
  o2 = ObjectID.new(@o.to_a)
43
- assert @o.eql?(o2)
44
- assert @o == o2
22
+ assert_equal @o, o2
45
23
  end
46
24
 
47
25
  def test_to_s
@@ -51,6 +29,15 @@ class ObjectIDTest < Test::Unit::TestCase
51
29
  assert_equal 24, $1.length
52
30
  end
53
31
 
32
+ def test_to_s_legacy
33
+ s = @o.to_s_legacy
34
+ assert_equal 24, s.length
35
+ s =~ /^([0-9a-f]+)$/
36
+ assert_equal 24, $1.length
37
+
38
+ assert_not_equal s, @o.to_s
39
+ end
40
+
54
41
  def test_save_and_restore
55
42
  host = ENV['MONGO_RUBY_DRIVER_HOST'] || 'localhost'
56
43
  port = ENV['MONGO_RUBY_DRIVER_PORT'] || Connection::DEFAULT_PORT
@@ -73,6 +60,14 @@ class ObjectIDTest < Test::Unit::TestCase
73
60
  assert_equal @o.to_s, o2.to_s
74
61
  end
75
62
 
63
+ def test_from_string_legacy
64
+ hex_str = @o.to_s_legacy
65
+ o2 = ObjectID.from_string_legacy(hex_str)
66
+ assert_equal hex_str, o2.to_s_legacy
67
+ assert_equal @o, o2
68
+ assert_equal @o.to_s, o2.to_s
69
+ end
70
+
76
71
  def test_legal
77
72
  assert !ObjectID.legal?(nil)
78
73
  assert !ObjectID.legal?("fred")
@@ -84,7 +79,7 @@ class ObjectIDTest < Test::Unit::TestCase
84
79
  end
85
80
 
86
81
  def test_from_string_leading_zeroes
87
- hex_str = '000000000000000000abcdef'
82
+ hex_str = '000000000000000000000000'
88
83
  o = ObjectID.from_string(hex_str)
89
84
  assert_equal hex_str, o.to_s
90
85
  end
@@ -92,7 +87,19 @@ class ObjectIDTest < Test::Unit::TestCase
92
87
  def test_byte_order
93
88
  hex_str = '000102030405060708090A0B'
94
89
  o = ObjectID.from_string(hex_str)
90
+ assert_equal [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b], o.to_a
91
+ end
92
+
93
+ def test_legacy_byte_order
94
+ hex_str = '000102030405060708090A0B'
95
+ o = ObjectID.from_string_legacy(hex_str)
95
96
  assert_equal [0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x0b, 0x0a, 0x09, 0x08], o.to_a
96
97
  end
97
98
 
99
+ def test_legacy_string_convert
100
+ l = @o.to_s_legacy
101
+ s = @o.to_s
102
+ assert_equal s, ObjectID.legacy_string_convert(l)
103
+ end
104
+
98
105
  end
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.13"
4
+ version: "0.14"
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jim Menard