mongo 1.1.2 → 1.1.3

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.
@@ -23,7 +23,7 @@ module Mongo
23
23
 
24
24
  attr_reader :collection, :selector, :fields,
25
25
  :order, :hint, :snapshot, :timeout,
26
- :full_collection_name, :batch_size
26
+ :full_collection_name
27
27
 
28
28
  # Create a new cursor.
29
29
  #
@@ -50,20 +50,26 @@ module Mongo
50
50
  @explain = options[:explain]
51
51
  @socket = options[:socket]
52
52
  @tailable = options[:tailable] || false
53
+ @closed = false
54
+ @query_run = false
53
55
  batch_size(options[:batch_size] || 0)
54
56
 
55
57
  @full_collection_name = "#{@collection.db.name}.#{@collection.name}"
56
58
  @cache = []
57
- @closed = false
58
- @query_run = false
59
59
  @returned = 0
60
+
61
+ if @collection.name =~ /^\$cmd/ || @collection.name =~ /^system/
62
+ @command = true
63
+ else
64
+ @command = false
65
+ end
60
66
  end
61
67
 
62
68
  # Get the next document specified the cursor options.
63
69
  #
64
70
  # @return [Hash, Nil] the next document or Nil if no documents remain.
65
71
  def next_document
66
- refresh if @cache.length == 0#empty?# num_remaining == 0
72
+ refresh if @cache.length == 0
67
73
  doc = @cache.shift
68
74
 
69
75
  if doc && doc['$err']
@@ -104,14 +110,21 @@ module Mongo
104
110
 
105
111
  # Get the size of the result set for this query.
106
112
  #
107
- # @return [Integer] the number of objects in the result set for this query. Does
108
- # not take limit and skip into account.
113
+ # @param [Boolean] whether of not to take notice of skip and limit
114
+ #
115
+ # @return [Integer] the number of objects in the result set for this query.
109
116
  #
110
117
  # @raise [OperationFailure] on a database error.
111
- def count
112
- command = BSON::OrderedHash["count", @collection.name,
113
- "query", @selector,
114
- "fields", @fields]
118
+ def count(skip_and_limit = false)
119
+ command = BSON::OrderedHash["count", @collection.name, "query", @selector]
120
+
121
+ if skip_and_limit
122
+ command.merge!(BSON::OrderedHash["limit", @limit]) if @limit != 0
123
+ command.merge!(BSON::OrderedHash["skip", @skip]) if @skip != 0
124
+ end
125
+
126
+ command.merge!(BSON::OrderedHash["fields", @fields])
127
+
115
128
  response = @db.command(command)
116
129
  return response['n'].to_i if Mongo::Support.ok?(response)
117
130
  return 0 if response['errmsg'] == "ns missing"
@@ -156,7 +169,6 @@ module Mongo
156
169
  def limit(number_to_return=nil)
157
170
  return @limit unless number_to_return
158
171
  check_modifiable
159
- raise ArgumentError, "limit requires an integer" unless number_to_return.is_a? Integer
160
172
 
161
173
  @limit = number_to_return
162
174
  self
@@ -174,7 +186,6 @@ module Mongo
174
186
  def skip(number_to_skip=nil)
175
187
  return @skip unless number_to_skip
176
188
  check_modifiable
177
- raise ArgumentError, "skip requires an integer" unless number_to_skip.is_a? Integer
178
189
 
179
190
  @skip = number_to_skip
180
191
  self
@@ -354,8 +365,8 @@ module Mongo
354
365
  # Cursor id.
355
366
  message.put_long(@cursor_id)
356
367
  @logger.debug("MONGODB cursor.refresh() for cursor #{@cursor_id}") if @logger
357
- results, @n_received, @cursor_id = @connection.receive_message(Mongo::Constants::OP_GET_MORE,
358
- message, nil, @socket)
368
+ results, @n_received, @cursor_id = @connection.receive_message(
369
+ Mongo::Constants::OP_GET_MORE, message, nil, @socket, @command)
359
370
  @returned += @n_received
360
371
  @cache += results
361
372
  close_cursor_if_query_complete
@@ -368,7 +379,8 @@ module Mongo
368
379
  else
369
380
  message = construct_query_message
370
381
  @logger.debug query_log_message if @logger
371
- results, @n_received, @cursor_id = @connection.receive_message(Mongo::Constants::OP_QUERY, message, nil, @socket)
382
+ results, @n_received, @cursor_id = @connection.receive_message(
383
+ Mongo::Constants::OP_QUERY, message, nil, @socket, @command)
372
384
  @returned += @n_received
373
385
  @cache += results
374
386
  @query_run = true
@@ -51,6 +51,9 @@ module Mongo
51
51
  # The Mongo::Connection instance connecting to the MongoDB server.
52
52
  attr_reader :connection
53
53
 
54
+ # The length of time that Collection.ensure_index should cache index calls
55
+ attr_accessor :cache_time
56
+
54
57
  # Instances of DB are normally obtained by calling Mongo#db.
55
58
  #
56
59
  # @param [String] db_name the database name.
@@ -70,6 +73,7 @@ module Mongo
70
73
  # value is provided, the default value set on this instance's Connection object will be used. This
71
74
  # default can be overridden upon instantiation of any collection by explicity setting a :safe value
72
75
  # on initialization
76
+ # @option options [Integer] :cache_time (300) Set the time that all ensure_index calls should cache the command.
73
77
  #
74
78
  # @core databases constructor_details
75
79
  def initialize(db_name, connection, options={})
@@ -78,6 +82,7 @@ module Mongo
78
82
  @strict = options[:strict]
79
83
  @pk_factory = options[:pk]
80
84
  @safe = options.has_key?(:safe) ? options[:safe] : @connection.safe
85
+ @cache_time = options[:cache_time] || 300 #5 minutes.
81
86
  end
82
87
 
83
88
  # Authenticate with the given username and password. Note that mongod
@@ -65,7 +65,7 @@ module Mongo
65
65
  #
66
66
  # @return [Mongo::ObjectId] the file's id.
67
67
  def put(data, opts={})
68
- filename = opts[:filename]
68
+ filename = opts.delete :filename
69
69
  opts.merge!(default_grid_io_opts)
70
70
  file = GridIO.new(@files, @chunks, filename, 'w', opts=opts)
71
71
  file.write(data)
@@ -18,11 +18,17 @@
18
18
  module Mongo
19
19
  class Pool
20
20
 
21
- def initialize(host, port, socket, options={})
21
+ attr_accessor :host, :port, :size, :timeout, :safe, :checked_out
22
+
23
+ # Create a new pool of connections.
24
+ #
25
+ def initialize(connection, host, port, options={})
26
+ @connection = connection
27
+
22
28
  @host, @port = host, port
23
29
 
24
30
  # Pool size and timeout.
25
- @size = options[:pool_size] || 1
31
+ @size = options[:size] || 1
26
32
  @timeout = options[:timeout] || 5.0
27
33
 
28
34
  # Mutex for synchronizing pool access
@@ -43,6 +49,12 @@ module Mongo
43
49
  end
44
50
 
45
51
  def close
52
+ @sockets.each do |sock|
53
+ sock.close
54
+ end
55
+ @host = @port = nil
56
+ @sockets.clear
57
+ @checked_out.clear
46
58
  end
47
59
 
48
60
  # Return a socket to the pool.
@@ -84,7 +96,7 @@ module Mongo
84
96
  # pool size has not been exceeded. Otherwise, wait for the next
85
97
  # available socket.
86
98
  def checkout
87
- connect if !connected?
99
+ @connection.connect if !@connection.connected?
88
100
  start_time = Time.now
89
101
  loop do
90
102
  if (Time.now - start_time) > @timeout
@@ -127,4 +127,9 @@ class ObjectIdTest < Test::Unit::TestCase
127
127
  id = ObjectId.new
128
128
  assert_equal "{\"$oid\": \"#{id}\"}", id.to_json
129
129
  end
130
+
131
+ def test_as_json
132
+ id = ObjectId.new
133
+ assert_equal({"$oid" => id.to_s}, id.as_json)
134
+ end
130
135
  end
@@ -67,6 +67,17 @@ class TestCollection < Test::Unit::TestCase
67
67
  assert_equal 5, @@db.collection("test.foo").find_one()["x"]
68
68
  end
69
69
 
70
+ def test_rename_collection
71
+ @@db.drop_collection('foo1')
72
+ @@db.drop_collection('bar1')
73
+
74
+ @col = @@db.create_collection('foo1')
75
+ assert_equal 'foo1', @col.name
76
+
77
+ @col.rename('bar1')
78
+ assert_equal 'bar1', @col.name
79
+ end
80
+
70
81
  def test_nil_id
71
82
  assert_equal 5, @@test.insert({"_id" => 5, "foo" => "bar"}, {:safe => true})
72
83
  assert_equal 5, @@test.save({"_id" => 5, "foo" => "baz"}, {:safe => true})
@@ -555,8 +566,40 @@ class TestCollection < Test::Unit::TestCase
555
566
  assert_equal 1, x
556
567
  end
557
568
 
569
+
570
+ def test_ensure_index
571
+ @@test.drop_indexes
572
+ @@test.insert("x" => "hello world")
573
+ assert_equal 1, @@test.index_information.keys.count #default index
574
+
575
+ @@test.ensure_index([["x", Mongo::DESCENDING]], {})
576
+ assert_equal 2, @@test.index_information.keys.count
577
+ assert @@test.index_information.keys.include? "x_-1"
578
+
579
+ @@test.ensure_index([["x", Mongo::ASCENDING]])
580
+ assert @@test.index_information.keys.include? "x_1"
581
+
582
+ @@test.drop_index("x_1")
583
+ assert_equal 2, @@test.index_information.keys.count
584
+ @@test.drop_index("x_-1")
585
+ assert_equal 1, @@test.index_information.keys.count
586
+
587
+ @@test.ensure_index([["x", Mongo::DESCENDING]], {}) #should work as not cached.
588
+ assert_equal 2, @@test.index_information.keys.count
589
+ assert @@test.index_information.keys.include? "x_-1"
590
+
591
+ # Make sure that drop_index expires cache properly
592
+ @@test.ensure_index([['a', 1]])
593
+ assert @@test.index_information.keys.include?("a_1")
594
+ @@test.drop_index("a_1")
595
+ assert !@@test.index_information.keys.include?("a_1")
596
+ @@test.ensure_index([['a', 1]])
597
+ assert @@test.index_information.keys.include?("a_1")
598
+ @@test.drop_index("a_1")
599
+ end
600
+
558
601
  context "Grouping" do
559
- setup do
602
+ setup do
560
603
  @@test.remove
561
604
  @@test.save("a" => 1)
562
605
  @@test.save("b" => 1)
@@ -576,6 +619,23 @@ class TestCollection < Test::Unit::TestCase
576
619
  end
577
620
  end
578
621
 
622
+ context "Grouping with key" do
623
+ setup do
624
+ @@test.remove
625
+ @@test.save("a" => 1, "pop" => 100)
626
+ @@test.save("a" => 1, "pop" => 100)
627
+ @@test.save("a" => 2, "pop" => 100)
628
+ @@test.save("a" => 2, "pop" => 100)
629
+ @initial = {"count" => 0, "foo" => 1}
630
+ @reduce_function = "function (obj, prev) { prev.count += obj.pop; }"
631
+ end
632
+
633
+ should "group" do
634
+ result = @@test.group([:a], {}, @initial, @reduce_function, nil)
635
+ assert result.all? { |r| r['count'] == 200 }
636
+ end
637
+ end
638
+
579
639
  context "Grouping with a key function" do
580
640
  setup do
581
641
  @@test.remove
@@ -699,6 +759,15 @@ class TestCollection < Test::Unit::TestCase
699
759
  @collection.create_index([['b', 1], ['a', 1]])
700
760
  end
701
761
 
762
+ should "allow multiple calls to create_index" do
763
+
764
+ end
765
+
766
+ should "allow creation of multiple indexes" do
767
+ assert @collection.create_index([['a', 1]])
768
+ assert @collection.create_index([['a', 1]])
769
+ end
770
+
702
771
  context "with an index created" do
703
772
  setup do
704
773
  @collection.create_index([['b', 1], ['a', 1]])
@@ -24,8 +24,8 @@ class TestConnection < Test::Unit::TestCase
24
24
 
25
25
  def test_connection_uri
26
26
  con = Connection.from_uri("mongodb://#{host_port}")
27
- assert_equal mongo_host, con.host
28
- assert_equal mongo_port, con.port
27
+ assert_equal mongo_host, con.primary_pool.host
28
+ assert_equal mongo_port, con.primary_pool.port
29
29
  end
30
30
 
31
31
  def test_server_version
@@ -44,8 +44,8 @@ class TestConnection < Test::Unit::TestCase
44
44
  end
45
45
 
46
46
  def test_replica_set_connection_name
47
- assert_raise_error(Mongo::ReplicaSetConnectionError, "replSet") do
48
- standard_connection(:name => "replica-set-foo")
47
+ assert_raise Mongo::ReplicaSetConnectionError do
48
+ standard_connection(:rs_name => "replica-set-wrong-name")
49
49
  end
50
50
  end
51
51
 
@@ -144,12 +144,6 @@ class TestConnection < Test::Unit::TestCase
144
144
  assert_equal ['bar', 27018], nodes[1]
145
145
  end
146
146
 
147
- def test_slave_ok_with_multiple_nodes
148
- assert_raise MongoArgumentError do
149
- Connection.multi([['foo', 27017], ['bar', 27018]], :connect => false, :slave_ok => true)
150
- end
151
- end
152
-
153
147
  def test_fsync_lock
154
148
  assert !@conn.locked?
155
149
  @conn.lock!
@@ -211,29 +205,29 @@ class TestConnection < Test::Unit::TestCase
211
205
 
212
206
  should "release connection if an exception is raised on send_message" do
213
207
  @con.stubs(:send_message_on_socket).raises(ConnectionFailure)
214
- assert_equal 0, @con.checked_out.size
208
+ assert_equal 0, @con.primary_pool.checked_out.size
215
209
  assert_raise ConnectionFailure do
216
210
  @coll.insert({:test => "insert"})
217
211
  end
218
- assert_equal 0, @con.checked_out.size
212
+ assert_equal 0, @con.primary_pool.checked_out.size
219
213
  end
220
214
 
221
215
  should "release connection if an exception is raised on send_with_safe_check" do
222
216
  @con.stubs(:receive).raises(ConnectionFailure)
223
- assert_equal 0, @con.checked_out.size
217
+ assert_equal 0, @con.primary_pool.checked_out.size
224
218
  assert_raise ConnectionFailure do
225
219
  @coll.insert({:test => "insert"}, :safe => true)
226
220
  end
227
- assert_equal 0, @con.checked_out.size
221
+ assert_equal 0, @con.primary_pool.checked_out.size
228
222
  end
229
223
 
230
224
  should "release connection if an exception is raised on receive_message" do
231
225
  @con.stubs(:receive).raises(ConnectionFailure)
232
- assert_equal 0, @con.checked_out.size
226
+ assert_equal 0, @con.primary_pool.checked_out.size
233
227
  assert_raise ConnectionFailure do
234
228
  @coll.find.to_a
235
229
  end
236
- assert_equal 0, @con.checked_out.size
230
+ assert_equal 0, @con.primary_pool.checked_out.size
237
231
  end
238
232
  end
239
233
  end
@@ -46,6 +46,10 @@ class CursorTest < Test::Unit::TestCase
46
46
  assert_equal 10, @@coll.find({}, :limit => 5).count()
47
47
  assert_equal 10, @@coll.find({}, :skip => 5).count()
48
48
 
49
+ assert_equal 5, @@coll.find({}, :limit => 5).count(true)
50
+ assert_equal 5, @@coll.find({}, :skip => 5).count(true)
51
+ assert_equal 2, @@coll.find({}, :skip => 5, :limit => 2).count(true)
52
+
49
53
  assert_equal 1, @@coll.find({"x" => 1}).count()
50
54
  assert_equal 5, @@coll.find({"x" => {"$lt" => 5}}).count()
51
55
 
@@ -182,10 +186,6 @@ class CursorTest < Test::Unit::TestCase
182
186
  end
183
187
 
184
188
  def test_limit_exceptions
185
- assert_raise ArgumentError do
186
- cursor = @@coll.find().limit('not-an-integer')
187
- end
188
-
189
189
  cursor = @@coll.find()
190
190
  firstResult = cursor.next_document
191
191
  assert_raise InvalidOperation, "Cannot modify the query once it has been run or closed." do
@@ -216,10 +216,6 @@ class CursorTest < Test::Unit::TestCase
216
216
  end
217
217
 
218
218
  def test_skip_exceptions
219
- assert_raise ArgumentError do
220
- cursor = @@coll.find().skip('not-an-integer')
221
- end
222
-
223
219
  cursor = @@coll.find()
224
220
  firstResult = cursor.next_document
225
221
  assert_raise InvalidOperation, "Cannot modify the query once it has been run or closed." do
@@ -364,15 +364,12 @@ class DBAPITest < Test::Unit::TestCase
364
364
  end
365
365
 
366
366
  def test_array
367
- @@coll << {'b' => [1, 2, 3]}
367
+ @@coll.remove
368
+ @@coll.insert({'b' => [1, 2, 3]})
369
+ @@coll.insert({'b' => [1, 2, 3]})
368
370
  rows = @@coll.find({}, {:fields => ['b']}).to_a
369
- if @@version < "1.1.3"
370
- assert_equal 1, rows.length
371
- assert_equal [1, 2, 3], rows[0]['b']
372
- else
373
- assert_equal 2, rows.length
374
- assert_equal [1, 2, 3], rows[1]['b']
375
- end
371
+ assert_equal 2, rows.length
372
+ assert_equal [1, 2, 3], rows[1]['b']
376
373
  end
377
374
 
378
375
  def test_regex
@@ -713,16 +710,7 @@ class DBAPITest < Test::Unit::TestCase
713
710
 
714
711
  a.rename("bar")
715
712
 
716
- assert_equal 0, a.count()
717
- assert_equal 2, b.count()
718
-
719
- assert_equal 1, b.find().to_a()[0]["x"]
720
- assert_equal 2, b.find().to_a()[1]["x"]
721
-
722
- b.rename(:foo)
723
-
724
713
  assert_equal 2, a.count()
725
- assert_equal 0, b.count()
726
714
  end
727
715
 
728
716
  # doesn't really test functionality, just that the option is set correctly
@@ -0,0 +1,40 @@
1
+ $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ require 'mongo'
3
+ require 'test/unit'
4
+ require './test/test_helper'
5
+
6
+ # NOTE: This test expects a replica set of three nodes to be running
7
+ # on the local host.
8
+ class ReplicaSetQuerySecondariesTest < Test::Unit::TestCase
9
+ include Mongo
10
+
11
+ def setup
12
+ @conn = Mongo::Connection.multi([['localhost', 27018]], :read_secondaries => true)
13
+ @db = @conn.db(MONGO_TEST_DB)
14
+ @db.drop_collection("test-sets")
15
+ @coll = @db.collection("test-sets", :safe => {:w => 2, :wtimeout => 100})
16
+ end
17
+
18
+ def test_query
19
+ @coll.save({:a => 20})
20
+ @coll.save({:a => 30})
21
+ @coll.save({:a => 40})
22
+ results = []
23
+ @coll.find.each {|r| results << r["a"]}
24
+ assert results.include?(20)
25
+ assert results.include?(30)
26
+ assert results.include?(40)
27
+
28
+ puts "Please disconnect the current master."
29
+ gets
30
+
31
+ results = []
32
+ rescue_connection_failure do
33
+ @coll.find.each {|r| results << r}
34
+ [20, 30, 40].each do |a|
35
+ assert results.any? {|r| r['a'] == a}, "Could not find record for a => #{a}"
36
+ end
37
+ end
38
+ end
39
+
40
+ end