├── .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: '
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 |
--------------------------------------------------------------------------------