mongo 1.12.5 → 2.0.0.beta

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 (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
@@ -0,0 +1,108 @@
1
+ # Copyright (C) 2014-2015 MongoDB, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'openssl'
16
+
17
+ module Mongo
18
+ class Socket
19
+
20
+ # Wrapper for SSL sockets.
21
+ #
22
+ # @since 2.0.0
23
+ class SSL < Socket
24
+ include OpenSSL
25
+
26
+ # @return [ SSLContext ] context The ssl context.
27
+ attr_reader :context
28
+
29
+ # @return [ String ] host The host to connect to.
30
+ attr_reader :host
31
+
32
+ # @return [ Hash ] The ssl options.
33
+ attr_reader :options
34
+
35
+ # @return [ Integer ] port The port to connect to.
36
+ attr_reader :port
37
+
38
+ # @return [ Float ] timeout The connection timeout.
39
+ attr_reader :timeout
40
+
41
+ # Establishes a socket connection.
42
+ #
43
+ # @example Connect the socket.
44
+ # sock.connect!
45
+ #
46
+ # @note This method mutates the object by setting the socket
47
+ # internally.
48
+ #
49
+ # @return [ SSL ] The connected socket instance.
50
+ #
51
+ # @since 2.0.0
52
+ def connect!
53
+ Timeout.timeout(timeout, Error::SocketTimeoutError) do
54
+ socket.setsockopt(IPPROTO_TCP, TCP_NODELAY, 1)
55
+ socket.connect(::Socket.pack_sockaddr_in(port, host))
56
+ ssl_socket = OpenSSL::SSL::SSLSocket.new(socket, context)
57
+ ssl_socket.sync_close = true
58
+ ssl_socket.connect
59
+ verify_certificate!(ssl_socket)
60
+ self
61
+ end
62
+ end
63
+
64
+ # Initializes a new SSL socket.
65
+ #
66
+ # @example Create the SSL socket.
67
+ # SSL.new('::1', 27017, 30)
68
+ #
69
+ # @param [ String ] host The hostname or IP address.
70
+ # @param [ Integer ] port The port number.
71
+ # @param [ Float ] timeout The socket timeout value.
72
+ # @param [ Integer ] family The socket family.
73
+ # @param [ Hash ] options The ssl options.
74
+ #
75
+ # @since 2.0.0
76
+ def initialize(host, port, timeout, family, options = {})
77
+ @host, @port, @timeout, @options = host, port, timeout, options
78
+ @context = create_context(options)
79
+ super(family)
80
+ end
81
+
82
+ private
83
+
84
+ def create_context(options)
85
+ context = OpenSSL::SSL::SSLContext.new
86
+ if options[:ssl_cert]
87
+ context.cert = OpenSSL::X509::Certificate.new(File.open(options[:ssl_cert]))
88
+ end
89
+ if options[:ssl_key]
90
+ context.key = OpenSSL::PKey::RSA.new(File.open(options[:ssl_key]))
91
+ end
92
+ if options[:ssl_verify] || options[:ssl_ca_cert]
93
+ context.ca_file = options[:ssl_ca_cert]
94
+ context.verify_mode = OpenSSL::SSL::VERIFY_PEER
95
+ end
96
+ context
97
+ end
98
+
99
+ def verify_certificate!(socket)
100
+ if context.verify_mode == OpenSSL::SSL::VERIFY_PEER
101
+ unless OpenSSL::SSL.verify_certificate_identity(socket.peer_cert, host)
102
+ raise Error::SocketError, 'SSL handshake failed due to a hostname mismatch.'
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,69 @@
1
+ # Copyright (C) 2014-2015 MongoDB, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module Mongo
16
+ class Socket
17
+
18
+ # Wrapper for TCP sockets.
19
+ #
20
+ # @since 2.0.0
21
+ class TCP < Socket
22
+
23
+ # @return [ String ] host The host to connect to.
24
+ attr_reader :host
25
+
26
+ # @return [ Integer ] port The port to connect to.
27
+ attr_reader :port
28
+
29
+ # @return [ Float ] timeout The connection timeout.
30
+ attr_reader :timeout
31
+
32
+ # Establishes a socket connection.
33
+ #
34
+ # @example Connect the socket.
35
+ # sock.connect!
36
+ #
37
+ # @note This method mutates the object by setting the socket
38
+ # internally.
39
+ #
40
+ # @return [ TCP ] The connected socket instance.
41
+ #
42
+ # @since 2.0.0
43
+ def connect!
44
+ Timeout.timeout(timeout, Error::SocketTimeoutError) do
45
+ socket.setsockopt(IPPROTO_TCP, TCP_NODELAY, 1)
46
+ socket.connect(::Socket.pack_sockaddr_in(port, host))
47
+ self
48
+ end
49
+ end
50
+
51
+ # Initializes a new TCP socket.
52
+ #
53
+ # @example Create the TCP socket.
54
+ # TCP.new('::1', 27017, 30)
55
+ # TCP.new('127.0.0.1', 27017, 30)
56
+ #
57
+ # @param [ String ] host The hostname or IP address.
58
+ # @param [ Integer ] port The port number.
59
+ # @param [ Float ] timeout The socket timeout value.
60
+ # @param [ Integer ] family The socket family.
61
+ #
62
+ # @since 2.0.0
63
+ def initialize(host, port, timeout, family)
64
+ @host, @port, @timeout = host, port, timeout
65
+ super(family)
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,66 @@
1
+ # Copyright (C) 2014-2015 MongoDB, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module Mongo
16
+ class Socket
17
+
18
+ # Wrapper for Unix sockets.
19
+ #
20
+ # @since 2.0.0
21
+ class Unix < Socket
22
+
23
+ # @return [ String ] path The path to connect to.
24
+ attr_reader :path
25
+
26
+ # @return [ Float ] timeout The connection timeout.
27
+ attr_reader :timeout
28
+
29
+ # Establishes a socket connection.
30
+ #
31
+ # @example Connect the socket.
32
+ # sock.connect!
33
+ #
34
+ # @note This method mutates the object by setting the socket
35
+ # internally.
36
+ #
37
+ # @return [ Unix ] The connected socket instance.
38
+ #
39
+ # @since 2.0.0
40
+ def connect!
41
+ Timeout.timeout(timeout, Error::SocketTimeoutError) do
42
+ socket.connect(path)
43
+ self
44
+ end
45
+ end
46
+
47
+ # Initializes a new Unix socket.
48
+ #
49
+ # @example Create the Unix socket.
50
+ # Unix.new('::1', 27017, 30)
51
+ # Unix.new('127.0.0.1', 27017, 30)
52
+ #
53
+ # @param [ String ] host The hostname or IP address.
54
+ # @param [ Integer ] port The port number.
55
+ # @param [ Float ] timeout The socket timeout value.
56
+ # @param [ Integer ] family The socket family.
57
+ #
58
+ # @since 2.0.0
59
+ def initialize(path, timeout, family)
60
+ @path, @timeout = path, timeout
61
+ super(family)
62
+ end
63
+ end
64
+ end
65
+ end
66
+
data/lib/mongo/uri.rb ADDED
@@ -0,0 +1,504 @@
1
+ # Copyright (C) 2014-2015 MongoDB, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the 'License');
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an 'AS IS' BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module Mongo
16
+
17
+ # The URI class provides a way for users to parse the MongoDB uri as
18
+ # defined in the connection string format spec.
19
+ #
20
+ # http://docs.mongodb.org/manual/reference/connection-string/
21
+ #
22
+ # @example Use the uri string to make a client connection.
23
+ # uri = URI.new('mongodb://localhost:27017')
24
+ # client = Client.new(uri.server, uri.options)
25
+ # client.login(uri.credentials)
26
+ # client[uri.database]
27
+ #
28
+ # @since 2.0.0
29
+ class URI
30
+
31
+ # Scheme Regex: non-capturing, matches scheme.
32
+ #
33
+ # @since 2.0.0
34
+ SCHEME = %r{(?:mongodb://)}.freeze
35
+
36
+ # User Regex: capturing, group 1, matches anything but ':'
37
+ #
38
+ # @since 2.0.0
39
+ USER = /([^:]+)/.freeze
40
+
41
+ # Password Regex: capturing, group 2, matches anything but '@'
42
+ #
43
+ # @since 2.0.0
44
+ PASSWORD = /([^@]+)/.freeze
45
+
46
+ # Credentials Regex: non capturing, matches 'user:password@'
47
+ #
48
+ # @since 2.0.0
49
+ CREDENTIALS = /(?:#{USER}:#{PASSWORD}?@)?/.freeze
50
+
51
+ # Host and port server Regex: matches anything but a forward slash
52
+ #
53
+ # @since 2.0.0
54
+ HOSTPORT = /[^\/]+/.freeze
55
+
56
+ # Unix socket server Regex: matches unix socket server
57
+ #
58
+ # @since 2.0.0
59
+ UNIX = /\/.+.sock?/.freeze
60
+
61
+ # server Regex: capturing, matches host and port server or unix server
62
+ #
63
+ # @since 2.0.0
64
+ SERVERS = /((?:(?:#{HOSTPORT}|#{UNIX}),?)+)/.freeze
65
+
66
+ # Database Regex: matches anything but the characters that cannot
67
+ # be part of any MongoDB database name.
68
+ #
69
+ # @since 2.0.0
70
+ DATABASE = %r{(?:/([^/\.\ "*<>:\|\?]*))?}.freeze
71
+
72
+ # Option Regex: notably only matches the ampersand separator and does
73
+ # not allow for semicolon to be used to separate options.
74
+ #
75
+ # @since 2.0.0
76
+ OPTIONS = /(?:\?(?:(.+=.+)&?)+)*/.freeze
77
+
78
+ # Complete URI Regex: matches all of the combined components
79
+ #
80
+ # @since 2.0.0
81
+ URI = /#{SCHEME}#{CREDENTIALS}#{SERVERS}#{DATABASE}#{OPTIONS}/.freeze
82
+
83
+ # MongoDB URI (connection string) documentation url
84
+ #
85
+ # @since 2.0.0
86
+ HELP = 'http://docs.mongodb.org/manual/reference/connection-string/'.freeze
87
+
88
+ # Map of URI read preference modes to ruby driver read preference modes
89
+ #
90
+ # @since 2.0.0
91
+ READ_MODE_MAP = {
92
+ 'primary' => :primary,
93
+ 'primaryPreferred' => :primary_preferred,
94
+ 'secondary' => :secondary,
95
+ 'secondaryPreferred' => :secondary_preferred,
96
+ 'nearest' => :nearest
97
+ }.freeze
98
+
99
+ # Map of URI authentication mechanisms to ruby driver mechanisms
100
+ #
101
+ # @since 2.0.0
102
+ AUTH_MECH_MAP = {
103
+ 'PLAIN' => :plain,
104
+ 'MONGODB-CR' => :mongodb_cr,
105
+ 'GSSAPI' => :gssapi
106
+ }.freeze
107
+
108
+ # Create the new uri from the provided string.
109
+ #
110
+ # @example Create the new URI.
111
+ # URI.new('mongodb://localhost:27017')
112
+ #
113
+ # @param [ String ] string The uri string.
114
+ #
115
+ # @raise [ BadURI ] If the uri does not match the spec.
116
+ #
117
+ # @since 2.0.0
118
+ def initialize(string)
119
+ @match = string.match(URI)
120
+ raise Invalid.new(string) unless @match
121
+ end
122
+
123
+ # Get the servers provided in the URI.
124
+ #
125
+ # @example Get the servers.
126
+ # uri.servers
127
+ #
128
+ # @return [ Array<String> ] The servers.
129
+ #
130
+ # @since 2.0.0
131
+ def servers
132
+ @match[3].split(',')
133
+ end
134
+
135
+ # Gets the options hash that needs to be passed to a Mongo::Client on
136
+ # instantiation, so we don't have to merge the credentials and database in
137
+ # at that point - we only have a single point here.
138
+ #
139
+ # @example Get the client options.
140
+ # uri.client_options
141
+ #
142
+ # @return [ Hash ] The options passed to the Mongo::Client
143
+ #
144
+ # @since 2.0.0
145
+ def client_options
146
+ opts = options.merge(:database => database)
147
+ user ? opts.merge(credentials) : opts
148
+ end
149
+
150
+ # Get the credentials provided in the URI.
151
+ #
152
+ # @example Get the credentials.
153
+ # uri.credentials
154
+ #
155
+ # @return [ Hash ] The credentials.
156
+ # * :user [ String ] The user.
157
+ # * :password [ String ] The provided password.
158
+ #
159
+ # @since 2.0.0
160
+ def credentials
161
+ { :user => user, :password => password }
162
+ end
163
+
164
+ # Get the database provided in the URI.
165
+ #
166
+ # @example Get the database.
167
+ # uri.database
168
+ #
169
+ # @return [String] The database.
170
+ #
171
+ # @since 2.0.0
172
+ def database
173
+ @match[4].nil? ? Database::ADMIN : @match[4]
174
+ end
175
+
176
+ # Get the options provided in the URI.
177
+ #
178
+ # @example Get The options.
179
+ # uri.options
180
+ #
181
+ # @return [Hash] The options.
182
+ #
183
+ # Generic Options
184
+ # * :replica_set [String] replica set name
185
+ # * :connect_timeout [Fixnum] connect timeout
186
+ # * :socket_timeout [Fixnum] socket timeout
187
+ # * :ssl [true, false] ssl enabled?
188
+ #
189
+ # Write Options (returned in a hash under the :write key)
190
+ # * :w [String, Fixnum] write concern value
191
+ # * :j [true, false] journal
192
+ # * :fsync [true, false] fsync
193
+ # * :timeout [Fixnum] timeout for write operation
194
+ #
195
+ # Read Options (returned in a hash under the :read key)
196
+ # * :mode [Symbol] read mode
197
+ # * :tag_sets [Array<Hash>] read tag sets
198
+ #
199
+ # @since 2.0.0
200
+ def options
201
+ parsed_options = @match[5]
202
+ return {} unless parsed_options
203
+ parsed_options.split('&').reduce({}) do |options, option|
204
+ key, value = option.split('=')
205
+ strategy = OPTION_MAP[key]
206
+ raise InvalidOption.new(key) if strategy.nil?
207
+ add_option(strategy, value, options)
208
+ options
209
+ end
210
+ end
211
+
212
+ # Exception that is raised when trying to parse a URI that does not match
213
+ # the specification.
214
+ #
215
+ # @since 2.0.0
216
+ class Invalid < RuntimeError
217
+
218
+ # MongoDB URI format specification.
219
+ #
220
+ # @since 2.0.0
221
+ FORMAT = 'mongodb://[username:password@]host1[:port1][,host2[:port2]' +
222
+ ',...[,hostN[:portN]]][/[database][?options]]'.freeze
223
+
224
+ # Creates a new instance of the BadURI error.
225
+ #
226
+ # @example Initialize the error.
227
+ # BadURI.new(uri)
228
+ #
229
+ # @param [ String ] uri The bad URI.
230
+ #
231
+ # @since 2.0.0
232
+ def initialize(uri)
233
+ super(message(uri))
234
+ end
235
+
236
+ private
237
+
238
+ def message(uri)
239
+ "MongoDB URI must be in the following format: #{FORMAT}\n" +
240
+ "Please see the following URL for more information: #{HELP}\n" +
241
+ "Bad URI: #{uri}"
242
+ end
243
+ end
244
+
245
+ # Raised if the URI is in the correct format but an option is provided that
246
+ # is not recognized.
247
+ #
248
+ # @since 2.0.0
249
+ class InvalidOption < RuntimeError
250
+
251
+ # Create the error.
252
+ #
253
+ # @example Create the error with the invalid option name.
254
+ # InvalidOption.new('nothing')
255
+ #
256
+ # @param [ String ] name The invalid option name.
257
+ #
258
+ # @since 2.0.0
259
+ def initialize(name)
260
+ super("Invalid option in URI: '#{name}'.\n" +
261
+ "Please see the following URL for more information: #{HELP}\n")
262
+ end
263
+ end
264
+
265
+ private
266
+
267
+ # Hash for storing map of URI option parameters to conversion strategies
268
+ OPTION_MAP = {}
269
+
270
+ # Simple internal dsl to register a MongoDB URI option in the OPTION_MAP.
271
+ #
272
+ # @param uri_key [String] The MongoDB URI option to register.
273
+ # @param name [Symbol] The name of the option in the driver.
274
+ # @param extra [Hash] Extra options.
275
+ # * :group [Symbol] Nested hash where option will go.
276
+ # * :type [Symbol] Name of function to transform value.
277
+ def self.option(uri_key, name, extra = {})
278
+ OPTION_MAP[uri_key] = { :name => name }.merge(extra)
279
+ end
280
+
281
+ # Replica Set Options
282
+ option 'replicaSet', :replica_set, :type => :replica_set
283
+
284
+ # Timeout Options
285
+ option 'connectTimeoutMS', :connect_timeout, :type => :ms_convert
286
+ option 'socketTimeoutMS', :socket_timeout, :type => :ms_convert
287
+ option 'serverSelectionTimeoutMS', :server_selection_timeout, :type => :ms_convert
288
+ option 'localThresholdMS', :local_threshold, :type => :ms_convert
289
+
290
+ # Write Options
291
+ option 'w', :w, :group => :write
292
+ option 'j', :j, :group => :write
293
+ option 'fsync', :fsync, :group => :write
294
+ option 'wtimeoutMS', :timeout, :group => :write
295
+
296
+ # Read Options
297
+ option 'readPreference', :mode, :group => :read, :type => :read_mode
298
+ option 'readPreferenceTags', :tag_sets, :group => :read, :type => :read_tags
299
+
300
+ # Pool options
301
+ option 'minPoolSize', :min_pool_size
302
+ option 'maxPoolSize', :max_pool_size
303
+ option 'waitQueueTimeoutMS', :wait_queue_timeout, :type => :ms_convert
304
+
305
+ # Security Options
306
+ option 'ssl', :ssl
307
+
308
+ # Topology options
309
+ option 'connect', :connect
310
+
311
+ # Auth Options
312
+ option 'authSource', :source, :group => :auth, :type => :auth_source
313
+ option 'authMechanism', :mechanism, :group => :auth, :type => :auth_mech
314
+ option 'authMechanismProperties', :auth_mech_properties, :group => :auth,
315
+ :type => :auth_mech_props
316
+
317
+ # Gets the user provided in the URI
318
+ #
319
+ # @return [String] The user.
320
+ def user
321
+ @match[1]
322
+ end
323
+
324
+ # Gets the password provided in the URI
325
+ #
326
+ # @return [String] The password.
327
+ def password
328
+ @match[2]
329
+ end
330
+
331
+ # Casts option values that do not have a specifically provided
332
+ # transofrmation to the appropriate type.
333
+ #
334
+ # @param value [String] The value to be cast.
335
+ #
336
+ # @return [true, false, Fixnum, Symbol] The cast value.
337
+ def cast(value)
338
+ if value == 'true'
339
+ true
340
+ elsif value == 'false'
341
+ false
342
+ elsif value =~ /[\d]/
343
+ value.to_i
344
+ else
345
+ value.to_sym
346
+ end
347
+ end
348
+
349
+ # Applies URI value transformation by either using the default cast
350
+ # or a transformation appropriate for the given type.
351
+ #
352
+ # @param value [String] The value to be transformed.
353
+ # @param type [Symbol] The transform method.
354
+ def apply_transform(value, type = nil)
355
+ if type
356
+ send(type, value)
357
+ else
358
+ cast(value)
359
+ end
360
+ end
361
+
362
+ # Selects the output destination for an option.
363
+ #
364
+ # @param options [Hash] The base target.
365
+ # @param group [Symbol] Group subtarget.
366
+ #
367
+ # @return [Hash] The target for the option.
368
+ def select_target(options, group = nil)
369
+ if group
370
+ options[group] ||= {}
371
+ else
372
+ options
373
+ end
374
+ end
375
+
376
+ # Merges a new option into the target.
377
+ #
378
+ # If the option exists at the target destination the merge will
379
+ # be an addition.
380
+ #
381
+ # Specifically required to append an additional tag set
382
+ # to the array of tag sets without overwriting the original.
383
+ #
384
+ # @param target [Hash] The destination.
385
+ # @param value [Object] The value to be merged.
386
+ # @param name [Symbol] The name of the option.
387
+ def merge_option(target, value, name)
388
+ if target.key?(name)
389
+ target[name] += value
390
+ else
391
+ target.merge!(name => value)
392
+ end
393
+ end
394
+
395
+ # Adds an option to the options hash via the supplied strategy.
396
+ #
397
+ # Acquires a target for the option based on group.
398
+ # Transforms the value.
399
+ # Merges the option into the target.
400
+ #
401
+ # @param strategy [Symbol] The strategy for this option.
402
+ # @param value [String] The value of the option.
403
+ # @param options [Hash] The base option target.
404
+ def add_option(strategy, value, options)
405
+ target = select_target(options, strategy[:group])
406
+ value = apply_transform(value, strategy[:type])
407
+ merge_option(target, value, strategy[:name])
408
+ end
409
+
410
+ # Replica set transformation, avoid converting to Symbol.
411
+ #
412
+ # @param value [String] Replica set name.
413
+ #
414
+ # @return [String] Same value to avoid cast to Symbol.
415
+ def replica_set(value)
416
+ value
417
+ end
418
+
419
+ # Auth source transformation, either db string or :external.
420
+ #
421
+ # @param value [String] Authentication source.
422
+ #
423
+ # @return [String] If auth source is database name.
424
+ # @return [:external] If auth source is external authentication.
425
+ def auth_source(value)
426
+ value == '$external' ? :external : value
427
+ end
428
+
429
+ # Authentication mechanism transformation.
430
+ #
431
+ # @param value [String] The authentication mechanism.
432
+ #
433
+ # @return [Symbol] The transformed authentication mechanism.
434
+ def auth_mech(value)
435
+ AUTH_MECH_MAP[value]
436
+ end
437
+
438
+ # Read preference mode transformation.
439
+ #
440
+ # @param value [String] The read mode string value.
441
+ #
442
+ # @return [Symbol] The read mode symbol.
443
+ def read_mode(value)
444
+ READ_MODE_MAP[value]
445
+ end
446
+
447
+ # Read preference tags transformation.
448
+ #
449
+ # @param value [String] The string representing tag set.
450
+ #
451
+ # @return [Array<Hash>] Array with tag set.
452
+ def read_tags(value)
453
+ [read_set(value)]
454
+ end
455
+
456
+ # Read preference tag set extractor.
457
+ #
458
+ # @param value [String] The tag set string.
459
+ #
460
+ # @return [Hash] The tag set hash.
461
+ def read_set(value)
462
+ hash_extractor(value)
463
+ end
464
+
465
+ # Auth mechanism properties extractor.
466
+ #
467
+ # @param value [ String ] The auth mechanism properties string.
468
+ #
469
+ # @return [ Hash ] The auth mechanism properties hash.
470
+ def auth_mech_props(value)
471
+ properties = hash_extractor(value)
472
+ if properties[:canonicalize_host_name]
473
+ properties.merge!(canonicalize_host_name:
474
+ properties[:canonicalize_host_name] == 'true')
475
+ end
476
+ properties
477
+ end
478
+
479
+ # Ruby's convention is to provide timeouts in seconds, not milliseconds and
480
+ # to use fractions where more precision is necessary. The connection string
481
+ # options are always in MS so we provide an easy conversion type.
482
+ #
483
+ # @param [ Integer ] value The millisecond value.
484
+ #
485
+ # @return [ Float ] The seconds value.
486
+ #
487
+ # @since 2.0.0
488
+ def ms_convert(value)
489
+ value.to_f / 1000
490
+ end
491
+
492
+ # Extract values from the string and put them into a nested hash.
493
+ #
494
+ # @param value [ String ] The string to build a hash from.
495
+ #
496
+ # @return [ Hash ] The hash built from the string.
497
+ def hash_extractor(value)
498
+ value.split(',').reduce({}) do |set, tag|
499
+ k, v = tag.split(':')
500
+ set.merge(k.downcase.to_sym => v)
501
+ end
502
+ end
503
+ end
504
+ end