├── .codeclimate.yml ├── .github └── workflows │ ├── specs.yml │ └── testkit.yml ├── .gitignore ├── .rspec ├── .rubocop.yml ├── CHANGELOG.md ├── History.txt ├── LICENSE.txt ├── README.md ├── Rakefile ├── bin ├── console ├── setup ├── testkit-backend └── testkit-setup ├── docs ├── dev_manual_examples.rb └── dev_manual_todo_examples.rb ├── jruby └── neo4j │ ├── driver.rb │ └── driver │ ├── ext │ ├── async_converter.rb │ ├── auth_tokens.rb │ ├── bookmark.rb │ ├── config_converter.rb │ ├── delegating_transaction_context.rb │ ├── exception_checkable.rb │ ├── exception_mapper.rb │ ├── graph_database.rb │ ├── internal │ │ ├── async │ │ │ └── internal_async_session.rb │ │ ├── cluster │ │ │ └── routing_table_registry_impl.rb │ │ ├── cursor │ │ │ └── disposable_async_result_cursor.rb │ │ ├── driver_factory.rb │ │ ├── internal_bookmark.rb │ │ ├── metrics │ │ │ └── internal_connection_pool_metrics.rb │ │ └── summary │ │ │ ├── internal_notification.rb │ │ │ ├── internal_plan.rb │ │ │ └── internal_result_summary.rb │ ├── internal_driver.rb │ ├── internal_entity.rb │ ├── internal_keys.rb │ ├── internal_node.rb │ ├── internal_record.rb │ ├── internal_relationship.rb │ ├── internal_result.rb │ ├── internal_session.rb │ ├── internal_transaction.rb │ ├── logger.rb │ ├── map_converter.rb │ ├── neo_converter.rb │ ├── query.rb │ ├── ruby_converter.rb │ ├── run_override.rb │ └── start_end_naming.rb │ └── version.rb ├── lib ├── neo4j-ruby-driver.rb ├── neo4j-ruby-driver_loader.rb ├── neo4j │ └── driver │ │ ├── auto_closable.rb │ │ ├── exceptions │ │ ├── authentication_exception.rb │ │ ├── authorization_expired_exception.rb │ │ ├── certificate_exception.rb │ │ ├── client_exception.rb │ │ ├── connection_read_timeout_exception.rb │ │ ├── database_exception.rb │ │ ├── discovery_exception.rb │ │ ├── fatal_discovery_exception.rb │ │ ├── illegal_state_exception.rb │ │ ├── neo4j_exception.rb │ │ ├── no_such_record_exception.rb │ │ ├── protocol_exception.rb │ │ ├── result_consumed_exception.rb │ │ ├── security_exception.rb │ │ ├── service_unavailable_exception.rb │ │ ├── session_expired_exception.rb │ │ ├── token_expired_exception.rb │ │ ├── transaction_nesting_exception.rb │ │ ├── transient_exception.rb │ │ ├── unsupported_feature_exception.rb │ │ ├── untrusted_server_exception.rb │ │ └── value │ │ │ ├── lossy_coercion.rb │ │ │ ├── not_multi_valued.rb │ │ │ ├── uncoercible.rb │ │ │ ├── unsizable.rb │ │ │ └── value_exception.rb │ │ ├── internal │ │ ├── bolt_server_address.rb │ │ ├── deprecator.rb │ │ ├── duration_normalizer.rb │ │ └── validator.rb │ │ ├── summary │ │ └── query_type.rb │ │ ├── synchronizable.rb │ │ └── types │ │ ├── local_date_time.rb │ │ ├── local_time.rb │ │ ├── offset_time.rb │ │ ├── point.rb │ │ └── time.rb └── neo4j_ruby_driver.rb ├── ruby └── neo4j │ ├── driver.rb │ └── driver │ ├── access_mode.rb │ ├── auth_tokens.rb │ ├── bookmark.rb │ ├── config.rb │ ├── graph_database.rb │ ├── internal │ ├── async │ │ ├── connection │ │ │ ├── bolt_protocol_util.rb │ │ │ ├── bootstrap_factory.rb │ │ │ ├── channel_attributes.rb │ │ │ ├── channel_connected_listener.rb │ │ │ ├── channel_connector_impl.rb │ │ │ ├── channel_pipeline_builder_impl.rb │ │ │ ├── direct_connection.rb │ │ │ ├── event_loop_group_factory.rb │ │ │ ├── handshake_completed_listener.rb │ │ │ ├── handshake_handler.rb │ │ │ ├── netty_channel_initializer.rb │ │ │ ├── netty_domain_name_resolver.rb │ │ │ ├── netty_domain_name_resolver_group.rb │ │ │ ├── routing_connection.rb │ │ │ ├── stream.rb │ │ │ └── stream_reader.rb │ │ ├── connection_context.rb │ │ ├── immutable_connection_context.rb │ │ ├── inbound │ │ │ ├── byte_buf_input.rb │ │ │ ├── channel_error_handler.rb │ │ │ ├── chunk_decoder.rb │ │ │ ├── connect_timeout_handler.rb │ │ │ ├── connection_read_timeout_handler.rb │ │ │ ├── inbound_message_dispatcher.rb │ │ │ ├── inbound_message_handler.rb │ │ │ └── message_decoder.rb │ │ ├── internal_async_session.rb │ │ ├── internal_async_transaction.rb │ │ ├── leak_logging_network_session.rb │ │ ├── network_connection.rb │ │ ├── network_session.rb │ │ ├── outbound │ │ │ ├── chunk_aware_byte_buf_output.rb │ │ │ └── outbound_message_handler.rb │ │ ├── pool │ │ │ ├── channel.rb │ │ │ ├── channel_pool.rb │ │ │ ├── channel_tracker.rb │ │ │ ├── connection_pool_impl.rb │ │ │ ├── netty_channel_health_checker.rb │ │ │ ├── netty_channel_pool.rb │ │ │ ├── network_connection_factory.rb │ │ │ ├── pool_settings.rb │ │ │ └── timed_stack.rb │ │ ├── result_cursors_holder.rb │ │ └── unmanaged_transaction.rb │ ├── bookmark_holder.rb │ ├── cluster │ │ ├── cluster_composition.rb │ │ ├── cluster_composition_lookup_result.rb │ │ ├── cluster_routing_table.rb │ │ ├── identity_resolver.rb │ │ ├── loadbalancing │ │ │ ├── least_connected_load_balancing_strategy.rb │ │ │ ├── load_balancer.rb │ │ │ └── round_robin_array_index.rb │ │ ├── multi_databases_routing_procedure_runner.rb │ │ ├── rediscovery_impl.rb │ │ ├── route_message_routing_procedure_runner.rb │ │ ├── routing_context.rb │ │ ├── routing_procedure_cluster_composition_provider.rb │ │ ├── routing_procedure_response.rb │ │ ├── routing_settings.rb │ │ ├── routing_table_handler_impl.rb │ │ ├── routing_table_registry_impl.rb │ │ └── single_database_routing_procedure_runner.rb │ ├── connection_settings.rb │ ├── cursor │ │ ├── async_result_cursor_impl.rb │ │ ├── async_result_cursor_only_factory.rb │ │ ├── disposable_async_result_cursor.rb │ │ ├── result_cursor_factory_impl.rb │ │ └── rx_result_cursor_impl.rb │ ├── database_name_util.rb │ ├── default_bookmark_holder.rb │ ├── default_domain_name_resolver.rb │ ├── delegating_transaction.rb │ ├── direct_connection_provider.rb │ ├── driver_factory.rb │ ├── handlers │ │ ├── begin_tx_response_handler.rb │ │ ├── channel_releasing_reset_response_handler.rb │ │ ├── commit_tx_response_handler.rb │ │ ├── hello_response_handler.rb │ │ ├── init_response_handler.rb │ │ ├── legacy_pull_all_response_handler.rb │ │ ├── no_op_response_handler.rb │ │ ├── ping_response_handler.rb │ │ ├── pull_handlers.rb │ │ ├── pulln │ │ │ ├── auto_pull_response_handler.rb │ │ │ ├── basic_pull_response_handler.rb │ │ │ └── fetch_size_util.rb │ │ ├── reset_response_handler.rb │ │ ├── rollback_tx_response_handler.rb │ │ ├── route_message_response_handler.rb │ │ ├── routing_response_handler.rb │ │ ├── run_response_handler.rb │ │ ├── session_pull_response_completion_listener.rb │ │ └── transaction_pull_response_completion_listener.rb │ ├── impersonation_util.rb │ ├── internal_bookmark.rb │ ├── internal_database_name.rb │ ├── internal_driver.rb │ ├── internal_entity.rb │ ├── internal_node.rb │ ├── internal_pair.rb │ ├── internal_path.rb │ ├── internal_point2_d.rb │ ├── internal_point3_d.rb │ ├── internal_record.rb │ ├── internal_relationship.rb │ ├── internal_result.rb │ ├── internal_session.rb │ ├── internal_transaction.rb │ ├── logging │ │ ├── channel_activity_logger.rb │ │ ├── channel_error_logger.rb │ │ ├── prefixed_logger.rb │ │ └── reformatted_logger.rb │ ├── messaging │ │ ├── abstract_message_writer.rb │ │ ├── bolt_protocol.rb │ │ ├── bolt_protocol_version.rb │ │ ├── common │ │ │ ├── common_message_reader.rb │ │ │ ├── common_value.rb │ │ │ ├── common_value_packer.rb │ │ │ └── common_value_unpacker.rb │ │ ├── encode │ │ │ ├── begin_message_encoder.rb │ │ │ ├── commit_message_encoder.rb │ │ │ ├── discard_all_message_encoder.rb │ │ │ ├── discard_message_encoder.rb │ │ │ ├── goodbye_message_encoder.rb │ │ │ ├── hello_message_encoder.rb │ │ │ ├── init_message_encoder.rb │ │ │ ├── logoff_message_encoder.rb │ │ │ ├── logon_message_encoder.rb │ │ │ ├── pull_all_message_encoder.rb │ │ │ ├── pull_message_encoder.rb │ │ │ ├── reset_message_encoder.rb │ │ │ ├── rollback_message_encoder.rb │ │ │ ├── route_message_encoder.rb │ │ │ ├── route_v44_message_encoder.rb │ │ │ ├── run_message_encoder.rb │ │ │ └── run_with_metadata_message_encoder.rb │ │ ├── request │ │ │ ├── abstract_streaming_message.rb │ │ │ ├── begin_message.rb │ │ │ ├── commit_message.rb │ │ │ ├── discard_all_message.rb │ │ │ ├── discard_message.rb │ │ │ ├── goodbye_message.rb │ │ │ ├── hello_message.rb │ │ │ ├── init_message.rb │ │ │ ├── logoff_message.rb │ │ │ ├── logon_message.rb │ │ │ ├── message_with_metadata.rb │ │ │ ├── multi_database_util.rb │ │ │ ├── pull_all_message.rb │ │ │ ├── pull_message.rb │ │ │ ├── reset_message.rb │ │ │ ├── rollback_message.rb │ │ │ ├── route_message.rb │ │ │ ├── run_message.rb │ │ │ ├── run_with_metadata_message.rb │ │ │ └── transaction_metadata_builder.rb │ │ ├── response │ │ │ ├── failure_message.rb │ │ │ ├── ignored_message.rb │ │ │ ├── record_message.rb │ │ │ └── success_message.rb │ │ ├── v3 │ │ │ ├── bolt_protocol_v3.rb │ │ │ ├── message_format_v3.rb │ │ │ └── message_writer_v3.rb │ │ ├── v4 │ │ │ ├── bolt_protocol_v4.rb │ │ │ ├── message_format_v4.rb │ │ │ └── message_writer_v4.rb │ │ ├── v41 │ │ │ └── bolt_protocol_v41.rb │ │ ├── v42 │ │ │ └── bolt_protocol_v42.rb │ │ ├── v43 │ │ │ ├── bolt_protocol_v43.rb │ │ │ ├── message_format_v43.rb │ │ │ └── message_writer_v43.rb │ │ ├── v44 │ │ │ ├── bolt_protocol_v44.rb │ │ │ ├── message_format_v44.rb │ │ │ └── message_writer_v44.rb │ │ ├── v5 │ │ │ ├── bolt_protocol_v5.rb │ │ │ ├── message_format_v5.rb │ │ │ └── value_unpacker_v5.rb │ │ └── v51 │ │ │ ├── bolt_protocol_v51.rb │ │ │ ├── message_format_v51.rb │ │ │ └── message_writer_v51.rb │ ├── metrics │ │ ├── connection_pool_metrics_listener.rb │ │ ├── internal_abstract_metrics.rb │ │ ├── internal_connection_pool_metrics.rb │ │ ├── internal_metrics.rb │ │ ├── internal_metrics_provider.rb │ │ ├── listener_event.rb │ │ ├── metrics_provider.rb │ │ └── time_recorder_listener_event.rb │ ├── packstream │ │ ├── byte_array_incompatible_packer.rb │ │ ├── pack_input.rb │ │ ├── pack_output.rb │ │ ├── pack_stream.rb │ │ └── pack_type.rb │ ├── read_only_bookmark_holder.rb │ ├── resolved_bolt_server_address.rb │ ├── retry │ │ └── exponential_backoff_retry_logic.rb │ ├── revocation_strategy.rb │ ├── scheme.rb │ ├── security │ │ ├── internal_auth_token.rb │ │ └── security_plan_impl.rb │ ├── security_setting.rb │ ├── session_factory_impl.rb │ ├── spi │ │ ├── connection.rb │ │ ├── connection_pool.rb │ │ └── response_handler.rb │ ├── summary │ │ ├── internal_database_info.rb │ │ ├── internal_input_position.rb │ │ ├── internal_notification.rb │ │ ├── internal_plan.rb │ │ ├── internal_profiled_plan.rb │ │ ├── internal_result_summary.rb │ │ ├── internal_server_info.rb │ │ └── internal_summary_counters.rb │ ├── svm │ │ ├── netty_substitutions.rb │ │ └── z_lib_substitutions.rb │ └── util │ │ ├── certificate_tool.rb │ │ ├── clock.rb │ │ ├── error_util.rb │ │ ├── extract.rb │ │ ├── format.rb │ │ ├── futures.rb │ │ ├── iterables.rb │ │ ├── lock_util.rb │ │ ├── metadata_extractor.rb │ │ ├── mutex.rb │ │ ├── preconditions.rb │ │ ├── result_holder.rb │ │ └── server_version.rb │ ├── logging1.rb │ ├── net │ └── server_address.rb │ ├── query.rb │ ├── records.rb │ ├── transaction_config.rb │ ├── values.rb │ └── version.rb ├── spec ├── integration │ ├── async │ │ └── async_session_spec.rb │ ├── bookmark_spec.rb │ ├── causal_clustering_spec.rb │ ├── direct_driver_spec.rb │ ├── load_csv_spec.rb │ ├── logging_spec.rb │ ├── parameters_spec.rb │ ├── result_stream_spec.rb │ ├── scalar_types_spec.rb │ ├── session_spec.rb │ ├── summary_spec.rb │ └── transaction_spec.rb ├── neo4j │ └── driver │ │ ├── auth_tokens_spec.rb │ │ ├── dev_manual_examples_spec.rb │ │ ├── duration_spec.rb │ │ ├── exceptions │ │ ├── authentication_exception_spec.rb │ │ └── client_exception_spec.rb │ │ ├── graph_database_spec.rb │ │ ├── result_spec.rb │ │ ├── simplified_examples_spec.rb │ │ ├── temporal_types_spec.rb │ │ ├── types │ │ ├── local_date_time_spec.rb │ │ ├── local_time_spec.rb │ │ ├── node_spec.rb │ │ ├── offset_time_spec.rb │ │ ├── path_spec.rb │ │ └── relationship_spec.rb │ │ ├── types_spec.rb │ │ └── util │ │ ├── cc │ │ ├── cluster.rb │ │ ├── cluster_control.rb │ │ ├── cluster_member.rb │ │ └── shared_cluster.rb │ │ └── test_util.rb ├── ruby │ └── neo4j │ │ └── driver │ │ └── internal │ │ └── util │ │ └── server_version_spec.rb ├── spec_helper.rb └── support │ ├── cluster_extension.rb │ ├── driver_helper.rb │ └── neo4j_cleaner.rb ├── testkit-backend ├── .gitignore ├── .rspec ├── .travis.yml ├── CODE_OF_CONDUCT.md ├── LICENSE.txt ├── README.md ├── Rakefile ├── bin │ ├── console │ ├── echo_server.rb │ ├── null-backend │ ├── setup │ └── testkit-backend ├── exe │ └── testkit-backend ├── gems.rb ├── lib │ └── testkit │ │ ├── backend.rb │ │ └── backend │ │ ├── command_processor.rb │ │ ├── loader.rb │ │ ├── messages │ │ ├── conversion.rb │ │ ├── request.rb │ │ ├── requests │ │ │ ├── authorization_token.rb │ │ │ ├── check_driver_is_encrypted.rb │ │ │ ├── check_multi_d_b_support.rb │ │ │ ├── check_session_auth_support.rb │ │ │ ├── cypher_bytes.rb │ │ │ ├── cypher_date.rb │ │ │ ├── cypher_date_time.rb │ │ │ ├── cypher_duration.rb │ │ │ ├── cypher_float.rb │ │ │ ├── cypher_list.rb │ │ │ ├── cypher_map.rb │ │ │ ├── cypher_time.rb │ │ │ ├── cypher_value.rb │ │ │ ├── domain_name_resolution_completed.rb │ │ │ ├── driver_close.rb │ │ │ ├── forced_routing_table_update.rb │ │ │ ├── get_connection_pool_metrics.rb │ │ │ ├── get_features.rb │ │ │ ├── get_routing_table.rb │ │ │ ├── new_driver.rb │ │ │ ├── new_session.rb │ │ │ ├── resolver_resolution_completed.rb │ │ │ ├── result_consume.rb │ │ │ ├── result_list.rb │ │ │ ├── result_next.rb │ │ │ ├── result_peek.rb │ │ │ ├── result_single.rb │ │ │ ├── retryable.rb │ │ │ ├── retryable_negative.rb │ │ │ ├── retryable_positive.rb │ │ │ ├── rollback_exception.rb │ │ │ ├── session_begin_transaction.rb │ │ │ ├── session_close.rb │ │ │ ├── session_last_bookmarks.rb │ │ │ ├── session_read_transaction.rb │ │ │ ├── session_run.rb │ │ │ ├── session_transaction.rb │ │ │ ├── session_write_transaction.rb │ │ │ ├── start_test.rb │ │ │ ├── transaction_close.rb │ │ │ ├── transaction_commit.rb │ │ │ ├── transaction_rollback.rb │ │ │ ├── transaction_run.rb │ │ │ ├── verify_authentication.rb │ │ │ └── verify_connectivity.rb │ │ ├── response.rb │ │ ├── responses │ │ │ ├── driver_error.rb │ │ │ └── result.rb │ │ └── rollback_exception.rb │ │ ├── object_cache.rb │ │ ├── runner.rb │ │ └── version.rb ├── spec │ ├── spec_helper.rb │ └── testkit │ │ ├── backend │ │ └── runner_spec.rb │ │ └── backend_spec.rb └── testkit-backend.gemspec └── testkit ├── .dockerignore ├── Dockerfile ├── backend.py ├── build.py ├── integration.py ├── stress.py └── unittests.py /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | plugins: 3 | structure: 4 | enabled: true 5 | duplication: 6 | enabled: true 7 | config: 8 | languages: 9 | - ruby 10 | fixme: 11 | enabled: true 12 | rubocop: 13 | enabled: true 14 | flog: 15 | enabled: true 16 | config: 17 | score_threshold: 20.0 18 | git-legal: 19 | enabled: true 20 | exclude_patterns: 21 | - db/ 22 | - docs/ 23 | - "**/log/" 24 | - "**.log" 25 | - ".idea/" 26 | - ".git/" 27 | - ".DS_Store" 28 | - ".autotest" 29 | - "**/neo4j-java-driver_jars.rb" 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.bundle/ 2 | /.yardoc 3 | /_yardoc/ 4 | /coverage/ 5 | /pkg/ 6 | /spec/reports/ 7 | /tmp/ 8 | 9 | # rspec failure tracking 10 | .rspec_status 11 | 12 | .ruby-version 13 | .rakeTasks 14 | *.lock 15 | *.jar 16 | *.gem 17 | *.gemspec 18 | *.crt 19 | .env 20 | .idea/ 21 | .mvn/ 22 | db/ 23 | servers/ 24 | obsolete/ 25 | 26 | neo4j-ruby-driver_jars.rb 27 | Gemfile 28 | 29 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --format documentation 2 | --color 3 | --require spec_helper 4 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | require: rubocop-rspec 2 | AllCops: 3 | TargetRubyVersion: 2.5 4 | Metrics/LineLength: 5 | Max: 120 6 | Metrics/BlockLength: 7 | ExcludedMethods: ['describe', 'context'] 8 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to this project will be documented in this file. 3 | This file should follow the standards specified on [http://keepachangelog.com/] 4 | This project adheres to [Semantic Versioning](http://semver.org/). 5 | 6 | ## [0.3.1] 2020-01-21 7 | 8 | ## Fixed 9 | 10 | - values Node#properties were not properly converted from java to ruby 11 | -------------------------------------------------------------------------------- /History.txt: -------------------------------------------------------------------------------- 1 | === 5.7.0.alpha.4 / 2025-01-14 2 | === 5.27.0.alpha.0 / 2025-01-13 3 | === 5.7.0.alpha.3 / 2025-01-13 4 | === 5.7.0.alpha.2 / 2025-01-13 5 | === 4.4.19 / 2024-12-16 6 | === 4.4.6 / 2024-12-16 7 | === 4.4.16 / 2023-05-03 8 | === 5.19.0.alpha.0 / 2023-04-24 9 | === 5.15.0.alpha.0 / 2023-12-14 10 | === 5.13.0.alpha.3 / 2023-10-15 11 | === 5.13.0.alpha.2 / 2023-10-15 12 | === 5.13.0.alpha.1 / 2023-10-08 13 | === 4.4.6 / 2023-10-12 14 | === 4.4.5 / 2023-02-09 15 | === 4.4.4 / 2023-02-06 16 | === 4.4.3 / 2023-02-06 17 | === 4.4.2 / 2023-01-10 18 | === 4.4.1 / 2023-01-10 19 | === 0.1.2 / 2019-09-20 20 | 21 | * Hoe migration 22 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 Heinrich Klobuczek 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /bin/console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | # frozen_string_literal: true 4 | 5 | require 'bundler/setup' 6 | require 'neo4j/driver' 7 | 8 | # You can add fixtures and/or initialization code here to make experimenting 9 | # with your gem easier. You can also use a different console, if you like. 10 | 11 | # (If you use this, don't forget to add pry to your Gemfile!) 12 | # require "pry" 13 | # Pry.start 14 | 15 | require 'irb' 16 | IRB.start(__FILE__) 17 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | IFS=$'\n\t' 4 | set -vx 5 | 6 | gem install rake 7 | gem install hoe 8 | gem install hoe-bundler 9 | gem install hoe-gemspec 10 | rake clean bundler:gemfile[,true] gem:spec 11 | bundle update 12 | 13 | # Do any other automated setup that you need to do here 14 | -------------------------------------------------------------------------------- /bin/testkit-backend: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | IFS=$'\n\t' 4 | set -vx 5 | 6 | (cd testkit-backend; bin/testkit-backend) 7 | # Do any other automated setup that you need to do here 8 | -------------------------------------------------------------------------------- /bin/testkit-setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | IFS=$'\n\t' 4 | set -vx 5 | 6 | (cd testkit-backend; bin/setup) 7 | # Do any other automated setup that you need to do here 8 | -------------------------------------------------------------------------------- /jruby/neo4j/driver/ext/auth_tokens.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Ext 6 | module AuthTokens 7 | include NeoConverter 8 | 9 | def basic(username, password, realm = nil) 10 | Neo4j::Driver::Internal::Validator.require_non_nil_credentials!(username, password) 11 | super 12 | end 13 | 14 | def custom(principal, credentials, realm, scheme, **parameters) 15 | super(principal, credentials, realm, scheme, to_neo(parameters)) 16 | end 17 | end 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /jruby/neo4j/driver/ext/bookmark.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Ext 6 | module Bookmark 7 | module ClassMethods 8 | def from(*values) 9 | super(java.util.HashSet.new(values)) 10 | end 11 | end 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /jruby/neo4j/driver/ext/delegating_transaction_context.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Ext 6 | module DelegatingTransactionContext 7 | include ExceptionCheckable 8 | include RunOverride 9 | 10 | def run(statement, **parameters) 11 | check { super(to_statement(statement, parameters)) } 12 | end 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /jruby/neo4j/driver/ext/exception_checkable.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Ext 6 | module ExceptionCheckable 7 | include ExceptionMapper 8 | 9 | def check 10 | yield 11 | rescue Java::JavaLang::RuntimeException => e 12 | raise mapped_exception(e) 13 | end 14 | 15 | def reverse_check 16 | yield 17 | rescue Neo4j::Driver::Exceptions::ServiceUnavailableException => e 18 | raise(throwable(e.cause) || Java::OrgNeo4jDriverExceptions::ServiceUnavailableException.new(e.message)) 19 | rescue Neo4j::Driver::Exceptions::Neo4jException, 20 | Neo4j::Driver::Exceptions::NoSuchRecordException, 21 | Neo4j::Driver::Exceptions::UntrustedServerException, 22 | Neo4j::Driver::Exceptions::IllegalStateException => e 23 | raise(throwable(e.cause) || e) 24 | end 25 | 26 | private 27 | 28 | def throwable(e) 29 | e if e.is_a? Java::JavaLang::Throwable 30 | end 31 | end 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /jruby/neo4j/driver/ext/graph_database.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Ext 6 | module GraphDatabase 7 | extend AutoClosable 8 | include ConfigConverter 9 | include ExceptionCheckable 10 | 11 | auto_closable :driver 12 | 13 | def driver(uri, auth_token = Neo4j::Driver::AuthTokens.none, **config) 14 | check do 15 | java_method(:driver, [java.lang.String, org.neo4j.driver.AuthToken, org.neo4j.driver.Config]) 16 | .call(uri.to_s, auth_token, to_java_config(Neo4j::Driver::Config, **config)) 17 | end 18 | end 19 | 20 | def internal_driver(uri, auth_token = Neo4j::Driver::AuthTokens.none, **config, &domain_name_resolver) 21 | check do 22 | java_uri = java.net.URI.create(uri.to_s) 23 | java_config = to_java_config(Neo4j::Driver::Config, **config) 24 | Internal::DriverFactory 25 | .new(&domain_name_resolver) 26 | .new_instance(java_uri, org.neo4j.driver.internal.security.StaticAuthTokenManager.new(auth_token), 27 | java_config) 28 | end 29 | end 30 | end 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /jruby/neo4j/driver/ext/internal/async/internal_async_session.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Ext 6 | module Internal 7 | module Async 8 | module InternalAsyncSession 9 | include ConfigConverter 10 | include RunOverride 11 | include AsyncConverter 12 | 13 | def run_async(statement, parameters = {}, config = {}) 14 | to_future( 15 | java_method(:runAsync, [org.neo4j.driver.Query, org.neo4j.driver.TransactionConfig]) 16 | .call(to_statement(statement, parameters), to_java_config(Neo4j::Driver::TransactionConfig, **config))) 17 | end 18 | end 19 | end 20 | end 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /jruby/neo4j/driver/ext/internal/cluster/routing_table_registry_impl.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j::Driver::Ext 4 | module Internal 5 | module Cluster 6 | module RoutingTableRegistryImpl 7 | def routing_table_handler(database) 8 | get_routing_table_handler(org.neo4j.driver.internal.bolt.api.DatabaseNameUtil.database(database)).then do |it| 9 | it.get if it.present? 10 | end 11 | end 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /jruby/neo4j/driver/ext/internal/cursor/disposable_async_result_cursor.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j::Driver::Ext 4 | module Internal 5 | module Cursor 6 | module DisposableAsyncResultCursor 7 | include AsyncConverter 8 | 9 | def next_async 10 | to_future(super) 11 | end 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /jruby/neo4j/driver/ext/internal/driver_factory.rb: -------------------------------------------------------------------------------- 1 | module Neo4j 2 | module Driver 3 | module Ext 4 | module Internal 5 | class DriverFactory < org.neo4j.driver.internal.DriverFactory 6 | def initialize(&domain_name_resolver) 7 | super() 8 | @domain_name_resolver = ->(name) do 9 | domain_name_resolver.call(name).map do |addr| 10 | java.net.InetAddress.get_by_name(addr) 11 | rescue java.net.UnknownHostException => e 12 | raise java.lang.RuntimeException.new(e) 13 | end 14 | end 15 | end 16 | 17 | def getDomainNameResolver 18 | @domain_name_resolver 19 | end 20 | end 21 | end 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /jruby/neo4j/driver/ext/internal/internal_bookmark.rb: -------------------------------------------------------------------------------- 1 | module Neo4j 2 | module Driver 3 | module Ext 4 | module Internal 5 | module InternalBookmark 6 | def values 7 | super.to_set 8 | end 9 | end 10 | end 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /jruby/neo4j/driver/ext/internal/metrics/internal_connection_pool_metrics.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Ext 6 | module Internal 7 | module Metrics 8 | module InternalConnectionPoolMetrics 9 | def address 10 | java_class.declared_method('getAddress').tap { |m| m.accessible = true }.invoke(java_object) 11 | end 12 | end 13 | end 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /jruby/neo4j/driver/ext/internal/summary/internal_notification.rb: -------------------------------------------------------------------------------- 1 | module Neo4j 2 | module Driver 3 | module Ext 4 | module Internal 5 | module Summary 6 | module InternalNotification 7 | def severity_level 8 | super.or_else(nil) 9 | end 10 | 11 | def raw_severity_level 12 | super.or_else(nil) 13 | end 14 | 15 | def raw_category 16 | super.or_else(nil) 17 | end 18 | 19 | def category 20 | super.or_else(nil) 21 | end 22 | end 23 | end 24 | end 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /jruby/neo4j/driver/ext/internal/summary/internal_plan.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Ext 6 | module Internal 7 | module Summary 8 | module InternalPlan 9 | def args 10 | arguments&.to_h&.transform_values(&:as_ruby_object) 11 | end 12 | 13 | def identifiers 14 | super.to_a 15 | end 16 | 17 | # this part should probably be included in testkit-backend 18 | def to_h 19 | {operator_type:, args:, identifiers:, children: children&.map(&:to_h)} 20 | end 21 | end 22 | end 23 | end 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /jruby/neo4j/driver/ext/internal/summary/internal_result_summary.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Ext 6 | module Internal 7 | module Summary 8 | module InternalResultSummary 9 | java_import org.neo4j.driver.summary.QueryType 10 | 11 | %i[result_available_after result_consumed_after].each do |method| 12 | define_method(method) do 13 | super(Java::JavaUtilConcurrent::TimeUnit::MILLISECONDS).then { |val| val unless val == -1 } 14 | end 15 | end 16 | 17 | def query_type 18 | case super 19 | when QueryType::READ_ONLY 20 | Driver::Summary::QueryType::READ_ONLY 21 | when QueryType::READ_WRITE 22 | Driver::Summary::QueryType::READ_WRITE 23 | when QueryType::WRITE_ONLY 24 | Driver::Summary::QueryType::WRITE_ONLY 25 | when QueryType::SCHEMA_WRITE 26 | Driver::Summary::QueryType::SCHEMA_WRITE 27 | end 28 | end 29 | end 30 | end 31 | end 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /jruby/neo4j/driver/ext/internal_driver.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Ext 6 | module InternalDriver 7 | extend AutoClosable 8 | include ConfigConverter 9 | include ExceptionCheckable 10 | include AsyncConverter 11 | 12 | auto_closable :session 13 | 14 | def session(**session_config) 15 | java_method(:session, [org.neo4j.driver.SessionConfig]) 16 | .call(to_java_config(Neo4j::Driver::SessionConfig, **session_config)) 17 | end 18 | 19 | def async_session(**session_config) 20 | java_method(:asyncSession, [org.neo4j.driver.SessionConfig]) 21 | .call(to_java_config(Neo4j::Driver::SessionConfig, **session_config)) 22 | end 23 | 24 | def close_async 25 | to_future(super) 26 | end 27 | 28 | def verify_connectivity 29 | check { super } 30 | end 31 | 32 | def verify_authentication(auth_token) 33 | check { super } 34 | end 35 | 36 | def supports_session_auth? 37 | check { supports_session_auth } 38 | end 39 | end 40 | end 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /jruby/neo4j/driver/ext/internal_entity.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Ext 6 | module InternalEntity 7 | include MapConverter 8 | 9 | alias properties to_h 10 | 11 | def [](key) 12 | get(key.to_s).as_ruby_object 13 | end 14 | 15 | def ==(other) 16 | java_method(:isEqual).call(other) 17 | end 18 | end 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /jruby/neo4j/driver/ext/internal_keys.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Ext 6 | module InternalKeys 7 | include ExceptionCheckable 8 | 9 | def keys 10 | check { super.map(&:to_sym) } 11 | end 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /jruby/neo4j/driver/ext/internal_node.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Ext 6 | module InternalNode 7 | def labels 8 | super.map(&:to_sym) 9 | end 10 | end 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /jruby/neo4j/driver/ext/internal_record.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Ext 6 | module InternalRecord 7 | include MapConverter 8 | include InternalKeys 9 | 10 | def values 11 | java_send(:values).map(&:as_ruby_object) 12 | end 13 | 14 | def [](key) 15 | case key 16 | when Integer 17 | java_method(:get, [Java::int]).call(key) 18 | else 19 | java_method(:get, [java.lang.String]).call(key.to_s) 20 | end.as_ruby_object 21 | end 22 | 23 | def first 24 | java_method(:get, [Java::int]).call(0).as_ruby_object 25 | end 26 | end 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /jruby/neo4j/driver/ext/internal_relationship.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Ext 6 | module InternalRelationship 7 | def type 8 | super.to_sym 9 | end 10 | end 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /jruby/neo4j/driver/ext/internal_result.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Ext 6 | module InternalResult 7 | include Enumerable 8 | include ExceptionCheckable 9 | include InternalKeys 10 | 11 | %i[has_next? next single consume peek].each do |method| 12 | define_method(method) do |*args, &block| 13 | check { super(*args, &block) } 14 | end 15 | end 16 | 17 | def each(&block) 18 | check { stream.for_each(&block) } 19 | end 20 | 21 | def to_a 22 | check { list.to_a } 23 | end 24 | end 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /jruby/neo4j/driver/ext/internal_transaction.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Ext 6 | module InternalTransaction 7 | include ExceptionCheckable 8 | include RunOverride 9 | 10 | def run(statement, **parameters) 11 | check { super(to_statement(statement, parameters)) } 12 | end 13 | 14 | def commit 15 | check { super } 16 | end 17 | 18 | def rollback 19 | check { super } 20 | end 21 | end 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /jruby/neo4j/driver/ext/map_converter.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Ext 6 | module MapConverter 7 | def to_h 8 | java_method(:asMap, [java.util.function.Function]).call(&:itself).to_hash 9 | .transform_values!(&:as_ruby_object).symbolize_keys! 10 | end 11 | end 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /jruby/neo4j/driver/ext/query.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Ext 6 | module Query 7 | def parameters 8 | super.as_ruby_object 9 | end 10 | end 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /jruby/neo4j/driver/ext/run_override.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Ext 6 | module RunOverride 7 | include NeoConverter 8 | 9 | def close 10 | check { super } 11 | end 12 | 13 | private 14 | 15 | def to_statement(text, parameters) 16 | Neo4j::Driver::Internal::Validator.require_hash_parameters!(parameters) 17 | Neo4j::Driver::Query.new(text, to_neo(parameters || {})) 18 | end 19 | end 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /jruby/neo4j/driver/ext/start_end_naming.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Ext 6 | module StartEndNaming 7 | def start_node 8 | java_send(:start) 9 | end 10 | 11 | def end_node 12 | java_send(:end) 13 | end 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /jruby/neo4j/driver/version.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | VERSION = '5.27.0.alpha.0' 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /lib/neo4j-ruby-driver.rb: -------------------------------------------------------------------------------- 1 | # This file is here so that there is a file with the same name as the gem that 2 | # can be required by Bundler.require. Applications should normally 3 | # require 'neo4j/driver'. 4 | 5 | require 'neo4j/driver' 6 | -------------------------------------------------------------------------------- /lib/neo4j/driver/auto_closable.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module AutoClosable 6 | def auto_closable(*methods) 7 | prepend with_block_definer(methods) 8 | end 9 | 10 | private 11 | 12 | def with_block_definer(methods) 13 | Module.new do 14 | methods.each do |method| 15 | define_method(method) do |*args, **kwargs, &block| 16 | closable = super(*args, **kwargs) 17 | if block 18 | begin 19 | block.arity.zero? ? closable.instance_eval(&block) : block.call(closable) 20 | ensure 21 | closable&.close 22 | end 23 | else 24 | closable 25 | end 26 | end 27 | end 28 | end 29 | end 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /lib/neo4j/driver/exceptions/authentication_exception.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Exceptions 6 | # Failed to authenticate the driver to the server due to bad credentials provided. 7 | # When this error happens, the error could be recovered by closing the current driver and restart a new driver with 8 | # the correct credentials. 9 | 10 | # @since 1.1 11 | class AuthenticationException < SecurityException 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /lib/neo4j/driver/exceptions/authorization_expired_exception.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Exceptions 6 | # The authorization info maintained on the server has expired. The client should reconnect. 7 | #

8 | # Error code: Neo.ClientError.Security.AuthorizationExpired 9 | class AuthorizationExpiredException < SecurityException 10 | DESCRIPTION = 'Authorization information kept on the server has expired, this connection is no longer valid.' 11 | end 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /lib/neo4j/driver/exceptions/certificate_exception.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Exceptions 6 | class CertificateException 7 | end 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /lib/neo4j/driver/exceptions/client_exception.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Exceptions 6 | # A ClientException indicates that the client has carried out an operation incorrectly. 7 | # The error code provided can be used to determine further detail for the problem. 8 | # @since 1.0 9 | class ClientException < Neo4jException 10 | class << self 11 | def unable_to_convert(object) 12 | raise self, "Unable to convert #{object.class.name} to Neo4j Value." 13 | end 14 | end 15 | end 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /lib/neo4j/driver/exceptions/connection_read_timeout_exception.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Exceptions 6 | # Indicates that read timed out due to it taking longer than the server-supplied timeout value via the {@code connection.recv_timeout_seconds} configuration 7 | # hint. The server might provide this value to clients to let them know when a given connection may be considered broken if client does not get any 8 | # communication from the server within the specified timeout period. This results in the server being removed from the routing table. 9 | class ConnectionReadTimeoutException < ServiceUnavailableException 10 | INSTANCE = new('Connection read timed out due to it taking longer than the server-supplied timeout value via configuration hint.') 11 | end 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /lib/neo4j/driver/exceptions/database_exception.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Exceptions 6 | # A DatabaseException indicates that there is a problem within the underlying database. 7 | # The error code provided can be used to determine further detail for the problem. 8 | # @since 1.0 9 | class DatabaseException < Neo4jException 10 | end 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /lib/neo4j/driver/exceptions/discovery_exception.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Exceptions 6 | # An error has happened while getting routing table with a remote server. 7 | # While this error is not fatal and we might be able to recover if we continue trying on another server. 8 | # If we fail to get a valid routing table from all routing servers known to this driver, 9 | # then we will end up with a fatal error {@link ServiceUnavailableException}. 10 | 11 | # If you see this error in your logs, it is safe to ignore if your cluster is temporarily changing structure during that time. 12 | class DiscoveryException < Neo4jException 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/neo4j/driver/exceptions/fatal_discovery_exception.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Exceptions 6 | # This error indicate a fatal problem to obtain routing tables such as the routing table for a specified database does not exist. 7 | # This exception should not be retried. 8 | # @since 4.0 9 | class FatalDiscoveryException < ClientException 10 | end 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /lib/neo4j/driver/exceptions/illegal_state_exception.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Exceptions 6 | class IllegalStateException < RuntimeError 7 | end 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /lib/neo4j/driver/exceptions/neo4j_exception.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Exceptions 6 | class Neo4jException < RuntimeError 7 | attr_reader :code, :suppressed 8 | 9 | def initialize(*args) 10 | @code = args.shift if args.count > 1 11 | message = args.shift 12 | @suppressed = args.shift 13 | super(message) 14 | end 15 | 16 | def add_suppressed(exception) 17 | (@suppressed ||= []) << exception 18 | end 19 | end 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /lib/neo4j/driver/exceptions/no_such_record_exception.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Exceptions 6 | class NoSuchRecordException < RuntimeError 7 | EMPTY = 'Cannot retrieve a single record, because this result is empty.' 8 | TOO_MANY = 'Expected a result with a single record, but this result ' \ 9 | 'contains at least one more. Ensure your query returns only one record.' 10 | NO_MORE = 'No more records' 11 | NO_PEEK_PAST = 'Cannot peek past the last record' 12 | 13 | class << self 14 | def empty 15 | new(EMPTY) 16 | end 17 | 18 | def too_many 19 | new(TOO_MANY) 20 | end 21 | 22 | def no_more 23 | new(NO_MORE) 24 | end 25 | 26 | def no_peek_past 27 | new(NO_PEEK_PAST) 28 | end 29 | end 30 | end 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /lib/neo4j/driver/exceptions/protocol_exception.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Exceptions 6 | # A signal that the contract for client-server communication has broken down. 7 | # The user should contact support and cannot resolve this his or herself. 8 | class ProtocolException < Neo4jException 9 | CODE = "Protocol violation: " 10 | 11 | def initialize(message, e = nil) 12 | super(nil, "#{CODE}#{message}", e) 13 | end 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /lib/neo4j/driver/exceptions/result_consumed_exception.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Exceptions 6 | # A user is trying to access resources that are no longer valid due to 7 | # the resources have already been consumed or 8 | # the {@link QueryRunner} where the resources are created has already been closed. 9 | class ResultConsumedException < ClientException 10 | end 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /lib/neo4j/driver/exceptions/security_exception.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Exceptions 6 | # Failed to communicate with the server due to security errors. 7 | # When this type of error happens, the security cause of the error should be fixed to ensure the safety of your data. 8 | # Restart of server/driver/cluster might be required to recover from this error. 9 | # @since 1.1 10 | class SecurityException < ClientException 11 | end 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /lib/neo4j/driver/exceptions/service_unavailable_exception.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Exceptions 6 | # An ServiceUnavailableException indicates that the driver cannot communicate with the cluster. 7 | # @since 1.1 8 | class ServiceUnavailableException < Neo4jException 9 | end 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /lib/neo4j/driver/exceptions/session_expired_exception.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Exceptions 6 | # A SessionExpiredException indicates that the session can no longer satisfy the criteria under which it 7 | # was acquired, e.g. a server no longer accepts write requests. A new session needs to be acquired from the driver 8 | # and all actions taken on the expired session must be replayed. 9 | # @since 1.1 10 | class SessionExpiredException < Neo4jException 11 | end 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /lib/neo4j/driver/exceptions/token_expired_exception.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Exceptions 6 | # The provided token has expired. 7 | #

8 | # The current driver instance is considered invalid. It should not be used anymore. The client must create a new driver instance with a valid token. 9 | #

10 | # Error code: Neo.ClientError.Security.TokenExpired 11 | class TokenExpiredException < SecurityException 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /lib/neo4j/driver/exceptions/transaction_nesting_exception.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Exceptions 6 | # This exception indicates a user is nesting new transaction with an on-going transaction (unmanaged and/or auto-commit). 7 | class TransactionNestingException < ClientException 8 | end 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /lib/neo4j/driver/exceptions/transient_exception.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Exceptions 6 | # A TransientException signals a temporary fault that may be worked around by retrying. 7 | # The error code provided can be used to determine further detail for the problem. 8 | # @since 1.0 9 | class TransientException < Neo4jException 10 | end 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /lib/neo4j/driver/exceptions/unsupported_feature_exception.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Exceptions 6 | # A feature is not supported in a given setup. 7 | class UnsupportedFeatureException < ClientException 8 | end 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /lib/neo4j/driver/exceptions/untrusted_server_exception.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Exceptions 6 | # Thrown if the remote server cannot be verified as Neo4j. 7 | class UntrustedServerException < RuntimeError 8 | end 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /lib/neo4j/driver/exceptions/value/lossy_coercion.rb: -------------------------------------------------------------------------------- 1 | module Neo4j 2 | module Driver 3 | module Exceptions 4 | module Value 5 | # A LossyCoercion exception indicates that the conversion cannot be achieved without losing precision. 6 | # @since 1.0 7 | class LossyCoercion < ValueException 8 | def initialize(source_type_name, destination_type_name) 9 | super("Cannot coerce #{source_type_name} to #{destination_type_name} without losing precision") 10 | end 11 | end 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /lib/neo4j/driver/exceptions/value/not_multi_valued.rb: -------------------------------------------------------------------------------- 1 | module Neo4j 2 | module Driver 3 | module Exceptions 4 | module Value 5 | # A NotMultiValued exception indicates that the value does not consist of multiple values, a.k.a. not a map 6 | # or array. 7 | # @since 1.0 8 | class NotMultiValued < ValueException 9 | end 10 | end 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /lib/neo4j/driver/exceptions/value/uncoercible.rb: -------------------------------------------------------------------------------- 1 | module Neo4j 2 | module Driver 3 | module Exceptions 4 | module Value 5 | # A Uncoercible exception indicates that the conversion cannot be achieved. 6 | # @since 1.0 7 | class Uncoercible < ValueException 8 | def initialize(source_type_name, destination_type_name) 9 | super("Cannot coerce #{source_type_name} to #{destination_type_name}") 10 | end 11 | end 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /lib/neo4j/driver/exceptions/value/unsizable.rb: -------------------------------------------------------------------------------- 1 | module Neo4j 2 | module Driver 3 | module Exceptions 4 | module Value 5 | # An Unsizable exception indicates that the value does not have a size. 6 | # @since 1.0 7 | class Unsizable < ValueException 8 | end 9 | end 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /lib/neo4j/driver/exceptions/value/value_exception.rb: -------------------------------------------------------------------------------- 1 | module Neo4j 2 | module Driver 3 | module Exceptions 4 | module Value 5 | # A ValueException indicates that the client has carried out an operation on values incorrectly. 6 | # @since 1.0 7 | class ValueException < ClientException 8 | end 9 | end 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /lib/neo4j/driver/internal/deprecator.rb: -------------------------------------------------------------------------------- 1 | module Neo4j 2 | module Driver 3 | module Internal 4 | module Deprecator 5 | def self.deprecator 6 | @deprecator ||= ActiveSupport::Deprecation.new('6.0', 'neo4j-ruby-driver') 7 | end 8 | 9 | def self.log_warning(old_method, new_method, version) 10 | deprecator.deprecation_warning(old_method, new_method) 11 | end 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /lib/neo4j/driver/internal/validator.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Internal 6 | module Validator 7 | def self.require_hash_parameters!(parameters) 8 | require_hash!(parameters) do 9 | "The parameters should be provided as Map type. Unsupported parameters type: #{parameters.class.name}" 10 | end 11 | end 12 | 13 | def self.require_hash!(obj) 14 | raise(ArgumentError, yield) unless obj.nil? || obj.is_a?(Hash) 15 | end 16 | 17 | def self.require_non_nil!(obj, message = nil) 18 | raise ArgumentError, [message, "can't be nil"].compact.join(' ') if obj.nil? 19 | obj 20 | end 21 | 22 | def self.require_non_nil_credentials!(username, password) 23 | require_non_nil! username, "Username" 24 | require_non_nil! password, "Password" 25 | end 26 | end 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /lib/neo4j/driver/summary/query_type.rb: -------------------------------------------------------------------------------- 1 | module Neo4j 2 | module Driver 3 | module Summary 4 | module QueryType 5 | READ_ONLY = 'r' 6 | READ_WRITE = 'rw' 7 | WRITE_ONLY = 'w' 8 | SCHEMA_WRITE = 's' 9 | end 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /lib/neo4j/driver/synchronizable.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Synchronizable 6 | def sync(*methods) 7 | prepend with_sync_wrapper(methods) 8 | end 9 | 10 | private 11 | 12 | def with_sync_wrapper(methods) 13 | Module.new do 14 | methods.each do |method| 15 | define_method(method) do |*args, **kwargs, &block| 16 | Sync { super(*args, **kwargs, &block) } 17 | end 18 | end 19 | end 20 | end 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /lib/neo4j/driver/types/local_date_time.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Types 6 | class LocalDateTime < Time 7 | class << self 8 | FIELDS = %i[year month day hour min sec nsec].freeze 9 | 10 | def significant_fields 11 | FIELDS 12 | end 13 | end 14 | 15 | delegate(*significant_fields, to: :@time) 16 | delegate :to_i, to: :@time 17 | end 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /lib/neo4j/driver/types/local_time.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Types 6 | class LocalTime < Time 7 | class << self 8 | FIELDS = %i[hour min sec nsec].freeze 9 | 10 | def significant_fields 11 | FIELDS 12 | end 13 | end 14 | 15 | delegate(*significant_fields, to: :@time) 16 | end 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /lib/neo4j/driver/types/offset_time.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Types 6 | class OffsetTime < Time 7 | class << self 8 | FIELDS = %i[hour min sec nsec utc_offset].freeze 9 | 10 | def significant_fields 11 | FIELDS 12 | end 13 | end 14 | 15 | delegate(*significant_fields, to: :@time) 16 | end 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /lib/neo4j/driver/types/point.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Types 6 | class Point 7 | attr_accessor :srid, :x, :y, :z 8 | 9 | SRID = { 10 | 'WGS-84': 4326, 11 | 'WGS-84-3D': 4979, 12 | cartesian: 7203, 13 | 'cartesian-3D': 9157 14 | }.with_indifferent_access.freeze 15 | 16 | def initialize(args) 17 | self.x = args[:longitude] || args[:x] 18 | self.y = args[:latitude] || args[:y] 19 | self.z = args[:height] || args[:z] 20 | self.srid = args[:srid] || SRID[args[:crs] || implied_crs(args[:longitude] || args[:latitude])] 21 | end 22 | 23 | def coordinates 24 | [x, y, z].compact.map(&:to_f) 25 | end 26 | 27 | private 28 | 29 | def implied_crs(geo) 30 | if geo 31 | z ? :'WGS-84-3D' : :'WGS-84' 32 | else 33 | z ? :'cartesian-3D' : :cartesian 34 | end 35 | end 36 | end 37 | end 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /lib/neo4j/driver/types/time.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Types 6 | class Time 7 | include Comparable 8 | 9 | delegate :hash, :to_a, to: :significant 10 | 11 | class << self 12 | def parse(date) 13 | new(::Time.parse(date)) 14 | end 15 | end 16 | 17 | def initialize(time) 18 | @time = time 19 | end 20 | 21 | def significant 22 | self.class.significant_fields.map(&method(:send)) 23 | end 24 | 25 | def <=>(other) 26 | return unless other.is_a?(self.class) 27 | 28 | self.class.significant_fields.reduce(0) do |acc, elem| 29 | acc.zero? ? send(elem) <=> other.send(elem) : (break acc) 30 | end 31 | end 32 | 33 | def ==(other) 34 | other.is_a?(self.class) && self.class.significant_fields.all? { |elem| send(elem) == other.send(elem) } 35 | end 36 | 37 | alias eql? == 38 | 39 | def +(numeric) 40 | self.class.new(@time + numeric) 41 | end 42 | end 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /lib/neo4j_ruby_driver.rb: -------------------------------------------------------------------------------- 1 | # This file is for backwards compatibility only. 2 | # Applications should require 'neo4j/driver'. 3 | 4 | require 'neo4j/driver' 5 | -------------------------------------------------------------------------------- /ruby/neo4j/driver.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'active_support/core_ext/array/grouping' 4 | require 'active_support/core_ext/hash/keys' 5 | require 'active_support/core_ext/object/blank' 6 | require 'active_support/logger' 7 | require 'async/io' 8 | require 'async/io/stream' 9 | require 'async/queue' 10 | require 'bigdecimal' 11 | require 'connection_pool' 12 | require 'neo4j-ruby-driver_loader' 13 | 14 | module Neo4j 15 | module Driver 16 | Loader.load 17 | 18 | Record = Neo4j::Driver::Internal::InternalRecord 19 | Result = Neo4j::Driver::Internal::InternalResult 20 | Transaction = Neo4j::Driver::Internal::InternalTransaction 21 | 22 | module Types 23 | Entity = Neo4j::Driver::Internal::InternalEntity 24 | Node = Neo4j::Driver::Internal::InternalNode 25 | Path = Neo4j::Driver::Internal::InternalPath 26 | Relationship = Neo4j::Driver::Internal::InternalRelationship 27 | end 28 | end 29 | end -------------------------------------------------------------------------------- /ruby/neo4j/driver/access_mode.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module AccessMode 6 | WRITE = :write 7 | READ = :read 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/bookmark.rb: -------------------------------------------------------------------------------- 1 | module Neo4j 2 | module Driver 3 | # Causal chaining is carried out by passing bookmarks between transactions. 4 | 5 | # When starting a session with initial bookmarks, the first transaction will be ensured to run at least after 6 | # the database is as up-to-date as the latest transaction referenced by the supplied bookmarks. 7 | 8 | # Within a session, bookmark propagation is carried out automatically. 9 | # Thus all transactions in a session (both managed and unmanaged) are guaranteed to be carried out one after another. 10 | 11 | # To opt out of this mechanism for unrelated units of work, applications can use multiple sessions. 12 | module Bookmark 13 | # Reconstruct bookmark from \bookmarks string values. 14 | # @param values values obtained from a previous bookmark. 15 | # @return A bookmark. 16 | def self.from(*values) 17 | Internal::InternalBookmark.parse(*values) 18 | end 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/async/connection/bootstrap_factory.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Async 4 | module Connection 5 | class BootstrapFactory 6 | class << self 7 | def new_bootstrap(thread_count: nil, 8 | event_loop_group: EventLoopGroupFactory.new_event_loop_group(thread_count)) 9 | # Ione::Io::IoReactor.new 10 | # Io::Bootstrap.new.tap do |bootstrap| 11 | # bootstrap.group = event_loop_group 12 | # bootstrap.channel(EventLoopGroupFactory.channel_class) 13 | # bootstrap.option(org.neo4j.driver.internal.shaded.io.netty.channel.ChannelOption::SO_KEEPALIVE, true) 14 | # bootstrap.option(org.neo4j.driver.internal.shaded.io.netty.channel.ChannelOption::SO_REUSEADDR, true) 15 | # end 16 | end 17 | end 18 | end 19 | end 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/async/connection/channel_pipeline_builder_impl.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Async 4 | module Connection 5 | class ChannelPipelineBuilderImpl 6 | def build(message_format, pipeline, logger) 7 | # inbound handlers 8 | pipeline.add_last(Inbound::ChunkDecoder.new(logger)) 9 | pipeline.add_last(Inbound::MessageDecoder.new) 10 | pipeline.add_last(Inbound::InboundMessageHandler.new(message_format, logger)) 11 | 12 | # outbound handlers 13 | pipeline.add_last(Outbound::OutboundMessageHandler::NAME, Outbound::OutboundMessageHandler.new(message_format, logger)) 14 | 15 | # last one - error handler 16 | pipeline.add_last(Inbound::ChannelErrorHandler.new(logger)) 17 | end 18 | end 19 | end 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/async/connection/direct_connection.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Async 4 | module Connection 5 | # This is a connection used by {@link DirectConnectionProvider} to connect to a remote database. 6 | class DirectConnection < Struct.new(:delegate, :database_name, :mode, :impersonated_user) 7 | delegate *%i[enable_auto_read disable_auto_read reset open? release terminate_and_release server_agent 8 | server_address server_version protocol flush], to: :delegate 9 | alias connection delegate 10 | 11 | def write(message1, handler1, message2 = nil, handler2 = nil) 12 | if message2.present? && handler2.present? 13 | delegate.write(message1, handler1, message2, handler2) 14 | else 15 | delegate.write(message1, handler1) 16 | end 17 | end 18 | 19 | def write_and_flush(message1, handler1, message2 = nil, handler2 = nil) 20 | if message2.present? && handler2.present? 21 | delegate.write_and_flush(message1, handler1, message2, handler2) 22 | else 23 | delegate.write_and_flush(message1, handler1) 24 | end 25 | end 26 | end 27 | end 28 | end 29 | end 30 | end -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/async/connection/handshake_completed_listener.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Async 4 | module Connection 5 | class HandshakeCompletedListener 6 | attr_reader :user_agent, :auth_token, :routing_context, :connection_initialized_promise 7 | 8 | def initialize(user_agent, auth_token, routing_context, connection_initialized_promise) 9 | @user_agent = java.util.Objects.require_non_null(user_agent) 10 | @auth_token = java.util.Objects.require_non_null(auth_token) 11 | @routing_context = routing_context 12 | @connection_initialized_promise = java.util.Objects.require_non_null(connection_initialized_promise) 13 | end 14 | 15 | def operation_complete(future) 16 | if future.is_success? 17 | protocol = Messaging::BoltProtocol.for_channel(future.channel) 18 | protocol.initialize_channel(user_agent, auth_token, routing_context, connection_initialized_promise) 19 | else 20 | connection_initialized_promise.set_failure(future.cause) 21 | end 22 | end 23 | end 24 | end 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/async/connection/netty_domain_name_resolver.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Async 4 | module Connection 5 | class NettyDomainNameResolver #< org.neo4j.driver.internal.shaded.io.netty.resolver.InetNameResolver 6 | def initialize(executor, domain_name_resolver) 7 | # super(executor) 8 | @domain_name_resolver = domain_name_resolver 9 | end 10 | 11 | def doResolve(inet_host, promise) 12 | promise.set_success(@domain_name_resolver.call(inet_host).first) 13 | rescue java.net.UnknownHostException => e 14 | promise.set_failure(e) 15 | end 16 | 17 | def doResolveAll(inet_host, promise) 18 | promise.set_success(@domain_name_resolver.call(inet_host)) 19 | rescue java.net.UnknownHostException => e 20 | promise.set_failure(e) 21 | end 22 | end 23 | end 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/async/connection/netty_domain_name_resolver_group.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Async 4 | module Connection 5 | class NettyDomainNameResolverGroup #< org.neo4j.driver.internal.shaded.io.netty.resolver.AddressResolverGroup 6 | attr_reader :domain_name_resolver 7 | 8 | def initialize(&domain_name_resolver) 9 | @domain_name_resolver = domain_name_resolver 10 | end 11 | 12 | def newResolver(executor) 13 | NettyDomainNameResolver.new(executor, domain_name_resolver).as_address_resolver 14 | end 15 | end 16 | end 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/async/connection/stream.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Async 4 | module Connection 5 | class Stream < ::Async::IO::Stream 6 | include Packstream::PackInput 7 | include Packstream::PackOutput 8 | end 9 | end 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/async/connection/stream_reader.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Async 4 | module Connection 5 | class StreamReader 6 | include Inbound::ChunkDecoder 7 | include Packstream::PackInput 8 | include Packstream::PackStream::Unpacker 9 | include Messaging::Common::CommonValueUnpacker 10 | # delegate_missing_to :@input 11 | 12 | end 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/async/connection_context.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Async 4 | module ConnectionContext 5 | PENDING_DATABASE_NAME_EXCEPTION_SUPPLIER = 6 | ->() { Exceptions::IllegalStateException.new('Pending database name encountered') } 7 | end 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/async/immutable_connection_context.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Async 4 | class ImmutableConnectionContext 5 | attr :database_name, :mode, :rediscovery_bookmark, :impersonated_user 6 | 7 | def initialize(database_name, bookmark, mode) 8 | @database_name = database_name 9 | @rediscovery_bookmark = bookmark 10 | @mode = mode 11 | end 12 | 13 | SINGLE_DB_CONTEXT = new(DatabaseNameUtil::DEFAULT_DATABASE, InternalBookmark::EMPTY, AccessMode::READ) 14 | MULTI_DB_CONTEXT = new(DatabaseNameUtil::SYSTEM_DATABASE, InternalBookmark::EMPTY, AccessMode::READ) 15 | 16 | # A simple context is used to test connectivity with a remote server/cluster. As long as there is a read only service, the connection shall be established 17 | # successfully. Depending on whether multidb is supported or not, this method returns different context for routing table discovery. 18 | def self.simple(supports_multi_db) 19 | supports_multi_db ? MULTI_DB_CONTEXT : SINGLE_DB_CONTEXT 20 | end 21 | end 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/async/inbound/byte_buf_input.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Async 4 | module Inbound 5 | class ByteBufInput 6 | delegate :read_byte, :read_short, :read_int, :read_long, :read_double, :read_bytes, to: :@buf 7 | 8 | def start(new_buf) 9 | assert_not_started 10 | @buf = Validator.require_non_nil!(new_buf) 11 | end 12 | 13 | def stop 14 | @buf = nil 15 | end 16 | 17 | def peek_byte 18 | @buf.get_byte(@buf.read_index) 19 | end 20 | 21 | private 22 | 23 | def assert_not_started 24 | raise Neo4j::Driver::Exceptions::IllegalStateException, 'Already started' if @buf 25 | end 26 | end 27 | end 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/async/inbound/chunk_decoder.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Async 4 | module Inbound 5 | module ChunkDecoder 6 | def initialize(input) 7 | @input = input 8 | @remaining = 0 9 | end 10 | 11 | def read_exactly(size, buffer = nil) 12 | while @remaining.zero? 13 | @remaining = read_length_field 14 | end 15 | if size > @remaining 16 | # (buffer ||= Buffer.new(capacity: size)) << super(@remaining) 17 | (buffer ||= ::Async::IO::Buffer.new) << @input.read_exactly(@remaining) 18 | size -= @remaining 19 | @remaining = 0 20 | read_exactly(size, buffer) 21 | else 22 | data = @input.read_exactly(size) 23 | @remaining -= size 24 | buffer ? buffer << data : data 25 | end 26 | end 27 | 28 | def ensure_termination 29 | raise 'Chunking problem' unless @remaining.zero? && read_length_field.zero? 30 | end 31 | 32 | private 33 | 34 | def read_length_field 35 | @input.read_exactly(2).unpack1('S>') 36 | end 37 | end 38 | end 39 | end 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/async/inbound/connect_timeout_handler.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Async 4 | module Inbound 5 | # Handler needed to limit amount of time connection performs TLS and Bolt handshakes. 6 | # It should only be used when connection is established and removed from the pipeline afterwards. 7 | # Otherwise it will make long running queries fail. 8 | class ConnectTimeoutHandler #< org.neo4j.driver.internal.shaded.io.netty.handler.timeout.ReadTimeoutHandler 9 | def initialize(timeout_millis) 10 | super(timeout_millis, java.util.concurrent.TimeUnit::MILLISECONDS) 11 | @timeout_millis = timeout_millis 12 | end 13 | 14 | protected 15 | 16 | def readTimedOut(ctx) 17 | unless @triggered 18 | @triggered = true 19 | ctx.fire_exception_caught(unable_to_connect_error) 20 | end 21 | end 22 | 23 | private 24 | 25 | def unable_to_connect_error 26 | Neo4j::Driver::Exceptions::ServiceUnavailableException.new("Unable to establish connection in #{@timeout_millis}ms") 27 | end 28 | end 29 | end 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/async/inbound/connection_read_timeout_handler.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Async 4 | module Inbound 5 | class ConnectionReadTimeoutHandler #< org.neo4j.driver.internal.shaded.io.netty.handler.timeout.ReadTimeoutHandler 6 | def read_timeout(ctx) 7 | unless @triggered 8 | ctx.fire_exception_caught(Neo4j::Driver::Exception::ConnectionReadTimeoutException::INSTANCE) 9 | ctx.close 10 | @triggered = true 11 | end 12 | end 13 | end 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/async/internal_async_transaction.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Async 4 | class InternalAsyncTransaction 5 | delegate :run_async, :commit_async, :rollback_async, :open?, to: :@tx 6 | 7 | def initialize(tx) 8 | @tx = tx 9 | end 10 | end 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/async/leak_logging_network_session.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Async 4 | class LeakLoggingNetworkSession < NetworkSession 5 | def initialize(connection_provider, retry_logic, database_name, mode, bookmark_holder, impersonated_user, fetch_size, logger) 6 | super 7 | @stack_trace = capture_stack_trace 8 | end 9 | 10 | def finalize 11 | log_leak_if_needed 12 | super 13 | end 14 | 15 | private 16 | 17 | def log_leak_if_needed 18 | is_open = Util::Futures.blocking_get(current_connection_is_open) 19 | if is_open 20 | @log.error do 21 | "Neo4j Session object leaked, please ensure that your application fully consumes results in "\ 22 | "Sessions or explicitly calls `close` on Sessions before disposing of the objects.\n"\ 23 | "Session was created at:\n#{@stack_trace}" 24 | end 25 | end 26 | end 27 | 28 | def capture_stack_trace 29 | Thread.current.backtrace.join("\n") 30 | end 31 | end 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/async/outbound/outbound_message_handler.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Async 4 | module Outbound 5 | class OutboundMessageHandler 6 | NAME = self.class.name 7 | 8 | def initialize(output, message_format, logger) 9 | @output = output 10 | @writer = message_format.new_writer(output) 11 | @log = logger 12 | end 13 | 14 | def handler_added(ctx) 15 | @log = Logging::ChannelActivityLogger.new(ctx.channel, @log, self.class) 16 | end 17 | 18 | def handler_removed(ctx) 19 | @log = nil 20 | end 21 | 22 | def encode(msg) 23 | @log.debug("C: #{msg}") 24 | 25 | @output.start 26 | begin 27 | @writer.write(msg) 28 | ensure 29 | @output.stop 30 | end 31 | 32 | @output.write_message_boundary 33 | # @log.debug( "C: #{}") if @log.debug_enabled? 34 | end 35 | end 36 | end 37 | end 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/async/pool/channel_pool.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Async 4 | module Pool 5 | class ChannelPool < ConnectionPool 6 | def initialize(limit: nil, acquisition_timeout: nil, &block) 7 | super(size: limit, timeout: acquisition_timeout, &block) 8 | @available = TimedStack.new(@size, &block) 9 | end 10 | 11 | def acquire(options = {}) 12 | @available.pop(options[:timeout] || @timeout) 13 | end 14 | 15 | def release(resource) 16 | @available.push(resource) 17 | nil 18 | end 19 | 20 | def close 21 | @available.shutdown(&:close) 22 | end 23 | 24 | def busy? 25 | @available.any_resource_busy? 26 | end 27 | end 28 | end 29 | end 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/async/pool/network_connection_factory.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Async 4 | module Pool 5 | class NetworkConnectionFactory 6 | attr_reader :clock, :metrics_listener, :logger 7 | 8 | def initialize(clock, metrics_listener, logger) 9 | @clock = clock 10 | @metrics_listener = metrics_listener 11 | @logger = logger 12 | end 13 | 14 | def create_connection(channel, pool) 15 | NetworkConnection.new(channel, pool, clock, metrics_listener, @logger) 16 | end 17 | end 18 | end 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/async/pool/timed_stack.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Async 4 | module Pool 5 | class TimedStack < ConnectionPool::TimedStack 6 | def any_resource_busy? 7 | @mutex.synchronize do 8 | @created > @que.length 9 | end 10 | end 11 | end 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/async/result_cursors_holder.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Async 4 | class ResultCursorsHolder < Array 5 | def retrieve_not_consumed_error 6 | retrieve_all_failures.find { |failure| failure } 7 | end 8 | 9 | private 10 | 11 | def retrieve_all_failures 12 | map(&:discard_all_failure_async) 13 | end 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/bookmark_holder.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | class BookmarkHolder 4 | NO_OP = Class.new(DefaultBookmarkHolder) do 5 | def bookmark=(_value) end 6 | end.new 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/cluster/cluster_composition_lookup_result.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Cluster 4 | class ClusterCompositionLookupResult 5 | attr_reader :cluster_composition, :resolved_initial_routers 6 | 7 | def initialize(composition, resolved_initial_routers = nil) 8 | @cluster_composition = composition 9 | @resolved_initial_routers = resolved_initial_routers 10 | end 11 | end 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/cluster/identity_resolver.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Cluster 4 | class IdentityResolver 5 | IDENTITY_RESOLVER = new 6 | alias resolve Array 7 | end 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/cluster/loadbalancing/round_robin_array_index.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Cluster 4 | module Loadbalancing 5 | class RoundRobinArrayIndex < Concurrent::AtomicFixnum 6 | def next(array_length) 7 | (increment - 1) % array_length if array_length.positive? 8 | end 9 | end 10 | end 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/cluster/multi_databases_routing_procedure_runner.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Cluster 4 | 5 | # This implementation of the {@link RoutingProcedureRunner} works with multi database versions of Neo4j calling 6 | # the procedure `dbms.routing.getRoutingTable` 7 | class MultiDatabasesRoutingProcedureRunner < SingleDatabaseRoutingProcedureRunner 8 | DATABASE_NAME = :database 9 | MULTI_DB_GET_ROUTING_TABLE = "CALL dbms.routing.getRoutingTable($%s, $%s)" % [SingleDatabaseRoutingProcedureRunner::ROUTING_CONTEXT, DATABASE_NAME] 10 | 11 | private 12 | 13 | def bookmark_holder(bookmark) 14 | ReadOnlyBookmarkHolder.new(bookmark) 15 | end 16 | 17 | def procedure_query(server_version, database_name) 18 | map = { 19 | SingleDatabaseRoutingProcedureRunner::ROUTING_CONTEXT => @context.to_h, 20 | DATABASE_NAME => database_name.database_name 21 | } 22 | Query.new(MULTI_DB_GET_ROUTING_TABLE, **map) 23 | end 24 | 25 | def connection(connection) 26 | Async::Connection::DirectConnection.new(connection, DatabaseNameUtil::SYSTEM_DATABASE, AccessMode::READ, nil) 27 | end 28 | end 29 | end 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/cluster/routing_procedure_response.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Cluster 4 | class RoutingProcedureResponse 5 | attr_reader :procedure 6 | 7 | def initialize(procedure, records: nil, error: nil) 8 | @procedure = procedure 9 | @records = records 10 | @error = error 11 | end 12 | 13 | def success? 14 | !@records.nil? 15 | end 16 | 17 | def records 18 | if success? 19 | @records 20 | else 21 | raise Exceptions::IllegalStateException, "Can't access records of a failed result #{@error}" 22 | end 23 | end 24 | 25 | def error 26 | if success? 27 | raise Exceptions::IllegalStateException, "Can't access error of a succeeded result #{@records}" 28 | else 29 | @error 30 | end 31 | end 32 | end 33 | end 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/cluster/routing_settings.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Cluster 4 | class RoutingSettings 5 | attr_reader :max_routing_failures, :retry_timeout_delay, :routing_context, :routing_table_purge_delay 6 | 7 | def initialize(max_routing_failures, retry_timeout_delay, routing_table_purge_delay, 8 | routing_context = RoutingContext::EMPTY) 9 | @max_routing_failures = max_routing_failures 10 | @retry_timeout_delay = retry_timeout_delay 11 | @routing_context = routing_context 12 | @routing_table_purge_delay = routing_table_purge_delay 13 | end 14 | 15 | STALE_ROUTING_TABLE_PURGE_DELAY = 30.seconds 16 | DEFAULT = new(1, 5.seconds, STALE_ROUTING_TABLE_PURGE_DELAY) 17 | 18 | def with_routing_context(new_routing_context) 19 | self.class.new(@max_routing_failures, @retry_timeout_delay, @routing_table_purge_delay, new_routing_context) 20 | end 21 | end 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/connection_settings.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | 4 | # The connection settings are used whenever a new connection is 5 | # established to a server, specifically as part of the INIT request. 6 | class ConnectionSettings 7 | attr_reader :auth_token, :user_agent, :connect_timeout_millis 8 | 9 | def initialize(auth_token, user_agent, connect_timeout_millis) 10 | @auth_token = auth_token 11 | @user_agent = user_agent 12 | @connect_timeout_millis = connect_timeout_millis 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/cursor/async_result_cursor_only_factory.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Cursor 4 | # Used by Bolt V1, V2, V3 5 | class AsyncResultCursorOnlyFactory 6 | def initialize(connection, run_message, run_handler, pull_handler) 7 | @connection = Internal::Validator.require_non_nil!(connection) 8 | @run_message = Internal::Validator.require_non_nil!(run_message) 9 | @run_handler = Internal::Validator.require_non_nil!(run_handler) 10 | 11 | @pull_all_handler = Internal::Validator.require_non_nil!(pull_handler) 12 | end 13 | 14 | def async_result 15 | # only write and flush messages when async result is wanted. 16 | @connection.write(@run_message, @run_handler) # queues the run message, will be flushed with pull message together 17 | @pull_all_handler.pre_populate_records 18 | 19 | DisposableAsyncResultCursor.new(AsyncResultCursorImpl.new(@run_handler, @pull_all_handler)) 20 | end 21 | end 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/cursor/result_cursor_factory_impl.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Cursor 4 | # Bolt V4 5 | class ResultCursorFactoryImpl 6 | def initialize(connection, run_message, run_handler, pull_handler, pull_all_handler) 7 | @connection = Internal::Validator.require_non_nil!(connection) 8 | @run_message = Internal::Validator.require_non_nil!(run_message) 9 | @run_handler = Internal::Validator.require_non_nil!(run_handler) 10 | @pull_handler = Internal::Validator.require_non_nil!(pull_handler) 11 | @pull_all_handler = Internal::Validator.require_non_nil!(pull_all_handler) 12 | end 13 | 14 | def async_result 15 | # only write and flush messages when async result is wanted. 16 | @connection.write(@run_message, @run_handler) # queues the run message, will be flushed with pull message together 17 | @pull_all_handler.pre_populate_records 18 | 19 | DisposableAsyncResultCursor.new(AsyncResultCursorImpl.new(@run_handler, @pull_all_handler)) 20 | end 21 | end 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/database_name_util.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | class DatabaseNameUtil 4 | DEFAULT_DATABASE_NAME = nil 5 | SYSTEM_DATABASE_NAME = 'system' 6 | 7 | private 8 | 9 | DEFAULT_DATABASE = InternalDatabaseName.new(description: '') 10 | SYSTEM_DATABASE = InternalDatabaseName.new(database_name: SYSTEM_DATABASE_NAME) 11 | 12 | public 13 | 14 | class << self 15 | def default_database 16 | DEFAULT_DATABASE 17 | end 18 | 19 | def system_database 20 | SYSTEM_DATABASE 21 | end 22 | 23 | def database(name) 24 | case name 25 | when DEFAULT_DATABASE_NAME 26 | default_database 27 | when SYSTEM_DATABASE_NAME 28 | system_database 29 | else 30 | InternalDatabaseName.new(database_name: name) 31 | end 32 | end 33 | end 34 | end 35 | end 36 | end 37 | 38 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/default_bookmark_holder.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | class DefaultBookmarkHolder < ReadOnlyBookmarkHolder 4 | def bookmark=(bookmark) 5 | @bookmark = bookmark if bookmark.present? 6 | end 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/default_domain_name_resolver.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | class DefaultDomainNameResolver 4 | INSTANCE = new 5 | 6 | def resolve(name) 7 | java.net.InetAddress.get_all_by_name(name) 8 | end 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/delegating_transaction.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j::Driver 4 | module Internal 5 | class DelegatingTransaction 6 | delegate :run, to: :@tx 7 | 8 | def initialize(tx) 9 | @tx = tx 10 | end 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/handlers/begin_tx_response_handler.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Handlers 4 | class BeginTxResponseHandler 5 | include Spi::ResponseHandler 6 | 7 | def on_success(_metadata) 8 | end 9 | 10 | def on_failure(error) 11 | raise error 12 | end 13 | 14 | def on_record(fields) 15 | raise "Transaction begin is not expected to receive records: #{fields}" 16 | end 17 | end 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/handlers/channel_releasing_reset_response_handler.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Handlers 4 | class ChannelReleasingResetResponseHandler < ResetResponseHandler 5 | def initialize(channel, pool, message_dispatcher, log, release_future) 6 | super(message_dispatcher, release_future) 7 | @channel = channel 8 | @pool = pool 9 | @log = log 10 | end 11 | 12 | def reset_completed(success) 13 | if success 14 | # update the last-used timestamp before returning the channel back to the pool 15 | # Async::Connection::ChannelAttributes.set_last_used_timestamp(@channel, @clock.millis) 16 | # closure_stage = Util::Futures.completed_with_null 17 | else 18 | # close the channel before returning it back to the pool if RESET failed 19 | @channel.close 20 | end 21 | rescue 22 | nil 23 | ensure 24 | @pool.release(@channel) 25 | @log.debug { "Channel #{@channel.object_id} released." } 26 | end 27 | end 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/handlers/commit_tx_response_handler.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Handlers 4 | class CommitTxResponseHandler 5 | include Spi::ResponseHandler 6 | 7 | def initialize(result_holder) 8 | @result_holder = result_holder 9 | end 10 | 11 | def on_success(metadata) 12 | @result_holder.succeed(metadata[:bookmark]&.then(&InternalBookmark.method(:parse))) 13 | end 14 | 15 | def on_failure(error) 16 | @result_holder.fail(error) 17 | end 18 | 19 | def on_record(fields) 20 | raise "Transaction commit is not expected to receive records: #{fields}" 21 | end 22 | end 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/handlers/init_response_handler.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Handlers 4 | class InitResponseHandler 5 | include Spi::ResponseHandler 6 | 7 | def initialize(connection_initialized_promise) 8 | @connection_initialized_promise = connection_initialized_promise 9 | @channel = connection_initialized_promise 10 | end 11 | 12 | def on_success(_metadata) 13 | begin 14 | server_version = Util::MetadataExtractor.extract_neo4j_server_version(metadata) 15 | Async::Connection::ChannelAttributes.set_server_version(@channel, server_version) 16 | 17 | @connection_initialized_promise.set_success 18 | rescue StandardError => error 19 | @connection_initialized_promise.set_failure(error) 20 | raise error 21 | end 22 | end 23 | 24 | def on_failure(error) 25 | @channel.close.add_listener(-> (_future) { @connection_initialized_promise.set_failure(error) }) 26 | end 27 | 28 | def on_record(fields) 29 | raise java.lang.UnsupportedOperationException 30 | end 31 | end 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/handlers/no_op_response_handler.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Handlers 4 | class NoOpResponseHandler 5 | include Spi::ResponseHandler 6 | INSTANCE = new 7 | 8 | def on_success(metadata) end 9 | 10 | def on_failure(error) end 11 | 12 | def on_record(fields) end 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/handlers/ping_response_handler.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Handlers 4 | class PingResponseHandler 5 | include Spi::ResponseHandler 6 | 7 | def initialize(result, channel, logger) 8 | @result = result 9 | @channel = channel 10 | @log = logger 11 | end 12 | 13 | def on_success(_metadata) 14 | @log.debug("Channel #{@channel} pinged successfully") 15 | @result.set_success(true) 16 | end 17 | 18 | def on_failure(error) 19 | @log.debug("Channel #{@channel} failed ping #{error}") 20 | @result.set_success(false) 21 | end 22 | 23 | def on_record(fields) 24 | raise java.lang.UnsupportedOperationException 25 | end 26 | end 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/handlers/pulln/fetch_size_util.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Handlers 4 | module Pulln 5 | class FetchSizeUtil 6 | UNLIMITED_FETCH_SIZE = -1 7 | DEFAULT_FETCH_SIZE = 1000 8 | 9 | def self.assert_valid_fetch_size(size) 10 | if size <= 0 && size != UNLIMITED_FETCH_SIZE 11 | raise ArgumentError, "The record fetch size may not be 0 or negative. Illegal record fetch size: #{size}." 12 | end 13 | 14 | size 15 | end 16 | end 17 | end 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/handlers/reset_response_handler.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Handlers 4 | class ResetResponseHandler 5 | include Spi::ResponseHandler 6 | 7 | def initialize(message_dispatcher, completion_future = nil) 8 | @message_dispatcher = message_dispatcher 9 | @completion_future = completion_future 10 | end 11 | 12 | def on_success(_metadata = {}) 13 | reset_completed(true) 14 | end 15 | 16 | def on_failure(_error) 17 | reset_completed(false) 18 | end 19 | 20 | def on_record(_fields) 21 | raise java.lang.UnsupportedOperationException 22 | end 23 | 24 | private def reset_completed(_success) 25 | @message_dispatcher.clear_current_error 26 | 27 | unless @completion_future.nil? 28 | @completion_future.complete(nil) 29 | end 30 | end 31 | end 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/handlers/rollback_tx_response_handler.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Handlers 4 | class RollbackTxResponseHandler 5 | include Spi::ResponseHandler 6 | 7 | def initialize(result_holder) 8 | @result_holder = result_holder 9 | end 10 | 11 | def on_success(_metadata) 12 | @result_holder.succeed 13 | end 14 | 15 | def on_failure(error) 16 | @result_holder.fail(error) 17 | end 18 | 19 | def on_record(fields) 20 | raise "Transaction rollback is not expected to receive records: #{fields}" 21 | end 22 | end 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/handlers/route_message_response_handler.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Handlers 4 | class RouteMessageResponseHandler < Struct.new(:completion_listener) 5 | include Spi::ResponseHandler 6 | 7 | def on_success(metadata) 8 | completion_listener.routing_table = metadata[:rt] 9 | end 10 | 11 | def on_failure(error) 12 | raise error 13 | end 14 | 15 | def on_record(fields) 16 | raise "Route is not expected to receive records: #{fields}" 17 | end 18 | end 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/handlers/session_pull_response_completion_listener.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Handlers 4 | class SessionPullResponseCompletionListener 5 | def initialize(connection, bookmark_holder) 6 | @connection = connection 7 | @bookmark_holder = bookmark_holder 8 | end 9 | 10 | def after_success(metadata) 11 | release_connection 12 | @bookmark_holder.bookmark = Util::MetadataExtractor.extract_bookmarks(metadata) 13 | end 14 | 15 | def after_failure(error) 16 | case error 17 | when Exceptions::AuthorizationExpiredException 18 | @connection.terminate_and_release(Exceptions::AuthorizationExpiredException::DESCRIPTION) 19 | when Exceptions::ConnectionReadTimeoutException 20 | @connection.terminate_and_release(error.message) 21 | else 22 | release_connection 23 | end 24 | end 25 | 26 | private 27 | 28 | def release_connection 29 | @connection.release 30 | end 31 | end 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/handlers/transaction_pull_response_completion_listener.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Handlers 4 | class TransactionPullResponseCompletionListener 5 | def initialize(tx) 6 | @tx = Validator.require_non_nil!(tx) 7 | end 8 | 9 | def after_success(_metadata) end 10 | 11 | def after_failure(error) 12 | # always mark transaction as terminated because every error is "acknowledged" with a RESET message 13 | # so database forgets about the transaction after the first error 14 | # such transaction should not attempt to commit and can be considered as rolled back 15 | @tx.mark_terminated(error) 16 | end 17 | end 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/impersonation_util.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | class ImpersonationUtil 4 | IMPERSONATION_UNSUPPORTED_ERROR_MESSAGE = 'Detected connection that does not support impersonation, please make sure to have all servers running 4.4 version or above and communicating over Bolt version 4.4 or above when using impersonation feature' 5 | 6 | def self.ensure_impersonation_support(connection, impersonated_user) 7 | if !impersonated_user.nil? && !supports_impersonation?(connection) 8 | raise Neo4j::Driver::Exceptions::ClientException, IMPERSONATION_UNSUPPORTED_ERROR_MESSAGE 9 | end 10 | 11 | connection 12 | end 13 | 14 | private 15 | 16 | def self.supports_impersonation?(connection) 17 | connection.server_version >= Util::ServerVersion::V4_4_0 && 18 | connection.protocol.version >= Messaging::V44::BoltProtocolV44::VERSION 19 | end 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/internal_bookmark.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | class InternalBookmark 4 | include Bookmark 5 | attr :values 6 | delegate :hash, :empty?, to: :values 7 | 8 | private def initialize(*values) 9 | @values = values.to_set 10 | end 11 | EMPTY = new.freeze 12 | 13 | def ==(other) 14 | equal?(other) || self.class == other.class && values == other.values 15 | end 16 | 17 | alias eql? == 18 | 19 | def to_s 20 | "Bookmark{values=#{values}}" 21 | end 22 | 23 | class << self 24 | def empty 25 | EMPTY 26 | end 27 | 28 | def from(*bookmarks) 29 | new(*bookmarks.reduce(Set.new) { |set, bookmark| set + bookmark.values }) 30 | end 31 | 32 | alias parse new 33 | end 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/internal_database_name.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | class InternalDatabaseName < Struct.new(:database_name, :description) 4 | def initialize(database_name: nil, description: database_name) 5 | super(database_name, description) 6 | end 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/internal_entity.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | class InternalEntity 4 | attr_reader :id, :element_id, :properties 5 | delegate :hash, to: :id 6 | delegate :[], :size, :key?, :keys, :values, :to_h, to: :properties 7 | 8 | def initialize(id, element_id, **properties) 9 | @id = id 10 | @element_id = element_id || id.to_s 11 | @properties = properties 12 | end 13 | 14 | def ==(other) 15 | equal?(other) || self.class == other.class && id == other.id 16 | end 17 | 18 | alias eql? == 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/internal_node.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | # {@link Node} implementation that directly contains labels and properties. 4 | class InternalNode < InternalEntity 5 | attr_reader :labels 6 | 7 | def initialize(id, element_id, *labels, **properties) 8 | super(id, element_id, **properties) 9 | @labels = labels 10 | end 11 | 12 | def label?(label) 13 | labels.include?(label) 14 | end 15 | 16 | def to_s 17 | "node<#{id}>" 18 | end 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/internal_pair.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | class InternalPair < Struct.new(:key, :value) 4 | def self.of(key, value) 5 | new(key, value) 6 | end 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/internal_path.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | class InternalPath < Array 4 | attr_reader :nodes, :relationships 5 | 6 | class Segment < Struct.new(:start_node, :relationship, :end_node) 7 | def to_s 8 | sprintf(relationship.start_node_id == start_node.id ? '(%s)-[%s:%s]->(%s)' : '(%s)<-[%s:%s]-(%s)', 9 | start_node.id, relationship.id, relationship.type, end_node.id) 10 | end 11 | end 12 | 13 | delegate :length, to: :relationships 14 | delegate :include?, to: :entities 15 | 16 | def initialize(nodes, relationships) 17 | super() 18 | @nodes = nodes 19 | @relationships = relationships 20 | end 21 | 22 | def to_s 23 | 'path' + super 24 | end 25 | 26 | def start_node 27 | @nodes.first 28 | end 29 | 30 | def end_node 31 | @nodes.last 32 | end 33 | end 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/internal_point2_d.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | class InternalPoint2D < Struct.new(:srid, :x, :y) 4 | def z 5 | Float::NAN 6 | end 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/internal_point3_d.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | class InternalPoint3D < Struct.new(:srid, :x, :y, :z) 4 | end 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/internal_record.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Internal 6 | class InternalRecord 7 | attr_reader :keys, :values 8 | delegate :first, :size,to: :values 9 | delegate :key?, to: :keys 10 | 11 | def initialize(keys, values) 12 | @keys = keys 13 | @values = values 14 | end 15 | 16 | def [](key) 17 | field_index = key.is_a?(Integer) ? key : @keys.index(key.to_sym) 18 | @values[field_index] if field_index 19 | end 20 | 21 | def to_h 22 | keys.zip(values).to_h 23 | end 24 | end 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/internal_relationship.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j::Driver 4 | module Internal 5 | class InternalRelationship < InternalEntity 6 | attr_accessor :start_node_id, :end_node_id, :start_node_element_id, :end_node_element_id 7 | attr_reader :type 8 | 9 | def initialize(id, element_id, start_node_id, start_node_element_id, end_node_id, end_node_element_id, type, **properties) 10 | super(id, element_id, **properties) 11 | set_start_and_end_node_ids(start_node_id, start_node_element_id, end_node_id, end_node_element_id) 12 | @type = type.to_sym 13 | end 14 | 15 | def set_start_and_end_node_ids(start_node_id, start_node_element_id, end_node_id, end_node_element_id) 16 | @start_node_id = start_node_id 17 | @start_node_element_id = start_node_element_id || start_node_id.to_s 18 | @end_node_id = end_node_id 19 | @end_node_element_id = end_node_element_id || end_node_id.to_s 20 | end 21 | 22 | def to_s 23 | "relationship<#{id}>" 24 | end 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/internal_result.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | class InternalResult 4 | extend Synchronizable 5 | include Enumerable 6 | sync :keys, :has_next?, :next, :single, :peek, :consume 7 | delegate :keys, to: :@cursor 8 | 9 | def initialize(connection, cursor) 10 | @connection = connection 11 | @cursor = cursor 12 | end 13 | 14 | def has_next? 15 | @cursor.peek_async.result! 16 | end 17 | 18 | def next 19 | @cursor.next_async.result! || raise(Exceptions::NoSuchRecordException.no_more) 20 | end 21 | 22 | def single 23 | @cursor.single_async.result! 24 | end 25 | 26 | def peek 27 | @cursor.peek_async.result! or raise Exceptions::NoSuchRecordException.no_peek_past 28 | end 29 | 30 | def each 31 | yield self.next while has_next? 32 | end 33 | 34 | def consume 35 | @cursor.consume_async.result! 36 | end 37 | 38 | def remove 39 | raise ClientException, 'Removing records from a result is not supported.' 40 | end 41 | 42 | private 43 | 44 | def terminate_connection_on_thread_interrupt 45 | @connection.terminate_and_release('Thread interrupted while waiting for result to arrive') 46 | end 47 | end 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/logging/channel_activity_logger.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Logging 4 | class ChannelActivityLogger < ReformattedLogger 5 | def initialize(channel, logger, owner) 6 | super(logger) 7 | @channel = channel 8 | @local_channel_id = channel&.object_id&.to_s 9 | @owner = owner 10 | end 11 | 12 | private 13 | 14 | def format_message(severity, datetime, progname, msg) 15 | super(severity, datetime, @owner || progname, 16 | @channel && "[0x#{@local_channel_id}] [#{server_address}] [#{db_connection_id}] #{msg}" || msg) 17 | end 18 | 19 | def db_connection_id 20 | @db_connection_id ||= Async::Connection::ChannelAttributes.connection_id(@channel) 21 | end 22 | 23 | def server_address 24 | @server_address ||= Async::Connection::ChannelAttributes.server_address(@channel)&.to_s 25 | end 26 | end 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/logging/channel_error_logger.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Logging 4 | class ChannelErrorLogger < ChannelActivityLogger 5 | DEBUG_MESSAGE_FORMAT = "%s (%s)" 6 | 7 | def initialize(channel, logger) 8 | super(channel, logger, self.class) 9 | end 10 | 11 | def debug(message, error) 12 | super(DEBUG_MESSAGE_FORMAT % [message, error.class]) 13 | end 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/logging/prefixed_logger.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Logging 4 | class PrefixedLogger < ReformattedLogger 5 | def initialize(message_prefix = nil, delegate) 6 | super(delegate) 7 | @message_prefix = message_prefix 8 | end 9 | 10 | private 11 | 12 | def format_message(severity, datetime, progname, msg) 13 | return super unless @message_prefix 14 | super(severity, datetime, progname, "#{@message_prefix} #{msg}") 15 | end 16 | end 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/logging/reformatted_logger.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Logging 4 | class ReformattedLogger 5 | delegate_missing_to :@delegate 6 | 7 | def initialize(delegate) 8 | @delegate = Validator.require_non_nil!(delegate) 9 | end 10 | 11 | def trace(*arg) 12 | debug(*arg) 13 | end 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/abstract_message_writer.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | class AbstractMessageWriter 5 | def initialize(packer) 6 | @packer = Internal::Validator.require_non_nil!(packer) 7 | @encoders_by_message_signature = Internal::Validator.require_non_nil!(build_encoders).transform_values(&:new) 8 | end 9 | 10 | def write(msg) 11 | signature = msg.class::SIGNATURE 12 | encoder = @encoders_by_message_signature[signature] 13 | 14 | if encoder.nil? 15 | raise IOError, "No encoder found for message #{msg} with signature #{signature}" 16 | end 17 | 18 | encoder.encode(msg, @packer) 19 | end 20 | end 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/bolt_protocol.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module BoltProtocol 5 | def self.for_channel(channel) 6 | for_version(channel.attributes[:protocol_version]) 7 | end 8 | 9 | def self.for_version(version) 10 | case version 11 | when V3::BoltProtocolV3::VERSION 12 | V3::BoltProtocolV3::INSTANCE 13 | when V4::BoltProtocolV4::VERSION 14 | V4::BoltProtocolV4::INSTANCE 15 | when V41::BoltProtocolV41::VERSION 16 | V41::BoltProtocolV41::INSTANCE 17 | when V42::BoltProtocolV42::VERSION 18 | V42::BoltProtocolV42::INSTANCE 19 | when V43::BoltProtocolV43::VERSION 20 | V43::BoltProtocolV43::INSTANCE 21 | when V44::BoltProtocolV44::VERSION 22 | V44::BoltProtocolV44::INSTANCE 23 | when V5::BoltProtocolV5::VERSION 24 | V5::BoltProtocolV5::INSTANCE 25 | else 26 | raise Exceptions::ClientException, "Unknown protocol version: #{version}" 27 | end 28 | end 29 | end 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/common/common_value.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module Common 5 | module CommonValue 6 | include Packstream::PackStream::Common 7 | DATE = 'D' 8 | DATE_STRUCT_SIZE = 1 9 | TIME = 'T' 10 | TIME_STRUCT_SIZE = 2 11 | LOCAL_TIME = 't' 12 | LOCAL_TIME_STRUCT_SIZE = 1 13 | LOCAL_DATE_TIME = 'd' 14 | LOCAL_DATE_TIME_STRUCT_SIZE = 2 15 | DATE_TIME_WITH_ZONE_OFFSET = 'F' 16 | DATE_TIME_WITH_ZONE_OFFSET_UTC = 'I' 17 | DATE_TIME_WITH_ZONE_ID = 'f' 18 | DATE_TIME_WITH_ZONE_ID_UTC = 'i' 19 | DATE_TIME_STRUCT_SIZE = 3 20 | DURATION = 'E' 21 | DURATION_TIME_STRUCT_SIZE = 4 22 | POINT_2D_STRUCT_TYPE = 'X' 23 | POINT_2D_STRUCT_SIZE = 3 24 | POINT_3D_STRUCT_TYPE = 'Y' 25 | POINT_3D_STRUCT_SIZE = 4 26 | 27 | EPOCH = Date.parse('1970-01-01') 28 | NANO_FACTOR = 1_000_000_000 29 | end 30 | end 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/encode/begin_message_encoder.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module Encode 5 | class BeginMessageEncoder 6 | def encode(message, packer) 7 | Util::Preconditions.check_argument(message, Request::BeginMessage) 8 | packer.pack_struct_header(1, message.signature) 9 | packer.pack(message.metadata) 10 | end 11 | end 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/encode/commit_message_encoder.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module Encode 5 | class CommitMessageEncoder 6 | def encode(message, packer) 7 | Util::Preconditions.check_argument(message, Request::CommitMessage) 8 | packer.pack_struct_header(0, Request::CommitMessage::SIGNATURE) 9 | end 10 | end 11 | end 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/encode/discard_all_message_encoder.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module Encode 5 | class DiscardAllMessageEncoder 6 | def encode(message, packer) 7 | Util::Preconditions.check_argument(message, Request::DiscardAllMessage) 8 | packer.pack_struct_header(0, Request::DiscardAllMessage::SIGNATURE) 9 | end 10 | end 11 | end 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/encode/discard_message_encoder.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module Encode 5 | class DiscardMessageEncoder 6 | def encode(message, packer) 7 | Util::Preconditions.check_argument(message, Request::DiscardMessage) 8 | packer.pack_struct_header(1, Request::DiscardMessage::SIGNATURE) 9 | packer.pack(message.metadata) 10 | end 11 | end 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/encode/goodbye_message_encoder.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module Encode 5 | class GoodbyeMessageEncoder 6 | def encode(message, packer) 7 | Util::Preconditions.check_argument(message, Request::GoodbyeMessage) 8 | packer.pack_struct_header(0, Request::GoodbyeMessage::SIGNATURE) 9 | end 10 | end 11 | end 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/encode/hello_message_encoder.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module Encode 5 | class HelloMessageEncoder 6 | def encode(message, packer) 7 | Util::Preconditions.check_argument(message, Request::HelloMessage) 8 | packer.pack_struct_header(1, message.class::SIGNATURE) 9 | packer.pack(message.metadata) 10 | end 11 | end 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/encode/init_message_encoder.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module Encode 5 | class InitMessageEncoder 6 | def encode(message, packer) 7 | Util::Preconditions.check_argument(message, Request::InitMessage) 8 | packer.pack_struct_header(2, message.signature) 9 | packer.pack(message.user_agent) 10 | packer.pack(message.auth_token) 11 | end 12 | end 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/encode/logoff_message_encoder.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module Encode 5 | class LogoffMessageEncoder 6 | def encode(message, packer) 7 | Util::Preconditions.check_argument(message, Request::LogoffMessage) 8 | packer.pack_struct_header(0, message.class::SIGNATURE) 9 | end 10 | end 11 | end 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/encode/logon_message_encoder.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module Encode 5 | class LogonMessageEncoder 6 | def encode(message, packer) 7 | Util::Preconditions.check_argument(message, Request::LogonMessage) 8 | packer.pack_struct_header(1, message.class::SIGNATURE) 9 | packer.pack(message.metadata) 10 | end 11 | end 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/encode/pull_all_message_encoder.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module Encode 5 | class PullAllMessageEncoder 6 | def encode(message, packer) 7 | Util::Preconditions.check_argument(message, Request::PullAllMessage) 8 | packer.pack_struct_header(0, Request::PullAllMessage::SIGNATURE) 9 | end 10 | end 11 | end 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/encode/pull_message_encoder.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module Encode 5 | class PullMessageEncoder 6 | def encode(message, packer) 7 | Util::Preconditions.check_argument(message, Request::PullMessage) 8 | packer.pack_struct_header(1, Request::PullMessage::SIGNATURE) 9 | packer.pack(message.metadata) 10 | end 11 | end 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/encode/reset_message_encoder.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module Encode 5 | class ResetMessageEncoder 6 | def encode(message, packer) 7 | Util::Preconditions.check_argument(message, Request::ResetMessage) 8 | packer.pack_struct_header(0, Request::ResetMessage::SIGNATURE) 9 | end 10 | end 11 | end 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/encode/rollback_message_encoder.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module Encode 5 | class RollbackMessageEncoder 6 | def encode(message, packer) 7 | Util::Preconditions.check_argument(message, Request::RollbackMessage) 8 | packer.pack_struct_header(0, Request::RollbackMessage::SIGNATURE) 9 | end 10 | end 11 | end 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/encode/route_message_encoder.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module Encode 5 | # Encodes the ROUTE message to the stream 6 | class RouteMessageEncoder 7 | def encode(message, packer) 8 | Util::Preconditions.check_argument(message, Request::RouteMessage) 9 | packer.pack_struct_header(3, message.signature) 10 | packer.pack(message.routing_context) 11 | packer.pack(message.bookmark&.values || []) 12 | packer.pack(option(message)) 13 | end 14 | 15 | private 16 | 17 | def option(message) 18 | message.database_name 19 | end 20 | end 21 | end 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/encode/route_v44_message_encoder.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module Encode 5 | # Encodes the ROUTE message to the stream 6 | class RouteV44MessageEncoder < RouteMessageEncoder 7 | private 8 | 9 | def option(message) 10 | if message.impersonated_user && !message.database_name 11 | { imp_user: message.impersonated_user } 12 | elsif message.database_name 13 | { db: message.database_name } 14 | else 15 | {} 16 | end 17 | end 18 | end 19 | end 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/encode/run_message_encoder.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module Encode 5 | class RunMessageEncoder 6 | def encode(message, packer) 7 | Util::Preconditions.check_argument(message, Request::RunMessage) 8 | packer.pack_struct_header(2, message.signature) 9 | packer.pack(message.query) 10 | packer.pack(message.parameters) 11 | end 12 | end 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/encode/run_with_metadata_message_encoder.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module Encode 5 | class RunWithMetadataMessageEncoder 6 | def encode(message, packer) 7 | Util::Preconditions.check_argument(message, Request::RunWithMetadataMessage) 8 | packer.pack_struct_header(3, message.signature) 9 | packer.pack(message.query) 10 | packer.pack(message.parameters) 11 | packer.pack(message.metadata) 12 | end 13 | end 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/request/abstract_streaming_message.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module Request 5 | class AbstractStreamingMessage < Struct.new(:n, :qid) 6 | STREAM_LIMIT_UNLIMITED = -1 7 | 8 | def metadata 9 | to_h.compact 10 | end 11 | 12 | def to_s 13 | "#{name} #{metadata}" 14 | end 15 | 16 | protected 17 | 18 | def name 19 | raise 'Abstract method called' 20 | end 21 | end 22 | end 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/request/begin_message.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module Request 5 | class BeginMessage < MessageWithMetadata 6 | SIGNATURE = 0x11 7 | 8 | def initialize(bookmark, config, database_name, mode, impersonated_user) 9 | super(Request::TransactionMetadataBuilder.build_metadata( 10 | timeout: config[:timeout], tx_metadata: config[:metadata], database_name: database_name, mode: mode, 11 | bookmark: bookmark, impersonated_user: impersonated_user)) 12 | end 13 | 14 | def signature 15 | SIGNATURE 16 | end 17 | 18 | def to_s 19 | "BEGIN #{metadata}" 20 | end 21 | end 22 | end 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/request/commit_message.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module Request 5 | class CommitMessage 6 | SIGNATURE = 0x12 7 | COMMIT = new 8 | 9 | def signature 10 | SIGNATURE 11 | end 12 | 13 | def to_s 14 | "COMMIT" 15 | end 16 | end 17 | end 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/request/discard_all_message.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module Request 5 | class DiscardAllMessage 6 | SIGNATURE = 0x2F 7 | DISCARD_ALL = new 8 | 9 | def signature 10 | SIGNATURE 11 | end 12 | 13 | def to_s 14 | "DISCARD_ALL" 15 | end 16 | end 17 | end 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/request/discard_message.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module Request 5 | class DiscardMessage < AbstractStreamingMessage 6 | SIGNATURE = 0x2F 7 | 8 | def self.new_discard_all_message(id) 9 | new(STREAM_LIMIT_UNLIMITED, id) 10 | end 11 | 12 | def name 13 | "DISCARD" 14 | end 15 | 16 | def signature 17 | SIGNATURE 18 | end 19 | end 20 | end 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/request/goodbye_message.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module Request 5 | class GoodbyeMessage 6 | SIGNATURE = 0x02 7 | GOODBYE = new 8 | 9 | def signature 10 | SIGNATURE 11 | end 12 | 13 | def to_s 14 | "GOODBYE" 15 | end 16 | end 17 | end 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/request/hello_message.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module Request 5 | class HelloMessage < MessageWithMetadata 6 | SIGNATURE = 0x01 7 | USER_AGENT_METADATA_KEY = :user_agent 8 | ROUTING_CONTEXT_METADATA_KEY = :routing 9 | 10 | def initialize(user_agent, auth_token, routing_context) 11 | super(build_metadata(user_agent, auth_token, routing_context)) 12 | end 13 | 14 | def to_s 15 | "HELLO #{safe_metadata}" 16 | end 17 | 18 | private 19 | 20 | def build_metadata(user_agent, auth_token, routing_context) 21 | auth_token.merge( 22 | USER_AGENT_METADATA_KEY => user_agent, 23 | ROUTING_CONTEXT_METADATA_KEY => routing_context 24 | ).compact 25 | end 26 | end 27 | end 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/request/init_message.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module Request 5 | class InitMessage < Struct.new(:user_agent, :auth_token) 6 | SIGNATURE = 0x01 7 | 8 | def signature 9 | SIGNATURE 10 | end 11 | 12 | def to_s 13 | "INIT \"#{user_agent}\" {...}" 14 | end 15 | end 16 | end 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/request/logoff_message.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module Request 5 | class LogoffMessage < MessageWithMetadata 6 | SIGNATURE = 0x6B 7 | 8 | def to_s = 'LOGOFF' 9 | end 10 | end 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/request/logon_message.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module Request 5 | class LogonMessage < MessageWithMetadata 6 | SIGNATURE = 0x6A 7 | 8 | def to_s = "LOGON #{safe_metadata}" 9 | end 10 | end 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/request/message_with_metadata.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module Request 5 | class MessageWithMetadata < Struct.new(:metadata) 6 | protected 7 | 8 | def safe_metadata = replace(metadata, Security::InternalAuthToken::CREDENTIALS_KEY, '******') 9 | 10 | private 11 | 12 | def replace(hash, key, value) = hash.key?(key) ? hash.merge(key => value) : hash 13 | end 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/request/multi_database_util.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module Request 5 | class MultiDatabaseUtil 6 | class << self 7 | def assert_empty_database_name(database_name, bolt_version) 8 | if database_name.database_name.present? 9 | raise Exceptions::ClientException, "Database name parameter for selecting database is not supported in Bolt Protocol Version #{bolt_version}. Database name: '#{database_name.description}'" 10 | end 11 | end 12 | 13 | def supports_multi_database?(connection) 14 | connection.server_version >= Util::ServerVersion::V4_0_0 && 15 | connection.protocol.version >= V4::BoltProtocolV4::VERSION 16 | end 17 | 18 | def supports_route_message?(connection) 19 | connection.protocol.version >= V43::BoltProtocolV43::VERSION 20 | end 21 | end 22 | end 23 | end 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/request/pull_all_message.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module Request 5 | # PULL_ALL request message 6 | #

7 | # Sent by clients to pull the entirety of the remaining stream down. 8 | class PullAllMessage 9 | SIGNATURE = 0x3F 10 | PULL_ALL = new 11 | 12 | def signature 13 | SIGNATURE 14 | end 15 | 16 | def to_s 17 | 'PULL_ALL' 18 | end 19 | end 20 | end 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/request/pull_message.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module Request 5 | # PULL request message 6 | #

7 | # Sent by clients to pull the entirety of the remaining stream down. 8 | class PullMessage < AbstractStreamingMessage 9 | SIGNATURE = 0x3F 10 | 11 | def name 12 | "PULL" 13 | end 14 | 15 | def signature 16 | SIGNATURE 17 | end 18 | end 19 | end 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/request/reset_message.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module Request 5 | # RESET request message 6 | #

7 | # Sent by clients to reset a session to a clean state - closing any open transaction or result streams. 8 | # This also acknowledges receipt of failures sent by the server. This is required to 9 | # allow optimistic sending of multiple messages before responses have been received - pipelining. 10 | #

11 | # When something goes wrong, we want the server to stop processing our already sent messages, 12 | # but the server cannot tell the difference between what was sent before and after we saw the 13 | # error. 14 | #

15 | # This message acts as a barrier after an error, informing the server that we've seen the error 16 | # message, and that messages that follow this one are safe to execute. 17 | class ResetMessage 18 | SIGNATURE = 0x0F 19 | RESET = new 20 | 21 | def to_s 22 | 'RESET' 23 | end 24 | 25 | def signature 26 | SIGNATURE 27 | end 28 | end 29 | end 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/request/rollback_message.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module Request 5 | class RollbackMessage 6 | SIGNATURE = 0x13 7 | ROLLBACK = new 8 | 9 | def signature 10 | SIGNATURE 11 | end 12 | 13 | def to_s 14 | 'ROLLBACK' 15 | end 16 | end 17 | end 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/request/route_message.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module Request 5 | # From the application point of view it is not interesting to know about the role a member plays in the cluster. Instead, the application needs to know which 6 | # instance can provide the wanted service. 7 | #

8 | # This message is used to fetch this routing information. 9 | # 10 | # @param routingContext The routing context used to define the routing table. Multi-datacenter deployments is one of its use cases. 11 | # @param bookmark The bookmark used when getting the routing table. 12 | # @param databaseName The name of the database to get the routing table for. 13 | # @param impersonatedUser The name of the impersonated user to get the routing table for, should be {@code null} for non-impersonated requests 14 | class RouteMessage < Struct.new(:routing_context, :bookmark, :database_name, :impersonated_user) 15 | SIGNATURE = 0x66 16 | 17 | def signature 18 | SIGNATURE 19 | end 20 | 21 | def to_s 22 | "ROUTE #{values.join(' ')}" 23 | end 24 | end 25 | end 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/request/run_message.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module Request 5 | # RUN request message 6 | #

7 | # Sent by clients to start a new Tank job for a given query and 8 | # parameter set. 9 | class RunMessage < Struct.new(:query, :parameters) 10 | SIGNATURE = 0x10 11 | 12 | def signature 13 | SIGNATURE 14 | end 15 | 16 | def to_s 17 | "RUN \"#{query}\" #{parameters}" 18 | end 19 | end 20 | end 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/request/transaction_metadata_builder.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module Request 5 | class TransactionMetadataBuilder 6 | MODE_READ_VALUE = 'r' 7 | 8 | class << self 9 | def build_metadata(timeout:, tx_metadata:, mode:, bookmark:, impersonated_user:, 10 | database_name: DatabaseNameUtil.default_database) 11 | { bookmarks: bookmark.presence, 12 | tx_timeout: timeout&.then(&DurationNormalizer.method(:milliseconds)), 13 | tx_metadata: tx_metadata.presence, 14 | mode: (MODE_READ_VALUE if mode == AccessMode::READ), 15 | db: database_name&.database_name, 16 | imp_user: impersonated_user 17 | }.compact 18 | end 19 | end 20 | end 21 | end 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/response/failure_message.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module Response 5 | # FAILURE response message 6 | #

7 | # Sent by the server to signal a failed operation. 8 | # Terminates response sequence. 9 | class FailureMessage 10 | SIGNATURE = 0x7F 11 | 12 | attr_reader :code, :message 13 | 14 | def initialize(code, message) 15 | @code = code 16 | @message = message 17 | end 18 | 19 | def to_s 20 | "FAILURE #{code} \"#{message}\"" 21 | end 22 | 23 | def equals(object) 24 | return true if self == object 25 | 26 | return false if object.nil? || self.class != object.class 27 | 28 | !(!code.nil? ? !code.equals(object.code) : !object.code.nil?) && !(!message.nil? ? !message.equals(object.message) : !object.message.nil?) 29 | end 30 | 31 | def hash_code 32 | result = !code.nil? ? code.hash_code : 0 33 | result = 31 * result + (!message.nil? ? message.hash_code : 0) 34 | result 35 | end 36 | end 37 | end 38 | end 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/response/ignored_message.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module Response 5 | # IGNORED response message 6 | 7 | #

8 | # Sent by the server to signal that an operation has been ignored. 9 | # Terminates response sequence. 10 | class IgnoredMessage 11 | SIGNATURE = 0x7E 12 | IGNORED = new 13 | 14 | def to_s 15 | "IGNORED {}" 16 | end 17 | 18 | def equals(obj) 19 | !obj.nil? && obj.class == self.class 20 | end 21 | 22 | def hash_code 23 | 1 24 | end 25 | end 26 | end 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/response/record_message.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module Response 5 | class RecordMessage 6 | SIGNATURE = 0x71 7 | 8 | attr_reader :fields 9 | 10 | def initialize(fields) 11 | @fields = fields 12 | end 13 | 14 | def to_s 15 | "RECORD #{fields}" 16 | end 17 | 18 | def equals(object) 19 | return true if self == object 20 | 21 | return false if object.nil? || self.class != object.class 22 | 23 | fields == object.fields 24 | end 25 | 26 | def hash_code 27 | java.util.Arrays.hash_code(fields) 28 | end 29 | end 30 | end 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/response/success_message.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module Response 5 | # SUCCESS response message 6 | 7 | #

8 | # Sent by the server to signal a successful operation. 9 | # Terminates response sequence. 10 | class SuccessMessage 11 | SIGNATURE = 0x70 12 | 13 | attr_reader :metadata 14 | 15 | def initialize(metadata) 16 | @metadata = metadata 17 | end 18 | 19 | def to_s 20 | "SUCCESS #{metadata}" 21 | end 22 | 23 | def equals(obj) 24 | !obj.nil? && obj.class == self.class 25 | end 26 | 27 | def hash_code 28 | 1 29 | end 30 | end 31 | end 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/v3/message_format_v3.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module V3 5 | class MessageFormatV3 6 | def new_writer(output) 7 | MessageWriterV3.new(output) 8 | end 9 | 10 | def new_reader(input) = Common::CommonMessageReader.new(new_value_unpacker(input)) 11 | 12 | def new_value_unpacker(input) = Async::Connection::StreamReader.new(input) 13 | end 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/v3/message_writer_v3.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module V3 5 | class MessageWriterV3 < AbstractMessageWriter 6 | COMMON_ENCODERS = { 7 | Request::HelloMessage::SIGNATURE => Encode::HelloMessageEncoder, 8 | Request::GoodbyeMessage::SIGNATURE => Encode::GoodbyeMessageEncoder, 9 | Request::RunWithMetadataMessage::SIGNATURE => Encode::RunWithMetadataMessageEncoder, 10 | Request::BeginMessage::SIGNATURE => Encode::BeginMessageEncoder, 11 | Request::CommitMessage::SIGNATURE => Encode::CommitMessageEncoder, 12 | Request::RollbackMessage::SIGNATURE => Encode::RollbackMessageEncoder, 13 | Request::ResetMessage::SIGNATURE => Encode::ResetMessageEncoder, 14 | } 15 | private 16 | 17 | def build_encoders 18 | COMMON_ENCODERS.merge( 19 | Request::DiscardAllMessage::SIGNATURE => Encode::DiscardAllMessageEncoder, 20 | Request::PullAllMessage::SIGNATURE => Encode::PullAllMessageEncoder, 21 | ) 22 | end 23 | end 24 | end 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/v4/bolt_protocol_v4.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module V4 5 | class BoltProtocolV4 < V3::BoltProtocolV3 6 | VERSION = BoltProtocolVersion.new(4,0) 7 | INSTANCE = new 8 | 9 | def create_message_format 10 | MessageFormatV4.new 11 | end 12 | 13 | def build_result_cursor_factory(connection, query, bookmark_holder, tx, run_message, fetch_size) 14 | run_handler = Handlers::RunResponseHandler.new(V3::BoltProtocolV3::METADATA_EXTRACTOR, connection, tx) 15 | 16 | pull_all_handler = Handlers::PullHandlers.new_bolt_v4_auto_pull_handler(query, run_handler, connection, bookmark_holder, tx, fetch_size) 17 | pull_handler = Handlers::PullHandlers.new_bolt_v4_basic_pull_handler(query, run_handler, connection, bookmark_holder, tx) 18 | 19 | Cursor::ResultCursorFactoryImpl.new(connection, run_message, run_handler, pull_handler, pull_all_handler) 20 | end 21 | 22 | def verify_database_name_before_transaction(_database_name) 23 | # Bolt V4.1 accepts database name 24 | end 25 | end 26 | end 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/v4/message_format_v4.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module V4 5 | class MessageFormatV4 < V3::MessageFormatV3 6 | def new_writer(output) 7 | MessageWriterV4.new(output) 8 | end 9 | end 10 | end 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/v4/message_writer_v4.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module V4 5 | class MessageWriterV4 < V3::MessageWriterV3 6 | private 7 | 8 | def build_encoders 9 | COMMON_ENCODERS.merge( 10 | Request::DiscardMessage::SIGNATURE => Encode::DiscardMessageEncoder, 11 | Request::PullMessage::SIGNATURE => Encode::PullMessageEncoder) 12 | end 13 | end 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/v41/bolt_protocol_v41.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module V41 5 | class BoltProtocolV41 < V4::BoltProtocolV4 6 | VERSION = BoltProtocolVersion.new(4, 1) 7 | INSTANCE = new 8 | 9 | def create_message_format 10 | V4::MessageFormatV4.new 11 | end 12 | 13 | def build_result_cursor_factory(connection, query, bookmark_holder, tx, run_message, fetch_size) 14 | run_handler = Handlers::RunResponseHandler.new(V3::BoltProtocolV3::METADATA_EXTRACTOR, connection, tx) 15 | 16 | pull_all_handler = Handlers::PullHandlers.new_bolt_v4_auto_pull_handler(query, run_handler, connection, bookmark_holder, tx, fetch_size) 17 | pull_handler = Handlers::PullHandlers.new_bolt_v4_basic_pull_handler(query, run_handler, connection, bookmark_holder, tx) 18 | 19 | Cursor::ResultCursorFactoryImpl.new(connection, run_message, run_handler, pull_handler, pull_all_handler) 20 | end 21 | end 22 | end 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/v42/bolt_protocol_v42.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module V42 5 | # Bolt V4.2 is identical to V4.1 6 | class BoltProtocolV42 < V41::BoltProtocolV41 7 | VERSION = BoltProtocolVersion.new(4,2) 8 | INSTANCE = new 9 | end 10 | end 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/v43/bolt_protocol_v43.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module V43 5 | # Definition of the Bolt Protocol 4.3 6 | 7 | # The version 4.3 use most of the 4.2 behaviours, but it extends it with new messages such as ROUTE 8 | class BoltProtocolV43 < V42::BoltProtocolV42 9 | VERSION = BoltProtocolVersion.new(4,3) 10 | INSTANCE = new 11 | 12 | def create_message_format 13 | MessageFormatV43.new 14 | end 15 | end 16 | end 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/v43/message_format_v43.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module V43 5 | # Bolt message format v4.3 6 | class MessageFormatV43 < V4::MessageFormatV4 7 | def new_writer(output) 8 | MessageWriterV43.new(output) 9 | end 10 | end 11 | end 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/v43/message_writer_v43.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module V43 5 | 6 | # Bolt message writer v4.3 7 | # This version is able to encode all the versions existing on v4.2, but it encodes 8 | 9 | # new messages such as ROUTE 10 | class MessageWriterV43 < V4::MessageWriterV4 11 | private 12 | 13 | def build_encoders 14 | super.merge(Request::RouteMessage::SIGNATURE => Encode::RouteMessageEncoder) 15 | end 16 | end 17 | end 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/v44/bolt_protocol_v44.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module V44 5 | # Definition of the Bolt Protocol 4.4 6 | class BoltProtocolV44 < V43::BoltProtocolV43 7 | VERSION = BoltProtocolVersion.new(4,4) 8 | INSTANCE = new 9 | 10 | def create_message_format 11 | MessageFormatV44.new 12 | end 13 | end 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/v44/message_format_v44.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module V44 5 | # Bolt message format v4.4 6 | class MessageFormatV44 < V43::MessageFormatV43 7 | def new_writer(output) 8 | MessageWriterV44.new(output) 9 | end 10 | end 11 | end 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/v44/message_writer_v44.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module V44 5 | class MessageWriterV44 < V4::MessageWriterV4 6 | private 7 | 8 | def build_encoders 9 | super.merge(Request::RouteMessage::SIGNATURE => Encode::RouteV44MessageEncoder) 10 | end 11 | end 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/v5/bolt_protocol_v5.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module V5 5 | # Definition of the Bolt Protocol 5.0 6 | class BoltProtocolV5 < V44::BoltProtocolV44 7 | VERSION = BoltProtocolVersion.new(5, 0) 8 | INSTANCE = new 9 | 10 | def create_message_format 11 | MessageFormatV5.new 12 | end 13 | 14 | protected 15 | 16 | def include_date_time_utc_patch_in_hello = false 17 | end 18 | end 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/v5/message_format_v5.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module V5 5 | # Bolt message format v5.0 6 | class MessageFormatV5 < V44::MessageFormatV44 7 | def new_writer(output) 8 | output.date_time_utc_enabled = true 9 | super 10 | end 11 | def new_value_unpacker(input) 12 | ValueUnpackerV5.new(input) 13 | end 14 | end 15 | end 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/v5/value_unpacker_v5.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module V5 5 | class ValueUnpackerV5 < Async::Connection::StreamReader 6 | alias unpack_element_id unpack 7 | 8 | def node_fields = 4 9 | 10 | def relationship_fields = 8 11 | 12 | def unbound_relationship_fields = 4 13 | end 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/v51/bolt_protocol_v51.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module V51 5 | class BoltProtocolV51 < V5::BoltProtocolV5 6 | VERSION = BoltProtocolVersion.new(5, 1) 7 | INSTANCE = new 8 | 9 | def create_message_format 10 | MessageFormatV51.new 11 | end 12 | 13 | def initialize_channel(channel, user_agent, auth_token, routing_context) 14 | message = Request::HelloMessage.new(user_agent, {}, 15 | (routing_context.to_h if routing_context.server_routing_enabled?)) 16 | handler = Handlers::HelloV51ResponseHandler.new(channel, VERSION) 17 | 18 | channel.message_dispatcher.enqueue(handler) 19 | channel.write(message) 20 | message = Request::LogonMessage(auth_token) 21 | channel.message_dispatcher.enqueue(LogonResponseHandle.new(channel, auth_token)) 22 | channel.write_and_flush(message) 23 | end 24 | 25 | def logoff 26 | 27 | end 28 | 29 | def logon 30 | 31 | end 32 | 33 | def version 34 | self.class::VERSION 35 | end 36 | end 37 | end 38 | end 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/v51/message_format_v51.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module V51 5 | # Bolt message format v4.4 6 | class MessageFormatV51 < V5::MessageFormatV5 7 | def new_writer(output) 8 | MessageWriterV51.new(output) 9 | end 10 | end 11 | end 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/messaging/v51/message_writer_v51.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Messaging 4 | module V51 5 | class MessageWriterV51 < V44::MessageWriterV44 6 | private 7 | 8 | def build_encoders 9 | super.merge( 10 | LogonMessage.SIGNATURE => Encode::LogonMessageEncoder, 11 | LogoffMessage.SIGNATURE => Encode::LogoffMessageEncoder) 12 | end 13 | end 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/metrics/connection_pool_metrics_listener.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Metrics 4 | module ConnectionPoolMetricsListener 5 | DEV_NULL_POOL_METRICS_LISTENER = 6 | Class.new do 7 | def before_creating(_listener_event) end 8 | 9 | def after_created(_listener_event) end 10 | 11 | def after_failed_to_create 12 | end 13 | 14 | def after_closed 15 | end 16 | 17 | def before_acquiring_or_creating(_acquire_event = nil) end 18 | 19 | def after_acquiring_or_creating 20 | end 21 | 22 | def after_acquired_or_created(_acquire_event) end 23 | 24 | def after_timed_out_to_acquire_or_create 25 | end 26 | 27 | def acquired(_in_use_event) end 28 | 29 | def released(_in_use_event) end 30 | end.new 31 | end 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/metrics/internal_metrics_provider.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Metrics 4 | class InternalMetricsProvider 5 | attr_reader :metrics 6 | alias metrics_listener metrics 7 | 8 | def initialize(logger) 9 | @metrics = InternalMetrics.new(logger) 10 | end 11 | 12 | def metrics_enabled? 13 | true 14 | end 15 | end 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/metrics/listener_event.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Metrics 4 | module ListenerEvent 5 | DEV_NULL_LISTENER_EVENT = 6 | Class.new do 7 | def start 8 | end 9 | 10 | def elapsed 11 | 0 12 | end 13 | end.new 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/metrics/metrics_provider.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Metrics 4 | module MetricsProvider 5 | METRICS_DISABLED_PROVIDER = 6 | Class.new do 7 | def metrics 8 | # To outside users, we forbidden their access to the metrics API 9 | raise Exceptions::ClientException, "Driver metrics not enabled. To access driver metrics, you need to enabled driver metrics in the driver's configuration." 10 | end 11 | 12 | def metrics_listener 13 | # Internally we can still register callbacks to this empty metrics listener. 14 | InternalAbstractMetrics::DEV_NULL_METRICS 15 | end 16 | 17 | def metrics_enabled? 18 | false 19 | end 20 | end.new 21 | end 22 | end 23 | end 24 | end -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/metrics/time_recorder_listener_event.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Metrics 4 | class TimeRecorderListenerEvent 5 | def start 6 | @start_time = Util::Clock::System.millis 7 | end 8 | 9 | def elapsed 10 | Util::Clock::System.millis - @start_time 11 | end 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/packstream/byte_array_incompatible_packer.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Packstream 4 | class ByteArrayIncompatiblePacker 5 | include PackStream::Packer 6 | def pack_bytes_header(_size) 7 | raise PackStream::UnPackable.new('Packing bytes is not supported as the current server this driver connected to does not support unpack bytes.') 8 | end 9 | end 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/packstream/pack_input.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Packstream 4 | module PackInput 5 | def read_char 6 | read_exactly(1) 7 | end 8 | 9 | def read_byte 10 | read_exactly(1).unpack1('c') 11 | end 12 | 13 | def read_ubyte 14 | read_exactly(1).unpack1('C') 15 | end 16 | 17 | def read_short 18 | read_exactly(2).unpack1('s>') 19 | end 20 | 21 | def read_ushort 22 | read_exactly(2).unpack1('S>') 23 | end 24 | 25 | def read_int 26 | read_exactly(4).unpack1('l>') 27 | end 28 | 29 | def read_uint 30 | read_exactly(4).unpack1('L>') 31 | end 32 | 33 | def read_long 34 | read_exactly(8).unpack1('q>') 35 | end 36 | 37 | def read_ulong 38 | read_exactly(8).unpack1('Q>') 39 | end 40 | 41 | def read_double 42 | read_exactly(8).unpack1('G') 43 | end 44 | end 45 | end 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/packstream/pack_output.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Packstream 4 | module PackOutput 5 | ## Produce a single byte 6 | def write_byte(value) 7 | value.is_a?(String) ? write(value) : write_value(value, 'c') 8 | end 9 | 10 | ## Produce a 4-byte signed integer 11 | def write_short(value) 12 | write_value(value, 's>') 13 | end 14 | 15 | ## Produce a 4-byte signed integer 16 | def write_int(value) 17 | write_value(value, 'l>') 18 | end 19 | 20 | ## Produce an 8-byte signed integer 21 | def write_long(value) 22 | write_value(value, 'q>') 23 | end 24 | 25 | ## Produce an 8-byte IEEE 754 "double format" floating-point number 26 | def write_double(value) 27 | write_value(value, 'G') 28 | end 29 | 30 | private 31 | 32 | def write_value(value, directive) 33 | write([value].pack(directive)) 34 | self 35 | end 36 | end 37 | end 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/packstream/pack_type.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Packstream 4 | class PackType 5 | NULL = :null 6 | BOOLEAN = :boolean 7 | INTEGER = :integer 8 | FLOAT = :float 9 | BYTES = :bytes 10 | STRING = :string 11 | LIST = :list 12 | MAP = :map 13 | STRUCT = :struct 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/read_only_bookmark_holder.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | class ReadOnlyBookmarkHolder 4 | attr_reader :bookmark 5 | 6 | def initialize(bookmark = InternalBookmark.empty) 7 | @bookmark = bookmark 8 | end 9 | 10 | def bookmark=(_value) end 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/revocation_strategy.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j::Driver::Internal 4 | module RevocationStrategy 5 | # Don't do any OCSP revocation checks, regardless whether there are stapled revocation statuses or not. 6 | NO_CHECKS = :no_checks 7 | 8 | # Verify OCSP revocation checks when the revocation status is stapled to the certificate, continue if not. 9 | VERIFY_IF_PRESENT = :verify_if_present 10 | 11 | # Require stapled revocation status and verify OCSP revocation checks, 12 | # fail if no revocation status is stapled to the certificate. 13 | STRICT = :strict 14 | 15 | def self.requires_revocation_checking?(revocation_strategy) 16 | revocation_strategy == STRICT || revocation_strategy == VERIFY_IF_PRESENT 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/scheme.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver::Internal::Scheme 2 | BOLT_URI_SCHEME = 'bolt' 3 | BOLT_HIGH_TRUST_URI_SCHEME = 'bolt+s' 4 | BOLT_LOW_TRUST_URI_SCHEME = 'bolt+ssc' 5 | NEO4J_URI_SCHEME = 'neo4j' 6 | NEO4J_HIGH_TRUST_URI_SCHEME = 'neo4j+s' 7 | NEO4J_LOW_TRUST_URI_SCHEME = 'neo4j+ssc' 8 | 9 | def validate_scheme!(scheme) 10 | unless [BOLT_URI_SCHEME, BOLT_LOW_TRUST_URI_SCHEME, BOLT_HIGH_TRUST_URI_SCHEME, NEO4J_URI_SCHEME, 11 | NEO4J_LOW_TRUST_URI_SCHEME, NEO4J_HIGH_TRUST_URI_SCHEME].include?(scheme) 12 | raise ArgumentError, scheme ? "Invalid address format #{scheme}" : 'Scheme must not be null' 13 | end 14 | end 15 | 16 | def high_trust_scheme?(scheme) 17 | [BOLT_HIGH_TRUST_URI_SCHEME, NEO4J_HIGH_TRUST_URI_SCHEME].include?(scheme) 18 | end 19 | 20 | def low_trust_scheme?(scheme) 21 | [BOLT_LOW_TRUST_URI_SCHEME, NEO4J_LOW_TRUST_URI_SCHEME].include?(scheme) 22 | end 23 | 24 | def security_scheme?(scheme) 25 | [BOLT_LOW_TRUST_URI_SCHEME, NEO4J_LOW_TRUST_URI_SCHEME, BOLT_HIGH_TRUST_URI_SCHEME, NEO4J_HIGH_TRUST_URI_SCHEME] 26 | .include?(scheme) 27 | end 28 | 29 | def routing_scheme?(scheme) 30 | [NEO4J_LOW_TRUST_URI_SCHEME, NEO4J_HIGH_TRUST_URI_SCHEME, NEO4J_URI_SCHEME].include?(scheme) 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/security/internal_auth_token.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Security 4 | # A simple common token for authentication schemes that easily convert to 5 | # an auth token map 6 | class InternalAuthToken < Hash 7 | SCHEME_KEY = :scheme 8 | PRINCIPAL_KEY = :principal 9 | CREDENTIALS_KEY = :credentials 10 | REALM_KEY = :realm 11 | PARAMETERS_KEY = :parameters 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/spi/connection.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Spi 4 | module Connection 5 | def mode 6 | raise java.lang.UnsupportedOperationException, "#{self.class} does not support access mode." 7 | end 8 | 9 | def database_name 10 | raise java.lang.UnsupportedOperationException, "#{self.class} does not support database name." 11 | end 12 | 13 | def impersonated_user 14 | raise java.lang.UnsupportedOperationException, "#{self.class} does not support impersonated user." 15 | end 16 | end 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/spi/connection_pool.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Spi 4 | module ConnectionPool 5 | CONNECTION_POOL_CLOSED_ERROR_MESSAGE = 'Pool closed' 6 | end 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/spi/response_handler.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Spi 4 | module ResponseHandler 5 | # Tells whether this response handler is able to manage auto-read of the underlying connection using {@link Connection#enableAutoRead()} and 6 | # {@link Connection#disableAutoRead()}. 7 | #

8 | # Implementations can use auto-read management to apply network-level backpressure when receiving a stream of records. 9 | # There should only be a single such handler active for a connection at one point in time. Otherwise, handlers can interfere and turn on/off auto-read 10 | # racing with each other. {@link InboundMessageDispatcher} is responsible for tracking these handlers and disabling auto-read management to maintain just 11 | # a single auto-read managing handler per connection. 12 | def can_manage_auto_read? 13 | false 14 | end 15 | 16 | # If this response handler is able to manage auto-read of the underlying connection, then this method signals it to 17 | # stop changing auto-read setting for the connection. 18 | def disable_auto_read_management 19 | end 20 | end 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/summary/internal_database_info.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j::Driver::Internal::Summary 4 | class InternalDatabaseInfo < Struct.new(:name) 5 | DEFAULT_DATABASE_INFO = new 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/summary/internal_input_position.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j::Driver::Internal::Summary 4 | # Creating a position from and offset, line number and a column number. 5 | # 6 | # @param offset the offset from the start of the string, starting from 0. 7 | # @param line the line number, starting from 1. 8 | # @param column the column number, starting from 1. 9 | class InternalInputPosition < Struct.new(:offset, :line, :column) 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/summary/internal_notification.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j::Driver::Internal::Summary 4 | class InternalNotification < Struct.new(:code, :title, :description, :severity, :position) 5 | 6 | VALUE_TO_NOTIFICATION = lambda do |value| 7 | severity = value[:severity] || 'N/A' 8 | 9 | position = value[:position]&.then do |pos_value| 10 | InternalInputPosition.new(*pos_value.values_at(:offset, :line, :column).map(&:to_i)) 11 | end 12 | 13 | InternalNotification.new(*value.values_at(:code, :title, :description), severity, position) 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/summary/internal_result_summary.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j::Driver::Internal::Summary 4 | class InternalResultSummary < Struct.new(:query, :server, :database, :query_type, :counters, :plan, :profile, 5 | :notifications, :result_available_after, :result_consumed_after) 6 | alias has_plan? plan 7 | alias has_profile? profile 8 | 9 | def initialize(*args) 10 | super 11 | self.plan = resolve_plan(plan, profile) 12 | end 13 | 14 | def counters 15 | super || InternalSummaryCounters::EMPTY_STATS 16 | end 17 | 18 | def notifications 19 | super || [] 20 | end 21 | 22 | private 23 | 24 | # Profiled plan is a superset of plan. This method returns profiled plan if plan is {@code null}. 25 | # 26 | # @param plan the given plan, possibly {@code null}. 27 | # @param profiled_plan the given profiled plan, possibly {@code null}. 28 | # @return available plan. 29 | def resolve_plan(plan, profiled_plan) 30 | plan || profiled_plan 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/summary/internal_server_info.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j::Driver::Internal::Summary 4 | class InternalServerInfo < Struct.new(:agent, :address, :version, :protocol_version) 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/summary/internal_summary_counters.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j::Driver::Internal::Summary 4 | class InternalSummaryCounters < Struct.new(:nodes_created, :nodes_deleted, :relationships_created, 5 | :relationships_deleted, :properties_set, :labels_added, :labels_removed, 6 | :indexes_added, :indexes_removed, :constraints_added, :constraints_removed, 7 | :system_updates) 8 | EMPTY_STATS = InternalSummaryCounters.new(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) 9 | 10 | def contains_updates? 11 | any?(&:positive?) 12 | end 13 | 14 | def contains_system_updates? 15 | system_updates.positive? 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/svm/z_lib_substitutions.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Svm 4 | # This substitution avoid having jcraft zlib added to the build 5 | class Target_org_neo4j_driver_internal_shaded_io_netty_handler_codec_compression_ZlibCodecFactory 6 | class << self 7 | def new_zlib_encoder(wrapper, compression_level) 8 | org.neo4j.driver.internal.shaded.io.netty.handler.codec.compression.JdkZlibEncoder.new(wrapper, compression_level) 9 | end 10 | 11 | def zlib_decoder(wrapper) 12 | org.neo4j.driver.internal.shaded.io.netty.handler.codec.compression.jdk_zlib_decoder(wrapper) 13 | end 14 | end 15 | end 16 | 17 | class ZLibSubstitutions 18 | end 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/util/clock.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Util 4 | module Clock 5 | module System 6 | class << self 7 | def millis() 8 | gettime(:millisecond) 9 | end 10 | 11 | def time() 12 | gettime(:float_second).seconds 13 | end 14 | 15 | def sleep(duration) 16 | super(duration.in_seconds) 17 | end 18 | 19 | private 20 | 21 | def gettime(unit) 22 | Process.clock_gettime(Process::CLOCK_MONOTONIC, unit) 23 | end 24 | end 25 | end 26 | end 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/util/format.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Util 4 | class Format 5 | def initialize 6 | raise java.lang.UnsupportedOperationException 7 | end 8 | 9 | # formats map using ':' as key-value separator instead of default '=' 10 | class << self 11 | def format_pairs(entries) 12 | case entries.size 13 | when 0 14 | '{}' 15 | when 1 16 | "#{key_value_string(entries.first)}" 17 | else 18 | builder = "" 19 | builder << "{" 20 | builder << key_value_string(entries.first) 21 | 22 | entries.each do |entry| 23 | builder << "," 24 | builder << " " 25 | builder << key_value_string(entry) 26 | end 27 | 28 | builder << "}" 29 | end 30 | end 31 | 32 | private def key_value_string(entry) 33 | "#{entry.keys.first}:#{entry.values.first}" 34 | end 35 | end 36 | end 37 | end 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/util/iterables.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Util 4 | class Iterables 5 | EMPTY_QUEUE = Queue.new 6 | 7 | class << self 8 | def single(it) 9 | if it.empty? 10 | raise ArgumentError, 'Given iterable is empty' 11 | end 12 | 13 | result = it.first 14 | 15 | if it.size > 1 16 | raise ArgumentError, "Given iterable contains more than one element: #{it}" 17 | end 18 | 19 | result 20 | end 21 | 22 | def map(alternating_key_value) 23 | out = {} 24 | 25 | (0...alternating_key_value.length).step(2) do |i| 26 | out[i] = out[i+1] 27 | end 28 | 29 | out 30 | end 31 | end 32 | end 33 | end 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/util/lock_util.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Util 4 | class LockUtil 5 | class << self 6 | def execute_with_lock(lock) 7 | lock.lock 8 | begin 9 | yield 10 | ensure 11 | lock.unlock 12 | end 13 | end 14 | 15 | def execute_with_lock_async(lock) 16 | lock.lock 17 | Concurrent::Promises.fulfilled_future(lock).then_flat { yield }.on_fulfillment! { lock.unlock } 18 | end 19 | end 20 | end 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/util/mutex.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver::Internal 2 | module Util 3 | class Mutex < Mutex 4 | def synchronize 5 | owned? ? yield : super 6 | end 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/internal/util/preconditions.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Internal 3 | module Util 4 | class Preconditions 5 | # Assert that given expression is true. 6 | 7 | # @param expression the value to check. 8 | # @param message the message. 9 | # @throws IllegalArgumentException if given value is {@code false}. 10 | def self.check_argument(expression, message) 11 | raise ArgumentError, message unless expression 12 | end 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/net/server_address.rb: -------------------------------------------------------------------------------- 1 | module Neo4j::Driver 2 | module Net 3 | module ServerAddress 4 | def self.of(host, port) 5 | Internal::BoltServerAddress.new(host: host, port: port) 6 | end 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/records.rb: -------------------------------------------------------------------------------- 1 | module Neo4j 2 | module Driver 3 | # Static utility methods for retaining records 4 | 5 | # @see Result#list() 6 | # @since 1.0 7 | class Records 8 | def self.column(index, map_function) 9 | java.util.function.Function.new.apply{ |record| map_function.apply(record[index]) } 10 | end 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/values.rb: -------------------------------------------------------------------------------- 1 | module Neo4j 2 | module Driver 3 | module Values 4 | def self.value(value) 5 | this_method = method(:value) 6 | case value 7 | when nil, TrueClass, FalseClass, Integer, Float, String, Symbol, Bookmark, ActiveSupport::Duration, 8 | Types::Point, Types::Time, Time, Date 9 | value 10 | when Hash 11 | value.transform_keys(&this_method).transform_values(&this_method) 12 | when Internal::InternalPath 13 | nonconvertible(value) 14 | when Enumerable 15 | value.map(&this_method) 16 | else 17 | nonconvertible(value) 18 | end 19 | end 20 | 21 | def self.nonconvertible(value) 22 | raise Exceptions::ClientException, "Unable to convert #{value.class.name} to Neo4j Value." 23 | end 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /ruby/neo4j/driver/version.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | VERSION = '5.7.0.alpha.4' 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /spec/integration/logging_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | RSpec.describe 'LoggingSpec', concurrency: true do 4 | let(:logger) { ActiveSupport::Logger.new(IO::NULL, level: ::Logger::DEBUG) } 5 | 6 | it 'log records debug and trace info' do 7 | expect(logger).to receive(:add).at_least(:twice) 8 | Neo4j::Driver::GraphDatabase.driver(uri, basic_auth_token, logger: logger) do |driver| 9 | driver.session do |session| 10 | session.run("CREATE (a {name:'Cat'})") 11 | end 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /spec/neo4j/driver/auth_tokens_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | RSpec.describe Neo4j::Driver::AuthTokens do 4 | describe '.basic' do 5 | it 'does not allow nil username' do 6 | expect { described_class.basic(nil, 'password') }.to raise_error ArgumentError, "Username can't be nil" 7 | end 8 | 9 | it 'does not allow nil password' do 10 | expect { described_class.basic('username', nil) }.to raise_error ArgumentError, "Password can't be nil" 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/neo4j/driver/exceptions/authentication_exception_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | RSpec.describe Neo4j::Driver::Exceptions::AuthenticationException do 4 | it 'wrong credentials' do 5 | Neo4j::Driver::GraphDatabase 6 | .driver(uri, Neo4j::Driver::AuthTokens.basic('neo4j', 'wrong_password')) do |driver| 7 | expect { driver.verify_connectivity }.to raise_exception described_class 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /spec/neo4j/driver/exceptions/client_exception_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | RSpec.describe Neo4j::Driver::Exceptions::ClientException do 4 | it 'incorrect syntax' do 5 | expect do 6 | session = driver.session 7 | driver.session.run('CRETE ()').to_a 8 | ensure 9 | session&.close 10 | end.to raise_error described_class 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /spec/neo4j/driver/graph_database_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | RSpec.describe Neo4j::Driver::GraphDatabase do 4 | def simple_query(driver) 5 | driver.session do |session| 6 | session.execute_read { |tx| tx.run('RETURN 1').single.first } 7 | end 8 | end 9 | 10 | let(:url) { URI::Generic.build(scheme: scheme, host: URI(uri).host, port: port).to_s } 11 | describe '.driver' do 12 | subject do 13 | Neo4j::Driver::GraphDatabase.driver(url, basic_auth_token, &method(:simple_query)) 14 | end 15 | 16 | context 'when bolt' do 17 | let(:scheme) { 'bolt' } 18 | it { is_expected.to eq 1 } 19 | end 20 | 21 | context 'when neo4j' do 22 | let(:scheme) { 'neo4j' } 23 | it { is_expected.to eq 1 } 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /spec/neo4j/driver/types/relationship_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | RSpec.describe Neo4j::Driver::Types::Relationship do 4 | subject do 5 | session = driver.session 6 | session.execute_write { |tx| tx.run('CREATE ()-[f:friend_of{strength: 1}]->() RETURN f').single.first } 7 | ensure 8 | session&.close 9 | end 10 | 11 | it { is_expected.to be_a_kind_of described_class } 12 | its(:type) { is_expected.to eq :friend_of } 13 | its(:id) { is_expected.to be_a(Integer) } 14 | its(:start_node_id) { is_expected.to be_a(Integer) } 15 | its(:end_node_id) { is_expected.to be_a(Integer) } 16 | its(:properties) { is_expected.to eq strength: 1 } 17 | end 18 | -------------------------------------------------------------------------------- /spec/neo4j/driver/util/cc/cluster_member.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Util 6 | module CC 7 | class ClusterMember 8 | SIMPLE_SCHEME = 'bolt://' 9 | #ROUTING_SCHEME = 'bolt+routing://' 10 | ROUTING_SCHEME = 'neo4j://' 11 | 12 | attr_accessor :bolt_uri, :path, :bolt_address 13 | 14 | def initialize(bolt_uri, path) 15 | self.bolt_uri = bolt_uri 16 | self.bolt_address = Neo4j::Driver::Net::ServerAddress.of(*URI(bolt_uri).then { |uri| [uri.host, uri.port] }) 17 | self.path = path 18 | end 19 | 20 | def routing_uri 21 | bolt_uri.gsub(SIMPLE_SCHEME, ROUTING_SCHEME) 22 | end 23 | end 24 | end 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /spec/neo4j/driver/util/test_util.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4j 4 | module Driver 5 | module Util 6 | module TestUtil 7 | def clean_db(driver) 8 | driver.session do |session| 9 | clean_db_in_session(session) 10 | session.last_bookmark 11 | end 12 | end 13 | 14 | def count_nodes(driver, bookmark) 15 | driver.session(bookmarks: bookmark) do |session| 16 | session.execute_read { |tx| tx.run('MATCH (n) RETURN count(n)').single.first } 17 | end 18 | end 19 | 20 | private 21 | 22 | def clean_db_in_session(session) 23 | nil while delete_batch_of_nodes(session).positive? 24 | end 25 | 26 | def delete_batch_of_nodes(session) 27 | session.execute_write do |tx| 28 | tx.run('MATCH (n) WITH n LIMIT 10000 DETACH DELETE n RETURN count(n)').single.first 29 | end 30 | end 31 | end 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /spec/support/neo4j_cleaner.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Neo4jCleaner 4 | def start; end 5 | 6 | def clean 7 | execute 'MATCH (n) DETACH DELETE n' 8 | end 9 | 10 | def cleaning 11 | start 12 | yield 13 | clean 14 | end 15 | 16 | def clean_with(*_args) 17 | clean 18 | end 19 | 20 | def clean_all 21 | p 'Cleaning neo4j database' 22 | execute 'CALL apoc.schema.assert({}, {})' 23 | clean 24 | end 25 | 26 | private 27 | 28 | def execute(query) 29 | driver.session { run(query) } 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /testkit-backend/.gitignore: -------------------------------------------------------------------------------- 1 | /.bundle/ 2 | /.yardoc 3 | /_yardoc/ 4 | /coverage/ 5 | /doc/ 6 | /pkg/ 7 | /spec/reports/ 8 | /tmp/ 9 | 10 | # rspec failure tracking 11 | .rspec_status 12 | gems.locked 13 | -------------------------------------------------------------------------------- /testkit-backend/.rspec: -------------------------------------------------------------------------------- 1 | --format documentation 2 | --color 3 | --require spec_helper 4 | -------------------------------------------------------------------------------- /testkit-backend/.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | language: ruby 3 | cache: bundler 4 | rvm: 5 | - 2.7.2 6 | before_install: gem install bundler -v 2.1.4 7 | -------------------------------------------------------------------------------- /testkit-backend/LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020 Heinrich Klobuczek 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /testkit-backend/Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | require "rspec/core/rake_task" 3 | 4 | RSpec::Core::RakeTask.new(:spec) 5 | 6 | task :default => :spec 7 | -------------------------------------------------------------------------------- /testkit-backend/bin/console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require "bundler/setup" 4 | require "testkit/backend" 5 | 6 | # You can add fixtures and/or initialization code here to make experimenting 7 | # with your gem easier. You can also use a different console, if you like. 8 | 9 | # (If you use this, don't forget to add pry to your Gemfile!) 10 | # require "pry" 11 | # Pry.start 12 | 13 | require "irb" 14 | IRB.start(__FILE__) 15 | -------------------------------------------------------------------------------- /testkit-backend/bin/null-backend: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require "bundler/setup" 4 | require "testkit/backend" 5 | 6 | puts "Before start" 7 | # Testkit::Backend::Runner.start 8 | puts "After start" -------------------------------------------------------------------------------- /testkit-backend/bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | IFS=$'\n\t' 4 | set -vx 5 | 6 | bundle update 7 | 8 | # Do any other automated setup that you need to do here 9 | -------------------------------------------------------------------------------- /testkit-backend/bin/testkit-backend: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require "bundler/setup" 4 | require 'ostruct' 5 | require "testkit/backend" 6 | require "active_support/core_ext/object/blank" 7 | 8 | Async do 9 | Testkit::Backend::Runner.new(9876).run 10 | end -------------------------------------------------------------------------------- /testkit-backend/exe/testkit-backend: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require "testkit/backend" 4 | -------------------------------------------------------------------------------- /testkit-backend/gems.rb: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | # Specify your gem's dependencies in testkit-backend.gemspec 4 | gemspec 5 | 6 | gem "rake", "~> 12.0" 7 | gem "rspec", "~> 3.0" 8 | gem "neo4j-ruby-driver", path: '..' 9 | -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend.rb: -------------------------------------------------------------------------------- 1 | require "active_support/core_ext/module/attribute_accessors" 2 | require 'active_support/inflector' 3 | require 'async/io' 4 | require 'bigdecimal' 5 | require 'neo4j/driver' 6 | require 'nio' 7 | require 'testkit/backend/loader' 8 | 9 | Testkit::Backend::Loader.load 10 | -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/loader.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'zeitwerk' 4 | 5 | module Testkit 6 | module Backend 7 | class Loader 8 | def self.load 9 | loader = Zeitwerk::Loader.new 10 | loader.tag = 'testkit-backend' 11 | loader.push_dir(File.expand_path('../..', __dir__)) 12 | loader.inflector = Zeitwerk::GemInflector.new(File.expand_path('.', __dir__)) 13 | loader.setup 14 | loader.eager_load 15 | end 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/messages/requests/authorization_token.rb: -------------------------------------------------------------------------------- 1 | module Testkit::Backend::Messages 2 | module Requests 3 | class AuthorizationToken < Request 4 | def to_object 5 | case (scheme) 6 | when 'basic' 7 | Neo4j::Driver::AuthTokens.basic(principal, credentials, realm) 8 | when 'bearer', 'kerberos' 9 | Neo4j::Driver::AuthTokens.send(scheme, credentials) 10 | else 11 | Neo4j::Driver::AuthTokens.custom(principal, credentials, realm, scheme, **parameters) 12 | end 13 | end 14 | end 15 | end 16 | end -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/messages/requests/check_driver_is_encrypted.rb: -------------------------------------------------------------------------------- 1 | module Testkit::Backend::Messages 2 | module Requests 3 | class CheckDriverIsEncrypted < Request 4 | def process 5 | named_entity('DriverIsEncrypted', encrypted: fetch(driver_id).encrypted?) 6 | end 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/messages/requests/check_multi_d_b_support.rb: -------------------------------------------------------------------------------- 1 | module Testkit::Backend::Messages 2 | module Requests 3 | class CheckMultiDBSupport < Request 4 | def process 5 | named_entity('MultiDBSupport', id: nil, available: fetch(driver_id).supports_multi_db?) 6 | end 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/messages/requests/check_session_auth_support.rb: -------------------------------------------------------------------------------- 1 | module Testkit::Backend::Messages 2 | module Requests 3 | class CheckSessionAuthSupport < Request 4 | def process 5 | named_entity('SessionAuthSupport', id: driver_id, available: fetch(driver_id).supports_session_auth?) 6 | end 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/messages/requests/cypher_bytes.rb: -------------------------------------------------------------------------------- 1 | module Testkit::Backend::Messages 2 | module Requests 3 | class CypherBytes < Request 4 | def to_object 5 | value.split.map { |byte| byte.to_i(16) }.pack('C*') 6 | end 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/messages/requests/cypher_date.rb: -------------------------------------------------------------------------------- 1 | module Testkit::Backend::Messages 2 | module Requests 3 | class CypherDate < Request 4 | def to_object 5 | Date.new(year, month, day) 6 | end 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/messages/requests/cypher_date_time.rb: -------------------------------------------------------------------------------- 1 | module Testkit::Backend::Messages 2 | module Requests 3 | class CypherDateTime < Request 4 | def to_object 5 | if timezone_id 6 | Time.new(year, month, day, hour, minute, second + nanosecond * 1e-9, utc_offset_s).in_time_zone(TZInfo::Timezone.get(timezone_id)) 7 | elsif utc_offset_s 8 | Time.new(year, month, day, hour, minute, second + nanosecond * 1e-9, utc_offset_s) 9 | else 10 | Neo4j::Driver::Types::LocalDateTime.new(Time.new(year, month, day, hour, minute, second + nanosecond * 1e-9)) 11 | end 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/messages/requests/cypher_duration.rb: -------------------------------------------------------------------------------- 1 | module Testkit::Backend::Messages 2 | module Requests 3 | class CypherDuration < Request 4 | def to_object 5 | Neo4j::Driver::Internal::DurationNormalizer.create(months, days, seconds, nanoseconds) 6 | end 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/messages/requests/cypher_float.rb: -------------------------------------------------------------------------------- 1 | module Testkit::Backend::Messages 2 | module Requests 3 | class CypherFloat < Request 4 | def to_object 5 | case value 6 | when "NaN" 7 | Float::NAN 8 | when "-Infinity" 9 | -Float::INFINITY 10 | when "+Infinity" 11 | Float::INFINITY 12 | else 13 | value.to_f 14 | end 15 | end 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/messages/requests/cypher_list.rb: -------------------------------------------------------------------------------- 1 | module Testkit::Backend::Messages 2 | module Requests 3 | class CypherList < Request 4 | def to_object 5 | value.map(&Request.method(:object_from)) 6 | end 7 | end 8 | end 9 | end -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/messages/requests/cypher_map.rb: -------------------------------------------------------------------------------- 1 | module Testkit::Backend::Messages 2 | module Requests 3 | class CypherMap < Request 4 | def to_object 5 | value.transform_values(&Request.method(:object_from)) 6 | end 7 | end 8 | end 9 | end -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/messages/requests/cypher_time.rb: -------------------------------------------------------------------------------- 1 | module Testkit::Backend::Messages 2 | module Requests 3 | class CypherTime < Request 4 | def to_object 5 | if utc_offset_s 6 | Neo4j::Driver::Types::OffsetTime.new(Time.new(1, 1, 1, hour, minute, second + nanosecond * 1e-9, utc_offset_s)) 7 | else 8 | Neo4j::Driver::Types::LocalTime.new(Time.new(1, 1, 1, hour, minute, second + nanosecond * 1e-9)) 9 | end 10 | end 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/messages/requests/cypher_value.rb: -------------------------------------------------------------------------------- 1 | module Testkit::Backend::Messages 2 | module Requests 3 | class CypherValue < Request 4 | def to_object 5 | value 6 | end 7 | end 8 | 9 | CypherBool = CypherNull = CypherInt = CypherString = CypherValue 10 | end 11 | end -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/messages/requests/domain_name_resolution_completed.rb: -------------------------------------------------------------------------------- 1 | module Testkit::Backend::Messages 2 | module Requests 3 | class DomainNameResolutionCompleted < Request 4 | def process 5 | end 6 | end 7 | end 8 | end -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/messages/requests/driver_close.rb: -------------------------------------------------------------------------------- 1 | module Testkit::Backend::Messages 2 | module Requests 3 | class DriverClose < Request 4 | def process 5 | reference('Driver') 6 | end 7 | 8 | def to_object 9 | delete(driver_id).tap(&:close) 10 | end 11 | end 12 | end 13 | end -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/messages/requests/forced_routing_table_update.rb: -------------------------------------------------------------------------------- 1 | module Testkit::Backend::Messages 2 | module Requests 3 | class ForcedRoutingTableUpdate < Request 4 | def process 5 | named_entity('Driver', id: driver_id) 6 | end 7 | 8 | # def to_object 9 | # end 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/messages/requests/get_connection_pool_metrics.rb: -------------------------------------------------------------------------------- 1 | module Testkit::Backend::Messages 2 | module Requests 3 | class GetConnectionPoolMetrics < Request 4 | def process 5 | uri = Neo4j::Driver::Internal::BoltServerAddress.uri_from(address) 6 | pool_metrics = fetch(driver_id).metrics.connection_pool_metrics.find do |pm| 7 | pm_address = pm.address 8 | pm_address.host == uri.host && pm_address.port == uri.port 9 | end 10 | raise ArgumentError, "Pool metrics for #{address} are not available" unless pool_metrics 11 | named_entity('ConnectionPoolMetrics', inUse: pool_metrics.in_use, idle: pool_metrics.idle) 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/messages/requests/get_routing_table.rb: -------------------------------------------------------------------------------- 1 | module Testkit::Backend::Messages 2 | module Requests 3 | class GetRoutingTable < Request 4 | def process 5 | named_entity('RoutingTable', 6 | **%i[routers writers readers] 7 | .each_with_object(database: database, ttl: nil) do |method, hash| 8 | hash[method] = to_object.send(method).to_a.map(&:to_s) 9 | end) 10 | end 11 | 12 | def to_object 13 | @obj ||= fetch(driver_id).session_factory.connection_provider.routing_table_registry 14 | .routing_table_handler(database).routing_table 15 | end 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/messages/requests/new_session.rb: -------------------------------------------------------------------------------- 1 | module Testkit::Backend::Messages 2 | module Requests 3 | class NewSession < Request 4 | def process 5 | reference('Session') 6 | end 7 | 8 | def to_object 9 | fetch(driver_id).session( 10 | default_access_mode: access_mode == 'r' ? Neo4j::Driver::AccessMode::READ : Neo4j::Driver::AccessMode::WRITE, 11 | bookmarks: Neo4j::Driver::Bookmark.from(*bookmarks), 12 | database: database, 13 | fetch_size: fetch_size, 14 | impersonated_user: impersonated_user 15 | ) 16 | end 17 | end 18 | end 19 | end -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/messages/requests/resolver_resolution_completed.rb: -------------------------------------------------------------------------------- 1 | module Testkit::Backend::Messages 2 | module Requests 3 | class ResolverResolutionCompleted < Request 4 | def process 5 | end 6 | end 7 | end 8 | end -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/messages/requests/result_list.rb: -------------------------------------------------------------------------------- 1 | module Testkit::Backend::Messages 2 | module Requests 3 | class ResultList < Request 4 | def process 5 | result = fetch(result_id) 6 | named_entity('RecordList', records: result.to_a.map do |record| 7 | { values: record.values.map do |value| 8 | to_testkit(value) 9 | end } 10 | end 11 | ) 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/messages/requests/result_next.rb: -------------------------------------------------------------------------------- 1 | module Testkit::Backend::Messages 2 | module Requests 3 | class ResultNext < Request 4 | def process 5 | result = fetch(result_id) 6 | result.has_next? ? named_entity('Record', values: result.next.values.map(&method(:to_testkit))) : named_entity('NullRecord') 7 | end 8 | end 9 | end 10 | end -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/messages/requests/result_peek.rb: -------------------------------------------------------------------------------- 1 | module Testkit::Backend::Messages 2 | module Requests 3 | class ResultPeek < Request 4 | def process 5 | result = fetch(result_id) 6 | result.has_next? ? named_entity('Record', values: result.peek.values.map(&method(:to_testkit))) : named_entity('NullRecord') 7 | end 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/messages/requests/result_single.rb: -------------------------------------------------------------------------------- 1 | module Testkit::Backend::Messages 2 | module Requests 3 | class ResultSingle < Request 4 | def process 5 | result = fetch(result_id) 6 | named_entity('Record', values: result.single.values.map(&method(:to_testkit))) 7 | end 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/messages/requests/retryable.rb: -------------------------------------------------------------------------------- 1 | module Testkit::Backend::Messages 2 | module Requests 3 | class Retryable < Request 4 | end 5 | end 6 | end -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/messages/requests/retryable_negative.rb: -------------------------------------------------------------------------------- 1 | module Testkit::Backend::Messages 2 | module Requests 3 | class RetryableNegative < Retryable 4 | def process_request 5 | process 6 | end 7 | 8 | def process 9 | raise error_id.present? ? fetch(error_id) : RollbackException 10 | end 11 | end 12 | end 13 | end -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/messages/requests/retryable_positive.rb: -------------------------------------------------------------------------------- 1 | module Testkit::Backend::Messages 2 | module Requests 3 | class RetryablePositive < Retryable 4 | def process 5 | end 6 | end 7 | end 8 | end -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/messages/requests/rollback_exception.rb: -------------------------------------------------------------------------------- 1 | module Testkit::Backend::Messages 2 | module Requests 3 | class RollbackException < StandardError 4 | end 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/messages/requests/session_begin_transaction.rb: -------------------------------------------------------------------------------- 1 | module Testkit::Backend::Messages 2 | module Requests 3 | class SessionBeginTransaction < Request 4 | def process 5 | reference('Transaction') 6 | end 7 | 8 | def to_object 9 | fetch(session_id).begin_transaction(metadata: decode(tx_meta), timeout: timeout_duration) 10 | end 11 | end 12 | end 13 | end -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/messages/requests/session_close.rb: -------------------------------------------------------------------------------- 1 | module Testkit::Backend::Messages 2 | module Requests 3 | class SessionClose < Request 4 | def process 5 | reference('Session') 6 | end 7 | 8 | def to_object 9 | delete(session_id).tap(&:close) 10 | end 11 | end 12 | end 13 | end -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/messages/requests/session_last_bookmarks.rb: -------------------------------------------------------------------------------- 1 | module Testkit::Backend::Messages 2 | module Requests 3 | class SessionLastBookmarks < Request 4 | def process 5 | named_entity('Bookmarks', bookmarks: to_object.values.to_a) 6 | end 7 | 8 | def to_object 9 | fetch(session_id).last_bookmark 10 | end 11 | end 12 | end 13 | end -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/messages/requests/session_read_transaction.rb: -------------------------------------------------------------------------------- 1 | module Testkit::Backend::Messages 2 | module Requests 3 | class SessionReadTransaction < SessionTransaction 4 | def process 5 | super(:execute_read) 6 | end 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/messages/requests/session_run.rb: -------------------------------------------------------------------------------- 1 | module Testkit::Backend::Messages 2 | module Requests 3 | class SessionRun < Request 4 | def response 5 | Responses::Result.new(fetch(session_id).run(cypher, decode(params), to_config)) 6 | end 7 | 8 | private 9 | 10 | def to_config 11 | { metadata: decode(tx_meta), timeout: timeout_duration } 12 | end 13 | end 14 | end 15 | end -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/messages/requests/session_transaction.rb: -------------------------------------------------------------------------------- 1 | module Testkit::Backend::Messages 2 | module Requests 3 | class SessionTransaction < Request 4 | def process(method) 5 | fetch(session_id).send(method, metadata: decode(tx_meta), timeout: timeout_duration) do |tx| 6 | tx_id = store(tx) 7 | @command_processor.process_response(named_entity('RetryableTry', id: tx_id)) 8 | until @command_processor.process(blocking: true).is_a?(Retryable) do 9 | end 10 | ensure 11 | delete(tx_id) 12 | end 13 | named_entity('RetryableDone') 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/messages/requests/session_write_transaction.rb: -------------------------------------------------------------------------------- 1 | module Testkit::Backend::Messages 2 | module Requests 3 | class SessionWriteTransaction < SessionTransaction 4 | def process 5 | super(:execute_write) 6 | end 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/messages/requests/transaction_close.rb: -------------------------------------------------------------------------------- 1 | module Testkit::Backend::Messages 2 | module Requests 3 | class TransactionClose < Request 4 | def process 5 | reference('Transaction') 6 | end 7 | 8 | def to_object 9 | fetch(tx_id).tap(&:close) 10 | end 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/messages/requests/transaction_commit.rb: -------------------------------------------------------------------------------- 1 | module Testkit::Backend::Messages 2 | module Requests 3 | class TransactionCommit < Request 4 | def process 5 | reference('Transaction') 6 | end 7 | 8 | def to_object 9 | fetch(tx_id).tap(&:commit) 10 | end 11 | end 12 | end 13 | end -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/messages/requests/transaction_rollback.rb: -------------------------------------------------------------------------------- 1 | module Testkit::Backend::Messages 2 | module Requests 3 | class TransactionRollback < Request 4 | def process 5 | reference('Transaction') 6 | end 7 | 8 | def to_object 9 | fetch(tx_id).tap(&:rollback) 10 | end 11 | end 12 | end 13 | end -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/messages/requests/transaction_run.rb: -------------------------------------------------------------------------------- 1 | module Testkit::Backend::Messages 2 | module Requests 3 | class TransactionRun < Request 4 | def response 5 | Responses::Result.new(fetch(tx_id).run(cypher, **decode(params))) 6 | end 7 | end 8 | end 9 | end -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/messages/requests/verify_authentication.rb: -------------------------------------------------------------------------------- 1 | module Testkit::Backend::Messages 2 | module Requests 3 | class VerifyAuthentication < Request 4 | def process 5 | named_entity('DriverIsAuthenticated', 6 | id: driver_id, 7 | authenticated: fetch(driver_id).verify_authentication(Request.object_from(authorization_token))) 8 | end 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/messages/requests/verify_connectivity.rb: -------------------------------------------------------------------------------- 1 | module Testkit::Backend::Messages 2 | module Requests 3 | class VerifyConnectivity < Request 4 | def process 5 | fetch(driver_id).verify_connectivity 6 | named_entity('Driver', id: driver_id) 7 | end 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/messages/response.rb: -------------------------------------------------------------------------------- 1 | module Testkit::Backend::Messages 2 | class Response 3 | extend Conversion 4 | delegate :delete, :fetch, :store, to: Testkit::Backend::ObjectCache 5 | 6 | def initialize(object) 7 | @object = object 8 | end 9 | 10 | def name 11 | self.class.name.split('::').last 12 | end 13 | 14 | def to_testkit 15 | named_entity(name, **data) 16 | end 17 | 18 | def named_entity(name, **hash) 19 | self.class.named_entity(name, **hash) 20 | end 21 | 22 | def self.named_entity(name, **hash) 23 | { name: name }.tap do |entity| 24 | entity[:data] = hash unless hash.empty? 25 | end 26 | end 27 | 28 | def value_entity(name, object) 29 | named_entity(name, value: object) 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/messages/responses/driver_error.rb: -------------------------------------------------------------------------------- 1 | module Testkit::Backend::Messages 2 | module Responses 3 | class DriverError < Response 4 | def data 5 | { id: store(@object), errorType: @object.class.name, msg: @object.message, code: @object.try(:code) }.compact 6 | end 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/messages/responses/result.rb: -------------------------------------------------------------------------------- 1 | module Testkit::Backend::Messages 2 | module Responses 3 | class Result < Response 4 | def data 5 | { id: store(@object), keys: @object.keys } 6 | end 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/messages/rollback_exception.rb: -------------------------------------------------------------------------------- 1 | module Testkit::Backend::Messages 2 | class RollbackException < RuntimeError 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/object_cache.rb: -------------------------------------------------------------------------------- 1 | module Testkit 2 | module Backend 3 | class ObjectCache < Hash 4 | cattr_reader :objects, default: new 5 | 6 | class << self 7 | def fetch(*args) 8 | objects.fetch(*args) 9 | end 10 | 11 | def delete(key) 12 | objects.delete(key) 13 | end 14 | 15 | def store(object) 16 | object.object_id.tap { |key| objects.store(key, object) } 17 | end 18 | end 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /testkit-backend/lib/testkit/backend/version.rb: -------------------------------------------------------------------------------- 1 | module Testkit 2 | module Backend 3 | VERSION = "0.1.0" 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /testkit-backend/spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require "bundler/setup" 2 | require "testkit/backend" 3 | require 'async/rspec' 4 | 5 | # require_relative 'addrinfo' 6 | 7 | RSpec.configure do |config| 8 | # Enable flags like --only-failures and --next-failure 9 | config.example_status_persistence_file_path = ".rspec_status" 10 | 11 | # Disable RSpec exposing methods globally on `Module` and `main` 12 | config.disable_monkey_patching! 13 | 14 | config.expect_with :rspec do |c| 15 | c.syntax = :expect 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /testkit-backend/spec/testkit/backend/runner_spec.rb: -------------------------------------------------------------------------------- 1 | RSpec.describe Testkit::Backend::Runner do 2 | # include_context Async::RSpec::Reactor 3 | 4 | def echo_client(server_address, data) 5 | Async do |task| 6 | Async::IO::Socket.connect(server_address) do |peer| 7 | peer.write(data) 8 | # peer.close_write 9 | 10 | message = peer.read(10) 11 | 12 | puts "Sent #{data}, got response: #{message}" 13 | end 14 | end 15 | end 16 | 17 | it "responds with reverse string" do 18 | Async do 19 | # server = described_class.start 20 | tasks = 10.times.map do |i| 21 | echo_client(Async::IO::Address.tcp('localhost', 9876), "Hello World #{i}") 22 | end 23 | tasks.each(&:wait) 24 | # server.stop 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /testkit-backend/spec/testkit/backend_spec.rb: -------------------------------------------------------------------------------- 1 | RSpec.describe Testkit::Backend do 2 | it "has a version number" do 3 | expect(Testkit::Backend::VERSION).not_to be nil 4 | end 5 | 6 | it "does something useful" do 7 | expect(false).to eq(false) 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /testkit/.dockerignore: -------------------------------------------------------------------------------- 1 | *.py 2 | -------------------------------------------------------------------------------- /testkit/Dockerfile: -------------------------------------------------------------------------------- 1 | # Install Maven 3.6, Java 11, Java 8 and Python3 2 | ARG RUBY=jruby:latest 3 | FROM $RUBY 4 | 5 | RUN apt-get --quiet --quiet update \ 6 | && apt-get --quiet --quiet install -y bash python3 maven \ 7 | && rm -rf /var/lib/apt/lists/* 8 | 9 | ENV PYTHON=python3 10 | 11 | # Install our own CAs on the image. 12 | # Assumes Linux Debian based image. 13 | # JAVA_HOME needed by update-ca-certificates hook to update Java with changed system CAs. 14 | COPY CAs/* /usr/local/share/ca-certificates/ 15 | COPY CustomCAs/* /usr/local/share/custom-ca-certificates/ 16 | RUN update-ca-certificates 17 | 18 | RUN gem install ruby-maven 19 | -------------------------------------------------------------------------------- /testkit/backend.py: -------------------------------------------------------------------------------- 1 | """ 2 | Executed in Ruby driver container. 3 | Assumes driver and backend has been built. 4 | Responsible for starting the test backend. 5 | """ 6 | import os 7 | import subprocess 8 | import sys 9 | 10 | if __name__ == "__main__": 11 | subprocess.check_call( 12 | ["bin/testkit-backend"], 13 | stdout=sys.stdout, stderr=sys.stderr 14 | ) 15 | -------------------------------------------------------------------------------- /testkit/build.py: -------------------------------------------------------------------------------- 1 | """ 2 | Executed in java driver container. 3 | Responsible for building driver and test backend. 4 | """ 5 | import os, subprocess 6 | 7 | def run(args): 8 | subprocess.run( 9 | args, universal_newlines=True, stderr=subprocess.STDOUT, check=True) 10 | 11 | if __name__ == "__main__": 12 | run(['bin/setup']) 13 | run(["bin/testkit-setup"]) 14 | -------------------------------------------------------------------------------- /testkit/integration.py: -------------------------------------------------------------------------------- 1 | if __name__ == "__main__": 2 | print("Integration tests not ported to testkit") 3 | -------------------------------------------------------------------------------- /testkit/stress.py: -------------------------------------------------------------------------------- 1 | if __name__ == "__main__": 2 | print("Stress tests not ported to testkit") 3 | -------------------------------------------------------------------------------- /testkit/unittests.py: -------------------------------------------------------------------------------- 1 | """ 2 | Executed in Java driver container. 3 | Responsible for running unit tests. 4 | Assumes driver has been setup by build script prior to this. 5 | """ 6 | 7 | import os, subprocess 8 | 9 | def run(args): 10 | subprocess.run( 11 | args, universal_newlines=True, stderr=subprocess.STDOUT, check=True) 12 | 13 | if __name__ == "__main__": 14 | print("Unit tests not ported to testkit") 15 | --------------------------------------------------------------------------------