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,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Neo4j
4
+ module Driver
5
+ module Internal
6
+ module Summary
7
+ class InternalSummaryCounters
8
+ def initialize(stats)
9
+ @stats = stats || RecursiveOpenStruct.new
10
+ end
11
+
12
+ def contains_updates?
13
+ @stats.to_h.values.any?(&:positive?)
14
+ end
15
+
16
+ def method_missing(method)
17
+ @stats.send(method) || 0
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Neo4j
4
+ module Driver
5
+ module Internal
6
+ module Util
7
+ class MetadataExtractor
8
+ def initialize(result_available_after_metadata_key, result_consumed_after_metadata_key); end
9
+
10
+ def extract_bookmarks(metadata); end
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Neo4j
4
+ module Driver
5
+ module Internal
6
+ module Value
7
+ module BaseTimeValue
8
+ NANO_FACTOR = 1_000_000_000
9
+
10
+ def time(nano_of_day_local, offset_seconds = nil)
11
+ min, sec = Rational(nano_of_day_local, NANO_FACTOR).divmod(60)
12
+ Time.new(0, 1, 1, *min.divmod(60), sec, offset_seconds)
13
+ end
14
+
15
+ def to_neo_values(local_time)
16
+ ((local_time.hour * 60 + local_time.min) * 60 + local_time.sec) * NANO_FACTOR + local_time.nsec
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Neo4j
4
+ module Driver
5
+ module Internal
6
+ module Value
7
+ module DateValue
8
+ CODE = :D
9
+ extend StructureValue
10
+ EPOCH = Date.parse('1970-01-01')
11
+
12
+ class << self
13
+ def to_ruby_value(epoch_day)
14
+ EPOCH + epoch_day
15
+ end
16
+
17
+ def to_neo_values(date)
18
+ (date - EPOCH).to_i
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Neo4j
4
+ module Driver
5
+ module Internal
6
+ module Value
7
+ module DurationValue
8
+ CODE = :E
9
+ extend StructureValue
10
+
11
+ class << self
12
+ def to_ruby_value(months, days, seconds, nanoseconds)
13
+ ActiveSupport::Duration.months(months) +
14
+ ActiveSupport::Duration.days(days) +
15
+ ActiveSupport::Duration.seconds(seconds) +
16
+ ActiveSupport::Duration.seconds(nanoseconds * BigDecimal('1e-9'))
17
+ end
18
+
19
+ def to_neo_values(object)
20
+ DurationNormalizer.normalize(object)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Neo4j
4
+ module Driver
5
+ module Internal
6
+ module Value
7
+ module LocalDateTimeValue
8
+ CODE = :d
9
+ extend StructureValue
10
+
11
+ class << self
12
+ def to_ruby_value(epoch_second_utc, nsec)
13
+ Types::LocalDateTime.new(Time.at(epoch_second_utc, nsec, :nsec).utc)
14
+ end
15
+
16
+ def to_neo_values(local_date_time)
17
+ [local_date_time.to_i, local_date_time.nsec]
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Neo4j
4
+ module Driver
5
+ module Internal
6
+ module Value
7
+ module LocalTimeValue
8
+ CODE = :t
9
+ extend StructureValue
10
+ extend BaseTimeValue
11
+
12
+ def self.to_ruby_value(nano_of_day_local)
13
+ Types::LocalTime.new(time(nano_of_day_local))
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Neo4j
4
+ module Driver
5
+ module Internal
6
+ module Value
7
+ module NodeValue
8
+ CODE = :N
9
+ extend StructureValue
10
+
11
+ def self.to_ruby_value(id, labels, properties)
12
+ Types::Node.new(id, labels, properties)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Neo4j
4
+ module Driver
5
+ module Internal
6
+ module Value
7
+ module OffsetTimeValue
8
+ CODE = :T
9
+ extend StructureValue
10
+ extend BaseTimeValue
11
+
12
+ class << self
13
+ def to_ruby_value(nano_of_day_local, offset_seconds)
14
+ Types::OffsetTime.new(time(nano_of_day_local, offset_seconds))
15
+ end
16
+
17
+ def to_neo_values(offset_time)
18
+ [super, offset_time.utc_offset]
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Neo4j
4
+ module Driver
5
+ module Internal
6
+ module Value
7
+ module PathValue
8
+ CODE = :P
9
+ extend StructureValue
10
+ class << self
11
+ def to_ruby_value(uniq_nodes, uniq_rels, sequence)
12
+ prev_node = uniq_nodes.first
13
+ nodes = [prev_node] # Start node is always 0, and isn't encoded in the sequence
14
+ rels = []
15
+ path = Types::Path.new(nodes, rels)
16
+ sequence.in_groups_of(2) do |node_idx, rel_idx|
17
+ node = uniq_nodes[node_idx]
18
+ nodes << node
19
+ rel = uniq_rels[rel_idx.abs - 1] # -1 because rel idx are 1-indexed
20
+ update(rel, prev_node, node, rel_idx.negative?)
21
+ rels << rel
22
+ path << Types::Path::Segment.new(prev_node, rel, node)
23
+ prev_node = node
24
+ end
25
+ path
26
+ end
27
+
28
+ private
29
+
30
+ def update(rel, prev_node, node, inversed)
31
+ # Negative rel index means this rel was traversed "inversed" from its direction
32
+ prev_node, node = node, prev_node if inversed
33
+ rel.start_node_id = prev_node.id
34
+ rel.end_node_id = node.id
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Neo4j
4
+ module Driver
5
+ module Internal
6
+ module Value
7
+ module Point2DValue
8
+ CODE = :X
9
+ extend StructureValue
10
+
11
+ class << self
12
+ def to_ruby_value(srid, x, y)
13
+ Types::Point.new(srid: srid, x: x, y: y)
14
+ end
15
+
16
+ def to_neo_values(point)
17
+ [point.srid.to_i, *point.coordinates]
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Neo4j
4
+ module Driver
5
+ module Internal
6
+ module Value
7
+ module Point3DValue
8
+ CODE = :Y
9
+ extend StructureValue
10
+
11
+ class << self
12
+ def to_ruby_value(srid, x, y, z)
13
+ Types::Point.new(srid: srid, x: x, y: y, z: z)
14
+ end
15
+
16
+ def to_neo_values(point)
17
+ [point.srid.to_i, *point.coordinates]
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Neo4j
4
+ module Driver
5
+ module Internal
6
+ module Value
7
+ module RelationshipValue
8
+ CODE = :R
9
+ extend StructureValue
10
+
11
+ def self.to_ruby_value(id, start_node_id, end_node_id, type, properties)
12
+ Types::Relationship.new(id, start_node_id, end_node_id, type, properties)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Neo4j
4
+ module Driver
5
+ module Internal
6
+ module Value
7
+ module StructureValue
8
+ def self.extended(mod)
9
+ code = mod.const_get('CODE').to_s.getbyte(0)
10
+ (@modules ||= {})[code] = mod
11
+ mod.define_singleton_method(:code) { code }
12
+ end
13
+
14
+ def self.to_ruby(value)
15
+ @modules[Bolt::Structure.code(value)]&.to_ruby_specific(value)
16
+ end
17
+
18
+ def to_ruby_specific(value)
19
+ to_ruby_value(*Array.new(size, &method(:ruby_value).curry.call(value)))
20
+ end
21
+
22
+ def to_neo(value, object)
23
+ Bolt::Value.format_as_structure(value, code, size)
24
+ Array(to_neo_values(object)).each_with_index do |elem, index|
25
+ ValueAdapter.to_neo(Bolt::Structure.value(value, index), elem)
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def ruby_value(value, index)
32
+ ValueAdapter.to_ruby(Bolt::Structure.value(value, index))
33
+ end
34
+
35
+ def size
36
+ @size ||= method(:to_ruby_value).arity
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Neo4j
4
+ module Driver
5
+ module Internal
6
+ module Value
7
+ module TimeWithZoneIdValue
8
+ CODE = :f
9
+ extend StructureValue
10
+
11
+ class << self
12
+ def to_ruby_value(epoch_second_local, nsec, zone_id_string)
13
+ time = Time.at(epoch_second_local, nsec, :nsec).in_time_zone(TZInfo::Timezone.get(zone_id_string))
14
+ time - time.utc_offset
15
+ end
16
+
17
+ def to_neo_values(time)
18
+ [time.to_i + time.utc_offset, time.nsec, time.time_zone.tzinfo.identifier]
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Neo4j
4
+ module Driver
5
+ module Internal
6
+ module Value
7
+ module TimeWithZoneOffsetValue
8
+ CODE = :F
9
+ extend StructureValue
10
+
11
+ class << self
12
+ def to_ruby_value(epoch_second_local, nsec, offset)
13
+ time = Time.at(epoch_second_local, nsec, :nsec).utc
14
+ Time.new(time.year, time.month, time.mday, time.hour, time.min, time.sec + Rational(nsec, 1_000_000_000),
15
+ offset)
16
+ # In ruby 2.6.x
17
+ # Time.at(sec, nsec, :nsec, tz: offset)
18
+ end
19
+
20
+ def to_neo_values(time)
21
+ [time.to_i + time.utc_offset, time.nsec, time.utc_offset]
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Neo4j
4
+ module Driver
5
+ module Internal
6
+ module Value
7
+ module UnboundRelationshipValue
8
+ CODE = :r
9
+ extend StructureValue
10
+
11
+ def self.to_ruby_value(id, type, properties)
12
+ Types::Relationship.new(id, nil, nil, type, properties)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Neo4j
4
+ module Driver
5
+ module Internal
6
+ module Value
7
+ module ValueAdapter
8
+ class << self
9
+ def to_ruby(value)
10
+ case Bolt::Value.type(value)
11
+ when :bolt_null
12
+ nil
13
+ when :bolt_boolean
14
+ Bolt::Boolean.get(value) == 1
15
+ when :bolt_integer
16
+ Bolt::Integer.get(value)
17
+ when :bolt_float
18
+ Bolt::Float.get(value)
19
+ when :bolt_bytes
20
+ Types::ByteArray.from_bytes(Array.new(Bolt::Value.size(value)) { |i| Bolt::Bytes.get(value, i) })
21
+ when :bolt_string
22
+ Bolt::String.get(value).read_string(Bolt::Value.size(value))
23
+ when :bolt_dictionary
24
+ Array.new(Bolt::Value.size(value)) do |i|
25
+ [to_ruby(Bolt::Dictionary.key(value, i)).to_sym, to_ruby(Bolt::Dictionary.value(value, i))]
26
+ end.to_h
27
+ when :bolt_list
28
+ Array.new(Bolt::Value.size(value)) { |i| to_ruby(Bolt::List.value(value, i)) }
29
+ when :bolt_structure
30
+ StructureValue.to_ruby(value)
31
+ else
32
+ raise Exception, 'unsupported neo4j type'
33
+ end
34
+ end
35
+
36
+ def to_neo(value, object)
37
+ case object
38
+ when nil
39
+ Bolt::Value.format_as_null(value)
40
+ when TrueClass
41
+ Bolt::Value.format_as_boolean(value, 1)
42
+ when FalseClass
43
+ Bolt::Value.format_as_boolean(value, 0)
44
+ when Integer
45
+ Bolt::Value.format_as_integer(value, object)
46
+ when Float
47
+ Bolt::Value.format_as_float(value, object)
48
+ when Types::ByteArray
49
+ Bolt::Value.format_as_bytes(value, object, object.size)
50
+ when String
51
+ Bolt::Value.format_as_string(value, object, object.size)
52
+ when Array
53
+ Bolt::Value.format_as_list(value, object.size)
54
+ object.each_with_index { |elem, index| to_neo(Bolt::List.value(value, index), elem) }
55
+ when Hash
56
+ Bolt::Value.format_as_dictionary(value, object.size)
57
+ object.each_with_index do |(key, elem), index|
58
+ key = key.to_s
59
+ Bolt::Dictionary.set_key(value, index, key, key.size)
60
+ to_neo(Bolt::Dictionary.value(value, index), elem)
61
+ end
62
+ when Date
63
+ DateValue.to_neo(value, object)
64
+ when ActiveSupport::Duration
65
+ DurationValue.to_neo(value, object)
66
+ when Neo4j::Driver::Types::Point
67
+ case object.coordinates.size
68
+ when 2
69
+ Point2DValue
70
+ when 3
71
+ Point3DValue
72
+ else
73
+ raise Exception
74
+ end&.to_neo(value, object)
75
+ when Types::OffsetTime
76
+ OffsetTimeValue.to_neo(value, object)
77
+ when Types::LocalTime
78
+ LocalTimeValue.to_neo(value, object)
79
+ when Types::LocalDateTime
80
+ LocalDateTimeValue.to_neo(value, object)
81
+ when ActiveSupport::TimeWithZone
82
+ TimeWithZoneIdValue.to_neo(value, object)
83
+ when Time
84
+ TimeWithZoneOffsetValue.to_neo(value, object)
85
+ else
86
+ raise Exception, 'unsupported ruby type'
87
+ end
88
+ value
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end