mongo 2.1.0.rc0 → 2.1.0

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.
Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +5 -2
  3. data.tar.gz.sig +0 -0
  4. data/Rakefile +2 -2
  5. data/lib/mongo.rb +2 -1
  6. data/lib/mongo/address.rb +11 -5
  7. data/lib/mongo/address/ipv4.rb +6 -1
  8. data/lib/mongo/auth/cr/conversation.rb +1 -1
  9. data/lib/mongo/auth/ldap/conversation.rb +1 -1
  10. data/lib/mongo/auth/scram/conversation.rb +1 -1
  11. data/lib/mongo/auth/user/view.rb +2 -2
  12. data/lib/mongo/auth/x509/conversation.rb +1 -1
  13. data/lib/mongo/bulk_write.rb +12 -9
  14. data/lib/mongo/bulk_write/transformable.rb +20 -5
  15. data/lib/mongo/client.rb +11 -11
  16. data/lib/mongo/cluster.rb +2 -2
  17. data/lib/mongo/collection.rb +21 -8
  18. data/lib/mongo/collection/view.rb +1 -0
  19. data/lib/mongo/collection/view/aggregation.rb +11 -5
  20. data/lib/mongo/collection/view/iterable.rb +6 -2
  21. data/lib/mongo/collection/view/map_reduce.rb +39 -5
  22. data/lib/mongo/collection/view/readable.rb +35 -30
  23. data/lib/mongo/collection/view/writable.rb +26 -18
  24. data/lib/mongo/database.rb +12 -2
  25. data/lib/mongo/database/view.rb +4 -3
  26. data/lib/mongo/dbref.rb +4 -4
  27. data/lib/mongo/grid/fs_bucket.rb +8 -1
  28. data/lib/mongo/grid/stream/read.rb +1 -1
  29. data/lib/mongo/index.rb +5 -0
  30. data/lib/mongo/index/view.rb +2 -2
  31. data/lib/mongo/monitoring/command_log_subscriber.rb +9 -3
  32. data/lib/mongo/monitoring/event.rb +1 -0
  33. data/lib/mongo/monitoring/event/command_started.rb +2 -1
  34. data/lib/mongo/monitoring/event/command_succeeded.rb +6 -3
  35. data/lib/mongo/monitoring/event/secure.rb +58 -0
  36. data/lib/mongo/operation.rb +31 -1
  37. data/lib/mongo/operation/commands/collections_info.rb +2 -0
  38. data/lib/mongo/operation/commands/collections_info/result.rb +39 -0
  39. data/lib/mongo/operation/commands/list_indexes/result.rb +2 -1
  40. data/lib/mongo/operation/commands/map_reduce/result.rb +1 -1
  41. data/lib/mongo/operation/read/query.rb +2 -0
  42. data/lib/mongo/operation/read/query/result.rb +40 -0
  43. data/lib/mongo/operation/result.rb +13 -1
  44. data/lib/mongo/operation/write/bulk/delete.rb +2 -2
  45. data/lib/mongo/operation/write/bulk/update.rb +3 -3
  46. data/lib/mongo/operation/write/delete.rb +2 -2
  47. data/lib/mongo/operation/write/update.rb +9 -4
  48. data/lib/mongo/options.rb +1 -0
  49. data/lib/mongo/options/redacted.rb +156 -0
  50. data/lib/mongo/protocol/insert.rb +25 -6
  51. data/lib/mongo/protocol/query.rb +45 -31
  52. data/lib/mongo/protocol/reply.rb +29 -6
  53. data/lib/mongo/protocol/serializers.rb +1 -1
  54. data/lib/mongo/retryable.rb +83 -0
  55. data/lib/mongo/server.rb +16 -3
  56. data/lib/mongo/server/connectable.rb +21 -3
  57. data/lib/mongo/server/connection.rb +38 -4
  58. data/lib/mongo/server/connection_pool.rb +12 -0
  59. data/lib/mongo/server/connection_pool/queue.rb +15 -0
  60. data/lib/mongo/server/monitor/connection.rb +2 -2
  61. data/lib/mongo/server_selector.rb +5 -0
  62. data/lib/mongo/server_selector/selectable.rb +16 -9
  63. data/lib/mongo/socket.rb +6 -2
  64. data/lib/mongo/uri.rb +1 -1
  65. data/lib/mongo/version.rb +1 -1
  66. data/spec/mongo/bulk_write/ordered_combiner_spec.rb +11 -11
  67. data/spec/mongo/bulk_write/unordered_combiner_spec.rb +10 -10
  68. data/spec/mongo/client_spec.rb +101 -18
  69. data/spec/mongo/collection_spec.rb +44 -0
  70. data/spec/mongo/connection_string_spec.rb +36 -58
  71. data/spec/mongo/database_spec.rb +20 -0
  72. data/spec/mongo/grid/fs_bucket_spec.rb +1 -1
  73. data/spec/mongo/grid/stream/write_spec.rb +2 -2
  74. data/spec/mongo/monitoring/event/command_started_spec.rb +26 -0
  75. data/spec/mongo/monitoring/event/command_succeeded_spec.rb +26 -0
  76. data/spec/mongo/monitoring/event/secure_spec.rb +57 -0
  77. data/spec/mongo/operation/commands/aggregate_spec.rb +0 -16
  78. data/spec/mongo/operation/commands/command_spec.rb +0 -18
  79. data/spec/mongo/operation/kill_cursors_spec.rb +0 -16
  80. data/spec/mongo/operation/read/get_more_spec.rb +0 -16
  81. data/spec/mongo/operation/read/query_spec.rb +19 -16
  82. data/spec/mongo/operation/write/bulk/delete_spec.rb +16 -16
  83. data/spec/mongo/operation/write/bulk/update_spec.rb +6 -6
  84. data/spec/mongo/operation/write/command/delete_spec.rb +0 -16
  85. data/spec/mongo/operation/write/command/insert_spec.rb +0 -16
  86. data/spec/mongo/operation/write/command/update_spec.rb +0 -16
  87. data/spec/mongo/operation/write/delete_spec.rb +3 -3
  88. data/spec/mongo/operation/write/update_spec.rb +6 -6
  89. data/spec/mongo/options/redacted_spec.rb +350 -0
  90. data/spec/mongo/protocol/query_spec.rb +15 -1
  91. data/spec/mongo/retryable_spec.rb +147 -0
  92. data/spec/mongo/server/connection_pool/queue_spec.rb +16 -0
  93. data/spec/mongo/server/connection_pool_spec.rb +32 -0
  94. data/spec/mongo/server/connection_spec.rb +37 -0
  95. data/spec/mongo/server_discovery_and_monitoring_spec.rb +24 -59
  96. data/spec/mongo/server_selection_rtt_spec.rb +37 -57
  97. data/spec/mongo/server_selection_spec.rb +2 -0
  98. data/spec/mongo/server_selector/nearest_spec.rb +1 -0
  99. data/spec/mongo/server_selector/primary_preferred_spec.rb +1 -0
  100. data/spec/mongo/server_selector/primary_spec.rb +8 -2
  101. data/spec/mongo/server_selector/secondary_preferred_spec.rb +1 -0
  102. data/spec/mongo/server_selector/secondary_spec.rb +1 -0
  103. data/spec/mongo/server_spec.rb +68 -1
  104. data/spec/mongo/socket/ssl_spec.rb +29 -5
  105. data/spec/mongo/uri_spec.rb +20 -20
  106. data/spec/support/crud.rb +7 -1
  107. data/spec/support/matchers.rb +1 -1
  108. data/spec/support/shared/server_selector.rb +58 -2
  109. metadata +20 -5
  110. metadata.gz.sig +0 -0
@@ -24,8 +24,18 @@ module Mongo
24
24
  extend Forwardable
25
25
  include Enumerable
26
26
  include Immutable
27
- include Iterable
28
27
  include Loggable
28
+ include Retryable
29
+
30
+ # The inline option.
31
+ #
32
+ # @since 2.1.0
33
+ INLINE = 'inline'.freeze
34
+
35
+ # Reroute message.
36
+ #
37
+ # @since 2.1.0
38
+ REROUTE = 'Rerouting the MapReduce operation to the primary server.'.freeze
29
39
 
30
40
  # @return [ View ] view The collection view.
31
41
  attr_reader :view
@@ -42,6 +52,31 @@ module Mongo
42
52
  # Delegate necessary operations to the collection.
43
53
  def_delegators :collection, :database
44
54
 
55
+ # Iterate through documents returned by the map/reduce.
56
+ #
57
+ # @example Iterate through the result of the map/reduce.
58
+ # map_reduce.each do |document|
59
+ # p document
60
+ # end
61
+ #
62
+ # @return [ Enumerator ] The enumerator.
63
+ #
64
+ # @since 2.0.0
65
+ #
66
+ # @yieldparam [ Hash ] Each matching document.
67
+ def each
68
+ @cursor = nil
69
+ write_with_retry do
70
+ server = read.select_server(cluster)
71
+ result = send_initial_query(server)
72
+ @cursor = Cursor.new(view, result, server)
73
+ end
74
+ @cursor.each do |doc|
75
+ yield doc
76
+ end if block_given?
77
+ @cursor.to_enum
78
+ end
79
+
45
80
  # Set or get the finalize function for the operation.
46
81
  #
47
82
  # @example Set the finalize function.
@@ -148,7 +183,7 @@ module Mongo
148
183
  private
149
184
 
150
185
  def inline?
151
- out.nil? || out == { inline: 1 } || out == { 'inline' => 1 }
186
+ out.nil? || out == { inline: 1 } || out == { INLINE => 1 }
152
187
  end
153
188
 
154
189
  def map_reduce_spec
@@ -182,13 +217,12 @@ module Mongo
182
217
  end
183
218
 
184
219
  def secondary_ok?
185
- out.respond_to?(:keys) &&
186
- out.keys.first.to_s.downcase == 'inline'
220
+ out.respond_to?(:keys) && out.keys.first.to_s.downcase == INLINE
187
221
  end
188
222
 
189
223
  def send_initial_query(server)
190
224
  unless valid_server?(server)
191
- log_warn('Rerouting the MapReduce operation to the primary server.')
225
+ log_warn(REROUTE)
192
226
  server = cluster.next_primary
193
227
  end
194
228
  result = initial_query_op.execute(server.context)
@@ -25,17 +25,17 @@ module Mongo
25
25
  #
26
26
  # @since 2.0.0
27
27
  SPECIAL_FIELDS = {
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
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
39
39
  }.freeze
40
40
 
41
41
  # Options to cursor flags mapping.
@@ -92,7 +92,7 @@ module Mongo
92
92
  #
93
93
  # @since 2.0.0
94
94
  def batch_size(batch_size = nil)
95
- configure(__method__, batch_size)
95
+ configure(:batch_size, batch_size)
96
96
  end
97
97
 
98
98
  # Associate a comment with the query.
@@ -110,7 +110,7 @@ module Mongo
110
110
  #
111
111
  # @since 2.0.0
112
112
  def comment(comment = nil)
113
- configure_modifier(__method__, comment)
113
+ configure_modifier(:comment, comment)
114
114
  end
115
115
 
116
116
  # Get a count of matching documents in the collection.
@@ -137,7 +137,9 @@ module Mongo
137
137
  cmd[:hint] = options[:hint] if options[:hint]
138
138
  cmd[:limit] = options[:limit] if options[:limit]
139
139
  cmd[:maxTimeMS] = options[:max_time_ms] if options[:max_time_ms]
140
- database.command(cmd, options).n
140
+ read_with_retry do
141
+ database.command(cmd, options).n
142
+ end
141
143
  end
142
144
 
143
145
  # Get a list of distinct values for a specific field.
@@ -160,7 +162,9 @@ module Mongo
160
162
  :key => field_name.to_s,
161
163
  :query => selector }
162
164
  cmd[:maxTimeMS] = options[:max_time_ms] if options[:max_time_ms]
163
- database.command(cmd, options).first['values']
165
+ read_with_retry do
166
+ database.command(cmd, options).first['values']
167
+ end
164
168
  end
165
169
 
166
170
  # The index that MongoDB will be forced to use for the query.
@@ -174,7 +178,7 @@ module Mongo
174
178
  #
175
179
  # @since 2.0.0
176
180
  def hint(hint = nil)
177
- configure_modifier(__method__, hint)
181
+ configure_modifier(:hint, hint)
178
182
  end
179
183
 
180
184
  # The max number of docs to return from the query.
@@ -188,7 +192,7 @@ module Mongo
188
192
  #
189
193
  # @since 2.0.0
190
194
  def limit(limit = nil)
191
- configure(__method__, limit)
195
+ configure(:limit, limit)
192
196
  end
193
197
 
194
198
  # Execute a map/reduce operation on the collection view.
@@ -218,7 +222,7 @@ module Mongo
218
222
  #
219
223
  # @since 2.0.0
220
224
  def max_scan(value = nil)
221
- configure_modifier(__method__, value)
225
+ configure_modifier(:max_scan, value)
222
226
  end
223
227
 
224
228
  # Set the maximum value to search.
@@ -232,7 +236,7 @@ module Mongo
232
236
  #
233
237
  # @since 2.1.0
234
238
  def max_value(value = nil)
235
- configure_modifier(__method__, value)
239
+ configure_modifier(:max_value, value)
236
240
  end
237
241
 
238
242
  # Set the minimum value to search.
@@ -246,7 +250,7 @@ module Mongo
246
250
  #
247
251
  # @since 2.1.0
248
252
  def min_value(value = nil)
249
- configure_modifier(__method__, value)
253
+ configure_modifier(:min_value, value)
250
254
  end
251
255
 
252
256
  # The server normally times out idle cursors after an inactivity period
@@ -259,7 +263,7 @@ module Mongo
259
263
  #
260
264
  # @since 2.0.0
261
265
  def no_cursor_timeout
262
- configure_flag(__method__)
266
+ configure_flag(:no_cursor_timeout)
263
267
  end
264
268
 
265
269
  # The fields to include or exclude from each doc in the result set.
@@ -278,7 +282,7 @@ module Mongo
278
282
  # @since 2.0.0
279
283
  def projection(document = nil)
280
284
  validate_doc!(document) if document
281
- configure(__method__, document)
285
+ configure(:projection, document)
282
286
  end
283
287
 
284
288
  # The read preference to use for the query.
@@ -294,7 +298,8 @@ module Mongo
294
298
  # @since 2.0.0
295
299
  def read(value = nil)
296
300
  return default_read if value.nil?
297
- configure(__method__, value.is_a?(Hash) ? ServerSelector.get(value) : value)
301
+ selector = value.is_a?(Hash) ? ServerSelector.get(client.options.merge(value)) : value
302
+ configure(:read, selector)
298
303
  end
299
304
 
300
305
  # Set whether to return only the indexed field or fields.
@@ -308,7 +313,7 @@ module Mongo
308
313
  #
309
314
  # @since 2.1.0
310
315
  def return_key(value = nil)
311
- configure_modifier(__method__, value)
316
+ configure_modifier(:return_key, value)
312
317
  end
313
318
 
314
319
  # Set whether the disk location should be shown for each document.
@@ -323,7 +328,7 @@ module Mongo
323
328
  #
324
329
  # @since 2.0.0
325
330
  def show_disk_loc(value = nil)
326
- configure_modifier(__method__, value)
331
+ configure_modifier(:show_disk_loc, value)
327
332
  end
328
333
 
329
334
  # The number of docs to skip before returning results.
@@ -338,7 +343,7 @@ module Mongo
338
343
  #
339
344
  # @since 2.0.0
340
345
  def skip(number = nil)
341
- configure(__method__, number)
346
+ configure(:skip, number)
342
347
  end
343
348
 
344
349
  # Set the snapshot value for the view.
@@ -353,7 +358,7 @@ module Mongo
353
358
  #
354
359
  # @since 2.0.0
355
360
  def snapshot(value = nil)
356
- configure_modifier(__method__, value)
361
+ configure_modifier(:snapshot, value)
357
362
  end
358
363
 
359
364
  # The key and direction pairs by which the result set will be sorted.
@@ -368,7 +373,7 @@ module Mongo
368
373
  #
369
374
  # @since 2.0.0
370
375
  def sort(spec = nil)
371
- configure_modifier(__method__, spec)
376
+ configure_modifier(:sort, spec)
372
377
  end
373
378
 
374
379
  # “meta” operators that let you modify the output or behavior of a query.
@@ -383,7 +388,7 @@ module Mongo
383
388
  # @since 2.1.0
384
389
  def modifiers(doc = nil)
385
390
  return @modifiers if doc.nil?
386
- new(options.merge(__method__ => doc))
391
+ new(options.merge(:modifiers => doc))
387
392
  end
388
393
 
389
394
  # A cumulative time limit in milliseconds for processing operations on a cursor.
@@ -397,7 +402,7 @@ module Mongo
397
402
  #
398
403
  # @since 2.1.0
399
404
  def max_time_ms(max = nil)
400
- configure_modifier(__method__, max)
405
+ configure_modifier(:max_time_ms, max)
401
406
  end
402
407
 
403
408
  private
@@ -35,7 +35,9 @@ module Mongo
35
35
  cmd[:fields] = projection if projection
36
36
  cmd[:sort] = sort if sort
37
37
  cmd[:maxTimeMS] = max_time_ms if max_time_ms
38
- database.command(cmd).first['value']
38
+ write_with_retry do
39
+ database.command(cmd).first['value']
40
+ end
39
41
  end
40
42
 
41
43
  # Finds a single document and replaces it.
@@ -81,8 +83,10 @@ module Mongo
81
83
  cmd[:new] = !!(opts[:return_document] && opts[:return_document] == :after)
82
84
  cmd[:upsert] = opts[:upsert] if opts[:upsert]
83
85
  cmd[:maxTimeMS] = max_time_ms if max_time_ms
84
- value = database.command(cmd).first['value']
85
- value unless value.nil? || value.empty?
86
+ write_with_retry do
87
+ value = database.command(cmd).first['value']
88
+ value unless value.nil? || value.empty?
89
+ end
86
90
  end
87
91
 
88
92
  # Remove documents from the collection.
@@ -166,24 +170,28 @@ module Mongo
166
170
  private
167
171
 
168
172
  def remove(value)
169
- Operation::Write::Delete.new(
170
- :delete => { q: selector, limit: value },
171
- :db_name => collection.database.name,
172
- :coll_name => collection.name,
173
- :write_concern => collection.write_concern
174
- ).execute(next_primary.context)
173
+ write_with_retry do
174
+ Operation::Write::Delete.new(
175
+ :delete => { Operation::Q => selector, Operation::LIMIT => value },
176
+ :db_name => collection.database.name,
177
+ :coll_name => collection.name,
178
+ :write_concern => collection.write_concern
179
+ ).execute(next_primary.context)
180
+ end
175
181
  end
176
182
 
177
183
  def update(spec, multi, opts)
178
- Operation::Write::Update.new(
179
- :update => { q: selector,
180
- u: spec,
181
- multi: multi,
182
- upsert: !!opts[:upsert] },
183
- :db_name => collection.database.name,
184
- :coll_name => collection.name,
185
- :write_concern => collection.write_concern
186
- ).execute(next_primary.context)
184
+ write_with_retry do
185
+ Operation::Write::Update.new(
186
+ :update => { Operation::Q => selector,
187
+ Operation::U => spec,
188
+ Operation::MULTI => multi,
189
+ Operation::UPSERT => !!opts[:upsert] },
190
+ :db_name => collection.database.name,
191
+ :coll_name => collection.name,
192
+ :write_concern => collection.write_concern
193
+ ).execute(next_primary.context)
194
+ end
187
195
  end
188
196
  end
189
197
  end
@@ -36,7 +36,17 @@ module Mongo
36
36
  # The default database options.
37
37
  #
38
38
  # @since 2.0.0
39
- DEFAULT_OPTIONS = { :database => ADMIN }.freeze
39
+ DEFAULT_OPTIONS = Options::Redacted.new(:database => ADMIN).freeze
40
+
41
+ # Database name field constant.
42
+ #
43
+ # @since 2.1.0
44
+ NAME = 'name'.freeze
45
+
46
+ # Databases constant.
47
+ #
48
+ # @since 2.1.0
49
+ DATABASES = 'databases'.freeze
40
50
 
41
51
  # The name of the collection that holds all the collection names.
42
52
  #
@@ -138,7 +148,7 @@ module Mongo
138
148
  #
139
149
  # @return [ Hash ] The result of the command execution.
140
150
  def command(operation, opts = {})
141
- preference = opts[:read] ? ServerSelector.get(opts[:read].merge(options)) : read_preference
151
+ preference = opts[:read] ? ServerSelector.get(client.options.merge(opts[:read])) : read_preference
142
152
  server = preference.select_server(cluster)
143
153
  Operation::Command.new({
144
154
  :selector => operation,
@@ -51,9 +51,10 @@ module Mongo
51
51
  def collection_names(options = {})
52
52
  @batch_size = options[:batch_size]
53
53
  server = next_primary
54
+ @limit = -1 if server.features.list_collections_enabled?
54
55
  collections_info(server).collect do |info|
55
- server.context.features.list_collections_enabled? ?
56
- info['name'] : info['name'].sub("#{@database.name}.", '')
56
+ server.features.list_collections_enabled? ?
57
+ info[Database::NAME] : info[Database::NAME].sub("#{@database.name}.", '')
57
58
  end
58
59
  end
59
60
 
@@ -80,7 +81,7 @@ module Mongo
80
81
  def initialize(database)
81
82
  @database = database
82
83
  @batch_size = nil
83
- @limit = -1
84
+ @limit = nil
84
85
  @collection = @database[Database::COMMAND]
85
86
  end
86
87
 
@@ -53,8 +53,8 @@ module Mongo
53
53
  #
54
54
  # @since 2.1.0
55
55
  def as_json(*args)
56
- document = { '$ref' => collection, '$id' => id }
57
- document.merge!('$db' => database) if database
56
+ document = { COLLECTION => collection, ID => id }
57
+ document.merge!(DATABASE => database) if database
58
58
  document
59
59
  end
60
60
 
@@ -101,8 +101,8 @@ module Mongo
101
101
  # @since 2.0.0
102
102
  def from_bson(bson)
103
103
  decoded = super
104
- if ref = decoded['$ref']
105
- decoded = DBRef.new(ref, decoded['$id'], decoded['$db'])
104
+ if ref = decoded[COLLECTION]
105
+ decoded = DBRef.new(ref, decoded[ID], decoded[DATABASE])
106
106
  end
107
107
  decoded
108
108
  end
@@ -19,6 +19,7 @@ module Mongo
19
19
  #
20
20
  # @since 2.0.0
21
21
  class FSBucket
22
+ extend Forwardable
22
23
 
23
24
  # The default root prefix.
24
25
  #
@@ -55,6 +56,12 @@ module Mongo
55
56
  # @since 2.1.0
56
57
  attr_reader :options
57
58
 
59
+ # Get client from the database.
60
+ #
61
+ # @since 2.1.0
62
+ def_delegators :database,
63
+ :client
64
+
58
65
  # Find files collection documents matching a given selector.
59
66
  #
60
67
  # @example Find files collection documents by a filename.
@@ -395,7 +402,7 @@ module Mongo
395
402
  # @since 2.1.0
396
403
  def read_preference
397
404
  @read_preference ||= @options[:read] ?
398
- ServerSelector.get((@options[:read] || {}).merge(database.options)) :
405
+ ServerSelector.get(Options::Redacted.new((@options[:read] || {}).merge(client.options))) :
399
406
  database.read_preference
400
407
  end
401
408
 
@@ -134,7 +134,7 @@ module Mongo
134
134
  # @since 2.1.0
135
135
  def read_preference
136
136
  @read_preference ||= @options[:read] ?
137
- ServerSelector.get((@options[:read] || {}).merge(fs.options)) :
137
+ ServerSelector.get(Options::Redacted.new((@options[:read] || {}).merge(fs.options))) :
138
138
  fs.read_preference
139
139
  end
140
140