mongo 2.15.0 → 2.16.0.alpha1

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 (328) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +1 -1
  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 +6 -0
  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_spec.rb +4 -3
  198. data/spec/mongo/session/session_pool_spec.rb +42 -10
  199. data/spec/mongo/session_transaction_spec.rb +15 -30
  200. data/spec/mongo/socket/unix_spec.rb +1 -0
  201. data/spec/mongo/uri_option_parsing_spec.rb +38 -5
  202. data/spec/runners/change_streams/test.rb +1 -1
  203. data/spec/runners/cmap.rb +1 -1
  204. data/spec/runners/connection_string.rb +7 -3
  205. data/spec/runners/crud/operation.rb +5 -3
  206. data/spec/runners/crud/requirement.rb +1 -0
  207. data/spec/runners/crud.rb +1 -1
  208. data/spec/runners/sdam.rb +2 -1
  209. data/spec/runners/transactions/test.rb +2 -2
  210. data/spec/runners/unified/assertions.rb +2 -3
  211. data/spec/runners/unified/event_subscriber.rb +2 -2
  212. data/spec/runners/unified/test.rb +3 -0
  213. data/spec/runners/unified.rb +1 -1
  214. data/spec/shared/lib/mrss/constraints.rb +11 -5
  215. data/spec/shared/lib/mrss/event_subscriber.rb +200 -0
  216. data/spec/shared/lib/mrss/server_version_registry.rb +17 -12
  217. data/spec/shared/share/Dockerfile.erb +2 -1
  218. data/spec/shared/shlib/server.sh +70 -20
  219. data/spec/spec_tests/change_streams_spec.rb +1 -1
  220. data/spec/spec_tests/cmap_spec.rb +4 -1
  221. data/spec/spec_tests/command_monitoring_spec.rb +2 -2
  222. data/spec/spec_tests/data/command_monitoring/find.yml +9 -9
  223. data/spec/spec_tests/data/crud/read/aggregate-collation.yml +2 -1
  224. data/spec/spec_tests/data/crud/read/aggregate-out.yml +1 -0
  225. data/spec/spec_tests/data/crud/read/count-collation.yml +2 -1
  226. data/spec/spec_tests/data/crud/read/distinct-collation.yml +2 -1
  227. data/spec/spec_tests/data/crud/read/find-collation.yml +2 -1
  228. data/spec/spec_tests/data/crud/write/bulkWrite-collation.yml +2 -1
  229. data/spec/spec_tests/data/crud/write/deleteMany-collation.yml +2 -1
  230. data/spec/spec_tests/data/crud/write/deleteOne-collation.yml +2 -1
  231. data/spec/spec_tests/data/crud/write/findOneAndDelete-collation.yml +3 -2
  232. data/spec/spec_tests/data/crud/write/findOneAndReplace-collation.yml +2 -1
  233. data/spec/spec_tests/data/crud/write/findOneAndUpdate-collation.yml +3 -2
  234. data/spec/spec_tests/data/crud/write/replaceOne-collation.yml +3 -2
  235. data/spec/spec_tests/data/crud/write/updateMany-collation.yml +2 -1
  236. data/spec/spec_tests/data/crud/write/updateOne-collation.yml +2 -1
  237. data/spec/spec_tests/data/load_balancers/event-monitoring.yml +99 -0
  238. data/spec/spec_tests/data/load_balancers/lb-connection-establishment.yml +36 -0
  239. data/spec/spec_tests/data/load_balancers/non-lb-connection-establishment.yml +56 -0
  240. data/spec/spec_tests/data/load_balancers/server-selection.yml +50 -0
  241. data/spec/spec_tests/data/retryable_reads/changeStreams-client.watch-serverErrors.yml +1 -1
  242. data/spec/spec_tests/data/retryable_reads/changeStreams-client.watch.yml +1 -1
  243. data/spec/spec_tests/data/retryable_reads/changeStreams-db.coll.watch-serverErrors.yml +1 -1
  244. data/spec/spec_tests/data/retryable_reads/changeStreams-db.coll.watch.yml +1 -1
  245. data/spec/spec_tests/data/retryable_reads/changeStreams-db.watch-serverErrors.yml +1 -1
  246. data/spec/spec_tests/data/retryable_reads/changeStreams-db.watch.yml +1 -1
  247. data/spec/spec_tests/data/retryable_reads/mapReduce.yml +3 -1
  248. data/spec/spec_tests/data/sdam/load-balanced/discover_load_balancer.yml +25 -0
  249. data/spec/spec_tests/data/sdam_integration/find-network-error.yml +2 -0
  250. data/spec/spec_tests/data/sdam_integration/find-shutdown-error.yml +2 -0
  251. data/spec/spec_tests/data/sdam_integration/hello-command-error.yml +3 -1
  252. data/spec/spec_tests/data/sdam_integration/hello-network-error.yml +3 -1
  253. data/spec/spec_tests/data/sdam_integration/hello-timeout.yml +2 -0
  254. data/spec/spec_tests/data/sdam_integration/insert-network-error.yml +2 -0
  255. data/spec/spec_tests/data/sdam_integration/insert-shutdown-error.yml +2 -0
  256. data/spec/spec_tests/data/sdam_monitoring/load_balancer.yml +65 -0
  257. data/spec/spec_tests/data/seed_list_discovery/load-balanced/loadBalanced-directConnection.yml +13 -0
  258. data/spec/spec_tests/data/seed_list_discovery/load-balanced/loadBalanced-replicaSet-errors.yml +6 -0
  259. data/spec/spec_tests/data/seed_list_discovery/load-balanced/loadBalanced-true-multiple-hosts.yml +5 -0
  260. data/spec/spec_tests/data/seed_list_discovery/load-balanced/loadBalanced-true-txt.yml +10 -0
  261. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/direct-connection-false.yml +0 -0
  262. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/direct-connection-true.yml +0 -0
  263. data/spec/spec_tests/data/seed_list_discovery/replica-set/encoded-userinfo-and-db.yml +15 -0
  264. data/spec/spec_tests/data/seed_list_discovery/replica-set/loadBalanced-false-txt.yml +10 -0
  265. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/longer-parent-in-return.yml +0 -0
  266. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/misformatted-option.yml +0 -0
  267. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/no-results.yml +0 -0
  268. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/not-enough-parts.yml +0 -0
  269. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/one-result-default-port.yml +0 -0
  270. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/one-txt-record-multiple-strings.yml +0 -0
  271. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/one-txt-record.yml +0 -0
  272. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/parent-part-mismatch1.yml +0 -0
  273. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/parent-part-mismatch2.yml +0 -0
  274. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/parent-part-mismatch3.yml +0 -0
  275. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/parent-part-mismatch4.yml +0 -0
  276. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/parent-part-mismatch5.yml +0 -0
  277. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/returned-parent-too-short.yml +0 -0
  278. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/returned-parent-wrong.yml +0 -0
  279. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/two-results-default-port.yml +0 -0
  280. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/two-results-nonstandard-port.yml +0 -0
  281. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/two-txt-records.yml +0 -0
  282. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/txt-record-not-allowed-option.yml +0 -0
  283. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/txt-record-with-overridden-ssl-option.yml +0 -0
  284. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/txt-record-with-overridden-uri-option.yml +0 -0
  285. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/txt-record-with-unallowed-option.yml +0 -0
  286. data/spec/spec_tests/data/seed_list_discovery/replica-set/uri-with-admin-database.yml +13 -0
  287. data/spec/spec_tests/data/seed_list_discovery/replica-set/uri-with-auth.yml +12 -0
  288. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/uri-with-port.yml +0 -0
  289. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/uri-with-two-hosts.yml +0 -0
  290. data/spec/spec_tests/data/transactions/retryable-abort-errorLabels.yml +2 -0
  291. data/spec/spec_tests/data/transactions/retryable-abort.yml +2 -0
  292. data/spec/spec_tests/data/transactions/retryable-commit-errorLabels.yml +2 -0
  293. data/spec/spec_tests/data/transactions/retryable-commit.yml +2 -0
  294. data/spec/spec_tests/data/transactions/retryable-writes.yml +2 -0
  295. data/spec/spec_tests/data/uri_options/connection-options.yml +60 -0
  296. data/spec/spec_tests/load_balancers_spec.rb +15 -0
  297. data/spec/spec_tests/retryable_reads_spec.rb +2 -2
  298. data/spec/spec_tests/retryable_writes_spec.rb +1 -1
  299. data/spec/spec_tests/sdam_integration_spec.rb +1 -1
  300. data/spec/spec_tests/sdam_monitoring_spec.rb +10 -5
  301. data/spec/spec_tests/sdam_spec.rb +1 -1
  302. data/spec/spec_tests/seed_list_discovery_spec.rb +118 -0
  303. data/spec/spec_tests/uri_options_spec.rb +4 -4
  304. data/spec/stress/fork_reconnect_stress_spec.rb +1 -5
  305. data/spec/stress/push_monitor_close_spec.rb +44 -0
  306. data/spec/support/certificates/atlas-ocsp-ca.crt +82 -90
  307. data/spec/support/certificates/atlas-ocsp.crt +127 -122
  308. data/spec/support/common_shortcuts.rb +2 -3
  309. data/spec/support/matchers.rb +13 -0
  310. data/spec/support/shared/auth_context.rb +16 -0
  311. data/spec/support/shared/session.rb +2 -2
  312. data/spec/support/spec_config.rb +9 -10
  313. data/spec/support/using_hash.rb +31 -0
  314. data/spec/support/utils.rb +1 -1
  315. data.tar.gz.sig +2 -4
  316. metadata +1050 -1004
  317. metadata.gz.sig +0 -0
  318. data/lib/mongo/collection/view/builder/find_command.rb +0 -173
  319. data/lib/mongo/collection/view/builder/op_query.rb +0 -94
  320. data/lib/mongo/cursor/builder/get_more_command.rb +0 -80
  321. data/lib/mongo/cursor/builder/kill_cursors_command.rb +0 -111
  322. data/lib/mongo/cursor/builder/op_get_more.rb +0 -64
  323. data/lib/mongo/cursor/builder/op_kill_cursors.rb +0 -106
  324. data/lib/mongo/server/context.rb +0 -72
  325. data/spec/mongo/cursor/builder/op_kill_cursors_spec.rb +0 -66
  326. data/spec/runners/unified/using_hash.rb +0 -34
  327. data/spec/spec_tests/dns_seedlist_discovery_spec.rb +0 -79
  328. data/spec/support/event_subscriber.rb +0 -221
@@ -17,7 +17,3 @@
17
17
 
18
18
  require 'mongo/collection/view/builder/aggregation'
19
19
  require 'mongo/collection/view/builder/map_reduce'
20
- require 'mongo/collection/view/builder/op_query'
21
- require 'mongo/collection/view/builder/find_command'
22
- require 'mongo/collection/view/builder/flags'
23
- require 'mongo/collection/view/builder/modifiers'
@@ -25,6 +25,13 @@ module Mongo
25
25
  # @since 2.0.0
26
26
  module Iterable
27
27
 
28
+ # Returns the cursor associated with this view, if any.
29
+ #
30
+ # @return [ nil | Cursor ] The cursor, if any.
31
+ #
32
+ # @api private
33
+ attr_reader :cursor
34
+
28
35
  # Iterate through documents returned by a query with this +View+.
29
36
  #
30
37
  # @example Iterate through the result of the view.
@@ -38,18 +45,28 @@ module Mongo
38
45
  #
39
46
  # @yieldparam [ Hash ] Each matching document.
40
47
  def each
41
- @cursor = if use_query_cache? && cached_cursor
48
+ # If the caching cursor is closed and was not fully iterated,
49
+ # the documents we have in it are not the complete result set and
50
+ # we have no way of completing that iteration.
51
+ # Therefore, discard that cursor and start iteration again.
52
+ # The case of the caching cursor not being closed and not having
53
+ # been fully iterated isn't tested - see RUBY-2773.
54
+ @cursor = if use_query_cache? && cached_cursor && (
55
+ cached_cursor.fully_iterated? || !cached_cursor.closed?
56
+ )
42
57
  cached_cursor
43
58
  else
44
59
  session = client.send(:get_session, @options)
45
- select_cursor(session)
60
+ select_cursor(session).tap do |cursor|
61
+ if use_query_cache?
62
+ # No need to store the cursor in the query cache if there is
63
+ # already a cached cursor stored at this key.
64
+ QueryCache.set(cursor, **cache_options)
65
+ end
66
+ end
46
67
  end
47
68
 
48
69
  if use_query_cache?
49
- # No need to store the cursor in the query cache if there is
50
- # already a cached cursor stored at this key.
51
- QueryCache.set(@cursor, **cache_options) unless cached_cursor
52
-
53
70
  # If a query with a limit is performed, the query cache will
54
71
  # re-use results from an earlier query with the same or larger
55
72
  # limit, and then impose the lower limit during iteration.
@@ -130,36 +147,53 @@ module Mongo
130
147
  projection: projection,
131
148
  collation: collation,
132
149
  read_concern: read_concern,
133
- read_preference: read_preference
134
-
150
+ read_preference: read_preference,
135
151
  }
136
152
  end
137
153
 
138
154
  def initial_query_op(server, session)
139
- if server.with_connection { |connection| connection.features }.find_command_enabled?
140
- initial_command_op(session)
141
- else
142
- # Server versions that do not have the find command feature
143
- # (versions older than 3.2) do not support the allow_disk_use option
144
- # but perform no validation and will not raise an error if it is
145
- # specified. If the allow_disk_use option is specified, raise an error
146
- # to alert the user.
147
- raise Error::UnsupportedOption.allow_disk_use_error if options.key?(:allow_disk_use)
148
- Operation::Find.new(Builder::OpQuery.new(self).specification)
155
+ spec = {
156
+ coll_name: collection.name,
157
+ filter: filter,
158
+ projection: projection,
159
+ db_name: database.name,
160
+ session: session,
161
+ collation: collation,
162
+ sort: sort,
163
+ skip: skip,
164
+ limit: limit,
165
+ allow_disk_use: options[:allow_disk_use],
166
+ read: read,
167
+ read_concern: options[:read_concern] || read_concern,
168
+ batch_size: batch_size,
169
+ hint: options[:hint],
170
+ max_scan: options[:max_scan],
171
+ max_time_ms: options[:max_time_ms],
172
+ max_value: options[:max_value],
173
+ min_value: options[:min_value],
174
+ return_key: options[:return_key],
175
+ show_disk_loc: options[:show_disk_loc],
176
+ comment: options[:comment],
177
+ oplog_replay: if (v = options[:oplog_replay]).nil?
178
+ collection.options[:oplog_replay]
179
+ else
180
+ v
181
+ end,
182
+ }
183
+
184
+ if spec[:oplog_replay]
185
+ collection.client.log_warn("The :oplog_replay option is deprecated and ignored by MongoDB 4.4 and later")
149
186
  end
150
- end
151
187
 
152
- def initial_command_op(session)
153
- builder = Builder::FindCommand.new(self, session)
154
188
  if explained?
155
- Operation::Explain.new(builder.explain_specification)
189
+ spec[:explain] = options[:explain]
190
+ Operation::Explain.new(spec)
156
191
  else
157
- Operation::Find.new(builder.specification)
192
+ Operation::Find.new(spec)
158
193
  end
159
194
  end
160
195
 
161
196
  def send_initial_query(server, session = nil)
162
- validate_collation!(server, collation)
163
197
  initial_query_op(server, session).execute(server, context: Operation::Context.new(client: client, session: session))
164
198
  end
165
199
 
@@ -156,6 +156,28 @@ module Mongo
156
156
  configure(:out, location)
157
157
  end
158
158
 
159
+ # Returns the collection name where the map-reduce result is written to.
160
+ # If the result is returned inline, returns nil.
161
+ def out_collection_name
162
+ if options[:out].respond_to?(:keys)
163
+ options[:out][OUT_ACTIONS.find do |action|
164
+ options[:out][action]
165
+ end]
166
+ end || options[:out]
167
+ end
168
+
169
+ # Returns the database name where the map-reduce result is written to.
170
+ # If the result is returned inline, returns nil.
171
+ def out_database_name
172
+ if options[:out]
173
+ if options[:out].respond_to?(:keys) && (db = options[:out][:db])
174
+ db
175
+ else
176
+ database.name
177
+ end
178
+ end
179
+ end
180
+
159
181
  # Set or get a scope on the operation.
160
182
  #
161
183
  # @example Set the scope value.
@@ -207,6 +229,8 @@ module Mongo
207
229
 
208
230
  private
209
231
 
232
+ OUT_ACTIONS = [ :replace, :merge, :reduce ].freeze
233
+
210
234
  def server_selector
211
235
  @view.send(:server_selector)
212
236
  end
@@ -228,10 +252,12 @@ module Mongo
228
252
  end
229
253
 
230
254
  def valid_server?(server)
231
- description = server.with_connection do |connection|
232
- connection.description
255
+ if secondary_ok?
256
+ true
257
+ else
258
+ description = server.description
259
+ description.standalone? || description.mongos? || description.primary? || description.load_balancer?
233
260
  end
234
- description.standalone? || description.mongos? || description.primary? || secondary_ok?
235
261
  end
236
262
 
237
263
  def secondary_ok?
@@ -244,7 +270,6 @@ module Mongo
244
270
  log_warn(msg)
245
271
  server = cluster.next_primary(nil, session)
246
272
  end
247
- validate_collation!(server)
248
273
  initial_query_op(session).execute(server, context: Operation::Context.new(client: client, session: session))
249
274
  end
250
275
 
@@ -257,22 +282,21 @@ module Mongo
257
282
  end
258
283
 
259
284
  def fetch_query_op(server, session)
260
- if server.with_connection { |connection| connection.features }.find_command_enabled?
261
- Operation::Find.new(find_command_spec(session))
262
- else
263
- Operation::Find.new(fetch_query_spec)
264
- end
285
+ spec = {
286
+ coll_name: out_collection_name,
287
+ db_name: out_database_name,
288
+ filter: {},
289
+ session: session,
290
+ read: read,
291
+ read_concern: options[:read_concern] || collection.read_concern,
292
+ collation: options[:collation] || view.options[:collation],
293
+ }
294
+ Operation::Find.new(spec)
265
295
  end
266
296
 
267
297
  def send_fetch_query(server, session)
268
298
  fetch_query_op(server, session).execute(server, context: Operation::Context.new(client: client, session: session))
269
299
  end
270
-
271
- def validate_collation!(server)
272
- if (view.options[:collation] || options[:collation]) && !server.with_connection { |connection| connection.features }.collation_enabled?
273
- raise Error::UnsupportedCollation.new
274
- end
275
- end
276
300
  end
277
301
  end
278
302
  end
@@ -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