Commit c35f82ca by Ashutosh Mestry Committed by apoorvnaik

ATLAS-2419: DSL Semantic Validation. Fix for limit & range.

parent 1fee4a5b
...@@ -103,7 +103,23 @@ public enum AtlasErrorCode { ...@@ -103,7 +103,23 @@ public enum AtlasErrorCode {
SAVED_SEARCH_CHANGE_USER(400, "ATLAS-400-00-056", "saved-search {0} can not be moved from user {1} to {2}"), 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_PARAM_LENGTH(400, "ATLAS-400-00-057" , "Length of query param {0} exceeds the limit"),
INVALID_QUERY_LENGTH(400, "ATLAS-400-00-058" , "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" ),
// DSL related error codes
INVALID_DSL_QUERY(400, "ATLAS-400-00-059" , "Invalid DSL query: {0} | Reason: {1}. Please refer to Atlas DSL grammar for more information" ), INVALID_DSL_QUERY(400, "ATLAS-400-00-059" , "Invalid DSL query: {0} | Reason: {1}. Please refer to Atlas DSL grammar for more information" ),
INVALID_DSL_GROUPBY(400, "ATLAS-400-00-05A", "DSL Semantic Error - GroupBy attribute {0} is non-primitive"),
INVALID_DSL_UNKNOWN_TYPE(400, "ATLAS-400-00-05B", "DSL Semantic Error - {0} type not found"),
INVALID_DSL_UNKNOWN_CLASSIFICATION(400, "ATLAS-400-00-05C", "DSL Semantic Error - {0} classification not found"),
INVALID_DSL_UNKNOWN_ATTR_TYPE(400, "ATLAS-400-00-05D", "DSL Semantic Error - {0} attribute not found for type {1}"),
INVALID_DSL_ORDERBY(400, "ATLAS-400-00-05E", "DSL Semantic Error - OrderBy attribute {0} is non-primitive"),
INVALID_DSL_FROM(400, "ATLAS-400-00-05F", "DSL Semantic Error - From source {0} is not a valid Entity/Classification type"),
INVALID_DSL_SELECT_REFERRED_ATTR(400, "ATLAS-400-00-060", "DSL Semantic Error - Select clause has multiple referred attributes {0}"),
INVALID_DSL_SELECT_INVALID_AGG(400, "ATLAS-400-00-061", "DSL Semantic Error - Select clause has aggregation on referred attributes {0}"),
INVALID_DSL_SELECT_ATTR_MIXING(400, "ATLAS-400-00-062", "DSL Semantic Error - Select clause has simple and referred attributes"),
INVALID_DSL_HAS_ATTRIBUTE(400, "ATLAS-400-00-063", "DSL Semantic Error - No attribute {0} exists for type {1}"),
INVALID_DSL_QUALIFIED_NAME(400, "ATLAS-400-00-064", "DSL Semantic Error - Qualified name for {0} failed!"),
INVALID_DSL_QUALIFIED_NAME2(400, "ATLAS-400-00-065", "DSL Semantic Error - Qualified name for {0} failed for type {1}. Cause: {2}"),
INVALID_DSL_DUPLICATE_ALIAS(400, "ATLAS-400-00-066", "DSL Semantic Error - Duplicate alias found: '{0}' for type '{1}' already present."),
INVALID_DSL_INVALID_DATE(400, "ATLAS-400-00-067", "DSL Semantic Error - Date format: {0}."),
INVALID_DSL_HAS_PROPERTY(400, "ATLAS-400-00-068", "DSL Semantic Error - Property needs to be a primitive type: {0}"),
// All Not found enums go here // All Not found enums go here
TYPE_NAME_NOT_FOUND(404, "ATLAS-404-00-001", "Given typename {0} was invalid"), TYPE_NAME_NOT_FOUND(404, "ATLAS-404-00-001", "Given typename {0} was invalid"),
......
...@@ -104,6 +104,8 @@ public class AtlasDSL { ...@@ -104,6 +104,8 @@ public class AtlasDSL {
} }
public static class Translator { public static class Translator {
private static final Logger LOG = LoggerFactory.getLogger(Translator.class);
private final AtlasDSLParser.QueryContext queryContext; private final AtlasDSLParser.QueryContext queryContext;
private final AtlasTypeRegistry typeRegistry; private final AtlasTypeRegistry typeRegistry;
private final int offset; private final int offset;
...@@ -123,33 +125,21 @@ public class AtlasDSL { ...@@ -123,33 +125,21 @@ public class AtlasDSL {
GremlinQueryComposer gremlinQueryComposer = new GremlinQueryComposer(typeRegistry, queryMetadata, limit, offset); GremlinQueryComposer gremlinQueryComposer = new GremlinQueryComposer(typeRegistry, queryMetadata, limit, offset);
DSLVisitor dslVisitor = new DSLVisitor(gremlinQueryComposer); DSLVisitor dslVisitor = new DSLVisitor(gremlinQueryComposer);
try { queryContext.accept(dslVisitor);
queryContext.accept(dslVisitor);
processErrorList(gremlinQueryComposer, null); processErrorList(gremlinQueryComposer);
return new GremlinQuery(gremlinQueryComposer.get(), queryMetadata.hasSelect()); String gremlinQuery = gremlinQueryComposer.get();
} catch (Exception e) {
processErrorList(gremlinQueryComposer, e);
}
return null; return new GremlinQuery(gremlinQuery, queryMetadata.hasSelect());
} }
private void processErrorList(GremlinQueryComposer gremlinQueryComposer, Exception e) throws AtlasBaseException { private void processErrorList(GremlinQueryComposer gremlinQueryComposer) throws AtlasBaseException {
final String errorMessage; final String errorMessage;
if (CollectionUtils.isNotEmpty(gremlinQueryComposer.getErrorList())) { if (CollectionUtils.isNotEmpty(gremlinQueryComposer.getErrorList())) {
errorMessage = StringUtils.join(gremlinQueryComposer.getErrorList(), ", "); errorMessage = StringUtils.join(gremlinQueryComposer.getErrorList(), ", ");
} else { LOG.warn("DSL Errors: {}", errorMessage);
errorMessage = e != null ? (e.getMessage() != null ? e.getMessage() : e.toString()) : null;
}
if (errorMessage != null) {
if (e != null) {
throw new AtlasBaseException(AtlasErrorCode.INVALID_DSL_QUERY, e, this.query, errorMessage);
}
throw new AtlasBaseException(AtlasErrorCode.INVALID_DSL_QUERY, this.query, errorMessage); throw new AtlasBaseException(AtlasErrorCode.INVALID_DSL_QUERY, this.query, errorMessage);
} }
} }
......
...@@ -26,15 +26,12 @@ import org.slf4j.LoggerFactory; ...@@ -26,15 +26,12 @@ import org.slf4j.LoggerFactory;
import java.util.*; import java.util.*;
import static org.apache.atlas.query.antlr4.AtlasDSLParser.RULE_whereClause;
public class DSLVisitor extends AtlasDSLParserBaseVisitor<Void> { public class DSLVisitor extends AtlasDSLParserBaseVisitor<Void> {
private static final Logger LOG = LoggerFactory.getLogger(DSLVisitor.class); private static final Logger LOG = LoggerFactory.getLogger(DSLVisitor.class);
private static final String AND = "AND"; private static final String AND = "AND";
private static final String OR = "OR"; private static final String OR = "OR";
private Set<Integer> visitedRuleIndexes = new HashSet<>();
private final GremlinQueryComposer gremlinQueryComposer; private final GremlinQueryComposer gremlinQueryComposer;
public DSLVisitor(GremlinQueryComposer gremlinQueryComposer) { public DSLVisitor(GremlinQueryComposer gremlinQueryComposer) {
...@@ -42,44 +39,6 @@ public class DSLVisitor extends AtlasDSLParserBaseVisitor<Void> { ...@@ -42,44 +39,6 @@ public class DSLVisitor extends AtlasDSLParserBaseVisitor<Void> {
} }
@Override @Override
public Void visitSpaceDelimitedQueries(SpaceDelimitedQueriesContext ctx) {
addVisitedRule(ctx.getRuleIndex());
return super.visitSpaceDelimitedQueries(ctx);
}
@Override
public Void visitCommaDelimitedQueries(CommaDelimitedQueriesContext ctx) {
addVisitedRule(ctx.getRuleIndex());
return super.visitCommaDelimitedQueries(ctx);
}
@Override
public Void visitIsClause(IsClauseContext ctx) {
if (LOG.isDebugEnabled()) {
LOG.debug("=> DSLVisitor.visitIsClause({})", ctx);
}
if(!hasVisitedRule(RULE_whereClause)) {
gremlinQueryComposer.addFromIsA(ctx.arithE().getText(), ctx.identifier().getText());
}
return super.visitIsClause(ctx);
}
@Override
public Void visitHasClause(HasClauseContext ctx) {
if (LOG.isDebugEnabled()) {
LOG.debug("=> DSLVisitor.visitHasClause({})", ctx);
}
if(!hasVisitedRule(RULE_whereClause)) {
gremlinQueryComposer.addFromProperty(ctx.arithE().getText(), ctx.identifier().getText());
}
return super.visitHasClause(ctx);
}
@Override
public Void visitLimitOffset(LimitOffsetContext ctx) { public Void visitLimitOffset(LimitOffsetContext ctx) {
if (LOG.isDebugEnabled()) { if (LOG.isDebugEnabled()) {
LOG.debug("=> DSLVisitor.visitLimitOffset({})", ctx); LOG.debug("=> DSLVisitor.visitLimitOffset({})", ctx);
...@@ -159,7 +118,6 @@ public class DSLVisitor extends AtlasDSLParserBaseVisitor<Void> { ...@@ -159,7 +118,6 @@ public class DSLVisitor extends AtlasDSLParserBaseVisitor<Void> {
LOG.debug("=> DSLVisitor.visitWhereClause({})", ctx); LOG.debug("=> DSLVisitor.visitWhereClause({})", ctx);
} }
addVisitedRule(ctx.getRuleIndex());
ExprContext expr = ctx.expr(); ExprContext expr = ctx.expr();
processExpr(expr, gremlinQueryComposer); processExpr(expr, gremlinQueryComposer);
return super.visitWhereClause(ctx); return super.visitWhereClause(ctx);
...@@ -171,7 +129,7 @@ public class DSLVisitor extends AtlasDSLParserBaseVisitor<Void> { ...@@ -171,7 +129,7 @@ public class DSLVisitor extends AtlasDSLParserBaseVisitor<Void> {
LOG.debug("=> DSLVisitor.visitFromExpression({})", ctx); LOG.debug("=> DSLVisitor.visitFromExpression({})", ctx);
} }
FromSrcContext fromSrc = ctx.fromSrc(); FromSrcContext fromSrc = ctx.fromSrc();
AliasExprContext aliasExpr = fromSrc.aliasExpr(); AliasExprContext aliasExpr = fromSrc.aliasExpr();
if (aliasExpr != null) { if (aliasExpr != null) {
...@@ -188,11 +146,13 @@ public class DSLVisitor extends AtlasDSLParserBaseVisitor<Void> { ...@@ -188,11 +146,13 @@ public class DSLVisitor extends AtlasDSLParserBaseVisitor<Void> {
@Override @Override
public Void visitSingleQrySrc(SingleQrySrcContext ctx) { public Void visitSingleQrySrc(SingleQrySrcContext ctx) {
if (!hasVisitedRule(RULE_whereClause)) { if (ctx.fromExpression() == null) {
if (ctx.fromExpression() == null) { if (ctx.expr() != null && !gremlinQueryComposer.hasFromClause()) {
if (ctx.expr() != null && gremlinQueryComposer.hasFromClause()) { inferFromClause(ctx);
processExpr(ctx.expr(), gremlinQueryComposer); }
}
if (ctx.expr() != null && gremlinQueryComposer.hasFromClause()) {
processExpr(ctx.expr(), gremlinQueryComposer);
} }
} }
...@@ -210,6 +170,43 @@ public class DSLVisitor extends AtlasDSLParserBaseVisitor<Void> { ...@@ -210,6 +170,43 @@ public class DSLVisitor extends AtlasDSLParserBaseVisitor<Void> {
return super.visitGroupByExpression(ctx); return super.visitGroupByExpression(ctx);
} }
private Void visitIsClause(GremlinQueryComposer gqc, IsClauseContext ctx) {
if (LOG.isDebugEnabled()) {
LOG.debug("=> DSLVisitor.visitIsClause({})", ctx);
}
gqc.addIsA(ctx.arithE().getText(), ctx.identifier().getText());
return super.visitIsClause(ctx);
}
private void visitHasClause(GremlinQueryComposer gqc, HasClauseContext ctx) {
if (LOG.isDebugEnabled()) {
LOG.debug("=> DSLVisitor.visitHasClause({})", ctx);
}
gqc.addFromProperty(ctx.arithE().getText(), ctx.identifier().getText());
super.visitHasClause(ctx);
}
private void inferFromClause(SingleQrySrcContext ctx) {
if (ctx.fromExpression() != null) {
return;
}
if (ctx.expr() != null && gremlinQueryComposer.hasFromClause()) {
return;
}
if (ctx.expr().compE() != null && ctx.expr().compE().isClause() != null && ctx.expr().compE().isClause().arithE() != null) {
gremlinQueryComposer.addFrom(ctx.expr().compE().isClause().arithE().getText());
return;
}
if (ctx.expr().compE() != null && ctx.expr().compE().hasClause() != null && ctx.expr().compE().hasClause().arithE() != null) {
gremlinQueryComposer.addFrom(ctx.expr().compE().hasClause().arithE().getText());
}
}
private void processExpr(final ExprContext expr, GremlinQueryComposer gremlinQueryComposer) { private void processExpr(final ExprContext expr, GremlinQueryComposer gremlinQueryComposer) {
if (CollectionUtils.isNotEmpty(expr.exprRight())) { if (CollectionUtils.isNotEmpty(expr.exprRight())) {
processExprRight(expr, gremlinQueryComposer); processExprRight(expr, gremlinQueryComposer);
...@@ -281,11 +278,11 @@ public class DSLVisitor extends AtlasDSLParserBaseVisitor<Void> { ...@@ -281,11 +278,11 @@ public class DSLVisitor extends AtlasDSLParserBaseVisitor<Void> {
} }
if (comparisonClause != null) { if (comparisonClause != null) {
String lhs = comparisonClause.arithE(0).getText(); String lhs = comparisonClause.arithE(0).getText();
String op, rhs; String op, rhs;
AtomEContext atomECtx = comparisonClause.arithE(1).multiE().atomE(); AtomEContext atomECtx = comparisonClause.arithE(1).multiE().atomE();
if (atomECtx.literal() == null || if (atomECtx.literal() == null ||
(atomECtx.literal() != null && atomECtx.literal().valueArray() == null)) { (atomECtx.literal() != null && atomECtx.literal().valueArray() == null)) {
op = comparisonClause.operator().getText().toUpperCase(); op = comparisonClause.operator().getText().toUpperCase();
rhs = comparisonClause.arithE(1).getText(); rhs = comparisonClause.arithE(1).getText();
} else { } else {
...@@ -300,31 +297,23 @@ public class DSLVisitor extends AtlasDSLParserBaseVisitor<Void> { ...@@ -300,31 +297,23 @@ public class DSLVisitor extends AtlasDSLParserBaseVisitor<Void> {
} }
if (compE != null && compE.isClause() != null) { if (compE != null && compE.isClause() != null) {
gremlinQueryComposer.addFromIsA(compE.isClause().arithE().getText(), compE.isClause().identifier().getText()); visitIsClause(gremlinQueryComposer, compE.isClause());
} }
if (compE != null && compE.hasClause() != null) { if (compE != null && compE.hasClause() != null) {
gremlinQueryComposer.addFromProperty(compE.hasClause().arithE().getText(), compE.hasClause().identifier().getText()); visitHasClause(gremlinQueryComposer, compE.hasClause());
} }
} }
private String getInClause(AtomEContext atomEContext) { private String getInClause(AtomEContext atomEContext) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
ValueArrayContext valueArrayContext = atomEContext.literal().valueArray(); ValueArrayContext valueArrayContext = atomEContext.literal().valueArray();
int startIdx = 1; int startIdx = 1;
int endIdx = valueArrayContext.children.size() - 1; int endIdx = valueArrayContext.children.size() - 1;
for (int i = startIdx; i < endIdx; i++) { for (int i = startIdx; i < endIdx; i++) {
sb.append(valueArrayContext.getChild(i)); sb.append(valueArrayContext.getChild(i));
} }
return sb.toString(); return sb.toString();
} }
}
private void addVisitedRule(int ruleIndex) { \ No newline at end of file
visitedRuleIndexes.add(ruleIndex);
}
private boolean hasVisitedRule(int ruleIndex) {
return visitedRuleIndexes.contains(ruleIndex);
}
}
...@@ -36,11 +36,11 @@ enum GremlinClause { ...@@ -36,11 +36,11 @@ enum GremlinClause {
AND("and(%s)"), AND("and(%s)"),
NESTED_START("__"), NESTED_START("__"),
NESTED_HAS_OPERATOR("has('%s', %s(%s))"), NESTED_HAS_OPERATOR("has('%s', %s(%s))"),
LIMIT("limit(%s)"), LIMIT("limit(local, %s).limit(%s)"),
ORDER_BY("order().by('%s')"), ORDER_BY("order().by('%s')"),
ORDER_BY_DESC("order().by('%s', decr)"), ORDER_BY_DESC("order().by('%s', decr)"),
OUT("out('%s')"), OUT("out('%s')"),
RANGE("range(%s, %s + %s)"), RANGE("range(local, %s, %s + %s).range(%s, %s + %s)"),
SELECT("select('%s')"), SELECT("select('%s')"),
TO_LIST("toList()"), TO_LIST("toList()"),
TEXT_CONTAINS("has('%s', org.janusgraph.core.attribute.Text.textRegex(%s))"), TEXT_CONTAINS("has('%s', org.janusgraph.core.attribute.Text.textRegex(%s))"),
......
/**
* 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.AtlasEntityType;
import java.util.LinkedList;
import java.util.List;
class GremlinClauseList {
private final List<GremlinQueryComposer.GremlinClauseValue> list;
GremlinClauseList() {
this.list = new LinkedList<>();
}
public void add(GremlinQueryComposer.GremlinClauseValue g) {
list.add(g);
}
public void add(int idx, GremlinQueryComposer.GremlinClauseValue g) {
list.add(idx, g);
}
public void add(GremlinQueryComposer.GremlinClauseValue g, AtlasEntityType t) {
add(g);
}
public void add(int idx, GremlinQueryComposer.GremlinClauseValue g, AtlasEntityType t) {
add(idx, g);
}
public void add(GremlinClause clause, String... args) {
list.add(new GremlinQueryComposer.GremlinClauseValue(clause, clause.get(args)));
}
public void add(int i, GremlinClause clause, String... args) {
list.add(i, new GremlinQueryComposer.GremlinClauseValue(clause, clause.get(args)));
}
public GremlinQueryComposer.GremlinClauseValue getAt(int i) {
return list.get(i);
}
public String getValue(int i) {
return list.get(i).getValue();
}
public GremlinQueryComposer.GremlinClauseValue get(int i) {
return list.get(i);
}
public int size() {
return list.size();
}
public int contains(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 || containsGVLimit();
}
private boolean containsGVLimit() {
return list.size() == 3 &&
list.get(0).getClause() == GremlinClause.G &&
list.get(1).getClause() == GremlinClause.V &&
list.get(2).getClause() == GremlinClause.LIMIT;
}
public void clear() {
list.clear();
}
public GremlinQueryComposer.GremlinClauseValue remove(int index) {
GremlinQueryComposer.GremlinClauseValue gcv = get(index);
list.remove(index);
return gcv;
}
}
...@@ -6,9 +6,9 @@ ...@@ -6,9 +6,9 @@
* to you under the Apache License, Version 2.0 (the * to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance * "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at * with the License. You may obtain a copy of the License at
* * <p>
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* * <p>
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
package org.apache.atlas.query; package org.apache.atlas.query;
import org.apache.atlas.AtlasErrorCode;
import org.apache.atlas.exception.AtlasBaseException; import org.apache.atlas.exception.AtlasBaseException;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
...@@ -46,10 +47,10 @@ public class IdentifierHelper { ...@@ -46,10 +47,10 @@ public class IdentifierHelper {
return ret; return ret;
} }
public static Advice create(GremlinQueryComposer.Context context, public static IdentifierMetadata create(GremlinQueryComposer.Context context,
org.apache.atlas.query.Lookup lookup, org.apache.atlas.query.Lookup lookup,
String identifier) { String identifier) {
Advice ia = new Advice(identifier); IdentifierMetadata ia = new IdentifierMetadata(identifier);
ia.update(lookup, context); ia.update(lookup, context);
return ia; return ia;
} }
...@@ -65,7 +66,7 @@ public class IdentifierHelper { ...@@ -65,7 +66,7 @@ public class IdentifierHelper {
try { try {
return lookup.getQualifiedName(context, name); return lookup.getQualifiedName(context, name);
} catch (AtlasBaseException e) { } catch (AtlasBaseException e) {
context.getErrorList().add(String.format("Error for %s.%s: %s", context.getActiveTypeName(), name, e.getMessage())); context.error(e, AtlasErrorCode.INVALID_DSL_QUALIFIED_NAME, context.getActiveTypeName(), name);
} }
return ""; return "";
...@@ -100,24 +101,29 @@ public class IdentifierHelper { ...@@ -100,24 +101,29 @@ public class IdentifierHelper {
return rhs.equalsIgnoreCase("true") || rhs.equalsIgnoreCase("false"); return rhs.equalsIgnoreCase("true") || rhs.equalsIgnoreCase("false");
} }
public static class Advice { public static String getFixedRegEx(String s) {
private String raw; return s.replace("*", ".*").replace('?', '.');
private String actual; }
public static class IdentifierMetadata {
private String raw;
private String actual;
private String[] parts; private String[] parts;
private String typeName; private String typeName;
private String attributeName; private String attributeName;
private boolean isPrimitive; private boolean isPrimitive;
private String edgeLabel; private String edgeLabel;
private boolean introduceType; private boolean introduceType;
private boolean hasSubtypes; private boolean hasSubtypes;
private String subTypes; private String subTypes;
private boolean isTrait; private boolean isTrait;
private boolean newContext; private boolean newContext;
private boolean isAttribute; private boolean isAttribute;
private String qualifiedName; private String qualifiedName;
private boolean isDate; private boolean isDate;
public Advice(String s) { public IdentifierMetadata(String s) {
this.raw = removeQuotes(s); this.raw = removeQuotes(s);
this.actual = IdentifierHelper.get(raw); this.actual = IdentifierHelper.get(raw);
} }
...@@ -132,7 +138,7 @@ public class IdentifierHelper { ...@@ -132,7 +138,7 @@ public class IdentifierHelper {
updateParts(); updateParts();
updateTypeInfo(lookup, context); updateTypeInfo(lookup, context);
isTrait = lookup.isTraitType(context); setIsTrait(context, lookup, attributeName);
updateEdgeInfo(lookup, context); updateEdgeInfo(lookup, context);
introduceType = !isPrimitive() && !context.hasAlias(parts[0]); introduceType = !isPrimitive() && !context.hasAlias(parts[0]);
updateSubTypes(lookup, context); updateSubTypes(lookup, context);
...@@ -142,41 +148,45 @@ public class IdentifierHelper { ...@@ -142,41 +148,45 @@ public class IdentifierHelper {
} }
} }
private void setIsTrait(GremlinQueryComposer.Context ctx, Lookup lookup, String s) {
isTrait = lookup.isTraitType(s);
}
private void updateSubTypes(org.apache.atlas.query.Lookup lookup, GremlinQueryComposer.Context context) { private void updateSubTypes(org.apache.atlas.query.Lookup lookup, GremlinQueryComposer.Context context) {
if(isTrait) { if (isTrait) {
return; return;
} }
hasSubtypes = lookup.doesTypeHaveSubTypes(context); hasSubtypes = lookup.doesTypeHaveSubTypes(context);
if(hasSubtypes) { if (hasSubtypes) {
subTypes = lookup.getTypeAndSubTypes(context); subTypes = lookup.getTypeAndSubTypes(context);
} }
} }
private void updateEdgeInfo(org.apache.atlas.query.Lookup lookup, GremlinQueryComposer.Context context) { private void updateEdgeInfo(org.apache.atlas.query.Lookup lookup, GremlinQueryComposer.Context context) {
if(isPrimitive == false && isTrait == false) { if (!isPrimitive && !isTrait && typeName != attributeName) {
edgeLabel = lookup.getRelationshipEdgeLabel(context, attributeName); edgeLabel = lookup.getRelationshipEdgeLabel(context, attributeName);
typeName = lookup.getTypeFromEdge(context, attributeName); typeName = lookup.getTypeFromEdge(context, attributeName);
} }
} }
private void updateTypeInfo(org.apache.atlas.query.Lookup lookup, GremlinQueryComposer.Context context) { private void updateTypeInfo(org.apache.atlas.query.Lookup lookup, GremlinQueryComposer.Context context) {
if(parts.length == 1) { if (parts.length == 1) {
typeName = context.hasAlias(parts[0]) ? typeName = context.hasAlias(parts[0]) ?
context.getTypeNameFromAlias(parts[0]) : context.getTypeNameFromAlias(parts[0]) :
context.getActiveTypeName(); context.getActiveTypeName();
qualifiedName = getDefaultQualifiedNameForSinglePartName(context, parts[0]); qualifiedName = getDefaultQualifiedNameForSinglePartName(context, parts[0]);
attributeName = parts[0]; attributeName = parts[0];
} }
if(parts.length == 2) { if (parts.length == 2) {
boolean isAttrOfActiveType = lookup.hasAttribute(context, parts[0]); boolean isAttrOfActiveType = lookup.hasAttribute(context, parts[0]);
if(isAttrOfActiveType) { if (isAttrOfActiveType) {
attributeName = parts[0]; attributeName = parts[0];
} else { } else {
typeName = context.hasAlias(parts[0]) ? typeName = context.hasAlias(parts[0]) ?
context.getTypeNameFromAlias(parts[0]) : context.getTypeNameFromAlias(parts[0]) :
parts[0]; parts[0];
attributeName = parts[1]; attributeName = parts[1];
} }
...@@ -190,7 +200,7 @@ public class IdentifierHelper { ...@@ -190,7 +200,7 @@ public class IdentifierHelper {
private String getDefaultQualifiedNameForSinglePartName(GremlinQueryComposer.Context context, String s) { private String getDefaultQualifiedNameForSinglePartName(GremlinQueryComposer.Context context, String s) {
String qn = context.getTypeNameFromAlias(s); String qn = context.getTypeNameFromAlias(s);
if(StringUtils.isEmpty(qn) && SelectClauseComposer.isKeyword(s)) { if (StringUtils.isEmpty(qn) && SelectClauseComposer.isKeyword(s)) {
return s; return s;
} }
...@@ -198,22 +208,17 @@ public class IdentifierHelper { ...@@ -198,22 +208,17 @@ public class IdentifierHelper {
} }
private void setQualifiedName(Lookup lookup, GremlinQueryComposer.Context context, boolean isAttribute, String attrName) { private void setQualifiedName(Lookup lookup, GremlinQueryComposer.Context context, boolean isAttribute, String attrName) {
if(isAttribute) { if (isAttribute) {
qualifiedName = getQualifiedName(lookup, context, attrName); qualifiedName = getQualifiedName(lookup, context, attrName);
} }
} }
private String getQualifiedName(Lookup lookup, GremlinQueryComposer.Context context, String name) { private String getQualifiedName(Lookup lookup, GremlinQueryComposer.Context context, String name) {
try { return IdentifierHelper.getQualifiedName(lookup, context, name);
return lookup.getQualifiedName(context, name);
} catch (AtlasBaseException e) {
context.getErrorList().add(String.format("Error for %s.%s: %s", context.getActiveTypeName(), name, e.getMessage()));
return "";
}
} }
private void setIsDate(Lookup lookup, GremlinQueryComposer.Context context, boolean isPrimitive, String attrName) { private void setIsDate(Lookup lookup, GremlinQueryComposer.Context context, boolean isPrimitive, String attrName) {
if(isPrimitive) { if (isPrimitive) {
isDate = lookup.isDate(context, attrName); isDate = lookup.isDate(context, attrName);
} }
} }
...@@ -246,7 +251,7 @@ public class IdentifierHelper { ...@@ -246,7 +251,7 @@ public class IdentifierHelper {
return typeName; return typeName;
} }
public boolean getIntroduceType() { public boolean isReferredType() {
return introduceType; return introduceType;
} }
...@@ -277,5 +282,6 @@ public class IdentifierHelper { ...@@ -277,5 +282,6 @@ public class IdentifierHelper {
public String getRaw() { public String getRaw() {
return raw; return raw;
} }
} }
} }
...@@ -21,9 +21,6 @@ package org.apache.atlas.query; ...@@ -21,9 +21,6 @@ package org.apache.atlas.query;
import org.apache.atlas.exception.AtlasBaseException; import org.apache.atlas.exception.AtlasBaseException;
import org.apache.atlas.type.AtlasType; import org.apache.atlas.type.AtlasType;
import java.util.Collection;
import java.util.List;
public interface Lookup { public interface Lookup {
AtlasType getType(String typeName) throws AtlasBaseException; AtlasType getType(String typeName) throws AtlasBaseException;
...@@ -39,7 +36,7 @@ public interface Lookup { ...@@ -39,7 +36,7 @@ public interface Lookup {
String getTypeAndSubTypes(GremlinQueryComposer.Context context); String getTypeAndSubTypes(GremlinQueryComposer.Context context);
boolean isTraitType(GremlinQueryComposer.Context context); boolean isTraitType(String s);
String getTypeFromEdge(GremlinQueryComposer.Context context, String item); String getTypeFromEdge(GremlinQueryComposer.Context context, String item);
......
...@@ -20,20 +20,27 @@ package org.apache.atlas.query; ...@@ -20,20 +20,27 @@ package org.apache.atlas.query;
import org.apache.atlas.exception.AtlasBaseException; import org.apache.atlas.exception.AtlasBaseException;
import org.apache.atlas.model.TypeCategory; import org.apache.atlas.model.TypeCategory;
import org.apache.atlas.model.instance.AtlasObjectId;
import org.apache.atlas.model.typedef.AtlasBaseTypeDef; import org.apache.atlas.model.typedef.AtlasBaseTypeDef;
import org.apache.atlas.repository.Constants;
import org.apache.atlas.type.*; import org.apache.atlas.type.*;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import java.util.ArrayList; import java.util.Arrays;
import java.util.List; import java.util.HashSet;
import java.util.Set;
class RegistryBasedLookup implements Lookup { class RegistryBasedLookup implements Lookup {
private final List<String> errorList; private static final Set<String> SYSTEM_ATTRIBUTES = new HashSet<>(
Arrays.asList(Constants.GUID_PROPERTY_KEY,
Constants.MODIFIED_BY_KEY,
Constants.CREATED_BY_KEY,
Constants.STATE_PROPERTY_KEY,
Constants.TIMESTAMP_PROPERTY_KEY,
Constants.MODIFICATION_TIMESTAMP_PROPERTY_KEY));
private final AtlasTypeRegistry typeRegistry; private final AtlasTypeRegistry typeRegistry;
public RegistryBasedLookup(AtlasTypeRegistry typeRegistry) { public RegistryBasedLookup(AtlasTypeRegistry typeRegistry) {
this.errorList = new ArrayList<>();
this.typeRegistry = typeRegistry; this.typeRegistry = typeRegistry;
} }
...@@ -49,7 +56,15 @@ class RegistryBasedLookup implements Lookup { ...@@ -49,7 +56,15 @@ class RegistryBasedLookup implements Lookup {
return ""; return "";
} }
return et.getQualifiedAttributeName(name); if(isSystemAttribute(name)) {
return name;
} else {
return et.getQualifiedAttributeName(name);
}
}
private boolean isSystemAttribute(String s) {
return SYSTEM_ATTRIBUTES.contains(s);
} }
@Override @Override
...@@ -59,6 +74,10 @@ class RegistryBasedLookup implements Lookup { ...@@ -59,6 +74,10 @@ class RegistryBasedLookup implements Lookup {
return false; return false;
} }
if(isSystemAttribute(attributeName)) {
return true;
}
AtlasType at = et.getAttributeType(attributeName); AtlasType at = et.getAttributeType(attributeName);
if(at == null) { if(at == null) {
return false; return false;
...@@ -97,7 +116,8 @@ class RegistryBasedLookup implements Lookup { ...@@ -97,7 +116,8 @@ class RegistryBasedLookup implements Lookup {
@Override @Override
public boolean hasAttribute(GremlinQueryComposer.Context context, String typeName) { public boolean hasAttribute(GremlinQueryComposer.Context context, String typeName) {
return (context.getActiveEntityType() != null) && context.getActiveEntityType().getAttribute(typeName) != null; return (context.getActiveEntityType() != null) &&
(isSystemAttribute(typeName) || context.getActiveEntityType().getAttribute(typeName) != null);
} }
@Override @Override
...@@ -123,9 +143,19 @@ class RegistryBasedLookup implements Lookup { ...@@ -123,9 +143,19 @@ class RegistryBasedLookup implements Lookup {
} }
@Override @Override
public boolean isTraitType(GremlinQueryComposer.Context context) { public boolean isTraitType(String typeName) {
return (context.getActiveType() != null && AtlasType t = null;
context.getActiveType().getTypeCategory() == TypeCategory.CLASSIFICATION); try {
t = typeRegistry.getType(typeName);
} catch (AtlasBaseException e) {
return false;
}
return isTraitType(t);
}
private boolean isTraitType(AtlasType t) {
return (t != null && t.getTypeCategory() == TypeCategory.CLASSIFICATION);
} }
@Override @Override
......
...@@ -41,9 +41,18 @@ class SelectClauseComposer { ...@@ -41,9 +41,18 @@ class SelectClauseComposer {
private int maxIdx = -1; private int maxIdx = -1;
private int minIdx = -1; private int minIdx = -1;
private int aggCount = 0; private int aggCount = 0;
private int introducedTypesCount = 0;
private int primitiveTypeCount = 0;
public SelectClauseComposer() {} public SelectClauseComposer() {}
public static boolean isKeyword(String s) {
return COUNT_STR.equals(s) ||
MIN_STR.equals(s) ||
MAX_STR.equals(s) ||
SUM_STR.equals(s);
}
public String[] getItems() { public String[] getItems() {
return items; return items;
} }
...@@ -73,13 +82,6 @@ class SelectClauseComposer { ...@@ -73,13 +82,6 @@ class SelectClauseComposer {
return ret; return ret;
} }
public static boolean isKeyword(String s) {
return COUNT_STR.equals(s) ||
MIN_STR.equals(s) ||
MAX_STR.equals(s) ||
SUM_STR.equals(s);
}
public String[] getAttributes() { public String[] getAttributes() {
return attributes; return attributes;
} }
...@@ -164,7 +166,7 @@ class SelectClauseComposer { ...@@ -164,7 +166,7 @@ class SelectClauseComposer {
return assign(items[i], inline.get(s, clause.get(p1, p1))); return assign(items[i], inline.get(s, clause.get(p1, p1)));
} }
private int getCountIdx() { public int getCountIdx() {
return countIdx; return countIdx;
} }
...@@ -173,7 +175,7 @@ class SelectClauseComposer { ...@@ -173,7 +175,7 @@ class SelectClauseComposer {
aggCount++; aggCount++;
} }
private int getSumIdx() { public int getSumIdx() {
return sumIdx; return sumIdx;
} }
...@@ -182,7 +184,7 @@ class SelectClauseComposer { ...@@ -182,7 +184,7 @@ class SelectClauseComposer {
aggCount++; aggCount++;
} }
private int getMaxIdx() { public int getMaxIdx() {
return maxIdx; return maxIdx;
} }
...@@ -191,7 +193,7 @@ class SelectClauseComposer { ...@@ -191,7 +193,7 @@ class SelectClauseComposer {
aggCount++; aggCount++;
} }
private int getMinIdx() { public int getMinIdx() {
return minIdx; return minIdx;
} }
...@@ -207,4 +209,32 @@ class SelectClauseComposer { ...@@ -207,4 +209,32 @@ class SelectClauseComposer {
.forEach(joiner::add); .forEach(joiner::add);
return joiner.toString(); return joiner.toString();
} }
public boolean isAggregatorWithArgument(int i) {
return i == getMaxIdx() || i == getMinIdx() || i == getSumIdx();
}
public void incrementTypesIntroduced() {
introducedTypesCount++;
}
public int getIntroducedTypesCount() {
return introducedTypesCount;
}
public void incrementPrimitiveType() {
primitiveTypeCount++;
}
public boolean hasMultipleReferredTypes() {
return getIntroducedTypesCount() > 1;
}
public boolean hasMixedAttributes() {
return getIntroducedTypesCount() > 0 && getPrimitiveTypeCount() > 0;
}
private int getPrimitiveTypeCount() {
return primitiveTypeCount;
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment