Skip to content

Commit

Permalink
Fixed _id validation which now allows for single character keys.
Browse files Browse the repository at this point in the history
Improved prune tests & documentation examples.
  • Loading branch information
LaravelFreelancerNL committed May 15, 2022
1 parent 051b6e1 commit 6f073a0
Show file tree
Hide file tree
Showing 3 changed files with 196 additions and 38 deletions.
87 changes: 81 additions & 6 deletions docs/api/graph-clauses.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,27 +181,102 @@ Resulting AQL: `WITH users, cities FOR v, e, p ANY "users/1" edge1, INBOUND edge

## PRUNE
```
prune($leftOperand, $comparisonOperator = null, $rightOperand = null, $logicalOperator = null)
prune($leftOperand, $comparisonOperator = null, $rightOperand = null, $logicalOperator = null, $pruneVariable)
```
Filter out data not matching the given predicate(s).

**Example - single predicate:**
```
$qb = new QueryBuilder();
$qb = (new QueryBuilder());
$qb->for(['v', 'e', 'p'], '1..5')
->traverse('circles/A', 'OUTBOUND')
->graph("traversalGraph")
->prune('e.theTruth' '==' true)
->prune('e.theTruth', '==', true)
->return([
'vertices' => 'p.vertices[*]._key',
'edges' => 'p.edges[*].label'
]);
])
->get();
```
Resulting AQL:
```
FOR v, e, p IN 1..5 OUTBOUND 'circles/A' GRAPH 'traversalGraph'
FOR v, e, p IN 1..5 OUTBOUND "circles/A" GRAPH "traversalGraph"'
PRUNE e.theTruth == true
RETURN { vertices: p.vertices[*]._key, edges: p.edges[*].label }
RETURN {"vertices":p.vertices[*]._key,"edges":p.edges[*].label}
```

**Example - multiple predicates:**
```
$qb = (new QueryBuilder());
$qb->for(['v', 'e', 'p'], '1..5')
->traverse('circles/A', 'OUTBOUND')
->graph("traversalGraph")
->prune([['e.active', '==', 'true'], ['e.age', '>', 18]])
->return([
'vertices' => 'p.vertices[*]._key',
'edges' => 'p.edges[*].label'
])
->get();
```
Resulting AQL:
```
FOR v, e, p IN 1..5 OUTBOUND "circles/A" GRAPH "traversalGraph"
PRUNE e.active == true AND e.age > 18
RETURN {"vertices":p.vertices[*]._key,"edges":p.edges[*].label}
```

**Example - store condition in variable:**
```
$qb = (new QueryBuilder());
$qb->for(['v', 'e', 'p'], '1..5')
->traverse('circles/A', 'OUTBOUND')
->graph("traversalGraph")
->prune(
'e.theTruth',
'==',
true,
'OR',
'pruneCondition'
)
->return([
'vertices' => 'p.vertices[*]._key',
'edges' => 'p.edges[*].label'
])
->get();
```
Resulting AQL:
```
FOR v, e, p IN 1..5 OUTBOUND "circles/A" GRAPH "traversalGraph"
PRUNE pruneCondition = e.theTruth == true
RETURN {"vertices":p.vertices[*]._key,"edges":p.edges[*].label}
```


**Example - multiple predicates stored in variable:**
```
$qb = (new QueryBuilder());
$qb->for(['v', 'e', 'p'], '1..5')
->traverse('circles/A', 'OUTBOUND')
->graph("traversalGraph")
->prune(
[
'e.theTruth',
'==',
true
],
pruneVariable: 'pruneCondition'
)
->return([
'vertices' => 'p.vertices[*]._key',
'edges' => 'p.edges[*].label'
])
->get();
```
Resulting AQL:
```
FOR v, e, p IN 1..5 OUTBOUND "circles/A" GRAPH "traversalGraph"
PRUNE pruneCondition = e.theTruth == true
RETURN {"vertices":p.vertices[*]._key,"edges":p.edges[*].label}
```

[ArangoDB PRUNE documentation](https://www.arangodb.com/docs/stable/aql/graphs-traversals.html#using-filters-and-the-explainer-to-extrapolate-the-costs)
2 changes: 1 addition & 1 deletion src/Traits/ValidatesExpressions.php
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ public function isId($value): bool
{
if (
is_string($value) &&
preg_match("/^[a-zA-Z0-9_-]+\/[a-zA-Z0-9_-]+\/?[a-zA-Z0-9_\-\:\.\@\(\)\+\,\=\;\$\!\*\'\%]+$/", $value)
preg_match("/^[a-zA-Z0-9_-]+\/(\/?[a-zA-Z0-9_\-\:\.\@\(\)\+\,\=\;\$\!\*\'\%])+$/", $value)
) {
return true;
}
Expand Down
145 changes: 114 additions & 31 deletions tests/Unit/AQL/GraphClausesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -128,58 +128,141 @@ public function testEdgeCollectionListClauseArrayInput()
*/
public function testPruneClause()
{
$result = (new QueryBuilder())
->for('u', 'users')
->prune('u.active', '==', 'true')
$qb = (new QueryBuilder());
$qb->for(['v', 'e', 'p'], '1..5')
->traverse('circles/A', 'OUTBOUND')
->graph("traversalGraph")
->prune('e.theTruth', '==', true)
->return([
'vertices' => 'p.vertices[*]._key',
'edges' => 'p.edges[*].label'
])
->get();
self::assertEquals('FOR u IN users PRUNE u.active == true', $result->query);
self::assertEquals(
'FOR v, e, p IN 1..5 OUTBOUND "circles/A" GRAPH "traversalGraph"'
. ' PRUNE e.theTruth == true'
. ' RETURN {"vertices":p.vertices[*]._key,"edges":p.edges[*].label}',
$qb->query
);

$result = (new QueryBuilder())
->for('u', 'Users')
->prune('u.active', '==', 'true', 'OR')
->get();
self::assertEquals('FOR u IN Users PRUNE u.active == true', $result->query);

$result = (new QueryBuilder())
->for('u', 'Users')
->prune('u.active', '==', 'true')
$qb = (new QueryBuilder());
$qb->for(['v', 'e', 'p'], '1..5')
->traverse('circles/A', 'OUTBOUND')
->graph("traversalGraph")
->prune('e.theTruth', '==', true, 'OR')
->return([
'vertices' => 'p.vertices[*]._key',
'edges' => 'p.edges[*].label'
])
->get();
self::assertEquals('FOR u IN Users PRUNE u.active == true', $result->query);
self::assertEquals(
'FOR v, e, p IN 1..5 OUTBOUND "circles/A" GRAPH "traversalGraph"'
. ' PRUNE e.theTruth == true'
. ' RETURN {"vertices":p.vertices[*]._key,"edges":p.edges[*].label}',
$qb->query
);
}

/**
* @covers \LaravelFreelancerNL\FluentAQL\Clauses\PruneClause
*/
public function testPruneClauseWithMultiplePredicates()
{
$result = (new QueryBuilder())
->for('u', 'Users')
->prune([['u.active', '==', 'true'], ['u.age', '>', 18]])
->get();
self::assertEquals('FOR u IN Users PRUNE u.active == true AND u.age > 18', $result->query);
$qb = (new QueryBuilder());
$qb->for(['v', 'e', 'p'], '1..5')
->traverse('circles/A', 'OUTBOUND')
->graph("traversalGraph")
->prune([['e.active', '==', 'true'], ['e.age', '>', 18]])
->return([
'vertices' => 'p.vertices[*]._key',
'edges' => 'p.edges[*].label'
])
->get();
self::assertEquals(
'FOR v, e, p IN 1..5 OUTBOUND "circles/A" GRAPH "traversalGraph"'
. ' PRUNE e.active == true AND e.age > 18'
. ' RETURN {"vertices":p.vertices[*]._key,"edges":p.edges[*].label}',
$qb->query
);
}

/**
* @covers \LaravelFreelancerNL\FluentAQL\Clauses\PruneClause
*/
public function testPruneClauseWithVariable()
{
$result = (new QueryBuilder())
->for('u', 'users')
->prune('u.active', '==', 'true', null, 'pruneCondition')
$qb = (new QueryBuilder());
$qb->for(['v', 'e', 'p'], '1..5')
->traverse('circles/A', 'OUTBOUND')
->graph("traversalGraph")
->prune(
'e.theTruth',
'==',
true,
'OR',
'pruneCondition'
)
->return([
'vertices' => 'p.vertices[*]._key',
'edges' => 'p.edges[*].label'
])
->get();
self::assertEquals('FOR u IN users PRUNE pruneCondition = u.active == true', $result->query);
self::assertEquals(
'FOR v, e, p IN 1..5 OUTBOUND "circles/A" GRAPH "traversalGraph"'
. ' PRUNE pruneCondition = e.theTruth == true'
. ' RETURN {"vertices":p.vertices[*]._key,"edges":p.edges[*].label}',
$qb->query
);

$result = (new QueryBuilder())
->for('u', 'Users')
->prune('u.active', '==', 'true', 'OR', 'pruneCondition')
$qb = (new QueryBuilder());
$qb->for(['v', 'e', 'p'], '1..5')
->traverse('circles/A', 'OUTBOUND')
->graph("traversalGraph")
->prune(
[
'e.theTruth',
'==',
true
],
pruneVariable: 'pruneCondition'
)
->return([
'vertices' => 'p.vertices[*]._key',
'edges' => 'p.edges[*].label'
])
->get();
self::assertEquals('FOR u IN Users PRUNE pruneCondition = u.active == true', $result->query);
self::assertEquals(
'FOR v, e, p IN 1..5 OUTBOUND "circles/A" GRAPH "traversalGraph"'
. ' PRUNE pruneCondition = e.theTruth == true'
. ' RETURN {"vertices":p.vertices[*]._key,"edges":p.edges[*].label}',
$qb->query
);

$result = (new QueryBuilder())
->for('u', 'Users')
->prune(['u.active', '==', 'true'], pruneVariable: 'pruneCondition')
$qb = (new QueryBuilder());
$qb->for(['v', 'e', 'p'], '1..5')
->traverse('circles/A', 'OUTBOUND')
->graph("traversalGraph")
->prune(
[
[
'e.theTruth', '==', true
],
[
'e.theTruth', '!=', false
]
],
pruneVariable: 'pruneCondition'
)
->return([
'vertices' => 'p.vertices[*]._key',
'edges' => 'p.edges[*].label'
])
->get();
self::assertEquals('FOR u IN Users PRUNE pruneCondition = u.active == true', $result->query);
self::assertEquals(
'FOR v, e, p IN 1..5 OUTBOUND "circles/A" GRAPH "traversalGraph"'
. ' PRUNE pruneCondition = e.theTruth == true AND e.theTruth != false'
. ' RETURN {"vertices":p.vertices[*]._key,"edges":p.edges[*].label}',
$qb->query
);
}
}

0 comments on commit 6f073a0

Please sign in to comment.