ATLAS-2229: DSL implementation using ANTLR - #4 (multiple fixes)

Signed-off-by: Madhan Neethiraj <mad...@apache.org>


Project: http://git-wip-us.apache.org/repos/asf/atlas/repo
Commit: http://git-wip-us.apache.org/repos/asf/atlas/commit/8db8b5c7
Tree: http://git-wip-us.apache.org/repos/asf/atlas/tree/8db8b5c7
Diff: http://git-wip-us.apache.org/repos/asf/atlas/diff/8db8b5c7

Branch: refs/heads/master
Commit: 8db8b5c7c199c25c6d83074940fc3020cd3815d0
Parents: 5384a74
Author: apoorvnaik <apoorvn...@apache.org>
Authored: Fri Dec 22 12:55:28 2017 -0800
Committer: Madhan Neethiraj <mad...@apache.org>
Committed: Sat Dec 23 21:51:34 2017 -0800

----------------------------------------------------------------------
 .../java/org/apache/atlas/AtlasErrorCode.java   |   3 +-
 .../atlas/discovery/EntityDiscoveryService.java |  17 +-
 .../java/org/apache/atlas/query/AtlasDSL.java   | 135 +++
 .../java/org/apache/atlas/query/DSLVisitor.java |  84 +-
 .../org/apache/atlas/query/Expressions.java     |  41 -
 .../atlas/query/GremlinQueryComposer.java       | 887 +++++++++++++++++++
 .../apache/atlas/query/GremlinTranslator.java   |  41 -
 .../apache/atlas/query/IdentifierHelper.java    |  38 +-
 .../java/org/apache/atlas/query/Lookup.java     |  18 +-
 .../org/apache/atlas/query/QueryParser.java     |  66 --
 .../org/apache/atlas/query/QueryProcessor.java  | 823 -----------------
 .../atlas/query/antlr4/AtlasDSLLexer.java       |  14 +-
 .../atlas/query/antlr4/AtlasDSLLexer.tokens     |  59 --
 .../apache/atlas/query/antlr4/AtlasDSLParser.g4 |   2 +-
 .../atlas/query/antlr4/AtlasDSLParser.tokens    |  59 --
 .../store/graph/v1/AtlasAbstractDefStoreV1.java |   4 +-
 .../graph/v1/AtlasRelationshipDefStoreV1.java   |   6 +-
 .../org/apache/atlas/query/DSLQueriesTest.java  |  30 +-
 .../atlas/query/GremlinQueryComposerTest.java   | 394 ++++++++
 .../apache/atlas/query/QueryProcessorTest.java  | 397 ---------
 20 files changed, 1527 insertions(+), 1591 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/atlas/blob/8db8b5c7/intg/src/main/java/org/apache/atlas/AtlasErrorCode.java
----------------------------------------------------------------------
diff --git a/intg/src/main/java/org/apache/atlas/AtlasErrorCode.java 
b/intg/src/main/java/org/apache/atlas/AtlasErrorCode.java
index fb741f8..0953725 100644
--- a/intg/src/main/java/org/apache/atlas/AtlasErrorCode.java
+++ b/intg/src/main/java/org/apache/atlas/AtlasErrorCode.java
@@ -102,7 +102,8 @@ public enum AtlasErrorCode {
     INVALID_ENTITY_FOR_CLASSIFICATION (400, "ATLAS-400-00-055", "Entity 
(guid=‘{0}‘,typename=‘{1}‘) cannot be classified by Classification 
‘{2}‘, because ‘{1}‘ is not in the ClassificationDef's restrictions."),
     SAVED_SEARCH_CHANGE_USER(400, "ATLAS-400-00-056", "saved-search {0} can 
not be moved from user {1} to {2}"),
     INVALID_QUERY_PARAM_LENGTH(400, "ATLAS-400-00-057" , "Length of query 
param {0} exceeds the limit"),
-    INVALID_QUERY_LENGTH(400, "ATLAS-400-00-057" , "Invalid query length, 
update {0} to change the limit" ),
+    INVALID_QUERY_LENGTH(400, "ATLAS-400-00-058" , "Invalid query length, 
update {0} to change the limit" ),
+    INVALID_DSL_QUERY(400, "ATLAS-400-00-059" , "Invalid DSL query: {0} 
Reason: {1}. Please refer to Atlas DSL grammar for more information" ),
 
     // All Not found enums go here
     TYPE_NAME_NOT_FOUND(404, "ATLAS-404-00-001", "Given typename {0} was 
invalid"),

http://git-wip-us.apache.org/repos/asf/atlas/blob/8db8b5c7/repository/src/main/java/org/apache/atlas/discovery/EntityDiscoveryService.java
----------------------------------------------------------------------
diff --git 
a/repository/src/main/java/org/apache/atlas/discovery/EntityDiscoveryService.java
 
b/repository/src/main/java/org/apache/atlas/discovery/EntityDiscoveryService.java
index ece1516..cbe9a5b 100644
--- 
a/repository/src/main/java/org/apache/atlas/discovery/EntityDiscoveryService.java
+++ 
b/repository/src/main/java/org/apache/atlas/discovery/EntityDiscoveryService.java
@@ -33,12 +33,9 @@ import org.apache.atlas.model.discovery.SearchParameters;
 import org.apache.atlas.model.instance.AtlasEntityHeader;
 import org.apache.atlas.model.instance.AtlasObjectId;
 import org.apache.atlas.model.profile.AtlasUserSavedSearch;
-import org.apache.atlas.query.Expressions.Expression;
+import org.apache.atlas.query.AtlasDSL;
 import org.apache.atlas.query.GremlinQuery;
-import org.apache.atlas.query.GremlinTranslator;
 import org.apache.atlas.query.QueryParams;
-import org.apache.atlas.query.QueryParser;
-import org.apache.atlas.query.QueryProcessor;
 import org.apache.atlas.repository.Constants;
 import org.apache.atlas.repository.graph.GraphBackedSearchIndexer;
 import org.apache.atlas.repository.graph.GraphHelper;
@@ -678,16 +675,8 @@ public class EntityDiscoveryService implements 
AtlasDiscoveryService {
     }
 
     private GremlinQuery toGremlinQuery(String query, int limit, int offset) 
throws AtlasBaseException {
-        QueryParams params     = validateSearchParams(limit, offset);
-        Expression  expression = QueryParser.apply(query, params);
-
-        if (expression == null) {
-            throw new AtlasBaseException(DISCOVERY_QUERY_FAILED, query);
-        }
-
-        QueryProcessor queryProcessor  = new QueryProcessor(typeRegistry, 
limit, offset);
-        Expression     validExpression = queryProcessor.validate(expression);
-        GremlinQuery   gremlinQuery    = new GremlinTranslator(queryProcessor, 
validExpression).translate();
+        QueryParams  params       = validateSearchParams(limit, offset);
+        GremlinQuery gremlinQuery = new 
AtlasDSL.Translator(AtlasDSL.Parser.parse(query), typeRegistry, 
params.offset(), params.limit()).translate();
 
         if (LOG.isDebugEnabled()) {
             LOG.debug("Translated Gremlin Query: {}", gremlinQuery.queryStr());

http://git-wip-us.apache.org/repos/asf/atlas/blob/8db8b5c7/repository/src/main/java/org/apache/atlas/query/AtlasDSL.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/query/AtlasDSL.java 
b/repository/src/main/java/org/apache/atlas/query/AtlasDSL.java
new file mode 100644
index 0000000..e4c8165
--- /dev/null
+++ b/repository/src/main/java/org/apache/atlas/query/AtlasDSL.java
@@ -0,0 +1,135 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.query;
+
+import org.antlr.v4.runtime.BaseErrorListener;
+import org.antlr.v4.runtime.CharStreams;
+import org.antlr.v4.runtime.CommonTokenStream;
+import org.antlr.v4.runtime.RecognitionException;
+import org.antlr.v4.runtime.Recognizer;
+import org.antlr.v4.runtime.TokenStream;
+import org.apache.atlas.AtlasErrorCode;
+import org.apache.atlas.exception.AtlasBaseException;
+import org.apache.atlas.query.antlr4.AtlasDSLLexer;
+import org.apache.atlas.query.antlr4.AtlasDSLParser;
+import org.apache.atlas.type.AtlasTypeRegistry;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+public class AtlasDSL {
+
+    public static class Parser {
+        private static final Logger LOG = 
LoggerFactory.getLogger(Parser.class);
+
+        private static final Set<String> RESERVED_KEYWORDS =
+                new HashSet<>(Arrays.asList("[", "]", "(", ")", "=", "<", ">", 
"!=", "<=", ">=", ",", "and", "or", "+", "-",
+                                            "*", "/", ".", "select", "from", 
"where", "groupby", "loop", "isa", "is", "has",
+                                            "as", "times", "withPath", 
"limit", "offset", "orderby", "count", "max", "min",
+                                            "sum", "by", "order", "like"));
+
+        public static boolean isKeyword(String word) {
+            return RESERVED_KEYWORDS.contains(word);
+        }
+
+        public static AtlasDSLParser.QueryContext parse(String queryStr) 
throws AtlasBaseException {
+            AtlasDSLParser.QueryContext ret;
+            try {
+
+                InputStream    stream           = new 
ByteArrayInputStream(queryStr.getBytes());
+                AtlasDSLLexer  lexer            = new 
AtlasDSLLexer(CharStreams.fromStream(stream));
+                Validator      validator        = new Validator();
+                TokenStream    inputTokenStream = new CommonTokenStream(lexer);
+                AtlasDSLParser parser           = new 
AtlasDSLParser(inputTokenStream);
+
+                parser.removeErrorListeners();
+                parser.addErrorListener(validator);
+
+                // Validate the syntax of the query here
+                ret = parser.query();
+                if (!validator.isValid()) {
+                    LOG.error("Invalid DSL: {} Reason: {}", queryStr, 
validator.getErrorMsg());
+                    throw new 
AtlasBaseException(AtlasErrorCode.INVALID_DSL_QUERY, queryStr, 
validator.getErrorMsg());
+                }
+
+            } catch (IOException e) {
+                throw new AtlasBaseException(e);
+            }
+
+            return ret;
+        }
+
+    }
+
+    static class Validator extends BaseErrorListener {
+        private boolean isValid  = true;
+        private String  errorMsg = "";
+
+        @Override
+        public void syntaxError(final Recognizer<?, ?> recognizer, final 
Object offendingSymbol, final int line, final int charPositionInLine, final 
String msg, final RecognitionException e) {
+            // TODO: Capture multiple datapoints
+            isValid = false;
+            errorMsg = msg;
+        }
+
+        public boolean isValid() {
+            return isValid;
+        }
+
+        public String getErrorMsg() {
+            return errorMsg;
+        }
+    }
+
+    public static class Translator {
+        private final AtlasDSLParser.QueryContext queryContext;
+        private final AtlasTypeRegistry           typeRegistry;
+        private final int                         offset;
+        private final int                         limit;
+
+        public Translator(final AtlasDSLParser.QueryContext queryContext, 
AtlasTypeRegistry typeRegistry, int offset, int limit) {
+            this.queryContext = queryContext;
+            this.typeRegistry = typeRegistry;
+            this.offset       = offset;
+            this.limit        = limit;
+        }
+
+        public GremlinQuery translate() {
+            GremlinQueryComposer gremlinQueryComposer = new 
GremlinQueryComposer(typeRegistry);
+
+            if (offset >= 0) {
+                if (!gremlinQueryComposer.hasLimitOffset()) {
+                    gremlinQueryComposer.addLimit(Integer.toString(limit), 
Integer.toString(offset));
+                }
+            }
+
+            DSLVisitor dslVisitor = new DSLVisitor(gremlinQueryComposer);
+
+            // Now process the Query and collect translation in
+            queryContext.accept(dslVisitor);
+
+            return new GremlinQuery(gremlinQueryComposer.get(), 
gremlinQueryComposer.hasSelect());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/atlas/blob/8db8b5c7/repository/src/main/java/org/apache/atlas/query/DSLVisitor.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/query/DSLVisitor.java 
b/repository/src/main/java/org/apache/atlas/query/DSLVisitor.java
index b597a0d..a21e884 100644
--- a/repository/src/main/java/org/apache/atlas/query/DSLVisitor.java
+++ b/repository/src/main/java/org/apache/atlas/query/DSLVisitor.java
@@ -28,51 +28,51 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
 
-public class DSLVisitor extends AtlasDSLParserBaseVisitor<String> {
+public class DSLVisitor extends AtlasDSLParserBaseVisitor<Void> {
     private static final Logger LOG = 
LoggerFactory.getLogger(DSLVisitor.class);
 
     private static final String AND = "AND";
     private static final String OR  = "OR";
 
-    private final QueryProcessor queryProcessor;
+    private final GremlinQueryComposer gremlinQueryComposer;
 
-    public DSLVisitor(QueryProcessor queryProcessor) {
-        this.queryProcessor = queryProcessor;
+    public DSLVisitor(GremlinQueryComposer gremlinQueryComposer) {
+        this.gremlinQueryComposer = gremlinQueryComposer;
     }
 
     @Override
-    public String visitIsClause(IsClauseContext ctx) {
+    public Void visitIsClause(IsClauseContext ctx) {
         if (LOG.isDebugEnabled()) {
             LOG.debug("=> DSLVisitor.visitIsClause({})", ctx);
         }
 
-        queryProcessor.addFromIsA(ctx.arithE().getText(), 
ctx.identifier().getText());
+        gremlinQueryComposer.addFromIsA(ctx.arithE().getText(), 
ctx.identifier().getText());
         return super.visitIsClause(ctx);
     }
 
     @Override
-    public String visitHasClause(HasClauseContext ctx) {
+    public Void visitHasClause(HasClauseContext ctx) {
         if (LOG.isDebugEnabled()) {
             LOG.debug("=> DSLVisitor.visitHasClause({})", ctx);
         }
 
-        queryProcessor.addFromProperty(ctx.arithE().getText(), 
ctx.identifier().getText());
+        gremlinQueryComposer.addFromProperty(ctx.arithE().getText(), 
ctx.identifier().getText());
         return super.visitHasClause(ctx);
     }
 
     @Override
-    public String visitLimitOffset(LimitOffsetContext ctx) {
+    public Void visitLimitOffset(LimitOffsetContext ctx) {
         if (LOG.isDebugEnabled()) {
             LOG.debug("=> DSLVisitor.visitLimitOffset({})", ctx);
         }
 
-        queryProcessor.addLimit(ctx.limitClause().NUMBER().toString(),
-                                (ctx.offsetClause() == null ? "0" : 
ctx.offsetClause().NUMBER().getText()));
+        gremlinQueryComposer.addLimit(ctx.limitClause().NUMBER().toString(),
+                                      (ctx.offsetClause() == null ? "0" : 
ctx.offsetClause().NUMBER().getText()));
         return super.visitLimitOffset(ctx);
     }
 
     @Override
-    public String visitSelectExpr(SelectExprContext ctx) {
+    public Void visitSelectExpr(SelectExprContext ctx) {
         if (LOG.isDebugEnabled()) {
             LOG.debug("=> DSLVisitor.visitSelectExpr({})", ctx);
         }
@@ -85,7 +85,7 @@ public class DSLVisitor extends 
AtlasDSLParserBaseVisitor<String> {
             String[] items  = new String[ctx.selectExpression().size()];
             String[] labels = new String[ctx.selectExpression().size()];
 
-            QueryProcessor.SelectExprMetadata selectExprMetadata = new 
QueryProcessor.SelectExprMetadata();
+            GremlinQueryComposer.SelectExprMetadata selectExprMetadata = new 
GremlinQueryComposer.SelectExprMetadata();
 
             for (int i = 0; i < ctx.selectExpression().size(); i++) {
                 SelectExpressionContext selectExpression = 
ctx.selectExpression(i);
@@ -116,23 +116,25 @@ public class DSLVisitor extends 
AtlasDSLParserBaseVisitor<String> {
 
             selectExprMetadata.setItems(items);
             selectExprMetadata.setLabels(labels);
-            queryProcessor.addSelect(selectExprMetadata);
+            gremlinQueryComposer.addSelect(selectExprMetadata);
         }
         return super.visitSelectExpr(ctx);
     }
 
     @Override
-    public String visitOrderByExpr(OrderByExprContext ctx) {
+    public Void visitOrderByExpr(OrderByExprContext ctx) {
         if (LOG.isDebugEnabled()) {
             LOG.debug("=> DSLVisitor.visitOrderByExpr({})", ctx);
         }
 
-        queryProcessor.addOrderBy(ctx.expr().getText(), (ctx.sortOrder() != 
null && ctx.sortOrder().getText().equalsIgnoreCase("desc")));
+        // Extract the attribute from parentheses
+        String text = ctx.expr().getText().replace("(", "").replace(")", "");
+        gremlinQueryComposer.addOrderBy(text, (ctx.sortOrder() != null && 
ctx.sortOrder().getText().equalsIgnoreCase("desc")));
         return super.visitOrderByExpr(ctx);
     }
 
     @Override
-    public String visitWhereClause(WhereClauseContext ctx) {
+    public Void visitWhereClause(WhereClauseContext ctx) {
         if (LOG.isDebugEnabled()) {
             LOG.debug("=> DSLVisitor.visitWhereClause({})", ctx);
         }
@@ -141,12 +143,12 @@ public class DSLVisitor extends 
AtlasDSLParserBaseVisitor<String> {
         // The first expr shouldn't be processed if there are following exprs
         ExprContext expr = ctx.expr();
 
-        processExpr(expr, queryProcessor);
+        processExpr(expr, gremlinQueryComposer);
         return super.visitWhereClause(ctx);
     }
 
     @Override
-    public String visitFromExpression(final FromExpressionContext ctx) {
+    public Void visitFromExpression(final FromExpressionContext ctx) {
         if (LOG.isDebugEnabled()) {
             LOG.debug("=> DSLVisitor.visitFromExpression({})", ctx);
         }
@@ -155,38 +157,38 @@ public class DSLVisitor extends 
AtlasDSLParserBaseVisitor<String> {
         AliasExprContext aliasExpr = fromSrc.aliasExpr();
 
         if (aliasExpr != null) {
-            queryProcessor.addFromAlias(aliasExpr.identifier(0).getText(), 
aliasExpr.identifier(1).getText());
+            
gremlinQueryComposer.addFromAlias(aliasExpr.identifier(0).getText(), 
aliasExpr.identifier(1).getText());
         } else {
             if (fromSrc.identifier() != null) {
-                queryProcessor.addFrom(fromSrc.identifier().getText());
+                gremlinQueryComposer.addFrom(fromSrc.identifier().getText());
             } else {
-                queryProcessor.addFrom(fromSrc.literal().getText());
+                gremlinQueryComposer.addFrom(fromSrc.literal().getText());
             }
         }
         return super.visitFromExpression(ctx);
     }
 
     @Override
-    public String visitGroupByExpression(GroupByExpressionContext ctx) {
+    public Void visitGroupByExpression(GroupByExpressionContext ctx) {
         if (LOG.isDebugEnabled()) {
             LOG.debug("=> DSLVisitor.visitGroupByExpression({})", ctx);
         }
 
         String s = ctx.selectExpr().getText();
-        queryProcessor.addGroupBy(s);
+        gremlinQueryComposer.addGroupBy(s);
         return super.visitGroupByExpression(ctx);
     }
 
-    private void processExpr(final ExprContext expr, QueryProcessor 
queryProcessor) {
+    private void processExpr(final ExprContext expr, GremlinQueryComposer 
gremlinQueryComposer) {
         if (CollectionUtils.isNotEmpty(expr.exprRight())) {
-            processExprRight(expr, queryProcessor);
+            processExprRight(expr, gremlinQueryComposer);
         } else {
-            processExpr(expr.compE(), queryProcessor);
+            processExpr(expr.compE(), gremlinQueryComposer);
         }
     }
 
-    private void processExprRight(final ExprContext expr, QueryProcessor 
queryProcessor) {
-        QueryProcessor nestedProcessor = 
queryProcessor.createNestedProcessor();
+    private void processExprRight(final ExprContext expr, GremlinQueryComposer 
gremlinQueryComposer) {
+        GremlinQueryComposer nestedProcessor = 
gremlinQueryComposer.createNestedProcessor();
 
         List<String> nestedQueries = new ArrayList<>();
         String       prev          = null;
@@ -194,20 +196,20 @@ public class DSLVisitor extends 
AtlasDSLParserBaseVisitor<String> {
         // Process first expression then proceed with the others
         // expr -> compE exprRight*
         processExpr(expr.compE(), nestedProcessor);
-        nestedQueries.add(nestedProcessor.getText());
+        nestedQueries.add(nestedProcessor.get());
 
         for (ExprRightContext exprRight : expr.exprRight()) {
-            nestedProcessor = queryProcessor.createNestedProcessor();
+            nestedProcessor = gremlinQueryComposer.createNestedProcessor();
 
             // AND expression
             if (exprRight.K_AND() != null) {
                 if (prev == null) prev = AND;
                 if (OR.equalsIgnoreCase(prev)) {
                     // Change of context
-                    QueryProcessor orClause = 
nestedProcessor.createNestedProcessor();
+                    GremlinQueryComposer orClause = 
nestedProcessor.createNestedProcessor();
                     orClause.addOrClauses(nestedQueries);
                     nestedQueries.clear();
-                    nestedQueries.add(orClause.getText());
+                    nestedQueries.add(orClause.get());
                 }
                 prev = AND;
             }
@@ -216,25 +218,25 @@ public class DSLVisitor extends 
AtlasDSLParserBaseVisitor<String> {
                 if (prev == null) prev = OR;
                 if (AND.equalsIgnoreCase(prev)) {
                     // Change of context
-                    QueryProcessor andClause = 
nestedProcessor.createNestedProcessor();
+                    GremlinQueryComposer andClause = 
nestedProcessor.createNestedProcessor();
                     andClause.addAndClauses(nestedQueries);
                     nestedQueries.clear();
-                    nestedQueries.add(andClause.getText());
+                    nestedQueries.add(andClause.get());
                 }
                 prev = OR;
             }
             processExpr(exprRight.compE(), nestedProcessor);
-            nestedQueries.add(nestedProcessor.getText());
+            nestedQueries.add(nestedProcessor.get());
         }
         if (AND.equalsIgnoreCase(prev)) {
-            queryProcessor.addAndClauses(nestedQueries);
+            gremlinQueryComposer.addAndClauses(nestedQueries);
         }
         if (OR.equalsIgnoreCase(prev)) {
-            queryProcessor.addOrClauses(nestedQueries);
+            gremlinQueryComposer.addOrClauses(nestedQueries);
         }
     }
 
-    private void processExpr(final CompEContext compE, final QueryProcessor 
queryProcessor) {
+    private void processExpr(final CompEContext compE, final 
GremlinQueryComposer gremlinQueryComposer) {
         if (compE != null && compE.isClause() == null && compE.hasClause() == 
null && compE.isClause() == null) {
             ComparisonClauseContext comparisonClause = 
compE.comparisonClause();
 
@@ -252,9 +254,9 @@ public class DSLVisitor extends 
AtlasDSLParserBaseVisitor<String> {
                 String op  = 
comparisonClause.operator().getText().toUpperCase();
                 String rhs = comparisonClause.arithE(1).getText();
 
-                queryProcessor.addWhere(lhs, op, rhs);
+                gremlinQueryComposer.addWhere(lhs, op, rhs);
             } else {
-                processExpr(compE.arithE().multiE().atomE().expr(), 
queryProcessor);
+                processExpr(compE.arithE().multiE().atomE().expr(), 
gremlinQueryComposer);
             }
         }
     }

http://git-wip-us.apache.org/repos/asf/atlas/blob/8db8b5c7/repository/src/main/java/org/apache/atlas/query/Expressions.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/query/Expressions.java 
b/repository/src/main/java/org/apache/atlas/query/Expressions.java
deleted file mode 100644
index 77350f0..0000000
--- a/repository/src/main/java/org/apache/atlas/query/Expressions.java
+++ /dev/null
@@ -1,41 +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.query;
-
-
-import org.apache.atlas.query.antlr4.AtlasDSLParser.QueryContext;
-
-
-public class Expressions {
-    public static class Expression {
-        private final QueryContext parsedQuery;
-
-
-        public Expression(QueryContext q) {
-            parsedQuery = q;
-        }
-
-        public Expression isReady() {
-            return (parsedQuery != null ? this : null);
-        }
-
-        public void accept(DSLVisitor qv) {
-            qv.visit(parsedQuery);
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/atlas/blob/8db8b5c7/repository/src/main/java/org/apache/atlas/query/GremlinQueryComposer.java
----------------------------------------------------------------------
diff --git 
a/repository/src/main/java/org/apache/atlas/query/GremlinQueryComposer.java 
b/repository/src/main/java/org/apache/atlas/query/GremlinQueryComposer.java
new file mode 100644
index 0000000..6af1db6
--- /dev/null
+++ b/repository/src/main/java/org/apache/atlas/query/GremlinQueryComposer.java
@@ -0,0 +1,887 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.query;
+
+import com.google.common.annotations.VisibleForTesting;
+import org.apache.atlas.exception.AtlasBaseException;
+import org.apache.atlas.model.TypeCategory;
+import org.apache.atlas.model.discovery.SearchParameters;
+import org.apache.atlas.model.typedef.AtlasBaseTypeDef;
+import org.apache.atlas.type.AtlasArrayType;
+import org.apache.atlas.type.AtlasBuiltInTypes;
+import org.apache.atlas.type.AtlasEntityType;
+import org.apache.atlas.type.AtlasStructType;
+import org.apache.atlas.type.AtlasStructType.AtlasAttribute;
+import org.apache.atlas.type.AtlasType;
+import org.apache.atlas.type.AtlasTypeRegistry;
+import org.apache.commons.lang.StringUtils;
+import org.joda.time.DateTime;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.inject.Inject;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.StringJoiner;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+public class GremlinQueryComposer {
+    private static final Logger LOG = 
LoggerFactory.getLogger(GremlinQueryComposer.class);
+
+    private final int DEFAULT_QUERY_RESULT_LIMIT = 25;
+    private final int DEFAULT_QUERY_RESULT_OFFSET = 0;
+
+    private final List<String>       errorList      = new ArrayList<>();
+    private final GremlinClauseList  queryClauses   = new GremlinClauseList();
+    private final Lookup             lookup;
+    private final boolean            isNestedQuery;
+    private       int                providedLimit  = 
DEFAULT_QUERY_RESULT_LIMIT;
+    private       int                providedOffset = 
DEFAULT_QUERY_RESULT_OFFSET;
+    private       boolean            hasSelect      = false;
+    private       boolean            isSelectNoop   = false;
+    private       boolean            hasGroupBy     = false;
+    private       boolean            hasOrderBy     = false;
+    private       boolean            hasLimitOffset = false;
+    private       String             offset         = null;
+    private       String             limit          = null;
+    private       Context            context;
+    private       SelectExprMetadata selectExprMetadata;
+
+    @Inject
+    public GremlinQueryComposer(AtlasTypeRegistry typeRegistry) {
+        isNestedQuery = false;
+        lookup        = new RegistryBasedLookup(errorList, typeRegistry);
+        context       = new Context(errorList, lookup);
+
+        init();
+    }
+
+    public GremlinQueryComposer(AtlasTypeRegistry typeRegistry, int limit, int 
offset) {
+        this(typeRegistry);
+
+        providedLimit = limit;
+        providedOffset = offset < 0 ? DEFAULT_QUERY_RESULT_OFFSET : offset;
+    }
+
+    @VisibleForTesting
+    GremlinQueryComposer(Lookup lookup, Context context) {
+        this.isNestedQuery = false;
+        this.lookup        = lookup;
+        this.context       = context;
+
+        init();
+    }
+
+    public GremlinQueryComposer(Lookup registryLookup, boolean isNestedQuery) {
+        this.isNestedQuery = isNestedQuery;
+        this.lookup        = registryLookup;
+
+        init();
+    }
+
+    public void addFrom(String typeName) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("addFrom(typeName={})", typeName);
+        }
+
+        IdentifierHelper.Advice ta = getAdvice(typeName);
+
+        if(context.shouldRegister(ta.get())) {
+            context.registerActive(ta.get());
+
+            IdentifierHelper.Advice ia = getAdvice(ta.get());
+
+            if (ia.isTrait()) {
+                add(GremlinClause.TRAIT, ia.get());
+            } else {
+                if (ia.hasSubtypes()) {
+                    add(GremlinClause.HAS_TYPE_WITHIN, ia.getSubTypes());
+                } else {
+                    add(GremlinClause.HAS_TYPE, ia.get());
+                }
+            }
+        } else {
+            IdentifierHelper.Advice ia = getAdvice(ta.get());
+            introduceType(ia);
+        }
+    }
+
+    public void addFromProperty(String typeName, String attribute) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("addFromProperty(typeName={}, attribute={})", typeName, 
attribute);
+        }
+
+        addFrom(typeName);
+        add(GremlinClause.HAS_PROPERTY,
+                IdentifierHelper.getQualifiedName(lookup, context, attribute));
+    }
+
+
+    public void addFromIsA(String typeName, String traitName) {
+        addFrom(typeName);
+        add(GremlinClause.TRAIT, traitName);
+    }
+
+    public void addWhere(String lhs, String operator, String rhs) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("addWhere(lhs={}, operator={}, rhs={})", lhs, operator, 
rhs);
+        }
+
+        String currentType  = context.getActiveTypeName();
+        SearchParameters.Operator op = 
SearchParameters.Operator.fromString(operator);
+        IdentifierHelper.Advice org = null;
+        IdentifierHelper.Advice lhsI = getAdvice(lhs);
+        if(!lhsI.isPrimitive()) {
+            introduceType(lhsI);
+            org = lhsI;
+            lhsI = getAdvice(lhs);
+        }
+
+        if(lhsI.isDate()) {
+            rhs = parseDate(rhs);
+        }
+
+        rhs = addQuotesIfNecessary(rhs);
+        if(op == SearchParameters.Operator.LIKE) {
+            add(GremlinClause.TEXT_CONTAINS, lhsI.getQualifiedName(), 
rhs.replace("*", ".*").replace('?', '.'));
+        } else if(op == SearchParameters.Operator.IN) {
+            add(GremlinClause.HAS_OPERATOR, lhsI.getQualifiedName(), "within", 
rhs);
+        } else {
+            add(GremlinClause.HAS_OPERATOR, lhsI.getQualifiedName(), 
op.getSymbols()[1], rhs);
+        }
+
+        if(org != null && !org.isPrimitive() && org.getIntroduceType()) {
+            add(GremlinClause.DEDUP);
+            add(GremlinClause.IN, org.getEdgeLabel());
+            context.registerActive(currentType);
+        }
+    }
+
+    public void addAndClauses(List<String> clauses) {
+        queryClauses.add(GremlinClause.AND, StringUtils.join(clauses, ','));
+    }
+
+    public void addOrClauses(List<String> clauses) {
+        queryClauses.add(GremlinClause.OR, StringUtils.join(clauses, ','));
+    }
+
+    public void addSelect(SelectExprMetadata selectExprMetadata) {
+        String[] items  = selectExprMetadata.getItems();
+        String[] labels = selectExprMetadata.getLabels();
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("addSelect(items.length={})", items != null ? 
items.length : 0);
+        }
+
+        if (items != null) {
+            for (int i = 0; i < items.length; i++) {
+                IdentifierHelper.Advice ia = getAdvice(items[i]);
+
+                if(!labels[i].equals(items[i])) {
+                    context.aliasMap.put(labels[i], ia.getQualifiedName());
+                }
+
+                if (i == selectExprMetadata.getCountIdx()) {
+                    items[i] = GremlinClause.INLINE_COUNT.get();
+                } else if (i == selectExprMetadata.getMinIdx()) {
+                    items[i] = 
GremlinClause.INLINE_MIN.get(ia.getQualifiedName(), ia.getQualifiedName());
+                } else if (i == selectExprMetadata.getMaxIdx()) {
+                    items[i] = 
GremlinClause.INLINE_MAX.get(ia.getQualifiedName(), ia.getQualifiedName());
+                } else if (i == selectExprMetadata.getSumIdx()) {
+                    items[i] = 
GremlinClause.INLINE_SUM.get(ia.getQualifiedName(), ia.getQualifiedName());
+                } else {
+                    if (!ia.isPrimitive() && ia.getIntroduceType()) {
+                        add(GremlinClause.OUT, ia.getEdgeLabel());
+                        context.registerActive(ia.getTypeName());
+
+                        int dotIdx = ia.get().indexOf(".");
+                        if (dotIdx != -1) {
+                            IdentifierHelper.Advice iax = getAdvice(ia.get());
+                            items[i] = 
GremlinClause.INLINE_GET_PROPERTY.get(iax.getQualifiedName());
+                        } else {
+                            isSelectNoop = true;
+                        }
+                    } else {
+                        items[i] = 
GremlinClause.INLINE_GET_PROPERTY.get(ia.getQualifiedName());
+                    }
+                }
+            }
+
+            // If GroupBy clause exists then the query spits out a 
List<Map<String, List<AtlasVertex>>> otherwise the query returns 
List<AtlasVertex>
+            // Different transformations are needed for DSLs with groupby and 
w/o groupby
+            GremlinClause transformationFn;
+            if (isSelectNoop) {
+                transformationFn = GremlinClause.SELECT_EXPR_NOOP_FN;
+            } else {
+                transformationFn = hasGroupBy ? 
GremlinClause.SELECT_WITH_GRPBY_HELPER_FN : GremlinClause.SELECT_EXPR_HELPER_FN;
+            }
+            queryClauses.add(0, transformationFn, getJoinedQuotedStr(labels), 
String.join(",", items));
+            queryClauses.add(GremlinClause.INLINE_TRANSFORM_CALL);
+
+            hasSelect = true;
+            this.selectExprMetadata = selectExprMetadata;
+        }
+    }
+
+    public GremlinQueryComposer createNestedProcessor() {
+        GremlinQueryComposer qp = new GremlinQueryComposer(lookup, true);
+        qp.context = this.context;
+        return qp;
+    }
+
+    public void addFromAlias(String typeName, String alias) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("addFromAlias(typeName={}, alias={})", typeName, alias);
+        }
+
+        addFrom(typeName);
+        addAsClause(alias);
+        context.registerAlias(alias);
+    }
+
+    public void addAsClause(String stepName) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("addAsClause(stepName={})", stepName);
+        }
+
+        add(GremlinClause.AS, stepName);
+    }
+
+    public void addGroupBy(String item) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("addGroupBy(item={})", item);
+        }
+
+        addGroupByClause(item);
+        hasGroupBy = true;
+    }
+
+    public void addLimit(String limit, String offset) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("addLimit(limit={}, offset={})", limit, offset);
+        }
+
+        this.limit  = limit;
+        this.offset = offset;
+
+        hasLimitOffset = true;
+    }
+
+    public String get() {
+        close();
+
+        String ret;
+        String[] items = new String[queryClauses.size()];
+
+        boolean needTransformation = needTransformation();
+        int     startIdx           = needTransformation ? 1 : 0;
+        int     endIdx             = needTransformation ? queryClauses.size() 
- 1 : queryClauses.size();
+
+        for (int i = startIdx; i < endIdx; i++) {
+            items[i] = queryClauses.getValue(i);
+        }
+
+        if (needTransformation) {
+            String body = String.join(".", 
Stream.of(items).filter(Objects::nonNull).collect(Collectors.toList()));
+            String inlineFn = queryClauses.getValue(queryClauses.size() - 1);
+            String funCall = String.format(inlineFn, body);
+            ret = queryClauses.getValue(0) + funCall;
+        } else {
+            ret = String.join(".", items);
+        }
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("get() => {}", ret);
+        }
+        return ret;
+    }
+
+    public boolean hasSelect() {
+        return hasSelect;
+    }
+
+    public boolean hasLimitOffset() {
+        return hasLimitOffset;
+    }
+
+    public void addOrderBy(String name, boolean isDesc) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("addOrderBy(name={}, isDesc={})", name, isDesc);
+        }
+
+        AtlasAttribute attribute = ((AtlasStructType) 
context.getActiveType()).getAttribute(getAttributeName(name));
+        if (hasGroupBy) {
+            GremlinClause transformationFn = isDesc ? 
GremlinClause.GRPBY_ORDERBY_DESC_HELPER_FN : 
GremlinClause.GRPBY_ORDERBY_ASC_HELPER_FN;
+            add(0, transformationFn, attribute.getQualifiedName(), 
attribute.getQualifiedName());
+            add(GremlinClause.INLINE_TRANSFORM_CALL);
+        } else {
+            addOrderByClause(attribute.getQualifiedName(), isDesc);
+        }
+        hasOrderBy = true;
+    }
+
+    private String getAttributeName(String fqdn) {
+        final String ret;
+
+        int lastSepIdx = fqdn.lastIndexOf('.');
+
+        return lastSepIdx == -1 ? fqdn : fqdn.substring(lastSepIdx + 1);
+    }
+
+    private boolean needTransformation() {
+        return (hasGroupBy && hasSelect && hasOrderBy) || (hasGroupBy && 
hasOrderBy) || hasSelect;
+    }
+
+    private static String quoted(String rhs) {
+        return IdentifierHelper.getQuoted(rhs);
+    }
+
+    private String addQuotesIfNecessary(String rhs) {
+        if(IdentifierHelper.isQuoted(rhs)) return rhs;
+        return quoted(rhs);
+    }
+
+    private String parseDate(String rhs) {
+        String s = IdentifierHelper.isQuoted(rhs) ?
+                IdentifierHelper.removeQuotes(rhs) :
+                rhs;
+        return String.format("'%d'", DateTime.parse(s).getMillis());
+    }
+
+    private void close() {
+        // No limits or toList() need to be added to the nested queries
+        if (isNestedQuery) return;
+
+        if (hasLimitOffset) {
+            // If there are any aggregator functions then implicit limits 
shouldn't be applied
+            if (selectExprMetadata == null || 
!selectExprMetadata.hasAggregatorFunction()) {
+                if (offset.equalsIgnoreCase("0")) {
+                    add(GremlinClause.LIMIT, limit);
+                } else {
+                    addRangeClause(offset, limit);
+                }
+            } else {
+                LOG.warn("Query has aggregator function. Performance might be 
slow for large dataset");
+            }
+        }
+
+        if (queryClauses.isEmpty()) {
+            queryClauses.clear();
+            return;
+        }
+
+        updatePosition(GremlinClause.LIMIT);
+        add(GremlinClause.TO_LIST);
+        updatePosition(GremlinClause.INLINE_TRANSFORM_CALL);
+    }
+
+    private void updatePosition(GremlinClause clause) {
+        int index = queryClauses.hasClause(clause);
+        if(-1 == index) {
+            return;
+        }
+
+        GremlinClauseValue gcv = queryClauses.remove(index);
+        queryClauses.add(gcv);
+    }
+
+    private void init() {
+        if (!isNestedQuery) {
+            add(GremlinClause.G);
+            add(GremlinClause.V);
+        } else {
+            add(GremlinClause.NESTED_START);
+        }
+    }
+
+    private void introduceType(IdentifierHelper.Advice ia) {
+        if (!ia.isPrimitive() && ia.getIntroduceType()) {
+            add(GremlinClause.OUT, ia.getEdgeLabel());
+            context.registerActive(ia.getTypeName());
+        }
+    }
+
+    private IdentifierHelper.Advice getAdvice(String actualTypeName) {
+        return IdentifierHelper.create(context, lookup, actualTypeName);
+    }
+
+    private String getJoinedQuotedStr(String[] elements) {
+        StringJoiner joiner = new StringJoiner(",");
+        Arrays.stream(elements)
+              .map(x -> x.contains("'") ? "\"" + x + "\"" : "'" + x + "'")
+              .forEach(joiner::add);
+        return joiner.toString();
+    }
+
+    private void add(GremlinClause clause, String... args) {
+        queryClauses.add(new GremlinClauseValue(clause, clause.get(args)));
+    }
+
+    private void add(int idx, GremlinClause clause, String... args) {
+        queryClauses.add(idx, new GremlinClauseValue(clause, 
clause.get(args)));
+    }
+
+    private void addRangeClause(String startIndex, String endIndex) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("addRangeClause(startIndex={}, endIndex={})", 
startIndex, endIndex);
+        }
+
+        if (hasSelect) {
+            add(queryClauses.size() - 1, GremlinClause.RANGE, startIndex, 
startIndex, endIndex);
+        } else {
+            add(GremlinClause.RANGE, startIndex, startIndex, endIndex);
+        }
+    }
+
+    private void addOrderByClause(String name, boolean descr) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("addOrderByClause(name={})", name, descr);
+        }
+
+        IdentifierHelper.Advice ia = getAdvice(name);
+        add((!descr) ? GremlinClause.ORDER_BY : GremlinClause.ORDER_BY_DESC, 
ia.getQualifiedName());
+    }
+
+    private void addGroupByClause(String name) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("addGroupByClause(name={})", name);
+        }
+
+        IdentifierHelper.Advice ia = getAdvice(name);
+        add(GremlinClause.GROUP_BY, ia.getQualifiedName());
+    }
+
+    private enum GremlinClause {
+        AS("as('%s')"),
+        DEDUP("dedup()"),
+        G("g"),
+        GROUP_BY("group().by('%s')"),
+        HAS("has('%s', %s)"),
+        HAS_OPERATOR("has('%s', %s(%s))"),
+        HAS_PROPERTY("has('%s')"),
+        WHERE("where(%s)"),
+        HAS_NOT_PROPERTY("hasNot('%s')"),
+        HAS_TYPE("has('__typeName', '%s')"),
+        HAS_TYPE_WITHIN("has('__typeName', within(%s))"),
+        HAS_WITHIN("has('%s', within(%s))"),
+        IN("in('%s')"),
+        OR("or(%s)"),
+        AND("and(%s)"),
+        NESTED_START("__"),
+        NESTED_HAS_OPERATOR("has('%s', %s(%s))"),
+        LIMIT("limit(%s)"),
+        ORDER_BY("order().by('%s')"),
+        ORDER_BY_DESC("order().by('%s', decr)"),
+        OUT("out('%s')"),
+        RANGE("range(%s, %s + %s)"),
+        SELECT("select('%s')"),
+        TO_LIST("toList()"),
+        TEXT_CONTAINS("has('%s', 
org.janusgraph.core.attribute.Text.textRegex(%s))"),
+        TEXT_PREFIX("has('%s', 
org.janusgraph.core.attribute.Text.textPrefix(%s))"),
+        TEXT_SUFFIX("has('%s', 
org.janusgraph.core.attribute.Text.textRegex(\".*\" + %s))"),
+        TRAIT("has('__traitNames', within('%s'))"),
+        SELECT_EXPR_NOOP_FN("def f(r){ r }; "),
+        SELECT_EXPR_HELPER_FN("def f(r){ return 
[[%s]].plus(r.collect({[%s]})).unique(); }; "),
+        SELECT_WITH_GRPBY_HELPER_FN("def f(r){ return 
[[%s]].plus(r.collect({it.values()}).flatten().collect({[%s]})).unique(); }; "),
+        GRPBY_ORDERBY_ASC_HELPER_FN("def f(r){ m=r.get(0); m.each({ k,v -> 
m[k] = v.sort{a,b -> a.value('%s') <=> b.value('%s')}}); r }; "),
+        GRPBY_ORDERBY_DESC_HELPER_FN("def f(r){ m=r.get(0); m.each({ k,v -> 
m[k] = v.sort{a,b -> b.value('%s') <=> a.value('%s')}}); r; }; "),
+        INLINE_COUNT("r.size()"),
+        INLINE_SUM("r.sum({it.value('%s')}).value('%s')"),
+        INLINE_MAX("r.max({it.value('%s')}).value('%s')"),
+        INLINE_MIN("r.min({it.value('%s')}).value('%s')"),
+        INLINE_GET_PROPERTY("it.value('%s')"),
+        INLINE_OUT_VERTEX("it.out('%s')"),
+        INLINE_OUT_VERTEX_VALUE("it.out('%s').value('%s')"), // This might 
require more closure introduction :(
+        INLINE_TRANSFORM_CALL("f(%s)"),
+        V("V()"),
+        VALUE_MAP("valueMap(%s)");
+
+        private final String format;
+
+        GremlinClause(String format) {
+            this.format = format;
+        }
+
+        String get(String... args) {
+            return (args == null || args.length == 0) ?
+                    format :
+                    String.format(format, args);
+        }
+    }
+
+    private static class GremlinClauseValue {
+        private final GremlinClause clause;
+        private final String value;
+
+        public GremlinClauseValue(GremlinClause clause, String value) {
+            this.clause = clause;
+            this.value = value;
+        }
+
+        public GremlinClause getClause() {
+            return clause;
+        }
+
+        public String getValue() {
+            return value;
+        }
+    }
+
+    private static class GremlinClauseList {
+        private final List<GremlinClauseValue> list;
+
+        private GremlinClauseList() {
+            this.list = new LinkedList<>();
+        }
+
+        public void add(GremlinClauseValue g) {
+            list.add(g);
+        }
+
+        public void add(int idx, GremlinClauseValue g) {
+            list.add(idx, g);
+        }
+
+        public void add(GremlinClauseValue g, AtlasEntityType t) {
+            add(g);
+        }
+
+        public void add(int idx, GremlinClauseValue g, AtlasEntityType t) {
+            add(idx, g);
+        }
+
+        public void add(GremlinClause clause, String... args) {
+            list.add(new GremlinClauseValue(clause, clause.get(args)));
+        }
+
+        public void add(int i, GremlinClause clause, String... args) {
+            list.add(i, new GremlinClauseValue(clause, clause.get(args)));
+        }
+
+        public GremlinClauseValue getAt(int i) {
+            return list.get(i);
+        }
+
+        public String getValue(int i) {
+            return list.get(i).value;
+        }
+
+        public GremlinClauseValue get(int i) {
+            return list.get(i);
+        }
+
+        public int size() {
+            return list.size();
+        }
+
+        public int hasClause(GremlinClause clause) {
+            for (int i = 0; i < list.size(); i++) {
+                if (list.get(i).getClause() == clause)
+                    return i;
+            }
+
+            return -1;
+        }
+
+        public boolean isEmpty() {
+            return list.size() == 0;
+        }
+
+        public void clear() {
+            list.clear();
+        }
+
+        public GremlinClauseValue remove(int index) {
+            GremlinClauseValue gcv = get(index);
+            list.remove(index);
+            return gcv;
+        }
+    }
+
+    @VisibleForTesting
+    static class Context {
+        private final List<String> errorList;
+        Lookup lookup;
+        Map<String, String> aliasMap = new HashMap<>();
+        private AtlasType activeType;
+
+        public Context(List<String> errorList, Lookup lookup) {
+            this.lookup = lookup;
+            this.errorList = errorList;
+        }
+
+        public void registerActive(String typeName) {
+            if(shouldRegister(typeName)) {
+                activeType = lookup.getType(typeName);
+            }
+
+            aliasMap.put(typeName, typeName);
+        }
+
+        public AtlasType getActiveType() {
+            return activeType;
+        }
+
+        public AtlasEntityType getActiveEntityType() {
+            return (activeType instanceof AtlasEntityType) ?
+                    (AtlasEntityType) activeType :
+                    null;
+        }
+
+        public String getActiveTypeName() {
+            return activeType.getTypeName();
+        }
+
+        public boolean shouldRegister(String typeName) {
+            return activeType == null ||
+                    (activeType != null && 
!StringUtils.equals(getActiveTypeName(), typeName)) &&
+                            (activeType != null && !lookup.hasAttribute(this, 
typeName));
+        }
+
+        public void registerAlias(String alias) {
+            if(aliasMap.containsKey(alias)) {
+                errorList.add(String.format("Duplicate alias found: %s for 
type %s already present.", alias, getActiveEntityType()));
+                return;
+            }
+
+            aliasMap.put(alias, getActiveTypeName());
+        }
+
+        public boolean hasAlias(String alias) {
+            return aliasMap.containsKey(alias);
+        }
+
+        public String getTypeNameFromAlias(String alias) {
+            return aliasMap.get(alias);
+        }
+
+        public boolean isEmpty() {
+            return activeType == null;
+        }
+    }
+
+    private static class RegistryBasedLookup implements Lookup {
+        private final List<String> errorList;
+        private final AtlasTypeRegistry typeRegistry;
+
+        public RegistryBasedLookup(List<String> errorList, AtlasTypeRegistry 
typeRegistry) {
+            this.errorList = errorList;
+            this.typeRegistry = typeRegistry;
+        }
+
+        @Override
+        public AtlasType getType(String typeName) {
+            try {
+                return typeRegistry.getType(typeName);
+            } catch (AtlasBaseException e) {
+                addError(e.getMessage());
+            }
+
+            return null;
+        }
+
+        @Override
+        public String getQualifiedName(Context context, String name) {
+            try {
+                AtlasEntityType et = context.getActiveEntityType();
+                if(et == null) {
+                    return "";
+                }
+
+                return et.getQualifiedAttributeName(name);
+            } catch (AtlasBaseException e) {
+                addError(e.getMessage());
+            }
+
+            return "";
+        }
+
+        @Override
+        public boolean isPrimitive(Context context, String attributeName) {
+            AtlasEntityType et = context.getActiveEntityType();
+            if(et == null) {
+                return false;
+            }
+
+            AtlasType attr = et.getAttributeType(attributeName);
+            if(attr == null) {
+                return false;
+            }
+
+            TypeCategory attrTypeCategory = attr.getTypeCategory();
+            return (attrTypeCategory != null) && (attrTypeCategory == 
TypeCategory.PRIMITIVE || attrTypeCategory == TypeCategory.ENUM);
+        }
+
+        @Override
+        public String getRelationshipEdgeLabel(Context context, String 
attributeName) {
+            AtlasEntityType et = context.getActiveEntityType();
+            if(et == null) {
+                return "";
+            }
+
+            AtlasAttribute attr = et.getAttribute(attributeName);
+            return (attr != null) ? attr.getRelationshipEdgeLabel() : "";
+        }
+
+        @Override
+        public boolean hasAttribute(Context context, String typeName) {
+            return (context.getActiveEntityType() != null) && 
context.getActiveEntityType().getAttribute(typeName) != null;
+        }
+
+        @Override
+        public boolean doesTypeHaveSubTypes(Context context) {
+            return (context.getActiveEntityType() != null && 
context.getActiveEntityType().getAllSubTypes().size() > 0);
+        }
+
+        @Override
+        public String getTypeAndSubTypes(Context context) {
+            String[] str = context.getActiveEntityType() != null ?
+                            
context.getActiveEntityType().getTypeAndAllSubTypes().toArray(new String[]{}) :
+                            new String[]{};
+            if(str.length == 0) {
+                return null;
+            }
+
+            String[] quoted = new String[str.length];
+            for (int i = 0; i < str.length; i++) {
+                quoted[i] = quoted(str[i]);
+            }
+
+            return StringUtils.join(quoted, ",");
+        }
+
+        @Override
+        public boolean isTraitType(Context context) {
+            return (context.getActiveType() != null &&
+                    context.getActiveType().getTypeCategory() == 
TypeCategory.CLASSIFICATION);
+        }
+
+        @Override
+        public String getTypeFromEdge(Context context, String item) {
+            AtlasEntityType et = context.getActiveEntityType();
+            if(et == null) {
+                return "";
+            }
+
+            AtlasAttribute attr = et.getAttribute(item);
+            if(attr == null) {
+                return null;
+            }
+
+            AtlasType at = attr.getAttributeType();
+            if(at.getTypeCategory() == TypeCategory.ARRAY) {
+                AtlasArrayType arrType = ((AtlasArrayType)at);
+                return ((AtlasBuiltInTypes.AtlasObjectIdType) 
arrType.getElementType()).getObjectType();
+            }
+
+            return 
context.getActiveEntityType().getAttribute(item).getTypeName();
+        }
+
+        @Override
+        public boolean isDate(Context context, String attributeName) {
+            AtlasEntityType et = context.getActiveEntityType();
+            if (et == null) {
+                return false;
+            }
+
+            AtlasType attr = et.getAttributeType(attributeName);
+            return attr != null && 
attr.getTypeName().equals(AtlasBaseTypeDef.ATLAS_TYPE_DATE);
+
+        }
+
+        protected void addError(String s) {
+            errorList.add(s);
+        }
+    }
+
+    static class SelectExprMetadata {
+        private String[] items;
+        private String[] labels;
+
+        private int countIdx = -1;
+        private int sumIdx   = -1;
+        private int maxIdx   = -1;
+        private int minIdx   = -1;
+        private boolean hasAggregator   = false;
+
+        public String[] getItems() {
+            return items;
+        }
+
+        public void setItems(final String[] items) {
+            this.items = items;
+        }
+
+        public int getCountIdx() {
+            return countIdx;
+        }
+
+        public void setCountIdx(final int countIdx) {
+            this.countIdx = countIdx;
+            setHasAggregator();
+        }
+
+        public int getSumIdx() {
+            return sumIdx;
+        }
+
+        public void setSumIdx(final int sumIdx) {
+            this.sumIdx = sumIdx;
+            setHasAggregator();
+        }
+
+        public int getMaxIdx() {
+            return maxIdx;
+        }
+
+        public void setMaxIdx(final int maxIdx) {
+            this.maxIdx = maxIdx;
+            setHasAggregator();
+        }
+
+        public int getMinIdx() {
+            return minIdx;
+        }
+
+        public void setMinIdx(final int minIdx) {
+            this.minIdx = minIdx;
+            setHasAggregator();
+        }
+
+        public String[] getLabels() {
+            return labels;
+        }
+
+        public void setLabels(final String[] labels) {
+            this.labels = labels;
+        }
+
+        public boolean hasAggregatorFunction(){
+            return hasAggregator;
+        }
+
+        private void setHasAggregator() {
+            hasAggregator = true;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/atlas/blob/8db8b5c7/repository/src/main/java/org/apache/atlas/query/GremlinTranslator.java
----------------------------------------------------------------------
diff --git 
a/repository/src/main/java/org/apache/atlas/query/GremlinTranslator.java 
b/repository/src/main/java/org/apache/atlas/query/GremlinTranslator.java
deleted file mode 100644
index 6ce90e6..0000000
--- a/repository/src/main/java/org/apache/atlas/query/GremlinTranslator.java
+++ /dev/null
@@ -1,41 +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.query;
-
-import org.apache.atlas.query.Expressions.Expression;
-
-
-public class GremlinTranslator {
-    private final QueryProcessor queryProcessor;
-    private       Expression     expression;
-
-    public GremlinTranslator(QueryProcessor queryProcessor, Expression 
expression) {
-        this.expression     = expression;
-        this.queryProcessor = queryProcessor;
-    }
-
-    public GremlinQuery translate() {
-        DSLVisitor qv = new DSLVisitor(queryProcessor);
-
-        expression.accept(qv);
-        queryProcessor.close();
-
-        GremlinQuery ret = new GremlinQuery(queryProcessor.getText(), 
queryProcessor.hasSelect());
-        return ret;
-    }
-}

http://git-wip-us.apache.org/repos/asf/atlas/blob/8db8b5c7/repository/src/main/java/org/apache/atlas/query/IdentifierHelper.java
----------------------------------------------------------------------
diff --git 
a/repository/src/main/java/org/apache/atlas/query/IdentifierHelper.java 
b/repository/src/main/java/org/apache/atlas/query/IdentifierHelper.java
index 0c7e2ed..fe1c5bd 100644
--- a/repository/src/main/java/org/apache/atlas/query/IdentifierHelper.java
+++ b/repository/src/main/java/org/apache/atlas/query/IdentifierHelper.java
@@ -25,17 +25,27 @@ import java.util.regex.Pattern;
 
 public class IdentifierHelper {
 
-    public static String stripQuotes(String quotedIdentifier) {
-        String ret = quotedIdentifier;
+    private static final Pattern SINGLE_QUOTED_IDENTIFIER   = 
Pattern.compile("'(\\w[\\w\\d\\.\\s]*)'");
+    private static final Pattern DOUBLE_QUOTED_IDENTIFIER   = 
Pattern.compile("\"(\\w[\\w\\d\\.\\s]*)\"");
+    private static final Pattern BACKTICK_QUOTED_IDENTIFIER = 
Pattern.compile("`(\\w[\\w\\d\\.\\s]*)`");
 
-        if (isQuoted(quotedIdentifier)) {
-            ret = quotedIdentifier.substring(1, quotedIdentifier.length() - 1);
+    public static String get(String quotedIdentifier) {
+        String ret;
+
+        if (quotedIdentifier.charAt(0) == '`') {
+            ret = extract(BACKTICK_QUOTED_IDENTIFIER, quotedIdentifier);
+        } else if (quotedIdentifier.charAt(0) == '\'') {
+            ret = extract(SINGLE_QUOTED_IDENTIFIER, quotedIdentifier);
+        } else if (quotedIdentifier.charAt(0) == '"') {
+            ret = extract(DOUBLE_QUOTED_IDENTIFIER, quotedIdentifier);
+        } else {
+            ret = quotedIdentifier;
         }
 
         return ret;
     }
 
-    public static Advice create(QueryProcessor.Context context,
+    public static Advice create(GremlinQueryComposer.Context context,
                                 org.apache.atlas.query.Lookup lookup,
                                 String identifier) {
         Advice ia = new Advice(identifier);
@@ -49,7 +59,7 @@ public class IdentifierHelper {
     }
 
     public static String getQualifiedName(org.apache.atlas.query.Lookup lookup,
-                                          QueryProcessor.Context context,
+                                          GremlinQueryComposer.Context context,
                                           String name) {
         return lookup.getQualifiedName(context, name);
     }
@@ -70,7 +80,9 @@ public class IdentifierHelper {
     }
 
     public static String removeQuotes(String rhs) {
-        return rhs.replace("\"", "").replace("'", "");
+        return rhs.replace("\"", "")
+                  .replace("'", "")
+                  .replace("`", "");
     }
 
     public static String getQuoted(String s) {
@@ -97,10 +109,10 @@ public class IdentifierHelper {
 
         public Advice(String s) {
             this.raw = removeQuotes(s);
-            this.actual = IdentifierHelper.stripQuotes(raw);
+            this.actual = IdentifierHelper.get(raw);
         }
 
-        private void update(org.apache.atlas.query.Lookup lookup, 
QueryProcessor.Context context) {
+        private void update(org.apache.atlas.query.Lookup lookup, 
GremlinQueryComposer.Context context) {
             newContext = context.isEmpty();
             if(!newContext) {
                 if(context.aliasMap.containsKey(this.raw)) {
@@ -116,7 +128,7 @@ public class IdentifierHelper {
             }
         }
 
-        private void updateSubTypes(org.apache.atlas.query.Lookup lookup, 
QueryProcessor.Context context) {
+        private void updateSubTypes(org.apache.atlas.query.Lookup lookup, 
GremlinQueryComposer.Context context) {
             if(isTrait) {
                 return;
             }
@@ -127,7 +139,7 @@ public class IdentifierHelper {
             }
         }
 
-        private void updateEdgeInfo(org.apache.atlas.query.Lookup lookup, 
QueryProcessor.Context context) {
+        private void updateEdgeInfo(org.apache.atlas.query.Lookup lookup, 
GremlinQueryComposer.Context context) {
             if(isPrimitive == false && isTrait == false) {
                 edgeLabel = lookup.getRelationshipEdgeLabel(context, 
attributeName);
                 edgeDirection = "OUT";
@@ -135,7 +147,7 @@ public class IdentifierHelper {
             }
         }
 
-        private void updateTypeInfo(org.apache.atlas.query.Lookup lookup, 
QueryProcessor.Context context) {
+        private void updateTypeInfo(org.apache.atlas.query.Lookup lookup, 
GremlinQueryComposer.Context context) {
             if(parts.length == 1) {
                 typeName = context.getActiveTypeName();
                 attributeName = parts[0];
@@ -171,7 +183,7 @@ public class IdentifierHelper {
             }
         }
 
-        private void setIsDate(Lookup lookup, QueryProcessor.Context context) {
+        private void setIsDate(Lookup lookup, GremlinQueryComposer.Context 
context) {
             if(isPrimitive) {
                 isDate = lookup.isDate(context, attributeName);
             }

http://git-wip-us.apache.org/repos/asf/atlas/blob/8db8b5c7/repository/src/main/java/org/apache/atlas/query/Lookup.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/query/Lookup.java 
b/repository/src/main/java/org/apache/atlas/query/Lookup.java
index a64b688..d09b207 100644
--- a/repository/src/main/java/org/apache/atlas/query/Lookup.java
+++ b/repository/src/main/java/org/apache/atlas/query/Lookup.java
@@ -23,21 +23,21 @@ import org.apache.atlas.type.AtlasType;
 public interface Lookup {
     AtlasType getType(String typeName);
 
-    String getQualifiedName(QueryProcessor.Context context, String name);
+    String getQualifiedName(GremlinQueryComposer.Context context, String name);
 
-    boolean isPrimitive(QueryProcessor.Context context, String attributeName);
+    boolean isPrimitive(GremlinQueryComposer.Context context, String 
attributeName);
 
-    String getRelationshipEdgeLabel(QueryProcessor.Context context, String 
attributeName);
+    String getRelationshipEdgeLabel(GremlinQueryComposer.Context context, 
String attributeName);
 
-    boolean hasAttribute(QueryProcessor.Context context, String typeName);
+    boolean hasAttribute(GremlinQueryComposer.Context context, String 
typeName);
 
-    boolean doesTypeHaveSubTypes(QueryProcessor.Context context);
+    boolean doesTypeHaveSubTypes(GremlinQueryComposer.Context context);
 
-    String getTypeAndSubTypes(QueryProcessor.Context context);
+    String getTypeAndSubTypes(GremlinQueryComposer.Context context);
 
-    boolean isTraitType(QueryProcessor.Context context);
+    boolean isTraitType(GremlinQueryComposer.Context context);
 
-    String getTypeFromEdge(QueryProcessor.Context context, String item);
+    String getTypeFromEdge(GremlinQueryComposer.Context context, String item);
 
-    boolean isDate(QueryProcessor.Context context, String attributeName);
+    boolean isDate(GremlinQueryComposer.Context context, String attributeName);
 }

http://git-wip-us.apache.org/repos/asf/atlas/blob/8db8b5c7/repository/src/main/java/org/apache/atlas/query/QueryParser.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/query/QueryParser.java 
b/repository/src/main/java/org/apache/atlas/query/QueryParser.java
deleted file mode 100644
index 6e378a1..0000000
--- a/repository/src/main/java/org/apache/atlas/query/QueryParser.java
+++ /dev/null
@@ -1,66 +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
- * <p>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p>
- * 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.query;
-
-import org.antlr.v4.runtime.CharStreams;
-import org.antlr.v4.runtime.CommonTokenStream;
-import org.antlr.v4.runtime.TokenStream;
-import org.apache.atlas.query.Expressions.Expression;
-import org.apache.atlas.query.antlr4.AtlasDSLLexer;
-import org.apache.atlas.query.antlr4.AtlasDSLParser;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Set;
-
-public class QueryParser {
-    private static final Logger LOG = 
LoggerFactory.getLogger(QueryParser.class);
-
-    private static final Set<String> RESERVED_KEYWORDS =
-            new HashSet<>(Arrays.asList("[", "]", "(", ")", "=", "<", ">", 
"!=", "<=", ">=", ",", "and", "or", "+", "-",
-                    "*", "/", ".", "select", "from", "where", "groupby", 
"loop", "isa", "is", "has",
-                    "as", "times", "withPath", "limit", "offset", "orderby", 
"count", "max", "min",
-                    "sum", "by", "order", "like"));
-
-    public static boolean isKeyword(String word) {
-        return RESERVED_KEYWORDS.contains(word);
-    }
-
-    public static Expression apply(String queryStr, QueryParams params) {
-        Expression ret = null;
-
-        try {
-            InputStream    stream           = new 
ByteArrayInputStream(queryStr.getBytes());
-            AtlasDSLLexer lexer            = new 
AtlasDSLLexer(CharStreams.fromStream(stream));
-            TokenStream    inputTokenStream = new CommonTokenStream(lexer);
-            AtlasDSLParser parser           = new 
AtlasDSLParser(inputTokenStream);
-
-            ret = new Expression(parser.query());
-        } catch (IOException e) {
-            ret = null;
-            LOG.error(e.getMessage(), e);
-        }
-
-        return ret;
-    }
-}

Reply via email to