mongo 2.9.2 → 2.10.0.rc0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (227) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/lib/mongo.rb +1 -0
  5. data/lib/mongo/auth/user/view.rb +4 -4
  6. data/lib/mongo/bulk_write.rb +14 -8
  7. data/lib/mongo/bulk_write/result.rb +1 -1
  8. data/lib/mongo/bulk_write/result_combiner.rb +2 -2
  9. data/lib/mongo/bulk_write/transformable.rb +17 -9
  10. data/lib/mongo/client.rb +107 -16
  11. data/lib/mongo/cluster.rb +47 -25
  12. data/lib/mongo/cluster/topology/replica_set_no_primary.rb +1 -1
  13. data/lib/mongo/cluster_time.rb +139 -0
  14. data/lib/mongo/collection.rb +84 -25
  15. data/lib/mongo/collection/view.rb +7 -3
  16. data/lib/mongo/collection/view/aggregation.rb +4 -4
  17. data/lib/mongo/collection/view/builder/aggregation.rb +31 -6
  18. data/lib/mongo/collection/view/builder/find_command.rb +4 -1
  19. data/lib/mongo/collection/view/builder/map_reduce.rb +4 -1
  20. data/lib/mongo/collection/view/change_stream.rb +54 -66
  21. data/lib/mongo/collection/view/iterable.rb +2 -2
  22. data/lib/mongo/collection/view/map_reduce.rb +6 -4
  23. data/lib/mongo/collection/view/readable.rb +36 -16
  24. data/lib/mongo/collection/view/writable.rb +68 -22
  25. data/lib/mongo/cursor.rb +87 -20
  26. data/lib/mongo/database.rb +47 -43
  27. data/lib/mongo/database/view.rb +54 -11
  28. data/lib/mongo/error.rb +13 -4
  29. data/lib/mongo/error/invalid_write_concern.rb +2 -2
  30. data/lib/mongo/error/operation_failure.rb +65 -11
  31. data/lib/mongo/error/parser.rb +41 -8
  32. data/lib/mongo/grid/fs_bucket.rb +26 -6
  33. data/lib/mongo/grid/stream/read.rb +9 -2
  34. data/lib/mongo/grid/stream/write.rb +21 -5
  35. data/lib/mongo/index/view.rb +3 -3
  36. data/lib/mongo/lint.rb +10 -3
  37. data/lib/mongo/operation.rb +2 -0
  38. data/lib/mongo/operation/aggregate/result.rb +19 -6
  39. data/lib/mongo/operation/collections_info.rb +1 -1
  40. data/lib/mongo/operation/get_more/result.rb +9 -0
  41. data/lib/mongo/operation/list_collections/command.rb +1 -3
  42. data/lib/mongo/operation/list_collections/op_msg.rb +1 -2
  43. data/lib/mongo/operation/parallel_scan/command.rb +4 -1
  44. data/lib/mongo/operation/parallel_scan/op_msg.rb +4 -1
  45. data/lib/mongo/operation/result.rb +27 -4
  46. data/lib/mongo/operation/shared/executable.rb +19 -5
  47. data/lib/mongo/operation/shared/executable_no_validate.rb +1 -2
  48. data/lib/mongo/operation/shared/executable_transaction_label.rb +0 -9
  49. data/lib/mongo/operation/shared/polymorphic_result.rb +9 -1
  50. data/lib/mongo/operation/shared/result/aggregatable.rb +2 -2
  51. data/lib/mongo/operation/shared/sessions_supported.rb +42 -32
  52. data/lib/mongo/operation/shared/specifiable.rb +40 -0
  53. data/lib/mongo/operation/shared/unpinnable.rb +39 -0
  54. data/lib/mongo/operation/shared/write.rb +1 -1
  55. data/lib/mongo/protocol/update.rb +6 -2
  56. data/lib/mongo/retryable.rb +79 -39
  57. data/lib/mongo/server/connection.rb +10 -3
  58. data/lib/mongo/server/description.rb +25 -1
  59. data/lib/mongo/server/monitor/connection.rb +1 -1
  60. data/lib/mongo/server_selector.rb +10 -0
  61. data/lib/mongo/server_selector/selectable.rb +172 -32
  62. data/lib/mongo/session.rb +654 -581
  63. data/lib/mongo/session/session_pool.rb +1 -1
  64. data/lib/mongo/socket.rb +7 -28
  65. data/lib/mongo/socket/ssl.rb +26 -1
  66. data/lib/mongo/socket/tcp.rb +3 -0
  67. data/lib/mongo/socket/unix.rb +3 -0
  68. data/lib/mongo/uri.rb +112 -265
  69. data/lib/mongo/uri/srv_protocol.rb +4 -1
  70. data/lib/mongo/version.rb +1 -1
  71. data/lib/mongo/write_concern.rb +10 -29
  72. data/lib/mongo/write_concern/acknowledged.rb +12 -0
  73. data/lib/mongo/write_concern/base.rb +17 -13
  74. data/lib/mongo/write_concern/unacknowledged.rb +12 -0
  75. data/spec/atlas/atlas_connectivity_spec.rb +7 -37
  76. data/spec/atlas/operations_spec.rb +25 -0
  77. data/spec/integration/change_stream_examples_spec.rb +45 -31
  78. data/spec/integration/change_stream_spec.rb +305 -5
  79. data/spec/integration/client_spec.rb +44 -0
  80. data/spec/integration/command_monitoring_spec.rb +1 -0
  81. data/spec/integration/command_spec.rb +7 -1
  82. data/spec/integration/mmapv1_spec.rb +28 -0
  83. data/spec/integration/mongos_pinning_spec.rb +34 -0
  84. data/spec/integration/operation_failure_code_spec.rb +2 -2
  85. data/spec/integration/{read_concern.rb → read_concern_spec.rb} +7 -1
  86. data/spec/integration/read_preference_spec.rb +485 -0
  87. data/spec/integration/retryable_writes_spec.rb +8 -19
  88. data/spec/integration/sdam_error_handling_spec.rb +1 -1
  89. data/spec/integration/sdam_events_spec.rb +2 -2
  90. data/spec/integration/server_description_spec.rb +14 -17
  91. data/spec/integration/server_selector_spec.rb +7 -3
  92. data/spec/integration/server_spec.rb +48 -0
  93. data/spec/integration/ssl_uri_options_spec.rb +1 -1
  94. data/spec/integration/step_down_spec.rb +10 -4
  95. data/spec/integration/transactions_examples_spec.rb +11 -10
  96. data/spec/lite_spec_helper.rb +19 -16
  97. data/spec/mongo/auth/scram/negotiation_spec.rb +11 -8
  98. data/spec/mongo/bulk_write/ordered_combiner_spec.rb +6 -6
  99. data/spec/mongo/bulk_write/unordered_combiner_spec.rb +4 -4
  100. data/spec/mongo/bulk_write_spec.rb +12 -2
  101. data/spec/mongo/client_construction_spec.rb +160 -8
  102. data/spec/mongo/client_spec.rb +5 -4
  103. data/spec/mongo/cluster_spec.rb +6 -6
  104. data/spec/mongo/cluster_time_spec.rb +148 -0
  105. data/spec/mongo/collection/view/aggregation_spec.rb +34 -15
  106. data/spec/mongo/collection/view/change_stream_spec.rb +62 -3
  107. data/spec/mongo/collection/view/map_reduce_spec.rb +7 -5
  108. data/spec/mongo/collection/view/readable_spec.rb +4 -4
  109. data/spec/mongo/collection_spec.rb +331 -14
  110. data/spec/mongo/cursor_spec.rb +117 -5
  111. data/spec/mongo/database_spec.rb +240 -8
  112. data/spec/mongo/error/operation_failure_spec.rb +47 -1
  113. data/spec/mongo/error/parser_spec.rb +160 -23
  114. data/spec/mongo/operation/insert/bulk_spec.rb +2 -1
  115. data/spec/mongo/operation/result_spec.rb +27 -0
  116. data/spec/mongo/operation/update/bulk_spec.rb +1 -0
  117. data/spec/mongo/retryable_spec.rb +2 -0
  118. data/spec/mongo/server/app_metadata_spec.rb +2 -2
  119. data/spec/mongo/server/connection_spec.rb +13 -17
  120. data/spec/mongo/server/monitor/connection_spec.rb +13 -10
  121. data/spec/mongo/server_selector_spec.rb +34 -2
  122. data/spec/mongo/session/session_pool_spec.rb +14 -3
  123. data/spec/mongo/session_spec.rb +3 -3
  124. data/spec/mongo/session_transaction_spec.rb +4 -3
  125. data/spec/mongo/socket/ssl_spec.rb +19 -5
  126. data/spec/mongo/socket_spec.rb +1 -62
  127. data/spec/mongo/uri/srv_protocol_spec.rb +14 -20
  128. data/spec/mongo/uri_option_parsing_spec.rb +94 -8
  129. data/spec/mongo/uri_spec.rb +23 -10
  130. data/spec/mongo/write_concern_spec.rb +56 -3
  131. data/spec/spec_tests/change_streams_spec.rb +2 -1
  132. data/spec/spec_tests/cmap_spec.rb +1 -1
  133. data/spec/spec_tests/crud_spec.rb +12 -2
  134. data/spec/spec_tests/data/change_streams/change-streams-errors.yml +24 -1
  135. data/spec/spec_tests/data/change_streams/change-streams.yml +172 -3
  136. data/spec/spec_tests/data/command_monitoring/bulkWrite.yml +1 -1
  137. data/spec/spec_tests/data/command_monitoring/updateMany.yml +0 -2
  138. data/spec/spec_tests/data/command_monitoring/updateOne.yml +0 -5
  139. data/spec/spec_tests/data/crud/read/aggregate-out.yml +0 -6
  140. data/spec/spec_tests/data/crud/read/count-empty.yml +29 -0
  141. data/spec/spec_tests/data/crud/write/bulkWrite-arrayFilters.yml +1 -0
  142. data/spec/spec_tests/data/crud/write/bulkWrite-collation.yml +101 -0
  143. data/spec/spec_tests/data/crud/write/bulkWrite.yml +401 -0
  144. data/spec/spec_tests/data/crud/write/insertMany.yml +58 -2
  145. data/spec/spec_tests/data/crud/write/updateMany-arrayFilters.yml +3 -0
  146. data/spec/spec_tests/data/crud/write/updateOne-arrayFilters.yml +6 -1
  147. data/spec/spec_tests/data/crud_v2/aggregate-merge.yml +103 -0
  148. data/spec/spec_tests/data/crud_v2/aggregate-out-readConcern.yml +110 -0
  149. data/spec/spec_tests/data/crud_v2/bulkWrite-arrayFilters.yml +81 -0
  150. data/spec/spec_tests/data/crud_v2/db-aggregate.yml +38 -0
  151. data/spec/spec_tests/data/crud_v2/updateWithPipelines.yml +92 -0
  152. data/spec/spec_tests/data/retryable_writes/insertOne-serverErrors.yml +2 -2
  153. data/spec/spec_tests/data/transactions/abort.yml +3 -0
  154. data/spec/spec_tests/data/transactions/bulk.yml +3 -8
  155. data/spec/spec_tests/data/transactions/causal-consistency.yml +3 -8
  156. data/spec/spec_tests/data/transactions/commit.yml +3 -1
  157. data/spec/spec_tests/data/transactions/count.yml +3 -0
  158. data/spec/spec_tests/data/transactions/delete.yml +3 -0
  159. data/spec/spec_tests/data/transactions/error-labels.yml +4 -1
  160. data/spec/spec_tests/data/transactions/errors-client.yml +56 -0
  161. data/spec/spec_tests/data/transactions/errors.yml +3 -0
  162. data/spec/spec_tests/data/transactions/findOneAndDelete.yml +3 -0
  163. data/spec/spec_tests/data/transactions/findOneAndReplace.yml +3 -0
  164. data/spec/spec_tests/data/transactions/findOneAndUpdate.yml +3 -0
  165. data/spec/spec_tests/data/transactions/insert.yml +3 -0
  166. data/spec/spec_tests/data/transactions/isolation.yml +3 -0
  167. data/spec/spec_tests/data/transactions/mongos-pin-auto.yml +1671 -0
  168. data/spec/spec_tests/data/transactions/mongos-recovery-token.yml +347 -0
  169. data/spec/spec_tests/data/transactions/pin-mongos.yml +557 -0
  170. data/spec/spec_tests/data/transactions/read-concern.yml +3 -0
  171. data/spec/spec_tests/data/transactions/read-pref.yml +3 -0
  172. data/spec/spec_tests/data/transactions/reads.yml +3 -0
  173. data/spec/spec_tests/data/transactions/retryable-abort.yml +5 -2
  174. data/spec/spec_tests/data/transactions/retryable-commit.yml +4 -1
  175. data/spec/spec_tests/data/transactions/retryable-writes.yml +3 -0
  176. data/spec/spec_tests/data/transactions/run-command.yml +3 -0
  177. data/spec/spec_tests/data/transactions/transaction-options.yml +6 -0
  178. data/spec/spec_tests/data/transactions/update.yml +3 -8
  179. data/spec/spec_tests/data/transactions/write-concern.yml +348 -38
  180. data/spec/spec_tests/data/transactions_api/callback-aborts.yml +6 -0
  181. data/spec/spec_tests/data/transactions_api/callback-commits.yml +5 -0
  182. data/spec/spec_tests/data/transactions_api/callback-retry.yml +7 -2
  183. data/spec/spec_tests/data/transactions_api/commit-retry.yml +70 -15
  184. data/spec/spec_tests/data/transactions_api/commit-transienttransactionerror-4.2.yml +3 -0
  185. data/spec/spec_tests/data/transactions_api/commit-transienttransactionerror.yml +3 -0
  186. data/spec/spec_tests/data/transactions_api/commit-writeconcernerror.yml +59 -109
  187. data/spec/spec_tests/data/transactions_api/commit.yml +5 -0
  188. data/spec/spec_tests/data/transactions_api/transaction-options.yml +10 -0
  189. data/spec/spec_tests/retryable_reads_spec.rb +5 -2
  190. data/spec/spec_tests/retryable_writes_spec.rb +5 -2
  191. data/spec/spec_tests/sdam_monitoring_spec.rb +3 -3
  192. data/spec/spec_tests/sdam_spec.rb +2 -2
  193. data/spec/spec_tests/transactions_api_spec.rb +1 -67
  194. data/spec/spec_tests/transactions_spec.rb +2 -66
  195. data/spec/support/authorization.rb +4 -0
  196. data/spec/support/change_streams.rb +30 -10
  197. data/spec/support/change_streams/operation.rb +27 -0
  198. data/spec/support/client_registry.rb +44 -25
  199. data/spec/support/cluster_config.rb +25 -14
  200. data/spec/support/cluster_tools.rb +32 -10
  201. data/spec/support/command_monitoring.rb +1 -1
  202. data/spec/support/common_shortcuts.rb +30 -0
  203. data/spec/support/connection_string.rb +8 -3
  204. data/spec/support/constraints.rb +34 -0
  205. data/spec/support/crud.rb +31 -16
  206. data/spec/support/crud/context.rb +23 -0
  207. data/spec/support/crud/operation.rb +311 -14
  208. data/spec/support/crud/spec.rb +2 -1
  209. data/spec/support/crud/test.rb +24 -27
  210. data/spec/support/crud/test_base.rb +22 -0
  211. data/spec/support/crud/verifier.rb +15 -1
  212. data/spec/support/event_subscriber.rb +12 -0
  213. data/spec/support/sdam_formatter_integration.rb +12 -6
  214. data/spec/support/shared/server_selector.rb +10 -0
  215. data/spec/support/shared/session.rb +13 -12
  216. data/spec/support/spec_config.rb +32 -22
  217. data/spec/support/spec_setup.rb +2 -2
  218. data/spec/support/transactions.rb +87 -0
  219. data/spec/support/transactions/context.rb +33 -0
  220. data/spec/support/transactions/operation.rb +99 -349
  221. data/spec/support/transactions/spec.rb +1 -3
  222. data/spec/support/transactions/test.rb +110 -49
  223. data/spec/support/utils.rb +74 -1
  224. metadata +52 -10
  225. metadata.gz.sig +0 -0
  226. data/spec/support/crud/read.rb +0 -265
  227. data/spec/support/crud/write.rb +0 -284
@@ -24,6 +24,8 @@ module Mongo
24
24
  include Retryable
25
25
 
26
26
  def_delegators :@database, :cluster, :read_preference, :client
27
+ # @api private
28
+ def_delegators :@database, :server_selector, :read_concern
27
29
  def_delegators :cluster, :next_primary
28
30
 
29
31
  # @return [ Integer ] batch_size The size of the batch of results
@@ -38,8 +40,8 @@ module Mongo
38
40
 
39
41
  # Get all the names of the non-system collections in the database.
40
42
  #
41
- # @example Get the collection names.
42
- # database.collection_names
43
+ # @note The set of returned collection names depends on the version of
44
+ # MongoDB server that fulfills the request.
43
45
  #
44
46
  # @param [ Hash ] options Options for the listCollections command.
45
47
  #
@@ -52,21 +54,27 @@ module Mongo
52
54
  def collection_names(options = {})
53
55
  @batch_size = options[:batch_size]
54
56
  session = client.send(:get_session, options)
55
- cursor = read_with_retry_cursor(session, ServerSelector.get(mode: :primary), self) do |server|
57
+ cursor = read_with_retry_cursor(session, ServerSelector.primary, self) do |server|
56
58
  send_initial_query(server, session, name_only: true)
57
59
  end
58
60
  cursor.map do |info|
59
61
  if cursor.server.features.list_collections_enabled?
60
- info[Database::NAME]
62
+ info['name']
61
63
  else
62
- (info[Database::NAME] &&
63
- info[Database::NAME].sub("#{@database.name}.", ''))
64
+ (info['name'] &&
65
+ info['name'].sub("#{@database.name}.", ''))
64
66
  end
67
+ end.reject do |name|
68
+ name.start_with?('system.') || name.include?('$')
65
69
  end
66
70
  end
67
71
 
68
72
  # Get info on all the collections in the database.
69
73
  #
74
+ # @note The set of collections returned, and the schema of the
75
+ # information hash per collection, depends on the MongoDB server
76
+ # version that fulfills the request.
77
+ #
70
78
  # @example Get info on each collection.
71
79
  # database.list_collections
72
80
  #
@@ -75,7 +83,7 @@ module Mongo
75
83
  # @since 2.0.5
76
84
  def list_collections
77
85
  session = client.send(:get_session)
78
- collections_info(session, ServerSelector.get(mode: :primary))
86
+ collections_info(session, ServerSelector.primary)
79
87
  end
80
88
 
81
89
  # Create the new database view.
@@ -93,18 +101,53 @@ module Mongo
93
101
  @collection = @database[Database::COMMAND]
94
102
  end
95
103
 
104
+ # @api private
105
+ attr_reader :database
106
+
107
+ # Execute an aggregation on the database view.
108
+ #
109
+ # @example Aggregate documents.
110
+ # view.aggregate([
111
+ # { "$listLocalSessions" => {} }
112
+ # ])
113
+ #
114
+ # @param [ Array<Hash> ] pipeline The aggregation pipeline.
115
+ # @param [ Hash ] options The aggregation options.
116
+ #
117
+ # @return [ Aggregation ] The aggregation object.
118
+ #
119
+ # @since 2.10.0
120
+ # @api private
121
+ def aggregate(pipeline, options = {})
122
+ Collection::View::Aggregation.new(self, pipeline, options)
123
+ end
124
+
96
125
  private
97
126
 
98
127
  def collections_info(session, server_selector, options = {}, &block)
128
+ description = nil
99
129
  cursor = read_with_retry_cursor(session, server_selector, self) do |server|
130
+ # TODO take description from the connection used to send the query
131
+ # once https://jira.mongodb.org/browse/RUBY-1601 is fixed.
132
+ description = server.description
100
133
  send_initial_query(server, session, options)
101
134
  end
102
- if block_given?
103
- cursor.each do |doc|
104
- yield doc
135
+ # On 3.0+ servers, we get just the collection names.
136
+ # On 2.6 server, we get collection names prefixed with the database
137
+ # name. We need to filter system collections out here because
138
+ # in the caller we don't know which server version executed the
139
+ # command and thus what the proper filtering logic should be
140
+ # (it is valid for collection names to have dots, thus filtering out
141
+ # collections named system.* here for 2.6 servers would actually
142
+ # filter out collections in the system database).
143
+ if description.server_version_gte?('3.0')
144
+ cursor.reject do |doc|
145
+ doc['name'].start_with?('system.') || doc['name'].include?('$')
105
146
  end
106
147
  else
107
- cursor.to_enum
148
+ docs = cursor.reject do |doc|
149
+ doc['name'].start_with?("#{database.name}.system") || doc['name'].include?('$')
150
+ end
108
151
  end
109
152
  end
110
153
 
@@ -41,16 +41,19 @@ module Mongo
41
41
  # The constant for the writeErrors array.
42
42
  #
43
43
  # @since 2.0.0
44
+ # @deprecated
44
45
  WRITE_ERRORS = 'writeErrors'.freeze
45
46
 
46
47
  # The constant for a write concern error.
47
48
  #
48
49
  # @since 2.0.0
50
+ # @deprecated
49
51
  WRITE_CONCERN_ERROR = 'writeConcernError'.freeze
50
52
 
51
53
  # The constant for write concern errors.
52
54
  #
53
55
  # @since 2.1.0
56
+ # @deprecated
54
57
  WRITE_CONCERN_ERRORS = 'writeConcernErrors'.freeze
55
58
 
56
59
  # Constant for an unknown error.
@@ -85,17 +88,19 @@ module Mongo
85
88
  # manually retried by the user.
86
89
  #
87
90
  # @since 2.6.0
91
+ # @deprecated
88
92
  UNKNOWN_TRANSACTION_COMMIT_RESULT_LABEL = 'UnknownTransactionCommitResult'.freeze
89
93
 
90
94
  # Error label describing errors that will likely not occur if a transaction is manually retried
91
95
  # from the start.
92
96
  #
93
97
  # @since 2.6.0
98
+ # @deprecated
94
99
  TRANSIENT_TRANSACTION_ERROR_LABEL = 'TransientTransactionError'.freeze
95
100
 
96
101
  def initialize(msg = nil)
97
- @labels ||= []
98
- super(msg)
102
+ super
103
+ @labels = []
99
104
  end
100
105
 
101
106
  # Does the error have the given label?
@@ -124,8 +129,12 @@ module Mongo
124
129
  @labels.dup
125
130
  end
126
131
 
127
- private
128
-
132
+ # Adds the specified label to the error instance, if the label is not
133
+ # already in the set of labels.
134
+ #
135
+ # @param [ String ] label The label to add.
136
+ #
137
+ # @api private
129
138
  def add_label(label)
130
139
  @labels << label unless label?(label)
131
140
  end
@@ -26,8 +26,8 @@ module Mongo
26
26
  # Mongo::Error::InvalidWriteConcern.new
27
27
  #
28
28
  # @since 2.2.0
29
- def initialize
30
- super('Invalid write concern options. If w is an Integer, it must be greater than or equal to 0. ' +
29
+ def initialize(msg = nil)
30
+ super(msg || 'Invalid write concern options. If w is an Integer, it must be greater than or equal to 0. ' +
31
31
  'If w is 0, it cannot be combined with a true value for fsync or j (journal).')
32
32
  end
33
33
  end
@@ -70,11 +70,13 @@ module Mongo
70
70
 
71
71
  def_delegators :@result, :operation_time
72
72
 
73
- # @return [ Integer ] code The error code parsed from the document.
73
+ # @return [ Integer ] The error code parsed from the document.
74
+ #
74
75
  # @since 2.6.0
75
76
  attr_reader :code
76
77
 
77
- # @return [ String ] code_name The error code name parsed from the document.
78
+ # @return [ String ] The error code name parsed from the document.
79
+ #
78
80
  # @since 2.6.0
79
81
  attr_reader :code_name
80
82
 
@@ -141,8 +143,9 @@ module Mongo
141
143
  # @since 2.6.0
142
144
  def change_stream_resumable?
143
145
  if @result && @result.is_a?(Mongo::Operation::GetMore::Result)
144
- change_stream_resumable_message? ||
145
- change_stream_resumable_code?
146
+ !change_stream_not_resumable_label? &&
147
+ (change_stream_resumable_message? ||
148
+ change_stream_resumable_code?)
146
149
  else
147
150
  false
148
151
  end
@@ -162,6 +165,39 @@ module Mongo
162
165
  end
163
166
  private :change_stream_resumable_code?
164
167
 
168
+ def change_stream_not_resumable_label?
169
+ if labels
170
+ labels.include? 'NonResumableChangeStreamError'
171
+ else
172
+ false
173
+ end
174
+ end
175
+ private :change_stream_not_resumable_label?
176
+
177
+ # @return [ true | false ] Whether the failure includes a write
178
+ # concern error. A failure may have a top level error and a write
179
+ # concern error or either one of the two.
180
+ #
181
+ # @since 2.10.0
182
+ # @api experimental
183
+ def write_concern_error?
184
+ @write_concern_error
185
+ end
186
+
187
+ # @return [ Integer | nil ] The error code for the write concern error,
188
+ # if a write concern error is present and has a code.
189
+ #
190
+ # @since 2.10.0
191
+ # @api experimental
192
+ attr_reader :write_concern_error_code
193
+
194
+ # @return [ String | nil ] The code name for the write concern error,
195
+ # if a write concern error is present and has a code name.
196
+ #
197
+ # @since 2.10.0
198
+ # @api experimental
199
+ attr_reader :write_concern_error_code_name
200
+
165
201
  # Create the operation failure.
166
202
  #
167
203
  # @example Create the error object
@@ -172,22 +208,31 @@ module Mongo
172
208
  #
173
209
  # @param [ String ] message The error message.
174
210
  # @param [ Operation::Result ] result The result object.
175
- # @param [ Hash ] options Additional parameters
211
+ # @param [ Hash ] options Additional parameters.
176
212
  #
177
- # @option options [ Integer ] :code Error code
178
- # @option options [ String ] :code_name Error code name
213
+ # @option options [ Integer ] :code Error code.
214
+ # @option options [ String ] :code_name Error code name.
215
+ # @option options [ true | false ] :write_concern_error Whether the
216
+ # write concern error is present.
217
+ # @option options [ Integer ] :write_concern_error_code Error code for
218
+ # write concern error, if any.
219
+ # @option options [ String ] :write_concern_error_code_name Error code
220
+ # name for write concern error, if any.
179
221
  # @option options [ Array<String> ] :labels The set of labels associated
180
- # with the error
181
- # @option options [ true | false ] :wtimeout Whether the error is a wtimeout
222
+ # with the error.
223
+ # @option options [ true | false ] :wtimeout Whether the error is a wtimeout.
182
224
  #
183
225
  # @since 2.5.0, options added in 2.6.0
184
226
  def initialize(message = nil, result = nil, options = {})
227
+ super(message)
185
228
  @result = result
186
229
  @code = options[:code]
187
230
  @code_name = options[:code_name]
188
- @labels = options[:labels]
231
+ @write_concern_error = !!options[:write_concern_error]
232
+ @write_concern_error_code = options[:write_concern_error_code]
233
+ @write_concern_error_code_name = options[:write_concern_error_code_name]
234
+ @labels = options[:labels] || []
189
235
  @wtimeout = !!options[:wtimeout]
190
- super(message)
191
236
  end
192
237
 
193
238
  # Whether the error is a write concern timeout.
@@ -198,6 +243,15 @@ module Mongo
198
243
  def wtimeout?
199
244
  @wtimeout
200
245
  end
246
+
247
+ # Whether the error is MaxTimeMSExpired.
248
+ #
249
+ # @return [ true | false ] Whether the error is MaxTimeMSExpired.
250
+ #
251
+ # @since 2.10.0
252
+ def max_time_ms_expired?
253
+ code == 50 # MaxTimeMSExpired
254
+ end
201
255
  end
202
256
  end
203
257
  end
@@ -102,16 +102,49 @@ module Mongo
102
102
  parse!
103
103
  end
104
104
 
105
+ # @return [ true | false ] Whether the document includes a write
106
+ # concern error. A failure may have a top level error and a write
107
+ # concern error or either one of the two.
108
+ #
109
+ # @since 2.10.0
110
+ # @api experimental
111
+ def write_concern_error?
112
+ !!write_concern_error_document
113
+ end
114
+
115
+ # @return [ Integer | nil ] The error code for the write concern error,
116
+ # if a write concern error is present and has a code.
117
+ #
118
+ # @since 2.10.0
119
+ # @api experimental
120
+ def write_concern_error_code
121
+ write_concern_error_document && write_concern_error_document['code']
122
+ end
123
+
124
+ # @return [ String | nil ] The code name for the write concern error,
125
+ # if a write concern error is present and has a code name.
126
+ #
127
+ # @since 2.10.0
128
+ # @api experimental
129
+ def write_concern_error_code_name
130
+ write_concern_error_document && write_concern_error_document['codeName']
131
+ end
132
+
105
133
  private
106
134
 
135
+ def write_concern_error_document
136
+ document['writeConcernError']
137
+ end
138
+
107
139
  def parse!
108
140
  @message = ""
109
141
  parse_single(@message, ERR)
110
142
  parse_single(@message, ERROR)
111
143
  parse_single(@message, ERRMSG)
112
- parse_multiple(@message, WRITE_ERRORS)
113
- parse_single(@message, ERRMSG,
114
- document[WRITE_CONCERN_ERROR]) if document[WRITE_CONCERN_ERROR]
144
+ parse_multiple(@message, 'writeErrors')
145
+ if write_concern_error_document
146
+ parse_single(@message, ERRMSG, write_concern_error_document)
147
+ end
115
148
  parse_flag(@message)
116
149
  parse_code
117
150
  parse_labels
@@ -160,7 +193,7 @@ module Mongo
160
193
  # In practice this should never be an issue as a write concern
161
194
  # can only fail after the operation succeeds on the primary.
162
195
  if @code.nil? && @code_name.nil?
163
- if subdoc = document[WRITE_CONCERN_ERROR]
196
+ if subdoc = write_concern_error_document
164
197
  @code = subdoc['code']
165
198
  @code_name = subdoc['codeName']
166
199
  end
@@ -169,7 +202,7 @@ module Mongo
169
202
  if @code.nil? && @code_name.nil?
170
203
  # If we have writeErrors, and all of their codes are the same,
171
204
  # use that code. Otherwise don't set the code
172
- if write_errors = document[WRITE_ERRORS]
205
+ if write_errors = document['writeErrors']
173
206
  codes = write_errors.map { |e| e['code'] }.compact
174
207
  if codes.uniq.length == 1
175
208
  @code = codes.first
@@ -185,9 +218,9 @@ module Mongo
185
218
  end
186
219
 
187
220
  def parse_wtimeout
188
- @wtimeout = document[WRITE_CONCERN_ERROR] &&
189
- document[WRITE_CONCERN_ERROR]['errInfo'] &&
190
- document[WRITE_CONCERN_ERROR]['errInfo']['wtimeout']
221
+ @wtimeout = write_concern_error_document &&
222
+ write_concern_error_document['errInfo'] &&
223
+ write_concern_error_document['errInfo']['wtimeout']
191
224
  end
192
225
  end
193
226
  end
@@ -145,14 +145,25 @@ module Mongo
145
145
  # collections.
146
146
  # @option options [ Integer ] :chunk_size Override the default chunk
147
147
  # size.
148
- # @option options [ String ] :write The write concern.
149
148
  # @option options [ String ] :read The read preference.
150
149
  # @option options [ Session ] :session The session to use.
150
+ # @option options [ Hash ] :write Deprecated. Equivalent to :write_concern
151
+ # option.
152
+ # @option options [ Hash ] :write_concern The write concern options.
153
+ # Can be :w => Integer|String, :fsync => Boolean, :j => Boolean.
151
154
  #
152
155
  # @since 2.0.0
153
156
  def initialize(database, options = {})
154
157
  @database = database
155
- @options = options
158
+ @options = options.dup
159
+ =begin WriteConcern object support
160
+ if @options[:write_concern].is_a?(WriteConcern::Base)
161
+ # Cache the instance so that we do not needlessly reconstruct it.
162
+ @write_concern = @options[:write_concern]
163
+ @options[:write_concern] = @write_concern.options
164
+ end
165
+ =end
166
+ @options.freeze
156
167
  @chunks_collection = database[chunks_name]
157
168
  @files_collection = database[files_name]
158
169
  end
@@ -347,13 +358,16 @@ module Mongo
347
358
  #
348
359
  # @option opts [ Object ] :file_id An optional unique file id. An ObjectId is generated otherwise.
349
360
  # @option opts [ Integer ] :chunk_size Override the default chunk size.
350
- # @option opts [ Hash ] :write The write concern.
351
361
  # @option opts [ Hash ] :metadata User data for the 'metadata' field of the files
352
362
  # collection document.
353
363
  # @option opts [ String ] :content_type The content type of the file.
354
364
  # Deprecated, please use the metadata document instead.
355
365
  # @option opts [ Array<String> ] :aliases A list of aliases.
356
366
  # Deprecated, please use the metadata document instead.
367
+ # @option options [ Hash ] :write Deprecated. Equivalent to :write_concern
368
+ # option.
369
+ # @option options [ Hash ] :write_concern The write concern options.
370
+ # Can be :w => Integer|String, :fsync => Boolean, :j => Boolean.
357
371
  #
358
372
  # @return [ Stream::Write ] The write stream.
359
373
  #
@@ -386,13 +400,16 @@ module Mongo
386
400
  #
387
401
  # @option opts [ Object ] :file_id An optional unique file id. An ObjectId is generated otherwise.
388
402
  # @option opts [ Integer ] :chunk_size Override the default chunk size.
389
- # @option opts [ Hash ] :write The write concern.
390
403
  # @option opts [ Hash ] :metadata User data for the 'metadata' field of the files
391
404
  # collection document.
392
405
  # @option opts [ String ] :content_type The content type of the file. Deprecated, please
393
406
  # use the metadata document instead.
394
407
  # @option opts [ Array<String> ] :aliases A list of aliases. Deprecated, please use the
395
408
  # metadata document instead.
409
+ # @option options [ Hash ] :write Deprecated. Equivalent to :write_concern
410
+ # option.
411
+ # @option options [ Hash ] :write_concern The write concern options.
412
+ # Can be :w => Integer|String, :fsync => Boolean, :j => Boolean.
396
413
  #
397
414
  # @return [ BSON::ObjectId ] The ObjectId file id.
398
415
  #
@@ -432,8 +449,11 @@ module Mongo
432
449
  #
433
450
  # @since 2.1.0
434
451
  def write_concern
435
- @write_concern ||= @options[:write] ? WriteConcern.get(@options[:write]) :
436
- database.write_concern
452
+ @write_concern ||= if wco = @options[:write_concern] || @options[:write]
453
+ WriteConcern.get(wco)
454
+ else
455
+ database.write_concern
456
+ end
437
457
  end
438
458
 
439
459
  private