mongo 1.12.5 → 2.0.0.beta

Sign up to get free protection for your applications and to get access to all the features.
Files changed (437) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/CONTRIBUTING.md +64 -0
  5. data/LICENSE +1 -1
  6. data/README.md +23 -125
  7. data/Rakefile +26 -21
  8. data/bin/mongo_console +6 -38
  9. data/lib/mongo.rb +23 -82
  10. data/lib/mongo/address.rb +111 -0
  11. data/lib/mongo/address/ipv4.rb +85 -0
  12. data/lib/mongo/address/ipv6.rb +85 -0
  13. data/lib/mongo/address/unix.rb +76 -0
  14. data/lib/mongo/auth.rb +108 -0
  15. data/lib/mongo/auth/cr.rb +44 -0
  16. data/lib/mongo/auth/cr/conversation.rb +119 -0
  17. data/lib/mongo/auth/executable.rb +52 -0
  18. data/lib/mongo/auth/ldap.rb +48 -0
  19. data/lib/mongo/auth/ldap/conversation.rb +92 -0
  20. data/lib/mongo/auth/roles.rb +104 -0
  21. data/lib/mongo/auth/scram.rb +53 -0
  22. data/lib/mongo/auth/scram/conversation.rb +450 -0
  23. data/lib/mongo/auth/user.rb +159 -0
  24. data/lib/mongo/auth/user/view.rb +102 -0
  25. data/lib/mongo/auth/x509.rb +48 -0
  26. data/lib/mongo/auth/x509/conversation.rb +92 -0
  27. data/lib/mongo/{gridfs.rb → bulk.rb} +2 -5
  28. data/lib/mongo/bulk/bulk_write.rb +307 -0
  29. data/lib/mongo/client.rb +233 -0
  30. data/lib/mongo/cluster.rb +203 -0
  31. data/lib/mongo/cluster/topology.rb +60 -0
  32. data/lib/mongo/cluster/topology/replica_set.rb +160 -0
  33. data/lib/mongo/cluster/topology/sharded.rb +132 -0
  34. data/lib/mongo/cluster/topology/standalone.rb +132 -0
  35. data/lib/mongo/cluster/topology/unknown.rb +155 -0
  36. data/lib/mongo/collection.rb +130 -1101
  37. data/lib/mongo/collection/view.rb +169 -0
  38. data/lib/mongo/collection/view/aggregation.rb +108 -0
  39. data/lib/mongo/collection/view/explainable.rb +49 -0
  40. data/lib/mongo/collection/view/immutable.rb +43 -0
  41. data/lib/mongo/collection/view/iterable.rb +48 -0
  42. data/lib/mongo/collection/view/map_reduce.rb +191 -0
  43. data/lib/mongo/collection/view/readable.rb +363 -0
  44. data/lib/mongo/collection/view/writable.rb +169 -0
  45. data/lib/mongo/cursor.rb +79 -680
  46. data/lib/mongo/database.rb +224 -0
  47. data/lib/mongo/database/view.rb +101 -0
  48. data/lib/mongo/error.rb +81 -0
  49. data/lib/mongo/error/bulk_write_failure.rb +41 -0
  50. data/lib/mongo/{utils/thread_local_variable_manager.rb → error/empty_batch.rb} +22 -8
  51. data/{test/functional/db_connection_test.rb → lib/mongo/error/invalid_bulk_operation.rb} +19 -8
  52. data/lib/mongo/error/invalid_collection_name.rb +39 -0
  53. data/lib/mongo/error/invalid_database_name.rb +39 -0
  54. data/{test/replica_set/ssl_test.rb → lib/mongo/error/invalid_document.rb} +21 -14
  55. data/lib/mongo/error/invalid_file.rb +38 -0
  56. data/lib/mongo/error/invalid_nonce.rb +46 -0
  57. data/lib/mongo/error/invalid_replacement_document.rb +39 -0
  58. data/lib/mongo/error/invalid_signature.rb +47 -0
  59. data/{test/functional/ssl_test.rb → lib/mongo/error/invalid_update_document.rb} +22 -12
  60. data/lib/mongo/error/max_bson_size.rb +40 -0
  61. data/lib/mongo/error/max_message_size.rb +42 -0
  62. data/lib/mongo/{utils.rb → error/need_primary_server.rb} +10 -6
  63. data/lib/mongo/{connection.rb → error/operation_failure.rb} +10 -6
  64. data/lib/mongo/error/parser.rb +77 -0
  65. data/lib/mongo/{connection/socket.rb → error/socket_error.rb} +10 -5
  66. data/lib/mongo/error/socket_timeout_error.rb +23 -0
  67. data/lib/mongo/error/unsupported_features.rb +43 -0
  68. data/lib/mongo/event.rb +40 -0
  69. data/lib/mongo/event/listeners.rb +63 -0
  70. data/lib/mongo/event/primary_elected.rb +53 -0
  71. data/lib/mongo/event/publisher.rb +42 -0
  72. data/lib/mongo/event/server_added.rb +53 -0
  73. data/lib/mongo/event/server_removed.rb +53 -0
  74. data/lib/mongo/event/subscriber.rb +41 -0
  75. data/lib/mongo/grid.rb +16 -0
  76. data/lib/mongo/grid/file.rb +94 -0
  77. data/lib/mongo/grid/file/chunk.rb +184 -0
  78. data/lib/mongo/grid/file/metadata.rb +223 -0
  79. data/lib/mongo/grid/fs.rb +149 -0
  80. data/lib/mongo/index.rb +64 -0
  81. data/lib/mongo/index/view.rb +205 -0
  82. data/lib/mongo/loggable.rb +126 -0
  83. data/lib/mongo/logger.rb +132 -0
  84. data/lib/mongo/operation.rb +26 -0
  85. data/lib/mongo/operation/aggregate.rb +100 -0
  86. data/lib/mongo/operation/aggregate/result.rb +84 -0
  87. data/lib/mongo/operation/batchable.rb +103 -0
  88. data/lib/mongo/operation/bulk_delete/result.rb +197 -0
  89. data/lib/mongo/operation/bulk_insert/result.rb +195 -0
  90. data/lib/mongo/operation/bulk_update/result.rb +295 -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 +116 -0
  96. data/lib/mongo/operation/list_indexes/result.rb +118 -0
  97. data/lib/mongo/operation/map_reduce.rb +96 -0
  98. data/lib/mongo/operation/map_reduce/result.rb +122 -0
  99. data/lib/mongo/{functional.rb → operation/read.rb} +7 -7
  100. data/lib/mongo/operation/read/collections_info.rb +67 -0
  101. data/lib/mongo/operation/read/get_more.rb +71 -0
  102. data/lib/mongo/operation/read/indexes.rb +68 -0
  103. data/lib/mongo/operation/read/list_collections.rb +75 -0
  104. data/lib/mongo/operation/read/list_indexes.rb +77 -0
  105. data/lib/mongo/operation/read/query.rb +71 -0
  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 +380 -0
  109. data/lib/mongo/operation/write.rb +25 -0
  110. data/lib/mongo/operation/write/bulk_delete.rb +158 -0
  111. data/lib/mongo/operation/write/bulk_insert.rb +160 -0
  112. data/lib/mongo/operation/write/bulk_update.rb +167 -0
  113. data/lib/mongo/{connection/socket/socket_util.rb → operation/write/command.rb} +9 -24
  114. data/lib/mongo/operation/write/command/create_user.rb +43 -0
  115. data/lib/mongo/operation/write/command/delete.rb +56 -0
  116. data/lib/mongo/operation/write/command/drop_index.rb +51 -0
  117. data/lib/mongo/operation/write/command/ensure_index.rb +55 -0
  118. data/lib/mongo/operation/write/command/insert.rb +55 -0
  119. data/lib/mongo/operation/write/command/remove_user.rb +42 -0
  120. data/lib/mongo/operation/write/command/update.rb +60 -0
  121. data/lib/mongo/operation/write/command/writable.rb +61 -0
  122. data/lib/mongo/operation/write/create_index.rb +84 -0
  123. data/lib/mongo/operation/write/create_user.rb +75 -0
  124. data/lib/mongo/operation/write/delete.rb +91 -0
  125. data/lib/mongo/operation/write/drop_index.rb +62 -0
  126. data/lib/mongo/operation/write/insert.rb +88 -0
  127. data/lib/mongo/operation/write/remove_user.rb +70 -0
  128. data/lib/mongo/operation/write/update.rb +98 -0
  129. data/lib/mongo/protocol.rb +15 -0
  130. data/lib/mongo/protocol/bit_vector.rb +61 -0
  131. data/lib/mongo/protocol/delete.rb +94 -0
  132. data/lib/mongo/protocol/get_more.rb +99 -0
  133. data/lib/mongo/protocol/insert.rb +99 -0
  134. data/lib/mongo/protocol/kill_cursors.rb +74 -0
  135. data/lib/mongo/protocol/message.rb +252 -0
  136. data/lib/mongo/protocol/query.rb +147 -0
  137. data/lib/mongo/protocol/reply.rb +72 -0
  138. data/lib/mongo/protocol/serializers.rb +180 -0
  139. data/lib/mongo/protocol/update.rb +111 -0
  140. data/lib/mongo/server.rb +163 -0
  141. data/lib/mongo/server/connectable.rb +99 -0
  142. data/lib/mongo/server/connection.rb +133 -0
  143. data/lib/mongo/server/connection_pool.rb +141 -0
  144. data/lib/mongo/server/connection_pool/queue.rb +182 -0
  145. data/lib/mongo/server/context.rb +66 -0
  146. data/lib/mongo/server/description.rb +450 -0
  147. data/lib/mongo/server/description/features.rb +85 -0
  148. data/lib/mongo/server/description/inspector.rb +79 -0
  149. data/lib/mongo/server/description/inspector/primary_elected.rb +58 -0
  150. data/lib/mongo/server/description/inspector/server_added.rb +59 -0
  151. data/lib/mongo/server/description/inspector/server_removed.rb +59 -0
  152. data/lib/mongo/server/monitor.rb +160 -0
  153. data/lib/mongo/server/monitor/connection.rb +88 -0
  154. data/lib/mongo/server_selector.rb +81 -0
  155. data/lib/mongo/server_selector/nearest.rb +94 -0
  156. data/lib/mongo/server_selector/primary.rb +88 -0
  157. data/lib/mongo/server_selector/primary_preferred.rb +94 -0
  158. data/lib/mongo/server_selector/secondary.rb +91 -0
  159. data/lib/mongo/server_selector/secondary_preferred.rb +96 -0
  160. data/lib/mongo/server_selector/selectable.rb +209 -0
  161. data/lib/mongo/socket.rb +179 -0
  162. data/lib/mongo/socket/ssl.rb +108 -0
  163. data/lib/mongo/socket/tcp.rb +69 -0
  164. data/lib/mongo/socket/unix.rb +66 -0
  165. data/lib/mongo/uri.rb +504 -0
  166. data/lib/mongo/version.rb +21 -0
  167. data/lib/mongo/write_concern.rb +99 -0
  168. data/lib/mongo/write_concern/acknowledged.rb +38 -0
  169. data/lib/mongo/write_concern/normalizable.rb +73 -0
  170. data/lib/mongo/write_concern/unacknowledged.rb +43 -0
  171. data/mongo.gemspec +17 -14
  172. data/spec/mongo/address/ipv4_spec.rb +74 -0
  173. data/spec/mongo/address/ipv6_spec.rb +74 -0
  174. data/spec/mongo/address/unix_spec.rb +30 -0
  175. data/spec/mongo/address_spec.rb +206 -0
  176. data/spec/mongo/auth/cr_spec.rb +59 -0
  177. data/spec/mongo/auth/ldap_spec.rb +40 -0
  178. data/spec/mongo/auth/scram/conversation_spec.rb +197 -0
  179. data/spec/mongo/auth/scram_spec.rb +55 -0
  180. data/spec/mongo/auth/user/view_spec.rb +76 -0
  181. data/spec/mongo/auth/user_spec.rb +190 -0
  182. data/spec/mongo/auth/x509_spec.rb +40 -0
  183. data/spec/mongo/auth_spec.rb +65 -0
  184. data/spec/mongo/bulk/bulk_write_spec.rb +175 -0
  185. data/spec/mongo/client_spec.rb +564 -0
  186. data/spec/mongo/cluster/topology/replica_set_spec.rb +101 -0
  187. data/spec/mongo/cluster/topology/sharded_spec.rb +74 -0
  188. data/spec/mongo/cluster/topology/standalone_spec.rb +79 -0
  189. data/spec/mongo/cluster/topology_spec.rb +65 -0
  190. data/spec/mongo/cluster_spec.rb +129 -0
  191. data/spec/mongo/collection/view/aggregation_spec.rb +135 -0
  192. data/spec/mongo/collection/view/explainable_spec.rb +32 -0
  193. data/spec/mongo/collection/view/map_reduce_spec.rb +242 -0
  194. data/spec/mongo/collection/view/readable_spec.rb +603 -0
  195. data/spec/mongo/collection/view/writable_spec.rb +504 -0
  196. data/spec/mongo/collection/view_spec.rb +521 -0
  197. data/spec/mongo/collection_spec.rb +362 -0
  198. data/spec/mongo/cursor_spec.rb +295 -0
  199. data/spec/mongo/database_spec.rb +306 -0
  200. data/spec/mongo/error/parser_spec.rb +119 -0
  201. data/spec/mongo/event/publisher_spec.rb +50 -0
  202. data/spec/mongo/event/subscriber_spec.rb +34 -0
  203. data/spec/mongo/grid/file/chunk_spec.rb +226 -0
  204. data/spec/mongo/grid/file/metadata_spec.rb +69 -0
  205. data/spec/mongo/grid/file_spec.rb +138 -0
  206. data/spec/mongo/grid/fs_spec.rb +129 -0
  207. data/spec/mongo/index/view_spec.rb +226 -0
  208. data/spec/mongo/loggable_spec.rb +62 -0
  209. data/spec/mongo/logger_spec.rb +97 -0
  210. data/spec/mongo/operation/aggregate/result_spec.rb +80 -0
  211. data/spec/mongo/operation/aggregate_spec.rb +135 -0
  212. data/spec/mongo/operation/command_spec.rb +106 -0
  213. data/spec/mongo/operation/kill_cursors_spec.rb +66 -0
  214. data/spec/mongo/operation/limited_spec.rb +50 -0
  215. data/spec/mongo/operation/map_reduce_spec.rb +143 -0
  216. data/spec/mongo/operation/read/collections_info_spec.rb +40 -0
  217. data/spec/mongo/operation/read/get_more_spec.rb +81 -0
  218. data/spec/mongo/operation/read/indexes_spec.rb +31 -0
  219. data/spec/mongo/operation/read/query_spec.rb +84 -0
  220. data/spec/mongo/operation/result_spec.rb +275 -0
  221. data/spec/mongo/operation/specifiable_spec.rb +53 -0
  222. data/spec/mongo/operation/write/bulk_delete_spec.rb +473 -0
  223. data/spec/mongo/operation/write/bulk_insert_spec.rb +466 -0
  224. data/spec/mongo/operation/write/bulk_update_spec.rb +524 -0
  225. data/spec/mongo/operation/write/command/delete_spec.rb +116 -0
  226. data/spec/mongo/operation/write/command/insert_spec.rb +117 -0
  227. data/spec/mongo/operation/write/command/update_spec.rb +123 -0
  228. data/spec/mongo/operation/write/create_user_spec.rb +44 -0
  229. data/spec/mongo/operation/write/delete_spec.rb +178 -0
  230. data/spec/mongo/operation/write/drop_index_spec.rb +51 -0
  231. data/spec/mongo/operation/write/ensure_index_spec.rb +81 -0
  232. data/spec/mongo/operation/write/insert_spec.rb +231 -0
  233. data/spec/mongo/operation/write/remove_user_spec.rb +46 -0
  234. data/spec/mongo/operation/write/response_spec.rb +85 -0
  235. data/spec/mongo/operation/write/update_spec.rb +177 -0
  236. data/spec/mongo/protocol/delete_spec.rb +167 -0
  237. data/spec/mongo/protocol/get_more_spec.rb +146 -0
  238. data/spec/mongo/protocol/insert_spec.rb +161 -0
  239. data/spec/mongo/protocol/kill_cursors_spec.rb +101 -0
  240. data/spec/mongo/protocol/query_spec.rb +285 -0
  241. data/spec/mongo/protocol/reply_spec.rb +157 -0
  242. data/spec/mongo/protocol/update_spec.rb +186 -0
  243. data/spec/mongo/server/connection_pool/queue_spec.rb +170 -0
  244. data/spec/mongo/server/connection_pool_spec.rb +120 -0
  245. data/spec/mongo/server/connection_spec.rb +289 -0
  246. data/spec/mongo/server/description/features_spec.rb +138 -0
  247. data/spec/mongo/server/description/inspector/primary_elected_spec.rb +94 -0
  248. data/spec/mongo/server/description/inspector/server_added_spec.rb +92 -0
  249. data/spec/mongo/server/description/inspector/server_removed_spec.rb +95 -0
  250. data/spec/mongo/server/description_spec.rb +510 -0
  251. data/spec/mongo/server/monitor_spec.rb +130 -0
  252. data/spec/mongo/server_discovery_and_monitoring_spec.rb +103 -0
  253. data/spec/mongo/server_selection_rtt_spec.rb +104 -0
  254. data/spec/mongo/server_selection_spec.rb +89 -0
  255. data/spec/mongo/server_selector/nearest_spec.rb +250 -0
  256. data/spec/mongo/server_selector/primary_preferred_spec.rb +290 -0
  257. data/spec/mongo/server_selector/primary_spec.rb +114 -0
  258. data/spec/mongo/server_selector/secondary_preferred_spec.rb +252 -0
  259. data/spec/mongo/server_selector/secondary_spec.rb +196 -0
  260. data/spec/mongo/server_selector_spec.rb +101 -0
  261. data/spec/mongo/server_spec.rb +131 -0
  262. data/spec/mongo/uri_spec.rb +517 -0
  263. data/spec/mongo/write_concern/acknowledged_spec.rb +44 -0
  264. data/spec/mongo/write_concern/unacknowledged_spec.rb +15 -0
  265. data/spec/mongo_orchestration_spec.rb +70 -0
  266. data/spec/spec_helper.rb +148 -0
  267. data/spec/support/authorization.rb +245 -0
  268. data/spec/support/helpers.rb +140 -0
  269. data/spec/support/matchers.rb +37 -0
  270. data/spec/support/mongo_orchestration.rb +61 -0
  271. data/spec/support/mongo_orchestration/requestable.rb +109 -0
  272. data/spec/support/mongo_orchestration/standalone.rb +57 -0
  273. data/spec/support/sdam/rs/discover_arbiters.yml +41 -0
  274. data/spec/support/sdam/rs/discover_passives.yml +41 -0
  275. data/spec/support/sdam/rs/discover_primary.yml +40 -0
  276. data/spec/support/sdam/rs/discover_secondary.yml +41 -0
  277. data/spec/support/sdam/rs/discovery.yml +195 -0
  278. data/spec/support/sdam/rs/ghost_discovered.yml +39 -0
  279. data/spec/support/sdam/rs/hosts_differ_from_seeds.yml +34 -0
  280. data/spec/support/sdam/rs/member_reconfig.yml +68 -0
  281. data/spec/support/sdam/rs/member_standalone.yml +60 -0
  282. data/spec/support/sdam/rs/new_primary.yml +74 -0
  283. data/spec/support/sdam/rs/new_primary_wrong_set_name.yml +71 -0
  284. data/spec/support/sdam/rs/non_rs_member.yml +31 -0
  285. data/spec/support/sdam/rs/normalize_case.yml +49 -0
  286. data/spec/support/sdam/rs/primary_becomes_standalone.yml +52 -0
  287. data/spec/support/sdam/rs/primary_changes_set_name.yml +57 -0
  288. data/spec/support/sdam/rs/primary_disconnect.yml +56 -0
  289. data/spec/support/sdam/rs/primary_wrong_set_name.yml +27 -0
  290. data/spec/support/sdam/rs/response_from_removed.yml +63 -0
  291. data/spec/support/sdam/rs/rsother_discovered.yml +41 -0
  292. data/spec/support/sdam/rs/sec_not_auth.yml +49 -0
  293. data/spec/support/sdam/rs/secondary_wrong_set_name.yml +28 -0
  294. data/spec/support/sdam/rs/secondary_wrong_set_name_with_primary.yml +69 -0
  295. data/spec/support/sdam/rs/unexpected_mongos.yml +26 -0
  296. data/spec/support/sdam/rs/wrong_set_name.yml +35 -0
  297. data/spec/support/sdam/sharded/multiple_mongoses.yml +46 -0
  298. data/spec/support/sdam/sharded/non_mongos_removed.yml +41 -0
  299. data/spec/support/sdam/sharded/normalize_uri_case.yml +32 -0
  300. data/spec/support/sdam/single/direct_connection_external_ip.yml +34 -0
  301. data/spec/support/sdam/single/direct_connection_mongos.yml +33 -0
  302. data/spec/support/sdam/single/direct_connection_rsarbiter.yml +35 -0
  303. data/spec/support/sdam/single/direct_connection_rsprimary.yml +34 -0
  304. data/spec/support/sdam/single/direct_connection_rssecondary.yml +35 -0
  305. data/spec/support/sdam/single/direct_connection_slave.yml +32 -0
  306. data/spec/support/sdam/single/direct_connection_standalone.yml +32 -0
  307. data/spec/support/sdam/single/not_ok_response.yml +39 -0
  308. data/spec/support/sdam/single/standalone_removed.yml +32 -0
  309. data/spec/support/sdam/single/unavailable_seed.yml +28 -0
  310. data/spec/support/server_discovery_and_monitoring.rb +167 -0
  311. data/spec/support/server_selection.rb +140 -0
  312. data/spec/support/server_selection/rtt/first_value.yml +4 -0
  313. data/spec/support/server_selection/rtt/first_value_zero.yml +4 -0
  314. data/spec/support/server_selection/rtt/value_test_1.yml +4 -0
  315. data/spec/support/server_selection/rtt/value_test_2.yml +4 -0
  316. data/spec/support/server_selection/rtt/value_test_3.yml +4 -0
  317. data/spec/support/server_selection/rtt/value_test_4.yml +4 -0
  318. data/spec/support/server_selection/rtt/value_test_5.yml +4 -0
  319. data/spec/support/server_selection/selection/ReplicaSetNoPrimary/read/Nearest.yml +32 -0
  320. data/spec/support/server_selection/selection/ReplicaSetNoPrimary/read/Nearest_non_matching.yml +27 -0
  321. data/spec/support/server_selection/selection/ReplicaSetNoPrimary/read/Primary.yml +23 -0
  322. data/spec/support/server_selection/selection/ReplicaSetNoPrimary/read/PrimaryPreferred.yml +32 -0
  323. data/spec/support/server_selection/selection/ReplicaSetNoPrimary/read/PrimaryPreferred_non_matching.yml +27 -0
  324. data/spec/support/server_selection/selection/ReplicaSetNoPrimary/read/Secondary.yml +32 -0
  325. data/spec/support/server_selection/selection/ReplicaSetNoPrimary/read/SecondaryPreferred.yml +32 -0
  326. data/spec/support/server_selection/selection/ReplicaSetNoPrimary/read/SecondaryPreferred_non_matching.yml +27 -0
  327. data/spec/support/server_selection/selection/ReplicaSetNoPrimary/read/Secondary_non_matching.yml +27 -0
  328. data/spec/support/server_selection/selection/ReplicaSetWithPrimary/read/Nearest.yml +41 -0
  329. data/spec/support/server_selection/selection/ReplicaSetWithPrimary/read/Nearest_non_matching.yml +34 -0
  330. data/spec/support/server_selection/selection/ReplicaSetWithPrimary/read/Primary.yml +33 -0
  331. data/spec/support/server_selection/selection/ReplicaSetWithPrimary/read/PrimaryPreferred.yml +39 -0
  332. data/spec/support/server_selection/selection/ReplicaSetWithPrimary/read/PrimaryPreferred_non_matching.yml +36 -0
  333. data/spec/support/server_selection/selection/Sharded/read/SecondaryPreferred.yml +32 -0
  334. data/spec/support/server_selection/selection/Single/read/SecondaryPreferred.yml +23 -0
  335. data/spec/support/server_selection/selection/Unknown/read/SecondaryPreferred.yml +13 -0
  336. data/spec/support/server_selection_rtt.rb +41 -0
  337. data/spec/support/shared/bulk_write.rb +498 -0
  338. data/spec/support/shared/cursor.rb +38 -0
  339. data/spec/support/shared/operation.rb +77 -0
  340. data/spec/support/shared/protocol.rb +31 -0
  341. data/spec/support/shared/server_selector.rb +111 -0
  342. data/spec/support/shared/socket.rb +82 -0
  343. data/spec/support/travis.rb +14 -0
  344. metadata +523 -189
  345. metadata.gz.sig +0 -0
  346. data/VERSION +0 -1
  347. data/lib/mongo/bulk_write_collection_view.rb +0 -387
  348. data/lib/mongo/collection_writer.rb +0 -364
  349. data/lib/mongo/connection/node.rb +0 -249
  350. data/lib/mongo/connection/pool.rb +0 -340
  351. data/lib/mongo/connection/pool_manager.rb +0 -320
  352. data/lib/mongo/connection/sharding_pool_manager.rb +0 -67
  353. data/lib/mongo/connection/socket/ssl_socket.rb +0 -95
  354. data/lib/mongo/connection/socket/tcp_socket.rb +0 -87
  355. data/lib/mongo/connection/socket/unix_socket.rb +0 -39
  356. data/lib/mongo/db.rb +0 -808
  357. data/lib/mongo/exception.rb +0 -145
  358. data/lib/mongo/functional/authentication.rb +0 -455
  359. data/lib/mongo/functional/logging.rb +0 -85
  360. data/lib/mongo/functional/read_preference.rb +0 -183
  361. data/lib/mongo/functional/scram.rb +0 -556
  362. data/lib/mongo/functional/uri_parser.rb +0 -409
  363. data/lib/mongo/functional/write_concern.rb +0 -66
  364. data/lib/mongo/gridfs/grid.rb +0 -112
  365. data/lib/mongo/gridfs/grid_ext.rb +0 -53
  366. data/lib/mongo/gridfs/grid_file_system.rb +0 -163
  367. data/lib/mongo/gridfs/grid_io.rb +0 -484
  368. data/lib/mongo/legacy.rb +0 -140
  369. data/lib/mongo/mongo_client.rb +0 -697
  370. data/lib/mongo/mongo_replica_set_client.rb +0 -535
  371. data/lib/mongo/mongo_sharded_client.rb +0 -159
  372. data/lib/mongo/networking.rb +0 -372
  373. data/lib/mongo/utils/conversions.rb +0 -110
  374. data/lib/mongo/utils/core_ext.rb +0 -70
  375. data/lib/mongo/utils/server_version.rb +0 -69
  376. data/lib/mongo/utils/support.rb +0 -80
  377. data/test/functional/authentication_test.rb +0 -39
  378. data/test/functional/bulk_api_stress_test.rb +0 -133
  379. data/test/functional/bulk_write_collection_view_test.rb +0 -1198
  380. data/test/functional/client_test.rb +0 -627
  381. data/test/functional/collection_test.rb +0 -2175
  382. data/test/functional/collection_writer_test.rb +0 -83
  383. data/test/functional/conversions_test.rb +0 -163
  384. data/test/functional/cursor_fail_test.rb +0 -57
  385. data/test/functional/cursor_message_test.rb +0 -56
  386. data/test/functional/cursor_test.rb +0 -683
  387. data/test/functional/db_api_test.rb +0 -835
  388. data/test/functional/db_test.rb +0 -348
  389. data/test/functional/grid_file_system_test.rb +0 -285
  390. data/test/functional/grid_io_test.rb +0 -252
  391. data/test/functional/grid_test.rb +0 -273
  392. data/test/functional/pool_test.rb +0 -136
  393. data/test/functional/safe_test.rb +0 -98
  394. data/test/functional/support_test.rb +0 -62
  395. data/test/functional/timeout_test.rb +0 -60
  396. data/test/functional/uri_test.rb +0 -446
  397. data/test/functional/write_concern_test.rb +0 -118
  398. data/test/helpers/general.rb +0 -50
  399. data/test/helpers/test_unit.rb +0 -476
  400. data/test/replica_set/authentication_test.rb +0 -37
  401. data/test/replica_set/basic_test.rb +0 -189
  402. data/test/replica_set/client_test.rb +0 -393
  403. data/test/replica_set/connection_test.rb +0 -138
  404. data/test/replica_set/count_test.rb +0 -66
  405. data/test/replica_set/cursor_test.rb +0 -220
  406. data/test/replica_set/insert_test.rb +0 -157
  407. data/test/replica_set/max_values_test.rb +0 -151
  408. data/test/replica_set/pinning_test.rb +0 -105
  409. data/test/replica_set/query_test.rb +0 -73
  410. data/test/replica_set/read_preference_test.rb +0 -219
  411. data/test/replica_set/refresh_test.rb +0 -211
  412. data/test/replica_set/replication_ack_test.rb +0 -95
  413. data/test/sharded_cluster/basic_test.rb +0 -203
  414. data/test/shared/authentication/basic_auth_shared.rb +0 -260
  415. data/test/shared/authentication/bulk_api_auth_shared.rb +0 -249
  416. data/test/shared/authentication/gssapi_shared.rb +0 -176
  417. data/test/shared/authentication/sasl_plain_shared.rb +0 -96
  418. data/test/shared/authentication/scram_shared.rb +0 -92
  419. data/test/shared/ssl_shared.rb +0 -235
  420. data/test/test_helper.rb +0 -61
  421. data/test/threading/basic_test.rb +0 -120
  422. data/test/tools/mongo_config.rb +0 -708
  423. data/test/tools/mongo_config_test.rb +0 -160
  424. data/test/unit/client_test.rb +0 -381
  425. data/test/unit/collection_test.rb +0 -166
  426. data/test/unit/connection_test.rb +0 -335
  427. data/test/unit/cursor_test.rb +0 -307
  428. data/test/unit/db_test.rb +0 -136
  429. data/test/unit/grid_test.rb +0 -76
  430. data/test/unit/mongo_sharded_client_test.rb +0 -48
  431. data/test/unit/node_test.rb +0 -93
  432. data/test/unit/pool_manager_test.rb +0 -111
  433. data/test/unit/read_pref_test.rb +0 -406
  434. data/test/unit/read_test.rb +0 -159
  435. data/test/unit/safe_test.rb +0 -158
  436. data/test/unit/sharding_pool_manager_test.rb +0 -84
  437. 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,128 @@
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
- #
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?
409
- #
410
- # @return [Boolean]
411
- def closed?
412
- @closed
413
- end
414
-
415
- # Returns an integer indicating which query options have been selected.
416
73
  #
417
- # @return [Integer]
74
+ # @yield param [Hash] Each matching document.
418
75
  #
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
76
+ # @return [ Enumerator ] The enumerator.
430
77
  #
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
78
+ # @since 2.0.0
79
+ def each
80
+ process(@initial_result).each { |doc| yield doc }
81
+ while more?
82
+ return kill_cursors if exhausted?
83
+ get_more.each { |doc| yield doc }
446
84
  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
85
  end
493
86
 
494
87
  private
495
88
 
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
89
+ def batch_size
90
+ @view.batch_size && @view.batch_size > 0 ? @view.batch_size : limit
616
91
  end
617
92
 
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
93
+ def exhausted?
94
+ limited? ? @remaining <= 0 : false
633
95
  end
634
96
 
635
- def checkin_socket(sock)
636
- @connection.checkin(sock)
97
+ def get_more
98
+ process(get_more_operation.execute(@server.context))
637
99
  end
638
100
 
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
101
+ def get_more_operation
102
+ Operation::Read::GetMore.new({
103
+ :to_return => to_return,
104
+ :cursor_id => @cursor_id,
105
+ :db_name => database.name,
106
+ :coll_name => @coll_name || collection.name
107
+ })
660
108
  end
661
109
 
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
110
+ def kill_cursors
111
+ kill_cursors_operation.execute(@server.context)
669
112
  end
670
113
 
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
114
+ def kill_cursors_operation
115
+ Operation::KillCursors.new({ :cursor_ids => [ @cursor_id ]})
689
116
  end
690
117
 
691
- def needs_read_pref?
692
- @connection.mongos? && @read != :primary
118
+ def limited?
119
+ limit ? limit > 0 : false
693
120
  end
694
121
 
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?
122
+ def more?
123
+ @cursor_id != 0
698
124
  end
699
125
 
700
- def close_cursor_if_query_complete
701
- if @limit > 0 && @returned >= @limit
702
- close
703
- end
126
+ def process(result)
127
+ @remaining -= result.returned_count if limited?
128
+ @cursor_id = result.cursor_id
129
+ @coll_name ||= result.namespace.sub("#{database.name}.", '') if result.namespace
130
+ result.documents
704
131
  end
705
132
 
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("_")
133
+ def to_return
134
+ use_limit? ? @remaining : (batch_size || 0)
735
135
  end
736
136
 
737
- def pin_pool?(response)
738
- ( response && (response['cursor'] || response['cursors']) ) ||
739
- ( !@socket && !@command )
137
+ def use_limit?
138
+ limited? && batch_size >= @remaining
740
139
  end
741
140
  end
742
141
  end