http://git-wip-us.apache.org/repos/asf/atlas/blob/0877e47c/repository/src/main/java/org/apache/atlas/gremlin/Gremlin3ExpressionFactory.java ---------------------------------------------------------------------- diff --git a/repository/src/main/java/org/apache/atlas/gremlin/Gremlin3ExpressionFactory.java b/repository/src/main/java/org/apache/atlas/gremlin/Gremlin3ExpressionFactory.java deleted file mode 100644 index b936695..0000000 --- a/repository/src/main/java/org/apache/atlas/gremlin/Gremlin3ExpressionFactory.java +++ /dev/null @@ -1,485 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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.apache.atlas.gremlin; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.apache.atlas.AtlasException; -import org.apache.atlas.groovy.AbstractFunctionExpression; -import org.apache.atlas.groovy.CastExpression; -import org.apache.atlas.groovy.ClosureExpression; -import org.apache.atlas.groovy.ComparisonExpression; -import org.apache.atlas.groovy.ComparisonExpression.ComparisonOperator; -import org.apache.atlas.groovy.ComparisonOperatorExpression; -import org.apache.atlas.groovy.FieldExpression; -import org.apache.atlas.groovy.FunctionCallExpression; -import org.apache.atlas.groovy.GroovyExpression; -import org.apache.atlas.groovy.IdentifierExpression; -import org.apache.atlas.groovy.LiteralExpression; -import org.apache.atlas.groovy.LogicalExpression; -import org.apache.atlas.groovy.LogicalExpression.LogicalOperator; -import org.apache.atlas.groovy.TernaryOperatorExpression; -import org.apache.atlas.groovy.TraversalStepType; -import org.apache.atlas.groovy.TypeCoersionExpression; -import org.apache.atlas.query.GraphPersistenceStrategies; -import org.apache.atlas.query.TypeUtils.FieldInfo; -import org.apache.atlas.repository.graph.AtlasGraphProvider; -import org.apache.atlas.repository.graphdb.AtlasGraph; -import org.apache.atlas.typesystem.types.AttributeInfo; -import org.apache.atlas.typesystem.types.IDataType; - -/** - * Generates gremlin query expressions using Gremlin 3 syntax. - * - */ -public class Gremlin3ExpressionFactory extends GremlinExpressionFactory { - - - - private static final String VERTEX_LIST_CLASS = "List<Vertex>"; - private static final String VERTEX_ARRAY_CLASS = "Vertex[]"; - private static final String OBJECT_ARRAY_CLASS = "Object[]"; - private static final String VERTEX_CLASS = "Vertex"; - private static final String FUNCTION_CLASS = "Function"; - - private static final String VALUE_METHOD = "value"; - private static final String IS_PRESENT_METHOD = "isPresent"; - private static final String MAP_METHOD = "map"; - private static final String VALUES_METHOD = "values"; - private static final String GET_METHOD = "get"; - private static final String OR_ELSE_METHOD = "orElse"; - private static final String PROPERTY_METHOD = "property"; - private static final String BY_METHOD = "by"; - private static final String EQ_METHOD = "eq"; - private static final String EMIT_METHOD = "emit"; - private static final String TIMES_METHOD = "times"; - private static final String REPEAT_METHOD = "repeat"; - private static final String RANGE_METHOD = "range"; - private static final String LAST_METHOD = "last"; - private static final String TO_STRING_METHOD = "toString"; - - private static final GroovyExpression EMPTY_STRING_EXPRESSION = new LiteralExpression(""); - - @Override - public GroovyExpression generateLogicalExpression(GroovyExpression parent, String operator, - List<GroovyExpression> operands) { - return new FunctionCallExpression(TraversalStepType.FILTER, parent, operator, operands); - } - - @Override - public GroovyExpression generateBackReferenceExpression(GroovyExpression parent, boolean inSelect, String alias) { - if (inSelect) { - return getFieldInSelect(); - } else { - return new FunctionCallExpression(TraversalStepType.MAP_TO_ELEMENT, parent, SELECT_METHOD, new LiteralExpression(alias)); - } - } - - @Override - public GroovyExpression typeTestExpression(GraphPersistenceStrategies s, String typeName, GroovyExpression itRef) { - LiteralExpression superTypeAttrExpr = new LiteralExpression(s.superTypeAttributeName()); - LiteralExpression typeNameExpr = new LiteralExpression(typeName); - LiteralExpression typeAttrExpr = new LiteralExpression(s.typeAttributeName()); - FunctionCallExpression result = new FunctionCallExpression(TraversalStepType.FILTER, HAS_METHOD, typeAttrExpr, new FunctionCallExpression(EQ_METHOD, typeNameExpr)); - result = new FunctionCallExpression(TraversalStepType.FILTER, result, "or"); - result = new FunctionCallExpression(TraversalStepType.FILTER, result, HAS_METHOD, superTypeAttrExpr, new FunctionCallExpression(EQ_METHOD, typeNameExpr)); - return result; - - } - - @Override - public GroovyExpression generateLoopExpression(GroovyExpression parent,GraphPersistenceStrategies s, IDataType dataType, GroovyExpression loopExpr, String alias, Integer times) { - - GroovyExpression emitExpr = generateLoopEmitExpression(s, dataType); - - GroovyExpression result = new FunctionCallExpression(TraversalStepType.BRANCH, parent, REPEAT_METHOD, loopExpr); - if (times != null) { - GroovyExpression timesExpr = new LiteralExpression(times); - result = new FunctionCallExpression(TraversalStepType.SIDE_EFFECT, result, TIMES_METHOD, timesExpr); - } - result = new FunctionCallExpression(TraversalStepType.SIDE_EFFECT, result, EMIT_METHOD, emitExpr); - return result; - - } - - @Override - public GroovyExpression getLoopExpressionParent(GroovyExpression inputQry) { - GroovyExpression curTraversal = getAnonymousTraversalStartExpression(); - return curTraversal; - } - - private IdentifierExpression getAnonymousTraversalStartExpression() { - return new IdentifierExpression(TraversalStepType.START, "__"); - } - - @Override - public GroovyExpression generateSelectExpression(GroovyExpression parent, List<LiteralExpression> sourceNames, - List<GroovyExpression> srcExprs) { - FunctionCallExpression result = new FunctionCallExpression(TraversalStepType.MAP_TO_VALUE, parent, SELECT_METHOD, sourceNames); - - for (GroovyExpression expr : srcExprs) { - GroovyExpression closure = new ClosureExpression(expr); - GroovyExpression castClosure = new TypeCoersionExpression(closure, FUNCTION_CLASS); - result = new FunctionCallExpression(TraversalStepType.SIDE_EFFECT, result, BY_METHOD, castClosure); - } - return result; - } - - @Override - public GroovyExpression generateFieldExpression(GroovyExpression parent, FieldInfo fInfo, - String propertyName, boolean inSelect) { - - AttributeInfo attrInfo = fInfo.attrInfo(); - IDataType attrType = attrInfo.dataType(); - GroovyExpression propertyNameExpr = new LiteralExpression(propertyName); - //Whether it is the user or shared graph does not matter here, since we're - //just getting the conversion expression. Ideally that would be moved someplace else. - AtlasGraph graph = AtlasGraphProvider.getGraphInstance(); - if (inSelect) { - - GroovyExpression expr = new FunctionCallExpression(parent, PROPERTY_METHOD, propertyNameExpr); - expr = new FunctionCallExpression(expr, OR_ELSE_METHOD, LiteralExpression.NULL); - return graph.generatePersisentToLogicalConversionExpression(expr, attrType); - } else { - - GroovyExpression unmapped = new FunctionCallExpression(TraversalStepType.FLAT_MAP_TO_VALUES, parent, VALUES_METHOD, propertyNameExpr); - if (graph.isPropertyValueConversionNeeded(attrType)) { - GroovyExpression toConvert = new FunctionCallExpression(getItVariable(), GET_METHOD); - - GroovyExpression conversionFunction = graph.generatePersisentToLogicalConversionExpression(toConvert, - attrType); - return new FunctionCallExpression(TraversalStepType.MAP_TO_VALUE, unmapped, MAP_METHOD, new ClosureExpression(conversionFunction)); - } else { - return unmapped; - } - - } - } - - private ComparisonOperator getGroovyOperator(String symbol) throws AtlasException { - - String toFind = symbol; - if (toFind.equals("=")) { - toFind = "=="; - } - return ComparisonOperator.lookup(toFind); - } - - private String getComparisonFunction(String op) throws AtlasException { - - if (op.equals("=")) { - return "eq"; - } - if (op.equals("!=")) { - return "neq"; - } - if (op.equals(">")) { - return "gt"; - } - if (op.equals(">=")) { - return "gte"; - } - if (op.equals("<")) { - return "lt"; - } - if (op.equals("<=")) { - return "lte"; - } - throw new AtlasException("Comparison operator " + op + " not supported in Gremlin"); - } - - @Override - public GroovyExpression generateHasExpression(GraphPersistenceStrategies s, GroovyExpression parent, - String propertyName, String symbol, GroovyExpression requiredValue, FieldInfo fInfo) throws AtlasException { - - AttributeInfo attrInfo = fInfo.attrInfo(); - IDataType attrType = attrInfo.dataType(); - GroovyExpression propertNameExpr = new LiteralExpression(propertyName); - if (s.isPropertyValueConversionNeeded(attrType)) { - // for some types, the logical value cannot be stored directly in - // the underlying graph, - // and conversion logic is needed to convert the persistent form of - // the value - // to the actual value. In cases like this, we generate a conversion - // expression to - // do this conversion and use the filter step to perform the - // comparsion in the gremlin query - GroovyExpression itExpr = getItVariable(); - GroovyExpression vertexExpr = new CastExpression(new FunctionCallExpression(itExpr, GET_METHOD), VERTEX_CLASS); - GroovyExpression propertyValueExpr = new FunctionCallExpression(vertexExpr, VALUE_METHOD, propertNameExpr); - GroovyExpression conversionExpr = s.generatePersisentToLogicalConversionExpression(propertyValueExpr, - attrType); - - GroovyExpression propertyIsPresentExpression = new FunctionCallExpression( - new FunctionCallExpression(vertexExpr, PROPERTY_METHOD, propertNameExpr), IS_PRESENT_METHOD); - GroovyExpression valueMatchesExpr = new ComparisonExpression(conversionExpr, getGroovyOperator(symbol), - requiredValue); - - GroovyExpression filterCondition = new LogicalExpression(propertyIsPresentExpression, LogicalOperator.AND, - valueMatchesExpr); - - GroovyExpression filterFunction = new ClosureExpression(filterCondition); - return new FunctionCallExpression(TraversalStepType.FILTER, parent, FILTER_METHOD, filterFunction); - } else { - GroovyExpression valueMatches = new FunctionCallExpression(getComparisonFunction(symbol), requiredValue); - return new FunctionCallExpression(TraversalStepType.FILTER, parent, HAS_METHOD, propertNameExpr, valueMatches); - } - } - - @Override - public GroovyExpression generateLikeExpressionUsingFilter(GroovyExpression parent, String propertyName, GroovyExpression propertyValue) throws AtlasException { - GroovyExpression vertexExpr = new FunctionCallExpression(getItVariable(), GET_METHOD); - GroovyExpression propertyValueExpr = new FunctionCallExpression(vertexExpr, VALUE_METHOD, new LiteralExpression(propertyName)); - GroovyExpression matchesExpr = new FunctionCallExpression(propertyValueExpr, MATCHES, escapePropertyValue(propertyValue)); - GroovyExpression closureExpr = new ClosureExpression(matchesExpr); - - return new FunctionCallExpression(TraversalStepType.FILTER, parent, FILTER_METHOD, closureExpr); - } - - private GroovyExpression escapePropertyValue(GroovyExpression propertyValue) { - GroovyExpression ret = propertyValue; - - if (propertyValue instanceof LiteralExpression) { - LiteralExpression exp = (LiteralExpression) propertyValue; - - if (exp != null && exp.getValue() instanceof String) { - String stringValue = (String) exp.getValue(); - - // replace '*' with ".*", replace '?' with '.' - stringValue = stringValue.replaceAll("\\*", ".*") - .replaceAll("\\?", "."); - - ret = new LiteralExpression(stringValue); - } - } - - return ret; - } - - @Override - protected GroovyExpression initialExpression(GroovyExpression varExpr, GraphPersistenceStrategies s) { - - // this bit of groovy magic converts the set of vertices in varName into - // a String containing the ids of all the vertices. This becomes the - // argument - // to g.V(). This is needed because Gremlin 3 does not support - // _() - // s"g.V(${varName}.collect{it.id()} as String[])" - - GroovyExpression gExpr = getGraphExpression(); - GroovyExpression varRefExpr = new TypeCoersionExpression(varExpr, OBJECT_ARRAY_CLASS); - GroovyExpression matchingVerticesExpr = new FunctionCallExpression(TraversalStepType.START, gExpr, V_METHOD, varRefExpr); - GroovyExpression isEmpty = new FunctionCallExpression(varExpr, "isEmpty"); - GroovyExpression emptyGraph = getEmptyTraversalExpression(); - - GroovyExpression expr = new TernaryOperatorExpression(isEmpty, emptyGraph, matchingVerticesExpr); - - return s.addInitialQueryCondition(expr); - } - - private GroovyExpression getEmptyTraversalExpression() { - GroovyExpression emptyGraph = new FunctionCallExpression(TraversalStepType.START, getGraphExpression(), V_METHOD, EMPTY_STRING_EXPRESSION); - return emptyGraph; - } - - @Override - public GroovyExpression generateRangeExpression(GroovyExpression parent, int startIndex, int endIndex) { - //treat as barrier step, since limits need to be applied globally (even though it - //is technically a filter step) - return new FunctionCallExpression(TraversalStepType.BARRIER, parent, RANGE_METHOD, new LiteralExpression(startIndex), new LiteralExpression(endIndex)); - } - - @Override - public boolean isRangeExpression(GroovyExpression expr) { - - return (expr instanceof FunctionCallExpression && ((FunctionCallExpression)expr).getFunctionName().equals(RANGE_METHOD)); - } - - @Override - public int[] getRangeParameters(AbstractFunctionExpression expr) { - - if (isRangeExpression(expr)) { - FunctionCallExpression rangeExpression = (FunctionCallExpression) expr; - List<GroovyExpression> arguments = rangeExpression.getArguments(); - int startIndex = (int)((LiteralExpression)arguments.get(0)).getValue(); - int endIndex = (int)((LiteralExpression)arguments.get(1)).getValue(); - return new int[]{startIndex, endIndex}; - } - else { - return null; - } - } - - @Override - public void setRangeParameters(GroovyExpression expr, int startIndex, int endIndex) { - - if (isRangeExpression(expr)) { - FunctionCallExpression rangeExpression = (FunctionCallExpression) expr; - rangeExpression.setArgument(0, new LiteralExpression(Integer.valueOf(startIndex))); - rangeExpression.setArgument(1, new LiteralExpression(Integer.valueOf(endIndex))); - } - else { - throw new IllegalArgumentException(expr + " is not a valid range expression"); - } - } - - @Override - public List<GroovyExpression> getOrderFieldParents() { - - List<GroovyExpression> result = new ArrayList<>(1); - result.add(null); - return result; - } - - @Override - public GroovyExpression generateOrderByExpression(GroovyExpression parent, List<GroovyExpression> translatedOrderBy, - boolean isAscending) { - - GroovyExpression orderByExpr = translatedOrderBy.get(0); - GroovyExpression orderByClosure = new ClosureExpression(orderByExpr); - GroovyExpression orderByClause = new TypeCoersionExpression(orderByClosure, FUNCTION_CLASS); - - GroovyExpression aExpr = new IdentifierExpression("a"); - GroovyExpression bExpr = new IdentifierExpression("b"); - - GroovyExpression aCompExpr = new FunctionCallExpression(new FunctionCallExpression(aExpr, TO_STRING_METHOD), TO_LOWER_CASE_METHOD); - GroovyExpression bCompExpr = new FunctionCallExpression(new FunctionCallExpression(bExpr, TO_STRING_METHOD), TO_LOWER_CASE_METHOD); - - GroovyExpression comparisonExpr = null; - if (isAscending) { - comparisonExpr = new ComparisonOperatorExpression(aCompExpr, bCompExpr); - } else { - comparisonExpr = new ComparisonOperatorExpression(bCompExpr, aCompExpr); - } - ClosureExpression comparisonFunction = new ClosureExpression(comparisonExpr, "a", "b"); - FunctionCallExpression orderCall = new FunctionCallExpression(TraversalStepType.BARRIER, parent, ORDER_METHOD); - return new FunctionCallExpression(TraversalStepType.SIDE_EFFECT, orderCall, BY_METHOD, orderByClause, comparisonFunction); - } - - @Override - public GroovyExpression getAnonymousTraversalExpression() { - return null; - } - - @Override - public GroovyExpression getFieldInSelect() { - // this logic is needed to remove extra results from - // what is emitted by repeat loops. Technically - // for queries that don't have a loop in them we could just use "it" - // the reason for this is that in repeat loops with an alias, - // although the alias gets set to the right value, for some - // reason the select actually includes all vertices that were traversed - // through in the loop. In these cases, we only want the last vertex - // traversed in the loop to be selected. The logic here handles that - // case by converting the result to a list and just selecting the - // last item from it. - - GroovyExpression itExpr = getItVariable(); - GroovyExpression expr1 = new TypeCoersionExpression(itExpr, VERTEX_ARRAY_CLASS); - GroovyExpression expr2 = new TypeCoersionExpression(expr1, VERTEX_LIST_CLASS); - - return new FunctionCallExpression(expr2, LAST_METHOD); - } - - @Override - public GroovyExpression generateGroupByExpression(GroovyExpression parent, GroovyExpression groupByExpression, - GroovyExpression aggregationFunction) { - - GroovyExpression result = new FunctionCallExpression(TraversalStepType.BARRIER, parent, "group"); - GroovyExpression groupByClosureExpr = new TypeCoersionExpression(new ClosureExpression(groupByExpression), "Function"); - result = new FunctionCallExpression(TraversalStepType.SIDE_EFFECT, result, "by", groupByClosureExpr); - result = new FunctionCallExpression(TraversalStepType.END, result, "toList"); - - GroovyExpression mapValuesClosure = new ClosureExpression(new FunctionCallExpression(new CastExpression(getItVariable(), "Map"), "values")); - - result = new FunctionCallExpression(result, "collect", mapValuesClosure); - - //when we call Map.values(), we end up with an extra list around the result. We remove this by calling toList().get(0). This - //leaves us with a list of lists containing the vertices that match each group. We then apply the aggregation functions - //specified in the select list to each of these inner lists. - - result = new FunctionCallExpression(result ,"toList"); - result = new FunctionCallExpression(result, "get", new LiteralExpression(0)); - - GroovyExpression aggregrationFunctionClosure = new ClosureExpression(aggregationFunction); - result = new FunctionCallExpression(result, "collect", aggregrationFunctionClosure); - return result; - } - - @Override - public GroovyExpression generateSeededTraversalExpresssion(boolean isMap, GroovyExpression valueCollection) { - GroovyExpression coersedExpression = new TypeCoersionExpression(valueCollection, isMap ? "Map[]" : "Vertex[]"); - if(isMap) { - - return new FunctionCallExpression(TraversalStepType.START, "__", coersedExpression); - } - else { - //We cannot always use an anonymous traversal because that breaks repeat steps - return new FunctionCallExpression(TraversalStepType.START, getEmptyTraversalExpression(), "inject", coersedExpression); - } - } - - @Override - public GroovyExpression getGroupBySelectFieldParent() { - return null; - } - - @Override - public String getTraversalExpressionClass() { - return "GraphTraversal"; - } - - @Override - public boolean isSelectGeneratesMap(int aliasCount) { - //in Gremlin 3, you only get a map if there is more than 1 alias. - return aliasCount > 1; - } - - @Override - public GroovyExpression generateMapExpression(GroovyExpression parent, ClosureExpression closureExpression) { - return new FunctionCallExpression(TraversalStepType.MAP_TO_ELEMENT, parent, "map", closureExpression); - } - - @Override - public GroovyExpression generateGetSelectedValueExpression(LiteralExpression key, - GroovyExpression rowMapExpr) { - rowMapExpr = new CastExpression(rowMapExpr, "Map"); - GroovyExpression getExpr = new FunctionCallExpression(rowMapExpr, "get", key); - return getExpr; - } - - @Override - public GroovyExpression getCurrentTraverserObject(GroovyExpression traverser) { - return new FunctionCallExpression(traverser, "get"); - } - - public List<String> getAliasesRequiredByExpression(GroovyExpression expr) { - return Collections.emptyList(); - } - - @Override - public boolean isRepeatExpression(GroovyExpression expr) { - if(!(expr instanceof FunctionCallExpression)) { - return false; - } - return ((FunctionCallExpression)expr).getFunctionName().equals(REPEAT_METHOD); - } -}
http://git-wip-us.apache.org/repos/asf/atlas/blob/0877e47c/repository/src/main/java/org/apache/atlas/gremlin/GremlinExpressionFactory.java ---------------------------------------------------------------------- diff --git a/repository/src/main/java/org/apache/atlas/gremlin/GremlinExpressionFactory.java b/repository/src/main/java/org/apache/atlas/gremlin/GremlinExpressionFactory.java deleted file mode 100644 index d603150..0000000 --- a/repository/src/main/java/org/apache/atlas/gremlin/GremlinExpressionFactory.java +++ /dev/null @@ -1,658 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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_METHOD 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.apache.atlas.gremlin; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.atlas.AtlasException; -import org.apache.atlas.groovy.AbstractFunctionExpression; -import org.apache.atlas.groovy.ArithmeticExpression; -import org.apache.atlas.groovy.ArithmeticExpression.ArithmeticOperator; -import org.apache.atlas.groovy.CastExpression; -import org.apache.atlas.groovy.ClosureExpression; -import org.apache.atlas.groovy.FieldExpression; -import org.apache.atlas.groovy.FunctionCallExpression; -import org.apache.atlas.groovy.GroovyExpression; -import org.apache.atlas.groovy.IdentifierExpression; -import org.apache.atlas.groovy.ListExpression; -import org.apache.atlas.groovy.LiteralExpression; -import org.apache.atlas.groovy.TraversalStepType; -import org.apache.atlas.groovy.TypeCoersionExpression; -import org.apache.atlas.groovy.VariableAssignmentExpression; -import org.apache.atlas.query.GraphPersistenceStrategies; -import org.apache.atlas.query.IntSequence; -import org.apache.atlas.query.TypeUtils.FieldInfo; -import org.apache.atlas.repository.graph.AtlasGraphProvider; -import org.apache.atlas.repository.graphdb.AtlasEdgeDirection; -import org.apache.atlas.repository.graphdb.GremlinVersion; -import org.apache.atlas.typesystem.types.IDataType; -import org.apache.atlas.typesystem.types.TypeSystem; -import org.apache.atlas.typesystem.types.cache.TypeCache.TYPE_FILTER; -import org.apache.atlas.util.AtlasRepositoryConfiguration; - -import com.google.common.collect.ImmutableList; - -/** - * Factory to generate Groovy expressions representing Gremlin syntax that that - * are independent of the specific version of Gremlin that is being used. - * - */ -public abstract class GremlinExpressionFactory { - - private static final String G_VARIABLE = "g"; - private static final String IT_VARIABLE = "it"; - - protected static final String SET_CLASS = "Set"; - - - private static final String OBJECT_FIELD = "object"; - - protected static final String V_METHOD = "V"; - protected static final String FILTER_METHOD = "filter"; - private static final String PATH_METHOD = "path"; - private static final String AS_METHOD = "as"; - private static final String IN_OPERATOR = "in"; - protected static final String HAS_METHOD = "has"; - protected static final String TO_LOWER_CASE_METHOD = "toLowerCase"; - protected static final String SELECT_METHOD = "select"; - protected static final String ORDER_METHOD = "order"; - protected static final String FILL_METHOD = "fill"; - protected static final String MATCHES = "matches"; - - public static final GremlinExpressionFactory INSTANCE = AtlasGraphProvider.getGraphInstance() - .getSupportedGremlinVersion() == GremlinVersion.THREE ? new Gremlin3ExpressionFactory() - : new Gremlin2ExpressionFactory(); - - /** - * Returns the unqualified name of the class used in this version of gremlin to - * represent Gremlin queries as they are being generated. - * @return - */ - public abstract String getTraversalExpressionClass(); - - /** - * Gets the expression to use as the parent when translating the loop - * expression in a loop - * - * @param inputQry - * the - * @return - */ - public abstract GroovyExpression getLoopExpressionParent(GroovyExpression inputQry); - - /** - * Generates a loop expression. - * - * @param parent - * the parent of the loop expression - * @param emitExpr - * Expression with the value that should be emitted by the loop - * expression. - * @param loopExpr - * the query expression that is being executed repeatedly - * executed in a loop - * @param alias - * The alias of the expression being looped over - * @param times - * the number of times to repeat, or null if a times condition - * should not be used. - * @return - */ - public abstract GroovyExpression generateLoopExpression(GroovyExpression parent, GraphPersistenceStrategies s, IDataType dataType, - GroovyExpression loopExpr, String alias, Integer times); - - - /** - * Generates a logical (and/or) expression with the given operands. - * @param parent - * @param operator - * @param operands - * @return - */ - public abstract GroovyExpression generateLogicalExpression(GroovyExpression parent, String operator, - List<GroovyExpression> operands); - - /** - * Generates a back reference expression that refers to the given alias. - * - * @param parent - * @param inSelect - * @param alias - * @return - */ - public abstract GroovyExpression generateBackReferenceExpression(GroovyExpression parent, boolean inSelect, - String alias); - - /** - * Generates a select expression - * - * @param parent - * @param sourceNames - * the names of the select fields - * @param srcExprs - * the corresponding values to return - * @return - */ - public abstract GroovyExpression generateSelectExpression(GroovyExpression parent, - List<LiteralExpression> sourceNames, List<GroovyExpression> srcExprs); - - /** - * Generates a an expression that gets the value of the given property from the - * vertex presented by the parent. - * - * @param parent - * @param fInfo - * @param propertyName - * @param inSelect - * @return - */ - public abstract GroovyExpression generateFieldExpression(GroovyExpression parent, FieldInfo fInfo, - String propertyName, boolean inSelect); - - /** - * Generates a has expression that checks whether the vertices match a specific condition - * - * @param s - * @param parent the object that we should call apply the "has" condition to. - * @param propertyName the name of the property whose value we are comparing - * @param symbol comparsion operator symbol ('=','<', etc.) - * @param requiredValue the value to compare against - * @param fInfo info about the field whose value we are checking - * @return - * @throws AtlasException - */ - public abstract GroovyExpression generateHasExpression(GraphPersistenceStrategies s, GroovyExpression parent, - String propertyName, String symbol, GroovyExpression requiredValue, FieldInfo fInfo) throws AtlasException; - - public abstract GroovyExpression generateLikeExpressionUsingFilter(GroovyExpression parent, String propertyName, - GroovyExpression propertyValue) throws AtlasException; - - /** - * Generates a range expression - * - * @param parent - * @param startIndex - * @param endIndex - * @return - */ - public abstract GroovyExpression generateRangeExpression(GroovyExpression parent, int startIndex, int endIndex); - - /** - * Determines if the specified expression is a range method call. - * - * @param expr - * @return - */ - public abstract boolean isRangeExpression(GroovyExpression expr); - - /** - * Set the start index and end index of a range expression - * - * @param expr - * @param startIndex - * @param endIndex - */ - public abstract void setRangeParameters(GroovyExpression expr, int startIndex, int endIndex); - - /** - * If the specified function expression is a range expression, returns the start and end index parameters - * otherwise returns null. - * - * @param expr - * @return int array with two elements - element 0 is start index, element 1 is end index - */ - public abstract int[] getRangeParameters(AbstractFunctionExpression expr); - - /** - * Generates an order by expression - * - * @param parent - * @param translatedOrderBy - * @param isAscending - * @return - */ - public abstract GroovyExpression generateOrderByExpression(GroovyExpression parent, - List<GroovyExpression> translatedOrderBy, boolean isAscending); - - /** - * Determines if specified expression is an order method call - * - * @param expr - * @return - */ - public boolean isOrderExpression(GroovyExpression expr) { - if (expr instanceof FunctionCallExpression) { - FunctionCallExpression functionCallExpression = (FunctionCallExpression) expr; - if (functionCallExpression.getFunctionName().equals(ORDER_METHOD)) { - return true; - } - } - return false; - } - - /** - * Returns the Groovy expressions that should be used as the parents when - * translating an order by expression. This is needed because Gremlin 2 and - * 3 handle order by expressions very differently. - * - */ - public abstract List<GroovyExpression> getOrderFieldParents(); - - /** - * Returns the expression that represents an anonymous graph traversal. - * - * @return - */ - public abstract GroovyExpression getAnonymousTraversalExpression(); - - public boolean isLeafAnonymousTraversalExpression(GroovyExpression expr) { - if(!(expr instanceof FunctionCallExpression)) { - return false; - } - FunctionCallExpression functionCallExpr = (FunctionCallExpression)expr; - if(functionCallExpr.getCaller() != null) { - return false; - } - return functionCallExpr.getFunctionName().equals("_") & functionCallExpr.getArguments().size() == 0; - } - - /** - * Returns an expression representing - * - * @return - */ - public abstract GroovyExpression getFieldInSelect(); - - /** - * Generates the expression the serves as the root of the Gremlin query. - * @param varExpr variable containing the vertices to traverse - * @return - */ - protected abstract GroovyExpression initialExpression(GroovyExpression varExpr, GraphPersistenceStrategies s); - - - /** - * Generates an expression that tests whether the vertex represented by the 'toTest' - * expression represents an instance of the specified type, checking both the type - * and super type names. - * - * @param s - * @param typeName - * @param itRef - * @return - */ - protected abstract GroovyExpression typeTestExpression(GraphPersistenceStrategies s, String typeName, - GroovyExpression vertexExpr); - - /** - /** - * Generates a sequence of groovy expressions that filter the vertices to only - * those that match the specified type. If GraphPersistenceStrategies.collectTypeInstancesIntoVar() - * is set and the gremlin optimizer is disabled, the vertices are put into a variable whose name is generated - * from the specified IntSequence. The last item in the result will be a graph traversal restricted to only - * the matching vertices. - */ - public List<GroovyExpression> generateTypeTestExpression(GraphPersistenceStrategies s, GroovyExpression parent, - String typeName, IntSequence intSeq) throws AtlasException { - - if(AtlasRepositoryConfiguration.isGremlinOptimizerEnabled()) { - GroovyExpression superTypeAttributeNameExpr = new LiteralExpression(s.superTypeAttributeName()); - GroovyExpression typeNameExpr = new LiteralExpression(typeName); - GroovyExpression superTypeMatchesExpr = new FunctionCallExpression(TraversalStepType.FILTER, HAS_METHOD, superTypeAttributeNameExpr, - typeNameExpr); - - GroovyExpression typeAttributeNameExpr = new LiteralExpression(s.typeAttributeName()); - - GroovyExpression typeMatchesExpr = new FunctionCallExpression(TraversalStepType.FILTER, HAS_METHOD, typeAttributeNameExpr, - typeNameExpr); - GroovyExpression result = new FunctionCallExpression(TraversalStepType.FILTER, parent, "or", typeMatchesExpr, superTypeMatchesExpr); - return Collections.singletonList(result); - } - else { - if (s.filterBySubTypes()) { - return typeTestExpressionUsingInFilter(s, parent, typeName); - } else if (s.collectTypeInstancesIntoVar()) { - return typeTestExpressionMultiStep(s, typeName, intSeq); - } else { - return typeTestExpressionUsingFilter(s, parent, typeName); - } - } - } - - private List<GroovyExpression> typeTestExpressionUsingInFilter(GraphPersistenceStrategies s, GroovyExpression parent, - final String typeName) throws AtlasException { - List<GroovyExpression> typeNames = new ArrayList<>(); - typeNames.add(new LiteralExpression(typeName)); - - Map<TYPE_FILTER, String> filters = new HashMap<TYPE_FILTER, String>() {{ - put(TYPE_FILTER.SUPERTYPE, typeName); - }}; - - ImmutableList<String> subTypes = TypeSystem.getInstance().getTypeNames(filters); - - if (!subTypes.isEmpty()) { - for (String subType : subTypes) { - typeNames.add(new LiteralExpression(subType)); - } - } - - GroovyExpression inFilterExpr = generateHasExpression(s, parent, s.typeAttributeName(), IN_OPERATOR, - new ListExpression(typeNames), null); - - return Collections.singletonList(inFilterExpr); - } - - private List<GroovyExpression> typeTestExpressionMultiStep(GraphPersistenceStrategies s, String typeName, - IntSequence intSeq) { - - String varName = "_var_" + intSeq.next(); - GroovyExpression varExpr = new IdentifierExpression(varName); - List<GroovyExpression> result = new ArrayList<>(); - - result.add(newSetVar(varName)); - result.add(fillVarWithTypeInstances(s, typeName, varName)); - result.add(fillVarWithSubTypeInstances(s, typeName, varName)); - result.add(initialExpression(varExpr, s)); - - return result; - } - - private GroovyExpression newSetVar(String varName) { - GroovyExpression castExpr = new TypeCoersionExpression(new ListExpression(), SET_CLASS); - return new VariableAssignmentExpression(varName, castExpr); - } - - private GroovyExpression fillVarWithTypeInstances(GraphPersistenceStrategies s, String typeName, String fillVar) { - GroovyExpression graphExpr = getAllVerticesExpr(); - GroovyExpression typeAttributeNameExpr = new LiteralExpression(s.typeAttributeName()); - GroovyExpression typeNameExpr = new LiteralExpression(typeName); - GroovyExpression hasExpr = new FunctionCallExpression(graphExpr, HAS_METHOD, typeAttributeNameExpr, typeNameExpr); - GroovyExpression fillExpr = new FunctionCallExpression(hasExpr, FILL_METHOD, new IdentifierExpression(fillVar)); - return fillExpr; - } - - private GroovyExpression fillVarWithSubTypeInstances(GraphPersistenceStrategies s, String typeName, - String fillVar) { - GroovyExpression graphExpr = getAllVerticesExpr(); - GroovyExpression superTypeAttributeNameExpr = new LiteralExpression(s.superTypeAttributeName()); - GroovyExpression typeNameExpr = new LiteralExpression(typeName); - GroovyExpression hasExpr = new FunctionCallExpression(graphExpr, HAS_METHOD, superTypeAttributeNameExpr, typeNameExpr); - GroovyExpression fillExpr = new FunctionCallExpression(hasExpr, FILL_METHOD, new IdentifierExpression(fillVar)); - return fillExpr; - } - - - private List<GroovyExpression> typeTestExpressionUsingFilter(GraphPersistenceStrategies s, GroovyExpression parent, - String typeName) { - GroovyExpression itExpr = getItVariable(); - GroovyExpression typeTestExpr = typeTestExpression(s, typeName, itExpr); - GroovyExpression closureExpr = new ClosureExpression(typeTestExpr); - GroovyExpression filterExpr = new FunctionCallExpression(parent, FILTER_METHOD, closureExpr); - return Collections.singletonList(filterExpr); - } - - /** - * Generates an expression which checks whether the vertices in the query have - * a field with the given name. - * - * @param parent - * @param fieldName - * @return - */ - public GroovyExpression generateUnaryHasExpression(GroovyExpression parent, String fieldName) { - return new FunctionCallExpression(TraversalStepType.FILTER, parent, HAS_METHOD, new LiteralExpression(fieldName)); - } - - /** - * Generates a path expression - * - * @param parent - * @return - */ - public GroovyExpression generatePathExpression(GroovyExpression parent) { - return new FunctionCallExpression(TraversalStepType.MAP_TO_VALUE, parent, PATH_METHOD); - } - - /** - * Generates the emit expression used in loop expressions. - * @param s - * @param dataType - * @return - */ - protected GroovyExpression generateLoopEmitExpression(GraphPersistenceStrategies s, IDataType dataType) { - return typeTestExpression(s, dataType.getName(), getCurrentObjectExpression()); - } - - /** - * Generates an alias expression - * - * @param parent - * @param alias - * @return - */ - public GroovyExpression generateAliasExpression(GroovyExpression parent, String alias) { - return new FunctionCallExpression(TraversalStepType.SIDE_EFFECT, parent, AS_METHOD, new LiteralExpression(alias)); - } - - /** - * Generates an expression that gets the vertices adjacent to the vertex in 'parent' - * in the specified direction. - * - * @param parent - * @param dir - * @return - */ - public GroovyExpression generateAdjacentVerticesExpression(GroovyExpression parent, AtlasEdgeDirection dir) { - return new FunctionCallExpression(TraversalStepType.FLAT_MAP_TO_ELEMENTS, parent, getGremlinFunctionName(dir)); - } - - private String getGremlinFunctionName(AtlasEdgeDirection dir) { - switch(dir) { - case IN: - return "in"; - case OUT: - return "out"; - case BOTH: - return "both"; - default: - throw new RuntimeException("Unknown Atlas Edge Direction: " + dir); - } - } - - /** - * Generates an expression that gets the vertices adjacent to the vertex in 'parent' - * in the specified direction, following only edges with the given label. - * - * @param parent - * @param dir - * @return - */ - public GroovyExpression generateAdjacentVerticesExpression(GroovyExpression parent, AtlasEdgeDirection dir, - String label) { - return new FunctionCallExpression(TraversalStepType.FLAT_MAP_TO_ELEMENTS, parent, getGremlinFunctionName(dir), new LiteralExpression(label)); - } - - /** - * Generates an arithmetic expression, e.g. a + b - * - */ - public GroovyExpression generateArithmeticExpression(GroovyExpression left, String operator, - GroovyExpression right) throws AtlasException { - ArithmeticOperator op = ArithmeticOperator.lookup(operator); - return new ArithmeticExpression(left, op, right); - } - - public abstract GroovyExpression generateGroupByExpression(GroovyExpression parent, GroovyExpression groupByExpression, GroovyExpression aggregationFunction); - - protected GroovyExpression getItVariable() { - return new IdentifierExpression(IT_VARIABLE); - } - - protected GroovyExpression getAllVerticesExpr() { - GroovyExpression gExpr = getGraphExpression(); - return new FunctionCallExpression(TraversalStepType.START, gExpr, V_METHOD); - } - - protected IdentifierExpression getGraphExpression() { - return new IdentifierExpression(TraversalStepType.SOURCE, G_VARIABLE); - } - - - protected GroovyExpression getCurrentObjectExpression() { - return new FieldExpression(getItVariable(), OBJECT_FIELD); - } - - //assumes cast already performed - public GroovyExpression generateCountExpression(GroovyExpression itExpr) { - GroovyExpression collectionExpr = new CastExpression(itExpr,"Collection"); - return new FunctionCallExpression(collectionExpr, "size"); - } - - public GroovyExpression generateMinExpression(GroovyExpression itExpr, GroovyExpression mapFunction) { - return getAggregrationExpression(itExpr, mapFunction, "min"); - } - - public GroovyExpression generateMaxExpression(GroovyExpression itExpr, GroovyExpression mapFunction) { - return getAggregrationExpression(itExpr, mapFunction, "max"); - } - - public GroovyExpression generateSumExpression(GroovyExpression itExpr, GroovyExpression mapFunction) { - return getAggregrationExpression(itExpr, mapFunction, "sum"); - } - - private GroovyExpression getAggregrationExpression(GroovyExpression itExpr, - GroovyExpression mapFunction, String functionName) { - GroovyExpression collectionExpr = new CastExpression(itExpr,"Collection"); - ClosureExpression collectFunction = new ClosureExpression(mapFunction); - GroovyExpression transformedList = new FunctionCallExpression(collectionExpr, "collect", collectFunction); - return new FunctionCallExpression(transformedList, functionName); - } - - public GroovyExpression getClosureArgumentValue() { - return getItVariable(); - } - - /** - * Specifies the parent to use when translating the select list in - * a group by statement. - * - * @return - */ - public abstract GroovyExpression getGroupBySelectFieldParent(); - - public GroovyExpression generateFillExpression(GroovyExpression parent, GroovyExpression variable) { - return new FunctionCallExpression(TraversalStepType.END,parent , "fill", variable); - } - - /** - * Generates an anonymous graph traversal initialized with the specified value. In Gremlin 3, we need - * to use a different syntax for this when the object is a map, so that information needs to be provided - * to this method so that the correct syntax is used. - * - * @param isMap true if the value contains Map instances, false if it contains Vertex instances - * @param valueCollection the source objects to start the traversal from. - */ - public abstract GroovyExpression generateSeededTraversalExpresssion(boolean isMap, GroovyExpression valueCollection); - - /** - * Returns the current value of the traverser. This is used when generating closure expressions that - * need to operate on the current value in the graph graversal. - * - * @param traverser - * @return - */ - public abstract GroovyExpression getCurrentTraverserObject(GroovyExpression traverser); - - /** - * Generates an expression that transforms the current value of the traverser by - * applying the function specified - * - * @param parent - * @param closureExpression - * @return - */ - public abstract GroovyExpression generateMapExpression(GroovyExpression parent, ClosureExpression closureExpression); - - /** - * Returns whether a select statement generates a map (or Gremlin 2 "Row") when it contains the specified - * number of aliases. - * - */ - public abstract boolean isSelectGeneratesMap(int aliasCount); - - /** - * Generates an expression to get the value of the value from the row map - * generated by select() with the specified key. - * - */ - public abstract GroovyExpression generateGetSelectedValueExpression(LiteralExpression key, - GroovyExpression rowMapExpr); - - public GroovyExpression removeExtraMapFromPathInResult(GroovyExpression parent) { - GroovyExpression listItem = getItVariable(); - GroovyExpression tailExpr = new FunctionCallExpression(listItem, "tail"); - return new FunctionCallExpression(parent, "collect", new ClosureExpression(tailExpr)); - - } - - /** - * Generates a toList expression to execute the gremlin query and - * store the result in a new list. - * - * @param expr - * @return - */ - public GroovyExpression generateToListExpression(GroovyExpression expr) { - return new FunctionCallExpression(TraversalStepType.END, expr, "toList"); - } - - /** - * Finds aliases that absolutely must be brought along with this expression into - * the output expression and cannot just be recreated there. For example, in the - * Gremlin 2 loop expression, the loop semantics break of the alias is simply recreated - * in the output expression. - * @param expr - * @return - */ - public abstract List<String> getAliasesRequiredByExpression(GroovyExpression expr); - - - /** - * Checks if the given expression is an alias expression, and if so - * returns the alias from the expression. Otherwise, null is - * returned. - */ - public String getAliasNameIfRelevant(GroovyExpression expr) { - if(!(expr instanceof FunctionCallExpression)) { - return null; - } - FunctionCallExpression fc = (FunctionCallExpression)expr; - if(! fc.getFunctionName().equals(AS_METHOD)) { - return null; - } - LiteralExpression aliasName = (LiteralExpression)fc.getArguments().get(0); - return aliasName.getValue().toString(); - - } - - public abstract boolean isRepeatExpression(GroovyExpression expr); -} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/atlas/blob/0877e47c/repository/src/main/java/org/apache/atlas/gremlin/optimizer/AliasFinder.java ---------------------------------------------------------------------- diff --git a/repository/src/main/java/org/apache/atlas/gremlin/optimizer/AliasFinder.java b/repository/src/main/java/org/apache/atlas/gremlin/optimizer/AliasFinder.java deleted file mode 100644 index 3e6c39a..0000000 --- a/repository/src/main/java/org/apache/atlas/gremlin/optimizer/AliasFinder.java +++ /dev/null @@ -1,103 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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.apache.atlas.gremlin.optimizer; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import org.apache.atlas.groovy.AbstractFunctionExpression; -import org.apache.atlas.groovy.FunctionCallExpression; -import org.apache.atlas.groovy.GroovyExpression; -import org.apache.atlas.groovy.LiteralExpression; -import org.apache.atlas.groovy.TraversalStepType; - -/** - * Finds all aliases in the expression. - */ -public class AliasFinder implements CallHierarchyVisitor { - - private List<LiteralExpression> foundAliases = new ArrayList<>(); - - //Whether a final alias is needed. A final alias is needed - //if there are transformation steps after the last alias in - //the expression. We initialize this to false since a final - //alias is not needed if there are no aliases. - private boolean finalAliasNeeded = false; - - @Override - public boolean preVisitFunctionCaller(AbstractFunctionExpression expr) { - return true; - } - - @Override - public void visitNonFunctionCaller(GroovyExpression expr) { - - } - - @Override - public void visitNullCaller() { - - } - - private static final Set<TraversalStepType> TRANSFORMATION_STEP_TYPES = new HashSet<>(Arrays.asList( - TraversalStepType.MAP_TO_ELEMENT, - TraversalStepType.MAP_TO_VALUE, - TraversalStepType.FLAT_MAP_TO_ELEMENTS, - TraversalStepType.FLAT_MAP_TO_VALUES, - TraversalStepType.BARRIER, - TraversalStepType.NONE)); - - - @Override - public boolean postVisitFunctionCaller(AbstractFunctionExpression functionCall) { - - if (functionCall instanceof FunctionCallExpression) { - FunctionCallExpression expr = (FunctionCallExpression)functionCall; - if (expr.getType() == TraversalStepType.SIDE_EFFECT && expr.getFunctionName().equals("as")) { - //We found an alias. This is currently the last expression we've seen - //in our traversal back up the expression tree, so at this point a final - //alias is not needed. - LiteralExpression aliasNameExpr = (LiteralExpression)expr.getArguments().get(0); - foundAliases.add(aliasNameExpr); - finalAliasNeeded=false; - } - } - - if(TRANSFORMATION_STEP_TYPES.contains(functionCall.getType())) { - //This step changes the value of the traverser. Now, a final alias - //needs to be added. - if(!foundAliases.isEmpty()) { - finalAliasNeeded = true; - } - } - - return true; - } - - public List<LiteralExpression> getAliases() { - return foundAliases; - } - - public boolean isFinalAliasNeeded() { - - return finalAliasNeeded; - } -} http://git-wip-us.apache.org/repos/asf/atlas/blob/0877e47c/repository/src/main/java/org/apache/atlas/gremlin/optimizer/CallHierarchyVisitor.java ---------------------------------------------------------------------- diff --git a/repository/src/main/java/org/apache/atlas/gremlin/optimizer/CallHierarchyVisitor.java b/repository/src/main/java/org/apache/atlas/gremlin/optimizer/CallHierarchyVisitor.java deleted file mode 100644 index 6089353..0000000 --- a/repository/src/main/java/org/apache/atlas/gremlin/optimizer/CallHierarchyVisitor.java +++ /dev/null @@ -1,62 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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.apache.atlas.gremlin.optimizer; - -import org.apache.atlas.groovy.AbstractFunctionExpression; -import org.apache.atlas.groovy.GroovyExpression; - -/** - * Call back interface for visiting the call hierarchy of a function call. - */ -public interface CallHierarchyVisitor { - - /** - * Visits a function expression before the visit to its caller. - * - * @param expr - * - * @return false to terminate the recursion - */ - boolean preVisitFunctionCaller(AbstractFunctionExpression expr); - - /** - * Called when a caller that is not an instance of - * AbstractFunctionExpression is found. This indicates that the deepest - * point in the call hierarchy has been reached. - * - * - */ - void visitNonFunctionCaller(GroovyExpression expr); - - /** - * Called when a null caller is found (this happens for static/user-defined - * functions). This indicates that the deepest point in the call hierarchy - * has been reached. - * - */ - void visitNullCaller(); - - /** - * Visits a function expression after the visit to its caller. - * - * @param expr - * - * @return false to terminate the recursion - */ - boolean postVisitFunctionCaller(AbstractFunctionExpression functionCall); -} http://git-wip-us.apache.org/repos/asf/atlas/blob/0877e47c/repository/src/main/java/org/apache/atlas/gremlin/optimizer/ExpandAndsOptimization.java ---------------------------------------------------------------------- diff --git a/repository/src/main/java/org/apache/atlas/gremlin/optimizer/ExpandAndsOptimization.java b/repository/src/main/java/org/apache/atlas/gremlin/optimizer/ExpandAndsOptimization.java deleted file mode 100644 index d8ecd07..0000000 --- a/repository/src/main/java/org/apache/atlas/gremlin/optimizer/ExpandAndsOptimization.java +++ /dev/null @@ -1,127 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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.apache.atlas.gremlin.optimizer; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.atlas.gremlin.GremlinExpressionFactory; -import org.apache.atlas.groovy.AbstractFunctionExpression; -import org.apache.atlas.groovy.FunctionCallExpression; -import org.apache.atlas.groovy.GroovyExpression; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Optimizer that pulls has expressions out of an 'and' expression. - * <p> - * For example: - * <pre class=code> - * g.V().and(has('x'),has('y') </pre> - * <p> - * is optimized to: - * <pre class=code> - * g.V().has('x').has('y') </pre> - * <p> - * There are certain cases where it is not safe to move an expression out - * of the 'and'. For example, in the expression - * <pre class=code> - * g.V().and(has('x').out('y'),has('z')) </pre> - * <p> - * has('x').out('y') cannot be moved out of the 'and', since it changes the value of the traverser. - * <p> - * At this time, the ExpandAndsOptimizer is not able to handle this scenario, so we don't extract - * that expression. In this case, the result is: - * <pre class=code> - * g.V().has('z').and(has('x').out('y')) </pre> - * <p> - * The optimizer will call ExpandAndsOptimization recursively on the children, so - * there is no need to recursively update the children here. - * - */ -public class ExpandAndsOptimization implements GremlinOptimization { - - private static final Logger logger_ = LoggerFactory.getLogger(ExpandAndsOptimization.class); - - - private final GremlinExpressionFactory factory; - - public ExpandAndsOptimization(GremlinExpressionFactory factory) { - this.factory = factory; - } - - @Override - public boolean appliesTo(GroovyExpression expr, OptimizationContext contxt) { - return expr instanceof FunctionCallExpression && ((FunctionCallExpression)expr).getFunctionName().equals("and"); - } - - /** - * Expands the given and expression. There is no need to recursively - * expand the children here. This method is called recursively by - * GremlinQueryOptimier on the children. - * - */ - @Override - public GroovyExpression apply(GroovyExpression expr, OptimizationContext context) { - - FunctionCallExpression exprAsFunction = (FunctionCallExpression)expr; - GroovyExpression result = exprAsFunction.getCaller(); - - List<GroovyExpression> nonExtractableArguments = new ArrayList<>(); - for(GroovyExpression argument : exprAsFunction.getArguments()) { - - if (GremlinQueryOptimizer.isExtractable(argument)) { - //Set the caller of the deepest expression in the call hierarchy - //of the argument to point to the current result. - //For example, if result is "g.V()" and the updatedArgument is "has('x').has('y')", - //updatedArgument would be a tree like this: - // - // has('y') - // / - // / caller - // |/_ - // has('x') - // / - // / caller - // |/_ - // (null) - // - //We would set the caller of has('x') to be g.V(), so result would become g.V().has('x').has('y'). - // - // Note: This operation is currently done by making a copy of the argument tree. That should - // be changed. - result = GremlinQueryOptimizer.copyWithNewLeafNode( - (AbstractFunctionExpression) argument, result); - } else { - logger_.warn("Found non-extractable argument '{}' in the 'and' expression '{}'",argument.toString(), expr.toString()); - nonExtractableArguments.add(argument); - } - } - - if (!nonExtractableArguments.isEmpty()) { - //add a final 'and' call with the arguments that could not be extracted - result = factory.generateLogicalExpression(result, "and", nonExtractableArguments); - } - return result; - } - - @Override - public boolean isApplyRecursively() { - return true; - } -}