NAME

Neo4j::Cypher::Abstract - Generate Cypher query statements

SYNOPSIS

DESCRIPTION

When writing code to automate database queries, sometimes it is convenient to use a wrapper that generates desired query strings. Then the user can think conceptually and avoid having to remember precise syntax or write and debug string manipulations. A good wrapper can also allow the user to produce query statements dynamically, hide dialect details, and may include some simple syntax checking. SQL::Abstract is an example of a widely-used wrapper for SQL.

The graph database Neo4j allows SQL-like declarative queries through its query language Cypher. Neo4j::Cypher::Abstract is a Cypher wrapper in the spirit of SQL::Abstract that creates very general Cypher productions in an intuitive, Perly way.

Basic idea : stringing clauses together with method calls

A clause is a portion of a complete query statement that plays a specific functional role in the statement and is set off by one or more reserved words. Clauses in Cypher include reading (e.g., MATCH), writing (CREATE), importing (LOAD CSV), and schema (CREATE CONSTRAINT) clauses, among others. They have arguments that define the clause's scope of action.

Cypher::Abstract objects possess methods for every Cypher clause. Each method adds its clause, with arguments, to the object's internal queue. Every method returns the object itself. When an object is rendered as a string, it concatenates its clauses to yield the entire query statement.

These features add up to the following idiom. Suppose we want to render the Cypher statement

MATCH (n:Users) WHERE n.name =~ 'Fred.*' RETURN n.manager

In Cypher::Abstract, we do

$s = Neo4j::Cypher::Abstract->new()->match('n:Users')
     ->where("n.name =~ 'Fred.*'")->return('n.manager');
print "$s;\n"; # "" is overloaded by $s->as_string()

Because you may create many such statements in a program, a short alias for the constructor can be imported, and extra variable assignments can be avoided.

use Neo4j::Cypher::Abstract qw/cypher/;
use DBI;

my $dbh = DBI->connect("dbi:Neo4p:http://127.0.0.1:7474;user=foo;pass=bar");
my $sth = $dbh->prepare(
  cypher->match('n:Users')->where("n.name =~ 'Fred.*'")->return('n.manager')
  );
$sth->execute();
...

Patterns

Patterns are representations of subgraphs with constraints that are key components of Cypher queries. They have their own syntax and are also amenable to wrapping. In the example above, match() uses a simple built-in shortcut:

$s->match('n:User') eq $s->match('(n:User)')

where (n:User) is the simple pattern for "all nodes with label 'User'". The module Neo4j::Cypher::Pattern handles complex and arbitrary patterns. It is loaded automatically on use Neo4j::Cypher::Abstract. Abstract patterns are written in a similar idiom as Cypher statements. They can be used anywhere a string is allowed. For example:

use Neo4j::Cypher::Abstract qw/cypher ptn/;

ptn->N(':Person',{name=>'Oliver Stone'})->R("r>")->N('movie') eq
 '(:Person {name:'Oliver Stone'})-[r]->(movie)'
$sth = $dbh->prepare(
   cypher->match(ptn->N(':Person',{name=>'Oliver Stone'})->R("r>")->N('movie'))
         ->return('type(r)')
   );

See Neo4j::Cypher::Pattern for a full description of how to specify patterns.

WHERE clauses

As in SQL, Cypher has a WHERE clause that is used to filter returned results. Rather than having to create custom strings for common WHERE expressions, SQL::Abstract provides an intuitive system for constructing valid expressions from Perl data structures made up of hash, array, and scalar references. Neo4j::Cypher::Abstract contains a new implementation of the SQL::Abstract expression "compiler". If the argument to the where() method (or any other method, in fact) is an array or hash reference, it is interpreted as an expression in SQL::Abstract style. (The parser is a complete reimplementation, so some idioms in that style may not result in exactly the same productions.)

Parameters

Parameters in Cypher are named, and given as alphanumeric tokens prefixed (sadly) with '$'. The Cypher::Abstract object collects these in the order they appear in the complete statement. The list of parameters can be recovered with the parameters() method.

$c = cypher->match('n:Person')->return('n.name')
           ->skip('$s')->limit('$l');
@p = $c->parameters; # @p is ('$s', '$l') /;

METHODS

Reading clauses

match(@ptns)
optional_match(@ptns)
where($expr)
start($ptn)

Writing clauses

create(@ptns), create_unique($ptn)
merge(@ptns)
foreach($running_var => $list, cypher-><update statement>)
set()
delete(), detach_delete()
on_create(), on_match()

Modifiers

limit($num)
skip($num)
order_by($identifier)

General clauses

return(@items), return_distinct(@items)
with(@identifiers), with_distinct(@identifiers)
unwind($list => $identifier)
union()
call()
yield()

Hinting

using_index($index)
using_scan()
using_join($identifier)

Loading

load_csv($file => $identifier), load_csv_with_headers(...)

Schema

create_constraint_exist($node => $label, $property),create_constraint_unique($node => $label, $property)
drop_constraint(...)
create_index($label => $property), drop_index($label => $property)

Utility Methods

parameters()

Return a list of statement parameters.

as_string()

Render the Cypher statement as a string. Overloads "".

SEE ALSO

REST::Neo4p, DBD::Neo4p, SQL::Abstract

AUTHOR

Mark A. Jensen
CPAN: MAJENSEN
majensen -at- cpan -dot- org

COPYRIGHT

(c) 2017 Mark A. Jensen