mongo 2.24.0 → 2.25.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 (139) hide show
  1. checksums.yaml +4 -4
  2. data/bin/mongo_console +2 -2
  3. data/lib/mongo/address/validator.rb +1 -1
  4. data/lib/mongo/address.rb +1 -3
  5. data/lib/mongo/auth/aws/conversation.rb +0 -4
  6. data/lib/mongo/auth/aws/credentials_retriever.rb +3 -8
  7. data/lib/mongo/auth/base.rb +1 -1
  8. data/lib/mongo/auth/sasl_conversation_base.rb +1 -1
  9. data/lib/mongo/auth/scram_conversation_base.rb +1 -8
  10. data/lib/mongo/auth/stringprep.rb +1 -6
  11. data/lib/mongo/auth/user/view.rb +1 -1
  12. data/lib/mongo/bulk_write/result.rb +10 -2
  13. data/lib/mongo/bulk_write/result_combiner.rb +11 -4
  14. data/lib/mongo/bulk_write.rb +1 -1
  15. data/lib/mongo/client.rb +82 -12
  16. data/lib/mongo/cluster/reapers/cursor_reaper.rb +12 -5
  17. data/lib/mongo/cluster/sdam_flow.rb +4 -4
  18. data/lib/mongo/cluster/topology/base.rb +1 -1
  19. data/lib/mongo/cluster.rb +12 -28
  20. data/lib/mongo/collection/view/aggregation/behavior.rb +1 -1
  21. data/lib/mongo/collection/view/aggregation.rb +2 -4
  22. data/lib/mongo/collection/view/builder/aggregation.rb +3 -5
  23. data/lib/mongo/collection/view/builder/map_reduce.rb +1 -1
  24. data/lib/mongo/collection/view/change_stream.rb +14 -9
  25. data/lib/mongo/collection/view/map_reduce.rb +2 -11
  26. data/lib/mongo/collection/view/readable.rb +11 -7
  27. data/lib/mongo/collection/view/writable.rb +4 -4
  28. data/lib/mongo/collection/view.rb +8 -4
  29. data/lib/mongo/collection.rb +1 -1
  30. data/lib/mongo/config.rb +5 -0
  31. data/lib/mongo/crypt/auto_encrypter.rb +1 -1
  32. data/lib/mongo/crypt/binary.rb +7 -4
  33. data/lib/mongo/crypt/binding.rb +88 -10
  34. data/lib/mongo/crypt/context.rb +50 -19
  35. data/lib/mongo/crypt/encryption_io.rb +11 -5
  36. data/lib/mongo/crypt/handle.rb +17 -5
  37. data/lib/mongo/crypt/kms/credentials.rb +70 -31
  38. data/lib/mongo/crypt/kms/kmip/master_document.rb +30 -1
  39. data/lib/mongo/crypt/kms/master_key_document.rb +11 -6
  40. data/lib/mongo/crypt/kms.rb +12 -1
  41. data/lib/mongo/cursor.rb +8 -2
  42. data/lib/mongo/database/cursor_command_view.rb +95 -0
  43. data/lib/mongo/database.rb +144 -18
  44. data/lib/mongo/error/bulk_write_error.rb +29 -1
  45. data/lib/mongo/error/invalid_server_preference.rb +3 -0
  46. data/lib/mongo/error/invalid_uri.rb +5 -1
  47. data/lib/mongo/error/operation_failure.rb +42 -3
  48. data/lib/mongo/error/parser.rb +3 -3
  49. data/lib/mongo/error/sdam_error_detection.rb +2 -3
  50. data/lib/mongo/grid/fs_bucket.rb +27 -21
  51. data/lib/mongo/grid/stream/write.rb +2 -2
  52. data/lib/mongo/index/view.rb +13 -7
  53. data/lib/mongo/monitoring/event/cmap/connection_check_out_failed.rb +1 -0
  54. data/lib/mongo/monitoring/event/cmap/connection_check_out_started.rb +1 -0
  55. data/lib/mongo/monitoring/event/cmap/connection_checked_in.rb +1 -0
  56. data/lib/mongo/monitoring/event/cmap/connection_checked_out.rb +1 -0
  57. data/lib/mongo/monitoring/event/cmap/connection_closed.rb +1 -0
  58. data/lib/mongo/monitoring/event/cmap/connection_created.rb +1 -0
  59. data/lib/mongo/monitoring/event/cmap/connection_ready.rb +1 -0
  60. data/lib/mongo/monitoring/event/cmap/pool_cleared.rb +1 -0
  61. data/lib/mongo/monitoring/event/cmap/pool_closed.rb +1 -0
  62. data/lib/mongo/monitoring/event/cmap/pool_created.rb +1 -0
  63. data/lib/mongo/monitoring/event/cmap/pool_ready.rb +1 -0
  64. data/lib/mongo/monitoring/event/command_failed.rb +1 -0
  65. data/lib/mongo/monitoring/event/command_started.rb +1 -0
  66. data/lib/mongo/monitoring/event/command_succeeded.rb +1 -0
  67. data/lib/mongo/monitoring/event/secure.rb +12 -17
  68. data/lib/mongo/monitoring/event/server_closed.rb +1 -0
  69. data/lib/mongo/monitoring/event/server_description_changed.rb +1 -0
  70. data/lib/mongo/monitoring/event/server_heartbeat_failed.rb +1 -0
  71. data/lib/mongo/monitoring/event/server_heartbeat_started.rb +1 -0
  72. data/lib/mongo/monitoring/event/server_heartbeat_succeeded.rb +1 -0
  73. data/lib/mongo/monitoring/event/server_opening.rb +1 -0
  74. data/lib/mongo/monitoring/event/topology_changed.rb +1 -0
  75. data/lib/mongo/monitoring/event/topology_closed.rb +1 -0
  76. data/lib/mongo/monitoring/event/topology_opening.rb +1 -0
  77. data/lib/mongo/monitoring/server_description_changed_log_subscriber.rb +2 -0
  78. data/lib/mongo/monitoring/topology_changed_log_subscriber.rb +3 -0
  79. data/lib/mongo/operation/create/op_msg.rb +1 -0
  80. data/lib/mongo/operation/create_index/op_msg.rb +2 -1
  81. data/lib/mongo/operation/cursor_command/op_msg.rb +37 -0
  82. data/lib/mongo/operation/cursor_command/result.rb +60 -0
  83. data/lib/mongo/operation/cursor_command.rb +33 -0
  84. data/lib/mongo/operation/delete/op_msg.rb +1 -0
  85. data/lib/mongo/operation/drop/op_msg.rb +1 -0
  86. data/lib/mongo/operation/drop_database/op_msg.rb +1 -0
  87. data/lib/mongo/operation/drop_index/op_msg.rb +1 -0
  88. data/lib/mongo/operation/find/builder/command.rb +1 -1
  89. data/lib/mongo/operation/insert/bulk_result.rb +2 -4
  90. data/lib/mongo/operation/insert/op_msg.rb +1 -0
  91. data/lib/mongo/operation/result.rb +14 -26
  92. data/lib/mongo/operation/shared/causal_consistency_supported.rb +4 -2
  93. data/lib/mongo/operation/shared/executable.rb +2 -10
  94. data/lib/mongo/operation/shared/result/aggregatable.rb +2 -2
  95. data/lib/mongo/operation/shared/sessions_supported.rb +3 -5
  96. data/lib/mongo/operation/update/bulk_result.rb +1 -1
  97. data/lib/mongo/operation/update/op_msg.rb +1 -0
  98. data/lib/mongo/operation/write_command/op_msg.rb +2 -0
  99. data/lib/mongo/operation.rb +1 -0
  100. data/lib/mongo/options/redacted.rb +2 -2
  101. data/lib/mongo/protocol/compressed.rb +15 -11
  102. data/lib/mongo/protocol/message.rb +16 -16
  103. data/lib/mongo/protocol/registry.rb +1 -1
  104. data/lib/mongo/protocol/serializers.rb +1 -3
  105. data/lib/mongo/query_cache.rb +3 -5
  106. data/lib/mongo/server/connection.rb +3 -1
  107. data/lib/mongo/server/connection_common.rb +9 -1
  108. data/lib/mongo/server/connection_pool/generation_manager.rb +1 -1
  109. data/lib/mongo/server/connection_pool.rb +79 -18
  110. data/lib/mongo/server/description/features.rb +2 -2
  111. data/lib/mongo/server/description.rb +24 -2
  112. data/lib/mongo/server/monitor/connection.rb +3 -2
  113. data/lib/mongo/server/monitor.rb +133 -30
  114. data/lib/mongo/server/pending_connection.rb +1 -0
  115. data/lib/mongo/server/push_monitor.rb +16 -2
  116. data/lib/mongo/server.rb +27 -7
  117. data/lib/mongo/server_selector/base.rb +16 -6
  118. data/lib/mongo/server_selector/nearest.rb +3 -0
  119. data/lib/mongo/server_selector/primary.rb +3 -0
  120. data/lib/mongo/server_selector/primary_preferred.rb +3 -0
  121. data/lib/mongo/server_selector/secondary.rb +3 -0
  122. data/lib/mongo/server_selector/secondary_preferred.rb +7 -1
  123. data/lib/mongo/session.rb +56 -24
  124. data/lib/mongo/socket/ssl.rb +3 -3
  125. data/lib/mongo/socket.rb +1 -7
  126. data/lib/mongo/srv/monitor.rb +11 -2
  127. data/lib/mongo/srv/resolver.rb +1 -1
  128. data/lib/mongo/srv/result.rb +5 -3
  129. data/lib/mongo/timeout.rb +10 -15
  130. data/lib/mongo/tracing/open_telemetry/command_tracer.rb +43 -2
  131. data/lib/mongo/uri/options_mapper.rb +21 -9
  132. data/lib/mongo/uri/srv_protocol.rb +4 -4
  133. data/lib/mongo/uri.rb +56 -8
  134. data/lib/mongo/utils.rb +1 -1
  135. data/lib/mongo/version.rb +1 -1
  136. data/lib/mongo.rb +1 -0
  137. metadata +6 -4
  138. data/lib/mongo/auth/stringprep/unicode_normalize/normalize.rb +0 -173
  139. data/lib/mongo/auth/stringprep/unicode_normalize/tables.rb +0 -1164
@@ -53,6 +53,10 @@ module Mongo
53
53
  # @api experimental
54
54
  attr_reader :server_message
55
55
 
56
+ # @return [ String | nil ] The address ("host:port") of the server
57
+ # that produced this error, if known.
58
+ attr_reader :server_address
59
+
56
60
  # Error codes and code names that should result in a failing getMore
57
61
  # command on a change stream NOT being resumed.
58
62
  #
@@ -172,6 +176,8 @@ module Mongo
172
176
  # error document.
173
177
  # @option options [ String ] server_message The server-returned
174
178
  # error message parsed from the response.
179
+ # @option options [ nil | String | Mongo::Address | Mongo::Server::Description ]
180
+ # :server_address The address of the server that produced the error.
175
181
  # @option options [ Hash ] :write_concern_error_document The
176
182
  # server-supplied write concern error document, if any.
177
183
  # @option options [ Integer ] :write_concern_error_code Error code for
@@ -185,7 +191,8 @@ module Mongo
185
191
  # @option options [ true | false ] :wtimeout Whether the error is a wtimeout.
186
192
  def initialize(message = nil, result = nil, options = {})
187
193
  @details = retrieve_details(options[:document])
188
- super(append_details(message, @details))
194
+ @server_address = normalize_server_address(options[:server_address])
195
+ super(append_server_address(append_details(message, @details)))
189
196
 
190
197
  @result = result
191
198
  @code = options[:code]
@@ -226,9 +233,9 @@ module Mongo
226
233
  def retrieve_details(document)
227
234
  return nil unless document
228
235
 
229
- if wce = document['writeConcernError']
236
+ if (wce = document['writeConcernError'])
230
237
  wce['errInfo']
231
- elsif we = document['writeErrors']&.first
238
+ elsif (we = document['writeErrors']&.first)
232
239
  we['errInfo']
233
240
  end
234
241
  end
@@ -241,6 +248,38 @@ module Mongo
241
248
 
242
249
  message + " -- #{details.to_json}"
243
250
  end
251
+
252
+ # Append the server address suffix to the message when the
253
+ # Mongo.include_server_address_in_errors flag is enabled and
254
+ # a server address is known.
255
+ #
256
+ # @return [ String | nil ] the message with the suffix appended,
257
+ # or the original message unchanged.
258
+ def append_server_address(message)
259
+ return message unless Mongo.include_server_address_in_errors
260
+ return message if @server_address.nil?
261
+ return "(on #{@server_address})" if message.nil? || message.empty?
262
+
263
+ "#{message} (on #{@server_address})"
264
+ end
265
+
266
+ # Normalize a server_address option into a String "host:port" form.
267
+ #
268
+ # @param [ nil | String | Mongo::Address | Mongo::Server::Description ] value
269
+ #
270
+ # @return [ String | nil ] The normalized address, or nil.
271
+ def normalize_server_address(value)
272
+ case value
273
+ when nil then nil
274
+ when String then value
275
+ when Mongo::Address then value.seed
276
+ when Mongo::Server::Description
277
+ value.address.is_a?(Mongo::Address) ? value.address.seed : nil
278
+ else
279
+ raise ArgumentError,
280
+ "server_address must be nil, String, Mongo::Address, or Mongo::Server::Description; got #{value.class}"
281
+ end
282
+ end
244
283
  end
245
284
 
246
285
  # OperationFailure is the canonical implementor of the
@@ -180,13 +180,13 @@ module Mongo
180
180
  end
181
181
 
182
182
  def parse_single(message, key, doc = document)
183
- return unless error = doc[key]
183
+ return unless (error = doc[key])
184
184
 
185
185
  append(message, error)
186
186
  end
187
187
 
188
188
  def parse_multiple(message, key)
189
- return unless errors = document[key]
189
+ return unless (errors = document[key])
190
190
 
191
191
  errors.each do |error|
192
192
  parse_single(message, 'errmsg', error)
@@ -228,7 +228,7 @@ module Mongo
228
228
  return unless @code.nil? && @code_name.nil?
229
229
  # If we have writeErrors, and all of their codes are the same,
230
230
  # use that code. Otherwise don't set the code
231
- return unless write_errors = document['writeErrors']
231
+ return unless (write_errors = document['writeErrors'])
232
232
 
233
233
  codes = write_errors.map { |e| e['code'] }.compact
234
234
  return unless codes.uniq.length == 1
@@ -29,10 +29,9 @@ module Mongo
29
29
  # Require the error to be communicated at the top level of the response
30
30
  # for it to influence SDAM state. See DRIVERS-1376 / RUBY-2516.
31
31
  return false if document && document['ok'] == 1
32
+ return false if node_recovering?
32
33
 
33
- if node_recovering?
34
- false
35
- elsif code
34
+ if code
36
35
  NOT_MASTER_CODES.include?(code)
37
36
  elsif message
38
37
  message.include?('not master')
@@ -480,7 +480,7 @@ module Mongo
480
480
  #
481
481
  # @since 2.1.0
482
482
  def write_concern
483
- @write_concern ||= if wco = @options[:write_concern] || @options[:write]
483
+ @write_concern ||= if (wco = @options[:write_concern] || @options[:write])
484
484
  WriteConcern.get(wco)
485
485
  else
486
486
  database.write_concern
@@ -494,6 +494,32 @@ module Mongo
494
494
  chunks_collection.drop(timeout_ms: context.remaining_timeout_ms)
495
495
  end
496
496
 
497
+ # Ensures the files and chunks collections have their required indexes,
498
+ # creating any that are missing.
499
+ #
500
+ # @param [ CsotTimeoutHolder | nil ] timeout_holder The timeout holder.
501
+ #
502
+ # @api private
503
+ def ensure_indexes!(timeout_holder = nil)
504
+ fc_idx = files_collection.find(
505
+ {},
506
+ limit: 1,
507
+ projection: { _id: 1 },
508
+ timeout_ms: timeout_holder&.remaining_timeout_ms
509
+ ).first
510
+ create_index_if_missing!(files_collection, FSBucket::FILES_INDEX) if fc_idx.nil?
511
+
512
+ cc_idx = chunks_collection.find(
513
+ {},
514
+ limit: 1,
515
+ projection: { _id: 1 },
516
+ timeout_ms: timeout_holder&.remaining_timeout_ms
517
+ ).first
518
+ return unless cc_idx.nil?
519
+
520
+ create_index_if_missing!(chunks_collection, FSBucket::CHUNKS_INDEX, unique: true)
521
+ end
522
+
497
523
  private
498
524
 
499
525
  # @param [ Hash ] opts The options.
@@ -516,26 +542,6 @@ module Mongo
516
542
  "#{prefix}.#{Grid::File::Info::COLLECTION}"
517
543
  end
518
544
 
519
- def ensure_indexes!(timeout_holder = nil)
520
- fc_idx = files_collection.find(
521
- {},
522
- limit: 1,
523
- projection: { _id: 1 },
524
- timeout_ms: timeout_holder&.remaining_timeout_ms
525
- ).first
526
- create_index_if_missing!(files_collection, FSBucket::FILES_INDEX) if fc_idx.nil?
527
-
528
- cc_idx = chunks_collection.find(
529
- {},
530
- limit: 1,
531
- projection: { _id: 1 },
532
- timeout_ms: timeout_holder&.remaining_timeout_ms
533
- ).first
534
- return unless cc_idx.nil?
535
-
536
- create_index_if_missing!(chunks_collection, FSBucket::CHUNKS_INDEX, unique: true)
537
- end
538
-
539
545
  def create_index_if_missing!(collection, index_spec, options = {})
540
546
  indexes_view = collection.indexes
541
547
  begin
@@ -148,7 +148,7 @@ module Mongo
148
148
  #
149
149
  # @since 2.1.0
150
150
  def write_concern
151
- @write_concern ||= if wco = @options[:write_concern] || @options[:write]
151
+ @write_concern ||= if (wco = @options[:write_concern] || @options[:write])
152
152
  WriteConcern.get(wco)
153
153
  else
154
154
  fs.write_concern
@@ -212,7 +212,7 @@ module Mongo
212
212
  end
213
213
 
214
214
  def ensure_indexes!
215
- fs.send(:ensure_indexes!, @timeout_holder)
215
+ fs.ensure_indexes!(@timeout_holder)
216
216
  end
217
217
 
218
218
  def ensure_open!
@@ -168,11 +168,11 @@ module Mongo
168
168
  options = options.dup
169
169
 
170
170
  create_options = {}
171
- if session = @options[:session]
171
+ if (session = @options[:session])
172
172
  create_options[:session] = session
173
173
  end
174
174
  %i[commit_quorum session comment timeout_ms max_time_ms].each do |key|
175
- if value = options.delete(key)
175
+ if (value = options.delete(key))
176
176
  create_options[key] = value
177
177
  end
178
178
  end
@@ -347,10 +347,20 @@ module Mongo
347
347
  end
348
348
  end
349
349
 
350
+ # The query limit for an index view. Always -1; present so a Cursor
351
+ # can treat an index view like a collection view.
352
+ #
353
+ # @api private
354
+ def limit
355
+ -1
356
+ end
357
+
350
358
  private
351
359
 
352
360
  def drop_by_name(name, opts = {})
353
- client.send(:with_session, @options) do |session|
361
+ session_options = @options.dup
362
+ session_options[:session] = opts[:session] if opts[:session]
363
+ client.with_session(session_options) do |session|
354
364
  spec = {
355
365
  db_name: database.name,
356
366
  coll_name: collection.name,
@@ -394,10 +404,6 @@ module Mongo
394
404
  Operation::Indexes.new(indexes_spec(session))
395
405
  end
396
406
 
397
- def limit
398
- -1
399
- end
400
-
401
407
  def normalize_keys(spec)
402
408
  return false if spec.is_a?(String)
403
409
 
@@ -62,6 +62,7 @@ module Mongo
62
62
  # @since 2.9.0
63
63
  # @api private
64
64
  def initialize(address, reason)
65
+ super()
65
66
  @reason = reason
66
67
  @address = address
67
68
  end
@@ -35,6 +35,7 @@ module Mongo
35
35
  # @since 2.9.0
36
36
  # @api private
37
37
  def initialize(address)
38
+ super()
38
39
  @address = address
39
40
  end
40
41
 
@@ -47,6 +47,7 @@ module Mongo
47
47
  # @since 2.9.0
48
48
  # @api private
49
49
  def initialize(address, id, pool)
50
+ super()
50
51
  @address = address
51
52
  @connection_id = id
52
53
  @pool = pool
@@ -48,6 +48,7 @@ module Mongo
48
48
  # @since 2.9.0
49
49
  # @api private
50
50
  def initialize(address, id, pool)
51
+ super()
51
52
  @address = address
52
53
  @connection_id = id
53
54
  @pool = pool
@@ -79,6 +79,7 @@ module Mongo
79
79
  # @since 2.9.0
80
80
  # @api private
81
81
  def initialize(address, id, reason)
82
+ super()
82
83
  @reason = reason
83
84
  @address = address
84
85
  @connection_id = id
@@ -41,6 +41,7 @@ module Mongo
41
41
  # @since 2.9.0
42
42
  # @api private
43
43
  def initialize(address, id)
44
+ super()
44
45
  @address = address
45
46
  @connection_id = id
46
47
  end
@@ -41,6 +41,7 @@ module Mongo
41
41
  # @since 2.9.0
42
42
  # @api private
43
43
  def initialize(address, id)
44
+ super()
44
45
  @address = address
45
46
  @connection_id = id
46
47
  end
@@ -43,6 +43,7 @@ module Mongo
43
43
  #
44
44
  # @api private
45
45
  def initialize(address, service_id: nil, interrupt_in_use_connections: nil)
46
+ super()
46
47
  @address = address
47
48
  @service_id = service_id
48
49
  @options = {}
@@ -42,6 +42,7 @@ module Mongo
42
42
  # @since 2.9.0
43
43
  # @api private
44
44
  def initialize(address, pool)
45
+ super()
45
46
  @address = address
46
47
  @pool = pool
47
48
  end
@@ -48,6 +48,7 @@ module Mongo
48
48
  # @since 2.9.0
49
49
  # @api private
50
50
  def initialize(address, options, pool)
51
+ super()
51
52
  @address = address
52
53
  @options = options.dup.freeze
53
54
  @pool = pool
@@ -41,6 +41,7 @@ module Mongo
41
41
  # @since 2.9.0
42
42
  # @api private
43
43
  def initialize(address, options, pool)
44
+ super()
44
45
  @address = address
45
46
  @options = options.dup.freeze
46
47
  @pool = pool
@@ -83,6 +83,7 @@ module Mongo
83
83
  def initialize(command_name, database_name, address,
84
84
  request_id, operation_id, message, failure, duration,
85
85
  started_event:, server_connection_id: nil, service_id: nil)
86
+ super()
86
87
  @command_name = command_name.to_s
87
88
  @database_name = database_name
88
89
  @address = address
@@ -84,6 +84,7 @@ module Mongo
84
84
  operation_id, command, socket_object_id: nil, connection_id: nil,
85
85
  connection_generation: nil, server_connection_id: nil,
86
86
  service_id: nil)
87
+ super()
87
88
  @command_name = command_name.to_s
88
89
  @database_name = database_name
89
90
  @address = address
@@ -76,6 +76,7 @@ module Mongo
76
76
  def initialize(command_name, database_name, address, request_id,
77
77
  operation_id, reply, duration, started_event:,
78
78
  server_connection_id: nil, service_id: nil)
79
+ super()
79
80
  @command_name = command_name.to_s
80
81
  @database_name = database_name
81
82
  @address = address
@@ -47,18 +47,14 @@ module Mongo
47
47
  #
48
48
  # @return [ true | false ] Whether the command is sensitive.
49
49
  def sensitive?(command_name:, document:)
50
- if REDACTED_COMMANDS.include?(command_name.to_s)
51
- true
52
- elsif %w[hello ismaster isMaster].include?(command_name.to_s) &&
53
- document['speculativeAuthenticate']
54
- # According to Command Monitoring spec, for hello/legacy hello commands
55
- # when speculativeAuthenticate is present, their commands AND replies
56
- # MUST be redacted from the events.
57
- # See https://github.com/mongodb/specifications/blob/master/source/command-logging-and-monitoring/command-logging-and-monitoring.md#security
58
- true
59
- else
60
- false
61
- end
50
+ return true if REDACTED_COMMANDS.include?(command_name.to_s)
51
+
52
+ # According to Command Monitoring spec, for hello/legacy hello commands
53
+ # when speculativeAuthenticate is present, their commands AND replies
54
+ # MUST be redacted from the events.
55
+ # See https://github.com/mongodb/specifications/blob/master/source/command-logging-and-monitoring/command-logging-and-monitoring.md#security
56
+ %w[hello ismaster isMaster].include?(command_name.to_s) &&
57
+ !!document['speculativeAuthenticate']
62
58
  end
63
59
 
64
60
  # Redact secure information from the document if:
@@ -77,11 +73,10 @@ module Mongo
77
73
  #
78
74
  # @since 2.1.0
79
75
  def redacted(command_name, document)
80
- if %w[1 true yes].include?(ENV['MONGO_RUBY_DRIVER_UNREDACT_EVENTS']&.downcase)
81
- document
82
- elsif respond_to?(:started_event) && started_event.sensitive
83
- BSON::Document.new
84
- elsif sensitive?(command_name: command_name, document: document)
76
+ return document if %w[1 true yes].include?(ENV['MONGO_RUBY_DRIVER_UNREDACT_EVENTS']&.downcase)
77
+
78
+ if (respond_to?(:started_event) && started_event.sensitive) ||
79
+ sensitive?(command_name: command_name, document: document)
85
80
  BSON::Document.new
86
81
  else
87
82
  document
@@ -37,6 +37,7 @@ module Mongo
37
37
  #
38
38
  # @since 2.4.0
39
39
  def initialize(address, topology)
40
+ super()
40
41
  @address = address
41
42
  @topology = topology
42
43
  end
@@ -58,6 +58,7 @@ module Mongo
58
58
  # @api private
59
59
  def initialize(address, topology, previous_description, new_description,
60
60
  awaited: false)
61
+ super()
61
62
  @address = address
62
63
  @topology = topology
63
64
  @previous_description = previous_description
@@ -35,6 +35,7 @@ module Mongo
35
35
  # @since 2.7.0
36
36
  # @api private
37
37
  def initialize(address, round_trip_time, error, started_event:, awaited: false)
38
+ super()
38
39
  @address = address
39
40
  @round_trip_time = round_trip_time
40
41
  @error = error
@@ -40,6 +40,7 @@ module Mongo
40
40
  # @since 2.7.0
41
41
  # @api private
42
42
  def initialize(address, awaited: false)
43
+ super()
43
44
  @address = address
44
45
  @awaited = !!awaited
45
46
  end
@@ -35,6 +35,7 @@ module Mongo
35
35
  # @since 2.7.0
36
36
  # @api private
37
37
  def initialize(address, round_trip_time, started_event:, awaited: false)
38
+ super()
38
39
  @address = address
39
40
  @round_trip_time = round_trip_time
40
41
  @awaited = !!awaited
@@ -37,6 +37,7 @@ module Mongo
37
37
  #
38
38
  # @since 2.4.0
39
39
  def initialize(address, topology)
40
+ super()
40
41
  @address = address
41
42
  @topology = topology
42
43
  end
@@ -37,6 +37,7 @@ module Mongo
37
37
  #
38
38
  # @since 2.4.0
39
39
  def initialize(previous_topology, new_topology)
40
+ super()
40
41
  @previous_topology = previous_topology
41
42
  @new_topology = new_topology
42
43
  end
@@ -33,6 +33,7 @@ module Mongo
33
33
  #
34
34
  # @since 2.4.0
35
35
  def initialize(topology)
36
+ super()
36
37
  @topology = topology
37
38
  end
38
39
 
@@ -33,6 +33,7 @@ module Mongo
33
33
  #
34
34
  # @since 2.4.0
35
35
  def initialize(topology)
36
+ super()
36
37
  @topology = topology
37
38
  end
38
39
 
@@ -23,6 +23,8 @@ module Mongo
23
23
  private
24
24
 
25
25
  def log_event(event)
26
+ return if event.previous_description == event.new_description
27
+
26
28
  log_debug(
27
29
  "Server description for #{event.address} changed from " +
28
30
  "'#{event.previous_description.server_type}' to '#{event.new_description.server_type}'#{awaited_indicator(event)}."
@@ -24,6 +24,9 @@ module Mongo
24
24
 
25
25
  def log_event(event)
26
26
  if event.previous_topology.class == event.new_topology.class
27
+ return if event.previous_topology.server_descriptions ==
28
+ event.new_topology.server_descriptions
29
+
27
30
  log_debug(
28
31
  "There was a change in the members of the '#{event.new_topology.display_name}' " +
29
32
  'topology.'
@@ -24,6 +24,7 @@ module Mongo
24
24
  # @since 2.5.2
25
25
  class OpMsg < OpMsgBase
26
26
  include ExecutableTransactionLabel
27
+ include CausalConsistencySupported
27
28
 
28
29
  private
29
30
 
@@ -24,6 +24,7 @@ module Mongo
24
24
  # @since 2.5.2
25
25
  class OpMsg < OpMsgBase
26
26
  include ExecutableTransactionLabel
27
+ include CausalConsistencySupported
27
28
 
28
29
  private
29
30
 
@@ -33,7 +34,7 @@ module Mongo
33
34
  indexes: indexes,
34
35
  comment: spec[:comment],
35
36
  }.compact.tap do |selector|
36
- if commit_quorum = spec[:commit_quorum]
37
+ if (commit_quorum = spec[:commit_quorum])
37
38
  # There was a bug on server versions 4.2.0 - 4.2.5 where
38
39
  # the server would accept the commitQuorum option and use it internally
39
40
  # (see SERVER-47193). As a result, the drivers specifications require
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (C) 2025 MongoDB Inc.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ module Mongo
18
+ module Operation
19
+ class CursorCommand
20
+ # A cursor command operation sent as an op message.
21
+ #
22
+ # @api private
23
+ class OpMsg < OpMsgBase
24
+ include PolymorphicResult
25
+
26
+ private
27
+
28
+ # The user's command is sent verbatim. The driver MUST NOT inspect or
29
+ # modify it; $db, lsid and other internal fields are attached by the
30
+ # shared command building code.
31
+ def selector(_connection)
32
+ spec[:selector].dup
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (C) 2025 MongoDB Inc.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ module Mongo
18
+ module Operation
19
+ class CursorCommand
20
+ # Parses the cursor field of a command response so a Cursor can be built
21
+ # from the result. The parsing is identical to a find command result.
22
+ #
23
+ # @api private
24
+ class Result < Operation::Result
25
+ # @return [ true | false ] Whether the command response contained a
26
+ # cursor field.
27
+ def cursor?
28
+ !cursor_document.nil?
29
+ end
30
+
31
+ # @return [ Integer | nil ] The cursor id from the cursor document.
32
+ def cursor_id
33
+ cursor? ? cursor_document[CURSOR_ID] : super
34
+ end
35
+
36
+ # @return [ Array<BSON::Document> ] The first batch of documents.
37
+ def documents
38
+ cursor? ? cursor_document[FIRST_BATCH] : []
39
+ end
40
+
41
+ # @return [ String | nil ] The cursor namespace, "database.collection".
42
+ def namespace
43
+ cursor? ? cursor_document['ns'] : super
44
+ end
45
+
46
+ private
47
+
48
+ def cursor_document
49
+ return @cursor_document if defined?(@cursor_document)
50
+
51
+ @cursor_document = first_document[CURSOR]
52
+ end
53
+
54
+ def first_document
55
+ @first_document ||= reply.documents[0]
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end