Skip to content

Commit

Permalink
Merge pull request #38 from majensen/compat-neo4j
Browse files Browse the repository at this point in the history
  • Loading branch information
majensen authored Dec 11, 2024
2 parents fef50b8 + 75aad27 commit c2a6381
Show file tree
Hide file tree
Showing 30 changed files with 217 additions and 122 deletions.
4 changes: 2 additions & 2 deletions Build.PL
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ my $build = $class->new
'experimental' => 0,
'MIME::Base64' => 0,
perl => 5.010001,
'Neo4j::Driver' => '0.19',
'Neo4j::Driver' => '0.26', # ServerInfo->agent
},
recommends => {
'Mojo::UserAgent' => 0,
Expand All @@ -96,6 +96,7 @@ my $build = $class->new
'Mock::Quick' => 0,
'List::MoreUtils' => 0,
'Mojo::Exception' => 0,
'Neo4j::Driver' => '0.26', # cypher_params v2
experimental => 0,
'IPC::Run' => 0,
'IO::Pty' => 0,
Expand All @@ -105,7 +106,6 @@ my $build = $class->new
'Test::Pod' => 1.0,
'Mojo::UserAgent' => 0,
'HTTP::Thin' => 0,
'Neo4j::Driver' => '0.19',
},
meta_merge => {
resources => {
Expand Down
4 changes: 2 additions & 2 deletions lib/REST/Neo4p.pm
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use URI;
use URI::Escape;
use HTTP::Tiny;
use JSON::ize;
use Neo4j::Driver 0.1801;
use Neo4j::Driver 0.26;
use REST::Neo4p::Agent;
use REST::Neo4p::Node;
use REST::Neo4p::Index;
Expand Down Expand Up @@ -164,7 +164,7 @@ sub get_neo4j_version {
my ($url, $user, $pass) = @_;
my $driver = Neo4j::Driver->new($url);
$driver->basic_auth($user, $pass) if $user || $pass;
my $version = $driver->session->server->version;
my $version = $driver->session->server->agent;
my ($major, $minor, $patch, $milestone) =
$version =~ /^Neo4j\/(?:([0-9]+)\.)(?:([0-9]+)\.)?([0-9]+)?(?:-M([0-9]+))?/;
return wantarray ? ($major, $minor, $patch, $milestone) : $version;
Expand Down
6 changes: 4 additions & 2 deletions lib/REST/Neo4p/Agent/Neo4j/Driver.pm
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package REST::Neo4p::Agent::Neo4j::Driver;
use v5.10;
use lib '../../../../../lib'; # testing
use base qw/REST::Neo4p::Agent/;
use Neo4j::Driver 0.1803;
use Neo4j::Driver 0.26;
use JSON::ize;
use REST::Neo4p::Agent::Neo4j::DriverActions;
use REST::Neo4p::Exceptions;
Expand Down Expand Up @@ -176,7 +176,7 @@ sub connect {
for (my $i = $REST::Neo4p::Agent::RQ_RETRIES; $i>0; $i--) {
my $f;
try {
my $version = $drv->session->server->version;
my $version = $drv->session->server->agent;
$version =~ s|^\S+/||; # server version strings look like "Neo4j/3.2.1"
$self->{_actions}{neo4j_version} = $version or
die "Can't find neo4j_version from server";
Expand Down Expand Up @@ -229,6 +229,7 @@ sub run_in_session {
$params = {} unless defined $params;
try {
$self->{_last_result} = $self->session->run($qry, $params);
$self->{_last_result}->has_next; # Make sure the query has executed and any errors have been thrown
} catch {
$self->{_last_errors} = $_;
};
Expand All @@ -243,6 +244,7 @@ sub run_in_transaction {
$params = {} unless defined $params;
try {
$self->{_last_result} = $tx->run($qry, $params);
$self->{_last_result}->has_next; # Make sure the query has executed and any errors have been thrown
} catch {
$self->{_last_errors} = $_;
};
Expand Down
26 changes: 24 additions & 2 deletions lib/REST/Neo4p/Agent/Neo4j/DriverActions.pm
Original file line number Diff line number Diff line change
Expand Up @@ -616,6 +616,8 @@ sub get_index {
$result = $self->is_version_4 ?
$self->run_in_session('call db.indexes() yield name, type, entityType where type = "FULLTEXT" and entityType = $ent return entityType, name, type',{ent => uc $ent}) :
$self->run_in_session('call db.index.explicit.list()');
# Neo4j 4.3+ syntax:
# $self->run_in_session('show indexes yield name, type, entityType where type = "FULLTEXT" and entityType = $ent return entityType, name, type',{ent => uc $ent}) :
}
else {
# find things
Expand Down Expand Up @@ -697,6 +699,8 @@ sub delete_index {
}
else {
$result = $tx->run("match ()-[r]->() where exists(r.__${idx}__keys) return distinct r.__${idx}__keys");
# Neo4j 4.3+ syntax:
# $result = $tx->run("match ()-[r]->() where r.`__${idx}__keys` is not null return distinct r.`__${idx}__keys`");
}
my (%k,%remove);
for my $k ($result->list()) {
Expand All @@ -712,9 +716,13 @@ sub delete_index {
else { #relationship
$tx->run("match ()-[r]->() where exists(r.__${idx}__keys) set r += \$rm remove r.__${idx}__keys",
{ rm => \%remove });
# Neo4j 4.3+ syntax:
# $tx->run("match ()-[r]->() where r.`__${idx}__keys` is not null set r += \$rm remove r.`__${idx}__keys`",
}
$tx->commit;
$result = $self->run_in_session('call db.index.fulltext.drop($idx)', {idx => $idx});
# Neo4j 4.3+ syntax:
# $result = $self->run_in_session(sprintf 'DROP INDEX `%s`', $idx);
}
else {
$result = $self->run_in_session('call db.index.explicit.drop($idx)',{idx => $idx});
Expand Down Expand Up @@ -785,6 +793,14 @@ sub post_index {
token => $content->{type} // "__$$content{name}__index",
prop => "__$$content{name}__keys"
});
# Neo4j 4.3+ syntax:
# my $token = $content->{type} // "__$$content{name}__index";
# my $ent_pattern = ($ent eq 'node') ? "(x:`$token`)" : "()-[x:`$token`]-()";
# $result = $self->run_in_session(
# sprintf "CREATE FULLTEXT INDEX `%s` FOR %s ON EACH [x.`%s`] OPTIONS {indexConfig: {`fulltext.analyzer`:'whitespace'}}",
# $content->{name}, $ent_pattern, "__$$content{name}__keys"
# )->consume;
# $result = $self->run_in_session("RETURN 1");
}
else {
my $for = ($ent eq 'node') ? 'forNodes' : 'forRelationships';
Expand Down Expand Up @@ -858,7 +874,8 @@ sub post_index {
for ($ent) {
/^node$/ && do {
$result = $self->run_in_session("create (n) $set_clause return n");
$content->{id} = 0+$result->fetch->get(0)->id;
my $node = $result->fetch->get(0);
$content->{id} = do { no warnings 'deprecated'; 0 + $node->id };
if ($self->is_version_4) {
my $hkey = encode_base64url($content->{key},'');
my $xi_prop = "_xi_$hkey";
Expand All @@ -885,7 +902,8 @@ sub post_index {
$content->{start} = 0+$start;
$content->{end} = 0+$end;
$result = $self->run_in_session("match (s), (t) where id(s)=\$start and id(t)=\$end create (s)-[n:$type]->(t) $set_clause return n", $content);
$content->{id} = 0+$result->fetch->get(0)->id;
my $relationship = $result->fetch->get(0);
$content->{id} = do { no warnings 'deprecated'; 0 + $relationship->id };
if ($self->is_version_4) {
my $hkey = encode_base64url($content->{key},'');
my $xi_prop = "_xi_$hkey";
Expand Down Expand Up @@ -945,6 +963,8 @@ sub get_schema_constraint {
my @constraints;
my $result;
$result = $self->run_in_session('call db.constraints()');
# Neo4j 4.3+ syntax:
# $result = $self->run_in_session($self->is_version_4 ? 'SHOW CONSTRAINTS' : 'call db.constraints()');
if ($result) {
while (my $rec = $result->fetch) {
my ($node_label,$reln_type,$x_prop, $u_prop) =
Expand Down Expand Up @@ -1060,6 +1080,8 @@ sub get_schema_index {
my $q;
if ($maj > 3) {
$q = 'call db.indexes() yield labelsOrTypes as labels, properties where $lbl in labels return { label:$lbl, property_keys:properties }';
# Neo4j 4.3+ syntax:
# $q = 'show indexes yield labelsOrTypes as labels, properties where $lbl in labels return { label:$lbl, property_keys:properties }';
}
elsif ($maj==3 && $min>=5) { # patch
$q = 'call db.indexes() yield tokenNames as labels, properties where $lbl in labels return { label:$lbl, property_keys:properties }';
Expand Down
58 changes: 33 additions & 25 deletions lib/REST/Neo4p/Agent/Neo4j/ResultProcessor.pm
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package
REST::Neo4p::Agent::Neo4j::Driver;

use REST::Neo4p::Exceptions;
use strict;

our %result_processors;

Expand All @@ -18,8 +19,9 @@ $result_processors{get_node} = sub {
my @r = $_->list;
REST::Neo4p::NotFoundException->throw unless @r;
$r = $r[0]->get(0);
return { metadata => { id => $r->id, labels => [$r->labels] },
self => 'node/'.$r->id,
my $id = do { no warnings 'deprecated'; $r->id };
return { metadata => { id => $id, labels => [$r->labels] },
self => 'node/'.$id,
data => $r->properties };
}
else {
Expand All @@ -33,12 +35,13 @@ $result_processors{get_node} = sub {
my $ret = [];
while (my $rec = $_->fetch) {
$r = $rec->get(0);
my $id = do { no warnings 'deprecated'; $r->id };
push @$ret, {
metadata => { id => $r->id, type => $r->type },
self => 'relationship/'.$r->id,
metadata => { id => $id, type => $r->type },
self => 'relationship/'.$id,
data => $r->properties,
start => 'node/'.$r->start_id,
end => 'node/'.$r->end_id,
start => 'node/' . do { no warnings 'deprecated'; $r->start_id },
end => 'node/' . do { no warnings 'deprecated'; $r->end_id },
type => $r->type
}
}
Expand All @@ -58,9 +61,10 @@ $result_processors{post_node} = sub {
my @r = $_->list;
REST::Neo4p::NotFoundException->throw unless @r;
$r = $r[0]->get(0);
my $id = do { no warnings 'deprecated'; $r->id };
return {
metadata => { id => $r->id, labels => [] },
self => 'node/'.$r->id,
metadata => { id => $id, labels => [] },
self => 'node/'.$id,
data => {}
};
}
Expand All @@ -73,12 +77,13 @@ $result_processors{post_node} = sub {
my @r = $_->list;
REST::Neo4p::NotFoundException->throw unless @r;
$r = $r[0]->get(0);
my $id = do { no warnings 'deprecated'; $r->id };
return {
metadata => { id => $r-id, type => $r->type },
self => 'relationship/'.$r->id,
metadata => { id => $id, type => $r->type },
self => 'relationship/'.$id,
data => $r->properties,
start => 'node/'.$r->start_id,
end => 'node/'.$r->end_id,
start => 'node/' . do { no warnings 'deprecated'; $r->start_id },
end => 'node/' . do { no warnings 'deprecated'; $r->end_id },
type => $r->type
};
};
Expand All @@ -95,12 +100,13 @@ $result_processors{get_relationship} = sub {
my @r = $_->list;
REST::Neo4p::NotFoundException->throw() unless @r;
my $r = $r[0]->get(0);
my $id = do { no warnings 'deprecated'; $r->id };
return {
metadata => { id => $r->id, type => $r->type },
self => 'relationship/'.$r->id,
metadata => { id => $id, type => $r->type },
self => 'relationship/'.$id,
data => $r->properties,
start => 'node/'.$r->start_id,
end => 'node/'.$r->end_id,
start => 'node/' . do { no warnings 'deprecated'; $r->start_id },
end => 'node/' . do { no warnings 'deprecated'; $r->end_id },
type => $r->type
};
};
Expand All @@ -109,7 +115,7 @@ $result_processors{get_relationship} = sub {
($other[0] eq 'properties') && do {
my @r = $_->list;
REST::Neo4p::NotFoundException->throw unless @r;
$r = $r[0]->get(0);
my $r = $r[0]->get(0);
return $r;
};
return;
Expand All @@ -132,8 +138,9 @@ $result_processors{get_label} = sub {
my $ret = [];
while (my $rec = $_->fetch) {
my $r = $rec->get(0);
push @$ret, { metadata => { id => $r->id, labels => [$r->labels] },
self => 'node/'.$r->id,
my $id = do { no warnings 'deprecated'; $r->id };
push @$ret, { metadata => { id => $id, labels => [$r->labels] },
self => 'node/'.$id,
data => $r->properties };
}
return $ret;
Expand All @@ -159,8 +166,9 @@ $result_processors{get_index} = sub {
while (my $rec = $_->fetch) {
my $r = $rec->get(0);
my @labels = (ref($r) =~ /Node/ ? (labels => [$r->labels]) : ());
push @$ret, { metadata => { id => $r->id, @labels },
self => 'node/'.$r->id,
my $id = do { no warnings 'deprecated'; $r->id };
push @$ret, { metadata => { id => $id, @labels },
self => 'node/'.$id,
data => $r->properties };
}
REST::Neo4p::NotFoundException->throw unless @$ret;
Expand All @@ -181,14 +189,14 @@ $result_processors{post_index} = sub {
else {
my $n = $_->fetch->get(0);
return unless ref $n;
my $id = $n->id;
my $id = do { no warnings 'deprecated'; $n->id };
return {
metadata => { id => $id },
self => "$ent/$id",
($n->properties ? (data => $n->properties) : ()),
($n->can(start_id) ? (
start_id => $n->start_id,
end_id => $n->end_id,
($n->can('start_id') ? (
start_id => do { no warnings 'deprecated'; $n->start_id },
end_id => do { no warnings 'deprecated'; $n->end_id },
type => $n->type
) : ()),
indexed => "index/$ent/$idx/$$content{key}/$$content{value}/$id"
Expand Down
8 changes: 5 additions & 3 deletions lib/REST/Neo4p/Entity.pm
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package REST::Neo4p::Entity;
use REST::Neo4p::Exceptions;
use Carp qw(croak carp);
use JSON;
use Scalar::Util qw(blessed);
use URI::Escape;
use strict;
use warnings;
Expand Down Expand Up @@ -65,7 +66,7 @@ sub new_from_json_response {
unless (defined $decoded_resp) {
REST::Neo4p::LocalException->throw("new_from_json_response() called with undef argument\n");
}
my $is_json = !(ref($decoded_resp) =~ /Neo4j::Driver/);
my $is_json = ! blessed $decoded_resp; # blessed via Neo4j::Driver
unless ($ENTITY_TABLE->{$entity_type}{_actions} || !$is_json) {
# capture the url suffix patterns for the entity actions:
for (keys %$decoded_resp) {
Expand All @@ -82,6 +83,7 @@ sub new_from_json_response {
($obj) = $self_url =~ /([a-z0-9_]+)\/?$/i;
}
else { # Driver
no warnings 'deprecated'; # id() in Neo4j 5
$obj = $decoded_resp->id;
$self_url = "$entity_type/$obj";
}
Expand All @@ -96,8 +98,8 @@ sub new_from_json_response {
}
else { # Driver
if ($decoded_resp->can('start_id')) {
$start_id = $decoded_resp->start_id;
$end_id = $decoded_resp->end_id;
$start_id = do { no warnings 'deprecated'; $decoded_resp->start_id };
$end_id = do { no warnings 'deprecated'; $decoded_resp->end_id };
$type = $decoded_resp->type;
}
}
Expand Down
2 changes: 2 additions & 0 deletions lib/REST/Neo4p/Index.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ functionality, the agent based on [Neo4j::Driver](https://metacpan.org/pod/Neo4j
indexes under the hood to emulate explicit indexes. This agent is used
automatically with Neo4j version 4.0 servers.

Note that this index emulation currently doesn't work with Neo4j 5.

# METHODS

- new()
Expand Down
2 changes: 2 additions & 0 deletions lib/REST/Neo4p/Index.pm
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,8 @@ functionality, the agent based on L<Neo4j::Driver> uses fulltext
indexes under the hood to emulate explicit indexes. This agent is used
automatically with Neo4j version 4.0 servers.
Note that this index emulation currently doesn't work with S<Neo4j 5.>
=head1 METHODS
=over
Expand Down
8 changes: 4 additions & 4 deletions lib/REST/Neo4p/Node.pm
Original file line number Diff line number Diff line change
Expand Up @@ -222,8 +222,8 @@ sub simple_from_json_response {
my $class = shift;
my ($decoded_resp) = @_;
my $ret;
for (ref $decoded_resp) {
/HASH/ && do {
for ($decoded_resp) {
ref eq 'HASH' && do {
# node id
($ret->{_node}) = $decoded_resp->{self} =~ m{.*/([0-9]+)$};
# node properties
Expand All @@ -235,8 +235,8 @@ sub simple_from_json_response {
}
last;
};
/Driver/ && do {
$ret->{_node} = $decoded_resp->id;
$_->isa('Neo4j::Types::Node') && do { # via Neo4j::Driver
$ret->{_node} = do { no warnings 'deprecated'; $decoded_resp->id };
$ret->{$_} = $decoded_resp->properties->{$_} for keys %{$decoded_resp->properties};
last;
};
Expand Down
Loading

0 comments on commit c2a6381

Please sign in to comment.