mongo 2.21.3 → 2.23.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 (43) hide show
  1. checksums.yaml +4 -4
  2. data/lib/mongo/address.rb +8 -2
  3. data/lib/mongo/bulk_write/transformable.rb +2 -0
  4. data/lib/mongo/client.rb +40 -4
  5. data/lib/mongo/cluster.rb +4 -1
  6. data/lib/mongo/collection/view/aggregation/behavior.rb +1 -1
  7. data/lib/mongo/collection/view/aggregation.rb +5 -2
  8. data/lib/mongo/collection/view/iterable.rb +16 -14
  9. data/lib/mongo/collection/view/readable.rb +64 -55
  10. data/lib/mongo/collection/view/writable.rb +64 -46
  11. data/lib/mongo/collection/view.rb +2 -0
  12. data/lib/mongo/collection.rb +66 -46
  13. data/lib/mongo/config.rb +4 -0
  14. data/lib/mongo/crypt/auto_decryption_context.rb +9 -0
  15. data/lib/mongo/crypt/binding.rb +1 -1
  16. data/lib/mongo/crypt/context.rb +10 -0
  17. data/lib/mongo/crypt/explicit_decryption_context.rb +9 -0
  18. data/lib/mongo/database/view.rb +25 -20
  19. data/lib/mongo/database.rb +17 -10
  20. data/lib/mongo/deprecations.rb +98 -0
  21. data/lib/mongo/index/view.rb +28 -19
  22. data/lib/mongo/operation/create.rb +4 -0
  23. data/lib/mongo/operation/insert/op_msg.rb +5 -2
  24. data/lib/mongo/operation/shared/executable.rb +11 -4
  25. data/lib/mongo/operation/shared/specifiable.rb +5 -1
  26. data/lib/mongo/search_index/view.rb +29 -9
  27. data/lib/mongo/server/app_metadata/platform.rb +17 -4
  28. data/lib/mongo/server/connection.rb +18 -0
  29. data/lib/mongo/server/description/features.rb +37 -8
  30. data/lib/mongo/server.rb +5 -2
  31. data/lib/mongo/session.rb +55 -19
  32. data/lib/mongo/socket.rb +1 -1
  33. data/lib/mongo/srv/monitor.rb +5 -1
  34. data/lib/mongo/srv/result.rb +14 -4
  35. data/lib/mongo/tracing/open_telemetry/command_tracer.rb +320 -0
  36. data/lib/mongo/tracing/open_telemetry/operation_tracer.rb +227 -0
  37. data/lib/mongo/tracing/open_telemetry/tracer.rb +236 -0
  38. data/lib/mongo/tracing/open_telemetry.rb +27 -0
  39. data/lib/mongo/tracing.rb +42 -0
  40. data/lib/mongo/uri/srv_protocol.rb +11 -6
  41. data/lib/mongo/version.rb +1 -1
  42. data/lib/mongo.rb +3 -0
  43. metadata +8 -2
@@ -57,6 +57,8 @@ module Mongo
57
57
  # Delegate to the cluster for the next primary.
58
58
  def_delegators :cluster, :next_primary
59
59
 
60
+ def_delegators :client, :tracer
61
+
60
62
  # Options that can be updated on a new Collection instance via the #with method.
61
63
  #
62
64
  # @since 2.1.0
@@ -410,21 +412,24 @@ module Mongo
410
412
  client: client,
411
413
  session: session
412
414
  )
413
- maybe_create_qe_collections(opts[:encrypted_fields], client, session) do |encrypted_fields|
414
- Operation::Create.new(
415
- selector: operation,
416
- db_name: database.name,
417
- write_concern: write_concern,
418
- session: session,
419
- # Note that these are collection options, collation isn't
420
- # taken from options passed to the create method.
421
- collation: options[:collation] || options['collation'],
422
- encrypted_fields: encrypted_fields,
423
- validator: options[:validator],
424
- ).execute(
425
- next_primary(nil, session),
426
- context: context
427
- )
415
+ operation = Operation::Create.new(
416
+ selector: operation,
417
+ db_name: database.name,
418
+ write_concern: write_concern,
419
+ session: session,
420
+ # Note that these are collection options, collation isn't
421
+ # taken from options passed to the create method.
422
+ collation: options[:collation] || options['collation'],
423
+ validator: options[:validator],
424
+ )
425
+ tracer.trace_operation(operation, context, op_name: 'createCollection') do
426
+ maybe_create_qe_collections(opts[:encrypted_fields], client, session) do |encrypted_fields|
427
+ operation.encrypted_fields = encrypted_fields
428
+ operation.execute(
429
+ next_primary(nil, session),
430
+ context: context
431
+ )
432
+ end
428
433
  end
429
434
  end
430
435
  end
@@ -453,25 +458,27 @@ module Mongo
453
458
  # @since 2.0.0
454
459
  def drop(opts = {})
455
460
  client.with_session(opts) do |session|
456
- maybe_drop_emm_collections(opts[:encrypted_fields], client, session) do
457
- temp_write_concern = write_concern
458
- write_concern = if opts[:write_concern]
459
- WriteConcern.get(opts[:write_concern])
460
- else
461
- temp_write_concern
461
+ context = Operation::Context.new(
462
+ client: client,
463
+ session: session,
464
+ operation_timeouts: operation_timeouts(opts)
465
+ )
466
+ temp_write_concern = write_concern
467
+ write_concern = if opts[:write_concern]
468
+ WriteConcern.get(opts[:write_concern])
469
+ else
470
+ temp_write_concern
471
+ end
472
+ operation = Operation::Drop.new({
473
+ selector: { :drop => name },
474
+ db_name: database.name,
475
+ write_concern: write_concern,
476
+ session: session,
477
+ })
478
+ tracer.trace_operation(operation, context, op_name: 'dropCollection') do
479
+ maybe_drop_emm_collections(opts[:encrypted_fields], client, session) do
480
+ do_drop(operation, session, context)
462
481
  end
463
- context = Operation::Context.new(
464
- client: client,
465
- session: session,
466
- operation_timeouts: operation_timeouts(opts)
467
- )
468
- operation = Operation::Drop.new({
469
- selector: { :drop => name },
470
- db_name: database.name,
471
- write_concern: write_concern,
472
- session: session,
473
- })
474
- do_drop(operation, session, context)
475
482
  end
476
483
  end
477
484
  end
@@ -865,19 +872,22 @@ module Mongo
865
872
  session: session,
866
873
  operation_timeouts: operation_timeouts(opts)
867
874
  )
868
- write_with_retry(write_concern, context: context) do |connection, txn_num, context|
869
- Operation::Insert.new(
870
- :documents => [ document ],
871
- :db_name => database.name,
872
- :coll_name => name,
873
- :write_concern => write_concern,
874
- :bypass_document_validation => !!opts[:bypass_document_validation],
875
- :options => opts,
876
- :id_generator => client.options[:id_generator],
877
- :session => session,
878
- :txn_num => txn_num,
879
- :comment => opts[:comment]
880
- ).execute_with_connection(connection, context: context)
875
+ operation = Operation::Insert.new(
876
+ :documents => [ document ],
877
+ :db_name => database.name,
878
+ :coll_name => name,
879
+ :write_concern => write_concern,
880
+ :bypass_document_validation => !!opts[:bypass_document_validation],
881
+ :options => opts,
882
+ :id_generator => client.options[:id_generator],
883
+ :session => session,
884
+ :comment => opts[:comment]
885
+ )
886
+ tracer.trace_operation(operation, context) do
887
+ write_with_retry(write_concern, context: context) do |connection, txn_num, context|
888
+ operation.txn_num = txn_num
889
+ operation.execute_with_connection(connection, context: context)
890
+ end
881
891
  end
882
892
  end
883
893
  end
@@ -1049,6 +1059,11 @@ module Mongo
1049
1059
  # May be specified as a Hash (e.g. { _id: 1 }) or a String (e.g. "_id_").
1050
1060
  # @option options [ Hash ] :let Mapping of variables to use in the command.
1051
1061
  # See the server documentation for details.
1062
+ # @option options [ Hash ] :sort Specifies which document the operation
1063
+ # replaces if the query matches multiple documents. The first document
1064
+ # matched by the sort order will be replaced.
1065
+ # This option is only supported by servers >= 8.0. Older servers will
1066
+ # report an error for using this option.
1052
1067
  #
1053
1068
  # @return [ Result ] The response from the database.
1054
1069
  #
@@ -1115,6 +1130,11 @@ module Mongo
1115
1130
  # May be specified as a Hash (e.g. { _id: 1 }) or a String (e.g. "_id_").
1116
1131
  # @option options [ Hash ] :let Mapping of variables to use in the command.
1117
1132
  # See the server documentation for details.
1133
+ # @option options [ Hash ] :sort Specifies which document the operation
1134
+ # updates if the query matches multiple documents. The first document
1135
+ # matched by the sort order will be updated.
1136
+ # This option is only supported by servers >= 8.0. Older servers will
1137
+ # report an error for using this option.
1118
1138
  #
1119
1139
  # @return [ Result ] The response from the database.
1120
1140
  #
data/lib/mongo/config.rb CHANGED
@@ -27,6 +27,10 @@ module Mongo
27
27
  # validate the parameters and raise an error if they are invalid.
28
28
  option :validate_update_replace, default: false
29
29
 
30
+ # When this flag is set to true, the CSFLE will use Ruby types for
31
+ # decryption instead of BSON types.
32
+ option :csfle_convert_to_ruby_types, default: false
33
+
30
34
  # Set the configuration options.
31
35
  #
32
36
  # @example Set the options.
@@ -38,6 +38,15 @@ module Mongo
38
38
 
39
39
  Binding.ctx_decrypt_init(self, @command)
40
40
  end
41
+
42
+ # Which BSON mode to use when creating documents from the outcome of
43
+ # the state machine. The returned value is based on the
44
+ # +Mongo::Config.csfle_convert_to_ruby_types+ option.
45
+ #
46
+ # @return [ Symbol, nil ] The BSON mode.
47
+ def bson_mode
48
+ Mongo::Config.csfle_convert_to_ruby_types ? nil : :bson
49
+ end
41
50
  end
42
51
  end
43
52
  end
@@ -1216,7 +1216,7 @@ module Mongo
1216
1216
  # TODO since the binary references a C pointer, and ByteBuffer is
1217
1217
  # written in C in MRI, we could omit a copy of the data by making
1218
1218
  # ByteBuffer reference the string that is owned by libmongocrypt.
1219
- BSON::Document.from_bson(BSON::ByteBuffer.new(binary.to_s), mode: :bson)
1219
+ BSON::Document.from_bson(BSON::ByteBuffer.new(binary.to_s), mode: context.bson_mode)
1220
1220
  end
1221
1221
 
1222
1222
  # @!method self.mongocrypt_ctx_destroy(ctx)
@@ -109,6 +109,16 @@ module Mongo
109
109
  end
110
110
  end
111
111
 
112
+ # Which BSON mode to use when creating documents from the outcome of
113
+ # the state machine. The default is :bson, which creates BSON::Document
114
+ # with BSON types. Subclasses may override this method to
115
+ # change this behavior.
116
+ #
117
+ # @return [ Symbol, nil ] The BSON mode.
118
+ def bson_mode
119
+ :bson
120
+ end
121
+
112
122
  private
113
123
 
114
124
  def provide_markings(timeout_ms)
@@ -38,6 +38,15 @@ module Mongo
38
38
  # explicit decryption
39
39
  Binding.ctx_explicit_decrypt_init(self, doc)
40
40
  end
41
+
42
+ # Which BSON mode to use when creating documents from the outcome of
43
+ # the state machine. The returned value is based on the
44
+ # +Mongo::Config.csfle_convert_to_ruby_types+ option.
45
+ #
46
+ # @return [ Symbol, nil ] The BSON mode.
47
+ def bson_mode
48
+ Mongo::Config.csfle_convert_to_ruby_types ? nil : :bson
49
+ end
41
50
  end
42
51
  end
43
52
  end
@@ -45,6 +45,8 @@ module Mongo
45
45
  # @return [ Collection ] collection The command collection.
46
46
  attr_reader :collection
47
47
 
48
+ def_delegators :@database, :tracer
49
+
48
50
  # Get all the names of the non-system collections in the database.
49
51
  #
50
52
  # @note The set of returned collection names depends on the version of
@@ -214,27 +216,30 @@ module Mongo
214
216
  session: session,
215
217
  operation_timeouts: operation_timeouts(options)
216
218
  )
217
- cursor = read_with_retry_cursor(session, server_selector, self, context: context) do |server|
218
- # TODO take description from the connection used to send the query
219
- # once https://jira.mongodb.org/browse/RUBY-1601 is fixed.
220
- description = server.description
221
- send_initial_query(server, session, context, options)
222
- end
223
- # On 3.0+ servers, we get just the collection names.
224
- # On 2.6 server, we get collection names prefixed with the database
225
- # name. We need to filter system collections out here because
226
- # in the caller we don't know which server version executed the
227
- # command and thus what the proper filtering logic should be
228
- # (it is valid for collection names to have dots, thus filtering out
229
- # collections named system.* here for 2.6 servers would actually
230
- # filter out collections in the system database).
231
- if description.server_version_gte?('3.0')
232
- cursor.reject do |doc|
233
- doc['name'].start_with?('system.') || doc['name'].include?('$')
219
+ op = initial_query_op(session, options)
220
+ tracer.trace_operation(op, context, op_name: 'listCollections') do
221
+ cursor = read_with_retry_cursor(session, server_selector, self, context: context) do |server|
222
+ # TODO take description from the connection used to send the query
223
+ # once https://jira.mongodb.org/browse/RUBY-1601 is fixed.
224
+ description = server.description
225
+ send_initial_query(server, session, context, options)
234
226
  end
235
- else
236
- cursor.reject do |doc|
237
- doc['name'].start_with?("#{database.name}.system") || doc['name'].include?('$')
227
+ # On 3.0+ servers, we get just the collection names.
228
+ # On 2.6 server, we get collection names prefixed with the database
229
+ # name. We need to filter system collections out here because
230
+ # in the caller we don't know which server version executed the
231
+ # command and thus what the proper filtering logic should be
232
+ # (it is valid for collection names to have dots, thus filtering out
233
+ # collections named system.* here for 2.6 servers would actually
234
+ # filter out collections in the system database).
235
+ if description.server_version_gte?('3.0')
236
+ cursor.reject do |doc|
237
+ doc['name'].start_with?('system.') || doc['name'].include?('$')
238
+ end
239
+ else
240
+ cursor.reject do |doc|
241
+ doc['name'].start_with?("#{database.name}.system") || doc['name'].include?('$')
242
+ end
238
243
  end
239
244
  end
240
245
  end
@@ -74,7 +74,8 @@ module Mongo
74
74
  :server_selector,
75
75
  :read_concern,
76
76
  :write_concern,
77
- :encrypted_fields_map
77
+ :encrypted_fields_map,
78
+ :tracer
78
79
 
79
80
  # @return [ Mongo::Server ] Get the primary server from the cluster.
80
81
  def_delegators :cluster,
@@ -267,10 +268,12 @@ module Mongo
267
268
  # @option opts :session [ Session ] The session to use for this command.
268
269
  # @option opts [ Object ] :comment A user-provided
269
270
  # comment to attach to this command.
270
- # @option options [ Integer ] :timeout_ms The operation timeout in milliseconds.
271
+ # @option opts [ Integer ] :timeout_ms The operation timeout in milliseconds.
271
272
  # Must be a non-negative integer. An explicit value of 0 means infinite.
272
273
  # The default value is unset which means the value is inherited from
273
274
  # the database or the client.
275
+ # @option opts :op_name [ String | nil ] The name of the operation for
276
+ # tracing purposes.
274
277
  #
275
278
  # @return [ Hash ] The result of the command execution.
276
279
  # @api private
@@ -290,14 +293,18 @@ module Mongo
290
293
  session: session,
291
294
  operation_timeouts: operation_timeouts(opts)
292
295
  )
293
- read_with_retry(session, preference, context) do |server|
294
- Operation::Command.new(
295
- selector: operation.dup,
296
- db_name: name,
297
- read: preference,
298
- session: session,
299
- comment: opts[:comment],
300
- ).execute(server, context: context)
296
+ operation = Operation::Command.new(
297
+ selector: operation.dup,
298
+ db_name: name,
299
+ read: preference,
300
+ session: session,
301
+ comment: opts[:comment],
302
+ )
303
+ op_name = opts[:op_name] || 'command'
304
+ tracer.trace_operation(operation, context, op_name: op_name) do
305
+ read_with_retry(session, preference, context) do |server|
306
+ operation.execute(server, context: context)
307
+ end
301
308
  end
302
309
  end
303
310
  end
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mongo/loggable'
4
+
5
+ module Mongo
6
+ # Used for reporting deprecated behavior in the driver. When it is possible
7
+ # to detect that a deprecated feature is being used, a warning should be issued
8
+ # through this module.
9
+ #
10
+ # The warning will be issued no more than once for that feature, regardless
11
+ # of how many times Mongo::Deprecations.warn is called.
12
+ #
13
+ # @example Issue a deprecation warning.
14
+ # Mongo::Deprecations.warn(:old_feature, "The old_feature is deprecated, use new_feature instead.")
15
+ #
16
+ # @api private
17
+ module Deprecations
18
+ extend self
19
+ extend Mongo::Loggable
20
+
21
+ # Mutex for synchronizing access to warned features.
22
+ # @api private
23
+ MUTEX = Thread::Mutex.new
24
+
25
+ # Issue a warning about a deprecated feature. The warning is written to the
26
+ # logger, and will not be written more than once per feature.
27
+ #
28
+ # @param [ String | Symbol ] feature The deprecated feature.
29
+ # @param [ String ] message The deprecation message.
30
+ def warn(feature, message)
31
+ MUTEX.synchronize do
32
+ return if _warned?(feature)
33
+
34
+ _warned!(feature)
35
+ log_warn("[DEPRECATION:#{feature}] #{message}")
36
+ end
37
+ end
38
+
39
+ # Check if a warning for a given deprecated feature has already been issued.
40
+ #
41
+ # @param [ String | Symbol ] feature The deprecated feature.
42
+ # @param [ true | false ] prefix Whether to check for prefix matches.
43
+ #
44
+ # @return [ true | false ] If a warning has already been issued.
45
+ def warned?(feature, prefix: false)
46
+ MUTEX.synchronize { _warned?(feature, prefix: prefix) }
47
+ end
48
+
49
+ # Mark that a warning for a given deprecated feature has been issued.
50
+ #
51
+ # @param [ String | Symbol ] feature The deprecated feature.
52
+ def warned!(feature)
53
+ MUTEX.synchronize { _warned!(feature) }
54
+ nil
55
+ end
56
+
57
+ # Clears all memory of previously warned features.
58
+ def clear!
59
+ MUTEX.synchronize { warned_features reset: true }
60
+ nil
61
+ end
62
+
63
+ private
64
+
65
+ # Set of features that have already been warned about.
66
+ #
67
+ # @param [ true | false ] reset Whether to reset the warned features.
68
+ #
69
+ # @return [ Set<String> ] The set of warned features.
70
+ def warned_features(reset: false)
71
+ @warned_features = nil if reset
72
+ @warned_features ||= Set.new
73
+ end
74
+
75
+ # Check if a warning for a given deprecated feature has already been issued.
76
+ # This version is not thread-safe.
77
+ #
78
+ # @param [ String | Symbol ] feature The deprecated feature.
79
+ # @param [ true | false ] prefix Whether to check for prefix matches.
80
+ #
81
+ # @return [ true | false ] If a warning has already been issued.
82
+ def _warned?(feature, prefix: false)
83
+ if prefix
84
+ warned_features.any? { |f| f.to_s.start_with?(feature) }
85
+ else
86
+ warned_features.include?(feature.to_s)
87
+ end
88
+ end
89
+
90
+ # Mark that a warning for a given deprecated feature has been issued.
91
+ # This version is not thread-safe.
92
+ #
93
+ # @param [ String | Symbol ] feature The deprecated feature.
94
+ def _warned!(feature)
95
+ warned_features.add(feature.to_s)
96
+ end
97
+ end
98
+ end
@@ -45,6 +45,7 @@ module Mongo
45
45
 
46
46
  def_delegators :@collection, :cluster, :database, :read_preference, :write_concern, :client
47
47
  def_delegators :cluster, :next_primary
48
+ def_delegators :client, :tracer
48
49
 
49
50
  # The index key field.
50
51
  #
@@ -221,9 +222,7 @@ module Mongo
221
222
  end
222
223
 
223
224
  client.with_session(@options.merge(options)) do |session|
224
- server = next_primary(nil, session)
225
-
226
- indexes = normalize_models(models, server)
225
+ indexes = normalize_models(models)
227
226
  indexes.each do |index|
228
227
  if index[:bucketSize] || index['bucketSize']
229
228
  client.log_warn("Haystack indexes (bucketSize index option) are deprecated as of MongoDB 4.4")
@@ -244,7 +243,11 @@ module Mongo
244
243
  session: session,
245
244
  operation_timeouts: operation_timeouts(options)
246
245
  )
247
- Operation::CreateIndex.new(spec).execute(server, context: context)
246
+ operation = Operation::CreateIndex.new(spec)
247
+ tracer.trace_operation(operation, context, op_name: 'createIndexes') do
248
+ server = next_primary(nil, session)
249
+ operation.execute(server, context: context)
250
+ end
248
251
  end
249
252
  end
250
253
 
@@ -283,16 +286,18 @@ module Mongo
283
286
  session: session,
284
287
  operation_timeouts: operation_timeouts(@options)
285
288
  )
286
-
287
- cursor = read_with_retry_cursor(session, ServerSelector.primary, self, context: context) do |server|
288
- send_initial_query(server, session, context)
289
- end
290
- if block_given?
291
- cursor.each do |doc|
292
- yield doc
289
+ op = initial_query_op(session)
290
+ tracer.trace_operation(op, context, op_name: 'listIndexes') do
291
+ cursor = read_with_retry_cursor(session, ServerSelector.primary, self, context: context) do |server|
292
+ send_initial_query(op, server, session, context)
293
+ end
294
+ if block_given?
295
+ cursor.each do |doc|
296
+ yield doc
297
+ end
298
+ else
299
+ cursor.to_enum
293
300
  end
294
- else
295
- cursor.to_enum
296
301
  end
297
302
  end
298
303
 
@@ -359,13 +364,17 @@ module Mongo
359
364
  write_concern: write_concern,
360
365
  }
361
366
  spec[:comment] = opts[:comment] unless opts[:comment].nil?
362
- server = next_primary(nil, session)
363
367
  context = Operation::Context.new(
364
368
  client: client,
365
369
  session: session,
366
370
  operation_timeouts: operation_timeouts(opts)
367
371
  )
368
- Operation::DropIndex.new(spec).execute(server, context: context)
372
+ op = Operation::DropIndex.new(spec)
373
+ op_name = name == Index::ALL ? 'dropIndexes' : 'dropIndex'
374
+ tracer.trace_operation(op, context, op_name: op_name) do
375
+ server = next_primary(nil, session)
376
+ op.execute(server, context: context)
377
+ end
369
378
  end
370
379
  end
371
380
 
@@ -394,7 +403,7 @@ module Mongo
394
403
  Options::Mapper.transform_keys_to_strings(spec)
395
404
  end
396
405
 
397
- def normalize_models(models, server)
406
+ def normalize_models(models)
398
407
  models.map do |model|
399
408
  # Transform options first which gives us a mutable hash
400
409
  Options::Mapper.transform(model, OPTIONS).tap do |model|
@@ -403,12 +412,12 @@ module Mongo
403
412
  end
404
413
  end
405
414
 
406
- def send_initial_query(server, session, context)
415
+ def send_initial_query(op, server, session, context)
407
416
  if server.load_balancer?
408
417
  connection = server.pool.check_out(context: context)
409
- initial_query_op(session).execute_with_connection(connection, context: context)
418
+ op.execute_with_connection(connection, context: context)
410
419
  else
411
- initial_query_op(session).execute(server, context: context)
420
+ op.execute(server, context: context)
412
421
  end
413
422
  end
414
423
  end
@@ -28,6 +28,10 @@ module Mongo
28
28
  class Create
29
29
  include Specifiable
30
30
  include OpMsgExecutable
31
+
32
+ def encrypted_fields=(value)
33
+ @spec[:encrypted_fields] = value
34
+ end
31
35
  end
32
36
  end
33
37
  end
@@ -34,8 +34,11 @@ module Mongo
34
34
  private
35
35
 
36
36
  def get_result(connection, context, options = {})
37
- # This is a Mongo::Operation::Insert::Result
38
- Result.new(*dispatch_message(connection, context), @ids, context: context)
37
+ message = build_message(connection, context)
38
+ connection.tracer.trace_command(message, context, connection) do
39
+ result = Result.new(*dispatch_message(message, connection, context), @ids, context: context)
40
+ yield result
41
+ end
39
42
  end
40
43
 
41
44
  def selector(connection)
@@ -45,7 +45,7 @@ module Mongo
45
45
  add_error_labels(connection, context) do
46
46
  check_for_network_error do
47
47
  add_server_diagnostics(connection) do
48
- get_result(connection, context, options).tap do |result|
48
+ get_result(connection, context, options) do |result|
49
49
  if session
50
50
  if session.in_transaction? &&
51
51
  connection.description.load_balancer?
@@ -104,12 +104,19 @@ module Mongo
104
104
  end
105
105
 
106
106
  def get_result(connection, context, options = {})
107
- result_class.new(*dispatch_message(connection, context, options), context: context, connection: connection)
107
+ message = build_message(connection, context)
108
+ connection.tracer.trace_command(message, context, connection) do
109
+ result = result_class.new(*dispatch_message(message, connection, context, options), context: context, connection: connection)
110
+ if block_given?
111
+ yield result
112
+ else
113
+ result
114
+ end
115
+ end
108
116
  end
109
117
 
110
118
  # Returns a Protocol::Message or nil as reply.
111
- def dispatch_message(connection, context, options = {})
112
- message = build_message(connection, context)
119
+ def dispatch_message(message, connection, context, options = {})
113
120
  message = message.maybe_encrypt(connection, context)
114
121
  reply = connection.dispatch([ message ], context, options)
115
122
  [reply, connection.description, connection.global_id]
@@ -233,7 +233,7 @@ module Mongo
233
233
  #
234
234
  # @since 2.0.0
235
235
  def coll_name
236
- spec.fetch(COLL_NAME)
236
+ spec[COLL_NAME]
237
237
  end
238
238
 
239
239
  # The id of the cursor created on the server.
@@ -526,6 +526,10 @@ module Mongo
526
526
  @spec[:txn_num]
527
527
  end
528
528
 
529
+ def txn_num=(num)
530
+ @spec[:txn_num] = num
531
+ end
532
+
529
533
  # The command.
530
534
  #
531
535
  # @return [ Hash ] The command.