mongo 1.1.2 → 1.1.3

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