neo4j-ruby-driver 0.1.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 (103) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +8 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.md +68 -0
  5. data/Rakefile +16 -0
  6. data/ffi/bolt/address.rb +11 -0
  7. data/ffi/bolt/auth.rb +10 -0
  8. data/ffi/bolt/auto_releasable.rb +22 -0
  9. data/ffi/bolt/boolean.rb +9 -0
  10. data/ffi/bolt/bytes.rb +10 -0
  11. data/ffi/bolt/config.rb +10 -0
  12. data/ffi/bolt/connection.rb +44 -0
  13. data/ffi/bolt/connector.rb +17 -0
  14. data/ffi/bolt/dictionary.rb +15 -0
  15. data/ffi/bolt/error.rb +74 -0
  16. data/ffi/bolt/float.rb +9 -0
  17. data/ffi/bolt/integer.rb +9 -0
  18. data/ffi/bolt/library.rb +12 -0
  19. data/ffi/bolt/lifecycle.rb +9 -0
  20. data/ffi/bolt/list.rb +10 -0
  21. data/ffi/bolt/status.rb +15 -0
  22. data/ffi/bolt/string.rb +9 -0
  23. data/ffi/bolt/structure.rb +10 -0
  24. data/ffi/bolt/value.rb +35 -0
  25. data/ffi/bolt/values_private.rb +36 -0
  26. data/ffi/neo4j/driver.rb +45 -0
  27. data/ffi/neo4j/driver/access_mode.rb +10 -0
  28. data/ffi/neo4j/driver/auth_tokens.rb +17 -0
  29. data/ffi/neo4j/driver/config.rb +11 -0
  30. data/ffi/neo4j/driver/graph_database.rb +29 -0
  31. data/ffi/neo4j/driver/internal/async/access_mode_connection.rb +19 -0
  32. data/ffi/neo4j/driver/internal/async/direct_connection.rb +88 -0
  33. data/ffi/neo4j/driver/internal/bookmarks_holder.rb +30 -0
  34. data/ffi/neo4j/driver/internal/direct_connection_provider.rb +27 -0
  35. data/ffi/neo4j/driver/internal/driver_factory.rb +38 -0
  36. data/ffi/neo4j/driver/internal/error_handling.rb +50 -0
  37. data/ffi/neo4j/driver/internal/explicit_transaction.rb +144 -0
  38. data/ffi/neo4j/driver/internal/handlers/pull_all_response_handler.rb +101 -0
  39. data/ffi/neo4j/driver/internal/handlers/response_handler.rb +46 -0
  40. data/ffi/neo4j/driver/internal/handlers/run_response_handler.rb +32 -0
  41. data/ffi/neo4j/driver/internal/handlers/session_pull_all_response_handler.rb +32 -0
  42. data/ffi/neo4j/driver/internal/handlers/transaction_pull_all_response_handler.rb +23 -0
  43. data/ffi/neo4j/driver/internal/internal_driver.rb +41 -0
  44. data/ffi/neo4j/driver/internal/internal_record.rb +22 -0
  45. data/ffi/neo4j/driver/internal/internal_statement_result.rb +52 -0
  46. data/ffi/neo4j/driver/internal/messaging/bolt_protocol.rb +24 -0
  47. data/ffi/neo4j/driver/internal/messaging/v1/bolt_protocol_v1.rb +59 -0
  48. data/ffi/neo4j/driver/internal/messaging/v2/bolt_protocol_v2.rb +16 -0
  49. data/ffi/neo4j/driver/internal/messaging/v3/bolt_protocol_v3.rb +63 -0
  50. data/ffi/neo4j/driver/internal/network_session.rb +124 -0
  51. data/ffi/neo4j/driver/internal/session_factory_impl.rb +28 -0
  52. data/ffi/neo4j/driver/internal/summary/internal_result_summary.rb +67 -0
  53. data/ffi/neo4j/driver/internal/summary/internal_server_info.rb +19 -0
  54. data/ffi/neo4j/driver/internal/summary/internal_summary_counters.rb +23 -0
  55. data/ffi/neo4j/driver/internal/util/metadata_extractor.rb +15 -0
  56. data/ffi/neo4j/driver/internal/value/base_time_value.rb +22 -0
  57. data/ffi/neo4j/driver/internal/value/date_value.rb +25 -0
  58. data/ffi/neo4j/driver/internal/value/duration_value.rb +27 -0
  59. data/ffi/neo4j/driver/internal/value/local_date_time_value.rb +24 -0
  60. data/ffi/neo4j/driver/internal/value/local_time_value.rb +19 -0
  61. data/ffi/neo4j/driver/internal/value/node_value.rb +18 -0
  62. data/ffi/neo4j/driver/internal/value/offset_time_value.rb +25 -0
  63. data/ffi/neo4j/driver/internal/value/path_value.rb +41 -0
  64. data/ffi/neo4j/driver/internal/value/point2_d_value.rb +24 -0
  65. data/ffi/neo4j/driver/internal/value/point3_d_value.rb +24 -0
  66. data/ffi/neo4j/driver/internal/value/relationship_value.rb +18 -0
  67. data/ffi/neo4j/driver/internal/value/structure_value.rb +42 -0
  68. data/ffi/neo4j/driver/internal/value/time_with_zone_id_value.rb +25 -0
  69. data/ffi/neo4j/driver/internal/value/time_with_zone_offset_value.rb +28 -0
  70. data/ffi/neo4j/driver/internal/value/unbound_relationship_value.rb +18 -0
  71. data/ffi/neo4j/driver/internal/value/value_adapter.rb +95 -0
  72. data/ffi/neo4j/driver/statement.rb +14 -0
  73. data/ffi/neo4j/driver/summary/statement_type.rb +14 -0
  74. data/ffi/neo4j/driver/types/entity.rb +17 -0
  75. data/ffi/neo4j/driver/types/node.rb +16 -0
  76. data/ffi/neo4j/driver/types/path.rb +35 -0
  77. data/ffi/neo4j/driver/types/relationship.rb +19 -0
  78. data/lib/loader.rb +18 -0
  79. data/lib/neo4j/driver/auto_closable.rb +32 -0
  80. data/lib/neo4j/driver/exceptions/authentication_exception.rb +10 -0
  81. data/lib/neo4j/driver/exceptions/client_exception.rb +10 -0
  82. data/lib/neo4j/driver/exceptions/database_exception.rb +10 -0
  83. data/lib/neo4j/driver/exceptions/illegal_state_exception.rb +10 -0
  84. data/lib/neo4j/driver/exceptions/neo4j_exception.rb +18 -0
  85. data/lib/neo4j/driver/exceptions/no_such_record_exception.rb +33 -0
  86. data/lib/neo4j/driver/exceptions/protocol_exception.rb +10 -0
  87. data/lib/neo4j/driver/exceptions/security_exception.rb +10 -0
  88. data/lib/neo4j/driver/exceptions/service_unavailable_exception.rb +10 -0
  89. data/lib/neo4j/driver/exceptions/session_expired_exception.rb +10 -0
  90. data/lib/neo4j/driver/exceptions/transient_exception.rb +10 -0
  91. data/lib/neo4j/driver/exceptions/untrusted_server_exception.rb +10 -0
  92. data/lib/neo4j/driver/internal/duration_normalizer.rb +42 -0
  93. data/lib/neo4j/driver/internal/ruby_signature.rb +18 -0
  94. data/lib/neo4j/driver/types/byte_array.rb +17 -0
  95. data/lib/neo4j/driver/types/local_date_time.rb +20 -0
  96. data/lib/neo4j/driver/types/local_time.rb +19 -0
  97. data/lib/neo4j/driver/types/offset_time.rb +19 -0
  98. data/lib/neo4j/driver/types/point.rb +39 -0
  99. data/lib/neo4j/driver/types/time.rb +43 -0
  100. data/lib/neo4j/driver/version.rb +7 -0
  101. data/lib/neo4j_ruby_driver.rb +19 -0
  102. data/neo4j-ruby-driver.gemspec +63 -0
  103. metadata +274 -0
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bolt
4
+ module Structure
5
+ extend Bolt::Library
6
+
7
+ attach_function :code, :BoltStructure_code, %i[pointer], :int16
8
+ attach_function :value, :BoltStructure_value, %i[pointer int32], :pointer
9
+ end
10
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bolt
4
+ module Value
5
+ extend Bolt::Library
6
+
7
+ enum :bolt_type,
8
+ %i[bolt_null
9
+ bolt_boolean
10
+ bolt_integer
11
+ bolt_float
12
+ bolt_string
13
+ bolt_dictionary
14
+ bolt_list
15
+ bolt_bytes
16
+ bolt_structure]
17
+
18
+ attach_function :create, :BoltValue_create, [], :auto_pointer
19
+ attach_function :destroy, :BoltValue_destroy, %i[pointer], :void
20
+ attach_function :duplicate, :BoltValue_duplicate, %i[pointer], :auto_pointer
21
+ attach_function :copy, :BoltValue_copy, %i[pointer pointer], :void
22
+ attach_function :size, :BoltValue_size, %i[pointer], :int32
23
+ attach_function :type, :BoltValue_type, %i[pointer], :bolt_type
24
+ attach_function :to_string, :BoltValue_to_string, %i[pointer pointer int32 pointer], :int32
25
+ attach_function :format_as_null, :BoltValue_format_as_Null, %i[pointer], :void
26
+ attach_function :format_as_boolean, :BoltValue_format_as_Boolean, %i[pointer char], :void
27
+ attach_function :format_as_integer, :BoltValue_format_as_Integer, %i[pointer int64], :void
28
+ attach_function :format_as_float, :BoltValue_format_as_Float, %i[pointer double], :void
29
+ attach_function :format_as_string, :BoltValue_format_as_String, %i[pointer string int32], :void
30
+ attach_function :format_as_dictionary, :BoltValue_format_as_Dictionary, %i[pointer int32], :void
31
+ attach_function :format_as_list, :BoltValue_format_as_List, %i[pointer int32], :void
32
+ attach_function :format_as_bytes, :BoltValue_format_as_Bytes, %i[pointer string int32], :void
33
+ attach_function :format_as_structure, :BoltValue_format_as_Structure, %i[pointer int16 int32], :void
34
+ end
35
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bolt
4
+ module ValuesPrivate
5
+ extend FFI::Library
6
+
7
+ typedef :pointer, :bolt_value
8
+ # typedef BoltData, :bolt_data
9
+ # typedef BoltExtendedValue, :bolt_extended_value
10
+ #
11
+ # class BoltValue < FFI::Struct
12
+ # layout :type, :int16,
13
+ # :subtype, :int16,
14
+ # :size, :int16,
15
+ # :data_size, :uint64,
16
+ # :data, :bolt_data
17
+ # end
18
+ #
19
+ # class BoltData < FFI::Union
20
+ # layout :as_char, [:char, 16],
21
+ # :as_uint32, [:uint32, 4],
22
+ # :as_int8, [:int8_t, 16],
23
+ # :as_int16, [:int16, 8],
24
+ # :as_int32, [:int32, 4],
25
+ # :as_int64, [:int64, 2],
26
+ # :as_double, [:double, 2],
27
+ # :extended, :bolt_extended_value
28
+ # end
29
+
30
+ class BoltExtendedValue < FFI::Union
31
+ layout :as_ptr, :pointer,
32
+ :as_char, :string,
33
+ :as_value, :bolt_value
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Workaround for missing zeitwerk support in jruby-9.2.7.0
4
+ if RUBY_PLATFORM.match?(/java/)
5
+ module Bolt
6
+ end
7
+ module Neo4j
8
+ module Driver
9
+ module Internal
10
+ module Async
11
+ end
12
+ module Handlers
13
+ end
14
+ module Messaging
15
+ module V1
16
+ end
17
+ module V2
18
+ end
19
+ module V3
20
+ end
21
+ end
22
+ module Summary
23
+ end
24
+ module Util
25
+ end
26
+ module Value
27
+ end
28
+ end
29
+ module Summary
30
+ end
31
+ module Types
32
+ end
33
+ end
34
+ end
35
+ end
36
+ # End workaround
37
+
38
+ require 'active_support/concern'
39
+ require 'active_support/core_ext/array/grouping'
40
+ require 'concurrent/atomic/atomic_boolean'
41
+ require 'concurrent/atomic/atomic_reference'
42
+ require 'ffi'
43
+ require 'loader'
44
+ require 'recursive-open-struct'
45
+ Loader.load
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Neo4j
4
+ module Driver
5
+ module AccessMode
6
+ WRITE = 0
7
+ READ = 1
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Neo4j
4
+ module Driver
5
+ class AuthTokens
6
+ class << self
7
+ def basic(username, password)
8
+ Bolt::Auth.basic(username, password, nil)
9
+ end
10
+
11
+ def none
12
+ Bolt::Auth.none
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Neo4j
4
+ module Driver
5
+ class Config
6
+ class TrustStrategy
7
+ def self.trust_all_certificates; end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Neo4j
4
+ module Driver
5
+ class GraphDatabase
6
+ Bolt::Lifecycle.startup
7
+
8
+ at_exit do
9
+ Bolt::Lifecycle.shutdown
10
+ end
11
+
12
+ class << self
13
+ extend AutoClosable
14
+
15
+ auto_closable :driver
16
+
17
+ def driver(uri, auth_token = Neo4j::Driver::AuthTokens.none, config = {})
18
+ config ||= Config.default_config
19
+ # routing_settings = config.routing_settings
20
+ # retry_settings = config.retry_settings
21
+ routing_settings = nil
22
+ retry_settings = nil
23
+
24
+ Internal::DriverFactory.new.new_instance(uri, auth_token, routing_settings, retry_settings, config)
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Neo4j
4
+ module Driver
5
+ module Internal
6
+ module Async
7
+ class AccessModeConnection
8
+ attr_reader :connection, :mode
9
+ delegate :open?, :protocol, :release, :reset, :write_and_flush, to: :connection
10
+
11
+ def initialize(connection, mode)
12
+ @connection = connection
13
+ @mode = mode
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Neo4j
4
+ module Driver
5
+ module Internal
6
+ module Async
7
+ class DirectConnection
8
+ include ErrorHandling
9
+
10
+ attr_reader :protocol
11
+ attr_reader :bolt_connection
12
+
13
+ def initialize(connector, mode)
14
+ @connector = connector
15
+ @bolt_connection = with_status { |status| Bolt::Connector.acquire(@connector, mode, status) }
16
+
17
+ # @protocol = Messaging::BoltProtocol.for_version(Bolt::Connection.server(bolt_connection).first)
18
+ @protocol = Messaging::BoltProtocol.for_version(3)
19
+ @status = Concurrent::AtomicReference.new(:open)
20
+ end
21
+
22
+ def write_and_flush(statement, parameters, boomarks_holder, config, run_handler, pull_handler)
23
+ check_error Bolt::Connection.clear_run(bolt_connection)
24
+ check_error Bolt::Connection.set_run_cypher(bolt_connection, statement, statement.size, parameters.size)
25
+ parameters.each_with_index do |(name, object), index|
26
+ name = name.to_s
27
+ Value::ValueAdapter.to_neo(
28
+ Bolt::Connection.set_run_cypher_parameter(bolt_connection, index, name, name.size), object
29
+ )
30
+ end
31
+ set_bookmarks(:set_run_bookmarks, boomarks_holder.bookmarks)
32
+ register(run_handler, Bolt::Connection.load_run_request(bolt_connection))
33
+ register(pull_handler, Bolt::Connection.load_pull_request(bolt_connection, -1))
34
+ flush
35
+ end
36
+
37
+ def flush
38
+ check_error Bolt::Connection.flush(bolt_connection)
39
+ end
40
+
41
+ def begin(bookmarks, config, begin_handler)
42
+ check_error Bolt::Connection.clear_begin(bolt_connection)
43
+ set_bookmarks(:set_begin_bookmarks, bookmarks)
44
+ register(begin_handler, Bolt::Connection.load_begin_request(bolt_connection))
45
+ end
46
+
47
+ def commit(handler)
48
+ register(handler, Bolt::Connection.load_commit_request(bolt_connection))
49
+ flush
50
+ end
51
+
52
+ def rollback(handler)
53
+ register(handler, Bolt::Connection.load_rollback_request(bolt_connection))
54
+ flush
55
+ end
56
+
57
+ def release
58
+ return unless @status.compare_and_set(:open, :terminated)
59
+ Bolt::Connector.release(@connector, bolt_connection)
60
+ @bolt_connection = nil
61
+ end
62
+
63
+ def open?
64
+ @status.get == :open
65
+ end
66
+
67
+ def last_bookmark
68
+ Bolt::Connection.last_bookmark(bolt_connection).first
69
+ end
70
+
71
+ private
72
+
73
+ def register(handler, error_code)
74
+ check_error(error_code)
75
+ handler.request = Bolt::Connection.last_request(bolt_connection)
76
+ end
77
+
78
+ def set_bookmarks(method, bookmarks)
79
+ return unless bookmarks.present?
80
+ value = Bolt::Value.create
81
+ Value::ValueAdapter.to_neo(value, bookmarks)
82
+ check_error Bolt::Connection.send(method, bolt_connection, value)
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Neo4j
4
+ module Driver
5
+ module Internal
6
+ module BookmarksHolder
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ attr_reader :bookmarks
11
+ end
12
+
13
+ def initialize
14
+ @bookmarks = []
15
+ end
16
+
17
+ def bookmarks=(bookmarks)
18
+ bookmarks = Array(bookmarks).select(&:present?)
19
+ @bookmarks = bookmarks if bookmarks.present?
20
+ end
21
+
22
+ NO_OP = Class.new do
23
+ include BookmarksHolder
24
+
25
+ def bookmarks=; end
26
+ end.new
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Neo4j
4
+ module Driver
5
+ module Internal
6
+ class DirectConnectionProvider
7
+ include ErrorHandling
8
+
9
+ def initialize(connector)
10
+ @connector = connector
11
+ end
12
+
13
+ def acquire_connection(mode)
14
+ Async::DirectConnection.new(@connector, mode)
15
+ end
16
+
17
+ def verify_connectivity
18
+ acquire_connection(AccessMode::READ).release
19
+ end
20
+
21
+ def close
22
+ Bolt::Connector.destroy(@connector)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Neo4j
4
+ module Driver
5
+ module Internal
6
+ class DriverFactory
7
+ def new_instance(uri, auth_token, routing_settings, retry_settings, config)
8
+ connector = create_connector(uri, auth_token)
9
+ create_driver(uri, connector).tap(&:verify_connectivity)
10
+ end
11
+
12
+ private
13
+
14
+ def create_connector(uri, auth_token)
15
+ uri = URI(uri)
16
+ address = Bolt::Address.create(uri.host, uri.port.to_s)
17
+ config = Bolt::Config.create
18
+ Bolt::Config.set_user_agent(config, 'seabolt-cmake/1.7')
19
+ Bolt::Connector.create(address, auth_token, config)
20
+ end
21
+
22
+ def create_driver(uri, connector)
23
+ create_direct_driver(connector)
24
+ end
25
+
26
+ def create_direct_driver(connector)
27
+ connection_provider = DirectConnectionProvider.new(connector)
28
+ session_factory = create_session_factory(connection_provider)
29
+ InternalDriver.new(session_factory)
30
+ end
31
+
32
+ def create_session_factory(connection_provider, retry_logic = nil, config = nil)
33
+ SessionFactoryImpl.new(connection_provider, retry_logic, config)
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Neo4j
4
+ module Driver
5
+ module Internal
6
+ module ErrorHandling
7
+ def check_error(error_code, status = nil, error_text = nil)
8
+ case error_code
9
+ # Identifies a successful operation which is defined as 0
10
+ when Bolt::Error::BOLT_SUCCESS # 0
11
+ nil
12
+ # Permission denied
13
+ when Bolt::Error::BOLT_PERMISSION_DENIED # 7
14
+ failure Exceptions::AuthenticationException.new(error_code, 'Permission denied')
15
+ # Connection refused
16
+ when Bolt::Error::BOLT_CONNECTION_REFUSED
17
+ failure Exceptions::ServiceUnavailableException.new(error_code, 'unable to acquire connection')
18
+ else
19
+ error_ctx = status && Bolt::Status.get_error_context(status)
20
+ failure Exceptions::Neo4jException.new(
21
+ error_code,
22
+ "#{error_text || 'Unknown Bolt failure'} (code: #{error_code.to_s(16)}, " \
23
+ "text: #{Bolt::Error.get_string(error_code)}, context: #{error_ctx})"
24
+ )
25
+ end
26
+ end
27
+
28
+ def on_failure(_error); end
29
+
30
+ def check_status(status)
31
+ check_error(Bolt::Status.get_error(status), status)
32
+ end
33
+
34
+ def with_status
35
+ status = Bolt::Status.create
36
+ yield status
37
+ ensure
38
+ check_status(status)
39
+ end
40
+
41
+ private
42
+
43
+ def failure(error)
44
+ on_failure(error)
45
+ raise error
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end