mongo 1.3.0 → 1.12.5
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.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data/{LICENSE.txt → LICENSE} +1 -1
- data/README.md +122 -271
- data/Rakefile +25 -209
- data/VERSION +1 -0
- data/bin/mongo_console +31 -9
- data/lib/mongo/bulk_write_collection_view.rb +387 -0
- data/lib/mongo/collection.rb +576 -269
- data/lib/mongo/collection_writer.rb +364 -0
- data/lib/mongo/connection/node.rb +249 -0
- data/lib/mongo/connection/pool.rb +340 -0
- data/lib/mongo/connection/pool_manager.rb +320 -0
- data/lib/mongo/connection/sharding_pool_manager.rb +67 -0
- data/lib/mongo/connection/socket/socket_util.rb +37 -0
- data/lib/mongo/connection/socket/ssl_socket.rb +95 -0
- data/lib/mongo/connection/socket/tcp_socket.rb +87 -0
- data/lib/mongo/connection/socket/unix_socket.rb +39 -0
- data/lib/mongo/connection/socket.rb +18 -0
- data/lib/mongo/connection.rb +7 -875
- data/lib/mongo/cursor.rb +403 -117
- data/lib/mongo/db.rb +444 -243
- data/lib/mongo/exception.rb +145 -0
- data/lib/mongo/functional/authentication.rb +455 -0
- data/lib/mongo/functional/logging.rb +85 -0
- data/lib/mongo/functional/read_preference.rb +183 -0
- data/lib/mongo/functional/scram.rb +556 -0
- data/lib/mongo/functional/uri_parser.rb +409 -0
- data/lib/mongo/functional/write_concern.rb +66 -0
- data/lib/mongo/functional.rb +20 -0
- data/lib/mongo/gridfs/grid.rb +30 -24
- data/lib/mongo/gridfs/grid_ext.rb +6 -10
- data/lib/mongo/gridfs/grid_file_system.rb +38 -20
- data/lib/mongo/gridfs/grid_io.rb +84 -75
- data/lib/mongo/gridfs.rb +18 -0
- data/lib/mongo/legacy.rb +140 -0
- data/lib/mongo/mongo_client.rb +697 -0
- data/lib/mongo/mongo_replica_set_client.rb +535 -0
- data/lib/mongo/mongo_sharded_client.rb +159 -0
- data/lib/mongo/networking.rb +372 -0
- data/lib/mongo/{util → utils}/conversions.rb +29 -8
- data/lib/mongo/{util → utils}/core_ext.rb +28 -18
- data/lib/mongo/{util → utils}/server_version.rb +4 -6
- data/lib/mongo/{util → utils}/support.rb +29 -31
- data/lib/mongo/utils/thread_local_variable_manager.rb +25 -0
- data/lib/mongo/utils.rb +19 -0
- data/lib/mongo.rb +51 -50
- data/mongo.gemspec +29 -32
- data/test/functional/authentication_test.rb +39 -0
- data/test/functional/bulk_api_stress_test.rb +133 -0
- data/test/functional/bulk_write_collection_view_test.rb +1198 -0
- data/test/functional/client_test.rb +627 -0
- data/test/functional/collection_test.rb +2175 -0
- data/test/functional/collection_writer_test.rb +83 -0
- data/test/{conversions_test.rb → functional/conversions_test.rb} +47 -3
- data/test/functional/cursor_fail_test.rb +57 -0
- data/test/functional/cursor_message_test.rb +56 -0
- data/test/functional/cursor_test.rb +683 -0
- data/test/functional/db_api_test.rb +835 -0
- data/test/functional/db_connection_test.rb +25 -0
- data/test/functional/db_test.rb +348 -0
- data/test/functional/grid_file_system_test.rb +285 -0
- data/test/{grid_io_test.rb → functional/grid_io_test.rb} +72 -11
- data/test/{grid_test.rb → functional/grid_test.rb} +88 -15
- data/test/functional/pool_test.rb +136 -0
- data/test/functional/safe_test.rb +98 -0
- data/test/functional/ssl_test.rb +29 -0
- data/test/functional/support_test.rb +62 -0
- data/test/functional/timeout_test.rb +60 -0
- data/test/functional/uri_test.rb +446 -0
- data/test/functional/write_concern_test.rb +118 -0
- data/test/helpers/general.rb +50 -0
- data/test/helpers/test_unit.rb +476 -0
- data/test/replica_set/authentication_test.rb +37 -0
- data/test/replica_set/basic_test.rb +189 -0
- data/test/replica_set/client_test.rb +393 -0
- data/test/replica_set/connection_test.rb +138 -0
- data/test/replica_set/count_test.rb +66 -0
- data/test/replica_set/cursor_test.rb +220 -0
- data/test/replica_set/insert_test.rb +157 -0
- data/test/replica_set/max_values_test.rb +151 -0
- data/test/replica_set/pinning_test.rb +105 -0
- data/test/replica_set/query_test.rb +73 -0
- data/test/replica_set/read_preference_test.rb +219 -0
- data/test/replica_set/refresh_test.rb +211 -0
- data/test/replica_set/replication_ack_test.rb +95 -0
- data/test/replica_set/ssl_test.rb +32 -0
- data/test/sharded_cluster/basic_test.rb +203 -0
- data/test/shared/authentication/basic_auth_shared.rb +260 -0
- data/test/shared/authentication/bulk_api_auth_shared.rb +249 -0
- data/test/shared/authentication/gssapi_shared.rb +176 -0
- data/test/shared/authentication/sasl_plain_shared.rb +96 -0
- data/test/shared/authentication/scram_shared.rb +92 -0
- data/test/shared/ssl_shared.rb +235 -0
- data/test/test_helper.rb +53 -94
- data/test/threading/basic_test.rb +120 -0
- data/test/tools/mongo_config.rb +708 -0
- data/test/tools/mongo_config_test.rb +160 -0
- data/test/unit/client_test.rb +381 -0
- data/test/unit/collection_test.rb +89 -53
- data/test/unit/connection_test.rb +282 -32
- data/test/unit/cursor_test.rb +206 -8
- data/test/unit/db_test.rb +55 -13
- data/test/unit/grid_test.rb +43 -16
- data/test/unit/mongo_sharded_client_test.rb +48 -0
- data/test/unit/node_test.rb +93 -0
- data/test/unit/pool_manager_test.rb +111 -0
- data/test/unit/read_pref_test.rb +406 -0
- data/test/unit/read_test.rb +159 -0
- data/test/unit/safe_test.rb +69 -36
- data/test/unit/sharding_pool_manager_test.rb +84 -0
- data/test/unit/write_concern_test.rb +175 -0
- data.tar.gz.sig +3 -0
- metadata +227 -216
- metadata.gz.sig +0 -0
- data/docs/CREDITS.md +0 -123
- data/docs/FAQ.md +0 -116
- data/docs/GridFS.md +0 -158
- data/docs/HISTORY.md +0 -244
- data/docs/RELEASES.md +0 -33
- data/docs/REPLICA_SETS.md +0 -72
- data/docs/TUTORIAL.md +0 -247
- data/docs/WRITE_CONCERN.md +0 -28
- data/lib/mongo/exceptions.rb +0 -71
- data/lib/mongo/gridfs/grid_io_fix.rb +0 -38
- data/lib/mongo/repl_set_connection.rb +0 -342
- data/lib/mongo/test.rb +0 -20
- data/lib/mongo/util/pool.rb +0 -177
- data/lib/mongo/util/uri_parser.rb +0 -185
- data/test/async/collection_test.rb +0 -224
- data/test/async/connection_test.rb +0 -24
- data/test/async/cursor_test.rb +0 -162
- data/test/async/worker_pool_test.rb +0 -99
- data/test/auxillary/1.4_features.rb +0 -166
- data/test/auxillary/authentication_test.rb +0 -68
- data/test/auxillary/autoreconnect_test.rb +0 -41
- data/test/auxillary/fork_test.rb +0 -30
- data/test/auxillary/repl_set_auth_test.rb +0 -58
- data/test/auxillary/slave_connection_test.rb +0 -36
- data/test/auxillary/threaded_authentication_test.rb +0 -101
- data/test/bson/binary_test.rb +0 -15
- data/test/bson/bson_test.rb +0 -649
- data/test/bson/byte_buffer_test.rb +0 -208
- data/test/bson/hash_with_indifferent_access_test.rb +0 -38
- data/test/bson/json_test.rb +0 -17
- data/test/bson/object_id_test.rb +0 -154
- data/test/bson/ordered_hash_test.rb +0 -204
- data/test/bson/timestamp_test.rb +0 -24
- data/test/collection_test.rb +0 -910
- data/test/connection_test.rb +0 -309
- data/test/cursor_fail_test.rb +0 -75
- data/test/cursor_message_test.rb +0 -43
- data/test/cursor_test.rb +0 -483
- data/test/db_api_test.rb +0 -726
- data/test/db_connection_test.rb +0 -15
- data/test/db_test.rb +0 -287
- data/test/grid_file_system_test.rb +0 -243
- data/test/load/resque/load.rb +0 -21
- data/test/load/resque/processor.rb +0 -26
- data/test/load/thin/load.rb +0 -24
- data/test/load/unicorn/load.rb +0 -23
- data/test/load/unicorn/unicorn.rb +0 -29
- data/test/replica_sets/connect_test.rb +0 -94
- data/test/replica_sets/connection_string_test.rb +0 -32
- data/test/replica_sets/count_test.rb +0 -35
- data/test/replica_sets/insert_test.rb +0 -53
- data/test/replica_sets/pooled_insert_test.rb +0 -55
- data/test/replica_sets/query_secondaries.rb +0 -96
- data/test/replica_sets/query_test.rb +0 -51
- data/test/replica_sets/replication_ack_test.rb +0 -66
- data/test/replica_sets/rs_test_helper.rb +0 -27
- data/test/safe_test.rb +0 -68
- data/test/support/hash_with_indifferent_access.rb +0 -186
- data/test/support/keys.rb +0 -45
- data/test/support_test.rb +0 -18
- data/test/threading/threading_with_large_pool_test.rb +0 -90
- data/test/threading_test.rb +0 -87
- data/test/tools/auth_repl_set_manager.rb +0 -14
- data/test/tools/load.rb +0 -58
- data/test/tools/repl_set_manager.rb +0 -266
- data/test/tools/sharding_manager.rb +0 -202
- data/test/tools/test.rb +0 -4
- data/test/unit/pool_test.rb +0 -9
- data/test/unit/repl_set_connection_test.rb +0 -59
- data/test/uri_test.rb +0 -91
data/lib/mongo/db.rb
CHANGED
@@ -1,36 +1,36 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
# --
|
4
|
-
# Copyright (C) 2008-2011 10gen Inc.
|
1
|
+
# Copyright (C) 2009-2013 MongoDB, Inc.
|
5
2
|
#
|
6
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
4
|
# you may not use this file except in compliance with the License.
|
8
5
|
# You may obtain a copy of the License at
|
9
6
|
#
|
10
|
-
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
8
|
#
|
12
9
|
# Unless required by applicable law or agreed to in writing, software
|
13
10
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
11
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
12
|
# See the License for the specific language governing permissions and
|
16
13
|
# limitations under the License.
|
17
|
-
# ++
|
18
|
-
|
19
|
-
require 'socket'
|
20
|
-
require 'timeout'
|
21
|
-
require 'thread'
|
22
14
|
|
23
15
|
module Mongo
|
24
16
|
|
25
17
|
# A MongoDB database.
|
26
18
|
class DB
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
19
|
+
include Mongo::WriteConcern
|
20
|
+
|
21
|
+
SYSTEM_NAMESPACE_COLLECTION = 'system.namespaces'
|
22
|
+
SYSTEM_INDEX_COLLECTION = 'system.indexes'
|
23
|
+
SYSTEM_PROFILE_COLLECTION = 'system.profile'
|
24
|
+
SYSTEM_USER_COLLECTION = 'system.users'
|
25
|
+
SYSTEM_JS_COLLECTION = 'system.js'
|
26
|
+
SYSTEM_COMMAND_COLLECTION = '$cmd'
|
27
|
+
MAX_TIME_MS_CODE = 50
|
28
|
+
|
29
|
+
PROFILE_LEVEL = {
|
30
|
+
:off => 0,
|
31
|
+
:slow_only => 1,
|
32
|
+
:all => 2
|
33
|
+
}
|
34
34
|
|
35
35
|
# Counter for generating unique request ids.
|
36
36
|
@@current_request_id = 0
|
@@ -40,98 +40,137 @@ module Mongo
|
|
40
40
|
# collection that already exists, raises an error.
|
41
41
|
#
|
42
42
|
# Strict mode is disabled by default, but enabled (+true+) at any time.
|
43
|
-
|
43
|
+
#
|
44
|
+
# @deprecated Support for strict will be removed in version 2.0 of the driver.
|
45
|
+
def strict=(value)
|
46
|
+
unless ENV['TEST_MODE']
|
47
|
+
warn "Support for strict mode has been deprecated and will be " +
|
48
|
+
"removed in version 2.0 of the driver."
|
49
|
+
end
|
50
|
+
@strict = value
|
51
|
+
end
|
44
52
|
|
45
53
|
# Returns the value of the +strict+ flag.
|
46
|
-
|
54
|
+
#
|
55
|
+
# @deprecated Support for strict will be removed in version 2.0 of the driver.
|
56
|
+
def strict?
|
57
|
+
@strict
|
58
|
+
end
|
47
59
|
|
48
|
-
# The name of the database and the local
|
49
|
-
attr_reader :name, :
|
60
|
+
# The name of the database and the local write concern options.
|
61
|
+
attr_reader :name, :write_concern
|
50
62
|
|
51
|
-
# The Mongo::
|
52
|
-
attr_reader :
|
63
|
+
# The Mongo::MongoClient instance connecting to the MongoDB server.
|
64
|
+
attr_reader :client
|
65
|
+
|
66
|
+
# for backward compatibility
|
67
|
+
alias_method :connection, :client
|
53
68
|
|
54
69
|
# The length of time that Collection.ensure_index should cache index calls
|
55
70
|
attr_accessor :cache_time
|
56
71
|
|
72
|
+
# Read Preference
|
73
|
+
attr_accessor :read, :tag_sets, :acceptable_latency
|
74
|
+
|
57
75
|
# Instances of DB are normally obtained by calling Mongo#db.
|
58
76
|
#
|
59
77
|
# @param [String] name the database name.
|
60
|
-
# @param [Mongo::
|
61
|
-
# that databases are usually instantiated via the
|
78
|
+
# @param [Mongo::MongoClient] client a connection object pointing to MongoDB. Note
|
79
|
+
# that databases are usually instantiated via the MongoClient class. See the examples below.
|
62
80
|
#
|
63
|
-
# @option opts [Boolean] :strict (False) If true, collections
|
64
|
-
#
|
81
|
+
# @option opts [Boolean] :strict (False) [DEPRECATED] If true, collections existence checks are
|
82
|
+
# performed during a number of relevant operations. See DB#collection, DB#create_collection and
|
83
|
+
# DB#drop_collection.
|
65
84
|
#
|
66
|
-
# @option opts [Object, #create_pk(doc)] :pk (
|
85
|
+
# @option opts [Object, #create_pk(doc)] :pk (BSON::ObjectId) A primary key factory object,
|
67
86
|
# which should take a hash and return a hash which merges the original hash with any primary key
|
68
87
|
# fields the factory wishes to inject. (NOTE: if the object already has a primary key,
|
69
88
|
# the factory should not inject a new key).
|
70
89
|
#
|
71
|
-
# @option opts [
|
72
|
-
#
|
73
|
-
#
|
74
|
-
#
|
75
|
-
#
|
76
|
-
#
|
90
|
+
# @option opts [String, Integer, Symbol] :w (1) Set default number of nodes to which a write
|
91
|
+
# should be acknowledged.
|
92
|
+
# @option opts [Integer] :wtimeout (nil) Set replica set acknowledgement timeout.
|
93
|
+
# @option opts [Boolean] :j (false) If true, block until write operations have been committed
|
94
|
+
# to the journal. Cannot be used in combination with 'fsync'. Prior to MongoDB 2.6 this option was
|
95
|
+
# ignored if the server was running without journaling. Starting with MongoDB 2.6, write operations will
|
96
|
+
# fail with an exception if this option is used when the server is running without journaling.
|
97
|
+
# @option opts [Boolean] :fsync (false) If true, and the server is running without journaling, blocks until
|
98
|
+
# the server has synced all data files to disk. If the server is running with journaling, this acts the same as
|
99
|
+
# the 'j' option, blocking until write operations have been committed to the journal.
|
100
|
+
# Cannot be used in combination with 'j'.
|
101
|
+
#
|
102
|
+
# Notes on write concern:
|
103
|
+
# These write concern options are propagated to Collection objects instantiated off of this DB. If no
|
104
|
+
# options are provided, the default write concern set on this instance's MongoClient object will be used. This
|
105
|
+
# default can be overridden upon instantiation of any collection by explicitly setting write concern options
|
106
|
+
# on initialization or at the time of an operation.
|
77
107
|
#
|
78
|
-
# @
|
79
|
-
|
80
|
-
|
81
|
-
|
108
|
+
# @option opts [Integer] :cache_time (300) Set the time that all ensure_index calls should cache the command.
|
109
|
+
|
110
|
+
def initialize(name, client, opts={})
|
111
|
+
# A database name of '$external' is permitted for some auth types
|
112
|
+
Support.validate_db_name(name) unless name == '$external'
|
113
|
+
|
114
|
+
@name = name
|
115
|
+
@client = client
|
82
116
|
@strict = opts[:strict]
|
83
117
|
@pk_factory = opts[:pk]
|
84
|
-
|
118
|
+
|
119
|
+
@write_concern = get_write_concern(opts, client)
|
120
|
+
|
121
|
+
@read = opts[:read] || @client.read
|
122
|
+
ReadPreference::validate(@read)
|
123
|
+
|
124
|
+
@tag_sets = opts.fetch(:tag_sets, @client.tag_sets)
|
125
|
+
@acceptable_latency = opts.fetch(:acceptable_latency,
|
126
|
+
@client.acceptable_latency)
|
127
|
+
|
85
128
|
@cache_time = opts[:cache_time] || 300 #5 minutes.
|
86
129
|
end
|
87
130
|
|
88
|
-
# Authenticate with the given username and password.
|
89
|
-
#
|
90
|
-
#
|
91
|
-
# @param [String]
|
92
|
-
#
|
93
|
-
# @param [Boolean]
|
94
|
-
# Save this authentication to the
|
95
|
-
# will ensure that the authentication will
|
96
|
-
#
|
131
|
+
# Authenticate with the given username and password.
|
132
|
+
#
|
133
|
+
# @param username [String] The username.
|
134
|
+
# @param password [String] The user's password. This is not required for
|
135
|
+
# some authentication mechanisms.
|
136
|
+
# @param save_auth [Boolean]
|
137
|
+
# Save this authentication to the client object using
|
138
|
+
# MongoClient#add_auth. This will ensure that the authentication will
|
139
|
+
# be applied to all sockets and upon database reconnect.
|
140
|
+
# @param source [String] Database with user credentials. This should be
|
141
|
+
# used to authenticate against a database when the credentials exist
|
142
|
+
# elsewhere.
|
143
|
+
# @param mechanism [String] The authentication mechanism to be used.
|
144
|
+
# @param extra [Hash] A optional hash of extra options to be stored with
|
145
|
+
# the credential set.
|
146
|
+
#
|
147
|
+
# @note The ability to disable the save_auth option has been deprecated.
|
148
|
+
# With save_auth=false specified, driver authentication behavior during
|
149
|
+
# failovers and reconnections becomes unreliable. This option still
|
150
|
+
# exists for API compatibility, but it no longer has any effect if
|
151
|
+
# disabled and now always uses the default behavior (safe_auth=true).
|
152
|
+
#
|
153
|
+
# @raise [AuthenticationError] Raised if authentication fails.
|
154
|
+
# @return [Boolean] The result of the authentication operation.
|
155
|
+
def authenticate(username, password=nil, save_auth=nil, source=nil, mechanism=nil, extra=nil)
|
156
|
+
warn "[DEPRECATED] Disabling the 'save_auth' option no longer has " +
|
157
|
+
"any effect. Please see the API documentation for more details " +
|
158
|
+
"on this change." unless save_auth.nil?
|
159
|
+
@client.add_auth(self.name, username, password, source, mechanism, extra)
|
160
|
+
true
|
161
|
+
end
|
162
|
+
|
163
|
+
# Deauthorizes use for this database for this client connection. Also removes
|
164
|
+
# the saved authentication in the MongoClient class associated with this
|
165
|
+
# database.
|
97
166
|
#
|
98
167
|
# @return [Boolean]
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
# @core authenticate authenticate-instance_method
|
103
|
-
def authenticate(username, password, save_auth=true)
|
104
|
-
if @connection.pool_size > 1
|
105
|
-
if !save_auth
|
106
|
-
raise MongoArgumentError, "If using connection pooling, :save_auth must be set to true."
|
107
|
-
end
|
108
|
-
@connection.authenticate_pools
|
109
|
-
end
|
110
|
-
|
111
|
-
issue_authentication(username, password, save_auth)
|
112
|
-
end
|
113
|
-
|
114
|
-
def issue_authentication(username, password, save_auth=true, opts={})
|
115
|
-
doc = command({:getnonce => 1}, :check_response => false, :socket => opts[:socket])
|
116
|
-
raise MongoDBError, "Error retrieving nonce: #{doc}" unless ok?(doc)
|
117
|
-
nonce = doc['nonce']
|
118
|
-
|
119
|
-
auth = BSON::OrderedHash.new
|
120
|
-
auth['authenticate'] = 1
|
121
|
-
auth['user'] = username
|
122
|
-
auth['nonce'] = nonce
|
123
|
-
auth['key'] = Mongo::Support.auth_key(username, password, nonce)
|
124
|
-
if ok?(self.command(auth, :check_response => false, :socket => opts[:socket]))
|
125
|
-
if save_auth
|
126
|
-
@connection.add_auth(@name, username, password)
|
127
|
-
end
|
128
|
-
true
|
129
|
-
else
|
130
|
-
raise(Mongo::AuthenticationError, "Failed to authenticate user '#{username}' on db '#{self.name}'")
|
131
|
-
end
|
168
|
+
def logout(opts={})
|
169
|
+
@client.remove_auth(self.name)
|
170
|
+
true
|
132
171
|
end
|
133
172
|
|
134
|
-
# Adds a stored Javascript function to the database which can executed
|
173
|
+
# Adds a stored Javascript function to the database which can executed
|
135
174
|
# server-side in map_reduce, db.eval and $where clauses.
|
136
175
|
#
|
137
176
|
# @param [String] function_name
|
@@ -141,7 +180,7 @@ module Mongo
|
|
141
180
|
def add_stored_function(function_name, code)
|
142
181
|
self[SYSTEM_JS_COLLECTION].save(
|
143
182
|
{
|
144
|
-
"_id" => function_name,
|
183
|
+
"_id" => function_name,
|
145
184
|
:value => BSON::Code.new(code)
|
146
185
|
}
|
147
186
|
)
|
@@ -154,26 +193,50 @@ module Mongo
|
|
154
193
|
#
|
155
194
|
# @return [Boolean]
|
156
195
|
def remove_stored_function(function_name)
|
157
|
-
|
158
|
-
|
159
|
-
else
|
160
|
-
return false
|
161
|
-
end
|
196
|
+
return false unless self[SYSTEM_JS_COLLECTION].find_one({"_id" => function_name})
|
197
|
+
self[SYSTEM_JS_COLLECTION].remove({"_id" => function_name}, :w => 1)
|
162
198
|
end
|
163
199
|
|
164
200
|
# Adds a user to this database for use with authentication. If the user already
|
165
|
-
# exists in the system, the password
|
201
|
+
# exists in the system, the password and any additional fields provided in opts
|
202
|
+
# will be updated.
|
166
203
|
#
|
167
204
|
# @param [String] username
|
168
205
|
# @param [String] password
|
206
|
+
# @param [Boolean] read_only
|
207
|
+
# Create a read-only user.
|
208
|
+
#
|
209
|
+
# @param [Hash] opts
|
210
|
+
# Optional fields for the user document (e.g. +userSource+, or +roles+)
|
211
|
+
#
|
212
|
+
# See {http://docs.mongodb.org/manual/reference/privilege-documents}
|
213
|
+
# for more information.
|
214
|
+
#
|
215
|
+
# @note The use of the opts argument to provide or update additional fields
|
216
|
+
# on the user document requires MongoDB >= 2.4.0
|
169
217
|
#
|
170
218
|
# @return [Hash] an object representing the user.
|
171
|
-
def add_user(username, password)
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
219
|
+
def add_user(username, password=nil, read_only=false, opts={})
|
220
|
+
user_info = command(:usersInfo => username)
|
221
|
+
if user_info.key?('users') && !user_info['users'].empty?
|
222
|
+
create_or_update_user(:updateUser, username, password, read_only, opts)
|
223
|
+
else
|
224
|
+
create_or_update_user(:createUser, username, password, read_only, opts)
|
225
|
+
end
|
226
|
+
# MongoDB >= 2.5.3 requires the use of commands to manage users.
|
227
|
+
# "Command not found" error didn't return an error code (59) before
|
228
|
+
# MongoDB 2.4.7 so we assume that a nil error code means the usersInfo
|
229
|
+
# command doesn't exist and we should fall back to the legacy add user code.
|
230
|
+
rescue OperationFailure => ex
|
231
|
+
if Mongo::ErrorCode::COMMAND_NOT_FOUND_CODES.include?(ex.error_code)
|
232
|
+
legacy_add_user(username, password, read_only, opts)
|
233
|
+
elsif ex.error_code == Mongo::ErrorCode::UNAUTHORIZED
|
234
|
+
# In MongoDB > 2.7 the localhost exception was narrowed, and the usersInfo
|
235
|
+
# command is no longer allowed. In this case, add the first user.
|
236
|
+
create_or_update_user(:createUser, username, password, read_only, opts)
|
237
|
+
else
|
238
|
+
raise ex
|
239
|
+
end
|
177
240
|
end
|
178
241
|
|
179
242
|
# Remove the given user from this database. Returns false if the user
|
@@ -183,35 +246,12 @@ module Mongo
|
|
183
246
|
#
|
184
247
|
# @return [Boolean]
|
185
248
|
def remove_user(username)
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
# Deauthorizes use for this database for this connection. Also removes
|
194
|
-
# any saved authentication in the connection class associated with this
|
195
|
-
# database.
|
196
|
-
#
|
197
|
-
# @raise [MongoDBError] if logging out fails.
|
198
|
-
#
|
199
|
-
# @return [Boolean]
|
200
|
-
def logout(opts={})
|
201
|
-
if @connection.pool_size > 1
|
202
|
-
@connection.logout_pools(@name)
|
203
|
-
end
|
204
|
-
|
205
|
-
issue_logout(opts)
|
206
|
-
end
|
207
|
-
|
208
|
-
def issue_logout(opts={})
|
209
|
-
doc = command({:logout => 1}, :socket => opts[:socket])
|
210
|
-
if ok?(doc)
|
211
|
-
@connection.remove_auth(@name)
|
212
|
-
true
|
213
|
-
else
|
214
|
-
raise MongoDBError, "error logging out: #{doc.inspect}"
|
249
|
+
begin
|
250
|
+
command(:dropUser => username)
|
251
|
+
rescue OperationFailure => ex
|
252
|
+
raise ex unless Mongo::ErrorCode::COMMAND_NOT_FOUND_CODES.include?(ex.error_code)
|
253
|
+
response = self[SYSTEM_USER_COLLECTION].remove({:user => username}, :w => 1)
|
254
|
+
response.key?('n') && response['n'] > 0 ? response : false
|
215
255
|
end
|
216
256
|
end
|
217
257
|
|
@@ -219,9 +259,14 @@ module Mongo
|
|
219
259
|
#
|
220
260
|
# @return [Array]
|
221
261
|
def collection_names
|
222
|
-
|
223
|
-
|
224
|
-
|
262
|
+
if @client.wire_version_feature?(Mongo::MongoClient::MONGODB_3_0)
|
263
|
+
names = collections_info.collect { |doc| doc['name'] || '' }
|
264
|
+
names.delete_if do |name|
|
265
|
+
name.index('$')
|
266
|
+
end
|
267
|
+
else
|
268
|
+
legacy_collection_names
|
269
|
+
end
|
225
270
|
end
|
226
271
|
|
227
272
|
# Get an array of Collection instances, one for each collection in this database.
|
@@ -237,13 +282,33 @@ module Mongo
|
|
237
282
|
# a cursor which can be iterated over. For each collection, a hash
|
238
283
|
# will be yielded containing a 'name' string and, optionally, an 'options' hash.
|
239
284
|
#
|
240
|
-
# @param [String] coll_name return info for the
|
285
|
+
# @param [String] coll_name return info for the specified collection only.
|
241
286
|
#
|
242
|
-
# @return [
|
287
|
+
# @return [Array] List of collection info.
|
243
288
|
def collections_info(coll_name=nil)
|
244
|
-
|
245
|
-
|
246
|
-
|
289
|
+
if @client.wire_version_feature?(Mongo::MongoClient::MONGODB_3_0)
|
290
|
+
cmd = BSON::OrderedHash[:listCollections, 1]
|
291
|
+
cmd.merge!(:filter => { :name => coll_name }) if coll_name
|
292
|
+
result = self.command(cmd, :cursor => {})
|
293
|
+
if result.key?('cursor')
|
294
|
+
cursor_info = result['cursor']
|
295
|
+
pinned_pool = @client.pinned_pool
|
296
|
+
pinned_pool = pinned_pool[:pool] if pinned_pool.respond_to?(:keys)
|
297
|
+
|
298
|
+
seed = {
|
299
|
+
:cursor_id => cursor_info['id'],
|
300
|
+
:first_batch => cursor_info['firstBatch'],
|
301
|
+
:pool => pinned_pool,
|
302
|
+
:ns => cursor_info['ns']
|
303
|
+
}
|
304
|
+
|
305
|
+
Cursor.new(Collection.new('$cmd', self), seed).to_a
|
306
|
+
else
|
307
|
+
result['collections']
|
308
|
+
end
|
309
|
+
else
|
310
|
+
legacy_collections_info(coll_name).to_a
|
311
|
+
end
|
247
312
|
end
|
248
313
|
|
249
314
|
# Create a collection.
|
@@ -251,52 +316,58 @@ module Mongo
|
|
251
316
|
# new collection. If +strict+ is true, will raise an error if
|
252
317
|
# collection +name+ already exists.
|
253
318
|
#
|
254
|
-
# @param [String] name the name of the new collection.
|
319
|
+
# @param [String, Symbol] name the name of the new collection.
|
255
320
|
#
|
256
321
|
# @option opts [Boolean] :capped (False) created a capped collection.
|
257
322
|
#
|
258
|
-
# @option opts [Integer] :size (Nil) If +capped+ is +true+,
|
259
|
-
#
|
323
|
+
# @option opts [Integer] :size (Nil) If +capped+ is +true+,
|
324
|
+
# specifies the maximum number of bytes for the capped collection.
|
325
|
+
# If +false+, specifies the number of bytes allocated
|
260
326
|
# for the initial extent of the collection.
|
261
327
|
#
|
262
|
-
# @option opts [Integer] :max (Nil) If +capped+ is +true+, indicates
|
263
|
-
# in a capped collection.
|
328
|
+
# @option opts [Integer] :max (Nil) If +capped+ is +true+, indicates
|
329
|
+
# the maximum number of records in a capped collection.
|
264
330
|
#
|
265
|
-
# @raise [MongoDBError] raised under two conditions:
|
331
|
+
# @raise [MongoDBError] raised under two conditions:
|
332
|
+
# either we're in +strict+ mode and the collection
|
266
333
|
# already exists or collection creation fails on the server.
|
267
334
|
#
|
335
|
+
# @note Note that the options listed may be subset of those available.
|
336
|
+
# Please see the MongoDB documentation for a full list of supported options by server version.
|
337
|
+
#
|
268
338
|
# @return [Mongo::Collection]
|
269
339
|
def create_collection(name, opts={})
|
270
|
-
|
271
|
-
if collection_names.include?(name)
|
272
|
-
|
273
|
-
raise MongoDBError, "Collection #{name} already exists. Currently in strict mode."
|
274
|
-
else
|
275
|
-
return Collection.new(name, self, opts)
|
276
|
-
end
|
340
|
+
name = name.to_s
|
341
|
+
if strict? && collection_names.include?(name)
|
342
|
+
raise MongoDBError, "Collection '#{name}' already exists. (strict=true)"
|
277
343
|
end
|
278
344
|
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
345
|
+
begin
|
346
|
+
cmd = BSON::OrderedHash.new
|
347
|
+
cmd[:create] = name
|
348
|
+
doc = command(cmd.merge(opts || {}))
|
349
|
+
return Collection.new(name, self, :pk => @pk_factory) if ok?(doc)
|
350
|
+
rescue OperationFailure => e
|
351
|
+
return Collection.new(name, self, :pk => @pk_factory) if e.message =~ /exists/
|
352
|
+
raise e
|
353
|
+
end
|
284
354
|
raise MongoDBError, "Error creating collection: #{doc.inspect}"
|
285
355
|
end
|
286
356
|
|
287
357
|
# Get a collection by name.
|
288
358
|
#
|
289
|
-
# @param [String] name the collection name.
|
359
|
+
# @param [String, Symbol] name the collection name.
|
290
360
|
# @param [Hash] opts any valid options that can be passed to Collection#new.
|
291
361
|
#
|
292
|
-
# @raise [MongoDBError] if collection does not already exist and we're in
|
362
|
+
# @raise [MongoDBError] if collection does not already exist and we're in
|
363
|
+
# +strict+ mode.
|
293
364
|
#
|
294
365
|
# @return [Mongo::Collection]
|
295
366
|
def collection(name, opts={})
|
296
|
-
if strict? && !collection_names.include?(name)
|
297
|
-
raise
|
367
|
+
if strict? && !collection_names.include?(name.to_s)
|
368
|
+
raise MongoDBError, "Collection '#{name}' doesn't exist. (strict=true)"
|
298
369
|
else
|
299
|
-
opts
|
370
|
+
opts = opts.dup
|
300
371
|
opts.merge!(:pk => @pk_factory) unless opts[:pk]
|
301
372
|
Collection.new(name, self, opts)
|
302
373
|
end
|
@@ -305,13 +376,16 @@ module Mongo
|
|
305
376
|
|
306
377
|
# Drop a collection by +name+.
|
307
378
|
#
|
308
|
-
# @param [String] name
|
379
|
+
# @param [String, Symbol] name
|
309
380
|
#
|
310
381
|
# @return [Boolean] +true+ on success or +false+ if the collection name doesn't exist.
|
311
382
|
def drop_collection(name)
|
312
|
-
return
|
313
|
-
|
314
|
-
|
383
|
+
return false if strict? && !collection_names.include?(name.to_s)
|
384
|
+
begin
|
385
|
+
ok?(command(:drop => name))
|
386
|
+
rescue OperationFailure
|
387
|
+
false
|
388
|
+
end
|
315
389
|
end
|
316
390
|
|
317
391
|
# Run the getlasterror command with the specified replication options.
|
@@ -319,6 +393,7 @@ module Mongo
|
|
319
393
|
# @option opts [Boolean] :fsync (false)
|
320
394
|
# @option opts [Integer] :w (nil)
|
321
395
|
# @option opts [Integer] :wtimeout (nil)
|
396
|
+
# @option opts [Boolean] :j (false)
|
322
397
|
#
|
323
398
|
# @return [Hash] the entire response to getlasterror.
|
324
399
|
#
|
@@ -328,7 +403,7 @@ module Mongo
|
|
328
403
|
cmd[:getlasterror] = 1
|
329
404
|
cmd.merge!(opts)
|
330
405
|
doc = command(cmd, :check_response => false)
|
331
|
-
raise MongoDBError, "
|
406
|
+
raise MongoDBError, "Error retrieving last error: #{doc.inspect}" unless ok?(doc)
|
332
407
|
doc
|
333
408
|
end
|
334
409
|
|
@@ -340,19 +415,15 @@ module Mongo
|
|
340
415
|
get_last_error['err'] != nil
|
341
416
|
end
|
342
417
|
|
343
|
-
# Get the most recent error to have
|
418
|
+
# Get the most recent error to have occurred on this database.
|
344
419
|
#
|
345
|
-
# This command only returns errors that have
|
420
|
+
# This command only returns errors that have occurred since the last call to
|
346
421
|
# DB#reset_error_history - returns +nil+ if there is no such error.
|
347
422
|
#
|
348
423
|
# @return [String, Nil] the text of the error or +nil+ if no error has occurred.
|
349
424
|
def previous_error
|
350
425
|
error = command(:getpreverror => 1)
|
351
|
-
|
352
|
-
error
|
353
|
-
else
|
354
|
-
nil
|
355
|
-
end
|
426
|
+
error["err"] ? error : nil
|
356
427
|
end
|
357
428
|
|
358
429
|
# Reset the error history of this database
|
@@ -379,19 +450,22 @@ module Mongo
|
|
379
450
|
# Evaluate a JavaScript expression in MongoDB.
|
380
451
|
#
|
381
452
|
# @param [String, Code] code a JavaScript expression to evaluate server-side.
|
382
|
-
# @param [Integer, Hash] args any additional argument to be passed to the +code+ expression when
|
453
|
+
# @param [Integer, Hash] args any additional argument to be passed to the +code+ expression when
|
383
454
|
# it's run on the server.
|
384
455
|
#
|
456
|
+
# @note the eval command is deprecated in MongoDB 3.0 and will be removed in a future server version.
|
457
|
+
#
|
385
458
|
# @return [String] the return value of the function.
|
386
459
|
def eval(code, *args)
|
387
|
-
|
460
|
+
unless code.is_a?(BSON::Code)
|
388
461
|
code = BSON::Code.new(code)
|
389
462
|
end
|
390
463
|
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
464
|
+
cmd = BSON::OrderedHash.new
|
465
|
+
cmd[:$eval] = code
|
466
|
+
cmd.merge!(args.pop) if args.last.respond_to?(:keys) && args.last.key?(:nolock)
|
467
|
+
cmd[:args] = args
|
468
|
+
doc = command(cmd)
|
395
469
|
doc['retval']
|
396
470
|
end
|
397
471
|
|
@@ -404,10 +478,10 @@ module Mongo
|
|
404
478
|
#
|
405
479
|
# @raise MongoDBError if there's an error renaming the collection.
|
406
480
|
def rename_collection(from, to)
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
doc = DB.new('admin', @
|
481
|
+
cmd = BSON::OrderedHash.new
|
482
|
+
cmd[:renameCollection] = "#{@name}.#{from}"
|
483
|
+
cmd[:to] = "#{@name}.#{to}"
|
484
|
+
doc = DB.new('admin', @client).command(cmd, :check_response => false)
|
411
485
|
ok?(doc) || raise(MongoDBError, "Error renaming collection: #{doc.inspect}")
|
412
486
|
end
|
413
487
|
|
@@ -419,12 +493,12 @@ module Mongo
|
|
419
493
|
#
|
420
494
|
# @return [True] returns +true+ on success.
|
421
495
|
#
|
422
|
-
# @raise MongoDBError if there's an error
|
496
|
+
# @raise MongoDBError if there's an error dropping the index.
|
423
497
|
def drop_index(collection_name, index_name)
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
doc = command(
|
498
|
+
cmd = BSON::OrderedHash.new
|
499
|
+
cmd[:deleteIndexes] = collection_name
|
500
|
+
cmd[:index] = index_name.to_s
|
501
|
+
doc = command(cmd, :check_response => false)
|
428
502
|
ok?(doc) || raise(MongoDBError, "Error with drop_index command: #{doc.inspect}")
|
429
503
|
end
|
430
504
|
|
@@ -433,22 +507,40 @@ module Mongo
|
|
433
507
|
#
|
434
508
|
# @param [String] collection_name
|
435
509
|
#
|
436
|
-
# @return [Hash] keys are index names and the values are lists of [key,
|
510
|
+
# @return [Hash] keys are index names and the values are lists of [key, type] pairs
|
437
511
|
# defining the index.
|
438
512
|
def index_information(collection_name)
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
513
|
+
if @client.wire_version_feature?(Mongo::MongoClient::MONGODB_3_0)
|
514
|
+
result = self.command({ :listIndexes => collection_name }, :cursor => {})
|
515
|
+
if result.key?('cursor')
|
516
|
+
cursor_info = result['cursor']
|
517
|
+
pinned_pool = @client.pinned_pool
|
518
|
+
pinned_pool = pinned_pool[:pool] if pinned_pool.respond_to?(:keys)
|
519
|
+
|
520
|
+
seed = {
|
521
|
+
:cursor_id => cursor_info['id'],
|
522
|
+
:first_batch => cursor_info['firstBatch'],
|
523
|
+
:pool => pinned_pool,
|
524
|
+
:ns => cursor_info['ns']
|
525
|
+
}
|
526
|
+
|
527
|
+
indexes = Cursor.new(Collection.new('$cmd', self), seed).to_a
|
528
|
+
else
|
529
|
+
indexes = result['indexes']
|
530
|
+
end
|
531
|
+
else
|
532
|
+
indexes = legacy_list_indexes(collection_name)
|
533
|
+
end
|
534
|
+
indexes.reduce({}) do |info, index|
|
535
|
+
info.merge!(index['name'] => index)
|
443
536
|
end
|
444
|
-
info
|
445
537
|
end
|
446
538
|
|
447
539
|
# Return stats on this database. Uses MongoDB's dbstats command.
|
448
540
|
#
|
449
541
|
# @return [Hash]
|
450
542
|
def stats
|
451
|
-
self.command(
|
543
|
+
self.command(:dbstats => 1)
|
452
544
|
end
|
453
545
|
|
454
546
|
# Return +true+ if the supplied +doc+ contains an 'ok' field with the value 1.
|
@@ -470,38 +562,75 @@ module Mongo
|
|
470
562
|
# to see how it works.
|
471
563
|
#
|
472
564
|
# @param [OrderedHash, Hash] selector an OrderedHash, or a standard Hash with just one
|
473
|
-
# key, specifying the command to be performed. In Ruby 1.9, OrderedHash isn't necessary
|
474
|
-
# hashes are ordered by default.
|
565
|
+
# key, specifying the command to be performed. In Ruby 1.9 and above, OrderedHash isn't necessary
|
566
|
+
# because hashes are ordered by default.
|
475
567
|
#
|
476
568
|
# @option opts [Boolean] :check_response (true) If +true+, raises an exception if the
|
477
|
-
#
|
569
|
+
# command fails.
|
478
570
|
# @option opts [Socket] :socket a socket to use for sending the command. This is mainly for internal use.
|
571
|
+
# @option opts [:primary, :secondary] :read Read preference for this command. See Collection#find for
|
572
|
+
# more details.
|
573
|
+
# @option opts [String] :comment (nil) a comment to include in profiling logs
|
574
|
+
# @option opts [Boolean] :compile_regex (true) whether BSON regex objects should be compiled into Ruby regexes.
|
575
|
+
# If false, a BSON::Regex object will be returned instead.
|
479
576
|
#
|
480
577
|
# @return [Hash]
|
481
|
-
#
|
482
|
-
# @core commands command_instance-method
|
483
578
|
def command(selector, opts={})
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
579
|
+
raise MongoArgumentError, "Command must be given a selector" unless selector.respond_to?(:keys) && !selector.empty?
|
580
|
+
|
581
|
+
opts = opts.dup
|
582
|
+
# deletes :check_response and returns the value, if nil defaults to the block result
|
583
|
+
check_response = opts.delete(:check_response) { true }
|
584
|
+
|
585
|
+
# build up the command hash
|
586
|
+
command = opts.key?(:socket) ? { :socket => opts.delete(:socket) } : {}
|
587
|
+
command.merge!(:comment => opts.delete(:comment)) if opts.key?(:comment)
|
588
|
+
command.merge!(:compile_regex => opts.delete(:compile_regex)) if opts.key?(:compile_regex)
|
589
|
+
command[:limit] = -1
|
590
|
+
command[:read] = Mongo::ReadPreference::cmd_read_pref(opts.delete(:read), selector) if opts.key?(:read)
|
591
|
+
|
592
|
+
if RUBY_VERSION < '1.9' && selector.class != BSON::OrderedHash
|
593
|
+
if selector.keys.length > 1
|
594
|
+
raise MongoArgumentError, "DB#command requires an OrderedHash when hash contains multiple keys"
|
595
|
+
end
|
596
|
+
if opts.keys.size > 0
|
597
|
+
# extra opts will be merged into the selector, so make sure it's an OH in versions < 1.9
|
598
|
+
selector = selector.dup
|
599
|
+
selector = BSON::OrderedHash.new.merge!(selector)
|
600
|
+
end
|
489
601
|
end
|
490
602
|
|
603
|
+
# arbitrary opts are merged into the selector
|
604
|
+
command[:selector] = selector.merge!(opts)
|
605
|
+
|
491
606
|
begin
|
492
|
-
result = Cursor.new(system_command_collection,
|
493
|
-
:limit => -1, :selector => selector, :socket => socket).next_document
|
607
|
+
result = Cursor.new(system_command_collection, command).next_document
|
494
608
|
rescue OperationFailure => ex
|
495
|
-
|
609
|
+
if check_response
|
610
|
+
raise ex.class.new("Database command '#{selector.keys.first}' failed: #{ex.message}", ex.error_code, ex.result)
|
611
|
+
else
|
612
|
+
result = ex.result
|
613
|
+
end
|
496
614
|
end
|
497
615
|
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
result
|
616
|
+
raise OperationFailure,
|
617
|
+
"Database command '#{selector.keys.first}' failed: returned null." unless result
|
618
|
+
|
619
|
+
if check_response && (!ok?(result) || result['writeErrors'] || result['writeConcernError'])
|
620
|
+
message = "Database command '#{selector.keys.first}' failed: ("
|
621
|
+
message << result.map do |key, value|
|
622
|
+
"#{key}: '#{value}'"
|
623
|
+
end.join('; ')
|
624
|
+
message << ').'
|
625
|
+
code = result['code'] || result['assertionCode']
|
626
|
+
if result['writeErrors']
|
627
|
+
code = result['writeErrors'].first['code']
|
628
|
+
end
|
629
|
+
raise ExecutionTimeout.new(message, code, result) if code == MAX_TIME_MS_CODE
|
630
|
+
raise OperationFailure.new(message, code, result)
|
504
631
|
end
|
632
|
+
|
633
|
+
result
|
505
634
|
end
|
506
635
|
|
507
636
|
# A shortcut returning db plus dot plus collection name.
|
@@ -524,9 +653,8 @@ module Mongo
|
|
524
653
|
#
|
525
654
|
# @raise [MongoArgumentError] if the primary key factory has already been set.
|
526
655
|
def pk_factory=(pk_factory)
|
527
|
-
|
528
|
-
|
529
|
-
end
|
656
|
+
raise MongoArgumentError,
|
657
|
+
"Cannot change primary key factory once it's been set" if @pk_factory
|
530
658
|
|
531
659
|
@pk_factory = pk_factory
|
532
660
|
end
|
@@ -535,23 +663,16 @@ module Mongo
|
|
535
663
|
# get the results using DB#profiling_info.
|
536
664
|
#
|
537
665
|
# @return [Symbol] :off, :slow_only, or :all
|
538
|
-
#
|
539
|
-
# @core profiling profiling_level-instance_method
|
540
666
|
def profiling_level
|
541
|
-
|
542
|
-
|
543
|
-
doc = command(
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
when 2
|
551
|
-
:all
|
552
|
-
else
|
553
|
-
raise "Error: illegal profiling level value #{doc['was']}"
|
554
|
-
end
|
667
|
+
cmd = BSON::OrderedHash.new
|
668
|
+
cmd[:profile] = -1
|
669
|
+
doc = command(cmd, :check_response => false)
|
670
|
+
|
671
|
+
raise "Error with profile command: #{doc.inspect}" unless ok?(doc)
|
672
|
+
|
673
|
+
level_sym = PROFILE_LEVEL.invert[doc['was'].to_i]
|
674
|
+
raise "Error: illegal profiling level value #{doc['was']}" unless level_sym
|
675
|
+
level_sym
|
555
676
|
end
|
556
677
|
|
557
678
|
# Set this database's profiling level. If profiling is enabled, you can
|
@@ -559,18 +680,9 @@ module Mongo
|
|
559
680
|
#
|
560
681
|
# @param [Symbol] level acceptable options are +:off+, +:slow_only+, or +:all+.
|
561
682
|
def profiling_level=(level)
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
0
|
566
|
-
when :slow_only
|
567
|
-
1
|
568
|
-
when :all
|
569
|
-
2
|
570
|
-
else
|
571
|
-
raise "Error: illegal profiling level value #{level}"
|
572
|
-
end
|
573
|
-
doc = command(oh, :check_response => false)
|
683
|
+
cmd = BSON::OrderedHash.new
|
684
|
+
cmd[:profile] = PROFILE_LEVEL[level]
|
685
|
+
doc = command(cmd, :check_response => false)
|
574
686
|
ok?(doc) || raise(MongoDBError, "Error with profile command: #{doc.inspect}")
|
575
687
|
end
|
576
688
|
|
@@ -590,11 +702,16 @@ module Mongo
|
|
590
702
|
# @raise [MongoDBError] if the command fails or there's a problem with the validation
|
591
703
|
# data, or if the collection is invalid.
|
592
704
|
def validate_collection(name)
|
593
|
-
|
705
|
+
cmd = BSON::OrderedHash.new
|
706
|
+
cmd[:validate] = name
|
707
|
+
cmd[:full] = true
|
708
|
+
doc = command(cmd, :check_response => false)
|
709
|
+
|
594
710
|
raise MongoDBError, "Error with validate command: #{doc.inspect}" unless ok?(doc)
|
595
|
-
|
596
|
-
|
597
|
-
|
711
|
+
|
712
|
+
if (doc.has_key?('valid') && !doc['valid']) || (doc['result'] =~ /\b(exception|corrupt)\b/i)
|
713
|
+
raise MongoDBError, "Error: invalid collection #{name}: #{doc.inspect}"
|
714
|
+
end
|
598
715
|
doc
|
599
716
|
end
|
600
717
|
|
@@ -603,5 +720,89 @@ module Mongo
|
|
603
720
|
def system_command_collection
|
604
721
|
Collection.new(SYSTEM_COMMAND_COLLECTION, self)
|
605
722
|
end
|
723
|
+
|
724
|
+
# Create a new user.
|
725
|
+
#
|
726
|
+
# @param username [String] The username.
|
727
|
+
# @param password [String] The user's password.
|
728
|
+
# @param read_only [Boolean] Create a read-only user (deprecated in MongoDB >= 2.6)
|
729
|
+
# @param opts [Hash]
|
730
|
+
#
|
731
|
+
# @private
|
732
|
+
def create_or_update_user(command, username, password, read_only, opts)
|
733
|
+
if read_only || !opts.key?(:roles)
|
734
|
+
warn "Creating a user with the read_only option or without roles is " +
|
735
|
+
"deprecated in MongoDB >= 2.6"
|
736
|
+
end
|
737
|
+
|
738
|
+
# The password is always salted and hashed by the driver.
|
739
|
+
if opts.key?(:digestPassword)
|
740
|
+
raise MongoArgumentError,
|
741
|
+
"The digestPassword option is not available via DB#add_user. " +
|
742
|
+
"Use DB#command(:createUser => ...) instead for this option."
|
743
|
+
end
|
744
|
+
|
745
|
+
opts = opts.dup
|
746
|
+
pwd = Mongo::Authentication.hash_password(username, password) if password
|
747
|
+
cmd_opts = pwd ? { :pwd => pwd } : {}
|
748
|
+
# specify that the server shouldn't digest the password because the driver does
|
749
|
+
cmd_opts[:digestPassword] = false
|
750
|
+
unless opts.key?(:roles)
|
751
|
+
if name == 'admin'
|
752
|
+
roles = read_only ? ['readAnyDatabase'] : ['root']
|
753
|
+
else
|
754
|
+
roles = read_only ? ['read'] : ["dbOwner"]
|
755
|
+
end
|
756
|
+
cmd_opts[:roles] = roles
|
757
|
+
end
|
758
|
+
cmd_opts[:writeConcern] =
|
759
|
+
opts.key?(:writeConcern) ? opts.delete(:writeConcern) : { :w => 1 }
|
760
|
+
cmd_opts.merge!(opts)
|
761
|
+
command({ command => username }, cmd_opts)
|
762
|
+
end
|
763
|
+
|
764
|
+
# Create a user in MongoDB versions < 2.5.3.
|
765
|
+
# Called by #add_user if the 'usersInfo' command fails.
|
766
|
+
#
|
767
|
+
# @param username [String] The username.
|
768
|
+
# @param password [String] (nil) The user's password.
|
769
|
+
# @param read_only [Boolean] (false) Create a read-only user.
|
770
|
+
# @param opts [Hash]
|
771
|
+
#
|
772
|
+
# @private
|
773
|
+
def legacy_add_user(username, password=nil, read_only=false, opts={})
|
774
|
+
users = self[SYSTEM_USER_COLLECTION]
|
775
|
+
user = users.find_one(:user => username) || {:user => username}
|
776
|
+
user['pwd'] =
|
777
|
+
Mongo::Authentication.hash_password(username, password) if password
|
778
|
+
user['readOnly'] = true if read_only
|
779
|
+
user.merge!(opts)
|
780
|
+
begin
|
781
|
+
users.save(user)
|
782
|
+
rescue OperationFailure => ex
|
783
|
+
# adding first admin user fails GLE in MongoDB 2.2
|
784
|
+
raise ex unless ex.message =~ /login/
|
785
|
+
end
|
786
|
+
user
|
787
|
+
end
|
788
|
+
|
789
|
+
def legacy_list_indexes(collection_name)
|
790
|
+
sel = {:ns => full_collection_name(collection_name)}
|
791
|
+
Cursor.new(Collection.new(SYSTEM_INDEX_COLLECTION, self), :selector => sel)
|
792
|
+
end
|
793
|
+
|
794
|
+
def legacy_collections_info(coll_name=nil)
|
795
|
+
selector = {}
|
796
|
+
selector[:name] = full_collection_name(coll_name) if coll_name
|
797
|
+
Cursor.new(Collection.new(SYSTEM_NAMESPACE_COLLECTION, self), :selector => selector)
|
798
|
+
end
|
799
|
+
|
800
|
+
def legacy_collection_names
|
801
|
+
names = legacy_collections_info.collect { |doc| doc['name'] || '' }
|
802
|
+
names = names.delete_if do |name|
|
803
|
+
name.index(@name).nil? || name.index('$')
|
804
|
+
end
|
805
|
+
names.map {|name| name.sub(@name + '.', '')}
|
806
|
+
end
|
606
807
|
end
|
607
808
|
end
|