mongo 1.12.5 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (475) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CONTRIBUTING.md +64 -0
  4. data/LICENSE +1 -1
  5. data/README.md +21 -126
  6. data/Rakefile +39 -21
  7. data/bin/mongo_console +6 -38
  8. data/lib/mongo/address/ipv4.rb +85 -0
  9. data/lib/mongo/address/ipv6.rb +85 -0
  10. data/lib/mongo/address/unix.rb +76 -0
  11. data/lib/mongo/address.rb +111 -0
  12. data/lib/mongo/auth/cr/conversation.rb +119 -0
  13. data/lib/mongo/auth/cr.rb +44 -0
  14. data/lib/mongo/auth/executable.rb +52 -0
  15. data/lib/mongo/auth/ldap/conversation.rb +92 -0
  16. data/lib/mongo/auth/ldap.rb +48 -0
  17. data/lib/mongo/auth/roles.rb +104 -0
  18. data/lib/mongo/auth/scram/conversation.rb +450 -0
  19. data/lib/mongo/auth/scram.rb +53 -0
  20. data/lib/mongo/auth/user/view.rb +102 -0
  21. data/lib/mongo/auth/user.rb +159 -0
  22. data/lib/mongo/auth/x509/conversation.rb +92 -0
  23. data/lib/mongo/auth/x509.rb +48 -0
  24. data/lib/mongo/auth.rb +108 -0
  25. data/lib/mongo/bulk_write/bulk_writable.rb +191 -0
  26. data/lib/mongo/bulk_write/deletable.rb +60 -0
  27. data/lib/mongo/bulk_write/insertable.rb +52 -0
  28. data/lib/mongo/bulk_write/ordered_bulk_write.rb +48 -0
  29. data/lib/mongo/bulk_write/replacable.rb +57 -0
  30. data/lib/mongo/bulk_write/unordered_bulk_write.rb +46 -0
  31. data/lib/mongo/bulk_write/updatable.rb +68 -0
  32. data/lib/mongo/bulk_write.rb +52 -0
  33. data/lib/mongo/client.rb +246 -0
  34. data/lib/mongo/cluster/topology/replica_set.rb +160 -0
  35. data/lib/mongo/cluster/topology/sharded.rb +132 -0
  36. data/lib/mongo/cluster/topology/standalone.rb +132 -0
  37. data/lib/mongo/cluster/topology/unknown.rb +155 -0
  38. data/lib/mongo/cluster/topology.rb +60 -0
  39. data/lib/mongo/cluster.rb +203 -0
  40. data/lib/mongo/collection/view/aggregation.rb +108 -0
  41. data/lib/mongo/collection/view/explainable.rb +49 -0
  42. data/lib/mongo/collection/view/immutable.rb +43 -0
  43. data/lib/mongo/collection/view/iterable.rb +48 -0
  44. data/lib/mongo/collection/view/map_reduce.rb +191 -0
  45. data/lib/mongo/collection/view/readable.rb +363 -0
  46. data/lib/mongo/collection/view/writable.rb +185 -0
  47. data/lib/mongo/collection/view.rb +169 -0
  48. data/lib/mongo/collection.rb +130 -1101
  49. data/lib/mongo/cursor.rb +78 -681
  50. data/lib/mongo/database/view.rb +101 -0
  51. data/lib/mongo/database.rb +224 -0
  52. data/lib/mongo/error/bulk_write_error.rb +41 -0
  53. data/lib/mongo/error/invalid_bulk_operation.rb +36 -0
  54. data/lib/mongo/error/invalid_bulk_operation_type.rb +36 -0
  55. data/lib/mongo/error/invalid_collection_name.rb +39 -0
  56. data/lib/mongo/error/invalid_database_name.rb +39 -0
  57. data/{test/replica_set/ssl_test.rb → lib/mongo/error/invalid_document.rb} +21 -14
  58. data/lib/mongo/error/invalid_file.rb +38 -0
  59. data/lib/mongo/error/invalid_nonce.rb +46 -0
  60. data/lib/mongo/error/invalid_replacement_document.rb +39 -0
  61. data/lib/mongo/error/invalid_signature.rb +47 -0
  62. data/{test/functional/ssl_test.rb → lib/mongo/error/invalid_update_document.rb} +22 -12
  63. data/lib/mongo/error/max_bson_size.rb +40 -0
  64. data/lib/mongo/error/max_message_size.rb +42 -0
  65. data/{test/functional/db_connection_test.rb → lib/mongo/error/multi_index_drop.rb} +17 -8
  66. data/lib/mongo/{utils.rb → error/need_primary_server.rb} +10 -6
  67. data/lib/mongo/{connection.rb → error/operation_failure.rb} +10 -6
  68. data/lib/mongo/error/parser.rb +77 -0
  69. data/lib/mongo/{connection/socket.rb → error/socket_error.rb} +10 -5
  70. data/lib/mongo/error/socket_timeout_error.rb +23 -0
  71. data/lib/mongo/error/unsupported_features.rb +43 -0
  72. data/lib/mongo/error.rb +82 -0
  73. data/lib/mongo/event/listeners.rb +63 -0
  74. data/lib/mongo/event/primary_elected.rb +53 -0
  75. data/lib/mongo/event/publisher.rb +42 -0
  76. data/lib/mongo/event/server_added.rb +53 -0
  77. data/lib/mongo/event/server_removed.rb +53 -0
  78. data/lib/mongo/event/subscriber.rb +41 -0
  79. data/lib/mongo/event.rb +40 -0
  80. data/lib/mongo/grid/file/chunk.rb +184 -0
  81. data/lib/mongo/grid/file/metadata.rb +229 -0
  82. data/lib/mongo/grid/file.rb +106 -0
  83. data/lib/mongo/grid/fs.rb +149 -0
  84. data/lib/mongo/{gridfs.rb → grid.rb} +3 -5
  85. data/lib/mongo/index/view.rb +261 -0
  86. data/lib/mongo/index.rb +64 -0
  87. data/lib/mongo/loggable.rb +126 -0
  88. data/lib/mongo/logger.rb +132 -0
  89. data/lib/mongo/operation/aggregate/result.rb +88 -0
  90. data/lib/mongo/operation/aggregate.rb +100 -0
  91. data/lib/mongo/operation/command.rb +62 -0
  92. data/lib/mongo/operation/executable.rb +105 -0
  93. data/lib/mongo/operation/kill_cursors.rb +39 -0
  94. data/lib/mongo/operation/limited.rb +37 -0
  95. data/lib/mongo/operation/list_collections/result.rb +114 -0
  96. data/lib/mongo/operation/list_indexes/result.rb +118 -0
  97. data/lib/mongo/operation/map_reduce/result.rb +122 -0
  98. data/lib/mongo/operation/map_reduce.rb +96 -0
  99. data/lib/mongo/operation/read/collections_info.rb +67 -0
  100. data/lib/mongo/operation/read/get_more.rb +71 -0
  101. data/lib/mongo/operation/read/indexes.rb +68 -0
  102. data/lib/mongo/operation/read/list_collections.rb +75 -0
  103. data/lib/mongo/operation/read/list_indexes.rb +77 -0
  104. data/lib/mongo/operation/read/query.rb +71 -0
  105. data/lib/mongo/{functional.rb → operation/read.rb} +7 -7
  106. data/lib/mongo/operation/read_preferrable.rb +34 -0
  107. data/lib/mongo/operation/result.rb +259 -0
  108. data/lib/mongo/operation/specifiable.rb +397 -0
  109. data/lib/mongo/operation/write/bulk/bulk_delete/result.rb +75 -0
  110. data/lib/mongo/operation/write/bulk/bulk_delete.rb +144 -0
  111. data/lib/mongo/operation/write/bulk/bulk_insert/result.rb +68 -0
  112. data/lib/mongo/operation/write/bulk/bulk_insert.rb +129 -0
  113. data/lib/mongo/operation/write/bulk/bulk_mergable.rb +67 -0
  114. data/lib/mongo/operation/write/bulk/bulk_update/result.rb +162 -0
  115. data/lib/mongo/operation/write/bulk/bulk_update.rb +153 -0
  116. data/lib/mongo/operation/write/bulk/legacy_bulk_mergable.rb +83 -0
  117. data/lib/mongo/operation/write/bulk.rb +17 -0
  118. data/lib/mongo/operation/write/command/create_index.rb +50 -0
  119. data/lib/mongo/operation/write/command/create_user.rb +43 -0
  120. data/lib/mongo/operation/write/command/delete.rb +56 -0
  121. data/lib/mongo/operation/write/command/drop_index.rb +51 -0
  122. data/lib/mongo/operation/write/command/insert.rb +55 -0
  123. data/lib/mongo/operation/write/command/remove_user.rb +42 -0
  124. data/lib/mongo/operation/write/command/update.rb +60 -0
  125. data/lib/mongo/operation/write/command/writable.rb +61 -0
  126. data/lib/mongo/operation/write/command.rb +22 -0
  127. data/lib/mongo/operation/write/create_index.rb +89 -0
  128. data/lib/mongo/operation/write/create_user.rb +75 -0
  129. data/lib/mongo/operation/write/delete/result.rb +40 -0
  130. data/lib/mongo/operation/write/delete.rb +93 -0
  131. data/lib/mongo/operation/write/drop_index.rb +62 -0
  132. data/lib/mongo/{utils/thread_local_variable_manager.rb → operation/write/insert/result.rb} +15 -8
  133. data/lib/mongo/operation/write/insert.rb +90 -0
  134. data/lib/mongo/operation/write/remove_user.rb +70 -0
  135. data/lib/mongo/operation/write/update/result.rb +160 -0
  136. data/lib/mongo/operation/write/update.rb +103 -0
  137. data/lib/mongo/{connection/socket/socket_util.rb → operation/write.rb} +10 -24
  138. data/lib/mongo/operation.rb +25 -0
  139. data/lib/mongo/options/mapper.rb +78 -0
  140. data/lib/mongo/options.rb +15 -0
  141. data/lib/mongo/protocol/bit_vector.rb +61 -0
  142. data/lib/mongo/protocol/delete.rb +94 -0
  143. data/lib/mongo/protocol/get_more.rb +99 -0
  144. data/lib/mongo/protocol/insert.rb +99 -0
  145. data/lib/mongo/protocol/kill_cursors.rb +74 -0
  146. data/lib/mongo/protocol/message.rb +252 -0
  147. data/lib/mongo/protocol/query.rb +147 -0
  148. data/lib/mongo/protocol/reply.rb +72 -0
  149. data/lib/mongo/protocol/serializers.rb +180 -0
  150. data/lib/mongo/protocol/update.rb +111 -0
  151. data/lib/mongo/protocol.rb +15 -0
  152. data/lib/mongo/server/connectable.rb +110 -0
  153. data/lib/mongo/server/connection.rb +134 -0
  154. data/lib/mongo/server/connection_pool/queue.rb +182 -0
  155. data/lib/mongo/server/connection_pool.rb +141 -0
  156. data/lib/mongo/server/context.rb +66 -0
  157. data/lib/mongo/server/description/features.rb +85 -0
  158. data/lib/mongo/server/description/inspector/primary_elected.rb +58 -0
  159. data/lib/mongo/server/description/inspector/server_added.rb +59 -0
  160. data/lib/mongo/server/description/inspector/server_removed.rb +59 -0
  161. data/lib/mongo/server/description/inspector.rb +79 -0
  162. data/lib/mongo/server/description.rb +450 -0
  163. data/lib/mongo/server/monitor/connection.rb +89 -0
  164. data/lib/mongo/server/monitor.rb +176 -0
  165. data/lib/mongo/server.rb +163 -0
  166. data/lib/mongo/server_selector/nearest.rb +94 -0
  167. data/lib/mongo/server_selector/primary.rb +88 -0
  168. data/lib/mongo/server_selector/primary_preferred.rb +94 -0
  169. data/lib/mongo/server_selector/secondary.rb +91 -0
  170. data/lib/mongo/server_selector/secondary_preferred.rb +96 -0
  171. data/lib/mongo/server_selector/selectable.rb +209 -0
  172. data/lib/mongo/server_selector.rb +81 -0
  173. data/lib/mongo/socket/ssl.rb +130 -0
  174. data/lib/mongo/socket/tcp.rb +69 -0
  175. data/lib/mongo/socket/unix.rb +64 -0
  176. data/lib/mongo/socket.rb +179 -0
  177. data/lib/mongo/uri.rb +504 -0
  178. data/lib/mongo/version.rb +21 -0
  179. data/lib/mongo/write_concern/acknowledged.rb +52 -0
  180. data/lib/mongo/write_concern/normalizable.rb +51 -0
  181. data/lib/mongo/write_concern/unacknowledged.rb +55 -0
  182. data/lib/mongo/write_concern.rb +99 -0
  183. data/lib/mongo.rb +24 -82
  184. data/mongo.gemspec +17 -14
  185. data/spec/certificates/ca.pem +17 -0
  186. data/spec/certificates/client.pem +101 -0
  187. data/spec/certificates/crl.pem +10 -0
  188. data/spec/certificates/crl_client_revoked.pem +12 -0
  189. data/spec/certificates/password_protected.pem +51 -0
  190. data/spec/certificates/server.pem +34 -0
  191. data/spec/mongo/address/ipv4_spec.rb +74 -0
  192. data/spec/mongo/address/ipv6_spec.rb +74 -0
  193. data/spec/mongo/address/unix_spec.rb +30 -0
  194. data/spec/mongo/address_spec.rb +206 -0
  195. data/spec/mongo/auth/cr_spec.rb +59 -0
  196. data/spec/mongo/auth/ldap_spec.rb +40 -0
  197. data/spec/mongo/auth/scram/conversation_spec.rb +197 -0
  198. data/spec/mongo/auth/scram_spec.rb +55 -0
  199. data/spec/mongo/auth/user/view_spec.rb +76 -0
  200. data/spec/mongo/auth/user_spec.rb +190 -0
  201. data/spec/mongo/auth/x509_spec.rb +40 -0
  202. data/spec/mongo/auth_spec.rb +65 -0
  203. data/spec/mongo/bulk/bulk_write_spec.rb +262 -0
  204. data/spec/mongo/client_spec.rb +564 -0
  205. data/spec/mongo/cluster/topology/replica_set_spec.rb +101 -0
  206. data/spec/mongo/cluster/topology/sharded_spec.rb +74 -0
  207. data/spec/mongo/cluster/topology/standalone_spec.rb +79 -0
  208. data/spec/mongo/cluster/topology_spec.rb +65 -0
  209. data/spec/mongo/cluster_spec.rb +129 -0
  210. data/spec/mongo/collection/view/aggregation_spec.rb +148 -0
  211. data/spec/mongo/collection/view/explainable_spec.rb +32 -0
  212. data/spec/mongo/collection/view/map_reduce_spec.rb +242 -0
  213. data/spec/mongo/collection/view/readable_spec.rb +603 -0
  214. data/spec/mongo/collection/view/writable_spec.rb +679 -0
  215. data/spec/mongo/collection/view_spec.rb +530 -0
  216. data/spec/mongo/collection_spec.rb +362 -0
  217. data/spec/mongo/crud_spec.rb +42 -0
  218. data/spec/mongo/cursor_spec.rb +295 -0
  219. data/spec/mongo/database_spec.rb +302 -0
  220. data/spec/mongo/error/parser_spec.rb +119 -0
  221. data/spec/mongo/event/publisher_spec.rb +50 -0
  222. data/spec/mongo/event/subscriber_spec.rb +34 -0
  223. data/spec/mongo/grid/file/chunk_spec.rb +226 -0
  224. data/spec/mongo/grid/file/metadata_spec.rb +92 -0
  225. data/spec/mongo/grid/file_spec.rb +172 -0
  226. data/spec/mongo/grid/fs_spec.rb +129 -0
  227. data/spec/mongo/index/view_spec.rb +330 -0
  228. data/spec/mongo/loggable_spec.rb +62 -0
  229. data/spec/mongo/logger_spec.rb +97 -0
  230. data/spec/mongo/operation/aggregate/result_spec.rb +80 -0
  231. data/spec/mongo/operation/aggregate_spec.rb +127 -0
  232. data/spec/mongo/operation/command_spec.rb +98 -0
  233. data/spec/mongo/operation/kill_cursors_spec.rb +66 -0
  234. data/spec/mongo/operation/limited_spec.rb +50 -0
  235. data/spec/mongo/operation/map_reduce_spec.rb +143 -0
  236. data/spec/mongo/operation/read/collections_info_spec.rb +40 -0
  237. data/spec/mongo/operation/read/get_more_spec.rb +81 -0
  238. data/spec/mongo/operation/read/indexes_spec.rb +31 -0
  239. data/spec/mongo/operation/read/query_spec.rb +84 -0
  240. data/spec/mongo/operation/result_spec.rb +275 -0
  241. data/spec/mongo/operation/specifiable_spec.rb +53 -0
  242. data/spec/mongo/operation/write/bulk_delete_spec.rb +235 -0
  243. data/spec/mongo/operation/write/bulk_insert_spec.rb +235 -0
  244. data/spec/mongo/operation/write/bulk_update_spec.rb +236 -0
  245. data/spec/mongo/operation/write/command/delete_spec.rb +103 -0
  246. data/spec/mongo/operation/write/command/insert_spec.rb +103 -0
  247. data/spec/mongo/operation/write/command/update_spec.rb +109 -0
  248. data/spec/mongo/operation/write/create_index_spec.rb +63 -0
  249. data/spec/mongo/operation/write/create_user_spec.rb +44 -0
  250. data/spec/mongo/operation/write/delete_spec.rb +186 -0
  251. data/spec/mongo/operation/write/drop_index_spec.rb +51 -0
  252. data/spec/mongo/operation/write/insert_spec.rb +244 -0
  253. data/spec/mongo/operation/write/remove_user_spec.rb +46 -0
  254. data/spec/mongo/operation/write/response_spec.rb +85 -0
  255. data/spec/mongo/operation/write/update_spec.rb +228 -0
  256. data/spec/mongo/protocol/delete_spec.rb +167 -0
  257. data/spec/mongo/protocol/get_more_spec.rb +146 -0
  258. data/spec/mongo/protocol/insert_spec.rb +161 -0
  259. data/spec/mongo/protocol/kill_cursors_spec.rb +101 -0
  260. data/spec/mongo/protocol/query_spec.rb +285 -0
  261. data/spec/mongo/protocol/reply_spec.rb +157 -0
  262. data/spec/mongo/protocol/update_spec.rb +186 -0
  263. data/spec/mongo/server/connection_pool/queue_spec.rb +170 -0
  264. data/spec/mongo/server/connection_pool_spec.rb +120 -0
  265. data/spec/mongo/server/connection_spec.rb +312 -0
  266. data/spec/mongo/server/description/features_spec.rb +138 -0
  267. data/spec/mongo/server/description/inspector/primary_elected_spec.rb +94 -0
  268. data/spec/mongo/server/description/inspector/server_added_spec.rb +92 -0
  269. data/spec/mongo/server/description/inspector/server_removed_spec.rb +95 -0
  270. data/spec/mongo/server/description_spec.rb +510 -0
  271. data/spec/mongo/server/monitor_spec.rb +144 -0
  272. data/spec/mongo/server_discovery_and_monitoring_spec.rb +103 -0
  273. data/spec/mongo/server_selection_rtt_spec.rb +104 -0
  274. data/spec/mongo/server_selection_spec.rb +89 -0
  275. data/spec/mongo/server_selector/nearest_spec.rb +250 -0
  276. data/spec/mongo/server_selector/primary_preferred_spec.rb +290 -0
  277. data/spec/mongo/server_selector/primary_spec.rb +114 -0
  278. data/spec/mongo/server_selector/secondary_preferred_spec.rb +252 -0
  279. data/spec/mongo/server_selector/secondary_spec.rb +196 -0
  280. data/spec/mongo/server_selector_spec.rb +101 -0
  281. data/spec/mongo/server_spec.rb +131 -0
  282. data/spec/mongo/uri_spec.rb +517 -0
  283. data/spec/mongo/write_concern/acknowledged_spec.rb +44 -0
  284. data/spec/mongo/write_concern/unacknowledged_spec.rb +15 -0
  285. data/spec/spec_helper.rb +133 -0
  286. data/spec/support/authorization.rb +247 -0
  287. data/spec/support/crud/read.rb +144 -0
  288. data/spec/support/crud/write.rb +214 -0
  289. data/spec/support/crud.rb +203 -0
  290. data/spec/support/crud_tests/read/aggregate.yml +43 -0
  291. data/spec/support/crud_tests/read/count.yml +37 -0
  292. data/spec/support/crud_tests/read/distinct.yml +33 -0
  293. data/spec/support/crud_tests/read/find.yml +50 -0
  294. data/spec/support/crud_tests/write/deleteMany.yml +36 -0
  295. data/spec/support/crud_tests/write/deleteOne.yml +49 -0
  296. data/spec/support/crud_tests/write/findOneAndDelete.yml +54 -0
  297. data/spec/support/crud_tests/write/findOneAndReplace.yml +153 -0
  298. data/spec/support/crud_tests/write/findOneAndUpdate.yml +161 -0
  299. data/spec/support/crud_tests/write/insertMany.yml +24 -0
  300. data/spec/support/crud_tests/write/insertOne.yml +19 -0
  301. data/spec/support/crud_tests/write/replaceOne.yml +96 -0
  302. data/spec/support/crud_tests/write/updateMany.yml +83 -0
  303. data/spec/support/crud_tests/write/updateOne.yml +80 -0
  304. data/spec/support/helpers.rb +140 -0
  305. data/spec/support/matchers.rb +37 -0
  306. data/spec/support/sdam/rs/discover_arbiters.yml +41 -0
  307. data/spec/support/sdam/rs/discover_passives.yml +41 -0
  308. data/spec/support/sdam/rs/discover_primary.yml +40 -0
  309. data/spec/support/sdam/rs/discover_secondary.yml +41 -0
  310. data/spec/support/sdam/rs/discovery.yml +195 -0
  311. data/spec/support/sdam/rs/ghost_discovered.yml +39 -0
  312. data/spec/support/sdam/rs/hosts_differ_from_seeds.yml +34 -0
  313. data/spec/support/sdam/rs/member_reconfig.yml +68 -0
  314. data/spec/support/sdam/rs/member_standalone.yml +60 -0
  315. data/spec/support/sdam/rs/new_primary.yml +74 -0
  316. data/spec/support/sdam/rs/new_primary_wrong_set_name.yml +71 -0
  317. data/spec/support/sdam/rs/non_rs_member.yml +31 -0
  318. data/spec/support/sdam/rs/normalize_case.yml +49 -0
  319. data/spec/support/sdam/rs/primary_becomes_standalone.yml +52 -0
  320. data/spec/support/sdam/rs/primary_changes_set_name.yml +57 -0
  321. data/spec/support/sdam/rs/primary_disconnect.yml +56 -0
  322. data/spec/support/sdam/rs/primary_wrong_set_name.yml +27 -0
  323. data/spec/support/sdam/rs/response_from_removed.yml +63 -0
  324. data/spec/support/sdam/rs/rsother_discovered.yml +41 -0
  325. data/spec/support/sdam/rs/sec_not_auth.yml +49 -0
  326. data/spec/support/sdam/rs/secondary_wrong_set_name.yml +28 -0
  327. data/spec/support/sdam/rs/secondary_wrong_set_name_with_primary.yml +69 -0
  328. data/spec/support/sdam/rs/unexpected_mongos.yml +26 -0
  329. data/spec/support/sdam/rs/wrong_set_name.yml +35 -0
  330. data/spec/support/sdam/sharded/multiple_mongoses.yml +46 -0
  331. data/spec/support/sdam/sharded/non_mongos_removed.yml +41 -0
  332. data/spec/support/sdam/sharded/normalize_uri_case.yml +32 -0
  333. data/spec/support/sdam/single/direct_connection_external_ip.yml +34 -0
  334. data/spec/support/sdam/single/direct_connection_mongos.yml +33 -0
  335. data/spec/support/sdam/single/direct_connection_rsarbiter.yml +35 -0
  336. data/spec/support/sdam/single/direct_connection_rsprimary.yml +34 -0
  337. data/spec/support/sdam/single/direct_connection_rssecondary.yml +35 -0
  338. data/spec/support/sdam/single/direct_connection_slave.yml +32 -0
  339. data/spec/support/sdam/single/direct_connection_standalone.yml +32 -0
  340. data/spec/support/sdam/single/not_ok_response.yml +39 -0
  341. data/spec/support/sdam/single/standalone_removed.yml +32 -0
  342. data/spec/support/sdam/single/unavailable_seed.yml +28 -0
  343. data/spec/support/server_discovery_and_monitoring.rb +167 -0
  344. data/spec/support/server_selection/rtt/first_value.yml +4 -0
  345. data/spec/support/server_selection/rtt/first_value_zero.yml +4 -0
  346. data/spec/support/server_selection/rtt/value_test_1.yml +4 -0
  347. data/spec/support/server_selection/rtt/value_test_2.yml +4 -0
  348. data/spec/support/server_selection/rtt/value_test_3.yml +4 -0
  349. data/spec/support/server_selection/rtt/value_test_4.yml +4 -0
  350. data/spec/support/server_selection/rtt/value_test_5.yml +4 -0
  351. data/spec/support/server_selection/selection/ReplicaSetNoPrimary/read/Nearest.yml +26 -0
  352. data/spec/support/server_selection/selection/ReplicaSetNoPrimary/read/Nearest_non_matching.yml +21 -0
  353. data/spec/support/server_selection/selection/ReplicaSetNoPrimary/read/Primary.yml +21 -0
  354. data/spec/support/server_selection/selection/ReplicaSetNoPrimary/read/PrimaryPreferred.yml +26 -0
  355. data/spec/support/server_selection/selection/ReplicaSetNoPrimary/read/PrimaryPreferred_non_matching.yml +21 -0
  356. data/spec/support/server_selection/selection/ReplicaSetNoPrimary/read/Secondary.yml +26 -0
  357. data/spec/support/server_selection/selection/ReplicaSetNoPrimary/read/SecondaryPreferred.yml +26 -0
  358. data/spec/support/server_selection/selection/ReplicaSetNoPrimary/read/SecondaryPreferred_non_matching.yml +21 -0
  359. data/spec/support/server_selection/selection/ReplicaSetNoPrimary/read/Secondary_non_matching.yml +21 -0
  360. data/spec/support/server_selection/selection/ReplicaSetWithPrimary/read/Nearest.yml +33 -0
  361. data/spec/support/server_selection/selection/ReplicaSetWithPrimary/read/Nearest_non_matching.yml +26 -0
  362. data/spec/support/server_selection/selection/ReplicaSetWithPrimary/read/Primary.yml +29 -0
  363. data/spec/support/server_selection/selection/ReplicaSetWithPrimary/read/PrimaryPreferred.yml +29 -0
  364. data/spec/support/server_selection/selection/ReplicaSetWithPrimary/read/PrimaryPreferred_non_matching.yml +29 -0
  365. data/spec/support/server_selection/selection/ReplicaSetWithPrimary/read/Secondary.yml +31 -0
  366. data/spec/support/server_selection/selection/ReplicaSetWithPrimary/read/SecondaryPreferred.yml +31 -0
  367. data/spec/support/server_selection/selection/ReplicaSetWithPrimary/read/SecondaryPreferred_non_matching.yml +29 -0
  368. data/spec/support/server_selection/selection/ReplicaSetWithPrimary/read/Secondary_non_matching.yml +26 -0
  369. data/spec/support/server_selection/selection/Sharded/read/SecondaryPreferred.yml +26 -0
  370. data/spec/support/server_selection/selection/Single/read/SecondaryPreferred.yml +19 -0
  371. data/spec/support/server_selection/selection/Unknown/read/SecondaryPreferred.yml +11 -0
  372. data/spec/support/server_selection.rb +157 -0
  373. data/spec/support/server_selection_rtt.rb +41 -0
  374. data/spec/support/shared/bulk_write.rb +535 -0
  375. data/spec/support/shared/cursor.rb +38 -0
  376. data/spec/support/shared/operation.rb +77 -0
  377. data/spec/support/shared/protocol.rb +31 -0
  378. data/spec/support/shared/server_selector.rb +111 -0
  379. data/spec/support/shared/socket.rb +82 -0
  380. data/spec/support/travis.rb +14 -0
  381. data.tar.gz.sig +2 -3
  382. metadata +583 -186
  383. metadata.gz.sig +0 -0
  384. data/VERSION +0 -1
  385. data/lib/mongo/bulk_write_collection_view.rb +0 -387
  386. data/lib/mongo/collection_writer.rb +0 -364
  387. data/lib/mongo/connection/node.rb +0 -249
  388. data/lib/mongo/connection/pool.rb +0 -340
  389. data/lib/mongo/connection/pool_manager.rb +0 -320
  390. data/lib/mongo/connection/sharding_pool_manager.rb +0 -67
  391. data/lib/mongo/connection/socket/ssl_socket.rb +0 -95
  392. data/lib/mongo/connection/socket/tcp_socket.rb +0 -87
  393. data/lib/mongo/connection/socket/unix_socket.rb +0 -39
  394. data/lib/mongo/db.rb +0 -808
  395. data/lib/mongo/exception.rb +0 -145
  396. data/lib/mongo/functional/authentication.rb +0 -455
  397. data/lib/mongo/functional/logging.rb +0 -85
  398. data/lib/mongo/functional/read_preference.rb +0 -183
  399. data/lib/mongo/functional/scram.rb +0 -556
  400. data/lib/mongo/functional/uri_parser.rb +0 -409
  401. data/lib/mongo/functional/write_concern.rb +0 -66
  402. data/lib/mongo/gridfs/grid.rb +0 -112
  403. data/lib/mongo/gridfs/grid_ext.rb +0 -53
  404. data/lib/mongo/gridfs/grid_file_system.rb +0 -163
  405. data/lib/mongo/gridfs/grid_io.rb +0 -484
  406. data/lib/mongo/legacy.rb +0 -140
  407. data/lib/mongo/mongo_client.rb +0 -697
  408. data/lib/mongo/mongo_replica_set_client.rb +0 -535
  409. data/lib/mongo/mongo_sharded_client.rb +0 -159
  410. data/lib/mongo/networking.rb +0 -372
  411. data/lib/mongo/utils/conversions.rb +0 -110
  412. data/lib/mongo/utils/core_ext.rb +0 -70
  413. data/lib/mongo/utils/server_version.rb +0 -69
  414. data/lib/mongo/utils/support.rb +0 -80
  415. data/test/functional/authentication_test.rb +0 -39
  416. data/test/functional/bulk_api_stress_test.rb +0 -133
  417. data/test/functional/bulk_write_collection_view_test.rb +0 -1198
  418. data/test/functional/client_test.rb +0 -627
  419. data/test/functional/collection_test.rb +0 -2175
  420. data/test/functional/collection_writer_test.rb +0 -83
  421. data/test/functional/conversions_test.rb +0 -163
  422. data/test/functional/cursor_fail_test.rb +0 -57
  423. data/test/functional/cursor_message_test.rb +0 -56
  424. data/test/functional/cursor_test.rb +0 -683
  425. data/test/functional/db_api_test.rb +0 -835
  426. data/test/functional/db_test.rb +0 -348
  427. data/test/functional/grid_file_system_test.rb +0 -285
  428. data/test/functional/grid_io_test.rb +0 -252
  429. data/test/functional/grid_test.rb +0 -273
  430. data/test/functional/pool_test.rb +0 -136
  431. data/test/functional/safe_test.rb +0 -98
  432. data/test/functional/support_test.rb +0 -62
  433. data/test/functional/timeout_test.rb +0 -60
  434. data/test/functional/uri_test.rb +0 -446
  435. data/test/functional/write_concern_test.rb +0 -118
  436. data/test/helpers/general.rb +0 -50
  437. data/test/helpers/test_unit.rb +0 -476
  438. data/test/replica_set/authentication_test.rb +0 -37
  439. data/test/replica_set/basic_test.rb +0 -189
  440. data/test/replica_set/client_test.rb +0 -393
  441. data/test/replica_set/connection_test.rb +0 -138
  442. data/test/replica_set/count_test.rb +0 -66
  443. data/test/replica_set/cursor_test.rb +0 -220
  444. data/test/replica_set/insert_test.rb +0 -157
  445. data/test/replica_set/max_values_test.rb +0 -151
  446. data/test/replica_set/pinning_test.rb +0 -105
  447. data/test/replica_set/query_test.rb +0 -73
  448. data/test/replica_set/read_preference_test.rb +0 -219
  449. data/test/replica_set/refresh_test.rb +0 -211
  450. data/test/replica_set/replication_ack_test.rb +0 -95
  451. data/test/sharded_cluster/basic_test.rb +0 -203
  452. data/test/shared/authentication/basic_auth_shared.rb +0 -260
  453. data/test/shared/authentication/bulk_api_auth_shared.rb +0 -249
  454. data/test/shared/authentication/gssapi_shared.rb +0 -176
  455. data/test/shared/authentication/sasl_plain_shared.rb +0 -96
  456. data/test/shared/authentication/scram_shared.rb +0 -92
  457. data/test/shared/ssl_shared.rb +0 -235
  458. data/test/test_helper.rb +0 -61
  459. data/test/threading/basic_test.rb +0 -120
  460. data/test/tools/mongo_config.rb +0 -708
  461. data/test/tools/mongo_config_test.rb +0 -160
  462. data/test/unit/client_test.rb +0 -381
  463. data/test/unit/collection_test.rb +0 -166
  464. data/test/unit/connection_test.rb +0 -335
  465. data/test/unit/cursor_test.rb +0 -307
  466. data/test/unit/db_test.rb +0 -136
  467. data/test/unit/grid_test.rb +0 -76
  468. data/test/unit/mongo_sharded_client_test.rb +0 -48
  469. data/test/unit/node_test.rb +0 -93
  470. data/test/unit/pool_manager_test.rb +0 -111
  471. data/test/unit/read_pref_test.rb +0 -406
  472. data/test/unit/read_test.rb +0 -159
  473. data/test/unit/safe_test.rb +0 -158
  474. data/test/unit/sharding_pool_manager_test.rb +0 -84
  475. data/test/unit/write_concern_test.rb +0 -175
data/lib/mongo/cursor.rb CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2009-2013 MongoDB, Inc.
1
+ # Copyright (C) 2014-2015 MongoDB, Inc.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -14,729 +14,126 @@
14
14
 
15
15
  module Mongo
16
16
 
17
- # A cursor over query results. Returned objects are hashes.
17
+ # Client-side representation of an iterator over a query result set on
18
+ # the server.
19
+ #
20
+ # A +Cursor+ is not created directly by a user. Rather, +CollectionView+
21
+ # creates a +Cursor+ in an Enumerable module method.
22
+ #
23
+ # @example Get an array of 5 users named Emily.
24
+ # users.find({:name => 'Emily'}).limit(5).to_a
25
+ #
26
+ # @example Call a block on each user doc.
27
+ # users.find.each { |doc| puts doc }
28
+ #
29
+ # @note The +Cursor+ API is semipublic.
30
+ # @api semipublic
18
31
  class Cursor
32
+ extend Forwardable
19
33
  include Enumerable
20
- include Mongo::Constants
21
- include Mongo::Conversions
22
- include Mongo::Logging
23
- include Mongo::ReadPreference
24
34
 
25
- attr_reader :collection, :selector, :fields,
26
- :order, :hint, :snapshot, :timeout, :transformer,
27
- :options, :cursor_id, :show_disk_loc,
28
- :comment, :compile_regex, :read, :tag_sets,
29
- :acceptable_latency
35
+ def_delegators :@view, :collection, :limit
36
+ def_delegators :collection, :client, :database
30
37
 
31
- # Create a new cursor.
38
+ # Creates a +Cursor+ object.
32
39
  #
33
- # Note: cursors are created when executing queries using [Collection#find] and other
34
- # similar methods. Application developers shouldn't have to create cursors manually.
40
+ # @example Instantiate the cursor.
41
+ # Mongo::Cursor.new(view, response, server)
35
42
  #
36
- # @return [Cursor]
37
- def initialize(collection, opts={})
38
- opts = opts.dup
39
- @cursor_id = opts.delete(:cursor_id)
40
- @db = collection.db
41
- @collection = collection
42
- @ns = opts.delete(:ns)
43
- @connection = @db.connection
44
- @logger = @connection.logger
45
-
46
- # Query selector
47
- @selector = opts.delete(:selector) || {}
48
-
49
- # Query pre-serialized bson to append
50
- @bson = @selector.delete(:bson)
51
-
52
- # Special operators that form part of $query
53
- @order = opts.delete(:order)
54
- @explain = opts.delete(:explain)
55
- @hint = opts.delete(:hint)
56
- @snapshot = opts.delete(:snapshot)
57
- @max_scan = opts.delete(:max_scan)
58
- @return_key = opts.delete(:return_key)
59
- @show_disk_loc = opts.delete(:show_disk_loc)
60
- @comment = opts.delete(:comment)
61
- @compile_regex = opts.key?(:compile_regex) ? opts.delete(:compile_regex) : true
62
-
63
- # Wire-protocol settings
64
- @fields = convert_fields_for_query(opts.delete(:fields))
65
- @skip = opts.delete(:skip) || 0
66
- @limit = opts.delete(:limit) || 0
67
- @tailable = opts.delete(:tailable)
68
- @timeout = opts.key?(:timeout) ? opts.delete(:timeout) : true
69
- @options = 0
70
-
71
- # Use this socket for the query
72
- @socket = opts.delete(:socket)
73
- @pool = opts.delete(:pool)
74
-
75
- @closed = false
76
- @query_run = false
77
-
78
- @transformer = opts.delete(:transformer)
79
- @read = opts.delete(:read) || @collection.read
80
- Mongo::ReadPreference::validate(@read)
81
- @tag_sets = opts.delete(:tag_sets) || @collection.tag_sets
82
- @acceptable_latency = opts.delete(:acceptable_latency) || @collection.acceptable_latency
83
-
84
- batch_size(opts.delete(:batch_size) || 0)
85
-
86
- @cache = opts.delete(:first_batch) || []
87
- @returned = 0
88
-
89
- if(!@timeout)
90
- add_option(OP_QUERY_NO_CURSOR_TIMEOUT)
91
- end
92
- if(@read != :primary)
93
- add_option(OP_QUERY_SLAVE_OK)
94
- end
95
- if(@tailable)
96
- add_option(OP_QUERY_TAILABLE)
97
- end
98
-
99
- # If a cursor_id is provided, this is a cursor for a command
100
- if @cursor_id
101
- @command_cursor = true
102
- @query_run = true
103
- end
104
-
105
- if @collection.name =~ /^\$cmd/ || @collection.name =~ /^system/
106
- @command = true
107
- else
108
- @command = false
109
- end
110
-
111
- @opts = opts
112
- end
113
-
114
- # Guess whether the cursor is alive on the server.
43
+ # @param [ CollectionView ] view The +CollectionView+ defining the query.
44
+ # @param [ Operation::Result ] result The result of the first execution.
45
+ # @param [ Server ] server The server this cursor is locked to.
115
46
  #
116
- # Note that this method only checks whether we have
117
- # a cursor id. The cursor may still have timed out
118
- # on the server. This will be indicated in the next
119
- # call to Cursor#next.
120
- #
121
- # @return [Boolean]
122
- def alive?
123
- @cursor_id && @cursor_id != 0
47
+ # @since 2.0.0
48
+ def initialize(view, result, server)
49
+ @view = view
50
+ @server = server
51
+ @initial_result = result
52
+ @remaining = limit if limited?
124
53
  end
125
54
 
126
- def full_collection_name
127
- @ns || "#{@collection.db.name}.#{@collection.name}"
128
- end
129
-
130
- # Get the next document specified the cursor options.
55
+ # Get a human-readable string representation of +Cursor+.
131
56
  #
132
- # @return [Hash, Nil] the next document or Nil if no documents remain.
133
- def next
134
- if @cache.length == 0
135
- if @query_run && exhaust?
136
- close
137
- return nil
138
- else
139
- refresh
140
- end
141
- end
142
- doc = @cache.shift
143
-
144
- if doc && (err = doc['errmsg'] || doc['$err']) # assignment
145
- code = doc['code'] || doc['assertionCode']
146
-
147
- # If the server has stopped being the master (e.g., it's one of a
148
- # pair but it has died or something like that) then we close that
149
- # connection. The next request will re-open on master server.
150
- if err.include?("not master")
151
- @connection.close
152
- raise ConnectionFailure.new(err, code, doc)
153
- end
154
-
155
- # Handle server side operation execution timeout
156
- if code == 50
157
- raise ExecutionTimeout.new(err, code, doc)
158
- end
159
-
160
- raise OperationFailure.new(err, code, doc)
161
- elsif doc && (write_concern_error = doc['writeConcernError']) # assignment
162
- raise WriteConcernError.new(write_concern_error['errmsg'], write_concern_error['code'], doc)
163
- end
164
-
165
- if @transformer.nil?
166
- doc
167
- else
168
- @transformer.call(doc) if doc
169
- end
170
- end
171
- alias :next_document :next
172
-
173
- # Reset this cursor on the server. Cursor options, such as the
174
- # query string and the values for skip and limit, are preserved.
175
- def rewind!
176
- check_command_cursor
177
- close
178
- @cache.clear
179
- @cursor_id = nil
180
- @closed = false
181
- @query_run = false
182
- @n_received = nil
183
- true
184
- end
185
-
186
- # Determine whether this cursor has any remaining results.
187
- #
188
- # @return [Boolean]
189
- def has_next?
190
- num_remaining > 0
191
- end
192
-
193
- # Get the size of the result set for this query.
57
+ # @example Inspect the cursor.
58
+ # cursor.inspect
194
59
  #
195
- # @param [Boolean] skip_and_limit whether or not to take skip or limit into account.
60
+ # @return [ String ] A string representation of a +Cursor+ instance.
196
61
  #
197
- # @return [Integer] the number of objects in the result set for this query.
198
- #
199
- # @raise [OperationFailure] on a database error.
200
- def count(skip_and_limit = false)
201
- check_command_cursor
202
- command = BSON::OrderedHash["count", @collection.name, "query", @selector]
203
-
204
- if skip_and_limit
205
- command.merge!(BSON::OrderedHash["limit", @limit]) if @limit != 0
206
- command.merge!(BSON::OrderedHash["skip", @skip]) if @skip != 0
207
- end
208
-
209
- if @hint
210
- hint = @hint.is_a?(String) ? @hint : generate_index_name(@hint)
211
- end
212
-
213
- command.merge!(BSON::OrderedHash["fields", @fields])
214
- command.merge!(BSON::OrderedHash["hint", hint]) if hint
215
-
216
- response = @db.command(command, :read => @read, :comment => @comment)
217
- return response['n'].to_i if Mongo::Support.ok?(response)
218
- return 0 if response['errmsg'] == "ns missing"
219
- raise OperationFailure.new("Count failed: #{response['errmsg']}", response['code'], response)
220
- end
221
-
222
- # Sort this cursor's results.
223
- #
224
- # This method overrides any sort order specified in the Collection#find
225
- # method, and only the last sort applied has an effect.
226
- #
227
- # @param [Symbol, Array, Hash, OrderedHash] order either 1) a key to sort by 2)
228
- # an array of [key, direction] pairs to sort by or 3) a hash of
229
- # field => direction pairs to sort by. Direction should be specified as
230
- # Mongo::ASCENDING (or :ascending / :asc) or Mongo::DESCENDING
231
- # (or :descending / :desc)
232
- #
233
- # @raise [InvalidOperation] if this cursor has already been used.
234
- #
235
- # @raise [InvalidSortValueError] if the specified order is invalid.
236
- def sort(order, direction=nil)
237
- check_modifiable
238
- order = [[order, direction]] unless direction.nil?
239
- @order = order
240
- self
241
- end
242
-
243
- # Limit the number of results to be returned by this cursor.
244
- #
245
- # This method overrides any limit specified in the Collection#find method,
246
- # and only the last limit applied has an effect.
247
- #
248
- # @return [Integer] the current number_to_return if no parameter is given.
249
- #
250
- # @raise [InvalidOperation] if this cursor has already been used.
251
- def limit(number_to_return=nil)
252
- return @limit unless number_to_return
253
- check_modifiable
254
-
255
- if (number_to_return != 0) && exhaust?
256
- raise MongoArgumentError, "Limit is incompatible with exhaust option."
257
- end
258
-
259
- @limit = number_to_return
260
- self
261
- end
262
-
263
- # Skips the first +number_to_skip+ results of this cursor.
264
- # Returns the current number_to_skip if no parameter is given.
265
- #
266
- # This method overrides any skip specified in the Collection#find method,
267
- # and only the last skip applied has an effect.
268
- #
269
- # @return [Integer]
270
- #
271
- # @raise [InvalidOperation] if this cursor has already been used.
272
- def skip(number_to_skip=nil)
273
- return @skip unless number_to_skip
274
- check_modifiable
275
-
276
- @skip = number_to_skip
277
- self
278
- end
279
-
280
- # Instruct the server to abort queries after they exceed the specified
281
- # wall-clock execution time.
282
- #
283
- # A query that completes in under its time limit will "roll over"
284
- # remaining time to the first getmore op (which will then "roll over"
285
- # its remaining time to the second getmore op and so on, until the
286
- # time limit is hit).
287
- #
288
- # Cursors returned by successful time-limited queries will still obey
289
- # the default cursor idle timeout (unless the "no cursor idle timeout"
290
- # flag has been set).
291
- #
292
- # @note This will only have an effect in MongoDB 2.5+
293
- #
294
- # @param max_time_ms [Fixnum] max execution time (in milliseconds)
295
- #
296
- # @return [Fixnum, Cursor] either the current max_time_ms or cursor
297
- def max_time_ms(max_time_ms=nil)
298
- return @max_time_ms unless max_time_ms
299
- check_modifiable
300
-
301
- @max_time_ms = max_time_ms
302
- self
303
- end
304
-
305
- # Set the batch size for server responses.
306
- #
307
- # Note that the batch size will take effect only on queries
308
- # where the number to be returned is greater than 100.
309
- #
310
- # This can not override MongoDB's limit on the amount of data it will
311
- # return to the client. Depending on server version this can be 4-16mb.
312
- #
313
- # @param [Integer] size either 0 or some integer greater than 1. If 0,
314
- # the server will determine the batch size.
315
- #
316
- # @return [Cursor]
317
- def batch_size(size=nil)
318
- return @batch_size unless size
319
- check_modifiable
320
- if size < 0 || size == 1
321
- raise ArgumentError, "Invalid value for batch_size #{size}; must be 0 or > 1."
322
- else
323
- @batch_size = @limit != 0 && size > @limit ? @limit : size
324
- end
325
-
326
- self
62
+ # @since 2.0.0
63
+ def inspect
64
+ "#<Mongo::Cursor:0x#{object_id} @view=#{@view.inspect}>"
327
65
  end
328
66
 
329
- # Iterate over each document in this cursor, yielding it to the given
330
- # block, if provided. An Enumerator is returned if no block is given.
331
- #
332
- # Iterating over an entire cursor will close it.
67
+ # Iterate through documents returned from the query.
333
68
  #
334
- # @yield passes each document to a block for processing.
335
- #
336
- # @example if 'comments' represents a collection of comments:
337
- # comments.find.each do |doc|
338
- # puts doc['user']
69
+ # @example Iterate over the documents in the cursor.
70
+ # cursor.each do |doc|
71
+ # ...
339
72
  # end
340
- def each
341
- if block_given? || !defined?(Enumerator)
342
- while doc = self.next
343
- yield doc
344
- end
345
- else
346
- Enumerator.new do |yielder|
347
- while doc = self.next
348
- yielder.yield doc
349
- end
350
- end
351
- end
352
- end
353
- # Receive all the documents from this cursor as an array of hashes.
354
- #
355
- # Notes:
356
- #
357
- # If you've already started iterating over the cursor, the array returned
358
- # by this method contains only the remaining documents. See Cursor#rewind! if you
359
- # need to reset the cursor.
360
- #
361
- # Use of this method is discouraged - in most cases, it's much more
362
- # efficient to retrieve documents as you need them by iterating over the cursor.
363
- #
364
- # @return [Array] an array of documents.
365
- def to_a
366
- super
367
- end
368
-
369
- # Get the explain plan for this cursor.
370
- #
371
- # @return [Hash] a document containing the explain plan for this cursor.
372
- def explain
373
- check_command_cursor
374
- c = Cursor.new(@collection,
375
- query_options_hash.merge(:limit => -@limit.abs, :explain => true))
376
- explanation = c.next_document
377
- c.close
378
-
379
- explanation
380
- end
381
-
382
- # Close the cursor.
383
- #
384
- # Note: if a cursor is read until exhausted (read until Mongo::Constants::OP_QUERY or
385
- # Mongo::Constants::OP_GETMORE returns zero for the cursor id), there is no need to
386
- # close it manually.
387
- #
388
- # Note also: Collection#find takes an optional block argument which can be used to
389
- # ensure that your cursors get closed.
390
73
  #
391
- # @return [True]
392
- def close
393
- if @cursor_id && @cursor_id != 0
394
- message = BSON::ByteBuffer.new([0, 0, 0, 0])
395
- message.put_int(1)
396
- message.put_long(@cursor_id)
397
- log(:debug, "Cursor#close #{@cursor_id}")
398
- @connection.send_message(
399
- Mongo::Constants::OP_KILL_CURSORS,
400
- message,
401
- :pool => @pool
402
- )
403
- end
404
- @cursor_id = 0
405
- @closed = true
406
- end
407
-
408
- # Is this cursor closed?
74
+ # @return [ Enumerator ] The enumerator.
409
75
  #
410
- # @return [Boolean]
411
- def closed?
412
- @closed
413
- end
414
-
415
- # Returns an integer indicating which query options have been selected.
416
- #
417
- # @return [Integer]
418
- #
419
- # @see http://www.mongodb.org/display/DOCS/Mongo+Wire+Protocol#MongoWireProtocol-Mongo::Constants::OPQUERY
420
- # The MongoDB wire protocol.
421
- def query_opts
422
- warn "The method Cursor#query_opts has been deprecated " +
423
- "and will removed in v2.0. Use Cursor#options instead."
424
- @options
425
- end
426
-
427
- # Add an option to the query options bitfield.
428
- #
429
- # @param opt a valid query option
430
- #
431
- # @raise InvalidOperation if this method is run after the cursor has bee
432
- # iterated for the first time.
433
- #
434
- # @return [Integer] the current value of the options bitfield for this cursor.
435
- #
436
- # @see http://www.mongodb.org/display/DOCS/Mongo+Wire+Protocol#MongoWireProtocol-Mongo::Constants::OPQUERY
437
- def add_option(opt)
438
- check_modifiable
439
-
440
- if exhaust?(opt)
441
- if @limit != 0
442
- raise MongoArgumentError, "Exhaust is incompatible with limit."
443
- elsif @connection.mongos?
444
- raise MongoArgumentError, "Exhaust is incompatible with mongos."
445
- end
76
+ # @since 2.0.0
77
+ def each
78
+ process(@initial_result).each { |doc| yield doc }
79
+ while more?
80
+ return kill_cursors if exhausted?
81
+ get_more.each { |doc| yield doc }
446
82
  end
447
-
448
- @options |= opt
449
- @options
450
- end
451
-
452
- # Remove an option from the query options bitfield.
453
- #
454
- # @param opt a valid query option
455
- #
456
- # @raise InvalidOperation if this method is run after the cursor has bee
457
- # iterated for the first time.
458
- #
459
- # @return [Integer] the current value of the options bitfield for this cursor.
460
- #
461
- # @see http://www.mongodb.org/display/DOCS/Mongo+Wire+Protocol#MongoWireProtocol-Mongo::Constants::OPQUERY
462
- def remove_option(opt)
463
- check_modifiable
464
-
465
- @options &= ~opt
466
- @options
467
- end
468
-
469
- # Get the query options for this Cursor.
470
- #
471
- # @return [Hash]
472
- def query_options_hash
473
- BSON::OrderedHash[
474
- :selector => @selector,
475
- :fields => @fields,
476
- :skip => @skip,
477
- :limit => @limit,
478
- :order => @order,
479
- :hint => @hint,
480
- :snapshot => @snapshot,
481
- :timeout => @timeout,
482
- :max_scan => @max_scan,
483
- :return_key => @return_key,
484
- :show_disk_loc => @show_disk_loc,
485
- :comment => @comment ]
486
- end
487
-
488
- # Clean output for inspect.
489
- def inspect
490
- "<Mongo::Cursor:0x#{object_id.to_s(16)} namespace='#{full_collection_name}' " +
491
- "@selector=#{@selector.inspect} @cursor_id=#{@cursor_id}>"
492
83
  end
493
84
 
494
85
  private
495
86
 
496
- # Convert the +:fields+ parameter from a single field name or an array
497
- # of fields names to a hash, with the field names for keys and '1' for each
498
- # value.
499
- def convert_fields_for_query(fields)
500
- case fields
501
- when String, Symbol
502
- {fields => 1}
503
- when Array
504
- return nil if fields.length.zero?
505
- fields.inject({}) do |hash, field|
506
- field.is_a?(Hash) ? hash.merge!(field) : hash[field] = 1
507
- hash
508
- end
509
- when Hash
510
- return fields
511
- end
512
- end
513
-
514
- # Return the number of documents remaining for this cursor.
515
- def num_remaining
516
- if @cache.length == 0
517
- if @query_run && exhaust?
518
- close
519
- return 0
520
- else
521
- refresh
522
- end
523
- end
524
-
525
- @cache.length
526
- end
527
-
528
- # Refresh the documents in @cache. This means either
529
- # sending the initial query or sending a GET_MORE operation.
530
- def refresh
531
- if !@query_run
532
- send_initial_query
533
- elsif !@cursor_id.zero?
534
- send_get_more
535
- end
536
- end
537
-
538
- # Sends initial query -- which is always a read unless it is a command
539
- #
540
- # Upon ConnectionFailure, tries query 3 times if socket was not provided
541
- # and the query is either not a command or is a secondary_ok command.
542
- #
543
- # Pins pools upon successful read and unpins pool upon ConnectionFailure
544
- #
545
- def send_initial_query
546
- tries = 0
547
- instrument(:find, instrument_payload) do
548
- begin
549
- message = construct_query_message
550
- socket = @socket || checkout_socket_from_connection
551
- results, @n_received, @cursor_id = @connection.receive_message(
552
- Mongo::Constants::OP_QUERY, message, nil, socket, @command,
553
- nil, exhaust?, compile_regex?)
554
- rescue ConnectionFailure => ex
555
- socket.close if socket
556
- @pool = nil
557
- @connection.unpin_pool
558
- @connection.refresh
559
- if tries < 3 && !@socket && (!@command || Mongo::ReadPreference::secondary_ok?(@selector))
560
- tries += 1
561
- retry
562
- else
563
- raise ex
564
- end
565
- rescue OperationFailure, OperationTimeout => ex
566
- raise ex
567
- ensure
568
- socket.checkin unless @socket || socket.nil?
569
- end
570
-
571
- if pin_pool?(results.first)
572
- @connection.pin_pool(socket.pool, read_preference)
573
- end
574
-
575
- @returned += @n_received
576
- @cache += results
577
- @query_run = true
578
- close_cursor_if_query_complete
579
- end
580
- end
581
-
582
- def send_get_more
583
- message = BSON::ByteBuffer.new([0, 0, 0, 0])
584
-
585
- # DB name.
586
- BSON::BSON_RUBY.serialize_cstr(message, full_collection_name)
587
-
588
- # Number of results to return.
589
- if @limit > 0
590
- limit = @limit - @returned
591
- if @batch_size > 0
592
- limit = limit < @batch_size ? limit : @batch_size
593
- end
594
- message.put_int(limit)
595
- else
596
- message.put_int(@batch_size)
597
- end
598
-
599
- # Cursor id.
600
- message.put_long(@cursor_id)
601
- log(:debug, "cursor.refresh() for cursor #{@cursor_id}") if @logger
602
-
603
- socket = @pool.checkout
604
-
605
- begin
606
- results, @n_received, @cursor_id = @connection.receive_message(
607
- Mongo::Constants::OP_GET_MORE, message, nil, socket, @command,
608
- nil, exhaust?, compile_regex?)
609
- ensure
610
- socket.checkin
611
- end
612
-
613
- @returned += @n_received
614
- @cache += results
615
- close_cursor_if_query_complete
87
+ def batch_size
88
+ @view.batch_size && @view.batch_size > 0 ? @view.batch_size : limit
616
89
  end
617
90
 
618
- def checkout_socket_from_connection
619
- begin
620
- if @pool
621
- socket = @pool.checkout
622
- elsif @command && !Mongo::ReadPreference::secondary_ok?(@selector)
623
- socket = @connection.checkout_reader({:mode => :primary})
624
- else
625
- socket = @connection.checkout_reader(read_preference)
626
- end
627
- rescue SystemStackError, NoMemoryError, SystemCallError => ex
628
- @connection.close
629
- raise ex
630
- end
631
- @pool = socket.pool
632
- socket
91
+ def exhausted?
92
+ limited? ? @remaining <= 0 : false
633
93
  end
634
94
 
635
- def checkin_socket(sock)
636
- @connection.checkin(sock)
95
+ def get_more
96
+ process(get_more_operation.execute(@server.context))
637
97
  end
638
98
 
639
- def construct_query_message
640
- message = BSON::ByteBuffer.new("", @connection.max_bson_size + MongoClient::COMMAND_HEADROOM)
641
- message.put_int(@options)
642
- BSON::BSON_RUBY.serialize_cstr(message, full_collection_name)
643
- message.put_int(@skip)
644
- @batch_size > 1 ? message.put_int(@batch_size) : message.put_int(@limit)
645
- if query_contains_special_fields? && @bson # costs two serialize calls
646
- query_message = BSON::BSON_CODER.serialize(@selector, false, false, @connection.max_bson_size + MongoClient::APPEND_HEADROOM)
647
- query_message.grow(@bson)
648
- query_spec = construct_query_spec
649
- query_spec.delete('$query')
650
- query_message.grow(BSON::BSON_CODER.serialize(query_spec, false, false, @connection.max_bson_size))
651
- else # costs only one serialize call
652
- spec = query_contains_special_fields? ? construct_query_spec : @selector
653
- spec.merge!(@opts)
654
- query_message = BSON::BSON_CODER.serialize(spec, false, false, @connection.max_bson_size + MongoClient::APPEND_HEADROOM)
655
- query_message.grow(@bson) if @bson
656
- end
657
- message.put_binary(query_message.to_s)
658
- message.put_binary(BSON::BSON_CODER.serialize(@fields, false, false, @connection.max_bson_size).to_s) if @fields
659
- message
99
+ def get_more_operation
100
+ Operation::Read::GetMore.new({
101
+ :to_return => to_return,
102
+ :cursor_id => @cursor_id,
103
+ :db_name => database.name,
104
+ :coll_name => @coll_name || collection.name
105
+ })
660
106
  end
661
107
 
662
- def instrument_payload
663
- log = { :database => @db.name, :collection => @collection.name, :selector => selector }
664
- log[:fields] = @fields if @fields
665
- log[:skip] = @skip if @skip && (@skip != 0)
666
- log[:limit] = @limit if @limit && (@limit != 0)
667
- log[:order] = @order if @order
668
- log
108
+ def kill_cursors
109
+ kill_cursors_operation.execute(@server.context)
669
110
  end
670
111
 
671
- def construct_query_spec
672
- return @selector if @selector.has_key?('$query')
673
- spec = BSON::OrderedHash.new
674
- spec['$query'] = @selector
675
- spec['$orderby'] = Mongo::Support.format_order_clause(@order) if @order
676
- spec['$hint'] = @hint if @hint && @hint.length > 0
677
- spec['$explain'] = true if @explain
678
- spec['$snapshot'] = true if @snapshot
679
- spec['$maxScan'] = @max_scan if @max_scan
680
- spec['$returnKey'] = true if @return_key
681
- spec['$showDiskLoc'] = true if @show_disk_loc
682
- spec['$comment'] = @comment if @comment
683
- spec['$maxTimeMS'] = @max_time_ms if @max_time_ms
684
- if needs_read_pref?
685
- read_pref = Mongo::ReadPreference::mongos(@read, @tag_sets)
686
- spec['$readPreference'] = read_pref if read_pref
687
- end
688
- spec
112
+ def kill_cursors_operation
113
+ Operation::KillCursors.new({ :cursor_ids => [ @cursor_id ]})
689
114
  end
690
115
 
691
- def needs_read_pref?
692
- @connection.mongos? && @read != :primary
116
+ def limited?
117
+ limit ? limit > 0 : false
693
118
  end
694
119
 
695
- def query_contains_special_fields?
696
- @order || @explain || @hint || @snapshot || @show_disk_loc ||
697
- @max_scan || @return_key || @comment || @max_time_ms || needs_read_pref?
120
+ def more?
121
+ @cursor_id != 0
698
122
  end
699
123
 
700
- def close_cursor_if_query_complete
701
- if @limit > 0 && @returned >= @limit
702
- close
703
- end
124
+ def process(result)
125
+ @remaining -= result.returned_count if limited?
126
+ @cursor_id = result.cursor_id
127
+ @coll_name ||= result.namespace.sub("#{database.name}.", '') if result.namespace
128
+ result.documents
704
129
  end
705
130
 
706
- # Check whether the exhaust option is set
707
- #
708
- # @return [true, false] The state of the exhaust flag.
709
- def exhaust?(opts = options)
710
- !(opts & OP_QUERY_EXHAUST).zero?
711
- end
712
-
713
- def check_modifiable
714
- if @query_run || @closed
715
- raise InvalidOperation, "Cannot modify the query once it has been run or closed."
716
- end
717
- end
718
-
719
- def check_command_cursor
720
- if @command_cursor
721
- raise InvalidOperation, "Cannot call #{caller.first} on command cursors"
722
- end
723
- end
724
-
725
- def compile_regex?
726
- @compile_regex
727
- end
728
-
729
- def generate_index_name(spec)
730
- indexes = []
731
- spec.each_pair do |field, type|
732
- indexes.push("#{field}_#{type}")
733
- end
734
- indexes.join("_")
131
+ def to_return
132
+ use_limit? ? @remaining : (batch_size || 0)
735
133
  end
736
134
 
737
- def pin_pool?(response)
738
- ( response && (response['cursor'] || response['cursors']) ) ||
739
- ( !@socket && !@command )
135
+ def use_limit?
136
+ limited? && batch_size >= @remaining
740
137
  end
741
138
  end
742
139
  end