Skip to content

Commit 6f073a0

Browse files
Fixed _id validation which now allows for single character keys.
Improved prune tests & documentation examples.
1 parent 051b6e1 commit 6f073a0

File tree

3 files changed

+196
-38
lines changed

3 files changed

+196
-38
lines changed

docs/api/graph-clauses.md

+81-6
Original file line numberDiff line numberDiff line change
@@ -181,27 +181,102 @@ Resulting AQL: `WITH users, cities FOR v, e, p ANY "users/1" edge1, INBOUND edge
181181

182182
## PRUNE
183183
```
184-
prune($leftOperand, $comparisonOperator = null, $rightOperand = null, $logicalOperator = null)
184+
prune($leftOperand, $comparisonOperator = null, $rightOperand = null, $logicalOperator = null, $pruneVariable)
185185
```
186186
Filter out data not matching the given predicate(s).
187187

188188
**Example - single predicate:**
189189
```
190-
$qb = new QueryBuilder();
190+
$qb = (new QueryBuilder());
191191
$qb->for(['v', 'e', 'p'], '1..5')
192192
->traverse('circles/A', 'OUTBOUND')
193193
->graph("traversalGraph")
194-
->prune('e.theTruth' '==' true)
194+
->prune('e.theTruth', '==', true)
195195
->return([
196196
'vertices' => 'p.vertices[*]._key',
197197
'edges' => 'p.edges[*].label'
198-
]);
198+
])
199+
->get();
199200
```
200201
Resulting AQL:
201202
```
202-
FOR v, e, p IN 1..5 OUTBOUND 'circles/A' GRAPH 'traversalGraph'
203+
FOR v, e, p IN 1..5 OUTBOUND "circles/A" GRAPH "traversalGraph"'
203204
PRUNE e.theTruth == true
204-
RETURN { vertices: p.vertices[*]._key, edges: p.edges[*].label }
205+
RETURN {"vertices":p.vertices[*]._key,"edges":p.edges[*].label}
206+
```
207+
208+
**Example - multiple predicates:**
209+
```
210+
$qb = (new QueryBuilder());
211+
$qb->for(['v', 'e', 'p'], '1..5')
212+
->traverse('circles/A', 'OUTBOUND')
213+
->graph("traversalGraph")
214+
->prune([['e.active', '==', 'true'], ['e.age', '>', 18]])
215+
->return([
216+
'vertices' => 'p.vertices[*]._key',
217+
'edges' => 'p.edges[*].label'
218+
])
219+
->get();
220+
```
221+
Resulting AQL:
222+
```
223+
FOR v, e, p IN 1..5 OUTBOUND "circles/A" GRAPH "traversalGraph"
224+
PRUNE e.active == true AND e.age > 18
225+
RETURN {"vertices":p.vertices[*]._key,"edges":p.edges[*].label}
226+
```
227+
228+
**Example - store condition in variable:**
229+
```
230+
$qb = (new QueryBuilder());
231+
$qb->for(['v', 'e', 'p'], '1..5')
232+
->traverse('circles/A', 'OUTBOUND')
233+
->graph("traversalGraph")
234+
->prune(
235+
'e.theTruth',
236+
'==',
237+
true,
238+
'OR',
239+
'pruneCondition'
240+
)
241+
->return([
242+
'vertices' => 'p.vertices[*]._key',
243+
'edges' => 'p.edges[*].label'
244+
])
245+
->get();
246+
```
247+
Resulting AQL:
248+
```
249+
FOR v, e, p IN 1..5 OUTBOUND "circles/A" GRAPH "traversalGraph"
250+
PRUNE pruneCondition = e.theTruth == true
251+
RETURN {"vertices":p.vertices[*]._key,"edges":p.edges[*].label}
252+
```
253+
254+
255+
**Example - multiple predicates stored in variable:**
256+
```
257+
$qb = (new QueryBuilder());
258+
$qb->for(['v', 'e', 'p'], '1..5')
259+
->traverse('circles/A', 'OUTBOUND')
260+
->graph("traversalGraph")
261+
->prune(
262+
[
263+
'e.theTruth',
264+
'==',
265+
true
266+
],
267+
pruneVariable: 'pruneCondition'
268+
)
269+
->return([
270+
'vertices' => 'p.vertices[*]._key',
271+
'edges' => 'p.edges[*].label'
272+
])
273+
->get();
274+
```
275+
Resulting AQL:
276+
```
277+
FOR v, e, p IN 1..5 OUTBOUND "circles/A" GRAPH "traversalGraph"
278+
PRUNE pruneCondition = e.theTruth == true
279+
RETURN {"vertices":p.vertices[*]._key,"edges":p.edges[*].label}
205280
```
206281

207282
[ArangoDB PRUNE documentation](https://www.arangodb.com/docs/stable/aql/graphs-traversals.html#using-filters-and-the-explainer-to-extrapolate-the-costs)

src/Traits/ValidatesExpressions.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ public function isId($value): bool
129129
{
130130
if (
131131
is_string($value) &&
132-
preg_match("/^[a-zA-Z0-9_-]+\/[a-zA-Z0-9_-]+\/?[a-zA-Z0-9_\-\:\.\@\(\)\+\,\=\;\$\!\*\'\%]+$/", $value)
132+
preg_match("/^[a-zA-Z0-9_-]+\/(\/?[a-zA-Z0-9_\-\:\.\@\(\)\+\,\=\;\$\!\*\'\%])+$/", $value)
133133
) {
134134
return true;
135135
}

tests/Unit/AQL/GraphClausesTest.php

+114-31
Original file line numberDiff line numberDiff line change
@@ -128,58 +128,141 @@ public function testEdgeCollectionListClauseArrayInput()
128128
*/
129129
public function testPruneClause()
130130
{
131-
$result = (new QueryBuilder())
132-
->for('u', 'users')
133-
->prune('u.active', '==', 'true')
131+
$qb = (new QueryBuilder());
132+
$qb->for(['v', 'e', 'p'], '1..5')
133+
->traverse('circles/A', 'OUTBOUND')
134+
->graph("traversalGraph")
135+
->prune('e.theTruth', '==', true)
136+
->return([
137+
'vertices' => 'p.vertices[*]._key',
138+
'edges' => 'p.edges[*].label'
139+
])
134140
->get();
135-
self::assertEquals('FOR u IN users PRUNE u.active == true', $result->query);
141+
self::assertEquals(
142+
'FOR v, e, p IN 1..5 OUTBOUND "circles/A" GRAPH "traversalGraph"'
143+
. ' PRUNE e.theTruth == true'
144+
. ' RETURN {"vertices":p.vertices[*]._key,"edges":p.edges[*].label}',
145+
$qb->query
146+
);
136147

137-
$result = (new QueryBuilder())
138-
->for('u', 'Users')
139-
->prune('u.active', '==', 'true', 'OR')
140-
->get();
141-
self::assertEquals('FOR u IN Users PRUNE u.active == true', $result->query);
142-
143-
$result = (new QueryBuilder())
144-
->for('u', 'Users')
145-
->prune('u.active', '==', 'true')
148+
$qb = (new QueryBuilder());
149+
$qb->for(['v', 'e', 'p'], '1..5')
150+
->traverse('circles/A', 'OUTBOUND')
151+
->graph("traversalGraph")
152+
->prune('e.theTruth', '==', true, 'OR')
153+
->return([
154+
'vertices' => 'p.vertices[*]._key',
155+
'edges' => 'p.edges[*].label'
156+
])
146157
->get();
147-
self::assertEquals('FOR u IN Users PRUNE u.active == true', $result->query);
158+
self::assertEquals(
159+
'FOR v, e, p IN 1..5 OUTBOUND "circles/A" GRAPH "traversalGraph"'
160+
. ' PRUNE e.theTruth == true'
161+
. ' RETURN {"vertices":p.vertices[*]._key,"edges":p.edges[*].label}',
162+
$qb->query
163+
);
148164
}
149165

150166
/**
151167
* @covers \LaravelFreelancerNL\FluentAQL\Clauses\PruneClause
152168
*/
153169
public function testPruneClauseWithMultiplePredicates()
154170
{
155-
$result = (new QueryBuilder())
156-
->for('u', 'Users')
157-
->prune([['u.active', '==', 'true'], ['u.age', '>', 18]])
158-
->get();
159-
self::assertEquals('FOR u IN Users PRUNE u.active == true AND u.age > 18', $result->query);
171+
$qb = (new QueryBuilder());
172+
$qb->for(['v', 'e', 'p'], '1..5')
173+
->traverse('circles/A', 'OUTBOUND')
174+
->graph("traversalGraph")
175+
->prune([['e.active', '==', 'true'], ['e.age', '>', 18]])
176+
->return([
177+
'vertices' => 'p.vertices[*]._key',
178+
'edges' => 'p.edges[*].label'
179+
])
180+
->get();
181+
self::assertEquals(
182+
'FOR v, e, p IN 1..5 OUTBOUND "circles/A" GRAPH "traversalGraph"'
183+
. ' PRUNE e.active == true AND e.age > 18'
184+
. ' RETURN {"vertices":p.vertices[*]._key,"edges":p.edges[*].label}',
185+
$qb->query
186+
);
160187
}
161188

162189
/**
163190
* @covers \LaravelFreelancerNL\FluentAQL\Clauses\PruneClause
164191
*/
165192
public function testPruneClauseWithVariable()
166193
{
167-
$result = (new QueryBuilder())
168-
->for('u', 'users')
169-
->prune('u.active', '==', 'true', null, 'pruneCondition')
194+
$qb = (new QueryBuilder());
195+
$qb->for(['v', 'e', 'p'], '1..5')
196+
->traverse('circles/A', 'OUTBOUND')
197+
->graph("traversalGraph")
198+
->prune(
199+
'e.theTruth',
200+
'==',
201+
true,
202+
'OR',
203+
'pruneCondition'
204+
)
205+
->return([
206+
'vertices' => 'p.vertices[*]._key',
207+
'edges' => 'p.edges[*].label'
208+
])
170209
->get();
171-
self::assertEquals('FOR u IN users PRUNE pruneCondition = u.active == true', $result->query);
210+
self::assertEquals(
211+
'FOR v, e, p IN 1..5 OUTBOUND "circles/A" GRAPH "traversalGraph"'
212+
. ' PRUNE pruneCondition = e.theTruth == true'
213+
. ' RETURN {"vertices":p.vertices[*]._key,"edges":p.edges[*].label}',
214+
$qb->query
215+
);
172216

173-
$result = (new QueryBuilder())
174-
->for('u', 'Users')
175-
->prune('u.active', '==', 'true', 'OR', 'pruneCondition')
217+
$qb = (new QueryBuilder());
218+
$qb->for(['v', 'e', 'p'], '1..5')
219+
->traverse('circles/A', 'OUTBOUND')
220+
->graph("traversalGraph")
221+
->prune(
222+
[
223+
'e.theTruth',
224+
'==',
225+
true
226+
],
227+
pruneVariable: 'pruneCondition'
228+
)
229+
->return([
230+
'vertices' => 'p.vertices[*]._key',
231+
'edges' => 'p.edges[*].label'
232+
])
176233
->get();
177-
self::assertEquals('FOR u IN Users PRUNE pruneCondition = u.active == true', $result->query);
234+
self::assertEquals(
235+
'FOR v, e, p IN 1..5 OUTBOUND "circles/A" GRAPH "traversalGraph"'
236+
. ' PRUNE pruneCondition = e.theTruth == true'
237+
. ' RETURN {"vertices":p.vertices[*]._key,"edges":p.edges[*].label}',
238+
$qb->query
239+
);
178240

179-
$result = (new QueryBuilder())
180-
->for('u', 'Users')
181-
->prune(['u.active', '==', 'true'], pruneVariable: 'pruneCondition')
241+
$qb = (new QueryBuilder());
242+
$qb->for(['v', 'e', 'p'], '1..5')
243+
->traverse('circles/A', 'OUTBOUND')
244+
->graph("traversalGraph")
245+
->prune(
246+
[
247+
[
248+
'e.theTruth', '==', true
249+
],
250+
[
251+
'e.theTruth', '!=', false
252+
]
253+
],
254+
pruneVariable: 'pruneCondition'
255+
)
256+
->return([
257+
'vertices' => 'p.vertices[*]._key',
258+
'edges' => 'p.edges[*].label'
259+
])
182260
->get();
183-
self::assertEquals('FOR u IN Users PRUNE pruneCondition = u.active == true', $result->query);
261+
self::assertEquals(
262+
'FOR v, e, p IN 1..5 OUTBOUND "circles/A" GRAPH "traversalGraph"'
263+
. ' PRUNE pruneCondition = e.theTruth == true AND e.theTruth != false'
264+
. ' RETURN {"vertices":p.vertices[*]._key,"edges":p.edges[*].label}',
265+
$qb->query
266+
);
184267
}
185268
}

0 commit comments

Comments
 (0)