mongo 1.1.5 → 1.2.rc0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +1 -1
- data/docs/HISTORY.md +8 -0
- data/docs/REPLICA_SETS.md +8 -12
- data/lib/mongo.rb +3 -1
- data/lib/mongo/collection.rb +32 -28
- data/lib/mongo/connection.rb +61 -42
- data/lib/mongo/cursor.rb +13 -13
- data/lib/mongo/db.rb +30 -30
- data/lib/mongo/repl_set_connection.rb +17 -3
- data/lib/mongo/util/pool.rb +3 -3
- data/lib/mongo/util/uri_parser.rb +119 -11
- data/test/bson/bson_test.rb +24 -2
- data/test/collection_test.rb +34 -6
- data/test/connection_test.rb +35 -0
- data/test/replica_sets/connect_test.rb +2 -1
- data/test/replica_sets/connection_string_test.rb +32 -0
- data/test/replica_sets/query_secondaries.rb +4 -0
- data/test/replica_sets/replication_ack_test.rb +2 -0
- data/test/replica_sets/rs_test_helper.rb +9 -11
- data/test/unit/collection_test.rb +0 -1
- data/test/unit/connection_test.rb +4 -4
- data/test/unit/repl_set_connection_test.rb +0 -10
- data/test/unit/safe_test.rb +2 -2
- data/test/uri_test.rb +75 -0
- metadata +20 -14
data/lib/mongo/db.rb
CHANGED
@@ -56,33 +56,33 @@ module Mongo
|
|
56
56
|
|
57
57
|
# Instances of DB are normally obtained by calling Mongo#db.
|
58
58
|
#
|
59
|
-
# @param [String]
|
59
|
+
# @param [String] name the database name.
|
60
60
|
# @param [Mongo::Connection] connection a connection object pointing to MongoDB. Note
|
61
61
|
# that databases are usually instantiated via the Connection class. See the examples below.
|
62
62
|
#
|
63
|
-
# @option
|
63
|
+
# @option opts [Boolean] :strict (False) If true, collections must exist to be accessed and must
|
64
64
|
# not exist to be created. See DB#collection and DB#create_collection.
|
65
65
|
#
|
66
|
-
# @option
|
66
|
+
# @option opts [Object, #create_pk(doc)] :pk (Mongo::ObjectId) A primary key factory object,
|
67
67
|
# which should take a hash and return a hash which merges the original hash with any primary key
|
68
68
|
# fields the factory wishes to inject. (NOTE: if the object already has a primary key,
|
69
69
|
# the factory should not inject a new key).
|
70
70
|
#
|
71
|
-
# @option
|
71
|
+
# @option opts [Boolean, Hash] :safe (false) Set the default safe-mode options
|
72
72
|
# propogated to Collection objects instantiated off of this DB. If no
|
73
73
|
# value is provided, the default value set on this instance's Connection object will be used. This
|
74
74
|
# default can be overridden upon instantiation of any collection by explicity setting a :safe value
|
75
75
|
# on initialization
|
76
|
-
# @option
|
76
|
+
# @option opts [Integer] :cache_time (300) Set the time that all ensure_index calls should cache the command.
|
77
77
|
#
|
78
78
|
# @core databases constructor_details
|
79
|
-
def initialize(
|
80
|
-
@name = Mongo::Support.validate_db_name(
|
79
|
+
def initialize(name, connection, opts={})
|
80
|
+
@name = Mongo::Support.validate_db_name(name)
|
81
81
|
@connection = connection
|
82
|
-
@strict =
|
83
|
-
@pk_factory =
|
84
|
-
@safe =
|
85
|
-
@cache_time =
|
82
|
+
@strict = opts[:strict]
|
83
|
+
@pk_factory = opts[:pk]
|
84
|
+
@safe = opts.fetch(:safe, @connection.safe)
|
85
|
+
@cache_time = opts[:cache_time] || 300 #5 minutes.
|
86
86
|
end
|
87
87
|
|
88
88
|
# Authenticate with the given username and password. Note that mongod
|
@@ -208,8 +208,8 @@ module Mongo
|
|
208
208
|
#
|
209
209
|
# @return [Array<Mongo::Collection>]
|
210
210
|
def collections
|
211
|
-
collection_names.map do |
|
212
|
-
Collection.new(
|
211
|
+
collection_names.map do |name|
|
212
|
+
Collection.new(name, self)
|
213
213
|
end
|
214
214
|
end
|
215
215
|
|
@@ -223,7 +223,7 @@ module Mongo
|
|
223
223
|
def collections_info(coll_name=nil)
|
224
224
|
selector = {}
|
225
225
|
selector[:name] = full_collection_name(coll_name) if coll_name
|
226
|
-
Cursor.new(Collection.new(
|
226
|
+
Cursor.new(Collection.new(SYSTEM_NAMESPACE_COLLECTION, self), :selector => selector)
|
227
227
|
end
|
228
228
|
|
229
229
|
# Create a collection.
|
@@ -233,52 +233,52 @@ module Mongo
|
|
233
233
|
#
|
234
234
|
# @param [String] name the name of the new collection.
|
235
235
|
#
|
236
|
-
# @option
|
236
|
+
# @option opts [Boolean] :capped (False) created a capped collection.
|
237
237
|
#
|
238
|
-
# @option
|
238
|
+
# @option opts [Integer] :size (Nil) If +capped+ is +true+, specifies the maximum number of
|
239
239
|
# bytes for the capped collection. If +false+, specifies the number of bytes allocated
|
240
240
|
# for the initial extent of the collection.
|
241
241
|
#
|
242
|
-
# @option
|
242
|
+
# @option opts [Integer] :max (Nil) If +capped+ is +true+, indicates the maximum number of records
|
243
243
|
# in a capped collection.
|
244
244
|
#
|
245
245
|
# @raise [MongoDBError] raised under two conditions: either we're in +strict+ mode and the collection
|
246
246
|
# already exists or collection creation fails on the server.
|
247
247
|
#
|
248
248
|
# @return [Mongo::Collection]
|
249
|
-
def create_collection(name,
|
249
|
+
def create_collection(name, opts={})
|
250
250
|
# Does the collection already exist?
|
251
251
|
if collection_names.include?(name)
|
252
252
|
if strict?
|
253
253
|
raise MongoDBError, "Collection #{name} already exists. Currently in strict mode."
|
254
254
|
else
|
255
|
-
return Collection.new(
|
255
|
+
return Collection.new(name, self)
|
256
256
|
end
|
257
257
|
end
|
258
258
|
|
259
259
|
# Create a new collection.
|
260
260
|
oh = BSON::OrderedHash.new
|
261
261
|
oh[:create] = name
|
262
|
-
doc = command(oh.merge(
|
263
|
-
return Collection.new(
|
262
|
+
doc = command(oh.merge(opts || {}))
|
263
|
+
return Collection.new(name, self, :pk => @pk_factory) if ok?(doc)
|
264
264
|
raise MongoDBError, "Error creating collection: #{doc.inspect}"
|
265
265
|
end
|
266
266
|
|
267
267
|
# Get a collection by name.
|
268
268
|
#
|
269
269
|
# @param [String] name the collection name.
|
270
|
-
# @param [Hash]
|
270
|
+
# @param [Hash] opts any valid options that can me passed to Collection#new.
|
271
271
|
#
|
272
272
|
# @raise [MongoDBError] if collection does not already exist and we're in +strict+ mode.
|
273
273
|
#
|
274
274
|
# @return [Mongo::Collection]
|
275
|
-
def collection(name,
|
275
|
+
def collection(name, opts={})
|
276
276
|
if strict? && !collection_names.include?(name)
|
277
277
|
raise Mongo::MongoDBError, "Collection #{name} doesn't exist. Currently in strict mode."
|
278
278
|
else
|
279
|
-
|
280
|
-
|
281
|
-
Collection.new(
|
279
|
+
opts[:safe] = opts.fetch(:safe, @safe)
|
280
|
+
opts.merge!(:pk => @pk_factory) unless opts[:pk]
|
281
|
+
Collection.new(name, self, opts)
|
282
282
|
end
|
283
283
|
end
|
284
284
|
alias_method :[], :collection
|
@@ -403,7 +403,7 @@ module Mongo
|
|
403
403
|
def drop_index(collection_name, index_name)
|
404
404
|
oh = BSON::OrderedHash.new
|
405
405
|
oh[:deleteIndexes] = collection_name
|
406
|
-
oh[:index] = index_name
|
406
|
+
oh[:index] = index_name.to_s
|
407
407
|
doc = command(oh, :check_response => false)
|
408
408
|
ok?(doc) || raise(MongoDBError, "Error with drop_index command: #{doc.inspect}")
|
409
409
|
end
|
@@ -418,7 +418,7 @@ module Mongo
|
|
418
418
|
def index_information(collection_name)
|
419
419
|
sel = {:ns => full_collection_name(collection_name)}
|
420
420
|
info = {}
|
421
|
-
Cursor.new(Collection.new(
|
421
|
+
Cursor.new(Collection.new(SYSTEM_INDEX_COLLECTION, self), :selector => sel).each do |index|
|
422
422
|
info[index['name']] = index
|
423
423
|
end
|
424
424
|
info
|
@@ -558,7 +558,7 @@ module Mongo
|
|
558
558
|
#
|
559
559
|
# @return [Array] a list of documents containing profiling information.
|
560
560
|
def profiling_info
|
561
|
-
Cursor.new(Collection.new(
|
561
|
+
Cursor.new(Collection.new(SYSTEM_PROFILE_COLLECTION, self), :selector => {}).to_a
|
562
562
|
end
|
563
563
|
|
564
564
|
# Validate a named collection.
|
@@ -581,7 +581,7 @@ module Mongo
|
|
581
581
|
private
|
582
582
|
|
583
583
|
def system_command_collection
|
584
|
-
Collection.new(
|
584
|
+
Collection.new(SYSTEM_COMMAND_COLLECTION, self)
|
585
585
|
end
|
586
586
|
end
|
587
587
|
end
|
@@ -32,6 +32,8 @@ module Mongo
|
|
32
32
|
# @param [Array] args A list of host-port pairs ending with a hash containing any options. See
|
33
33
|
# the examples below for exactly how to use the constructor.
|
34
34
|
#
|
35
|
+
# @option options [String] :rs_name (nil) The name of the replica set to connect to. You
|
36
|
+
# can use this option to verify that you're connecting to the right replica set.
|
35
37
|
# @option options [Boolean, Hash] :safe (false) Set the default safe-mode options
|
36
38
|
# propogated to DB objects instantiated off of this Connection. This
|
37
39
|
# default can be overridden upon instantiation of any DB by explicity setting a :safe value
|
@@ -48,8 +50,10 @@ module Mongo
|
|
48
50
|
# @example Connect to a replica set and provide two seed nodes:
|
49
51
|
# ReplSetConnection.new(['localhost', 30000], ['localhost', 30001])
|
50
52
|
#
|
51
|
-
# @example Connect to a replica set providing two seed nodes and
|
52
|
-
#
|
53
|
+
# @example Connect to a replica set providing two seed nodes and ensuring a connection to the replica set named 'prod':
|
54
|
+
# ReplSetConnection.new(['localhost', 30000], ['localhost', 30001], :rs_name => 'prod')
|
55
|
+
#
|
56
|
+
# @example Connect to a replica set providing two seed nodes and allowing reads from a secondary node:
|
53
57
|
# ReplSetConnection.new(['localhost', 30000], ['localhost', 30001], :read_secondary => true)
|
54
58
|
#
|
55
59
|
# @see http://api.mongodb.org/ruby/current/file.REPLICA_SETS.html Replica sets in Ruby
|
@@ -111,7 +115,9 @@ module Mongo
|
|
111
115
|
|
112
116
|
pick_secondary_for_read if @read_secondary
|
113
117
|
|
114
|
-
if
|
118
|
+
if connected?
|
119
|
+
BSON::BSON_CODER.update_max_bson_size(self)
|
120
|
+
else
|
115
121
|
if @secondary_pools.empty?
|
116
122
|
raise ConnectionFailure, "Failed to connect any given host:port"
|
117
123
|
else
|
@@ -124,6 +130,14 @@ module Mongo
|
|
124
130
|
@nodes_to_try.length > 0
|
125
131
|
end
|
126
132
|
|
133
|
+
# Determine whether we're reading from a primary node. If false,
|
134
|
+
# this connection connects to a secondary node and @read_secondaries is true.
|
135
|
+
#
|
136
|
+
# @return [Boolean]
|
137
|
+
def read_primary?
|
138
|
+
!@read_pool || @read_pool.length.zero?
|
139
|
+
end
|
140
|
+
|
127
141
|
# Close the connection to the database.
|
128
142
|
def close
|
129
143
|
super
|
data/lib/mongo/util/pool.rb
CHANGED
@@ -22,14 +22,14 @@ module Mongo
|
|
22
22
|
|
23
23
|
# Create a new pool of connections.
|
24
24
|
#
|
25
|
-
def initialize(connection, host, port,
|
25
|
+
def initialize(connection, host, port, opts={})
|
26
26
|
@connection = connection
|
27
27
|
|
28
28
|
@host, @port = host, port
|
29
29
|
|
30
30
|
# Pool size and timeout.
|
31
|
-
@size =
|
32
|
-
@timeout =
|
31
|
+
@size = opts[:size] || 1
|
32
|
+
@timeout = opts[:timeout] || 5.0
|
33
33
|
|
34
34
|
# Mutex for synchronizing pool access
|
35
35
|
@connection_mutex = Mutex.new
|
@@ -17,28 +17,99 @@
|
|
17
17
|
# ++
|
18
18
|
|
19
19
|
module Mongo
|
20
|
-
|
20
|
+
class URIParser
|
21
21
|
|
22
22
|
DEFAULT_PORT = 27017
|
23
23
|
MONGODB_URI_MATCHER = /(([-_.\w\d]+):([-_\w\d]+)@)?([-.\w\d]+)(:([\w\d]+))?(\/([-\d\w]+))?/
|
24
24
|
MONGODB_URI_SPEC = "mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/database]"
|
25
|
+
SPEC_ATTRS = [:nodes, :auths]
|
26
|
+
OPT_ATTRS = [:connect, :replicaset, :slaveok, :safe, :w, :wtimeout, :fsync]
|
25
27
|
|
26
|
-
|
28
|
+
OPT_VALID = {:connect => lambda {|arg| ['direct', 'replicaset'].include?(arg)},
|
29
|
+
:replicaset => lambda {|arg| arg.length > 0},
|
30
|
+
:slaveok => lambda {|arg| ['true', 'false'].include?(arg)},
|
31
|
+
:safe => lambda {|arg| ['true', 'false'].include?(arg)},
|
32
|
+
:w => lambda {|arg| arg =~ /^\d+$/ },
|
33
|
+
:wtimeout => lambda {|arg| arg =~ /^\d+$/ },
|
34
|
+
:fsync => lambda {|arg| ['true', 'false'].include?(arg)}
|
35
|
+
}
|
36
|
+
|
37
|
+
OPT_ERR = {:connect => "must be 'direct' or 'replicaset'",
|
38
|
+
:replicaset => "must be a string containing the name of the replica set to connect to",
|
39
|
+
:slaveok => "must be 'true' or 'false'",
|
40
|
+
:safe => "must be 'true' or 'false'",
|
41
|
+
:w => "must be an integer specifying number of nodes to replica to",
|
42
|
+
:wtimeout => "must be an integer specifying milliseconds",
|
43
|
+
:fsync => "must be 'true' or 'false'"
|
44
|
+
}
|
45
|
+
|
46
|
+
OPT_CONV = {:connect => lambda {|arg| arg},
|
47
|
+
:replicaset => lambda {|arg| arg},
|
48
|
+
:slaveok => lambda {|arg| arg == 'true' ? true : false},
|
49
|
+
:safe => lambda {|arg| arg == 'true' ? true : false},
|
50
|
+
:w => lambda {|arg| arg.to_i},
|
51
|
+
:wtimeout => lambda {|arg| arg.to_i},
|
52
|
+
:fsync => lambda {|arg| arg == 'true' ? true : false}
|
53
|
+
}
|
54
|
+
|
55
|
+
attr_reader :nodes, :auths, :connect, :replicaset, :slaveok, :safe, :w, :wtimeout, :fsync
|
27
56
|
|
28
57
|
# Parse a MongoDB URI. This method is used by Connection.from_uri.
|
29
58
|
# Returns an array of nodes and an array of db authorizations, if applicable.
|
30
59
|
#
|
31
|
-
# @
|
32
|
-
def
|
60
|
+
# @core connections
|
61
|
+
def initialize(string)
|
33
62
|
if string =~ /^mongodb:\/\//
|
34
63
|
string = string[10..-1]
|
35
64
|
else
|
36
65
|
raise MongoArgumentError, "MongoDB URI must match this spec: #{MONGODB_URI_SPEC}"
|
37
66
|
end
|
38
67
|
|
39
|
-
|
40
|
-
|
41
|
-
|
68
|
+
hosts, opts = string.split('?')
|
69
|
+
parse_hosts(hosts)
|
70
|
+
parse_options(opts)
|
71
|
+
configure_connect
|
72
|
+
end
|
73
|
+
|
74
|
+
def connection_options
|
75
|
+
opts = {}
|
76
|
+
|
77
|
+
if (@w || @wtimeout || @fsync) && !@safe
|
78
|
+
raise MongoArgumentError, "Safe must be true if w, wtimeout, or fsync is specified"
|
79
|
+
end
|
80
|
+
|
81
|
+
if @safe
|
82
|
+
if @w || @wtimeout || @fsync
|
83
|
+
safe_opts = {}
|
84
|
+
safe_opts[:w] = @w if @w
|
85
|
+
safe_opts[:wtimeout] = @wtimeout if @wtimeout
|
86
|
+
safe_opts[:fsync] = @fsync if @fsync
|
87
|
+
else
|
88
|
+
safe_opts = true
|
89
|
+
end
|
90
|
+
|
91
|
+
opts[:safe] = safe_opts
|
92
|
+
end
|
93
|
+
|
94
|
+
if @slaveok
|
95
|
+
if @connect == 'direct'
|
96
|
+
opts[:slave_ok] = true
|
97
|
+
else
|
98
|
+
opts[:read_secondary] = true
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
opts[:rs_name] = @replicaset if @replicaset
|
103
|
+
|
104
|
+
opts
|
105
|
+
end
|
106
|
+
|
107
|
+
private
|
108
|
+
|
109
|
+
def parse_hosts(hosts)
|
110
|
+
@nodes = []
|
111
|
+
@auths = []
|
112
|
+
specs = hosts.split(',')
|
42
113
|
specs.each do |spec|
|
43
114
|
matches = MONGODB_URI_MATCHER.match(spec)
|
44
115
|
if !matches
|
@@ -52,8 +123,8 @@ module Mongo
|
|
52
123
|
if !(port.to_s =~ /^\d+$/)
|
53
124
|
raise MongoArgumentError, "Invalid port #{port}; port must be specified as digits."
|
54
125
|
end
|
55
|
-
port
|
56
|
-
db
|
126
|
+
port = port.to_i
|
127
|
+
db = matches[8]
|
57
128
|
|
58
129
|
if uname && pwd && db
|
59
130
|
auths << {'db_name' => db, 'username' => uname, 'password' => pwd}
|
@@ -62,10 +133,47 @@ module Mongo
|
|
62
133
|
"and db if any one of these is specified."
|
63
134
|
end
|
64
135
|
|
65
|
-
nodes << [host, port]
|
136
|
+
@nodes << [host, port]
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# This method uses the lambdas defined in OPT_VALID and OPT_CONV to validate
|
141
|
+
# and convert the given options.
|
142
|
+
def parse_options(opts)
|
143
|
+
return unless opts
|
144
|
+
separator = opts.include?('&') ? '&' : ';'
|
145
|
+
opts.split(separator).each do |attr|
|
146
|
+
key, value = attr.split('=')
|
147
|
+
key = key.to_sym
|
148
|
+
value = value.strip.downcase
|
149
|
+
if !OPT_ATTRS.include?(key)
|
150
|
+
raise MongoArgumentError, "Invalid Mongo URI option #{key}"
|
151
|
+
end
|
152
|
+
|
153
|
+
if OPT_VALID[key].call(value)
|
154
|
+
instance_variable_set("@#{key}", OPT_CONV[key].call(value))
|
155
|
+
else
|
156
|
+
raise MongoArgumentError, "Invalid value for #{key}: #{OPT_ERR[key]}"
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def configure_connect
|
162
|
+
if @nodes.length > 1 && !@connect
|
163
|
+
@connect = 'replicaset'
|
66
164
|
end
|
67
165
|
|
68
|
-
|
166
|
+
if !@connect
|
167
|
+
if @nodes.length > 1
|
168
|
+
@connect = 'replicaset'
|
169
|
+
else
|
170
|
+
@connect = 'direct'
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
if @connect == 'direct' && @replicaset
|
175
|
+
raise MongoArgumentError, "If specifying a replica set name, please also specify that connect=replicaset"
|
176
|
+
end
|
69
177
|
end
|
70
178
|
end
|
71
179
|
end
|
data/test/bson/bson_test.rb
CHANGED
@@ -67,13 +67,26 @@ class BSONTest < Test::Unit::TestCase
|
|
67
67
|
assert_doc_pass(doc)
|
68
68
|
end
|
69
69
|
|
70
|
-
def
|
71
|
-
doc = {'name' => 'a' *
|
70
|
+
def test_limit_max_bson_size
|
71
|
+
doc = {'name' => 'a' * BSON_CODER.max_bson_size}
|
72
72
|
assert_raise InvalidDocument do
|
73
73
|
assert @encoder.serialize(doc)
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
77
|
+
def test_max_bson_size
|
78
|
+
assert BSON_CODER.max_bson_size >= BSON::DEFAULT_MAX_BSON_SIZE
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_update_max_bson_size
|
82
|
+
require 'ostruct'
|
83
|
+
mock_conn = OpenStruct.new
|
84
|
+
size = 7 * 1024 * 1024
|
85
|
+
mock_conn.max_bson_size = size
|
86
|
+
assert_equal size, BSON_CODER.update_max_bson_size(mock_conn)
|
87
|
+
assert_equal size, BSON_CODER.max_bson_size
|
88
|
+
end
|
89
|
+
|
77
90
|
def test_round_trip
|
78
91
|
doc = {'doc' => 123}
|
79
92
|
@encoder.deserialize(@encoder.serialize(doc))
|
@@ -200,6 +213,15 @@ class BSONTest < Test::Unit::TestCase
|
|
200
213
|
assert_doc_pass(doc)
|
201
214
|
end
|
202
215
|
|
216
|
+
def test_array_keys
|
217
|
+
doc = {'doc' => [1, 2, 'a', 'b']}
|
218
|
+
bson = @encoder.serialize(doc).to_a
|
219
|
+
assert_equal 48, bson[14]
|
220
|
+
assert_equal 49, bson[21]
|
221
|
+
assert_equal 50, bson[28]
|
222
|
+
assert_equal 51, bson[37]
|
223
|
+
end
|
224
|
+
|
203
225
|
def test_regex
|
204
226
|
doc = {'doc' => /foobar/i}
|
205
227
|
assert_doc_pass(doc)
|
data/test/collection_test.rb
CHANGED
@@ -32,11 +32,11 @@ class TestCollection < Test::Unit::TestCase
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def test_pk_factory_on_collection
|
35
|
-
@coll = Collection.new(
|
35
|
+
@coll = Collection.new('foo', @@db, TestPK)
|
36
36
|
assert_equal TestPK, @coll.pk_factory
|
37
37
|
|
38
38
|
|
39
|
-
@coll2 = Collection.new(
|
39
|
+
@coll2 = Collection.new('foo', @@db, :pk => TestPK)
|
40
40
|
assert_equal TestPK, @coll2.pk_factory
|
41
41
|
end
|
42
42
|
|
@@ -417,7 +417,7 @@ class TestCollection < Test::Unit::TestCase
|
|
417
417
|
|
418
418
|
m = "function() { emit(this.user_id, 1); }"
|
419
419
|
r = "function(k,vals) { return 1; }"
|
420
|
-
res = @@test.map_reduce(m, r);
|
420
|
+
res = @@test.map_reduce(m, r, :out => 'foo');
|
421
421
|
assert res.find_one({"_id" => 1})
|
422
422
|
assert res.find_one({"_id" => 2})
|
423
423
|
end
|
@@ -428,7 +428,7 @@ class TestCollection < Test::Unit::TestCase
|
|
428
428
|
|
429
429
|
m = Code.new("function() { emit(this.user_id, 1); }")
|
430
430
|
r = Code.new("function(k,vals) { return 1; }")
|
431
|
-
res = @@test.map_reduce(m, r);
|
431
|
+
res = @@test.map_reduce(m, r, :out => 'foo');
|
432
432
|
assert res.find_one({"_id" => 1})
|
433
433
|
assert res.find_one({"_id" => 2})
|
434
434
|
end
|
@@ -441,7 +441,7 @@ class TestCollection < Test::Unit::TestCase
|
|
441
441
|
|
442
442
|
m = Code.new("function() { emit(this.user_id, 1); }")
|
443
443
|
r = Code.new("function(k,vals) { return 1; }")
|
444
|
-
res = @@test.map_reduce(m, r, :query => {"user_id" => {"$gt" => 1}});
|
444
|
+
res = @@test.map_reduce(m, r, :query => {"user_id" => {"$gt" => 1}}, :out => 'foo');
|
445
445
|
assert_equal 2, res.count
|
446
446
|
assert res.find_one({"_id" => 2})
|
447
447
|
assert res.find_one({"_id" => 3})
|
@@ -450,7 +450,7 @@ class TestCollection < Test::Unit::TestCase
|
|
450
450
|
def test_map_reduce_with_raw_response
|
451
451
|
m = Code.new("function() { emit(this.user_id, 1); }")
|
452
452
|
r = Code.new("function(k,vals) { return 1; }")
|
453
|
-
res = @@test.map_reduce(m, r, :raw => true)
|
453
|
+
res = @@test.map_reduce(m, r, :raw => true, :out => 'foo')
|
454
454
|
assert res["result"]
|
455
455
|
assert res["counts"]
|
456
456
|
assert res["timeMillis"]
|
@@ -600,6 +600,23 @@ class TestCollection < Test::Unit::TestCase
|
|
600
600
|
@@test.drop_index("a_1")
|
601
601
|
end
|
602
602
|
|
603
|
+
def test_ensure_index_timeout
|
604
|
+
@@db.cache_time = 2
|
605
|
+
coll = @@db['ensure_test']
|
606
|
+
coll.expects(:generate_indexes).twice
|
607
|
+
coll.ensure_index([['a', 1]])
|
608
|
+
|
609
|
+
# These will be cached
|
610
|
+
coll.ensure_index([['a', 1]])
|
611
|
+
coll.ensure_index([['a', 1]])
|
612
|
+
coll.ensure_index([['a', 1]])
|
613
|
+
coll.ensure_index([['a', 1]])
|
614
|
+
|
615
|
+
sleep(3)
|
616
|
+
# This won't be, so generate_indexes will be called twice
|
617
|
+
coll.ensure_index([['a', 1]])
|
618
|
+
end
|
619
|
+
|
603
620
|
context "Grouping" do
|
604
621
|
setup do
|
605
622
|
@@test.remove
|
@@ -693,6 +710,17 @@ class TestCollection < Test::Unit::TestCase
|
|
693
710
|
@geo = @@db.collection('geo')
|
694
711
|
end
|
695
712
|
|
713
|
+
should "create index using symbols" do
|
714
|
+
@collection.create_index :foo, :name => :bar
|
715
|
+
@geo.create_index :goo, :name => :baz
|
716
|
+
assert @collection.index_information['bar']
|
717
|
+
@collection.drop_index :bar
|
718
|
+
assert_nil @collection.index_information['bar']
|
719
|
+
assert @geo.index_information['baz']
|
720
|
+
@geo.drop_index(:baz)
|
721
|
+
assert_nil @geo.index_information['baz']
|
722
|
+
end
|
723
|
+
|
696
724
|
should "create a geospatial index" do
|
697
725
|
@geo.save({'loc' => [-100, 100]})
|
698
726
|
@geo.create_index([['loc', Mongo::GEO2D]])
|