ATLAS-2229: DSL implementation using ANTLR #2

Signed-off-by: Madhan Neethiraj <[email protected]>


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

Branch: refs/heads/master
Commit: ac0764beeabb3d7e7f93231c73095c867fb0ec13
Parents: 728aac6
Author: Ashutosh Mestry <[email protected]>
Authored: Wed Dec 13 09:27:00 2017 -0800
Committer: Madhan Neethiraj <[email protected]>
Committed: Tue Dec 19 14:40:57 2017 -0800

----------------------------------------------------------------------
 .../atlas/model/discovery/SearchParameters.java |   4 +-
 .../atlas/discovery/EntityDiscoveryService.java |  17 +-
 .../java/org/apache/atlas/query/DSLVisitor.java | 216 +++++--
 .../apache/atlas/query/IdentifierHelper.java    | 228 +++++++
 .../java/org/apache/atlas/query/Lookup.java     |  43 ++
 .../org/apache/atlas/query/QueryProcessor.java  | 636 +++++++++++--------
 .../atlas/query/antlr4/AtlasDSLLexer.java       |   2 +-
 .../apache/atlas/query/antlr4/AtlasDSLParser.g4 |   9 +-
 .../atlas/query/antlr4/AtlasDSLParser.java      | 631 +++++++-----------
 .../query/antlr4/AtlasDSLParserBaseVisitor.java |  16 +-
 .../query/antlr4/AtlasDSLParserVisitor.java     |  14 +-
 .../org/apache/atlas/query/BasicTestSetup.java  | 155 +++--
 .../org/apache/atlas/query/DSLQueriesTest.java  | 468 +++-----------
 .../apache/atlas/query/QueryProcessorTest.java  | 249 +++++---
 .../resources/MetadataDiscoveryResource.java    |  69 +-
 15 files changed, 1450 insertions(+), 1307 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/atlas/blob/ac0764be/intg/src/main/java/org/apache/atlas/model/discovery/SearchParameters.java
----------------------------------------------------------------------
diff --git 
a/intg/src/main/java/org/apache/atlas/model/discovery/SearchParameters.java 
b/intg/src/main/java/org/apache/atlas/model/discovery/SearchParameters.java
index b816e80..347a314 100644
--- a/intg/src/main/java/org/apache/atlas/model/discovery/SearchParameters.java
+++ b/intg/src/main/java/org/apache/atlas/model/discovery/SearchParameters.java
@@ -392,8 +392,8 @@ public class SearchParameters implements Serializable {
         GT(new String[]{">", "gt"}),
         LTE(new String[]{"<=", "lte"}),
         GTE(new String[]{">=", "gte"}),
-        EQ(new String[]{"eq", "="}),
-        NEQ(new String[]{"neq", "!="}),
+        EQ(new String[]{"=", "eq"}),
+        NEQ(new String[]{"!=", "neq"}),
         IN(new String[]{"in", "IN"}),
         LIKE(new String[]{"like", "LIKE"}),
         STARTS_WITH(new String[]{"startsWith", "STARTSWITH", "begins_with", 
"BEGINS_WITH"}),

http://git-wip-us.apache.org/repos/asf/atlas/blob/ac0764be/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 cbc08b8..e742496 100644
--- 
a/repository/src/main/java/org/apache/atlas/discovery/EntityDiscoveryService.java
+++ 
b/repository/src/main/java/org/apache/atlas/discovery/EntityDiscoveryService.java
@@ -685,7 +685,7 @@ public class EntityDiscoveryService implements 
AtlasDiscoveryService {
             throw new AtlasBaseException(DISCOVERY_QUERY_FAILED, query);
         }
 
-        QueryProcessor queryProcessor  = new QueryProcessor(typeRegistry);
+        QueryProcessor queryProcessor  = new QueryProcessor(typeRegistry, 
limit, offset);
         Expression     validExpression = queryProcessor.validate(expression);
         GremlinQuery   gremlinQuery    = new GremlinTranslator(queryProcessor, 
validExpression).translate();
 
@@ -928,13 +928,24 @@ public class EntityDiscoveryService implements 
AtlasDiscoveryService {
 
     @Override
     public String getDslQueryUsingTypeNameClassification(String query, String 
typeName, String classification) {
+        final String whereDSLKeyword = "where";
+        final String limitDSLKeyword = "limit";
+        final String whereFormat = whereDSLKeyword + " %s";
+
         String queryStr = query == null ? "" : query;
 
-        if (org.apache.commons.lang3.StringUtils.isNoneEmpty(typeName)) {
+        if (StringUtils.isNotEmpty(typeName)) {
+            if(StringUtils.isNotEmpty(query)) {
+                String s = query.toLowerCase();
+                if(!s.startsWith(whereDSLKeyword) && 
!s.startsWith(limitDSLKeyword)) {
+                    queryStr = String.format(whereFormat, query);
+                }
+            }
+
             queryStr = escapeTypeName(typeName) + " " + queryStr;
         }
 
-        if (org.apache.commons.lang3.StringUtils.isNoneEmpty(classification)) {
+        if (StringUtils.isNotEmpty(classification)) {
             // isa works with a type name only - like hive_column isa PII; it 
doesn't work with more complex query
             if (StringUtils.isEmpty(query)) {
                 queryStr += (" isa " + classification);

http://git-wip-us.apache.org/repos/asf/atlas/blob/ac0764be/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 a2c6b98..064f6dd 100644
--- a/repository/src/main/java/org/apache/atlas/query/DSLVisitor.java
+++ b/repository/src/main/java/org/apache/atlas/query/DSLVisitor.java
@@ -21,8 +21,20 @@ package org.apache.atlas.query;
 import org.apache.atlas.query.antlr4.AtlasDSLParser.*;
 import org.apache.atlas.query.antlr4.AtlasDSLParserBaseVisitor;
 import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.tuple.MutablePair;
+import org.apache.commons.lang3.tuple.Pair;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
 
 public class DSLVisitor extends AtlasDSLParserBaseVisitor<String> {
+    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;
 
     public DSLVisitor(QueryProcessor queryProcessor) {
@@ -30,62 +42,50 @@ public class DSLVisitor extends 
AtlasDSLParserBaseVisitor<String> {
     }
 
     @Override
-    public String visitFromExpression(final FromExpressionContext ctx) {
-        FromSrcContext fromSrc = ctx.fromSrc();
-        AliasExprContext aliasExpr = fromSrc.aliasExpr();
-
-        if (aliasExpr != null) {
-            queryProcessor.addFromAlias(aliasExpr.identifier(0).getText(), 
aliasExpr.identifier(1).getText());
-        } else {
-            if (fromSrc.identifier() != null) {
-                queryProcessor.addFrom(fromSrc.identifier().getText());
-            } else {
-                queryProcessor.addFrom(fromSrc.literal().getText());
-            }
+    public String visitIsClause(IsClauseContext ctx) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("=> DSLVisitor.visitIsClause({})", ctx);
         }
-        return super.visitFromExpression(ctx);
+
+        queryProcessor.addFromIsA(ctx.arithE().getText(), 
ctx.identifier().getText());
+        return super.visitIsClause(ctx);
     }
 
     @Override
-    public String visitWhereClause(WhereClauseContext ctx) {
-        ExprContext expr = ctx.expr();
-        processExpr(expr.compE());
-
-        if (CollectionUtils.isNotEmpty(expr.exprRight())) {
-            for (ExprRightContext exprRight : expr.exprRight()) {
-                if (exprRight.K_AND() != null) {
-                    // AND expression
-                    processExpr(exprRight.compE());
-                }
-                // OR is tricky
-            }
+    public String visitHasClause(HasClauseContext ctx) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("=> DSLVisitor.visitHasClause({})", ctx);
         }
-        return super.visitWhereClause(ctx);
-    }
 
-    private void processExpr(final CompEContext compE) {
-        if (compE != null && compE.isClause() == null && compE.hasClause() == 
null && compE.isClause() == null) {
-            ComparisonClauseContext comparisonClause = 
compE.comparisonClause();
-            if(comparisonClause == null) {
-                comparisonClause = 
compE.arithE().multiE().atomE().expr().compE().comparisonClause();
-            }
-
-            if (comparisonClause != null) {
-                String lhs = comparisonClause.arithE(0).getText();
-                String op = 
comparisonClause.operator().getText().toUpperCase();
-                String rhs = comparisonClause.arithE(1).getText();
+        queryProcessor.addFromProperty(ctx.arithE().getText(), 
ctx.identifier().getText());
+        return super.visitHasClause(ctx);
+    }
 
-                queryProcessor.addWhere(lhs, op, rhs);
-            }
+    @Override
+    public String 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()));
+        return super.visitLimitOffset(ctx);
     }
 
     @Override
     public String visitSelectExpr(SelectExprContext ctx) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("=> DSLVisitor.visitSelectExpr({})", ctx);
+        }
+
         if (!(ctx.getParent() instanceof GroupByExpressionContext)) {
-            String[] items = new String[ctx.selectExpression().size()];
+            List<Pair<String, String>> items = new ArrayList<>();
             for (int i = 0; i < ctx.selectExpression().size(); i++) {
-                items[i] = ctx.selectExpression(i).expr().getText();
+                String idf = ctx.selectExpression(i).expr().getText();
+                String alias = (ctx.selectExpression(i).K_AS() != null) ?
+                        ctx.selectExpression(i).identifier().getText() : "";
+
+                items.add(new MutablePair<String, String>(idf, alias));
             }
 
             queryProcessor.addSelect(items);
@@ -94,34 +94,140 @@ public class DSLVisitor extends 
AtlasDSLParserBaseVisitor<String> {
     }
 
     @Override
-    public String visitLimitOffset(LimitOffsetContext ctx) {
-        queryProcessor.addLimit(ctx.limitClause().NUMBER().toString(),
-                (ctx.offsetClause() == null ? "0" : 
ctx.offsetClause().NUMBER().getText()));
-        return super.visitLimitOffset(ctx);
-    }
-
-    @Override
     public String visitOrderByExpr(OrderByExprContext ctx) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("=> DSLVisitor.visitOrderByExpr({})", ctx);
+        }
+
         queryProcessor.addOrderBy(ctx.expr().getText(), (ctx.sortOrder() != 
null && ctx.sortOrder().getText().equalsIgnoreCase("desc")));
         return super.visitOrderByExpr(ctx);
     }
 
     @Override
-    public String visitIsClause(IsClauseContext ctx) {
-        queryProcessor.addFromIsA(ctx.arithE().getText(), 
ctx.identifier().getText());
-        return super.visitIsClause(ctx);
+    public String visitWhereClause(WhereClauseContext ctx) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("=> DSLVisitor.visitWhereClause({})", ctx);
+        }
+
+
+        // The first expr shouldn't be processed if there are following exprs
+        ExprContext expr = ctx.expr();
+
+        processExpr(expr, queryProcessor);
+        return super.visitWhereClause(ctx);
     }
 
     @Override
-    public String visitHasClause(HasClauseContext ctx) {
-        queryProcessor.addFromProperty(ctx.arithE().getText(), 
ctx.identifier().getText());
-        return super.visitHasClause(ctx);
+    public String visitFromExpression(final FromExpressionContext ctx) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("=> DSLVisitor.visitFromExpression({})", ctx);
+        }
+
+        FromSrcContext fromSrc = ctx.fromSrc();
+        AliasExprContext aliasExpr = fromSrc.aliasExpr();
+
+        if (aliasExpr != null) {
+            queryProcessor.addFromAlias(aliasExpr.identifier(0).getText(), 
aliasExpr.identifier(1).getText());
+        } else {
+            if (fromSrc.identifier() != null) {
+                queryProcessor.addFrom(fromSrc.identifier().getText());
+            } else {
+                queryProcessor.addFrom(fromSrc.literal().getText());
+            }
+        }
+        return super.visitFromExpression(ctx);
     }
 
     @Override
     public String visitGroupByExpression(GroupByExpressionContext ctx) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("=> DSLVisitor.visitGroupByExpression({})", ctx);
+        }
+
         String s = ctx.selectExpr().getText();
         queryProcessor.addGroupBy(s);
         return super.visitGroupByExpression(ctx);
     }
+
+    private void processExpr(final ExprContext expr, QueryProcessor 
queryProcessor) {
+        if (CollectionUtils.isNotEmpty(expr.exprRight())) {
+            processExprRight(expr, queryProcessor);
+        } else {
+            processExpr(expr.compE(), queryProcessor);
+        }
+    }
+
+    private void processExprRight(final ExprContext expr, QueryProcessor 
queryProcessor) {
+        QueryProcessor nestedProcessor = 
queryProcessor.createNestedProcessor();
+
+        List<String> nestedQueries = new ArrayList<>();
+        String       prev          = null;
+
+        // Process first expression then proceed with the others
+        // expr -> compE exprRight*
+        processExpr(expr.compE(), nestedProcessor);
+        nestedQueries.add(nestedProcessor.getText());
+
+        for (ExprRightContext exprRight : expr.exprRight()) {
+            nestedProcessor = queryProcessor.createNestedProcessor();
+
+            // AND expression
+            if (exprRight.K_AND() != null) {
+                if (prev == null) prev = AND;
+                if (OR.equalsIgnoreCase(prev)) {
+                    // Change of context
+                    QueryProcessor orClause = 
nestedProcessor.createNestedProcessor();
+                    orClause.addOrClauses(nestedQueries);
+                    nestedQueries.clear();
+                    nestedQueries.add(orClause.getText());
+                }
+                prev = AND;
+            }
+            // OR expression
+            if (exprRight.K_OR() != null) {
+                if (prev == null) prev = OR;
+                if (AND.equalsIgnoreCase(prev)) {
+                    // Change of context
+                    QueryProcessor andClause = 
nestedProcessor.createNestedProcessor();
+                    andClause.addAndClauses(nestedQueries);
+                    nestedQueries.clear();
+                    nestedQueries.add(andClause.getText());
+                }
+                prev = OR;
+            }
+            processExpr(exprRight.compE(), nestedProcessor);
+            nestedQueries.add(nestedProcessor.getText());
+        }
+        if (AND.equalsIgnoreCase(prev)) {
+            queryProcessor.addAndClauses(nestedQueries);
+        }
+        if (OR.equalsIgnoreCase(prev)) {
+            queryProcessor.addOrClauses(nestedQueries);
+        }
+    }
+
+    private void processExpr(final CompEContext compE, final QueryProcessor 
queryProcessor) {
+        if (compE != null && compE.isClause() == null && compE.hasClause() == 
null && compE.isClause() == null) {
+            ComparisonClauseContext comparisonClause = 
compE.comparisonClause();
+
+            // The nested expression might have ANDs/ORs
+            if(comparisonClause == null) {
+                ExprContext exprContext = 
compE.arithE().multiE().atomE().expr();
+                // Only extract comparison clause if there are no nested 
exprRight clauses
+                if (CollectionUtils.isEmpty(exprContext.exprRight())) {
+                    comparisonClause = exprContext.compE().comparisonClause();
+                }
+            }
+
+            if (comparisonClause != null) {
+                String lhs = comparisonClause.arithE(0).getText();
+                String op  = 
comparisonClause.operator().getText().toUpperCase();
+                String rhs = comparisonClause.arithE(1).getText();
+
+                queryProcessor.addWhere(lhs, op, rhs);
+            } else {
+                processExpr(compE.arithE().multiE().atomE().expr(), 
queryProcessor);
+            }
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/atlas/blob/ac0764be/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
new file mode 100644
index 0000000..6bbadc4
--- /dev/null
+++ b/repository/src/main/java/org/apache/atlas/query/IdentifierHelper.java
@@ -0,0 +1,228 @@
+/**
+ * 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.commons.lang.StringUtils;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class IdentifierHelper {
+
+    public static String stripQuotes(String quotedIdentifier) {
+        String ret = quotedIdentifier;
+
+        if (isQuoted(quotedIdentifier)) {
+            ret = quotedIdentifier.substring(1, quotedIdentifier.length() - 1);
+        }
+
+        return ret;
+    }
+
+    public static Advice create(QueryProcessor.Context context,
+                                org.apache.atlas.query.Lookup lookup,
+                                String identifier) {
+        Advice ia = new Advice(identifier);
+        ia.update(lookup, context);
+        return ia;
+    }
+
+    private static String extract(Pattern p, String s) {
+        Matcher m = p.matcher(s);
+        return m.find() ? m.group(1) : s;
+    }
+
+    public static String getQualifiedName(org.apache.atlas.query.Lookup lookup,
+                                          QueryProcessor.Context context,
+                                          String name) {
+        return lookup.getQualifiedName(context, name);
+    }
+
+    public static boolean isQuoted(String val) {
+        boolean ret = false;
+
+        if (val != null && val.length() > 1) {
+            char first = val.charAt(0);
+            char last  = val.charAt(val.length() - 1);
+
+            if (first == last && (first == '\'' || first == '"' || first == 
'`')) {
+                ret = true;
+            }
+        }
+
+        return ret;
+    }
+
+    public static String removeQuotes(String rhs) {
+        return rhs.replace("\"", "").replace("'", "");
+    }
+
+    public static String getQuoted(String s) {
+        return String.format("'%s'", s);
+    }
+
+    public static class Advice {
+        private String raw;
+        private String actual;
+        private String[] parts;
+        private String typeName;
+        private String attributeName;
+        private boolean isPrimitive;
+        private String edgeLabel;
+        private String edgeDirection;
+        private boolean introduceType;
+        private boolean hasSubtypes;
+        private String subTypes;
+        private boolean isTrait;
+        private boolean newContext;
+        private boolean isAttribute;
+        private String qualifiedName;
+        private boolean isDate;
+
+        public Advice(String s) {
+            this.raw = removeQuotes(s);
+            this.actual = IdentifierHelper.stripQuotes(raw);
+        }
+
+        private void update(org.apache.atlas.query.Lookup lookup, 
QueryProcessor.Context context) {
+            newContext = context.isEmpty();
+            if(!newContext) {
+                if(context.aliasMap.containsKey(this.raw)) {
+                    raw = context.aliasMap.get(this.raw);
+                }
+
+                updateParts();
+                updateTypeInfo(lookup, context);
+                isTrait = lookup.isTraitType(context);
+                updateEdgeInfo(lookup, context);
+                introduceType = !context.hasAlias(parts[0]);
+                updateSubTypes(lookup, context);
+            }
+        }
+
+        private void updateSubTypes(org.apache.atlas.query.Lookup lookup, 
QueryProcessor.Context context) {
+            if(isTrait) {
+                return;
+            }
+
+            hasSubtypes = lookup.doesTypeHaveSubTypes(context);
+            if(hasSubtypes) {
+                subTypes = lookup.getTypeAndSubTypes(context);
+            }
+        }
+
+        private void updateEdgeInfo(org.apache.atlas.query.Lookup lookup, 
QueryProcessor.Context context) {
+            if(isPrimitive == false && isTrait == false) {
+                edgeLabel = lookup.getRelationshipEdgeLabel(context, 
attributeName);
+                edgeDirection = "OUT";
+                typeName = lookup.getTypeFromEdge(context, attributeName);
+            }
+        }
+
+        private void updateTypeInfo(org.apache.atlas.query.Lookup lookup, 
QueryProcessor.Context context) {
+            if(parts.length == 1) {
+                typeName = context.getActiveTypeName();
+                attributeName = parts[0];
+                isAttribute = lookup.hasAttribute(context, typeName);
+                qualifiedName = lookup.getQualifiedName(context, 
attributeName);
+                isPrimitive = lookup.isPrimitive(context, attributeName);
+
+                setIsDate(lookup, context);
+            }
+
+            if(parts.length == 2) {
+                if(context.hasAlias(parts[0])) {
+                    typeName = context.getTypeNameFromAlias(parts[0]);
+                    attributeName = parts[1];
+                    isPrimitive = lookup.isPrimitive(context, attributeName);
+                    setIsDate(lookup, context);
+                }
+                else {
+                    isAttribute = lookup.hasAttribute(context, parts[0]);
+                    if(isAttribute) {
+                        attributeName = parts[0];
+                        isPrimitive = lookup.isPrimitive(context, 
attributeName);
+                        setIsDate(lookup, context);
+                    } else {
+                        typeName = parts[0];
+                        attributeName = parts[1];
+                        isPrimitive = lookup.isPrimitive(context, 
attributeName);
+                        setIsDate(lookup, context);
+                    }
+                }
+
+                qualifiedName = lookup.getQualifiedName(context, 
attributeName);
+            }
+        }
+
+        private void setIsDate(Lookup lookup, QueryProcessor.Context context) {
+            if(isPrimitive) {
+                isDate = lookup.isDate(context, attributeName);
+            }
+        }
+
+        private void updateParts() {
+            parts = StringUtils.split(raw, ".");
+        }
+
+        public String getQualifiedName() {
+            return qualifiedName;
+        }
+
+        public boolean isPrimitive() {
+            return isPrimitive;
+        }
+
+        public String getEdgeLabel() {
+            return edgeLabel;
+        }
+
+        public String getTypeName() {
+            return typeName;
+        }
+
+        public boolean getIntroduceType() {
+            return introduceType;
+        }
+
+        public boolean isTrait() {
+            return isTrait;
+        }
+
+        public boolean hasSubtypes() {
+            return hasSubtypes;
+        }
+
+        public String getSubTypes() {
+            return subTypes;
+        }
+
+        public String get() {
+            return actual;
+        }
+
+        public boolean isNewContext() {
+            return newContext;
+        }
+
+        public boolean isDate() {
+            return isDate;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/atlas/blob/ac0764be/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
new file mode 100644
index 0000000..a64b688
--- /dev/null
+++ b/repository/src/main/java/org/apache/atlas/query/Lookup.java
@@ -0,0 +1,43 @@
+/**
+ * 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.type.AtlasType;
+
+public interface Lookup {
+    AtlasType getType(String typeName);
+
+    String getQualifiedName(QueryProcessor.Context context, String name);
+
+    boolean isPrimitive(QueryProcessor.Context context, String attributeName);
+
+    String getRelationshipEdgeLabel(QueryProcessor.Context context, String 
attributeName);
+
+    boolean hasAttribute(QueryProcessor.Context context, String typeName);
+
+    boolean doesTypeHaveSubTypes(QueryProcessor.Context context);
+
+    String getTypeAndSubTypes(QueryProcessor.Context context);
+
+    boolean isTraitType(QueryProcessor.Context context);
+
+    String getTypeFromEdge(QueryProcessor.Context context, String item);
+
+    boolean isDate(QueryProcessor.Context context, String attributeName);
+}

http://git-wip-us.apache.org/repos/asf/atlas/blob/ac0764be/repository/src/main/java/org/apache/atlas/query/QueryProcessor.java
----------------------------------------------------------------------
diff --git 
a/repository/src/main/java/org/apache/atlas/query/QueryProcessor.java 
b/repository/src/main/java/org/apache/atlas/query/QueryProcessor.java
index 60480a1..599f370 100644
--- a/repository/src/main/java/org/apache/atlas/query/QueryProcessor.java
+++ b/repository/src/main/java/org/apache/atlas/query/QueryProcessor.java
@@ -22,13 +22,10 @@ import org.apache.atlas.exception.AtlasBaseException;
 import org.apache.atlas.model.TypeCategory;
 import org.apache.atlas.model.discovery.SearchParameters;
 import org.apache.atlas.query.Expressions.Expression;
-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.AtlasType;
-import org.apache.atlas.type.AtlasTypeRegistry;
+import org.apache.atlas.type.*;
 import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang3.tuple.Pair;
+import org.joda.time.DateTime;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -38,167 +35,196 @@ import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
 public class QueryProcessor {
     private static final Logger LOG = 
LoggerFactory.getLogger(QueryProcessor.class);
 
     private final int DEFAULT_QUERY_RESULT_LIMIT = 25;
+    private final int DEFAULT_QUERY_RESULT_OFFSET = 0;
 
-    private final Pattern SINGLE_QUOTED_IDENTIFIER   = 
Pattern.compile("'(\\w[\\w\\d\\.\\s]*)'");
-    private final Pattern DOUBLE_QUOTED_IDENTIFIER   = 
Pattern.compile("\"(\\w[\\w\\d\\.\\s]*)\"");
-    private final Pattern BACKTICK_QUOTED_IDENTIFIER = 
Pattern.compile("`(\\w[\\w\\d\\.\\s]*)`");
-
-    private final List<String> errorList         = new ArrayList<>();
-    private final GremlinClauseList queryClauses = new 
GremlinClauseList(errorList);
+    private final boolean isNestedQuery;
+    private final List<String>      errorList    = new ArrayList<>();
+    private final GremlinClauseList queryClauses = new GremlinClauseList();
+    private int providedLimit = DEFAULT_QUERY_RESULT_LIMIT;
+    private int providedOffset = DEFAULT_QUERY_RESULT_OFFSET;
     private int currentStep;
-    private final TypeRegistryLookup registryLookup;
+    private final org.apache.atlas.query.Lookup lookup;
+    private Context context;
 
     @Inject
     public QueryProcessor(AtlasTypeRegistry typeRegistry) {
-        registryLookup = new TypeRegistryLookup(errorList, typeRegistry);
+        this.isNestedQuery = false;
+        lookup = new Lookup(errorList, typeRegistry);
+        context = new Context(errorList, lookup);
         init();
     }
 
+    public QueryProcessor(AtlasTypeRegistry typeRegistry, int limit, int 
offset) {
+        this(typeRegistry);
+        this.providedLimit = limit;
+        this.providedOffset = offset < 0 ? DEFAULT_QUERY_RESULT_OFFSET : 
offset;
+    }
+
     @VisibleForTesting
-    public QueryProcessor(TypeRegistryLookup lookup) {
-        registryLookup = lookup;
+    QueryProcessor(org.apache.atlas.query.Lookup lookup, Context context) {
+        this.isNestedQuery = false;
+        this.lookup = lookup;
+        this.context = context;
         init();
     }
 
-    private void init() {
-        add(GremlinClause.G);
-        add(GremlinClause.V);
+    public QueryProcessor(org.apache.atlas.query.Lookup registryLookup, 
boolean isNestedQuery) {
+        this.isNestedQuery = isNestedQuery;
+        this.lookup = registryLookup;
+        init();
     }
 
     public Expression validate(Expression expression) {
         return expression.isReady();
     }
 
+    private void init() {
+        if (!isNestedQuery) {
+            add(GremlinClause.G);
+            add(GremlinClause.V);
+        } else {
+            add(GremlinClause.NESTED_START);
+        }
+    }
+
     public void addFrom(String typeName) {
         if (LOG.isDebugEnabled()) {
             LOG.debug("addFrom(typeName={})", typeName);
         }
 
-        String actualTypeName = extractIdentifier(typeName);
+        IdentifierHelper.Advice ta = getAdvice(typeName);
+        if(context.shouldRegister(ta.get())) {
+            context.registerActive(ta.get());
 
-        if(registryLookup.isTypeTrait(actualTypeName)) {
-            addTraitAndRegister(actualTypeName);
-        } else if (!registryLookup.hasActiveType()) {
-            registryLookup.registerActive(actualTypeName);
-            if(registryLookup.doesActiveTypeHaveSubTypes()) {
-                add(GremlinClause.HAS_TYPE_WITHIN, 
registryLookup.getActiveTypeAndSubTypes());
+            IdentifierHelper.Advice ia = getAdvice(ta.get());
+            if (ia.isTrait()) {
+                add(GremlinClause.TRAIT, ia.get());
             } else {
-                add(GremlinClause.HAS_TYPE, actualTypeName);
+                if (ia.hasSubtypes()) {
+                    add(GremlinClause.HAS_TYPE_WITHIN, ia.getSubTypes());
+                } else {
+                    add(GremlinClause.HAS_TYPE, ia.get());
+                }
             }
         } else {
-            add(GremlinClause.OUT, 
registryLookup.getRelationshipEdgeLabelForActiveType(actualTypeName));
-            
registryLookup.registerActive(registryLookup.getTypeFromEdge(actualTypeName));
+            IdentifierHelper.Advice ia = getAdvice(ta.get());
+            introduceType(ia);
         }
     }
 
-    private void addTraitAndRegister(String typeName) {
-        if (LOG.isDebugEnabled()) {
-            LOG.debug("addTraitAndRegister(typeName={})", typeName);
+    private void introduceType(IdentifierHelper.Advice ia) {
+        if (!ia.isPrimitive() && ia.getIntroduceType()) {
+            add(GremlinClause.OUT, ia.getEdgeLabel());
+            context.registerActive(ia.getTypeName());
         }
+    }
 
-        add(GremlinClause.TRAIT, typeName);
-        registryLookup.registerActive(typeName);
+    private IdentifierHelper.Advice getAdvice(String actualTypeName) {
+        return IdentifierHelper.create(context, lookup, actualTypeName);
     }
 
-    public void addFromIsA(String typeName, String trait) {
+    public void addFromProperty(String typeName, String attribute) {
         if (LOG.isDebugEnabled()) {
-            LOG.debug("addFromIsA(typeName={}, trait={})", typeName, trait);
+            LOG.debug("addFromProperty(typeName={}, attribute={})", typeName, 
attribute);
         }
 
-        if(!registryLookup.hasActiveType()) {
-            addFrom(typeName);
-        }
+        addFrom(typeName);
+        add(GremlinClause.HAS_PROPERTY,
+                IdentifierHelper.getQualifiedName(lookup, context, attribute));
+    }
 
-        add(GremlinClause.TRAIT, trait);
+
+    public void addFromIsA(String typeName, String traitName) {
+        addFrom(typeName);
+        add(GremlinClause.TRAIT, traitName);
     }
 
-    public void addFromProperty(String typeName, String attribute) {
+    public void addWhere(String lhs, String operator, String rhs) {
         if (LOG.isDebugEnabled()) {
-            LOG.debug("addFromIsA(typeName={}, attribute={})", typeName, 
attribute);
+            LOG.debug("addWhere(lhs={}, operator={}, rhs={})", lhs, operator, 
rhs);
         }
 
-        if(registryLookup.isSameAsActive(typeName) == false) {
-            addFrom(typeName);
+        String currentType  = context.getActiveTypeName();
+        SearchParameters.Operator op = 
SearchParameters.Operator.fromString(operator);
+        IdentifierHelper.Advice org = null;
+        IdentifierHelper.Advice lhsI = getAdvice(lhs);
+        if(lhsI.isPrimitive() == false) {
+            introduceType(lhsI);
+            org = lhsI;
+            lhsI = getAdvice(lhs);
         }
 
-        add(GremlinClause.HAS_PROPERTY, 
registryLookup.getQualifiedAttributeName(attribute));
-    }
+        if(lhsI.isDate()) {
+            rhs = parseDate(rhs);
+        }
 
-    public void addFromAlias(String typeName, String alias) {
-        if (LOG.isDebugEnabled()) {
-            LOG.debug("addFromAlias(typeName={}, alias={})", typeName, alias);
+        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);
         }
 
-        addFrom(typeName);
-        addAsClause(alias);
+        if(org != null && org.isPrimitive() == false && 
org.getIntroduceType()) {
+            add(GremlinClause.IN, org.getEdgeLabel());
+            context.registerActive(currentType);
+        }
     }
 
-    public void addWhere(String lhs, String operator, String rhs) {
-        if (LOG.isDebugEnabled()) {
-            LOG.debug("addWhere(lhs={}, operator={}, rhs={})", lhs, operator, 
rhs);
-        }
+    private String addQuotesIfNecessary(String rhs) {
+        if(IdentifierHelper.isQuoted(rhs)) return rhs;
+        return quoted(rhs);
+    }
 
-        lhs = registryLookup.getQualifiedAttributeName(lhs);
+    private static String quoted(String rhs) {
+        return IdentifierHelper.getQuoted(rhs);
+    }
 
-        SearchParameters.Operator op = 
SearchParameters.Operator.fromString(operator);
-        switch (op) {
-            case LT:
-                add(GremlinClause.HAS_OPERATOR, lhs, "lt", rhs);
-                break;
-            case GT:
-                add(GremlinClause.HAS_OPERATOR, lhs, "gt", rhs);
-                break;
-            case LTE:
-                add(GremlinClause.HAS_OPERATOR, lhs, "lte", rhs);
-                break;
-            case GTE:
-                add(GremlinClause.HAS_OPERATOR, lhs, "gte", rhs);
-                break;
-            case EQ:
-                add(GremlinClause.HAS_OPERATOR, lhs, "eq", rhs);
-                break;
-            case NEQ:
-                add(GremlinClause.HAS_OPERATOR, lhs, "neq", rhs);
-                break;
-            case IN:
-                // TODO: Handle multiple RHS values
-                add(GremlinClause.HAS_OPERATOR, lhs, "within", rhs);
-                break;
-            case LIKE:
-                add(GremlinClause.TEXT_CONTAINS, lhs, rhs.replace("*", 
".*").replace('?', '.'));
-                break;
-        }
-    }
-
-    public void addSelect(String[] items) {
+    private String parseDate(String rhs) {
+        String s = IdentifierHelper.isQuoted(rhs) ?
+                IdentifierHelper.removeQuotes(rhs) :
+                rhs;
+        return String.format("'%d'", DateTime.parse(s).getMillis());
+    }
+
+    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(List<Pair<String, String>> items) {
         if (LOG.isDebugEnabled()) {
-            LOG.debug("addSelect(items.length={})", items != null ? 
items.length : -1);
+            LOG.debug("addSelect(items.length={})", items != null ? 
items.size() : -1);
         }
 
         StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < items.size(); i++) {
+            IdentifierHelper.Advice ia = getAdvice(items.get(i).getLeft());
+            if(StringUtils.isNotEmpty(items.get(i).getRight())) {
+                context.aliasMap.put(items.get(i).getRight(), 
ia.getQualifiedName());
+            }
 
-        for (int i = 0; i < items.length; i++) {
-            String s = registryLookup.getQualifiedAttributeName(items[i]);
-
-            if (items[i].contains(".") || 
registryLookup.isAttributePrimitiveTypeForActiveType(items[i])) {
-                sb.append(String.format("'%s'", s));
-
-                if (i != items.length - 1) {
-                    sb.append(", ");
-                }
-            } else {
-                add(GremlinClause.OUT, 
registryLookup.getRelationshipEdgeLabelForActiveType(items[i]));
+            if(!ia.isPrimitive() && ia.getIntroduceType()) {
+                add(GremlinClause.OUT, ia.getEdgeLabel());
                 add(GremlinClause.AS, getCurrentStep());
                 addSelectClause(getCurrentStep());
                 incrementCurrentStep();
+            }  else {
+                sb.append(quoted(ia.getQualifiedName()));
+            }
+
+            if (i != items.size() - 1) {
+                sb.append(",");
             }
         }
 
@@ -207,62 +233,44 @@ public class QueryProcessor {
         }
     }
 
-    public void addLimit(String limit, String offset) {
+    private void addSelectClause(String s) {
         if (LOG.isDebugEnabled()) {
-            LOG.debug("addLimit(limit={}, offset={})", limit, offset);
+            LOG.debug("addSelectClause(s={})", s);
         }
 
-        add(GremlinClause.ORDER);
-
-        if (offset.equalsIgnoreCase("0")) {
-            add(GremlinClause.LIMIT, limit);
-        } else {
-            addRangeClause(offset, limit);
-        }
+        add(GremlinClause.SELECT, s);
     }
 
-    public void addGroupBy(String item) {
-        if (LOG.isDebugEnabled()) {
-            LOG.debug("addGroupBy(item={})", item);
-        }
-
-        add(GremlinClause.GROUP);
-        addByClause(item, false);
+    private String getCurrentStep() {
+        return String.format("s%d", currentStep);
     }
 
-    private void addRangeClause(String startIndex, String endIndex) {
-        if (LOG.isDebugEnabled()) {
-            LOG.debug("addRangeClause(startIndex={}, endIndex={})", 
startIndex, endIndex);
-        }
-
-        add(GremlinClause.RANGE, startIndex, startIndex, endIndex);
+    private void incrementCurrentStep() {
+        currentStep++;
     }
 
-    public String getText() {
-        String[] items = new String[queryClauses.size()];
-
-        for (int i = 0; i < queryClauses.size(); i++) {
-            items[i] = queryClauses.getValue(i);
-        }
-
-        String ret = StringUtils.join(items, ".");
+    public QueryProcessor createNestedProcessor() {
+        QueryProcessor qp = new QueryProcessor(lookup, true);
+        qp.context = this.context;
+        return qp;
+    }
 
+    private void addValueMapClause(String s) {
         if (LOG.isDebugEnabled()) {
-            LOG.debug("getText() => {}", ret);
+            LOG.debug("addValueMapClause(s={})", s);
         }
 
-        return ret;
+        add(GremlinClause.VALUE_MAP, s);
     }
 
-    public void close() {
-        if(queryClauses.hasClause(GremlinClause.LIMIT) == -1) {
-            add(GremlinClause.LIMIT, "" + DEFAULT_QUERY_RESULT_LIMIT);
+    public void addFromAlias(String typeName, String alias) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("addFromAlias(typeName={}, alias={})", typeName, alias);
         }
-        add(GremlinClause.TO_LIST);
-    }
 
-    public boolean hasSelect() {
-        return (queryClauses.hasClause(GremlinClause.VALUE_MAP) != -1);
+        addFrom(typeName);
+        addAsClause(alias);
+        context.registerAlias(alias);
     }
 
     public void addAsClause(String stepName) {
@@ -271,32 +279,28 @@ public class QueryProcessor {
         }
 
         add(GremlinClause.AS, stepName);
-        registryLookup.registerStepType(stepName);
     }
 
-    public void addOrderBy(String name, boolean isDesc) {
-        if (LOG.isDebugEnabled()) {
-            LOG.debug("addOrderBy(name={}, isDesc={})", name, isDesc);
-        }
-
-        add(GremlinClause.ORDER);
-        addByClause(registryLookup.getQualifiedAttributeName(name), isDesc);
+    private void add(GremlinClause clause, String... args) {
+        queryClauses.add(new GremlinClauseValue(clause, clause.get(args)));
     }
 
-    private void addValueMapClause(String s) {
+    private void addRangeClause(String startIndex, String endIndex) {
         if (LOG.isDebugEnabled()) {
-            LOG.debug("addValueMapClause(s={})", s);
+            LOG.debug("addRangeClause(startIndex={}, endIndex={})", 
startIndex, endIndex);
         }
 
-        add(GremlinClause.VALUE_MAP, s);
+        add(GremlinClause.RANGE, startIndex, startIndex, endIndex);
     }
 
-    private void addSelectClause(String s) {
+
+    public void addGroupBy(String item) {
         if (LOG.isDebugEnabled()) {
-            LOG.debug("addSelectClause(s={})", s);
+            LOG.debug("addGroupBy(item={})", item);
         }
 
-        add(GremlinClause.SELECT, s);
+        add(GremlinClause.GROUP);
+        addByClause(item, false);
     }
 
     private void addByClause(String name, boolean descr) {
@@ -304,47 +308,81 @@ public class QueryProcessor {
             LOG.debug("addByClause(name={})", name, descr);
         }
 
+        IdentifierHelper.Advice ia = getAdvice(name);
         add((!descr) ? GremlinClause.BY : GremlinClause.BY_DESC,
-                registryLookup.getQualifiedAttributeName(name));
+                ia.getQualifiedName());
     }
 
-    private String getCurrentStep() {
-        return String.format("s%d", currentStep);
-    }
+    public void addLimit(String limit, String offset) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("addLimit(limit={}, offset={})", limit, offset);
+        }
 
-    private void incrementCurrentStep() {
-        currentStep++;
+        if (offset.equalsIgnoreCase("0")) {
+            add(GremlinClause.LIMIT, limit);
+        } else {
+            addRangeClause(offset, limit);
+        }
     }
 
-    private void add(GremlinClause clause, String... args) {
-        queryClauses.add(new GremlinClauseValue(clause, clause.get(args)));
+    public void close() {
+        if (queryClauses.isEmpty()) {
+            queryClauses.clear();
+            return;
+        }
+
+        if (queryClauses.hasClause(GremlinClause.LIMIT) == -1) {
+            addLimit(Integer.toString(providedLimit), 
Integer.toString(providedOffset));
+        }
+
+        add(GremlinClause.TO_LIST);
     }
 
-    private String extractIdentifier(String quotedIdentifier) {
-        String ret;
+    public String getText() {
+        String[] items = new String[queryClauses.size()];
+
+        for (int i = 0; i < queryClauses.size(); i++) {
+            items[i] = queryClauses.getValue(i);
+        }
+
+        String ret = StringUtils.join(items, ".");
 
-        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;
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("getText() => {}", ret);
         }
 
         return ret;
     }
 
-    private String extract(Pattern p, String s) {
-        Matcher m = p.matcher(s);
-        return m.find() ? m.group(1) : s;
+    public boolean hasSelect() {
+        return (queryClauses.hasClause(GremlinClause.VALUE_MAP) != -1);
+    }
+
+    public void addOrderBy(String name, boolean isDesc) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("addOrderBy(name={}, isDesc={})", name, isDesc);
+        }
+
+        add(GremlinClause.ORDER);
+        addByClause(name, isDesc);
+        updateSelectClausePosition();
+    }
+
+    private void updateSelectClausePosition() {
+        int selectClauseIndex = 
queryClauses.hasClause(GremlinClause.VALUE_MAP);
+        if(-1 == selectClauseIndex) {
+            return;
+        }
+
+        GremlinClauseValue gcv = queryClauses.remove(selectClauseIndex);
+        queryClauses.add(gcv);
     }
 
     private enum GremlinClause {
         AS("as('%s')"),
         BY("by('%s')"),
         BY_DESC("by('%s', decr)"),
+        DEDUP("dedup()"),
         G("g"),
         GROUP("group()"),
         HAS("has('%s', %s)"),
@@ -354,7 +392,11 @@ public class QueryProcessor {
         HAS_TYPE("has('__typeName', '%s')"),
         HAS_TYPE_WITHIN("has('__typeName', within(%s))"),
         HAS_WITHIN("has('%s', within(%s))"),
-        IN("in()"),
+        IN("in('%s')"),
+        OR("or(%s)"),
+        AND("and(%s)"),
+        NESTED_START("__"),
+        NESTED_HAS_OPERATOR("has('%s', %s(%s))"),
         LIMIT("limit(%s)"),
         ORDER("order()"),
         OUT("out('%s')"),
@@ -400,13 +442,9 @@ public class QueryProcessor {
     }
 
     private static class GremlinClauseList {
-        private final List<String> errorList;
-        private AtlasEntityType activeType;
-
         private final List<GremlinClauseValue> list;
 
-        private GremlinClauseList(List<String> errorList) {
-            this.errorList = errorList;
+        private GremlinClauseList() {
             this.list = new LinkedList<>();
         }
 
@@ -416,7 +454,6 @@ public class QueryProcessor {
 
         public void add(GremlinClauseValue g, AtlasEntityType t) {
             add(g);
-            activeType = t;
         }
 
         public void add(GremlinClause clause, String... args) {
@@ -427,6 +464,10 @@ public class QueryProcessor {
             return list.get(i).value;
         }
 
+        public GremlinClauseValue get(int i) {
+            return list.get(i);
+        }
+
         public int size() {
             return list.size();
         }
@@ -439,133 +480,218 @@ public class QueryProcessor {
 
             return -1;
         }
+
+        public boolean isEmpty() {
+            return list.size() == 0 || list.size() == 2;
+        }
+
+        public void clear() {
+            list.clear();
+        }
+
+        public GremlinClauseValue remove(int index) {
+            GremlinClauseValue gcv = get(index);
+            list.remove(index);
+            return gcv;
+        }
     }
 
     @VisibleForTesting
-    static class TypeRegistryLookup {
+    static class Context {
         private final List<String> errorList;
-        private final AtlasTypeRegistry typeRegistry;
+        org.apache.atlas.query.Lookup lookup;
+        private AtlasType activeType;
+        Map<String, String> aliasMap = new HashMap<>();
 
-        private AtlasEntityType activeType;
-        private final Map<String, AtlasEntityType> asClauseContext = new 
HashMap<>();
-
-        public TypeRegistryLookup(List<String> errorList, AtlasTypeRegistry 
typeRegistry) {
+        public Context(List<String> errorList, org.apache.atlas.query.Lookup 
lookup) {
+            this.lookup = lookup;
             this.errorList = errorList;
-            this.typeRegistry = typeRegistry;
         }
 
         public void registerActive(String typeName) {
-            activeType = typeRegistry.getEntityTypeByName(typeName);
+            if(shouldRegister(typeName)) {
+                activeType = lookup.getType(typeName);
+            }
+
+            aliasMap.put(typeName, typeName);
         }
 
-        public boolean hasActiveType() {
-            return (activeType != null);
+        public AtlasType getActiveType() {
+            return activeType;
         }
 
-        public void registerStepType(String stepName) {
-            if (!asClauseContext.containsKey(stepName)) {
-                asClauseContext.put(stepName, activeType);
-            } else {
-                addError(String.format("Multiple steps with same name 
detected: %s", stepName));
-            }
+        public AtlasEntityType getActiveEntityType() {
+            return (activeType instanceof AtlasEntityType) ?
+                    (AtlasEntityType) activeType :
+                    null;
         }
 
-        protected void addError(String s) {
-            errorList.add(s);
+        public String getActiveTypeName() {
+            return activeType.getTypeName();
         }
 
-        public String getRelationshipEdgeLabelForActiveType(String item) {
-            return getRelationshipEdgeLabel(activeType, item);
+        public boolean shouldRegister(String typeName) {
+            return activeType == null ||
+                    (activeType != null && 
!StringUtils.equals(getActiveTypeName(), typeName)) &&
+                            (activeType != null && !lookup.hasAttribute(this, 
typeName));
         }
 
-        private String getRelationshipEdgeLabel(AtlasEntityType t, String 
item) {
-            if(t == null) {
-                return "";
+        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;
             }
 
-            AtlasStructType.AtlasAttribute attr = t.getAttribute(item);
-            return (attr != null) ? attr.getRelationshipEdgeLabel() : "";
+            aliasMap.put(alias, getActiveTypeName());
         }
 
-        protected boolean isAttributePrimitiveTypeForActiveType(String name) {
-            return isAttributePrimitiveType(activeType, name);
+        public boolean hasAlias(String alias) {
+            return aliasMap.containsKey(alias);
         }
 
-        private boolean isAttributePrimitiveType(AtlasEntityType t, String 
name) {
-            if (activeType == null) {
-                return false;
+        public String getTypeNameFromAlias(String alias) {
+            return aliasMap.get(alias);
+        }
+
+        public boolean isEmpty() {
+            return activeType == null;
+        }
+    }
+
+    private static class Lookup implements org.apache.atlas.query.Lookup {
+        private final List<String> errorList;
+        private final AtlasTypeRegistry typeRegistry;
+
+        public Lookup(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());
             }
 
-            AtlasType attrType = t.getAttributeType(name);
-            TypeCategory attrTypeCategory = attrType.getTypeCategory();
+            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 (attrTypeCategory == TypeCategory.PRIMITIVE || 
attrTypeCategory == TypeCategory.ENUM);
+            return "";
         }
 
-        public boolean isTypeTrait(String name) {
-            return (typeRegistry.getClassificationTypeByName(name) != null);
+        protected void addError(String s) {
+            errorList.add(s);
         }
 
-        public String getQualifiedAttributeName(String item) {
-            if (item.contains(".")) {
-                String[] keyValue = StringUtils.split(item, ".");
+        @Override
+        public boolean isPrimitive(Context context, String attributeName) {
+            AtlasEntityType et = context.getActiveEntityType();
+            if(et == null) {
+                return false;
+            }
 
-                if (!asClauseContext.containsKey(keyValue[0])) {
-                    return item;
-                } else {
-                    String s = getStitchedString(keyValue, 1, keyValue.length 
- 1);
-                    return getQualifiedAttributeNameFromType(
-                            asClauseContext.get(keyValue[0]), s);
-                }
+            AtlasType attr = et.getAttributeType(attributeName);
+            if(attr == null) {
+                return false;
             }
 
-            return getQualifiedAttributeNameFromType(activeType, item);
+            TypeCategory attrTypeCategory = attr.getTypeCategory();
+            return (attrTypeCategory != null) && (attrTypeCategory == 
TypeCategory.PRIMITIVE || attrTypeCategory == TypeCategory.ENUM);
         }
 
-        protected String getStitchedString(String[] keyValue, int startIndex, 
int endIndex) {
-            if(startIndex == endIndex) {
-                return keyValue[startIndex];
+        @Override
+        public String getRelationshipEdgeLabel(Context context, String 
attributeName) {
+            AtlasEntityType et = context.getActiveEntityType();
+            if(et == null) {
+                return "";
             }
 
-            return StringUtils.join(keyValue, ".", startIndex, endIndex);
+            AtlasStructType.AtlasAttribute attr = 
et.getAttribute(attributeName);
+            return (attr != null) ? attr.getRelationshipEdgeLabel() : "";
         }
 
-        private String getQualifiedAttributeNameFromType(AtlasEntityType t, 
String item) {
-            try {
-                return (t != null) ? t.getQualifiedAttributeName(item) : item;
-            } catch (AtlasBaseException e) {
-                addError(e.getMessage());
+        @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;
             }
 
-            return item;
+            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);
         }
 
-        public String getTypeFromEdge(String item) {
-            AtlasType at = activeType.getAttribute(item).getAttributeType();
+        @Override
+        public String getTypeFromEdge(Context context, String item) {
+            AtlasEntityType et = context.getActiveEntityType();
+            if(et == null) {
+                return "";
+            }
+
+            AtlasStructType.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 activeType.getAttribute(item).getTypeName();
+            return 
context.getActiveEntityType().getAttribute(item).getTypeName();
         }
 
-        public boolean doesActiveTypeHaveSubTypes() {
-            return (activeType.getAllSubTypes().size() != 0);
-        }
-
-        public String getActiveTypeAndSubTypes() {
-            Set<String> set = activeType.getTypeAndAllSubTypes();
-            String[] str = set.toArray(new String[]{});
-            for (int i = 0; i < str.length; i++) {
-                str[i] = String.format("'%s'", str[i]);
+        @Override
+        public boolean isDate(Context context, String attributeName) {
+            AtlasEntityType et = context.getActiveEntityType();
+            if(et == null) {
+                return false;
             }
 
-            return StringUtils.join(str, ",");
-        }
+            AtlasType attr = et.getAttributeType(attributeName);
+            if(attr == null) {
+                return false;
+            }
 
-        public boolean isSameAsActive(String typeName) {
-            return (activeType != null) && 
activeType.getTypeName().equalsIgnoreCase(typeName);
+            return attr.getTypeName().equals("date");
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/atlas/blob/ac0764be/repository/src/main/java/org/apache/atlas/query/antlr4/AtlasDSLLexer.java
----------------------------------------------------------------------
diff --git 
a/repository/src/main/java/org/apache/atlas/query/antlr4/AtlasDSLLexer.java 
b/repository/src/main/java/org/apache/atlas/query/antlr4/AtlasDSLLexer.java
index 85f8d61..576e129 100644
--- a/repository/src/main/java/org/apache/atlas/query/antlr4/AtlasDSLLexer.java
+++ b/repository/src/main/java/org/apache/atlas/query/antlr4/AtlasDSLLexer.java
@@ -1,4 +1,4 @@
-// Generated from AtlasDSLLexer.g4 by ANTLR 4.7
+// Generated from 
repository/src/main/java/org/apache/atlas/query/antlr4/AtlasDSLLexer.g4 by 
ANTLR 4.7
 package org.apache.atlas.query.antlr4;
 import org.antlr.v4.runtime.Lexer;
 import org.antlr.v4.runtime.CharStream;

http://git-wip-us.apache.org/repos/asf/atlas/blob/ac0764be/repository/src/main/java/org/apache/atlas/query/antlr4/AtlasDSLParser.g4
----------------------------------------------------------------------
diff --git 
a/repository/src/main/java/org/apache/atlas/query/antlr4/AtlasDSLParser.g4 
b/repository/src/main/java/org/apache/atlas/query/antlr4/AtlasDSLParser.g4
index bf6b7e3..058a5c8 100644
--- a/repository/src/main/java/org/apache/atlas/query/antlr4/AtlasDSLParser.g4
+++ b/repository/src/main/java/org/apache/atlas/query/antlr4/AtlasDSLParser.g4
@@ -20,8 +20,6 @@ parser grammar AtlasDSLParser;
 
 options { tokenVocab=AtlasDSLLexer; }
 
-// Start of rules, bottom-up (rules at the end are built using the core rules)
-
 // Core rules
 identifier: ID ;
 
@@ -98,8 +96,6 @@ selectClause: K_SELECT selectExpr ;
 
 singleQrySrc: fromClause | whereClause | fromExpression | expr ;
 
-loopExpression: K_LOOP K_LPAREN query K_RPAREN NUMBER? (K_AS identifier)? ;
-
 groupByExpression: K_GROUPBY K_LPAREN selectExpr K_RPAREN ;
 
 commaDelimitedQueries: singleQrySrc (K_COMMA singleQrySrc)* ;
@@ -108,10 +104,7 @@ spaceDelimitedQueries: singleQrySrc singleQrySrc* ;
 
 querySrc: commaDelimitedQueries | spaceDelimitedQueries ;
 
-query: querySrc loopExpression?
-                groupByExpression?
+query: querySrc groupByExpression?
                 selectClause?
                 orderByExpr?
                 limitOffset? ;
-
-queryWithPath: query (K_WITHPATH)? ;

Reply via email to