neo4j-ruby-driver 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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