johannessen / neo4j-driver-perl

Neo4j graph database driver (Bolt/Jolt) for Perl
https://metacpan.org/pod/Neo4j::Driver
Artistic License 2.0
5 stars 1 forks source link

Allow customised package names in Cypher type system #4

Closed johannessen closed 3 years ago

johannessen commented 4 years ago

The package names that this driver’s Cypher type system uses to bless objects like Neo4j nodes and Neo4j relationships returned from executed queries should be customisable. This would support clients adding their own methods to such objects. See https://github.com/majensen/rest-neo4p/issues/20#issuecomment-543798074 for an example of how this might work.

API usage might look like this:

use Neo4j::Driver;

my $driver = Neo4j::Driver->new('bolt://localhost')->basic_auth(...);
$driver->config(cypher_types => {
    node => 'REST::Neo4p::Node',
    ...
});

my $query = 'CREATE (n) SET n = {properties} RETURN n';

my $result = $driver->session->run($query, properties => {...});
my $node = $result->single->get();
say $node->isa('REST::Neo4p::Node');  # result: 1

The client’s type package could implement any methods that it likes. For example, REST::Neo4p::Node might wish to offer methods such as new() or add_labels(), which Neo4j::Driver::Type::Node doesn’t have.

johannessen commented 4 years ago

A possible problem with this approach is that the client’s type package would use the exact same data structure as the Neo4j::Driver type package does. This might violate encapsulation and result in more brittle code.

To combat this, Neo4j::Driver should document that direct data structure access is unsupported, even from the client’s package. Instead, clients should inherit from the Neo4j::Driver type package using @ISA (or equivalent) and use the accessor methods provided.

package REST::Neo4p::Node;

# Bad example
sub add_labels {
    my $id = shift->{_meta}->{id};  # Don't do this!
    ...
}

# Good example
our @ISA = qw( Neo4j::Driver::Type::Node );
sub add_labels {
    my $id = shift->id();
    ...
}

Additionally, Neo4j::Driver should provide at least one hash key for safe internal use by the client. For example, Neo4j::Driver documentation could guarantee to never use hash keys beginning with __, so that methods in REST::Neo4p::Node could use $_[0]->{__whatever} to store any private data they may need to store.

johannessen commented 4 years ago

Initial implementation landed, see "Type system customisation" in Neo4j::Driver 0.14. Would @majensen consider this suitable for adapting REST::Neo4p to use Neo4j::Driver? Are any other changes to Neo4j::Driver necessary (or perhaps just useful)?

majensen commented 4 years ago

Will have a go at this

johannessen commented 4 years ago

Great! Just let me know what you need.

johannessen commented 3 years ago

With REST::Neo4p 0.4000 released, I guess this can be closed.

But I like the flexibility this option provides, and am leaning towards eventually making it a stable feature.