mongo 2.15.0 → 2.16.1

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 (332) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/README.md +1 -1
  4. data/lib/mongo/bulk_write.rb +2 -2
  5. data/lib/mongo/client.rb +45 -5
  6. data/lib/mongo/cluster/periodic_executor.rb +4 -3
  7. data/lib/mongo/cluster/reapers/cursor_reaper.rb +76 -43
  8. data/lib/mongo/cluster/sdam_flow.rb +9 -3
  9. data/lib/mongo/cluster/topology/base.rb +13 -9
  10. data/lib/mongo/cluster/topology/load_balanced.rb +102 -0
  11. data/lib/mongo/cluster/topology.rb +28 -8
  12. data/lib/mongo/cluster.rb +136 -51
  13. data/lib/mongo/collection/view/aggregation.rb +5 -10
  14. data/lib/mongo/collection/view/builder/aggregation.rb +6 -5
  15. data/lib/mongo/collection/view/builder/map_reduce.rb +12 -49
  16. data/lib/mongo/collection/view/builder.rb +0 -4
  17. data/lib/mongo/collection/view/iterable.rb +58 -24
  18. data/lib/mongo/collection/view/map_reduce.rb +39 -15
  19. data/lib/mongo/collection/view/readable.rb +60 -51
  20. data/lib/mongo/collection/view/writable.rb +178 -175
  21. data/lib/mongo/collection/view.rb +15 -21
  22. data/lib/mongo/collection.rb +13 -13
  23. data/lib/mongo/cursor/kill_spec.rb +38 -0
  24. data/lib/mongo/cursor.rb +72 -31
  25. data/lib/mongo/database/view.rb +1 -1
  26. data/lib/mongo/error/bad_load_balancer_target.rb +26 -0
  27. data/lib/mongo/error/missing_service_id.rb +26 -0
  28. data/lib/mongo/error/no_service_connection_available.rb +49 -0
  29. data/lib/mongo/error/notable.rb +7 -0
  30. data/lib/mongo/error.rb +3 -0
  31. data/lib/mongo/grid/fs_bucket.rb +21 -2
  32. data/lib/mongo/id.rb +7 -5
  33. data/lib/mongo/index/view.rb +22 -41
  34. data/lib/mongo/monitoring/event/cmap/pool_cleared.rb +7 -4
  35. data/lib/mongo/monitoring/event/command_failed.rb +1 -1
  36. data/lib/mongo/monitoring/event/command_started.rb +2 -0
  37. data/lib/mongo/monitoring/publishable.rb +2 -2
  38. data/lib/mongo/operation/aggregate/command.rb +8 -0
  39. data/lib/mongo/operation/context.rb +19 -1
  40. data/lib/mongo/operation/count/command.rb +6 -0
  41. data/lib/mongo/operation/count/op_msg.rb +6 -0
  42. data/lib/mongo/operation/create/command.rb +7 -1
  43. data/lib/mongo/operation/create/op_msg.rb +7 -0
  44. data/lib/mongo/operation/create_index/command.rb +17 -1
  45. data/lib/mongo/operation/create_index/op_msg.rb +17 -4
  46. data/lib/mongo/operation/delete/command.rb +6 -3
  47. data/lib/mongo/operation/delete/legacy.rb +9 -2
  48. data/lib/mongo/operation/delete/op_msg.rb +8 -1
  49. data/lib/mongo/operation/distinct/command.rb +6 -0
  50. data/lib/mongo/operation/distinct/op_msg.rb +7 -0
  51. data/lib/mongo/operation/explain/command.rb +13 -1
  52. data/lib/mongo/operation/explain/legacy.rb +12 -5
  53. data/lib/mongo/operation/explain/op_msg.rb +9 -1
  54. data/lib/mongo/operation/find/builder/command.rb +110 -0
  55. data/lib/mongo/{collection/view → operation/find}/builder/flags.rb +10 -14
  56. data/lib/mongo/operation/find/builder/legacy.rb +123 -0
  57. data/lib/mongo/{collection/view → operation/find}/builder/modifiers.rb +31 -25
  58. data/lib/mongo/{cursor → operation/find}/builder.rb +4 -4
  59. data/lib/mongo/operation/find/command.rb +9 -0
  60. data/lib/mongo/operation/find/legacy.rb +10 -1
  61. data/lib/mongo/operation/find/op_msg.rb +12 -0
  62. data/lib/mongo/operation/find.rb +1 -0
  63. data/lib/mongo/operation/get_more/command.rb +1 -0
  64. data/lib/mongo/operation/get_more/command_builder.rb +38 -0
  65. data/lib/mongo/operation/get_more/op_msg.rb +1 -0
  66. data/lib/mongo/operation/get_more.rb +1 -0
  67. data/lib/mongo/operation/kill_cursors/command.rb +8 -0
  68. data/lib/mongo/operation/kill_cursors/command_builder.rb +35 -0
  69. data/lib/mongo/operation/kill_cursors/legacy.rb +2 -1
  70. data/lib/mongo/operation/kill_cursors/op_msg.rb +10 -0
  71. data/lib/mongo/operation/kill_cursors.rb +1 -0
  72. data/lib/mongo/operation/map_reduce/command.rb +8 -0
  73. data/lib/mongo/operation/map_reduce/op_msg.rb +1 -1
  74. data/lib/mongo/operation/shared/executable.rb +15 -1
  75. data/lib/mongo/operation/shared/polymorphic_operation.rb +1 -1
  76. data/lib/mongo/operation/shared/read_preference_supported.rb +3 -1
  77. data/lib/mongo/operation/shared/response_handling.rb +1 -0
  78. data/lib/mongo/operation/shared/sessions_supported.rb +12 -12
  79. data/lib/mongo/operation/shared/specifiable.rb +11 -29
  80. data/lib/mongo/operation/shared/validatable.rb +87 -0
  81. data/lib/mongo/operation/shared/write.rb +1 -1
  82. data/lib/mongo/operation/update/command.rb +6 -3
  83. data/lib/mongo/operation/update/legacy.rb +19 -11
  84. data/lib/mongo/operation/update/op_msg.rb +7 -4
  85. data/lib/mongo/operation/write_command/command.rb +51 -0
  86. data/lib/mongo/operation/write_command/op_msg.rb +43 -0
  87. data/lib/mongo/operation/write_command.rb +32 -0
  88. data/lib/mongo/operation.rb +10 -0
  89. data/lib/mongo/protocol/query.rb +35 -18
  90. data/lib/mongo/server/connection.rb +25 -3
  91. data/lib/mongo/server/connection_base.rb +12 -1
  92. data/lib/mongo/server/connection_common.rb +38 -1
  93. data/lib/mongo/server/connection_pool/generation_manager.rb +71 -0
  94. data/lib/mongo/server/connection_pool.rb +100 -27
  95. data/lib/mongo/server/description/features.rb +17 -16
  96. data/lib/mongo/server/description/load_balancer.rb +33 -0
  97. data/lib/mongo/server/description.rb +85 -6
  98. data/lib/mongo/server/monitor/connection.rb +5 -6
  99. data/lib/mongo/server/monitor.rb +2 -1
  100. data/lib/mongo/server/pending_connection.rb +47 -31
  101. data/lib/mongo/server/push_monitor.rb +10 -1
  102. data/lib/mongo/server.rb +73 -26
  103. data/lib/mongo/server_selector/base.rb +5 -1
  104. data/lib/mongo/session/session_pool.rb +11 -0
  105. data/lib/mongo/session.rb +21 -1
  106. data/lib/mongo/socket/ocsp_verifier.rb +6 -37
  107. data/lib/mongo/uri/options_mapper.rb +1 -0
  108. data/lib/mongo/uri/srv_protocol.rb +6 -8
  109. data/lib/mongo/uri.rb +18 -0
  110. data/lib/mongo/utils.rb +0 -7
  111. data/lib/mongo/version.rb +1 -1
  112. data/mongo.gemspec +1 -1
  113. data/spec/integration/auth_spec.rb +31 -1
  114. data/spec/integration/awaited_ismaster_spec.rb +1 -1
  115. data/spec/integration/bulk_write_spec.rb +1 -1
  116. data/spec/integration/change_stream_spec.rb +3 -3
  117. data/spec/integration/client_construction_spec.rb +54 -0
  118. data/spec/integration/client_side_encryption/auto_encryption_bulk_writes_spec.rb +1 -1
  119. data/spec/integration/client_side_encryption/auto_encryption_command_monitoring_spec.rb +1 -1
  120. data/spec/integration/client_side_encryption/bson_size_limit_spec.rb +1 -1
  121. data/spec/integration/client_side_encryption/data_key_spec.rb +1 -1
  122. data/spec/integration/client_spec.rb +2 -0
  123. data/spec/integration/command_monitoring_spec.rb +1 -1
  124. data/spec/integration/command_spec.rb +1 -1
  125. data/spec/integration/connection_spec.rb +52 -35
  126. data/spec/integration/crud_spec.rb +174 -1
  127. data/spec/integration/cursor_pinning_spec.rb +121 -0
  128. data/spec/integration/cursor_reaping_spec.rb +8 -4
  129. data/spec/integration/fork_reconnect_spec.rb +1 -5
  130. data/spec/integration/get_more_spec.rb +1 -1
  131. data/spec/integration/heartbeat_events_spec.rb +1 -1
  132. data/spec/integration/map_reduce_spec.rb +77 -0
  133. data/spec/integration/query_cache_spec.rb +47 -2
  134. data/spec/integration/query_cache_transactions_spec.rb +1 -1
  135. data/spec/integration/read_concern_spec.rb +1 -1
  136. data/spec/integration/read_preference_spec.rb +1 -1
  137. data/spec/integration/reconnect_spec.rb +30 -12
  138. data/spec/integration/retryable_errors_spec.rb +1 -1
  139. data/spec/integration/retryable_writes/retryable_writes_36_and_older_spec.rb +1 -1
  140. data/spec/integration/retryable_writes/retryable_writes_40_and_newer_spec.rb +1 -1
  141. data/spec/integration/sdam_error_handling_spec.rb +5 -3
  142. data/spec/integration/sdam_events_spec.rb +35 -19
  143. data/spec/integration/sdam_prose_spec.rb +1 -1
  144. data/spec/integration/server_monitor_spec.rb +1 -0
  145. data/spec/integration/server_selector_spec.rb +22 -5
  146. data/spec/integration/server_spec.rb +2 -0
  147. data/spec/integration/srv_monitoring_spec.rb +1 -1
  148. data/spec/integration/step_down_spec.rb +1 -1
  149. data/spec/integration/transaction_pinning_spec.rb +120 -0
  150. data/spec/integration/versioned_api_examples_spec.rb +45 -0
  151. data/spec/integration/x509_auth_spec.rb +1 -1
  152. data/spec/lite_spec_helper.rb +1 -2
  153. data/spec/mongo/address/unix_spec.rb +1 -0
  154. data/spec/mongo/auth/cr_spec.rb +2 -3
  155. data/spec/mongo/auth/ldap_spec.rb +2 -3
  156. data/spec/mongo/auth/scram_spec.rb +2 -3
  157. data/spec/mongo/auth/user/view_spec.rb +1 -1
  158. data/spec/mongo/auth/x509_spec.rb +2 -3
  159. data/spec/mongo/bulk_write_spec.rb +3 -3
  160. data/spec/mongo/client_construction_spec.rb +259 -28
  161. data/spec/mongo/client_spec.rb +6 -4
  162. data/spec/mongo/cluster/cursor_reaper_spec.rb +36 -21
  163. data/spec/mongo/cluster/periodic_executor_spec.rb +3 -1
  164. data/spec/mongo/cluster_spec.rb +44 -3
  165. data/spec/mongo/collection/view/aggregation_spec.rb +1 -1
  166. data/spec/mongo/collection/view/builder/find_command_spec.rb +4 -0
  167. data/spec/mongo/collection/view/builder/op_query_spec.rb +4 -0
  168. data/spec/mongo/collection/view/map_reduce_spec.rb +1 -1
  169. data/spec/mongo/collection_crud_spec.rb +7 -2
  170. data/spec/mongo/collection_ddl_spec.rb +1 -1
  171. data/spec/mongo/collection_spec.rb +1 -1
  172. data/spec/mongo/cursor/builder/get_more_command_spec.rb +4 -0
  173. data/spec/mongo/cursor/builder/op_get_more_spec.rb +4 -0
  174. data/spec/mongo/cursor_spec.rb +15 -5
  175. data/spec/mongo/database_spec.rb +15 -15
  176. data/spec/mongo/error/operation_failure_heavy_spec.rb +1 -1
  177. data/spec/mongo/grid/fs_bucket_spec.rb +18 -12
  178. data/spec/mongo/grid/stream/write_spec.rb +3 -9
  179. data/spec/mongo/grid/stream_spec.rb +1 -1
  180. data/spec/mongo/index/view_spec.rb +2 -2
  181. data/spec/mongo/operation/delete/op_msg_spec.rb +1 -1
  182. data/spec/mongo/{collection/view → operation/find}/builder/flags_spec.rb +2 -2
  183. data/spec/mongo/{collection/view → operation/find}/builder/modifiers_spec.rb +2 -2
  184. data/spec/mongo/operation/find/legacy_spec.rb +1 -0
  185. data/spec/mongo/operation/insert/bulk_spec.rb +1 -1
  186. data/spec/mongo/operation/insert/op_msg_spec.rb +1 -1
  187. data/spec/mongo/operation/kill_cursors_spec.rb +4 -1
  188. data/spec/mongo/operation/read_preference_legacy_spec.rb +4 -0
  189. data/spec/mongo/operation/read_preference_op_msg_spec.rb +2 -0
  190. data/spec/mongo/operation/update/bulk_spec.rb +1 -1
  191. data/spec/mongo/operation/update/op_msg_spec.rb +1 -1
  192. data/spec/mongo/query_cache_spec.rb +6 -2
  193. data/spec/mongo/server/connection_common_spec.rb +62 -11
  194. data/spec/mongo/server/connection_pool_spec.rb +73 -7
  195. data/spec/mongo/server/connection_spec.rb +138 -43
  196. data/spec/mongo/server/description_spec.rb +1 -1
  197. data/spec/mongo/server/monitor/connection_spec.rb +22 -0
  198. data/spec/mongo/server/monitor_spec.rb +4 -3
  199. data/spec/mongo/server/push_monitor_spec.rb +101 -0
  200. data/spec/mongo/session/session_pool_spec.rb +42 -10
  201. data/spec/mongo/session_transaction_spec.rb +15 -30
  202. data/spec/mongo/socket/unix_spec.rb +1 -0
  203. data/spec/mongo/uri_option_parsing_spec.rb +38 -5
  204. data/spec/runners/change_streams/test.rb +1 -1
  205. data/spec/runners/cmap.rb +1 -1
  206. data/spec/runners/connection_string.rb +7 -3
  207. data/spec/runners/crud/operation.rb +5 -3
  208. data/spec/runners/crud/requirement.rb +1 -0
  209. data/spec/runners/crud.rb +1 -1
  210. data/spec/runners/sdam.rb +2 -1
  211. data/spec/runners/transactions/test.rb +2 -2
  212. data/spec/runners/unified/assertions.rb +2 -3
  213. data/spec/runners/unified/event_subscriber.rb +2 -2
  214. data/spec/runners/unified/support_operations.rb +10 -2
  215. data/spec/runners/unified/test.rb +3 -0
  216. data/spec/runners/unified.rb +1 -1
  217. data/spec/shared/lib/mrss/cluster_config.rb +6 -1
  218. data/spec/shared/lib/mrss/constraints.rb +11 -5
  219. data/spec/shared/lib/mrss/event_subscriber.rb +200 -0
  220. data/spec/shared/lib/mrss/server_version_registry.rb +17 -12
  221. data/spec/shared/share/Dockerfile.erb +5 -4
  222. data/spec/shared/shlib/server.sh +70 -20
  223. data/spec/spec_tests/change_streams_spec.rb +1 -1
  224. data/spec/spec_tests/cmap_spec.rb +4 -1
  225. data/spec/spec_tests/command_monitoring_spec.rb +2 -2
  226. data/spec/spec_tests/data/command_monitoring/find.yml +9 -9
  227. data/spec/spec_tests/data/crud/read/aggregate-collation.yml +2 -1
  228. data/spec/spec_tests/data/crud/read/aggregate-out.yml +1 -0
  229. data/spec/spec_tests/data/crud/read/count-collation.yml +2 -1
  230. data/spec/spec_tests/data/crud/read/distinct-collation.yml +2 -1
  231. data/spec/spec_tests/data/crud/read/find-collation.yml +2 -1
  232. data/spec/spec_tests/data/crud/write/bulkWrite-collation.yml +2 -1
  233. data/spec/spec_tests/data/crud/write/deleteMany-collation.yml +2 -1
  234. data/spec/spec_tests/data/crud/write/deleteOne-collation.yml +2 -1
  235. data/spec/spec_tests/data/crud/write/findOneAndDelete-collation.yml +3 -2
  236. data/spec/spec_tests/data/crud/write/findOneAndReplace-collation.yml +2 -1
  237. data/spec/spec_tests/data/crud/write/findOneAndUpdate-collation.yml +3 -2
  238. data/spec/spec_tests/data/crud/write/replaceOne-collation.yml +3 -2
  239. data/spec/spec_tests/data/crud/write/updateMany-collation.yml +2 -1
  240. data/spec/spec_tests/data/crud/write/updateOne-collation.yml +2 -1
  241. data/spec/spec_tests/data/load_balancers/event-monitoring.yml +99 -0
  242. data/spec/spec_tests/data/load_balancers/lb-connection-establishment.yml +36 -0
  243. data/spec/spec_tests/data/load_balancers/non-lb-connection-establishment.yml +56 -0
  244. data/spec/spec_tests/data/load_balancers/server-selection.yml +50 -0
  245. data/spec/spec_tests/data/retryable_reads/changeStreams-client.watch-serverErrors.yml +1 -1
  246. data/spec/spec_tests/data/retryable_reads/changeStreams-client.watch.yml +1 -1
  247. data/spec/spec_tests/data/retryable_reads/changeStreams-db.coll.watch-serverErrors.yml +1 -1
  248. data/spec/spec_tests/data/retryable_reads/changeStreams-db.coll.watch.yml +1 -1
  249. data/spec/spec_tests/data/retryable_reads/changeStreams-db.watch-serverErrors.yml +1 -1
  250. data/spec/spec_tests/data/retryable_reads/changeStreams-db.watch.yml +1 -1
  251. data/spec/spec_tests/data/retryable_reads/mapReduce.yml +3 -1
  252. data/spec/spec_tests/data/sdam/load-balanced/discover_load_balancer.yml +25 -0
  253. data/spec/spec_tests/data/sdam_integration/find-network-error.yml +2 -0
  254. data/spec/spec_tests/data/sdam_integration/find-shutdown-error.yml +2 -0
  255. data/spec/spec_tests/data/sdam_integration/hello-command-error.yml +3 -1
  256. data/spec/spec_tests/data/sdam_integration/hello-network-error.yml +3 -1
  257. data/spec/spec_tests/data/sdam_integration/hello-timeout.yml +2 -0
  258. data/spec/spec_tests/data/sdam_integration/insert-network-error.yml +2 -0
  259. data/spec/spec_tests/data/sdam_integration/insert-shutdown-error.yml +2 -0
  260. data/spec/spec_tests/data/sdam_monitoring/load_balancer.yml +65 -0
  261. data/spec/spec_tests/data/seed_list_discovery/load-balanced/loadBalanced-directConnection.yml +13 -0
  262. data/spec/spec_tests/data/seed_list_discovery/load-balanced/loadBalanced-replicaSet-errors.yml +6 -0
  263. data/spec/spec_tests/data/seed_list_discovery/load-balanced/loadBalanced-true-multiple-hosts.yml +5 -0
  264. data/spec/spec_tests/data/seed_list_discovery/load-balanced/loadBalanced-true-txt.yml +10 -0
  265. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/direct-connection-false.yml +0 -0
  266. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/direct-connection-true.yml +0 -0
  267. data/spec/spec_tests/data/seed_list_discovery/replica-set/encoded-userinfo-and-db.yml +15 -0
  268. data/spec/spec_tests/data/seed_list_discovery/replica-set/loadBalanced-false-txt.yml +10 -0
  269. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/longer-parent-in-return.yml +0 -0
  270. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/misformatted-option.yml +0 -0
  271. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/no-results.yml +0 -0
  272. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/not-enough-parts.yml +0 -0
  273. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/one-result-default-port.yml +0 -0
  274. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/one-txt-record-multiple-strings.yml +0 -0
  275. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/one-txt-record.yml +0 -0
  276. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/parent-part-mismatch1.yml +0 -0
  277. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/parent-part-mismatch2.yml +0 -0
  278. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/parent-part-mismatch3.yml +0 -0
  279. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/parent-part-mismatch4.yml +0 -0
  280. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/parent-part-mismatch5.yml +0 -0
  281. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/returned-parent-too-short.yml +0 -0
  282. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/returned-parent-wrong.yml +0 -0
  283. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/two-results-default-port.yml +0 -0
  284. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/two-results-nonstandard-port.yml +0 -0
  285. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/two-txt-records.yml +0 -0
  286. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/txt-record-not-allowed-option.yml +0 -0
  287. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/txt-record-with-overridden-ssl-option.yml +0 -0
  288. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/txt-record-with-overridden-uri-option.yml +0 -0
  289. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/txt-record-with-unallowed-option.yml +0 -0
  290. data/spec/spec_tests/data/seed_list_discovery/replica-set/uri-with-admin-database.yml +13 -0
  291. data/spec/spec_tests/data/seed_list_discovery/replica-set/uri-with-auth.yml +12 -0
  292. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/uri-with-port.yml +0 -0
  293. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/uri-with-two-hosts.yml +0 -0
  294. data/spec/spec_tests/data/transactions/retryable-abort-errorLabels.yml +2 -0
  295. data/spec/spec_tests/data/transactions/retryable-abort.yml +2 -0
  296. data/spec/spec_tests/data/transactions/retryable-commit-errorLabels.yml +2 -0
  297. data/spec/spec_tests/data/transactions/retryable-commit.yml +2 -0
  298. data/spec/spec_tests/data/transactions/retryable-writes.yml +2 -0
  299. data/spec/spec_tests/data/uri_options/connection-options.yml +60 -0
  300. data/spec/spec_tests/load_balancers_spec.rb +15 -0
  301. data/spec/spec_tests/retryable_reads_spec.rb +2 -2
  302. data/spec/spec_tests/retryable_writes_spec.rb +1 -1
  303. data/spec/spec_tests/sdam_integration_spec.rb +1 -1
  304. data/spec/spec_tests/sdam_monitoring_spec.rb +10 -5
  305. data/spec/spec_tests/sdam_spec.rb +1 -1
  306. data/spec/spec_tests/seed_list_discovery_spec.rb +118 -0
  307. data/spec/spec_tests/uri_options_spec.rb +4 -4
  308. data/spec/stress/fork_reconnect_stress_spec.rb +1 -5
  309. data/spec/stress/push_monitor_close_spec.rb +44 -0
  310. data/spec/support/certificates/atlas-ocsp-ca.crt +82 -90
  311. data/spec/support/certificates/atlas-ocsp.crt +127 -122
  312. data/spec/support/common_shortcuts.rb +2 -3
  313. data/spec/support/matchers.rb +13 -0
  314. data/spec/support/shared/auth_context.rb +16 -0
  315. data/spec/support/shared/session.rb +2 -2
  316. data/spec/support/spec_config.rb +10 -11
  317. data/spec/support/using_hash.rb +31 -0
  318. data/spec/support/utils.rb +1 -1
  319. data.tar.gz.sig +0 -0
  320. metadata +1077 -1029
  321. metadata.gz.sig +0 -0
  322. data/lib/mongo/collection/view/builder/find_command.rb +0 -173
  323. data/lib/mongo/collection/view/builder/op_query.rb +0 -94
  324. data/lib/mongo/cursor/builder/get_more_command.rb +0 -80
  325. data/lib/mongo/cursor/builder/kill_cursors_command.rb +0 -111
  326. data/lib/mongo/cursor/builder/op_get_more.rb +0 -64
  327. data/lib/mongo/cursor/builder/op_kill_cursors.rb +0 -106
  328. data/lib/mongo/server/context.rb +0 -72
  329. data/spec/mongo/cursor/builder/op_kill_cursors_spec.rb +0 -66
  330. data/spec/runners/unified/using_hash.rb +0 -34
  331. data/spec/spec_tests/dns_seedlist_discovery_spec.rb +0 -79
  332. data/spec/support/event_subscriber.rb +0 -221
@@ -24,16 +24,6 @@ module Mongo
24
24
  # @since 2.0.0
25
25
  module Readable
26
26
 
27
- # The query modifier constant.
28
- #
29
- # @since 2.2.0
30
- QUERY = '$query'.freeze
31
-
32
- # The modifiers option constant.
33
- #
34
- # @since 2.2.0
35
- MODIFIERS = 'modifiers'.freeze
36
-
37
27
  # Execute an aggregation on the collection view.
38
28
  #
39
29
  # @example Aggregate documents.
@@ -169,13 +159,15 @@ module Mongo
169
159
  selector = ServerSelector.get(read_pref || server_selector)
170
160
  with_session(opts) do |session|
171
161
  read_with_retry(session, selector) do |server|
172
- apply_collation!(cmd, server, opts)
173
162
  Operation::Count.new(
174
- :selector => cmd,
175
- :db_name => database.name,
176
- :options => {:limit => -1},
177
- :read => read_pref,
178
- :session => session,
163
+ selector: cmd,
164
+ db_name: database.name,
165
+ options: {:limit => -1},
166
+ read: read_pref,
167
+ session: session,
168
+ # For some reason collation was historically accepted as a
169
+ # string key. Note that this isn't documented as valid usage.
170
+ collation: opts[:collation] || opts['collation'] || collation,
179
171
  ).execute(server, context: Operation::Context.new(client: client, session: session))
180
172
  end.n.to_i
181
173
  end
@@ -243,8 +235,8 @@ module Mongo
243
235
  read_pref = opts[:read] || read_preference
244
236
  selector = ServerSelector.get(read_pref || server_selector)
245
237
  with_session(opts) do |session|
246
- context = Operation::Context.new(client: client, session: session)
247
238
  read_with_retry(session, selector) do |server|
239
+ context = Operation::Context.new(client: client, session: session)
248
240
  if server.description.server_version_gte?('5.0')
249
241
  pipeline = [
250
242
  {'$collStats' => {'count' => {}}},
@@ -315,14 +307,16 @@ module Mongo
315
307
  selector = ServerSelector.get(read_pref || server_selector)
316
308
  with_session(opts) do |session|
317
309
  read_with_retry(session, selector) do |server|
318
- apply_collation!(cmd, server, opts)
319
- Operation::Distinct.new({
320
- :selector => cmd,
321
- :db_name => database.name,
322
- :options => {:limit => -1},
323
- :read => read_pref,
324
- :session => session,
325
- }).execute(server, context: Operation::Context.new(client: client, session: session))
310
+ Operation::Distinct.new(
311
+ selector: cmd,
312
+ db_name: database.name,
313
+ options: {:limit => -1},
314
+ read: read_pref,
315
+ session: session,
316
+ # For some reason collation was historically accepted as a
317
+ # string key. Note that this isn't documented as valid usage.
318
+ collation: opts[:collation] || opts['collation'] || collation,
319
+ ).execute(server, context: Operation::Context.new(client: client, session: session))
326
320
  end.first['values']
327
321
  end
328
322
  end
@@ -542,7 +536,11 @@ module Mongo
542
536
  configure(:sort, spec)
543
537
  end
544
538
 
545
- # “meta” operators that let you modify the output or behavior of a query.
539
+ # If called without arguments or with a nil argument, returns
540
+ # the legacy (OP_QUERY) server modifiers for the current view.
541
+ # If called with a non-nil argument, which must be a Hash or a
542
+ # subclass, merges the provided modifiers into the current view.
543
+ # Both string and symbol keys are allowed in the input hash.
546
544
  #
547
545
  # @example Set the modifiers document.
548
546
  # view.modifiers(:$orderby => Mongo::Index::ASCENDING)
@@ -553,8 +551,11 @@ module Mongo
553
551
  #
554
552
  # @since 2.1.0
555
553
  def modifiers(doc = nil)
556
- return Builder::Modifiers.map_server_modifiers(options) if doc.nil?
557
- new(options.merge(Builder::Modifiers.map_driver_options(doc)))
554
+ if doc.nil?
555
+ Operation::Find::Builder::Modifiers.map_server_modifiers(options)
556
+ else
557
+ new(options.merge(Operation::Find::Builder::Modifiers.map_driver_options(BSON::Document.new(doc))))
558
+ end
558
559
  end
559
560
 
560
561
  # A cumulative time limit in milliseconds for processing get more operations
@@ -645,34 +646,42 @@ module Mongo
645
646
 
646
647
  def parallel_scan(cursor_count, options = {})
647
648
  if options[:session]
649
+ # The session would be overwritten by the one in +options+ later.
648
650
  session = client.send(:get_session, @options)
649
651
  else
650
652
  session = nil
651
653
  end
652
654
  server = server_selector.select_server(cluster, nil, session)
653
- cmd = Operation::ParallelScan.new({
654
- :coll_name => collection.name,
655
- :db_name => database.name,
656
- :cursor_count => cursor_count,
657
- :read_concern => read_concern,
658
- :session => session,
659
- }.merge!(options))
660
- cmd.execute(server, context: Operation::Context.new(client: client, session: session)).cursor_ids.map do |cursor_id|
661
- result = if server.with_connection { |connection| connection.features }.find_command_enabled?
662
- Operation::GetMore.new({
663
- :selector => {:getMore => BSON::Int64.new(cursor_id),
664
- :collection => collection.name},
665
- :db_name => database.name,
666
- :session => session,
667
- }).execute(server, context: Operation::Context.new(client: client, session: session))
668
- else
669
- Operation::GetMore.new({
670
- :to_return => 0,
671
- :cursor_id => BSON::Int64.new(cursor_id),
672
- :db_name => database.name,
673
- :coll_name => collection.name
674
- }).execute(server, context: Operation::Context.new(client: client, session: session))
675
- end
655
+ spec = {
656
+ coll_name: collection.name,
657
+ db_name: database.name,
658
+ cursor_count: cursor_count,
659
+ read_concern: read_concern,
660
+ session: session,
661
+ }.update(options)
662
+ session = spec[:session]
663
+ op = Operation::ParallelScan.new(spec)
664
+ # Note that the context object shouldn't be reused for subsequent
665
+ # GetMore operations.
666
+ context = Operation::Context.new(client: client, session: session)
667
+ result = op.execute(server, context: context)
668
+ result.cursor_ids.map do |cursor_id|
669
+ spec = {
670
+ cursor_id: cursor_id,
671
+ coll_name: collection.name,
672
+ db_name: database.name,
673
+ session: session,
674
+ batch_size: batch_size,
675
+ to_return: 0,
676
+ # max_time_ms is not being passed here, I assume intentionally?
677
+ }
678
+ op = Operation::GetMore.new(spec)
679
+ context = Operation::Context.new(
680
+ client: client,
681
+ session: session,
682
+ service_id: result.connection_description.service_id,
683
+ )
684
+ result = op.execute(server, context: context)
676
685
  Cursor.new(self, result, server, session: session)
677
686
  end
678
687
  end
@@ -46,33 +46,44 @@ module Mongo
46
46
  # @option opts [ Session ] :session The session to use.
47
47
  # @option opts [ Hash | String ] :hint The index to use for this operation.
48
48
  # May be specified as a Hash (e.g. { _id: 1 }) or a String (e.g. "_id_").
49
+ # @option opts [ Hash ] :write_concern The write concern options.
50
+ # Can be :w => Integer, :fsync => Boolean, :j => Boolean.
49
51
  #
50
52
  # @return [ BSON::Document, nil ] The document, if found.
51
53
  #
52
54
  # @since 2.0.0
53
55
  def find_one_and_delete(opts = {})
54
- QueryCache.clear_namespace(collection.namespace)
55
-
56
- cmd = { :findAndModify => collection.name, :query => filter, :remove => true }
57
- cmd[:fields] = projection if projection
58
- cmd[:sort] = sort if sort
59
- cmd[:maxTimeMS] = max_time_ms if max_time_ms
60
- if opts[:bypass_document_validation]
61
- cmd[:bypassDocumentValidation] = true
62
- end
63
-
64
56
  with_session(opts) do |session|
65
- applied_write_concern = applied_write_concern(session)
66
- cmd[:writeConcern] = applied_write_concern.options if applied_write_concern
67
- write_with_retry(session, applied_write_concern) do |server, txn_num|
68
- apply_collation!(cmd, server, opts)
69
- apply_hint!(cmd, server, opts.merge(write_concern: applied_write_concern))
70
-
71
- Operation::Command.new(
72
- :selector => cmd,
73
- :db_name => database.name,
74
- :session => session,
75
- :txn_num => txn_num,
57
+ write_concern = if opts[:write_concern]
58
+ WriteConcern.get(opts[:write_concern])
59
+ else
60
+ write_concern_with_session(session)
61
+ end
62
+ if opts[:hint] && write_concern && !write_concern.acknowledged?
63
+ raise Error::UnsupportedOption.hint_error(unacknowledged_write: true)
64
+ end
65
+
66
+ QueryCache.clear_namespace(collection.namespace)
67
+
68
+ cmd = {
69
+ findAndModify: collection.name,
70
+ query: filter,
71
+ remove: true,
72
+ fields: projection,
73
+ sort: sort,
74
+ maxTimeMS: max_time_ms,
75
+ bypassDocumentValidation: opts[:bypass_document_validation],
76
+ hint: opts[:hint],
77
+ collation: opts[:collation] || opts['collation'] || collation,
78
+ }.compact
79
+
80
+ write_with_retry(session, write_concern) do |server, txn_num|
81
+ Operation::WriteCommand.new(
82
+ selector: cmd,
83
+ db_name: database.name,
84
+ write_concern: write_concern,
85
+ session: session,
86
+ txn_num: txn_num,
76
87
  ).execute(server, context: Operation::Context.new(client: client, session: session))
77
88
  end
78
89
  end.first['value']
@@ -96,6 +107,8 @@ module Mongo
96
107
  # @option opts [ Hash ] :collation The collation to use.
97
108
  # @option opts [ Hash | String ] :hint The index to use for this operation.
98
109
  # May be specified as a Hash (e.g. { _id: 1 }) or a String (e.g. "_id_").
110
+ # @option opts [ Hash ] :write_concern The write concern options.
111
+ # Can be :w => Integer, :fsync => Boolean, :j => Boolean.
99
112
  #
100
113
  # @return [ BSON::Document ] The document.
101
114
  #
@@ -127,37 +140,47 @@ module Mongo
127
140
  # @option opts [ Session ] :session The session to use.
128
141
  # @option opts [ Hash | String ] :hint The index to use for this operation.
129
142
  # May be specified as a Hash (e.g. { _id: 1 }) or a String (e.g. "_id_").
143
+ # @option opts [ Hash ] :write_concern The write concern options.
144
+ # Can be :w => Integer, :fsync => Boolean, :j => Boolean.
130
145
  #
131
146
  # @return [ BSON::Document ] The document.
132
147
  #
133
148
  # @since 2.0.0
134
149
  def find_one_and_update(document, opts = {})
135
- QueryCache.clear_namespace(collection.namespace)
136
-
137
- cmd = { :findAndModify => collection.name, :query => filter }
138
- cmd[:update] = document
139
- cmd[:fields] = projection if projection
140
- cmd[:sort] = sort if sort
141
- cmd[:new] = !!(opts[:return_document] && opts[:return_document] == :after)
142
- cmd[:upsert] = opts[:upsert] if opts[:upsert]
143
- cmd[:maxTimeMS] = max_time_ms if max_time_ms
144
- if opts[:bypass_document_validation]
145
- cmd[:bypassDocumentValidation] = true
146
- end
147
-
148
150
  value = with_session(opts) do |session|
149
- applied_write_concern = applied_write_concern(opts[:session])
150
- cmd[:writeConcern] = applied_write_concern.options if applied_write_concern
151
- write_with_retry(session, applied_write_concern) do |server, txn_num|
152
- apply_collation!(cmd, server, opts)
153
- apply_array_filters!(cmd, server, opts)
154
- apply_hint!(cmd, server, opts.merge(write_concern: applied_write_concern))
155
-
156
- Operation::Command.new(
157
- :selector => cmd,
158
- :db_name => database.name,
159
- :session => session,
160
- :txn_num => txn_num,
151
+ write_concern = if opts[:write_concern]
152
+ WriteConcern.get(opts[:write_concern])
153
+ else
154
+ write_concern_with_session(session)
155
+ end
156
+ if opts[:hint] && write_concern && !write_concern.acknowledged?
157
+ raise Error::UnsupportedOption.hint_error(unacknowledged_write: true)
158
+ end
159
+
160
+ QueryCache.clear_namespace(collection.namespace)
161
+
162
+ cmd = {
163
+ findAndModify: collection.name,
164
+ query: filter,
165
+ arrayFilters: opts[:array_filters] || opts['array_filters'],
166
+ update: document,
167
+ fields: projection,
168
+ sort: sort,
169
+ new: !!(opts[:return_document] && opts[:return_document] == :after),
170
+ upsert: opts[:upsert],
171
+ maxTimeMS: max_time_ms,
172
+ bypassDocumentValidation: opts[:bypass_document_validation],
173
+ hint: opts[:hint],
174
+ collation: opts[:collation] || opts['collation'] || collation,
175
+ }.compact
176
+
177
+ write_with_retry(session, write_concern) do |server, txn_num|
178
+ Operation::WriteCommand.new(
179
+ selector: cmd,
180
+ db_name: database.name,
181
+ write_concern: write_concern,
182
+ session: session,
183
+ txn_num: txn_num,
161
184
  ).execute(server, context: Operation::Context.new(client: client, session: session))
162
185
  end
163
186
  end.first['value']
@@ -182,26 +205,33 @@ module Mongo
182
205
  #
183
206
  # @since 2.0.0
184
207
  def delete_many(opts = {})
185
- QueryCache.clear_namespace(collection.namespace)
186
-
187
- delete_doc = { Operation::Q => filter, Operation::LIMIT => 0 }
188
208
  with_session(opts) do |session|
189
209
  write_concern = if opts[:write_concern]
190
210
  WriteConcern.get(opts[:write_concern])
191
211
  else
192
212
  write_concern_with_session(session)
193
213
  end
194
- nro_write_with_retry(session, write_concern) do |server|
195
- apply_collation!(delete_doc, server, opts)
196
- apply_hint!(delete_doc, server, opts.merge(write_concern: write_concern))
214
+ if opts[:hint] && write_concern && !write_concern.acknowledged?
215
+ raise Error::UnsupportedOption.hint_error(unacknowledged_write: true)
216
+ end
217
+
218
+ QueryCache.clear_namespace(collection.namespace)
197
219
 
220
+ delete_doc = {
221
+ Operation::Q => filter,
222
+ Operation::LIMIT => 0,
223
+ hint: opts[:hint],
224
+ collation: opts[:collation] || opts['collation'] || collation,
225
+ }.compact
226
+
227
+ nro_write_with_retry(session, write_concern) do |server|
198
228
  Operation::Delete.new(
199
- :deletes => [ delete_doc ],
200
- :db_name => collection.database.name,
201
- :coll_name => collection.name,
202
- :write_concern => write_concern,
203
- :bypass_document_validation => !!opts[:bypass_document_validation],
204
- :session => session,
229
+ deletes: [ delete_doc ],
230
+ db_name: collection.database.name,
231
+ coll_name: collection.name,
232
+ write_concern: write_concern,
233
+ bypass_document_validation: !!opts[:bypass_document_validation],
234
+ session: session,
205
235
  ).execute(server, context: Operation::Context.new(client: client, session: session))
206
236
  end
207
237
  end
@@ -225,27 +255,34 @@ module Mongo
225
255
  #
226
256
  # @since 2.0.0
227
257
  def delete_one(opts = {})
228
- QueryCache.clear_namespace(collection.namespace)
229
-
230
- delete_doc = { Operation::Q => filter, Operation::LIMIT => 1 }
231
258
  with_session(opts) do |session|
232
259
  write_concern = if opts[:write_concern]
233
260
  WriteConcern.get(opts[:write_concern])
234
261
  else
235
262
  write_concern_with_session(session)
236
263
  end
237
- write_with_retry(session, write_concern) do |server, txn_num|
238
- apply_collation!(delete_doc, server, opts)
239
- apply_hint!(delete_doc, server, opts.merge(write_concern: write_concern))
264
+ if opts[:hint] && write_concern && !write_concern.acknowledged?
265
+ raise Error::UnsupportedOption.hint_error(unacknowledged_write: true)
266
+ end
267
+
268
+ QueryCache.clear_namespace(collection.namespace)
240
269
 
270
+ delete_doc = {
271
+ Operation::Q => filter,
272
+ Operation::LIMIT => 1,
273
+ hint: opts[:hint],
274
+ collation: opts[:collation] || opts['collation'] || collation,
275
+ }.compact
276
+
277
+ write_with_retry(session, write_concern) do |server, txn_num|
241
278
  Operation::Delete.new(
242
- :deletes => [ delete_doc ],
243
- :db_name => collection.database.name,
244
- :coll_name => collection.name,
245
- :write_concern => write_concern,
246
- :bypass_document_validation => !!opts[:bypass_document_validation],
247
- :session => session,
248
- :txn_num => txn_num,
279
+ deletes: [ delete_doc ],
280
+ db_name: collection.database.name,
281
+ coll_name: collection.name,
282
+ write_concern: write_concern,
283
+ bypass_document_validation: !!opts[:bypass_document_validation],
284
+ session: session,
285
+ txn_num: txn_num,
249
286
  ).execute(server, context: Operation::Context.new(client: client, session: session))
250
287
  end
251
288
  end
@@ -274,34 +311,38 @@ module Mongo
274
311
  #
275
312
  # @since 2.0.0
276
313
  def replace_one(replacement, opts = {})
277
- QueryCache.clear_namespace(collection.namespace)
278
-
279
- update_doc = { Operation::Q => filter,
280
- Operation::U => replacement,
281
- }
282
- if opts[:upsert]
283
- update_doc['upsert'] = true
284
- end
285
314
  with_session(opts) do |session|
286
315
  write_concern = if opts[:write_concern]
287
316
  WriteConcern.get(opts[:write_concern])
288
317
  else
289
318
  write_concern_with_session(session)
290
319
  end
320
+ if opts[:hint] && write_concern && !write_concern.acknowledged?
321
+ raise Error::UnsupportedOption.hint_error(unacknowledged_write: true)
322
+ end
291
323
 
292
- write_with_retry(session, write_concern) do |server, txn_num|
293
- apply_collation!(update_doc, server, opts)
294
- apply_array_filters!(update_doc, server, opts)
295
- apply_hint!(update_doc, server, opts.merge(write_concern: write_concern))
324
+ QueryCache.clear_namespace(collection.namespace)
325
+
326
+ update_doc = {
327
+ Operation::Q => filter,
328
+ arrayFilters: opts[:array_filters] || opts['array_filters'],
329
+ Operation::U => replacement,
330
+ hint: opts[:hint],
331
+ collation: opts[:collation] || opts['collation'] || collation,
332
+ }.compact
333
+ if opts[:upsert]
334
+ update_doc['upsert'] = true
335
+ end
296
336
 
337
+ write_with_retry(session, write_concern) do |server, txn_num|
297
338
  Operation::Update.new(
298
- :updates => [ update_doc ],
299
- :db_name => collection.database.name,
300
- :coll_name => collection.name,
301
- :write_concern => write_concern,
302
- :bypass_document_validation => !!opts[:bypass_document_validation],
303
- :session => session,
304
- :txn_num => txn_num,
339
+ updates: [ update_doc ],
340
+ db_name: collection.database.name,
341
+ coll_name: collection.name,
342
+ write_concern: write_concern,
343
+ bypass_document_validation: !!opts[:bypass_document_validation],
344
+ session: session,
345
+ txn_num: txn_num,
305
346
  ).execute(server, context: Operation::Context.new(client: client, session: session))
306
347
  end
307
348
  end
@@ -332,33 +373,38 @@ module Mongo
332
373
  #
333
374
  # @since 2.0.0
334
375
  def update_many(spec, opts = {})
335
- QueryCache.clear_namespace(collection.namespace)
336
-
337
- update_doc = { Operation::Q => filter,
338
- Operation::U => spec,
339
- Operation::MULTI => true,
340
- }
341
- if opts[:upsert]
342
- update_doc['upsert'] = true
343
- end
344
376
  with_session(opts) do |session|
345
377
  write_concern = if opts[:write_concern]
346
378
  WriteConcern.get(opts[:write_concern])
347
379
  else
348
380
  write_concern_with_session(session)
349
381
  end
350
- nro_write_with_retry(session, write_concern) do |server|
351
- apply_collation!(update_doc, server, opts)
352
- apply_array_filters!(update_doc, server, opts)
353
- apply_hint!(update_doc, server, opts.merge(write_concern: write_concern))
382
+ if opts[:hint] && write_concern && !write_concern.acknowledged?
383
+ raise Error::UnsupportedOption.hint_error(unacknowledged_write: true)
384
+ end
385
+
386
+ QueryCache.clear_namespace(collection.namespace)
387
+
388
+ update_doc = {
389
+ Operation::Q => filter,
390
+ arrayFilters: opts[:array_filters] || opts['array_filters'],
391
+ Operation::U => spec,
392
+ Operation::MULTI => true,
393
+ hint: opts[:hint],
394
+ collation: opts[:collation] || opts['collation'] || collation,
395
+ }.compact
396
+ if opts[:upsert]
397
+ update_doc['upsert'] = true
398
+ end
354
399
 
400
+ nro_write_with_retry(session, write_concern) do |server|
355
401
  Operation::Update.new(
356
- :updates => [ update_doc ],
357
- :db_name => collection.database.name,
358
- :coll_name => collection.name,
359
- :write_concern => write_concern,
360
- :bypass_document_validation => !!opts[:bypass_document_validation],
361
- :session => session,
402
+ updates: [ update_doc ],
403
+ db_name: collection.database.name,
404
+ coll_name: collection.name,
405
+ write_concern: write_concern,
406
+ bypass_document_validation: !!opts[:bypass_document_validation],
407
+ session: session,
362
408
  ).execute(server, context: Operation::Context.new(client: client, session: session))
363
409
  end
364
410
  end
@@ -389,83 +435,40 @@ module Mongo
389
435
  #
390
436
  # @since 2.0.0
391
437
  def update_one(spec, opts = {})
392
- QueryCache.clear_namespace(collection.namespace)
393
-
394
- update_doc = { Operation::Q => filter,
395
- Operation::U => spec,
396
- }
397
- if opts[:upsert]
398
- update_doc['upsert'] = true
399
- end
400
438
  with_session(opts) do |session|
401
439
  write_concern = if opts[:write_concern]
402
440
  WriteConcern.get(opts[:write_concern])
403
441
  else
404
442
  write_concern_with_session(session)
405
443
  end
406
- write_with_retry(session, write_concern) do |server, txn_num|
407
- apply_collation!(update_doc, server, opts)
408
- apply_array_filters!(update_doc, server, opts)
409
- apply_hint!(update_doc, server, opts.merge(write_concern: write_concern))
410
-
411
- Operation::Update.new(
412
- :updates => [ update_doc ],
413
- :db_name => collection.database.name,
414
- :coll_name => collection.name,
415
- :write_concern => write_concern,
416
- :bypass_document_validation => !!opts[:bypass_document_validation],
417
- :session => session,
418
- :txn_num => txn_num,
419
- ).execute(server, context: Operation::Context.new(client: client, session: session))
420
- end
421
- end
422
- end
423
-
424
- private
425
-
426
- def apply_hint!(doc, server, opts)
427
- if hint = opts[:hint]
428
- features = server.with_connection do |connection|
429
- connection.description.features
430
- end
431
-
432
- write_concern = opts[:write_concern]
433
- if write_concern && !write_concern.acknowledged?
444
+ if opts[:hint] && write_concern && !write_concern.acknowledged?
434
445
  raise Error::UnsupportedOption.hint_error(unacknowledged_write: true)
435
446
  end
436
447
 
437
- if doc.key?(:findAndModify) &&
438
- !features.find_and_modify_option_validation_enabled?
439
- raise Error::UnsupportedOption.hint_error
440
- elsif !features.update_delete_option_validation_enabled?
441
- raise Error::UnsupportedOption.hint_error
448
+ QueryCache.clear_namespace(collection.namespace)
449
+
450
+ update_doc = {
451
+ Operation::Q => filter,
452
+ arrayFilters: opts[:array_filters] || opts['array_filters'],
453
+ Operation::U => spec,
454
+ hint: opts[:hint],
455
+ collation: opts[:collation] || opts['collation'] || collation,
456
+ }.compact
457
+ if opts[:upsert]
458
+ update_doc['upsert'] = true
442
459
  end
443
460
 
444
- doc[:hint] = opts[:hint]
445
- end
446
- end
447
-
448
- def apply_array_filters!(doc, server, opts = {})
449
- if filters = opts[:array_filters] || opts[ARRAY_FILTERS]
450
- validate_array_filters!(server, filters)
451
- doc[:arrayFilters] = filters
452
- end
453
- end
454
-
455
- def validate_array_filters!(server, filters)
456
- if filters && !server.with_connection { |connection| connection.features }.array_filters_enabled?
457
- raise Error::UnsupportedArrayFilters.new
458
- end
459
- end
460
-
461
- # Get the write concern for an operation
462
- #
463
- # @return [ Mongo::WriteConcern ] The write concern.
464
- def applied_write_concern(session)
465
- if wco = options[:write_concern] || options[:write]
466
- WriteConcern.get(wco)
467
- else
468
- write_concern_with_session(session)
461
+ write_with_retry(session, write_concern) do |server, txn_num|
462
+ Operation::Update.new(
463
+ updates: [ update_doc ],
464
+ db_name: collection.database.name,
465
+ coll_name: collection.name,
466
+ write_concern: write_concern,
467
+ bypass_document_validation: !!opts[:bypass_document_validation],
468
+ session: session,
469
+ txn_num: txn_num,
470
+ ).execute(server, context: Operation::Context.new(client: client, session: session))
471
+ end
469
472
  end
470
473
  end
471
474
  end