TODO

This software has pre-release quality. The interface is not yet stable.

Neo4j::Driver

  • Write tests.

  • Remove close method.

  • Consider if the 6 second timeout is too long. It should in fact be as short as reasonably possible.

  • The driver should accept a setting that specifies the expected server version. The driver could use this to work around server bugs or known differences between versions, such as the Cypher parameter syntax. If not used, the default should be to use the most recent version. Neo4j appears to use SemVer versioning, but in order to avoid a SemVer dependency here, it's probably best to rely just on version->declare. (The exact behaviour must be documented.) That could look like this: $d = Neo4j::Driver->new; $d->{server} = 'v3.2.1';

  • An option method could be provided to supply rarely needed settings to the driver or session, such as the network timeout, the expected server version or whether or not to request graph results. So far, such settings are set using attributes. An option method would be chainable by returning $self. Using it could look like this: $d = Neo4j::Driver->new->option(timeout => 10)->basic_auth('neo4j', 'neo4j')

Neo4j::Driver::Session

  • Remove close method. Neo4j::Bolt::Cxn automatically closes the connection in the destructor, and HTTP transactions are rolled back on timeout, so an explicit close method quite simply is superfluous.

  • Sessions of some of the official drivers can have at most one transaction running at a time. This restriction is not necessary for this Perl driver when HTTP is used, but perhaps we should implement it anyway for consistency.

  • DBI uses begin_work in place of begin_transaction as a method name. Even though begin_work is shorter, it should not be the main method name because begin_transaction is well established in the official Neo4j drivers, and after all this is not DBI. However, as this is the only (almost) exact equivalence with DBI that we have, we should perhaps offer begin_work as an experimental alias at least.

  • Consider whether to offer transaction functions. If available, these should consist of subrefs passed to methods called write_transaction and read_transaction. These access modes are only an optimisation for Enterprise features. We don't target those at present, but read_transaction could then eventually be routed to a high-performance read-only server once clusters are supported. It would make sense to offer both methods right away even though initially they'd work exactly the same.

Neo4j::Driver::Transaction

  • The option to send multiple statements at once should no longer be exposed to the client. It should only be used internally for running statements lazily.

  • Consider unrolling deep_bless recursion. Based on initial profiling, this may save up to about 5% CPU time (for a specific HTTP test query cached in RAM, performance went from about 2700/s to 2850/s when skipping the call to deep_bless entirely). However, when accessing the database, the bottleneck is typically I/O (querying Neo4j itself instead of the RAM-cached response let the performance for the very same query drop down to 650/s when executed over HTTP). So this optimisation may not be worth it (OTOH, Bolt performance was something like 7000/s, so optimising deep_bless may be more useful there).

  • An alternative to using $client->{_res}->status_line (to get the HTTP error message) might be to call $client->getUseragent->add_handler(response_header => sub { $status_line = shift->status_line }). However, this is probably slower and would likely need to be run for each and every POST including those with 2xx status codes, which might not be acceptable.

  • Disabling die_on_error probably makes errors harder to find, but has no clear advantages. In particular, errors are often missing the proper header fields for the commit URL etc., so it's likely the failed request doesn't produce useful return values and the next request will fail anyway with a misleading error message due to the URLs being corrupted. This feature is not present in the official drivers anyway; it was inspired by Neo4p and should probably be removed completely.

  • Consider supporting re-using Record objects for query parameters in run. The Java and C# drivers do this.

  • Profile whether Tie::IxHash or sorting JSON:PP is quicker and adjust the code accordingly. Note, however, that the testing simulator requires fully sorted JSON, so Tie::IxHash may not be enough.

  • Investigate which JSON module is the best. While Cpanel::JSON::XS may have some advantages in terms of correctness (I think?), maybe JSON::MaybeXS is more compatible.

  • Run statements lazily: Just like with the official drivers, statements passed to run should be gathered until their results are actually accessed. Then, and only then, all statements gathered so far should be sent to the server using a single request. Challenges of this approach include that notifications are not associated with a single statement, so there must be an option to disable this behaviour; indeed, disabled should probably be the default when stats are requested. Additionally, there are some bugs with multiple statements (see tests non-arrayref individual statement and include empty statement). Since stats are now requested by default, this item might mean investing time in developing an optimisation feature that is almost never used. Since the server is often run on localhost anyway where latency is very close to zero, this item should not have high priority.

  • Replace old {} parameter style with new $ style; see https://neo4j.com/docs/cypher-manual/current/deprecations-additions-removals-compatibility/.

Neo4j::Driver::StatementResult

Neo4j::Driver::Record

Neo4j::Driver::ResultColumns

  • Bugfix: The get method behaves unpredictably for queries that have fields with conflicting indexes and keys such as RETURN 1, 0. It would technically be possible to distinguish between a key and an index by inspecting the scalar's FLAGS (namely, POK/IOK; see https://metacpan.org/pod/Devel::Peek#EXAMPLES and JSON::PP's _looks_like_number). Then get(0) would mean index 0 and get('0') would mean key 0. Not sure if this is the best approach though. (FWIW, it's exactly what the JS driver does.)

  • The list implementation is quite ugly and probably has bugs with regards to index/key collisions.

Neo4j::Driver::ResultSummary

  • Profile the server-side performance penalty of requesting stats for various kinds of queries. If the penalty turns out to be high, stats should perhaps have to be requested explicitly by clients (rather than being obtained by default, as with 0.13 and higher). However, using Bolt always provides stats, and different APIs for HTTP and Bolt seem like a bad idea.

  • Add timers.

Neo4j::Driver::SummaryCounters

  • use Class::Accessor::Fast 0.34;

Neo4j::Driver::Type::*

  • Implement spatial and temporal types.

  • The eq and ne operators should be overloaded to allow for ID comparison on nodes and relationships.

  • Consider whether to use use overload '%{}' to allow direct access to e. g. properties using the pre-0.13 hashref syntax. See https://metacpan.org/pod/overload#Two-face-References for an example.