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

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 (346) 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 +1054 -0
  9. data/lib/neo4j/driver/bolt/handshake.rb +232 -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 +136 -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 +258 -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/protocol_exception.rb +0 -5
  48. data/lib/neo4j/driver/exceptions/security_retryable_exception.rb +14 -0
  49. data/lib/neo4j/driver/exceptions/transaction_terminated_exception.rb +13 -0
  50. data/lib/neo4j/driver/graph_database.rb +29 -0
  51. data/lib/neo4j/driver/internal/clock.rb +20 -0
  52. data/lib/neo4j/driver/internal/clock_adapter.rb +21 -0
  53. data/lib/neo4j/driver/internal/default_bookmark_manager.rb +54 -0
  54. data/lib/neo4j/driver/internal/deprecator.rb +9 -5
  55. data/lib/neo4j/driver/internal/driver_factory.rb +128 -0
  56. data/lib/neo4j/driver/internal/duration_normalizer.rb +14 -41
  57. data/lib/neo4j/driver/internal/extras.rb +23 -0
  58. data/lib/neo4j/driver/internal/home_db_cache.rb +57 -0
  59. data/lib/neo4j/driver/internal/internal_auth_token_manager.rb +37 -0
  60. data/lib/neo4j/driver/internal/metrics.rb +31 -0
  61. data/lib/neo4j/driver/internal/security/static_auth_token_manager.rb +25 -0
  62. data/lib/neo4j/driver/internal/validator.rb +10 -0
  63. data/lib/neo4j/driver/net.rb +29 -0
  64. data/lib/neo4j/driver/packstream/markers.rb +49 -0
  65. data/lib/neo4j/driver/packstream/packer.rb +333 -0
  66. data/lib/neo4j/driver/packstream/structure.rb +27 -0
  67. data/lib/neo4j/driver/packstream/unpacker.rb +168 -0
  68. data/lib/neo4j/driver/record.rb +49 -0
  69. data/lib/neo4j/driver/result.rb +282 -0
  70. data/lib/neo4j/driver/routing/load_balancer.rb +690 -0
  71. data/lib/neo4j/driver/routing/routed_connection.rb +132 -0
  72. data/lib/neo4j/driver/routing/routing_table.rb +127 -0
  73. data/lib/neo4j/driver/routing/server_address.rb +25 -0
  74. data/lib/neo4j/driver/routing_control.rb +13 -0
  75. data/lib/neo4j/driver/session.rb +575 -0
  76. data/lib/neo4j/driver/summary/database_info.rb +25 -0
  77. data/lib/neo4j/driver/summary/gql_notification.rb +38 -0
  78. data/lib/neo4j/driver/summary/gql_status_object.rb +35 -0
  79. data/lib/neo4j/driver/summary/notification.rb +46 -0
  80. data/lib/neo4j/driver/summary/plan.rb +23 -0
  81. data/lib/neo4j/driver/summary/profile.rb +28 -0
  82. data/lib/neo4j/driver/summary/query.rb +19 -0
  83. data/lib/neo4j/driver/summary/query_type.rb +5 -1
  84. data/lib/neo4j/driver/summary/result_summary.rb +213 -0
  85. data/lib/neo4j/driver/summary/server_info.rb +33 -0
  86. data/lib/neo4j/driver/summary/summary_counters.rb +72 -0
  87. data/lib/neo4j/driver/transaction.rb +341 -0
  88. data/lib/neo4j/driver/types/duration.rb +76 -0
  89. data/lib/neo4j/driver/types/local_date_time.rb +52 -8
  90. data/lib/neo4j/driver/types/local_time.rb +42 -7
  91. data/lib/neo4j/driver/types/node.rb +27 -0
  92. data/lib/neo4j/driver/types/offset_time.rb +71 -7
  93. data/lib/neo4j/driver/types/path.rb +68 -0
  94. data/lib/neo4j/driver/types/point.rb +38 -18
  95. data/lib/neo4j/driver/types/relationship.rb +41 -0
  96. data/lib/neo4j/driver/types/temporal_value.rb +43 -0
  97. data/lib/neo4j/driver/types/unbound_relationship.rb +29 -0
  98. data/lib/neo4j/driver/types/unresolvable_zoned_date_time.rb +38 -0
  99. data/lib/neo4j/driver/types/unsupported_type.rb +25 -0
  100. data/lib/neo4j/driver/types/uuid.rb +29 -0
  101. data/{ruby → lib}/neo4j/driver/version.rb +1 -1
  102. data/lib/neo4j/driver.rb +16 -0
  103. data/lib/neo4j-ruby-driver_loader.rb +34 -20
  104. metadata +132 -390
  105. data/lib/neo4j/driver/internal/bolt_server_address.rb +0 -97
  106. data/lib/neo4j/driver/synchronizable.rb +0 -23
  107. data/lib/neo4j/driver/types/time.rb +0 -45
  108. data/ruby/neo4j/driver/auth_tokens.rb +0 -34
  109. data/ruby/neo4j/driver/bookmark.rb +0 -21
  110. data/ruby/neo4j/driver/config.rb +0 -89
  111. data/ruby/neo4j/driver/graph_database.rb +0 -78
  112. data/ruby/neo4j/driver/internal/async/connection/bolt_protocol_util.rb +0 -51
  113. data/ruby/neo4j/driver/internal/async/connection/bootstrap_factory.rb +0 -22
  114. data/ruby/neo4j/driver/internal/async/connection/channel_attributes.rb +0 -31
  115. data/ruby/neo4j/driver/internal/async/connection/channel_connected_listener.rb +0 -32
  116. data/ruby/neo4j/driver/internal/async/connection/channel_connector_impl.rb +0 -83
  117. data/ruby/neo4j/driver/internal/async/connection/channel_pipeline_builder_impl.rb +0 -22
  118. data/ruby/neo4j/driver/internal/async/connection/direct_connection.rb +0 -30
  119. data/ruby/neo4j/driver/internal/async/connection/event_loop_group_factory.rb +0 -83
  120. data/ruby/neo4j/driver/internal/async/connection/handshake_completed_listener.rb +0 -27
  121. data/ruby/neo4j/driver/internal/async/connection/handshake_handler.rb +0 -113
  122. data/ruby/neo4j/driver/internal/async/connection/netty_channel_initializer.rb +0 -57
  123. data/ruby/neo4j/driver/internal/async/connection/netty_domain_name_resolver.rb +0 -26
  124. data/ruby/neo4j/driver/internal/async/connection/netty_domain_name_resolver_group.rb +0 -19
  125. data/ruby/neo4j/driver/internal/async/connection/routing_connection.rb +0 -36
  126. data/ruby/neo4j/driver/internal/async/connection/stream.rb +0 -12
  127. data/ruby/neo4j/driver/internal/async/connection/stream_reader.rb +0 -16
  128. data/ruby/neo4j/driver/internal/async/connection_context.rb +0 -10
  129. data/ruby/neo4j/driver/internal/async/immutable_connection_context.rb +0 -24
  130. data/ruby/neo4j/driver/internal/async/inbound/byte_buf_input.rb +0 -30
  131. data/ruby/neo4j/driver/internal/async/inbound/channel_error_handler.rb +0 -77
  132. data/ruby/neo4j/driver/internal/async/inbound/chunk_decoder.rb +0 -41
  133. data/ruby/neo4j/driver/internal/async/inbound/connect_timeout_handler.rb +0 -32
  134. data/ruby/neo4j/driver/internal/async/inbound/connection_read_timeout_handler.rb +0 -17
  135. data/ruby/neo4j/driver/internal/async/inbound/inbound_message_dispatcher.rb +0 -171
  136. data/ruby/neo4j/driver/internal/async/inbound/inbound_message_handler.rb +0 -42
  137. data/ruby/neo4j/driver/internal/async/inbound/message_decoder.rb +0 -51
  138. data/ruby/neo4j/driver/internal/async/internal_async_session.rb +0 -92
  139. data/ruby/neo4j/driver/internal/async/internal_async_transaction.rb +0 -13
  140. data/ruby/neo4j/driver/internal/async/leak_logging_network_session.rb +0 -34
  141. data/ruby/neo4j/driver/internal/async/network_connection.rb +0 -194
  142. data/ruby/neo4j/driver/internal/async/network_session.rb +0 -150
  143. data/ruby/neo4j/driver/internal/async/outbound/chunk_aware_byte_buf_output.rb +0 -110
  144. data/ruby/neo4j/driver/internal/async/outbound/outbound_message_handler.rb +0 -39
  145. data/ruby/neo4j/driver/internal/async/pool/channel.rb +0 -66
  146. data/ruby/neo4j/driver/internal/async/pool/channel_pool.rb +0 -31
  147. data/ruby/neo4j/driver/internal/async/pool/channel_tracker.rb +0 -135
  148. data/ruby/neo4j/driver/internal/async/pool/connection_pool_impl.rb +0 -156
  149. data/ruby/neo4j/driver/internal/async/pool/netty_channel_health_checker.rb +0 -87
  150. data/ruby/neo4j/driver/internal/async/pool/netty_channel_pool.rb +0 -52
  151. data/ruby/neo4j/driver/internal/async/pool/network_connection_factory.rb +0 -21
  152. data/ruby/neo4j/driver/internal/async/pool/pool_settings.rb +0 -34
  153. data/ruby/neo4j/driver/internal/async/pool/timed_stack.rb +0 -15
  154. data/ruby/neo4j/driver/internal/async/result_cursors_holder.rb +0 -17
  155. data/ruby/neo4j/driver/internal/async/unmanaged_transaction.rb +0 -212
  156. data/ruby/neo4j/driver/internal/bookmark_holder.rb +0 -9
  157. data/ruby/neo4j/driver/internal/cluster/cluster_composition.rb +0 -48
  158. data/ruby/neo4j/driver/internal/cluster/cluster_composition_lookup_result.rb +0 -14
  159. data/ruby/neo4j/driver/internal/cluster/cluster_routing_table.rb +0 -122
  160. data/ruby/neo4j/driver/internal/cluster/identity_resolver.rb +0 -10
  161. data/ruby/neo4j/driver/internal/cluster/loadbalancing/least_connected_load_balancing_strategy.rb +0 -68
  162. data/ruby/neo4j/driver/internal/cluster/loadbalancing/load_balancer.rb +0 -125
  163. data/ruby/neo4j/driver/internal/cluster/loadbalancing/round_robin_array_index.rb +0 -13
  164. data/ruby/neo4j/driver/internal/cluster/multi_databases_routing_procedure_runner.rb +0 -31
  165. data/ruby/neo4j/driver/internal/cluster/rediscovery_impl.rb +0 -147
  166. data/ruby/neo4j/driver/internal/cluster/route_message_routing_procedure_runner.rb +0 -43
  167. data/ruby/neo4j/driver/internal/cluster/routing_context.rb +0 -77
  168. data/ruby/neo4j/driver/internal/cluster/routing_procedure_cluster_composition_provider.rb +0 -60
  169. data/ruby/neo4j/driver/internal/cluster/routing_procedure_response.rb +0 -35
  170. data/ruby/neo4j/driver/internal/cluster/routing_settings.rb +0 -24
  171. data/ruby/neo4j/driver/internal/cluster/routing_table_handler_impl.rb +0 -95
  172. data/ruby/neo4j/driver/internal/cluster/routing_table_registry_impl.rb +0 -121
  173. data/ruby/neo4j/driver/internal/cluster/single_database_routing_procedure_runner.rb +0 -73
  174. data/ruby/neo4j/driver/internal/connection_settings.rb +0 -16
  175. data/ruby/neo4j/driver/internal/cursor/async_result_cursor_impl.rb +0 -55
  176. data/ruby/neo4j/driver/internal/cursor/async_result_cursor_only_factory.rb +0 -24
  177. data/ruby/neo4j/driver/internal/cursor/disposable_async_result_cursor.rb +0 -61
  178. data/ruby/neo4j/driver/internal/cursor/result_cursor_factory_impl.rb +0 -24
  179. data/ruby/neo4j/driver/internal/cursor/rx_result_cursor_impl.rb +0 -110
  180. data/ruby/neo4j/driver/internal/database_name_util.rb +0 -37
  181. data/ruby/neo4j/driver/internal/default_bookmark_holder.rb +0 -9
  182. data/ruby/neo4j/driver/internal/default_domain_name_resolver.rb +0 -11
  183. data/ruby/neo4j/driver/internal/direct_connection_provider.rb +0 -40
  184. data/ruby/neo4j/driver/internal/driver_factory.rb +0 -126
  185. data/ruby/neo4j/driver/internal/eager_result_value.rb +0 -5
  186. data/ruby/neo4j/driver/internal/handlers/begin_tx_response_handler.rb +0 -20
  187. data/ruby/neo4j/driver/internal/handlers/channel_releasing_reset_response_handler.rb +0 -30
  188. data/ruby/neo4j/driver/internal/handlers/commit_tx_response_handler.rb +0 -23
  189. data/ruby/neo4j/driver/internal/handlers/hello_response_handler.rb +0 -65
  190. data/ruby/neo4j/driver/internal/handlers/init_response_handler.rb +0 -34
  191. data/ruby/neo4j/driver/internal/handlers/legacy_pull_all_response_handler.rb +0 -199
  192. data/ruby/neo4j/driver/internal/handlers/no_op_response_handler.rb +0 -16
  193. data/ruby/neo4j/driver/internal/handlers/ping_response_handler.rb +0 -29
  194. data/ruby/neo4j/driver/internal/handlers/pull_handlers.rb +0 -32
  195. data/ruby/neo4j/driver/internal/handlers/pulln/auto_pull_response_handler.rb +0 -169
  196. data/ruby/neo4j/driver/internal/handlers/pulln/basic_pull_response_handler.rb +0 -298
  197. data/ruby/neo4j/driver/internal/handlers/pulln/fetch_size_util.rb +0 -20
  198. data/ruby/neo4j/driver/internal/handlers/reset_response_handler.rb +0 -34
  199. data/ruby/neo4j/driver/internal/handlers/rollback_tx_response_handler.rb +0 -25
  200. data/ruby/neo4j/driver/internal/handlers/route_message_response_handler.rb +0 -21
  201. data/ruby/neo4j/driver/internal/handlers/routing_response_handler.rb +0 -79
  202. data/ruby/neo4j/driver/internal/handlers/run_response_handler.rb +0 -38
  203. data/ruby/neo4j/driver/internal/handlers/session_pull_response_completion_listener.rb +0 -34
  204. data/ruby/neo4j/driver/internal/handlers/transaction_pull_response_completion_listener.rb +0 -20
  205. data/ruby/neo4j/driver/internal/impersonation_util.rb +0 -22
  206. data/ruby/neo4j/driver/internal/internal_bookmark.rb +0 -9
  207. data/ruby/neo4j/driver/internal/internal_database_name.rb +0 -9
  208. data/ruby/neo4j/driver/internal/internal_driver.rb +0 -83
  209. data/ruby/neo4j/driver/internal/internal_entity.rb +0 -21
  210. data/ruby/neo4j/driver/internal/internal_node.rb +0 -21
  211. data/ruby/neo4j/driver/internal/internal_pair.rb +0 -9
  212. data/ruby/neo4j/driver/internal/internal_path.rb +0 -35
  213. data/ruby/neo4j/driver/internal/internal_point2_d.rb +0 -9
  214. data/ruby/neo4j/driver/internal/internal_point3_d.rb +0 -6
  215. data/ruby/neo4j/driver/internal/internal_record.rb +0 -27
  216. data/ruby/neo4j/driver/internal/internal_relationship.rb +0 -27
  217. data/ruby/neo4j/driver/internal/internal_result.rb +0 -49
  218. data/ruby/neo4j/driver/internal/internal_session.rb +0 -91
  219. data/ruby/neo4j/driver/internal/internal_transaction.rb +0 -48
  220. data/ruby/neo4j/driver/internal/logging/channel_activity_logger.rb +0 -29
  221. data/ruby/neo4j/driver/internal/logging/channel_error_logger.rb +0 -17
  222. data/ruby/neo4j/driver/internal/logging/prefixed_logger.rb +0 -19
  223. data/ruby/neo4j/driver/internal/logging/reformatted_logger.rb +0 -17
  224. data/ruby/neo4j/driver/internal/messaging/abstract_message_writer.rb +0 -23
  225. data/ruby/neo4j/driver/internal/messaging/bolt_protocol.rb +0 -32
  226. data/ruby/neo4j/driver/internal/messaging/bolt_protocol_version.rb +0 -48
  227. data/ruby/neo4j/driver/internal/messaging/common/common_message_reader.rb +0 -51
  228. data/ruby/neo4j/driver/internal/messaging/common/common_value.rb +0 -33
  229. data/ruby/neo4j/driver/internal/messaging/common/common_value_packer.rb +0 -104
  230. data/ruby/neo4j/driver/internal/messaging/common/common_value_unpacker.rb +0 -256
  231. data/ruby/neo4j/driver/internal/messaging/encode/begin_message_encoder.rb +0 -15
  232. data/ruby/neo4j/driver/internal/messaging/encode/commit_message_encoder.rb +0 -14
  233. data/ruby/neo4j/driver/internal/messaging/encode/discard_all_message_encoder.rb +0 -14
  234. data/ruby/neo4j/driver/internal/messaging/encode/discard_message_encoder.rb +0 -15
  235. data/ruby/neo4j/driver/internal/messaging/encode/goodbye_message_encoder.rb +0 -14
  236. data/ruby/neo4j/driver/internal/messaging/encode/hello_message_encoder.rb +0 -15
  237. data/ruby/neo4j/driver/internal/messaging/encode/init_message_encoder.rb +0 -16
  238. data/ruby/neo4j/driver/internal/messaging/encode/logoff_message_encoder.rb +0 -14
  239. data/ruby/neo4j/driver/internal/messaging/encode/logon_message_encoder.rb +0 -15
  240. data/ruby/neo4j/driver/internal/messaging/encode/pull_all_message_encoder.rb +0 -14
  241. data/ruby/neo4j/driver/internal/messaging/encode/pull_message_encoder.rb +0 -15
  242. data/ruby/neo4j/driver/internal/messaging/encode/reset_message_encoder.rb +0 -14
  243. data/ruby/neo4j/driver/internal/messaging/encode/rollback_message_encoder.rb +0 -14
  244. data/ruby/neo4j/driver/internal/messaging/encode/route_message_encoder.rb +0 -24
  245. data/ruby/neo4j/driver/internal/messaging/encode/route_v44_message_encoder.rb +0 -22
  246. data/ruby/neo4j/driver/internal/messaging/encode/run_message_encoder.rb +0 -16
  247. data/ruby/neo4j/driver/internal/messaging/encode/run_with_metadata_message_encoder.rb +0 -17
  248. data/ruby/neo4j/driver/internal/messaging/request/abstract_streaming_message.rb +0 -25
  249. data/ruby/neo4j/driver/internal/messaging/request/begin_message.rb +0 -25
  250. data/ruby/neo4j/driver/internal/messaging/request/commit_message.rb +0 -20
  251. data/ruby/neo4j/driver/internal/messaging/request/discard_all_message.rb +0 -20
  252. data/ruby/neo4j/driver/internal/messaging/request/discard_message.rb +0 -23
  253. data/ruby/neo4j/driver/internal/messaging/request/goodbye_message.rb +0 -20
  254. data/ruby/neo4j/driver/internal/messaging/request/hello_message.rb +0 -30
  255. data/ruby/neo4j/driver/internal/messaging/request/init_message.rb +0 -19
  256. data/ruby/neo4j/driver/internal/messaging/request/logoff_message.rb +0 -13
  257. data/ruby/neo4j/driver/internal/messaging/request/logon_message.rb +0 -13
  258. data/ruby/neo4j/driver/internal/messaging/request/message_with_metadata.rb +0 -17
  259. data/ruby/neo4j/driver/internal/messaging/request/multi_database_util.rb +0 -26
  260. data/ruby/neo4j/driver/internal/messaging/request/pull_all_message.rb +0 -23
  261. data/ruby/neo4j/driver/internal/messaging/request/pull_message.rb +0 -22
  262. data/ruby/neo4j/driver/internal/messaging/request/reset_message.rb +0 -32
  263. data/ruby/neo4j/driver/internal/messaging/request/rollback_message.rb +0 -20
  264. data/ruby/neo4j/driver/internal/messaging/request/route_message.rb +0 -28
  265. data/ruby/neo4j/driver/internal/messaging/request/run_message.rb +0 -23
  266. data/ruby/neo4j/driver/internal/messaging/request/run_with_metadata_message.rb +0 -49
  267. data/ruby/neo4j/driver/internal/messaging/request/transaction_metadata_builder.rb +0 -24
  268. data/ruby/neo4j/driver/internal/messaging/response/failure_message.rb +0 -40
  269. data/ruby/neo4j/driver/internal/messaging/response/ignored_message.rb +0 -29
  270. data/ruby/neo4j/driver/internal/messaging/response/record_message.rb +0 -33
  271. data/ruby/neo4j/driver/internal/messaging/response/success_message.rb +0 -34
  272. data/ruby/neo4j/driver/internal/messaging/v3/bolt_protocol_v3.rb +0 -82
  273. data/ruby/neo4j/driver/internal/messaging/v3/message_format_v3.rb +0 -17
  274. data/ruby/neo4j/driver/internal/messaging/v3/message_writer_v3.rb +0 -27
  275. data/ruby/neo4j/driver/internal/messaging/v4/bolt_protocol_v4.rb +0 -29
  276. data/ruby/neo4j/driver/internal/messaging/v4/message_format_v4.rb +0 -13
  277. data/ruby/neo4j/driver/internal/messaging/v4/message_writer_v4.rb +0 -17
  278. data/ruby/neo4j/driver/internal/messaging/v41/bolt_protocol_v41.rb +0 -25
  279. data/ruby/neo4j/driver/internal/messaging/v42/bolt_protocol_v42.rb +0 -13
  280. data/ruby/neo4j/driver/internal/messaging/v43/bolt_protocol_v43.rb +0 -19
  281. data/ruby/neo4j/driver/internal/messaging/v43/message_format_v43.rb +0 -14
  282. data/ruby/neo4j/driver/internal/messaging/v43/message_writer_v43.rb +0 -20
  283. data/ruby/neo4j/driver/internal/messaging/v44/bolt_protocol_v44.rb +0 -17
  284. data/ruby/neo4j/driver/internal/messaging/v44/message_format_v44.rb +0 -14
  285. data/ruby/neo4j/driver/internal/messaging/v44/message_writer_v44.rb +0 -15
  286. data/ruby/neo4j/driver/internal/messaging/v5/bolt_protocol_v5.rb +0 -21
  287. data/ruby/neo4j/driver/internal/messaging/v5/message_format_v5.rb +0 -18
  288. data/ruby/neo4j/driver/internal/messaging/v5/value_unpacker_v5.rb +0 -17
  289. data/ruby/neo4j/driver/internal/messaging/v51/bolt_protocol_v51.rb +0 -40
  290. data/ruby/neo4j/driver/internal/messaging/v51/message_format_v51.rb +0 -14
  291. data/ruby/neo4j/driver/internal/messaging/v51/message_writer_v51.rb +0 -17
  292. data/ruby/neo4j/driver/internal/metrics/connection_pool_metrics_listener.rb +0 -34
  293. data/ruby/neo4j/driver/internal/metrics/internal_abstract_metrics.rb +0 -46
  294. data/ruby/neo4j/driver/internal/metrics/internal_connection_pool_metrics.rb +0 -105
  295. data/ruby/neo4j/driver/internal/metrics/internal_metrics.rb +0 -82
  296. data/ruby/neo4j/driver/internal/metrics/internal_metrics_provider.rb +0 -18
  297. data/ruby/neo4j/driver/internal/metrics/listener_event.rb +0 -17
  298. data/ruby/neo4j/driver/internal/metrics/metrics_provider.rb +0 -24
  299. data/ruby/neo4j/driver/internal/metrics/time_recorder_listener_event.rb +0 -15
  300. data/ruby/neo4j/driver/internal/packstream/byte_array_incompatible_packer.rb +0 -12
  301. data/ruby/neo4j/driver/internal/packstream/pack_input.rb +0 -47
  302. data/ruby/neo4j/driver/internal/packstream/pack_output.rb +0 -39
  303. data/ruby/neo4j/driver/internal/packstream/pack_stream.rb +0 -324
  304. data/ruby/neo4j/driver/internal/packstream/pack_type.rb +0 -17
  305. data/ruby/neo4j/driver/internal/read_only_bookmark_holder.rb +0 -13
  306. data/ruby/neo4j/driver/internal/resolved_bolt_server_address.rb +0 -35
  307. data/ruby/neo4j/driver/internal/retry/exponential_backoff_retry_logic.rb +0 -150
  308. data/ruby/neo4j/driver/internal/revocation_strategy.rb +0 -19
  309. data/ruby/neo4j/driver/internal/scheme.rb +0 -32
  310. data/ruby/neo4j/driver/internal/security/internal_auth_token.rb +0 -15
  311. data/ruby/neo4j/driver/internal/security/security_plan_impl.rb +0 -48
  312. data/ruby/neo4j/driver/internal/security_setting.rb +0 -66
  313. data/ruby/neo4j/driver/internal/session_factory_impl.rb +0 -32
  314. data/ruby/neo4j/driver/internal/spi/connection.rb +0 -19
  315. data/ruby/neo4j/driver/internal/spi/connection_pool.rb +0 -9
  316. data/ruby/neo4j/driver/internal/spi/response_handler.rb +0 -23
  317. data/ruby/neo4j/driver/internal/summary/internal_database_info.rb +0 -7
  318. data/ruby/neo4j/driver/internal/summary/internal_input_position.rb +0 -11
  319. data/ruby/neo4j/driver/internal/summary/internal_notification.rb +0 -16
  320. data/ruby/neo4j/driver/internal/summary/internal_plan.rb +0 -41
  321. data/ruby/neo4j/driver/internal/summary/internal_profiled_plan.rb +0 -32
  322. data/ruby/neo4j/driver/internal/summary/internal_result_summary.rb +0 -33
  323. data/ruby/neo4j/driver/internal/summary/internal_server_info.rb +0 -6
  324. data/ruby/neo4j/driver/internal/summary/internal_summary_counters.rb +0 -18
  325. data/ruby/neo4j/driver/internal/svm/netty_substitutions.rb +0 -196
  326. data/ruby/neo4j/driver/internal/svm/z_lib_substitutions.rb +0 -21
  327. data/ruby/neo4j/driver/internal/util/certificate_tool.rb +0 -65
  328. data/ruby/neo4j/driver/internal/util/clock.rb +0 -29
  329. data/ruby/neo4j/driver/internal/util/error_util.rb +0 -104
  330. data/ruby/neo4j/driver/internal/util/extract.rb +0 -123
  331. data/ruby/neo4j/driver/internal/util/format.rb +0 -39
  332. data/ruby/neo4j/driver/internal/util/futures.rb +0 -99
  333. data/ruby/neo4j/driver/internal/util/iterables.rb +0 -35
  334. data/ruby/neo4j/driver/internal/util/lock_util.rb +0 -23
  335. data/ruby/neo4j/driver/internal/util/metadata_extractor.rb +0 -101
  336. data/ruby/neo4j/driver/internal/util/mutex.rb +0 -9
  337. data/ruby/neo4j/driver/internal/util/preconditions.rb +0 -16
  338. data/ruby/neo4j/driver/internal/util/result_holder.rb +0 -72
  339. data/ruby/neo4j/driver/internal/util/server_version.rb +0 -60
  340. data/ruby/neo4j/driver/logging1.rb +0 -51
  341. data/ruby/neo4j/driver/net/server_address.rb +0 -9
  342. data/ruby/neo4j/driver/query.rb +0 -48
  343. data/ruby/neo4j/driver/records.rb +0 -13
  344. data/ruby/neo4j/driver/transaction_config.rb +0 -50
  345. data/ruby/neo4j/driver/values.rb +0 -26
  346. data/ruby/neo4j/driver.rb +0 -30
@@ -0,0 +1,333 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Neo4j
4
+ module Driver
5
+ module PackStream
6
+ # PackStream Packer - serializes Ruby objects to PackStream binary format
7
+ # Based on https://neo4j.com/docs/bolt/current/packstream/
8
+ class Packer
9
+ include Markers
10
+
11
+ # When true, datetimes are packed as the UTC-seconds Bolt 5.0+
12
+ # structures (0x49 / 0x69) instead of the legacy local-seconds
13
+ # variants (0x46 / 0x66). Connection sets this after a
14
+ # successful handshake negotiates Bolt 5.0+; ignored on 4.x.
15
+ attr_accessor :use_utc_datetime
16
+
17
+ def initialize(protocol)
18
+ @buffer = String.new(encoding: Encoding::BINARY)
19
+ @use_utc_datetime = false
20
+ @protocol = protocol
21
+ end
22
+
23
+ def pack(value)
24
+ case value
25
+ when nil
26
+ pack_null
27
+ when true, false
28
+ pack_boolean(value)
29
+ when Integer
30
+ pack_integer(value)
31
+ when Float
32
+ pack_float(value)
33
+ when String
34
+ # Pack binary strings as BYTES, text strings as STRING
35
+ value.encoding == Encoding::BINARY ? pack_bytes(value) : pack_string(value)
36
+ when Symbol
37
+ pack_string(value.to_s)
38
+ when Hash
39
+ # Check Hash before Enumerable since Hash is also Enumerable
40
+ pack_map(value)
41
+ when Types::Node, Types::Relationship, Types::Path, Types::UnsupportedType
42
+ # Graph types are not valid query parameters; neither is an
43
+ # UnsupportedType (a value the driver couldn't materialise — it
44
+ # must not be sent back to the server). Reject before the Enumerable
45
+ # branch since Path includes Enumerable.
46
+ Exceptions::ClientException.unable_to_convert(value)
47
+ when Array, Set, Range
48
+ # Known sized collections — pack_list uses #size, which is O(1) here.
49
+ pack_list(value)
50
+ when Enumerable
51
+ # Generic Enumerable (lazy enumerators, custom collections) — materialise
52
+ # so #size is well-defined.
53
+ pack_list(value.to_a)
54
+ when ::DateTime, ::Time
55
+ # Check DateTime before Date — DateTime < Date in Ruby, so the
56
+ # Date branch would match first and pack away the time component.
57
+ pack_datetime(value)
58
+ when ::Date
59
+ # Pack Ruby Date as Neo4j Date structure
60
+ pack_date(value)
61
+ when Types::LocalDateTime
62
+ pack_local_datetime(value)
63
+ when Types::LocalTime
64
+ pack_local_time(value)
65
+ when Types::OffsetTime
66
+ pack_offset_time(value)
67
+ when Types::Point
68
+ pack_point(value)
69
+ when Types::Duration
70
+ pack_duration(value)
71
+ when Types::UUID
72
+ # A PackStream V2 type: only the negotiated protocol decides whether
73
+ # it can be sent — V61 packs it, every earlier version rejects it.
74
+ @protocol.pack_uuid(self, value)
75
+ else
76
+ Exceptions::ClientException.unable_to_convert(value)
77
+ end
78
+ self
79
+ end
80
+
81
+ # Serialise a Bolt protocol message (a PackStream::Structure) onto the buffer.
82
+ # Distinct from #pack so the user-value path doesn't carry knowledge of
83
+ # the wire-level Structure type.
84
+ def pack_message(structure)
85
+ pack_structure(structure)
86
+ self
87
+ end
88
+
89
+ def bytes
90
+ @buffer
91
+ end
92
+
93
+ def reset
94
+ @buffer.clear
95
+ self
96
+ end
97
+
98
+ # PackStream V2 UUID (Bolt 6.1+): marker 0xE0 + 16 raw bytes. Called by
99
+ # Protocol::V61#pack_uuid — every earlier protocol rejects a UUID
100
+ # instead, so this is only reached once 6.1 is negotiated.
101
+ def pack_uuid_value(value)
102
+ @buffer << [UUID].pack('C')
103
+ @buffer << [value.to_s.delete('-')].pack('H*')
104
+ end
105
+
106
+ private
107
+
108
+ def pack_null
109
+ @buffer << [NULL].pack('C')
110
+ end
111
+
112
+ def pack_boolean(value)
113
+ @buffer << [value ? TRUE : FALSE].pack('C')
114
+ end
115
+
116
+ def pack_integer(value)
117
+ if value >= -16 && value <= 127
118
+ # TINY_INT: -16 to +127
119
+ @buffer << [value].pack('c')
120
+ elsif value >= -128 && value <= 127
121
+ @buffer << [INT_8, value].pack('Cc')
122
+ elsif value >= -32_768 && value <= 32_767
123
+ @buffer << [INT_16, value].pack('Cs>')
124
+ elsif value >= -2_147_483_648 && value <= 2_147_483_647
125
+ @buffer << [INT_32, value].pack('Cl>')
126
+ elsif value >= -9_223_372_036_854_775_808 && value <= 9_223_372_036_854_775_807
127
+ @buffer << [INT_64, value].pack('Cq>')
128
+ else
129
+ raise ArgumentError, "Integer value out of range: #{value}"
130
+ end
131
+ end
132
+
133
+ def pack_float(value)
134
+ @buffer << [FLOAT_64].pack('C')
135
+ @buffer << [value].pack('G')
136
+ end
137
+
138
+ def pack_string(value)
139
+ bytes = value.encode(Encoding::UTF_8).b
140
+ size = bytes.bytesize
141
+
142
+ if size < 16
143
+ @buffer << [TINY_STRING | size].pack('C')
144
+ elsif size <= 255
145
+ @buffer << [STRING_8, size].pack('CC')
146
+ elsif size <= 65_535
147
+ @buffer << [STRING_16, size].pack('CS>')
148
+ elsif size <= 2_147_483_647
149
+ @buffer << [STRING_32, size].pack('CL>')
150
+ else
151
+ raise ArgumentError, "String too long: #{size} bytes"
152
+ end
153
+
154
+ @buffer << bytes
155
+ end
156
+
157
+ def pack_bytes(value)
158
+ size = value.bytesize
159
+
160
+ if size <= 255
161
+ @buffer << [BYTES_8, size].pack('CC')
162
+ elsif size <= 65_535
163
+ @buffer << [BYTES_16, size].pack('CS>')
164
+ elsif size <= 2_147_483_647
165
+ @buffer << [BYTES_32, size].pack('CL>')
166
+ else
167
+ raise ArgumentError, "Bytes too long: #{size} bytes"
168
+ end
169
+
170
+ @buffer << value
171
+ end
172
+
173
+ def pack_list(value)
174
+ size = value.size
175
+
176
+ if size < 16
177
+ @buffer << [TINY_LIST | size].pack('C')
178
+ elsif size <= 255
179
+ @buffer << [LIST_8, size].pack('CC')
180
+ elsif size <= 65_535
181
+ @buffer << [LIST_16, size].pack('CS>')
182
+ elsif size <= 2_147_483_647
183
+ @buffer << [LIST_32, size].pack('CL>')
184
+ else
185
+ raise ArgumentError, "List too long: #{size} items"
186
+ end
187
+
188
+ value.each { pack(it) }
189
+ end
190
+
191
+ def pack_map(value)
192
+ size = value.size
193
+
194
+ if size < 16
195
+ @buffer << [TINY_MAP | size].pack('C')
196
+ elsif size <= 255
197
+ @buffer << [MAP_8, size].pack('CC')
198
+ elsif size <= 65_535
199
+ @buffer << [MAP_16, size].pack('CS>')
200
+ elsif size <= 2_147_483_647
201
+ @buffer << [MAP_32, size].pack('CL>')
202
+ else
203
+ raise ArgumentError, "Map too long: #{size} entries"
204
+ end
205
+
206
+ value.each do |key, val|
207
+ pack(key.to_s)
208
+ pack(val)
209
+ end
210
+ end
211
+
212
+ def pack_structure(value)
213
+ size = value.fields.size
214
+
215
+ if size < 16
216
+ @buffer << [TINY_STRUCT | size].pack('C')
217
+ elsif size <= 255
218
+ @buffer << [STRUCT_8, size].pack('CC')
219
+ elsif size <= 65_535
220
+ @buffer << [STRUCT_16, size].pack('CS>')
221
+ else
222
+ raise ArgumentError, "Structure too large: #{size} fields"
223
+ end
224
+
225
+ @buffer << [value.signature].pack('C')
226
+ value.fields.each { |field| pack(field) }
227
+ end
228
+
229
+ def pack_date(value)
230
+ days = (value - ::Date.new(1970, 1, 1)).to_i
231
+ # Date structure: signature 0x44, 1 field (days)
232
+ @buffer << [TINY_STRUCT | 1, 0x44].pack('CC')
233
+ pack_integer(days)
234
+ end
235
+
236
+ def pack_datetime(value)
237
+ # Normalise DateTime to Time so we can rely on Time's API (nsec,
238
+ # utc_offset, to_i) uniformly.
239
+ value = value.to_time if value.is_a?(::DateTime)
240
+
241
+ tz_offset = value.utc_offset
242
+ nanoseconds = value.nsec
243
+ # Bolt 5.0+ (and 4.4-with-patch_bolt:utc) want true UTC
244
+ # seconds in 0x49 / 0x69; the legacy 0x46 / 0x66 carry LOCAL
245
+ # seconds (wall-clock treated as if it were UTC). See the
246
+ # matching hydration handlers in Bolt::Connection.
247
+ if @use_utc_datetime
248
+ epoch_seconds = value.to_i
249
+ offset_sig, zone_sig = 0x49, 0x69
250
+ else
251
+ epoch_seconds = value.to_i + tz_offset
252
+ offset_sig, zone_sig = 0x46, 0x66
253
+ end
254
+ zone_name = named_zone_for(value)
255
+
256
+ if zone_name
257
+ # ZonedDateTime: fields [seconds, nanos, tz_name]
258
+ @buffer << [TINY_STRUCT | 3, zone_sig].pack('CC')
259
+ pack_integer(epoch_seconds)
260
+ pack_integer(nanoseconds)
261
+ pack_string(zone_name)
262
+ else
263
+ # DateTime with offset: fields [seconds, nanos, tz_offset]
264
+ @buffer << [TINY_STRUCT | 3, offset_sig].pack('CC')
265
+ pack_integer(epoch_seconds)
266
+ pack_integer(nanoseconds)
267
+ pack_integer(tz_offset)
268
+ end
269
+ end
270
+
271
+ # Return the IANA zone name for a TimeWithZone-like value when it has
272
+ # one, otherwise nil (so the caller falls back to offset-only 0x46).
273
+ # Offset-shaped names like "+07:00" or "-05:00" don't round-trip
274
+ # through Neo4j's zoned DateTime and are treated as nil.
275
+ def named_zone_for(value)
276
+ return nil unless value.respond_to?(:time_zone)
277
+
278
+ tz = value.time_zone
279
+ name = tz.respond_to?(:name) ? tz.name : nil
280
+ return nil if name.nil? || name.empty? || name.match?(/\A[+-]?\d/)
281
+
282
+ name
283
+ end
284
+
285
+ def pack_local_datetime(value)
286
+ # LocalDateTime structure: signature 0x64, 2 fields (seconds, nanos)
287
+ @buffer << [TINY_STRUCT | 2, 0x64].pack('CC')
288
+ pack_integer(value.epoch_seconds)
289
+ pack_integer(value.nanoseconds)
290
+ end
291
+
292
+ def pack_offset_time(value)
293
+ # OffsetTime structure: signature 0x54, 2 fields (nanos, tz_offset)
294
+ @buffer << [TINY_STRUCT | 2, 0x54].pack('CC')
295
+ pack_integer(value.nanoseconds)
296
+ pack_integer(value.tz_offset_seconds)
297
+ end
298
+
299
+ def pack_local_time(value)
300
+ # LocalTime structure: signature 0x74, 1 field (nanos)
301
+ @buffer << [TINY_STRUCT | 1, 0x74].pack('CC')
302
+ pack_integer(value.nanoseconds)
303
+ end
304
+
305
+ def pack_point(value)
306
+ if value.z.nil?
307
+ # Point2D: signature 0x58, 3 fields (srid, x, y)
308
+ @buffer << [TINY_STRUCT | 3, 0x58].pack('CC')
309
+ pack_integer(value.srid)
310
+ pack_float(value.x)
311
+ pack_float(value.y)
312
+ else
313
+ # Point3D: signature 0x59, 4 fields (srid, x, y, z)
314
+ @buffer << [TINY_STRUCT | 4, 0x59].pack('CC')
315
+ pack_integer(value.srid)
316
+ pack_float(value.x)
317
+ pack_float(value.y)
318
+ pack_float(value.z)
319
+ end
320
+ end
321
+
322
+ def pack_duration(value)
323
+ # Duration: signature 0x45, 4 fields (months, days, seconds, nanoseconds)
324
+ @buffer << [TINY_STRUCT | 4, 0x45].pack('CC')
325
+ pack_integer(value.months)
326
+ pack_integer(value.days)
327
+ pack_integer(value.seconds)
328
+ pack_integer(value.nanoseconds)
329
+ end
330
+ end
331
+ end
332
+ end
333
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Neo4j
4
+ module Driver
5
+ module PackStream
6
+ # Represents a PackStream Structure with a signature and fields
7
+ class Structure
8
+ attr_reader :signature, :fields
9
+
10
+ def initialize(signature, fields = [])
11
+ @signature = signature
12
+ @fields = fields
13
+ end
14
+
15
+ def ==(other)
16
+ other.is_a?(Structure) &&
17
+ other.signature == @signature &&
18
+ other.fields == @fields
19
+ end
20
+
21
+ def to_s
22
+ "Structure(0x#{@signature.to_s(16).upcase}, #{@fields.inspect})"
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,168 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Neo4j
4
+ module Driver
5
+ module PackStream
6
+ # PackStream Unpacker - deserializes PackStream binary format to Ruby objects
7
+ class Unpacker
8
+ include Markers
9
+
10
+ def initialize(io, protocol)
11
+ @io = io
12
+ @hydration_handlers = {}
13
+ @protocol = protocol
14
+ end
15
+
16
+ def register_hydration_handler(signature, handler = nil, &block)
17
+ @hydration_handlers[signature] = handler || block
18
+ end
19
+
20
+ def unpack
21
+ marker_byte = read_bytes(1).unpack1('C')
22
+ unpack_value(marker_byte)
23
+ end
24
+
25
+ # PackStream V2 UUID (Bolt 6.1+): 16 raw bytes (big-endian) after the
26
+ # marker, rendered to the canonical hyphenated form for Types::UUID.
27
+ # Called by Protocol::V61#unpack_uuid — earlier protocols reject the
28
+ # marker instead, so this is only reached once 6.1 is negotiated.
29
+ def unpack_uuid_value
30
+ hex = read_bytes(16).unpack1('H*')
31
+ Types::UUID.from_string(
32
+ "#{hex[0, 8]}-#{hex[8, 4]}-#{hex[12, 4]}-#{hex[16, 4]}-#{hex[20, 12]}")
33
+ end
34
+
35
+ # A ProtocolException (not a bare RuntimeError) so the failure reaches
36
+ # the user as a DriverError. The wording carries "PackStream" and the
37
+ # zero-padded marker byte — e.g. a UUID (0xE0) received before Bolt 6.1,
38
+ # which Protocol::Base#unpack_uuid routes here. testkit's UUID-over-6.0
39
+ # assertion greps the lowercased message for "unknown packstream" and
40
+ # "e0", both of which this satisfies.
41
+ def raise_unknown_marker(marker)
42
+ raise Exceptions::ProtocolException,
43
+ format('Unknown PackStream type marker: 0x%02x', marker)
44
+ end
45
+
46
+ private
47
+
48
+ def unpack_value(marker)
49
+ case marker
50
+ when NULL
51
+ nil
52
+ when FALSE
53
+ false
54
+ when TRUE
55
+ true
56
+ when FLOAT_64
57
+ read_bytes(8).unpack1('G')
58
+ when INT_8
59
+ read_bytes(1).unpack1('c')
60
+ when INT_16
61
+ read_bytes(2).unpack1('s>')
62
+ when INT_32
63
+ read_bytes(4).unpack1('l>')
64
+ when INT_64
65
+ read_bytes(8).unpack1('q>')
66
+ when 0xC8..0xCB
67
+ # Already handled above, but needed for case coverage
68
+ raise "Unexpected marker in unpack_value: #{marker}"
69
+ when BYTES_8
70
+ size = read_bytes(1).unpack1('C')
71
+ read_bytes(size).force_encoding(Encoding::BINARY)
72
+ when BYTES_16
73
+ size = read_bytes(2).unpack1('S>')
74
+ read_bytes(size).force_encoding(Encoding::BINARY)
75
+ when BYTES_32
76
+ size = read_bytes(4).unpack1('L>')
77
+ read_bytes(size).force_encoding(Encoding::BINARY)
78
+ when STRING_8
79
+ size = read_bytes(1).unpack1('C')
80
+ read_bytes(size).force_encoding(Encoding::UTF_8)
81
+ when STRING_16
82
+ size = read_bytes(2).unpack1('S>')
83
+ read_bytes(size).force_encoding(Encoding::UTF_8)
84
+ when STRING_32
85
+ size = read_bytes(4).unpack1('L>')
86
+ read_bytes(size).force_encoding(Encoding::UTF_8)
87
+ when LIST_8
88
+ size = read_bytes(1).unpack1('C')
89
+ unpack_list(size)
90
+ when LIST_16
91
+ size = read_bytes(2).unpack1('S>')
92
+ unpack_list(size)
93
+ when LIST_32
94
+ size = read_bytes(4).unpack1('L>')
95
+ unpack_list(size)
96
+ when MAP_8
97
+ size = read_bytes(1).unpack1('C')
98
+ unpack_map(size)
99
+ when MAP_16
100
+ size = read_bytes(2).unpack1('S>')
101
+ unpack_map(size)
102
+ when MAP_32
103
+ size = read_bytes(4).unpack1('L>')
104
+ unpack_map(size)
105
+ when STRUCT_8
106
+ size = read_bytes(1).unpack1('C')
107
+ unpack_structure(size)
108
+ when STRUCT_16
109
+ size = read_bytes(2).unpack1('S>')
110
+ unpack_structure(size)
111
+ when UUID
112
+ # A PackStream V2 type: only the negotiated protocol decides whether
113
+ # the marker is known — V61 reads it, every earlier version rejects
114
+ # it as an unknown marker.
115
+ @protocol.unpack_uuid(self)
116
+ else
117
+ # Check for TINY types
118
+ if (marker & 0xF0) == TINY_STRING
119
+ size = marker & 0x0F
120
+ read_bytes(size).force_encoding(Encoding::UTF_8)
121
+ elsif (marker & 0xF0) == TINY_LIST
122
+ size = marker & 0x0F
123
+ unpack_list(size)
124
+ elsif (marker & 0xF0) == TINY_MAP
125
+ size = marker & 0x0F
126
+ unpack_map(size)
127
+ elsif (marker & 0xF0) == TINY_STRUCT
128
+ size = marker & 0x0F
129
+ unpack_structure(size)
130
+ elsif marker >= 0xF0 || marker <= 0x7F
131
+ # TINY_INT range: -16 to 127
132
+ # Values from 0xF0-0xFF represent -16 to -1
133
+ # Values from 0x00-0x7F represent 0 to 127
134
+ if marker >= 0xF0
135
+ marker - 256 # Convert to negative
136
+ else
137
+ marker
138
+ end
139
+ else
140
+ raise_unknown_marker(marker)
141
+ end
142
+ end
143
+ end
144
+
145
+ def unpack_list(size) = Array.new(size) { unpack }
146
+
147
+ def unpack_map(size)
148
+ {}.tap { |map| size.times { map[unpack.to_sym] = unpack } }
149
+ end
150
+
151
+ def unpack_structure(size)
152
+ signature = read_bytes(1).unpack1('C')
153
+ fields = Array.new(size) { unpack }
154
+ handler = @hydration_handlers[signature] or
155
+ raise "No hydration handler for PackStream structure signature 0x#{signature.to_s(16)}"
156
+
157
+ handler.call(fields)
158
+ end
159
+
160
+ def read_bytes(n)
161
+ data = @io.read(n)
162
+ raise IOError, "Unexpected end of stream" if data.nil? || data.bytesize < n
163
+ data
164
+ end
165
+ end
166
+ end
167
+ end
168
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Neo4j
4
+ module Driver
5
+ # Represents a single record (row) in a result
6
+ class Record
7
+ def initialize(keys, values)
8
+ @keys = keys
9
+ @values = values
10
+ # Create map with string keys for consistent lookup
11
+ @map = {}
12
+ @keys.each_with_index do |key, idx|
13
+ @map[key.to_s] = @values[idx]
14
+ end
15
+ end
16
+
17
+ def keys
18
+ @keys
19
+ end
20
+
21
+ def values
22
+ @values
23
+ end
24
+
25
+ def [](key)
26
+ case key
27
+ when Integer
28
+ @values[key]
29
+ when String, Symbol
30
+ @map[key.to_s]
31
+ else
32
+ raise ArgumentError, "Invalid key type: #{key.class}"
33
+ end
34
+ end
35
+
36
+ def first
37
+ @values.first
38
+ end
39
+
40
+ def to_h
41
+ @map.dup
42
+ end
43
+
44
+ def each(&block)
45
+ @map.each(&block)
46
+ end
47
+ end
48
+ end
49
+ end