mongo 2.15.1 → 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 (326) 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 +42 -18
  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 +62 -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.rb +73 -26
  102. data/lib/mongo/server_selector/base.rb +5 -1
  103. data/lib/mongo/session/session_pool.rb +11 -0
  104. data/lib/mongo/session.rb +21 -1
  105. data/lib/mongo/socket/ocsp_verifier.rb +6 -37
  106. data/lib/mongo/uri/options_mapper.rb +1 -0
  107. data/lib/mongo/uri/srv_protocol.rb +6 -8
  108. data/lib/mongo/uri.rb +18 -0
  109. data/lib/mongo/utils.rb +0 -7
  110. data/lib/mongo/version.rb +1 -1
  111. data/mongo.gemspec +1 -1
  112. data/spec/integration/auth_spec.rb +31 -1
  113. data/spec/integration/awaited_ismaster_spec.rb +1 -1
  114. data/spec/integration/bulk_write_spec.rb +1 -1
  115. data/spec/integration/change_stream_spec.rb +3 -3
  116. data/spec/integration/client_construction_spec.rb +54 -0
  117. data/spec/integration/client_side_encryption/auto_encryption_bulk_writes_spec.rb +1 -1
  118. data/spec/integration/client_side_encryption/auto_encryption_command_monitoring_spec.rb +1 -1
  119. data/spec/integration/client_side_encryption/bson_size_limit_spec.rb +1 -1
  120. data/spec/integration/client_side_encryption/data_key_spec.rb +1 -1
  121. data/spec/integration/client_spec.rb +2 -0
  122. data/spec/integration/command_monitoring_spec.rb +1 -1
  123. data/spec/integration/command_spec.rb +1 -1
  124. data/spec/integration/connection_spec.rb +52 -35
  125. data/spec/integration/crud_spec.rb +174 -1
  126. data/spec/integration/cursor_pinning_spec.rb +121 -0
  127. data/spec/integration/cursor_reaping_spec.rb +8 -4
  128. data/spec/integration/fork_reconnect_spec.rb +1 -5
  129. data/spec/integration/get_more_spec.rb +1 -1
  130. data/spec/integration/heartbeat_events_spec.rb +1 -1
  131. data/spec/integration/map_reduce_spec.rb +77 -0
  132. data/spec/integration/query_cache_spec.rb +2 -2
  133. data/spec/integration/query_cache_transactions_spec.rb +1 -1
  134. data/spec/integration/read_concern_spec.rb +1 -1
  135. data/spec/integration/read_preference_spec.rb +1 -1
  136. data/spec/integration/reconnect_spec.rb +30 -12
  137. data/spec/integration/retryable_errors_spec.rb +1 -1
  138. data/spec/integration/retryable_writes/retryable_writes_36_and_older_spec.rb +1 -1
  139. data/spec/integration/retryable_writes/retryable_writes_40_and_newer_spec.rb +1 -1
  140. data/spec/integration/sdam_error_handling_spec.rb +5 -3
  141. data/spec/integration/sdam_events_spec.rb +35 -19
  142. data/spec/integration/sdam_prose_spec.rb +1 -1
  143. data/spec/integration/server_monitor_spec.rb +1 -0
  144. data/spec/integration/server_selector_spec.rb +22 -5
  145. data/spec/integration/server_spec.rb +2 -0
  146. data/spec/integration/srv_monitoring_spec.rb +1 -1
  147. data/spec/integration/step_down_spec.rb +1 -1
  148. data/spec/integration/transaction_pinning_spec.rb +120 -0
  149. data/spec/integration/versioned_api_examples_spec.rb +45 -0
  150. data/spec/integration/x509_auth_spec.rb +1 -1
  151. data/spec/lite_spec_helper.rb +1 -2
  152. data/spec/mongo/address/unix_spec.rb +1 -0
  153. data/spec/mongo/auth/cr_spec.rb +2 -3
  154. data/spec/mongo/auth/ldap_spec.rb +2 -3
  155. data/spec/mongo/auth/scram_spec.rb +2 -3
  156. data/spec/mongo/auth/user/view_spec.rb +1 -1
  157. data/spec/mongo/auth/x509_spec.rb +2 -3
  158. data/spec/mongo/bulk_write_spec.rb +3 -3
  159. data/spec/mongo/client_construction_spec.rb +259 -28
  160. data/spec/mongo/client_spec.rb +6 -4
  161. data/spec/mongo/cluster/cursor_reaper_spec.rb +36 -21
  162. data/spec/mongo/cluster/periodic_executor_spec.rb +3 -1
  163. data/spec/mongo/cluster_spec.rb +44 -3
  164. data/spec/mongo/collection/view/aggregation_spec.rb +1 -1
  165. data/spec/mongo/collection/view/builder/find_command_spec.rb +4 -0
  166. data/spec/mongo/collection/view/builder/op_query_spec.rb +4 -0
  167. data/spec/mongo/collection/view/map_reduce_spec.rb +1 -1
  168. data/spec/mongo/collection_crud_spec.rb +7 -2
  169. data/spec/mongo/collection_ddl_spec.rb +1 -1
  170. data/spec/mongo/collection_spec.rb +1 -1
  171. data/spec/mongo/cursor/builder/get_more_command_spec.rb +4 -0
  172. data/spec/mongo/cursor/builder/op_get_more_spec.rb +4 -0
  173. data/spec/mongo/cursor_spec.rb +15 -5
  174. data/spec/mongo/database_spec.rb +15 -15
  175. data/spec/mongo/error/operation_failure_heavy_spec.rb +1 -1
  176. data/spec/mongo/grid/fs_bucket_spec.rb +18 -12
  177. data/spec/mongo/grid/stream/write_spec.rb +3 -9
  178. data/spec/mongo/grid/stream_spec.rb +1 -1
  179. data/spec/mongo/index/view_spec.rb +2 -2
  180. data/spec/mongo/operation/delete/op_msg_spec.rb +1 -1
  181. data/spec/mongo/{collection/view → operation/find}/builder/flags_spec.rb +2 -2
  182. data/spec/mongo/{collection/view → operation/find}/builder/modifiers_spec.rb +2 -2
  183. data/spec/mongo/operation/find/legacy_spec.rb +1 -0
  184. data/spec/mongo/operation/insert/bulk_spec.rb +1 -1
  185. data/spec/mongo/operation/insert/op_msg_spec.rb +1 -1
  186. data/spec/mongo/operation/kill_cursors_spec.rb +4 -1
  187. data/spec/mongo/operation/read_preference_legacy_spec.rb +4 -0
  188. data/spec/mongo/operation/read_preference_op_msg_spec.rb +2 -0
  189. data/spec/mongo/operation/update/bulk_spec.rb +1 -1
  190. data/spec/mongo/operation/update/op_msg_spec.rb +1 -1
  191. data/spec/mongo/query_cache_spec.rb +6 -2
  192. data/spec/mongo/server/connection_common_spec.rb +62 -11
  193. data/spec/mongo/server/connection_pool_spec.rb +73 -7
  194. data/spec/mongo/server/connection_spec.rb +138 -43
  195. data/spec/mongo/server/description_spec.rb +1 -1
  196. data/spec/mongo/server/monitor_spec.rb +4 -3
  197. data/spec/mongo/session/session_pool_spec.rb +42 -10
  198. data/spec/mongo/session_transaction_spec.rb +15 -30
  199. data/spec/mongo/socket/unix_spec.rb +1 -0
  200. data/spec/mongo/uri_option_parsing_spec.rb +38 -5
  201. data/spec/runners/change_streams/test.rb +1 -1
  202. data/spec/runners/cmap.rb +1 -1
  203. data/spec/runners/connection_string.rb +7 -3
  204. data/spec/runners/crud/operation.rb +5 -3
  205. data/spec/runners/crud/requirement.rb +1 -0
  206. data/spec/runners/crud.rb +1 -1
  207. data/spec/runners/sdam.rb +2 -1
  208. data/spec/runners/transactions/test.rb +2 -2
  209. data/spec/runners/unified/assertions.rb +2 -3
  210. data/spec/runners/unified/event_subscriber.rb +2 -2
  211. data/spec/runners/unified/test.rb +3 -0
  212. data/spec/runners/unified.rb +1 -1
  213. data/spec/shared/lib/mrss/constraints.rb +11 -5
  214. data/spec/shared/lib/mrss/event_subscriber.rb +200 -0
  215. data/spec/shared/lib/mrss/server_version_registry.rb +17 -12
  216. data/spec/shared/share/Dockerfile.erb +2 -1
  217. data/spec/shared/shlib/server.sh +70 -20
  218. data/spec/spec_tests/change_streams_spec.rb +1 -1
  219. data/spec/spec_tests/cmap_spec.rb +4 -1
  220. data/spec/spec_tests/command_monitoring_spec.rb +2 -2
  221. data/spec/spec_tests/data/command_monitoring/find.yml +9 -9
  222. data/spec/spec_tests/data/crud/read/aggregate-collation.yml +2 -1
  223. data/spec/spec_tests/data/crud/read/aggregate-out.yml +1 -0
  224. data/spec/spec_tests/data/crud/read/count-collation.yml +2 -1
  225. data/spec/spec_tests/data/crud/read/distinct-collation.yml +2 -1
  226. data/spec/spec_tests/data/crud/read/find-collation.yml +2 -1
  227. data/spec/spec_tests/data/crud/write/bulkWrite-collation.yml +2 -1
  228. data/spec/spec_tests/data/crud/write/deleteMany-collation.yml +2 -1
  229. data/spec/spec_tests/data/crud/write/deleteOne-collation.yml +2 -1
  230. data/spec/spec_tests/data/crud/write/findOneAndDelete-collation.yml +3 -2
  231. data/spec/spec_tests/data/crud/write/findOneAndReplace-collation.yml +2 -1
  232. data/spec/spec_tests/data/crud/write/findOneAndUpdate-collation.yml +3 -2
  233. data/spec/spec_tests/data/crud/write/replaceOne-collation.yml +3 -2
  234. data/spec/spec_tests/data/crud/write/updateMany-collation.yml +2 -1
  235. data/spec/spec_tests/data/crud/write/updateOne-collation.yml +2 -1
  236. data/spec/spec_tests/data/load_balancers/event-monitoring.yml +99 -0
  237. data/spec/spec_tests/data/load_balancers/lb-connection-establishment.yml +36 -0
  238. data/spec/spec_tests/data/load_balancers/non-lb-connection-establishment.yml +56 -0
  239. data/spec/spec_tests/data/load_balancers/server-selection.yml +50 -0
  240. data/spec/spec_tests/data/retryable_reads/changeStreams-client.watch-serverErrors.yml +1 -1
  241. data/spec/spec_tests/data/retryable_reads/changeStreams-client.watch.yml +1 -1
  242. data/spec/spec_tests/data/retryable_reads/changeStreams-db.coll.watch-serverErrors.yml +1 -1
  243. data/spec/spec_tests/data/retryable_reads/changeStreams-db.coll.watch.yml +1 -1
  244. data/spec/spec_tests/data/retryable_reads/changeStreams-db.watch-serverErrors.yml +1 -1
  245. data/spec/spec_tests/data/retryable_reads/changeStreams-db.watch.yml +1 -1
  246. data/spec/spec_tests/data/retryable_reads/mapReduce.yml +3 -1
  247. data/spec/spec_tests/data/sdam/load-balanced/discover_load_balancer.yml +25 -0
  248. data/spec/spec_tests/data/sdam_integration/find-network-error.yml +2 -0
  249. data/spec/spec_tests/data/sdam_integration/find-shutdown-error.yml +2 -0
  250. data/spec/spec_tests/data/sdam_integration/hello-command-error.yml +3 -1
  251. data/spec/spec_tests/data/sdam_integration/hello-network-error.yml +3 -1
  252. data/spec/spec_tests/data/sdam_integration/hello-timeout.yml +2 -0
  253. data/spec/spec_tests/data/sdam_integration/insert-network-error.yml +2 -0
  254. data/spec/spec_tests/data/sdam_integration/insert-shutdown-error.yml +2 -0
  255. data/spec/spec_tests/data/sdam_monitoring/load_balancer.yml +65 -0
  256. data/spec/spec_tests/data/seed_list_discovery/load-balanced/loadBalanced-directConnection.yml +13 -0
  257. data/spec/spec_tests/data/seed_list_discovery/load-balanced/loadBalanced-replicaSet-errors.yml +6 -0
  258. data/spec/spec_tests/data/seed_list_discovery/load-balanced/loadBalanced-true-multiple-hosts.yml +5 -0
  259. data/spec/spec_tests/data/seed_list_discovery/load-balanced/loadBalanced-true-txt.yml +10 -0
  260. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/direct-connection-false.yml +0 -0
  261. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/direct-connection-true.yml +0 -0
  262. data/spec/spec_tests/data/seed_list_discovery/replica-set/encoded-userinfo-and-db.yml +15 -0
  263. data/spec/spec_tests/data/seed_list_discovery/replica-set/loadBalanced-false-txt.yml +10 -0
  264. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/longer-parent-in-return.yml +0 -0
  265. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/misformatted-option.yml +0 -0
  266. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/no-results.yml +0 -0
  267. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/not-enough-parts.yml +0 -0
  268. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/one-result-default-port.yml +0 -0
  269. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/one-txt-record-multiple-strings.yml +0 -0
  270. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/one-txt-record.yml +0 -0
  271. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/parent-part-mismatch1.yml +0 -0
  272. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/parent-part-mismatch2.yml +0 -0
  273. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/parent-part-mismatch3.yml +0 -0
  274. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/parent-part-mismatch4.yml +0 -0
  275. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/parent-part-mismatch5.yml +0 -0
  276. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/returned-parent-too-short.yml +0 -0
  277. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/returned-parent-wrong.yml +0 -0
  278. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/two-results-default-port.yml +0 -0
  279. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/two-results-nonstandard-port.yml +0 -0
  280. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/two-txt-records.yml +0 -0
  281. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/txt-record-not-allowed-option.yml +0 -0
  282. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/txt-record-with-overridden-ssl-option.yml +0 -0
  283. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/txt-record-with-overridden-uri-option.yml +0 -0
  284. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/txt-record-with-unallowed-option.yml +0 -0
  285. data/spec/spec_tests/data/seed_list_discovery/replica-set/uri-with-admin-database.yml +13 -0
  286. data/spec/spec_tests/data/seed_list_discovery/replica-set/uri-with-auth.yml +12 -0
  287. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/uri-with-port.yml +0 -0
  288. data/spec/spec_tests/data/{dns_seedlist_discovery → seed_list_discovery/replica-set}/uri-with-two-hosts.yml +0 -0
  289. data/spec/spec_tests/data/transactions/retryable-abort-errorLabels.yml +2 -0
  290. data/spec/spec_tests/data/transactions/retryable-abort.yml +2 -0
  291. data/spec/spec_tests/data/transactions/retryable-commit-errorLabels.yml +2 -0
  292. data/spec/spec_tests/data/transactions/retryable-commit.yml +2 -0
  293. data/spec/spec_tests/data/transactions/retryable-writes.yml +2 -0
  294. data/spec/spec_tests/data/uri_options/connection-options.yml +60 -0
  295. data/spec/spec_tests/load_balancers_spec.rb +15 -0
  296. data/spec/spec_tests/retryable_reads_spec.rb +2 -2
  297. data/spec/spec_tests/retryable_writes_spec.rb +1 -1
  298. data/spec/spec_tests/sdam_integration_spec.rb +1 -1
  299. data/spec/spec_tests/sdam_monitoring_spec.rb +10 -5
  300. data/spec/spec_tests/sdam_spec.rb +1 -1
  301. data/spec/spec_tests/seed_list_discovery_spec.rb +118 -0
  302. data/spec/spec_tests/uri_options_spec.rb +4 -4
  303. data/spec/stress/fork_reconnect_stress_spec.rb +1 -5
  304. data/spec/support/certificates/atlas-ocsp-ca.crt +82 -90
  305. data/spec/support/certificates/atlas-ocsp.crt +127 -122
  306. data/spec/support/common_shortcuts.rb +2 -3
  307. data/spec/support/matchers.rb +13 -0
  308. data/spec/support/shared/auth_context.rb +16 -0
  309. data/spec/support/shared/session.rb +2 -2
  310. data/spec/support/spec_config.rb +9 -10
  311. data/spec/support/using_hash.rb +31 -0
  312. data/spec/support/utils.rb +1 -1
  313. data.tar.gz.sig +0 -0
  314. metadata +120 -76
  315. metadata.gz.sig +0 -0
  316. data/lib/mongo/collection/view/builder/find_command.rb +0 -173
  317. data/lib/mongo/collection/view/builder/op_query.rb +0 -94
  318. data/lib/mongo/cursor/builder/get_more_command.rb +0 -80
  319. data/lib/mongo/cursor/builder/kill_cursors_command.rb +0 -111
  320. data/lib/mongo/cursor/builder/op_get_more.rb +0 -64
  321. data/lib/mongo/cursor/builder/op_kill_cursors.rb +0 -106
  322. data/lib/mongo/server/context.rb +0 -72
  323. data/spec/mongo/cursor/builder/op_kill_cursors_spec.rb +0 -66
  324. data/spec/runners/unified/using_hash.rb +0 -34
  325. data/spec/spec_tests/dns_seedlist_discovery_spec.rb +0 -79
  326. data/spec/support/event_subscriber.rb +0 -221
data/lib/mongo/cluster.rb CHANGED
@@ -159,6 +159,10 @@ module Mongo
159
159
  @sdam_flow_lock = Mutex.new
160
160
  Session::SessionPool.create(self)
161
161
 
162
+ if seeds.empty? && load_balanced?
163
+ raise ArgumentError, 'Load-balanced clusters with no seeds are prohibited'
164
+ end
165
+
162
166
  # The opening topology is always unknown with no servers.
163
167
  # https://github.com/mongodb/specifications/pull/388
164
168
  opening_topology = Topology::Unknown.new(options, monitoring, self)
@@ -171,7 +175,7 @@ module Mongo
171
175
  @seeds = seeds = seeds.uniq
172
176
  servers = seeds.map do |seed|
173
177
  # Server opening events must be sent after topology change events.
174
- # Therefore separate server addition, done here before topoolgy change
178
+ # Therefore separate server addition, done here before topology change
175
179
  # event is published, from starting to monitor the server which is
176
180
  # done later.
177
181
  add(seed, monitor: false)
@@ -179,11 +183,20 @@ module Mongo
179
183
 
180
184
  if seeds.size >= 1
181
185
  # Recreate the topology to get the current server list into it
182
- @topology = topology.class.new(topology.options, topology.monitoring, self)
183
- publish_sdam_event(
184
- Monitoring::TOPOLOGY_CHANGED,
185
- Monitoring::Event::TopologyChanged.new(opening_topology, @topology)
186
- )
186
+ recreate_topology(topology, opening_topology)
187
+ end
188
+
189
+ if load_balanced?
190
+ # We are required by the specifications to produce certain SDAM events
191
+ # when in load-balanced topology.
192
+ # These events don't make a lot of sense from the standpoint of the
193
+ # driver's SDAM implementation, nor from the standpoint of the
194
+ # driver's load balancer implementation.
195
+ # They are just required boilerplate.
196
+ #
197
+ # Note that this call must be done above the monitoring_io check
198
+ # because that short-circuits the rest of the constructor.
199
+ fabricate_lb_sdam_events_and_set_server_type
187
200
  end
188
201
 
189
202
  if options[:monitoring_io] == false
@@ -203,7 +216,7 @@ module Mongo
203
216
  @connected = true
204
217
 
205
218
  if options[:cleanup] != false
206
- @cursor_reaper = CursorReaper.new
219
+ @cursor_reaper = CursorReaper.new(self)
207
220
  @socket_reaper = SocketReaper.new(self)
208
221
  @periodic_executor = PeriodicExecutor.new([
209
222
  @cursor_reaper, @socket_reaper,
@@ -212,54 +225,56 @@ module Mongo
212
225
  @periodic_executor.run!
213
226
  end
214
227
 
215
- # Need to record start time prior to starting monitoring
216
- start_monotime = Utils.monotonic_time
217
-
218
- servers.each do |server|
219
- server.start_monitoring
220
- end
228
+ unless load_balanced?
229
+ # Need to record start time prior to starting monitoring
230
+ start_monotime = Utils.monotonic_time
221
231
 
222
- if options[:scan] != false
223
- server_selection_timeout = options[:server_selection_timeout] || ServerSelector::SERVER_SELECTION_TIMEOUT
224
- # The server selection timeout can be very short especially in
225
- # tests, when the client waits for a synchronous scan before
226
- # starting server selection. Limiting the scan to server selection time
227
- # then aborts the scan before it can process even local servers.
228
- # Therefore, allow at least 3 seconds for the scan here.
229
- if server_selection_timeout < 3
230
- server_selection_timeout = 3
232
+ servers.each do |server|
233
+ server.start_monitoring
231
234
  end
232
- deadline = start_monotime + server_selection_timeout
233
- # Wait for the first scan of each server to complete, for
234
- # backwards compatibility.
235
- # If any servers are discovered during this SDAM round we are going to
236
- # wait for these servers to also be queried, and so on, up to the
237
- # server selection timeout or the 3 second minimum.
238
- loop do
239
- # Ensure we do not try to read the servers list while SDAM is running
240
- servers = @sdam_flow_lock.synchronize do
241
- servers_list.dup
242
- end
243
- if servers.all? { |server| server.last_scan_monotime && server.last_scan_monotime >= start_monotime }
244
- break
245
- end
246
- if (time_remaining = deadline - Utils.monotonic_time) <= 0
247
- break
235
+
236
+ if options[:scan] != false
237
+ server_selection_timeout = options[:server_selection_timeout] || ServerSelector::SERVER_SELECTION_TIMEOUT
238
+ # The server selection timeout can be very short especially in
239
+ # tests, when the client waits for a synchronous scan before
240
+ # starting server selection. Limiting the scan to server selection time
241
+ # then aborts the scan before it can process even local servers.
242
+ # Therefore, allow at least 3 seconds for the scan here.
243
+ if server_selection_timeout < 3
244
+ server_selection_timeout = 3
248
245
  end
249
- log_debug("Waiting for up to #{'%.2f' % time_remaining} seconds for servers to be scanned: #{summary}")
250
- # Since the semaphore may have been signaled between us checking
251
- # the servers list above and the wait call below, we should not
252
- # wait for the full remaining time - wait for up to 1 second, then
253
- # recheck the state.
254
- begin
255
- server_selection_semaphore.wait([time_remaining, 1].min)
256
- rescue ::Timeout::Error
257
- # nothing
246
+ deadline = start_monotime + server_selection_timeout
247
+ # Wait for the first scan of each server to complete, for
248
+ # backwards compatibility.
249
+ # If any servers are discovered during this SDAM round we are going to
250
+ # wait for these servers to also be queried, and so on, up to the
251
+ # server selection timeout or the 3 second minimum.
252
+ loop do
253
+ # Ensure we do not try to read the servers list while SDAM is running
254
+ servers = @sdam_flow_lock.synchronize do
255
+ servers_list.dup
256
+ end
257
+ if servers.all? { |server| server.last_scan_monotime && server.last_scan_monotime >= start_monotime }
258
+ break
259
+ end
260
+ if (time_remaining = deadline - Utils.monotonic_time) <= 0
261
+ break
262
+ end
263
+ log_debug("Waiting for up to #{'%.2f' % time_remaining} seconds for servers to be scanned: #{summary}")
264
+ # Since the semaphore may have been signaled between us checking
265
+ # the servers list above and the wait call below, we should not
266
+ # wait for the full remaining time - wait for up to 1 second, then
267
+ # recheck the state.
268
+ begin
269
+ server_selection_semaphore.wait([time_remaining, 1].min)
270
+ rescue ::Timeout::Error
271
+ # nothing
272
+ end
258
273
  end
259
274
  end
260
- end
261
275
 
262
- start_stop_srv_monitor
276
+ start_stop_srv_monitor
277
+ end
263
278
  end
264
279
 
265
280
  # Create a cluster for the provided client, for use when we don't want the
@@ -321,6 +336,14 @@ module Mongo
321
336
  def_delegators :topology, :replica_set?, :replica_set_name, :sharded?,
322
337
  :single?, :unknown?
323
338
 
339
+ # Returns whether the cluster is configured to be in the load-balanced
340
+ # topology.
341
+ #
342
+ # @return [ true | false ] Whether the topology is load-balanced.
343
+ def load_balanced?
344
+ topology.is_a?(Topology::LoadBalanced)
345
+ end
346
+
324
347
  [:register_cursor, :schedule_kill_cursor, :unregister_cursor].each do |m|
325
348
  define_method(m) do |*args|
326
349
  if options[:cleanup] != false
@@ -599,9 +622,25 @@ module Mongo
599
622
  # on 4.2+ servers).
600
623
  # @option aptions [ true | false ] :awaited Whether the updated description
601
624
  # was a result of processing an awaited hello.
625
+ # @option options [ Object ] :service_id Change state for the specified
626
+ # service id only.
602
627
  #
603
628
  # @api private
604
629
  def run_sdam_flow(previous_desc, updated_desc, options = {})
630
+ if load_balanced?
631
+ if updated_desc.config.empty?
632
+ unless options[:keep_connection_pool]
633
+ servers_list.each do |server|
634
+ # TODO should service id be taken out of updated_desc?
635
+ # We could also assert that
636
+ # options[:service_id] == updated_desc.service_id
637
+ server.clear_connection_pool(service_id: options[:service_id])
638
+ end
639
+ end
640
+ end
641
+ return
642
+ end
643
+
605
644
  @sdam_flow_lock.synchronize do
606
645
  flow = SdamFlow.new(self, previous_desc, updated_desc,
607
646
  awaited: options[:awaited])
@@ -782,8 +821,15 @@ module Mongo
782
821
  def add(host, add_options=nil)
783
822
  address = Address.new(host, options)
784
823
  if !addresses.include?(address)
785
- server = Server.new(address, self, @monitoring, event_listeners, options.merge(
786
- monitor: false))
824
+ opts = options.merge(monitor: false)
825
+ # Note that in a load-balanced topology, every server must be a
826
+ # load balancer (load_balancer: true is specified in the options)
827
+ # but this option isn't set here because we are required by the
828
+ # specifications to pretent the server started out as an unknown one
829
+ # and publish server description change event into the load balancer
830
+ # one. The actual correct description for this server will be set
831
+ # by the fabricate_lb_sdam_events_and_set_server_type method.
832
+ server = Server.new(address, self, @monitoring, event_listeners, opts)
787
833
  @update_lock.synchronize do
788
834
  # Need to recheck whether server is present in @servers, because
789
835
  # the previous check was not under a lock.
@@ -899,6 +945,10 @@ module Mongo
899
945
  #
900
946
  # @api private
901
947
  def validate_session_support!
948
+ if topology.is_a?(Topology::LoadBalanced)
949
+ return
950
+ end
951
+
902
952
  @state_change_lock.synchronize do
903
953
  @sdam_flow_lock.synchronize do
904
954
  if topology.data_bearing_servers?
@@ -982,6 +1032,41 @@ module Mongo
982
1032
  msg = "The deployment that the driver is connected to does not support sessions: #{reason}"
983
1033
  raise Error::SessionsNotSupported, msg
984
1034
  end
1035
+
1036
+ def fabricate_lb_sdam_events_and_set_server_type
1037
+ # Although there is no monitoring connection in load balanced mode,
1038
+ # we must emit the following series of SDAM events.
1039
+ server = @servers.first
1040
+ # We are guaranteed to have the server here.
1041
+ server.publish_opening_event
1042
+ server_desc = server.description
1043
+ # This is where a load balancer actually gets its correct server
1044
+ # description.
1045
+ server.update_description(
1046
+ Server::Description.new(server.address, {},
1047
+ load_balancer: true,
1048
+ force_load_balancer: options[:connect] == :load_balanced,
1049
+ )
1050
+ )
1051
+ publish_sdam_event(
1052
+ Monitoring::SERVER_DESCRIPTION_CHANGED,
1053
+ Monitoring::Event::ServerDescriptionChanged.new(
1054
+ server.address,
1055
+ topology,
1056
+ server_desc,
1057
+ server.description
1058
+ )
1059
+ )
1060
+ recreate_topology(topology, topology)
1061
+ end
1062
+
1063
+ def recreate_topology(new_topology_template, previous_topology)
1064
+ @topology = topology.class.new(new_topology_template.options, new_topology_template.monitoring, self)
1065
+ publish_sdam_event(
1066
+ Monitoring::TOPOLOGY_CHANGED,
1067
+ Monitoring::Event::TopologyChanged.new(previous_topology, @topology)
1068
+ )
1069
+ end
985
1070
  end
986
1071
  end
987
1072
 
@@ -121,10 +121,12 @@ module Mongo
121
121
  end
122
122
 
123
123
  def valid_server?(server)
124
- description = server.with_connection do |connection|
125
- connection.description
124
+ if secondary_ok?
125
+ true
126
+ else
127
+ description = server.description
128
+ description.standalone? || description.mongos? || description.primary? || description.load_balancer?
126
129
  end
127
- description.standalone? || description.mongos? || description.primary? || secondary_ok?
128
130
  end
129
131
 
130
132
  def secondary_ok?
@@ -136,16 +138,9 @@ module Mongo
136
138
  log_warn("Rerouting the Aggregation operation to the primary server - #{server.summary} is not suitable")
137
139
  server = cluster.next_primary(nil, session)
138
140
  end
139
- validate_collation!(server)
140
141
  initial_query_op(session).execute(server, context: Operation::Context.new(client: client, session: session))
141
142
  end
142
143
 
143
- def validate_collation!(server)
144
- if options[:collation] && !server.with_connection { |connection| connection.features }.collation_enabled?
145
- raise Error::UnsupportedCollation.new
146
- end
147
- end
148
-
149
144
  # Skip, sort, limit, projection are specified as pipeline stages
150
145
  # rather than as options.
151
146
  def cache_options
@@ -79,11 +79,12 @@ module Mongo
79
79
  # @since 2.2.0
80
80
  def specification
81
81
  spec = {
82
- selector: aggregation_command,
83
- db_name: database.name,
84
- read: view.read_preference,
85
- session: @options[:session]
86
- }
82
+ selector: aggregation_command,
83
+ db_name: database.name,
84
+ read: view.read_preference,
85
+ session: @options[:session],
86
+ collation: @options[:collation],
87
+ }
87
88
  if write?
88
89
  spec.update(write_concern: write_concern)
89
90
  end
@@ -36,7 +36,7 @@ module Mongo
36
36
  scope: 'scope',
37
37
  verbose: 'verbose',
38
38
  bypass_document_validation: 'bypassDocumentValidation',
39
- collation: 'collation'
39
+ collation: 'collation',
40
40
  ).freeze
41
41
 
42
42
  def_delegators :@view, :collection, :database, :filter, :read, :write_concern
@@ -71,36 +71,6 @@ module Mongo
71
71
  @options = options
72
72
  end
73
73
 
74
- # Get the specification for issuing a find command on the map/reduce
75
- # results.
76
- #
77
- # @example Get the command specification.
78
- # builder.command_specification
79
- #
80
- # @return [ Hash ] The specification.
81
- #
82
- # @since 2.2.0
83
- def command_specification
84
- {
85
- selector: find_command,
86
- db_name: query_database,
87
- read: read,
88
- session: options[:session]
89
- }
90
- end
91
-
92
- # Get the specification for the document query after a map/reduce.
93
- #
94
- # @example Get the query specification.
95
- # builder.query_specification
96
- #
97
- # @return [ Hash ] The specification.
98
- #
99
- # @since 2.2.0
100
- def query_specification
101
- { selector: {}, options: {}, db_name: query_database, coll_name: query_collection }
102
- end
103
-
104
74
  # Get the specification to pass to the map/reduce operation.
105
75
  #
106
76
  # @example Get the specification.
@@ -113,6 +83,8 @@ module Mongo
113
83
  spec = {
114
84
  selector: map_reduce_command,
115
85
  db_name: database.name,
86
+ # Note that selector just above may also have a read preference
87
+ # specified, per the #map_reduce_command method below.
116
88
  read: read,
117
89
  session: options[:session]
118
90
  }
@@ -121,8 +93,6 @@ module Mongo
121
93
 
122
94
  private
123
95
 
124
- OUT_ACTIONS = [ :replace, :merge, :reduce ].freeze
125
-
126
96
  def write?(spec)
127
97
  if out = spec[:selector][:out]
128
98
  out.is_a?(String) ||
@@ -130,37 +100,30 @@ module Mongo
130
100
  end
131
101
  end
132
102
 
133
- def find_command
134
- BSON::Document.new('find' => query_collection, 'filter' => {})
135
- end
136
-
137
103
  def map_reduce_command
138
104
  command = BSON::Document.new(
139
105
  :mapReduce => collection.name,
140
106
  :map => map,
141
107
  :reduce => reduce,
142
108
  :query => filter,
143
- :out => { inline: 1 }
109
+ :out => { inline: 1 },
144
110
  )
111
+ # Shouldn't this use self.read ?
145
112
  if collection.read_concern
146
113
  command[:readConcern] = Options::Mapper.transform_values_to_strings(
147
114
  collection.read_concern)
148
115
  end
149
- command.merge!(view_options)
116
+ command.update(view_options)
117
+ command.update(Utils.slice_hash(options, :collation))
118
+ # Read preference isn't simply passed in the command payload
119
+ # (it may need to be converted to wire protocol flags)
120
+ # so remove it here and hopefully it's handled elsewhere.
121
+ # If not, RUBY-2706.
122
+ command.delete(:read)
150
123
  command.merge!(Options::Mapper.transform_documents(options, MAPPINGS))
151
124
  command
152
125
  end
153
126
 
154
- def query_database
155
- options[:out].respond_to?(:keys) && options[:out][:db] ? options[:out][:db] : database.name
156
- end
157
-
158
- def query_collection
159
- if options[:out].respond_to?(:keys)
160
- options[:out][OUT_ACTIONS.find { |action| options[:out][action] }]
161
- end || options[:out]
162
- end
163
-
164
127
  def view_options
165
128
  @view_options ||= (opts = view.options.dup
166
129
  opts.delete(:session)
@@ -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.
@@ -140,36 +147,53 @@ module Mongo
140
147
  projection: projection,
141
148
  collation: collation,
142
149
  read_concern: read_concern,
143
- read_preference: read_preference
144
-
150
+ read_preference: read_preference,
145
151
  }
146
152
  end
147
153
 
148
154
  def initial_query_op(server, session)
149
- if server.with_connection { |connection| connection.features }.find_command_enabled?
150
- initial_command_op(session)
151
- else
152
- # Server versions that do not have the find command feature
153
- # (versions older than 3.2) do not support the allow_disk_use option
154
- # but perform no validation and will not raise an error if it is
155
- # specified. If the allow_disk_use option is specified, raise an error
156
- # to alert the user.
157
- raise Error::UnsupportedOption.allow_disk_use_error if options.key?(:allow_disk_use)
158
- 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")
159
186
  end
160
- end
161
187
 
162
- def initial_command_op(session)
163
- builder = Builder::FindCommand.new(self, session)
164
188
  if explained?
165
- Operation::Explain.new(builder.explain_specification)
189
+ spec[:explain] = options[:explain]
190
+ Operation::Explain.new(spec)
166
191
  else
167
- Operation::Find.new(builder.specification)
192
+ Operation::Find.new(spec)
168
193
  end
169
194
  end
170
195
 
171
196
  def send_initial_query(server, session = nil)
172
- validate_collation!(server, collation)
173
197
  initial_query_op(server, session).execute(server, context: Operation::Context.new(client: client, session: session))
174
198
  end
175
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