mongo-lyon 1.2.4
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.
- data/LICENSE.txt +190 -0
- data/README.md +344 -0
- data/Rakefile +202 -0
- data/bin/mongo_console +34 -0
- data/docs/1.0_UPGRADE.md +21 -0
- data/docs/CREDITS.md +123 -0
- data/docs/FAQ.md +116 -0
- data/docs/GridFS.md +158 -0
- data/docs/HISTORY.md +225 -0
- data/docs/REPLICA_SETS.md +72 -0
- data/docs/TUTORIAL.md +247 -0
- data/docs/WRITE_CONCERN.md +28 -0
- data/lib/mongo.rb +77 -0
- data/lib/mongo/collection.rb +872 -0
- data/lib/mongo/connection.rb +875 -0
- data/lib/mongo/cursor.rb +449 -0
- data/lib/mongo/db.rb +607 -0
- data/lib/mongo/exceptions.rb +68 -0
- data/lib/mongo/gridfs/grid.rb +106 -0
- data/lib/mongo/gridfs/grid_ext.rb +57 -0
- data/lib/mongo/gridfs/grid_file_system.rb +145 -0
- data/lib/mongo/gridfs/grid_io.rb +394 -0
- data/lib/mongo/gridfs/grid_io_fix.rb +38 -0
- data/lib/mongo/repl_set_connection.rb +342 -0
- data/lib/mongo/util/conversions.rb +89 -0
- data/lib/mongo/util/core_ext.rb +60 -0
- data/lib/mongo/util/pool.rb +185 -0
- data/lib/mongo/util/server_version.rb +71 -0
- data/lib/mongo/util/support.rb +82 -0
- data/lib/mongo/util/uri_parser.rb +181 -0
- data/lib/mongo/version.rb +3 -0
- data/mongo.gemspec +34 -0
- data/test/auxillary/1.4_features.rb +166 -0
- data/test/auxillary/authentication_test.rb +68 -0
- data/test/auxillary/autoreconnect_test.rb +41 -0
- data/test/auxillary/repl_set_auth_test.rb +58 -0
- data/test/auxillary/slave_connection_test.rb +36 -0
- data/test/auxillary/threaded_authentication_test.rb +101 -0
- data/test/bson/binary_test.rb +15 -0
- data/test/bson/bson_test.rb +614 -0
- data/test/bson/byte_buffer_test.rb +190 -0
- data/test/bson/hash_with_indifferent_access_test.rb +38 -0
- data/test/bson/json_test.rb +17 -0
- data/test/bson/object_id_test.rb +154 -0
- data/test/bson/ordered_hash_test.rb +197 -0
- data/test/collection_test.rb +893 -0
- data/test/connection_test.rb +303 -0
- data/test/conversions_test.rb +120 -0
- data/test/cursor_fail_test.rb +75 -0
- data/test/cursor_message_test.rb +43 -0
- data/test/cursor_test.rb +457 -0
- data/test/db_api_test.rb +715 -0
- data/test/db_connection_test.rb +15 -0
- data/test/db_test.rb +287 -0
- data/test/grid_file_system_test.rb +244 -0
- data/test/grid_io_test.rb +120 -0
- data/test/grid_test.rb +200 -0
- data/test/load/thin/load.rb +24 -0
- data/test/load/unicorn/load.rb +23 -0
- data/test/replica_sets/connect_test.rb +86 -0
- data/test/replica_sets/connection_string_test.rb +32 -0
- data/test/replica_sets/count_test.rb +35 -0
- data/test/replica_sets/insert_test.rb +53 -0
- data/test/replica_sets/pooled_insert_test.rb +55 -0
- data/test/replica_sets/query_secondaries.rb +96 -0
- data/test/replica_sets/query_test.rb +51 -0
- data/test/replica_sets/replication_ack_test.rb +66 -0
- data/test/replica_sets/rs_test_helper.rb +27 -0
- data/test/safe_test.rb +68 -0
- data/test/support/hash_with_indifferent_access.rb +199 -0
- data/test/support/keys.rb +45 -0
- data/test/support_test.rb +19 -0
- data/test/test_helper.rb +83 -0
- data/test/threading/threading_with_large_pool_test.rb +90 -0
- data/test/threading_test.rb +87 -0
- data/test/tools/auth_repl_set_manager.rb +14 -0
- data/test/tools/repl_set_manager.rb +266 -0
- data/test/unit/collection_test.rb +130 -0
- data/test/unit/connection_test.rb +98 -0
- data/test/unit/cursor_test.rb +99 -0
- data/test/unit/db_test.rb +96 -0
- data/test/unit/grid_test.rb +49 -0
- data/test/unit/pool_test.rb +9 -0
- data/test/unit/repl_set_connection_test.rb +72 -0
- data/test/unit/safe_test.rb +125 -0
- data/test/uri_test.rb +91 -0
- metadata +202 -0
@@ -0,0 +1,38 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
# --
|
4
|
+
# Copyright (C) 2008-2011 10gen Inc.
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
# ++
|
18
|
+
|
19
|
+
module Mongo
|
20
|
+
class GridIO
|
21
|
+
|
22
|
+
# This fixes a comparson issue in JRuby 1.9
|
23
|
+
def get_md5
|
24
|
+
md5_command = BSON::OrderedHash.new
|
25
|
+
md5_command['filemd5'] = @files_id
|
26
|
+
md5_command['root'] = @fs_name
|
27
|
+
@server_md5 = @files.db.command(md5_command)['md5']
|
28
|
+
if @safe
|
29
|
+
@client_md5 = @local_md5.hexdigest
|
30
|
+
if @local_md5.to_s != @server_md5.to_s
|
31
|
+
raise GridMD5Failure, "File on server failed MD5 check"
|
32
|
+
end
|
33
|
+
else
|
34
|
+
@server_md5
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,342 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
# --
|
4
|
+
# Copyright (C) 2008-2011 10gen Inc.
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
# ++
|
18
|
+
|
19
|
+
module Mongo
|
20
|
+
|
21
|
+
# Instantiates and manages connections to a MongoDB replica set.
|
22
|
+
class ReplSetConnection < Connection
|
23
|
+
attr_reader :nodes, :secondaries, :arbiters, :read_pool, :secondary_pools
|
24
|
+
|
25
|
+
# Create a connection to a MongoDB replica set.
|
26
|
+
#
|
27
|
+
# Once connected to a replica set, you can find out which nodes are primary, secondary, and
|
28
|
+
# arbiters with the corresponding accessors: Connection#primary, Connection#secondaries, and
|
29
|
+
# Connection#arbiters. This is useful if your application needs to connect manually to nodes other
|
30
|
+
# than the primary.
|
31
|
+
#
|
32
|
+
# @param [Array] args A list of host-port pairs to be used as seed nodes followed by a
|
33
|
+
# hash containing any options. See the examples below for exactly how to use the constructor.
|
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.
|
37
|
+
# @option options [Boolean, Hash] :safe (false) Set the default safe-mode options
|
38
|
+
# propogated to DB objects instantiated off of this Connection. This
|
39
|
+
# default can be overridden upon instantiation of any DB by explicity setting a :safe value
|
40
|
+
# on initialization.
|
41
|
+
# @option options [Boolean] :read_secondary(false) If true, a random secondary node will be chosen,
|
42
|
+
# and all reads will be directed to that node.
|
43
|
+
# @option options [Logger, #debug] :logger (nil) Logger instance to receive driver operation log.
|
44
|
+
# @option options [Integer] :pool_size (1) The maximum number of socket connections allowed per
|
45
|
+
# connection pool. Note: this setting is relevant only for multi-threaded applications.
|
46
|
+
# @option options [Float] :timeout (5.0) When all of the connections a pool are checked out,
|
47
|
+
# this is the number of seconds to wait for a new connection to be released before throwing an exception.
|
48
|
+
# Note: this setting is relevant only for multi-threaded applications.
|
49
|
+
#
|
50
|
+
# @example Connect to a replica set and provide two seed nodes. Note that the number of seed nodes does
|
51
|
+
# not have to be equal to the number of replica set members. The purpose of seed nodes is to permit
|
52
|
+
# the driver to find at least one replica set member even if a member is down.
|
53
|
+
# ReplSetConnection.new(['localhost', 30000], ['localhost', 30001])
|
54
|
+
#
|
55
|
+
# @example Connect to a replica set providing two seed nodes and ensuring a connection to the replica set named 'prod':
|
56
|
+
# ReplSetConnection.new(['localhost', 30000], ['localhost', 30001], :rs_name => 'prod')
|
57
|
+
#
|
58
|
+
# @example Connect to a replica set providing two seed nodes and allowing reads from a secondary node:
|
59
|
+
# ReplSetConnection.new(['localhost', 30000], ['localhost', 30001], :read_secondary => true)
|
60
|
+
#
|
61
|
+
# @see http://api.mongodb.org/ruby/current/file.REPLICA_SETS.html Replica sets in Ruby
|
62
|
+
#
|
63
|
+
# @raise [ReplicaSetConnectionError] This is raised if a replica set name is specified and the
|
64
|
+
# driver fails to connect to a replica set with that name.
|
65
|
+
def initialize(*args)
|
66
|
+
if args.last.is_a?(Hash)
|
67
|
+
opts = args.pop
|
68
|
+
else
|
69
|
+
opts = {}
|
70
|
+
end
|
71
|
+
|
72
|
+
unless args.length > 0
|
73
|
+
raise MongoArgumentError, "A ReplSetConnection requires at least one node."
|
74
|
+
end
|
75
|
+
|
76
|
+
# Get seed nodes
|
77
|
+
@nodes = args
|
78
|
+
|
79
|
+
# Replica set name
|
80
|
+
@replica_set = opts[:rs_name]
|
81
|
+
|
82
|
+
# Cache the various node types when connecting to a replica set.
|
83
|
+
@secondaries = []
|
84
|
+
@arbiters = []
|
85
|
+
|
86
|
+
# Connection pools for each secondary node
|
87
|
+
@secondary_pools = []
|
88
|
+
@read_pool = nil
|
89
|
+
|
90
|
+
# Are we allowing reads from secondaries?
|
91
|
+
@read_secondary = opts.fetch(:read_secondary, false)
|
92
|
+
|
93
|
+
setup(opts)
|
94
|
+
end
|
95
|
+
|
96
|
+
# Create a new socket and attempt to connect to master.
|
97
|
+
# If successful, sets host and port to master and returns the socket.
|
98
|
+
#
|
99
|
+
# If connecting to a replica set, this method will replace the
|
100
|
+
# initially-provided seed list with any nodes known to the set.
|
101
|
+
#
|
102
|
+
# @raise [ConnectionFailure] if unable to connect to any host or port.
|
103
|
+
def connect
|
104
|
+
reset_connection
|
105
|
+
@nodes_to_try = @nodes.clone
|
106
|
+
|
107
|
+
while connecting?
|
108
|
+
node = @nodes_to_try.shift
|
109
|
+
config = check_is_master(node)
|
110
|
+
|
111
|
+
if is_primary?(config)
|
112
|
+
set_primary(node)
|
113
|
+
else
|
114
|
+
set_auxillary(node, config)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
pick_secondary_for_read if @read_secondary
|
119
|
+
|
120
|
+
if connected?
|
121
|
+
BSON::BSON_CODER.update_max_bson_size(self)
|
122
|
+
else
|
123
|
+
if @secondary_pools.empty?
|
124
|
+
close # close any existing pools and sockets
|
125
|
+
raise ConnectionFailure, "Failed to connect any given host:port"
|
126
|
+
else
|
127
|
+
close # close any existing pools and sockets
|
128
|
+
raise ConnectionFailure, "Failed to connect to primary node."
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
alias :reconnect :connect
|
133
|
+
|
134
|
+
def connecting?
|
135
|
+
@nodes_to_try.length > 0
|
136
|
+
end
|
137
|
+
|
138
|
+
# Determine whether we're reading from a primary node. If false,
|
139
|
+
# this connection connects to a secondary node and @read_secondaries is true.
|
140
|
+
#
|
141
|
+
# @return [Boolean]
|
142
|
+
def read_primary?
|
143
|
+
!@read_pool
|
144
|
+
end
|
145
|
+
alias :primary? :read_primary?
|
146
|
+
|
147
|
+
# Close the connection to the database.
|
148
|
+
def close
|
149
|
+
super
|
150
|
+
@read_pool = nil
|
151
|
+
@secondary_pools.each do |pool|
|
152
|
+
pool.close
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
# If a ConnectionFailure is raised, this method will be called
|
157
|
+
# to close the connection and reset connection values.
|
158
|
+
# TODO: what's the point of this method?
|
159
|
+
def reset_connection
|
160
|
+
super
|
161
|
+
@secondaries = []
|
162
|
+
@secondary_pools = []
|
163
|
+
@arbiters = []
|
164
|
+
@nodes_tried = []
|
165
|
+
@nodes_to_try = []
|
166
|
+
end
|
167
|
+
|
168
|
+
# Is it okay to connect to a slave?
|
169
|
+
#
|
170
|
+
# @return [Boolean]
|
171
|
+
def slave_ok?
|
172
|
+
@read_secondary || @slave_ok
|
173
|
+
end
|
174
|
+
|
175
|
+
def authenticate_pools
|
176
|
+
super
|
177
|
+
@secondary_pools.each do |pool|
|
178
|
+
pool.authenticate_existing
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def logout_pools(db)
|
183
|
+
super
|
184
|
+
@secondary_pools.each do |pool|
|
185
|
+
pool.logout_existing(db)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
private
|
190
|
+
|
191
|
+
def check_is_master(node)
|
192
|
+
begin
|
193
|
+
if node[1]
|
194
|
+
host, port = *node
|
195
|
+
socket = TCPSocket.new(host, port)
|
196
|
+
socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
197
|
+
else
|
198
|
+
socket = UNIXSocket.new(node[0])
|
199
|
+
end
|
200
|
+
|
201
|
+
config = self['admin'].command({:ismaster => 1}, :socket => socket)
|
202
|
+
|
203
|
+
check_set_name(config, socket)
|
204
|
+
rescue OperationFailure, SocketError, SystemCallError, IOError => ex
|
205
|
+
# It's necessary to rescue here. The #connect method will keep trying
|
206
|
+
# until it has no more nodes to try and raise a ConnectionFailure if
|
207
|
+
# it can't connect to a primary.
|
208
|
+
ensure
|
209
|
+
socket.close if socket
|
210
|
+
@nodes_tried << node
|
211
|
+
|
212
|
+
if config
|
213
|
+
nodes = []
|
214
|
+
nodes += config['hosts'] if config['hosts']
|
215
|
+
nodes += config['arbiters'] if config['arbiters']
|
216
|
+
nodes += config['passives'] if config['passives']
|
217
|
+
update_node_list(nodes)
|
218
|
+
|
219
|
+
if config['msg'] && @logger
|
220
|
+
@logger.warn("MONGODB #{config['msg']}")
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
config
|
226
|
+
end
|
227
|
+
|
228
|
+
# Primary, when connecting to a replica can, can only be a true primary node.
|
229
|
+
# (And not a slave, which is possible when connecting with the standard
|
230
|
+
# Connection class.
|
231
|
+
def is_primary?(config)
|
232
|
+
config && (config['ismaster'] == 1 || config['ismaster'] == true)
|
233
|
+
end
|
234
|
+
|
235
|
+
# Pick a node randomly from the set of possible secondaries.
|
236
|
+
def pick_secondary_for_read
|
237
|
+
if (size = @secondary_pools.size) > 0
|
238
|
+
@read_pool = @secondary_pools[rand(size)]
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
# Make sure that we're connected to the expected replica set.
|
243
|
+
def check_set_name(config, socket)
|
244
|
+
if @replica_set
|
245
|
+
config = self['admin'].command({:replSetGetStatus => 1},
|
246
|
+
:socket => socket, :check_response => false)
|
247
|
+
|
248
|
+
if !Mongo::Support.ok?(config)
|
249
|
+
raise ReplicaSetConnectionError, config['errmsg']
|
250
|
+
elsif config['set'] != @replica_set
|
251
|
+
raise ReplicaSetConnectionError,
|
252
|
+
"Attempting to connect to replica set '#{config['set']}' but expected '#{@replica_set}'"
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
# Determines what kind of node we have and caches its host
|
258
|
+
# and port so that users can easily connect manually.
|
259
|
+
def set_auxillary(node, config)
|
260
|
+
if config
|
261
|
+
if config['secondary']
|
262
|
+
@secondaries << node unless @secondaries.include?(node)
|
263
|
+
if node[1]
|
264
|
+
host, port = *node
|
265
|
+
@secondary_pools << Pool.new(self, host, port, :size => @pool_size, :timeout => @timeout)
|
266
|
+
else
|
267
|
+
unix_socket_path = *node
|
268
|
+
@secondary_pools << Pool.new(self, unix_socket_path, nil, :size => @pool_size, :timeout => @timeout)
|
269
|
+
end
|
270
|
+
elsif config['arbiterOnly']
|
271
|
+
@arbiters << node unless @arbiters.include?(node)
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
# Update the list of known nodes. Only applies to replica sets,
|
277
|
+
# where the response to the ismaster command will return a list
|
278
|
+
# of known hosts.
|
279
|
+
#
|
280
|
+
# @param hosts [Array] a list of hosts, specified as string-encoded
|
281
|
+
# host-port values. Example: ["myserver-1.org:27017", "myserver-1.org:27017"]
|
282
|
+
#
|
283
|
+
# @return [Array] the updated list of nodes
|
284
|
+
def update_node_list(hosts)
|
285
|
+
new_nodes = hosts.map do |host|
|
286
|
+
if !host.respond_to?(:split)
|
287
|
+
warn "Could not parse host #{host.inspect}."
|
288
|
+
next
|
289
|
+
end
|
290
|
+
|
291
|
+
host, port = host.split(':')
|
292
|
+
unless port || File.exists?(host)
|
293
|
+
port = Connection::DEFAULT_PORT
|
294
|
+
end
|
295
|
+
if port
|
296
|
+
[host, port.to_i]
|
297
|
+
else
|
298
|
+
[host]
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
# Replace the list of seed nodes with the canonical list.
|
303
|
+
@nodes = new_nodes.clone
|
304
|
+
|
305
|
+
@nodes_to_try = new_nodes - @nodes_tried
|
306
|
+
end
|
307
|
+
|
308
|
+
# Checkout a socket for reading (i.e., a secondary node).
|
309
|
+
def checkout_reader
|
310
|
+
connect unless connected?
|
311
|
+
|
312
|
+
if @read_pool
|
313
|
+
@read_pool.checkout
|
314
|
+
else
|
315
|
+
checkout_writer
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
# Checkout a socket for writing (i.e., a primary node).
|
320
|
+
def checkout_writer
|
321
|
+
connect unless connected?
|
322
|
+
|
323
|
+
@primary_pool.checkout
|
324
|
+
end
|
325
|
+
|
326
|
+
# Checkin a socket used for reading.
|
327
|
+
def checkin_reader(socket)
|
328
|
+
if @read_pool
|
329
|
+
@read_pool.checkin(socket)
|
330
|
+
else
|
331
|
+
checkin_writer(socket)
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
# Checkin a socket used for writing.
|
336
|
+
def checkin_writer(socket)
|
337
|
+
if @primary_pool
|
338
|
+
@primary_pool.checkin(socket)
|
339
|
+
end
|
340
|
+
end
|
341
|
+
end
|
342
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
# --
|
4
|
+
# Copyright (C) 2008-2011 10gen Inc.
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
# ++
|
18
|
+
module Mongo #:nodoc:
|
19
|
+
|
20
|
+
# Utility module to include when needing to convert certain types of
|
21
|
+
# objects to mongo-friendly parameters.
|
22
|
+
module Conversions
|
23
|
+
|
24
|
+
ASCENDING_CONVERSION = ["ascending", "asc", "1"]
|
25
|
+
DESCENDING_CONVERSION = ["descending", "desc", "-1"]
|
26
|
+
|
27
|
+
# Converts the supplied +Array+ to a +Hash+ to pass to mongo as
|
28
|
+
# sorting parameters. The returned +Hash+ will vary depending
|
29
|
+
# on whether the passed +Array+ is one or two dimensional.
|
30
|
+
#
|
31
|
+
# Example:
|
32
|
+
#
|
33
|
+
# <tt>array_as_sort_parameters([["field1", :asc], ["field2", :desc]])</tt> =>
|
34
|
+
# <tt>{ "field1" => 1, "field2" => -1}</tt>
|
35
|
+
def array_as_sort_parameters(value)
|
36
|
+
order_by = BSON::OrderedHash.new
|
37
|
+
if value.first.is_a? Array
|
38
|
+
value.each do |param|
|
39
|
+
if (param.class.name == "String")
|
40
|
+
order_by[param] = 1
|
41
|
+
else
|
42
|
+
order_by[param[0]] = sort_value(param[1]) unless param[1].nil?
|
43
|
+
end
|
44
|
+
end
|
45
|
+
elsif !value.empty?
|
46
|
+
if order_by.size == 1
|
47
|
+
order_by[value.first] = 1
|
48
|
+
else
|
49
|
+
order_by[value.first] = sort_value(value[1])
|
50
|
+
end
|
51
|
+
end
|
52
|
+
order_by
|
53
|
+
end
|
54
|
+
|
55
|
+
# Converts the supplied +String+ or +Symbol+ to a +Hash+ to pass to mongo as
|
56
|
+
# a sorting parameter with ascending order. If the +String+
|
57
|
+
# is empty then an empty +Hash+ will be returned.
|
58
|
+
#
|
59
|
+
# Example:
|
60
|
+
#
|
61
|
+
# *DEPRECATED
|
62
|
+
#
|
63
|
+
# <tt>string_as_sort_parameters("field")</tt> => <tt>{ "field" => 1 }</tt>
|
64
|
+
# <tt>string_as_sort_parameters("")</tt> => <tt>{}</tt>
|
65
|
+
def string_as_sort_parameters(value)
|
66
|
+
return {} if (str = value.to_s).empty?
|
67
|
+
{ str => 1 }
|
68
|
+
end
|
69
|
+
|
70
|
+
# Converts the +String+, +Symbol+, or +Integer+ to the
|
71
|
+
# corresponding sort value in MongoDB.
|
72
|
+
#
|
73
|
+
# Valid conversions (case-insensitive):
|
74
|
+
#
|
75
|
+
# <tt>ascending, asc, :ascending, :asc, 1</tt> => <tt>1</tt>
|
76
|
+
# <tt>descending, desc, :descending, :desc, -1</tt> => <tt>-1</tt>
|
77
|
+
#
|
78
|
+
# If the value is invalid then an error will be raised.
|
79
|
+
def sort_value(value)
|
80
|
+
val = value.to_s.downcase
|
81
|
+
return 1 if ASCENDING_CONVERSION.include?(val)
|
82
|
+
return -1 if DESCENDING_CONVERSION.include?(val)
|
83
|
+
raise InvalidSortValueError.new(
|
84
|
+
"#{self} was supplied as a sort direction when acceptable values are: " +
|
85
|
+
"Mongo::ASCENDING, 'ascending', 'asc', :ascending, :asc, 1, Mongo::DESCENDING, " +
|
86
|
+
"'descending', 'desc', :descending, :desc, -1.")
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|