// Copyright 2017 JanusGraph Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package org.janusgraph.graphdb.tinkerpop.optimize;
import com.google.common.collect.Iterables;
import org.apache.tinkerpop.gremlin.structure.Graph;
import org.janusgraph.core.JanusGraphQuery;
import org.janusgraph.core.JanusGraphTransaction;
import org.janusgraph.graphdb.query.BaseQuery;
import org.janusgraph.graphdb.query.JanusGraphPredicate;
import org.janusgraph.graphdb.query.graph.GraphCentricQueryBuilder;
import org.janusgraph.graphdb.query.profile.QueryProfiler;
import org.janusgraph.graphdb.tinkerpop.profile.TP3ProfileWrapper;
import org.apache.tinkerpop.gremlin.process.traversal.Order;
import org.apache.tinkerpop.gremlin.process.traversal.step.HasContainerHolder;
import org.apache.tinkerpop.gremlin.process.traversal.step.Profiling;
import org.apache.tinkerpop.gremlin.process.traversal.step.map.GraphStep;
import org.apache.tinkerpop.gremlin.process.traversal.step.util.HasContainer;
import org.apache.tinkerpop.gremlin.process.traversal.util.MutableMetrics;
import org.apache.tinkerpop.gremlin.structure.Element;
import org.apache.tinkerpop.gremlin.structure.Vertex;
import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
/**
* @author Matthias Broecheler (me@matthiasb.com)
*/
public class JanusGraphStep<S, E extends Element> extends GraphStep<S, E> implements HasStepFolder<S, E>, Profiling, HasContainerHolder {
private final List<HasContainer> hasContainers = new ArrayList<>();
private int limit = BaseQuery.NO_LIMIT;
private List<OrderEntry> orders = new ArrayList<>();
private QueryProfiler queryProfiler = QueryProfiler.NO_OP;
public JanusGraphStep(final GraphStep<S, E> originalStep) {
super(originalStep.getTraversal(), originalStep.getReturnClass(), originalStep.isStartStep(), originalStep.getIds());
originalStep.getLabels().forEach(this::addLabel);
this.setIteratorSupplier(() -> {
if (this.ids != null && this.ids.length > 0) {
final Graph graph = (Graph)traversal.asAdmin().getGraph().get();
return iteratorList((Iterator)graph.vertices(this.ids));
}
JanusGraphTransaction tx = JanusGraphTraversalUtil.getTx(traversal);
JanusGraphQuery query = tx.query();
for (HasContainer condition : hasContainers) {
query.has(condition.getKey(), JanusGraphPredicate.Converter.convert(condition.getBiPredicate()), condition.getValue());
}
for (OrderEntry order : orders) query.orderBy(order.key, order.order);
if (limit != BaseQuery.NO_LIMIT) query.limit(limit);
((GraphCentricQueryBuilder) query).profiler(queryProfiler);
return Vertex.class.isAssignableFrom(this.returnClass) ? query.vertices().iterator() : query.edges().iterator();
});
}
@Override
public String toString() {
return this.hasContainers.isEmpty() ?
super.toString() : StringFactory.stepString(this, Arrays.toString(this.ids), this.hasContainers);
}
@Override
public void addAll(Iterable<HasContainer> has) {
HasStepFolder.splitAndP(hasContainers, has);
}
@Override
public void orderBy(String key, Order order) {
orders.add(new OrderEntry(key, order));
}
@Override
public void setLimit(int limit) {
this.limit = limit;
}
@Override
public int getLimit() {
return this.limit;
}
@Override
public void setMetrics(MutableMetrics metrics) {
queryProfiler = new TP3ProfileWrapper(metrics);
}
@Override
public List<HasContainer> getHasContainers() {
return this.hasContainers;
}
@Override
public void addHasContainer(final HasContainer hasContainer) {
this.addAll(Collections.singleton(hasContainer));
}
private <E extends Element> Iterator<E> iteratorList(final Iterator<E> iterator) {
final List<E> list = new ArrayList<E>();
while (iterator.hasNext()) {
final E e = iterator.next();
if (HasContainer.testAll(e, this.hasContainers))
list.add(e);
}
return list.iterator();
}
}