neo4j-ruby-driver 6.0.3.alpha.0 → 6.2.1.beta.2

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