in gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SubgraphStrategy.java [133:281]
public void apply(final Traversal.Admin<?, ?> traversal) {
// do not apply subgraph strategy to already created subgraph filter branches (or else you get infinite recursion)
if (traversal.getStartStep().getLabels().contains(MARKER)) {
traversal.getStartStep().removeLabel(MARKER);
return;
}
final List<GraphStep> graphSteps = TraversalHelper.getStepsOfAssignableClass(GraphStep.class, traversal);
final List<VertexStep> vertexSteps = TraversalHelper.getStepsOfAssignableClass(VertexStep.class, traversal);
if (null != this.vertexCriterion) {
final List<Step> vertexStepsToInsertFilterAfter = new ArrayList<>();
vertexStepsToInsertFilterAfter.addAll(TraversalHelper.getStepsOfAssignableClass(EdgeOtherVertexStep.class, traversal));
vertexStepsToInsertFilterAfter.addAll(TraversalHelper.getStepsOfAssignableClass(EdgeVertexStep.class, traversal));
vertexStepsToInsertFilterAfter.addAll(TraversalHelper.getStepsOfAssignableClass(AddVertexStep.class, traversal));
vertexStepsToInsertFilterAfter.addAll(TraversalHelper.getStepsOfAssignableClass(AddVertexStartStep.class, traversal));
vertexStepsToInsertFilterAfter.addAll(graphSteps.stream().filter(GraphStep::returnsVertex).collect(Collectors.toList()));
vertexStepsToInsertFilterAfter.addAll(vertexSteps.stream().filter(VertexStep::returnsVertex).collect(Collectors.toList()));
applyCriterion(vertexStepsToInsertFilterAfter, traversal, s -> Optional.of(this.vertexCriterion.clone()));
}
if (null != this.edgeCriterion || checkAdjacentVertices) {
final List<Step> edgeStepsToInsertFilterAfter = new ArrayList<>();
edgeStepsToInsertFilterAfter.addAll(TraversalHelper.getStepsOfAssignableClass(AddEdgeStep.class, traversal));
edgeStepsToInsertFilterAfter.addAll(graphSteps.stream().filter(GraphStep::returnsEdge).collect(Collectors.toList()));
edgeStepsToInsertFilterAfter.addAll(vertexSteps.stream().filter(VertexStep::returnsEdge).collect(Collectors.toList()));
applyCriterion(edgeStepsToInsertFilterAfter, traversal, s -> {
if (checkAdjacentVertices && this.vertexCriterion != null) {
if (s instanceof VertexStep) {
// based on the directionality of the step choose the appropriate filter direction to apply.
// we scan skip AddEdgeStep, because its vertices must be in the Subgraph for it to even work.
final Direction d = ((VertexStep) s).getDirection();
final Traversal.Admin<Edge, ? extends Element> vertexPredicate;
vertexPredicate = getVertexPredicateGivenDirection(d);
return applyVertexPredicate(vertexPredicate);
} else if (s instanceof GraphStep) {
// for E() we need to test both incident vertices as there is no directionality
final Traversal.Admin<Edge, ? extends Element> vertexPredicate = __.<Edge>and(
__.inV().filter(this.vertexCriterion.clone()),
__.outV().filter(this.vertexCriterion.clone())).asAdmin();
return applyVertexPredicate(vertexPredicate);
}
}
if (null == edgeCriterion)
return Optional.empty();
else {
final Traversal.Admin<Edge, ?> ec = edgeCriterion.clone();
TraversalHelper.applyTraversalRecursively(t -> t.getStartStep().addLabel(MARKER), ec);
return Optional.of(ec);
}
});
}
// turn g.V().out() to g.V().outE().inV() only if there is an edge predicate
for (final VertexStep<?> step : vertexSteps) {
if (step.returnsEdge())
continue;
if (edgeCriterion != null) {
final VertexStep<Edge> someEStep = new VertexStep<>(traversal, Edge.class, step.getDirection(), step.getEdgeLabelsGValue());
final Step<Edge, Vertex> someVStep = step.getDirection() == Direction.BOTH ?
new EdgeOtherVertexStep(traversal) :
new EdgeVertexStep(traversal, step.getDirection().opposite());
TraversalHelper.replaceStep((Step<Vertex, Edge>) step, someEStep, traversal);
TraversalHelper.insertAfterStep(someVStep, someEStep, traversal);
TraversalHelper.copyLabels(step, someVStep, true);
TraversalHelper.insertAfterStep(new TraversalFilterStep<>(traversal, this.edgeCriterion.clone()), someEStep, traversal);
if (null != this.vertexCriterion)
TraversalHelper.insertAfterStep(new TraversalFilterStep<>(traversal, this.vertexCriterion.clone()), someVStep, traversal);
}
}
// turn g.V().properties() to g.V().properties().xxx
// turn g.V().values() to g.V().properties().xxx.value()
if (null != this.vertexPropertyCriterion) {
final OrStep<Object> checkPropertyCriterion = new OrStep(traversal,
new DefaultTraversal<>().addStep(new ClassFilterStep<>(traversal, VertexProperty.class, false)),
new DefaultTraversal<>().addStep(new TraversalFilterStep<>(traversal, this.vertexPropertyCriterion)));
final Traversal.Admin nonCheckPropertyCriterion = new DefaultTraversal<>().addStep(new TraversalFilterStep<>(traversal, this.vertexPropertyCriterion));
// turn all ElementValueTraversals into filters
for (final Step<?, ?> step : traversal.getSteps()) {
if (step instanceof TraversalParent) {
if (step instanceof PropertyMapStep) {
final char propertyType = processesPropertyType(step.getPreviousStep());
if ('p' != propertyType) {
final Traversal.Admin<?, ?> temp = new DefaultTraversal<>();
temp.addStep(new PropertiesStep<>(temp, PropertyType.PROPERTY, ((PropertyMapStep) step).getPropertyKeys()));
if ('v' == propertyType)
TraversalHelper.insertTraversal(0, nonCheckPropertyCriterion.clone(), temp);
else
temp.addStep(checkPropertyCriterion.clone());
((PropertyMapStep) step).setPropertyTraversal(temp);
}
} else {
Stream.concat(((TraversalParent) step).getGlobalChildren().stream(), ((TraversalParent) step).getLocalChildren().stream())
.filter(t -> t instanceof ValueTraversal)
.forEach(t -> {
final char propertyType = processesPropertyType(step.getPreviousStep());
if ('p' != propertyType) {
final Traversal.Admin<?, ?> temp = new DefaultTraversal<>();
temp.addStep(new PropertiesStep<>(temp, PropertyType.PROPERTY, ((ValueTraversal) t).getPropertyKey()));
if ('v' == propertyType)
TraversalHelper.insertTraversal(0, nonCheckPropertyCriterion.clone(), temp);
else
temp.addStep(checkPropertyCriterion.clone());
temp.addStep(new PropertyValueStep<>(temp));
temp.setParent((TraversalParent) step);
((ValueTraversal) t).setBypassTraversal(temp);
}
});
}
}
}
for (final PropertiesStep<?> step : TraversalHelper.getStepsOfAssignableClass(PropertiesStep.class, traversal)) {
final char propertyType = processesPropertyType(step.getPreviousStep());
if ('p' != propertyType) {
if (PropertyType.PROPERTY == ((PropertiesStep) step).getReturnType()) {
// if the property step returns a property, then simply append the criterion
if ('v' == propertyType) {
final Traversal.Admin<?, ?> temp = nonCheckPropertyCriterion.clone();
TraversalHelper.insertTraversal((Step) step, temp, traversal);
TraversalHelper.copyLabels(step, temp.getEndStep(), true);
} else {
final Step<?, ?> temp = checkPropertyCriterion.clone();
TraversalHelper.insertAfterStep(temp, (Step) step, traversal);
TraversalHelper.copyLabels(step, temp, true);
}
} else {
// if the property step returns value, then replace it with a property step, append criterion, then append a value() step
final Step propertiesStep = new PropertiesStep(traversal, PropertyType.PROPERTY, ((PropertiesStep) step).getPropertyKeys());
TraversalHelper.replaceStep(step, propertiesStep, traversal);
final Step propertyValueStep = new PropertyValueStep(traversal);
TraversalHelper.copyLabels(step, propertyValueStep, false);
if ('v' == propertyType) {
TraversalHelper.insertAfterStep(propertyValueStep, propertiesStep, traversal);
TraversalHelper.insertTraversal(propertiesStep, nonCheckPropertyCriterion.clone(), traversal);
} else {
TraversalHelper.insertAfterStep(propertyValueStep, propertiesStep, traversal);
TraversalHelper.insertAfterStep(checkPropertyCriterion.clone(), propertiesStep, traversal);
}
}
}
}
}
}