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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/CONTRIBUTING.md +64 -0
- data/LICENSE +1 -1
- data/README.md +23 -125
- data/Rakefile +26 -21
- data/bin/mongo_console +6 -38
- data/lib/mongo.rb +23 -82
- data/lib/mongo/address.rb +111 -0
- data/lib/mongo/address/ipv4.rb +85 -0
- data/lib/mongo/address/ipv6.rb +85 -0
- data/lib/mongo/address/unix.rb +76 -0
- data/lib/mongo/auth.rb +108 -0
- data/lib/mongo/auth/cr.rb +44 -0
- data/lib/mongo/auth/cr/conversation.rb +119 -0
- data/lib/mongo/auth/executable.rb +52 -0
- data/lib/mongo/auth/ldap.rb +48 -0
- data/lib/mongo/auth/ldap/conversation.rb +92 -0
- data/lib/mongo/auth/roles.rb +104 -0
- data/lib/mongo/auth/scram.rb +53 -0
- data/lib/mongo/auth/scram/conversation.rb +450 -0
- data/lib/mongo/auth/user.rb +159 -0
- data/lib/mongo/auth/user/view.rb +102 -0
- data/lib/mongo/auth/x509.rb +48 -0
- data/lib/mongo/auth/x509/conversation.rb +92 -0
- data/lib/mongo/{gridfs.rb → bulk.rb} +2 -5
- data/lib/mongo/bulk/bulk_write.rb +307 -0
- data/lib/mongo/client.rb +233 -0
- data/lib/mongo/cluster.rb +203 -0
- data/lib/mongo/cluster/topology.rb +60 -0
- data/lib/mongo/cluster/topology/replica_set.rb +160 -0
- data/lib/mongo/cluster/topology/sharded.rb +132 -0
- data/lib/mongo/cluster/topology/standalone.rb +132 -0
- data/lib/mongo/cluster/topology/unknown.rb +155 -0
- data/lib/mongo/collection.rb +130 -1101
- data/lib/mongo/collection/view.rb +169 -0
- data/lib/mongo/collection/view/aggregation.rb +108 -0
- data/lib/mongo/collection/view/explainable.rb +49 -0
- data/lib/mongo/collection/view/immutable.rb +43 -0
- data/lib/mongo/collection/view/iterable.rb +48 -0
- data/lib/mongo/collection/view/map_reduce.rb +191 -0
- data/lib/mongo/collection/view/readable.rb +363 -0
- data/lib/mongo/collection/view/writable.rb +169 -0
- data/lib/mongo/cursor.rb +79 -680
- data/lib/mongo/database.rb +224 -0
- data/lib/mongo/database/view.rb +101 -0
- data/lib/mongo/error.rb +81 -0
- data/lib/mongo/error/bulk_write_failure.rb +41 -0
- data/lib/mongo/{utils/thread_local_variable_manager.rb → error/empty_batch.rb} +22 -8
- data/{test/functional/db_connection_test.rb → lib/mongo/error/invalid_bulk_operation.rb} +19 -8
- data/lib/mongo/error/invalid_collection_name.rb +39 -0
- data/lib/mongo/error/invalid_database_name.rb +39 -0
- data/{test/replica_set/ssl_test.rb → lib/mongo/error/invalid_document.rb} +21 -14
- data/lib/mongo/error/invalid_file.rb +38 -0
- data/lib/mongo/error/invalid_nonce.rb +46 -0
- data/lib/mongo/error/invalid_replacement_document.rb +39 -0
- data/lib/mongo/error/invalid_signature.rb +47 -0
- data/{test/functional/ssl_test.rb → lib/mongo/error/invalid_update_document.rb} +22 -12
- data/lib/mongo/error/max_bson_size.rb +40 -0
- data/lib/mongo/error/max_message_size.rb +42 -0
- data/lib/mongo/{utils.rb → error/need_primary_server.rb} +10 -6
- data/lib/mongo/{connection.rb → error/operation_failure.rb} +10 -6
- data/lib/mongo/error/parser.rb +77 -0
- data/lib/mongo/{connection/socket.rb → error/socket_error.rb} +10 -5
- data/lib/mongo/error/socket_timeout_error.rb +23 -0
- data/lib/mongo/error/unsupported_features.rb +43 -0
- data/lib/mongo/event.rb +40 -0
- data/lib/mongo/event/listeners.rb +63 -0
- data/lib/mongo/event/primary_elected.rb +53 -0
- data/lib/mongo/event/publisher.rb +42 -0
- data/lib/mongo/event/server_added.rb +53 -0
- data/lib/mongo/event/server_removed.rb +53 -0
- data/lib/mongo/event/subscriber.rb +41 -0
- data/lib/mongo/grid.rb +16 -0
- data/lib/mongo/grid/file.rb +94 -0
- data/lib/mongo/grid/file/chunk.rb +184 -0
- data/lib/mongo/grid/file/metadata.rb +223 -0
- data/lib/mongo/grid/fs.rb +149 -0
- data/lib/mongo/index.rb +64 -0
- data/lib/mongo/index/view.rb +205 -0
- data/lib/mongo/loggable.rb +126 -0
- data/lib/mongo/logger.rb +132 -0
- data/lib/mongo/operation.rb +26 -0
- data/lib/mongo/operation/aggregate.rb +100 -0
- data/lib/mongo/operation/aggregate/result.rb +84 -0
- data/lib/mongo/operation/batchable.rb +103 -0
- data/lib/mongo/operation/bulk_delete/result.rb +197 -0
- data/lib/mongo/operation/bulk_insert/result.rb +195 -0
- data/lib/mongo/operation/bulk_update/result.rb +295 -0
- data/lib/mongo/operation/command.rb +62 -0
- data/lib/mongo/operation/executable.rb +105 -0
- data/lib/mongo/operation/kill_cursors.rb +39 -0
- data/lib/mongo/operation/limited.rb +37 -0
- data/lib/mongo/operation/list_collections/result.rb +116 -0
- data/lib/mongo/operation/list_indexes/result.rb +118 -0
- data/lib/mongo/operation/map_reduce.rb +96 -0
- data/lib/mongo/operation/map_reduce/result.rb +122 -0
- data/lib/mongo/{functional.rb → operation/read.rb} +7 -7
- data/lib/mongo/operation/read/collections_info.rb +67 -0
- data/lib/mongo/operation/read/get_more.rb +71 -0
- data/lib/mongo/operation/read/indexes.rb +68 -0
- data/lib/mongo/operation/read/list_collections.rb +75 -0
- data/lib/mongo/operation/read/list_indexes.rb +77 -0
- data/lib/mongo/operation/read/query.rb +71 -0
- data/lib/mongo/operation/read_preferrable.rb +34 -0
- data/lib/mongo/operation/result.rb +259 -0
- data/lib/mongo/operation/specifiable.rb +380 -0
- data/lib/mongo/operation/write.rb +25 -0
- data/lib/mongo/operation/write/bulk_delete.rb +158 -0
- data/lib/mongo/operation/write/bulk_insert.rb +160 -0
- data/lib/mongo/operation/write/bulk_update.rb +167 -0
- data/lib/mongo/{connection/socket/socket_util.rb → operation/write/command.rb} +9 -24
- data/lib/mongo/operation/write/command/create_user.rb +43 -0
- data/lib/mongo/operation/write/command/delete.rb +56 -0
- data/lib/mongo/operation/write/command/drop_index.rb +51 -0
- data/lib/mongo/operation/write/command/ensure_index.rb +55 -0
- data/lib/mongo/operation/write/command/insert.rb +55 -0
- data/lib/mongo/operation/write/command/remove_user.rb +42 -0
- data/lib/mongo/operation/write/command/update.rb +60 -0
- data/lib/mongo/operation/write/command/writable.rb +61 -0
- data/lib/mongo/operation/write/create_index.rb +84 -0
- data/lib/mongo/operation/write/create_user.rb +75 -0
- data/lib/mongo/operation/write/delete.rb +91 -0
- data/lib/mongo/operation/write/drop_index.rb +62 -0
- data/lib/mongo/operation/write/insert.rb +88 -0
- data/lib/mongo/operation/write/remove_user.rb +70 -0
- data/lib/mongo/operation/write/update.rb +98 -0
- data/lib/mongo/protocol.rb +15 -0
- data/lib/mongo/protocol/bit_vector.rb +61 -0
- data/lib/mongo/protocol/delete.rb +94 -0
- data/lib/mongo/protocol/get_more.rb +99 -0
- data/lib/mongo/protocol/insert.rb +99 -0
- data/lib/mongo/protocol/kill_cursors.rb +74 -0
- data/lib/mongo/protocol/message.rb +252 -0
- data/lib/mongo/protocol/query.rb +147 -0
- data/lib/mongo/protocol/reply.rb +72 -0
- data/lib/mongo/protocol/serializers.rb +180 -0
- data/lib/mongo/protocol/update.rb +111 -0
- data/lib/mongo/server.rb +163 -0
- data/lib/mongo/server/connectable.rb +99 -0
- data/lib/mongo/server/connection.rb +133 -0
- data/lib/mongo/server/connection_pool.rb +141 -0
- data/lib/mongo/server/connection_pool/queue.rb +182 -0
- data/lib/mongo/server/context.rb +66 -0
- data/lib/mongo/server/description.rb +450 -0
- data/lib/mongo/server/description/features.rb +85 -0
- data/lib/mongo/server/description/inspector.rb +79 -0
- data/lib/mongo/server/description/inspector/primary_elected.rb +58 -0
- data/lib/mongo/server/description/inspector/server_added.rb +59 -0
- data/lib/mongo/server/description/inspector/server_removed.rb +59 -0
- data/lib/mongo/server/monitor.rb +160 -0
- data/lib/mongo/server/monitor/connection.rb +88 -0
- data/lib/mongo/server_selector.rb +81 -0
- data/lib/mongo/server_selector/nearest.rb +94 -0
- data/lib/mongo/server_selector/primary.rb +88 -0
- data/lib/mongo/server_selector/primary_preferred.rb +94 -0
- data/lib/mongo/server_selector/secondary.rb +91 -0
- data/lib/mongo/server_selector/secondary_preferred.rb +96 -0
- data/lib/mongo/server_selector/selectable.rb +209 -0
- data/lib/mongo/socket.rb +179 -0
- data/lib/mongo/socket/ssl.rb +108 -0
- data/lib/mongo/socket/tcp.rb +69 -0
- data/lib/mongo/socket/unix.rb +66 -0
- data/lib/mongo/uri.rb +504 -0
- data/lib/mongo/version.rb +21 -0
- data/lib/mongo/write_concern.rb +99 -0
- data/lib/mongo/write_concern/acknowledged.rb +38 -0
- data/lib/mongo/write_concern/normalizable.rb +73 -0
- data/lib/mongo/write_concern/unacknowledged.rb +43 -0
- data/mongo.gemspec +17 -14
- data/spec/mongo/address/ipv4_spec.rb +74 -0
- data/spec/mongo/address/ipv6_spec.rb +74 -0
- data/spec/mongo/address/unix_spec.rb +30 -0
- data/spec/mongo/address_spec.rb +206 -0
- data/spec/mongo/auth/cr_spec.rb +59 -0
- data/spec/mongo/auth/ldap_spec.rb +40 -0
- data/spec/mongo/auth/scram/conversation_spec.rb +197 -0
- data/spec/mongo/auth/scram_spec.rb +55 -0
- data/spec/mongo/auth/user/view_spec.rb +76 -0
- data/spec/mongo/auth/user_spec.rb +190 -0
- data/spec/mongo/auth/x509_spec.rb +40 -0
- data/spec/mongo/auth_spec.rb +65 -0
- data/spec/mongo/bulk/bulk_write_spec.rb +175 -0
- data/spec/mongo/client_spec.rb +564 -0
- data/spec/mongo/cluster/topology/replica_set_spec.rb +101 -0
- data/spec/mongo/cluster/topology/sharded_spec.rb +74 -0
- data/spec/mongo/cluster/topology/standalone_spec.rb +79 -0
- data/spec/mongo/cluster/topology_spec.rb +65 -0
- data/spec/mongo/cluster_spec.rb +129 -0
- data/spec/mongo/collection/view/aggregation_spec.rb +135 -0
- data/spec/mongo/collection/view/explainable_spec.rb +32 -0
- data/spec/mongo/collection/view/map_reduce_spec.rb +242 -0
- data/spec/mongo/collection/view/readable_spec.rb +603 -0
- data/spec/mongo/collection/view/writable_spec.rb +504 -0
- data/spec/mongo/collection/view_spec.rb +521 -0
- data/spec/mongo/collection_spec.rb +362 -0
- data/spec/mongo/cursor_spec.rb +295 -0
- data/spec/mongo/database_spec.rb +306 -0
- data/spec/mongo/error/parser_spec.rb +119 -0
- data/spec/mongo/event/publisher_spec.rb +50 -0
- data/spec/mongo/event/subscriber_spec.rb +34 -0
- data/spec/mongo/grid/file/chunk_spec.rb +226 -0
- data/spec/mongo/grid/file/metadata_spec.rb +69 -0
- data/spec/mongo/grid/file_spec.rb +138 -0
- data/spec/mongo/grid/fs_spec.rb +129 -0
- data/spec/mongo/index/view_spec.rb +226 -0
- data/spec/mongo/loggable_spec.rb +62 -0
- data/spec/mongo/logger_spec.rb +97 -0
- data/spec/mongo/operation/aggregate/result_spec.rb +80 -0
- data/spec/mongo/operation/aggregate_spec.rb +135 -0
- data/spec/mongo/operation/command_spec.rb +106 -0
- data/spec/mongo/operation/kill_cursors_spec.rb +66 -0
- data/spec/mongo/operation/limited_spec.rb +50 -0
- data/spec/mongo/operation/map_reduce_spec.rb +143 -0
- data/spec/mongo/operation/read/collections_info_spec.rb +40 -0
- data/spec/mongo/operation/read/get_more_spec.rb +81 -0
- data/spec/mongo/operation/read/indexes_spec.rb +31 -0
- data/spec/mongo/operation/read/query_spec.rb +84 -0
- data/spec/mongo/operation/result_spec.rb +275 -0
- data/spec/mongo/operation/specifiable_spec.rb +53 -0
- data/spec/mongo/operation/write/bulk_delete_spec.rb +473 -0
- data/spec/mongo/operation/write/bulk_insert_spec.rb +466 -0
- data/spec/mongo/operation/write/bulk_update_spec.rb +524 -0
- data/spec/mongo/operation/write/command/delete_spec.rb +116 -0
- data/spec/mongo/operation/write/command/insert_spec.rb +117 -0
- data/spec/mongo/operation/write/command/update_spec.rb +123 -0
- data/spec/mongo/operation/write/create_user_spec.rb +44 -0
- data/spec/mongo/operation/write/delete_spec.rb +178 -0
- data/spec/mongo/operation/write/drop_index_spec.rb +51 -0
- data/spec/mongo/operation/write/ensure_index_spec.rb +81 -0
- data/spec/mongo/operation/write/insert_spec.rb +231 -0
- data/spec/mongo/operation/write/remove_user_spec.rb +46 -0
- data/spec/mongo/operation/write/response_spec.rb +85 -0
- data/spec/mongo/operation/write/update_spec.rb +177 -0
- data/spec/mongo/protocol/delete_spec.rb +167 -0
- data/spec/mongo/protocol/get_more_spec.rb +146 -0
- data/spec/mongo/protocol/insert_spec.rb +161 -0
- data/spec/mongo/protocol/kill_cursors_spec.rb +101 -0
- data/spec/mongo/protocol/query_spec.rb +285 -0
- data/spec/mongo/protocol/reply_spec.rb +157 -0
- data/spec/mongo/protocol/update_spec.rb +186 -0
- data/spec/mongo/server/connection_pool/queue_spec.rb +170 -0
- data/spec/mongo/server/connection_pool_spec.rb +120 -0
- data/spec/mongo/server/connection_spec.rb +289 -0
- data/spec/mongo/server/description/features_spec.rb +138 -0
- data/spec/mongo/server/description/inspector/primary_elected_spec.rb +94 -0
- data/spec/mongo/server/description/inspector/server_added_spec.rb +92 -0
- data/spec/mongo/server/description/inspector/server_removed_spec.rb +95 -0
- data/spec/mongo/server/description_spec.rb +510 -0
- data/spec/mongo/server/monitor_spec.rb +130 -0
- data/spec/mongo/server_discovery_and_monitoring_spec.rb +103 -0
- data/spec/mongo/server_selection_rtt_spec.rb +104 -0
- data/spec/mongo/server_selection_spec.rb +89 -0
- data/spec/mongo/server_selector/nearest_spec.rb +250 -0
- data/spec/mongo/server_selector/primary_preferred_spec.rb +290 -0
- data/spec/mongo/server_selector/primary_spec.rb +114 -0
- data/spec/mongo/server_selector/secondary_preferred_spec.rb +252 -0
- data/spec/mongo/server_selector/secondary_spec.rb +196 -0
- data/spec/mongo/server_selector_spec.rb +101 -0
- data/spec/mongo/server_spec.rb +131 -0
- data/spec/mongo/uri_spec.rb +517 -0
- data/spec/mongo/write_concern/acknowledged_spec.rb +44 -0
- data/spec/mongo/write_concern/unacknowledged_spec.rb +15 -0
- data/spec/mongo_orchestration_spec.rb +70 -0
- data/spec/spec_helper.rb +148 -0
- data/spec/support/authorization.rb +245 -0
- data/spec/support/helpers.rb +140 -0
- data/spec/support/matchers.rb +37 -0
- data/spec/support/mongo_orchestration.rb +61 -0
- data/spec/support/mongo_orchestration/requestable.rb +109 -0
- data/spec/support/mongo_orchestration/standalone.rb +57 -0
- data/spec/support/sdam/rs/discover_arbiters.yml +41 -0
- data/spec/support/sdam/rs/discover_passives.yml +41 -0
- data/spec/support/sdam/rs/discover_primary.yml +40 -0
- data/spec/support/sdam/rs/discover_secondary.yml +41 -0
- data/spec/support/sdam/rs/discovery.yml +195 -0
- data/spec/support/sdam/rs/ghost_discovered.yml +39 -0
- data/spec/support/sdam/rs/hosts_differ_from_seeds.yml +34 -0
- data/spec/support/sdam/rs/member_reconfig.yml +68 -0
- data/spec/support/sdam/rs/member_standalone.yml +60 -0
- data/spec/support/sdam/rs/new_primary.yml +74 -0
- data/spec/support/sdam/rs/new_primary_wrong_set_name.yml +71 -0
- data/spec/support/sdam/rs/non_rs_member.yml +31 -0
- data/spec/support/sdam/rs/normalize_case.yml +49 -0
- data/spec/support/sdam/rs/primary_becomes_standalone.yml +52 -0
- data/spec/support/sdam/rs/primary_changes_set_name.yml +57 -0
- data/spec/support/sdam/rs/primary_disconnect.yml +56 -0
- data/spec/support/sdam/rs/primary_wrong_set_name.yml +27 -0
- data/spec/support/sdam/rs/response_from_removed.yml +63 -0
- data/spec/support/sdam/rs/rsother_discovered.yml +41 -0
- data/spec/support/sdam/rs/sec_not_auth.yml +49 -0
- data/spec/support/sdam/rs/secondary_wrong_set_name.yml +28 -0
- data/spec/support/sdam/rs/secondary_wrong_set_name_with_primary.yml +69 -0
- data/spec/support/sdam/rs/unexpected_mongos.yml +26 -0
- data/spec/support/sdam/rs/wrong_set_name.yml +35 -0
- data/spec/support/sdam/sharded/multiple_mongoses.yml +46 -0
- data/spec/support/sdam/sharded/non_mongos_removed.yml +41 -0
- data/spec/support/sdam/sharded/normalize_uri_case.yml +32 -0
- data/spec/support/sdam/single/direct_connection_external_ip.yml +34 -0
- data/spec/support/sdam/single/direct_connection_mongos.yml +33 -0
- data/spec/support/sdam/single/direct_connection_rsarbiter.yml +35 -0
- data/spec/support/sdam/single/direct_connection_rsprimary.yml +34 -0
- data/spec/support/sdam/single/direct_connection_rssecondary.yml +35 -0
- data/spec/support/sdam/single/direct_connection_slave.yml +32 -0
- data/spec/support/sdam/single/direct_connection_standalone.yml +32 -0
- data/spec/support/sdam/single/not_ok_response.yml +39 -0
- data/spec/support/sdam/single/standalone_removed.yml +32 -0
- data/spec/support/sdam/single/unavailable_seed.yml +28 -0
- data/spec/support/server_discovery_and_monitoring.rb +167 -0
- data/spec/support/server_selection.rb +140 -0
- data/spec/support/server_selection/rtt/first_value.yml +4 -0
- data/spec/support/server_selection/rtt/first_value_zero.yml +4 -0
- data/spec/support/server_selection/rtt/value_test_1.yml +4 -0
- data/spec/support/server_selection/rtt/value_test_2.yml +4 -0
- data/spec/support/server_selection/rtt/value_test_3.yml +4 -0
- data/spec/support/server_selection/rtt/value_test_4.yml +4 -0
- data/spec/support/server_selection/rtt/value_test_5.yml +4 -0
- data/spec/support/server_selection/selection/ReplicaSetNoPrimary/read/Nearest.yml +32 -0
- data/spec/support/server_selection/selection/ReplicaSetNoPrimary/read/Nearest_non_matching.yml +27 -0
- data/spec/support/server_selection/selection/ReplicaSetNoPrimary/read/Primary.yml +23 -0
- data/spec/support/server_selection/selection/ReplicaSetNoPrimary/read/PrimaryPreferred.yml +32 -0
- data/spec/support/server_selection/selection/ReplicaSetNoPrimary/read/PrimaryPreferred_non_matching.yml +27 -0
- data/spec/support/server_selection/selection/ReplicaSetNoPrimary/read/Secondary.yml +32 -0
- data/spec/support/server_selection/selection/ReplicaSetNoPrimary/read/SecondaryPreferred.yml +32 -0
- data/spec/support/server_selection/selection/ReplicaSetNoPrimary/read/SecondaryPreferred_non_matching.yml +27 -0
- data/spec/support/server_selection/selection/ReplicaSetNoPrimary/read/Secondary_non_matching.yml +27 -0
- data/spec/support/server_selection/selection/ReplicaSetWithPrimary/read/Nearest.yml +41 -0
- data/spec/support/server_selection/selection/ReplicaSetWithPrimary/read/Nearest_non_matching.yml +34 -0
- data/spec/support/server_selection/selection/ReplicaSetWithPrimary/read/Primary.yml +33 -0
- data/spec/support/server_selection/selection/ReplicaSetWithPrimary/read/PrimaryPreferred.yml +39 -0
- data/spec/support/server_selection/selection/ReplicaSetWithPrimary/read/PrimaryPreferred_non_matching.yml +36 -0
- data/spec/support/server_selection/selection/Sharded/read/SecondaryPreferred.yml +32 -0
- data/spec/support/server_selection/selection/Single/read/SecondaryPreferred.yml +23 -0
- data/spec/support/server_selection/selection/Unknown/read/SecondaryPreferred.yml +13 -0
- data/spec/support/server_selection_rtt.rb +41 -0
- data/spec/support/shared/bulk_write.rb +498 -0
- data/spec/support/shared/cursor.rb +38 -0
- data/spec/support/shared/operation.rb +77 -0
- data/spec/support/shared/protocol.rb +31 -0
- data/spec/support/shared/server_selector.rb +111 -0
- data/spec/support/shared/socket.rb +82 -0
- data/spec/support/travis.rb +14 -0
- metadata +523 -189
- metadata.gz.sig +0 -0
- data/VERSION +0 -1
- data/lib/mongo/bulk_write_collection_view.rb +0 -387
- data/lib/mongo/collection_writer.rb +0 -364
- data/lib/mongo/connection/node.rb +0 -249
- data/lib/mongo/connection/pool.rb +0 -340
- data/lib/mongo/connection/pool_manager.rb +0 -320
- data/lib/mongo/connection/sharding_pool_manager.rb +0 -67
- data/lib/mongo/connection/socket/ssl_socket.rb +0 -95
- data/lib/mongo/connection/socket/tcp_socket.rb +0 -87
- data/lib/mongo/connection/socket/unix_socket.rb +0 -39
- data/lib/mongo/db.rb +0 -808
- data/lib/mongo/exception.rb +0 -145
- data/lib/mongo/functional/authentication.rb +0 -455
- data/lib/mongo/functional/logging.rb +0 -85
- data/lib/mongo/functional/read_preference.rb +0 -183
- data/lib/mongo/functional/scram.rb +0 -556
- data/lib/mongo/functional/uri_parser.rb +0 -409
- data/lib/mongo/functional/write_concern.rb +0 -66
- data/lib/mongo/gridfs/grid.rb +0 -112
- data/lib/mongo/gridfs/grid_ext.rb +0 -53
- data/lib/mongo/gridfs/grid_file_system.rb +0 -163
- data/lib/mongo/gridfs/grid_io.rb +0 -484
- data/lib/mongo/legacy.rb +0 -140
- data/lib/mongo/mongo_client.rb +0 -697
- data/lib/mongo/mongo_replica_set_client.rb +0 -535
- data/lib/mongo/mongo_sharded_client.rb +0 -159
- data/lib/mongo/networking.rb +0 -372
- data/lib/mongo/utils/conversions.rb +0 -110
- data/lib/mongo/utils/core_ext.rb +0 -70
- data/lib/mongo/utils/server_version.rb +0 -69
- data/lib/mongo/utils/support.rb +0 -80
- data/test/functional/authentication_test.rb +0 -39
- data/test/functional/bulk_api_stress_test.rb +0 -133
- data/test/functional/bulk_write_collection_view_test.rb +0 -1198
- data/test/functional/client_test.rb +0 -627
- data/test/functional/collection_test.rb +0 -2175
- data/test/functional/collection_writer_test.rb +0 -83
- data/test/functional/conversions_test.rb +0 -163
- data/test/functional/cursor_fail_test.rb +0 -57
- data/test/functional/cursor_message_test.rb +0 -56
- data/test/functional/cursor_test.rb +0 -683
- data/test/functional/db_api_test.rb +0 -835
- data/test/functional/db_test.rb +0 -348
- data/test/functional/grid_file_system_test.rb +0 -285
- data/test/functional/grid_io_test.rb +0 -252
- data/test/functional/grid_test.rb +0 -273
- data/test/functional/pool_test.rb +0 -136
- data/test/functional/safe_test.rb +0 -98
- data/test/functional/support_test.rb +0 -62
- data/test/functional/timeout_test.rb +0 -60
- data/test/functional/uri_test.rb +0 -446
- data/test/functional/write_concern_test.rb +0 -118
- data/test/helpers/general.rb +0 -50
- data/test/helpers/test_unit.rb +0 -476
- data/test/replica_set/authentication_test.rb +0 -37
- data/test/replica_set/basic_test.rb +0 -189
- data/test/replica_set/client_test.rb +0 -393
- data/test/replica_set/connection_test.rb +0 -138
- data/test/replica_set/count_test.rb +0 -66
- data/test/replica_set/cursor_test.rb +0 -220
- data/test/replica_set/insert_test.rb +0 -157
- data/test/replica_set/max_values_test.rb +0 -151
- data/test/replica_set/pinning_test.rb +0 -105
- data/test/replica_set/query_test.rb +0 -73
- data/test/replica_set/read_preference_test.rb +0 -219
- data/test/replica_set/refresh_test.rb +0 -211
- data/test/replica_set/replication_ack_test.rb +0 -95
- data/test/sharded_cluster/basic_test.rb +0 -203
- data/test/shared/authentication/basic_auth_shared.rb +0 -260
- data/test/shared/authentication/bulk_api_auth_shared.rb +0 -249
- data/test/shared/authentication/gssapi_shared.rb +0 -176
- data/test/shared/authentication/sasl_plain_shared.rb +0 -96
- data/test/shared/authentication/scram_shared.rb +0 -92
- data/test/shared/ssl_shared.rb +0 -235
- data/test/test_helper.rb +0 -61
- data/test/threading/basic_test.rb +0 -120
- data/test/tools/mongo_config.rb +0 -708
- data/test/tools/mongo_config_test.rb +0 -160
- data/test/unit/client_test.rb +0 -381
- data/test/unit/collection_test.rb +0 -166
- data/test/unit/connection_test.rb +0 -335
- data/test/unit/cursor_test.rb +0 -307
- data/test/unit/db_test.rb +0 -136
- data/test/unit/grid_test.rb +0 -76
- data/test/unit/mongo_sharded_client_test.rb +0 -48
- data/test/unit/node_test.rb +0 -93
- data/test/unit/pool_manager_test.rb +0 -111
- data/test/unit/read_pref_test.rb +0 -406
- data/test/unit/read_test.rb +0 -159
- data/test/unit/safe_test.rb +0 -158
- data/test/unit/sharding_pool_manager_test.rb +0 -84
- data/test/unit/write_concern_test.rb +0 -175
|
@@ -0,0 +1,159 @@
|
|
|
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 'mongo/auth/user/view'
|
|
16
|
+
|
|
17
|
+
module Mongo
|
|
18
|
+
module Auth
|
|
19
|
+
|
|
20
|
+
# Represents a user in MongoDB.
|
|
21
|
+
#
|
|
22
|
+
# @since 2.0.0
|
|
23
|
+
class User
|
|
24
|
+
|
|
25
|
+
# The users collection for the database.
|
|
26
|
+
#
|
|
27
|
+
# @since 2.0.0
|
|
28
|
+
COLLECTION = 'system.users'.freeze
|
|
29
|
+
|
|
30
|
+
# @return [ String ] The authorization source, either a database or
|
|
31
|
+
# external name.
|
|
32
|
+
attr_reader :auth_source
|
|
33
|
+
|
|
34
|
+
# @return [ String ] The database the user is created in.
|
|
35
|
+
attr_reader :database
|
|
36
|
+
|
|
37
|
+
# @return [ Hash ] The authentication mechanism properties.
|
|
38
|
+
attr_reader :auth_mech_properties
|
|
39
|
+
|
|
40
|
+
# @return [ Symbol ] The authorization mechanism.
|
|
41
|
+
attr_reader :mechanism
|
|
42
|
+
|
|
43
|
+
# @return [ String ] The username.
|
|
44
|
+
attr_reader :name
|
|
45
|
+
|
|
46
|
+
# @return [ String ] The cleartext password.
|
|
47
|
+
attr_reader :password
|
|
48
|
+
|
|
49
|
+
# @return [ Array<String> ] roles The user roles.
|
|
50
|
+
attr_reader :roles
|
|
51
|
+
|
|
52
|
+
# Determine if this user is equal to another.
|
|
53
|
+
#
|
|
54
|
+
# @example Check user equality.
|
|
55
|
+
# user == other
|
|
56
|
+
#
|
|
57
|
+
# @param [ Object ] other The object to compare against.
|
|
58
|
+
#
|
|
59
|
+
# @return [ true, false ] If the objects are equal.
|
|
60
|
+
#
|
|
61
|
+
# @since 2.0.0
|
|
62
|
+
def ==(other)
|
|
63
|
+
return false unless other.is_a?(User)
|
|
64
|
+
name == other.name && database == other.database && password == other.password
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Get an authentication key for the user based on a nonce from the
|
|
68
|
+
# server.
|
|
69
|
+
#
|
|
70
|
+
# @example Get the authentication key.
|
|
71
|
+
# user.auth_key(nonce)
|
|
72
|
+
#
|
|
73
|
+
# @param [ String ] nonce The response from the server.
|
|
74
|
+
#
|
|
75
|
+
# @return [ String ] The authentication key.
|
|
76
|
+
#
|
|
77
|
+
# @since 2.0.0
|
|
78
|
+
def auth_key(nonce)
|
|
79
|
+
Digest::MD5.hexdigest("#{nonce}#{name}#{hashed_password}")
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Get the UTF-8 encoded name with escaped special characters for use with
|
|
83
|
+
# SCRAM authorization.
|
|
84
|
+
#
|
|
85
|
+
# @example Get the encoded name.
|
|
86
|
+
# user.encoded_name
|
|
87
|
+
#
|
|
88
|
+
# @return [ String ] The encoded user name.
|
|
89
|
+
#
|
|
90
|
+
# @since 2.0.0
|
|
91
|
+
def encoded_name
|
|
92
|
+
name.encode(BSON::UTF8).gsub('=','=3D').gsub(',','=2C')
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Get the hash key for the user.
|
|
96
|
+
#
|
|
97
|
+
# @example Get the hash key.
|
|
98
|
+
# user.hash
|
|
99
|
+
#
|
|
100
|
+
# @return [ String ] The user hash key.
|
|
101
|
+
#
|
|
102
|
+
# @since 2.0.0
|
|
103
|
+
def hash
|
|
104
|
+
[ name, database, password ].hash
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Get the user's hashed password.
|
|
108
|
+
#
|
|
109
|
+
# @example Get the user's hashed password.
|
|
110
|
+
# user.hashed_password
|
|
111
|
+
#
|
|
112
|
+
# @return [ String ] The hashed password.
|
|
113
|
+
#
|
|
114
|
+
# @since 2.0.0
|
|
115
|
+
def hashed_password
|
|
116
|
+
@hashed_password ||= Digest::MD5.hexdigest("#{name}:mongo:#{password}").encode(BSON::UTF8)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Create the new user.
|
|
120
|
+
#
|
|
121
|
+
# @example Create a new user.
|
|
122
|
+
# Mongo::Auth::User.new(options)
|
|
123
|
+
#
|
|
124
|
+
# @param [ Hash ] options The options to create the user from.
|
|
125
|
+
#
|
|
126
|
+
# @option options [ String ] :auth_source The authorization database or
|
|
127
|
+
# external source.
|
|
128
|
+
# @option options [ String ] :database The database the user is
|
|
129
|
+
# authorized for.
|
|
130
|
+
# @option options [ String ] :user The user name.
|
|
131
|
+
# @option options [ String ] :password The user's password.
|
|
132
|
+
# @option options [ Symbol ] :auth_mech The authorization mechanism.
|
|
133
|
+
# @option options [ Array<String>, Array<Hash> ] roles The user roles.
|
|
134
|
+
#
|
|
135
|
+
# @since 2.0.0
|
|
136
|
+
def initialize(options)
|
|
137
|
+
@auth_source = options[:auth_source] || options[:database] || Database::ADMIN
|
|
138
|
+
@database = options[:database] || Database::ADMIN
|
|
139
|
+
@name = options[:user]
|
|
140
|
+
@password = options[:password] || options[:pwd]
|
|
141
|
+
@mechanism = options[:auth_mech] || :mongodb_cr
|
|
142
|
+
@auth_mech_properties = options[:auth_mech_properties] || {}
|
|
143
|
+
@roles = options[:roles] || []
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# Get the specification for the user, used in creation.
|
|
147
|
+
#
|
|
148
|
+
# @example Get the user's specification.
|
|
149
|
+
# user.spec
|
|
150
|
+
#
|
|
151
|
+
# @return [ Hash ] The user spec.
|
|
152
|
+
#
|
|
153
|
+
# @since 2.0.0
|
|
154
|
+
def spec
|
|
155
|
+
{ pwd: hashed_password, roles: roles }
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
end
|
|
@@ -0,0 +1,102 @@
|
|
|
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
|
+
module Auth
|
|
17
|
+
class User
|
|
18
|
+
|
|
19
|
+
# Defines behaviour for user related operation on databases.
|
|
20
|
+
#
|
|
21
|
+
# @since 2.0.0
|
|
22
|
+
class View
|
|
23
|
+
extend Forwardable
|
|
24
|
+
|
|
25
|
+
# @return [ Database ] database The view's database.
|
|
26
|
+
attr_reader :database
|
|
27
|
+
|
|
28
|
+
def_delegators :database, :cluster, :read_preference
|
|
29
|
+
def_delegators :cluster, :next_primary
|
|
30
|
+
|
|
31
|
+
# Create a new user in the database.
|
|
32
|
+
#
|
|
33
|
+
# @example Create a new read/write user.
|
|
34
|
+
# view.create('user', password: 'password', roles: [ 'readWrite' ])
|
|
35
|
+
#
|
|
36
|
+
# @param [ Auth::User, String ] user_or_name The user object or user name.
|
|
37
|
+
# @param [ Hash ] options The user options.
|
|
38
|
+
#
|
|
39
|
+
# @return [ Result ] The command response.
|
|
40
|
+
#
|
|
41
|
+
# @since 2.0.0
|
|
42
|
+
def create(user_or_name, options = {})
|
|
43
|
+
user = generate(user_or_name, options)
|
|
44
|
+
Operation::Write::CreateUser.new(
|
|
45
|
+
user: user,
|
|
46
|
+
db_name: database.name
|
|
47
|
+
).execute(next_primary.context)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Initialize the new user view.
|
|
51
|
+
#
|
|
52
|
+
# @example Initialize the user view.
|
|
53
|
+
# View::User.new(database)
|
|
54
|
+
#
|
|
55
|
+
# @param [ Mongo::Database ] database The database the view is for.
|
|
56
|
+
#
|
|
57
|
+
# @since 2.0.0
|
|
58
|
+
def initialize(database)
|
|
59
|
+
@database = database
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Remove a user from the database.
|
|
63
|
+
#
|
|
64
|
+
# @example Remove the user from the database.
|
|
65
|
+
# view.remove('user')
|
|
66
|
+
#
|
|
67
|
+
# @param [ String ] name The user name.
|
|
68
|
+
#
|
|
69
|
+
# @return [ Result ] The command response.
|
|
70
|
+
#
|
|
71
|
+
# @since 2.0.0
|
|
72
|
+
def remove(name)
|
|
73
|
+
Operation::Write::RemoveUser.new(
|
|
74
|
+
user_name: name,
|
|
75
|
+
db_name: database.name
|
|
76
|
+
).execute(next_primary.context)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Update a user in the database.
|
|
80
|
+
#
|
|
81
|
+
# @example Update a user.
|
|
82
|
+
# view.update('name', password: 'testpwd')
|
|
83
|
+
#
|
|
84
|
+
# @param [ Auth::User, String ] user_or_name The user object or user name.
|
|
85
|
+
# @param [ Hash ] options The user options.
|
|
86
|
+
#
|
|
87
|
+
# @return [ Result ] The response.
|
|
88
|
+
#
|
|
89
|
+
# @since 2.0.0
|
|
90
|
+
def update(user_or_name, options = {})
|
|
91
|
+
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
private
|
|
95
|
+
|
|
96
|
+
def generate(user, options)
|
|
97
|
+
user.is_a?(String) ? Auth::User.new({ user: user }.merge(options)) : user
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
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 'mongo/auth/x509/conversation'
|
|
16
|
+
|
|
17
|
+
module Mongo
|
|
18
|
+
module Auth
|
|
19
|
+
|
|
20
|
+
# Defines behaviour for x.509 authentication.
|
|
21
|
+
#
|
|
22
|
+
# @since 2.0.0
|
|
23
|
+
class X509
|
|
24
|
+
include Executable
|
|
25
|
+
|
|
26
|
+
# The authentication mechinism string.
|
|
27
|
+
#
|
|
28
|
+
# @since 2.0.0
|
|
29
|
+
MECHANISM = 'MONGODB-X509'.freeze
|
|
30
|
+
|
|
31
|
+
# Log the user in on the given connection.
|
|
32
|
+
#
|
|
33
|
+
# @example Log the user in.
|
|
34
|
+
# user.login(connection)
|
|
35
|
+
#
|
|
36
|
+
# @param [ Mongo::Connection ] connection The connection to log into.
|
|
37
|
+
# on.
|
|
38
|
+
#
|
|
39
|
+
# @return [ Protocol::Reply ] The authentication response.
|
|
40
|
+
#
|
|
41
|
+
# @since 2.0.0
|
|
42
|
+
def login(connection)
|
|
43
|
+
conversation = Conversation.new(user)
|
|
44
|
+
conversation.finalize(connection.dispatch([ conversation.start ]))
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# Copyright (C) 2014 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
|
+
module Auth
|
|
17
|
+
class X509
|
|
18
|
+
|
|
19
|
+
# Defines behaviour around a single x.509 conversation between the
|
|
20
|
+
# client and server.
|
|
21
|
+
#
|
|
22
|
+
# @since 2.0.0
|
|
23
|
+
class Conversation
|
|
24
|
+
|
|
25
|
+
# The login message.
|
|
26
|
+
#
|
|
27
|
+
# @since 2.0.0
|
|
28
|
+
LOGIN = { authenticate: 1 }.freeze
|
|
29
|
+
|
|
30
|
+
# @return [ Protocol::Reply ] reply The current reply in the
|
|
31
|
+
# conversation.
|
|
32
|
+
attr_reader :reply
|
|
33
|
+
|
|
34
|
+
# @return [ User ] user The user for the conversation.
|
|
35
|
+
attr_reader :user
|
|
36
|
+
|
|
37
|
+
# Finalize the x.509 conversation. This is meant to be iterated until
|
|
38
|
+
# the provided reply indicates the conversation is finished.
|
|
39
|
+
#
|
|
40
|
+
# @example Finalize the conversation.
|
|
41
|
+
# conversation.finalize(reply)
|
|
42
|
+
#
|
|
43
|
+
# @param [ Protocol::Reply ] reply The reply of the previous
|
|
44
|
+
# message.
|
|
45
|
+
#
|
|
46
|
+
# @return [ Protocol::Query ] The next message to send.
|
|
47
|
+
#
|
|
48
|
+
# @since 2.0.0
|
|
49
|
+
def finalize(reply)
|
|
50
|
+
validate!(reply)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Start the x.509 conversation. This returns the first message that
|
|
54
|
+
# needs to be send to the server.
|
|
55
|
+
#
|
|
56
|
+
# @example Start the conversation.
|
|
57
|
+
# conversation.start
|
|
58
|
+
#
|
|
59
|
+
# @return [ Protocol::Query ] The first x.509 conversation message.
|
|
60
|
+
#
|
|
61
|
+
# @since 2.0.0
|
|
62
|
+
def start
|
|
63
|
+
Protocol::Query.new(
|
|
64
|
+
Auth::EXTERNAL,
|
|
65
|
+
Database::COMMAND,
|
|
66
|
+
LOGIN.merge(user: user.name, mechanism: X509::MECHANISM),
|
|
67
|
+
limit: -1
|
|
68
|
+
)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Create the new conversation.
|
|
72
|
+
#
|
|
73
|
+
# @example Create the new coversation.
|
|
74
|
+
# Conversation.new(user, "admin")
|
|
75
|
+
#
|
|
76
|
+
# @param [ Auth::User ] user The user to converse about.
|
|
77
|
+
#
|
|
78
|
+
# @since 2.0.0
|
|
79
|
+
def initialize(user)
|
|
80
|
+
@user = user
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
private
|
|
84
|
+
|
|
85
|
+
def validate!(reply)
|
|
86
|
+
raise Unauthorized.new(user) if reply.documents[0]['ok'] != 1
|
|
87
|
+
@reply = reply
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright (C)
|
|
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.
|
|
@@ -12,7 +12,4 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
-
require 'mongo/
|
|
16
|
-
require 'mongo/gridfs/grid'
|
|
17
|
-
require 'mongo/gridfs/grid_file_system'
|
|
18
|
-
require 'mongo/gridfs/grid_io'
|
|
15
|
+
require 'mongo/bulk/bulk_write'
|
|
@@ -0,0 +1,307 @@
|
|
|
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
|
+
# This semi-public class handles the logic for executing a batch of
|
|
18
|
+
# operations.
|
|
19
|
+
#
|
|
20
|
+
# @since 2.0.0
|
|
21
|
+
class BulkWrite
|
|
22
|
+
|
|
23
|
+
# @return [ Mongo::Collection ] The collection on which this bulk write
|
|
24
|
+
# operation will be executed.
|
|
25
|
+
attr_reader :collection
|
|
26
|
+
|
|
27
|
+
# @return [ Array<Hash> ] operations The list of operations.
|
|
28
|
+
attr_reader :operations
|
|
29
|
+
|
|
30
|
+
# @return [ Hash ] options The options.
|
|
31
|
+
attr_reader :options
|
|
32
|
+
|
|
33
|
+
# @return [ Acknowledged, Unacknowledged ] write_concern The write concern.
|
|
34
|
+
attr_reader :write_concern
|
|
35
|
+
|
|
36
|
+
# Initialize the BulkWrite object.
|
|
37
|
+
#
|
|
38
|
+
# @example Create an ordered bulk write object.
|
|
39
|
+
# BulkWrite.new([
|
|
40
|
+
# { insert_one: { x: 1 }},
|
|
41
|
+
# { update_one: [{ x: 1 }, { '$set' => { x: 2 }}]}
|
|
42
|
+
# ],
|
|
43
|
+
# { ordered: true },
|
|
44
|
+
# collection
|
|
45
|
+
# )
|
|
46
|
+
#
|
|
47
|
+
# @example Create an unordered bulk write object.
|
|
48
|
+
# BulkWrite.new([
|
|
49
|
+
# { insert_one: { x: 1 }},
|
|
50
|
+
# { update_one: [{ x: 1 }, { '$set' => { x: 2 }}]}
|
|
51
|
+
# ],
|
|
52
|
+
# { ordered: false },
|
|
53
|
+
# collection
|
|
54
|
+
# )
|
|
55
|
+
#
|
|
56
|
+
# @param [ Array<Hash> ] operations The operations to execute.
|
|
57
|
+
# @param [ Hash ] options The options for executing the operations.
|
|
58
|
+
# @param [ Collection ] collection The collection on which the
|
|
59
|
+
# operations will be executed.
|
|
60
|
+
#
|
|
61
|
+
# @option options [ String ] :ordered Whether the operations should
|
|
62
|
+
# be executed in order.
|
|
63
|
+
# @option options [ Hash ] :write_concern The write concern to use when
|
|
64
|
+
# executing the operations.
|
|
65
|
+
#
|
|
66
|
+
# @since 2.0.0
|
|
67
|
+
def initialize(operations, options, collection)
|
|
68
|
+
@operations = operations
|
|
69
|
+
@options = options
|
|
70
|
+
@collection = collection
|
|
71
|
+
if options[:write_concern]
|
|
72
|
+
@write_concern = WriteConcern.get(options[:write_concern])
|
|
73
|
+
else
|
|
74
|
+
@write_concern = collection.write_concern
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Is the bulk write operation ordered?
|
|
79
|
+
#
|
|
80
|
+
# @example Is the bulk write operation ordered?
|
|
81
|
+
# bulk_write.ordered?
|
|
82
|
+
#
|
|
83
|
+
# @return [ true, false ] If the bulk write is ordered.
|
|
84
|
+
#
|
|
85
|
+
# @since 2.0.0
|
|
86
|
+
def ordered?
|
|
87
|
+
@ordered ||= !!options[:ordered]
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Execute the bulk write.
|
|
91
|
+
#
|
|
92
|
+
# @example execute the bulk write operations.
|
|
93
|
+
# bulk.execute
|
|
94
|
+
#
|
|
95
|
+
# @return [ Hash ] The result of doing the bulk write.
|
|
96
|
+
def execute
|
|
97
|
+
raise Error::EmptyBatch.new if operations.empty?
|
|
98
|
+
|
|
99
|
+
@index = -1
|
|
100
|
+
@ops = []
|
|
101
|
+
|
|
102
|
+
operations.each do |operation|
|
|
103
|
+
operation.each do |name, document|
|
|
104
|
+
if respond_to?(name, true)
|
|
105
|
+
send(name, document)
|
|
106
|
+
else
|
|
107
|
+
raise Error::InvalidBulkOperation.new(name)
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
ops = merge_ops
|
|
113
|
+
|
|
114
|
+
replies = []
|
|
115
|
+
until ops.empty?
|
|
116
|
+
op = ops.shift
|
|
117
|
+
|
|
118
|
+
until op.valid_batch_size?(collection.next_primary.context.max_write_batch_size)
|
|
119
|
+
ops = op.batch(2) + ops
|
|
120
|
+
op = ops.shift
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
begin
|
|
124
|
+
replies << op.execute(collection.next_primary.context)
|
|
125
|
+
# @todo: No test for max message size.
|
|
126
|
+
rescue Error::MaxBSONSize, Error::MaxMessageSize => ex
|
|
127
|
+
raise ex unless op.batchable?
|
|
128
|
+
ops = op.batch(2) + ops
|
|
129
|
+
end
|
|
130
|
+
return make_response!(replies) if stop_executing?(replies.last)
|
|
131
|
+
end
|
|
132
|
+
make_response!(replies) if op.write_concern.get_last_error
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
private
|
|
136
|
+
|
|
137
|
+
def increment_index
|
|
138
|
+
@index += 1
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def valid_doc?(doc)
|
|
142
|
+
doc.respond_to?(:keys)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def update_doc?(doc)
|
|
146
|
+
!doc.empty? &&
|
|
147
|
+
doc.respond_to?(:keys) &&
|
|
148
|
+
doc.keys.first.to_s =~ /^\$/
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def replacement_doc?(doc)
|
|
152
|
+
doc.respond_to?(:keys) && doc.keys.all?{|key| key !~ /^\$/}
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def insert_one(doc)
|
|
156
|
+
raise Error::InvalidDocument.new unless valid_doc?(doc)
|
|
157
|
+
spec = { documents: [ doc ],
|
|
158
|
+
db_name: db_name,
|
|
159
|
+
coll_name: collection.name,
|
|
160
|
+
ordered: ordered?,
|
|
161
|
+
write_concern: write_concern }
|
|
162
|
+
|
|
163
|
+
push_op(Mongo::Operation::Write::BulkInsert, spec)
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def delete_one(selector)
|
|
167
|
+
raise Error::InvalidDocument.new unless valid_doc?(selector)
|
|
168
|
+
spec = { deletes: [{ q: selector, limit: 1 }],
|
|
169
|
+
db_name: db_name,
|
|
170
|
+
coll_name: collection.name,
|
|
171
|
+
ordered: ordered?,
|
|
172
|
+
write_concern: write_concern }
|
|
173
|
+
|
|
174
|
+
push_op(Mongo::Operation::Write::BulkDelete, spec)
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def delete_many(selector)
|
|
178
|
+
raise Error::InvalidDocument.new unless valid_doc?(selector)
|
|
179
|
+
spec = { deletes: [{ q: selector, limit: 0 }],
|
|
180
|
+
db_name: db_name,
|
|
181
|
+
coll_name: collection.name,
|
|
182
|
+
ordered: ordered?,
|
|
183
|
+
write_concern: write_concern }
|
|
184
|
+
|
|
185
|
+
push_op(Mongo::Operation::Write::BulkDelete, spec)
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def replace_one(docs)
|
|
189
|
+
selector = docs[0]
|
|
190
|
+
replacement = docs[1]
|
|
191
|
+
upsert = (docs[2] || {})[:upsert]
|
|
192
|
+
raise ArgumentError unless selector && replacement
|
|
193
|
+
raise Error::InvalidReplacementDocument.new unless replacement_doc?(replacement)
|
|
194
|
+
upsert = !!upsert
|
|
195
|
+
spec = { updates: [{ q: selector,
|
|
196
|
+
u: replacement,
|
|
197
|
+
multi: false,
|
|
198
|
+
upsert: upsert }],
|
|
199
|
+
db_name: db_name,
|
|
200
|
+
coll_name: collection.name,
|
|
201
|
+
ordered: ordered?,
|
|
202
|
+
write_concern: write_concern }
|
|
203
|
+
|
|
204
|
+
push_op(Mongo::Operation::Write::BulkUpdate, spec)
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def update_one(docs)
|
|
208
|
+
upsert = (docs[2] || {})[:upsert]
|
|
209
|
+
update_one_or_many(docs[0], docs[1], upsert, false)
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def update_many(docs)
|
|
213
|
+
upsert = (docs[2] || {})[:upsert]
|
|
214
|
+
update_one_or_many(docs[0], docs[1], upsert, true)
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
def update_one_or_many(selector, update, upsert, multi)
|
|
218
|
+
raise ArgumentError unless selector && update
|
|
219
|
+
raise Error::InvalidUpdateDocument.new unless update_doc?(update)
|
|
220
|
+
upsert = !!upsert
|
|
221
|
+
spec = { updates: [{ q: selector,
|
|
222
|
+
u: update,
|
|
223
|
+
multi: multi,
|
|
224
|
+
upsert: upsert }],
|
|
225
|
+
db_name: db_name,
|
|
226
|
+
coll_name: collection.name,
|
|
227
|
+
ordered: ordered?,
|
|
228
|
+
write_concern: write_concern }
|
|
229
|
+
|
|
230
|
+
push_op(Mongo::Operation::Write::BulkUpdate, spec)
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
def push_op(op_class, spec)
|
|
234
|
+
spec.merge!(indexes: [ increment_index ])
|
|
235
|
+
@ops << op_class.send(:new, spec)
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
def merge_ops
|
|
239
|
+
if ordered?
|
|
240
|
+
merge_consecutive_ops(@ops)
|
|
241
|
+
else
|
|
242
|
+
merge_ops_by_type(@ops)
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
def merge_consecutive_ops(operations)
|
|
247
|
+
operations.inject([]) do |merged_ops, op|
|
|
248
|
+
previous_op = merged_ops.last
|
|
249
|
+
if previous_op.class == op.class
|
|
250
|
+
merged_ops.tap do |m|
|
|
251
|
+
m[m.size - 1] = previous_op.merge!(op)
|
|
252
|
+
end
|
|
253
|
+
else
|
|
254
|
+
merged_ops << op
|
|
255
|
+
end
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
def merge_ops_by_type(operations)
|
|
260
|
+
ops_by_type = operations.inject({}) do |merged_ops, op|
|
|
261
|
+
if merged_ops[op.class]
|
|
262
|
+
merged_ops.tap do |m|
|
|
263
|
+
m[op.class] << op
|
|
264
|
+
end
|
|
265
|
+
else
|
|
266
|
+
merged_ops.tap do |m|
|
|
267
|
+
m[op.class] = [ op ]
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
ops_by_type.keys.inject([]) do |merged_ops, type|
|
|
273
|
+
merged_ops << merge_consecutive_ops( ops_by_type[ type ] )
|
|
274
|
+
end.flatten
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
def stop_executing?(result)
|
|
278
|
+
result && ordered? && !result.successful?
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
def make_response!(results)
|
|
282
|
+
response = results.reduce({}) do |response, result|
|
|
283
|
+
write_errors = result.aggregate_write_errors
|
|
284
|
+
write_concern_errors = result.aggregate_write_concern_errors
|
|
285
|
+
response.tap do |r|
|
|
286
|
+
r['nInserted'] = ( r['nInserted'] || 0 ) + result.n_inserted if result.respond_to?(:n_inserted)
|
|
287
|
+
r['nMatched'] = ( r['nMatched'] || 0 ) + result.n_matched if result.respond_to?(:n_matched)
|
|
288
|
+
r['nModified'] = ( r['nModified'] || 0 ) + result.n_modified if result.respond_to?(:n_modified) && result.n_modified
|
|
289
|
+
r['nUpserted'] = ( r['nUpserted'] || 0 ) + result.n_upserted if result.respond_to?(:n_upserted)
|
|
290
|
+
r['nRemoved'] = ( r['nRemoved'] || 0 ) + result.n_removed if result.respond_to?(:n_removed)
|
|
291
|
+
r['writeErrors'] = ( r['writeErrors'] || [] ) + write_errors if write_errors
|
|
292
|
+
r['writeConcernErrors'] = ( r['writeConcernErrors'] || [] ) + write_concern_errors if write_concern_errors
|
|
293
|
+
end
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
if response['writeErrors'] || response['writeConcernErrors']
|
|
297
|
+
response.merge!('errmsg' => 'batch item errors occurred')
|
|
298
|
+
raise Error::BulkWriteFailure.new(response)
|
|
299
|
+
end
|
|
300
|
+
response
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
def db_name
|
|
304
|
+
collection.database.name
|
|
305
|
+
end
|
|
306
|
+
end
|
|
307
|
+
end
|