# PODNAME: Neo4j::Driver::Deprecations
# ABSTRACT: Explains features that have been deprecated, but not yet removed

__END__

=pod

=encoding UTF-8

=head1 NAME

Neo4j::Driver::Deprecations - Explains features that have been deprecated, but not yet removed

=head1 VERSION

version 0.31

=head1 OVERVIEW

Deprecated features are removed from the pod documentation of
the individual modules in this distribution in an attempt to
keep those short and clear. This document describes all features
that are deprecated, but still working for completeness' sake,
briefly explains the reason for their deprecation, and suggests
alternatives where possible.

The intention is that most deprecated features will be removed with
the next major update to L<Neo4j::Driver>. There is no schedule for
the release of that update S<(version 1.00),> but there is a decent
chance that it will happen in the year 2022.

=head1 Neo4j::Driver

=head2 close()

I<Deprecated in version 0.14 and to be removed in 1.00.
Originally added in 0.02 as an experimental feature.>

 $driver->close;  # no-op

All resources opened by the Perl driver are closed automatically once
they are no longer required. Explicit calls to C<close()> are neither
required nor useful.

=head2 Config option C<ca_file>

I<Deprecated in version 0.15 and to be removed in 1.00.
Originally added in 0.13 as an experimental feature.>

 $driver->config(ca_file => 'neo4j/certificates/neo4j.cert');

Specifies the location of a local copy of the server certificate
for the then-experimental HTTPS self-signed certificate support.
The driver config option C<ca_file> corresponded to C<SSL_ca_file>
in L<LWP::UserAgent> and L<IO::Socket::SSL>.

This option was renamed C<tls_ca> in S<version 0.15> to be more
consistent with the C<tls> option, then later renamed C<trust_ca>
in S<version 0.27> to be more consistent with the Neo4j Driver API.
See L<Neo4j::Driver/"trust_ca">.

=head2 Custom networking modules

I<Deprecated in version 0.31 and to be removed in 1.00.
Originally added in 0.21 as an experimental feature.>

 use Local::MyNetModule;
 $driver->config(net_module => 'Local::MyNetModule');

The module to be used for network communication may be specified
using the C<net_module> config option. The specified module must
implement the API described in L<Neo4j::Driver::Net/"EXTENSIONS">.
Your code must C<use> or C<require> the module it specifies here.

The default value of C<undef> will cause the driver to use its
built-in modules. An empty string C<""> will do the same.

 # use the built-in networking modules
 $driver->config(net_module => undef);
 $driver->config(net_module => '');

Some versions of the driver also allow users to run its test suite
against a custom net module.

 TEST_NEO4J_NETMODULE=Local::MyNetModule prove

The C<net_module> option provides decent flexibility for extending
the driver. However, some interesting possible extensions have
little to do with networking, and the C<net_module> API itself
lacks flexibility.

Existing networking modules should be converted to HTTP network
adapters. This is easily done with the the following two steps.

=over

=item 1.

Rename your existing C<sub new {}> constructor to (for example)
C<sub _net_module_new {}>.

=item 2.

Insert the following code into your module:

 use parent 'Neo4j::Driver::Plugin';
 
 sub new {
   bless [], shift;
 }
 
 sub register {
   my ($self, $manager) = @_;
   $manager->add_event_handler(
     http_adapter_factory => sub {
       my ($continue, $driver) = @_;
       __PACKAGE__->_net_module_new($driver);
     },
   );
 }

See L<Neo4j::Driver::Plugin/"http_adapter_factory"> for details.

=back

At that point, your code setting the C<net_module> config option
can simply be replaced by calls to L<Neo4j::Driver/"plugin">.

 # Deprecated config option:
 use Local::Foo;
 $driver->config( net_module => 'Local::Foo' );
 
 # New plug-in interface:
 use Local::Foo;
 $driver->plugin( 'Local::Foo' );

=head2 Disable or enforce Jolt

I<Deprecated in version 0.30 and to be removed in 1.00.
Originally added in 0.21 as an experimental feature.>

 $d->config(jolt => undef);  # prefer Jolt (the default)
 $d->config(jolt => 0);      # accept only JSON
 $d->config(jolt => 1);      # accept only Jolt
 
 # Accept only Jolt and request ...
 $d->config(jolt => 'sparse');  # sparse Jolt mode + RFC 7464
 $d->config(jolt => 'strict');  # strict Jolt mode + RFC 7464
 $d->config(jolt => 'ndjson');  # newline delimited mode (non RFC)

Since driver S<version 0.24>, the
L<Jolt|https://neo4j.com/docs/http-api/4.3/actions/result-format/#_jolt>
response format (JSON Bolt) is preferred for HTTP connections
because the older REST-style JSON response format has several
known issues and is much slower than Jolt.

This option is no longer useful. The driver will pick the fastest
and most reliable format automatically (S<RFC 7464> sparse Jolt, if
available). If you do need a specific response format, for example
because you use driver internals to access the raw server response,
you can use a plug-in to manipulate the HTTP
C<Accept> header according to your needs. See L<Neo4j::Driver::Net>.

=head2 Mutable auth credentials

I<Deprecated in version 0.15 and to be removed in 1.00.
Originally added in 0.01 as an experimental feature.>

 $session1 = $driver->basic_auth('user1', 'password')->session;
 $session2 = $driver->basic_auth('user2', 'password')->session;

Early versions allowed modifying the driver object after session
creation. This is not very useful in practice. The official Neo4j
drivers are explicitly designed to be immutable.

=head2 Parameter syntax conversion using C<cypher_filter>

I<< Config option C<cypher_filter> deprecated in version 0.26
and to be removed in 1.00.
Originally added in 0.14 as an experimental feature. >>

 $driver->config( cypher_filter => 'params' );

When this option is set, the driver automatically uses a regular
expression to convert the old Cypher parameter syntax C<{param}>
supported by Neo4j S<versions 2 and 3> to the new syntax C<$param>
supported by Neo4j S<versions 3 and 4>.

This option was meant to support more general filtering of Cypher
statements at some point in the future. But plug-ins
already make that very easy. Therefore the C<cypher_filter>
option won't be extended any further. However, the existing
parameter syntax conversion is probably useful enough to stand
on its own feet if given a more appropriate name.

Instead of this option, C<cypher_params> should be used;
see L<Neo4j::Driver/"Parameter syntax conversion">.

 $driver->config( cypher_params => v2 );

=head2 Suppress exceptions

I<Deprecated in version 0.14 and to be removed in 1.00.
Originally added in 0.01 as an experimental feature.>

 $driver = Neo4j::Driver->new;
 $driver->{die_on_error} = 0;
 $result = $driver->session->run('...');

The default value of the C<die_on_error> attribute is C<1>. Setting
this to C<0> causes the driver to no longer die on I<server> errors.

This is much less useful than it sounds. Not only is the
L<Result|Neo4j::Driver::Result> structure not
well-defined for such situations, but also the internal state of the
L<Transaction|Neo4j::Driver::Transaction> object may be corrupted.
For example, when a minor server error occurs on the first request
(which would normally establish the connection), the expected
C<Location> header may be missing from the error message and the
transaction may therefore be marked as closed, even though it still
is open. The next request would then fail anyway, but with a
misleading error message.

Additionally, I<client> errors (such as trying to call C<single()> on
a result with multiple result records) have always caused the driver
to die in spite of C<die_on_error = 0>.

Such inconsistent behaviour makes bugs harder to find and has no
clear advantages. It is not present in the official drivers.

To suppress errors, wrap your calls in
L<< C<try>/C<catch> blocks|perlsyn/"Try Catch Exception Handling" >>:

 use Feature::Compat::Try;
 my $result;
 try {
   $result = $session->run('MATCH (n:Test) RETURN m');
   $result->has_next;  # Wait for statement execution
 }
 catch ($e) { warn "Got a Neo4j error: $e" }

=head2 Type system customisation

I<Deprecated in version 0.25 and to be removed in 1.00.
Originally added in 0.14 as an experimental feature.>

 $driver->config(cypher_types => {
   node => 'Local::Node',
   relationship => 'Local::Relationship',
   path => 'Local::Path',
   point => 'Local::Point',
   temporal => 'Local::Temporal',
   init => sub { my $object = shift; ... },
 });

The package names used for C<bless>ing objects in query results
can be modified. This allows clients to add their own methods to
such objects.

Clients must make sure their custom type packages are subtypes
of the base type packages that this module provides (S<e. g.>
with L<parent>):

=over

=item * L<Neo4j::Driver::Type::Node>

=item * L<Neo4j::Driver::Type::Relationship>

=item * L<Neo4j::Driver::Type::Path>

=item * L<Neo4j::Driver::Type::Point>

=item * L<Neo4j::Driver::Type::Temporal>

=back

Clients may only use the documented API to access the data in the
base type. As an exception, clients may store private data by calling
the C<_private()> method, which returns a hashref. Within that
hashref, clients may make free use of any hash keys that begin with
two underscores (C<__>). All other hash keys are reserved for use
by Neo4j::Driver.

The implementation of the custom type packages continues to be
defined by the driver. In particular, it is the driver's choice
what I<kind> of reference to bless E<ndash> hash, array, or scalar.
This severely limits the freedom of the custom type packages.

Instead of the C<cypher_types> option, users should consider a
custom networking module that provides a custom result handler.
This approach offers even more flexibility (albeit at the cost
of some degree of convenience).
See L<Neo4j::Driver::Net/"Custom result handlers"> for details.

=head1 Neo4j::Driver::Net::HTTP::LWP

=head2 agent

I<Deprecated in version 0.30 and currently planned to be removed
in 1.00. Originally added in 0.21 as an experimental feature.>

 use parent 'Neo4j::Driver::Net::HTTP::LWP';
 sub foo {
   my ($self) = @_;
   my $lwp_ua = $self->agent;
   ...
 }

Returns the L<LWP::UserAgent> instance in use.
Meant to facilitate subclassing.
In version 0.30, this method was renamed
L<C<ua()>|Neo4j::Driver::Net::HTTP::LWP/"ua">
because L<LWP> itself uses C<agent> for the User-Agent
identification string and this was deemed a possible
source of confusion.

=head2 protocol

I<Deprecated in version 0.30 and currently planned to be removed
in 1.00. Originally added in 0.21 as an experimental feature.>

 use parent 'Neo4j::Driver::Net::HTTP::LWP';
 sub foo {
   my ($self) = @_;
   my $http_version = $self->protocol;
   ...
 }

Returns the HTTP version of the last response (typically
C<"HTTP/1.1">). Since version 0.26, this method was no longer
required for a net module and using it was discouraged.

=head1 Neo4j::Driver::Record

=head2 Cypher type system

I<Direct access deprecated in version 0.13 and currently
planned to be removed in 1.00. Originally added in 0.01.>

 $result = $session->run('MATCH (n:Person) RETURN (n)');
 foreach my $node ( map { $_->get } $result->list ) {
   my $properties = $node;
   say $properties->{birthday};
 }

Early versions of this driver returned nodes and relationships as
unblessed hash references of their properties. Neo4j paths were
returned as unblessed array references. This was a bug because
this driver's goal always was to implement the Neo4j Driver API,
which doesn't work this way. This bug made it impossible to
distinguish between structural types and simple maps / lists.
It also made it difficult to access metadata. See GitHub issues
L<#2|https://github.com/johannessen/neo4j-driver-perl/issues/2> and L<#8|https://github.com/johannessen/neo4j-driver-perl/issues/8>.

Proper blessed types for L<nodes|Neo4j::Driver::Type::Node>,
L<relationships|Neo4j::Driver::Type::Relationship> and
L<paths|Neo4j::Driver::Type::Path> were added in S<version 0.13,>
and directly accessing their elements and properties using
C<< ->[] >> or C<< ->{} >> was deprecated at the same time.
A deprecation warning was added in version 0.18.
The current plan is to remove direct access in version 1.00.

To obtain a hash reference of all properties of a
L<node|Neo4j::Types::Node/"properties"> or
L<relationship|Neo4j::Types::Relationship/"properties">,
use the C<properties()> method:

 $result = $session->run('MATCH (n) RETURN (n)');
 foreach my $node ( map { $_->get } $result->list ) {
   my $properties = $node->properties;
   say $properties->{birthday};
 }

To obtain all nodes and relationships in a path as an alternating
array, use the L<< C<elements()>|Neo4j::Types::Path/"elements" >>
method:

 $result = $session->run('MATCH p=(:Person)-[]->() RETURN (p)');
 foreach my $path ( map { $_->get } $result->list ) {
   my $array = [ $path->elements ];
   ...
 }

=head2 get_bool()

I<Deprecated in version 0.07 and to be removed in 1.00.
Originally added in 0.02 as an experimental feature.>

 $bool  = $session->run('RETURN false')->single->get_bool;
 $ref   = ref $bool;        # ''
 $undef = ! defined $bool;  # 1

Get a boolean value from this record. Behaves exactly like
L<C<get()>|Neo4j::Driver::Record/"get">, except that non-truthy
boolean values are returned as C<undef>.

In Perl, which doesn't have a native boolean type, JSON booleans are
represented as a blessed scalar that uses L<overload> to evaluate
truthy or non-truthy as appropriate in Perl expressions. This almost
always works perfectly fine. However, some conditions may not expect
a non-truthy value to be blessed, which can result in wrong
interpretation of query results. The C<get_bool()> method was meant
to ensure boolean results would evaluate correctly in such cases.

If you do need an unblessed Perl scalar to express a boolean value,
simply use C<!!> to force evaluation in a boolean context.

 $val  = $session->run('RETURN false')->single->get;
 $ref  = ref $val;  # 'JSON::PP::Boolean'
 $bool = !! $val;

=head2 Raw meta data access

I<Deprecated in version 0.18 and to be removed in 1.00.
Originally added in 0.01 as an experimental feature.>

 $meta = $record->{meta};

Allows accessing the entity meta data that some versions of
the Neo4j server provide. This meta data is not available
reliably due to a known bug in the Neo4j server
(L<#12306|https://github.com/neo4j/neo4j/issues/12306>).
If it I<is> available, it can since S<version 0.13> be
accessed via object methods. This raw access shouldn't be
needed anymore and should no longer be relied upon.

=head2 stats()

I<Deprecated in version 0.07 and to be removed in 1.00.
Originally added in 0.02 as an experimental feature.>

Shortcut for L<"stats()" in Neo4j::Driver::Result|/"stats()1">
(only for records obtained via L<Neo4j::Driver::Result/"single">).

=head2 Virtual columns

I<Deprecated in version 0.18 and to be removed in 1.00.
Originally added in 0.01 as an experimental feature.>

 $size = $record->{column_keys}->count;
 $record->{column_keys}->add('new_field_key');

Access to the internal C<{column_keys}> data structure allows
adding new 'virtual' columns to the record's field key / index
resolution used by the C<get()> method. The virtual columns
can then be accessed just like regular columns.

Rather than manipulating the driver's Neo4j statement result,
users should make an in-memory copy of the results in a data
structure under their own control.

=head1 Neo4j::Driver::Result

=head2 Control result stream attachment

I<Deprecated in version 0.30 and to be removed in 1.00.
Originally added in 0.13 as an experimental feature.>

 $buffered = $result->attached;  # boolean
 $count = $result->detach;  # number of records fetched

C<detach()> forces the entire result stream to be buffered locally,
so that it is available to C<fetch()> indefinitely, irrespective of
other statements run on the same session. Essentially, the outcome
is the same as calling C<list()>, except that C<fetch()> can continue
to be used because the result is not exhausted.

The utility of these methods could never be demonstrated. Clients are
more likely to call C<list()> instead. (To begin statement execution,
calling C<has_next()> is a potentially cheaper alternative.) Only one
of the official Neo4j drivers has ever offered these methods, and even
that one no longer does so in its latest version.

=head2 stats()

I<Deprecated in version 0.07 and to be removed in 1.00.
Originally added in 0.02 as an experimental feature.>

 $tx = $session->begin_transaction;
 $tx->{return_stats} = 1;
 $stats = $tx->run('...')->stats;

Return a hash ref. The hash ref contains query statistics if these
were requested in advance. The hash ref may or may not be blessed.

In the Neo4j Driver API, query statistics are available from the
L<Neo4j::Driver::ResultSummary> instead, which is obtained using
L<C<summary()>|Neo4j::Driver::Result/"summary">.

 $stats = $session->run('...')->summary->counters;

=head1 Neo4j::Driver::ServerInfo

=head2 Protocol string

I<Deprecated in version 0.26 and to be removed in 1.00.
Originally added in 0.19 as an experimental feature.>

 $protocol_string = $session->server->protocol;

Returns the protocol name and version number announced by the server.
Similar to an agent string, this value is formed by the protocol
name followed by a slash and the version number, usually two digits
separated by a dot (for example: C<Bolt/1.0> or C<HTTP/1.1>).
If the protocol version is unknown, just the name is returned.

Since Neo4j 4.3, the driver API has an official method for this
purpose, L<Neo4j::Driver::ServerInfo/"protocol_version">.
Therefore the experimental C<protocol()> method is expendable.
In the future, the behaviour of the deprecated C<protocol()>
method can be approximated as follows:

 $protocol_string = $_ ? "Bolt/$_" : defined ? "Bolt" : "HTTP/1.1"
   for $session->server->protocol_version;

=head1 Neo4j::Driver::Session

=head2 Call run() in list context

I<Deprecated in version 0.26 and to be removed in 1.00.
Originally added in 0.01 as an experimental feature.>

 @records = $session->run('...');

See L<Neo4j::Driver::Transaction|/"Call-run()-in-list-context1">
below for details.

=head2 close()

I<Deprecated in version 0.14 and to be removed in 1.00.
Originally added in 0.02 as an experimental feature.>

 $session->close;  # no-op

All resources opened by the Perl driver are closed automatically once
they are no longer required. Explicit calls to C<close()> are neither
required nor useful.

=head1 Neo4j::Driver::StatementResult

I<Deprecated in version 0.19 and to be removed in 1.00.
Originally added in 0.01.>

 $result = $session->run('...');
 warn 'Unexpected type'
   unless $result->isa('Neo4j::Driver::StatementResult');

With version 4 of the official Neo4j drivers, C<StatementResult>
was renamed C<Result>.

This driver deprecated any use of the
L<Neo4j::Driver::StatementResult> module name in version 0.19.
Use L<Neo4j::Driver::Result> instead.

=head1 Neo4j::Driver::Transaction

=head2 Call run() in list context

I<Deprecated in version 0.26 and to be removed in 1.00.
Originally added in 0.01 as an experimental feature.>

 @records = $transaction->run('...');

The C<run> method tries to Do What You Mean if called in list
context. However, this may result in unexpected behaviour.
For example, consider this code:

 $people = {
   jane => $tx->run('MATCH (n) WHERE n.name = "Jane" RETURN n'),
   john => $tx->run('MATCH (n) WHERE n.name = "John" RETURN n'),
 };

You might expect the result to be a hash with two Neo4j nodes as
entry values. However, if no nodes match these queries, the list
context will make C<run()> return empty lists and you might end up
with the hash C<< {jane => 'john'} >> instead. If one node matches
and the other doesn't, the code may die.

To avoid this issue, you can wrap every call to C<run()> in
C<scalar()>. This will always get you a L<Neo4j::Driver::Result>.
In the next major version of the driver, wrapping the call
in C<scalar()> will no longer be necessary, because a
L<Neo4j::Driver::Result> will be returned in every context.

To obtain a list of L<Neo4j::Driver::Record> instances, simply
use C<list()> in list context:

 @records = $tx->run('...')->list;

=head2 Call run() with an array of multiple statements

I<Deprecated in version 0.25 and to be removed in 1.00.
Originally added in 0.01 as an experimental feature.>

 $statements = [
   [ 'RETURN 42' ],
   [ 'RETURN {value}', value => 'forty-two' ],
 ];
 $results = $transaction->run($statements);
 foreach $result ( @$results ) {
   say $result->single->get;
 }
 
 # Call in list context (also deprecated):
 @results = $transaction->run($statements);

The Neo4j HTTP API supports executing multiple statements within a
single HTTP request. This driver exposes this feature to the client
by allowing a multi-dimensional array to be passed to C<run()>.
Unfortunately, the resulting API is confusing to use and implement
and is therefore bug-prone.

If you need this feature, you should consider using the
private C<_run_multiple()> method instead; see
L<Neo4j::Driver::Transaction/"Execute multiple statements at once">.

=head2 Disable obtaining query statistics

I<Deprecated in version 0.28 and now an internal API.
Originally added in 0.02 / 0.13 as an experimental feature.>

 $transaction = $session->begin_transaction;
 $transaction->{return_stats} = 0;
 $result = $transaction->run('...');

The experimental C<{return_stats}> feature for requesting query
statistics from the Neo4j server was first added to the driver
in S<version 0.02.> Starting with version 0.13, stats are enabled
by default. When using HTTP, this feature allowed disabling them.
Doing so might provide a very minor performance increase.

As of version 0.28, allowing stats to be disabled is considered
to be a failed experiment. The performance impact is too minor
to matter; on the other hand, the advantages of a common API
between Bolt and HTTP connections are very clear. The driver
currently uses C<{return_stats} = 0> internally, so this feature
will likely not be removed soon, but going forward, it will be
treated as an internal API. There will be no deprecation warning.
See L<Neo4j::Driver::Plugin/"USE OF INTERNAL APIS">.

To disable query stats in future, use a plug-in
to modify C<includeStats> in the server request.

=head2 Return results in graph format

I<Deprecated in version 0.28 and to be removed in 1.00.
Originally added in 0.01 as an experimental feature.>

 $session = $driver->config( jolt => 0 )->session;
 $transaction = $session->begin_transaction;
 $transaction->{return_graph} = 1;
 $records = $transaction->run('...')->list;
 for $record ( @$records ) {
   $graph_data = $record->{graph};
   ...
 }

The Neo4j HTTP JSON API supports a
L<"graph" results data format|https://neo4j.com/docs/http-api/4.4/actions/return-results-in-graph-format/>.
This feature is only available when Jolt is disabled, which is
not recommended.

To request graph format in future, use a plug-in
to disable Jolt and modify the C<resultDataContents> in the server
request. Note that C<< $record->{graph} >> is an internal API that
may or may not be available in future versions.
See L<Neo4j::Driver::Plugin/"USE OF INTERNAL APIS">.

If there is demand for the graph format, equivalent functionality
might be added to a future version of the driver itself.
This would then also be available for Bolt and Jolt connections.

=head1 Neo4j::Driver::Type::Node, Neo4j::Driver::Type::Relationship

=head2 Deletion indicator

I<Deprecated in version 0.26 and to be removed in 1.00.
Originally added in 0.13 as an experimental feature.>

 $node_definitely_deleted = $node->deleted;
 $node_definitely_exists  = ! $node->deleted && defined $node->deleted;
 $node_status_unknown     = ! defined $node->deleted;
 
 $reln_definitely_deleted = $relationship->deleted;
 ...

In some circumstances, Cypher statements using C<DELETE> may still
C<RETURN> nodes or relationships that were deleted. To help avoid
confusion in such cases, the server sometimes reports whether
or not a node was deleted. If the deletion status of a node or
relationship is unknown, C<undef> will be returned by this method.

However, that information is not reliably available. In particular,
it is only reported for HTTP connections using JSON responses
(not for Bolt or Jolt). Additionally, some Neo4j server versions
may not report it at all, and I<if> reported, it may be affected
by a known bug in the Neo4j server
(L<#12306|https://github.com/neo4j/neo4j/issues/12306>).
Finally, the deletion indicator doesn't reflect whether or
not a transaction was successful or rolled back.

Given the low availability and reliability of this indicator,
consistency suggests to remove the C<deleted()> method entirely.
To obtain this indicator in the future, use a plug-in
to disable Jolt, then try to access the result's raw meta data.
For caveats, see L<Neo4j::Driver::Plugin/"USE OF INTERNAL APIS">.

=head1 Neo4j::Driver::Type::Path

=head2 path()

I<Deprecated in version 0.18 and to be removed in 1.00.
Originally added in 0.13 as an experimental feature.>

 $array = $path->path;
 $start_node = $array->[0];

Return the path as an array reference, alternating between nodes
and relationships in path sequence order.

The word C<path()> is singular, implying the return of a reference.
The alternative methods L<C<nodes()>|Neo4j::Types::Path/"nodes">
and L<C<relationships()>|Neo4j::Types::Path/"relationships"> are
plural, implying the return of a list. This was inconsistent.
Additionally, the C<path()> method led to awkward expressions such
as C<< $path->path >>, which are needlessly difficult to comprehend.

Use L<C<elements()>|Neo4j::Types::Path/"elements"> instead.

 $array = [ $path->elements ];

=head1 AUTHOR

Arne Johannessen <ajnn@cpan.org>

=head1 COPYRIGHT AND LICENSE

This software is Copyright (c) 2016-2022 by Arne Johannessen.

This is free software, licensed under:

  The Artistic License 2.0 (GPL Compatible)

=cut