diff --git a/ruby/neo4j/driver/internal/messaging/v5/bolt_protocol_v5.rb b/ruby/neo4j/driver/internal/messaging/v5/bolt_protocol_v5.rb new file mode 100644 index 00000000..03e93b83 --- /dev/null +++ b/ruby/neo4j/driver/internal/messaging/v5/bolt_protocol_v5.rb @@ -0,0 +1,21 @@ +module Neo4j::Driver + module Internal + module Messaging + module V5 + # Definition of the Bolt Protocol 4.4 + class BoltProtocolV5 < V44::BoltProtocolV44 + VERSION = BoltProtocolVersion.new(5,0) + INSTANCE = new + + def create_message_format + MessageFormatV5.new + end + + def include_date_time_utc_patch_in_hello + false + end + end + end + end + end +end diff --git a/ruby/neo4j/driver/internal/messaging/v5/message_format_v5.rb b/ruby/neo4j/driver/internal/messaging/v5/message_format_v5.rb new file mode 100644 index 00000000..4c9c7c3a --- /dev/null +++ b/ruby/neo4j/driver/internal/messaging/v5/message_format_v5.rb @@ -0,0 +1,18 @@ +module Neo4j::Driver + module Internal + module Messaging + module V5 + # Bolt message format v4.4 + class MessageFormatV5 + def new_writer(output) + MessageWriterV5.new(output) + end + + def new_reader(input) + MessageReaderV5.new(input) + end + end + end + end + end +end diff --git a/ruby/neo4j/driver/internal/messaging/v5/message_reader_v5.rb b/ruby/neo4j/driver/internal/messaging/v5/message_reader_v5.rb new file mode 100644 index 00000000..f9814ec3 --- /dev/null +++ b/ruby/neo4j/driver/internal/messaging/v5/message_reader_v5.rb @@ -0,0 +1,13 @@ +module Neo4j::Driver + module Internal + module Messaging + module V5 + class MessageReaderV5 < Common::CommonMessageReader + def initialize(input) + super(ValueUnpackerV5.new(input)) + end + end + end + end + end +end diff --git a/ruby/neo4j/driver/internal/messaging/v5/message_writer_v5.rb b/ruby/neo4j/driver/internal/messaging/v5/message_writer_v5.rb new file mode 100644 index 00000000..7fc8b584 --- /dev/null +++ b/ruby/neo4j/driver/internal/messaging/v5/message_writer_v5.rb @@ -0,0 +1,33 @@ +module Neo4j::Driver + module Internal + module Messaging + module V5 + class MessageWriterV5 < AbstractMessageWriter + def initialize(input) + super(Common::CommonValuePacker.new(output), build_encoders) + end + + private + + def build_encoders + result[Request::HelloMessage::SIGNATURE] = Encode::HelloMessageEncoder.new + result[Request::GoodbyeMessage::SIGNATURE] = Encode::GoodbyeMessageEncoder.new + result[Request::RunWithMetadataMessage::SIGNATURE] = Encode::RunWithMetadataMessageEncoder.new + result[Request::RouteMessage::SIGNATURE] = Encode::RouteV44MessageEncoder.new + + result[Request::DiscardMessage::SIGNATURE] = Encode::DiscardMessageEncoder.new + result[Request::PullMessage::SIGNATURE] = Encode::PullMessageEncoder.new + + result[Request::BeginMessage::SIGNATURE] = Encode::BeginMessageEncoder.new + result[Request::CommitMessage::SIGNATURE] = Encode::CommitMessageEncoder.new + result[Request::RollbackMessage::SIGNATURE] = Encode::RollbackMessageEncoder.new + + result[Request::ResetMessage::SIGNATURE] = Encode::ResetMessageEncoder.new + + result + end + end + end + end + end +end diff --git a/ruby/neo4j/driver/internal/messaging/v5/value_unpacker_v5.rb b/ruby/neo4j/driver/internal/messaging/v5/value_unpacker_v5.rb new file mode 100644 index 00000000..fd5551aa --- /dev/null +++ b/ruby/neo4j/driver/internal/messaging/v5/value_unpacker_v5.rb @@ -0,0 +1,113 @@ +module Neo4j::Driver + module Internal + module Messaging + module V5 + class ValueUnpackerV5 < Common::CommonValueUnpacker + NODE_FIELDS = 4 + RELATIONSHIP_FIELDS = 8 + + def initialize(input) + super(input, true) + end + + def node_fiunpack_nodeelds + urn = unpacker.unpack_long + + num_labels = unpacker.unpack_list_header + labels = [] + + num_labels.times do + labels << unpacker.unpack_string + end + + num_props = unpacker.unpack_map_header + props = {} + + num_props.times do + props[unpacker.unpack_string] = unpack + end + + element_id = unpacker.unpack_string + + Internal::InternalNode.new(urn, element_id, labels, props) + end + + def unpack_path + # List of unique nodes + uniq_nodes = Internal::InternalNode.new(unpacker.unpack_list_header) + + uniq_nodes.times do |i| + ensure_correct_struct_size(:NODE, NODE_FIELDS, unpacker.unpack_struct_header) + ensure_correct_struct_signature("NODE", NODE, unpacker.unpack_struct_signature) + uniq_nodes[i] = unpack_node + end + + # List of unique relationships, without start/end information + uniq_rels = Internal::InternalRelationship.new(unpacker.unpack_list_header) + + uniq_rels.times do |i| + ensure_correct_struct_size(:RELATIONSHIP, 4, unpacker.unpack_struct_header) + ensure_correct_struct_signature("UNBOUND_RELATIONSHIP", UNBOUND_RELATIONSHIP, unpacker.unpack_struct_signature) + id = unpacker.unpack_long + rel_type = unpacker.unpack_string + props = unpack_map + element_id = unpacker.unpack_string + uniq_rels[i] = Internal::InternalRelationship.new(id, element_id, -1.to_s, -1, -1.to_s, rel_type, props) + end + + # Path sequence + length = unpacker.unpack_list_header + + # Knowing the sequence length, we can create the arrays that will represent the nodes, rels and segments in + # their "path order + segments = length / 2 + nodes = segments.length = 1 + rels = segments.length + + prev_node = uniq_nodes[0], next_node # Start node is always 0, and isn't encoded in the sequence + nodes[0] = prev_node + + segments.length.times do |i| + rel_idx = unpacker.unpack_long + next_node = uniq_nodes[unpacker.unpack_long] + # Negative rel index means this rel was traversed "inversed" from its direction + + if rel_idx < 0 + rel = uniq_rels[(-rel_idx) - 1] # -1 because rel idx are 1-indexed + set_start_and_end(rel, next_node, prev_node) + else + rel = uniq_rels[rel_idx - 1] + set_start_and_end(rel, prev_node, next_node) + end + + nodes[i + 1] = next_node + rels[i] = rel + segments[i] = Internal::InternalPath::Segment.new(prev_node, rel, next_node) + prev_node = next_node + end + + Internal::InternalPath.new(segments, nodes, rels) + end + + private def set_start_and_end(rel, start, finish) + rel.set_start_and_end(start.id, start.element_id, finish.id, finish.element_id) + end + + def unpack_relationship + urn = unpacker.unpack_long + start_urn = unpacker.unpack_long + end_urn = unpacker.unpack_long + rel_type = unpacker.unpack_string + props = unpack_map + element_id = unpacker.unpack_string + start_element_id = unpacker.unpack_string + end_element_id = unpacker.unpack_string + + adapted = Internal::InternalRelationship.new(urn, element_id, start_urn, start_element_id, end_urn, end_element_id, rel_type, props) + Internal::Value::RelationshipValue.new(adapted) + end + end + end + end + end +end