grakn.core.graql.gremlin.fragment.Fragments.java Source code

Java tutorial

Introduction

Here is the source code for grakn.core.graql.gremlin.fragment.Fragments.java

Source

/*
 * GRAKN.AI - THE KNOWLEDGE GRAPH
 * Copyright (C) 2018 Grakn Labs Ltd
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

package grakn.core.graql.gremlin.fragment;

import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import grakn.core.concept.ConceptId;
import grakn.core.concept.Label;
import grakn.core.concept.type.AttributeType;
import grakn.core.graql.executor.property.ValueExecutor;
import grakn.core.concept.printer.StringPrinter;
import grakn.core.server.kb.Schema;
import graql.lang.property.VarProperty;
import graql.lang.statement.Variable;
import org.apache.tinkerpop.gremlin.process.traversal.P;
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
import org.apache.tinkerpop.gremlin.structure.Edge;
import org.apache.tinkerpop.gremlin.structure.Element;
import org.apache.tinkerpop.gremlin.structure.Vertex;

import javax.annotation.Nullable;
import java.util.Set;

import static grakn.core.server.kb.Schema.EdgeLabel.SUB;
import static grakn.core.server.kb.Schema.VertexProperty.LABEL_ID;
import static grakn.core.server.kb.Schema.VertexProperty.THING_TYPE_LABEL_ID;
import static java.util.stream.Collectors.joining;

/**
 * Factory for creating instances of {@link Fragment}.
 */
public class Fragments {

    public static int TRAVERSE_ALL_SUB_EDGES = -1;
    public static int TRAVERSE_ONE_SUB_EDGE = 1;

    private Fragments() {
    }

    public static Fragment inRolePlayer(VarProperty varProperty, Variable rolePlayer, Variable edge,
            Variable relation, @Nullable Variable role, @Nullable ImmutableSet<Label> roleLabels,
            @Nullable ImmutableSet<Label> relationTypeLabels) {
        return new AutoValue_InRolePlayerFragment(varProperty, rolePlayer, relation, edge, role, roleLabels,
                relationTypeLabels);
    }

    public static Fragment outRolePlayer(VarProperty varProperty, Variable relation, Variable edge,
            Variable rolePlayer, @Nullable Variable role, @Nullable ImmutableSet<Label> roleLabels,
            @Nullable ImmutableSet<Label> relationTypeLabels) {
        return new AutoValue_OutRolePlayerFragment(varProperty, relation, rolePlayer, edge, role, roleLabels,
                relationTypeLabels);
    }

    public static Fragment inSub(VarProperty varProperty, Variable start, Variable end,
            int subTraversalDepthlimit) {
        return new AutoValue_InSubFragment(varProperty, start, end, subTraversalDepthlimit);
    }

    public static Fragment outSub(VarProperty varProperty, Variable start, Variable end,
            int subTraversalDepthLimit) {
        return new AutoValue_OutSubFragment(varProperty, start, end, subTraversalDepthLimit);
    }

    public static InRelatesFragment inRelates(VarProperty varProperty, Variable start, Variable end) {
        return new AutoValue_InRelatesFragment(varProperty, start, end);
    }

    public static Fragment outRelates(VarProperty varProperty, Variable start, Variable end) {
        return new AutoValue_OutRelatesFragment(varProperty, start, end);
    }

    public static Fragment inIsa(VarProperty varProperty, Variable start, Variable end,
            boolean mayHaveEdgeInstances) {
        return new AutoValue_InIsaFragment(varProperty, start, end, mayHaveEdgeInstances);
    }

    public static Fragment outIsa(VarProperty varProperty, Variable start, Variable end) {
        return new AutoValue_OutIsaFragment(varProperty, start, end);
    }

    public static Fragment dataType(VarProperty varProperty, Variable start, AttributeType.DataType dataType) {
        return new AutoValue_DataTypeFragment(varProperty, start, dataType);
    }

    public static Fragment inPlays(VarProperty varProperty, Variable start, Variable end, boolean required) {
        return new AutoValue_InPlaysFragment(varProperty, start, end, required);
    }

    public static Fragment outPlays(VarProperty varProperty, Variable start, Variable end, boolean required) {
        return new AutoValue_OutPlaysFragment(varProperty, start, end, required);
    }

    public static Fragment id(VarProperty varProperty, Variable start, ConceptId id) {
        return new AutoValue_IdFragment(varProperty, start, id);
    }

    // TODO: rename this to align with TypeProperty and TypeExecutor
    public static Fragment label(VarProperty varProperty, Variable start, ImmutableSet<Label> labels) {
        return new AutoValue_LabelFragment(varProperty, start, labels);
    }

    public static Fragment value(VarProperty varProperty, Variable start, ValueExecutor.Operation<?, ?> predicate) {
        return new ValueFragment(varProperty, start, predicate);
    }

    public static Fragment isAbstract(VarProperty varProperty, Variable start) {
        return new AutoValue_AbstractFragment(varProperty, start);
    }

    public static Fragment regex(VarProperty varProperty, Variable start, String regex) {
        return new AutoValue_RegexFragment(varProperty, start, regex);
    }

    public static Fragment notInternal(VarProperty varProperty, Variable start) {
        return new AutoValue_NotInternalFragment(varProperty, start);
    }

    public static Fragment neq(VarProperty varProperty, Variable start, Variable other) {
        return new AutoValue_NeqFragment(varProperty, start, other);
    }

    /**
     * A {@link Fragment} that uses an index stored on each attribute. Attributes are indexed by direct type and value.
     */
    public static Fragment attributeIndex(@Nullable VarProperty varProperty, Variable start, Label label,
            Object attributeValue) {
        return new AutoValue_AttributeIndexFragment(varProperty, start, label, attributeValue.toString());
    }

    /**
     * Default unlimiteid depth sub-edge traversal
     * @param traversal
     * @param <T>
     * @return
     */
    static <T> GraphTraversal<T, Vertex> outSubs(GraphTraversal<T, Vertex> traversal) {
        return outSubs(traversal, TRAVERSE_ALL_SUB_EDGES);
    }

    /**
     * @param traversal
     * @param subTraversalDepth: the number of `sub` edges to follow. -1 (= TRAVERSE_ALL_SUB_EDGES) applies no limit, 0 follows no edges, 1 (= TRAVERSE_ONE_SUB_EDGE) follows 1 edge etc.
     * @param <T>
     * @return
     */
    static <T> GraphTraversal<T, Vertex> outSubs(GraphTraversal<T, Vertex> traversal, int subTraversalDepth) {
        // These traversals make sure to only navigate types by checking they do not have a `THING_TYPE_LABEL_ID` property
        return union(traversal,
                ImmutableSet.of(
                        __.<Vertex>not(__.has(THING_TYPE_LABEL_ID.name()))
                                .not(__.hasLabel(Schema.BaseType.SHARD.name())),
                        __.<Vertex>until(__.loops().is(subTraversalDepth)).repeat(__.out(SUB.getLabel())).emit()))
                                .unfold();
    }

    /**
     * Default unlimited-depth sub-edge traversal
     * @param traversal
     * @param <T>
     * @return
     */
    static <T> GraphTraversal<T, Vertex> inSubs(GraphTraversal<T, Vertex> traversal) {
        return inSubs(traversal, TRAVERSE_ALL_SUB_EDGES);
    }

    /**
     * @param traversal
     * @param subTraversalDepth: the number of `sub` edges to follow. -1 (= TRAVERSE_ALL_SUB_EDGES) applies no limit, 0 follows no edges, 1 (= TRAVERSE_ONE_SUB_EDGE) follows 1 edge etc.
     * @param <T>
     * @return
     */
    static <T> GraphTraversal<T, Vertex> inSubs(GraphTraversal<T, Vertex> traversal, int subTraversalDepth) {
        // These traversals make sure to only navigate types by checking they do not have a `THING_TYPE_LABEL_ID` property
        return union(traversal,
                ImmutableSet.of(
                        __.<Vertex>not(__.has(THING_TYPE_LABEL_ID.name()))
                                .not(__.hasLabel(Schema.BaseType.SHARD.name())),
                        __.<Vertex>until(__.loops().is(subTraversalDepth)).repeat(__.in(SUB.getLabel())).emit()))
                                .unfold();
    }

    /**
     * A type-safe way to do `__.union(a, b)`, as `Fragments.union(ImmutableSet.of(a, b))`.
     * This avoids issues with unchecked varargs.
     */
    static <S, E> GraphTraversal<S, E> union(Iterable<GraphTraversal<? super S, ? extends E>> traversals) {
        return union(__.identity(), traversals);
    }

    /**
     * A type-safe way to do `a.union(b, c)`, as `Fragments.union(a, ImmutableSet.of(b, c))`.
     * This avoids issues with unchecked varargs.
     */
    static <S, E1, E2> GraphTraversal<S, E2> union(GraphTraversal<S, ? extends E1> start,
            Iterable<GraphTraversal<? super E1, ? extends E2>> traversals) {
        // This is safe, because we know all the arguments are of the right type
        //noinspection unchecked
        GraphTraversal<E1, E2>[] array = (GraphTraversal<E1, E2>[]) Iterables.toArray(traversals,
                GraphTraversal.class);

        return start.union(array);
    }

    /**
     * Create a traversal that filters to only vertices
     */
    static <T> GraphTraversal<T, Vertex> isVertex(GraphTraversal<T, ? extends Element> traversal) {
        // This cast is safe because we filter only to vertices
        //noinspection unchecked
        return (GraphTraversal<T, Vertex>) traversal.filter(e -> e.get() instanceof Vertex);
    }

    /**
     * Create a traversal that filters to only edges
     */
    static <T> GraphTraversal<T, Edge> isEdge(GraphTraversal<T, ? extends Element> traversal) {
        // This cast is safe because we filter only to edges
        //noinspection unchecked
        return (GraphTraversal<T, Edge>) traversal.filter(e -> e.get() instanceof Edge);
    }

    static String displayOptionalTypeLabels(String name, @Nullable Set<Label> typeLabels) {
        if (typeLabels != null) {
            return " " + name + ":" + typeLabels.stream().map(StringPrinter::label).collect(joining(","));
        } else {
            return "";
        }
    }

    static <S> GraphTraversal<S, Vertex> traverseSchemaConceptFromEdge(GraphTraversal<S, Edge> traversal,
            Schema.EdgeProperty edgeProperty) {

        // Access label ID from edge
        Variable labelId = new Variable();
        traversal.values(edgeProperty.name()).as(labelId.symbol());

        // Look up schema concept using ID
        return traversal.V().has(LABEL_ID.name(), __.where(P.eq(labelId.symbol())));
    }

}