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,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