ATLAS-1195 Clean up DSL Translation (jnhagelb via dkantor)
Project: http://git-wip-us.apache.org/repos/asf/incubator-atlas/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-atlas/commit/69af0ae7 Tree: http://git-wip-us.apache.org/repos/asf/incubator-atlas/tree/69af0ae7 Diff: http://git-wip-us.apache.org/repos/asf/incubator-atlas/diff/69af0ae7 Branch: refs/heads/master Commit: 69af0ae77a389afffa5dcfedd6297528628b12f8 Parents: aa15cd0 Author: Jeff Hagelberg <[email protected]> Authored: Thu Oct 27 14:52:18 2016 -0400 Committer: Dave Kantor <[email protected]> Committed: Thu Oct 27 14:52:18 2016 -0400 ---------------------------------------------------------------------- .../atlas/groovy/AbstractGroovyExpression.java | 36 ++ .../atlas/groovy/ArithmeticExpression.java | 59 +++ .../apache/atlas/groovy/BinaryExpression.java | 51 ++ .../org/apache/atlas/groovy/CastExpression.java | 44 ++ .../apache/atlas/groovy/ClosureExpression.java | 63 +++ .../atlas/groovy/CodeBlockExpression.java | 61 +++ .../atlas/groovy/ComparisonExpression.java | 64 +++ .../groovy/ComparisonOperatorExpression.java | 32 ++ .../apache/atlas/groovy/FieldExpression.java | 44 ++ .../atlas/groovy/FunctionCallExpression.java | 86 +++ .../apache/atlas/groovy/GroovyExpression.java | 34 ++ .../atlas/groovy/GroovyGenerationContext.java | 68 +++ .../atlas/groovy/IdentifierExpression.java | 42 ++ .../org/apache/atlas/groovy/ListExpression.java | 60 +++ .../apache/atlas/groovy/LiteralExpression.java | 99 ++++ .../apache/atlas/groovy/LogicalExpression.java | 46 ++ .../apache/atlas/groovy/RangeExpression.java | 45 ++ .../atlas/groovy/TernaryOperatorExpression.java | 56 ++ .../atlas/groovy/TypeCoersionExpression.java | 44 ++ .../groovy/VariableAssignmentExpression.java | 58 ++ .../atlas/repository/graphdb/AtlasGraph.java | 7 +- .../repository/graphdb/titan0/Titan0Graph.java | 11 +- release-log.txt | 1 + .../graph/DefaultGraphPersistenceStrategy.java | 47 +- .../gremlin/Gremlin2ExpressionFactory.java | 223 ++++++++ .../gremlin/Gremlin3ExpressionFactory.java | 325 ++++++++++++ .../atlas/gremlin/GremlinExpressionFactory.java | 409 +++++++++++++++ .../query/GraphPersistenceStrategies.scala | 175 +------ .../org/apache/atlas/query/GremlinQuery.scala | 525 +++++++++---------- 29 files changed, 2340 insertions(+), 475 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/69af0ae7/common/src/main/java/org/apache/atlas/groovy/AbstractGroovyExpression.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/org/apache/atlas/groovy/AbstractGroovyExpression.java b/common/src/main/java/org/apache/atlas/groovy/AbstractGroovyExpression.java new file mode 100644 index 0000000..49eaae8 --- /dev/null +++ b/common/src/main/java/org/apache/atlas/groovy/AbstractGroovyExpression.java @@ -0,0 +1,36 @@ +/** + * 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.groovy; + +/** + * Abstract implementation of GroovyExpression that adds a convenient + * toString method. + * + */ +public abstract class AbstractGroovyExpression implements GroovyExpression { + + @Override + public String toString() { + GroovyGenerationContext ctx = new GroovyGenerationContext(); + ctx.setParametersAllowed(false); + generateGroovy(ctx); + return ctx.getQuery(); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/69af0ae7/common/src/main/java/org/apache/atlas/groovy/ArithmeticExpression.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/org/apache/atlas/groovy/ArithmeticExpression.java b/common/src/main/java/org/apache/atlas/groovy/ArithmeticExpression.java new file mode 100644 index 0000000..0aec5d0 --- /dev/null +++ b/common/src/main/java/org/apache/atlas/groovy/ArithmeticExpression.java @@ -0,0 +1,59 @@ +/** + * 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.groovy; + +import org.apache.atlas.AtlasException; + +/** + * Represents an arithmetic expression such as a+b. + */ +public class ArithmeticExpression extends BinaryExpression { + + /** + * Allowed arithmetic operators. + */ + public enum ArithmeticOperator { + PLUS("+"), + MINUS("-"), + TIMES("*"), + DIVIDE("/"), + MODULUS("%"); + + private String groovyValue; + ArithmeticOperator(String groovyValue) { + this.groovyValue = groovyValue; + } + public String getGroovyValue() { + return groovyValue; + } + + public static ArithmeticOperator lookup(String groovyValue) throws AtlasException { + for(ArithmeticOperator op : ArithmeticOperator.values()) { + if (op.getGroovyValue().equals(groovyValue)) { + return op; + } + } + throw new AtlasException("Unknown Operator:" + groovyValue); + } + + } + + public ArithmeticExpression(GroovyExpression left, ArithmeticOperator op, GroovyExpression right) { + super(left, op.getGroovyValue(), right); + } +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/69af0ae7/common/src/main/java/org/apache/atlas/groovy/BinaryExpression.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/org/apache/atlas/groovy/BinaryExpression.java b/common/src/main/java/org/apache/atlas/groovy/BinaryExpression.java new file mode 100644 index 0000000..ccc9204 --- /dev/null +++ b/common/src/main/java/org/apache/atlas/groovy/BinaryExpression.java @@ -0,0 +1,51 @@ +/** + * 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.groovy; + +/** + * Represents any kind of binary expression. This could + * be an arithmetic expression, such as a + 3, a boolean + * expression such as a < 5, or even a comparison function + * such as a <=> b. + * + */ +public abstract class BinaryExpression extends AbstractGroovyExpression { + + + private GroovyExpression left; + private GroovyExpression right; + private String op; + + public BinaryExpression(GroovyExpression left, String op, GroovyExpression right) { + this.left = left; + this.op = op; + this.right = right; + } + + @Override + public void generateGroovy(GroovyGenerationContext context) { + + left.generateGroovy(context); + context.append(" "); + context.append(op); + context.append(" "); + right.generateGroovy(context); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/69af0ae7/common/src/main/java/org/apache/atlas/groovy/CastExpression.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/org/apache/atlas/groovy/CastExpression.java b/common/src/main/java/org/apache/atlas/groovy/CastExpression.java new file mode 100644 index 0000000..963724c --- /dev/null +++ b/common/src/main/java/org/apache/atlas/groovy/CastExpression.java @@ -0,0 +1,44 @@ +/** + * 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.groovy; + +/** + * Groovy expression that represents a cast. + */ +public class CastExpression extends AbstractGroovyExpression { + + private GroovyExpression expr; + private String className; + + public CastExpression(GroovyExpression expr, String className) { + this.expr = expr; + this.className =className; + } + + @Override + public void generateGroovy(GroovyGenerationContext context) { + + context.append("(("); + context.append(className); + context.append(")"); + expr.generateGroovy(context); + context.append(")"); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/69af0ae7/common/src/main/java/org/apache/atlas/groovy/ClosureExpression.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/org/apache/atlas/groovy/ClosureExpression.java b/common/src/main/java/org/apache/atlas/groovy/ClosureExpression.java new file mode 100644 index 0000000..2d70209 --- /dev/null +++ b/common/src/main/java/org/apache/atlas/groovy/ClosureExpression.java @@ -0,0 +1,63 @@ +/** + * 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.groovy; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +/** + * Groovy expression that represents a Groovy closure. + */ +public class ClosureExpression extends AbstractGroovyExpression { + + private List<String> varNames = new ArrayList<>(); + private GroovyExpression body; + + public ClosureExpression(GroovyExpression body, String... varNames) { + this.body = body; + this.varNames.addAll(Arrays.asList(varNames)); + } + + public ClosureExpression(List<String> varNames, GroovyExpression body) { + this.body = body; + this.varNames.addAll(varNames); + } + + @Override + public void generateGroovy(GroovyGenerationContext context) { + + context.append("{"); + if (!varNames.isEmpty()) { + Iterator<String> varIt = varNames.iterator(); + while(varIt.hasNext()) { + String varName = varIt.next(); + context.append(varName); + if (varIt.hasNext()) { + context.append(", "); + } + } + context.append("->"); + } + body.generateGroovy(context); + context.append("}"); + + } +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/69af0ae7/common/src/main/java/org/apache/atlas/groovy/CodeBlockExpression.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/org/apache/atlas/groovy/CodeBlockExpression.java b/common/src/main/java/org/apache/atlas/groovy/CodeBlockExpression.java new file mode 100644 index 0000000..9a726f2 --- /dev/null +++ b/common/src/main/java/org/apache/atlas/groovy/CodeBlockExpression.java @@ -0,0 +1,61 @@ +/** + * 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.groovy; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * Groovy expression that represents a block of code + * that contains 0 or more statements that are delimited + * by semicolons. + */ +public class CodeBlockExpression extends AbstractGroovyExpression { + + private List<GroovyExpression> body = new ArrayList<>(); + + public void addStatement(GroovyExpression expr) { + body.add(expr); + } + + public void addStatements(List<GroovyExpression> exprs) { + body.addAll(exprs); + } + + @Override + public void generateGroovy(GroovyGenerationContext context) { + + /* + * the L:{} represents a groovy code block; the label is needed + * to distinguish it from a groovy closure. + */ + context.append("L:{"); + Iterator<GroovyExpression> stmtIt = body.iterator(); + while(stmtIt.hasNext()) { + GroovyExpression stmt = stmtIt.next(); + stmt.generateGroovy(context); + if (stmtIt.hasNext()) { + context.append(";"); + } + } + context.append("}"); + + } +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/69af0ae7/common/src/main/java/org/apache/atlas/groovy/ComparisonExpression.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/org/apache/atlas/groovy/ComparisonExpression.java b/common/src/main/java/org/apache/atlas/groovy/ComparisonExpression.java new file mode 100644 index 0000000..345f838 --- /dev/null +++ b/common/src/main/java/org/apache/atlas/groovy/ComparisonExpression.java @@ -0,0 +1,64 @@ +/** + * 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.groovy; + +import org.apache.atlas.AtlasException; + +/** + * Represents an expression that compares two expressions + * using a comparison operator (==, <, >, etc). + * + */ +public class ComparisonExpression extends BinaryExpression { + + /** + * Allowed comparison operators. + * + */ + public enum ComparisonOperator { + + GREATER_THAN_EQ_(">="), + GREATER_THAN(">"), + EQUALS("=="), + NOT_EQUALS("!="), + LESS_THAN("<"), + LESS_THAN_EQ("<="); + + private String groovyValue; + ComparisonOperator(String groovyValue) { + this.groovyValue = groovyValue; + } + public String getGroovyValue() { + return groovyValue; + } + + public static ComparisonOperator lookup(String groovyValue) throws AtlasException { + for(ComparisonOperator op : ComparisonOperator.values()) { + if (op.getGroovyValue().equals(groovyValue)) { + return op; + } + } + throw new AtlasException("Unknown Operator:" + groovyValue); + } + + } + + public ComparisonExpression(GroovyExpression left, ComparisonOperator op, GroovyExpression right) { + super(left, op.getGroovyValue(), right); + } +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/69af0ae7/common/src/main/java/org/apache/atlas/groovy/ComparisonOperatorExpression.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/org/apache/atlas/groovy/ComparisonOperatorExpression.java b/common/src/main/java/org/apache/atlas/groovy/ComparisonOperatorExpression.java new file mode 100644 index 0000000..63638b7 --- /dev/null +++ b/common/src/main/java/org/apache/atlas/groovy/ComparisonOperatorExpression.java @@ -0,0 +1,32 @@ +/** + * 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.groovy; + +/** + * Represents an expression that compares two expressions using + * the Groovy "spaceship" operator. This is basically the + * same as calling left.compareTo(right), except that it has + * built-in null handling and some other nice features. + * + */ +public class ComparisonOperatorExpression extends BinaryExpression { + + public ComparisonOperatorExpression(GroovyExpression left, GroovyExpression right) { + super(left, "<=>", right); + } +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/69af0ae7/common/src/main/java/org/apache/atlas/groovy/FieldExpression.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/org/apache/atlas/groovy/FieldExpression.java b/common/src/main/java/org/apache/atlas/groovy/FieldExpression.java new file mode 100644 index 0000000..f6d06bd --- /dev/null +++ b/common/src/main/java/org/apache/atlas/groovy/FieldExpression.java @@ -0,0 +1,44 @@ +/** + * 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.groovy; + +/** + * Groovy expression that accesses a field in an object. + */ +public class FieldExpression extends AbstractGroovyExpression { + + private GroovyExpression target; + private String fieldName; + + public FieldExpression(GroovyExpression target, String fieldName) { + this.target = target; + this.fieldName = fieldName; + } + + @Override + public void generateGroovy(GroovyGenerationContext context) { + + target.generateGroovy(context); + context.append(".'"); + + context.append(fieldName); + context.append("'"); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/69af0ae7/common/src/main/java/org/apache/atlas/groovy/FunctionCallExpression.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/org/apache/atlas/groovy/FunctionCallExpression.java b/common/src/main/java/org/apache/atlas/groovy/FunctionCallExpression.java new file mode 100644 index 0000000..b60edef --- /dev/null +++ b/common/src/main/java/org/apache/atlas/groovy/FunctionCallExpression.java @@ -0,0 +1,86 @@ +/** + * 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.groovy; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +/** + * Groovy expression that calls a method on an object. + */ +public class FunctionCallExpression extends AbstractGroovyExpression { + + // null for global functions + private GroovyExpression target; + + private String functionName; + private List<GroovyExpression> arguments = new ArrayList<GroovyExpression>(); + + public FunctionCallExpression(String functionName, List<? extends GroovyExpression> arguments) { + this.target = null; + this.functionName = functionName; + this.arguments.addAll(arguments); + } + + public FunctionCallExpression(GroovyExpression target, String functionName, + List<? extends GroovyExpression> arguments) { + this.target = target; + this.functionName = functionName; + this.arguments.addAll(arguments); + } + + public FunctionCallExpression(String functionName, GroovyExpression... arguments) { + this.target = null; + this.functionName = functionName; + this.arguments.addAll(Arrays.asList(arguments)); + } + + public FunctionCallExpression(GroovyExpression target, String functionName, GroovyExpression... arguments) { + this.target = target; + this.functionName = functionName; + this.arguments.addAll(Arrays.asList(arguments)); + } + + public void addArgument(GroovyExpression expr) { + arguments.add(expr); + } + + @Override + public void generateGroovy(GroovyGenerationContext context) { + + if (target != null) { + target.generateGroovy(context); + context.append("."); + } + context.append(functionName); + context.append("("); + Iterator<GroovyExpression> it = arguments.iterator(); + while (it.hasNext()) { + GroovyExpression expr = it.next(); + expr.generateGroovy(context); + if (it.hasNext()) { + context.append(", "); + } + } + context.append(")"); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/69af0ae7/common/src/main/java/org/apache/atlas/groovy/GroovyExpression.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/org/apache/atlas/groovy/GroovyExpression.java b/common/src/main/java/org/apache/atlas/groovy/GroovyExpression.java new file mode 100644 index 0000000..493bd3d --- /dev/null +++ b/common/src/main/java/org/apache/atlas/groovy/GroovyExpression.java @@ -0,0 +1,34 @@ +/** + * 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.groovy; + +/** + * Represents an expression in the Groovy programming language, which + * is the language that Gremlin scripts are written and interpreted in. + */ +public interface GroovyExpression { + + /** + * Generates a groovy script from the expression. + * + * @param context + */ + void generateGroovy(GroovyGenerationContext context); + +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/69af0ae7/common/src/main/java/org/apache/atlas/groovy/GroovyGenerationContext.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/org/apache/atlas/groovy/GroovyGenerationContext.java b/common/src/main/java/org/apache/atlas/groovy/GroovyGenerationContext.java new file mode 100644 index 0000000..a4e485b --- /dev/null +++ b/common/src/main/java/org/apache/atlas/groovy/GroovyGenerationContext.java @@ -0,0 +1,68 @@ +/** + * 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.groovy; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * Context used when generating Groovy queries. Keeps track of query parameters + * that are created during the process as well as the portion of the query that + * has been generated so far. + * + */ +public class GroovyGenerationContext { + + private boolean parametersAllowed = true; + private int parameterCount = 0; + private Map<String, Object> parameterValues = new HashMap<>(); + + //used to build up the groovy script + private StringBuilder generatedQuery = new StringBuilder(); + + public void setParametersAllowed(boolean value) { + this.parametersAllowed = value; + } + + public GroovyExpression addParameter(Object value) { + if (this.parametersAllowed) { + String parameterName = "p" + (++parameterCount); + this.parameterValues.put(parameterName, value); + return new IdentifierExpression(parameterName); + } else { + LiteralExpression expr = new LiteralExpression(value); + expr.setTranslateToParameter(false); + return expr; + } + } + + public StringBuilder append(String gremlin) { + this.generatedQuery.append(gremlin); + return generatedQuery; + } + + public String getQuery() { + return generatedQuery.toString(); + } + + public Map<String, Object> getParameters() { + return Collections.unmodifiableMap(parameterValues); + } +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/69af0ae7/common/src/main/java/org/apache/atlas/groovy/IdentifierExpression.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/org/apache/atlas/groovy/IdentifierExpression.java b/common/src/main/java/org/apache/atlas/groovy/IdentifierExpression.java new file mode 100644 index 0000000..6abdbf0 --- /dev/null +++ b/common/src/main/java/org/apache/atlas/groovy/IdentifierExpression.java @@ -0,0 +1,42 @@ +/** + * 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.groovy; + +/** + * Groovy expression that references the variable with the given name. + * + */ +public class IdentifierExpression extends AbstractGroovyExpression { + + private String varName; + + public IdentifierExpression(String varName) { + this.varName = varName; + } + + public String getVariableName() { + return varName; + } + + @Override + public void generateGroovy(GroovyGenerationContext context) { + context.append(varName); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/69af0ae7/common/src/main/java/org/apache/atlas/groovy/ListExpression.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/org/apache/atlas/groovy/ListExpression.java b/common/src/main/java/org/apache/atlas/groovy/ListExpression.java new file mode 100644 index 0000000..f7acaac --- /dev/null +++ b/common/src/main/java/org/apache/atlas/groovy/ListExpression.java @@ -0,0 +1,60 @@ +/** + * 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.groovy; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +/** + * Groovy expression that represents a list literal. + */ +public class ListExpression extends AbstractGroovyExpression { + + private List<GroovyExpression> values = new ArrayList<>(); + + + public ListExpression(GroovyExpression... values) { + this.values = Arrays.asList(values); + } + + public ListExpression(List<? extends GroovyExpression> values) { + this.values.addAll(values); + } + + public void addArgument(GroovyExpression expr) { + values.add(expr); + } + + public void generateGroovy(GroovyGenerationContext context) { + + context.append("["); + Iterator<GroovyExpression> it = values.iterator(); + while(it.hasNext()) { + GroovyExpression expr = it.next(); + expr.generateGroovy(context); + if (it.hasNext()) { + context.append(", "); + } + } + context.append("]"); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/69af0ae7/common/src/main/java/org/apache/atlas/groovy/LiteralExpression.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/org/apache/atlas/groovy/LiteralExpression.java b/common/src/main/java/org/apache/atlas/groovy/LiteralExpression.java new file mode 100644 index 0000000..008c885 --- /dev/null +++ b/common/src/main/java/org/apache/atlas/groovy/LiteralExpression.java @@ -0,0 +1,99 @@ +/** + * 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.groovy; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Represents a literal value. + */ +public class LiteralExpression implements GroovyExpression { + + public static final LiteralExpression TRUE = new LiteralExpression(true); + public static final LiteralExpression FALSE = new LiteralExpression(false); + public static final LiteralExpression NULL = new LiteralExpression(null); + + private Object value; + private boolean translateToParameter = true; + private boolean addTypeSuffix = false; + + public LiteralExpression(Object value, boolean addTypeSuffix) { + this.value = value; + this.translateToParameter = value instanceof String; + this.addTypeSuffix = addTypeSuffix; + } + + public LiteralExpression(Object value) { + this.value = value; + this.translateToParameter = value instanceof String; + } + + private String getTypeSuffix() { + if (!addTypeSuffix) { + return ""; + } + if (value.getClass() == Long.class) { + return "L"; + } + + if (value.getClass() == Float.class) { + return "f"; + } + + if (value.getClass() == Double.class) { + return "d"; + } + + return ""; + } + + @Override + public void generateGroovy(GroovyGenerationContext context) { + + if (translateToParameter) { + GroovyExpression result = context.addParameter(value); + result.generateGroovy(context); + return; + } + + if (value instanceof String) { + String escapedValue = getEscapedValue(); + context.append("'"); + context.append(escapedValue); + context.append("'"); + + } else { + context.append(String.valueOf(value)); + context.append(getTypeSuffix()); + } + + } + + private String getEscapedValue() { + String escapedValue = (String)value; + escapedValue = escapedValue.replaceAll(Pattern.quote("\\"), Matcher.quoteReplacement("\\\\")); + escapedValue = escapedValue.replaceAll(Pattern.quote("'"), Matcher.quoteReplacement("\\'")); + return escapedValue; + } + + public void setTranslateToParameter(boolean translateToParameter) { + this.translateToParameter = translateToParameter; + } +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/69af0ae7/common/src/main/java/org/apache/atlas/groovy/LogicalExpression.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/org/apache/atlas/groovy/LogicalExpression.java b/common/src/main/java/org/apache/atlas/groovy/LogicalExpression.java new file mode 100644 index 0000000..ee5829b --- /dev/null +++ b/common/src/main/java/org/apache/atlas/groovy/LogicalExpression.java @@ -0,0 +1,46 @@ +/** + * 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.groovy; + +/** + * Represents a logical (and/or) expression. + * + */ +public class LogicalExpression extends BinaryExpression { + + /** + * Allowed logical operators. + * + */ + public enum LogicalOperator { + AND("&&"), + OR("||"); + + private String groovyValue; + LogicalOperator(String groovyValue) { + this.groovyValue = groovyValue; + } + public String getGroovyValue() { + return groovyValue; + } + } + + public LogicalExpression(GroovyExpression left, LogicalOperator op, GroovyExpression right) { + super(left, op.getGroovyValue(), right); + } +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/69af0ae7/common/src/main/java/org/apache/atlas/groovy/RangeExpression.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/org/apache/atlas/groovy/RangeExpression.java b/common/src/main/java/org/apache/atlas/groovy/RangeExpression.java new file mode 100644 index 0000000..7322f69 --- /dev/null +++ b/common/src/main/java/org/apache/atlas/groovy/RangeExpression.java @@ -0,0 +1,45 @@ +/** + * 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.groovy; + +/** + * Represents an "exclusive" range expression, e.g. [0..<10]. + */ +public class RangeExpression extends AbstractGroovyExpression { + + private GroovyExpression parent; + private int offset; + private int count; + + public RangeExpression(GroovyExpression parent, int offset, int count) { + this.parent = parent; + this.offset = offset; + this.count = count; + } + + @Override + public void generateGroovy(GroovyGenerationContext context) { + parent.generateGroovy(context); + context.append(" ["); + new LiteralExpression(offset).generateGroovy(context); + context.append("..<"); + new LiteralExpression(count).generateGroovy(context); + context.append("]"); + } +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/69af0ae7/common/src/main/java/org/apache/atlas/groovy/TernaryOperatorExpression.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/org/apache/atlas/groovy/TernaryOperatorExpression.java b/common/src/main/java/org/apache/atlas/groovy/TernaryOperatorExpression.java new file mode 100644 index 0000000..75a2f86 --- /dev/null +++ b/common/src/main/java/org/apache/atlas/groovy/TernaryOperatorExpression.java @@ -0,0 +1,56 @@ +/** + * 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.groovy; + +/** + * Groovy expression that represents the ternary operator (expr ? trueValue : + * falseValue) + */ +public class TernaryOperatorExpression extends AbstractGroovyExpression { + + private GroovyExpression booleanExpr; + private GroovyExpression trueValue; + private GroovyExpression falseValue; + + public TernaryOperatorExpression(GroovyExpression booleanExpr, GroovyExpression trueValue, + GroovyExpression falseValue) { + + this.booleanExpr = booleanExpr; + this.trueValue = trueValue; + this.falseValue = falseValue; + } + + @Override + public void generateGroovy(GroovyGenerationContext context) { + + context.append("(("); + booleanExpr.generateGroovy(context); + context.append(") ? ("); + trueValue.generateGroovy(context); + context.append(") : ("); + falseValue.generateGroovy(context); + context.append("))"); + } + + public String toString() { + GroovyGenerationContext context = new GroovyGenerationContext(); + generateGroovy(context); + return context.getQuery(); + } +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/69af0ae7/common/src/main/java/org/apache/atlas/groovy/TypeCoersionExpression.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/org/apache/atlas/groovy/TypeCoersionExpression.java b/common/src/main/java/org/apache/atlas/groovy/TypeCoersionExpression.java new file mode 100644 index 0000000..4a61052 --- /dev/null +++ b/common/src/main/java/org/apache/atlas/groovy/TypeCoersionExpression.java @@ -0,0 +1,44 @@ +/** + * 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.groovy; + +/** + * Groovy expression that represents a type coersion (e.g obj as Set). + */ +public class TypeCoersionExpression extends AbstractGroovyExpression { + + private GroovyExpression expr; + private String className; + + public TypeCoersionExpression(GroovyExpression expr, String className) { + this.expr = expr; + this.className =className; + } + + @Override + public void generateGroovy(GroovyGenerationContext context) { + + context.append("("); + expr.generateGroovy(context); + context.append(")"); + context.append(" as "); + context.append(className); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/69af0ae7/common/src/main/java/org/apache/atlas/groovy/VariableAssignmentExpression.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/org/apache/atlas/groovy/VariableAssignmentExpression.java b/common/src/main/java/org/apache/atlas/groovy/VariableAssignmentExpression.java new file mode 100644 index 0000000..7e018f1 --- /dev/null +++ b/common/src/main/java/org/apache/atlas/groovy/VariableAssignmentExpression.java @@ -0,0 +1,58 @@ +/** + * 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.groovy; + +/** + * Groovy statement that assigns a value to a variable. + */ +public class VariableAssignmentExpression extends AbstractGroovyExpression { + + private String type = null; + private String name; + private GroovyExpression value; + + /** + * @param string + * @param v + */ + public VariableAssignmentExpression(String type, String name, GroovyExpression v) { + this.type = type; + this.name = name; + this.value = v; + } + + public VariableAssignmentExpression(String name, GroovyExpression v) { + this(null, name, v); + } + + @Override + public void generateGroovy(GroovyGenerationContext context) { + if (type == null) { + context.append("def "); + } else { + context.append(type); + context.append(" "); + } + context.append(name); + context.append(" = "); + value.generateGroovy(context); + + } + +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/69af0ae7/graphdb/api/src/main/java/org/apache/atlas/repository/graphdb/AtlasGraph.java ---------------------------------------------------------------------- diff --git a/graphdb/api/src/main/java/org/apache/atlas/repository/graphdb/AtlasGraph.java b/graphdb/api/src/main/java/org/apache/atlas/repository/graphdb/AtlasGraph.java index 22280d5..13b9a11 100644 --- a/graphdb/api/src/main/java/org/apache/atlas/repository/graphdb/AtlasGraph.java +++ b/graphdb/api/src/main/java/org/apache/atlas/repository/graphdb/AtlasGraph.java @@ -23,6 +23,7 @@ import java.util.Set; import javax.script.ScriptException; +import org.apache.atlas.groovy.GroovyExpression; import org.apache.atlas.typesystem.types.IDataType; /** @@ -204,7 +205,7 @@ public interface AtlasGraph<V, E> { * @param type * @return */ - String generatePersisentToLogicalConversionExpression(String valueExpr, IDataType<?> type); + GroovyExpression generatePersisentToLogicalConversionExpression(GroovyExpression valueExpr, IDataType<?> type); /** * Indicates whether or not stored values with the specified type need to be converted @@ -240,7 +241,7 @@ public interface AtlasGraph<V, E> { * * @return */ - String getInitialIndexedPredicate(); + GroovyExpression getInitialIndexedPredicate(GroovyExpression parent); /** * As an optimization, a graph database implementation may want to retrieve additional @@ -249,7 +250,7 @@ public interface AtlasGraph<V, E> { * avoid the need to make an extra REST API call to look up those edges. For implementations * that do not require any kind of transform, an empty String should be returned. */ - String getOutputTransformationPredicate(boolean isSelect, boolean isPath); + GroovyExpression addOutputTransformationPredicate(GroovyExpression expr, boolean isSelect, boolean isPath); /** * Executes a Gremlin script, returns an object with the result. http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/69af0ae7/graphdb/titan0/src/main/java/org/apache/atlas/repository/graphdb/titan0/Titan0Graph.java ---------------------------------------------------------------------- diff --git a/graphdb/titan0/src/main/java/org/apache/atlas/repository/graphdb/titan0/Titan0Graph.java b/graphdb/titan0/src/main/java/org/apache/atlas/repository/graphdb/titan0/Titan0Graph.java index b540788..2dbe742 100644 --- a/graphdb/titan0/src/main/java/org/apache/atlas/repository/graphdb/titan0/Titan0Graph.java +++ b/graphdb/titan0/src/main/java/org/apache/atlas/repository/graphdb/titan0/Titan0Graph.java @@ -34,6 +34,7 @@ import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; +import org.apache.atlas.groovy.GroovyExpression; import org.apache.atlas.repository.graphdb.AtlasEdge; import org.apache.atlas.repository.graphdb.AtlasGraph; import org.apache.atlas.repository.graphdb.AtlasGraphManagement; @@ -286,7 +287,7 @@ public class Titan0Graph implements AtlasGraph<Titan0Vertex, Titan0Edge> { } @Override - public String generatePersisentToLogicalConversionExpression(String expr, IDataType<?> type) { + public GroovyExpression generatePersisentToLogicalConversionExpression(GroovyExpression expr, IDataType<?> type) { //nothing special needed, value is stored in required type return expr; @@ -304,13 +305,13 @@ public class Titan0Graph implements AtlasGraph<Titan0Vertex, Titan0Edge> { } @Override - public String getInitialIndexedPredicate() { - return ""; + public GroovyExpression getInitialIndexedPredicate(GroovyExpression expr) { + return expr; } @Override - public String getOutputTransformationPredicate(boolean inSelect, boolean isPath) { - return ""; + public GroovyExpression addOutputTransformationPredicate(GroovyExpression expr, boolean inSelect, boolean isPath) { + return expr; } public Iterable<AtlasEdge<Titan0Vertex, Titan0Edge>> wrapEdges(Iterator<Edge> it) { http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/69af0ae7/release-log.txt ---------------------------------------------------------------------- diff --git a/release-log.txt b/release-log.txt index 76c6a77..67e83a9 100644 --- a/release-log.txt +++ b/release-log.txt @@ -9,6 +9,7 @@ ATLAS-1060 Add composite indexes for exact match performance improvements for al ATLAS-1127 Modify creation and modification timestamps to Date instead of Long(sumasai) ALL CHANGES: +ATLAS-1195 Clean up DSL Translation (jnhagelb via dkantor) ATLAS-1139 Parameter name of a HDFS DataSet entity should contain filesystem path (svimal2106 via sumasai) ATLAS-1200 Error Catalog enhancement (apoorvnaik via sumasai) ATLAS-1207 Dataset exists query in lineage APIs takes longer (shwethags) http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/69af0ae7/repository/src/main/java/org/apache/atlas/discovery/graph/DefaultGraphPersistenceStrategy.java ---------------------------------------------------------------------- diff --git a/repository/src/main/java/org/apache/atlas/discovery/graph/DefaultGraphPersistenceStrategy.java b/repository/src/main/java/org/apache/atlas/discovery/graph/DefaultGraphPersistenceStrategy.java index 1133b48..aad056f 100755 --- a/repository/src/main/java/org/apache/atlas/discovery/graph/DefaultGraphPersistenceStrategy.java +++ b/repository/src/main/java/org/apache/atlas/discovery/graph/DefaultGraphPersistenceStrategy.java @@ -23,16 +23,16 @@ import java.util.List; import javax.inject.Inject; import org.apache.atlas.AtlasException; -import org.apache.atlas.query.Expressions; +import org.apache.atlas.groovy.GroovyExpression; import org.apache.atlas.query.GraphPersistenceStrategies; import org.apache.atlas.query.GraphPersistenceStrategies$class; -import org.apache.atlas.query.IntSequence; import org.apache.atlas.query.TypeUtils; import org.apache.atlas.repository.Constants; import org.apache.atlas.repository.MetadataRepository; import org.apache.atlas.repository.RepositoryException; import org.apache.atlas.repository.graph.GraphBackedMetadataRepository; import org.apache.atlas.repository.graph.GraphHelper; +import org.apache.atlas.repository.graphdb.AtlasEdgeDirection; import org.apache.atlas.repository.graphdb.AtlasGraph; import org.apache.atlas.repository.graphdb.AtlasVertex; import org.apache.atlas.repository.graphdb.GremlinVersion; @@ -105,11 +105,6 @@ public class DefaultGraphPersistenceStrategy implements GraphPersistenceStrategi } @Override - public String fieldPrefixInSelect() { - return "it"; - } - - @Override public Id getIdFromVertex(String dataTypeName, AtlasVertex vertex) { return GraphHelper.getIdFromVertex(dataTypeName, vertex); } @@ -212,28 +207,13 @@ public class DefaultGraphPersistenceStrategy implements GraphPersistenceStrategi } @Override - public String gremlinCompOp(Expressions.ComparisonExpression op) { - return GraphPersistenceStrategies$class.gremlinCompOp(this, op); - } - - @Override - public String gremlinPrimitiveOp(Expressions.ComparisonExpression op) { - return GraphPersistenceStrategies$class.gremlinPrimitiveOp(this, op); - } - - @Override - public String loopObjectExpression(IDataType<?> dataType) { - return GraphPersistenceStrategies$class.loopObjectExpression(this, dataType); + public AtlasEdgeDirection instanceToTraitEdgeDirection() { + return AtlasEdgeDirection.OUT; } @Override - public String instanceToTraitEdgeDirection() { - return "out"; - } - - @Override - public String traitToInstanceEdgeDirection() { - return "in"; + public AtlasEdgeDirection traitToInstanceEdgeDirection() { + return AtlasEdgeDirection.IN; } @Override @@ -247,33 +227,28 @@ public class DefaultGraphPersistenceStrategy implements GraphPersistenceStrategi } @Override - public scala.collection.Seq<String> typeTestExpression(String typeName, IntSequence intSeq) { - return GraphPersistenceStrategies$class.typeTestExpression(this, typeName, intSeq); - } - - @Override public boolean collectTypeInstancesIntoVar() { return GraphPersistenceStrategies$class.collectTypeInstancesIntoVar(this); } @Override - public boolean addGraphVertexPrefix(scala.collection.Traversable<String> preStatements) { + public boolean addGraphVertexPrefix(scala.collection.Traversable<GroovyExpression> preStatements) { return GraphPersistenceStrategies$class.addGraphVertexPrefix(this, preStatements); } - + @Override public GremlinVersion getSupportedGremlinVersion() { return GraphPersistenceStrategies$class.getSupportedGremlinVersion(this); } @Override - public String generatePersisentToLogicalConversionExpression(String expr, IDataType<?> t) { + public GroovyExpression generatePersisentToLogicalConversionExpression(GroovyExpression expr, IDataType<?> t) { return GraphPersistenceStrategies$class.generatePersisentToLogicalConversionExpression(this,expr, t); } @Override - public String initialQueryCondition() { - return GraphPersistenceStrategies$class.initialQueryCondition(this); + public GroovyExpression addInitialQueryCondition(GroovyExpression expr) { + return GraphPersistenceStrategies$class.addInitialQueryCondition(this, expr); } @Override http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/69af0ae7/repository/src/main/java/org/apache/atlas/gremlin/Gremlin2ExpressionFactory.java ---------------------------------------------------------------------- diff --git a/repository/src/main/java/org/apache/atlas/gremlin/Gremlin2ExpressionFactory.java b/repository/src/main/java/org/apache/atlas/gremlin/Gremlin2ExpressionFactory.java new file mode 100644 index 0000000..a901b51 --- /dev/null +++ b/repository/src/main/java/org/apache/atlas/gremlin/Gremlin2ExpressionFactory.java @@ -0,0 +1,223 @@ +/** + * 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.List; + +import org.apache.atlas.AtlasException; +import org.apache.atlas.groovy.ClosureExpression; +import org.apache.atlas.groovy.ComparisonExpression; +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.ListExpression; +import org.apache.atlas.groovy.LiteralExpression; +import org.apache.atlas.groovy.LogicalExpression; +import org.apache.atlas.groovy.RangeExpression; +import org.apache.atlas.groovy.TernaryOperatorExpression; +import org.apache.atlas.groovy.ComparisonExpression.ComparisonOperator; +import org.apache.atlas.groovy.LogicalExpression.LogicalOperator; +import org.apache.atlas.query.GraphPersistenceStrategies; +import org.apache.atlas.query.TypeUtils.FieldInfo; +import org.apache.atlas.typesystem.types.IDataType; + + +/** + * Generates gremlin query expressions using Gremlin 2 syntax. + * + */ +public class Gremlin2ExpressionFactory extends GremlinExpressionFactory { + + private static final String LOOP_METHOD = "loop"; + private static final String CONTAINS = "contains"; + private static final String LOOP_COUNT_FIELD = "loops"; + private static final String PATH_FIELD = "path"; + private static final String ENABLE_PATH_METHOD = "enablePath"; + private static final String BACK_METHOD = "back"; + + + @Override + public GroovyExpression generateLogicalExpression(GroovyExpression parent, String operator, List<GroovyExpression> operands) { + return new FunctionCallExpression(parent, operator, operands); + } + + + @Override + public GroovyExpression generateBackReferenceExpression(GroovyExpression parent, boolean inSelect, String alias) { + if (inSelect) { + return getFieldInSelect(); + } + else { + return new FunctionCallExpression(parent, BACK_METHOD, new LiteralExpression(alias)); + } + } + + @Override + public GroovyExpression getLoopExpressionParent(GroovyExpression inputQry) { + return inputQry; + } + + @Override + public GroovyExpression generateLoopExpression(GroovyExpression parent,GraphPersistenceStrategies s, IDataType dataType, GroovyExpression loopExpr, String alias, Integer times) { + + GroovyExpression emitExpr = generateLoopEmitExpression(s, dataType); + //note that in Gremlin 2 (unlike Gremlin 3), the parent is not explicitly used. It is incorporated + //in the loopExpr. + GroovyExpression whileFunction = null; + if(times != null) { + GroovyExpression loopsExpr = new FieldExpression(getItVariable(), LOOP_COUNT_FIELD); + GroovyExpression timesExpr = new LiteralExpression(times); + whileFunction = new ClosureExpression(new ComparisonExpression(loopsExpr, ComparisonOperator.LESS_THAN, timesExpr)); + } + else { + GroovyExpression pathExpr = new FieldExpression(getItVariable(),PATH_FIELD); + GroovyExpression itObjectExpr = getCurrentObjectExpression(); + GroovyExpression pathContainsExpr = new FunctionCallExpression(pathExpr, CONTAINS, itObjectExpr); + whileFunction = new ClosureExpression(new TernaryOperatorExpression(pathContainsExpr, LiteralExpression.FALSE, LiteralExpression.TRUE)); + } + GroovyExpression emitFunction = new ClosureExpression(emitExpr); + GroovyExpression loopCall = new FunctionCallExpression(loopExpr, LOOP_METHOD, new LiteralExpression(alias), whileFunction, emitFunction); + + return new FunctionCallExpression(loopCall, ENABLE_PATH_METHOD); + } + + @Override + public GroovyExpression typeTestExpression(GraphPersistenceStrategies s, String typeName, GroovyExpression itRef) { + + GroovyExpression typeAttrExpr = new FieldExpression(itRef, s.typeAttributeName()); + GroovyExpression superTypeAttrExpr = new FieldExpression(itRef, s.superTypeAttributeName()); + GroovyExpression typeNameExpr = new LiteralExpression(typeName); + + GroovyExpression typeMatchesExpr = new ComparisonExpression(typeAttrExpr, ComparisonOperator.EQUALS, typeNameExpr); + GroovyExpression isSuperTypeExpr = new FunctionCallExpression(superTypeAttrExpr, CONTAINS, typeNameExpr); + GroovyExpression hasSuperTypeAttrExpr = superTypeAttrExpr; + GroovyExpression superTypeMatchesExpr = new TernaryOperatorExpression(hasSuperTypeAttrExpr, isSuperTypeExpr, LiteralExpression.FALSE); + + return new LogicalExpression(typeMatchesExpr, LogicalOperator.OR, superTypeMatchesExpr); + } + + @Override + public GroovyExpression generateSelectExpression(GroovyExpression parent, List<LiteralExpression> sourceNames, + List<GroovyExpression> srcExprs) { + + GroovyExpression srcNamesExpr = new ListExpression(sourceNames); + List<GroovyExpression> selectArgs = new ArrayList<>(); + selectArgs.add(srcNamesExpr); + for(GroovyExpression expr : srcExprs) { + selectArgs.add(new ClosureExpression(expr)); + } + return new FunctionCallExpression(parent, SELECT_METHOD, selectArgs); + } + + @Override + public GroovyExpression generateFieldExpression(GroovyExpression parent, FieldInfo fInfo, String propertyName, boolean inSelect) { + return new FieldExpression(parent, propertyName); + } + + @Override + public GroovyExpression generateHasExpression(GraphPersistenceStrategies s, GroovyExpression parent, String propertyName, String symbol, + GroovyExpression requiredValue, FieldInfo fInfo) throws AtlasException { + GroovyExpression op = gremlin2CompOp(symbol); + GroovyExpression propertyNameExpr = new LiteralExpression(propertyName); + return new FunctionCallExpression(parent, HAS_METHOD, propertyNameExpr, op, requiredValue); + } + + private GroovyExpression gremlin2CompOp(String op) throws AtlasException { + + GroovyExpression tExpr = new IdentifierExpression("T"); + if(op.equals("=")) { + return new FieldExpression(tExpr, "eq"); + } + if(op.equals("!=")) { + return new FieldExpression(tExpr, "neq"); + } + if(op.equals(">")) { + return new FieldExpression(tExpr, "gt"); + } + if(op.equals(">=")) { + return new FieldExpression(tExpr, "gte"); + } + if(op.equals("<")) { + return new FieldExpression(tExpr, "lt"); + } + if(op.equals("<=")) { + return new FieldExpression(tExpr, "lte"); + } + throw new AtlasException("Comparison operator " + op + " not supported in Gremlin"); + } + + @Override + protected GroovyExpression initialExpression(GraphPersistenceStrategies s, GroovyExpression varExpr) { + return new FunctionCallExpression(varExpr, "_"); + } + + @Override + public GroovyExpression generateLimitExpression(GroovyExpression parent, int offset, int totalRows) { + return new RangeExpression(parent, offset, totalRows); + } + + @Override + public List<GroovyExpression> getOrderFieldParents() { + + GroovyExpression itExpr = getItVariable(); + List<GroovyExpression> result = new ArrayList<>(2); + result.add(new FieldExpression(itExpr, "a")); + result.add(new FieldExpression(itExpr, "b")); + return result; + } + + + @Override + public GroovyExpression generateOrderByExpression(GroovyExpression parent, List<GroovyExpression> translatedOrderBy, boolean isAscending) { + GroovyExpression itExpr = getItVariable(); + GroovyExpression aPropertyExpr = translatedOrderBy.get(0); + GroovyExpression bPropertyExpr = translatedOrderBy.get(1); + + GroovyExpression aPropertyNotNull = new ComparisonExpression(aPropertyExpr, ComparisonOperator.NOT_EQUALS, LiteralExpression.NULL); + GroovyExpression bPropertyNotNull = new ComparisonExpression(bPropertyExpr, ComparisonOperator.NOT_EQUALS, LiteralExpression.NULL); + + GroovyExpression aCondition = new TernaryOperatorExpression(aPropertyNotNull, new FunctionCallExpression(aPropertyExpr,TO_LOWER_CASE_METHOD), aPropertyExpr); + GroovyExpression bCondition = new TernaryOperatorExpression(bPropertyNotNull, new FunctionCallExpression(bPropertyExpr,TO_LOWER_CASE_METHOD), bPropertyExpr); + + GroovyExpression comparisonFunction = null; + if(isAscending) { + comparisonFunction = new ComparisonOperatorExpression(aCondition, bCondition); + } + else { + comparisonFunction = new ComparisonOperatorExpression(bCondition, aCondition); + } + return new FunctionCallExpression(parent, ORDER_METHOD, new ClosureExpression(comparisonFunction)); + } + + + @Override + public GroovyExpression getAnonymousTraversalExpression() { + return new FunctionCallExpression("_"); + } + + + @Override + public GroovyExpression getFieldInSelect() { + return getItVariable(); + } +} + http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/69af0ae7/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 new file mode 100644 index 0000000..32189bc --- /dev/null +++ b/repository/src/main/java/org/apache/atlas/gremlin/Gremlin3ExpressionFactory.java @@ -0,0 +1,325 @@ +/** + * 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.List; + +import org.apache.atlas.AtlasException; +import org.apache.atlas.groovy.CastExpression; +import org.apache.atlas.groovy.ClosureExpression; +import org.apache.atlas.groovy.ComparisonExpression; +import org.apache.atlas.groovy.ComparisonOperatorExpression; +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.TypeCoersionExpression; +import org.apache.atlas.groovy.ComparisonExpression.ComparisonOperator; +import org.apache.atlas.groovy.LogicalExpression.LogicalOperator; +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 WHERE_METHOD = "where"; + private static final String TO_STRING_METHOD = "toString"; + + @Override + public GroovyExpression generateLogicalExpression(GroovyExpression parent, String operator, + List<GroovyExpression> operands) { + if (operands.size() == 1) { + // gremlin 3 treats one element expressions as 'false'. Avoid + // creating a boolean expression in this case. Inline the expression + // note: we can't simply omit it, since it will cause us to traverse + // the edge! + // use 'where' instead + GroovyExpression expr = operands.get(0); + // if child is a back expression, that expression becomes an + // argument to where + return new FunctionCallExpression(parent, WHERE_METHOD, expr); + } else { + // Gremlin 3 does not support _() syntax + // + return new FunctionCallExpression(parent, operator, operands); + } + } + + @Override + public GroovyExpression generateBackReferenceExpression(GroovyExpression parent, boolean inSelect, String alias) { + if (inSelect) { + return getFieldInSelect(); + } else { + return new FunctionCallExpression(parent, SELECT_METHOD, new LiteralExpression(alias)); + } + } + + @Override + public GroovyExpression typeTestExpression(GraphPersistenceStrategies s, String typeName, GroovyExpression itRef) { + LiteralExpression typeAttrExpr = new LiteralExpression(s.typeAttributeName()); + LiteralExpression superTypeAttrExpr = new LiteralExpression(s.superTypeAttributeName()); + LiteralExpression typeNameExpr = new LiteralExpression(typeName); + + FunctionCallExpression result = new FunctionCallExpression(HAS_METHOD, typeAttrExpr, new FunctionCallExpression(EQ_METHOD, typeNameExpr)); + result = new FunctionCallExpression(result, "or"); + result = new FunctionCallExpression(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(parent, REPEAT_METHOD, loopExpr); + if (times != null) { + GroovyExpression timesExpr = new LiteralExpression(times); + result = new FunctionCallExpression(result, TIMES_METHOD, timesExpr); + } + result = new FunctionCallExpression(result, EMIT_METHOD, emitExpr); + return result; + + } + + @Override + public GroovyExpression getLoopExpressionParent(GroovyExpression inputQry) { + GroovyExpression curTraversal = new IdentifierExpression("__"); + return curTraversal; + } + + @Override + public GroovyExpression generateSelectExpression(GroovyExpression parent, List<LiteralExpression> sourceNames, + List<GroovyExpression> srcExprs) { + FunctionCallExpression result = new FunctionCallExpression(parent, SELECT_METHOD, sourceNames); + + for (GroovyExpression expr : srcExprs) { + GroovyExpression closure = new ClosureExpression(expr); + GroovyExpression castClosure = new TypeCoersionExpression(closure, FUNCTION_CLASS); + result = new FunctionCallExpression(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); + 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(parent, VALUES_METHOD, propertyNameExpr); + if (graph.isPropertyValueConversionNeeded(attrType)) { + GroovyExpression toConvert = new FunctionCallExpression(getItVariable(), GET_METHOD); + + GroovyExpression conversionFunction = graph.generatePersisentToLogicalConversionExpression(toConvert, + attrType); + return new FunctionCallExpression(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(parent, FILTER_METHOD, filterFunction); + } else { + GroovyExpression valueMatches = new FunctionCallExpression(getComparisonFunction(symbol), requiredValue); + return new FunctionCallExpression(parent, HAS_METHOD, propertNameExpr, valueMatches); + } + } + + @Override + protected GroovyExpression initialExpression(GraphPersistenceStrategies s, GroovyExpression varExpr) { + + // 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 = getGraph(); + GroovyExpression varRefExpr = new TypeCoersionExpression(varExpr, OBJECT_ARRAY_CLASS); + FunctionCallExpression expr = new FunctionCallExpression(gExpr, V_METHOD, varRefExpr); + return s.addInitialQueryCondition(expr); + } + + @Override + public GroovyExpression generateLimitExpression(GroovyExpression parent, int offset, int totalRows) { + return new FunctionCallExpression(parent, RANGE_METHOD, new LiteralExpression(offset), new LiteralExpression(totalRows)); + } + + @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 orderByClause = translatedOrderBy.get(0); + + 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"); + return new FunctionCallExpression(new FunctionCallExpression(parent, ORDER_METHOD), 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); + } + +}
