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,335 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Neo4j
|
|
4
|
+
module Driver
|
|
5
|
+
module PackStream
|
|
6
|
+
# PackStream Packer - serializes Ruby objects to PackStream binary format
|
|
7
|
+
# Based on https://neo4j.com/docs/bolt/current/packstream/
|
|
8
|
+
class Packer
|
|
9
|
+
include Markers
|
|
10
|
+
|
|
11
|
+
# When true, datetimes are packed as the UTC-seconds Bolt 5.0+
|
|
12
|
+
# structures (0x49 / 0x69) instead of the legacy local-seconds
|
|
13
|
+
# variants (0x46 / 0x66). Connection sets this after a
|
|
14
|
+
# successful handshake negotiates Bolt 5.0+; ignored on 4.x.
|
|
15
|
+
attr_accessor :use_utc_datetime
|
|
16
|
+
|
|
17
|
+
def initialize(protocol)
|
|
18
|
+
@buffer = String.new(encoding: Encoding::BINARY)
|
|
19
|
+
@use_utc_datetime = false
|
|
20
|
+
@protocol = protocol
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def pack(value)
|
|
24
|
+
case value
|
|
25
|
+
when nil
|
|
26
|
+
pack_null
|
|
27
|
+
when true, false
|
|
28
|
+
pack_boolean(value)
|
|
29
|
+
when Integer
|
|
30
|
+
pack_integer(value)
|
|
31
|
+
when Float
|
|
32
|
+
pack_float(value)
|
|
33
|
+
when String
|
|
34
|
+
# Pack binary strings as BYTES, text strings as STRING
|
|
35
|
+
value.encoding == Encoding::BINARY ? pack_bytes(value) : pack_string(value)
|
|
36
|
+
when Symbol
|
|
37
|
+
pack_string(value.to_s)
|
|
38
|
+
when Hash
|
|
39
|
+
# Check Hash before Enumerable since Hash is also Enumerable
|
|
40
|
+
pack_map(value)
|
|
41
|
+
when Types::Node, Types::Relationship, Types::Path, Types::UnsupportedType
|
|
42
|
+
# Graph types are not valid query parameters; neither is an
|
|
43
|
+
# UnsupportedType (a value the driver couldn't materialise — it
|
|
44
|
+
# must not be sent back to the server). Reject before the Enumerable
|
|
45
|
+
# branch since Path includes Enumerable.
|
|
46
|
+
Exceptions::ClientException.unable_to_convert(value)
|
|
47
|
+
when Array, Set, Range
|
|
48
|
+
# Known sized collections — pack_list uses #size, which is O(1) here.
|
|
49
|
+
pack_list(value)
|
|
50
|
+
when Enumerable
|
|
51
|
+
# Generic Enumerable (lazy enumerators, custom collections) — materialise
|
|
52
|
+
# so #size is well-defined.
|
|
53
|
+
pack_list(value.to_a)
|
|
54
|
+
when ::DateTime, ::Time
|
|
55
|
+
# Check DateTime before Date — DateTime < Date in Ruby, so the
|
|
56
|
+
# Date branch would match first and pack away the time component.
|
|
57
|
+
pack_datetime(value)
|
|
58
|
+
when ::Date
|
|
59
|
+
# Pack Ruby Date as Neo4j Date structure
|
|
60
|
+
pack_date(value)
|
|
61
|
+
when Types::LocalDateTime
|
|
62
|
+
pack_local_datetime(value)
|
|
63
|
+
when Types::LocalTime
|
|
64
|
+
pack_local_time(value)
|
|
65
|
+
when Types::OffsetTime
|
|
66
|
+
pack_offset_time(value)
|
|
67
|
+
when Types::Point
|
|
68
|
+
pack_point(value)
|
|
69
|
+
when Types::Duration
|
|
70
|
+
pack_duration(value)
|
|
71
|
+
when Types::UUID
|
|
72
|
+
# A PackStream V2 type: only the negotiated protocol decides whether
|
|
73
|
+
# it can be sent — V61 packs it, every earlier version rejects it.
|
|
74
|
+
@protocol.pack_uuid(self, value)
|
|
75
|
+
else
|
|
76
|
+
Exceptions::ClientException.unable_to_convert(value)
|
|
77
|
+
end
|
|
78
|
+
self
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Serialise a Bolt protocol message (a PackStream::Structure) onto the buffer.
|
|
82
|
+
# Distinct from #pack so the user-value path doesn't carry knowledge of
|
|
83
|
+
# the wire-level Structure type.
|
|
84
|
+
def pack_message(structure)
|
|
85
|
+
pack_structure(structure)
|
|
86
|
+
self
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def bytes
|
|
90
|
+
@buffer
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def reset
|
|
94
|
+
@buffer.clear
|
|
95
|
+
self
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# PackStream V2 UUID (Bolt 6.1+): marker 0xE0 + 16 raw bytes. Called by
|
|
99
|
+
# Protocol::V61#pack_uuid — every earlier protocol rejects a UUID
|
|
100
|
+
# instead, so this is only reached once 6.1 is negotiated.
|
|
101
|
+
def pack_uuid_value(value)
|
|
102
|
+
@buffer << [UUID].pack('C')
|
|
103
|
+
@buffer << [value.to_s.delete('-')].pack('H*')
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
private
|
|
107
|
+
|
|
108
|
+
def pack_null
|
|
109
|
+
@buffer << [NULL].pack('C')
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def pack_boolean(value)
|
|
113
|
+
@buffer << [value ? BOOLEAN_TRUE : BOOLEAN_FALSE].pack('C')
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def pack_integer(value)
|
|
117
|
+
if value >= -16 && value <= 127
|
|
118
|
+
# TINY_INT: -16 to +127
|
|
119
|
+
@buffer << [value].pack('c')
|
|
120
|
+
elsif value >= -128 && value <= 127
|
|
121
|
+
@buffer << [INT_8, value].pack('Cc')
|
|
122
|
+
elsif value >= -32_768 && value <= 32_767
|
|
123
|
+
@buffer << [INT_16, value].pack('Cs>')
|
|
124
|
+
elsif value >= -2_147_483_648 && value <= 2_147_483_647
|
|
125
|
+
@buffer << [INT_32, value].pack('Cl>')
|
|
126
|
+
elsif value >= -9_223_372_036_854_775_808 && value <= 9_223_372_036_854_775_807
|
|
127
|
+
@buffer << [INT_64, value].pack('Cq>')
|
|
128
|
+
else
|
|
129
|
+
raise ArgumentError, "Integer value out of range: #{value}"
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def pack_float(value)
|
|
134
|
+
@buffer << [FLOAT_64].pack('C')
|
|
135
|
+
@buffer << [value].pack('G')
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def pack_string(value)
|
|
139
|
+
bytes = value.encode(Encoding::UTF_8).b
|
|
140
|
+
size = bytes.bytesize
|
|
141
|
+
|
|
142
|
+
if size < 16
|
|
143
|
+
@buffer << [TINY_STRING | size].pack('C')
|
|
144
|
+
elsif size <= 255
|
|
145
|
+
@buffer << [STRING_8, size].pack('CC')
|
|
146
|
+
elsif size <= 65_535
|
|
147
|
+
@buffer << [STRING_16, size].pack('CS>')
|
|
148
|
+
elsif size <= 2_147_483_647
|
|
149
|
+
@buffer << [STRING_32, size].pack('CL>')
|
|
150
|
+
else
|
|
151
|
+
raise ArgumentError, "String too long: #{size} bytes"
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
@buffer << bytes
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def pack_bytes(value)
|
|
158
|
+
size = value.bytesize
|
|
159
|
+
|
|
160
|
+
if size <= 255
|
|
161
|
+
@buffer << [BYTES_8, size].pack('CC')
|
|
162
|
+
elsif size <= 65_535
|
|
163
|
+
@buffer << [BYTES_16, size].pack('CS>')
|
|
164
|
+
elsif size <= 2_147_483_647
|
|
165
|
+
@buffer << [BYTES_32, size].pack('CL>')
|
|
166
|
+
else
|
|
167
|
+
raise ArgumentError, "Bytes too long: #{size} bytes"
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
@buffer << value
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def pack_list(value)
|
|
174
|
+
size = value.size
|
|
175
|
+
|
|
176
|
+
if size < 16
|
|
177
|
+
@buffer << [TINY_LIST | size].pack('C')
|
|
178
|
+
elsif size <= 255
|
|
179
|
+
@buffer << [LIST_8, size].pack('CC')
|
|
180
|
+
elsif size <= 65_535
|
|
181
|
+
@buffer << [LIST_16, size].pack('CS>')
|
|
182
|
+
elsif size <= 2_147_483_647
|
|
183
|
+
@buffer << [LIST_32, size].pack('CL>')
|
|
184
|
+
else
|
|
185
|
+
raise ArgumentError, "List too long: #{size} items"
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
value.each { pack(it) }
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def pack_map(value)
|
|
192
|
+
size = value.size
|
|
193
|
+
|
|
194
|
+
if size < 16
|
|
195
|
+
@buffer << [TINY_MAP | size].pack('C')
|
|
196
|
+
elsif size <= 255
|
|
197
|
+
@buffer << [MAP_8, size].pack('CC')
|
|
198
|
+
elsif size <= 65_535
|
|
199
|
+
@buffer << [MAP_16, size].pack('CS>')
|
|
200
|
+
elsif size <= 2_147_483_647
|
|
201
|
+
@buffer << [MAP_32, size].pack('CL>')
|
|
202
|
+
else
|
|
203
|
+
raise ArgumentError, "Map too long: #{size} entries"
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
value.each do |key, val|
|
|
207
|
+
pack(key.to_s)
|
|
208
|
+
pack(val)
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def pack_structure(value)
|
|
213
|
+
size = value.fields.size
|
|
214
|
+
|
|
215
|
+
if size < 16
|
|
216
|
+
@buffer << [TINY_STRUCT | size].pack('C')
|
|
217
|
+
elsif size <= 255
|
|
218
|
+
@buffer << [STRUCT_8, size].pack('CC')
|
|
219
|
+
elsif size <= 65_535
|
|
220
|
+
@buffer << [STRUCT_16, size].pack('CS>')
|
|
221
|
+
else
|
|
222
|
+
raise ArgumentError, "Structure too large: #{size} fields"
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
@buffer << [value.signature].pack('C')
|
|
226
|
+
value.fields.each { |field| pack(field) }
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
def pack_date(value)
|
|
230
|
+
days = (value - ::Date.new(1970, 1, 1)).to_i
|
|
231
|
+
# Date structure: signature 0x44, 1 field (days)
|
|
232
|
+
@buffer << [TINY_STRUCT | 1, 0x44].pack('CC')
|
|
233
|
+
pack_integer(days)
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
def pack_datetime(value)
|
|
237
|
+
# Normalise DateTime to Time so we can rely on Time's API (nsec,
|
|
238
|
+
# utc_offset, to_i) uniformly.
|
|
239
|
+
value = value.to_time if value.is_a?(::DateTime)
|
|
240
|
+
|
|
241
|
+
tz_offset = value.utc_offset
|
|
242
|
+
nanoseconds = value.nsec
|
|
243
|
+
# Bolt 5.0+ (and 4.4-with-patch_bolt:utc) want true UTC
|
|
244
|
+
# seconds in 0x49 / 0x69; the legacy 0x46 / 0x66 carry LOCAL
|
|
245
|
+
# seconds (wall-clock treated as if it were UTC). See the
|
|
246
|
+
# matching hydration handlers in Bolt::Connection.
|
|
247
|
+
if @use_utc_datetime
|
|
248
|
+
epoch_seconds = value.to_i
|
|
249
|
+
offset_sig = 0x49
|
|
250
|
+
zone_sig = 0x69
|
|
251
|
+
else
|
|
252
|
+
epoch_seconds = value.to_i + tz_offset
|
|
253
|
+
offset_sig = 0x46
|
|
254
|
+
zone_sig = 0x66
|
|
255
|
+
end
|
|
256
|
+
zone_name = named_zone_for(value)
|
|
257
|
+
|
|
258
|
+
if zone_name
|
|
259
|
+
# ZonedDateTime: fields [seconds, nanos, tz_name]
|
|
260
|
+
@buffer << [TINY_STRUCT | 3, zone_sig].pack('CC')
|
|
261
|
+
pack_integer(epoch_seconds)
|
|
262
|
+
pack_integer(nanoseconds)
|
|
263
|
+
pack_string(zone_name)
|
|
264
|
+
else
|
|
265
|
+
# DateTime with offset: fields [seconds, nanos, tz_offset]
|
|
266
|
+
@buffer << [TINY_STRUCT | 3, offset_sig].pack('CC')
|
|
267
|
+
pack_integer(epoch_seconds)
|
|
268
|
+
pack_integer(nanoseconds)
|
|
269
|
+
pack_integer(tz_offset)
|
|
270
|
+
end
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
# Return the IANA zone name for a TimeWithZone-like value when it has
|
|
274
|
+
# one, otherwise nil (so the caller falls back to offset-only 0x46).
|
|
275
|
+
# Offset-shaped names like "+07:00" or "-05:00" don't round-trip
|
|
276
|
+
# through Neo4j's zoned DateTime and are treated as nil.
|
|
277
|
+
def named_zone_for(value)
|
|
278
|
+
return nil unless value.respond_to?(:time_zone)
|
|
279
|
+
|
|
280
|
+
tz = value.time_zone
|
|
281
|
+
name = tz.respond_to?(:name) ? tz.name : nil
|
|
282
|
+
return nil if name.nil? || name.empty? || name.match?(/\A[+-]?\d/)
|
|
283
|
+
|
|
284
|
+
name
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
def pack_local_datetime(value)
|
|
288
|
+
# LocalDateTime structure: signature 0x64, 2 fields (seconds, nanos)
|
|
289
|
+
@buffer << [TINY_STRUCT | 2, 0x64].pack('CC')
|
|
290
|
+
pack_integer(value.epoch_seconds)
|
|
291
|
+
pack_integer(value.nanoseconds)
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
def pack_offset_time(value)
|
|
295
|
+
# OffsetTime structure: signature 0x54, 2 fields (nanos, tz_offset)
|
|
296
|
+
@buffer << [TINY_STRUCT | 2, 0x54].pack('CC')
|
|
297
|
+
pack_integer(value.nanoseconds)
|
|
298
|
+
pack_integer(value.tz_offset_seconds)
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
def pack_local_time(value)
|
|
302
|
+
# LocalTime structure: signature 0x74, 1 field (nanos)
|
|
303
|
+
@buffer << [TINY_STRUCT | 1, 0x74].pack('CC')
|
|
304
|
+
pack_integer(value.nanoseconds)
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
def pack_point(value)
|
|
308
|
+
if value.z.nil?
|
|
309
|
+
# Point2D: signature 0x58, 3 fields (srid, x, y)
|
|
310
|
+
@buffer << [TINY_STRUCT | 3, 0x58].pack('CC')
|
|
311
|
+
pack_integer(value.srid)
|
|
312
|
+
pack_float(value.x)
|
|
313
|
+
pack_float(value.y)
|
|
314
|
+
else
|
|
315
|
+
# Point3D: signature 0x59, 4 fields (srid, x, y, z)
|
|
316
|
+
@buffer << [TINY_STRUCT | 4, 0x59].pack('CC')
|
|
317
|
+
pack_integer(value.srid)
|
|
318
|
+
pack_float(value.x)
|
|
319
|
+
pack_float(value.y)
|
|
320
|
+
pack_float(value.z)
|
|
321
|
+
end
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
def pack_duration(value)
|
|
325
|
+
# Duration: signature 0x45, 4 fields (months, days, seconds, nanoseconds)
|
|
326
|
+
@buffer << [TINY_STRUCT | 4, 0x45].pack('CC')
|
|
327
|
+
pack_integer(value.months)
|
|
328
|
+
pack_integer(value.days)
|
|
329
|
+
pack_integer(value.seconds)
|
|
330
|
+
pack_integer(value.nanoseconds)
|
|
331
|
+
end
|
|
332
|
+
end
|
|
333
|
+
end
|
|
334
|
+
end
|
|
335
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Neo4j
|
|
4
|
+
module Driver
|
|
5
|
+
module PackStream
|
|
6
|
+
# Represents a PackStream Structure with a signature and fields
|
|
7
|
+
class Structure
|
|
8
|
+
attr_reader :signature, :fields
|
|
9
|
+
|
|
10
|
+
def initialize(signature, fields = [])
|
|
11
|
+
@signature = signature
|
|
12
|
+
@fields = fields
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def ==(other)
|
|
16
|
+
other.is_a?(Structure) &&
|
|
17
|
+
other.signature == @signature &&
|
|
18
|
+
other.fields == @fields
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def to_s
|
|
22
|
+
"Structure(0x#{@signature.to_s(16).upcase}, #{@fields.inspect})"
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Neo4j
|
|
4
|
+
module Driver
|
|
5
|
+
module PackStream
|
|
6
|
+
# PackStream Unpacker - deserializes PackStream binary format to Ruby objects
|
|
7
|
+
class Unpacker
|
|
8
|
+
include Markers
|
|
9
|
+
|
|
10
|
+
def initialize(io, protocol)
|
|
11
|
+
@io = io
|
|
12
|
+
@hydration_handlers = {}
|
|
13
|
+
@protocol = protocol
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def register_hydration_handler(signature, handler = nil, &block)
|
|
17
|
+
@hydration_handlers[signature] = handler || block
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def unpack
|
|
21
|
+
marker_byte = read_bytes(1).unpack1('C')
|
|
22
|
+
unpack_value(marker_byte)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# PackStream V2 UUID (Bolt 6.1+): 16 raw bytes (big-endian) after the
|
|
26
|
+
# marker, rendered to the canonical hyphenated form for Types::UUID.
|
|
27
|
+
# Called by Protocol::V61#unpack_uuid — earlier protocols reject the
|
|
28
|
+
# marker instead, so this is only reached once 6.1 is negotiated.
|
|
29
|
+
def unpack_uuid_value
|
|
30
|
+
hex = read_bytes(16).unpack1('H*')
|
|
31
|
+
Types::UUID.from_string(
|
|
32
|
+
"#{hex[0, 8]}-#{hex[8, 4]}-#{hex[12, 4]}-#{hex[16, 4]}-#{hex[20, 12]}"
|
|
33
|
+
)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# A ProtocolException (not a bare RuntimeError) so the failure reaches
|
|
37
|
+
# the user as a DriverError. The wording carries "PackStream" and the
|
|
38
|
+
# zero-padded marker byte — e.g. a UUID (0xE0) received before Bolt 6.1,
|
|
39
|
+
# which Protocol::Base#unpack_uuid routes here. testkit's UUID-over-6.0
|
|
40
|
+
# assertion greps the lowercased message for "unknown packstream" and
|
|
41
|
+
# "e0", both of which this satisfies.
|
|
42
|
+
def raise_unknown_marker(marker)
|
|
43
|
+
raise Exceptions::ProtocolException,
|
|
44
|
+
format('Unknown PackStream type marker: 0x%02x', marker)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
private
|
|
48
|
+
|
|
49
|
+
def unpack_value(marker)
|
|
50
|
+
case marker
|
|
51
|
+
when NULL
|
|
52
|
+
nil
|
|
53
|
+
when BOOLEAN_FALSE
|
|
54
|
+
false
|
|
55
|
+
when BOOLEAN_TRUE
|
|
56
|
+
true
|
|
57
|
+
when FLOAT_64
|
|
58
|
+
read_bytes(8).unpack1('G')
|
|
59
|
+
when INT_8
|
|
60
|
+
read_bytes(1).unpack1('c')
|
|
61
|
+
when INT_16
|
|
62
|
+
read_bytes(2).unpack1('s>')
|
|
63
|
+
when INT_32
|
|
64
|
+
read_bytes(4).unpack1('l>')
|
|
65
|
+
when INT_64
|
|
66
|
+
read_bytes(8).unpack1('q>')
|
|
67
|
+
when 0xC8..0xCB
|
|
68
|
+
# Already handled above, but needed for case coverage
|
|
69
|
+
raise "Unexpected marker in unpack_value: #{marker}"
|
|
70
|
+
when BYTES_8
|
|
71
|
+
size = read_bytes(1).unpack1('C')
|
|
72
|
+
read_bytes(size).force_encoding(Encoding::BINARY)
|
|
73
|
+
when BYTES_16
|
|
74
|
+
size = read_bytes(2).unpack1('S>')
|
|
75
|
+
read_bytes(size).force_encoding(Encoding::BINARY)
|
|
76
|
+
when BYTES_32
|
|
77
|
+
size = read_bytes(4).unpack1('L>')
|
|
78
|
+
read_bytes(size).force_encoding(Encoding::BINARY)
|
|
79
|
+
when STRING_8
|
|
80
|
+
size = read_bytes(1).unpack1('C')
|
|
81
|
+
read_bytes(size).force_encoding(Encoding::UTF_8)
|
|
82
|
+
when STRING_16
|
|
83
|
+
size = read_bytes(2).unpack1('S>')
|
|
84
|
+
read_bytes(size).force_encoding(Encoding::UTF_8)
|
|
85
|
+
when STRING_32
|
|
86
|
+
size = read_bytes(4).unpack1('L>')
|
|
87
|
+
read_bytes(size).force_encoding(Encoding::UTF_8)
|
|
88
|
+
when LIST_8
|
|
89
|
+
size = read_bytes(1).unpack1('C')
|
|
90
|
+
unpack_list(size)
|
|
91
|
+
when LIST_16
|
|
92
|
+
size = read_bytes(2).unpack1('S>')
|
|
93
|
+
unpack_list(size)
|
|
94
|
+
when LIST_32
|
|
95
|
+
size = read_bytes(4).unpack1('L>')
|
|
96
|
+
unpack_list(size)
|
|
97
|
+
when MAP_8
|
|
98
|
+
size = read_bytes(1).unpack1('C')
|
|
99
|
+
unpack_map(size)
|
|
100
|
+
when MAP_16
|
|
101
|
+
size = read_bytes(2).unpack1('S>')
|
|
102
|
+
unpack_map(size)
|
|
103
|
+
when MAP_32
|
|
104
|
+
size = read_bytes(4).unpack1('L>')
|
|
105
|
+
unpack_map(size)
|
|
106
|
+
when STRUCT_8
|
|
107
|
+
size = read_bytes(1).unpack1('C')
|
|
108
|
+
unpack_structure(size)
|
|
109
|
+
when STRUCT_16
|
|
110
|
+
size = read_bytes(2).unpack1('S>')
|
|
111
|
+
unpack_structure(size)
|
|
112
|
+
when UUID
|
|
113
|
+
# A PackStream V2 type: only the negotiated protocol decides whether
|
|
114
|
+
# the marker is known — V61 reads it, every earlier version rejects
|
|
115
|
+
# it as an unknown marker.
|
|
116
|
+
@protocol.unpack_uuid(self)
|
|
117
|
+
else
|
|
118
|
+
# Check for TINY types
|
|
119
|
+
if (marker & 0xF0) == TINY_STRING
|
|
120
|
+
size = marker & 0x0F
|
|
121
|
+
read_bytes(size).force_encoding(Encoding::UTF_8)
|
|
122
|
+
elsif (marker & 0xF0) == TINY_LIST
|
|
123
|
+
size = marker & 0x0F
|
|
124
|
+
unpack_list(size)
|
|
125
|
+
elsif (marker & 0xF0) == TINY_MAP
|
|
126
|
+
size = marker & 0x0F
|
|
127
|
+
unpack_map(size)
|
|
128
|
+
elsif (marker & 0xF0) == TINY_STRUCT
|
|
129
|
+
size = marker & 0x0F
|
|
130
|
+
unpack_structure(size)
|
|
131
|
+
elsif marker >= 0xF0 || marker <= 0x7F
|
|
132
|
+
# TINY_INT range: -16 to 127
|
|
133
|
+
# Values from 0xF0-0xFF represent -16 to -1
|
|
134
|
+
# Values from 0x00-0x7F represent 0 to 127
|
|
135
|
+
if marker >= 0xF0
|
|
136
|
+
marker - 256 # Convert to negative
|
|
137
|
+
else
|
|
138
|
+
marker
|
|
139
|
+
end
|
|
140
|
+
else
|
|
141
|
+
raise_unknown_marker(marker)
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def unpack_list(size) = Array.new(size) { unpack }
|
|
147
|
+
|
|
148
|
+
def unpack_map(size)
|
|
149
|
+
{}.tap { |map| size.times { map[unpack.to_sym] = unpack } }
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def unpack_structure(size)
|
|
153
|
+
signature = read_bytes(1).unpack1('C')
|
|
154
|
+
fields = Array.new(size) { unpack }
|
|
155
|
+
handler = @hydration_handlers[signature] or
|
|
156
|
+
raise "No hydration handler for PackStream structure signature 0x#{signature.to_s(16)}"
|
|
157
|
+
|
|
158
|
+
handler.call(fields)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def read_bytes(n)
|
|
162
|
+
data = @io.read(n)
|
|
163
|
+
raise IOError, 'Unexpected end of stream' if data.nil? || data.bytesize < n
|
|
164
|
+
|
|
165
|
+
data
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Neo4j
|
|
4
|
+
module Driver
|
|
5
|
+
# Represents a single record (row) in a result
|
|
6
|
+
class Record
|
|
7
|
+
def initialize(keys, values)
|
|
8
|
+
@keys = keys
|
|
9
|
+
@values = values
|
|
10
|
+
# Create map with string keys for consistent lookup
|
|
11
|
+
@map = {}
|
|
12
|
+
@keys.each_with_index do |key, idx|
|
|
13
|
+
@map[key.to_s] = @values[idx]
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
attr_reader :keys, :values
|
|
18
|
+
|
|
19
|
+
def [](key)
|
|
20
|
+
case key
|
|
21
|
+
when Integer
|
|
22
|
+
@values[key]
|
|
23
|
+
when String, Symbol
|
|
24
|
+
@map[key.to_s]
|
|
25
|
+
else
|
|
26
|
+
raise ArgumentError, "Invalid key type: #{key.class}"
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def first
|
|
31
|
+
@values.first
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def to_h
|
|
35
|
+
@map.dup
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def each(&)
|
|
39
|
+
@map.each(&)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|