@@ -21,30 +21,23 @@ class View
2121 # @since 2.0.0
2222 module Readable
2323
24- # Special fields and their getters for the query selector.
24+ # Special fields and their option names for the query selector.
2525 #
2626 # @since 2.0.0
2727 SPECIAL_FIELDS = {
28- :$query => :selector ,
29- :$readPreference => :read_pref_formatted ,
30- :$orderby => :sort ,
31- :$hint => :hint ,
32- :$comment => :comment ,
33- :$snapshot => :snapshot ,
34- :$maxScan => :max_scan ,
35- :$max => :max_value ,
36- :$min => :min_value ,
37- :$maxTimeMS => :max_time_ms ,
38- :$returnKey => :return_key ,
39- :$showDiskLoc => :show_disk_loc ,
40- :$explain => :explained?
28+ :sort => :$orderby ,
29+ :hint => :$hint ,
30+ :comment => :$comment ,
31+ :snapshot => :$snapshot ,
32+ :max_scan => :$maxScan ,
33+ :max_value => :$max ,
34+ :min_value => :$min ,
35+ :max_time_ms => :$maxTimeMS ,
36+ :return_key => :$returnKey ,
37+ :show_disk_loc => :$showDiskLoc ,
38+ :explain => :$explain
4139 } . freeze
4240
43- # Get just the names of the special fields.
44- #
45- # @since 2.1.0
46- SPECIAL_FIELD_OPTION_NAMES = SPECIAL_FIELDS . values . freeze
47-
4841 # Options to cursor flags mapping.
4942 #
5043 # @since 2.1.0
@@ -99,7 +92,7 @@ def allow_partial_results
9992 #
10093 # @since 2.0.0
10194 def batch_size ( batch_size = nil )
102- configure ( :batch_size , batch_size )
95+ configure ( __method__ , batch_size )
10396 end
10497
10598 # Associate a comment with the query.
@@ -117,7 +110,7 @@ def batch_size(batch_size = nil)
117110 #
118111 # @since 2.0.0
119112 def comment ( comment = nil )
120- configure ( :comment , comment )
113+ configure_modifier ( __method__ , comment )
121114 end
122115
123116 # Get a count of matching documents in the collection.
@@ -181,7 +174,7 @@ def distinct(field_name, options={})
181174 #
182175 # @since 2.0.0
183176 def hint ( hint = nil )
184- configure ( :hint , hint )
177+ configure_modifier ( __method__ , hint )
185178 end
186179
187180 # The max number of docs to return from the query.
@@ -195,7 +188,7 @@ def hint(hint = nil)
195188 #
196189 # @since 2.0.0
197190 def limit ( limit = nil )
198- configure ( :limit , limit )
191+ configure ( __method__ , limit )
199192 end
200193
201194 # Execute a map/reduce operation on the collection view.
@@ -225,7 +218,7 @@ def map_reduce(map, reduce, options = {})
225218 #
226219 # @since 2.0.0
227220 def max_scan ( value = nil )
228- configure ( :max_scan , value )
221+ configure_modifier ( __method__ , value )
229222 end
230223
231224 # Set the maximum value to search.
@@ -239,7 +232,7 @@ def max_scan(value = nil)
239232 #
240233 # @since 2.1.0
241234 def max_value ( value = nil )
242- configure ( :max_value , value )
235+ configure_modifier ( __method__ , value )
243236 end
244237
245238 # Set the minimum value to search.
@@ -253,7 +246,7 @@ def max_value(value = nil)
253246 #
254247 # @since 2.1.0
255248 def min_value ( value = nil )
256- configure ( :min_value , value )
249+ configure_modifier ( __method__ , value )
257250 end
258251
259252 # The server normally times out idle cursors after an inactivity period
@@ -266,7 +259,7 @@ def min_value(value = nil)
266259 #
267260 # @since 2.0.0
268261 def no_cursor_timeout
269- configure_flag ( :no_cursor_timeout )
262+ configure_flag ( __method__ )
270263 end
271264
272265 # The fields to include or exclude from each doc in the result set.
@@ -285,7 +278,7 @@ def no_cursor_timeout
285278 # @since 2.0.0
286279 def projection ( document = nil )
287280 validate_doc! ( document ) if document
288- configure ( :projection , document )
281+ configure ( __method__ , document )
289282 end
290283
291284 # The read preference to use for the query.
@@ -301,7 +294,7 @@ def projection(document = nil)
301294 # @since 2.0.0
302295 def read ( value = nil )
303296 return default_read if value . nil?
304- configure ( :read , value . is_a? ( Hash ) ? ServerSelector . get ( value ) : value )
297+ configure ( __method__ , value . is_a? ( Hash ) ? ServerSelector . get ( value ) : value )
305298 end
306299
307300 # Set whether to return only the indexed field or fields.
@@ -315,7 +308,7 @@ def read(value = nil)
315308 #
316309 # @since 2.1.0
317310 def return_key ( value = nil )
318- configure ( :return_key , value )
311+ configure_modifier ( __method__ , value )
319312 end
320313
321314 # Set whether the disk location should be shown for each document.
@@ -330,7 +323,7 @@ def return_key(value = nil)
330323 #
331324 # @since 2.0.0
332325 def show_disk_loc ( value = nil )
333- configure ( :show_disk_loc , value )
326+ configure_modifier ( __method__ , value )
334327 end
335328
336329 # The number of docs to skip before returning results.
@@ -345,7 +338,7 @@ def show_disk_loc(value = nil)
345338 #
346339 # @since 2.0.0
347340 def skip ( number = nil )
348- configure ( :skip , number )
341+ configure ( __method__ , number )
349342 end
350343
351344 # Set the snapshot value for the view.
@@ -360,7 +353,7 @@ def skip(number = nil)
360353 #
361354 # @since 2.0.0
362355 def snapshot ( value = nil )
363- configure ( :snapshot , value )
356+ configure_modifier ( __method__ , value )
364357 end
365358
366359 # The key and direction pairs by which the result set will be sorted.
@@ -375,7 +368,7 @@ def snapshot(value = nil)
375368 #
376369 # @since 2.0.0
377370 def sort ( spec = nil )
378- configure ( :sort , spec )
371+ configure_modifier ( __method__ , spec )
379372 end
380373
381374 # “meta” operators that let you modify the output or behavior of a query.
@@ -389,7 +382,8 @@ def sort(spec = nil)
389382 #
390383 # @since 2.1.0
391384 def modifiers ( doc = nil )
392- configure ( :modifiers , doc )
385+ return @modifiers if doc . nil?
386+ new ( options . merge ( __method__ => doc ) )
393387 end
394388
395389 # A cumulative time limit in milliseconds for processing operations on a cursor.
@@ -403,7 +397,7 @@ def modifiers(doc = nil)
403397 #
404398 # @since 2.1.0
405399 def max_time_ms ( max = nil )
406- configure ( :max_time_ms , max )
400+ configure_modifier ( __method__ , max )
407401 end
408402
409403 private
@@ -421,10 +415,6 @@ def flags
421415 end
422416 end
423417
424- def has_special_fields?
425- contains_modifiers? || explained? || cluster . sharded?
426- end
427-
428418 def parallel_scan ( cursor_count )
429419 server = read . select_server ( cluster )
430420 Operation ::ParallelScan . new (
@@ -441,6 +431,27 @@ def parallel_scan(cursor_count)
441431 end
442432 end
443433
434+ def setup ( sel , opts )
435+ setup_options ( opts )
436+ setup_selector ( sel )
437+ end
438+
439+ def setup_options ( opts )
440+ @options = opts ? opts . dup : { }
441+ @modifiers = @options [ :modifiers ] ? @options . delete ( :modifiers ) . dup : BSON ::Document . new
442+ @options . keys . each { |k | @modifiers . merge! ( SPECIAL_FIELDS [ k ] => @options . delete ( k ) ) if SPECIAL_FIELDS [ k ] }
443+ @options . freeze
444+ end
445+
446+ def setup_selector ( sel )
447+ @selector = sel ? sel . dup : { }
448+ if @selector [ :$query ] || @selector [ '$query' ]
449+ @selector . keys . each { |k | @modifiers . merge! ( k => @selector . delete ( k ) ) if k [ 0 ] == '$' }
450+ end
451+ @modifiers . freeze
452+ @selector . freeze
453+ end
454+
444455 def query_options
445456 {
446457 :project => projection ,
@@ -451,8 +462,12 @@ def query_options
451462 }
452463 end
453464
465+ def requires_special_selector?
466+ !modifiers . empty? || cluster . sharded?
467+ end
468+
454469 def query_spec
455- sel = has_special_fields ? ? special_selector : selector
470+ sel = requires_special_selector ? ? special_selector : selector
456471 { :selector => sel ,
457472 :read => read ,
458473 :options => query_options ,
@@ -461,26 +476,18 @@ def query_spec
461476 end
462477
463478 def read_pref_formatted
464- read . to_mongos
479+ @read_formatted ||= read . to_mongos
465480 end
466481
467482 def special_selector
468- SPECIAL_FIELDS . reduce ( { } ) do |hash , ( key , method ) |
469- value = send ( method ) || ( options [ :modifiers ] && options [ :modifiers ] [ key ] )
470- hash [ key ] = value unless value . nil?
471- hash
472- end
483+ sel = BSON ::Document . new ( :$query => selector ) . merge! ( modifiers )
484+ sel [ :$readPreference ] = read_pref_formatted unless read_pref_formatted . nil?
485+ sel
473486 end
474487
475488 def validate_doc! ( doc )
476489 raise Error ::InvalidDocument . new unless doc . respond_to? ( :keys )
477490 end
478-
479- def contains_modifiers?
480- modifiers || options . keys . any? do |key |
481- SPECIAL_FIELD_OPTION_NAMES . include? ( key )
482- end
483- end
484491 end
485492 end
486493 end
0 commit comments