neo4j-ruby-driver 6.0.3.alpha.0 → 6.2.1.beta.2
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
- data/README.md +113 -411
- data/{ruby → lib}/neo4j/driver/access_mode.rb +2 -1
- data/lib/neo4j/driver/auth_token_managers.rb +31 -0
- data/lib/neo4j/driver/auth_tokens.rb +41 -0
- data/lib/neo4j/driver/auto_commit_retries_mode.rb +18 -0
- data/lib/neo4j/driver/bolt/bolt_version.rb +67 -0
- data/lib/neo4j/driver/bolt/connection.rb +1091 -0
- data/lib/neo4j/driver/bolt/handshake.rb +236 -0
- data/lib/neo4j/driver/bolt/message/failure.rb +139 -0
- data/lib/neo4j/driver/bolt/message/ignored.rb +27 -0
- data/lib/neo4j/driver/bolt/message/record.rb +30 -0
- data/lib/neo4j/driver/bolt/message/success.rb +34 -0
- data/lib/neo4j/driver/bolt/message.rb +112 -0
- data/lib/neo4j/driver/bolt/pool.rb +255 -0
- data/lib/neo4j/driver/bolt/protocol/base.rb +146 -0
- data/lib/neo4j/driver/bolt/protocol/v3.rb +43 -0
- data/lib/neo4j/driver/bolt/protocol/v4.rb +24 -0
- data/lib/neo4j/driver/bolt/protocol/v43.rb +28 -0
- data/lib/neo4j/driver/bolt/protocol/v44.rb +23 -0
- data/lib/neo4j/driver/bolt/protocol/v5.rb +27 -0
- data/lib/neo4j/driver/bolt/protocol/v51.rb +24 -0
- data/lib/neo4j/driver/bolt/protocol/v52.rb +28 -0
- data/lib/neo4j/driver/bolt/protocol/v53.rb +27 -0
- data/lib/neo4j/driver/bolt/protocol/v54.rb +14 -0
- data/lib/neo4j/driver/bolt/protocol/v55.rb +17 -0
- data/lib/neo4j/driver/bolt/protocol/v56.rb +14 -0
- data/lib/neo4j/driver/bolt/protocol/v57.rb +31 -0
- data/lib/neo4j/driver/bolt/protocol/v58.rb +15 -0
- data/lib/neo4j/driver/bolt/protocol/v6.rb +43 -0
- data/lib/neo4j/driver/bolt/protocol/v61.rb +21 -0
- data/lib/neo4j/driver/bolt/protocol_version_handler.rb +39 -0
- data/lib/neo4j/driver/bolt/record_buffer.rb +143 -0
- data/lib/neo4j/driver/bolt/stream_handler.rb +53 -0
- data/lib/neo4j/driver/bolt/tls_config.rb +129 -0
- data/lib/neo4j/driver/bolt/wire.rb +321 -0
- data/lib/neo4j/driver/bookmark.rb +15 -0
- data/lib/neo4j/driver/bookmark_managers.rb +39 -0
- data/lib/neo4j/driver/client_certificate.rb +19 -0
- data/lib/neo4j/driver/client_certificate_manager.rb +37 -0
- data/lib/neo4j/driver/client_certificate_managers.rb +15 -0
- data/lib/neo4j/driver/client_certificates.rb +14 -0
- data/lib/neo4j/driver/direct/connection_provider.rb +262 -0
- data/lib/neo4j/driver/driver.rb +268 -0
- data/lib/neo4j/driver/eager_result.rb +10 -0
- data/lib/neo4j/driver/exceptions/neo4j_exception.rb +16 -7
- data/lib/neo4j/driver/exceptions/no_such_record_exception.rb +1 -1
- data/lib/neo4j/driver/exceptions/protocol_exception.rb +0 -5
- data/lib/neo4j/driver/exceptions/security_retryable_exception.rb +14 -0
- data/lib/neo4j/driver/exceptions/transaction_terminated_exception.rb +13 -0
- data/lib/neo4j/driver/graph_database.rb +29 -0
- data/lib/neo4j/driver/internal/clock.rb +20 -0
- data/lib/neo4j/driver/internal/clock_adapter.rb +21 -0
- data/lib/neo4j/driver/internal/default_bookmark_manager.rb +54 -0
- data/lib/neo4j/driver/internal/deprecator.rb +9 -5
- data/lib/neo4j/driver/internal/driver_factory.rb +128 -0
- data/lib/neo4j/driver/internal/duration_normalizer.rb +14 -39
- data/lib/neo4j/driver/internal/extras.rb +23 -0
- data/lib/neo4j/driver/internal/home_db_cache.rb +57 -0
- data/lib/neo4j/driver/internal/internal_auth_token_manager.rb +37 -0
- data/lib/neo4j/driver/internal/metrics.rb +31 -0
- data/lib/neo4j/driver/internal/security/static_auth_token_manager.rb +25 -0
- data/lib/neo4j/driver/internal/validator.rb +16 -2
- data/lib/neo4j/driver/net.rb +29 -0
- data/lib/neo4j/driver/packstream/markers.rb +49 -0
- data/lib/neo4j/driver/packstream/packer.rb +335 -0
- data/lib/neo4j/driver/packstream/structure.rb +27 -0
- data/lib/neo4j/driver/packstream/unpacker.rb +170 -0
- data/lib/neo4j/driver/record.rb +43 -0
- data/lib/neo4j/driver/result.rb +282 -0
- data/lib/neo4j/driver/routing/load_balancer.rb +706 -0
- data/lib/neo4j/driver/routing/routed_connection.rb +132 -0
- data/lib/neo4j/driver/routing/routing_table.rb +127 -0
- data/lib/neo4j/driver/routing/server_address.rb +25 -0
- data/lib/neo4j/driver/routing_control.rb +13 -0
- data/lib/neo4j/driver/session.rb +577 -0
- data/lib/neo4j/driver/summary/database_info.rb +25 -0
- data/lib/neo4j/driver/summary/gql_notification.rb +38 -0
- data/lib/neo4j/driver/summary/gql_status_object.rb +35 -0
- data/lib/neo4j/driver/summary/notification.rb +46 -0
- data/lib/neo4j/driver/summary/plan.rb +23 -0
- data/lib/neo4j/driver/summary/profile.rb +28 -0
- data/lib/neo4j/driver/summary/query.rb +19 -0
- data/lib/neo4j/driver/summary/query_type.rb +5 -1
- data/lib/neo4j/driver/summary/result_summary.rb +215 -0
- data/lib/neo4j/driver/summary/server_info.rb +33 -0
- data/lib/neo4j/driver/summary/summary_counters.rb +72 -0
- data/lib/neo4j/driver/transaction.rb +344 -0
- data/lib/neo4j/driver/types/duration.rb +76 -0
- data/lib/neo4j/driver/types/entity.rb +40 -0
- data/lib/neo4j/driver/types/local_date_time.rb +77 -8
- data/lib/neo4j/driver/types/local_time.rb +50 -7
- data/lib/neo4j/driver/types/node.rb +18 -0
- data/lib/neo4j/driver/types/offset_time.rb +78 -7
- data/lib/neo4j/driver/types/path.rb +68 -0
- data/lib/neo4j/driver/types/point.rb +38 -18
- data/lib/neo4j/driver/types/relationship.rb +32 -0
- data/lib/neo4j/driver/types/temporal_value.rb +44 -0
- data/lib/neo4j/driver/types/unbound_relationship.rb +24 -0
- data/lib/neo4j/driver/types/unresolvable_zoned_date_time.rb +38 -0
- data/lib/neo4j/driver/types/unsupported_type.rb +25 -0
- data/lib/neo4j/driver/types/uuid.rb +29 -0
- data/{ruby → lib}/neo4j/driver/version.rb +1 -1
- data/lib/neo4j/driver.rb +15 -0
- data/lib/neo4j-ruby-driver_loader.rb +34 -20
- metadata +115 -441
- data/lib/neo4j/driver/internal/bolt_server_address.rb +0 -97
- data/lib/neo4j/driver/synchronizable.rb +0 -23
- data/lib/neo4j/driver/types/time.rb +0 -45
- data/ruby/neo4j/driver/auth_tokens.rb +0 -34
- data/ruby/neo4j/driver/bookmark.rb +0 -21
- data/ruby/neo4j/driver/config.rb +0 -89
- data/ruby/neo4j/driver/graph_database.rb +0 -78
- data/ruby/neo4j/driver/internal/async/connection/bolt_protocol_util.rb +0 -51
- data/ruby/neo4j/driver/internal/async/connection/bootstrap_factory.rb +0 -22
- data/ruby/neo4j/driver/internal/async/connection/channel_attributes.rb +0 -31
- data/ruby/neo4j/driver/internal/async/connection/channel_connected_listener.rb +0 -32
- data/ruby/neo4j/driver/internal/async/connection/channel_connector_impl.rb +0 -83
- data/ruby/neo4j/driver/internal/async/connection/channel_pipeline_builder_impl.rb +0 -22
- data/ruby/neo4j/driver/internal/async/connection/direct_connection.rb +0 -30
- data/ruby/neo4j/driver/internal/async/connection/event_loop_group_factory.rb +0 -83
- data/ruby/neo4j/driver/internal/async/connection/handshake_completed_listener.rb +0 -27
- data/ruby/neo4j/driver/internal/async/connection/handshake_handler.rb +0 -113
- data/ruby/neo4j/driver/internal/async/connection/netty_channel_initializer.rb +0 -57
- data/ruby/neo4j/driver/internal/async/connection/netty_domain_name_resolver.rb +0 -26
- data/ruby/neo4j/driver/internal/async/connection/netty_domain_name_resolver_group.rb +0 -19
- data/ruby/neo4j/driver/internal/async/connection/routing_connection.rb +0 -36
- data/ruby/neo4j/driver/internal/async/connection/stream.rb +0 -12
- data/ruby/neo4j/driver/internal/async/connection/stream_reader.rb +0 -16
- data/ruby/neo4j/driver/internal/async/connection_context.rb +0 -10
- data/ruby/neo4j/driver/internal/async/immutable_connection_context.rb +0 -24
- data/ruby/neo4j/driver/internal/async/inbound/byte_buf_input.rb +0 -30
- data/ruby/neo4j/driver/internal/async/inbound/channel_error_handler.rb +0 -77
- data/ruby/neo4j/driver/internal/async/inbound/chunk_decoder.rb +0 -41
- data/ruby/neo4j/driver/internal/async/inbound/connect_timeout_handler.rb +0 -32
- data/ruby/neo4j/driver/internal/async/inbound/connection_read_timeout_handler.rb +0 -17
- data/ruby/neo4j/driver/internal/async/inbound/inbound_message_dispatcher.rb +0 -171
- data/ruby/neo4j/driver/internal/async/inbound/inbound_message_handler.rb +0 -42
- data/ruby/neo4j/driver/internal/async/inbound/message_decoder.rb +0 -51
- data/ruby/neo4j/driver/internal/async/internal_async_session.rb +0 -92
- data/ruby/neo4j/driver/internal/async/internal_async_transaction.rb +0 -13
- data/ruby/neo4j/driver/internal/async/leak_logging_network_session.rb +0 -34
- data/ruby/neo4j/driver/internal/async/network_connection.rb +0 -194
- data/ruby/neo4j/driver/internal/async/network_session.rb +0 -150
- data/ruby/neo4j/driver/internal/async/outbound/chunk_aware_byte_buf_output.rb +0 -110
- data/ruby/neo4j/driver/internal/async/outbound/outbound_message_handler.rb +0 -39
- data/ruby/neo4j/driver/internal/async/pool/channel.rb +0 -66
- data/ruby/neo4j/driver/internal/async/pool/channel_pool.rb +0 -31
- data/ruby/neo4j/driver/internal/async/pool/channel_tracker.rb +0 -135
- data/ruby/neo4j/driver/internal/async/pool/connection_pool_impl.rb +0 -156
- data/ruby/neo4j/driver/internal/async/pool/netty_channel_health_checker.rb +0 -87
- data/ruby/neo4j/driver/internal/async/pool/netty_channel_pool.rb +0 -52
- data/ruby/neo4j/driver/internal/async/pool/network_connection_factory.rb +0 -21
- data/ruby/neo4j/driver/internal/async/pool/pool_settings.rb +0 -34
- data/ruby/neo4j/driver/internal/async/pool/timed_stack.rb +0 -15
- data/ruby/neo4j/driver/internal/async/result_cursors_holder.rb +0 -17
- data/ruby/neo4j/driver/internal/async/unmanaged_transaction.rb +0 -212
- data/ruby/neo4j/driver/internal/bookmark_holder.rb +0 -9
- data/ruby/neo4j/driver/internal/cluster/cluster_composition.rb +0 -48
- data/ruby/neo4j/driver/internal/cluster/cluster_composition_lookup_result.rb +0 -14
- data/ruby/neo4j/driver/internal/cluster/cluster_routing_table.rb +0 -122
- data/ruby/neo4j/driver/internal/cluster/identity_resolver.rb +0 -10
- data/ruby/neo4j/driver/internal/cluster/loadbalancing/least_connected_load_balancing_strategy.rb +0 -68
- data/ruby/neo4j/driver/internal/cluster/loadbalancing/load_balancer.rb +0 -125
- data/ruby/neo4j/driver/internal/cluster/loadbalancing/round_robin_array_index.rb +0 -13
- data/ruby/neo4j/driver/internal/cluster/multi_databases_routing_procedure_runner.rb +0 -31
- data/ruby/neo4j/driver/internal/cluster/rediscovery_impl.rb +0 -147
- data/ruby/neo4j/driver/internal/cluster/route_message_routing_procedure_runner.rb +0 -43
- data/ruby/neo4j/driver/internal/cluster/routing_context.rb +0 -77
- data/ruby/neo4j/driver/internal/cluster/routing_procedure_cluster_composition_provider.rb +0 -60
- data/ruby/neo4j/driver/internal/cluster/routing_procedure_response.rb +0 -35
- data/ruby/neo4j/driver/internal/cluster/routing_settings.rb +0 -24
- data/ruby/neo4j/driver/internal/cluster/routing_table_handler_impl.rb +0 -95
- data/ruby/neo4j/driver/internal/cluster/routing_table_registry_impl.rb +0 -121
- data/ruby/neo4j/driver/internal/cluster/single_database_routing_procedure_runner.rb +0 -73
- data/ruby/neo4j/driver/internal/connection_settings.rb +0 -16
- data/ruby/neo4j/driver/internal/cursor/async_result_cursor_impl.rb +0 -55
- data/ruby/neo4j/driver/internal/cursor/async_result_cursor_only_factory.rb +0 -24
- data/ruby/neo4j/driver/internal/cursor/disposable_async_result_cursor.rb +0 -61
- data/ruby/neo4j/driver/internal/cursor/result_cursor_factory_impl.rb +0 -24
- data/ruby/neo4j/driver/internal/cursor/rx_result_cursor_impl.rb +0 -110
- data/ruby/neo4j/driver/internal/database_name_util.rb +0 -37
- data/ruby/neo4j/driver/internal/default_bookmark_holder.rb +0 -9
- data/ruby/neo4j/driver/internal/default_domain_name_resolver.rb +0 -11
- data/ruby/neo4j/driver/internal/direct_connection_provider.rb +0 -40
- data/ruby/neo4j/driver/internal/driver_factory.rb +0 -126
- data/ruby/neo4j/driver/internal/eager_result_value.rb +0 -5
- data/ruby/neo4j/driver/internal/handlers/begin_tx_response_handler.rb +0 -20
- data/ruby/neo4j/driver/internal/handlers/channel_releasing_reset_response_handler.rb +0 -30
- data/ruby/neo4j/driver/internal/handlers/commit_tx_response_handler.rb +0 -23
- data/ruby/neo4j/driver/internal/handlers/hello_response_handler.rb +0 -65
- data/ruby/neo4j/driver/internal/handlers/init_response_handler.rb +0 -34
- data/ruby/neo4j/driver/internal/handlers/legacy_pull_all_response_handler.rb +0 -199
- data/ruby/neo4j/driver/internal/handlers/no_op_response_handler.rb +0 -16
- data/ruby/neo4j/driver/internal/handlers/ping_response_handler.rb +0 -29
- data/ruby/neo4j/driver/internal/handlers/pull_handlers.rb +0 -32
- data/ruby/neo4j/driver/internal/handlers/pulln/auto_pull_response_handler.rb +0 -169
- data/ruby/neo4j/driver/internal/handlers/pulln/basic_pull_response_handler.rb +0 -298
- data/ruby/neo4j/driver/internal/handlers/pulln/fetch_size_util.rb +0 -20
- data/ruby/neo4j/driver/internal/handlers/reset_response_handler.rb +0 -34
- data/ruby/neo4j/driver/internal/handlers/rollback_tx_response_handler.rb +0 -25
- data/ruby/neo4j/driver/internal/handlers/route_message_response_handler.rb +0 -21
- data/ruby/neo4j/driver/internal/handlers/routing_response_handler.rb +0 -79
- data/ruby/neo4j/driver/internal/handlers/run_response_handler.rb +0 -38
- data/ruby/neo4j/driver/internal/handlers/session_pull_response_completion_listener.rb +0 -34
- data/ruby/neo4j/driver/internal/handlers/transaction_pull_response_completion_listener.rb +0 -20
- data/ruby/neo4j/driver/internal/impersonation_util.rb +0 -22
- data/ruby/neo4j/driver/internal/internal_bookmark.rb +0 -9
- data/ruby/neo4j/driver/internal/internal_database_name.rb +0 -9
- data/ruby/neo4j/driver/internal/internal_driver.rb +0 -83
- data/ruby/neo4j/driver/internal/internal_entity.rb +0 -21
- data/ruby/neo4j/driver/internal/internal_node.rb +0 -21
- data/ruby/neo4j/driver/internal/internal_pair.rb +0 -9
- data/ruby/neo4j/driver/internal/internal_path.rb +0 -35
- data/ruby/neo4j/driver/internal/internal_point2_d.rb +0 -9
- data/ruby/neo4j/driver/internal/internal_point3_d.rb +0 -6
- data/ruby/neo4j/driver/internal/internal_record.rb +0 -27
- data/ruby/neo4j/driver/internal/internal_relationship.rb +0 -27
- data/ruby/neo4j/driver/internal/internal_result.rb +0 -49
- data/ruby/neo4j/driver/internal/internal_session.rb +0 -91
- data/ruby/neo4j/driver/internal/internal_transaction.rb +0 -48
- data/ruby/neo4j/driver/internal/logging/channel_activity_logger.rb +0 -29
- data/ruby/neo4j/driver/internal/logging/channel_error_logger.rb +0 -17
- data/ruby/neo4j/driver/internal/logging/prefixed_logger.rb +0 -19
- data/ruby/neo4j/driver/internal/logging/reformatted_logger.rb +0 -17
- data/ruby/neo4j/driver/internal/messaging/abstract_message_writer.rb +0 -23
- data/ruby/neo4j/driver/internal/messaging/bolt_protocol.rb +0 -32
- data/ruby/neo4j/driver/internal/messaging/bolt_protocol_version.rb +0 -48
- data/ruby/neo4j/driver/internal/messaging/common/common_message_reader.rb +0 -51
- data/ruby/neo4j/driver/internal/messaging/common/common_value.rb +0 -33
- data/ruby/neo4j/driver/internal/messaging/common/common_value_packer.rb +0 -104
- data/ruby/neo4j/driver/internal/messaging/common/common_value_unpacker.rb +0 -256
- data/ruby/neo4j/driver/internal/messaging/encode/begin_message_encoder.rb +0 -15
- data/ruby/neo4j/driver/internal/messaging/encode/commit_message_encoder.rb +0 -14
- data/ruby/neo4j/driver/internal/messaging/encode/discard_all_message_encoder.rb +0 -14
- data/ruby/neo4j/driver/internal/messaging/encode/discard_message_encoder.rb +0 -15
- data/ruby/neo4j/driver/internal/messaging/encode/goodbye_message_encoder.rb +0 -14
- data/ruby/neo4j/driver/internal/messaging/encode/hello_message_encoder.rb +0 -15
- data/ruby/neo4j/driver/internal/messaging/encode/init_message_encoder.rb +0 -16
- data/ruby/neo4j/driver/internal/messaging/encode/logoff_message_encoder.rb +0 -14
- data/ruby/neo4j/driver/internal/messaging/encode/logon_message_encoder.rb +0 -15
- data/ruby/neo4j/driver/internal/messaging/encode/pull_all_message_encoder.rb +0 -14
- data/ruby/neo4j/driver/internal/messaging/encode/pull_message_encoder.rb +0 -15
- data/ruby/neo4j/driver/internal/messaging/encode/reset_message_encoder.rb +0 -14
- data/ruby/neo4j/driver/internal/messaging/encode/rollback_message_encoder.rb +0 -14
- data/ruby/neo4j/driver/internal/messaging/encode/route_message_encoder.rb +0 -24
- data/ruby/neo4j/driver/internal/messaging/encode/route_v44_message_encoder.rb +0 -22
- data/ruby/neo4j/driver/internal/messaging/encode/run_message_encoder.rb +0 -16
- data/ruby/neo4j/driver/internal/messaging/encode/run_with_metadata_message_encoder.rb +0 -17
- data/ruby/neo4j/driver/internal/messaging/request/abstract_streaming_message.rb +0 -25
- data/ruby/neo4j/driver/internal/messaging/request/begin_message.rb +0 -25
- data/ruby/neo4j/driver/internal/messaging/request/commit_message.rb +0 -20
- data/ruby/neo4j/driver/internal/messaging/request/discard_all_message.rb +0 -20
- data/ruby/neo4j/driver/internal/messaging/request/discard_message.rb +0 -23
- data/ruby/neo4j/driver/internal/messaging/request/goodbye_message.rb +0 -20
- data/ruby/neo4j/driver/internal/messaging/request/hello_message.rb +0 -30
- data/ruby/neo4j/driver/internal/messaging/request/init_message.rb +0 -19
- data/ruby/neo4j/driver/internal/messaging/request/logoff_message.rb +0 -13
- data/ruby/neo4j/driver/internal/messaging/request/logon_message.rb +0 -13
- data/ruby/neo4j/driver/internal/messaging/request/message_with_metadata.rb +0 -17
- data/ruby/neo4j/driver/internal/messaging/request/multi_database_util.rb +0 -26
- data/ruby/neo4j/driver/internal/messaging/request/pull_all_message.rb +0 -23
- data/ruby/neo4j/driver/internal/messaging/request/pull_message.rb +0 -22
- data/ruby/neo4j/driver/internal/messaging/request/reset_message.rb +0 -32
- data/ruby/neo4j/driver/internal/messaging/request/rollback_message.rb +0 -20
- data/ruby/neo4j/driver/internal/messaging/request/route_message.rb +0 -28
- data/ruby/neo4j/driver/internal/messaging/request/run_message.rb +0 -23
- data/ruby/neo4j/driver/internal/messaging/request/run_with_metadata_message.rb +0 -49
- data/ruby/neo4j/driver/internal/messaging/request/transaction_metadata_builder.rb +0 -24
- data/ruby/neo4j/driver/internal/messaging/response/failure_message.rb +0 -40
- data/ruby/neo4j/driver/internal/messaging/response/ignored_message.rb +0 -29
- data/ruby/neo4j/driver/internal/messaging/response/record_message.rb +0 -33
- data/ruby/neo4j/driver/internal/messaging/response/success_message.rb +0 -34
- data/ruby/neo4j/driver/internal/messaging/v3/bolt_protocol_v3.rb +0 -82
- data/ruby/neo4j/driver/internal/messaging/v3/message_format_v3.rb +0 -17
- data/ruby/neo4j/driver/internal/messaging/v3/message_writer_v3.rb +0 -27
- data/ruby/neo4j/driver/internal/messaging/v4/bolt_protocol_v4.rb +0 -29
- data/ruby/neo4j/driver/internal/messaging/v4/message_format_v4.rb +0 -13
- data/ruby/neo4j/driver/internal/messaging/v4/message_writer_v4.rb +0 -17
- data/ruby/neo4j/driver/internal/messaging/v41/bolt_protocol_v41.rb +0 -25
- data/ruby/neo4j/driver/internal/messaging/v42/bolt_protocol_v42.rb +0 -13
- data/ruby/neo4j/driver/internal/messaging/v43/bolt_protocol_v43.rb +0 -19
- data/ruby/neo4j/driver/internal/messaging/v43/message_format_v43.rb +0 -14
- data/ruby/neo4j/driver/internal/messaging/v43/message_writer_v43.rb +0 -20
- data/ruby/neo4j/driver/internal/messaging/v44/bolt_protocol_v44.rb +0 -17
- data/ruby/neo4j/driver/internal/messaging/v44/message_format_v44.rb +0 -14
- data/ruby/neo4j/driver/internal/messaging/v44/message_writer_v44.rb +0 -15
- data/ruby/neo4j/driver/internal/messaging/v5/bolt_protocol_v5.rb +0 -21
- data/ruby/neo4j/driver/internal/messaging/v5/message_format_v5.rb +0 -18
- data/ruby/neo4j/driver/internal/messaging/v5/value_unpacker_v5.rb +0 -17
- data/ruby/neo4j/driver/internal/messaging/v51/bolt_protocol_v51.rb +0 -40
- data/ruby/neo4j/driver/internal/messaging/v51/message_format_v51.rb +0 -14
- data/ruby/neo4j/driver/internal/messaging/v51/message_writer_v51.rb +0 -17
- data/ruby/neo4j/driver/internal/metrics/connection_pool_metrics_listener.rb +0 -34
- data/ruby/neo4j/driver/internal/metrics/internal_abstract_metrics.rb +0 -46
- data/ruby/neo4j/driver/internal/metrics/internal_connection_pool_metrics.rb +0 -105
- data/ruby/neo4j/driver/internal/metrics/internal_metrics.rb +0 -82
- data/ruby/neo4j/driver/internal/metrics/internal_metrics_provider.rb +0 -18
- data/ruby/neo4j/driver/internal/metrics/listener_event.rb +0 -17
- data/ruby/neo4j/driver/internal/metrics/metrics_provider.rb +0 -24
- data/ruby/neo4j/driver/internal/metrics/time_recorder_listener_event.rb +0 -15
- data/ruby/neo4j/driver/internal/packstream/byte_array_incompatible_packer.rb +0 -12
- data/ruby/neo4j/driver/internal/packstream/pack_input.rb +0 -47
- data/ruby/neo4j/driver/internal/packstream/pack_output.rb +0 -39
- data/ruby/neo4j/driver/internal/packstream/pack_stream.rb +0 -324
- data/ruby/neo4j/driver/internal/packstream/pack_type.rb +0 -17
- data/ruby/neo4j/driver/internal/read_only_bookmark_holder.rb +0 -13
- data/ruby/neo4j/driver/internal/resolved_bolt_server_address.rb +0 -35
- data/ruby/neo4j/driver/internal/retry/exponential_backoff_retry_logic.rb +0 -150
- data/ruby/neo4j/driver/internal/revocation_strategy.rb +0 -19
- data/ruby/neo4j/driver/internal/scheme.rb +0 -32
- data/ruby/neo4j/driver/internal/security/internal_auth_token.rb +0 -15
- data/ruby/neo4j/driver/internal/security/security_plan_impl.rb +0 -48
- data/ruby/neo4j/driver/internal/security_setting.rb +0 -66
- data/ruby/neo4j/driver/internal/session_factory_impl.rb +0 -32
- data/ruby/neo4j/driver/internal/spi/connection.rb +0 -19
- data/ruby/neo4j/driver/internal/spi/connection_pool.rb +0 -9
- data/ruby/neo4j/driver/internal/spi/response_handler.rb +0 -23
- data/ruby/neo4j/driver/internal/summary/internal_database_info.rb +0 -7
- data/ruby/neo4j/driver/internal/summary/internal_input_position.rb +0 -11
- data/ruby/neo4j/driver/internal/summary/internal_notification.rb +0 -16
- data/ruby/neo4j/driver/internal/summary/internal_plan.rb +0 -41
- data/ruby/neo4j/driver/internal/summary/internal_profiled_plan.rb +0 -32
- data/ruby/neo4j/driver/internal/summary/internal_result_summary.rb +0 -33
- data/ruby/neo4j/driver/internal/summary/internal_server_info.rb +0 -6
- data/ruby/neo4j/driver/internal/summary/internal_summary_counters.rb +0 -18
- data/ruby/neo4j/driver/internal/svm/netty_substitutions.rb +0 -196
- data/ruby/neo4j/driver/internal/svm/z_lib_substitutions.rb +0 -21
- data/ruby/neo4j/driver/internal/util/certificate_tool.rb +0 -65
- data/ruby/neo4j/driver/internal/util/clock.rb +0 -29
- data/ruby/neo4j/driver/internal/util/error_util.rb +0 -104
- data/ruby/neo4j/driver/internal/util/extract.rb +0 -123
- data/ruby/neo4j/driver/internal/util/format.rb +0 -39
- data/ruby/neo4j/driver/internal/util/futures.rb +0 -99
- data/ruby/neo4j/driver/internal/util/iterables.rb +0 -35
- data/ruby/neo4j/driver/internal/util/lock_util.rb +0 -23
- data/ruby/neo4j/driver/internal/util/metadata_extractor.rb +0 -101
- data/ruby/neo4j/driver/internal/util/mutex.rb +0 -9
- data/ruby/neo4j/driver/internal/util/preconditions.rb +0 -16
- data/ruby/neo4j/driver/internal/util/result_holder.rb +0 -72
- data/ruby/neo4j/driver/internal/util/server_version.rb +0 -60
- data/ruby/neo4j/driver/logging1.rb +0 -51
- data/ruby/neo4j/driver/net/server_address.rb +0 -9
- data/ruby/neo4j/driver/query.rb +0 -48
- data/ruby/neo4j/driver/records.rb +0 -13
- data/ruby/neo4j/driver/transaction_config.rb +0 -50
- data/ruby/neo4j/driver/values.rb +0 -26
- data/ruby/neo4j/driver.rb +0 -30
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Neo4j
|
|
4
|
+
module Driver
|
|
5
|
+
module Direct
|
|
6
|
+
# Single-server connection provider for `bolt://` URIs.
|
|
7
|
+
#
|
|
8
|
+
# Sibling of Routing::LoadBalancer — both implement the same interface
|
|
9
|
+
# (acquire / release / verify_connectivity / supports_multi_db? / close)
|
|
10
|
+
# so Driver can hold either polymorphically without branching on scheme.
|
|
11
|
+
#
|
|
12
|
+
# Direct ignores the `access_mode`, `database`, and `bookmarks`
|
|
13
|
+
# kwargs to acquire: all sessions hit the same server, so
|
|
14
|
+
# role/database/bookmark-aware routing is not its concern. The
|
|
15
|
+
# kwargs are accepted so call sites stay polymorphic with
|
|
16
|
+
# Routing::LoadBalancer.
|
|
17
|
+
class ConnectionProvider
|
|
18
|
+
# `domain_name_resolver` is the factory-injected hostname->IPs hook
|
|
19
|
+
# (nil = system DNS); baked into every connection this provider builds.
|
|
20
|
+
def initialize(uri, auth_manager, options = {}, domain_name_resolver: nil, clock: Internal::Clock.new)
|
|
21
|
+
@uri = uri
|
|
22
|
+
@auth_manager = auth_manager
|
|
23
|
+
@options = options
|
|
24
|
+
@clock = clock
|
|
25
|
+
@domain_name_resolver = domain_name_resolver
|
|
26
|
+
# Authorization-expired generation counter (see Connection#auth_epoch).
|
|
27
|
+
# Bumped when any connection reports AuthorizationExpired so every
|
|
28
|
+
# other pooled connection re-authenticates on its next acquire.
|
|
29
|
+
# Guarded by a mutex: the pool is shared across threads and on JRuby
|
|
30
|
+
# (mri-on-jruby) there's no GIL, so a bare `+= 1` could lose bumps.
|
|
31
|
+
@auth_epoch = 0
|
|
32
|
+
@auth_epoch_mutex = Mutex.new
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Current auth generation, read atomically.
|
|
36
|
+
def auth_epoch = @auth_epoch_mutex.synchronize { @auth_epoch }
|
|
37
|
+
|
|
38
|
+
# No home-database resolution on the direct path: a bolt:// driver
|
|
39
|
+
# talks to one server, which resolves the user's home database itself
|
|
40
|
+
# when the operation omits `db`. Returns nil so the session leaves it
|
|
41
|
+
# unset (matches Java's DirectConnectionProvider).
|
|
42
|
+
def home_database(_bookmarks, _imp_user = nil, _auth = nil) = nil
|
|
43
|
+
|
|
44
|
+
# No home-db cache on the direct path (one server, no discovery to skip):
|
|
45
|
+
# never guess, never track SSR. Keeps Session polymorphic across providers.
|
|
46
|
+
def ssr_enabled? = false
|
|
47
|
+
def home_db_guess(_imp_user, _auth) = nil
|
|
48
|
+
def cache_home_db(_imp_user, _auth, _database) = nil
|
|
49
|
+
|
|
50
|
+
# The current default identity, sourced from the auth-token
|
|
51
|
+
# manager (which refreshes / re-fetches as needed). Sessions
|
|
52
|
+
# re-auth pooled connections to this on acquire unless they carry
|
|
53
|
+
# their own per-session :auth_token.
|
|
54
|
+
def current_auth_token = @auth_manager.get_token
|
|
55
|
+
|
|
56
|
+
# Feed a security failure back to the manager. Returns true when
|
|
57
|
+
# the manager considers it retryable (token refreshed), so the
|
|
58
|
+
# caller can re-auth and retry. An AuthorizationExpired failure also
|
|
59
|
+
# bumps the auth epoch: the server dropped its authorization cache
|
|
60
|
+
# for this identity, so every pooled connection must re-authenticate
|
|
61
|
+
# (with whatever token is current) before its next use.
|
|
62
|
+
def on_security_exception(token, error, session_scoped = false)
|
|
63
|
+
# Provider-side invalidation happens regardless of who owns the token.
|
|
64
|
+
@auth_epoch_mutex.synchronize { @auth_epoch += 1 } if error.is_a?(Exceptions::AuthorizationExpiredException)
|
|
65
|
+
# A per-session token wasn't issued by the manager — don't notify it
|
|
66
|
+
# (testkit: handle_security_exception_count stays 0), and don't treat
|
|
67
|
+
# the failure as manager-retryable.
|
|
68
|
+
return false if session_scoped
|
|
69
|
+
|
|
70
|
+
@auth_manager.handle_security_exception(token, error)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# imp_user is accepted for signature parity with
|
|
74
|
+
# Routing::LoadBalancer#acquire but unused here: the direct path
|
|
75
|
+
# has no discovery, so impersonation is enforced on RUN/BEGIN by
|
|
76
|
+
# the protocol handler (Bolt::Protocol::Base#enforce_impersonation_support!).
|
|
77
|
+
def acquire(access_mode: nil, database: nil, bookmarks: nil, imp_user: nil, auth: nil, deadline: nil)
|
|
78
|
+
# See Routing::LoadBalancer#acquire for the rationale.
|
|
79
|
+
raise Exceptions::IllegalStateException, 'Driver is closed' if @closed
|
|
80
|
+
|
|
81
|
+
# `auth` is the per-session override (nil = use the manager's
|
|
82
|
+
# current token). `effective` is the identity this acquire should
|
|
83
|
+
# hand out; resolving it consults the manager (get_auth_count == 1
|
|
84
|
+
# for the default identity, 0 when the session carries its own
|
|
85
|
+
# token). A freshly-built connection authenticates with it directly
|
|
86
|
+
# (no LOGOFF/LOGON); a reused one is re-authed to it via
|
|
87
|
+
# ensure_identity on Bolt 5.1+.
|
|
88
|
+
#
|
|
89
|
+
# On Bolt 5.0 there is no in-place re-auth, so a *reused* connection
|
|
90
|
+
# keeps its creation-time identity. If the manager has since rotated
|
|
91
|
+
# its token, that connection is stale — discard it and loop, letting
|
|
92
|
+
# the pool build a fresh one authenticated as the current identity
|
|
93
|
+
# (Java's backwards-compatible behaviour). Re-resolving `effective`
|
|
94
|
+
# each turn means the replacement issues its own get_token, as the
|
|
95
|
+
# managed-auth contract expects (one extra get_auth per rotation).
|
|
96
|
+
loop do
|
|
97
|
+
# Snapshot the epoch once per turn so the staleness check and the
|
|
98
|
+
# connection's stamp (in ensure_identity) use one consistent value.
|
|
99
|
+
epoch = auth_epoch
|
|
100
|
+
effective = auth || @auth_manager.get_token
|
|
101
|
+
conn = pool.pop(auth: effective, deadline: deadline)
|
|
102
|
+
begin
|
|
103
|
+
ensure_identity(conn, effective, session_auth: auth, epoch: epoch)
|
|
104
|
+
rescue StandardError
|
|
105
|
+
# Identity enforcement can raise (per-session auth on Bolt < 5.1,
|
|
106
|
+
# or a re-auth LOGON failure). Free the just-checked-out slot
|
|
107
|
+
# instead of leaking it for the driver's lifetime, then re-raise.
|
|
108
|
+
pool.discard(conn)
|
|
109
|
+
raise
|
|
110
|
+
end
|
|
111
|
+
# On Bolt 5.1+ ensure_identity already brought the connection to
|
|
112
|
+
# the right identity (and re-auth generation). On 5.0 it can't, so
|
|
113
|
+
# a reused connection is only usable if its token AND auth epoch
|
|
114
|
+
# already match — otherwise discard and let the pool rebuild a
|
|
115
|
+
# fresh one (token rotation, or an AuthorizationExpired refresh).
|
|
116
|
+
return conn if conn.protocol.supports_re_auth? ||
|
|
117
|
+
(conn.auth == effective && conn.auth_epoch == epoch)
|
|
118
|
+
|
|
119
|
+
pool.discard(conn)
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def release(connection)
|
|
124
|
+
return unless connection
|
|
125
|
+
|
|
126
|
+
# Honor a connection flagged for discard (e.g. after an auth
|
|
127
|
+
# failure) — close it and free the slot rather than pooling a
|
|
128
|
+
# compromised / server-closed connection.
|
|
129
|
+
if connection.discard_on_release
|
|
130
|
+
pool.discard(connection)
|
|
131
|
+
else
|
|
132
|
+
pool.push(connection)
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def verify_connectivity
|
|
137
|
+
# Probe the connection with a RESET so a reused (pooled) connection
|
|
138
|
+
# is actually exercised on the wire — matches Java's
|
|
139
|
+
# verifyConnectivity and the routing LoadBalancer, and testkit's
|
|
140
|
+
# test_direct_from_pool (which asserts one RESET on the pooled
|
|
141
|
+
# connection). `propagate: true` surfaces a failed probe (rather than
|
|
142
|
+
# reporting false success); a failed probe means a dead connection,
|
|
143
|
+
# so discard it instead of returning it to the pool.
|
|
144
|
+
conn = acquire
|
|
145
|
+
begin
|
|
146
|
+
conn.reset!(propagate: true)
|
|
147
|
+
rescue StandardError
|
|
148
|
+
pool.discard(conn)
|
|
149
|
+
raise
|
|
150
|
+
end
|
|
151
|
+
release(conn)
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# Single-address pool snapshot (driver.metrics). Empty until the pool
|
|
155
|
+
# has been lazily built by the first acquire.
|
|
156
|
+
def connection_pool_metrics
|
|
157
|
+
return [] unless @pool
|
|
158
|
+
|
|
159
|
+
address = Routing::ServerAddress.new(host: @uri.host,
|
|
160
|
+
port: @uri.port || Routing::ServerAddress::DEFAULT_PORT)
|
|
161
|
+
in_use, idle = @pool.metrics_snapshot
|
|
162
|
+
[Internal::Metrics::ConnectionPoolMetrics.new(address, in_use, idle)]
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# True iff the negotiated Bolt protocol supports multi-database
|
|
166
|
+
# routing (Bolt 4.0+). Acquires a connection to ensure HELLO has
|
|
167
|
+
# happened.
|
|
168
|
+
def supports_multi_db?
|
|
169
|
+
conn = acquire
|
|
170
|
+
conn.protocol.supports_multiple_databases?
|
|
171
|
+
ensure
|
|
172
|
+
release(conn)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# Mirrors Java: a Direct (bolt://) driver has no routing-table
|
|
176
|
+
# registry. testkit's GetRoutingTable / ForcedRoutingTableUpdate
|
|
177
|
+
# handlers expect a clean error here rather than NoMethodError
|
|
178
|
+
# so callers can distinguish "wrong scheme" from a real bug.
|
|
179
|
+
def routing_table_registry
|
|
180
|
+
raise Exceptions::ClientException,
|
|
181
|
+
'Routing table is only available on routing (neo4j://) drivers'
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
def close
|
|
185
|
+
@closed = true
|
|
186
|
+
@pool&.shutdown do |conn|
|
|
187
|
+
conn.close
|
|
188
|
+
rescue StandardError
|
|
189
|
+
nil
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
private
|
|
194
|
+
|
|
195
|
+
# Bring a popped connection to the `effective` identity. A fresh
|
|
196
|
+
# connection was built with it, so authenticate is a no-op; a reused
|
|
197
|
+
# one currently authenticated as somebody else is re-authed (LOGOFF/
|
|
198
|
+
# LOGON, Bolt 5.1+).
|
|
199
|
+
#
|
|
200
|
+
# When `session_auth` is set (per-session token), the identity must
|
|
201
|
+
# be enforceable, so we require Bolt 5.1+ even if the popped
|
|
202
|
+
# connection already happens to hold the token — a 5.0 connection
|
|
203
|
+
# built with the session token would otherwise silently bypass the
|
|
204
|
+
# "per-session auth needs re-auth support" contract. With the default
|
|
205
|
+
# identity, re-auth is applied only where it exists (5.1+); on 5.0 a
|
|
206
|
+
# pooled connection keeps its creation-time token and the manager's
|
|
207
|
+
# refresh reaches new connections instead.
|
|
208
|
+
def ensure_identity(conn, effective, session_auth:, epoch: auth_epoch)
|
|
209
|
+
# Record whose identity this connection currently holds so a later
|
|
210
|
+
# security failure knows whether to notify the manager. Updated
|
|
211
|
+
# every acquire because a pooled connection changes lessee.
|
|
212
|
+
conn.session_scoped_auth = !session_auth.nil?
|
|
213
|
+
# Force a re-auth (even to the same token) when this connection was
|
|
214
|
+
# authed before the latest AuthorizationExpired — the server needs
|
|
215
|
+
# a fresh LOGON to rebuild its authorization cache.
|
|
216
|
+
force = conn.auth_epoch < epoch
|
|
217
|
+
if session_auth
|
|
218
|
+
unless conn.protocol.supports_re_auth?
|
|
219
|
+
raise Exceptions::UnsupportedFeatureException,
|
|
220
|
+
"Per-session auth requires Bolt 5.1+; negotiated #{conn.protocol.version}"
|
|
221
|
+
end
|
|
222
|
+
conn.authenticate(effective, force: force)
|
|
223
|
+
conn.auth_epoch = epoch
|
|
224
|
+
elsif conn.protocol.supports_re_auth?
|
|
225
|
+
conn.authenticate(effective, force: force)
|
|
226
|
+
conn.auth_epoch = epoch
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
# Bolt::Pool wraps connection_pool's TimedStack primitive
|
|
231
|
+
# and adds the lifetime / liveness / acquisition-timeout gates
|
|
232
|
+
# (see Bolt::Pool docstring). TimedStack is used because, unlike
|
|
233
|
+
# ConnectionPool#checkout, it does NOT cache per-thread — each
|
|
234
|
+
# Session in the same thread must hold its own connection
|
|
235
|
+
# (they can't share server-side transaction state).
|
|
236
|
+
def pool
|
|
237
|
+
@pool ||= Bolt::Pool.new(
|
|
238
|
+
size: max_pool_size,
|
|
239
|
+
options: @options,
|
|
240
|
+
clock: @clock,
|
|
241
|
+
connect_factory: lambda { |auth, deadline = nil|
|
|
242
|
+
# `auth` is the per-acquire identity resolved in #acquire and
|
|
243
|
+
# threaded through pool.pop. The `||` is a belt-and-braces
|
|
244
|
+
# fallback for any future pop path that forgets to pass one.
|
|
245
|
+
conn = Bolt::Connection.new(@uri, auth || @auth_manager.get_token, @options,
|
|
246
|
+
domain_name_resolver: @domain_name_resolver, clock: @clock).connect(deadline: deadline)
|
|
247
|
+
conn.security_exception_handler = method(:on_security_exception)
|
|
248
|
+
# A freshly-authenticated connection belongs to the current
|
|
249
|
+
# auth generation, so ensure_identity won't force-re-auth it.
|
|
250
|
+
conn.auth_epoch = auth_epoch
|
|
251
|
+
conn
|
|
252
|
+
}
|
|
253
|
+
)
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
def max_pool_size
|
|
257
|
+
@options[:max_connection_pool_size] || Driver::DEFAULT_MAX_POOL_SIZE
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
end
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Neo4j
|
|
4
|
+
module Driver
|
|
5
|
+
# Driver for connecting to Neo4j.
|
|
6
|
+
#
|
|
7
|
+
# Holds a single ConnectionProvider (Direct for `bolt://`, Routing for
|
|
8
|
+
# `neo4j://`) chosen at construction. All connection work delegates to
|
|
9
|
+
# the provider — no scheme branching here.
|
|
10
|
+
class Driver
|
|
11
|
+
DEFAULT_MAX_POOL_SIZE = 100
|
|
12
|
+
DEFAULT_ACQUISITION_TIMEOUT = 60
|
|
13
|
+
|
|
14
|
+
# URI schemes that imply transport encryption.
|
|
15
|
+
ENCRYPTED_SCHEMES = %w[bolt+s bolt+ssc neo4j+s neo4j+ssc].freeze
|
|
16
|
+
|
|
17
|
+
# The ConnectionProvider is assembled by the DriverFactory (which wires
|
|
18
|
+
# in non-public hooks like the domain-name resolver), so the Driver
|
|
19
|
+
# itself never sees those extension points — it just uses the provider.
|
|
20
|
+
def initialize(uri, options, connection_provider, clock: Internal::Clock.new)
|
|
21
|
+
@uri = URI(uri)
|
|
22
|
+
@options = options
|
|
23
|
+
@clock = clock
|
|
24
|
+
@closed = false
|
|
25
|
+
@connection_provider = connection_provider
|
|
26
|
+
# Driver-wide default BookmarkManager for execute_query: shared across
|
|
27
|
+
# calls so they're causally chained (a read after a write sees it).
|
|
28
|
+
# Built once here rather than lazily so concurrent first calls can't
|
|
29
|
+
# race into two managers. Mirrors Java's default query bookmark manager.
|
|
30
|
+
@query_bookmark_manager = BookmarkManagers.default_manager
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def session(**options)
|
|
34
|
+
raise Exceptions::ClientException, 'Driver is closed' if @closed
|
|
35
|
+
|
|
36
|
+
merged_options = @options.merge(options)
|
|
37
|
+
# A nil session fetch_size means "inherit the driver default", so it
|
|
38
|
+
# must not clobber a driver-level value the plain merge just overwrote
|
|
39
|
+
# (callers — the testkit backend included — may pass fetch_size: nil
|
|
40
|
+
# when the session didn't set one). Mirrors Java's SessionConfig
|
|
41
|
+
# falling back to Config#fetchSize.
|
|
42
|
+
merged_options[:fetch_size] ||= @options[:fetch_size]
|
|
43
|
+
session = Session.new(@connection_provider, merged_options, clock: @clock)
|
|
44
|
+
|
|
45
|
+
return session unless block_given?
|
|
46
|
+
|
|
47
|
+
begin
|
|
48
|
+
result = yield session
|
|
49
|
+
rescue StandardError => e
|
|
50
|
+
# Block raised; preserve as primary, attach close-time failures
|
|
51
|
+
# as suppressed (Java try-with-resources semantics).
|
|
52
|
+
begin
|
|
53
|
+
session.close
|
|
54
|
+
rescue Exceptions::Neo4jException => close_error
|
|
55
|
+
e.add_suppressed(close_error) if e.respond_to?(:add_suppressed)
|
|
56
|
+
end
|
|
57
|
+
raise
|
|
58
|
+
else
|
|
59
|
+
# Block exited cleanly. Any close-time error here comes from
|
|
60
|
+
# draining a result the user never iterated — Java semantics
|
|
61
|
+
# treat that as cancellation, not a real failure.
|
|
62
|
+
begin
|
|
63
|
+
session.close
|
|
64
|
+
rescue Exceptions::Neo4jException
|
|
65
|
+
end
|
|
66
|
+
result
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def close
|
|
71
|
+
return if @closed
|
|
72
|
+
|
|
73
|
+
@closed = true
|
|
74
|
+
@connection_provider.close
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def verify_connectivity
|
|
78
|
+
@connection_provider.verify_connectivity
|
|
79
|
+
rescue Exceptions::Neo4jException
|
|
80
|
+
# Propagate driver exceptions (auth/security/client/service-
|
|
81
|
+
# unavailable) as-is, like Java — wrapping them would hide the
|
|
82
|
+
# type and message callers assert on. Only unexpected non-driver
|
|
83
|
+
# errors get the contextual wrapper.
|
|
84
|
+
raise
|
|
85
|
+
rescue StandardError => e
|
|
86
|
+
raise Exceptions::ServiceUnavailableException, "Failed to verify connectivity: #{e.message}"
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def supports_multi_db?
|
|
90
|
+
@connection_provider.supports_multi_db?
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def closed?
|
|
94
|
+
@closed
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# True iff the driver was constructed to enforce transport encryption
|
|
98
|
+
# — either via a +s/+ssc URI scheme or an explicit `encryption: true`
|
|
99
|
+
# option. Mirrors Java's Driver.isEncrypted().
|
|
100
|
+
def encrypted?
|
|
101
|
+
ENCRYPTED_SCHEMES.include?(@uri.scheme) || @options[:encryption] == true
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Whether the connected server supports per-session re-authentication
|
|
105
|
+
# (Bolt 5.1+). Probes a connection to read the negotiated protocol's
|
|
106
|
+
# capability flag. Today our handshake only advertises Bolt 4.4, so
|
|
107
|
+
# this returns false until the Bolt 5.x HELLO/LOGON work lands.
|
|
108
|
+
def supports_session_auth?
|
|
109
|
+
connection = @connection_provider.acquire(access_mode: :read)
|
|
110
|
+
connection.protocol.supports_re_auth?
|
|
111
|
+
ensure
|
|
112
|
+
@connection_provider.release(connection) if connection
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Run a query in a managed transaction and return EagerResult
|
|
116
|
+
# (keys, materialised records, summary). Convenience for "I just
|
|
117
|
+
# want results, don't make me build a session".
|
|
118
|
+
#
|
|
119
|
+
# Signature: `(query, params = {}, config = {})`. Same shape
|
|
120
|
+
# Session#run uses.
|
|
121
|
+
#
|
|
122
|
+
# `config` keys (snake_case):
|
|
123
|
+
# :database — string, the database to target.
|
|
124
|
+
# :routing — RoutingControl::READ / ::WRITE.
|
|
125
|
+
# :bookmark_manager — BookmarkManager for cross-session
|
|
126
|
+
# causal consistency. Pass `nil`
|
|
127
|
+
# explicitly to disable; omit to use
|
|
128
|
+
# the driver default.
|
|
129
|
+
# :impersonated_user — server runs the query as if this user
|
|
130
|
+
# had issued it (Bolt 4.4+, requires
|
|
131
|
+
# impersonator privileges).
|
|
132
|
+
# :metadata — map echoed back in summary; used by
|
|
133
|
+
# query-log / monitoring tooling.
|
|
134
|
+
# :timeout — seconds (or ActiveSupport::Duration);
|
|
135
|
+
# server-side transaction timeout.
|
|
136
|
+
# :auth_token — run this query under a specific identity
|
|
137
|
+
# (Bolt 5.1+ re-auths the connection via
|
|
138
|
+
# LOGOFF/LOGON); omit to use the driver's.
|
|
139
|
+
def execute_query(cypher, params = {}, config = {})
|
|
140
|
+
routing = config[:routing] || RoutingControl::WRITE
|
|
141
|
+
|
|
142
|
+
# `bookmark_manager: nil` is meaningful (explicitly disables the
|
|
143
|
+
# manager) and differs from omitting the key, so it's added
|
|
144
|
+
# conditionally rather than via .compact. `:database` /
|
|
145
|
+
# `:impersonated_user` / `:auth_token` keep .compact semantics
|
|
146
|
+
# (nil == omitted). A per-query `:auth_token` pins the session (and so
|
|
147
|
+
# its connection) to that identity — the provider re-auths on Bolt 5.1+
|
|
148
|
+
# (Feature:API:Driver.ExecuteQuery:WithAuth).
|
|
149
|
+
session_opts = {
|
|
150
|
+
database: config[:database],
|
|
151
|
+
default_access_mode: routing,
|
|
152
|
+
impersonated_user: config[:impersonated_user],
|
|
153
|
+
auth_token: config[:auth_token]
|
|
154
|
+
}.compact
|
|
155
|
+
# execute_query chains bookmarks across successive calls via a
|
|
156
|
+
# driver-wide default BookmarkManager, so a read after a write sees
|
|
157
|
+
# the write (matches Java's Driver.executeQuery). A caller can override
|
|
158
|
+
# per call; `bookmark_manager: nil` explicitly disables the chaining.
|
|
159
|
+
session_opts[:bookmark_manager] =
|
|
160
|
+
config.key?(:bookmark_manager) ? config[:bookmark_manager] : @query_bookmark_manager
|
|
161
|
+
# The managed tx this session runs reports TELEMETRY api = 3
|
|
162
|
+
# (DRIVER_EXECUTE_QUERY), not a plain managed transaction (api 0).
|
|
163
|
+
# Carried on the session since execute_query drives it through
|
|
164
|
+
# execute_read/write.
|
|
165
|
+
session_opts[:telemetry_api] = 3
|
|
166
|
+
|
|
167
|
+
# Forwarded to the managed-tx call below — the BEGIN extras
|
|
168
|
+
# honour metadata/timeout per-tx, not session-wide.
|
|
169
|
+
tx_kwargs = {
|
|
170
|
+
metadata: config[:metadata],
|
|
171
|
+
timeout: config[:timeout]
|
|
172
|
+
}.compact
|
|
173
|
+
|
|
174
|
+
keys = nil
|
|
175
|
+
records = nil
|
|
176
|
+
summary = nil
|
|
177
|
+
|
|
178
|
+
session(**session_opts) do |s|
|
|
179
|
+
method = routing == RoutingControl::READ ? :execute_read : :execute_write
|
|
180
|
+
s.send(method, **tx_kwargs) do |tx|
|
|
181
|
+
result = tx.run(cypher, **params)
|
|
182
|
+
records = result.to_a
|
|
183
|
+
keys = result.keys
|
|
184
|
+
summary = result.consume
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
EagerResult.new(keys, records, summary)
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
# Verify that the supplied auth token would succeed against the
|
|
192
|
+
# server, without disturbing the existing connection state. Returns
|
|
193
|
+
# true when the credentials are accepted, false when the server
|
|
194
|
+
# rejects them (see VERIFY_AUTH_NEGATIVE_CODES). Any other error
|
|
195
|
+
# (transport failure, TLS rejection, server unreachable, a security
|
|
196
|
+
# code outside the negative set) propagates so the caller can
|
|
197
|
+
# distinguish "credentials rejected" from "couldn't even ask".
|
|
198
|
+
#
|
|
199
|
+
# Mirrors Java's `Driver.verifyAuthentication(AuthToken)` — the token
|
|
200
|
+
# is required; pass AuthTokens.none for the unauthenticated probe.
|
|
201
|
+
|
|
202
|
+
# Security failure codes that mean "these credentials are not valid"
|
|
203
|
+
# (verify_authentication returns false). Every other security error —
|
|
204
|
+
# AuthorizationExpired, an unknown Security.* code, a rate-limit — is a
|
|
205
|
+
# condition the caller must see, so it propagates. Mirrors Java's
|
|
206
|
+
# verifyAuthentication NEGATIVE/PROPAGATE split.
|
|
207
|
+
VERIFY_AUTH_NEGATIVE_CODES = %w[
|
|
208
|
+
Neo.ClientError.Security.Unauthorized
|
|
209
|
+
Neo.ClientError.Security.CredentialsExpired
|
|
210
|
+
Neo.ClientError.Security.Forbidden
|
|
211
|
+
Neo.ClientError.Security.TokenExpired
|
|
212
|
+
].freeze
|
|
213
|
+
|
|
214
|
+
def verify_authentication(auth_token)
|
|
215
|
+
# Acquire a read connection AS the supplied identity, routing through
|
|
216
|
+
# `system` exactly like Java's verifyAuthentication: for neo4j:// this
|
|
217
|
+
# discovers (ROUTE on system) then reaches a reader; for bolt:// it
|
|
218
|
+
# uses the single server. We then force a LOGON with the token: a clean
|
|
219
|
+
# response means the credentials are good. The connection is one-shot —
|
|
220
|
+
# discarded, never pooled under the probe identity.
|
|
221
|
+
connection = @connection_provider.acquire(
|
|
222
|
+
access_mode: AccessMode::READ, database: 'system', auth: auth_token
|
|
223
|
+
)
|
|
224
|
+
begin
|
|
225
|
+
# Force a fresh LOGON even when the pooled connection already holds
|
|
226
|
+
# this identity (warm verify, or verifying the driver's own token):
|
|
227
|
+
# verification has to actually round-trip the credentials to the
|
|
228
|
+
# server, not trust a cached auth state. On a freshly built
|
|
229
|
+
# connection this is a redundant re-auth the scripts tolerate; on a
|
|
230
|
+
# reused one it's the whole point. Synchronous (pipelined: false): verify
|
|
231
|
+
# discards the connection with no operation to carry and drain the
|
|
232
|
+
# LOGOFF/LOGON replies, so it must read the LOGON result itself.
|
|
233
|
+
connection.authenticate(auth_token, force: true, pipelined: false)
|
|
234
|
+
ensure
|
|
235
|
+
connection.discard_on_release = true
|
|
236
|
+
@connection_provider.release(connection)
|
|
237
|
+
end
|
|
238
|
+
true
|
|
239
|
+
rescue Exceptions::SecurityException => e
|
|
240
|
+
raise unless VERIFY_AUTH_NEGATIVE_CODES.include?(e.code)
|
|
241
|
+
|
|
242
|
+
false
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
# Driver metrics. Currently exposes per-server connection-pool metrics
|
|
246
|
+
# (in-use / idle counts per address) via `metrics.connection_pool_metrics`
|
|
247
|
+
# — what testkit's GetConnectionPoolMetrics reads. The provider owns the
|
|
248
|
+
# pools and produces the snapshots.
|
|
249
|
+
def metrics
|
|
250
|
+
Internal::Metrics.new(@connection_provider)
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
# Routing table for `database` (testkit GetRoutingTable). Returns the
|
|
254
|
+
# routing table from the load balancer; testkit reads routers/writers/
|
|
255
|
+
# readers + ttl off it without knowing this internal path.
|
|
256
|
+
def routing_table(database)
|
|
257
|
+
connection_provider.routing_table_registry.routing_table_handler(database).routing_table
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
# Force a routing-table refresh (testkit ForcedRoutingTableUpdate).
|
|
261
|
+
def routing_table_refresh(database, bookmarks)
|
|
262
|
+
connection_provider.routing_table_registry.refresh(database, bookmarks)
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
attr_reader :connection_provider
|
|
266
|
+
end
|
|
267
|
+
end
|
|
268
|
+
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Neo4j
|
|
4
|
+
module Driver
|
|
5
|
+
# Materialised query result returned by Driver#execute_query: keys
|
|
6
|
+
# (column names), records (already-drained array), and the consumed
|
|
7
|
+
# summary. Modelled on Java's org.neo4j.driver.EagerResult.
|
|
8
|
+
EagerResult = Struct.new(:keys, :records, :summary)
|
|
9
|
+
end
|
|
10
|
+
end
|
|
@@ -4,17 +4,26 @@ module Neo4j
|
|
|
4
4
|
module Driver
|
|
5
5
|
module Exceptions
|
|
6
6
|
class Neo4jException < RuntimeError
|
|
7
|
-
attr_reader :code, :suppressed
|
|
7
|
+
attr_reader :code, :suppressed, :gql_status, :status_description,
|
|
8
|
+
:classification, :raw_classification, :diagnostic_record, :gql_cause
|
|
8
9
|
|
|
9
|
-
def initialize(
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
def initialize(message = nil, code: nil, suppressed: nil,
|
|
11
|
+
gql_status: nil, status_description: nil,
|
|
12
|
+
classification: nil, raw_classification: nil,
|
|
13
|
+
diagnostic_record: nil, gql_cause: nil)
|
|
14
|
+
super(message)
|
|
15
|
+
@code = code
|
|
16
|
+
@suppressed = Array(suppressed)
|
|
17
|
+
@gql_status = gql_status
|
|
18
|
+
@status_description = status_description
|
|
19
|
+
@classification = classification
|
|
20
|
+
@raw_classification = raw_classification
|
|
21
|
+
@diagnostic_record = diagnostic_record
|
|
22
|
+
@gql_cause = gql_cause
|
|
14
23
|
end
|
|
15
24
|
|
|
16
25
|
def add_suppressed(*exceptions)
|
|
17
|
-
|
|
26
|
+
@suppressed.concat(exceptions)
|
|
18
27
|
end
|
|
19
28
|
end
|
|
20
29
|
end
|
|
@@ -6,7 +6,7 @@ module Neo4j
|
|
|
6
6
|
class NoSuchRecordException < RuntimeError
|
|
7
7
|
EMPTY = 'Cannot retrieve a single record, because this result is empty.'
|
|
8
8
|
TOO_MANY = 'Expected a result with a single record, but this result ' \
|
|
9
|
-
|
|
9
|
+
'contains at least one more. Ensure your query returns only one record.'
|
|
10
10
|
NO_MORE = 'No more records'
|
|
11
11
|
NO_PEEK_PAST = 'Cannot peek past the last record'
|
|
12
12
|
|
|
@@ -6,11 +6,6 @@ module Neo4j
|
|
|
6
6
|
# A signal that the contract for client-server communication has broken down.
|
|
7
7
|
# The user should contact support and cannot resolve this his or herself.
|
|
8
8
|
class ProtocolException < Neo4jException
|
|
9
|
-
CODE = "Protocol violation: "
|
|
10
|
-
|
|
11
|
-
def initialize(message, e = nil)
|
|
12
|
-
super(nil, "#{CODE}#{message}", e)
|
|
13
|
-
end
|
|
14
9
|
end
|
|
15
10
|
end
|
|
16
11
|
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Neo4j
|
|
4
|
+
module Driver
|
|
5
|
+
module Exceptions
|
|
6
|
+
# A security exception the driver considers retryable: the auth-token
|
|
7
|
+
# manager handled the underlying security failure (e.g. an expired
|
|
8
|
+
# token), so a managed transaction may retry with a fresh token.
|
|
9
|
+
# Mirrors org.neo4j.driver.exceptions.SecurityRetryableException.
|
|
10
|
+
class SecurityRetryableException < SecurityException
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Neo4j
|
|
4
|
+
module Driver
|
|
5
|
+
module Exceptions
|
|
6
|
+
# The transaction has been terminated, so the work it was running
|
|
7
|
+
# cannot continue. Mirrors
|
|
8
|
+
# org.neo4j.driver.exceptions.TransactionTerminatedException.
|
|
9
|
+
class TransactionTerminatedException < ClientException
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Neo4j
|
|
4
|
+
module Driver
|
|
5
|
+
# Main entry point for creating Neo4j drivers. Wraps the supplied
|
|
6
|
+
# `AuthToken` in a `StaticAuthTokenManager` and delegates the
|
|
7
|
+
# actual construction to `Internal::DriverFactory#new_instance`
|
|
8
|
+
# — same shape as Java's `GraphDatabase.driver(...)` →
|
|
9
|
+
# `DriverFactory#newInstance(...)`.
|
|
10
|
+
module GraphDatabase
|
|
11
|
+
class << self
|
|
12
|
+
def driver(uri, auth_token = nil, auth_token_manager: nil, **config, &block)
|
|
13
|
+
mgr = auth_token_manager || Internal::Security::StaticAuthTokenManager.new(auth_token || AuthTokens.none)
|
|
14
|
+
driver = Internal::DriverFactory.new.new_instance(uri, mgr, **config)
|
|
15
|
+
|
|
16
|
+
if block_given?
|
|
17
|
+
begin
|
|
18
|
+
yield driver
|
|
19
|
+
ensure
|
|
20
|
+
driver.close
|
|
21
|
+
end
|
|
22
|
+
else
|
|
23
|
+
driver
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Neo4j
|
|
4
|
+
module Driver
|
|
5
|
+
module Internal
|
|
6
|
+
# The driver's clock. Every internal that measures elapsed time — pool
|
|
7
|
+
# idle/lifetime/acquisition, connection deadlines, routing-table ttl,
|
|
8
|
+
# managed-tx retry budget — reads it instead of calling Process/Time
|
|
9
|
+
# directly, and gets it injected (DriverFactory#create_clock, threaded
|
|
10
|
+
# through as its own `clock:` parameter). This default reads the real monotonic
|
|
11
|
+
# and wall clocks; testkit-backend supplies its own via the same seam
|
|
12
|
+
# (see Internal::ClockAdapter). The internals are agnostic to which clock
|
|
13
|
+
# they hold — there is no notion of "real" vs "mock" below this line.
|
|
14
|
+
class Clock
|
|
15
|
+
def monotonic = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
16
|
+
def realtime = ::Time.now
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|