neo4j-ruby-driver 6.0.3.alpha.0-java → 6.2.1.beta.2-java

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 (84) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +113 -411
  3. data/lib/neo4j/driver/auth_token_manager.rb +29 -0
  4. data/lib/neo4j/driver/client_certificate_manager.rb +31 -0
  5. data/lib/neo4j/driver/exceptions/neo4j_exception.rb +16 -7
  6. data/lib/neo4j/driver/exceptions/no_such_record_exception.rb +1 -1
  7. data/lib/neo4j/driver/exceptions/protocol_exception.rb +0 -5
  8. data/lib/neo4j/driver/exceptions/security_retryable_exception.rb +14 -0
  9. data/lib/neo4j/driver/exceptions/transaction_terminated_exception.rb +13 -0
  10. data/lib/neo4j/driver/ext/auth_token.rb +17 -0
  11. data/{jruby → lib}/neo4j/driver/ext/auth_tokens.rb +5 -1
  12. data/lib/neo4j/driver/ext/bookmark_managers.rb +21 -0
  13. data/lib/neo4j/driver/ext/client_certificates.rb +21 -0
  14. data/{jruby → lib}/neo4j/driver/ext/config_converter.rb +36 -7
  15. data/{jruby → lib}/neo4j/driver/ext/exception_checkable.rb +3 -3
  16. data/lib/neo4j/driver/ext/exception_mapper.rb +173 -0
  17. data/lib/neo4j/driver/ext/graph_database.rb +25 -0
  18. data/lib/neo4j/driver/ext/internal/clock_adapter.rb +33 -0
  19. data/lib/neo4j/driver/ext/internal/cluster/routing_table_registry_impl.rb +28 -0
  20. data/lib/neo4j/driver/ext/internal/driver_factory.rb +54 -0
  21. data/lib/neo4j/driver/ext/internal/internal_notification_severity.rb +15 -0
  22. data/lib/neo4j/driver/ext/internal/reflection.rb +22 -0
  23. data/lib/neo4j/driver/ext/internal/summary/internal_gql_notification.rb +22 -0
  24. data/lib/neo4j/driver/ext/internal/summary/internal_gql_status_object.rb +18 -0
  25. data/{jruby → lib}/neo4j/driver/ext/internal/summary/internal_plan.rb +3 -5
  26. data/lib/neo4j/driver/ext/internal/summary/internal_query_profile.rb +36 -0
  27. data/lib/neo4j/driver/ext/internal/summary/internal_result_summary.rb +44 -0
  28. data/lib/neo4j/driver/ext/internal_driver.rb +102 -0
  29. data/{jruby → lib}/neo4j/driver/ext/internal_result.rb +2 -2
  30. data/{jruby → lib}/neo4j/driver/ext/internal_session.rb +5 -1
  31. data/lib/neo4j/driver/ext/logger.rb +55 -0
  32. data/lib/neo4j/driver/ext/map_converter.rb +13 -0
  33. data/lib/neo4j/driver/ext/neo_converter.rb +70 -0
  34. data/lib/neo4j/driver/ext/plain_map_converter.rb +11 -0
  35. data/{jruby → lib}/neo4j/driver/ext/ruby_converter.rb +20 -6
  36. data/lib/neo4j/driver/ext/unsupported_type.rb +14 -0
  37. data/lib/neo4j/driver/internal/deprecator.rb +9 -5
  38. data/lib/neo4j/driver/internal/duration_normalizer.rb +14 -39
  39. data/lib/neo4j/driver/internal/internal_auth_token_manager.rb +37 -0
  40. data/lib/neo4j/driver/internal/validator.rb +16 -2
  41. data/lib/neo4j/driver/summary/query_type.rb +5 -1
  42. data/lib/neo4j/driver/types/duration.rb +76 -0
  43. data/lib/neo4j/driver/types/local_date_time.rb +77 -8
  44. data/lib/neo4j/driver/types/local_time.rb +50 -7
  45. data/lib/neo4j/driver/types/offset_time.rb +78 -7
  46. data/lib/neo4j/driver/types/point.rb +38 -18
  47. data/lib/neo4j/driver/types/temporal_value.rb +44 -0
  48. data/lib/neo4j/driver/types/unresolvable_zoned_date_time.rb +38 -0
  49. data/{jruby → lib}/neo4j/driver/version.rb +1 -1
  50. data/{jruby → lib}/neo4j/driver.rb +31 -7
  51. data/lib/neo4j-ruby-driver_jars.rb +14 -0
  52. data/lib/neo4j-ruby-driver_loader.rb +34 -20
  53. data/lib/org/neo4j/driver/neo4j-java-driver-all/6.2.1/neo4j-java-driver-all-6.2.1.jar +0 -0
  54. data/lib/org/neo4j/driver/neo4j-java-driver-observation-metrics/6.2.1/neo4j-java-driver-observation-metrics-6.2.1.jar +0 -0
  55. data/lib/org/reactivestreams/reactive-streams/1.0.4/reactive-streams-1.0.4.jar +0 -0
  56. metadata +76 -226
  57. data/jruby/neo4j/driver/ext/async_converter.rb +0 -55
  58. data/jruby/neo4j/driver/ext/exception_mapper.rb +0 -92
  59. data/jruby/neo4j/driver/ext/graph_database.rb +0 -33
  60. data/jruby/neo4j/driver/ext/internal/async/internal_async_session.rb +0 -23
  61. data/jruby/neo4j/driver/ext/internal/cluster/routing_table_registry_impl.rb +0 -15
  62. data/jruby/neo4j/driver/ext/internal/cursor/disposable_async_result_cursor.rb +0 -15
  63. data/jruby/neo4j/driver/ext/internal/driver_factory.rb +0 -24
  64. data/jruby/neo4j/driver/ext/internal/summary/internal_result_summary.rb +0 -34
  65. data/jruby/neo4j/driver/ext/internal_driver.rb +0 -52
  66. data/jruby/neo4j/driver/ext/logger.rb +0 -60
  67. data/jruby/neo4j/driver/ext/map_converter.rb +0 -14
  68. data/jruby/neo4j/driver/ext/neo_converter.rb +0 -59
  69. data/lib/neo4j/driver/internal/bolt_server_address.rb +0 -97
  70. data/lib/neo4j/driver/synchronizable.rb +0 -23
  71. data/lib/neo4j/driver/types/time.rb +0 -45
  72. /data/{jruby → lib}/neo4j/driver/ext/internal/abstract_query_runner.rb +0 -0
  73. /data/{jruby → lib}/neo4j/driver/ext/internal/eager_result_value.rb +0 -0
  74. /data/{jruby → lib}/neo4j/driver/ext/internal/metrics/internal_connection_pool_metrics.rb +0 -0
  75. /data/{jruby → lib}/neo4j/driver/ext/internal/summary/internal_notification.rb +0 -0
  76. /data/{jruby → lib}/neo4j/driver/ext/internal_entity.rb +0 -0
  77. /data/{jruby → lib}/neo4j/driver/ext/internal_keys.rb +0 -0
  78. /data/{jruby → lib}/neo4j/driver/ext/internal_node.rb +0 -0
  79. /data/{jruby → lib}/neo4j/driver/ext/internal_record.rb +0 -0
  80. /data/{jruby → lib}/neo4j/driver/ext/internal_relationship.rb +0 -0
  81. /data/{jruby → lib}/neo4j/driver/ext/internal_transaction.rb +0 -0
  82. /data/{jruby → lib}/neo4j/driver/ext/query.rb +0 -0
  83. /data/{jruby → lib}/neo4j/driver/ext/run_override.rb +0 -0
  84. /data/{jruby → lib}/neo4j/driver/ext/start_end_naming.rb +0 -0
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Neo4j
4
+ module Driver
5
+ module Types
6
+ # Bolt Duration. Stores months, days, seconds, nanoseconds as
7
+ # distinct ints — Neo4j keeps these separate because months are
8
+ # variable-length (no fixed conversion to seconds).
9
+ class Duration < TemporalValue
10
+ attr_reader :months, :days, :seconds, :nanoseconds
11
+
12
+ def self.significant_fields = %i[months days seconds nanoseconds]
13
+
14
+ def initialize(months, days, seconds, nanoseconds)
15
+ @months = months.to_i
16
+ @days = days.to_i
17
+ @seconds = seconds.to_i
18
+ @nanoseconds = nanoseconds.to_i
19
+ normalize!
20
+ end
21
+
22
+ # Parse ISO 8601 duration: "P1Y2M3DT4H5M6.789S", "P3M", "PT2H30M"
23
+ def self.parse(string)
24
+ unless string =~ /^P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+(?:\.\d+)?)S)?)?$/
25
+ raise ArgumentError, "Invalid ISO 8601 duration format: #{string}"
26
+ end
27
+
28
+ years = (::Regexp.last_match(1) || 0).to_i
29
+ months = (::Regexp.last_match(2) || 0).to_i
30
+ days = (::Regexp.last_match(3) || 0).to_i
31
+ hours = (::Regexp.last_match(4) || 0).to_i
32
+ minutes = (::Regexp.last_match(5) || 0).to_i
33
+ seconds_with_fraction = (::Regexp.last_match(6) || 0).to_f
34
+
35
+ total_months = years * 12 + months
36
+ whole_seconds = seconds_with_fraction.to_i
37
+ fractional_seconds = seconds_with_fraction - whole_seconds
38
+ nanos = (fractional_seconds * NANOS_PER_SECOND).round
39
+ total_seconds = hours * 3600 + minutes * 60 + whole_seconds
40
+
41
+ new(total_months, days, total_seconds, nanos)
42
+ end
43
+
44
+ def parts
45
+ { months: @months, days: @days, seconds: @seconds, nanoseconds: @nanoseconds }
46
+ end
47
+
48
+ # ISO 8601 form. Nanoseconds get a 9-digit zero-padded suffix on
49
+ # seconds so 1s + 5ns prints as "PT1.000000005S", not "PT1.5S".
50
+ def to_s
51
+ if @nanoseconds.zero?
52
+ format('P%dM%dDT%dS', @months, @days, @seconds)
53
+ else
54
+ format('P%dM%dDT%d.%09dS', @months, @days, @seconds, @nanoseconds)
55
+ end
56
+ end
57
+
58
+ private
59
+
60
+ # Normalize nanoseconds overflow/underflow into seconds:
61
+ # -1ns becomes -1s + 999999999ns; 1.5e9 ns becomes 1s + 5e8 ns.
62
+ def normalize!
63
+ if @nanoseconds < 0
64
+ sec_adjust = (@nanoseconds.abs / NANOS_PER_SECOND.to_f).ceil
65
+ @seconds -= sec_adjust
66
+ @nanoseconds += sec_adjust * NANOS_PER_SECOND
67
+ elsif @nanoseconds >= NANOS_PER_SECOND
68
+ sec_adjust = @nanoseconds / NANOS_PER_SECOND
69
+ @seconds += sec_adjust
70
+ @nanoseconds %= NANOS_PER_SECOND
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -3,17 +3,86 @@
3
3
  module Neo4j
4
4
  module Driver
5
5
  module Types
6
- class LocalDateTime < Time
7
- class << self
8
- FIELDS = %i[year month day hour min sec nsec].freeze
6
+ # Bolt LocalDateTime a wall-clock datetime with no timezone
7
+ # (java.time.LocalDateTime). Stored as the wire-format pair
8
+ # (epoch_seconds, nanoseconds), where epoch_seconds encodes the
9
+ # wall-clock components as if they were UTC — so the value reads the
10
+ # same regardless of the host TZ.
11
+ #
12
+ # There is deliberately no #to_time: a zone-less value cannot become a
13
+ # zoned Ruby Time without inventing a zone, and every serious datetime
14
+ # library refuses that implicit conversion (Java's LocalDateTime forces
15
+ # .atZone/.atOffset; Python yields a naive datetime). Read the fields via
16
+ # the component getters instead.
17
+ class LocalDateTime < TemporalValue
18
+ PARSE_FORMATS = [
19
+ '%Y-%m-%d %H:%M:%S.%N',
20
+ '%Y-%m-%dT%H:%M:%S.%N',
21
+ '%Y-%m-%d %H:%M:%S',
22
+ '%Y-%m-%dT%H:%M:%S',
23
+ '%Y-%m-%d %H:%M'
24
+ ].freeze
9
25
 
10
- def significant_fields
11
- FIELDS
12
- end
26
+ attr_reader :epoch_seconds, :nanoseconds
27
+
28
+ def self.significant_fields = %i[epoch_seconds nanoseconds]
29
+
30
+ def initialize(epoch_seconds, nanoseconds)
31
+ @epoch_seconds = epoch_seconds
32
+ @nanoseconds = nanoseconds
33
+ end
34
+
35
+ def self.from_epoch(epoch_seconds, nanoseconds) = new(epoch_seconds, nanoseconds)
36
+
37
+ # Store the Time's wall clock (its date and time-of-day *in its own
38
+ # zone*), dropping the zone. We read that wall clock off the instant
39
+ # using the offset the Time already carries — we never invent a zone,
40
+ # so from_time(t) and from_time(t.utc) differ (they show different
41
+ # clocks). epoch_seconds encodes it as-if-UTC per the class contract.
42
+ def self.from_time(time)
43
+ new(time.to_i + time.utc_offset, time.nsec)
44
+ end
45
+
46
+ def self.parse(string)
47
+ # Strip trailing timezone if present — naive datetime ignores it.
48
+ naive = string.sub(/[Z+-]\d{2}:?\d{2}?$/, '')
49
+ time = PARSE_FORMATS.lazy.filter_map do |fmt|
50
+ ::Time.strptime(naive, fmt)
51
+ rescue StandardError
52
+ nil
53
+ end.first
54
+ raise ArgumentError, "Invalid LocalDateTime format: #{string}" unless time
55
+
56
+ from_time(time)
13
57
  end
14
58
 
15
- delegate(*significant_fields, to: :@time)
16
- delegate :to_i, to: :@time
59
+ def year = wall_clock.year
60
+ def month = wall_clock.month
61
+ def day = wall_clock.day
62
+ def hour = wall_clock.hour
63
+ def minute = wall_clock.min
64
+ def second = wall_clock.sec
65
+ def nanosecond = @nanoseconds
66
+
67
+ # Add a numeric or ActiveSupport::Duration. A wall clock has no DST,
68
+ # so this is plain second arithmetic; sub-second precision preserved.
69
+ def +(other)
70
+ total = (@epoch_seconds * NANOS_PER_SECOND) + @nanoseconds +
71
+ (other.to_f * NANOS_PER_SECOND).round
72
+ self.class.new(total / NANOS_PER_SECOND, total % NANOS_PER_SECOND)
73
+ end
74
+
75
+ def to_s
76
+ wall_clock.strftime('%Y-%m-%d %H:%M:%S.%N')
77
+ end
78
+
79
+ private
80
+
81
+ # epoch_seconds read back as its wall clock. UTC by construction, so
82
+ # the components never depend on the host TZ.
83
+ def wall_clock
84
+ ::Time.at(@epoch_seconds, @nanoseconds.to_i, :nanosecond, in: 'UTC')
85
+ end
17
86
  end
18
87
  end
19
88
  end
@@ -3,16 +3,59 @@
3
3
  module Neo4j
4
4
  module Driver
5
5
  module Types
6
- class LocalTime < Time
7
- class << self
8
- FIELDS = %i[hour min sec nsec].freeze
6
+ # Bolt LocalTime time of day without timezone, stored as
7
+ # nanoseconds since midnight.
8
+ class LocalTime < TemporalValue
9
+ attr_reader :nanoseconds
9
10
 
10
- def significant_fields
11
- FIELDS
12
- end
11
+ def self.significant_fields = %i[nanoseconds]
12
+
13
+ def initialize(nanoseconds)
14
+ @nanoseconds = nanoseconds % NANOS_PER_DAY
15
+ end
16
+
17
+ def self.from_nanos(nanoseconds) = new(nanoseconds)
18
+
19
+ # Build from a Ruby Time, taking its displayed wall clock (so the
20
+ # host zone / .utc of the Time decides which time-of-day is captured).
21
+ # Mirrors LocalDateTime.from_time.
22
+ def self.from_time(time)
23
+ new(time.hour * NANOS_PER_HOUR + time.min * NANOS_PER_MINUTE +
24
+ time.sec * NANOS_PER_SECOND + time.nsec)
25
+ end
26
+
27
+ # Accepts "12:34:56.123456789" or any string containing such a
28
+ # time component (so a full datetime works too — we just take the
29
+ # time fields).
30
+ def self.parse(string)
31
+ match = string.match(/(\d{1,2}):(\d{2})(?::(\d{2})(?:\.(\d+))?)?/)
32
+ raise ArgumentError, "Invalid LocalTime format: #{string}" unless match
33
+
34
+ new(parse_nanos(match[1].to_i, match[2].to_i, (match[3] || 0).to_i, match[4] || '0'))
13
35
  end
14
36
 
15
- delegate(*significant_fields, to: :@time)
37
+ def self.parse_nanos(hour, minute, second, fraction)
38
+ hour * NANOS_PER_HOUR +
39
+ minute * NANOS_PER_MINUTE +
40
+ second * NANOS_PER_SECOND +
41
+ fraction.ljust(9, '0')[0..8].to_i
42
+ end
43
+ private_class_method :parse_nanos
44
+
45
+ def hour = (@nanoseconds / NANOS_PER_HOUR) % 24
46
+ def minute = (@nanoseconds / NANOS_PER_MINUTE) % 60
47
+ def second = (@nanoseconds / NANOS_PER_SECOND) % 60
48
+ def nanosecond = @nanoseconds % NANOS_PER_SECOND
49
+
50
+ # Add a numeric or ActiveSupport::Duration. Sub-second precision
51
+ # preserved by going through to_f (NOT to_i, which dropped 0.5s).
52
+ def +(other)
53
+ self.class.new(@nanoseconds + (other.to_f * NANOS_PER_SECOND).round)
54
+ end
55
+
56
+ def to_s
57
+ format('%02d:%02d:%02d.%09d', hour, minute, second, nanosecond)
58
+ end
16
59
  end
17
60
  end
18
61
  end
@@ -3,16 +3,87 @@
3
3
  module Neo4j
4
4
  module Driver
5
5
  module Types
6
- class OffsetTime < Time
7
- class << self
8
- FIELDS = %i[hour min sec nsec utc_offset].freeze
6
+ # Bolt OffsetTime time of day with a fixed UTC offset, stored as
7
+ # nanoseconds-since-midnight (in local wall clock) plus offset
8
+ # seconds. Equivalent to java.time.OffsetTime. Was previously
9
+ # called Types::Time, which collided cosmetically with ::Time.
10
+ class OffsetTime < TemporalValue
11
+ attr_reader :nanoseconds, :tz_offset_seconds
9
12
 
10
- def significant_fields
11
- FIELDS
12
- end
13
+ def self.significant_fields = %i[nanoseconds tz_offset_seconds]
14
+
15
+ def initialize(nanoseconds, tz_offset_seconds)
16
+ @nanoseconds = nanoseconds % NANOS_PER_DAY
17
+ @tz_offset_seconds = tz_offset_seconds
18
+ end
19
+
20
+ def self.from_nanos(nanoseconds, tz_offset_seconds) = new(nanoseconds, tz_offset_seconds)
21
+
22
+ # Build from a Ruby Time — its wall clock plus its UTC offset.
23
+ # Reuses LocalTime's field extraction. Mirrors LocalDateTime.from_time.
24
+ def self.from_time(time)
25
+ new(LocalTime.from_time(time).nanoseconds, time.utc_offset)
26
+ end
27
+
28
+ # Accepts "12:34:56.123456789+01:00", "12:34:56Z", or any string
29
+ # containing such a time-with-offset component.
30
+ def self.parse(string)
31
+ match = string.match(/(\d{1,2}):(\d{2})(?::(\d{2})(?:\.(\d+))?)?([Z+-][\d:]*)?/)
32
+ raise ArgumentError, "Invalid OffsetTime format: #{string}" unless match
33
+
34
+ nanos = LocalTime.send(:parse_nanos,
35
+ match[1].to_i, match[2].to_i, (match[3] || 0).to_i, match[4] || '0')
36
+ new(nanos, parse_offset(match[5] || 'Z'))
37
+ end
38
+
39
+ def self.parse_offset(str)
40
+ return 0 if str == 'Z'
41
+ raise ArgumentError, "Invalid timezone offset: #{str}" unless str =~ /^([+-])(\d{2}):?(\d{2})?$/
42
+
43
+ sign = ::Regexp.last_match(1) == '+' ? 1 : -1
44
+ sign * (::Regexp.last_match(2).to_i * 3600 + (::Regexp.last_match(3) || 0).to_i * 60)
13
45
  end
46
+ private_class_method :parse_offset
14
47
 
15
- delegate(*significant_fields, to: :@time)
48
+ def hour = (@nanoseconds / NANOS_PER_HOUR) % 24
49
+ def minute = (@nanoseconds / NANOS_PER_MINUTE) % 60
50
+ def second = (@nanoseconds / NANOS_PER_SECOND) % 60
51
+ def nanosecond = @nanoseconds % NANOS_PER_SECOND
52
+
53
+ # Add a numeric or ActiveSupport::Duration. Sub-second precision
54
+ # preserved (see LocalTime#+).
55
+ def +(other)
56
+ self.class.new(@nanoseconds + (other.to_f * NANOS_PER_SECOND).round, @tz_offset_seconds)
57
+ end
58
+
59
+ def to_s
60
+ # Apply the sign to the formatted offset as a whole, not to
61
+ # `hours` alone — Ruby integer division for `-12600 / 3600` is
62
+ # -4 (floor toward -∞), which would render -03:30 as -04:30.
63
+ abs = @tz_offset_seconds.abs
64
+ sign = @tz_offset_seconds.negative? ? '-' : '+'
65
+ format('%02d:%02d:%02d.%09d%s%02d:%02d',
66
+ hour, minute, second, nanosecond,
67
+ sign, abs / 3600, (abs % 3600) / 60)
68
+ end
69
+
70
+ # Order by underlying UTC instant. Two OffsetTimes representing
71
+ # the same UTC instant in different offsets compare equal under
72
+ # <=>; == still requires same fields (they're not the same value).
73
+ def <=>(other)
74
+ return nil unless other.is_a?(OffsetTime)
75
+
76
+ utc_nanos <=> other.utc_nanos
77
+ end
78
+
79
+ protected
80
+
81
+ # UTC = local − offset. Positive offset means "ahead of UTC", so
82
+ # the UTC instant is *earlier* (smaller nanos). The previous
83
+ # implementation added instead of subtracting, inverting ordering.
84
+ def utc_nanos
85
+ @nanoseconds - (@tz_offset_seconds * NANOS_PER_SECOND)
86
+ end
16
87
  end
17
88
  end
18
89
  end
@@ -3,36 +3,56 @@
3
3
  module Neo4j
4
4
  module Driver
5
5
  module Types
6
+ # Point (2D or 3D)
6
7
  class Point
7
- attr_accessor :srid, :x, :y, :z
8
+ attr_reader :srid, :x, :y, :z
8
9
 
9
- SRID = {
10
- 'WGS-84': 4326,
11
- 'WGS-84-3D': 4979,
12
- cartesian: 7203,
13
- 'cartesian-3D': 9157
14
- }.with_indifferent_access.freeze
10
+ # SRID constants for coordinate reference systems
11
+ WGS_84_2D = 4326 # Geographic 2D (longitude, latitude)
12
+ WGS_84_3D = 4979 # Geographic 3D (longitude, latitude, height)
13
+ CARTESIAN_2D = 7203 # Cartesian 2D (x, y)
14
+ CARTESIAN_3D = 9157 # Cartesian 3D (x, y, z)
15
15
 
16
- def initialize(args)
17
- self.x = args[:longitude] || args[:x]
18
- self.y = args[:latitude] || args[:y]
19
- self.z = args[:height] || args[:z]
20
- self.srid = args[:srid] || SRID[args[:crs] || implied_crs(args[:longitude] || args[:latitude])]
16
+ def initialize(srid: nil, x: nil, y: nil, z: nil, longitude: nil, latitude: nil, height: nil)
17
+ # Handle longitude/latitude aliases for x/y
18
+ if longitude || latitude
19
+ @x = (longitude || x).to_f
20
+ @y = (latitude || y).to_f
21
+ @z = (height || z)&.to_f
22
+ # Use WGS-84 SRID for geographic coordinates
23
+ @srid = srid || (@z ? WGS_84_3D : WGS_84_2D)
24
+ else
25
+ @x = x.to_f
26
+ @y = y.to_f
27
+ @z = z&.to_f
28
+ # Use Cartesian SRID for x/y/z coordinates
29
+ @srid = srid || (@z ? CARTESIAN_3D : CARTESIAN_2D)
30
+ end
31
+ end
32
+
33
+ def dimension
34
+ @z.nil? ? 2 : 3
21
35
  end
22
36
 
23
37
  def coordinates
24
38
  [x, y, z].compact.map(&:to_f)
25
39
  end
26
40
 
27
- private
28
-
29
- def implied_crs(geo)
30
- if geo
31
- z ? :'WGS-84-3D' : :'WGS-84'
41
+ def to_s
42
+ if @z
43
+ "Point{srid=#{@srid}, x=#{@x}, y=#{@y}, z=#{@z}}"
32
44
  else
33
- z ? :'cartesian-3D' : :cartesian
45
+ "Point{srid=#{@srid}, x=#{@x}, y=#{@y}}"
34
46
  end
35
47
  end
48
+
49
+ def ==(other)
50
+ other.is_a?(Point) &&
51
+ other.srid == @srid &&
52
+ (other.x - @x).abs < 0.00001 &&
53
+ (other.y - @y).abs < 0.00001 &&
54
+ (@z.nil? || (other.z - @z).abs < 0.00001)
55
+ end
36
56
  end
37
57
  end
38
58
  end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Neo4j
4
+ module Driver
5
+ module Types
6
+ # Shared base for the Bolt temporal value types: Duration,
7
+ # LocalDateTime, LocalTime, OffsetTime. Each subclass declares its
8
+ # `significant_fields` and gets `<=>`, `==`, `eql?`, `hash` derived
9
+ # from them automatically. Comparable mixed in here gives `<`, `>`,
10
+ # `between?`, `clamp` etc. for free.
11
+ class TemporalValue
12
+ include Comparable
13
+
14
+ NANOS_PER_SECOND = 1_000_000_000
15
+ NANOS_PER_MINUTE = 60 * NANOS_PER_SECOND
16
+ NANOS_PER_HOUR = 60 * NANOS_PER_MINUTE
17
+ NANOS_PER_DAY = 24 * NANOS_PER_HOUR
18
+
19
+ def self.significant_fields
20
+ raise NotImplementedError, "#{self} must define .significant_fields"
21
+ end
22
+
23
+ def significant
24
+ self.class.significant_fields.map { send(it) }
25
+ end
26
+
27
+ def <=>(other)
28
+ return nil unless other.is_a?(self.class)
29
+
30
+ significant <=> other.significant
31
+ end
32
+
33
+ def ==(other)
34
+ other.is_a?(self.class) && significant == other.significant
35
+ end
36
+ alias eql? ==
37
+
38
+ def hash
39
+ significant.hash
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Neo4j
4
+ module Driver
5
+ module Types
6
+ # A ZonedDateTime the driver received with a zone id its runtime's time
7
+ # zone database can't resolve (e.g. the server sent "Europe/Neo4j").
8
+ #
9
+ # Hydration can't build a real Time, but raising mid-record on the reader
10
+ # thread would break the connection and strand the whole result — so the
11
+ # failure is deferred into this placeholder. Any consumer that tries to
12
+ # interpret the value raises (naming the zone), matching the Java driver,
13
+ # while the record and connection stay intact so an open transaction can
14
+ # still roll back cleanly.
15
+ class UnresolvableZonedDateTime
16
+ attr_reader :zone_name
17
+
18
+ def initialize(zone_name)
19
+ @zone_name = zone_name
20
+ end
21
+
22
+ # The driver error this value stands in for. Raised by any consumer
23
+ # that tries to use it (the testkit backend on serialize; a public-API
24
+ # caller via #value).
25
+ def error
26
+ Exceptions::ClientException.new(
27
+ "The server returned a ZonedDateTime with a zone id (#{@zone_name.inspect}) " \
28
+ "that this runtime's time zone database does not recognise"
29
+ )
30
+ end
31
+
32
+ def value
33
+ raise error
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Neo4j
4
4
  module Driver
5
- VERSION = '6.0.3.alpha.0'
5
+ VERSION = '6.2.1.beta.2'
6
6
  end
7
7
  end
@@ -1,12 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'active_support/core_ext/hash/keys'
4
3
  require 'neo4j-ruby-driver_jars'
5
4
  require 'neo4j-ruby-driver_loader'
6
5
 
7
6
  module Neo4j
8
7
  module Driver
9
- Loader.load
8
+ Loader.load(:jruby) do |loader|
9
+ impl_root = File.expand_path('..', __dir__)
10
+ loader.ignore(File.expand_path('org', impl_root))
11
+ loader.ignore(File.expand_path('neo4j-ruby-driver_jars.rb', impl_root))
12
+ end
10
13
 
11
14
  include_package 'org.neo4j.driver'
12
15
 
@@ -17,6 +20,11 @@ module Neo4j
17
20
 
18
21
  module Internal
19
22
  java_import org.neo4j.driver.internal.shaded.bolt.connection.DatabaseName
23
+ java_import org.neo4j.driver.internal.DriverFactory
24
+
25
+ module Security
26
+ java_import org.neo4j.driver.internal.security.StaticAuthTokenManager
27
+ end
20
28
  end
21
29
 
22
30
  module Net
@@ -25,6 +33,7 @@ module Neo4j
25
33
 
26
34
  module Summary
27
35
  include_package 'org.neo4j.driver.summary'
36
+ GqlNotification = Java::OrgNeo4jDriverInternalSummary::InternalGqlNotification
28
37
  end
29
38
 
30
39
  module Types
@@ -32,31 +41,46 @@ module Neo4j
32
41
  Node = Java::OrgNeo4jDriverInternal::InternalNode
33
42
  Path = Java::OrgNeo4jDriverInternal::InternalPath
34
43
  Relationship = Java::OrgNeo4jDriverInternal::InternalRelationship
44
+ # Bolt 6.0 forward-compat marker. Aliasing the Java type here lets the
45
+ # testkit backend match it with the same `Neo4j::Driver::Types::
46
+ # UnsupportedType` case MRI uses (which has its own pure-Ruby class).
47
+ UnsupportedType = Java::OrgNeo4jDriverTypes::UnsupportedType
48
+ # Bolt 6.1 UUID. Native java.util.UUID (immutable, value-equal,
49
+ # fromString) — MRI has its own opaque Types::UUID with the same
50
+ # from_string / to_s surface.
51
+ UUID = Java::JavaUtil::UUID
35
52
  end
36
53
  end
37
54
  end
38
55
 
56
+ Java::JavaUtil::Map.include Neo4j::Driver::Ext::PlainMapConverter
39
57
  Java::OrgNeo4jDriver::AuthTokens.singleton_class.prepend Neo4j::Driver::Ext::AuthTokens
58
+ Java::OrgNeo4jDriver::BookmarkManagers.singleton_class.prepend Neo4j::Driver::Ext::BookmarkManagers
59
+ Java::OrgNeo4jDriver::ClientCertificates.singleton_class.prepend Neo4j::Driver::Ext::ClientCertificates
40
60
  Java::OrgNeo4jDriver::GraphDatabase.singleton_class.prepend Neo4j::Driver::Ext::GraphDatabase
41
61
  Java::OrgNeo4jDriver::Query.prepend Neo4j::Driver::Ext::Query
62
+ Java::OrgNeo4jDriverInternal::DelegatingTransactionContext.prepend Neo4j::Driver::Ext::Internal::AbstractQueryRunner
63
+ Java::OrgNeo4jDriverInternal::DriverFactory.prepend Neo4j::Driver::Ext::Internal::DriverFactory
42
64
  Java::OrgNeo4jDriverInternal::EagerResultValue.prepend Neo4j::Driver::Ext::Internal::EagerResultValue
43
65
  Java::OrgNeo4jDriverInternal::InternalDriver.prepend Neo4j::Driver::Ext::InternalDriver
44
66
  Java::OrgNeo4jDriverInternal::InternalEntity.include Neo4j::Driver::Ext::InternalEntity
45
67
  Java::OrgNeo4jDriverInternal::InternalNode.prepend Neo4j::Driver::Ext::InternalNode
46
- Java::OrgNeo4jDriverInternal::InternalNotificationSeverity.delegate :name, to: :type
68
+ Java::OrgNeo4jDriverInternal::InternalNotificationSeverity.include Neo4j::Driver::Ext::Internal::InternalNotificationSeverity
47
69
  Java::OrgNeo4jDriverInternal::InternalPath.include Neo4j::Driver::Ext::StartEndNaming
48
70
  Java::OrgNeo4jDriverInternal::InternalPath::SelfContainedSegment.include Neo4j::Driver::Ext::StartEndNaming
49
71
  Java::OrgNeo4jDriverInternal::InternalRecord.prepend Neo4j::Driver::Ext::InternalRecord
50
72
  Java::OrgNeo4jDriverInternal::InternalRelationship.prepend Neo4j::Driver::Ext::InternalRelationship
73
+ Java::OrgNeo4jDriverInternal::InternalUnsupportedType.prepend Neo4j::Driver::Ext::UnsupportedType
51
74
  Java::OrgNeo4jDriverInternal::InternalResult.prepend Neo4j::Driver::Ext::InternalResult
52
75
  Java::OrgNeo4jDriverInternal::InternalSession.prepend Neo4j::Driver::Ext::InternalSession
53
76
  Java::OrgNeo4jDriverInternal::InternalTransaction.prepend Neo4j::Driver::Ext::InternalTransaction
54
- Java::OrgNeo4jDriverInternal::DelegatingTransactionContext.prepend Neo4j::Driver::Ext::Internal::AbstractQueryRunner
55
- Java::OrgNeo4jDriverInternalAsync::InternalAsyncSession.prepend Neo4j::Driver::Ext::Internal::Async::InternalAsyncSession
77
+ Java::OrgNeo4jDriverInternalSecurity::InternalAuthToken.include Neo4j::Driver::Ext::AuthToken
56
78
  Java::OrgNeo4jDriverInternalShadedBoltConnectionRoutedImplCluster::RoutingTableRegistryImpl.include Neo4j::Driver::Ext::Internal::Cluster::RoutingTableRegistryImpl
57
- # Java::OrgNeo4jDriverInternalCursor::DisposableAsyncResultCursor.prepend Neo4j::Driver::Ext::Internal::Cursor::DisposableAsyncResultCursor
58
- Java::OrgNeo4jDriverObservationMetricsInternal::InternalConnectionPoolMetrics.include Neo4j::Driver::Ext::Internal::Metrics::InternalConnectionPoolMetrics
79
+ Java::OrgNeo4jDriverInternalSummary::InternalGqlNotification.prepend Neo4j::Driver::Ext::Internal::Summary::InternalGqlNotification
80
+ Java::OrgNeo4jDriverInternalSummary::InternalGqlStatusObject.prepend Neo4j::Driver::Ext::Internal::Summary::InternalGqlStatusObject
59
81
  Java::OrgNeo4jDriverInternalSummary::InternalNotification.prepend Neo4j::Driver::Ext::Internal::Summary::InternalNotification
60
82
  Java::OrgNeo4jDriverInternalSummary::InternalPlan.prepend Neo4j::Driver::Ext::Internal::Summary::InternalPlan
83
+ Java::OrgNeo4jDriverInternalSummary::InternalQueryProfile.prepend Neo4j::Driver::Ext::Internal::Summary::InternalQueryProfile
61
84
  Java::OrgNeo4jDriverInternalSummary::InternalResultSummary.prepend Neo4j::Driver::Ext::Internal::Summary::InternalResultSummary
62
85
  Java::OrgNeo4jDriverInternalValue::ValueAdapter.include Neo4j::Driver::Ext::RubyConverter
86
+ Java::OrgNeo4jDriverObservationMetricsInternal::InternalConnectionPoolMetrics.include Neo4j::Driver::Ext::Internal::Metrics::InternalConnectionPoolMetrics
@@ -0,0 +1,14 @@
1
+ # this is a generated file, to avoid over-writing it just delete this comment
2
+ begin
3
+ require 'jar_dependencies'
4
+ rescue LoadError
5
+ require 'org/neo4j/driver/neo4j-java-driver-all/6.2.1/neo4j-java-driver-all-6.2.1.jar'
6
+ require 'org/reactivestreams/reactive-streams/1.0.4/reactive-streams-1.0.4.jar'
7
+ require 'org/neo4j/driver/neo4j-java-driver-observation-metrics/6.2.1/neo4j-java-driver-observation-metrics-6.2.1.jar'
8
+ end
9
+
10
+ if defined? Jars
11
+ require_jar 'org.neo4j.driver', 'neo4j-java-driver-all', '6.2.1'
12
+ require_jar 'org.reactivestreams', 'reactive-streams', '1.0.4'
13
+ require_jar 'org.neo4j.driver', 'neo4j-java-driver-observation-metrics', '6.2.1'
14
+ end