php-graph-group/cypher-query-builder

Cypher 查询语言的具有观点的查询构建器

0.0.2 2023-06-08 06:26 UTC

This package is auto-updated.

Last update: 2024-09-04 21:23:50 UTC


README

通过具有观点的构建器模式,以流畅且易于理解的方式创建 Cypher 查询。

示例

简单模式匹配示例

此查询查找 Alice 和 Bob 的所有同事

use PhpGraphGroup\CypherQueryBuilder\QueryBuilder;

$results = QueryBuilder::fromNode('a:Person')
    ->matchingRelationship('a', 'IS_COLLEAGUE', 'b:Person')
    ->whereIn('a.name', ['Alice', 'Bob'])
    ->return('b.name AS name') // Notice of the present tense implies the query gets executed immediately.

构建器运行此查询并返回结果

MATCH (a:Person)-[:IS_COLLEAGUE]->(b:Person)
WHERE a.name IN $names
RETURN b.name AS name

复杂模式匹配示例

此查询包含一个更复杂的模式,该模式正在使用模式构建器构建。

use PhpGraphGroup\CypherQueryBuilder\QueryBuilder;
use PhpGraphGroup\CypherQueryBuilder\Builders\GraphPatternBuilder;

GraphPatternBuilder::from('node:MyNode') // MATCH (node:MyNode)
GraphPatternBuilder::from('MyNode', 'otherNode') // MATCH (otherNode:MyNode)
GraphPatternBuilder::from('myNode:MyNode', 'otherNode') // MATCH (otherNode:MyNode) (TODO: log warning here?)
GraphPatternBuilder::from('Hello') // MATCH (hello:Hello)
GraphPatternBuilder::from('<Hello') // MATCH () <-[hello:Hello]-()
GraphPatternBuilder::from('<Hello')->addChildNode('Heya') // MATCH () <- [hello:Hello] - (heya:Heya)
// TODO: maybe rename this to addNode to allow for a parallel node, aka joining.
// TODO: If a node gets joined by a child node, it should have an anonymous relationship.
GraphPatternBuilder::from('MyNode')->addChildNode('MyOtherNode') // MATCH (myNode:MyNode), (myOtherNode:MyOtherNode)
GraphPatternBuilder::from('MyNode')->addRelationship()->addChildNode('MyOtherNode') // MATCH (myNode:MyNode)--(myOtherNode:MyOtherNode)
GraphPatternBuilder::from(name: 'noLabel') // MATCH (noLabel)
// TODO: Should it inject numbering in the automatic naming? -> no
// TODO: Should we pre-emptively throw an error or let the syntax error be found by the database?
// => first version should stay away from this, but we can revisit.
GraphPatternBuilder::from('MyNode')->addRelationship()->addChildNode('MyNode') // MATCH (myNode:MyNode) - [] -> (myNode:MyNode)

$results = QueryBuilder::from(GraphPatternBuilder::from('node:MyNode')
    ->addRelationship('<Parent')
        ->addChildNode('sibling1:MyNode')->end()
        ->addChildNode('sibling2:MyNode')->end()
    ->end()
    ->addRelationship('Parent>')
        ->addChildNode('grandParent:MyNode')->end()
    ->end()    
)->whereIn('sibling1.name', ['Harry', 'Bart'])
    ->andWhere('sibling2.name', '<>', 'Maria')
    ->andWhere('grandParent.age', '>=', 70)
    ->count('grandParent')

变为

MATCH (node:MyNode), (sibling1:MyNode)

简单创建示例

创建一个新的 Person 并使其成为 Alice 的同事。

use PhpGraphGroup\CypherQueryBuilder\QueryBuilder;

$results = QueryBuilder::new()
    ->matchingNode('a:Person')
    ->where('a.name', '=', 'Alice')
    ->creatingNode('b:Person')
    ->creatingRelationship('a', 'IS_COLLEAGUE', 'b')
    ->create(['b.name' => 'Bob'])

构建器运行此查询

MATCH (a:Person)
WHERE a.name = $param0
CREATE (b:Person), (a)-[:IS_COLLEAGUE]->(b)
SET b.name = $param1

简单更新示例

工作原理

Cypher 是一种功能强大的查询语言,提供了极大的灵活性。然而,这种灵活性可能会使得查询的理解和维护变得困难,尤其是在查询构建器的形式下。

此库旨在通过提供易于理解的流畅构建器模式,使编写和维护 Cypher 查询变得更加容易。

它具体限制了可能性,以便构建器更容易推理和使用。所有数据库操作仍然是可能的,但不再可能连续使用长而复杂的子句。

这是因为此查询构建器的主要观点和观点是,长而复杂的多个子句查询是不受欢迎的。它们难以理解,且查询的性能很可能下降。

构建器只提供每种子句的一个,并且这些子句的位置是固定的

MATCH { match patterns }
OPTIONAL MATCH* { optional match patterns }
CALL* { subquery }
WHERE { where conditions }

DELETE { deleted variables }
DETACH DELETE { deleted variables }

REMOVE { removed properties & labels }
CREATE { create patterns }
SET { set assignments }
MERGE { merge pattern }
ON CREATE SET { set assignments }
ON MATCH SET { set assignments }

RETURN { return expressions }
ORDER BY { ASC|DESC } { order expressions }
SKIP { skip count }
LIMIT { limit count }

查询构建器将只运行查询的某些部分,具体取决于您调用的方法。这些方法是直观且易于理解的

在某些情况下,会使用 UNWIND 在幕后实现以允许大量插入,但这超出了本介绍的范畴。

变量使用

变量用于引用节点、关系和别名。别名可以引用属性、节点、关系或函数调用结果。

由于构建器构建查询的方式,Cypher 不允许变量重新赋值。为了保持灵活性并允许使用原始语句,构建器不会检查变量的存在或重新赋值。只有当查询构建并发送到服务器后,才会发生错误。

属性使用

属性指代变量上的属性。这意味着用户应该使用点符号来明确地引用属性。如果不使用点符号而只引用属性,构建器将使用它来引用构建器入口节点或关系的变量上的属性。

use PhpGraphGroup\CypherQueryBuilder\QueryBuilder;

// Refer unambiguously to the property 'name' on the variable 'p'
$name = QueryBuilder::from('Person', 'p')
    ->where('p.name', '=', 'Alice')
    ->returning('p.name')
    ->only()
// Runs like:
// MATCH (p:Person) WHERE p.name = $param0 RETURN p.name AS name LIMIT 1

// Refer to the property of p without using the dot notation.
$lastNames = QueryBuilder::from('Person', 'p')
    ->where('name', '=', 'Alice')
    ->pluck('lastName')
// Runs like:
// MATCH (p:Person) WHERE p.name = $param0 RETURN p.lastName AS lastName

// Automatically generate a name based on the Label and get al the friends of Alice for over a year.
$friends = QueryBuilder::from('Person')
    ->matchingRelationship('person', 'FRIENDS_WITH', 'friend', 'friendsWith')
    ->matchingNode('Person', 'friend')
    ->where('friendsWith.since', '<=', (new DateTime())->sub(new DateInterval('P1Y')))
    ->andWhere('person.name', '=', 'Alice')
    ->return('friend.name AS name', 'friendsWith.since AS friendsSince')
// Runs like:
// MATCH (person:Person)-[friendsWith:FRIENDS_WITH]->(friend:Person) WHERE friendsWith <= $param0 AND person.name = $param1 RETURN friend.name AS name, friendsWith.since AS friendsSince