mongodb-mongo 0.13 → 0.14

Sign up to get free protection for your applications and to get access to all the features.
@@ -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