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,236 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Neo4j
|
|
4
|
+
module Driver
|
|
5
|
+
module Bolt
|
|
6
|
+
# Bolt handshake negotiation. Two paths share the same 20-byte
|
|
7
|
+
# preamble (magic + four 4-byte slots, slot 1 = manifest sentinel):
|
|
8
|
+
#
|
|
9
|
+
# Legacy: server replies with one of the proposed versions
|
|
10
|
+
# (4 bytes, big-endian). Pre-5.7 servers always take
|
|
11
|
+
# this path because they don't speak manifest.
|
|
12
|
+
#
|
|
13
|
+
# Manifest v1: server replies with the sentinel 0x000001FF,
|
|
14
|
+
# then sends a varint count + N×4-byte version ranges +
|
|
15
|
+
# a varlong capabilities mask. Client picks the highest
|
|
16
|
+
# version it supports and writes back the chosen
|
|
17
|
+
# version (4 bytes) + a varlong of capabilities
|
|
18
|
+
# (currently always 0 — we negotiate no capabilities).
|
|
19
|
+
#
|
|
20
|
+
# Mirrors `BoltProtocolUtil` / `HandshakeHandler` / `ManifestHandlerV1`
|
|
21
|
+
# in neo4j-bolt-connection-java.
|
|
22
|
+
class Handshake
|
|
23
|
+
MAGIC_PREAMBLE = "\x60\x60\xB0\x17".b
|
|
24
|
+
|
|
25
|
+
# First four bytes of an HTTP response ("HTTP") read as a
|
|
26
|
+
# big-endian int — a server speaking HTTP on the Bolt port.
|
|
27
|
+
HTTP_REPLY = 0x4854_5450
|
|
28
|
+
|
|
29
|
+
# Slot 1 advertises "I speak HandshakeManifestV1". Decodes as
|
|
30
|
+
# BoltVersion(major=255, minor=1); servers that don't understand
|
|
31
|
+
# the sentinel ignore it and pick from slots 2-4 instead.
|
|
32
|
+
MANIFEST_SENTINEL = 0x00_00_01_FF
|
|
33
|
+
|
|
34
|
+
# Range encoding: [reserved=0, range=N, minor, major]. Each
|
|
35
|
+
# slot covers `major.minor` down to `major.(minor-N)`. We
|
|
36
|
+
# advertise 5.0–5.8 (slot 2), 4.2–4.4 (slot 3) and 3.0 (slot 4).
|
|
37
|
+
# Bolt 3.0 is fully wired now (Protocol::V3: PULL_ALL /
|
|
38
|
+
# DISCARD_ALL, single-DB, no routing in HELLO).
|
|
39
|
+
SLOTS = [
|
|
40
|
+
MANIFEST_SENTINEL,
|
|
41
|
+
0x00_08_08_05, # 5.0–5.8
|
|
42
|
+
0x00_02_04_04, # 4.2–4.4
|
|
43
|
+
0x00_00_00_03 # 3.0
|
|
44
|
+
].freeze
|
|
45
|
+
|
|
46
|
+
# Versions we'd accept from a manifest, highest-preference first.
|
|
47
|
+
# Used to pick a winner from whatever the server advertises.
|
|
48
|
+
SUPPORTED_VERSIONS = [
|
|
49
|
+
BoltVersion::V6_1,
|
|
50
|
+
BoltVersion::V6_0,
|
|
51
|
+
BoltVersion::V5_8,
|
|
52
|
+
BoltVersion::V5_7,
|
|
53
|
+
BoltVersion::V5_6,
|
|
54
|
+
BoltVersion::V5_5,
|
|
55
|
+
BoltVersion::V5_4,
|
|
56
|
+
BoltVersion::V5_3,
|
|
57
|
+
BoltVersion::V5_2,
|
|
58
|
+
BoltVersion::V5_1,
|
|
59
|
+
BoltVersion::V5_0,
|
|
60
|
+
BoltVersion::V4_4,
|
|
61
|
+
BoltVersion::V4_3,
|
|
62
|
+
BoltVersion::V4_2,
|
|
63
|
+
BoltVersion::V3_0
|
|
64
|
+
].freeze
|
|
65
|
+
|
|
66
|
+
# `deadline` (monotonic) bounds the negotiation reads so a server that
|
|
67
|
+
# stalls the magic-byte exchange can't outlast the acquisition timeout.
|
|
68
|
+
# We read via wait_readable + read_nonblock rather than read(n)+IO#timeout
|
|
69
|
+
# because IO#timeout is honored for read() only on CRuby, not JRuby —
|
|
70
|
+
# wait_readable times out on both, so the bound works on every flavor.
|
|
71
|
+
def initialize(socket, deadline: nil, clock: Internal::Clock.new)
|
|
72
|
+
@socket = socket
|
|
73
|
+
@deadline = deadline
|
|
74
|
+
@clock = clock
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Run the handshake to completion. Returns the negotiated
|
|
78
|
+
# version as a 32-bit int in the wire's slot encoding
|
|
79
|
+
# ([reserved, range=0, minor, major]).
|
|
80
|
+
# Sanity cap on the manifest's range-count varint. The varint
|
|
81
|
+
# itself is bounded to 63 usable bits but a server (malicious
|
|
82
|
+
# or buggy) could still ask us to allocate billions of slots.
|
|
83
|
+
# 256 is comfortably above the realistic upper bound (Java
|
|
84
|
+
# currently advertises ~5 ranges) and well below anything
|
|
85
|
+
# that'd hurt to allocate.
|
|
86
|
+
MAX_MANIFEST_RANGES = 256
|
|
87
|
+
|
|
88
|
+
def negotiate
|
|
89
|
+
@socket.write(MAGIC_PREAMBLE)
|
|
90
|
+
SLOTS.each { |slot| @socket.write([slot].pack('L>')) }
|
|
91
|
+
@socket.flush
|
|
92
|
+
|
|
93
|
+
server_reply = read_int32!('Server closed the connection during handshake')
|
|
94
|
+
if server_reply.zero?
|
|
95
|
+
raise Exceptions::ServiceUnavailableException,
|
|
96
|
+
'Server does not support any of the proposed Bolt versions'
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# An HTTP server on the Bolt port replies with an HTTP status
|
|
100
|
+
# line; its first four bytes spell "HTTP". Mirror Java's helpful
|
|
101
|
+
# error instead of reporting a bogus protocol version.
|
|
102
|
+
if server_reply == HTTP_REPLY
|
|
103
|
+
raise Exceptions::ClientException,
|
|
104
|
+
'Server responded HTTP. Make sure you are not trying to connect to the http ' \
|
|
105
|
+
'endpoint (HTTP defaults to port 7474 whereas BOLT defaults to port 7687)'
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
server_reply == MANIFEST_SENTINEL ? negotiate_manifest : server_reply
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
private
|
|
112
|
+
|
|
113
|
+
# The manifest path: read the server's supported-version list
|
|
114
|
+
# and capabilities, pick the highest version we know, write
|
|
115
|
+
# back our choice + an empty-capabilities varlong.
|
|
116
|
+
def negotiate_manifest
|
|
117
|
+
count = read_varint
|
|
118
|
+
if count > MAX_MANIFEST_RANGES
|
|
119
|
+
raise Exceptions::ServiceUnavailableException,
|
|
120
|
+
"Server's manifest range count #{count} exceeds the #{MAX_MANIFEST_RANGES} cap"
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
ranges = Array.new(count) { read_int32!('Connection closed mid-manifest while reading version ranges') }
|
|
124
|
+
read_varlong # server capabilities — consume but ignore (no caps requested)
|
|
125
|
+
|
|
126
|
+
chosen = pick_version(ranges)
|
|
127
|
+
unless chosen
|
|
128
|
+
# Tell the server we couldn't agree (4 bytes of zero +
|
|
129
|
+
# zero-varlong cap), then bail. Same shape as Java's
|
|
130
|
+
# ManifestHandlerV1 no-match path.
|
|
131
|
+
@socket.write([0].pack('L>'))
|
|
132
|
+
write_varlong(0)
|
|
133
|
+
@socket.flush
|
|
134
|
+
raise Exceptions::ServiceUnavailableException,
|
|
135
|
+
"Server's manifest offered no Bolt version we support"
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
@socket.write([chosen.to_wire].pack('L>'))
|
|
139
|
+
# We don't request any capabilities yet (BoltCapability.FABRIC
|
|
140
|
+
# is the only one Java defines, and we don't use Fabric).
|
|
141
|
+
write_varlong(0)
|
|
142
|
+
@socket.flush
|
|
143
|
+
|
|
144
|
+
chosen.to_wire
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# The server's version list comes as raw ints encoded
|
|
148
|
+
# `(minor_count << 16) | (minor << 8) | major`. Walk our
|
|
149
|
+
# preference list and pick the first that any advertised range
|
|
150
|
+
# covers.
|
|
151
|
+
def pick_version(ranges)
|
|
152
|
+
SUPPORTED_VERSIONS.find { |v| ranges.any? { |range_int| range_covers?(range_int, v) } }
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def range_covers?(range_int, version)
|
|
156
|
+
major = range_int & 0xFF
|
|
157
|
+
top_minor = (range_int >> 8) & 0xFF
|
|
158
|
+
count = (range_int >> 16) & 0xFF
|
|
159
|
+
return false unless version.major == major
|
|
160
|
+
|
|
161
|
+
version.minor <= top_minor && version.minor >= top_minor - count
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def read_int32
|
|
165
|
+
bytes = read_fully(4)
|
|
166
|
+
bytes ? bytes.unpack1('L>') : nil
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# Read exactly n bytes, bounded by @deadline. Returns the bytes, or nil
|
|
170
|
+
# on EOF / deadline (callers turn nil into the right handshake error).
|
|
171
|
+
# wait_readable yields under a Fiber scheduler and times out on every
|
|
172
|
+
# Ruby (unlike read()+IO#timeout, which only times out on CRuby).
|
|
173
|
+
def read_fully(n)
|
|
174
|
+
buf = String.new(encoding: Encoding::BINARY)
|
|
175
|
+
while buf.bytesize < n
|
|
176
|
+
case (chunk = @socket.read_nonblock(n - buf.bytesize, exception: false))
|
|
177
|
+
when :wait_readable then @socket.wait_readable(remaining_budget) || return
|
|
178
|
+
when :wait_writable then @socket.wait_writable(remaining_budget) || return
|
|
179
|
+
when nil then return
|
|
180
|
+
else buf << chunk
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
buf
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def remaining_budget
|
|
187
|
+
return nil unless @deadline
|
|
188
|
+
|
|
189
|
+
[@deadline - @clock.monotonic, 0.0].max
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
# Same as read_int32 but raises a ServiceUnavailableException
|
|
193
|
+
# on short read instead of returning nil. Use this whenever a
|
|
194
|
+
# nil result would propagate into bitmasks / arithmetic and
|
|
195
|
+
# crash with a less helpful TypeError downstream.
|
|
196
|
+
def read_int32!(message)
|
|
197
|
+
read_int32 || raise(Exceptions::ServiceUnavailableException, message)
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
# LEB128 unsigned varint / varlong. 7 data bits per byte, MSB
|
|
201
|
+
# is the continuation flag. Java caps at 9 bytes (63 usable
|
|
202
|
+
# bits) and so do we — anything wider is a malformed peer.
|
|
203
|
+
def read_varint
|
|
204
|
+
value = 0
|
|
205
|
+
shift = 0
|
|
206
|
+
9.times do
|
|
207
|
+
byte = read_fully(1)&.unpack1('C')
|
|
208
|
+
raise IOError, 'Unexpected end of stream while reading varint' if byte.nil?
|
|
209
|
+
|
|
210
|
+
value |= (byte & 0x7F) << shift
|
|
211
|
+
return value if byte & 0x80 == 0
|
|
212
|
+
|
|
213
|
+
shift += 7
|
|
214
|
+
end
|
|
215
|
+
raise Exceptions::ServiceUnavailableException, 'Varint overflow during handshake'
|
|
216
|
+
end
|
|
217
|
+
alias read_varlong read_varint
|
|
218
|
+
|
|
219
|
+
def write_varlong(value)
|
|
220
|
+
# do/while so zero still emits a single 0x00 byte (matches
|
|
221
|
+
# Java's writeVarLong).
|
|
222
|
+
loop do
|
|
223
|
+
byte = value & 0x7F
|
|
224
|
+
value >>= 7
|
|
225
|
+
if value.zero?
|
|
226
|
+
@socket.write([byte].pack('C'))
|
|
227
|
+
break
|
|
228
|
+
else
|
|
229
|
+
@socket.write([byte | 0x80].pack('C'))
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
end
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Neo4j
|
|
4
|
+
module Driver
|
|
5
|
+
module Bolt
|
|
6
|
+
module Message
|
|
7
|
+
# Failure response from Neo4j server.
|
|
8
|
+
#
|
|
9
|
+
# Two wire shapes, both handled by #to_exception:
|
|
10
|
+
# * Legacy (pre-Bolt 5.7): { code:, message: }.
|
|
11
|
+
# * GQL (Bolt 5.7+): { gql_status:, description:, message:, neo4j_code:,
|
|
12
|
+
# diagnostic_record:, cause: } — `cause` nests the same shape.
|
|
13
|
+
# Since the driver speaks 5.7, a legacy failure is *synthesised* into the
|
|
14
|
+
# GQL shape (gql_status 50N42, default diagnostic record) so the exception
|
|
15
|
+
# exposes the same fields regardless of the server's protocol version —
|
|
16
|
+
# matching the Java driver's GqlStatusException behaviour.
|
|
17
|
+
class Failure
|
|
18
|
+
# Code-prefix → driver exception class. Order matters: more specific
|
|
19
|
+
# patterns must come first.
|
|
20
|
+
EXCEPTION_FOR_CODE = [
|
|
21
|
+
[/^Neo\.ClientError\.Security\.Unauthorized/, Exceptions::AuthenticationException],
|
|
22
|
+
[/^Neo\.ClientError\.Security\.AuthorizationExpired/, Exceptions::AuthorizationExpiredException],
|
|
23
|
+
[/^Neo\.ClientError\.Security\.TokenExpired/, Exceptions::TokenExpiredException],
|
|
24
|
+
[/^Neo\.ClientError\.Security/, Exceptions::SecurityException],
|
|
25
|
+
[/^Neo\.ClientError\.Database\.DatabaseNotFound/, Exceptions::FatalDiscoveryException],
|
|
26
|
+
[/^Neo\.ClientError/, Exceptions::ClientException],
|
|
27
|
+
[/^Neo\.TransientError/, Exceptions::TransientException],
|
|
28
|
+
[/^Neo\.DatabaseError/, Exceptions::DatabaseException]
|
|
29
|
+
].freeze
|
|
30
|
+
|
|
31
|
+
# Two `TransientError` codes the server may send that are actually
|
|
32
|
+
# non-retryable: the driver rewrites them to their `ClientError` form
|
|
33
|
+
# (so they map to a non-retryable ClientException, not a retryable
|
|
34
|
+
# TransientException) and surfaces the rewritten code. Mirrors the
|
|
35
|
+
# Java driver's ErrorUtil special-case; testkit's
|
|
36
|
+
# test_should_not_retry_non_retryable_tx_failures asserts both the
|
|
37
|
+
# rewritten code and that the managed-tx executor does not retry.
|
|
38
|
+
CODE_REWRITES = {
|
|
39
|
+
'Neo.TransientError.Transaction.Terminated' => 'Neo.ClientError.Transaction.Terminated',
|
|
40
|
+
'Neo.TransientError.Transaction.LockClientStopped' => 'Neo.ClientError.Transaction.LockClientStopped'
|
|
41
|
+
}.freeze
|
|
42
|
+
|
|
43
|
+
# GQL diagnostic-record keys the server may omit; filled with these
|
|
44
|
+
# defaults so the record is always complete (mirrors the Java driver).
|
|
45
|
+
DEFAULT_DIAGNOSTIC_RECORD = { OPERATION: '', OPERATION_CODE: '0', CURRENT_SCHEMA: '/' }.freeze
|
|
46
|
+
|
|
47
|
+
# Fallback GQL status for a legacy (non-GQL) failure: 50N42 =
|
|
48
|
+
# "general processing exception - unexpected error".
|
|
49
|
+
DEFAULT_GQL_STATUS = '50N42'
|
|
50
|
+
DEFAULT_STATUS_DESCRIPTION_PREFIX = 'error: general processing exception - unexpected error. '
|
|
51
|
+
|
|
52
|
+
# Diagnostic-record classifications the spec recognises; anything else
|
|
53
|
+
# (or absent) surfaces as the catch-all UNKNOWN.
|
|
54
|
+
KNOWN_CLASSIFICATIONS = %w[CLIENT_ERROR DATABASE_ERROR TRANSIENT_ERROR].freeze
|
|
55
|
+
|
|
56
|
+
attr_reader :metadata
|
|
57
|
+
|
|
58
|
+
def initialize(metadata)
|
|
59
|
+
@metadata = metadata
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def code
|
|
63
|
+
@metadata[:neo4j_code] || @metadata[:code]
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def message
|
|
67
|
+
@metadata[:message]
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Map this server FAILURE to its driver-side exception. Single owner of
|
|
71
|
+
# the code→exception logic — used to live in 4+ places.
|
|
72
|
+
def to_exception
|
|
73
|
+
gql?(@metadata) ? build_gql(@metadata) : build_legacy(@metadata)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def accept(visitor)
|
|
77
|
+
visitor.on_failure(self)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def assert_success!
|
|
81
|
+
raise to_exception
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def terminal? = true
|
|
85
|
+
|
|
86
|
+
private
|
|
87
|
+
|
|
88
|
+
def gql?(meta) = meta.key?(:gql_status)
|
|
89
|
+
|
|
90
|
+
def exception_class(code)
|
|
91
|
+
(EXCEPTION_FOR_CODE.find { |pattern, _| code.to_s.match?(pattern) }&.last if code) ||
|
|
92
|
+
Exceptions::Neo4jException
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# A handful of TransientError codes are non-retryable and surface
|
|
96
|
+
# under their ClientError code (see CODE_REWRITES).
|
|
97
|
+
def rewrite_code(code) = CODE_REWRITES[code] || code
|
|
98
|
+
|
|
99
|
+
# Bolt 5.7+ GQL failure: read the fields straight off the wire, fill the
|
|
100
|
+
# diagnostic-record defaults, and recurse into the cause chain.
|
|
101
|
+
def build_gql(meta)
|
|
102
|
+
diagnostic_record = fill_defaults(meta[:diagnostic_record])
|
|
103
|
+
raw_classification = diagnostic_record[:_classification]
|
|
104
|
+
raw_classification = nil unless raw_classification.is_a?(String)
|
|
105
|
+
|
|
106
|
+
code = rewrite_code(meta[:neo4j_code])
|
|
107
|
+
exception_class(code).new(
|
|
108
|
+
meta[:message],
|
|
109
|
+
code: code,
|
|
110
|
+
gql_status: meta[:gql_status],
|
|
111
|
+
status_description: meta[:description],
|
|
112
|
+
diagnostic_record: diagnostic_record,
|
|
113
|
+
raw_classification: raw_classification,
|
|
114
|
+
classification: (raw_classification if KNOWN_CLASSIFICATIONS.include?(raw_classification)),
|
|
115
|
+
gql_cause: meta[:cause] && build_gql(meta[:cause])
|
|
116
|
+
)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Legacy { code:, message: } failure — synthesise the GQL shape so the
|
|
120
|
+
# exception carries the same fields a 5.7 server would have sent.
|
|
121
|
+
def build_legacy(meta)
|
|
122
|
+
code = rewrite_code(meta[:code])
|
|
123
|
+
exception_class(code).new(
|
|
124
|
+
meta[:message],
|
|
125
|
+
code: code,
|
|
126
|
+
gql_status: DEFAULT_GQL_STATUS,
|
|
127
|
+
status_description: "#{DEFAULT_STATUS_DESCRIPTION_PREFIX}#{meta[:message]}",
|
|
128
|
+
diagnostic_record: DEFAULT_DIAGNOSTIC_RECORD.dup
|
|
129
|
+
)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def fill_defaults(record)
|
|
133
|
+
DEFAULT_DIAGNOSTIC_RECORD.merge(record || {})
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Neo4j
|
|
4
|
+
module Driver
|
|
5
|
+
module Bolt
|
|
6
|
+
module Message
|
|
7
|
+
# Ignored response from Neo4j server (previous request was ignored)
|
|
8
|
+
class Ignored
|
|
9
|
+
def initialize(metadata = {})
|
|
10
|
+
@metadata = metadata
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def accept(visitor)
|
|
14
|
+
visitor.on_ignored(self)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def assert_success!
|
|
18
|
+
raise Exceptions::ClientException,
|
|
19
|
+
'Server IGNORED the request — a previous request in this batch failed'
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def terminal? = true
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Neo4j
|
|
4
|
+
module Driver
|
|
5
|
+
module Bolt
|
|
6
|
+
module Message
|
|
7
|
+
# Record response from Neo4j server containing result data
|
|
8
|
+
class Record
|
|
9
|
+
attr_reader :fields
|
|
10
|
+
|
|
11
|
+
def initialize(fields)
|
|
12
|
+
@fields = fields
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def accept(visitor)
|
|
16
|
+
visitor.on_record(self)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def assert_success!
|
|
20
|
+
raise Exceptions::ClientException, 'Unexpected RECORD where SUCCESS was expected'
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# A RECORD is a streamed row, not a request summary — it never
|
|
24
|
+
# completes the request, so it doesn't decrement the in-flight count.
|
|
25
|
+
def terminal? = false
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Neo4j
|
|
4
|
+
module Driver
|
|
5
|
+
module Bolt
|
|
6
|
+
module Message
|
|
7
|
+
# Success response from Neo4j server
|
|
8
|
+
class Success
|
|
9
|
+
attr_reader :metadata
|
|
10
|
+
|
|
11
|
+
def initialize(metadata = {})
|
|
12
|
+
@metadata = metadata
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Visitor double-dispatch: streaming consumers use this to avoid
|
|
16
|
+
# `case/when` on the response class.
|
|
17
|
+
def accept(visitor)
|
|
18
|
+
visitor.on_success(self)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# One-shot pattern: caller expects a SUCCESS, raises otherwise.
|
|
22
|
+
# Returns self so callers can chain `.metadata`.
|
|
23
|
+
def assert_success!
|
|
24
|
+
self
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# A SUCCESS completes the request it answers — the connection uses
|
|
28
|
+
# this to tell summary responses apart from streamed RECORDs.
|
|
29
|
+
def terminal? = true
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Neo4j
|
|
4
|
+
module Driver
|
|
5
|
+
module Bolt
|
|
6
|
+
# Bolt Protocol Messages
|
|
7
|
+
module Message
|
|
8
|
+
# Request messages (sent from client to server)
|
|
9
|
+
HELLO = 0x01
|
|
10
|
+
GOODBYE = 0x02
|
|
11
|
+
RESET = 0x0F
|
|
12
|
+
RUN = 0x10
|
|
13
|
+
BEGIN_TX = 0x11
|
|
14
|
+
COMMIT = 0x12
|
|
15
|
+
ROLLBACK = 0x13
|
|
16
|
+
PULL = 0x3F
|
|
17
|
+
DISCARD = 0x2F
|
|
18
|
+
ROUTE = 0x66
|
|
19
|
+
LOGON = 0x6A
|
|
20
|
+
LOGOFF = 0x6B
|
|
21
|
+
TELEMETRY = 0x54
|
|
22
|
+
|
|
23
|
+
# Response messages (sent from server to client)
|
|
24
|
+
SUCCESS = 0x70
|
|
25
|
+
RECORD = 0x71
|
|
26
|
+
IGNORED = 0x7E
|
|
27
|
+
FAILURE = 0x7F
|
|
28
|
+
|
|
29
|
+
class << self
|
|
30
|
+
# NOTE: HELLO message building is now handled by protocol-specific handlers
|
|
31
|
+
# This method kept for backward compatibility but shouldn't be used directly
|
|
32
|
+
def hello(user_agent:, auth:, routing: nil)
|
|
33
|
+
extra = { user_agent: user_agent }
|
|
34
|
+
extra[:routing] = routing if routing
|
|
35
|
+
# Default to Bolt 5.0+ format (merged auth)
|
|
36
|
+
extra.merge!(auth) if auth
|
|
37
|
+
PackStream::Structure.new(HELLO, [extra])
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def run(query, parameters = {}, extra = {})
|
|
41
|
+
PackStream::Structure.new(RUN, [query, parameters, extra])
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def begin_transaction(extra = {})
|
|
45
|
+
PackStream::Structure.new(BEGIN_TX, [extra])
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def commit
|
|
49
|
+
PackStream::Structure.new(COMMIT, [])
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def rollback
|
|
53
|
+
PackStream::Structure.new(ROLLBACK, [])
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Caller must specify n explicitly — Java/Python default is 1000
|
|
57
|
+
# records per batch but the call site (Session/Transaction) knows
|
|
58
|
+
# the configured fetch_size and passes it through. Default-here
|
|
59
|
+
# would silently mask "forgot to plumb fetch_size".
|
|
60
|
+
def pull(extra = {})
|
|
61
|
+
PackStream::Structure.new(PULL, [extra])
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def discard(extra = {})
|
|
65
|
+
extra = { n: -1 }.merge(extra)
|
|
66
|
+
PackStream::Structure.new(DISCARD, [extra])
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Bolt 5.4+ TELEMETRY: reports which driver API opened the coming
|
|
70
|
+
# transaction/query (0 tx-function, 1 unmanaged tx, 2 auto-commit,
|
|
71
|
+
# 3 execute_query). Sent only when the server advertised
|
|
72
|
+
# `telemetry.enabled` and the driver didn't disable it.
|
|
73
|
+
def telemetry(api)
|
|
74
|
+
PackStream::Structure.new(TELEMETRY, [api])
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def reset
|
|
78
|
+
PackStream::Structure.new(RESET, [])
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def goodbye
|
|
82
|
+
PackStream::Structure.new(GOODBYE, [])
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# LOGON (Bolt 5.1+). Carries the auth fields that 5.0 used to
|
|
86
|
+
# send inside HELLO. The server's success here marks the
|
|
87
|
+
# connection authenticated and READY.
|
|
88
|
+
def logon(auth)
|
|
89
|
+
PackStream::Structure.new(LOGON, [auth || {}])
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# LOGOFF (Bolt 5.1+). De-authenticates the connection; the
|
|
93
|
+
# next LOGON re-authenticates with a possibly-different
|
|
94
|
+
# token. Used by per-session auth (`driver.session(auth: …)`)
|
|
95
|
+
# to switch identity on a pooled connection without tearing
|
|
96
|
+
# it down.
|
|
97
|
+
def logoff
|
|
98
|
+
PackStream::Structure.new(LOGOFF, [])
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# ROUTE (Bolt 4.3+) — fetch the cluster's routing table.
|
|
102
|
+
# routing_context : map (typically built from the URI query string)
|
|
103
|
+
# bookmarks : list of bookmarks (or nil for Bolt 4.3 compat)
|
|
104
|
+
# extra : {db: <database or nil>, imp_user: <or nil>}
|
|
105
|
+
def route(routing_context, bookmarks, extra)
|
|
106
|
+
PackStream::Structure.new(ROUTE, [routing_context, bookmarks, extra])
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|