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.
- checksums.yaml +4 -4
- data/README.md +113 -411
- data/lib/neo4j/driver/auth_token_manager.rb +29 -0
- data/lib/neo4j/driver/client_certificate_manager.rb +31 -0
- data/lib/neo4j/driver/exceptions/neo4j_exception.rb +16 -7
- data/lib/neo4j/driver/exceptions/no_such_record_exception.rb +1 -1
- data/lib/neo4j/driver/exceptions/protocol_exception.rb +0 -5
- data/lib/neo4j/driver/exceptions/security_retryable_exception.rb +14 -0
- data/lib/neo4j/driver/exceptions/transaction_terminated_exception.rb +13 -0
- data/lib/neo4j/driver/ext/auth_token.rb +17 -0
- data/{jruby → lib}/neo4j/driver/ext/auth_tokens.rb +5 -1
- data/lib/neo4j/driver/ext/bookmark_managers.rb +21 -0
- data/lib/neo4j/driver/ext/client_certificates.rb +21 -0
- data/{jruby → lib}/neo4j/driver/ext/config_converter.rb +36 -7
- data/{jruby → lib}/neo4j/driver/ext/exception_checkable.rb +3 -3
- data/lib/neo4j/driver/ext/exception_mapper.rb +173 -0
- data/lib/neo4j/driver/ext/graph_database.rb +25 -0
- data/lib/neo4j/driver/ext/internal/clock_adapter.rb +33 -0
- data/lib/neo4j/driver/ext/internal/cluster/routing_table_registry_impl.rb +28 -0
- data/lib/neo4j/driver/ext/internal/driver_factory.rb +54 -0
- data/lib/neo4j/driver/ext/internal/internal_notification_severity.rb +15 -0
- data/lib/neo4j/driver/ext/internal/reflection.rb +22 -0
- data/lib/neo4j/driver/ext/internal/summary/internal_gql_notification.rb +22 -0
- data/lib/neo4j/driver/ext/internal/summary/internal_gql_status_object.rb +18 -0
- data/{jruby → lib}/neo4j/driver/ext/internal/summary/internal_plan.rb +3 -5
- data/lib/neo4j/driver/ext/internal/summary/internal_query_profile.rb +36 -0
- data/lib/neo4j/driver/ext/internal/summary/internal_result_summary.rb +44 -0
- data/lib/neo4j/driver/ext/internal_driver.rb +102 -0
- data/{jruby → lib}/neo4j/driver/ext/internal_result.rb +2 -2
- data/{jruby → lib}/neo4j/driver/ext/internal_session.rb +5 -1
- data/lib/neo4j/driver/ext/logger.rb +55 -0
- data/lib/neo4j/driver/ext/map_converter.rb +13 -0
- data/lib/neo4j/driver/ext/neo_converter.rb +70 -0
- data/lib/neo4j/driver/ext/plain_map_converter.rb +11 -0
- data/{jruby → lib}/neo4j/driver/ext/ruby_converter.rb +20 -6
- data/lib/neo4j/driver/ext/unsupported_type.rb +14 -0
- data/lib/neo4j/driver/internal/deprecator.rb +9 -5
- data/lib/neo4j/driver/internal/duration_normalizer.rb +14 -39
- data/lib/neo4j/driver/internal/internal_auth_token_manager.rb +37 -0
- data/lib/neo4j/driver/internal/validator.rb +16 -2
- data/lib/neo4j/driver/summary/query_type.rb +5 -1
- data/lib/neo4j/driver/types/duration.rb +76 -0
- data/lib/neo4j/driver/types/local_date_time.rb +77 -8
- data/lib/neo4j/driver/types/local_time.rb +50 -7
- data/lib/neo4j/driver/types/offset_time.rb +78 -7
- data/lib/neo4j/driver/types/point.rb +38 -18
- data/lib/neo4j/driver/types/temporal_value.rb +44 -0
- data/lib/neo4j/driver/types/unresolvable_zoned_date_time.rb +38 -0
- data/{jruby → lib}/neo4j/driver/version.rb +1 -1
- data/{jruby → lib}/neo4j/driver.rb +31 -7
- data/lib/neo4j-ruby-driver_jars.rb +14 -0
- data/lib/neo4j-ruby-driver_loader.rb +34 -20
- data/lib/org/neo4j/driver/neo4j-java-driver-all/6.2.1/neo4j-java-driver-all-6.2.1.jar +0 -0
- data/lib/org/neo4j/driver/neo4j-java-driver-observation-metrics/6.2.1/neo4j-java-driver-observation-metrics-6.2.1.jar +0 -0
- data/lib/org/reactivestreams/reactive-streams/1.0.4/reactive-streams-1.0.4.jar +0 -0
- metadata +76 -226
- data/jruby/neo4j/driver/ext/async_converter.rb +0 -55
- data/jruby/neo4j/driver/ext/exception_mapper.rb +0 -92
- data/jruby/neo4j/driver/ext/graph_database.rb +0 -33
- data/jruby/neo4j/driver/ext/internal/async/internal_async_session.rb +0 -23
- data/jruby/neo4j/driver/ext/internal/cluster/routing_table_registry_impl.rb +0 -15
- data/jruby/neo4j/driver/ext/internal/cursor/disposable_async_result_cursor.rb +0 -15
- data/jruby/neo4j/driver/ext/internal/driver_factory.rb +0 -24
- data/jruby/neo4j/driver/ext/internal/summary/internal_result_summary.rb +0 -34
- data/jruby/neo4j/driver/ext/internal_driver.rb +0 -52
- data/jruby/neo4j/driver/ext/logger.rb +0 -60
- data/jruby/neo4j/driver/ext/map_converter.rb +0 -14
- data/jruby/neo4j/driver/ext/neo_converter.rb +0 -59
- data/lib/neo4j/driver/internal/bolt_server_address.rb +0 -97
- data/lib/neo4j/driver/synchronizable.rb +0 -23
- data/lib/neo4j/driver/types/time.rb +0 -45
- /data/{jruby → lib}/neo4j/driver/ext/internal/abstract_query_runner.rb +0 -0
- /data/{jruby → lib}/neo4j/driver/ext/internal/eager_result_value.rb +0 -0
- /data/{jruby → lib}/neo4j/driver/ext/internal/metrics/internal_connection_pool_metrics.rb +0 -0
- /data/{jruby → lib}/neo4j/driver/ext/internal/summary/internal_notification.rb +0 -0
- /data/{jruby → lib}/neo4j/driver/ext/internal_entity.rb +0 -0
- /data/{jruby → lib}/neo4j/driver/ext/internal_keys.rb +0 -0
- /data/{jruby → lib}/neo4j/driver/ext/internal_node.rb +0 -0
- /data/{jruby → lib}/neo4j/driver/ext/internal_record.rb +0 -0
- /data/{jruby → lib}/neo4j/driver/ext/internal_relationship.rb +0 -0
- /data/{jruby → lib}/neo4j/driver/ext/internal_transaction.rb +0 -0
- /data/{jruby → lib}/neo4j/driver/ext/query.rb +0 -0
- /data/{jruby → lib}/neo4j/driver/ext/run_override.rb +0 -0
- /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
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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
|
-
|
|
16
|
-
|
|
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
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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
|
-
|
|
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
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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
|
-
|
|
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
|
-
|
|
8
|
+
attr_reader :srid, :x, :y, :z
|
|
8
9
|
|
|
9
|
-
SRID
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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(
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
|
|
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
|
|
@@ -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.
|
|
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::
|
|
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
|
-
|
|
58
|
-
Java::
|
|
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
|