diff --git a/build.gradle b/build.gradle index f64c7edbdc..02ea4c9871 100644 --- a/build.gradle +++ b/build.gradle @@ -232,10 +232,19 @@ configurations { check.dependsOn jacocoTestReport // TODO: fix code style in main and test source code +subprojects { + apply plugin: 'checkstyle' + checkstyle { + configFile rootProject.file("config/checkstyle/google_checks.xml") + toolVersion "8.20" + configProperties = [ + "org.checkstyle.google.suppressionfilter.config": rootProject.file("config/checkstyle/suppressions.xml")] + ignoreFailures = false + } +} checkstyle { configFile file("config/checkstyle/checkstyle.xml") } - checkstyleMain.ignoreFailures = false checkstyleTest.ignoreFailures = true diff --git a/common/build.gradle b/common/build.gradle index 59ba428729..0849fae080 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -9,7 +9,7 @@ repositories { dependencies { compile "org.antlr:antlr4-runtime:4.7.1" - compile group: 'com.google.guava', name: 'guava', version:'23.0' + compile group: 'com.google.guava', name: 'guava', version: '23.0' testCompile group: 'junit', name: 'junit', version: '4.12' } diff --git a/common/src/main/java/com/amazon/opendistroforelasticsearch/sql/common/antlr/CaseInsensitiveCharStream.java b/common/src/main/java/com/amazon/opendistroforelasticsearch/sql/common/antlr/CaseInsensitiveCharStream.java index 7ab5a15ac0..f251076d6c 100644 --- a/common/src/main/java/com/amazon/opendistroforelasticsearch/sql/common/antlr/CaseInsensitiveCharStream.java +++ b/common/src/main/java/com/amazon/opendistroforelasticsearch/sql/common/antlr/CaseInsensitiveCharStream.java @@ -20,63 +20,64 @@ import org.antlr.v4.runtime.misc.Interval; /** - * Custom stream to convert character to upper case for case insensitive grammar before sending to lexer. + * Custom stream to convert character to upper case for case insensitive grammar before sending to + * lexer. */ public class CaseInsensitiveCharStream implements CharStream { - /** Character stream */ - private final CharStream charStream; + /** Character stream. */ + private final CharStream charStream; - public CaseInsensitiveCharStream(String sql) { - this.charStream = CharStreams.fromString(sql); - } + public CaseInsensitiveCharStream(String sql) { + this.charStream = CharStreams.fromString(sql); + } - @Override - public String getText(Interval interval) { - return charStream.getText(interval); - } + @Override + public String getText(Interval interval) { + return charStream.getText(interval); + } - @Override - public void consume() { - charStream.consume(); - } + @Override + public void consume() { + charStream.consume(); + } - @Override - public int LA(int i) { - int c = charStream.LA(i); - if (c <= 0) { - return c; - } - return Character.toUpperCase(c); + @Override + public int LA(int i) { + int c = charStream.LA(i); + if (c <= 0) { + return c; } + return Character.toUpperCase(c); + } - @Override - public int mark() { - return charStream.mark(); - } + @Override + public int mark() { + return charStream.mark(); + } - @Override - public void release(int marker) { - charStream.release(marker); - } + @Override + public void release(int marker) { + charStream.release(marker); + } - @Override - public int index() { - return charStream.index(); - } + @Override + public int index() { + return charStream.index(); + } - @Override - public void seek(int index) { - charStream.seek(index); - } + @Override + public void seek(int index) { + charStream.seek(index); + } - @Override - public int size() { - return charStream.size(); - } + @Override + public int size() { + return charStream.size(); + } - @Override - public String getSourceName() { - return charStream.getSourceName(); - } + @Override + public String getSourceName() { + return charStream.getSourceName(); + } } diff --git a/common/src/main/java/com/amazon/opendistroforelasticsearch/sql/common/antlr/SyntaxAnalysisErrorListener.java b/common/src/main/java/com/amazon/opendistroforelasticsearch/sql/common/antlr/SyntaxAnalysisErrorListener.java index 6f7c8a5d1a..8bd7731ab0 100644 --- a/common/src/main/java/com/amazon/opendistroforelasticsearch/sql/common/antlr/SyntaxAnalysisErrorListener.java +++ b/common/src/main/java/com/amazon/opendistroforelasticsearch/sql/common/antlr/SyntaxAnalysisErrorListener.java @@ -15,6 +15,7 @@ package com.amazon.opendistroforelasticsearch.sql.common.antlr; +import java.util.Locale; import org.antlr.v4.runtime.BaseErrorListener; import org.antlr.v4.runtime.CommonTokenStream; import org.antlr.v4.runtime.RecognitionException; @@ -22,53 +23,55 @@ import org.antlr.v4.runtime.Token; import org.antlr.v4.runtime.misc.IntervalSet; -import java.util.Locale; - /** - * Syntax analysis error listener that handles any syntax error by throwing exception with useful information. + * Syntax analysis error listener that handles any syntax error by throwing exception with useful + * information. */ public class SyntaxAnalysisErrorListener extends BaseErrorListener { - @Override - public void syntaxError(Recognizer recognizer, Object offendingSymbol, - int line, int charPositionInLine, String msg, - RecognitionException e) { + @Override + public void syntaxError( + Recognizer recognizer, + Object offendingSymbol, + int line, + int charPositionInLine, + String msg, + RecognitionException e) { - CommonTokenStream tokens = (CommonTokenStream) recognizer.getInputStream(); - Token offendingToken = (Token) offendingSymbol; - String query = tokens.getText(); + CommonTokenStream tokens = (CommonTokenStream) recognizer.getInputStream(); + Token offendingToken = (Token) offendingSymbol; + String query = tokens.getText(); - throw new RuntimeException( - String.format(Locale.ROOT, - "Failed to parse query due to offending symbol [%s] at: '%s' <--- HERE... More details: %s", - getOffendingText(offendingToken), - truncateQueryAtOffendingToken(query, offendingToken), - getDetails(recognizer, msg, e) - ) - ); - } + throw new RuntimeException( + String.format( + Locale.ROOT, + "Failed to parse query due to offending symbol [%s] " + + "at: '%s' <--- HERE... More details: %s", + getOffendingText(offendingToken), + truncateQueryAtOffendingToken(query, offendingToken), + getDetails(recognizer, msg, e))); + } - private String getOffendingText(Token offendingToken) { - return offendingToken.getText(); - } + private String getOffendingText(Token offendingToken) { + return offendingToken.getText(); + } - private String truncateQueryAtOffendingToken(String query, Token offendingToken) { - return query.substring(0, offendingToken.getStopIndex() + 1); - } + private String truncateQueryAtOffendingToken(String query, Token offendingToken) { + return query.substring(0, offendingToken.getStopIndex() + 1); + } - /** - * As official JavaDoc says, e=null means parser was able to recover from the error. - * In other words, "msg" argument includes the information we want. - */ - private String getDetails(Recognizer recognizer, String msg, RecognitionException e) { - String details; - if (e == null) { - details = msg; - } else { - IntervalSet followSet = e.getExpectedTokens(); - details = "Expecting tokens in " + followSet.toString(recognizer.getVocabulary()); - } - return details; + /** + * As official JavaDoc says, e=null means parser was able to recover from the error. In other + * words, "msg" argument includes the information we want. + */ + private String getDetails(Recognizer recognizer, String msg, RecognitionException e) { + String details; + if (e == null) { + details = msg; + } else { + IntervalSet followSet = e.getExpectedTokens(); + details = "Expecting tokens in " + followSet.toString(recognizer.getVocabulary()); } - + return details; + } } diff --git a/common/src/main/java/com/amazon/opendistroforelasticsearch/sql/common/response/ResponseListener.java b/common/src/main/java/com/amazon/opendistroforelasticsearch/sql/common/response/ResponseListener.java index 2ebbdd0fac..e786de0bf4 100644 --- a/common/src/main/java/com/amazon/opendistroforelasticsearch/sql/common/response/ResponseListener.java +++ b/common/src/main/java/com/amazon/opendistroforelasticsearch/sql/common/response/ResponseListener.java @@ -17,23 +17,24 @@ package com.amazon.opendistroforelasticsearch.sql.common.response; /** - * Response listener for response post-processing callback. - * This is necessary because execution engine may schedule and execute in different thread. + * Response listener for response post-processing callback. This is necessary because execution + * engine may schedule and execute in different thread. * - * @param response class + * @param response class */ -public interface ResponseListener { +public interface ResponseListener { - /** - * Handle successful response. - * @param response successful response - */ - void onResponse(Response response); - - /** - * Handle failed response. - * @param e exception captured - */ - void onFailure(Exception e); + /** + * Handle successful response. + * + * @param response successful response + */ + void onResponse(R response); + /** + * Handle failed response. + * + * @param e exception captured + */ + void onFailure(Exception e); } diff --git a/common/src/main/java/com/amazon/opendistroforelasticsearch/sql/common/utils/StringUtils.java b/common/src/main/java/com/amazon/opendistroforelasticsearch/sql/common/utils/StringUtils.java index 75d590878e..1df4b26758 100644 --- a/common/src/main/java/com/amazon/opendistroforelasticsearch/sql/common/utils/StringUtils.java +++ b/common/src/main/java/com/amazon/opendistroforelasticsearch/sql/common/utils/StringUtils.java @@ -18,27 +18,35 @@ import com.google.common.base.Strings; public class StringUtils { - /** - * @param text string - * @param mark quotation mark - * @return An unquoted string whose outer pair of (single/double/back-tick) quotes have been removed - */ - public static String unquoteIdentifier(String text, String mark) { - if (isQuoted(text, mark)) { - return text.substring(mark.length(), text.length() - mark.length()); - } - return text; + /** + * Unquote Identifier with mark. + * @param text string + * @param mark quotation mark + * @return An unquoted string whose outer pair of (single/double/back-tick) quotes have been + * removed + */ + public static String unquoteIdentifier(String text, String mark) { + if (isQuoted(text, mark)) { + return text.substring(mark.length(), text.length() - mark.length()); } + return text; + } - public static String unquoteIdentifier(String text) { - if (isQuoted(text, "\"") || isQuoted(text, "'") || isQuoted(text, "`")) { - return text.substring(1, text.length() - 1); - } else { - return text; - } + /** + * Unquote Identifier which has " or ' or ` as mark. + * @param text string + * @return An unquoted string whose outer pair of (single/double/back-tick) quotes have been + * removed + */ + public static String unquoteIdentifier(String text) { + if (isQuoted(text, "\"") || isQuoted(text, "'") || isQuoted(text, "`")) { + return text.substring(1, text.length() - 1); + } else { + return text; } + } - private static boolean isQuoted(String text, String mark) { - return !Strings.isNullOrEmpty(text) && text.startsWith(mark) && text.endsWith(mark); - } + private static boolean isQuoted(String text, String mark) { + return !Strings.isNullOrEmpty(text) && text.startsWith(mark) && text.endsWith(mark); + } } diff --git a/config/checkstyle/google_checks.xml b/config/checkstyle/google_checks.xml new file mode 100644 index 0000000000..4dfcaf39cb --- /dev/null +++ b/config/checkstyle/google_checks.xml @@ -0,0 +1,264 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/checkstyle/suppressions.xml b/config/checkstyle/suppressions.xml index ec4edb849d..15f02089e2 100644 --- a/config/checkstyle/suppressions.xml +++ b/config/checkstyle/suppressions.xml @@ -6,5 +6,6 @@ + \ No newline at end of file diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/analysis/AnalysisContext.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/analysis/AnalysisContext.java index f9d51b32c8..b04c88ef2d 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/analysis/AnalysisContext.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/analysis/AnalysisContext.java @@ -21,41 +21,45 @@ * The context used for Analyzer. */ public class AnalysisContext { - /** Environment stack for symbol scope management */ - private TypeEnvironment environment; - - public AnalysisContext() { - this.environment = new TypeEnvironment(null); - } - - public AnalysisContext(TypeEnvironment environment) { - this.environment = environment; - } - - /** - * Push a new environment - */ - public void push() { - environment = new TypeEnvironment(environment); - } - - /** - * Return current environment - * @return current environment - */ - public TypeEnvironment peek() { - return environment; - } - - /** - * Pop up current environment from environment chain - * @return current environment (before pop) - */ - public TypeEnvironment pop() { - Objects.requireNonNull(environment, "Fail to pop context due to no environment present"); - - TypeEnvironment curEnv = environment; - environment = curEnv.getParent(); - return curEnv; - } + /** + * Environment stack for symbol scope management. + */ + private TypeEnvironment environment; + + public AnalysisContext() { + this.environment = new TypeEnvironment(null); + } + + public AnalysisContext(TypeEnvironment environment) { + this.environment = environment; + } + + /** + * Push a new environment. + */ + public void push() { + environment = new TypeEnvironment(environment); + } + + /** + * Return current environment. + * + * @return current environment + */ + public TypeEnvironment peek() { + return environment; + } + + /** + * Pop up current environment from environment chain. + * + * @return current environment (before pop) + */ + public TypeEnvironment pop() { + Objects.requireNonNull(environment, "Fail to pop context due to no environment present"); + + TypeEnvironment curEnv = environment; + environment = curEnv.getParent(); + return curEnv; + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/analysis/Analyzer.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/analysis/Analyzer.java index 7b283f57b2..23afac1c4b 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/analysis/Analyzer.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/analysis/Analyzer.java @@ -61,7 +61,7 @@ /** * Analyze the {@link UnresolvedPlan} in the {@link AnalysisContext} to construct the {@link - * LogicalPlan} + * LogicalPlan}. */ @RequiredArgsConstructor public class Analyzer extends AbstractNodeVisitor { @@ -88,7 +88,9 @@ public LogicalPlan visitFilter(Filter node, AnalysisContext context) { return new LogicalFilter(child, condition); } - /** Build {@link LogicalRename} */ + /** + * Build {@link LogicalRename}. + */ @Override public LogicalPlan visitRename(Rename node, AnalysisContext context) { LogicalPlan child = node.getChild().get(0).accept(this, context); @@ -111,18 +113,20 @@ public LogicalPlan visitRename(Rename node, AnalysisContext context) { return new LogicalRename(child, renameMapBuilder.build()); } - /** Build {@link LogicalAggregation} */ + /** + * Build {@link LogicalAggregation}. + */ @Override public LogicalPlan visitAggregation(Aggregation node, AnalysisContext context) { LogicalPlan child = node.getChild().get(0).accept(this, context); ImmutableList.Builder aggregatorBuilder = new ImmutableList.Builder<>(); - for (UnresolvedExpression uExpr : node.getAggExprList()) { - aggregatorBuilder.add((Aggregator) expressionAnalyzer.analyze(uExpr, context)); + for (UnresolvedExpression expr : node.getAggExprList()) { + aggregatorBuilder.add((Aggregator) expressionAnalyzer.analyze(expr, context)); } ImmutableList.Builder groupbyBuilder = new ImmutableList.Builder<>(); - for (UnresolvedExpression uExpr : node.getGroupExprList()) { - groupbyBuilder.add(expressionAnalyzer.analyze(uExpr, context)); + for (UnresolvedExpression expr : node.getGroupExprList()) { + groupbyBuilder.add(expressionAnalyzer.analyze(expr, context)); } return new LogicalAggregation(child, aggregatorBuilder.build(), groupbyBuilder.build()); } @@ -155,7 +159,9 @@ public LogicalPlan visitProject(Project node, AnalysisContext context) { return new LogicalProject(child, referenceExpressions); } - /** Build {@link LogicalEval} */ + /** + * Build {@link LogicalEval}. + */ @Override public LogicalPlan visitEval(Eval node, AnalysisContext context) { LogicalPlan child = node.getChild().get(0).accept(this, context); @@ -172,7 +178,9 @@ public LogicalPlan visitEval(Eval node, AnalysisContext context) { return new LogicalEval(child, expressionsBuilder.build()); } - /** Build {@link LogicalSort} */ + /** + * Build {@link LogicalSort}. + */ @Override public LogicalPlan visitSort(Sort node, AnalysisContext context) { LogicalPlan child = node.getChild().get(0).accept(this, context); @@ -193,7 +201,9 @@ public LogicalPlan visitSort(Sort node, AnalysisContext context) { return new LogicalSort(child, count, sortList); } - /** Build {@link LogicalDedupe} */ + /** + * Build {@link LogicalDedupe}. + */ @Override public LogicalPlan visitDedupe(Dedupe node, AnalysisContext context) { LogicalPlan child = node.getChild().get(0).accept(this, context); diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/analysis/ExpressionAnalyzer.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/analysis/ExpressionAnalyzer.java index bc0146fc22..6f724a9a54 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/analysis/ExpressionAnalyzer.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/analysis/ExpressionAnalyzer.java @@ -43,7 +43,7 @@ /** * Analyze the {@link UnresolvedExpression} in the {@link AnalysisContext} to construct the {@link - * Expression} + * Expression}. */ public class ExpressionAnalyzer extends AbstractNodeVisitor { private final BuiltinFunctionRepository repository; diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/analysis/TypeEnvironment.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/analysis/TypeEnvironment.java index cb05efb1a0..dac91e4a25 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/analysis/TypeEnvironment.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/analysis/TypeEnvironment.java @@ -23,63 +23,62 @@ import com.amazon.opendistroforelasticsearch.sql.expression.Expression; import com.amazon.opendistroforelasticsearch.sql.expression.ReferenceExpression; import com.amazon.opendistroforelasticsearch.sql.expression.env.Environment; -import lombok.Getter; - import java.util.Optional; +import lombok.Getter; /** * The definition of Type Environment. */ public class TypeEnvironment implements Environment { - @Getter - private final TypeEnvironment parent; - private final SymbolTable symbolTable; + @Getter + private final TypeEnvironment parent; + private final SymbolTable symbolTable; - public TypeEnvironment(TypeEnvironment parent) { - this.parent = parent; - this.symbolTable = new SymbolTable(); - } + public TypeEnvironment(TypeEnvironment parent) { + this.parent = parent; + this.symbolTable = new SymbolTable(); + } - public TypeEnvironment(TypeEnvironment parent, SymbolTable symbolTable) { - this.parent = parent; - this.symbolTable = symbolTable; - } + public TypeEnvironment(TypeEnvironment parent, SymbolTable symbolTable) { + this.parent = parent; + this.symbolTable = symbolTable; + } - /** - * Resolve the {@link Expression} from environment. - * - * @param var expression - * @return resolved {@link ExprType} - */ - @Override - public ExprType resolve(Expression var) { - if (var instanceof ReferenceExpression) { - ReferenceExpression ref = (ReferenceExpression) var; - for (TypeEnvironment cur = this; cur != null; cur = cur.parent) { - Optional typeOptional = cur.symbolTable.lookup(new Symbol(Namespace.FIELD_NAME, - ref.getAttr())); - if (typeOptional.isPresent()) { - return typeOptional.get(); - } - } + /** + * Resolve the {@link Expression} from environment. + * + * @param var expression + * @return resolved {@link ExprType} + */ + @Override + public ExprType resolve(Expression var) { + if (var instanceof ReferenceExpression) { + ReferenceExpression ref = (ReferenceExpression) var; + for (TypeEnvironment cur = this; cur != null; cur = cur.parent) { + Optional typeOptional = cur.symbolTable.lookup(new Symbol(Namespace.FIELD_NAME, + ref.getAttr())); + if (typeOptional.isPresent()) { + return typeOptional.get(); } - throw new SemanticCheckException(String.format("can't resolve expression %s in type env", var)); + } } + throw new SemanticCheckException(String.format("can't resolve expression %s in type env", var)); + } - /** - * Define symbol with the type - * - * @param var symbol to define - * @param type type - */ - public void define(Expression var, ExprType type) { - if (var instanceof ReferenceExpression) { - ReferenceExpression ref = (ReferenceExpression) var; - symbolTable.store(new Symbol(Namespace.FIELD_NAME, ref.getAttr()), type); - } else { - throw new IllegalArgumentException(String.format("only support define reference, unexpected expression %s" - , var)); - } + /** + * Define symbol with the type. + * + * @param var symbol to define + * @param type type + */ + public void define(Expression var, ExprType type) { + if (var instanceof ReferenceExpression) { + ReferenceExpression ref = (ReferenceExpression) var; + symbolTable.store(new Symbol(Namespace.FIELD_NAME, ref.getAttr()), type); + } else { + throw new IllegalArgumentException( + String.format("only support define reference, unexpected expression %s", var)); } + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/analysis/symbol/Namespace.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/analysis/symbol/Namespace.java index 79fd719f31..f7a17c5706 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/analysis/symbol/Namespace.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/analysis/symbol/Namespace.java @@ -16,17 +16,17 @@ package com.amazon.opendistroforelasticsearch.sql.analysis.symbol; /** - * Namespace of symbol to avoid naming conflict + * Namespace of symbol to avoid naming conflict. */ public enum Namespace { - FIELD_NAME("Field"), - FUNCTION_NAME("Function"); + FIELD_NAME("Field"), + FUNCTION_NAME("Function"); - private final String name; + private final String name; - Namespace(String name) { - this.name = name; - } + Namespace(String name) { + this.name = name; + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/analysis/symbol/Symbol.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/analysis/symbol/Symbol.java index e5a734b505..d36c1de481 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/analysis/symbol/Symbol.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/analysis/symbol/Symbol.java @@ -19,11 +19,11 @@ import lombok.RequiredArgsConstructor; /** - * Symbol in the scope + * Symbol in the scope. */ @Getter @RequiredArgsConstructor public class Symbol { - private final Namespace namespace; - private final String name; + private final Namespace namespace; + private final String name; } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/analysis/symbol/SymbolTable.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/analysis/symbol/SymbolTable.java index ea3daa18af..a646413383 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/analysis/symbol/SymbolTable.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/analysis/symbol/SymbolTable.java @@ -15,70 +15,76 @@ package com.amazon.opendistroforelasticsearch.sql.analysis.symbol; -import com.amazon.opendistroforelasticsearch.sql.data.model.ExprType; +import static java.util.Collections.emptyMap; +import static java.util.Collections.emptyNavigableMap; +import com.amazon.opendistroforelasticsearch.sql.data.model.ExprType; import java.util.EnumMap; import java.util.Map; import java.util.NavigableMap; import java.util.Optional; import java.util.TreeMap; -import static java.util.Collections.emptyMap; -import static java.util.Collections.emptyNavigableMap; - /** * Symbol table for symbol definition and resolution. */ public class SymbolTable { - /** Two-dimension hash table to manage symbols with type in different namespace */ - private Map> tableByNamespace = new EnumMap<>(Namespace.class); + /** + * Two-dimension hash table to manage symbols with type in different namespace. + */ + private Map> tableByNamespace = + new EnumMap<>(Namespace.class); - /** - * Store symbol with the type. Create new map for namespace for the first time. - * @param symbol symbol to define - * @param type symbol type - */ - public void store(Symbol symbol, ExprType type) { - tableByNamespace.computeIfAbsent( - symbol.getNamespace(), - ns -> new TreeMap<>() - ).put(symbol.getName(), type); - } + /** + * Store symbol with the type. Create new map for namespace for the first time. + * + * @param symbol symbol to define + * @param type symbol type + */ + public void store(Symbol symbol, ExprType type) { + tableByNamespace.computeIfAbsent( + symbol.getNamespace(), + ns -> new TreeMap<>() + ).put(symbol.getName(), type); + } - /** - * Look up symbol in the namespace map. - * @param symbol symbol to look up - * @return symbol type which is optional - */ - public Optional lookup(Symbol symbol) { - Map table = tableByNamespace.get(symbol.getNamespace()); - ExprType type = null; - if (table != null) { - type = table.get(symbol.getName()); - } - return Optional.ofNullable(type); + /** + * Look up symbol in the namespace map. + * + * @param symbol symbol to look up + * @return symbol type which is optional + */ + public Optional lookup(Symbol symbol) { + Map table = tableByNamespace.get(symbol.getNamespace()); + ExprType type = null; + if (table != null) { + type = table.get(symbol.getName()); } + return Optional.ofNullable(type); + } - /** - * Look up symbols by a prefix. - * @param prefix a symbol prefix - * @return symbols starting with the prefix - */ - public Map lookupByPrefix(Symbol prefix) { - NavigableMap table = tableByNamespace.get(prefix.getNamespace()); - if (table != null) { - return table.subMap(prefix.getName(), prefix.getName() + Character.MAX_VALUE); - } - return emptyMap(); + /** + * Look up symbols by a prefix. + * + * @param prefix a symbol prefix + * @return symbols starting with the prefix + */ + public Map lookupByPrefix(Symbol prefix) { + NavigableMap table = tableByNamespace.get(prefix.getNamespace()); + if (table != null) { + return table.subMap(prefix.getName(), prefix.getName() + Character.MAX_VALUE); } + return emptyMap(); + } - /** - * Check if namespace map in empty (none definition) - * @param namespace a namespace - * @return true for empty - */ - public boolean isEmpty(Namespace namespace) { - return tableByNamespace.getOrDefault(namespace, emptyNavigableMap()).isEmpty(); - } + /** + * Check if namespace map in empty (none definition). + * + * @param namespace a namespace + * @return true for empty + */ + public boolean isEmpty(Namespace namespace) { + return tableByNamespace.getOrDefault(namespace, emptyNavigableMap()).isEmpty(); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/AbstractNodeVisitor.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/AbstractNodeVisitor.java index fd32458892..7e3b161ec8 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/AbstractNodeVisitor.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/AbstractNodeVisitor.java @@ -40,13 +40,21 @@ import com.amazon.opendistroforelasticsearch.sql.ast.tree.Rename; import com.amazon.opendistroforelasticsearch.sql.ast.tree.Sort; -/** AST nodes visitor Defines the traverse path */ +/** + * AST nodes visitor Defines the traverse path. + */ public abstract class AbstractNodeVisitor { public T visit(Node node, C context) { return null; } + /** + * Visit child node. + * @param node {@link Node} + * @param context Context + * @return Return Type. + */ public T visitChildren(Node node, C context) { T result = defaultResult(); diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/Node.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/Node.java index c9774342f6..e4701e09fa 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/Node.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/Node.java @@ -20,17 +20,17 @@ import lombok.ToString; /** - * AST node + * AST node. */ @EqualsAndHashCode @ToString public abstract class Node { - public R accept(AbstractNodeVisitor visitor, C context) { - return visitor.visitChildren(this, context); - } + public R accept(AbstractNodeVisitor visitor, C context) { + return visitor.visitChildren(this, context); + } - public List getChild() { - return null; - } + public List getChild() { + return null; + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/dsl/AstDSL.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/dsl/AstDSL.java index 76c6990460..1e1cb911a2 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/dsl/AstDSL.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/dsl/AstDSL.java @@ -43,8 +43,12 @@ import com.amazon.opendistroforelasticsearch.sql.ast.tree.UnresolvedPlan; import java.util.Arrays; import java.util.List; +import lombok.experimental.UtilityClass; -/** Class of static methods to create specific node instances */ +/** + * Class of static methods to create specific node instances. + */ +@UtilityClass public class AstDSL { public static UnresolvedPlan filter(UnresolvedPlan input, UnresolvedExpression expression) { @@ -205,6 +209,9 @@ public static List defaultFieldsArgs() { return exprList(argument("exclude", booleanLiteral(false))); } + /** + * Default Stats Command Args. + */ public static List defaultStatsArgs() { return exprList( argument("partitions", intLiteral(1)), @@ -213,6 +220,9 @@ public static List defaultStatsArgs() { argument("dedupsplit", booleanLiteral(false))); } + /** + * Default Dedup Command Args. + */ public static List defaultDedupArgs() { return exprList( argument("number", intLiteral(1)), diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/AggregateFunction.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/AggregateFunction.java index 38b0466580..dac1445426 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/AggregateFunction.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/AggregateFunction.java @@ -23,35 +23,40 @@ import lombok.RequiredArgsConstructor; /** - * Expression node of aggregate functions - * Params include aggregate function name (AVG, SUM, MAX etc.) and the field to aggregate + * Expression node of aggregate functions. + * Params include aggregate function name (AVG, SUM, MAX etc.) and the field to aggregate. */ @Getter @EqualsAndHashCode(callSuper = false) @RequiredArgsConstructor public class AggregateFunction extends UnresolvedExpression { - private final String funcName; - private final UnresolvedExpression field; - private final List argList; + private final String funcName; + private final UnresolvedExpression field; + private final List argList; - public AggregateFunction(String funcName, UnresolvedExpression field) { - this.funcName = funcName; - this.field = field; - this.argList = Collections.emptyList(); - } + /** + * Constructor. + * @param funcName function name. + * @param field {@link UnresolvedExpression}. + */ + public AggregateFunction(String funcName, UnresolvedExpression field) { + this.funcName = funcName; + this.field = field; + this.argList = Collections.emptyList(); + } - @Override - public List getChild() { - return Collections.singletonList(field); - } + @Override + public List getChild() { + return Collections.singletonList(field); + } - @Override - public R accept(AbstractNodeVisitor nodeVisitor, C context) { - return nodeVisitor.visitAggregateFunction(this, context); - } + @Override + public R accept(AbstractNodeVisitor nodeVisitor, C context) { + return nodeVisitor.visitAggregateFunction(this, context); + } - @Override - public String toString() { - return String.format("%s(%s)", funcName, field); - } + @Override + public String toString() { + return String.format("%s(%s)", funcName, field); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/And.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/And.java index fbda17d1b4..6bab1bd33e 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/And.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/And.java @@ -24,23 +24,23 @@ import lombok.ToString; /** - * Expression node of logic AND + * Expression node of logic AND. */ @Getter @ToString @EqualsAndHashCode(callSuper = false) @RequiredArgsConstructor public class And extends UnresolvedExpression { - private final UnresolvedExpression left; - private final UnresolvedExpression right; + private final UnresolvedExpression left; + private final UnresolvedExpression right; - @Override - public List getChild() { - return Arrays.asList(left, right); - } + @Override + public List getChild() { + return Arrays.asList(left, right); + } - @Override - public R accept(AbstractNodeVisitor nodeVisitor, C context) { - return nodeVisitor.visitAnd(this, context); - } + @Override + public R accept(AbstractNodeVisitor nodeVisitor, C context) { + return nodeVisitor.visitAnd(this, context); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/Argument.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/Argument.java index 31da0acb44..7f16b16ece 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/Argument.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/Argument.java @@ -23,21 +23,25 @@ import lombok.RequiredArgsConstructor; import lombok.ToString; +/** + * Argument. + */ @Getter @ToString @RequiredArgsConstructor @EqualsAndHashCode(callSuper = false) public class Argument extends UnresolvedExpression { - private final String argName; - private final Literal value; - // private final DataType valueType; - @Override - public List getChild() { - return Arrays.asList(value); - } + private final String argName; + private final Literal value; + + // private final DataType valueType; + @Override + public List getChild() { + return Arrays.asList(value); + } - @Override - public R accept(AbstractNodeVisitor nodeVisitor, C context) { - return nodeVisitor.visitArgument(this, context); - } + @Override + public R accept(AbstractNodeVisitor nodeVisitor, C context) { + return nodeVisitor.visitArgument(this, context); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/AttributeList.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/AttributeList.java index 069d44d0a7..b659365834 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/AttributeList.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/AttributeList.java @@ -24,22 +24,22 @@ import lombok.ToString; /** - * Expression node that includes a list of Expression nodes + * Expression node that includes a list of Expression nodes. */ @ToString @EqualsAndHashCode(callSuper = false) @AllArgsConstructor public class AttributeList extends UnresolvedExpression { - @Getter - private List attrList; + @Getter + private List attrList; - @Override - public List getChild() { - return ImmutableList.copyOf(attrList); - } + @Override + public List getChild() { + return ImmutableList.copyOf(attrList); + } - @Override - public R accept(AbstractNodeVisitor nodeVisitor, C context) { - return nodeVisitor.visitAttributeList(this, context); - } + @Override + public R accept(AbstractNodeVisitor nodeVisitor, C context) { + return nodeVisitor.visitAttributeList(this, context); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/Compare.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/Compare.java index 5a3a4e42a3..5ba9383dc7 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/Compare.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/Compare.java @@ -28,16 +28,17 @@ @EqualsAndHashCode(callSuper = false) @RequiredArgsConstructor public class Compare extends UnresolvedExpression { - private final String operator; - private final UnresolvedExpression left; - private final UnresolvedExpression right; - @Override - public List getChild() { - return Arrays.asList(left, right); - } + private final String operator; + private final UnresolvedExpression left; + private final UnresolvedExpression right; - @Override - public R accept(AbstractNodeVisitor nodeVisitor, C context) { - return nodeVisitor.visitCompare(this, context); - } + @Override + public List getChild() { + return Arrays.asList(left, right); + } + + @Override + public R accept(AbstractNodeVisitor nodeVisitor, C context) { + return nodeVisitor.visitCompare(this, context); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/DataType.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/DataType.java index 683d1eb70a..51662e6c53 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/DataType.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/DataType.java @@ -16,11 +16,11 @@ package com.amazon.opendistroforelasticsearch.sql.ast.expression; public enum DataType { - TYPE_ERROR, - NULL, + TYPE_ERROR, + NULL, - INTEGER, - DOUBLE, - STRING, - BOOLEAN + INTEGER, + DOUBLE, + STRING, + BOOLEAN } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/EqualTo.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/EqualTo.java index faa95af8d3..5d745314f0 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/EqualTo.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/EqualTo.java @@ -24,24 +24,24 @@ import lombok.ToString; /** - * Expression node of binary operator or comparison relation EQUAL + * Expression node of binary operator or comparison relation EQUAL. */ @ToString @EqualsAndHashCode(callSuper = false) @AllArgsConstructor public class EqualTo extends UnresolvedExpression { - @Getter - private UnresolvedExpression left; - @Getter - private UnresolvedExpression right; + @Getter + private UnresolvedExpression left; + @Getter + private UnresolvedExpression right; - @Override - public List getChild() { - return Arrays.asList(left, right); - } + @Override + public List getChild() { + return Arrays.asList(left, right); + } - @Override - public R accept(AbstractNodeVisitor nodeVisitor, C context) { - return nodeVisitor.visitEqualTo(this, context); - } + @Override + public R accept(AbstractNodeVisitor nodeVisitor, C context) { + return nodeVisitor.visitEqualTo(this, context); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/Field.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/Field.java index 1825760459..c8152f280d 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/Field.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/Field.java @@ -29,33 +29,33 @@ @EqualsAndHashCode(callSuper = false) @AllArgsConstructor public class Field extends UnresolvedExpression { - private QualifiedName field; - private List fieldArgs = Collections.emptyList(); - - public Field(QualifiedName field) { - this.field = field; - } - - public Field(String field) { - this.field = new QualifiedName(field); - } - - public Field(String field, List fieldArgs) { - this.field = new QualifiedName(field); - this.fieldArgs = fieldArgs; - } - - public boolean hasArgument() { - return !fieldArgs.isEmpty(); - } - - @Override - public List getChild() { - return ImmutableList.of(this.field); - } - - @Override - public R accept(AbstractNodeVisitor nodeVisitor, C context) { - return nodeVisitor.visitField(this, context); - } + private QualifiedName field; + private List fieldArgs = Collections.emptyList(); + + public Field(QualifiedName field) { + this.field = field; + } + + public Field(String field) { + this.field = new QualifiedName(field); + } + + public Field(String field, List fieldArgs) { + this.field = new QualifiedName(field); + this.fieldArgs = fieldArgs; + } + + public boolean hasArgument() { + return !fieldArgs.isEmpty(); + } + + @Override + public List getChild() { + return ImmutableList.of(this.field); + } + + @Override + public R accept(AbstractNodeVisitor nodeVisitor, C context) { + return nodeVisitor.visitField(this, context); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/Function.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/Function.java index 42b01cc645..e4b12ea3a3 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/Function.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/Function.java @@ -24,7 +24,7 @@ import lombok.ToString; /** - * Expression node of scalar function + * Expression node of scalar function. * Params include function name (@funcName) and function arguments (@funcArgs) */ @Getter @@ -32,16 +32,16 @@ @EqualsAndHashCode(callSuper = false) @RequiredArgsConstructor public class Function extends UnresolvedExpression { - private final String funcName; - private final List funcArgs; + private final String funcName; + private final List funcArgs; - @Override - public List getChild() { - return ImmutableList.of(); - } + @Override + public List getChild() { + return ImmutableList.of(); + } - @Override - public R accept(AbstractNodeVisitor nodeVisitor, C context) { - return nodeVisitor.visitFunction(this, context); - } + @Override + public R accept(AbstractNodeVisitor nodeVisitor, C context) { + return nodeVisitor.visitFunction(this, context); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/In.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/In.java index 07343082fe..365787780b 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/In.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/In.java @@ -24,25 +24,26 @@ import lombok.ToString; /** - * Expression node of one-to-many mapping relation IN - * Params include the field expression and/or wildcard field expression, nested field expression (@field) - * And the values that the field is mapped to (@valueList) + * Expression node of one-to-many mapping relation IN. + * Params include the field expression and/or wildcard field expression, + * nested field expression (@field). + * And the values that the field is mapped to (@valueList). */ @Getter @ToString @EqualsAndHashCode(callSuper = false) @RequiredArgsConstructor public class In extends UnresolvedExpression { - private final UnresolvedExpression field; - private final List valueList; + private final UnresolvedExpression field; + private final List valueList; - @Override - public List getChild() { - return Arrays.asList(field); - } + @Override + public List getChild() { + return Arrays.asList(field); + } - @Override - public R accept(AbstractNodeVisitor nodeVisitor, C context) { - return nodeVisitor.visitIn(this, context); - } + @Override + public R accept(AbstractNodeVisitor nodeVisitor, C context) { + return nodeVisitor.visitIn(this, context); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/Let.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/Let.java index 68d3862ee1..c4109e8b13 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/Let.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/Let.java @@ -23,7 +23,9 @@ import lombok.RequiredArgsConstructor; import lombok.ToString; -/** Represent the assign operation. e.g. velocity = distance/speed. */ +/** + * Represent the assign operation. e.g. velocity = distance/speed. + */ @Getter @ToString @EqualsAndHashCode(callSuper = false) diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/Literal.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/Literal.java index 884f0642f0..5a0f60175c 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/Literal.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/Literal.java @@ -25,7 +25,8 @@ /** * Expression node of literal type - * Params include literal value (@value) and literal data type (@type) which can be selected from {@link DataType} + * Params include literal value (@value) and + * literal data type (@type) which can be selected from {@link DataType}. */ @Getter @ToString @@ -33,16 +34,16 @@ @RequiredArgsConstructor public class Literal extends UnresolvedExpression { - private final Object value; - private final DataType type; + private final Object value; + private final DataType type; - @Override - public List getChild() { - return ImmutableList.of(); - } + @Override + public List getChild() { + return ImmutableList.of(); + } - @Override - public R accept(AbstractNodeVisitor nodeVisitor, C context) { - return nodeVisitor.visitLiteral(this, context); - } + @Override + public R accept(AbstractNodeVisitor nodeVisitor, C context) { + return nodeVisitor.visitLiteral(this, context); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/Map.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/Map.java index bca06f6f54..6fe1f307c5 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/Map.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/Map.java @@ -24,23 +24,23 @@ import lombok.ToString; /** - * Expression node of one-to-one mapping relation + * Expression node of one-to-one mapping relation. */ @Getter @ToString @EqualsAndHashCode(callSuper = false) @RequiredArgsConstructor public class Map extends UnresolvedExpression { - private final UnresolvedExpression origin; - private final UnresolvedExpression target; + private final UnresolvedExpression origin; + private final UnresolvedExpression target; - @Override - public List getChild() { - return Arrays.asList(origin, target); - } + @Override + public List getChild() { + return Arrays.asList(origin, target); + } - @Override - public R accept(AbstractNodeVisitor nodeVisitor, C context) { - return nodeVisitor.visitMap(this, context); - } + @Override + public R accept(AbstractNodeVisitor nodeVisitor, C context) { + return nodeVisitor.visitMap(this, context); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/Not.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/Not.java index c294e86e71..1597b4fe55 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/Not.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/Not.java @@ -24,22 +24,22 @@ import lombok.ToString; /** - * Expression node of the logic NOT + * Expression node of the logic NOT. */ @Getter @ToString @EqualsAndHashCode(callSuper = false) @RequiredArgsConstructor public class Not extends UnresolvedExpression { - private final UnresolvedExpression expression; + private final UnresolvedExpression expression; - @Override - public List getChild() { - return Arrays.asList(expression); - } + @Override + public List getChild() { + return Arrays.asList(expression); + } - @Override - public R accept(AbstractNodeVisitor nodeVisitor, C context) { - return nodeVisitor.visitNot(this, context); - } + @Override + public R accept(AbstractNodeVisitor nodeVisitor, C context) { + return nodeVisitor.visitNot(this, context); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/Or.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/Or.java index cfe6c3df91..8ed108f591 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/Or.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/Or.java @@ -24,23 +24,23 @@ import lombok.ToString; /** - * Expression node of the logic OR + * Expression node of the logic OR. */ @Getter @ToString @EqualsAndHashCode(callSuper = false) @RequiredArgsConstructor public class Or extends UnresolvedExpression { - private final UnresolvedExpression left; - private final UnresolvedExpression right; + private final UnresolvedExpression left; + private final UnresolvedExpression right; - @Override - public List getChild() { - return Arrays.asList(left, right); - } + @Override + public List getChild() { + return Arrays.asList(left, right); + } - @Override - public R accept(AbstractNodeVisitor nodeVisitor, C context) { - return nodeVisitor.visitOr(this, context); - } + @Override + public R accept(AbstractNodeVisitor nodeVisitor, C context) { + return nodeVisitor.visitOr(this, context); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/QualifiedName.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/QualifiedName.java index cf4d656f84..3d1e35ff06 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/QualifiedName.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/QualifiedName.java @@ -15,6 +15,9 @@ package com.amazon.opendistroforelasticsearch.sql.ast.expression; +import static java.util.Objects.requireNonNull; +import static java.util.stream.Collectors.toList; + import com.amazon.opendistroforelasticsearch.sql.ast.AbstractNodeVisitor; import com.google.common.collect.ImmutableList; import java.util.ArrayList; @@ -26,60 +29,66 @@ import lombok.EqualsAndHashCode; import lombok.Getter; -import static java.util.Objects.requireNonNull; -import static java.util.stream.Collectors.toList; - @Getter @EqualsAndHashCode(callSuper = false) public class QualifiedName extends UnresolvedExpression { - private final List parts; + private final List parts; - public QualifiedName(String name) { - this.parts = Collections.singletonList(name); - } + public QualifiedName(String name) { + this.parts = Collections.singletonList(name); + } - public QualifiedName(Iterable parts) { - List partsList = StreamSupport.stream(parts.spliterator(), false).collect(toList()); - if (partsList.isEmpty()) { - throw new IllegalArgumentException("parts is empty"); - } - this.parts = partsList; + /** + * QualifiedName Constructor. + */ + public QualifiedName(Iterable parts) { + List partsList = StreamSupport.stream(parts.spliterator(), false).collect(toList()); + if (partsList.isEmpty()) { + throw new IllegalArgumentException("parts is empty"); } + this.parts = partsList; + } - public static QualifiedName of(String first, String... rest) { - requireNonNull(first); - ArrayList parts = new ArrayList<>(); - parts.add(first); - parts.addAll(Arrays.asList(rest)); - return new QualifiedName(parts); - } + /** + * Construct {@link QualifiedName} from list of string. + */ + public static QualifiedName of(String first, String... rest) { + requireNonNull(first); + ArrayList parts = new ArrayList<>(); + parts.add(first); + parts.addAll(Arrays.asList(rest)); + return new QualifiedName(parts); + } - private static QualifiedName of(Iterable parts) { - return new QualifiedName(parts); - } + private static QualifiedName of(Iterable parts) { + return new QualifiedName(parts); + } - public Optional getPrefix() { - if (parts.size() == 1) { - return Optional.empty(); - } - return Optional.of(QualifiedName.of(parts.subList(0, parts.size() - 1))); + /** + * Get Prefix of {@link QualifiedName}. + */ + public Optional getPrefix() { + if (parts.size() == 1) { + return Optional.empty(); } + return Optional.of(QualifiedName.of(parts.subList(0, parts.size() - 1))); + } - public String getSuffix() { - return parts.get(parts.size() - 1); - } + public String getSuffix() { + return parts.get(parts.size() - 1); + } - public String toString() { - return String.join(".", this.parts); - } + public String toString() { + return String.join(".", this.parts); + } - @Override - public List getChild() { - return ImmutableList.of(); - } + @Override + public List getChild() { + return ImmutableList.of(); + } - @Override - public R accept(AbstractNodeVisitor nodeVisitor, C context) { - return nodeVisitor.visitQualifiedName(this, context); - } + @Override + public R accept(AbstractNodeVisitor nodeVisitor, C context) { + return nodeVisitor.visitQualifiedName(this, context); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/UnresolvedAttribute.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/UnresolvedAttribute.java index 9c2450f5ca..a08e762e15 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/UnresolvedAttribute.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/UnresolvedAttribute.java @@ -24,7 +24,8 @@ import lombok.ToString; /** - * Expression node, representing the syntax that is not resolved to any other expression nodes yet but non-negligible + * Expression node, representing the syntax that is not resolved to + * any other expression nodes yet but non-negligible * This expression is often created as the index name, field name etc. */ @ToString @@ -32,15 +33,15 @@ @RequiredArgsConstructor @Getter public class UnresolvedAttribute extends UnresolvedExpression { - private final String attr; + private final String attr; - @Override - public List getChild() { - return ImmutableList.of(); - } + @Override + public List getChild() { + return ImmutableList.of(); + } - @Override - public R accept(AbstractNodeVisitor nodeVisitor, C context) { - return nodeVisitor.visitUnresolvedAttribute(this, context); - } + @Override + public R accept(AbstractNodeVisitor nodeVisitor, C context) { + return nodeVisitor.visitUnresolvedAttribute(this, context); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/UnresolvedExpression.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/UnresolvedExpression.java index 1507b68832..e63aa167df 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/UnresolvedExpression.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/expression/UnresolvedExpression.java @@ -23,8 +23,8 @@ @EqualsAndHashCode(callSuper = false) @ToString public abstract class UnresolvedExpression extends Node { - @Override - public T accept(AbstractNodeVisitor nodeVisitor, C context) { - return nodeVisitor.visitChildren(this, context); - } + @Override + public T accept(AbstractNodeVisitor nodeVisitor, C context) { + return nodeVisitor.visitChildren(this, context); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/tree/Aggregation.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/tree/Aggregation.java index bc7eb46eff..c996c205bb 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/tree/Aggregation.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/tree/Aggregation.java @@ -27,55 +27,58 @@ import lombok.ToString; /** - * Logical plan node of Aggregation, the interface for building aggregation actions in queries + * Logical plan node of Aggregation, the interface for building aggregation actions in queries. */ @Getter @Setter @ToString @EqualsAndHashCode(callSuper = false) public class Aggregation extends UnresolvedPlan { - private List aggExprList; - private List sortExprList; - private List groupExprList; - private List argExprList; - private UnresolvedPlan child; + private List aggExprList; + private List sortExprList; + private List groupExprList; + private List argExprList; + private UnresolvedPlan child; - public Aggregation(List aggExprList, - List sortExprList, - List groupExprList) { - this.aggExprList = aggExprList; - this.sortExprList = sortExprList; - this.groupExprList = groupExprList; - this.argExprList = Collections.emptyList(); - } + /** + * Aggregation Constructor without argument. + */ + public Aggregation(List aggExprList, + List sortExprList, + List groupExprList) { + this(aggExprList, sortExprList, groupExprList, Collections.emptyList()); + } - public Aggregation(List aggExprList, - List sortExprList, - List groupExprList, - List argExprList) { - this.aggExprList = aggExprList; - this.sortExprList = sortExprList; - this.groupExprList = groupExprList; - this.argExprList = argExprList; - } + /** + * Aggregation Constructor. + */ + public Aggregation(List aggExprList, + List sortExprList, + List groupExprList, + List argExprList) { + this.aggExprList = aggExprList; + this.sortExprList = sortExprList; + this.groupExprList = groupExprList; + this.argExprList = argExprList; + } - public boolean hasArgument() { - return !aggExprList.isEmpty(); - } + public boolean hasArgument() { + return !aggExprList.isEmpty(); + } - @Override - public Aggregation attach(UnresolvedPlan child) { - this.child = child; - return this; - } + @Override + public Aggregation attach(UnresolvedPlan child) { + this.child = child; + return this; + } - @Override - public List getChild() { - return ImmutableList.of(this.child); - } + @Override + public List getChild() { + return ImmutableList.of(this.child); + } - @Override - public T accept(AbstractNodeVisitor nodeVisitor, C context) { - return nodeVisitor.visitAggregation(this, context); - } + @Override + public T accept(AbstractNodeVisitor nodeVisitor, C context) { + return nodeVisitor.visitAggregation(this, context); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/tree/Eval.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/tree/Eval.java index 3f2f3856ea..23ba92d815 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/tree/Eval.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/tree/Eval.java @@ -25,7 +25,9 @@ import lombok.Setter; import lombok.ToString; -/** AST node represent Eval operation. */ +/** + * AST node represent Eval operation. + */ @Getter @Setter @ToString diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/tree/Filter.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/tree/Filter.java index fc7f651192..7f8626b846 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/tree/Filter.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/tree/Filter.java @@ -24,32 +24,32 @@ import lombok.ToString; /** - * Logical plan node of Filter, the interface for building filters in queries + * Logical plan node of Filter, the interface for building filters in queries. */ @ToString @EqualsAndHashCode(callSuper = false) @Getter public class Filter extends UnresolvedPlan { - private UnresolvedExpression condition; - private UnresolvedPlan child; + private UnresolvedExpression condition; + private UnresolvedPlan child; - public Filter(UnresolvedExpression condition) { - this.condition = condition; - } + public Filter(UnresolvedExpression condition) { + this.condition = condition; + } - @Override - public Filter attach(UnresolvedPlan child) { - this.child = child; - return this; - } + @Override + public Filter attach(UnresolvedPlan child) { + this.child = child; + return this; + } - @Override - public List getChild() { - return ImmutableList.of(child); - } + @Override + public List getChild() { + return ImmutableList.of(child); + } - @Override - public T accept(AbstractNodeVisitor nodeVisitor, C context) { - return nodeVisitor.visitFilter(this, context); - } + @Override + public T accept(AbstractNodeVisitor nodeVisitor, C context) { + return nodeVisitor.visitFilter(this, context); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/tree/Project.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/tree/Project.java index a47b8d2bfd..c11018192f 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/tree/Project.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/tree/Project.java @@ -27,45 +27,45 @@ import lombok.ToString; /** - * Logical plan node of Project, the interface for building the list of searching fields + * Logical plan node of Project, the interface for building the list of searching fields. */ @ToString @Getter @EqualsAndHashCode(callSuper = false) public class Project extends UnresolvedPlan { - @Setter - private List projectList; - private List argExprList; - private UnresolvedPlan child; + @Setter + private List projectList; + private List argExprList; + private UnresolvedPlan child; - public Project(List projectList) { - this.projectList = projectList; - this.argExprList = Collections.emptyList(); - } + public Project(List projectList) { + this.projectList = projectList; + this.argExprList = Collections.emptyList(); + } - public Project(List projectList, List argExprList) { - this.projectList = projectList; - this.argExprList = argExprList; - } + public Project(List projectList, List argExprList) { + this.projectList = projectList; + this.argExprList = argExprList; + } - public boolean hasArgument() { - return !argExprList.isEmpty(); - } + public boolean hasArgument() { + return !argExprList.isEmpty(); + } - @Override - public Project attach(UnresolvedPlan child) { - this.child = child; - return this; - } + @Override + public Project attach(UnresolvedPlan child) { + this.child = child; + return this; + } - @Override - public List getChild() { - return ImmutableList.of(this.child); - } + @Override + public List getChild() { + return ImmutableList.of(this.child); + } - @Override - public T accept(AbstractNodeVisitor nodeVisitor, C context) { + @Override + public T accept(AbstractNodeVisitor nodeVisitor, C context) { - return nodeVisitor.visitProject(this, context); - } + return nodeVisitor.visitProject(this, context); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/tree/Relation.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/tree/Relation.java index f827c88018..9fa002e177 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/tree/Relation.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/tree/Relation.java @@ -24,30 +24,30 @@ import lombok.ToString; /** - * Logical plan node of Relation, the interface for building the searching sources + * Logical plan node of Relation, the interface for building the searching sources. */ @ToString @EqualsAndHashCode(callSuper = false) @RequiredArgsConstructor public class Relation extends UnresolvedPlan { - private final UnresolvedExpression tableName; + private final UnresolvedExpression tableName; - public String getTableName() { - return tableName.toString(); - } + public String getTableName() { + return tableName.toString(); + } - @Override - public List getChild() { - return ImmutableList.of(); - } + @Override + public List getChild() { + return ImmutableList.of(); + } - @Override - public T accept(AbstractNodeVisitor nodeVisitor, C context) { - return nodeVisitor.visitRelation(this, context); - } + @Override + public T accept(AbstractNodeVisitor nodeVisitor, C context) { + return nodeVisitor.visitRelation(this, context); + } - @Override - public UnresolvedPlan attach(UnresolvedPlan child) { - return this; - } + @Override + public UnresolvedPlan attach(UnresolvedPlan child) { + return this; + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/tree/Rename.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/tree/Rename.java index 9b7d0d5cf6..3576a93c36 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/tree/Rename.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/tree/Rename.java @@ -18,43 +18,42 @@ import com.amazon.opendistroforelasticsearch.sql.ast.AbstractNodeVisitor; import com.amazon.opendistroforelasticsearch.sql.ast.expression.Map; import com.google.common.collect.ImmutableList; +import java.util.List; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.ToString; -import java.util.List; - @ToString @EqualsAndHashCode(callSuper = false) @Getter @RequiredArgsConstructor public class Rename extends UnresolvedPlan { - private final List renameList; - private UnresolvedPlan child; - - public Rename(List renameList, UnresolvedPlan child) { - this.renameList = renameList; - this.child = child; - } - - @Override - public Rename attach(UnresolvedPlan child) { - if (null == this.child) { - this.child = child; - } else { - this.child.attach(child); - } - return this; - } - - @Override - public List getChild() { - return ImmutableList.of(child); - } - - @Override - public T accept(AbstractNodeVisitor nodeVisitor, C context) { - return nodeVisitor.visitRename(this, context); + private final List renameList; + private UnresolvedPlan child; + + public Rename(List renameList, UnresolvedPlan child) { + this.renameList = renameList; + this.child = child; + } + + @Override + public Rename attach(UnresolvedPlan child) { + if (null == this.child) { + this.child = child; + } else { + this.child.attach(child); } + return this; + } + + @Override + public List getChild() { + return ImmutableList.of(child); + } + + @Override + public T accept(AbstractNodeVisitor nodeVisitor, C context) { + return nodeVisitor.visitRename(this, context); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/tree/Sort.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/tree/Sort.java index 5eff4ae795..954a338e87 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/tree/Sort.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/tree/Sort.java @@ -32,7 +32,9 @@ import lombok.RequiredArgsConstructor; import lombok.ToString; -/** AST node for Sort {@link Sort#sortList} represent a list of sort expression and sort options. */ +/** + * AST node for Sort {@link Sort#sortList} represent a list of sort expression and sort options. + */ @ToString @EqualsAndHashCode(callSuper = false) @Getter @@ -59,13 +61,19 @@ public T accept(AbstractNodeVisitor nodeVisitor, C context) { return nodeVisitor.visitSort(this, context); } - /** Sort Options. */ + /** + * Sort Options. + */ @Data public static class SortOption { - /** PPL ascending sort option, null first. */ + /** + * PPL ascending sort option, null first. + */ public static SortOption PPL_ASC = new SortOption(ASC, NULL_FIRST); - /** PPL descending sort option, null last. */ + /** + * PPL descending sort option, null last. + */ public static SortOption PPL_DESC = new SortOption(DESC, NULL_LAST); private final SortOrder sortOrder; diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/tree/UnresolvedPlan.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/tree/UnresolvedPlan.java index ea378b2414..6e2e17c912 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/tree/UnresolvedPlan.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/ast/tree/UnresolvedPlan.java @@ -21,15 +21,15 @@ import lombok.ToString; /** - * Abstract unresolved plan + * Abstract unresolved plan. */ @EqualsAndHashCode(callSuper = false) @ToString public abstract class UnresolvedPlan extends Node { - @Override - public T accept(AbstractNodeVisitor nodeVisitor, C context) { - return nodeVisitor.visitChildren(this, context); - } + @Override + public T accept(AbstractNodeVisitor nodeVisitor, C context) { + return nodeVisitor.visitChildren(this, context); + } - public abstract UnresolvedPlan attach(UnresolvedPlan child); + public abstract UnresolvedPlan attach(UnresolvedPlan child); } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprBooleanValue.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprBooleanValue.java index 5753671c9e..0660f2f70e 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprBooleanValue.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprBooleanValue.java @@ -19,35 +19,35 @@ @EqualsAndHashCode public class ExprBooleanValue implements ExprValue { - private static final ExprValue TRUE = new ExprBooleanValue(true); - private static final ExprValue FALSE = new ExprBooleanValue(false); + private static final ExprValue TRUE = new ExprBooleanValue(true); + private static final ExprValue FALSE = new ExprBooleanValue(false); - private final Boolean value; + private final Boolean value; - private ExprBooleanValue(Boolean value) { - this.value = value; - } + private ExprBooleanValue(Boolean value) { + this.value = value; + } - public static ExprValue ofTrue() { - return TRUE; - } + public static ExprValue ofTrue() { + return TRUE; + } - public static ExprValue ofFalse() { - return FALSE; - } + public static ExprValue ofFalse() { + return FALSE; + } - @Override - public Object value() { - return value; - } + @Override + public Object value() { + return value; + } - @Override - public ExprType type() { - return ExprType.BOOLEAN; - } + @Override + public ExprType type() { + return ExprType.BOOLEAN; + } - @Override - public String toString() { - return value.toString(); - } + @Override + public String toString() { + return value.toString(); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprCollectionValue.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprCollectionValue.java index e9eec5f91c..188db3cd41 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprCollectionValue.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprCollectionValue.java @@ -15,31 +15,30 @@ package com.amazon.opendistroforelasticsearch.sql.data.model; -import lombok.EqualsAndHashCode; -import lombok.RequiredArgsConstructor; - import java.util.List; import java.util.stream.Collectors; +import lombok.EqualsAndHashCode; +import lombok.RequiredArgsConstructor; @EqualsAndHashCode @RequiredArgsConstructor public class ExprCollectionValue implements ExprValue { - private final List valueList; + private final List valueList; - @Override - public Object value() { - return valueList; - } + @Override + public Object value() { + return valueList; + } - @Override - public ExprType type() { - return ExprType.ARRAY; - } + @Override + public ExprType type() { + return ExprType.ARRAY; + } - @Override - public String toString() { - return valueList.stream() - .map(Object::toString) - .collect(Collectors.joining(",", "[", "]")); - } + @Override + public String toString() { + return valueList.stream() + .map(Object::toString) + .collect(Collectors.joining(",", "[", "]")); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprDoubleValue.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprDoubleValue.java index b00d64714e..7a6858d0ea 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprDoubleValue.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprDoubleValue.java @@ -21,20 +21,20 @@ @EqualsAndHashCode @RequiredArgsConstructor public class ExprDoubleValue implements ExprValue { - private final Double value; + private final Double value; - @Override - public Object value() { - return value; - } + @Override + public Object value() { + return value; + } - @Override - public ExprType type() { - return ExprType.DOUBLE; - } + @Override + public ExprType type() { + return ExprType.DOUBLE; + } - @Override - public String toString() { - return value.toString(); - } + @Override + public String toString() { + return value.toString(); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprFloatValue.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprFloatValue.java index cdc67a8a64..9dcafc439d 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprFloatValue.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprFloatValue.java @@ -21,20 +21,20 @@ @EqualsAndHashCode @RequiredArgsConstructor public class ExprFloatValue implements ExprValue { - private final Float value; + private final Float value; - @Override - public Object value() { - return value; - } + @Override + public Object value() { + return value; + } - @Override - public ExprType type() { - return ExprType.FLOAT; - } + @Override + public ExprType type() { + return ExprType.FLOAT; + } - @Override - public String toString() { - return value.toString(); - } + @Override + public String toString() { + return value.toString(); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprIntegerValue.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprIntegerValue.java index 7536160d6d..8b828bb583 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprIntegerValue.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprIntegerValue.java @@ -21,20 +21,20 @@ @EqualsAndHashCode @RequiredArgsConstructor public class ExprIntegerValue implements ExprValue { - private final Integer value; + private final Integer value; - @Override - public Object value() { - return value; - } + @Override + public Object value() { + return value; + } - @Override - public ExprType type() { - return ExprType.INTEGER; - } + @Override + public ExprType type() { + return ExprType.INTEGER; + } - @Override - public String toString() { - return value.toString(); - } + @Override + public String toString() { + return value.toString(); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprLongValue.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprLongValue.java index 5f81e02142..51f014c7ba 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprLongValue.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprLongValue.java @@ -21,20 +21,20 @@ @EqualsAndHashCode @RequiredArgsConstructor public class ExprLongValue implements ExprValue { - private final Long value; + private final Long value; - @Override - public Object value() { - return value; - } + @Override + public Object value() { + return value; + } - @Override - public ExprType type() { - return ExprType.LONG; - } + @Override + public ExprType type() { + return ExprType.LONG; + } - @Override - public String toString() { - return value.toString(); - } + @Override + public String toString() { + return value.toString(); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprMissingValue.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprMissingValue.java index a97e501964..86697b3fb7 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprMissingValue.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprMissingValue.java @@ -23,27 +23,27 @@ */ @EqualsAndHashCode public class ExprMissingValue implements ExprValue { - private static final ExprValue instance = new ExprMissingValue(); + private static final ExprValue instance = new ExprMissingValue(); - private ExprMissingValue() { - } + private ExprMissingValue() { + } - public static ExprValue of() { - return instance; - } + public static ExprValue of() { + return instance; + } - @Override - public Object value() { - throw new ExpressionEvaluationException("invalid to call value operation on missing value"); - } + @Override + public Object value() { + throw new ExpressionEvaluationException("invalid to call value operation on missing value"); + } - @Override - public ExprType type() { - throw new ExpressionEvaluationException("invalid to call type operation on missing value"); - } + @Override + public ExprType type() { + throw new ExpressionEvaluationException("invalid to call type operation on missing value"); + } - @Override - public boolean isMissing() { - return true; - } + @Override + public boolean isMissing() { + return true; + } } \ No newline at end of file diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprNullValue.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprNullValue.java index 7e28a56bb1..d166dd786e 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprNullValue.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprNullValue.java @@ -23,27 +23,27 @@ */ @EqualsAndHashCode public class ExprNullValue implements ExprValue { - private static final ExprValue instance = new ExprNullValue(); + private static final ExprValue instance = new ExprNullValue(); - private ExprNullValue() { - } + private ExprNullValue() { + } - public static ExprValue of() { - return instance; - } + public static ExprValue of() { + return instance; + } - @Override - public Object value() { - return null; - } + @Override + public Object value() { + return null; + } - @Override - public ExprType type() { - throw new ExpressionEvaluationException("invalid to call type operation on null value"); - } + @Override + public ExprType type() { + throw new ExpressionEvaluationException("invalid to call type operation on null value"); + } - @Override - public boolean isNull() { - return true; - } + @Override + public boolean isNull() { + return true; + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprStringValue.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprStringValue.java index eb5400b1a7..d8abd275a5 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprStringValue.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprStringValue.java @@ -21,20 +21,20 @@ @EqualsAndHashCode @RequiredArgsConstructor public class ExprStringValue implements ExprValue { - private final String value; + private final String value; - @Override - public Object value() { - return value; - } + @Override + public Object value() { + return value; + } - @Override - public ExprType type() { - return ExprType.STRING; - } + @Override + public ExprType type() { + return ExprType.STRING; + } - @Override - public String toString() { - return String.format("\"%s\"", value); - } + @Override + public String toString() { + return String.format("\"%s\"", value); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprTupleValue.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprTupleValue.java index 5be8e7b649..36bf01607f 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprTupleValue.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprTupleValue.java @@ -27,52 +27,57 @@ @RequiredArgsConstructor public class ExprTupleValue implements ExprValue { - private final LinkedHashMap valueMap; + private final LinkedHashMap valueMap; - public static ExprTupleValue fromExprValueMap(Map map) { - LinkedHashMap linkedHashMap = new LinkedHashMap<>(map); - return new ExprTupleValue(linkedHashMap); - } + public static ExprTupleValue fromExprValueMap(Map map) { + LinkedHashMap linkedHashMap = new LinkedHashMap<>(map); + return new ExprTupleValue(linkedHashMap); + } - @Override - public Object value() { - return valueMap; - } + @Override + public Object value() { + return valueMap; + } - @Override - public ExprType type() { - return ExprType.STRUCT; - } + @Override + public ExprType type() { + return ExprType.STRUCT; + } - @Override - public String toString() { - return valueMap.entrySet() - .stream() - .map(entry -> String.format("%s:%s", entry.getKey(), entry.getValue())) - .collect(Collectors.joining(",", "{", "}")); - } + @Override + public String toString() { + return valueMap.entrySet() + .stream() + .map(entry -> String.format("%s:%s", entry.getKey(), entry.getValue())) + .collect(Collectors.joining(",", "{", "}")); + } - @Override - public BindingTuple bindingTuples() { - return new LazyBindingTuple(bindingName -> valueMap.getOrDefault(bindingName, ExprMissingValue.of())); - } + @Override + public BindingTuple bindingTuples() { + return new LazyBindingTuple( + bindingName -> valueMap.getOrDefault(bindingName, ExprMissingValue.of())); + } - public boolean equals(Object o) { - if (o == this) { - return true; - } else if (!(o instanceof ExprTupleValue)) { - return false; - } else { - ExprTupleValue other = (ExprTupleValue) o; - Iterator> thisIterator = this.valueMap.entrySet().iterator(); - Iterator> otherIterator = other.valueMap.entrySet().iterator(); - while (thisIterator.hasNext() && otherIterator.hasNext()) { - if (!thisIterator.next().equals(otherIterator.next())) { - return false; - } - } - return !(thisIterator.hasNext() || otherIterator.hasNext()); + /** + * Override the equals method. + * @return true for equal, otherwise false. + */ + public boolean equals(Object o) { + if (o == this) { + return true; + } else if (!(o instanceof ExprTupleValue)) { + return false; + } else { + ExprTupleValue other = (ExprTupleValue) o; + Iterator> thisIterator = this.valueMap.entrySet().iterator(); + Iterator> otherIterator = other.valueMap.entrySet().iterator(); + while (thisIterator.hasNext() && otherIterator.hasNext()) { + if (!thisIterator.next().equals(otherIterator.next())) { + return false; } + } + return !(thisIterator.hasNext() || otherIterator.hasNext()); } + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprType.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprType.java index e6e1dbc755..4b17db27fd 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprType.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprType.java @@ -19,15 +19,15 @@ * Expression Type. */ public enum ExprType { - UNKNOWN, + UNKNOWN, - DOUBLE, - FLOAT, - LONG, - INTEGER, + DOUBLE, + FLOAT, + LONG, + INTEGER, - BOOLEAN, - STRING, - STRUCT, - ARRAY + BOOLEAN, + STRING, + STRUCT, + ARRAY } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprValue.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprValue.java index dfb8e01a49..f6f51162fe 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprValue.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprValue.java @@ -21,36 +21,38 @@ * The definition of the Expression Value. */ public interface ExprValue { - /** - * Get the Object value of the Expression Value. - */ - Object value(); + /** + * Get the Object value of the Expression Value. + */ + Object value(); - /** - * Get the {@link ExprType} of the Expression Value. - */ - ExprType type(); + /** + * Get the {@link ExprType} of the Expression Value. + */ + ExprType type(); - /** - * Is null value? - * @return true: is null value, otherwise false - */ - default boolean isNull() { - return false; - } + /** + * Is null value. + * + * @return true: is null value, otherwise false + */ + default boolean isNull() { + return false; + } - /** - * Is missing value? - * @return true: is missing value, otherwise false - */ - default boolean isMissing() { - return false; - } + /** + * Is missing value. + * + * @return true: is missing value, otherwise false + */ + default boolean isMissing() { + return false; + } - /** - * Get the {@link BindingTuple} - */ - default BindingTuple bindingTuples() { - return BindingTuple.EMPTY; - } + /** + * Get the {@link BindingTuple}. + */ + default BindingTuple bindingTuples() { + return BindingTuple.EMPTY; + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprValueUtils.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprValueUtils.java index fb4ecdc9cd..b0cc193ef5 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprValueUtils.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprValueUtils.java @@ -15,153 +15,166 @@ package com.amazon.opendistroforelasticsearch.sql.data.model; +import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprType.ARRAY; +import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprType.BOOLEAN; +import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprType.STRING; +import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprType.STRUCT; + import com.amazon.opendistroforelasticsearch.sql.exception.ExpressionEvaluationException; import com.google.common.annotations.VisibleForTesting; -import java.util.LinkedHashMap; -import lombok.experimental.UtilityClass; - import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; - -import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprType.ARRAY; -import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprType.BOOLEAN; -import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprType.STRING; -import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprType.STRUCT; +import lombok.experimental.UtilityClass; /** * The definition of {@link ExprValue} factory. */ @UtilityClass public class ExprValueUtils { - public static final ExprValue LITERAL_TRUE = ExprBooleanValue.ofTrue(); - public static final ExprValue LITERAL_FALSE = ExprBooleanValue.ofFalse(); - public static final ExprValue LITERAL_NULL = ExprNullValue.of(); - public static final ExprValue LITERAL_MISSING = ExprMissingValue.of(); - - public static ExprValue booleanValue(Boolean value) { - return value ? LITERAL_TRUE : LITERAL_FALSE; - } - - public static ExprValue integerValue(Integer value) { - return new ExprIntegerValue(value); - } - - public static ExprValue doubleValue(Double value) { - return new ExprDoubleValue(value); - } - - public static ExprValue floatValue(Float value) { - return new ExprFloatValue(value); - } - - public static ExprValue longValue(Long value) { - return new ExprLongValue(value); - } - - public static ExprValue stringValue(String value) { - return new ExprStringValue(value); - } - - public static ExprValue tupleValue(Map map) { - LinkedHashMap valueMap = new LinkedHashMap<>(); - map.forEach((k, v) -> valueMap.put(k, fromObjectValue(v))); - return new ExprTupleValue(valueMap); - } - - public static ExprValue collectionValue(List list) { - List valueList = new ArrayList<>(); - list.forEach(o -> valueList.add(fromObjectValue(o))); - return new ExprCollectionValue(valueList); - } - - public static ExprValue missingValue() { - return ExprMissingValue.of(); - } - - public static ExprValue nullValue() { - return ExprNullValue.of(); - } - - public static ExprValue fromObjectValue(Object o) { - if ( null == o) { - return LITERAL_NULL; - } - if (o instanceof Map) { - return tupleValue((Map) o); - } else if (o instanceof List) { - return collectionValue(((List) o)); - } else if (o instanceof Integer) { - return integerValue((Integer) o); - } else if (o instanceof Long) { - return longValue(((Long) o)); - } else if (o instanceof Boolean) { - return booleanValue((Boolean) o); - } else if (o instanceof Double) { - return doubleValue((Double) o); - } else if (o instanceof String) { - return stringValue((String) o); - } else if (o instanceof Float) { - return floatValue((Float) o); - } else { - throw new ExpressionEvaluationException("unsupported object " + o.getClass()); - } - } - - public static Integer getIntegerValue(ExprValue exprValue) { - return getNumberValue(exprValue).intValue(); - } - - public static Double getDoubleValue(ExprValue exprValue) { - return getNumberValue(exprValue).doubleValue(); - } - - public static Long getLongValue(ExprValue exprValue) { - return getNumberValue(exprValue).longValue(); - } - - public static Float getFloatValue(ExprValue exprValue) { - return getNumberValue(exprValue).floatValue(); - } - - public static String getStringValue(ExprValue exprValue) { - return convert(exprValue, STRING); - } - - public static List getCollectionValue(ExprValue exprValue) { - return convert(exprValue, ARRAY); - } - - public static Map getTupleValue(ExprValue exprValue) { - return convert(exprValue, STRUCT); - } - - public static Boolean getBooleanValue(ExprValue exprValue) { - return convert(exprValue, BOOLEAN); - } - - @VisibleForTesting - public static Number getNumberValue(ExprValue exprValue) { - switch (exprValue.type()) { - case INTEGER: - case DOUBLE: - case LONG: - case FLOAT: - return (Number) exprValue.value(); - default: - break; - } - throw new ExpressionEvaluationException( - String.format("invalid to getNumberValue with expression has type of %s", exprValue.type())); - } - - @SuppressWarnings("unchecked") - private static T convert(ExprValue exprValue, ExprType toType) { - if (exprValue.type() == toType) { - return (T) exprValue.value(); - } else { - throw new ExpressionEvaluationException( - String.format("invalid to convert expression with type:%s to type:%s", exprValue.type(), toType)); - } - } + public static final ExprValue LITERAL_TRUE = ExprBooleanValue.ofTrue(); + public static final ExprValue LITERAL_FALSE = ExprBooleanValue.ofFalse(); + public static final ExprValue LITERAL_NULL = ExprNullValue.of(); + public static final ExprValue LITERAL_MISSING = ExprMissingValue.of(); + + public static ExprValue booleanValue(Boolean value) { + return value ? LITERAL_TRUE : LITERAL_FALSE; + } + + public static ExprValue integerValue(Integer value) { + return new ExprIntegerValue(value); + } + + public static ExprValue doubleValue(Double value) { + return new ExprDoubleValue(value); + } + + public static ExprValue floatValue(Float value) { + return new ExprFloatValue(value); + } + + public static ExprValue longValue(Long value) { + return new ExprLongValue(value); + } + + public static ExprValue stringValue(String value) { + return new ExprStringValue(value); + } + + /** + * {@link ExprTupleValue} constructor. + */ + public static ExprValue tupleValue(Map map) { + LinkedHashMap valueMap = new LinkedHashMap<>(); + map.forEach((k, v) -> valueMap.put(k, fromObjectValue(v))); + return new ExprTupleValue(valueMap); + } + + /** + * {@link ExprCollectionValue} constructor. + */ + public static ExprValue collectionValue(List list) { + List valueList = new ArrayList<>(); + list.forEach(o -> valueList.add(fromObjectValue(o))); + return new ExprCollectionValue(valueList); + } + + public static ExprValue missingValue() { + return ExprMissingValue.of(); + } + + public static ExprValue nullValue() { + return ExprNullValue.of(); + } + + /** + * Construct ExprValue from Object. + */ + public static ExprValue fromObjectValue(Object o) { + if (null == o) { + return LITERAL_NULL; + } + if (o instanceof Map) { + return tupleValue((Map) o); + } else if (o instanceof List) { + return collectionValue(((List) o)); + } else if (o instanceof Integer) { + return integerValue((Integer) o); + } else if (o instanceof Long) { + return longValue(((Long) o)); + } else if (o instanceof Boolean) { + return booleanValue((Boolean) o); + } else if (o instanceof Double) { + return doubleValue((Double) o); + } else if (o instanceof String) { + return stringValue((String) o); + } else if (o instanceof Float) { + return floatValue((Float) o); + } else { + throw new ExpressionEvaluationException("unsupported object " + o.getClass()); + } + } + + public static Integer getIntegerValue(ExprValue exprValue) { + return getNumberValue(exprValue).intValue(); + } + + public static Double getDoubleValue(ExprValue exprValue) { + return getNumberValue(exprValue).doubleValue(); + } + + public static Long getLongValue(ExprValue exprValue) { + return getNumberValue(exprValue).longValue(); + } + + public static Float getFloatValue(ExprValue exprValue) { + return getNumberValue(exprValue).floatValue(); + } + + public static String getStringValue(ExprValue exprValue) { + return convert(exprValue, STRING); + } + + public static List getCollectionValue(ExprValue exprValue) { + return convert(exprValue, ARRAY); + } + + public static Map getTupleValue(ExprValue exprValue) { + return convert(exprValue, STRUCT); + } + + public static Boolean getBooleanValue(ExprValue exprValue) { + return convert(exprValue, BOOLEAN); + } + + /** + * Get Number Value from {@link ExprValue}. + */ + @VisibleForTesting + public static Number getNumberValue(ExprValue exprValue) { + switch (exprValue.type()) { + case INTEGER: + case DOUBLE: + case LONG: + case FLOAT: + return (Number) exprValue.value(); + default: + break; + } + throw new ExpressionEvaluationException( + String + .format("invalid to getNumberValue with expression has type of %s", exprValue.type())); + } + + @SuppressWarnings("unchecked") + private static T convert(ExprValue exprValue, ExprType toType) { + if (exprValue.type() == toType) { + return (T) exprValue.value(); + } else { + throw new ExpressionEvaluationException( + String.format("invalid to convert expression with type:%s to type:%s", exprValue.type(), + toType)); + } + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/utils/NaturalExprValueOrdering.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/utils/NaturalExprValueOrdering.java index 5d2e4dcc19..7d9616599d 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/utils/NaturalExprValueOrdering.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/data/utils/NaturalExprValueOrdering.java @@ -71,9 +71,10 @@ public int compare(ExprValue left, ExprValue right) { return MAP_COMPARATOR.apply(getTupleValue(left), getTupleValue(right)); case ARRAY: return LIST_COMPARATOR.apply(getCollectionValue(left), getCollectionValue(right)); + default: + throw new ExpressionEvaluationException( + String.format("compare doesn't support type [%s]", left.type())); } - throw new ExpressionEvaluationException( - String.format("compare doesn't support type [%s]", left.type())); } @Override diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/exception/ExpressionEvaluationException.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/exception/ExpressionEvaluationException.java index 0b86891b31..040d0d522d 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/exception/ExpressionEvaluationException.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/exception/ExpressionEvaluationException.java @@ -19,7 +19,7 @@ * Exception for Expression Evaluation. */ public class ExpressionEvaluationException extends QueryEngineException { - public ExpressionEvaluationException(String message) { - super(message); - } + public ExpressionEvaluationException(String message) { + super(message); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/exception/QueryEngineException.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/exception/QueryEngineException.java index 75c9d78b5e..2239d6e17c 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/exception/QueryEngineException.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/exception/QueryEngineException.java @@ -20,7 +20,7 @@ */ public class QueryEngineException extends RuntimeException { - public QueryEngineException(String message) { - super(message); - } + public QueryEngineException(String message) { + super(message); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/exception/SemanticCheckException.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/exception/SemanticCheckException.java index bd21ff4465..611e19d8c1 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/exception/SemanticCheckException.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/exception/SemanticCheckException.java @@ -19,7 +19,7 @@ * Semantic Check Exception. */ public class SemanticCheckException extends QueryEngineException { - public SemanticCheckException(String message) { - super(message); - } + public SemanticCheckException(String message) { + super(message); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/executor/ExecutionEngine.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/executor/ExecutionEngine.java index 16d6f72f78..ec6e5bfbf2 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/executor/ExecutionEngine.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/executor/ExecutionEngine.java @@ -19,28 +19,28 @@ import com.amazon.opendistroforelasticsearch.sql.common.response.ResponseListener; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprValue; import com.amazon.opendistroforelasticsearch.sql.planner.physical.PhysicalPlan; -import lombok.Data; - import java.util.List; +import lombok.Data; /** * Execution engine that encapsulates execution details. */ public interface ExecutionEngine { - /** - * Execute physical plan and call back response listener - * @param plan executable physical plan - * @param listener response listener - */ - void execute(PhysicalPlan plan, ResponseListener listener); + /** + * Execute physical plan and call back response listener. + * + * @param plan executable physical plan + * @param listener response listener + */ + void execute(PhysicalPlan plan, ResponseListener listener); - /** - * Data class that encapsulates ExprValue - */ - @Data - class QueryResponse { - private final List results; - } + /** + * Data class that encapsulates ExprValue. + */ + @Data + class QueryResponse { + private final List results; + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/Expression.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/Expression.java index 1f49b0afd9..3a0b9e7b4c 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/Expression.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/Expression.java @@ -24,13 +24,13 @@ */ public interface Expression { - /** - * Evaluate the value of expression in the value environment - */ - ExprValue valueOf(Environment valueEnv); + /** + * Evaluate the value of expression in the value environment. + */ + ExprValue valueOf(Environment valueEnv); - /** - * Evaluate the type of expression in the type environment - */ - ExprType type(Environment typeEnv); + /** + * Evaluate the type of expression in the type environment. + */ + ExprType type(Environment typeEnv); } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/FunctionExpression.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/FunctionExpression.java index e43a82192b..6271d7e0d1 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/FunctionExpression.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/FunctionExpression.java @@ -17,21 +17,20 @@ import com.amazon.opendistroforelasticsearch.sql.expression.function.FunctionImplementation; import com.amazon.opendistroforelasticsearch.sql.expression.function.FunctionName; +import java.util.List; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.RequiredArgsConstructor; -import java.util.List; - /** - * Function Expression + * Function Expression. */ @EqualsAndHashCode @RequiredArgsConstructor public abstract class FunctionExpression implements Expression, FunctionImplementation { - @Getter - private final FunctionName functionName; + @Getter + private final FunctionName functionName; - @Getter - private final List arguments; + @Getter + private final List arguments; } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/LiteralExpression.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/LiteralExpression.java index e6ae042e7a..40ecd71cbe 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/LiteralExpression.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/LiteralExpression.java @@ -22,25 +22,25 @@ import lombok.RequiredArgsConstructor; /** - * Literal Expression + * Literal Expression. */ @EqualsAndHashCode @RequiredArgsConstructor public class LiteralExpression implements Expression { - private final ExprValue exprValue; + private final ExprValue exprValue; - @Override - public ExprValue valueOf(Environment env) { - return exprValue; - } + @Override + public ExprValue valueOf(Environment env) { + return exprValue; + } - @Override - public ExprType type(Environment env) { - return exprValue.type(); - } + @Override + public ExprType type(Environment env) { + return exprValue.type(); + } - @Override - public String toString() { - return exprValue.toString(); - } + @Override + public String toString() { + return exprValue.toString(); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/ReferenceExpression.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/ReferenceExpression.java index 03eb384b0b..9186fb3f0b 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/ReferenceExpression.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/ReferenceExpression.java @@ -25,21 +25,21 @@ @EqualsAndHashCode @RequiredArgsConstructor public class ReferenceExpression implements Expression { - @Getter - private final String attr; + @Getter + private final String attr; - @Override - public ExprValue valueOf(Environment env) { - return env.resolve(this); - } + @Override + public ExprValue valueOf(Environment env) { + return env.resolve(this); + } - @Override - public ExprType type(Environment env) { - return env.resolve(this); - } + @Override + public ExprType type(Environment env) { + return env.resolve(this); + } - @Override - public String toString() { - return attr; - } + @Override + public String toString() { + return attr; + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/aggregation/AggregationState.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/aggregation/AggregationState.java index 7a0a65c7d7..87f32d3f2c 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/aggregation/AggregationState.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/aggregation/AggregationState.java @@ -22,8 +22,8 @@ * Maintain the state when {@link Aggregator} iterate on the {@link BindingTuple}. */ public interface AggregationState { - /** - * Get {@link ExprValue} result. - */ - ExprValue result(); + /** + * Get {@link ExprValue} result. + */ + ExprValue result(); } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/aggregation/Aggregator.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/aggregation/Aggregator.java index 79f80fe0fe..ea36b46a59 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/aggregation/Aggregator.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/aggregation/Aggregator.java @@ -24,47 +24,49 @@ import com.amazon.opendistroforelasticsearch.sql.expression.function.FunctionImplementation; import com.amazon.opendistroforelasticsearch.sql.expression.function.FunctionName; import com.amazon.opendistroforelasticsearch.sql.storage.bindingtuple.BindingTuple; +import java.util.List; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.RequiredArgsConstructor; -import java.util.List; - /** * Aggregator which will iterate on the {@link BindingTuple}s to aggregate the result. * The Aggregator is not well fit into Expression, because it has side effect. - * But we still want to make it implement {@link Expression} interface to make {@link ExpressionAnalyzer} easier. + * But we still want to make it implement {@link Expression} interface to make + * {@link ExpressionAnalyzer} easier. */ @EqualsAndHashCode @RequiredArgsConstructor -public abstract class Aggregator implements FunctionImplementation, Expression { - @Getter - private final FunctionName functionName; - @Getter - private final List arguments; - protected final ExprType returnType; +public abstract class Aggregator + implements FunctionImplementation, Expression { + @Getter + private final FunctionName functionName; + @Getter + private final List arguments; + protected final ExprType returnType; - /** - * Create an {@link AggregationState} which will be used for aggregation - */ - public abstract S create(); + /** + * Create an {@link AggregationState} which will be used for aggregation. + */ + public abstract S create(); - /** - * Iterate on the {@link BindingTuple}. - * - * @param tuple {@link BindingTuple} - * @param state {@link AggregationState} - * @return {@link AggregationState} - */ - public abstract S iterate(BindingTuple tuple, S state); + /** + * Iterate on the {@link BindingTuple}. + * + * @param tuple {@link BindingTuple} + * @param state {@link AggregationState} + * @return {@link AggregationState} + */ + public abstract S iterate(BindingTuple tuple, S state); - @Override - public ExprValue valueOf(Environment valueEnv) { - throw new ExpressionEvaluationException(String.format("can't evaluate on aggregator: %s", functionName)); - } + @Override + public ExprValue valueOf(Environment valueEnv) { + throw new ExpressionEvaluationException( + String.format("can't evaluate on aggregator: %s", functionName)); + } - @Override - public ExprType type(Environment typeEnv) { - return returnType; - } + @Override + public ExprType type(Environment typeEnv) { + return returnType; + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/aggregation/AggregatorFunction.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/aggregation/AggregatorFunction.java index 60ff968fde..079b0d2dc5 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/aggregation/AggregatorFunction.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/aggregation/AggregatorFunction.java @@ -23,9 +23,8 @@ import com.amazon.opendistroforelasticsearch.sql.expression.function.FunctionResolver; import com.amazon.opendistroforelasticsearch.sql.expression.function.FunctionSignature; import com.google.common.collect.ImmutableMap; -import lombok.experimental.UtilityClass; - import java.util.Collections; +import lombok.experimental.UtilityClass; /** * The definition of aggregator function @@ -37,63 +36,66 @@ */ @UtilityClass public class AggregatorFunction { + /** + * Register Aggregation Function. + * @param repository {@link BuiltinFunctionRepository}. + */ + public static void register(BuiltinFunctionRepository repository) { + repository.register(avg()); + repository.register(sum()); + repository.register(count()); + } - public static void register(BuiltinFunctionRepository repository) { - repository.register(avg()); - repository.register(sum()); - repository.register(count()); - } - - private static FunctionResolver avg() { - FunctionName functionName = BuiltinFunctionName.AVG.getName(); - return new FunctionResolver( - functionName, - new ImmutableMap.Builder() - .put(new FunctionSignature(functionName, Collections.singletonList(ExprType.DOUBLE)), - arguments -> new AvgAggregator(arguments, ExprType.DOUBLE)) - .build() - ); - } + private static FunctionResolver avg() { + FunctionName functionName = BuiltinFunctionName.AVG.getName(); + return new FunctionResolver( + functionName, + new ImmutableMap.Builder() + .put(new FunctionSignature(functionName, Collections.singletonList(ExprType.DOUBLE)), + arguments -> new AvgAggregator(arguments, ExprType.DOUBLE)) + .build() + ); + } - private static FunctionResolver count() { - FunctionName functionName = BuiltinFunctionName.COUNT.getName(); - return new FunctionResolver( - functionName, - new ImmutableMap.Builder() - .put(new FunctionSignature(functionName, Collections.singletonList(ExprType.INTEGER)), - arguments -> new CountAggregator(arguments, ExprType.INTEGER)) - .put(new FunctionSignature(functionName, Collections.singletonList(ExprType.LONG)), - arguments -> new CountAggregator(arguments, ExprType.INTEGER)) - .put(new FunctionSignature(functionName, Collections.singletonList(ExprType.FLOAT)), - arguments -> new CountAggregator(arguments, ExprType.INTEGER)) - .put(new FunctionSignature(functionName, Collections.singletonList(ExprType.DOUBLE)), - arguments -> new CountAggregator(arguments, ExprType.INTEGER)) - .put(new FunctionSignature(functionName, Collections.singletonList(ExprType.STRING)), - arguments -> new CountAggregator(arguments, ExprType.INTEGER)) - .put(new FunctionSignature(functionName, Collections.singletonList(ExprType.STRUCT)), - arguments -> new CountAggregator(arguments, ExprType.INTEGER)) - .put(new FunctionSignature(functionName, Collections.singletonList(ExprType.ARRAY)), - arguments -> new CountAggregator(arguments, ExprType.INTEGER)) - .put(new FunctionSignature(functionName, Collections.singletonList(ExprType.BOOLEAN)), - arguments -> new CountAggregator(arguments, ExprType.INTEGER)) - .build() - ); - } + private static FunctionResolver count() { + FunctionName functionName = BuiltinFunctionName.COUNT.getName(); + return new FunctionResolver( + functionName, + new ImmutableMap.Builder() + .put(new FunctionSignature(functionName, Collections.singletonList(ExprType.INTEGER)), + arguments -> new CountAggregator(arguments, ExprType.INTEGER)) + .put(new FunctionSignature(functionName, Collections.singletonList(ExprType.LONG)), + arguments -> new CountAggregator(arguments, ExprType.INTEGER)) + .put(new FunctionSignature(functionName, Collections.singletonList(ExprType.FLOAT)), + arguments -> new CountAggregator(arguments, ExprType.INTEGER)) + .put(new FunctionSignature(functionName, Collections.singletonList(ExprType.DOUBLE)), + arguments -> new CountAggregator(arguments, ExprType.INTEGER)) + .put(new FunctionSignature(functionName, Collections.singletonList(ExprType.STRING)), + arguments -> new CountAggregator(arguments, ExprType.INTEGER)) + .put(new FunctionSignature(functionName, Collections.singletonList(ExprType.STRUCT)), + arguments -> new CountAggregator(arguments, ExprType.INTEGER)) + .put(new FunctionSignature(functionName, Collections.singletonList(ExprType.ARRAY)), + arguments -> new CountAggregator(arguments, ExprType.INTEGER)) + .put(new FunctionSignature(functionName, Collections.singletonList(ExprType.BOOLEAN)), + arguments -> new CountAggregator(arguments, ExprType.INTEGER)) + .build() + ); + } - private static FunctionResolver sum() { - FunctionName functionName = BuiltinFunctionName.SUM.getName(); - return new FunctionResolver( - functionName, - new ImmutableMap.Builder() - .put(new FunctionSignature(functionName, Collections.singletonList(ExprType.INTEGER)), - arguments -> new SumAggregator(arguments, ExprType.INTEGER)) - .put(new FunctionSignature(functionName, Collections.singletonList(ExprType.LONG)), - arguments -> new SumAggregator(arguments, ExprType.LONG)) - .put(new FunctionSignature(functionName, Collections.singletonList(ExprType.FLOAT)), - arguments -> new SumAggregator(arguments, ExprType.FLOAT)) - .put(new FunctionSignature(functionName, Collections.singletonList(ExprType.DOUBLE)), - arguments -> new SumAggregator(arguments, ExprType.DOUBLE)) - .build() - ); - } + private static FunctionResolver sum() { + FunctionName functionName = BuiltinFunctionName.SUM.getName(); + return new FunctionResolver( + functionName, + new ImmutableMap.Builder() + .put(new FunctionSignature(functionName, Collections.singletonList(ExprType.INTEGER)), + arguments -> new SumAggregator(arguments, ExprType.INTEGER)) + .put(new FunctionSignature(functionName, Collections.singletonList(ExprType.LONG)), + arguments -> new SumAggregator(arguments, ExprType.LONG)) + .put(new FunctionSignature(functionName, Collections.singletonList(ExprType.FLOAT)), + arguments -> new SumAggregator(arguments, ExprType.FLOAT)) + .put(new FunctionSignature(functionName, Collections.singletonList(ExprType.DOUBLE)), + arguments -> new SumAggregator(arguments, ExprType.DOUBLE)) + .build() + ); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/aggregation/AvgAggregator.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/aggregation/AvgAggregator.java index b7c95568a4..1dfb7008f4 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/aggregation/AvgAggregator.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/aggregation/AvgAggregator.java @@ -15,6 +15,8 @@ package com.amazon.opendistroforelasticsearch.sql.expression.aggregation; +import static com.amazon.opendistroforelasticsearch.sql.utils.ExpressionUtils.format; + import com.amazon.opendistroforelasticsearch.sql.data.model.ExprNullValue; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprType; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprValue; @@ -22,61 +24,58 @@ import com.amazon.opendistroforelasticsearch.sql.expression.Expression; import com.amazon.opendistroforelasticsearch.sql.expression.function.BuiltinFunctionName; import com.amazon.opendistroforelasticsearch.sql.storage.bindingtuple.BindingTuple; - import java.util.List; import java.util.Locale; -import static com.amazon.opendistroforelasticsearch.sql.utils.ExpressionUtils.format; - /** * The average aggregator aggregate the value evaluated by the expression. * If the expression evaluated result is NULL or MISSING, then the result is NULL. */ public class AvgAggregator extends Aggregator { - public AvgAggregator(List arguments, ExprType returnType) { - super(BuiltinFunctionName.AVG.getName(), arguments, returnType); - } + public AvgAggregator(List arguments, ExprType returnType) { + super(BuiltinFunctionName.AVG.getName(), arguments, returnType); + } - @Override - public AvgState create() { - return new AvgState(); - } + @Override + public AvgState create() { + return new AvgState(); + } - @Override - public AvgState iterate(BindingTuple tuple, AvgState state) { - Expression expression = getArguments().get(0); - ExprValue value = expression.valueOf(tuple); - if (value.isNull() || value.isMissing()) { - state.isNullResult = true; - } else { - state.count++; - state.total += ExprValueUtils.getDoubleValue(value); - } - return state; + @Override + public AvgState iterate(BindingTuple tuple, AvgState state) { + Expression expression = getArguments().get(0); + ExprValue value = expression.valueOf(tuple); + if (value.isNull() || value.isMissing()) { + state.isNullResult = true; + } else { + state.count++; + state.total += ExprValueUtils.getDoubleValue(value); } + return state; + } - @Override - public String toString() { - return String.format(Locale.ROOT, "avg(%s)", format(getArguments())); - } + @Override + public String toString() { + return String.format(Locale.ROOT, "avg(%s)", format(getArguments())); + } - /** - * Average State. - */ - protected class AvgState implements AggregationState { - private int count; - private double total; - private boolean isNullResult = false; + /** + * Average State. + */ + protected class AvgState implements AggregationState { + private int count; + private double total; + private boolean isNullResult = false; - public AvgState() { - this.count = 0; - this.total = 0d; - } + public AvgState() { + this.count = 0; + this.total = 0d; + } - @Override - public ExprValue result() { - return isNullResult ? ExprNullValue.of() : ExprValueUtils.doubleValue(total / count); - } + @Override + public ExprValue result() { + return isNullResult ? ExprNullValue.of() : ExprValueUtils.doubleValue(total / count); } + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/aggregation/CountAggregator.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/aggregation/CountAggregator.java index eeae8d1a20..f2de120fcf 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/aggregation/CountAggregator.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/aggregation/CountAggregator.java @@ -53,7 +53,9 @@ public String toString() { return String.format(Locale.ROOT, "count(%s)", format(getArguments())); } - /** Count State. */ + /** + * Count State. + */ protected class CountState implements AggregationState { private int count; diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/aggregation/SumAggregator.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/aggregation/SumAggregator.java index 00212cafb6..2285694e7d 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/aggregation/SumAggregator.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/aggregation/SumAggregator.java @@ -43,72 +43,72 @@ */ public class SumAggregator extends Aggregator { - public SumAggregator(List arguments, ExprType returnType) { - super(BuiltinFunctionName.SUM.getName(), arguments, returnType); - } + public SumAggregator(List arguments, ExprType returnType) { + super(BuiltinFunctionName.SUM.getName(), arguments, returnType); + } - @Override - public SumState create() { - return new SumState(returnType); - } + @Override + public SumState create() { + return new SumState(returnType); + } - @Override - public SumState iterate(BindingTuple tuple, SumState state) { - Expression expression = getArguments().get(0); - ExprValue value = expression.valueOf(tuple); - if (value.isNull() || value.isMissing()) { - state.isNullResult = true; - } else { - state.add(value); - } - return state; + @Override + public SumState iterate(BindingTuple tuple, SumState state) { + Expression expression = getArguments().get(0); + ExprValue value = expression.valueOf(tuple); + if (value.isNull() || value.isMissing()) { + state.isNullResult = true; + } else { + state.add(value); } + return state; + } - @Override - public String toString() { - return String.format(Locale.ROOT, "sum(%s)", format(getArguments())); - } + @Override + public String toString() { + return String.format(Locale.ROOT, "sum(%s)", format(getArguments())); + } - /** - * Sum State. - */ - protected class SumState implements AggregationState { + /** + * Sum State. + */ + protected class SumState implements AggregationState { - private final ExprType type; - private ExprValue sumResult; - private boolean isNullResult = false; + private final ExprType type; + private ExprValue sumResult; + private boolean isNullResult = false; - public SumState(ExprType type) { - this.type = type; - sumResult = ExprValueUtils.integerValue(0); - } + public SumState(ExprType type) { + this.type = type; + sumResult = ExprValueUtils.integerValue(0); + } - /** - * Add value to current sumResult - */ - public void add(ExprValue value) { - switch (type) { - case INTEGER: - sumResult = integerValue(getIntegerValue(sumResult) + getIntegerValue(value)); - break; - case LONG: - sumResult = longValue(getLongValue(sumResult) + getLongValue(value)); - break; - case FLOAT: - sumResult = floatValue(getFloatValue(sumResult) + getFloatValue(value)); - break; - case DOUBLE: - sumResult = doubleValue(getDoubleValue(sumResult) + getDoubleValue(value)); - break; - default: - throw new ExpressionEvaluationException( - String.format("unexpected type [%s] in sum aggregation", type)); - } - } + /** + * Add value to current sumResult. + */ + public void add(ExprValue value) { + switch (type) { + case INTEGER: + sumResult = integerValue(getIntegerValue(sumResult) + getIntegerValue(value)); + break; + case LONG: + sumResult = longValue(getLongValue(sumResult) + getLongValue(value)); + break; + case FLOAT: + sumResult = floatValue(getFloatValue(sumResult) + getFloatValue(value)); + break; + case DOUBLE: + sumResult = doubleValue(getDoubleValue(sumResult) + getDoubleValue(value)); + break; + default: + throw new ExpressionEvaluationException( + String.format("unexpected type [%s] in sum aggregation", type)); + } + } - @Override - public ExprValue result() { - return isNullResult ? ExprNullValue.of() : sumResult; - } + @Override + public ExprValue result() { + return isNullResult ? ExprNullValue.of() : sumResult; } + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/config/ExpressionConfig.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/config/ExpressionConfig.java index c81ef3625a..4b49faa3dd 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/config/ExpressionConfig.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/config/ExpressionConfig.java @@ -22,14 +22,18 @@ import com.amazon.opendistroforelasticsearch.sql.expression.scalar.arthmetic.UnaryFunction; import com.amazon.opendistroforelasticsearch.sql.expression.scalar.predicate.BinaryPredicateFunction; import com.amazon.opendistroforelasticsearch.sql.expression.scalar.predicate.UnaryPredicateFunction; +import java.util.HashMap; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import java.util.HashMap; - -/** Expression Config for Spring IoC. */ +/** + * Expression Config for Spring IoC. + */ @Configuration public class ExpressionConfig { + /** + * BuiltinFunctionRepository constructor. + */ @Bean public BuiltinFunctionRepository functionRepository() { BuiltinFunctionRepository builtinFunctionRepository = diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/env/Environment.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/env/Environment.java index c8e182af6d..51ac2e0806 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/env/Environment.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/env/Environment.java @@ -15,24 +15,30 @@ package com.amazon.opendistroforelasticsearch.sql.expression.env; -/** The definition of the environment. */ -public interface Environment { +/** + * The definition of the environment. + * @param the type of expression + * @param the type of expression value + */ +public interface Environment { - /** resolve the value of expression from the environment. */ - Value resolve(Expr var); + /** + * resolve the value of expression from the environment. + */ + V resolve(E var); /** * Extend the environment. * - * @param env environment - * @param expr expression. - * @param value expression value. - * @param the type of expression - * @param the type of expression value + * @param env environment + * @param expr expression. + * @param value expression value. + * @param the type of expression + * @param the type of expression value * @return extended environment. */ - static Environment extendEnv( - Environment env, Expr expr, Value value) { + static Environment extendEnv( + Environment env, E expr, V value) { return var -> { if (var.equals(expr)) { return value; diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java index 29ecb26fd6..493a19ae5d 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionName.java @@ -1,13 +1,14 @@ package com.amazon.opendistroforelasticsearch.sql.expression.function; import com.google.common.collect.ImmutableMap; -import lombok.Getter; -import lombok.RequiredArgsConstructor; - import java.util.Map; import java.util.Optional; +import lombok.Getter; +import lombok.RequiredArgsConstructor; -/** Builtin Function Name */ +/** + * Builtin Function Name. + */ @Getter @RequiredArgsConstructor public enum BuiltinFunctionName { @@ -22,7 +23,7 @@ public enum BuiltinFunctionName { TOSTRING(FunctionName.of("tostring")), /** - * Operator + * Operator. */ ADD(FunctionName.of("+")), SUBTRACT(FunctionName.of("-")), @@ -31,7 +32,9 @@ public enum BuiltinFunctionName { MODULES(FunctionName.of("%")), EQUAL(FunctionName.of("=")), - /** Aggregation Function. */ + /** + * Aggregation Function. + */ AVG(FunctionName.of("avg")), SUM(FunctionName.of("sum")), COUNT(FunctionName.of("count")); diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionRepository.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionRepository.java index d6ffe863a9..80c871b617 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionRepository.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionRepository.java @@ -1,55 +1,53 @@ package com.amazon.opendistroforelasticsearch.sql.expression.function; - import com.amazon.opendistroforelasticsearch.sql.data.model.ExprType; import com.amazon.opendistroforelasticsearch.sql.exception.ExpressionEvaluationException; import com.amazon.opendistroforelasticsearch.sql.expression.Expression; import com.amazon.opendistroforelasticsearch.sql.expression.env.Environment; -import lombok.RequiredArgsConstructor; - import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; /** - * Builtin Function Repository + * Builtin Function Repository. */ @RequiredArgsConstructor public class BuiltinFunctionRepository { - private final Map functionResolverMap; + private final Map functionResolverMap; - /** - * Register {@link FunctionResolver} to the Builtin Function Repository. - * - * @param resolver {@link FunctionResolver} to be registered - */ - public void register(FunctionResolver resolver) { - functionResolverMap.put(resolver.getFunctionName(), resolver); - } + /** + * Register {@link FunctionResolver} to the Builtin Function Repository. + * + * @param resolver {@link FunctionResolver} to be registered + */ + public void register(FunctionResolver resolver) { + functionResolverMap.put(resolver.getFunctionName(), resolver); + } - /** - * Compile FunctionExpression - */ - public FunctionImplementation compile(FunctionName functionName, List expressions, - Environment env) { - FunctionBuilder resolvedFunctionBuilder = resolve(new FunctionSignature(functionName, - expressions.stream().map(expression -> expression.type(env)).collect(Collectors.toList()))); - return resolvedFunctionBuilder.apply(expressions); - } + /** + * Compile FunctionExpression. + */ + public FunctionImplementation compile(FunctionName functionName, List expressions, + Environment env) { + FunctionBuilder resolvedFunctionBuilder = resolve(new FunctionSignature(functionName, + expressions.stream().map(expression -> expression.type(env)).collect(Collectors.toList()))); + return resolvedFunctionBuilder.apply(expressions); + } - /** - * Resolve the {@link FunctionBuilder} in Builtin Function Repository. - * - * @param functionSignature {@link FunctionSignature} - * @return {@link FunctionBuilder} - */ - public FunctionBuilder resolve(FunctionSignature functionSignature) { - FunctionName functionName = functionSignature.getFunctionName(); - if (functionResolverMap.containsKey(functionName)) { - return functionResolverMap.get(functionName).resolve(functionSignature); - } else { - throw new ExpressionEvaluationException( - String.format("unsupported function name: %s", functionName.getFunctionName())); - } + /** + * Resolve the {@link FunctionBuilder} in Builtin Function Repository. + * + * @param functionSignature {@link FunctionSignature} + * @return {@link FunctionBuilder} + */ + public FunctionBuilder resolve(FunctionSignature functionSignature) { + FunctionName functionName = functionSignature.getFunctionName(); + if (functionResolverMap.containsKey(functionName)) { + return functionResolverMap.get(functionName).resolve(functionSignature); + } else { + throw new ExpressionEvaluationException( + String.format("unsupported function name: %s", functionName.getFunctionName())); } + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/FunctionBuilder.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/FunctionBuilder.java index 30a889b28e..16353bb73d 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/FunctionBuilder.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/FunctionBuilder.java @@ -16,19 +16,19 @@ package com.amazon.opendistroforelasticsearch.sql.expression.function; import com.amazon.opendistroforelasticsearch.sql.expression.Expression; - import java.util.List; /** - * The definition of function which create {@link FunctionImplementation} from input {@link Expression} list. + * The definition of function which create {@link FunctionImplementation} + * from input {@link Expression} list. */ public interface FunctionBuilder { - /** - * Create {@link FunctionImplementation} from input {@link Expression} list - * - * @param arguments {@link Expression} list - * @return {@link FunctionImplementation} - */ - FunctionImplementation apply(List arguments); + /** + * Create {@link FunctionImplementation} from input {@link Expression} list. + * + * @param arguments {@link Expression} list + * @return {@link FunctionImplementation} + */ + FunctionImplementation apply(List arguments); } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/FunctionImplementation.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/FunctionImplementation.java index 852b0cc364..9236e3dfae 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/FunctionImplementation.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/FunctionImplementation.java @@ -16,7 +16,6 @@ package com.amazon.opendistroforelasticsearch.sql.expression.function; import com.amazon.opendistroforelasticsearch.sql.expression.Expression; - import java.util.List; /** @@ -24,13 +23,13 @@ */ public interface FunctionImplementation { - /** - * Get Function Name. - */ - FunctionName getFunctionName(); + /** + * Get Function Name. + */ + FunctionName getFunctionName(); - /** - * Get Function Arguments. - */ - List getArguments(); + /** + * Get Function Arguments. + */ + List getArguments(); } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/FunctionName.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/FunctionName.java index 1b4eb06b56..a3611a0506 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/FunctionName.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/FunctionName.java @@ -25,15 +25,15 @@ @EqualsAndHashCode @RequiredArgsConstructor public class FunctionName { - @Getter - private final String functionName; + @Getter + private final String functionName; - public static FunctionName of(String functionName) { - return new FunctionName(functionName); - } + public static FunctionName of(String functionName) { + return new FunctionName(functionName); + } - @Override - public String toString() { - return functionName; - } + @Override + public String toString() { + return functionName; + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/FunctionResolver.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/FunctionResolver.java index 0727d9ddea..7df7423c48 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/FunctionResolver.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/FunctionResolver.java @@ -1,16 +1,15 @@ package com.amazon.opendistroforelasticsearch.sql.expression.function; import com.amazon.opendistroforelasticsearch.sql.exception.ExpressionEvaluationException; -import lombok.Builder; -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import lombok.Singular; - import java.util.AbstractMap; import java.util.Map; import java.util.PriorityQueue; import java.util.Set; import java.util.stream.Collectors; +import lombok.Builder; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Singular; /** * The Function Resolver hold the overload {@link FunctionBuilder} implementation. @@ -21,39 +20,40 @@ @Builder @RequiredArgsConstructor public class FunctionResolver { - @Getter - private final FunctionName functionName; - @Singular("functionBundle") - private final Map functionBundle; + @Getter + private final FunctionName functionName; + @Singular("functionBundle") + private final Map functionBundle; - /** - * Resolve the {@link FunctionBuilder} by using input {@link FunctionSignature}. - * If found the {@link FunctionBuilder} exactly match the input {@link FunctionSignature}, return it. - * If applying the widening rule, found the most match one, return it. - * If nothing found, throw {@link ExpressionEvaluationException} - */ - public FunctionBuilder resolve(FunctionSignature unresolvedSignature) { - PriorityQueue> functionMatchQueue = new PriorityQueue<>( - Map.Entry.comparingByKey()); + /** + * Resolve the {@link FunctionBuilder} by using input {@link FunctionSignature}. + * If the {@link FunctionBuilder} exactly match the input {@link FunctionSignature}, return it. + * If applying the widening rule, found the most match one, return it. + * If nothing found, throw {@link ExpressionEvaluationException} + */ + public FunctionBuilder resolve(FunctionSignature unresolvedSignature) { + PriorityQueue> functionMatchQueue = new PriorityQueue<>( + Map.Entry.comparingByKey()); - for (FunctionSignature functionSignature : functionBundle.keySet()) { - functionMatchQueue.add( - new AbstractMap.SimpleEntry<>(unresolvedSignature.match(functionSignature), functionSignature)); - } - Map.Entry bestMatchEntry = functionMatchQueue.peek(); - if (FunctionSignature.NOT_MATCH.equals(bestMatchEntry.getKey())) { - throw new ExpressionEvaluationException( - String.format("%s function expected %s, but get %s", functionName, - formatFunctions(functionBundle.keySet()), - unresolvedSignature.formatTypes() - )); - } else { - return functionBundle.get(bestMatchEntry.getValue()); - } + for (FunctionSignature functionSignature : functionBundle.keySet()) { + functionMatchQueue.add( + new AbstractMap.SimpleEntry<>(unresolvedSignature.match(functionSignature), + functionSignature)); } - - private String formatFunctions(Set functionSignatures) { - return functionSignatures.stream().map(FunctionSignature::formatTypes) - .collect(Collectors.joining(",", "{", "}")); + Map.Entry bestMatchEntry = functionMatchQueue.peek(); + if (FunctionSignature.NOT_MATCH.equals(bestMatchEntry.getKey())) { + throw new ExpressionEvaluationException( + String.format("%s function expected %s, but get %s", functionName, + formatFunctions(functionBundle.keySet()), + unresolvedSignature.formatTypes() + )); + } else { + return functionBundle.get(bestMatchEntry.getValue()); } + } + + private String formatFunctions(Set functionSignatures) { + return functionSignatures.stream().map(FunctionSignature::formatTypes) + .collect(Collectors.joining(",", "{", "}")); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/FunctionSignature.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/FunctionSignature.java index 7706c4571d..80f4a9444a 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/FunctionSignature.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/FunctionSignature.java @@ -1,13 +1,12 @@ package com.amazon.opendistroforelasticsearch.sql.expression.function; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprType; +import java.util.List; +import java.util.stream.Collectors; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.RequiredArgsConstructor; -import java.util.List; -import java.util.stream.Collectors; - /** * Function signature is composed by function name and arguments list. */ @@ -15,44 +14,46 @@ @RequiredArgsConstructor @EqualsAndHashCode public class FunctionSignature { - public static final Integer NOT_MATCH = Integer.MAX_VALUE; - public static final Integer EXACTLY_MATCH = 0; - - private final FunctionName functionName; - private final List paramTypeList; + public static final Integer NOT_MATCH = Integer.MAX_VALUE; + public static final Integer EXACTLY_MATCH = 0; - /** - * calculate the function signature match degree. - * - * @return EXACTLY_MATCH: exactly match, NOT_MATCH: not match, by widening rule small number means better match. - */ - public int match(FunctionSignature functionSignature) { - List functionTypeList = functionSignature.getParamTypeList(); - if (!functionName.equals(functionSignature.getFunctionName()) - || paramTypeList.size() != functionTypeList.size()) { - return NOT_MATCH; - } + private final FunctionName functionName; + private final List paramTypeList; - int matchDegree = EXACTLY_MATCH; - for (int i = 0; i < paramTypeList.size(); i++) { - ExprType paramType = paramTypeList.get(i); - ExprType funcType = functionTypeList.get(i); - int match = WideningTypeRule.distance(paramType, funcType); - if (match == WideningTypeRule.IMPOSSIBLE_WIDENING) { - return NOT_MATCH; - } else { - matchDegree += match; - } - } - return matchDegree; + /** + * calculate the function signature match degree. + * + * @return EXACTLY_MATCH: exactly match + * NOT_MATCH: not match + * By widening rule, the small number means better match + */ + public int match(FunctionSignature functionSignature) { + List functionTypeList = functionSignature.getParamTypeList(); + if (!functionName.equals(functionSignature.getFunctionName()) + || paramTypeList.size() != functionTypeList.size()) { + return NOT_MATCH; } - /** - * util function for formatted arguments list - */ - public String formatTypes() { - return getParamTypeList().stream() - .map(Enum::toString) - .collect(Collectors.joining(",", "[", "]")); + int matchDegree = EXACTLY_MATCH; + for (int i = 0; i < paramTypeList.size(); i++) { + ExprType paramType = paramTypeList.get(i); + ExprType funcType = functionTypeList.get(i); + int match = WideningTypeRule.distance(paramType, funcType); + if (match == WideningTypeRule.IMPOSSIBLE_WIDENING) { + return NOT_MATCH; + } else { + matchDegree += match; + } } + return matchDegree; + } + + /** + * util function for formatted arguments list. + */ + public String formatTypes() { + return getParamTypeList().stream() + .map(Enum::toString) + .collect(Collectors.joining(",", "[", "]")); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/WideningTypeRule.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/WideningTypeRule.java index eba5e992f0..02b344ddba 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/WideningTypeRule.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/function/WideningTypeRule.java @@ -15,13 +15,6 @@ package com.amazon.opendistroforelasticsearch.sql.expression.function; -import com.amazon.opendistroforelasticsearch.sql.data.model.ExprType; -import com.amazon.opendistroforelasticsearch.sql.exception.ExpressionEvaluationException; -import com.google.common.collect.ImmutableMap; -import lombok.experimental.UtilityClass; - -import java.util.Map; - import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprType.ARRAY; import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprType.BOOLEAN; import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprType.DOUBLE; @@ -32,6 +25,12 @@ import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprType.STRUCT; import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprType.UNKNOWN; +import com.amazon.opendistroforelasticsearch.sql.data.model.ExprType; +import com.amazon.opendistroforelasticsearch.sql.exception.ExpressionEvaluationException; +import com.google.common.collect.ImmutableMap; +import java.util.Map; +import lombok.experimental.UtilityClass; + /** * The definition of widening type rule for expression value. * ExprType Widens to data types @@ -46,63 +45,65 @@ */ @UtilityClass public class WideningTypeRule { - public static final int IMPOSSIBLE_WIDENING = Integer.MAX_VALUE; - public static final int TYPE_EQUAL = 0; + public static final int IMPOSSIBLE_WIDENING = Integer.MAX_VALUE; + public static final int TYPE_EQUAL = 0; - private static final Map typeToWidenParent; + private static final Map typeToWidenParent; - static { - ImmutableMap.Builder builder = new ImmutableMap.Builder<>(); - builder.put(INTEGER, LONG); - builder.put(LONG, FLOAT); - builder.put(FLOAT, DOUBLE); - builder.put(DOUBLE, UNKNOWN); - builder.put(STRING, UNKNOWN); - builder.put(BOOLEAN, UNKNOWN); - builder.put(ARRAY, UNKNOWN); - builder.put(STRUCT, UNKNOWN); - typeToWidenParent = builder.build(); - } + static { + ImmutableMap.Builder builder = new ImmutableMap.Builder<>(); + builder.put(INTEGER, LONG); + builder.put(LONG, FLOAT); + builder.put(FLOAT, DOUBLE); + builder.put(DOUBLE, UNKNOWN); + builder.put(STRING, UNKNOWN); + builder.put(BOOLEAN, UNKNOWN); + builder.put(ARRAY, UNKNOWN); + builder.put(STRUCT, UNKNOWN); + typeToWidenParent = builder.build(); + } - /** - * The widening distance is calculated from the leaf to root. - * e.g. distance(INTEGER, FLOAT) = 2, but distance(FLOAT, INTEGER) = - * - * @param type1 widen from type - * @param type2 widen to type - * @return The widening distance when widen one type to another type. - */ - public static int distance(ExprType type1, ExprType type2) { - return distance(type1, type2, TYPE_EQUAL); - } + /** + * The widening distance is calculated from the leaf to root. + * e.g. distance(INTEGER, FLOAT) = 2, but distance(FLOAT, INTEGER) = + * + * @param type1 widen from type + * @param type2 widen to type + * @return The widening distance when widen one type to another type. + */ + public static int distance(ExprType type1, ExprType type2) { + return distance(type1, type2, TYPE_EQUAL); + } - private static int distance(ExprType type1, ExprType type2, int distance) { - if (type1 == UNKNOWN) { - return IMPOSSIBLE_WIDENING; - } else if (type1 == type2) { - return distance; - } else { - return distance(typeToWidenParent.get(type1), type2, distance + 1); - } + private static int distance(ExprType type1, ExprType type2, int distance) { + if (type1 == UNKNOWN) { + return IMPOSSIBLE_WIDENING; + } else if (type1 == type2) { + return distance; + } else { + return distance(typeToWidenParent.get(type1), type2, distance + 1); } + } - /** - * The max type among two types. The max is defined as follow - * if type1 could widen to type2, then max is type2, vice versa - * if type1 could't widen to type2 and type2 could't widen to type1, then throw {@link ExpressionEvaluationException} - * - * @param type1 type1 - * @param type2 type2 - * @return the max type among two types. - */ - public static ExprType max(ExprType type1, ExprType type2) { - int type1To2 = distance(type1, type2); - int type2To1 = distance(type2, type1); + /** + * The max type among two types. The max is defined as follow + * if type1 could widen to type2, then max is type2, vice versa + * if type1 could't widen to type2 and type2 could't widen to type1, + * then throw {@link ExpressionEvaluationException}. + * + * @param type1 type1 + * @param type2 type2 + * @return the max type among two types. + */ + public static ExprType max(ExprType type1, ExprType type2) { + int type1To2 = distance(type1, type2); + int type2To1 = distance(type2, type1); - if (type1To2 == Integer.MAX_VALUE && type2To1 == Integer.MAX_VALUE) { - throw new ExpressionEvaluationException(String.format("no max type of %s and %s ", type1, type2)); - } else { - return type1To2 == Integer.MAX_VALUE ? type1 : type2; - } + if (type1To2 == Integer.MAX_VALUE && type2To1 == Integer.MAX_VALUE) { + throw new ExpressionEvaluationException( + String.format("no max type of %s and %s ", type1, type2)); + } else { + return type1To2 == Integer.MAX_VALUE ? type1 : type2; } + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/scalar/OperatorUtils.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/scalar/OperatorUtils.java index 3bae857cc8..d4c20fe38d 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/scalar/OperatorUtils.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/scalar/OperatorUtils.java @@ -36,11 +36,11 @@ public class OperatorUtils { * Construct {@link FunctionBuilder} which call function with arguments produced by observer. * * @param functionName function name - * @param function {@link BiFunction} - * @param observer extract the value of type T from the first argument - * @param returnType return type - * @param the type of the first and second argument to the function - * @param the type of the result of the function + * @param function {@link BiFunction} + * @param observer extract the value of type T from the first argument + * @param returnType return type + * @param the type of the first and second argument to the function + * @param the type of the result of the function * @return {@link FunctionBuilder} */ public static FunctionBuilder binaryOperator( @@ -55,16 +55,16 @@ public static FunctionBuilder binaryOperator( * Construct {@link FunctionBuilder} which call function with arguments produced by observer1 and * observer2 In general, if any operand evaluates to a MISSING value, the enclosing operator will * return MISSING; if none of operands evaluates to a MISSING value but there is an operand - * evaluates to a NULL value, the enclosing operator will return NULL + * evaluates to a NULL value, the enclosing operator will return NULL. * * @param functionName function name - * @param function {@link BiFunction} - * @param observer1 extract the value of type T from the first argument - * @param observer2 extract the value of type U from the second argument - * @param returnType return type - * @param the type of the first argument to the function - * @param the type of the second argument to the function - * @param the type of the result of the function + * @param function {@link BiFunction} + * @param observer1 extract the value of type T from the first argument + * @param observer2 extract the value of type U from the second argument + * @param returnType return type + * @param the type of the first argument to the function + * @param the type of the second argument to the function + * @param the type of the result of the function * @return {@link FunctionBuilder} */ public static FunctionBuilder binaryOperator( @@ -100,14 +100,14 @@ public ExprType type(Environment env) { * Construct {@link FunctionBuilder} which call function with arguments produced by observer In * general, if any operand evaluates to a MISSING value, the enclosing operator will return * MISSING; if none of operands evaluates to a MISSING value but there is an operand evaluates to - * a NULL value, the enclosing operator will return NULL + * a NULL value, the enclosing operator will return NULL. * * @param functionName function name - * @param function {@link Function} - * @param observer extract the value of type T from the first argument - * @param returnType return type - * @param the type of the first argument to the function - * @param the type of the result of the function + * @param function {@link Function} + * @param observer extract the value of type T from the first argument + * @param returnType return type + * @param the type of the first argument to the function + * @param the type of the result of the function * @return {@link FunctionBuilder} */ public static FunctionBuilder unaryOperator( @@ -136,15 +136,23 @@ public ExprType type(Environment env) { }; } - /** String comparator */ + /** + * String comparator. + */ public static final BiFunction STRING_COMPARATOR = String::compareTo; - /** List comparator */ + /** + * List comparator. + */ public static final BiFunction LIST_COMPARATOR = (left, right) -> Integer.compare(left.size(), right.size()); - /** Map comparator */ + /** + * Map comparator. + */ public static final BiFunction MAP_COMPARATOR = (left, right) -> Integer.compare(left.size(), right.size()); - /** Predicate NULL or MISSING */ + /** + * Predicate NULL or MISSING. + */ public static final BiPredicate COMPARE_WITH_NULL_OR_MISSING = (left, right) -> left.isMissing() || right.isMissing() || left.isNull() || right.isNull(); } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/scalar/arthmetic/ArithmeticFunction.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/scalar/arthmetic/ArithmeticFunction.java index c409b76fc0..a949d68c5d 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/scalar/arthmetic/ArithmeticFunction.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/scalar/arthmetic/ArithmeticFunction.java @@ -15,6 +15,8 @@ package com.amazon.opendistroforelasticsearch.sql.expression.scalar.arthmetic; +import static com.amazon.opendistroforelasticsearch.sql.expression.scalar.OperatorUtils.binaryOperator; + import com.amazon.opendistroforelasticsearch.sql.data.model.ExprType; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils; import com.amazon.opendistroforelasticsearch.sql.expression.function.BuiltinFunctionName; @@ -24,13 +26,10 @@ import com.amazon.opendistroforelasticsearch.sql.expression.function.FunctionResolver; import com.amazon.opendistroforelasticsearch.sql.expression.function.FunctionSignature; import com.google.common.collect.ImmutableMap; -import lombok.experimental.UtilityClass; - import java.util.Arrays; import java.util.Map; import java.util.function.BiFunction; - -import static com.amazon.opendistroforelasticsearch.sql.expression.scalar.OperatorUtils.binaryOperator; +import lombok.experimental.UtilityClass; /** * The definition of arithmetic function @@ -42,86 +41,93 @@ */ @UtilityClass public class ArithmeticFunction { + /** + * Register Arithmetic Function. + * @param repository {@link BuiltinFunctionRepository}. + */ + public static void register(BuiltinFunctionRepository repository) { + repository.register(add()); + repository.register(subtract()); + repository.register(multiply()); + repository.register(divide()); + repository.register(modules()); + } - public static void register(BuiltinFunctionRepository repository) { - repository.register(add()); - repository.register(subtract()); - repository.register(multiply()); - repository.register(divide()); - repository.register(modules()); - } - - private static FunctionResolver add() { - return new FunctionResolver( - BuiltinFunctionName.ADD.getName(), - scalarFunction(BuiltinFunctionName.ADD.getName(), - Math::addExact, - Math::addExact, - Float::sum, - Double::sum) - ); - } + private static FunctionResolver add() { + return new FunctionResolver( + BuiltinFunctionName.ADD.getName(), + scalarFunction(BuiltinFunctionName.ADD.getName(), + Math::addExact, + Math::addExact, + Float::sum, + Double::sum) + ); + } - private static FunctionResolver subtract() { - return new FunctionResolver( - BuiltinFunctionName.SUBTRACT.getName(), - scalarFunction(BuiltinFunctionName.SUBTRACT.getName(), - Math::subtractExact, - Math::subtractExact, - (v1, v2) -> v1 - v2, - (v1, v2) -> v1 - v2) - ); - } + private static FunctionResolver subtract() { + return new FunctionResolver( + BuiltinFunctionName.SUBTRACT.getName(), + scalarFunction(BuiltinFunctionName.SUBTRACT.getName(), + Math::subtractExact, + Math::subtractExact, + (v1, v2) -> v1 - v2, + (v1, v2) -> v1 - v2) + ); + } - private static FunctionResolver multiply() { - return new FunctionResolver( - BuiltinFunctionName.MULTIPLY.getName(), - scalarFunction(BuiltinFunctionName.MULTIPLY.getName(), - Math::multiplyExact, - Math::multiplyExact, - (v1, v2) -> v1 * v2, - (v1, v2) -> v1 * v2) - ); - } + private static FunctionResolver multiply() { + return new FunctionResolver( + BuiltinFunctionName.MULTIPLY.getName(), + scalarFunction(BuiltinFunctionName.MULTIPLY.getName(), + Math::multiplyExact, + Math::multiplyExact, + (v1, v2) -> v1 * v2, + (v1, v2) -> v1 * v2) + ); + } - private static FunctionResolver divide() { - return new FunctionResolver( - BuiltinFunctionName.DIVIDE.getName(), - scalarFunction(BuiltinFunctionName.DIVIDE.getName(), - (v1, v2) -> v1 / v2, - (v1, v2) -> v1 / v2, - (v1, v2) -> v1 / v2, - (v1, v2) -> v1 / v2) - ); - } + private static FunctionResolver divide() { + return new FunctionResolver( + BuiltinFunctionName.DIVIDE.getName(), + scalarFunction(BuiltinFunctionName.DIVIDE.getName(), + (v1, v2) -> v1 / v2, + (v1, v2) -> v1 / v2, + (v1, v2) -> v1 / v2, + (v1, v2) -> v1 / v2) + ); + } - private static FunctionResolver modules() { - return new FunctionResolver( - BuiltinFunctionName.MODULES.getName(), - scalarFunction(BuiltinFunctionName.MODULES.getName(), - (v1, v2) -> v1 % v2, - (v1, v2) -> v1 % v2, - (v1, v2) -> v1 % v2, - (v1, v2) -> v1 % v2) - ); - } + private static FunctionResolver modules() { + return new FunctionResolver( + BuiltinFunctionName.MODULES.getName(), + scalarFunction(BuiltinFunctionName.MODULES.getName(), + (v1, v2) -> v1 % v2, + (v1, v2) -> v1 % v2, + (v1, v2) -> v1 % v2, + (v1, v2) -> v1 % v2) + ); + } - private static Map scalarFunction( - FunctionName functionName, - BiFunction integerFunc, - BiFunction longFunc, - BiFunction floatFunc, - BiFunction doubleFunc) { - ImmutableMap.Builder builder = new ImmutableMap.Builder<>(); - builder.put(new FunctionSignature(functionName, Arrays.asList(ExprType.INTEGER, ExprType.INTEGER)), - binaryOperator(functionName, integerFunc, ExprValueUtils::getIntegerValue, ExprType.INTEGER)); - builder.put(new FunctionSignature(functionName, Arrays.asList(ExprType.LONG, ExprType.LONG)), - binaryOperator(functionName, longFunc, ExprValueUtils::getLongValue, ExprType.LONG)); - builder.put(new FunctionSignature(functionName, Arrays.asList(ExprType.FLOAT, ExprType.FLOAT)), - binaryOperator(functionName, floatFunc, ExprValueUtils::getFloatValue, ExprType.FLOAT)); - builder.put(new FunctionSignature(functionName, Arrays.asList(ExprType.DOUBLE, ExprType.DOUBLE)), - binaryOperator(functionName, doubleFunc, ExprValueUtils::getDoubleValue, ExprType.DOUBLE)); - return builder.build(); - } + private static Map scalarFunction( + FunctionName functionName, + BiFunction integerFunc, + BiFunction longFunc, + BiFunction floatFunc, + BiFunction doubleFunc) { + ImmutableMap.Builder builder = new ImmutableMap.Builder<>(); + builder + .put(new FunctionSignature(functionName, Arrays.asList(ExprType.INTEGER, ExprType.INTEGER)), + binaryOperator(functionName, integerFunc, ExprValueUtils::getIntegerValue, + ExprType.INTEGER)); + builder.put(new FunctionSignature(functionName, Arrays.asList(ExprType.LONG, ExprType.LONG)), + binaryOperator(functionName, longFunc, ExprValueUtils::getLongValue, ExprType.LONG)); + builder.put(new FunctionSignature(functionName, Arrays.asList(ExprType.FLOAT, ExprType.FLOAT)), + binaryOperator(functionName, floatFunc, ExprValueUtils::getFloatValue, ExprType.FLOAT)); + builder + .put(new FunctionSignature(functionName, Arrays.asList(ExprType.DOUBLE, ExprType.DOUBLE)), + binaryOperator(functionName, doubleFunc, ExprValueUtils::getDoubleValue, + ExprType.DOUBLE)); + return builder.build(); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/scalar/predicate/BinaryPredicateFunction.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/scalar/predicate/BinaryPredicateFunction.java index e1e962aad7..67d01b63d1 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/scalar/predicate/BinaryPredicateFunction.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/scalar/predicate/BinaryPredicateFunction.java @@ -15,6 +15,11 @@ package com.amazon.opendistroforelasticsearch.sql.expression.scalar.predicate; +import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.LITERAL_FALSE; +import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.LITERAL_MISSING; +import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.LITERAL_NULL; +import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.LITERAL_TRUE; + import com.amazon.opendistroforelasticsearch.sql.data.model.ExprType; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprValue; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils; @@ -30,265 +35,269 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableTable; import com.google.common.collect.Table; -import lombok.experimental.UtilityClass; - import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.function.BiFunction; import java.util.function.Function; - -import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.LITERAL_FALSE; -import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.LITERAL_MISSING; -import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.LITERAL_NULL; -import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.LITERAL_TRUE; +import lombok.experimental.UtilityClass; /** * The definition of binary predicate function * and, Accepts two Boolean values and produces a Boolean. * or, Accepts two Boolean values and produces a Boolean. * xor, Accepts two Boolean values and produces a Boolean. - * equal, Compare the left expression and right expression and produces a Boolean. + * equalTo, Compare the left expression and right expression and produces a Boolean. */ @UtilityClass public class BinaryPredicateFunction { - public static void register(BuiltinFunctionRepository repository) { - repository.register(and()); - repository.register(or()); - repository.register(xor()); - repository.register(equal()); - } + /** + * Register Binary Predicate Function. + * + * @param repository {@link BuiltinFunctionRepository}. + */ + public static void register(BuiltinFunctionRepository repository) { + repository.register(and()); + repository.register(or()); + repository.register(xor()); + repository.register(equal()); + } - /** - * The and logic - * A B A AND B - * TRUE TRUE TRUE - * TRUE FALSE FALSE - * TRUE NULL NULL - * TRUE MISSING MISSING - * FALSE FALSE FALSE - * FALSE NULL FALSE - * FALSE MISSING FALSE - * NULL NULL NULL - * NULL MISSING MISSING - * MISSING MISSING MISSING - */ - private static Table andTable = - new ImmutableTable.Builder() - .put(LITERAL_TRUE, LITERAL_TRUE, LITERAL_TRUE) - .put(LITERAL_TRUE, LITERAL_FALSE, LITERAL_FALSE) - .put(LITERAL_TRUE, LITERAL_NULL, LITERAL_NULL) - .put(LITERAL_TRUE, LITERAL_MISSING, LITERAL_MISSING) - .put(LITERAL_FALSE, LITERAL_FALSE, LITERAL_FALSE) - .put(LITERAL_FALSE, LITERAL_NULL, LITERAL_FALSE) - .put(LITERAL_FALSE, LITERAL_MISSING, LITERAL_FALSE) - .put(LITERAL_NULL, LITERAL_NULL, LITERAL_NULL) - .put(LITERAL_NULL, LITERAL_MISSING, LITERAL_MISSING) - .put(LITERAL_MISSING, LITERAL_MISSING, LITERAL_MISSING) - .build(); + /** + * The and logic. + * A B A AND B + * TRUE TRUE TRUE + * TRUE FALSE FALSE + * TRUE NULL NULL + * TRUE MISSING MISSING + * FALSE FALSE FALSE + * FALSE NULL FALSE + * FALSE MISSING FALSE + * NULL NULL NULL + * NULL MISSING MISSING + * MISSING MISSING MISSING + */ + private static Table andTable = + new ImmutableTable.Builder() + .put(LITERAL_TRUE, LITERAL_TRUE, LITERAL_TRUE) + .put(LITERAL_TRUE, LITERAL_FALSE, LITERAL_FALSE) + .put(LITERAL_TRUE, LITERAL_NULL, LITERAL_NULL) + .put(LITERAL_TRUE, LITERAL_MISSING, LITERAL_MISSING) + .put(LITERAL_FALSE, LITERAL_FALSE, LITERAL_FALSE) + .put(LITERAL_FALSE, LITERAL_NULL, LITERAL_FALSE) + .put(LITERAL_FALSE, LITERAL_MISSING, LITERAL_FALSE) + .put(LITERAL_NULL, LITERAL_NULL, LITERAL_NULL) + .put(LITERAL_NULL, LITERAL_MISSING, LITERAL_MISSING) + .put(LITERAL_MISSING, LITERAL_MISSING, LITERAL_MISSING) + .build(); - /** - * The or logic - * A B A AND B - * TRUE TRUE TRUE - * TRUE FALSE TRUE - * TRUE NULL TRUE - * TRUE MISSING TRUE - * FALSE FALSE FALSE - * FALSE NULL NULL - * FALSE MISSING MISSING - * NULL NULL NULL - * NULL MISSING NULL - * MISSING MISSING MISSING - */ - private static Table orTable = - new ImmutableTable.Builder() - .put(LITERAL_TRUE, LITERAL_TRUE, LITERAL_TRUE) - .put(LITERAL_TRUE, LITERAL_FALSE, LITERAL_TRUE) - .put(LITERAL_TRUE, LITERAL_NULL, LITERAL_TRUE) - .put(LITERAL_TRUE, LITERAL_MISSING, LITERAL_TRUE) - .put(LITERAL_FALSE, LITERAL_FALSE, LITERAL_FALSE) - .put(LITERAL_FALSE, LITERAL_NULL, LITERAL_NULL) - .put(LITERAL_FALSE, LITERAL_MISSING, LITERAL_MISSING) - .put(LITERAL_NULL, LITERAL_NULL, LITERAL_NULL) - .put(LITERAL_NULL, LITERAL_MISSING, LITERAL_NULL) - .put(LITERAL_MISSING, LITERAL_MISSING, LITERAL_MISSING) - .build(); + /** + * The or logic. + * A B A AND B + * TRUE TRUE TRUE + * TRUE FALSE TRUE + * TRUE NULL TRUE + * TRUE MISSING TRUE + * FALSE FALSE FALSE + * FALSE NULL NULL + * FALSE MISSING MISSING + * NULL NULL NULL + * NULL MISSING NULL + * MISSING MISSING MISSING + */ + private static Table orTable = + new ImmutableTable.Builder() + .put(LITERAL_TRUE, LITERAL_TRUE, LITERAL_TRUE) + .put(LITERAL_TRUE, LITERAL_FALSE, LITERAL_TRUE) + .put(LITERAL_TRUE, LITERAL_NULL, LITERAL_TRUE) + .put(LITERAL_TRUE, LITERAL_MISSING, LITERAL_TRUE) + .put(LITERAL_FALSE, LITERAL_FALSE, LITERAL_FALSE) + .put(LITERAL_FALSE, LITERAL_NULL, LITERAL_NULL) + .put(LITERAL_FALSE, LITERAL_MISSING, LITERAL_MISSING) + .put(LITERAL_NULL, LITERAL_NULL, LITERAL_NULL) + .put(LITERAL_NULL, LITERAL_MISSING, LITERAL_NULL) + .put(LITERAL_MISSING, LITERAL_MISSING, LITERAL_MISSING) + .build(); - /** - * The xor logic - * A B A AND B - * TRUE TRUE FALSE - * TRUE FALSE TRUE - * TRUE NULL TRUE - * TRUE MISSING TRUE - * FALSE FALSE FALSE - * FALSE NULL NULL - * FALSE MISSING MISSING - * NULL NULL NULL - * NULL MISSING NULL - * MISSING MISSING MISSING - */ - private static Table xorTable = - new ImmutableTable.Builder() - .put(LITERAL_TRUE, LITERAL_TRUE, LITERAL_FALSE) - .put(LITERAL_TRUE, LITERAL_FALSE, LITERAL_TRUE) - .put(LITERAL_TRUE, LITERAL_NULL, LITERAL_TRUE) - .put(LITERAL_TRUE, LITERAL_MISSING, LITERAL_TRUE) - .put(LITERAL_FALSE, LITERAL_FALSE, LITERAL_FALSE) - .put(LITERAL_FALSE, LITERAL_NULL, LITERAL_NULL) - .put(LITERAL_FALSE, LITERAL_MISSING, LITERAL_MISSING) - .put(LITERAL_NULL, LITERAL_NULL, LITERAL_NULL) - .put(LITERAL_NULL, LITERAL_MISSING, LITERAL_NULL) - .put(LITERAL_MISSING, LITERAL_MISSING, LITERAL_MISSING) - .build(); + /** + * The xor logic. + * A B A AND B + * TRUE TRUE FALSE + * TRUE FALSE TRUE + * TRUE NULL TRUE + * TRUE MISSING TRUE + * FALSE FALSE FALSE + * FALSE NULL NULL + * FALSE MISSING MISSING + * NULL NULL NULL + * NULL MISSING NULL + * MISSING MISSING MISSING + */ + private static Table xorTable = + new ImmutableTable.Builder() + .put(LITERAL_TRUE, LITERAL_TRUE, LITERAL_FALSE) + .put(LITERAL_TRUE, LITERAL_FALSE, LITERAL_TRUE) + .put(LITERAL_TRUE, LITERAL_NULL, LITERAL_TRUE) + .put(LITERAL_TRUE, LITERAL_MISSING, LITERAL_TRUE) + .put(LITERAL_FALSE, LITERAL_FALSE, LITERAL_FALSE) + .put(LITERAL_FALSE, LITERAL_NULL, LITERAL_NULL) + .put(LITERAL_FALSE, LITERAL_MISSING, LITERAL_MISSING) + .put(LITERAL_NULL, LITERAL_NULL, LITERAL_NULL) + .put(LITERAL_NULL, LITERAL_MISSING, LITERAL_NULL) + .put(LITERAL_MISSING, LITERAL_MISSING, LITERAL_MISSING) + .build(); - /** - * The equal logic - * A B A == B - * NULL NULL TRUE - * NULL MISSING FALSE - * MISSING NULL FALSE - * MISSING MISSING TRUE - */ - private static Table equalTable = - new ImmutableTable.Builder() - .put(LITERAL_NULL, LITERAL_NULL, LITERAL_TRUE) - .put(LITERAL_NULL, LITERAL_MISSING, LITERAL_FALSE) - .put(LITERAL_MISSING, LITERAL_NULL, LITERAL_FALSE) - .put(LITERAL_MISSING, LITERAL_MISSING, LITERAL_TRUE) - .build(); + /** + * The equalTo logic. + * A B A == B + * NULL NULL TRUE + * NULL MISSING FALSE + * MISSING NULL FALSE + * MISSING MISSING TRUE + */ + private static Table equalTable = + new ImmutableTable.Builder() + .put(LITERAL_NULL, LITERAL_NULL, LITERAL_TRUE) + .put(LITERAL_NULL, LITERAL_MISSING, LITERAL_FALSE) + .put(LITERAL_MISSING, LITERAL_NULL, LITERAL_FALSE) + .put(LITERAL_MISSING, LITERAL_MISSING, LITERAL_TRUE) + .build(); - private static FunctionResolver and() { - FunctionName functionName = BuiltinFunctionName.AND.getName(); - return FunctionResolver.builder() - .functionName(functionName) - .functionBundle(new FunctionSignature(functionName, - Arrays.asList(ExprType.BOOLEAN, ExprType.BOOLEAN)), binaryPredicate(functionName, - andTable, ExprType.BOOLEAN)) - .build(); - } + private static FunctionResolver and() { + FunctionName functionName = BuiltinFunctionName.AND.getName(); + return FunctionResolver.builder() + .functionName(functionName) + .functionBundle(new FunctionSignature(functionName, + Arrays.asList(ExprType.BOOLEAN, ExprType.BOOLEAN)), binaryPredicate(functionName, + andTable, ExprType.BOOLEAN)) + .build(); + } - private static FunctionResolver or() { - FunctionName functionName = BuiltinFunctionName.OR.getName(); - return FunctionResolver.builder() - .functionName(functionName) - .functionBundle(new FunctionSignature(functionName, - Arrays.asList(ExprType.BOOLEAN, ExprType.BOOLEAN)), binaryPredicate(functionName, - orTable, ExprType.BOOLEAN)) - .build(); - } + private static FunctionResolver or() { + FunctionName functionName = BuiltinFunctionName.OR.getName(); + return FunctionResolver.builder() + .functionName(functionName) + .functionBundle(new FunctionSignature(functionName, + Arrays.asList(ExprType.BOOLEAN, ExprType.BOOLEAN)), binaryPredicate(functionName, + orTable, ExprType.BOOLEAN)) + .build(); + } - private static FunctionResolver xor() { - FunctionName functionName = BuiltinFunctionName.XOR.getName(); - return FunctionResolver.builder() - .functionName(functionName) - .functionBundle(new FunctionSignature(functionName, - Arrays.asList(ExprType.BOOLEAN, ExprType.BOOLEAN)), binaryPredicate(functionName, - xorTable, ExprType.BOOLEAN)) - .build(); - } + private static FunctionResolver xor() { + FunctionName functionName = BuiltinFunctionName.XOR.getName(); + return FunctionResolver.builder() + .functionName(functionName) + .functionBundle(new FunctionSignature(functionName, + Arrays.asList(ExprType.BOOLEAN, ExprType.BOOLEAN)), binaryPredicate(functionName, + xorTable, ExprType.BOOLEAN)) + .build(); + } - private static FunctionResolver equal() { - return new FunctionResolver( - BuiltinFunctionName.EQUAL.getName(), - predicateFunction( - BuiltinFunctionName.EQUAL.getName(), - Integer::equals, - Long::equals, - Float::equals, - Double::equals, - String::equals, - Boolean::equals, - List::equals, - Map::equals - ) - ); - } + private static FunctionResolver equal() { + return new FunctionResolver( + BuiltinFunctionName.EQUAL.getName(), + predicateFunction( + BuiltinFunctionName.EQUAL.getName(), + Integer::equals, + Long::equals, + Float::equals, + Double::equals, + String::equals, + Boolean::equals, + List::equals, + Map::equals + ) + ); + } - private static Map predicateFunction( - FunctionName functionName, - BiFunction integerFunc, - BiFunction longFunc, - BiFunction floatFunc, - BiFunction doubleFunc, - BiFunction stringFunc, - BiFunction booleanFunc, - BiFunction listFunc, - BiFunction mapFunc) { - ImmutableMap.Builder builder = new ImmutableMap.Builder<>(); - builder.put(new FunctionSignature(functionName, Arrays.asList(ExprType.INTEGER, ExprType.INTEGER)), - equal(functionName, integerFunc, ExprValueUtils::getIntegerValue, - ExprType.BOOLEAN)); - builder.put(new FunctionSignature(functionName, Arrays.asList(ExprType.LONG, ExprType.LONG)), - equal(functionName, longFunc, ExprValueUtils::getLongValue, - ExprType.BOOLEAN)); - builder.put(new FunctionSignature(functionName, Arrays.asList(ExprType.FLOAT, ExprType.FLOAT)), - equal(functionName, floatFunc, ExprValueUtils::getFloatValue, - ExprType.BOOLEAN)); - builder.put(new FunctionSignature(functionName, Arrays.asList(ExprType.DOUBLE, ExprType.DOUBLE)), - equal(functionName, doubleFunc, ExprValueUtils::getDoubleValue, - ExprType.BOOLEAN)); - builder.put(new FunctionSignature(functionName, Arrays.asList(ExprType.STRING, ExprType.STRING)), - equal(functionName, stringFunc, ExprValueUtils::getStringValue, - ExprType.BOOLEAN)); - builder.put(new FunctionSignature(functionName, Arrays.asList(ExprType.BOOLEAN, ExprType.BOOLEAN)), - equal(functionName, booleanFunc, ExprValueUtils::getBooleanValue, - ExprType.BOOLEAN)); - builder.put(new FunctionSignature(functionName, Arrays.asList(ExprType.ARRAY, ExprType.ARRAY)), - equal(functionName, listFunc, ExprValueUtils::getCollectionValue, - ExprType.BOOLEAN)); - builder.put(new FunctionSignature(functionName, Arrays.asList(ExprType.STRUCT, ExprType.STRUCT)), - equal(functionName, mapFunc, ExprValueUtils::getTupleValue, - ExprType.BOOLEAN)); - return builder.build(); - } + private static Map predicateFunction( + FunctionName functionName, + BiFunction integerFunc, + BiFunction longFunc, + BiFunction floatFunc, + BiFunction doubleFunc, + BiFunction stringFunc, + BiFunction booleanFunc, + BiFunction listFunc, + BiFunction mapFunc) { + ImmutableMap.Builder builder = new ImmutableMap.Builder<>(); + builder + .put(new FunctionSignature(functionName, Arrays.asList(ExprType.INTEGER, ExprType.INTEGER)), + equalTo(functionName, integerFunc, ExprValueUtils::getIntegerValue, + ExprType.BOOLEAN)); + builder.put(new FunctionSignature(functionName, Arrays.asList(ExprType.LONG, ExprType.LONG)), + equalTo(functionName, longFunc, ExprValueUtils::getLongValue, + ExprType.BOOLEAN)); + builder.put(new FunctionSignature(functionName, Arrays.asList(ExprType.FLOAT, ExprType.FLOAT)), + equalTo(functionName, floatFunc, ExprValueUtils::getFloatValue, + ExprType.BOOLEAN)); + builder + .put(new FunctionSignature(functionName, Arrays.asList(ExprType.DOUBLE, ExprType.DOUBLE)), + equalTo(functionName, doubleFunc, ExprValueUtils::getDoubleValue, + ExprType.BOOLEAN)); + builder + .put(new FunctionSignature(functionName, Arrays.asList(ExprType.STRING, ExprType.STRING)), + equalTo(functionName, stringFunc, ExprValueUtils::getStringValue, + ExprType.BOOLEAN)); + builder + .put(new FunctionSignature(functionName, Arrays.asList(ExprType.BOOLEAN, ExprType.BOOLEAN)), + equalTo(functionName, booleanFunc, ExprValueUtils::getBooleanValue, + ExprType.BOOLEAN)); + builder.put(new FunctionSignature(functionName, Arrays.asList(ExprType.ARRAY, ExprType.ARRAY)), + equalTo(functionName, listFunc, ExprValueUtils::getCollectionValue, + ExprType.BOOLEAN)); + builder + .put(new FunctionSignature(functionName, Arrays.asList(ExprType.STRUCT, ExprType.STRUCT)), + equalTo(functionName, mapFunc, ExprValueUtils::getTupleValue, + ExprType.BOOLEAN)); + return builder.build(); + } - private static FunctionBuilder binaryPredicate(FunctionName functionName, - Table logicalTable, - ExprType returnType) { - return arguments -> new FunctionExpression(functionName, arguments) { - @Override - public ExprValue valueOf(Environment env) { - ExprValue arg1 = arguments.get(0).valueOf(env); - ExprValue arg2 = arguments.get(1).valueOf(env); - if (logicalTable.contains(arg1, arg2)) { - return logicalTable.get(arg1, arg2); - } else { - return logicalTable.get(arg2, arg1); - } - } + private static FunctionBuilder binaryPredicate(FunctionName functionName, + Table table, + ExprType returnType) { + return arguments -> new FunctionExpression(functionName, arguments) { + @Override + public ExprValue valueOf(Environment env) { + ExprValue arg1 = arguments.get(0).valueOf(env); + ExprValue arg2 = arguments.get(1).valueOf(env); + if (table.contains(arg1, arg2)) { + return table.get(arg1, arg2); + } else { + return table.get(arg2, arg1); + } + } - @Override - public ExprType type(Environment env) { - return returnType; - } - }; - } + @Override + public ExprType type(Environment env) { + return returnType; + } + }; + } - private static FunctionBuilder equal(FunctionName functionName, + private static FunctionBuilder equalTo(FunctionName functionName, BiFunction function, Function observer, ExprType returnType) { - return arguments -> new FunctionExpression(functionName, arguments) { - @Override - public ExprValue valueOf(Environment env) { - ExprValue arg1 = arguments.get(0).valueOf(env); - ExprValue arg2 = arguments.get(1).valueOf(env); - if (equalTable.contains(arg1, arg2)) { - return equalTable.get(arg1, arg2); - } else if (arg1.isMissing() || arg1.isNull() || arg2.isMissing() || arg2.isNull()) { - return LITERAL_FALSE; - } else { - return ExprValueUtils.fromObjectValue( - function.apply(observer.apply(arg1), observer.apply(arg2))); - } - } + return arguments -> new FunctionExpression(functionName, arguments) { + @Override + public ExprValue valueOf(Environment env) { + ExprValue arg1 = arguments.get(0).valueOf(env); + ExprValue arg2 = arguments.get(1).valueOf(env); + if (equalTable.contains(arg1, arg2)) { + return equalTable.get(arg1, arg2); + } else if (arg1.isMissing() || arg1.isNull() || arg2.isMissing() || arg2.isNull()) { + return LITERAL_FALSE; + } else { + return ExprValueUtils.fromObjectValue( + function.apply(observer.apply(arg1), observer.apply(arg2))); + } + } - @Override - public ExprType type(Environment env) { - return returnType; - } - }; - } + @Override + public ExprType type(Environment env) { + return returnType; + } + }; + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/scalar/predicate/UnaryPredicateFunction.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/scalar/predicate/UnaryPredicateFunction.java index d70f92b29f..953fb6b025 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/scalar/predicate/UnaryPredicateFunction.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/expression/scalar/predicate/UnaryPredicateFunction.java @@ -15,6 +15,11 @@ package com.amazon.opendistroforelasticsearch.sql.expression.scalar.predicate; +import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.LITERAL_FALSE; +import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.LITERAL_MISSING; +import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.LITERAL_NULL; +import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.LITERAL_TRUE; + import com.amazon.opendistroforelasticsearch.sql.data.model.ExprType; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprValue; import com.amazon.opendistroforelasticsearch.sql.expression.Expression; @@ -27,15 +32,9 @@ import com.amazon.opendistroforelasticsearch.sql.expression.function.FunctionResolver; import com.amazon.opendistroforelasticsearch.sql.expression.function.FunctionSignature; import com.google.common.collect.ImmutableMap; -import lombok.experimental.UtilityClass; - import java.util.Arrays; import java.util.Map; - -import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.LITERAL_FALSE; -import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.LITERAL_MISSING; -import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.LITERAL_NULL; -import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.LITERAL_TRUE; +import lombok.experimental.UtilityClass; /** * The definition of unary predicate function @@ -43,50 +42,50 @@ */ @UtilityClass public class UnaryPredicateFunction { - public static void register(BuiltinFunctionRepository repository) { - repository.register(not()); - } + public static void register(BuiltinFunctionRepository repository) { + repository.register(not()); + } - /** - * The or logic - * A NOT A - * TRUE FALSE - * FALSE TRUE - * NULL NULL - * MISSING MISSING - */ - private static Map notMap = - new ImmutableMap.Builder() - .put(LITERAL_TRUE, LITERAL_FALSE) - .put(LITERAL_FALSE, LITERAL_TRUE) - .put(LITERAL_NULL, LITERAL_NULL) - .put(LITERAL_MISSING, LITERAL_MISSING) - .build(); + /** + * The or logic. + * A NOT A + * TRUE FALSE + * FALSE TRUE + * NULL NULL + * MISSING MISSING + */ + private static Map notMap = + new ImmutableMap.Builder() + .put(LITERAL_TRUE, LITERAL_FALSE) + .put(LITERAL_FALSE, LITERAL_TRUE) + .put(LITERAL_NULL, LITERAL_NULL) + .put(LITERAL_MISSING, LITERAL_MISSING) + .build(); - private static FunctionResolver not() { - FunctionName functionName = BuiltinFunctionName.NOT.getName(); - return FunctionResolver.builder() - .functionName(functionName) - .functionBundle(new FunctionSignature(functionName, - Arrays.asList(ExprType.BOOLEAN)), predicateFunction(functionName, - notMap, ExprType.BOOLEAN)) - .build(); - } + private static FunctionResolver not() { + FunctionName functionName = BuiltinFunctionName.NOT.getName(); + return FunctionResolver.builder() + .functionName(functionName) + .functionBundle(new FunctionSignature(functionName, + Arrays.asList(ExprType.BOOLEAN)), predicateFunction(functionName, + notMap, ExprType.BOOLEAN)) + .build(); + } - private static FunctionBuilder predicateFunction( - FunctionName functionName, - Map map, - ExprType returnType) { - return arguments -> new FunctionExpression(functionName, arguments) { - @Override - public ExprValue valueOf(Environment env) { - return map.get(arguments.get(0).valueOf(env)); - } + private static FunctionBuilder predicateFunction( + FunctionName functionName, + Map map, + ExprType returnType) { + return arguments -> new FunctionExpression(functionName, arguments) { + @Override + public ExprValue valueOf(Environment env) { + return map.get(arguments.get(0).valueOf(env)); + } - @Override - public ExprType type(Environment env) { - return returnType; - } - }; - } + @Override + public ExprType type(Environment env) { + return returnType; + } + }; + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/PlanNode.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/PlanNode.java index 2af2f381d8..49bac8cf46 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/PlanNode.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/PlanNode.java @@ -18,14 +18,14 @@ import java.util.List; /** - * The definition of Plan Node + * The definition of Plan Node. */ public interface PlanNode { - /** - * Return the child nodes. - * - * @return child nodes. - */ - List getChild(); + /** + * Return the child nodes. + * + * @return child nodes. + */ + List getChild(); } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/Planner.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/Planner.java index 9815c74f29..fb96e02444 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/Planner.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/Planner.java @@ -30,39 +30,39 @@ @RequiredArgsConstructor public class Planner { - /** - * Storage engine - */ - private final StorageEngine storageEngine; + /** + * Storage engine. + */ + private final StorageEngine storageEngine; - /** - * Generate optimal physical plan for logical plan. - * TODO: for now just delegate entire logical plan to storage engine. - * - * @param plan logical plan - * @return optimal physical plan - */ - public PhysicalPlan plan(LogicalPlan plan) { - String tableName = findTableName(plan); - Table table = storageEngine.getTable(tableName); - return table.implement(plan); - } + /** + * Generate optimal physical plan for logical plan. + * TODO: for now just delegate entire logical plan to storage engine. + * + * @param plan logical plan + * @return optimal physical plan + */ + public PhysicalPlan plan(LogicalPlan plan) { + String tableName = findTableName(plan); + Table table = storageEngine.getTable(tableName); + return table.implement(plan); + } - private String findTableName(LogicalPlan plan) { - return plan.accept(new LogicalPlanNodeVisitor() { + private String findTableName(LogicalPlan plan) { + return plan.accept(new LogicalPlanNodeVisitor() { - @Override - protected String visitNode(LogicalPlan node, Object context) { - // So far all logical node has single child except LogicalRelation - // whose visitRelation() is already overridden. - return node.getChild().get(0).accept(this, context); - } + @Override + protected String visitNode(LogicalPlan node, Object context) { + // So far all logical node has single child except LogicalRelation + // whose visitRelation() is already overridden. + return node.getChild().get(0).accept(this, context); + } - @Override - public String visitRelation(LogicalRelation node, Object context) { - return node.getRelationName(); - } - }, null); - } + @Override + public String visitRelation(LogicalRelation node, Object context) { + return node.getRelationName(); + } + }, null); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalAggregation.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalAggregation.java index 0e6c10cd71..ef89d91cef 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalAggregation.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalAggregation.java @@ -17,14 +17,13 @@ import com.amazon.opendistroforelasticsearch.sql.expression.Expression; import com.amazon.opendistroforelasticsearch.sql.expression.aggregation.Aggregator; +import java.util.Collections; +import java.util.List; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.ToString; -import java.util.Collections; -import java.util.List; - /** * Logical Aggregation. */ @@ -32,19 +31,19 @@ @EqualsAndHashCode @RequiredArgsConstructor public class LogicalAggregation extends LogicalPlan { - private final LogicalPlan child; - @Getter - private final List aggregatorList; - @Getter - private final List groupByList; + private final LogicalPlan child; + @Getter + private final List aggregatorList; + @Getter + private final List groupByList; - @Override - public List getChild() { - return Collections.singletonList(child); - } + @Override + public List getChild() { + return Collections.singletonList(child); + } - @Override - public R accept(LogicalPlanNodeVisitor visitor, C context) { - return visitor.visitAggregation(this, context); - } + @Override + public R accept(LogicalPlanNodeVisitor visitor, C context) { + return visitor.visitAggregation(this, context); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalDedupe.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalDedupe.java index f410e56d46..5276c7a0b6 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalDedupe.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalDedupe.java @@ -24,7 +24,7 @@ import lombok.ToString; /** - * Logical Dedupe Plan + * Logical Dedupe Plan. */ @Getter @ToString diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalEval.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalEval.java index 8582a779ef..5e3f117610 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalEval.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalEval.java @@ -35,7 +35,8 @@ @RequiredArgsConstructor public class LogicalEval extends LogicalPlan { private final LogicalPlan child; - @Getter private final List> expressions; + @Getter + private final List> expressions; @Override public List getChild() { diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalFilter.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalFilter.java index 20d2a8476f..306104ca6f 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalFilter.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalFilter.java @@ -16,14 +16,13 @@ package com.amazon.opendistroforelasticsearch.sql.planner.logical; import com.amazon.opendistroforelasticsearch.sql.expression.Expression; +import java.util.Arrays; +import java.util.List; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.ToString; -import java.util.Arrays; -import java.util.List; - /** * Logical Filter represent the filter relation. */ @@ -31,17 +30,17 @@ @EqualsAndHashCode @RequiredArgsConstructor public class LogicalFilter extends LogicalPlan { - private final LogicalPlan child; - @Getter - private final Expression condition; + private final LogicalPlan child; + @Getter + private final Expression condition; - @Override - public List getChild() { - return Arrays.asList(child); - } + @Override + public List getChild() { + return Arrays.asList(child); + } - @Override - public R accept(LogicalPlanNodeVisitor visitor, C context) { - return visitor.visitFilter(this, context); - } + @Override + public R accept(LogicalPlanNodeVisitor visitor, C context) { + return visitor.visitFilter(this, context); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalPlan.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalPlan.java index 5f1d60bed0..035598d568 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalPlan.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalPlan.java @@ -21,14 +21,14 @@ * The abstract base class for all the Logical Plan node. */ public abstract class LogicalPlan implements PlanNode { - /** - * Accept the {@link LogicalPlanNodeVisitor}. - * - * @param visitor visitor. - * @param context visitor context. - * @param returned object type. - * @param context type. - * @return returned object. - */ - public abstract R accept(LogicalPlanNodeVisitor visitor, C context); + /** + * Accept the {@link LogicalPlanNodeVisitor}. + * + * @param visitor visitor. + * @param context visitor context. + * @param returned object type. + * @param context type. + * @return returned object. + */ + public abstract R accept(LogicalPlanNodeVisitor visitor, C context); } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalPlanDSL.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalPlanDSL.java index fb1cbb69f4..98df7dacf3 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalPlanDSL.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalPlanDSL.java @@ -21,13 +21,14 @@ import com.amazon.opendistroforelasticsearch.sql.expression.aggregation.Aggregator; import com.google.common.collect.ImmutableSet; import java.util.Arrays; -import lombok.experimental.UtilityClass; - import java.util.List; import java.util.Map; +import lombok.experimental.UtilityClass; import org.apache.commons.lang3.tuple.Pair; -/** Logical Plan DSL. */ +/** + * Logical Plan DSL. + */ @UtilityClass public class LogicalPlanDSL { public static LogicalPlan aggregation( diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalProject.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalProject.java index a8ab31523b..a24e5be68a 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalProject.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalProject.java @@ -30,17 +30,17 @@ @EqualsAndHashCode @RequiredArgsConstructor public class LogicalProject extends LogicalPlan { - private final LogicalPlan child; - @Getter - private final List projectList; + private final LogicalPlan child; + @Getter + private final List projectList; - @Override - public List getChild() { - return Arrays.asList(child); - } + @Override + public List getChild() { + return Arrays.asList(child); + } - @Override - public R accept(LogicalPlanNodeVisitor visitor, C context) { - return visitor.visitProject(this, context); - } + @Override + public R accept(LogicalPlanNodeVisitor visitor, C context) { + return visitor.visitProject(this, context); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalRelation.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalRelation.java index 61dd8f95f5..a836ce043b 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalRelation.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalRelation.java @@ -16,13 +16,12 @@ package com.amazon.opendistroforelasticsearch.sql.planner.logical; import com.google.common.collect.ImmutableList; +import java.util.List; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.ToString; -import java.util.List; - /** * Logical Relation represent the data source. */ @@ -30,16 +29,16 @@ @EqualsAndHashCode @RequiredArgsConstructor public class LogicalRelation extends LogicalPlan { - @Getter - private final String relationName; + @Getter + private final String relationName; - @Override - public List getChild() { - return ImmutableList.of(); - } + @Override + public List getChild() { + return ImmutableList.of(); + } - @Override - public R accept(LogicalPlanNodeVisitor visitor, C context) { - return visitor.visitRelation(this, context); - } + @Override + public R accept(LogicalPlanNodeVisitor visitor, C context) { + return visitor.visitRelation(this, context); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalRemove.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalRemove.java index 4b73048c64..11d280cd9b 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalRemove.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalRemove.java @@ -31,17 +31,17 @@ @EqualsAndHashCode @RequiredArgsConstructor public class LogicalRemove extends LogicalPlan { - private final LogicalPlan child; - @Getter - private final Set removeList; + private final LogicalPlan child; + @Getter + private final Set removeList; - @Override - public List getChild() { - return Arrays.asList(child); - } + @Override + public List getChild() { + return Arrays.asList(child); + } - @Override - public R accept(LogicalPlanNodeVisitor visitor, C context) { - return visitor.visitRemove(this, context); - } + @Override + public R accept(LogicalPlanNodeVisitor visitor, C context) { + return visitor.visitRemove(this, context); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalRename.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalRename.java index 14a8a26ba5..812ac329e1 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalRename.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalRename.java @@ -32,17 +32,17 @@ @EqualsAndHashCode @RequiredArgsConstructor public class LogicalRename extends LogicalPlan { - private final LogicalPlan child; - @Getter - private final Map renameMap; + private final LogicalPlan child; + @Getter + private final Map renameMap; - @Override - public List getChild() { - return Collections.singletonList(child); - } + @Override + public List getChild() { + return Collections.singletonList(child); + } - @Override - public R accept(LogicalPlanNodeVisitor visitor, C context) { - return visitor.visitRename(this, context); - } + @Override + public R accept(LogicalPlanNodeVisitor visitor, C context) { + return visitor.visitRename(this, context); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/AggregationOperator.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/AggregationOperator.java index 68d19e13b5..6e58ad07e6 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/AggregationOperator.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/AggregationOperator.java @@ -37,128 +37,138 @@ import lombok.ToString; /** - * Group the all the input {@link BindingTuple} by {@link AggregationOperator#groupByExprList}, calculate the - * aggregation result by using {@link AggregationOperator#aggregatorList} + * Group the all the input {@link BindingTuple} by {@link AggregationOperator#groupByExprList}, + * calculate the aggregation result by using {@link AggregationOperator#aggregatorList}. */ @EqualsAndHashCode @ToString public class AggregationOperator extends PhysicalPlan { - private final PhysicalPlan input; - private final List aggregatorList; - private final List groupByExprList; - @EqualsAndHashCode.Exclude - private final Group group; - @EqualsAndHashCode.Exclude - private Iterator iterator; - - public AggregationOperator(PhysicalPlan input, List aggregatorList, - List groupByExprList) { - this.input = input; - this.aggregatorList = aggregatorList; - this.groupByExprList = groupByExprList; - this.group = new Group(); + private final PhysicalPlan input; + private final List aggregatorList; + private final List groupByExprList; + @EqualsAndHashCode.Exclude + private final Group group; + @EqualsAndHashCode.Exclude + private Iterator iterator; + + /** + * AggregationOperator Constructor. + * @param input Input {@link PhysicalPlan} + * @param aggregatorList List of {@link Aggregator} + * @param groupByExprList List of group by {@link Expression} + */ + public AggregationOperator(PhysicalPlan input, List aggregatorList, + List groupByExprList) { + this.input = input; + this.aggregatorList = aggregatorList; + this.groupByExprList = groupByExprList; + this.group = new Group(); + } + + @Override + public R accept(PhysicalPlanNodeVisitor visitor, C context) { + return visitor.visitAggregation(this, context); + } + + @Override + public List getChild() { + return Collections.singletonList(input); + } + + + @Override + public boolean hasNext() { + return iterator.hasNext(); + } + + @Override + public ExprValue next() { + return iterator.next(); + } + + @Override + public void open() { + super.open(); + while (input.hasNext()) { + group.push(input.next()); } + iterator = group.result().iterator(); + } - @Override - public R accept(PhysicalPlanNodeVisitor visitor, C context) { - return visitor.visitAggregation(this, context); - } - - @Override - public List getChild() { - return Collections.singletonList(input); - } + @VisibleForTesting + @RequiredArgsConstructor + public class Group { + private final Map>> groupListMap = + new HashMap<>(); - @Override - public boolean hasNext() { - return iterator.hasNext(); - } - - @Override - public ExprValue next() { - return iterator.next(); + /** + * Push the BindingTuple to Group. Two functions will be applied to each BindingTuple to + * generate the {@link GroupKey} and {@link AggregationState} + * Key = GroupKey(bindingTuple), State = Aggregator(bindingTuple) + */ + public void push(ExprValue inputValue) { + GroupKey groupKey = new GroupKey(inputValue); + groupListMap.computeIfAbsent(groupKey, k -> + aggregatorList.stream() + .map(aggregator -> new AbstractMap.SimpleEntry<>(aggregator, + aggregator.create())) + .collect(Collectors.toList()) + ); + groupListMap.computeIfPresent(groupKey, (key, aggregatorList) -> { + aggregatorList + .forEach(entry -> entry.getKey().iterate(inputValue.bindingTuples(), entry.getValue())); + return aggregatorList; + }); } - @Override - public void open() { - super.open(); - while (input.hasNext()) { - group.push(input.next()); + /** + * Get the list of {@link BindingTuple} for each group. + */ + public List result() { + ImmutableList.Builder resultBuilder = new ImmutableList.Builder<>(); + for (Map.Entry>> entry : groupListMap + .entrySet()) { + LinkedHashMap map = new LinkedHashMap<>(); + map.putAll(entry.getKey().groupKeyMap()); + for (Map.Entry stateEntry : entry.getValue()) { + map.put(stateEntry.getKey().toString(), stateEntry.getValue().result()); } - iterator = group.result().iterator(); + resultBuilder.add(ExprTupleValue.fromExprValueMap(map)); + } + return resultBuilder.build(); } + } - @VisibleForTesting - @RequiredArgsConstructor - public class Group { - - private final Map>> groupListMap = new HashMap<>(); - - /** - * Push the BindingTuple to Group. Two functions will be applied to each BindingTuple to generate the - * {@link GroupKey} and {@link AggregationState} - * Key = GroupKey(bindingTuple), State = Aggregator(bindingTuple) - */ - public void push(ExprValue inputValue) { - GroupKey groupKey = new GroupKey(inputValue); - groupListMap.computeIfAbsent(groupKey, k -> - aggregatorList.stream() - .map(aggregator -> new AbstractMap.SimpleEntry<>(aggregator, - aggregator.create())) - .collect(Collectors.toList()) - ); - groupListMap.computeIfPresent(groupKey, (key, aggregatorList) -> { - aggregatorList - .forEach(entry -> entry.getKey().iterate(inputValue.bindingTuples(), entry.getValue())); - return aggregatorList; - }); - } + /** + * Group Key. + */ + @EqualsAndHashCode + @VisibleForTesting + public class GroupKey { - /** - * Get the list of {@link BindingTuple} for each group. - */ - public List result() { - ImmutableList.Builder resultBuilder = new ImmutableList.Builder<>(); - for (Map.Entry>> entry : groupListMap - .entrySet()) { - LinkedHashMap map = new LinkedHashMap<>(); - map.putAll(entry.getKey().groupKeyMap()); - for (Map.Entry stateEntry : entry.getValue()) { - map.put(stateEntry.getKey().toString(), stateEntry.getValue().result()); - } - resultBuilder.add(ExprTupleValue.fromExprValueMap(map)); - } - return resultBuilder.build(); - } - } + private final List groupByValueList; /** - * Group Key. + * GroupKey constructor. */ - @EqualsAndHashCode - @VisibleForTesting - public class GroupKey { - - private final List groupByValueList; - - public GroupKey(ExprValue value) { - this.groupByValueList = new ArrayList<>(); - for (Expression groupExpr : groupByExprList) { - this.groupByValueList.add(groupExpr.valueOf(value.bindingTuples())); - } - } + public GroupKey(ExprValue value) { + this.groupByValueList = new ArrayList<>(); + for (Expression groupExpr : groupByExprList) { + this.groupByValueList.add(groupExpr.valueOf(value.bindingTuples())); + } + } - /** - * Return the Map of group field and group field value. - */ - public LinkedHashMap groupKeyMap() { - LinkedHashMap map = new LinkedHashMap<>(); - for (int i = 0; i < groupByExprList.size(); i++) { - map.put(groupByExprList.get(i).toString(), groupByValueList.get(i)); - } - return map; - } + /** + * Return the Map of group field and group field value. + */ + public LinkedHashMap groupKeyMap() { + LinkedHashMap map = new LinkedHashMap<>(); + for (int i = 0; i < groupByExprList.size(); i++) { + map.put(groupByExprList.get(i).toString(), groupByValueList.get(i)); + } + return map; } + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/DedupeOperator.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/DedupeOperator.java index bdd22d186a..c29d6a2ab6 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/DedupeOperator.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/DedupeOperator.java @@ -41,8 +41,10 @@ public class DedupeOperator extends PhysicalPlan { private final Boolean keepEmpty; private final Boolean consecutive; - @EqualsAndHashCode.Exclude private final Deduper> deduper; - @EqualsAndHashCode.Exclude private ExprValue next; + @EqualsAndHashCode.Exclude + private final Deduper> deduper; + @EqualsAndHashCode.Exclude + private ExprValue next; private static final Integer ALL_ONE_DUPLICATION = 1; private static final Boolean IGNORE_EMPTY = false; @@ -55,6 +57,14 @@ public DedupeOperator(PhysicalPlan input, List dedupeList) { this(input, dedupeList, ALL_ONE_DUPLICATION, IGNORE_EMPTY, NON_CONSECUTIVE); } + /** + * Dedup Constructor. + * @param input input {@link PhysicalPlan} + * @param dedupeList list of dedupe {@link Expression} + * @param allowedDuplication max allowed duplication + * @param keepEmpty keep empty + * @param consecutive consecutive mode + */ @NonNull public DedupeOperator( PhysicalPlan input, @@ -103,7 +113,7 @@ public ExprValue next() { *

If any value evaluted by {@link DedupeOperator#dedupeList} is NULL or MISSING, then the * * return value is decided by keepEmpty option, default value is ignore. * - * @param value + * @param value {@link ExprValue}. * @return true: keep, false: ignore */ public boolean keep(ExprValue value) { @@ -132,7 +142,9 @@ static class Deduper { private final BiFunction, K, Integer> seenFirstTime; private final Map seenMap = new ConcurrentHashMap<>(); - /** The Historical Deduper monitor the duplicated element with all the seen value. */ + /** + * The Historical Deduper monitor the duplicated element with all the seen value. + */ public static Deduper historicalDeduper() { return new Deduper<>( (map, key) -> { diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/EvalOperator.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/EvalOperator.java index dc8c067414..340bddd4ef 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/EvalOperator.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/EvalOperator.java @@ -90,7 +90,11 @@ public ExprValue next() { } } - /** Construct Map from {@link EvalOperator#expressionList} */ + /** + * Evaluate the expression in the {@link EvalOperator#expressionList} with {@link Environment}. + * @param env {@link Environment} + * @return The mapping of reference and {@link ExprValue} for each expression. + */ private Map eval(Environment env) { Map evalResultMap = new LinkedHashMap<>(); for (Pair pair : expressionList) { diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/FilterOperator.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/FilterOperator.java index 0c24808074..0a20bad304 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/FilterOperator.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/FilterOperator.java @@ -5,13 +5,12 @@ import com.amazon.opendistroforelasticsearch.sql.expression.Expression; import com.amazon.opendistroforelasticsearch.sql.expression.scalar.predicate.BinaryPredicateFunction; import com.amazon.opendistroforelasticsearch.sql.storage.bindingtuple.BindingTuple; +import java.util.Collections; +import java.util.List; import lombok.EqualsAndHashCode; import lombok.RequiredArgsConstructor; import lombok.ToString; -import java.util.Collections; -import java.util.List; - /** * The Filter operator use the conditions to evaluate the input {@link BindingTuple}. * The Filter operator only return the results that evaluated to true. @@ -21,35 +20,35 @@ @ToString @RequiredArgsConstructor public class FilterOperator extends PhysicalPlan { - private final PhysicalPlan input; - private final Expression conditions; - private ExprValue next = null; + private final PhysicalPlan input; + private final Expression conditions; + private ExprValue next = null; - @Override - public R accept(PhysicalPlanNodeVisitor visitor, C context) { - return visitor.visitFilter(this, context); - } + @Override + public R accept(PhysicalPlanNodeVisitor visitor, C context) { + return visitor.visitFilter(this, context); + } - @Override - public List getChild() { - return Collections.singletonList(input); - } + @Override + public List getChild() { + return Collections.singletonList(input); + } - @Override - public boolean hasNext() { - while (input.hasNext()) { - ExprValue inputValue = input.next(); - ExprValue exprValue = conditions.valueOf(inputValue.bindingTuples()); - if (ExprValueUtils.getBooleanValue(exprValue)) { - next = inputValue; - return true; - } - } - return false; + @Override + public boolean hasNext() { + while (input.hasNext()) { + ExprValue inputValue = input.next(); + ExprValue exprValue = conditions.valueOf(inputValue.bindingTuples()); + if (ExprValueUtils.getBooleanValue(exprValue)) { + next = inputValue; + return true; + } } + return false; + } - @Override - public ExprValue next() { - return next; - } + @Override + public ExprValue next() { + return next; + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/PhysicalPlan.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/PhysicalPlan.java index 3fa9e09fcc..e7f64c84ec 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/PhysicalPlan.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/PhysicalPlan.java @@ -20,27 +20,27 @@ import java.util.Iterator; /** - * Physical plan + * Physical plan. */ public abstract class PhysicalPlan implements PlanNode, - Iterator, - AutoCloseable { - /** - * Accept the {@link PhysicalPlanNodeVisitor}. - * - * @param visitor visitor. - * @param context visitor context. - * @param returned object type. - * @param context type. - * @return returned object. - */ - public abstract R accept(PhysicalPlanNodeVisitor visitor, C context); + Iterator, + AutoCloseable { + /** + * Accept the {@link PhysicalPlanNodeVisitor}. + * + * @param visitor visitor. + * @param context visitor context. + * @param returned object type. + * @param context type. + * @return returned object. + */ + public abstract R accept(PhysicalPlanNodeVisitor visitor, C context); - public void open() { - getChild().forEach(PhysicalPlan::open); - } + public void open() { + getChild().forEach(PhysicalPlan::open); + } - public void close() { - getChild().forEach(PhysicalPlan::close); - } + public void close() { + getChild().forEach(PhysicalPlan::close); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/PhysicalPlanDSL.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/PhysicalPlanDSL.java index e91dd29ceb..620a18d3a6 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/PhysicalPlanDSL.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/PhysicalPlanDSL.java @@ -26,7 +26,9 @@ import lombok.experimental.UtilityClass; import org.apache.commons.lang3.tuple.Pair; -/** Physical Plan DSL. */ +/** + * Physical Plan DSL. + */ @UtilityClass public class PhysicalPlanDSL { diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/PhysicalPlanNodeVisitor.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/PhysicalPlanNodeVisitor.java index b676e15a15..7975aa07bf 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/PhysicalPlanNodeVisitor.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/PhysicalPlanNodeVisitor.java @@ -25,39 +25,39 @@ */ public abstract class PhysicalPlanNodeVisitor { - protected R visitNode(PhysicalPlan node, C context) { - return null; - } + protected R visitNode(PhysicalPlan node, C context) { + return null; + } - public R visitFilter(FilterOperator node, C context) { - return visitNode(node, context); - } + public R visitFilter(FilterOperator node, C context) { + return visitNode(node, context); + } - public R visitAggregation(AggregationOperator node, C context) { - return visitNode(node, context); - } + public R visitAggregation(AggregationOperator node, C context) { + return visitNode(node, context); + } - public R visitRename(RenameOperator node, C context) { - return visitNode(node, context); - } + public R visitRename(RenameOperator node, C context) { + return visitNode(node, context); + } - public R visitTableScan(TableScanOperator node, C context) { - return visitNode(node, context); - } + public R visitTableScan(TableScanOperator node, C context) { + return visitNode(node, context); + } - public R visitProject(ProjectOperator node, C context) { - return visitNode(node, context); - } + public R visitProject(ProjectOperator node, C context) { + return visitNode(node, context); + } - public R visitRemove(RemoveOperator node, C context) { - return visitNode(node, context); - } + public R visitRemove(RemoveOperator node, C context) { + return visitNode(node, context); + } - public R visitEval(EvalOperator node, C context) { - return visitNode(node, context); - } + public R visitEval(EvalOperator node, C context) { + return visitNode(node, context); + } - public R visitDedupe(DedupeOperator node, C context) { - return visitNode(node, context); - } + public R visitDedupe(DedupeOperator node, C context) { + return visitNode(node, context); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/ProjectOperator.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/ProjectOperator.java index 30928bd1ab..019c7a7f0b 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/ProjectOperator.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/ProjectOperator.java @@ -26,7 +26,9 @@ import lombok.RequiredArgsConstructor; import lombok.ToString; -/** Project the fields specified in {@link ProjectOperator#projectList} from input. */ +/** + * Project the fields specified in {@link ProjectOperator#projectList} from input. + */ @ToString @EqualsAndHashCode @RequiredArgsConstructor diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/RemoveOperator.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/RemoveOperator.java index 20f151c35e..810469de72 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/RemoveOperator.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/RemoveOperator.java @@ -33,7 +33,9 @@ import lombok.RequiredArgsConstructor; import lombok.ToString; -/** Remove the fields specified in {@link RemoveOperator#removeList} from input. */ +/** + * Remove the fields specified in {@link RemoveOperator#removeList} from input. + */ @ToString @EqualsAndHashCode @RequiredArgsConstructor diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/RenameOperator.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/RenameOperator.java index 8fb029e0c2..bbf3cc69ab 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/RenameOperator.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/RenameOperator.java @@ -41,40 +41,40 @@ @ToString @RequiredArgsConstructor public class RenameOperator extends PhysicalPlan { - private final PhysicalPlan input; - private final Map mapping; + private final PhysicalPlan input; + private final Map mapping; - @Override - public R accept(PhysicalPlanNodeVisitor visitor, C context) { - return visitor.visitRename(this, context); - } + @Override + public R accept(PhysicalPlanNodeVisitor visitor, C context) { + return visitor.visitRename(this, context); + } - @Override - public List getChild() { - return Collections.singletonList(input); - } + @Override + public List getChild() { + return Collections.singletonList(input); + } - @Override - public boolean hasNext() { - return input.hasNext(); - } + @Override + public boolean hasNext() { + return input.hasNext(); + } - @Override - public ExprValue next() { - ExprValue inputValue = input.next(); - if (STRUCT == inputValue.type()) { - Map tupleValue = ExprValueUtils.getTupleValue(inputValue); - ImmutableMap.Builder mapBuilder = new Builder<>(); - for (String bindName : tupleValue.keySet()) { - if (mapping.containsKey(DSL.ref(bindName))) { - mapBuilder.put(mapping.get(DSL.ref(bindName)).getAttr(), tupleValue.get(bindName)); - } else { - mapBuilder.put(bindName, tupleValue.get(bindName)); - } - } - return ExprTupleValue.fromExprValueMap(mapBuilder.build()); + @Override + public ExprValue next() { + ExprValue inputValue = input.next(); + if (STRUCT == inputValue.type()) { + Map tupleValue = ExprValueUtils.getTupleValue(inputValue); + ImmutableMap.Builder mapBuilder = new Builder<>(); + for (String bindName : tupleValue.keySet()) { + if (mapping.containsKey(DSL.ref(bindName))) { + mapBuilder.put(mapping.get(DSL.ref(bindName)).getAttr(), tupleValue.get(bindName)); } else { - return inputValue; + mapBuilder.put(bindName, tupleValue.get(bindName)); } + } + return ExprTupleValue.fromExprValueMap(mapBuilder.build()); + } else { + return inputValue; } + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/SortOperator.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/SortOperator.java index 6706feeb51..fc5e6054d1 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/SortOperator.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/SortOperator.java @@ -24,7 +24,6 @@ import com.amazon.opendistroforelasticsearch.sql.expression.Expression; import com.amazon.opendistroforelasticsearch.sql.planner.physical.SortOperator.Sorter.SorterBuilder; import com.google.common.collect.Iterators; -import com.google.common.collect.TreeMultiset; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; @@ -47,9 +46,18 @@ public class SortOperator extends PhysicalPlan { private final PhysicalPlan input; private final Integer count; private final List> sortList; - @EqualsAndHashCode.Exclude private final Sorter sorter; - @EqualsAndHashCode.Exclude private Iterator iterator; + @EqualsAndHashCode.Exclude + private final Sorter sorter; + @EqualsAndHashCode.Exclude + private Iterator iterator; + /** + * Sort Operator Constructor. + * @param input input {@link PhysicalPlan} + * @param count how many sorted result should been return + * @param sortList list of sort sort field. + * The sort field is specified by the {@link Expression} with {@link SortOption} + */ public SortOperator( PhysicalPlan input, Integer count, List> sortList) { this.input = input; @@ -111,7 +119,8 @@ public ExprValue next() { @Builder public static class Sorter implements Comparator { - @Singular private final List>> comparators; + @Singular + private final List>> comparators; @Override public int compare(ExprValue o1, ExprValue o2) { diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/storage/StorageEngine.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/storage/StorageEngine.java index 68da18d536..a9eb5fee7e 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/storage/StorageEngine.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/storage/StorageEngine.java @@ -16,12 +16,12 @@ package com.amazon.opendistroforelasticsearch.sql.storage; /** - * Storage engine for different storage to provide data access API implementation + * Storage engine for different storage to provide data access API implementation. */ public interface StorageEngine { - /** - * Get {@link Table} from storage engine. - */ - Table getTable(String name); + /** + * Get {@link Table} from storage engine. + */ + Table getTable(String name); } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/storage/Table.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/storage/Table.java index 0d3b04c232..cec317dd59 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/storage/Table.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/storage/Table.java @@ -18,24 +18,24 @@ import com.amazon.opendistroforelasticsearch.sql.data.model.ExprType; import com.amazon.opendistroforelasticsearch.sql.planner.logical.LogicalPlan; import com.amazon.opendistroforelasticsearch.sql.planner.physical.PhysicalPlan; - import java.util.Map; /** - * Table + * Table. */ public interface Table { - /** - * Get the {@link ExprType} for each field in the table. - */ - Map getFieldTypes(); + /** + * Get the {@link ExprType} for each field in the table. + */ + Map getFieldTypes(); - /** - * Implement a {@link LogicalPlan} by {@link PhysicalPlan} in storage engine. - * @param plan logical plan - * @return physical plan - */ - PhysicalPlan implement(LogicalPlan plan); + /** + * Implement a {@link LogicalPlan} by {@link PhysicalPlan} in storage engine. + * + * @param plan logical plan + * @return physical plan + */ + PhysicalPlan implement(LogicalPlan plan); } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/storage/TableScanOperator.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/storage/TableScanOperator.java index 45693adb3f..bcc5a8cab2 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/storage/TableScanOperator.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/storage/TableScanOperator.java @@ -18,7 +18,6 @@ import com.amazon.opendistroforelasticsearch.sql.planner.physical.PhysicalPlan; import com.amazon.opendistroforelasticsearch.sql.planner.physical.PhysicalPlanNodeVisitor; - import java.util.Collections; import java.util.List; @@ -28,14 +27,14 @@ */ public abstract class TableScanOperator extends PhysicalPlan { - @Override - public R accept(PhysicalPlanNodeVisitor visitor, C context) { - return visitor.visitTableScan(this, context); - } + @Override + public R accept(PhysicalPlanNodeVisitor visitor, C context) { + return visitor.visitTableScan(this, context); + } - @Override - public List getChild() { - return Collections.emptyList(); - } + @Override + public List getChild() { + return Collections.emptyList(); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/storage/bindingtuple/BindingTuple.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/storage/bindingtuple/BindingTuple.java index a102d82dad..3d1d0aba74 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/storage/bindingtuple/BindingTuple.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/storage/bindingtuple/BindingTuple.java @@ -27,27 +27,27 @@ * e.g. The operation output column name is bindingName, the value is the ExprValue. */ public abstract class BindingTuple implements Environment { - public static BindingTuple EMPTY = new BindingTuple() { - @Override - public ExprValue resolve(ReferenceExpression ref) { - return ExprMissingValue.of(); - } - }; - - /** - * Resolve {@link Expression} in the BindingTuple environment. - */ + public static BindingTuple EMPTY = new BindingTuple() { @Override - public ExprValue resolve(Expression var) { - if (var instanceof ReferenceExpression) { - return resolve(((ReferenceExpression) var)); - } else { - throw new ExpressionEvaluationException(String.format("can resolve expression: %s", var)); - } + public ExprValue resolve(ReferenceExpression ref) { + return ExprMissingValue.of(); + } + }; + + /** + * Resolve {@link Expression} in the BindingTuple environment. + */ + @Override + public ExprValue resolve(Expression var) { + if (var instanceof ReferenceExpression) { + return resolve(((ReferenceExpression) var)); + } else { + throw new ExpressionEvaluationException(String.format("can resolve expression: %s", var)); } + } - /** - * Resolve the {@link ReferenceExpression} in BindingTuple context. - */ - public abstract ExprValue resolve(ReferenceExpression ref); + /** + * Resolve the {@link ReferenceExpression} in BindingTuple context. + */ + public abstract ExprValue resolve(ReferenceExpression ref); } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/storage/bindingtuple/LazyBindingTuple.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/storage/bindingtuple/LazyBindingTuple.java index 4aa19293d4..f5e29594b9 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/storage/bindingtuple/LazyBindingTuple.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/storage/bindingtuple/LazyBindingTuple.java @@ -25,10 +25,10 @@ */ @RequiredArgsConstructor public class LazyBindingTuple extends BindingTuple { - private final Function lazyBinding; + private final Function lazyBinding; - @Override - public ExprValue resolve(ReferenceExpression ref) { - return lazyBinding.apply(ref.getAttr()); - } + @Override + public ExprValue resolve(ReferenceExpression ref) { + return lazyBinding.apply(ref.getAttr()); + } } diff --git a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/utils/ExpressionUtils.java b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/utils/ExpressionUtils.java index 313674adfc..dcb8b10239 100644 --- a/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/utils/ExpressionUtils.java +++ b/core/src/main/java/com/amazon/opendistroforelasticsearch/sql/utils/ExpressionUtils.java @@ -16,10 +16,9 @@ package com.amazon.opendistroforelasticsearch.sql.utils; import com.amazon.opendistroforelasticsearch.sql.expression.Expression; -import lombok.experimental.UtilityClass; - import java.util.List; import java.util.stream.Collectors; +import lombok.experimental.UtilityClass; /** * Utils for {@link Expression}. @@ -27,10 +26,10 @@ @UtilityClass public class ExpressionUtils { - /** - * Format the list of {@link Expression} - */ - public static String format(List expressionList) { - return expressionList.stream().map(Expression::toString).collect(Collectors.joining(",")); - } + /** + * Format the list of {@link Expression}. + */ + public static String format(List expressionList) { + return expressionList.stream().map(Expression::toString).collect(Collectors.joining(",")); + } } diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/analysis/AnalysisContextTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/analysis/AnalysisContextTest.java index 22dd81e2b7..225d962185 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/analysis/AnalysisContextTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/analysis/AnalysisContextTest.java @@ -15,34 +15,36 @@ package com.amazon.opendistroforelasticsearch.sql.analysis; -import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; class AnalysisContextTest { - private final AnalysisContext context = new AnalysisContext(); - - @Test - public void rootEnvironmentShouldBeThereInitially() { - assertNotNull(context.peek()); - } - - @Test - public void pushAndPopEnvironmentShouldPass() { - context.push(); - context.pop(); - } - - @Test - public void popRootEnvironmentShouldPass() { - context.pop(); - } - - @Test - public void popEmptyEnvironmentStackShouldFail() { - context.pop(); - NullPointerException exception = assertThrows(NullPointerException.class, () -> context.pop()); - assertEquals("Fail to pop context due to no environment present", exception.getMessage()); - } + private final AnalysisContext context = new AnalysisContext(); + + @Test + public void rootEnvironmentShouldBeThereInitially() { + assertNotNull(context.peek()); + } + + @Test + public void pushAndPopEnvironmentShouldPass() { + context.push(); + context.pop(); + } + + @Test + public void popRootEnvironmentShouldPass() { + context.pop(); + } + + @Test + public void popEmptyEnvironmentStackShouldFail() { + context.pop(); + NullPointerException exception = assertThrows(NullPointerException.class, () -> context.pop()); + assertEquals("Fail to pop context due to no environment present", exception.getMessage()); + } } \ No newline at end of file diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/analysis/AnalyzerTestBase.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/analysis/AnalyzerTestBase.java index 7f66b8fb9d..6bc67bca91 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/analysis/AnalyzerTestBase.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/analysis/AnalyzerTestBase.java @@ -40,15 +40,20 @@ @ContextConfiguration(classes = {ExpressionConfig.class, AnalyzerTestBase.class, TestConfig.class}) public class AnalyzerTestBase { - @Autowired protected DSL dsl; + @Autowired + protected DSL dsl; - @Autowired protected AnalysisContext analysisContext; + @Autowired + protected AnalysisContext analysisContext; - @Autowired protected ExpressionAnalyzer expressionAnalyzer; + @Autowired + protected ExpressionAnalyzer expressionAnalyzer; - @Autowired protected Analyzer analyzer; + @Autowired + protected Analyzer analyzer; - @Autowired protected Environment typeEnv; + @Autowired + protected Environment typeEnv; @Bean protected Analyzer analyzer(ExpressionAnalyzer expressionAnalyzer, StorageEngine engine) { diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/analysis/ExpressionAnalyzerTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/analysis/ExpressionAnalyzerTest.java index 84986b8097..9aff7ba030 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/analysis/ExpressionAnalyzerTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/analysis/ExpressionAnalyzerTest.java @@ -15,6 +15,12 @@ package com.amazon.opendistroforelasticsearch.sql.analysis; +import static com.amazon.opendistroforelasticsearch.sql.ast.dsl.AstDSL.field; +import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.LITERAL_TRUE; +import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.integerValue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + import com.amazon.opendistroforelasticsearch.sql.ast.dsl.AstDSL; import com.amazon.opendistroforelasticsearch.sql.ast.expression.UnresolvedExpression; import com.amazon.opendistroforelasticsearch.sql.exception.SemanticCheckException; @@ -22,58 +28,54 @@ import com.amazon.opendistroforelasticsearch.sql.expression.Expression; import org.junit.jupiter.api.Test; -import static com.amazon.opendistroforelasticsearch.sql.ast.dsl.AstDSL.field; -import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.LITERAL_TRUE; -import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.integerValue; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; - class ExpressionAnalyzerTest extends AnalyzerTestBase { - @Test - public void equal() { - assertAnalyzeEqual( - dsl.equal(typeEnv, DSL.ref("integer_value"), DSL.literal(integerValue(1))), - AstDSL.equalTo(AstDSL.unresolvedAttr("integer_value"), AstDSL.intLiteral(1)) - ); - } + @Test + public void equal() { + assertAnalyzeEqual( + dsl.equal(typeEnv, DSL.ref("integer_value"), DSL.literal(integerValue(1))), + AstDSL.equalTo(AstDSL.unresolvedAttr("integer_value"), AstDSL.intLiteral(1)) + ); + } - @Test - public void and() { - assertAnalyzeEqual( - dsl.and(typeEnv, DSL.ref("boolean_value"), DSL.literal(LITERAL_TRUE)), - AstDSL.and(AstDSL.unresolvedAttr("boolean_value"), AstDSL.booleanLiteral(true)) - ); - } + @Test + public void and() { + assertAnalyzeEqual( + dsl.and(typeEnv, DSL.ref("boolean_value"), DSL.literal(LITERAL_TRUE)), + AstDSL.and(AstDSL.unresolvedAttr("boolean_value"), AstDSL.booleanLiteral(true)) + ); + } - @Test - public void or() { - assertAnalyzeEqual( - dsl.or(typeEnv, DSL.ref("boolean_value"), DSL.literal(LITERAL_TRUE)), - AstDSL.or(AstDSL.unresolvedAttr("boolean_value"), AstDSL.booleanLiteral(true)) - ); - } + @Test + public void or() { + assertAnalyzeEqual( + dsl.or(typeEnv, DSL.ref("boolean_value"), DSL.literal(LITERAL_TRUE)), + AstDSL.or(AstDSL.unresolvedAttr("boolean_value"), AstDSL.booleanLiteral(true)) + ); + } - @Test - public void undefined_var_semantic_check_failed() { - SemanticCheckException exception = assertThrows(SemanticCheckException.class, - () -> analyze(AstDSL.and(AstDSL.unresolvedAttr("undefined_field"), AstDSL.booleanLiteral(true)))); - assertEquals("can't resolve expression undefined_field in type env", exception.getMessage()); - } + @Test + public void undefined_var_semantic_check_failed() { + SemanticCheckException exception = assertThrows(SemanticCheckException.class, + () -> analyze( + AstDSL.and(AstDSL.unresolvedAttr("undefined_field"), AstDSL.booleanLiteral(true)))); + assertEquals("can't resolve expression undefined_field in type env", exception.getMessage()); + } - @Test - public void undefined_aggregation_function() { - SemanticCheckException exception = assertThrows(SemanticCheckException.class, - () -> analyze(AstDSL.aggregate("ESTDC_ERROR", field("integer_value")))); - assertEquals("Unsupported aggregation function ESTDC_ERROR", exception.getMessage()); - } + @Test + public void undefined_aggregation_function() { + SemanticCheckException exception = assertThrows(SemanticCheckException.class, + () -> analyze(AstDSL.aggregate("ESTDC_ERROR", field("integer_value")))); + assertEquals("Unsupported aggregation function ESTDC_ERROR", exception.getMessage()); + } - protected Expression analyze(UnresolvedExpression unresolvedExpression) { - return expressionAnalyzer.analyze(unresolvedExpression, analysisContext); - } + protected Expression analyze(UnresolvedExpression unresolvedExpression) { + return expressionAnalyzer.analyze(unresolvedExpression, analysisContext); + } - protected void assertAnalyzeEqual(Expression expected, UnresolvedExpression unresolvedExpression) { - assertEquals(expected, analyze(unresolvedExpression)); - } + protected void assertAnalyzeEqual(Expression expected, + UnresolvedExpression unresolvedExpression) { + assertEquals(expected, analyze(unresolvedExpression)); + } } \ No newline at end of file diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/analysis/TypeEnvironmentTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/analysis/TypeEnvironmentTest.java index d9555c3ca6..ce00697682 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/analysis/TypeEnvironmentTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/analysis/TypeEnvironmentTest.java @@ -15,6 +15,9 @@ package com.amazon.opendistroforelasticsearch.sql.analysis; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + import com.amazon.opendistroforelasticsearch.sql.data.model.ExprType; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils; import com.amazon.opendistroforelasticsearch.sql.exception.SemanticCheckException; @@ -22,80 +25,78 @@ import com.amazon.opendistroforelasticsearch.sql.expression.Expression; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; - public class TypeEnvironmentTest { - /** - * Use context class for push/pop - */ - private AnalysisContext context = new AnalysisContext(); - - @Test - public void defineFieldSymbolInDifferentEnvironmentsShouldBeAbleToResolve() { - // Root environment - Expression age = DSL.ref("s.age"); - environment().define(age, ExprType.INTEGER); - assertEquals(ExprType.INTEGER, environment().resolve(age)); - - // New environment 1 - context.push(); - Expression city = DSL.ref("s.city"); - environment().define(city, ExprType.STRING); - assertEquals(ExprType.INTEGER, environment().resolve(age)); - assertEquals(ExprType.STRING, environment().resolve(city)); - - // New environment 2 - context.push(); - Expression manager = DSL.ref("s.manager"); - environment().define(manager, ExprType.STRUCT); - assertEquals(ExprType.INTEGER, environment().resolve(age)); - assertEquals(ExprType.STRING, environment().resolve(city)); - assertEquals(ExprType.STRUCT, environment().resolve(manager)); - } - - @Test - public void defineFieldSymbolInDifferentEnvironmentsShouldNotAbleToResolveOncePopped() { - // Root environment - Expression age = DSL.ref("s.age"); - environment().define(age, ExprType.INTEGER); - - // New environment - context.push(); - Expression city = DSL.ref("s.city"); - environment().define(city, ExprType.STRING); - Expression manager = DSL.ref("s.manager"); - environment().define(manager, ExprType.STRUCT); - assertEquals(ExprType.INTEGER, environment().resolve(age)); - assertEquals(ExprType.STRING, environment().resolve(city)); - assertEquals(ExprType.STRUCT, environment().resolve(manager)); - - context.pop(); - assertEquals(ExprType.INTEGER, environment().resolve(age)); - SemanticCheckException exception = assertThrows(SemanticCheckException.class, () -> environment().resolve(city)); - assertEquals("can't resolve expression s.city in type env", exception.getMessage()); - exception = assertThrows(SemanticCheckException.class, () -> environment().resolve(manager)); - assertEquals("can't resolve expression s.manager in type env", exception.getMessage()); - } - - @Test - public void resolveLiteralInEnvFailed() { - SemanticCheckException exception = assertThrows(SemanticCheckException.class, - () -> environment().resolve(DSL.literal(ExprValueUtils.integerValue(1)))); - assertEquals("can't resolve expression 1 in type env", exception.getMessage()); - } - - - @Test - public void defineLiteralInEnvIsIllegal() { - IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, - () -> environment().define(DSL.literal(ExprValueUtils.integerValue(1)), ExprType.INTEGER)); - assertEquals("only support define reference, unexpected expression 1", exception.getMessage()); - } - - private TypeEnvironment environment() { - return context.peek(); - } + /** + * Use context class for push/pop. + */ + private AnalysisContext context = new AnalysisContext(); + + @Test + public void defineFieldSymbolInDifferentEnvironmentsShouldBeAbleToResolve() { + // Root environment + Expression age = DSL.ref("s.age"); + environment().define(age, ExprType.INTEGER); + assertEquals(ExprType.INTEGER, environment().resolve(age)); + + // New environment 1 + context.push(); + Expression city = DSL.ref("s.city"); + environment().define(city, ExprType.STRING); + assertEquals(ExprType.INTEGER, environment().resolve(age)); + assertEquals(ExprType.STRING, environment().resolve(city)); + + // New environment 2 + context.push(); + Expression manager = DSL.ref("s.manager"); + environment().define(manager, ExprType.STRUCT); + assertEquals(ExprType.INTEGER, environment().resolve(age)); + assertEquals(ExprType.STRING, environment().resolve(city)); + assertEquals(ExprType.STRUCT, environment().resolve(manager)); + } + + @Test + public void defineFieldSymbolInDifferentEnvironmentsShouldNotAbleToResolveOncePopped() { + // Root environment + Expression age = DSL.ref("s.age"); + environment().define(age, ExprType.INTEGER); + + // New environment + context.push(); + Expression city = DSL.ref("s.city"); + environment().define(city, ExprType.STRING); + Expression manager = DSL.ref("s.manager"); + environment().define(manager, ExprType.STRUCT); + assertEquals(ExprType.INTEGER, environment().resolve(age)); + assertEquals(ExprType.STRING, environment().resolve(city)); + assertEquals(ExprType.STRUCT, environment().resolve(manager)); + + context.pop(); + assertEquals(ExprType.INTEGER, environment().resolve(age)); + SemanticCheckException exception = + assertThrows(SemanticCheckException.class, () -> environment().resolve(city)); + assertEquals("can't resolve expression s.city in type env", exception.getMessage()); + exception = assertThrows(SemanticCheckException.class, () -> environment().resolve(manager)); + assertEquals("can't resolve expression s.manager in type env", exception.getMessage()); + } + + @Test + public void resolveLiteralInEnvFailed() { + SemanticCheckException exception = assertThrows(SemanticCheckException.class, + () -> environment().resolve(DSL.literal(ExprValueUtils.integerValue(1)))); + assertEquals("can't resolve expression 1 in type env", exception.getMessage()); + } + + + @Test + public void defineLiteralInEnvIsIllegal() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, + () -> environment().define(DSL.literal(ExprValueUtils.integerValue(1)), ExprType.INTEGER)); + assertEquals("only support define reference, unexpected expression 1", exception.getMessage()); + } + + private TypeEnvironment environment() { + return context.peek(); + } } diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/analysis/symbol/SymbolTableTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/analysis/symbol/SymbolTableTest.java index a44e443d1c..d04456abf5 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/analysis/symbol/SymbolTableTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/analysis/symbol/SymbolTableTest.java @@ -15,12 +15,6 @@ package com.amazon.opendistroforelasticsearch.sql.analysis.symbol; -import com.amazon.opendistroforelasticsearch.sql.data.model.ExprType; -import org.junit.jupiter.api.Test; - -import java.util.Map; -import java.util.Optional; - import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprType.BOOLEAN; import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprType.INTEGER; import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprType.STRING; @@ -33,54 +27,61 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; +import com.amazon.opendistroforelasticsearch.sql.data.model.ExprType; +import java.util.Map; +import java.util.Optional; +import org.junit.jupiter.api.Test; -public class SymbolTableTest { - - private final SymbolTable symbolTable = new SymbolTable(); - - @Test - public void defineFieldSymbolShouldBeAbleToResolve() { - defineSymbolShouldBeAbleToResolve(new Symbol(Namespace.FIELD_NAME, "age"), INTEGER); - } - - - @Test - public void defineFieldSymbolShouldBeAbleToResolveByPrefix() { - symbolTable.store(new Symbol(Namespace.FIELD_NAME, "s.projects.active"), BOOLEAN); - symbolTable.store(new Symbol(Namespace.FIELD_NAME, "s.address"), STRING); - symbolTable.store(new Symbol(Namespace.FIELD_NAME, "s.manager.name"), STRING); - - Map typeByName = symbolTable.lookupByPrefix(new Symbol(Namespace.FIELD_NAME, "s.projects")); - - assertThat( - typeByName, - allOf( - aMapWithSize(1), - hasEntry("s.projects.active", BOOLEAN) - ) - ); - } - - @Test - public void failedToResolveSymbolNoNamespaceMatched() { - symbolTable.store(new Symbol(Namespace.FUNCTION_NAME, "customFunction"), BOOLEAN); - assertFalse(symbolTable.lookup(new Symbol(Namespace.FIELD_NAME, "s.projects")).isPresent()); - - assertThat(symbolTable.lookupByPrefix(new Symbol(Namespace.FIELD_NAME, "s.projects")), anEmptyMap()); - } - - @Test - public void isEmpty() { - symbolTable.store(new Symbol(Namespace.FUNCTION_NAME, "customFunction"), BOOLEAN); - assertTrue(symbolTable.isEmpty(Namespace.FIELD_NAME)); - } - private void defineSymbolShouldBeAbleToResolve(Symbol symbol, ExprType expectedType) { - symbolTable.store(symbol, expectedType); +public class SymbolTableTest { - Optional actualType = symbolTable.lookup(symbol); - assertTrue(actualType.isPresent()); - assertEquals(expectedType, actualType.get()); - } + private final SymbolTable symbolTable = new SymbolTable(); + + @Test + public void defineFieldSymbolShouldBeAbleToResolve() { + defineSymbolShouldBeAbleToResolve(new Symbol(Namespace.FIELD_NAME, "age"), INTEGER); + } + + + @Test + public void defineFieldSymbolShouldBeAbleToResolveByPrefix() { + symbolTable.store(new Symbol(Namespace.FIELD_NAME, "s.projects.active"), BOOLEAN); + symbolTable.store(new Symbol(Namespace.FIELD_NAME, "s.address"), STRING); + symbolTable.store(new Symbol(Namespace.FIELD_NAME, "s.manager.name"), STRING); + + Map typeByName = + symbolTable.lookupByPrefix(new Symbol(Namespace.FIELD_NAME, "s.projects")); + + assertThat( + typeByName, + allOf( + aMapWithSize(1), + hasEntry("s.projects.active", BOOLEAN) + ) + ); + } + + @Test + public void failedToResolveSymbolNoNamespaceMatched() { + symbolTable.store(new Symbol(Namespace.FUNCTION_NAME, "customFunction"), BOOLEAN); + assertFalse(symbolTable.lookup(new Symbol(Namespace.FIELD_NAME, "s.projects")).isPresent()); + + assertThat(symbolTable.lookupByPrefix(new Symbol(Namespace.FIELD_NAME, "s.projects")), + anEmptyMap()); + } + + @Test + public void isEmpty() { + symbolTable.store(new Symbol(Namespace.FUNCTION_NAME, "customFunction"), BOOLEAN); + assertTrue(symbolTable.isEmpty(Namespace.FIELD_NAME)); + } + + private void defineSymbolShouldBeAbleToResolve(Symbol symbol, ExprType expectedType) { + symbolTable.store(symbol, expectedType); + + Optional actualType = symbolTable.lookup(symbol); + assertTrue(actualType.isPresent()); + assertEquals(expectedType, actualType.get()); + } } \ No newline at end of file diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/config/TestConfig.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/config/TestConfig.java index 025fc0616b..1bbf6d2d98 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/config/TestConfig.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/config/TestConfig.java @@ -28,76 +28,76 @@ import com.amazon.opendistroforelasticsearch.sql.storage.StorageEngine; import com.amazon.opendistroforelasticsearch.sql.storage.Table; import com.google.common.collect.ImmutableMap; +import java.util.Map; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import java.util.Map; - /** * Configuration will be used for UT. */ @Configuration public class TestConfig { - public static final String INT_TYPE_NULL_VALUE_FIELD = "int_null_value"; - public static final String INT_TYPE_MISSING_VALUE_FIELD = "int_missing_value"; - public static final String BOOL_TYPE_NULL_VALUE_FIELD = "null_value_boolean"; - public static final String BOOL_TYPE_MISSING_VALUE_FIELD = "missing_value_boolean"; + public static final String INT_TYPE_NULL_VALUE_FIELD = "int_null_value"; + public static final String INT_TYPE_MISSING_VALUE_FIELD = "int_missing_value"; + public static final String BOOL_TYPE_NULL_VALUE_FIELD = "null_value_boolean"; + public static final String BOOL_TYPE_MISSING_VALUE_FIELD = "missing_value_boolean"; - private static Map typeMapping = new ImmutableMap.Builder() - .put("integer_value", ExprType.INTEGER) - .put(INT_TYPE_NULL_VALUE_FIELD, ExprType.INTEGER) - .put(INT_TYPE_MISSING_VALUE_FIELD, ExprType.INTEGER) - .put("long_value", ExprType.LONG) - .put("float_value", ExprType.FLOAT) - .put("double_value", ExprType.DOUBLE) - .put("boolean_value", ExprType.BOOLEAN) - .put(BOOL_TYPE_NULL_VALUE_FIELD, ExprType.BOOLEAN) - .put(BOOL_TYPE_MISSING_VALUE_FIELD, ExprType.BOOLEAN) - .put("string_value", ExprType.STRING) - .put("struct_value", ExprType.STRUCT) - .put("array_value", ExprType.ARRAY) - .build(); + private static Map typeMapping = new ImmutableMap.Builder() + .put("integer_value", ExprType.INTEGER) + .put(INT_TYPE_NULL_VALUE_FIELD, ExprType.INTEGER) + .put(INT_TYPE_MISSING_VALUE_FIELD, ExprType.INTEGER) + .put("long_value", ExprType.LONG) + .put("float_value", ExprType.FLOAT) + .put("double_value", ExprType.DOUBLE) + .put("boolean_value", ExprType.BOOLEAN) + .put(BOOL_TYPE_NULL_VALUE_FIELD, ExprType.BOOLEAN) + .put(BOOL_TYPE_MISSING_VALUE_FIELD, ExprType.BOOLEAN) + .put("string_value", ExprType.STRING) + .put("struct_value", ExprType.STRUCT) + .put("array_value", ExprType.ARRAY) + .build(); - @Bean - protected StorageEngine storageEngine() { - return new StorageEngine() { - @Override - public Table getTable(String name) { - return new Table() { - @Override - public Map getFieldTypes() { - return typeMapping; - } + @Bean + protected StorageEngine storageEngine() { + return new StorageEngine() { + @Override + public Table getTable(String name) { + return new Table() { + @Override + public Map getFieldTypes() { + return typeMapping; + } - @Override - public PhysicalPlan implement(LogicalPlan plan) { - throw new UnsupportedOperationException(); - } - }; - } + @Override + public PhysicalPlan implement(LogicalPlan plan) { + throw new UnsupportedOperationException(); + } }; - } + } + }; + } - @Bean - protected SymbolTable symbolTable() { - SymbolTable symbolTable = new SymbolTable(); - typeMapping.entrySet() - .forEach( - entry -> symbolTable.store(new Symbol(Namespace.FIELD_NAME, entry.getKey()), entry.getValue())); - return symbolTable; - } + @Bean + protected SymbolTable symbolTable() { + SymbolTable symbolTable = new SymbolTable(); + typeMapping.entrySet() + .forEach( + entry -> symbolTable + .store(new Symbol(Namespace.FIELD_NAME, entry.getKey()), entry.getValue())); + return symbolTable; + } - @Bean - protected Environment typeEnv() { - return var -> { - if (var instanceof ReferenceExpression) { - ReferenceExpression refExpr = (ReferenceExpression) var; - if (typeMapping.containsKey(refExpr.getAttr())) { - return typeMapping.get(refExpr.getAttr()); - } - } - throw new ExpressionEvaluationException("type resolved failed"); - }; - } + @Bean + protected Environment typeEnv() { + return var -> { + if (var instanceof ReferenceExpression) { + ReferenceExpression refExpr = (ReferenceExpression) var; + if (typeMapping.containsKey(refExpr.getAttr())) { + return typeMapping.get(refExpr.getAttr()); + } + } + throw new ExpressionEvaluationException("type resolved failed"); + }; + } } diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprMissingValueTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprMissingValueTest.java index 3393444dd2..7fec1d002d 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprMissingValueTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprMissingValueTest.java @@ -15,33 +15,33 @@ package com.amazon.opendistroforelasticsearch.sql.data.model; -import com.amazon.opendistroforelasticsearch.sql.exception.ExpressionEvaluationException; -import org.junit.jupiter.api.Test; - import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.LITERAL_MISSING; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +import com.amazon.opendistroforelasticsearch.sql.exception.ExpressionEvaluationException; +import org.junit.jupiter.api.Test; + class ExprMissingValueTest { - @Test - public void test_is_missing() { - assertTrue(LITERAL_MISSING.isMissing()); - } - - @Test - public void getValue() { - ExpressionEvaluationException exception = assertThrows(ExpressionEvaluationException.class, - () -> LITERAL_MISSING.value()); - assertEquals("invalid to call value operation on missing value", exception.getMessage()); - } - - @Test - public void getType() { - ExpressionEvaluationException exception = assertThrows(ExpressionEvaluationException.class, - () -> LITERAL_MISSING.type()); - assertEquals("invalid to call type operation on missing value", exception.getMessage()); - } + @Test + public void test_is_missing() { + assertTrue(LITERAL_MISSING.isMissing()); + } + + @Test + public void getValue() { + ExpressionEvaluationException exception = assertThrows(ExpressionEvaluationException.class, + () -> LITERAL_MISSING.value()); + assertEquals("invalid to call value operation on missing value", exception.getMessage()); + } + + @Test + public void getType() { + ExpressionEvaluationException exception = assertThrows(ExpressionEvaluationException.class, + () -> LITERAL_MISSING.type()); + assertEquals("invalid to call type operation on missing value", exception.getMessage()); + } } \ No newline at end of file diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprNullValueTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprNullValueTest.java index d16f2d6bc2..db0bd4041b 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprNullValueTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprNullValueTest.java @@ -15,31 +15,31 @@ package com.amazon.opendistroforelasticsearch.sql.data.model; -import com.amazon.opendistroforelasticsearch.sql.exception.ExpressionEvaluationException; -import org.junit.jupiter.api.Test; - import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.LITERAL_NULL; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +import com.amazon.opendistroforelasticsearch.sql.exception.ExpressionEvaluationException; +import org.junit.jupiter.api.Test; + public class ExprNullValueTest { - @Test - public void test_is_null() { - assertTrue(LITERAL_NULL.isNull()); - } + @Test + public void test_is_null() { + assertTrue(LITERAL_NULL.isNull()); + } - @Test - public void getValue() { - assertNull(LITERAL_NULL.value()); - } + @Test + public void getValue() { + assertNull(LITERAL_NULL.value()); + } - @Test - public void getType() { - ExpressionEvaluationException exception = assertThrows(ExpressionEvaluationException.class, - () -> LITERAL_NULL.type()); - assertEquals("invalid to call type operation on null value", exception.getMessage()); - } + @Test + public void getType() { + ExpressionEvaluationException exception = assertThrows(ExpressionEvaluationException.class, + () -> LITERAL_NULL.type()); + assertEquals("invalid to call type operation on null value", exception.getMessage()); + } } diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprTupleValueTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprTupleValueTest.java index 0004915b17..4ed62bf066 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprTupleValueTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprTupleValueTest.java @@ -22,24 +22,25 @@ import org.junit.jupiter.api.Test; class ExprTupleValueTest { - @Test - public void equal_to_itself() { - ExprValue tupleValue = ExprValueUtils.tupleValue(ImmutableMap.of("integer_value", 2)); - assertTrue(tupleValue.equals(tupleValue)); - } + @Test + public void equal_to_itself() { + ExprValue tupleValue = ExprValueUtils.tupleValue(ImmutableMap.of("integer_value", 2)); + assertTrue(tupleValue.equals(tupleValue)); + } - @Test - public void tuple_compare_int() { - ExprValue tupleValue = ExprValueUtils.tupleValue(ImmutableMap.of("integer_value", 2)); - ExprValue intValue = ExprValueUtils.integerValue(10); - assertFalse(tupleValue.equals(intValue)); - } + @Test + public void tuple_compare_int() { + ExprValue tupleValue = ExprValueUtils.tupleValue(ImmutableMap.of("integer_value", 2)); + ExprValue intValue = ExprValueUtils.integerValue(10); + assertFalse(tupleValue.equals(intValue)); + } - @Test - public void compre_tuple_with_different_size() { - ExprValue tupleValue1 = ExprValueUtils.tupleValue(ImmutableMap.of("integer_value", 2)); - ExprValue tupleValue2 = ExprValueUtils.tupleValue(ImmutableMap.of("integer_value", 2, "float_value", 1f)); - assertFalse(tupleValue1.equals(tupleValue2)); - assertFalse(tupleValue2.equals(tupleValue1)); - } + @Test + public void compre_tuple_with_different_size() { + ExprValue tupleValue1 = ExprValueUtils.tupleValue(ImmutableMap.of("integer_value", 2)); + ExprValue tupleValue2 = + ExprValueUtils.tupleValue(ImmutableMap.of("integer_value", 2, "float_value", 1f)); + assertFalse(tupleValue1.equals(tupleValue2)); + assertFalse(tupleValue2.equals(tupleValue1)); + } } \ No newline at end of file diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprValueUtilsTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprValueUtilsTest.java index 26ef90bc6b..7daa64b090 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprValueUtilsTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/data/model/ExprValueUtilsTest.java @@ -15,17 +15,16 @@ package com.amazon.opendistroforelasticsearch.sql.data.model; +import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.integerValue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + import com.amazon.opendistroforelasticsearch.sql.exception.ExpressionEvaluationException; import com.amazon.opendistroforelasticsearch.sql.storage.bindingtuple.BindingTuple; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - import java.util.AbstractMap; import java.util.ArrayList; import java.util.Arrays; @@ -34,139 +33,157 @@ import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; - -import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.integerValue; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; @DisplayName("Test Expression Value Utils") public class ExprValueUtilsTest { - private static List numberValues = Stream.of(1, 1L, 1f, 1D) - .map(ExprValueUtils::fromObjectValue).collect(Collectors.toList()); - private static List nonNumberValues = Stream.of("1", true, Arrays.asList(1), - ImmutableMap.of("1", 1)).map(ExprValueUtils::fromObjectValue).collect(Collectors.toList()); - private static List allValues = Lists.newArrayList(Iterables.concat(numberValues, nonNumberValues)); - - private static List> numberValueExtractor = Arrays.asList( - ExprValueUtils::getIntegerValue, - ExprValueUtils::getLongValue, - ExprValueUtils::getFloatValue, - ExprValueUtils::getDoubleValue); - private static List> nonNumberValueExtractor = Arrays.asList( - ExprValueUtils::getStringValue, - ExprValueUtils::getBooleanValue, - ExprValueUtils::getCollectionValue, - ExprValueUtils::getTupleValue); - private static List> allValueExtractor = Lists.newArrayList( - Iterables.concat(numberValueExtractor, nonNumberValueExtractor)); - - private static List numberTypes = Arrays.asList(ExprType.INTEGER, ExprType.LONG, ExprType.FLOAT, - ExprType.DOUBLE); - private static List nonNumberTypes = Arrays.asList(ExprType.STRING, ExprType.BOOLEAN, ExprType.ARRAY, - ExprType.STRUCT); - private static List allTypes = Lists.newArrayList(Iterables.concat(numberTypes, nonNumberTypes)); - - private static Stream getValueTestArgumentStream() { - List expectedValues = Arrays.asList(1, 1L, 1f, 1D, "1", true, - Arrays.asList(integerValue(1)), - ImmutableMap.of("1", integerValue(1))); - Stream.Builder builder = Stream.builder(); - for (int i = 0; i < expectedValues.size(); i++) { - builder.add(Arguments.of( - allValues.get(i), - allValueExtractor.get(i), - expectedValues.get(i))); - } - return builder.build(); - } - - private static Stream getTypeTestArgumentStream() { - Stream.Builder builder = Stream.builder(); - for (int i = 0; i < allValues.size(); i++) { - builder.add(Arguments.of( - allValues.get(i), - allTypes.get(i))); - } - return builder.build(); - } - - private static Stream invalidGetNumberValueArgumentStream() { - return Lists.cartesianProduct(nonNumberValues, numberValueExtractor) - .stream() - .map(list -> Arguments.of(list.get(0), list.get(1))); - } - - @SuppressWarnings("unchecked") - private static Stream invalidConvert() { - List, ExprType>> extractorWithTypeList = new ArrayList<>(); - for (int i = 0; i < nonNumberValueExtractor.size(); i++) { - extractorWithTypeList.add( - new AbstractMap.SimpleEntry<>(nonNumberValueExtractor.get(i), nonNumberTypes.get(i))); - } - return Lists.cartesianProduct(allValues, extractorWithTypeList) - .stream() - .filter(list -> { - ExprValue value = (ExprValue) list.get(0); - Map.Entry, ExprType> entry = (Map.Entry, - ExprType>) list - .get(1); - return entry.getValue() != value.type(); - }) - .map(list -> { - Map.Entry, ExprType> entry = (Map.Entry, - ExprType>) list - .get(1); - return Arguments.of(list.get(0), entry.getKey(), entry.getValue()); - }); + private static List numberValues = Stream.of(1, 1L, 1f, 1D) + .map(ExprValueUtils::fromObjectValue).collect(Collectors.toList()); + private static List nonNumberValues = Stream.of("1", true, Arrays.asList(1), + ImmutableMap.of("1", 1)).map(ExprValueUtils::fromObjectValue).collect(Collectors.toList()); + private static List allValues = + Lists.newArrayList(Iterables.concat(numberValues, nonNumberValues)); + + private static List> numberValueExtractor = Arrays.asList( + ExprValueUtils::getIntegerValue, + ExprValueUtils::getLongValue, + ExprValueUtils::getFloatValue, + ExprValueUtils::getDoubleValue); + private static List> nonNumberValueExtractor = Arrays.asList( + ExprValueUtils::getStringValue, + ExprValueUtils::getBooleanValue, + ExprValueUtils::getCollectionValue, + ExprValueUtils::getTupleValue); + private static List> allValueExtractor = Lists.newArrayList( + Iterables.concat(numberValueExtractor, nonNumberValueExtractor)); + + private static List numberTypes = + Arrays.asList(ExprType.INTEGER, ExprType.LONG, ExprType.FLOAT, + ExprType.DOUBLE); + private static List nonNumberTypes = + Arrays.asList(ExprType.STRING, ExprType.BOOLEAN, ExprType.ARRAY, + ExprType.STRUCT); + private static List allTypes = + Lists.newArrayList(Iterables.concat(numberTypes, nonNumberTypes)); + + private static Stream getValueTestArgumentStream() { + List expectedValues = Arrays.asList(1, 1L, 1f, 1D, "1", true, + Arrays.asList(integerValue(1)), + ImmutableMap.of("1", integerValue(1))); + Stream.Builder builder = Stream.builder(); + for (int i = 0; i < expectedValues.size(); i++) { + builder.add(Arguments.of( + allValues.get(i), + allValueExtractor.get(i), + expectedValues.get(i))); } - - @ParameterizedTest(name = "the value of ExprValue:{0} is: {2} ") - @MethodSource("getValueTestArgumentStream") - public void getValue(ExprValue value, Function extractor, Object expect) { - assertEquals(expect, extractor.apply(value)); + return builder.build(); + } + + private static Stream getTypeTestArgumentStream() { + Stream.Builder builder = Stream.builder(); + for (int i = 0; i < allValues.size(); i++) { + builder.add(Arguments.of( + allValues.get(i), + allTypes.get(i))); } - - @ParameterizedTest(name = "the type of ExprValue:{0} is: {1} ") - @MethodSource("getTypeTestArgumentStream") - public void getType(ExprValue value, ExprType expectType) { - assertEquals(expectType, value.type()); + return builder.build(); + } + + private static Stream invalidGetNumberValueArgumentStream() { + return Lists.cartesianProduct(nonNumberValues, numberValueExtractor) + .stream() + .map(list -> Arguments.of(list.get(0), list.get(1))); + } + + @SuppressWarnings("unchecked") + private static Stream invalidConvert() { + List, ExprType>> extractorWithTypeList = + new ArrayList<>(); + for (int i = 0; i < nonNumberValueExtractor.size(); i++) { + extractorWithTypeList.add( + new AbstractMap.SimpleEntry<>(nonNumberValueExtractor.get(i), nonNumberTypes.get(i))); } - - @ParameterizedTest(name = "invalid to get number value of ExprValue:{0}") - @MethodSource("invalidGetNumberValueArgumentStream") - public void invalidGetNumberValue(ExprValue value, Function extractor) { - Exception exception = assertThrows(ExpressionEvaluationException.class, - () -> extractor.apply(value)); - assertEquals(String.format("invalid to getNumberValue with expression has type of %s", value.type()), - exception.getMessage()); - } - - @ParameterizedTest(name = "invalid convert ExprValue:{0} to ExprType:{2}") - @MethodSource("invalidConvert") - public void invalidConvert(ExprValue value, Function extractor, ExprType toType) { - Exception exception = assertThrows(ExpressionEvaluationException.class, - () -> extractor.apply(value)); - assertEquals(String.format("invalid to convert expression with type:%s to type:%s", value.type(), toType), - exception.getMessage()); - } - - @Test - public void unSupportedObject() { - Exception exception = assertThrows(ExpressionEvaluationException.class, - () -> ExprValueUtils.fromObjectValue(integerValue(1))); - assertEquals("unsupported object class com.amazon.opendistroforelasticsearch.sql.data.model.ExprIntegerValue", - exception.getMessage()); - } - - @Test - public void bindingTuples() { - for (ExprValue value : allValues) { - if (ExprType.STRUCT == value.type()) { - assertNotEquals(BindingTuple.EMPTY, value.bindingTuples()); - } else { - assertEquals(BindingTuple.EMPTY, value.bindingTuples()); - } - } + return Lists.cartesianProduct(allValues, extractorWithTypeList) + .stream() + .filter(list -> { + ExprValue value = (ExprValue) list.get(0); + Map.Entry, ExprType> entry = + (Map.Entry, + ExprType>) list + .get(1); + return entry.getValue() != value.type(); + }) + .map(list -> { + Map.Entry, ExprType> entry = + (Map.Entry, + ExprType>) list + .get(1); + return Arguments.of(list.get(0), entry.getKey(), entry.getValue()); + }); + } + + @ParameterizedTest(name = "the value of ExprValue:{0} is: {2} ") + @MethodSource("getValueTestArgumentStream") + public void getValue(ExprValue value, Function extractor, Object expect) { + assertEquals(expect, extractor.apply(value)); + } + + @ParameterizedTest(name = "the type of ExprValue:{0} is: {1} ") + @MethodSource("getTypeTestArgumentStream") + public void getType(ExprValue value, ExprType expectType) { + assertEquals(expectType, value.type()); + } + + /** + * Test Invalid to get number. + */ + @ParameterizedTest(name = "invalid to get number value of ExprValue:{0}") + @MethodSource("invalidGetNumberValueArgumentStream") + public void invalidGetNumberValue(ExprValue value, Function extractor) { + Exception exception = assertThrows(ExpressionEvaluationException.class, + () -> extractor.apply(value)); + assertEquals( + String.format("invalid to getNumberValue with expression has type of %s", value.type()), + exception.getMessage()); + } + + /** + * Test Invalid to convert. + */ + @ParameterizedTest(name = "invalid convert ExprValue:{0} to ExprType:{2}") + @MethodSource("invalidConvert") + public void invalidConvertExprValue(ExprValue value, Function extractor, + ExprType toType) { + Exception exception = assertThrows(ExpressionEvaluationException.class, + () -> extractor.apply(value)); + assertEquals(String + .format("invalid to convert expression with type:%s to type:%s", value.type(), toType), + exception.getMessage()); + } + + @Test + public void unSupportedObject() { + Exception exception = assertThrows(ExpressionEvaluationException.class, + () -> ExprValueUtils.fromObjectValue(integerValue(1))); + assertEquals( + "unsupported object " + + "class com.amazon.opendistroforelasticsearch.sql.data.model.ExprIntegerValue", + exception.getMessage()); + } + + @Test + public void bindingTuples() { + for (ExprValue value : allValues) { + if (ExprType.STRUCT == value.type()) { + assertNotEquals(BindingTuple.EMPTY, value.bindingTuples()); + } else { + assertEquals(BindingTuple.EMPTY, value.bindingTuples()); + } } + } } \ No newline at end of file diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/data/utils/ExprValueOrderingTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/data/utils/ExprValueOrderingTest.java index c837f9b78d..ce81c3662e 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/data/utils/ExprValueOrderingTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/data/utils/ExprValueOrderingTest.java @@ -42,8 +42,10 @@ @ExtendWith(MockitoExtension.class) class ExprValueOrderingTest { - @Mock ExprValue left; - @Mock ExprValue right; + @Mock + ExprValue left; + @Mock + ExprValue right; @Test public void natural() { @@ -136,9 +138,9 @@ public void natural_order_float_value() { @Test public void natural_order_long_value() { ExprValueOrdering ordering = ExprValueOrdering.natural(); - assertEquals(1, ordering.compare(longValue(5l), longValue(4l))); - assertEquals(0, ordering.compare(longValue(5l), longValue(5l))); - assertEquals(-1, ordering.compare(longValue(4l), longValue(5l))); + assertEquals(1, ordering.compare(longValue(5L), longValue(4L))); + assertEquals(0, ordering.compare(longValue(5L), longValue(5L))); + assertEquals(-1, ordering.compare(longValue(4L), longValue(5L))); } @Test diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/data/utils/NullsFirstExprValueOrderingTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/data/utils/NullsFirstExprValueOrderingTest.java index d5916eecf3..84f4c4de99 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/data/utils/NullsFirstExprValueOrderingTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/data/utils/NullsFirstExprValueOrderingTest.java @@ -18,7 +18,7 @@ import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.LITERAL_MISSING; import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.LITERAL_NULL; import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.integerValue; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprValue; import org.junit.jupiter.api.Test; diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/data/utils/NullsLastExprValueOrderingTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/data/utils/NullsLastExprValueOrderingTest.java index a02e1ce774..47251506ad 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/data/utils/NullsLastExprValueOrderingTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/data/utils/NullsLastExprValueOrderingTest.java @@ -18,7 +18,7 @@ import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.LITERAL_MISSING; import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.LITERAL_NULL; import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.integerValue; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprValue; import org.junit.jupiter.api.Test; diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/data/utils/ReverseExprValueOrderingTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/data/utils/ReverseExprValueOrderingTest.java index 15387f999c..d8e07cc205 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/data/utils/ReverseExprValueOrderingTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/data/utils/ReverseExprValueOrderingTest.java @@ -16,7 +16,7 @@ package com.amazon.opendistroforelasticsearch.sql.data.utils; import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.integerValue; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.Test; diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/ExpressionTestBase.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/ExpressionTestBase.java index e40303f514..222ef2925e 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/ExpressionTestBase.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/ExpressionTestBase.java @@ -15,6 +15,21 @@ package com.amazon.opendistroforelasticsearch.sql.expression; +import static com.amazon.opendistroforelasticsearch.sql.config.TestConfig.BOOL_TYPE_MISSING_VALUE_FIELD; +import static com.amazon.opendistroforelasticsearch.sql.config.TestConfig.BOOL_TYPE_NULL_VALUE_FIELD; +import static com.amazon.opendistroforelasticsearch.sql.config.TestConfig.INT_TYPE_MISSING_VALUE_FIELD; +import static com.amazon.opendistroforelasticsearch.sql.config.TestConfig.INT_TYPE_NULL_VALUE_FIELD; +import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.booleanValue; +import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.collectionValue; +import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.doubleValue; +import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.floatValue; +import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.integerValue; +import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.longValue; +import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.missingValue; +import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.nullValue; +import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.stringValue; +import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.tupleValue; + import com.amazon.opendistroforelasticsearch.sql.config.TestConfig; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprType; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprValue; @@ -23,6 +38,8 @@ import com.amazon.opendistroforelasticsearch.sql.expression.function.BuiltinFunctionName; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import java.util.List; +import java.util.function.BiFunction; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; @@ -30,82 +47,74 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; -import java.util.List; -import java.util.function.BiFunction; - -import static com.amazon.opendistroforelasticsearch.sql.config.TestConfig.BOOL_TYPE_NULL_VALUE_FIELD; -import static com.amazon.opendistroforelasticsearch.sql.config.TestConfig.INT_TYPE_NULL_VALUE_FIELD; -import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.booleanValue; -import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.collectionValue; -import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.doubleValue; -import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.floatValue; -import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.integerValue; -import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.longValue; -import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.missingValue; -import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.nullValue; -import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.stringValue; -import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.tupleValue; - @Configuration @ExtendWith(SpringExtension.class) -@ContextConfiguration(classes = {ExpressionConfig.class, ExpressionTestBase.class, TestConfig.class}) +@ContextConfiguration(classes = {ExpressionConfig.class, ExpressionTestBase.class, + TestConfig.class}) public class ExpressionTestBase { - @Autowired - protected DSL dsl; + @Autowired + protected DSL dsl; - @Autowired - protected Environment typeEnv; + @Autowired + protected Environment typeEnv; - @Bean - protected Environment valueEnv() { - return var -> { - if (var instanceof ReferenceExpression) { - switch (((ReferenceExpression) var).getAttr()) { - case "integer_value": - return integerValue(1); - case "long_value": - return longValue(1L); - case "float_value": - return floatValue(1f); - case "double_value": - return doubleValue(1d); - case "boolean_value": - return booleanValue(true); - case "string_value": - return stringValue("str"); - case "struct_value": - return tupleValue(ImmutableMap.of("str", 1)); - case "array_value": - return collectionValue(ImmutableList.of(1)); - case BOOL_TYPE_NULL_VALUE_FIELD: - case INT_TYPE_NULL_VALUE_FIELD: - return nullValue(); - } - } + @Bean + protected Environment valueEnv() { + return var -> { + if (var instanceof ReferenceExpression) { + switch (((ReferenceExpression) var).getAttr()) { + case "integer_value": + return integerValue(1); + case "long_value": + return longValue(1L); + case "float_value": + return floatValue(1f); + case "double_value": + return doubleValue(1d); + case "boolean_value": + return booleanValue(true); + case "string_value": + return stringValue("str"); + case "struct_value": + return tupleValue(ImmutableMap.of("str", 1)); + case "array_value": + return collectionValue(ImmutableList.of(1)); + case BOOL_TYPE_NULL_VALUE_FIELD: + case INT_TYPE_NULL_VALUE_FIELD: + return nullValue(); + case INT_TYPE_MISSING_VALUE_FIELD: + case BOOL_TYPE_MISSING_VALUE_FIELD: return missingValue(); - }; - } + default: + throw new IllegalArgumentException("undefined reference"); + } + } else { + throw new IllegalArgumentException("var must be ReferenceExpression"); + } + }; + } - @Bean - protected Environment typeEnv() { - return typeEnv; - } + @Bean + protected Environment typeEnv() { + return typeEnv; + } - protected BiFunction, - List, FunctionExpression> functionMapping(BuiltinFunctionName builtinFunctionName) { - switch (builtinFunctionName) { - case ADD: - return (env, expressions) -> dsl.add(env, expressions.get(0), expressions.get(1)); - case SUBTRACT: - return (env, expressions) -> dsl.subtract(env, expressions.get(0), expressions.get(1)); - case MULTIPLY: - return (env, expressions) -> dsl.multiply(env, expressions.get(0), expressions.get(1)); - case DIVIDE: - return (env, expressions) -> dsl.divide(env, expressions.get(0), expressions.get(1)); - case MODULES: - return (env, expressions) -> dsl.module(env, expressions.get(0), expressions.get(1)); - default: - throw new RuntimeException(); - } + protected BiFunction, + List, FunctionExpression> functionMapping( + BuiltinFunctionName builtinFunctionName) { + switch (builtinFunctionName) { + case ADD: + return (env, expressions) -> dsl.add(env, expressions.get(0), expressions.get(1)); + case SUBTRACT: + return (env, expressions) -> dsl.subtract(env, expressions.get(0), expressions.get(1)); + case MULTIPLY: + return (env, expressions) -> dsl.multiply(env, expressions.get(0), expressions.get(1)); + case DIVIDE: + return (env, expressions) -> dsl.divide(env, expressions.get(0), expressions.get(1)); + case MODULES: + return (env, expressions) -> dsl.module(env, expressions.get(0), expressions.get(1)); + default: + throw new RuntimeException(); } + } } diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/ReferenceExpressionTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/ReferenceExpressionTest.java index f1bd4a9099..ed6feba7a7 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/ReferenceExpressionTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/ReferenceExpressionTest.java @@ -15,14 +15,6 @@ package com.amazon.opendistroforelasticsearch.sql.expression; -import com.amazon.opendistroforelasticsearch.sql.data.model.ExprType; -import com.amazon.opendistroforelasticsearch.sql.exception.ExpressionEvaluationException; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import org.junit.jupiter.api.DisplayNameGeneration; -import org.junit.jupiter.api.DisplayNameGenerator; -import org.junit.jupiter.api.Test; - import static com.amazon.opendistroforelasticsearch.sql.config.TestConfig.BOOL_TYPE_MISSING_VALUE_FIELD; import static com.amazon.opendistroforelasticsearch.sql.config.TestConfig.BOOL_TYPE_NULL_VALUE_FIELD; import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.LITERAL_MISSING; @@ -38,33 +30,43 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; +import com.amazon.opendistroforelasticsearch.sql.data.model.ExprType; +import com.amazon.opendistroforelasticsearch.sql.exception.ExpressionEvaluationException; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator; +import org.junit.jupiter.api.Test; + @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) class ReferenceExpressionTest extends ExpressionTestBase { - @Test - public void resolve_value() { - assertEquals(integerValue(1), DSL.ref("integer_value").valueOf(valueEnv())); - assertEquals(longValue(1L), DSL.ref("long_value").valueOf(valueEnv())); - assertEquals(floatValue(1f), DSL.ref("float_value").valueOf(valueEnv())); - assertEquals(doubleValue(1d), DSL.ref("double_value").valueOf(valueEnv())); - assertEquals(booleanValue(true), DSL.ref("boolean_value").valueOf(valueEnv())); - assertEquals(stringValue("str"), DSL.ref("string_value").valueOf(valueEnv())); - assertEquals(tupleValue(ImmutableMap.of("str", 1)), DSL.ref("struct_value").valueOf(valueEnv())); - assertEquals(collectionValue(ImmutableList.of(1)), DSL.ref("array_value").valueOf(valueEnv())); - assertEquals(LITERAL_NULL, DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD).valueOf(valueEnv())); - assertEquals(LITERAL_MISSING, DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD).valueOf(valueEnv())); - } + @Test + public void resolve_value() { + assertEquals(integerValue(1), DSL.ref("integer_value").valueOf(valueEnv())); + assertEquals(longValue(1L), DSL.ref("long_value").valueOf(valueEnv())); + assertEquals(floatValue(1f), DSL.ref("float_value").valueOf(valueEnv())); + assertEquals(doubleValue(1d), DSL.ref("double_value").valueOf(valueEnv())); + assertEquals(booleanValue(true), DSL.ref("boolean_value").valueOf(valueEnv())); + assertEquals(stringValue("str"), DSL.ref("string_value").valueOf(valueEnv())); + assertEquals(tupleValue(ImmutableMap.of("str", 1)), + DSL.ref("struct_value").valueOf(valueEnv())); + assertEquals(collectionValue(ImmutableList.of(1)), DSL.ref("array_value").valueOf(valueEnv())); + assertEquals(LITERAL_NULL, DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD).valueOf(valueEnv())); + assertEquals(LITERAL_MISSING, DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD).valueOf(valueEnv())); + } - @Test - public void resolve_type() { - assertEquals(ExprType.INTEGER, DSL.ref("integer_value").type(typeEnv())); - assertEquals(ExprType.LONG, DSL.ref("long_value").type(typeEnv())); - assertEquals(ExprType.FLOAT, DSL.ref("float_value").type(typeEnv())); - assertEquals(ExprType.DOUBLE, DSL.ref("double_value").type(typeEnv())); - assertEquals(ExprType.BOOLEAN, DSL.ref("boolean_value").type(typeEnv())); - assertEquals(ExprType.STRING, DSL.ref("string_value").type(typeEnv())); - assertEquals(ExprType.STRUCT, DSL.ref("struct_value").type(typeEnv())); - assertEquals(ExprType.ARRAY, DSL.ref("array_value").type(typeEnv())); - assertThrows(ExpressionEvaluationException.class, () -> DSL.ref("not_exist_field").type(typeEnv())); - } + @Test + public void resolve_type() { + assertEquals(ExprType.INTEGER, DSL.ref("integer_value").type(typeEnv())); + assertEquals(ExprType.LONG, DSL.ref("long_value").type(typeEnv())); + assertEquals(ExprType.FLOAT, DSL.ref("float_value").type(typeEnv())); + assertEquals(ExprType.DOUBLE, DSL.ref("double_value").type(typeEnv())); + assertEquals(ExprType.BOOLEAN, DSL.ref("boolean_value").type(typeEnv())); + assertEquals(ExprType.STRING, DSL.ref("string_value").type(typeEnv())); + assertEquals(ExprType.STRUCT, DSL.ref("struct_value").type(typeEnv())); + assertEquals(ExprType.ARRAY, DSL.ref("array_value").type(typeEnv())); + assertThrows(ExpressionEvaluationException.class, + () -> DSL.ref("not_exist_field").type(typeEnv())); + } } \ No newline at end of file diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/aggregation/AggregationTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/aggregation/AggregationTest.java index 5ddf8db89d..ec42a97b2c 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/aggregation/AggregationTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/aggregation/AggregationTest.java @@ -15,10 +15,6 @@ package com.amazon.opendistroforelasticsearch.sql.expression.aggregation; -import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.booleanValue; -import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.collectionValue; -import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.tupleValue; - import com.amazon.opendistroforelasticsearch.sql.data.model.ExprValue; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils; import com.amazon.opendistroforelasticsearch.sql.expression.ExpressionTestBase; diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/aggregation/AvgAggregatorTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/aggregation/AvgAggregatorTest.java index 31cd295968..a9331217f1 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/aggregation/AvgAggregatorTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/aggregation/AvgAggregatorTest.java @@ -15,47 +15,50 @@ package com.amazon.opendistroforelasticsearch.sql.expression.aggregation; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + import com.amazon.opendistroforelasticsearch.sql.data.model.ExprValue; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils; import com.amazon.opendistroforelasticsearch.sql.exception.ExpressionEvaluationException; import com.amazon.opendistroforelasticsearch.sql.expression.DSL; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - class AvgAggregatorTest extends AggregationTest { - @Test - public void avg_field_expression() { - ExprValue result = aggregation(dsl.avg(typeEnv,DSL.ref("integer_value")), tuples); - assertEquals(2.5, result.value()); - } - - @Test - public void avg_arithmetic_expression() { - ExprValue result = aggregation(dsl.avg(typeEnv, - dsl.multiply(typeEnv, DSL.ref("integer_value"), DSL.literal(ExprValueUtils.integerValue(10)))), tuples); - assertEquals(25.0, result.value()); - } - - @Test - public void avg_with_missing() { - ExprValue result = aggregation(dsl.avg(typeEnv,DSL.ref("integer_value")), tuples_with_null_and_missing); - assertTrue(result.isNull()); - } - - @Test - public void avg_with_null() { - ExprValue result = aggregation(dsl.avg(typeEnv,DSL.ref("double_value")), tuples_with_null_and_missing); - assertTrue(result.isNull()); - } - - @Test - public void valueOf() { - ExpressionEvaluationException exception = assertThrows(ExpressionEvaluationException.class, - () -> dsl.avg(typeEnv, DSL.ref("double_value")).valueOf(valueEnv())); - assertEquals("can't evaluate on aggregator: avg", exception.getMessage()); - } + @Test + public void avg_field_expression() { + ExprValue result = aggregation(dsl.avg(typeEnv, DSL.ref("integer_value")), tuples); + assertEquals(2.5, result.value()); + } + + @Test + public void avg_arithmetic_expression() { + ExprValue result = aggregation(dsl.avg(typeEnv, + dsl.multiply(typeEnv, DSL.ref("integer_value"), + DSL.literal(ExprValueUtils.integerValue(10)))), tuples); + assertEquals(25.0, result.value()); + } + + @Test + public void avg_with_missing() { + ExprValue result = + aggregation(dsl.avg(typeEnv, DSL.ref("integer_value")), tuples_with_null_and_missing); + assertTrue(result.isNull()); + } + + @Test + public void avg_with_null() { + ExprValue result = + aggregation(dsl.avg(typeEnv, DSL.ref("double_value")), tuples_with_null_and_missing); + assertTrue(result.isNull()); + } + + @Test + public void valueOf() { + ExpressionEvaluationException exception = assertThrows(ExpressionEvaluationException.class, + () -> dsl.avg(typeEnv, DSL.ref("double_value")).valueOf(valueEnv())); + assertEquals("can't evaluate on aggregator: avg", exception.getMessage()); + } } \ No newline at end of file diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/aggregation/CountAggregatorTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/aggregation/CountAggregatorTest.java index b98b4ef88e..32196459a4 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/aggregation/CountAggregatorTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/aggregation/CountAggregatorTest.java @@ -53,7 +53,8 @@ public void count_double_field_expression() { @Test public void count_arithmetic_expression() { ExprValue result = aggregation(dsl.count(typeEnv, - dsl.multiply(typeEnv, DSL.ref("integer_value"), DSL.literal(ExprValueUtils.integerValue(10)))), tuples); + dsl.multiply(typeEnv, DSL.ref("integer_value"), + DSL.literal(ExprValueUtils.integerValue(10)))), tuples); assertEquals(4, result.value()); } diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/aggregation/SumAggregatorTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/aggregation/SumAggregatorTest.java index f7bf317ed3..6774c6627c 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/aggregation/SumAggregatorTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/aggregation/SumAggregatorTest.java @@ -31,64 +31,70 @@ class SumAggregatorTest extends AggregationTest { - @Test - public void sum_integer_field_expression() { - ExprValue result = aggregation(dsl.sum(typeEnv, DSL.ref("integer_value")), tuples); - assertEquals(10, result.value()); - } + @Test + public void sum_integer_field_expression() { + ExprValue result = aggregation(dsl.sum(typeEnv, DSL.ref("integer_value")), tuples); + assertEquals(10, result.value()); + } - @Test - public void sum_long_field_expression() { - ExprValue result = aggregation(dsl.sum(typeEnv, DSL.ref("long_value")), tuples); - assertEquals(10L, result.value()); - } + @Test + public void sum_long_field_expression() { + ExprValue result = aggregation(dsl.sum(typeEnv, DSL.ref("long_value")), tuples); + assertEquals(10L, result.value()); + } - @Test - public void sum_float_field_expression() { - ExprValue result = aggregation(dsl.sum(typeEnv, DSL.ref("float_value")), tuples); - assertEquals(10f, result.value()); - } + @Test + public void sum_float_field_expression() { + ExprValue result = aggregation(dsl.sum(typeEnv, DSL.ref("float_value")), tuples); + assertEquals(10f, result.value()); + } - @Test - public void sum_double_field_expression() { - ExprValue result = aggregation(dsl.sum(typeEnv, DSL.ref("double_value")), tuples); - assertEquals(10d, result.value()); - } + @Test + public void sum_double_field_expression() { + ExprValue result = aggregation(dsl.sum(typeEnv, DSL.ref("double_value")), tuples); + assertEquals(10d, result.value()); + } - @Test - public void sum_arithmetic_expression() { - ExprValue result = aggregation(dsl.sum(typeEnv, - dsl.multiply(typeEnv, DSL.ref("integer_value"), DSL.literal(ExprValueUtils.integerValue(10)))), tuples); - assertEquals(100, result.value()); - } + @Test + public void sum_arithmetic_expression() { + ExprValue result = aggregation(dsl.sum(typeEnv, + dsl.multiply(typeEnv, DSL.ref("integer_value"), + DSL.literal(ExprValueUtils.integerValue(10)))), tuples); + assertEquals(100, result.value()); + } - @Test - public void sum_string_field_expression() { - SumAggregator sumAggregator = new SumAggregator(ImmutableList.of(DSL.ref("string_value")), ExprType.STRING); - SumState sumState = sumAggregator.create(); - ExpressionEvaluationException exception = assertThrows(ExpressionEvaluationException.class, - () -> sumAggregator - .iterate(ExprValueUtils.tupleValue(ImmutableMap.of("string_value", "m")).bindingTuples(), sumState) - ); - assertEquals("unexpected type [STRING] in sum aggregation", exception.getMessage()); - } + @Test + public void sum_string_field_expression() { + SumAggregator sumAggregator = + new SumAggregator(ImmutableList.of(DSL.ref("string_value")), ExprType.STRING); + SumState sumState = sumAggregator.create(); + ExpressionEvaluationException exception = assertThrows(ExpressionEvaluationException.class, + () -> sumAggregator + .iterate( + ExprValueUtils.tupleValue(ImmutableMap.of("string_value", "m")).bindingTuples(), + sumState) + ); + assertEquals("unexpected type [STRING] in sum aggregation", exception.getMessage()); + } - @Test - public void sum_with_missing() { - ExprValue result = aggregation(dsl.sum(typeEnv, DSL.ref("integer_value")), tuples_with_null_and_missing); - assertTrue(result.isNull()); - } + @Test + public void sum_with_missing() { + ExprValue result = + aggregation(dsl.sum(typeEnv, DSL.ref("integer_value")), tuples_with_null_and_missing); + assertTrue(result.isNull()); + } - @Test - public void sum_with_null() { - ExprValue result = aggregation(dsl.sum(typeEnv, DSL.ref("double_value")), tuples_with_null_and_missing); - assertTrue(result.isNull()); - } + @Test + public void sum_with_null() { + ExprValue result = + aggregation(dsl.sum(typeEnv, DSL.ref("double_value")), tuples_with_null_and_missing); + assertTrue(result.isNull()); + } - @Test - public void valueOf() { - ExpressionEvaluationException exception = assertThrows(ExpressionEvaluationException.class, - () -> dsl.sum(typeEnv, DSL.ref("double_value")).valueOf(valueEnv())); - assertEquals("can't evaluate on aggregator: sum", exception.getMessage()); - } + @Test + public void valueOf() { + ExpressionEvaluationException exception = assertThrows(ExpressionEvaluationException.class, + () -> dsl.sum(typeEnv, DSL.ref("double_value")).valueOf(valueEnv())); + assertEquals("can't evaluate on aggregator: sum", exception.getMessage()); + } } \ No newline at end of file diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionNameTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionNameTest.java index 874dc07bf5..6feeb831b4 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionNameTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionNameTest.java @@ -15,29 +15,28 @@ package com.amazon.opendistroforelasticsearch.sql.expression.function; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.Arrays; import java.util.stream.Stream; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; class BuiltinFunctionNameTest { - private static Stream ofArguments() { - Stream.Builder builder = Stream.builder(); - return Arrays.asList(BuiltinFunctionName.values()) - .stream() - .map(functionName -> Arguments.of(functionName.getName().getFunctionName(), functionName)); - } + private static Stream ofArguments() { + Stream.Builder builder = Stream.builder(); + return Arrays.asList(BuiltinFunctionName.values()) + .stream() + .map(functionName -> Arguments.of(functionName.getName().getFunctionName(), functionName)); + } - @ParameterizedTest - @MethodSource("ofArguments") - public void of(String name, BuiltinFunctionName expected) { - assertTrue(BuiltinFunctionName.of(name).isPresent()); - assertEquals(expected, BuiltinFunctionName.of(name).get()); - } + @ParameterizedTest + @MethodSource("ofArguments") + public void of(String name, BuiltinFunctionName expected) { + assertTrue(BuiltinFunctionName.of(name).isPresent()); + assertEquals(expected, BuiltinFunctionName.of(name).get()); + } } \ No newline at end of file diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionRepositoryTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionRepositoryTest.java index f53b0efab0..7a540cedfd 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionRepositoryTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/function/BuiltinFunctionRepositoryTest.java @@ -15,88 +15,87 @@ package com.amazon.opendistroforelasticsearch.sql.expression.function; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import com.amazon.opendistroforelasticsearch.sql.data.model.ExprType; import com.amazon.opendistroforelasticsearch.sql.exception.ExpressionEvaluationException; import com.amazon.opendistroforelasticsearch.sql.expression.Expression; import com.amazon.opendistroforelasticsearch.sql.expression.env.Environment; +import java.util.Arrays; +import java.util.Map; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import java.util.Arrays; -import java.util.Map; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - @ExtendWith(MockitoExtension.class) class BuiltinFunctionRepositoryTest { - @Mock - private FunctionResolver mockfunctionResolver; - @Mock - private Map mockMap; - @Mock - private FunctionName mockFunctionName; - @Mock - private FunctionBuilder functionExpressionBuilder; - @Mock - private FunctionSignature functionSignature; - @Mock - private Expression mockExpression; - @Mock - private Environment emptyEnv; + @Mock + private FunctionResolver mockfunctionResolver; + @Mock + private Map mockMap; + @Mock + private FunctionName mockFunctionName; + @Mock + private FunctionBuilder functionExpressionBuilder; + @Mock + private FunctionSignature functionSignature; + @Mock + private Expression mockExpression; + @Mock + private Environment emptyEnv; - @Test - void register() { - BuiltinFunctionRepository repo = new BuiltinFunctionRepository(mockMap); - when(mockfunctionResolver.getFunctionName()).thenReturn(mockFunctionName); - repo.register(mockfunctionResolver); + @Test + void register() { + BuiltinFunctionRepository repo = new BuiltinFunctionRepository(mockMap); + when(mockfunctionResolver.getFunctionName()).thenReturn(mockFunctionName); + repo.register(mockfunctionResolver); - verify(mockMap, times(1)).put(mockFunctionName, mockfunctionResolver); - } + verify(mockMap, times(1)).put(mockFunctionName, mockfunctionResolver); + } - @Test - void compile() { - BuiltinFunctionRepository repo = new BuiltinFunctionRepository(mockMap); - when(mockfunctionResolver.getFunctionName()).thenReturn(mockFunctionName); - when(mockfunctionResolver.resolve(any())).thenReturn(functionExpressionBuilder); - when(mockMap.containsKey(any())).thenReturn(true); - when(mockMap.get(any())).thenReturn(mockfunctionResolver); - repo.register(mockfunctionResolver); + @Test + void compile() { + when(mockfunctionResolver.getFunctionName()).thenReturn(mockFunctionName); + when(mockfunctionResolver.resolve(any())).thenReturn(functionExpressionBuilder); + when(mockMap.containsKey(any())).thenReturn(true); + when(mockMap.get(any())).thenReturn(mockfunctionResolver); + BuiltinFunctionRepository repo = new BuiltinFunctionRepository(mockMap); + repo.register(mockfunctionResolver); - repo.compile(mockFunctionName, Arrays.asList(mockExpression), emptyEnv); - verify(functionExpressionBuilder, times(1)).apply(any()); - } + repo.compile(mockFunctionName, Arrays.asList(mockExpression), emptyEnv); + verify(functionExpressionBuilder, times(1)).apply(any()); + } - @Test - @DisplayName("resolve registered function should pass") - void resolve() { - BuiltinFunctionRepository repo = new BuiltinFunctionRepository(mockMap); - when(functionSignature.getFunctionName()).thenReturn(mockFunctionName); - when(mockfunctionResolver.getFunctionName()).thenReturn(mockFunctionName); - when(mockfunctionResolver.resolve(functionSignature)).thenReturn(functionExpressionBuilder); - when(mockMap.containsKey(mockFunctionName)).thenReturn(true); - when(mockMap.get(mockFunctionName)).thenReturn(mockfunctionResolver); - repo.register(mockfunctionResolver); + @Test + @DisplayName("resolve registered function should pass") + void resolve() { + when(functionSignature.getFunctionName()).thenReturn(mockFunctionName); + when(mockfunctionResolver.getFunctionName()).thenReturn(mockFunctionName); + when(mockfunctionResolver.resolve(functionSignature)).thenReturn(functionExpressionBuilder); + when(mockMap.containsKey(mockFunctionName)).thenReturn(true); + when(mockMap.get(mockFunctionName)).thenReturn(mockfunctionResolver); + BuiltinFunctionRepository repo = new BuiltinFunctionRepository(mockMap); + repo.register(mockfunctionResolver); - assertEquals(functionExpressionBuilder, repo.resolve(functionSignature)); - } + assertEquals(functionExpressionBuilder, repo.resolve(functionSignature)); + } - @Test - @DisplayName("resolve unregistered function should throw exception") - void resolve_unregistered() { - BuiltinFunctionRepository repo = new BuiltinFunctionRepository(mockMap); - when(mockMap.containsKey(any())).thenReturn(false); - repo.register(mockfunctionResolver); + @Test + @DisplayName("resolve unregistered function should throw exception") + void resolve_unregistered() { + BuiltinFunctionRepository repo = new BuiltinFunctionRepository(mockMap); + when(mockMap.containsKey(any())).thenReturn(false); + repo.register(mockfunctionResolver); - ExpressionEvaluationException exception = assertThrows(ExpressionEvaluationException.class, - () -> repo.resolve(new FunctionSignature(FunctionName.of("unknown"), Arrays.asList()))); - assertEquals("unsupported function name: unknown", exception.getMessage()); - } + ExpressionEvaluationException exception = assertThrows(ExpressionEvaluationException.class, + () -> repo.resolve(new FunctionSignature(FunctionName.of("unknown"), Arrays.asList()))); + assertEquals("unsupported function name: unknown", exception.getMessage()); + } } \ No newline at end of file diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/function/FunctionResolverTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/function/FunctionResolverTest.java index 1ad39af6ed..d0b055334c 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/function/FunctionResolverTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/function/FunctionResolverTest.java @@ -15,6 +15,10 @@ package com.amazon.opendistroforelasticsearch.sql.expression.function; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.when; + import com.amazon.opendistroforelasticsearch.sql.exception.ExpressionEvaluationException; import com.google.common.collect.ImmutableMap; import org.junit.jupiter.api.DisplayNameGeneration; @@ -24,63 +28,60 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.when; - @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) @ExtendWith(MockitoExtension.class) class FunctionResolverTest { - @Mock - private FunctionSignature exactlyMatchFS; - @Mock - private FunctionSignature bestMatchFS; - @Mock - private FunctionSignature leastMatchFS; - @Mock - private FunctionSignature notMatchFS; - @Mock - private FunctionSignature functionSignature; - @Mock - private FunctionBuilder exactlyMatchBuilder; - @Mock - private FunctionBuilder bestMatchBuilder; - @Mock - private FunctionBuilder leastMatchBuilder; - @Mock - private FunctionBuilder notMatchBuilder; + @Mock + private FunctionSignature exactlyMatchFS; + @Mock + private FunctionSignature bestMatchFS; + @Mock + private FunctionSignature leastMatchFS; + @Mock + private FunctionSignature notMatchFS; + @Mock + private FunctionSignature functionSignature; + @Mock + private FunctionBuilder exactlyMatchBuilder; + @Mock + private FunctionBuilder bestMatchBuilder; + @Mock + private FunctionBuilder leastMatchBuilder; + @Mock + private FunctionBuilder notMatchBuilder; - private FunctionName functionName = FunctionName.of("add"); + private FunctionName functionName = FunctionName.of("add"); - @Test - void resolve_function_signature_exactly_match() { - when(functionSignature.match(exactlyMatchFS)).thenReturn(WideningTypeRule.TYPE_EQUAL); - FunctionResolver resolver = new FunctionResolver(functionName, - ImmutableMap.of(exactlyMatchFS, exactlyMatchBuilder)); + @Test + void resolve_function_signature_exactly_match() { + when(functionSignature.match(exactlyMatchFS)).thenReturn(WideningTypeRule.TYPE_EQUAL); + FunctionResolver resolver = new FunctionResolver(functionName, + ImmutableMap.of(exactlyMatchFS, exactlyMatchBuilder)); - assertEquals(exactlyMatchBuilder, resolver.resolve(functionSignature)); - } + assertEquals(exactlyMatchBuilder, resolver.resolve(functionSignature)); + } - @Test - void resolve_function_signature_best_match() { - when(functionSignature.match(bestMatchFS)).thenReturn(1); - when(functionSignature.match(leastMatchFS)).thenReturn(2); - FunctionResolver resolver = new FunctionResolver(functionName, - ImmutableMap.of(bestMatchFS, bestMatchBuilder, leastMatchFS, leastMatchBuilder)); + @Test + void resolve_function_signature_best_match() { + when(functionSignature.match(bestMatchFS)).thenReturn(1); + when(functionSignature.match(leastMatchFS)).thenReturn(2); + FunctionResolver resolver = new FunctionResolver(functionName, + ImmutableMap.of(bestMatchFS, bestMatchBuilder, leastMatchFS, leastMatchBuilder)); - assertEquals(bestMatchBuilder, resolver.resolve(functionSignature)); - } + assertEquals(bestMatchBuilder, resolver.resolve(functionSignature)); + } - @Test - void resolve_function_not_match() { - when(functionSignature.match(notMatchFS)).thenReturn(WideningTypeRule.IMPOSSIBLE_WIDENING); - when(notMatchFS.formatTypes()).thenReturn("[INTEGER,INTEGER]"); - when(functionSignature.formatTypes()).thenReturn("[BOOLEAN,BOOLEAN]"); - FunctionResolver resolver = new FunctionResolver(functionName, - ImmutableMap.of(notMatchFS, notMatchBuilder)); + @Test + void resolve_function_not_match() { + when(functionSignature.match(notMatchFS)).thenReturn(WideningTypeRule.IMPOSSIBLE_WIDENING); + when(notMatchFS.formatTypes()).thenReturn("[INTEGER,INTEGER]"); + when(functionSignature.formatTypes()).thenReturn("[BOOLEAN,BOOLEAN]"); + FunctionResolver resolver = new FunctionResolver(functionName, + ImmutableMap.of(notMatchFS, notMatchBuilder)); - ExpressionEvaluationException exception = assertThrows(ExpressionEvaluationException.class, - () -> resolver.resolve(functionSignature)); - assertEquals("add function expected {[INTEGER,INTEGER]}, but get [BOOLEAN,BOOLEAN]", exception.getMessage()); - } + ExpressionEvaluationException exception = assertThrows(ExpressionEvaluationException.class, + () -> resolver.resolve(functionSignature)); + assertEquals("add function expected {[INTEGER,INTEGER]}, but get [BOOLEAN,BOOLEAN]", + exception.getMessage()); + } } \ No newline at end of file diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/function/FunctionSignatureTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/function/FunctionSignatureTest.java index 47436ef46a..ed73a16dc9 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/function/FunctionSignatureTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/function/FunctionSignatureTest.java @@ -15,7 +15,14 @@ package com.amazon.opendistroforelasticsearch.sql.expression.function; +import static com.amazon.opendistroforelasticsearch.sql.expression.function.FunctionSignature.EXACTLY_MATCH; +import static com.amazon.opendistroforelasticsearch.sql.expression.function.FunctionSignature.NOT_MATCH; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.when; + import com.amazon.opendistroforelasticsearch.sql.data.model.ExprType; +import java.util.Arrays; +import java.util.List; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator; import org.junit.jupiter.api.Test; @@ -23,74 +30,74 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import java.util.Arrays; -import java.util.List; - -import static com.amazon.opendistroforelasticsearch.sql.expression.function.FunctionSignature.EXACTLY_MATCH; -import static com.amazon.opendistroforelasticsearch.sql.expression.function.FunctionSignature.NOT_MATCH; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.when; - @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) @ExtendWith(MockitoExtension.class) class FunctionSignatureTest { - @Mock - private FunctionSignature funcSignature; - @Mock - private List funcParamTypeList; - - private FunctionName unresolvedFuncName = FunctionName.of("add"); - private List unresolvedParamTypeList = Arrays.asList(ExprType.INTEGER, ExprType.FLOAT); - - @Test - void signature_name_not_match() { - when(funcSignature.getFunctionName()).thenReturn(FunctionName.of(("diff"))); - FunctionSignature unresolvedFunSig = new FunctionSignature(this.unresolvedFuncName, unresolvedParamTypeList); - - assertEquals(NOT_MATCH, unresolvedFunSig.match(funcSignature)); - } - - @Test - void signature_arguments_size_not_match() { - when(funcSignature.getFunctionName()).thenReturn(unresolvedFuncName); - when(funcSignature.getParamTypeList()).thenReturn(funcParamTypeList); - when(funcParamTypeList.size()).thenReturn(1); - FunctionSignature unresolvedFunSig = new FunctionSignature(unresolvedFuncName, unresolvedParamTypeList); - - assertEquals(NOT_MATCH, unresolvedFunSig.match(funcSignature)); - } - - @Test - void signature_exactly_match() { - when(funcSignature.getFunctionName()).thenReturn(unresolvedFuncName); - when(funcSignature.getParamTypeList()).thenReturn(unresolvedParamTypeList); - FunctionSignature unresolvedFunSig = new FunctionSignature(unresolvedFuncName, unresolvedParamTypeList); - - assertEquals(EXACTLY_MATCH, unresolvedFunSig.match(funcSignature)); - } - - @Test - void signature_not_match() { - when(funcSignature.getFunctionName()).thenReturn(unresolvedFuncName); - when(funcSignature.getParamTypeList()).thenReturn(Arrays.asList(ExprType.STRING, ExprType.STRING)); - FunctionSignature unresolvedFunSig = new FunctionSignature(unresolvedFuncName, unresolvedParamTypeList); - - assertEquals(NOT_MATCH, unresolvedFunSig.match(funcSignature)); - } - - @Test - void signature_widening_match() { - when(funcSignature.getFunctionName()).thenReturn(unresolvedFuncName); - when(funcSignature.getParamTypeList()).thenReturn(Arrays.asList(ExprType.FLOAT, ExprType.FLOAT)); - FunctionSignature unresolvedFunSig = new FunctionSignature(unresolvedFuncName, unresolvedParamTypeList); - - assertEquals(2, unresolvedFunSig.match(funcSignature)); - } - - @Test - void format_types() { - FunctionSignature unresolvedFunSig = new FunctionSignature(unresolvedFuncName, unresolvedParamTypeList); - - assertEquals("[INTEGER,FLOAT]", unresolvedFunSig.formatTypes()); - } + @Mock + private FunctionSignature funcSignature; + @Mock + private List funcParamTypeList; + + private FunctionName unresolvedFuncName = FunctionName.of("add"); + private List unresolvedParamTypeList = Arrays.asList(ExprType.INTEGER, ExprType.FLOAT); + + @Test + void signature_name_not_match() { + when(funcSignature.getFunctionName()).thenReturn(FunctionName.of(("diff"))); + FunctionSignature unresolvedFunSig = + new FunctionSignature(this.unresolvedFuncName, unresolvedParamTypeList); + + assertEquals(NOT_MATCH, unresolvedFunSig.match(funcSignature)); + } + + @Test + void signature_arguments_size_not_match() { + when(funcSignature.getFunctionName()).thenReturn(unresolvedFuncName); + when(funcSignature.getParamTypeList()).thenReturn(funcParamTypeList); + when(funcParamTypeList.size()).thenReturn(1); + FunctionSignature unresolvedFunSig = + new FunctionSignature(unresolvedFuncName, unresolvedParamTypeList); + + assertEquals(NOT_MATCH, unresolvedFunSig.match(funcSignature)); + } + + @Test + void signature_exactly_match() { + when(funcSignature.getFunctionName()).thenReturn(unresolvedFuncName); + when(funcSignature.getParamTypeList()).thenReturn(unresolvedParamTypeList); + FunctionSignature unresolvedFunSig = + new FunctionSignature(unresolvedFuncName, unresolvedParamTypeList); + + assertEquals(EXACTLY_MATCH, unresolvedFunSig.match(funcSignature)); + } + + @Test + void signature_not_match() { + when(funcSignature.getFunctionName()).thenReturn(unresolvedFuncName); + when(funcSignature.getParamTypeList()) + .thenReturn(Arrays.asList(ExprType.STRING, ExprType.STRING)); + FunctionSignature unresolvedFunSig = + new FunctionSignature(unresolvedFuncName, unresolvedParamTypeList); + + assertEquals(NOT_MATCH, unresolvedFunSig.match(funcSignature)); + } + + @Test + void signature_widening_match() { + when(funcSignature.getFunctionName()).thenReturn(unresolvedFuncName); + when(funcSignature.getParamTypeList()) + .thenReturn(Arrays.asList(ExprType.FLOAT, ExprType.FLOAT)); + FunctionSignature unresolvedFunSig = + new FunctionSignature(unresolvedFuncName, unresolvedParamTypeList); + + assertEquals(2, unresolvedFunSig.match(funcSignature)); + } + + @Test + void format_types() { + FunctionSignature unresolvedFunSig = + new FunctionSignature(unresolvedFuncName, unresolvedParamTypeList); + + assertEquals("[INTEGER,FLOAT]", unresolvedFunSig.formatTypes()); + } } \ No newline at end of file diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/function/WideningTypeRuleTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/function/WideningTypeRuleTest.java index dd0288dca2..81a831fe91 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/function/WideningTypeRuleTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/function/WideningTypeRuleTest.java @@ -15,20 +15,6 @@ package com.amazon.opendistroforelasticsearch.sql.expression.function; -import com.amazon.opendistroforelasticsearch.sql.data.model.ExprType; -import com.amazon.opendistroforelasticsearch.sql.exception.ExpressionEvaluationException; -import com.google.common.collect.ImmutableTable; -import com.google.common.collect.Lists; -import com.google.common.collect.Table; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.Stream; - import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprType.DOUBLE; import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprType.FLOAT; import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprType.INTEGER; @@ -39,68 +25,84 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; +import com.amazon.opendistroforelasticsearch.sql.data.model.ExprType; +import com.amazon.opendistroforelasticsearch.sql.exception.ExpressionEvaluationException; +import com.google.common.collect.ImmutableTable; +import com.google.common.collect.Lists; +import com.google.common.collect.Table; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + class WideningTypeRuleTest { - private static Table numberWidenRule = new ImmutableTable.Builder() - .put(INTEGER, LONG, 1) - .put(INTEGER, FLOAT, 2) - .put(INTEGER, DOUBLE, 3) - .put(LONG, FLOAT, 1) - .put(LONG, DOUBLE, 2) - .put(FLOAT, DOUBLE, 1) - .build(); + private static Table numberWidenRule = + new ImmutableTable.Builder() + .put(INTEGER, LONG, 1) + .put(INTEGER, FLOAT, 2) + .put(INTEGER, DOUBLE, 3) + .put(LONG, FLOAT, 1) + .put(LONG, DOUBLE, 2) + .put(FLOAT, DOUBLE, 1) + .build(); - private static Stream distanceArguments() { - List exprTypes = Arrays.asList(ExprType.values()).stream().filter(type -> type != UNKNOWN).collect( - Collectors.toList()); - return Lists.cartesianProduct(exprTypes, exprTypes).stream() - .map(list -> { - ExprType type1 = list.get(0); - ExprType type2 = list.get(1); - if (type1 == type2) { - return Arguments.of(type1, type2, TYPE_EQUAL); - } else if (numberWidenRule.contains(type1, type2)) { - return Arguments.of(type1, type2, numberWidenRule.get(type1, type2)); - } else { - return Arguments.of(type1, type2, IMPOSSIBLE_WIDENING); - } - }); - } + private static Stream distanceArguments() { + List exprTypes = + Arrays.asList(ExprType.values()).stream().filter(type -> type != UNKNOWN).collect( + Collectors.toList()); + return Lists.cartesianProduct(exprTypes, exprTypes).stream() + .map(list -> { + ExprType type1 = list.get(0); + ExprType type2 = list.get(1); + if (type1 == type2) { + return Arguments.of(type1, type2, TYPE_EQUAL); + } else if (numberWidenRule.contains(type1, type2)) { + return Arguments.of(type1, type2, numberWidenRule.get(type1, type2)); + } else { + return Arguments.of(type1, type2, IMPOSSIBLE_WIDENING); + } + }); + } - private static Stream validMaxTypes() { - List exprTypes = Arrays.asList(ExprType.values()).stream().filter(type -> type != UNKNOWN).collect( - Collectors.toList()); - return Lists.cartesianProduct(exprTypes, exprTypes).stream() - .map(list -> { - ExprType type1 = list.get(0); - ExprType type2 = list.get(1); - if (type1 == type2) { - return Arguments.of(type1, type2, type1); - } else if (numberWidenRule.contains(type1, type2)) { - return Arguments.of(type1, type2, type2); - } else if (numberWidenRule.contains(type2, type1)){ - return Arguments.of(type1, type2, type1); - } else { - return Arguments.of(type1, type2, null); - } - }); - } + private static Stream validMaxTypes() { + List exprTypes = + Arrays.asList(ExprType.values()).stream().filter(type -> type != UNKNOWN).collect( + Collectors.toList()); + return Lists.cartesianProduct(exprTypes, exprTypes).stream() + .map(list -> { + ExprType type1 = list.get(0); + ExprType type2 = list.get(1); + if (type1 == type2) { + return Arguments.of(type1, type2, type1); + } else if (numberWidenRule.contains(type1, type2)) { + return Arguments.of(type1, type2, type2); + } else if (numberWidenRule.contains(type2, type1)) { + return Arguments.of(type1, type2, type1); + } else { + return Arguments.of(type1, type2, null); + } + }); + } - @ParameterizedTest - @MethodSource("distanceArguments") - public void distance(ExprType v1, ExprType v2, Integer expected) { - assertEquals(expected, WideningTypeRule.distance(v1, v2)); - } + @ParameterizedTest + @MethodSource("distanceArguments") + public void distance(ExprType v1, ExprType v2, Integer expected) { + assertEquals(expected, WideningTypeRule.distance(v1, v2)); + } - @ParameterizedTest - @MethodSource("validMaxTypes") - public void max(ExprType v1, ExprType v2, ExprType expected) { - if (null == expected) { - ExpressionEvaluationException exception = assertThrows( - ExpressionEvaluationException.class, () -> WideningTypeRule.max(v1, v2)); - assertEquals(String.format("no max type of %s and %s ", v1, v2),exception.getMessage()); - } else { - assertEquals(expected, WideningTypeRule.max(v1, v2)); - } + @ParameterizedTest + @MethodSource("validMaxTypes") + public void max(ExprType v1, ExprType v2, ExprType expected) { + if (null == expected) { + ExpressionEvaluationException exception = assertThrows( + ExpressionEvaluationException.class, () -> WideningTypeRule.max(v1, v2)); + assertEquals(String.format("no max type of %s and %s ", v1, v2), exception.getMessage()); + } else { + assertEquals(expected, WideningTypeRule.max(v1, v2)); } + } } \ No newline at end of file diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/scalar/arthmetic/ArithmeticFunctionTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/scalar/arthmetic/ArithmeticFunctionTest.java index 863086d205..07633f0a7f 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/scalar/arthmetic/ArithmeticFunctionTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/scalar/arthmetic/ArithmeticFunctionTest.java @@ -15,6 +15,14 @@ package com.amazon.opendistroforelasticsearch.sql.expression.scalar.arthmetic; +import static com.amazon.opendistroforelasticsearch.sql.config.TestConfig.INT_TYPE_MISSING_VALUE_FIELD; +import static com.amazon.opendistroforelasticsearch.sql.config.TestConfig.INT_TYPE_NULL_VALUE_FIELD; +import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.LITERAL_MISSING; +import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.LITERAL_NULL; +import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.integerValue; +import static com.amazon.opendistroforelasticsearch.sql.expression.DSL.literal; +import static com.amazon.opendistroforelasticsearch.sql.expression.DSL.ref; +import static org.junit.jupiter.api.Assertions.assertEquals; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprType; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprValue; @@ -26,244 +34,242 @@ import com.amazon.opendistroforelasticsearch.sql.expression.function.BuiltinFunctionName; import com.amazon.opendistroforelasticsearch.sql.expression.function.WideningTypeRule; import com.google.common.collect.Lists; -import org.junit.jupiter.api.DisplayNameGeneration; -import org.junit.jupiter.api.DisplayNameGenerator; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - import java.util.Arrays; import java.util.List; import java.util.function.BiFunction; import java.util.stream.Collectors; import java.util.stream.Stream; - -import static com.amazon.opendistroforelasticsearch.sql.config.TestConfig.INT_TYPE_MISSING_VALUE_FIELD; -import static com.amazon.opendistroforelasticsearch.sql.config.TestConfig.INT_TYPE_NULL_VALUE_FIELD; -import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.LITERAL_MISSING; -import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.LITERAL_NULL; -import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.integerValue; -import static com.amazon.opendistroforelasticsearch.sql.expression.DSL.literal; -import static com.amazon.opendistroforelasticsearch.sql.expression.DSL.ref; -import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) class ArithmeticFunctionTest extends ExpressionTestBase { - private static Stream arithmeticFunctionArguments() { - List numberOp1 = Stream.of(3, 3L, 3f, 3D) - .map(ExprValueUtils::fromObjectValue).collect(Collectors.toList()); - List numberOp2 = Stream.of(2, 2L, 2f, 2D) - .map(ExprValueUtils::fromObjectValue).collect(Collectors.toList()); - return Lists.cartesianProduct(numberOp1, numberOp2).stream() - .map(list -> Arguments.of(list.get(0), list.get(1))); - } + private static Stream arithmeticFunctionArguments() { + List numberOp1 = Stream.of(3, 3L, 3f, 3D) + .map(ExprValueUtils::fromObjectValue).collect(Collectors.toList()); + List numberOp2 = Stream.of(2, 2L, 2f, 2D) + .map(ExprValueUtils::fromObjectValue).collect(Collectors.toList()); + return Lists.cartesianProduct(numberOp1, numberOp2).stream() + .map(list -> Arguments.of(list.get(0), list.get(1))); + } - private static Stream arithmeticOperatorArguments() { - return Stream.of(BuiltinFunctionName.ADD, BuiltinFunctionName.SUBTRACT, BuiltinFunctionName.MULTIPLY, - BuiltinFunctionName.DIVIDE, BuiltinFunctionName.DIVIDE).map(Arguments::of); - } + private static Stream arithmeticOperatorArguments() { + return Stream + .of(BuiltinFunctionName.ADD, BuiltinFunctionName.SUBTRACT, BuiltinFunctionName.MULTIPLY, + BuiltinFunctionName.DIVIDE, BuiltinFunctionName.DIVIDE).map(Arguments::of); + } - @ParameterizedTest(name = "add({1}, {2})") - @MethodSource("arithmeticFunctionArguments") - public void add(ExprValue op1, ExprValue op2) { - FunctionExpression expression = dsl.add(typeEnv(), literal(op1), literal(op2)); - ExprType expectedType = WideningTypeRule.max(op1.type(), op2.type()); - assertEquals(expectedType, expression.type(null)); - assertValueEqual(BuiltinFunctionName.ADD, expectedType, op1, op2, expression.valueOf(null)); - } + @ParameterizedTest(name = "add({1}, {2})") + @MethodSource("arithmeticFunctionArguments") + public void add(ExprValue op1, ExprValue op2) { + FunctionExpression expression = dsl.add(typeEnv(), literal(op1), literal(op2)); + ExprType expectedType = WideningTypeRule.max(op1.type(), op2.type()); + assertEquals(expectedType, expression.type(null)); + assertValueEqual(BuiltinFunctionName.ADD, expectedType, op1, op2, expression.valueOf(null)); + } - @ParameterizedTest(name = "{0}(int,null)") - @MethodSource("arithmeticOperatorArguments") - public void arithmetic_int_null(BuiltinFunctionName builtinFunctionName) { - BiFunction, - List, FunctionExpression> function = functionMapping(builtinFunctionName); + @ParameterizedTest(name = "{0}(int,null)") + @MethodSource("arithmeticOperatorArguments") + public void arithmetic_int_null(BuiltinFunctionName builtinFunctionName) { + BiFunction, + List, FunctionExpression> function = functionMapping(builtinFunctionName); - FunctionExpression functionExpression = function.apply(typeEnv(), Arrays.asList(literal(integerValue(1)), - ref(INT_TYPE_NULL_VALUE_FIELD))); - assertEquals(ExprType.INTEGER, functionExpression.type(typeEnv())); - assertEquals(LITERAL_NULL, functionExpression.valueOf(valueEnv())); + FunctionExpression functionExpression = + function.apply(typeEnv(), Arrays.asList(literal(integerValue(1)), + ref(INT_TYPE_NULL_VALUE_FIELD))); + assertEquals(ExprType.INTEGER, functionExpression.type(typeEnv())); + assertEquals(LITERAL_NULL, functionExpression.valueOf(valueEnv())); - functionExpression = function.apply(typeEnv(), - Arrays.asList(ref(INT_TYPE_NULL_VALUE_FIELD), literal(integerValue(1)))); - assertEquals(ExprType.INTEGER, functionExpression.type(typeEnv())); - assertEquals(LITERAL_NULL, functionExpression.valueOf(valueEnv())); - } + functionExpression = function.apply(typeEnv(), + Arrays.asList(ref(INT_TYPE_NULL_VALUE_FIELD), literal(integerValue(1)))); + assertEquals(ExprType.INTEGER, functionExpression.type(typeEnv())); + assertEquals(LITERAL_NULL, functionExpression.valueOf(valueEnv())); + } - @ParameterizedTest(name = "{0}(int,missing)") - @MethodSource("arithmeticOperatorArguments") - public void arithmetic_int_missing(BuiltinFunctionName builtinFunctionName) { - BiFunction, - List, FunctionExpression> function = functionMapping(builtinFunctionName); - FunctionExpression functionExpression = function.apply(typeEnv(), Arrays.asList(literal(integerValue(1)), - ref(INT_TYPE_MISSING_VALUE_FIELD))); - assertEquals(ExprType.INTEGER, functionExpression.type(typeEnv())); - assertEquals(LITERAL_MISSING, functionExpression.valueOf(valueEnv())); + @ParameterizedTest(name = "{0}(int,missing)") + @MethodSource("arithmeticOperatorArguments") + public void arithmetic_int_missing(BuiltinFunctionName builtinFunctionName) { + BiFunction, + List, FunctionExpression> function = functionMapping(builtinFunctionName); + FunctionExpression functionExpression = + function.apply(typeEnv(), Arrays.asList(literal(integerValue(1)), + ref(INT_TYPE_MISSING_VALUE_FIELD))); + assertEquals(ExprType.INTEGER, functionExpression.type(typeEnv())); + assertEquals(LITERAL_MISSING, functionExpression.valueOf(valueEnv())); - functionExpression = function.apply(typeEnv(), Arrays.asList(ref(INT_TYPE_MISSING_VALUE_FIELD), - literal(integerValue(1)))); - assertEquals(ExprType.INTEGER, functionExpression.type(typeEnv())); - assertEquals(LITERAL_MISSING, functionExpression.valueOf(valueEnv())); - } + functionExpression = function.apply(typeEnv(), Arrays.asList(ref(INT_TYPE_MISSING_VALUE_FIELD), + literal(integerValue(1)))); + assertEquals(ExprType.INTEGER, functionExpression.type(typeEnv())); + assertEquals(LITERAL_MISSING, functionExpression.valueOf(valueEnv())); + } - @ParameterizedTest(name = "{0}(null,missing)") - @MethodSource("arithmeticOperatorArguments") - public void arithmetic_null_missing(BuiltinFunctionName builtinFunctionName) { - BiFunction, - List, FunctionExpression> function = functionMapping(builtinFunctionName); - FunctionExpression functionExpression = function.apply(typeEnv(), - Arrays.asList(ref(INT_TYPE_NULL_VALUE_FIELD), ref(INT_TYPE_NULL_VALUE_FIELD))); - assertEquals(ExprType.INTEGER, functionExpression.type(typeEnv())); - assertEquals(LITERAL_NULL, functionExpression.valueOf(valueEnv())); + @ParameterizedTest(name = "{0}(null,missing)") + @MethodSource("arithmeticOperatorArguments") + public void arithmetic_null_missing(BuiltinFunctionName builtinFunctionName) { + BiFunction, + List, FunctionExpression> function = functionMapping(builtinFunctionName); + FunctionExpression functionExpression = function.apply(typeEnv(), + Arrays.asList(ref(INT_TYPE_NULL_VALUE_FIELD), ref(INT_TYPE_NULL_VALUE_FIELD))); + assertEquals(ExprType.INTEGER, functionExpression.type(typeEnv())); + assertEquals(LITERAL_NULL, functionExpression.valueOf(valueEnv())); - functionExpression = function.apply(typeEnv(), - Arrays.asList(ref(INT_TYPE_MISSING_VALUE_FIELD), ref(INT_TYPE_MISSING_VALUE_FIELD))); - assertEquals(ExprType.INTEGER, functionExpression.type(typeEnv())); - assertEquals(LITERAL_MISSING, functionExpression.valueOf(valueEnv())); + functionExpression = function.apply(typeEnv(), + Arrays.asList(ref(INT_TYPE_MISSING_VALUE_FIELD), ref(INT_TYPE_MISSING_VALUE_FIELD))); + assertEquals(ExprType.INTEGER, functionExpression.type(typeEnv())); + assertEquals(LITERAL_MISSING, functionExpression.valueOf(valueEnv())); - functionExpression = function.apply(typeEnv(), - Arrays.asList(ref(INT_TYPE_MISSING_VALUE_FIELD), ref(INT_TYPE_NULL_VALUE_FIELD))); - assertEquals(ExprType.INTEGER, functionExpression.type(typeEnv())); - assertEquals(LITERAL_MISSING, functionExpression.valueOf(valueEnv())); + functionExpression = function.apply(typeEnv(), + Arrays.asList(ref(INT_TYPE_MISSING_VALUE_FIELD), ref(INT_TYPE_NULL_VALUE_FIELD))); + assertEquals(ExprType.INTEGER, functionExpression.type(typeEnv())); + assertEquals(LITERAL_MISSING, functionExpression.valueOf(valueEnv())); - functionExpression = function.apply(typeEnv(), - Arrays.asList(ref(INT_TYPE_NULL_VALUE_FIELD), ref(INT_TYPE_MISSING_VALUE_FIELD))); - assertEquals(ExprType.INTEGER, functionExpression.type(typeEnv())); - assertEquals(LITERAL_MISSING, functionExpression.valueOf(valueEnv())); - } + functionExpression = function.apply(typeEnv(), + Arrays.asList(ref(INT_TYPE_NULL_VALUE_FIELD), ref(INT_TYPE_MISSING_VALUE_FIELD))); + assertEquals(ExprType.INTEGER, functionExpression.type(typeEnv())); + assertEquals(LITERAL_MISSING, functionExpression.valueOf(valueEnv())); + } - @ParameterizedTest(name = "subtract({1}, {2})") - @MethodSource("arithmeticFunctionArguments") - public void subtract(ExprValue op1, ExprValue op2) { - FunctionExpression expression = dsl.subtract(typeEnv(), literal(op1), literal(op2)); - ExprType expectedType = WideningTypeRule.max(op1.type(), op2.type()); - assertEquals(expectedType, expression.type(null)); - assertValueEqual(BuiltinFunctionName.SUBTRACT, expectedType, op1, op2, expression.valueOf(null)); - } + @ParameterizedTest(name = "subtract({1}, {2})") + @MethodSource("arithmeticFunctionArguments") + public void subtract(ExprValue op1, ExprValue op2) { + FunctionExpression expression = dsl.subtract(typeEnv(), literal(op1), literal(op2)); + ExprType expectedType = WideningTypeRule.max(op1.type(), op2.type()); + assertEquals(expectedType, expression.type(null)); + assertValueEqual(BuiltinFunctionName.SUBTRACT, expectedType, op1, op2, + expression.valueOf(null)); + } - @ParameterizedTest(name = "multiply({1}, {2})") - @MethodSource("arithmeticFunctionArguments") - public void multiply(ExprValue op1, ExprValue op2) { - FunctionExpression expression = dsl.multiply(typeEnv(), literal(op1), literal(op2)); - ExprType expectedType = WideningTypeRule.max(op1.type(), op2.type()); - assertEquals(expectedType, expression.type(null)); - assertValueEqual(BuiltinFunctionName.MULTIPLY, expectedType, op1, op2, expression.valueOf(null)); - } + @ParameterizedTest(name = "multiply({1}, {2})") + @MethodSource("arithmeticFunctionArguments") + public void multiply(ExprValue op1, ExprValue op2) { + FunctionExpression expression = dsl.multiply(typeEnv(), literal(op1), literal(op2)); + ExprType expectedType = WideningTypeRule.max(op1.type(), op2.type()); + assertEquals(expectedType, expression.type(null)); + assertValueEqual(BuiltinFunctionName.MULTIPLY, expectedType, op1, op2, + expression.valueOf(null)); + } - @ParameterizedTest(name = "divide({1}, {2})") - @MethodSource("arithmeticFunctionArguments") - public void divide(ExprValue op1, ExprValue op2) { - FunctionExpression expression = dsl.divide(typeEnv(), literal(op1), literal(op2)); - ExprType expectedType = WideningTypeRule.max(op1.type(), op2.type()); - assertEquals(expectedType, expression.type(null)); - assertValueEqual(BuiltinFunctionName.DIVIDE, expectedType, op1, op2, expression.valueOf(null)); - } + @ParameterizedTest(name = "divide({1}, {2})") + @MethodSource("arithmeticFunctionArguments") + public void divide(ExprValue op1, ExprValue op2) { + FunctionExpression expression = dsl.divide(typeEnv(), literal(op1), literal(op2)); + ExprType expectedType = WideningTypeRule.max(op1.type(), op2.type()); + assertEquals(expectedType, expression.type(null)); + assertValueEqual(BuiltinFunctionName.DIVIDE, expectedType, op1, op2, expression.valueOf(null)); + } - @ParameterizedTest(name = "module({1}, {2})") - @MethodSource("arithmeticFunctionArguments") - public void module(ExprValue op1, ExprValue op2) { - FunctionExpression expression = dsl.module(typeEnv(), literal(op1), literal(op2)); - ExprType expectedType = WideningTypeRule.max(op1.type(), op2.type()); - assertEquals(expectedType, expression.type(null)); - assertValueEqual(BuiltinFunctionName.MODULES, expectedType, op1, op2, expression.valueOf(null)); - } + @ParameterizedTest(name = "module({1}, {2})") + @MethodSource("arithmeticFunctionArguments") + public void module(ExprValue op1, ExprValue op2) { + FunctionExpression expression = dsl.module(typeEnv(), literal(op1), literal(op2)); + ExprType expectedType = WideningTypeRule.max(op1.type(), op2.type()); + assertEquals(expectedType, expression.type(null)); + assertValueEqual(BuiltinFunctionName.MODULES, expectedType, op1, op2, expression.valueOf(null)); + } - protected void assertValueEqual(BuiltinFunctionName builtinFunctionName, ExprType type, ExprValue op1, - ExprValue op2, - ExprValue actual) { - switch (type) { - case INTEGER: - Integer vi1 = ExprValueUtils.getIntegerValue(op1); - Integer vi2 = ExprValueUtils.getIntegerValue(op2); - Integer viActual = ExprValueUtils.getIntegerValue(actual); - switch (builtinFunctionName) { - case ADD: - assertEquals(vi1 + vi2, viActual); - return; - case SUBTRACT: - assertEquals(vi1 - vi2, viActual); - return; - case DIVIDE: - assertEquals(vi1 / vi2, viActual); - return; - case MULTIPLY: - assertEquals(vi1 * vi2, viActual); - return; - case MODULES: - assertEquals(vi1 % vi2, viActual); - return; - default: - throw new IllegalStateException("illegal function name " + builtinFunctionName); - } - case LONG: - Long vl1 = ExprValueUtils.getLongValue(op1); - Long vl2 = ExprValueUtils.getLongValue(op2); - Long vlActual = ExprValueUtils.getLongValue(actual); - switch (builtinFunctionName) { - case ADD: - assertEquals(vl1 + vl2, vlActual); - return; - case SUBTRACT: - assertEquals(vl1 - vl2, vlActual); - return; - case DIVIDE: - assertEquals(vl1 / vl2, vlActual); - return; - case MULTIPLY: - assertEquals(vl1 * vl2, vlActual); - return; - case MODULES: - assertEquals(vl1 % vl2, vlActual); - return; - default: - throw new IllegalStateException("illegal function name " + builtinFunctionName); - } - case FLOAT: - Float vf1 = ExprValueUtils.getFloatValue(op1); - Float vf2 = ExprValueUtils.getFloatValue(op2); - Float vfActual = ExprValueUtils.getFloatValue(actual); - switch (builtinFunctionName) { - case ADD: - assertEquals(vf1 + vf2, vfActual); - return; - case SUBTRACT: - assertEquals(vf1 - vf2, vfActual); - return; - case DIVIDE: - assertEquals(vf1 / vf2, vfActual); - return; - case MULTIPLY: - assertEquals(vf1 * vf2, vfActual); - return; - case MODULES: - assertEquals(vf1 % vf2, vfActual); - return; - default: - throw new IllegalStateException("illegal function name " + builtinFunctionName); - } - case DOUBLE: - Double vd1 = ExprValueUtils.getDoubleValue(op1); - Double vd2 = ExprValueUtils.getDoubleValue(op2); - Double vdActual = ExprValueUtils.getDoubleValue(actual); - switch (builtinFunctionName) { - case ADD: - assertEquals(vd1 + vd2, vdActual); - return; - case SUBTRACT: - assertEquals(vd1 - vd2, vdActual); - return; - case DIVIDE: - assertEquals(vd1 / vd2, vdActual); - return; - case MULTIPLY: - assertEquals(vd1 * vd2, vdActual); - return; - case MODULES: - assertEquals(vd1 % vd2, vdActual); - return; - default: - throw new IllegalStateException("illegal function name " + builtinFunctionName); - } + protected void assertValueEqual(BuiltinFunctionName builtinFunctionName, ExprType type, + ExprValue op1, + ExprValue op2, + ExprValue actual) { + switch (type) { + case INTEGER: + Integer vi1 = ExprValueUtils.getIntegerValue(op1); + Integer vi2 = ExprValueUtils.getIntegerValue(op2); + Integer viActual = ExprValueUtils.getIntegerValue(actual); + switch (builtinFunctionName) { + case ADD: + assertEquals(vi1 + vi2, viActual); + return; + case SUBTRACT: + assertEquals(vi1 - vi2, viActual); + return; + case DIVIDE: + assertEquals(vi1 / vi2, viActual); + return; + case MULTIPLY: + assertEquals(vi1 * vi2, viActual); + return; + case MODULES: + assertEquals(vi1 % vi2, viActual); + return; + default: + throw new IllegalStateException("illegal function name " + builtinFunctionName); + } + case LONG: + Long vl1 = ExprValueUtils.getLongValue(op1); + Long vl2 = ExprValueUtils.getLongValue(op2); + Long vlActual = ExprValueUtils.getLongValue(actual); + switch (builtinFunctionName) { + case ADD: + assertEquals(vl1 + vl2, vlActual); + return; + case SUBTRACT: + assertEquals(vl1 - vl2, vlActual); + return; + case DIVIDE: + assertEquals(vl1 / vl2, vlActual); + return; + case MULTIPLY: + assertEquals(vl1 * vl2, vlActual); + return; + case MODULES: + assertEquals(vl1 % vl2, vlActual); + return; + default: + throw new IllegalStateException("illegal function name " + builtinFunctionName); + } + case FLOAT: + Float vf1 = ExprValueUtils.getFloatValue(op1); + Float vf2 = ExprValueUtils.getFloatValue(op2); + Float vfActual = ExprValueUtils.getFloatValue(actual); + switch (builtinFunctionName) { + case ADD: + assertEquals(vf1 + vf2, vfActual); + return; + case SUBTRACT: + assertEquals(vf1 - vf2, vfActual); + return; + case DIVIDE: + assertEquals(vf1 / vf2, vfActual); + return; + case MULTIPLY: + assertEquals(vf1 * vf2, vfActual); + return; + case MODULES: + assertEquals(vf1 % vf2, vfActual); + return; + default: + throw new IllegalStateException("illegal function name " + builtinFunctionName); + } + case DOUBLE: + Double vd1 = ExprValueUtils.getDoubleValue(op1); + Double vd2 = ExprValueUtils.getDoubleValue(op2); + Double vdActual = ExprValueUtils.getDoubleValue(actual); + switch (builtinFunctionName) { + case ADD: + assertEquals(vd1 + vd2, vdActual); + return; + case SUBTRACT: + assertEquals(vd1 - vd2, vdActual); + return; + case DIVIDE: + assertEquals(vd1 / vd2, vdActual); + return; + case MULTIPLY: + assertEquals(vd1 * vd2, vdActual); + return; + case MODULES: + assertEquals(vd1 % vd2, vdActual); + return; + default: + throw new IllegalStateException("illegal function name " + builtinFunctionName); } + default: + throw new IllegalStateException("illegal function name " + builtinFunctionName); } + } } \ No newline at end of file diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/scalar/arthmetic/UnaryFunctionTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/scalar/arthmetic/UnaryFunctionTest.java index 2f7e8e49a1..5984ac5feb 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/scalar/arthmetic/UnaryFunctionTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/scalar/arthmetic/UnaryFunctionTest.java @@ -35,6 +35,9 @@ @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) public class UnaryFunctionTest extends ExpressionTestBase { + /** + * Test abs with integer value. + */ @ParameterizedTest(name = "abs({0})") @ValueSource(ints = {-2, 2}) public void abs_int_value(Integer value) { @@ -43,6 +46,9 @@ public void abs_int_value(Integer value) { allOf(hasType(ExprType.INTEGER), hasValue(Math.abs(value)))); } + /** + * Test abs with long value. + */ @ParameterizedTest(name = "abs({0})") @ValueSource(longs = {-2L, 2L}) public void abs_long_value(Long value) { @@ -51,6 +57,9 @@ public void abs_long_value(Long value) { allOf(hasType(ExprType.LONG), hasValue(Math.abs(value)))); } + /** + * Test abs with float value. + */ @ParameterizedTest(name = "abs({0})") @ValueSource(floats = {-2f, 2f}) public void abs_float_value(Float value) { @@ -59,6 +68,9 @@ public void abs_float_value(Float value) { allOf(hasType(ExprType.FLOAT), hasValue(Math.abs(value)))); } + /** + * Test abs with double value. + */ @ParameterizedTest(name = "abs({0})") @ValueSource(doubles = {-2L, 2L}) public void abs_double_value(Double value) { diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/scalar/predicate/BinaryPredicateFunctionTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/scalar/predicate/BinaryPredicateFunctionTest.java index b300511991..f81c6c6e8c 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/scalar/predicate/BinaryPredicateFunctionTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/scalar/predicate/BinaryPredicateFunctionTest.java @@ -15,6 +15,16 @@ package com.amazon.opendistroforelasticsearch.sql.expression.scalar.predicate; +import static com.amazon.opendistroforelasticsearch.sql.config.TestConfig.BOOL_TYPE_MISSING_VALUE_FIELD; +import static com.amazon.opendistroforelasticsearch.sql.config.TestConfig.BOOL_TYPE_NULL_VALUE_FIELD; +import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.LITERAL_FALSE; +import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.LITERAL_MISSING; +import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.LITERAL_NULL; +import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.LITERAL_TRUE; +import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.booleanValue; +import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.fromObjectValue; +import static org.junit.jupiter.api.Assertions.assertEquals; + import com.amazon.opendistroforelasticsearch.sql.data.model.ExprType; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprValue; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils; @@ -24,283 +34,294 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Stream; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import java.util.Arrays; -import java.util.List; -import java.util.stream.Stream; - -import static com.amazon.opendistroforelasticsearch.sql.config.TestConfig.BOOL_TYPE_MISSING_VALUE_FIELD; -import static com.amazon.opendistroforelasticsearch.sql.config.TestConfig.BOOL_TYPE_NULL_VALUE_FIELD; -import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.LITERAL_FALSE; -import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.LITERAL_MISSING; -import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.LITERAL_NULL; -import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.LITERAL_TRUE; -import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.booleanValue; -import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.fromObjectValue; -import static org.junit.jupiter.api.Assertions.assertEquals; - class BinaryPredicateFunctionTest extends ExpressionTestBase { - private static Stream binaryPredicateArguments() { - List booleans = Arrays.asList(true, false); - return Lists.cartesianProduct(booleans, booleans).stream() - .map(list -> Arguments.of(list.get(0), list.get(1))); - } - - private static Stream testEqualArguments() { - List arguments = Arrays.asList(1, 1L, 1F, 1D, "str", true, ImmutableList.of(1), - ImmutableMap.of("str", 1)); - Stream.Builder builder = Stream.builder(); - for (Object argument : arguments) { - builder.add(Arguments.of(fromObjectValue(argument), fromObjectValue(argument))); - } - return builder.build(); - } - - @ParameterizedTest(name = "and({0}, {1})") - @MethodSource("binaryPredicateArguments") - public void test_and(Boolean v1, Boolean v2) { - FunctionExpression and = dsl.and(typeEnv(), DSL.literal(booleanValue(v1)), DSL.literal(booleanValue(v2))); - assertEquals(ExprType.BOOLEAN, and.type(typeEnv())); - assertEquals(v1 && v2, ExprValueUtils.getBooleanValue(and.valueOf(valueEnv()))); - } - - @Test - public void test_boolean_and_null() { - FunctionExpression and = dsl.and(typeEnv(), DSL.literal(LITERAL_TRUE), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD)); - assertEquals(ExprType.BOOLEAN, and.type(typeEnv())); - assertEquals(LITERAL_NULL, and.valueOf(valueEnv())); - - and = dsl.and(typeEnv(), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD), DSL.literal(LITERAL_TRUE)); - assertEquals(ExprType.BOOLEAN, and.type(typeEnv())); - assertEquals(LITERAL_NULL, and.valueOf(valueEnv())); - - and = dsl.and(typeEnv(), DSL.literal(LITERAL_FALSE), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD)); - assertEquals(ExprType.BOOLEAN, and.type(typeEnv())); - assertEquals(LITERAL_FALSE, and.valueOf(valueEnv())); - - and = dsl.and(typeEnv(), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD), DSL.literal(LITERAL_FALSE)); - assertEquals(ExprType.BOOLEAN, and.type(typeEnv())); - assertEquals(LITERAL_FALSE, and.valueOf(valueEnv())); - } - - @Test - public void test_boolean_and_missing() { - FunctionExpression and = dsl.and(typeEnv(), DSL.literal(LITERAL_TRUE), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD)); - assertEquals(ExprType.BOOLEAN, and.type(typeEnv())); - assertEquals(LITERAL_MISSING, and.valueOf(valueEnv())); - - and = dsl.and(typeEnv(), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD), DSL.literal(LITERAL_TRUE)); - assertEquals(ExprType.BOOLEAN, and.type(typeEnv())); - assertEquals(LITERAL_MISSING, and.valueOf(valueEnv())); - - and = dsl.and(typeEnv(), DSL.literal(LITERAL_FALSE), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD)); - assertEquals(ExprType.BOOLEAN, and.type(typeEnv())); - assertEquals(LITERAL_FALSE, and.valueOf(valueEnv())); - - and = dsl.and(typeEnv(), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD), DSL.literal(LITERAL_FALSE)); - assertEquals(ExprType.BOOLEAN, and.type(typeEnv())); - assertEquals(LITERAL_FALSE, and.valueOf(valueEnv())); - } - - @Test - public void test_null_and_missing() { - FunctionExpression and = dsl.and(typeEnv(), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD), - DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD)); - assertEquals(ExprType.BOOLEAN, and.type(typeEnv())); - assertEquals(LITERAL_MISSING, and.valueOf(valueEnv())); - - and = dsl.and(typeEnv(), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD)); - assertEquals(ExprType.BOOLEAN, and.type(typeEnv())); - assertEquals(LITERAL_NULL, and.valueOf(valueEnv())); - - and = dsl.and(typeEnv(), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD)); - assertEquals(ExprType.BOOLEAN, and.type(typeEnv())); - assertEquals(LITERAL_MISSING, and.valueOf(valueEnv())); - - and = dsl.and(typeEnv(), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD)); - assertEquals(ExprType.BOOLEAN, and.type(typeEnv())); - assertEquals(LITERAL_MISSING, and.valueOf(valueEnv())); - } - - @ParameterizedTest(name = "or({0}, {1})") - @MethodSource("binaryPredicateArguments") - public void test_or(Boolean v1, Boolean v2) { - FunctionExpression and = dsl.or(typeEnv(), DSL.literal(booleanValue(v1)), DSL.literal(booleanValue(v2))); - assertEquals(ExprType.BOOLEAN, and.type(typeEnv())); - assertEquals(v1 || v2, ExprValueUtils.getBooleanValue(and.valueOf(valueEnv()))); - } - - @Test - public void test_boolean_or_null() { - FunctionExpression or = dsl.or(typeEnv(), DSL.literal(LITERAL_TRUE), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD)); - assertEquals(ExprType.BOOLEAN, or.type(typeEnv())); - assertEquals(LITERAL_TRUE, or.valueOf(valueEnv())); - - or = dsl.or(typeEnv(), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD), DSL.literal(LITERAL_TRUE)); - assertEquals(ExprType.BOOLEAN, or.type(typeEnv())); - assertEquals(LITERAL_TRUE, or.valueOf(valueEnv())); - - or = dsl.or(typeEnv(), DSL.literal(LITERAL_FALSE), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD)); - assertEquals(ExprType.BOOLEAN, or.type(typeEnv())); - assertEquals(LITERAL_NULL, or.valueOf(valueEnv())); - - or = dsl.or(typeEnv(), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD), DSL.literal(LITERAL_FALSE)); - assertEquals(ExprType.BOOLEAN, or.type(typeEnv())); - assertEquals(LITERAL_NULL, or.valueOf(valueEnv())); - } - - @Test - public void test_boolean_or_missing() { - FunctionExpression or = dsl.or(typeEnv(), DSL.literal(LITERAL_TRUE), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD)); - assertEquals(ExprType.BOOLEAN, or.type(typeEnv())); - assertEquals(LITERAL_TRUE, or.valueOf(valueEnv())); - - or = dsl.or(typeEnv(), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD), DSL.literal(LITERAL_TRUE)); - assertEquals(ExprType.BOOLEAN, or.type(typeEnv())); - assertEquals(LITERAL_TRUE, or.valueOf(valueEnv())); - - or = dsl.or(typeEnv(), DSL.literal(LITERAL_FALSE), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD)); - assertEquals(ExprType.BOOLEAN, or.type(typeEnv())); - assertEquals(LITERAL_MISSING, or.valueOf(valueEnv())); - - or = dsl.or(typeEnv(), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD), DSL.literal(LITERAL_FALSE)); - assertEquals(ExprType.BOOLEAN, or.type(typeEnv())); - assertEquals(LITERAL_MISSING, or.valueOf(valueEnv())); - } - - @Test - public void test_null_or_missing() { - FunctionExpression or = dsl.or(typeEnv(), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD), - DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD)); - assertEquals(ExprType.BOOLEAN, or.type(typeEnv())); - assertEquals(LITERAL_MISSING, or.valueOf(valueEnv())); - - or = dsl.or(typeEnv(), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD)); - assertEquals(ExprType.BOOLEAN, or.type(typeEnv())); - assertEquals(LITERAL_NULL, or.valueOf(valueEnv())); - - or = dsl.or(typeEnv(), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD)); - assertEquals(ExprType.BOOLEAN, or.type(typeEnv())); - assertEquals(LITERAL_NULL, or.valueOf(valueEnv())); - - or = dsl.or(typeEnv(), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD)); - assertEquals(ExprType.BOOLEAN, or.type(typeEnv())); - assertEquals(LITERAL_NULL, or.valueOf(valueEnv())); - } - - - @ParameterizedTest(name = "xor({0}, {1})") - @MethodSource("binaryPredicateArguments") - public void test_xor(Boolean v1, Boolean v2) { - FunctionExpression and = dsl.xor(typeEnv(), DSL.literal(booleanValue(v1)), DSL.literal(booleanValue(v2))); - assertEquals(ExprType.BOOLEAN, and.type(typeEnv())); - assertEquals(v1 ^ v2, ExprValueUtils.getBooleanValue(and.valueOf(valueEnv()))); - } - - @Test - public void test_boolean_xor_null() { - FunctionExpression xor = dsl.xor(typeEnv(), DSL.literal(LITERAL_TRUE), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD)); - assertEquals(ExprType.BOOLEAN, xor.type(typeEnv())); - assertEquals(LITERAL_TRUE, xor.valueOf(valueEnv())); - - xor = dsl.xor(typeEnv(), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD), DSL.literal(LITERAL_TRUE)); - assertEquals(ExprType.BOOLEAN, xor.type(typeEnv())); - assertEquals(LITERAL_TRUE, xor.valueOf(valueEnv())); - - xor = dsl.xor(typeEnv(), DSL.literal(LITERAL_FALSE), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD)); - assertEquals(ExprType.BOOLEAN, xor.type(typeEnv())); - assertEquals(LITERAL_NULL, xor.valueOf(valueEnv())); - - xor = dsl.xor(typeEnv(), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD), DSL.literal(LITERAL_FALSE)); - assertEquals(ExprType.BOOLEAN, xor.type(typeEnv())); - assertEquals(LITERAL_NULL, xor.valueOf(valueEnv())); - } - - @Test - public void test_boolean_xor_missing() { - FunctionExpression xor = dsl.xor(typeEnv(), DSL.literal(LITERAL_TRUE), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD)); - assertEquals(ExprType.BOOLEAN, xor.type(typeEnv())); - assertEquals(LITERAL_TRUE, xor.valueOf(valueEnv())); - - xor = dsl.xor(typeEnv(), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD), DSL.literal(LITERAL_TRUE)); - assertEquals(ExprType.BOOLEAN, xor.type(typeEnv())); - assertEquals(LITERAL_TRUE, xor.valueOf(valueEnv())); - - xor = dsl.xor(typeEnv(), DSL.literal(LITERAL_FALSE), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD)); - assertEquals(ExprType.BOOLEAN, xor.type(typeEnv())); - assertEquals(LITERAL_MISSING, xor.valueOf(valueEnv())); - - xor = dsl.xor(typeEnv(), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD), DSL.literal(LITERAL_FALSE)); - assertEquals(ExprType.BOOLEAN, xor.type(typeEnv())); - assertEquals(LITERAL_MISSING, xor.valueOf(valueEnv())); - } - - @Test - public void test_null_xor_missing() { - FunctionExpression xor = dsl.xor(typeEnv(), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD), - DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD)); - assertEquals(ExprType.BOOLEAN, xor.type(typeEnv())); - assertEquals(LITERAL_MISSING, xor.valueOf(valueEnv())); - - xor = dsl.xor(typeEnv(), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD)); - assertEquals(ExprType.BOOLEAN, xor.type(typeEnv())); - assertEquals(LITERAL_NULL, xor.valueOf(valueEnv())); - - xor = dsl.xor(typeEnv(), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD)); - assertEquals(ExprType.BOOLEAN, xor.type(typeEnv())); - assertEquals(LITERAL_NULL, xor.valueOf(valueEnv())); - - xor = dsl.xor(typeEnv(), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD)); - assertEquals(ExprType.BOOLEAN, xor.type(typeEnv())); - assertEquals(LITERAL_NULL, xor.valueOf(valueEnv())); - } - - @ParameterizedTest(name = "equal({0}, {1})") - @MethodSource("testEqualArguments") - public void test_equal(ExprValue v1, ExprValue v2) { - FunctionExpression equal = dsl.equal(typeEnv(), DSL.literal(v1), DSL.literal(v2)); - assertEquals(ExprType.BOOLEAN, equal.type(typeEnv())); - assertEquals(v1.value().equals(v2.value()), ExprValueUtils.getBooleanValue(equal.valueOf(valueEnv()))); - } - - @Test - public void test_null_equal_missing() { - FunctionExpression equal = dsl.equal(typeEnv(), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD), - DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD)); - assertEquals(ExprType.BOOLEAN, equal.type(typeEnv())); - assertEquals(LITERAL_TRUE, equal.valueOf(valueEnv())); - - equal = dsl.equal(typeEnv(), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD)); - assertEquals(ExprType.BOOLEAN, equal.type(typeEnv())); - assertEquals(LITERAL_TRUE, equal.valueOf(valueEnv())); - - equal = dsl.equal(typeEnv(), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD)); - assertEquals(ExprType.BOOLEAN, equal.type(typeEnv())); - assertEquals(LITERAL_FALSE, equal.valueOf(valueEnv())); - - equal = dsl.equal(typeEnv(), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD)); - assertEquals(ExprType.BOOLEAN, equal.type(typeEnv())); - assertEquals(LITERAL_FALSE, equal.valueOf(valueEnv())); - - equal = dsl.equal(typeEnv(), DSL.literal(LITERAL_TRUE), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD)); - assertEquals(ExprType.BOOLEAN, equal.type(typeEnv())); - assertEquals(LITERAL_FALSE, equal.valueOf(valueEnv())); - - equal = dsl.equal(typeEnv(), DSL.literal(LITERAL_TRUE), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD)); - assertEquals(ExprType.BOOLEAN, equal.type(typeEnv())); - assertEquals(LITERAL_FALSE, equal.valueOf(valueEnv())); - - equal = dsl.equal(typeEnv(), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD), DSL.literal(LITERAL_TRUE)); - assertEquals(ExprType.BOOLEAN, equal.type(typeEnv())); - assertEquals(LITERAL_FALSE, equal.valueOf(valueEnv())); - - equal = dsl.equal(typeEnv(), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD), DSL.literal(LITERAL_TRUE)); - assertEquals(ExprType.BOOLEAN, equal.type(typeEnv())); - assertEquals(LITERAL_FALSE, equal.valueOf(valueEnv())); + private static Stream binaryPredicateArguments() { + List booleans = Arrays.asList(true, false); + return Lists.cartesianProduct(booleans, booleans).stream() + .map(list -> Arguments.of(list.get(0), list.get(1))); + } + + private static Stream testEqualArguments() { + List arguments = Arrays.asList(1, 1L, 1F, 1D, "str", true, ImmutableList.of(1), + ImmutableMap.of("str", 1)); + Stream.Builder builder = Stream.builder(); + for (Object argument : arguments) { + builder.add(Arguments.of(fromObjectValue(argument), fromObjectValue(argument))); } + return builder.build(); + } + + @ParameterizedTest(name = "and({0}, {1})") + @MethodSource("binaryPredicateArguments") + public void test_and(Boolean v1, Boolean v2) { + FunctionExpression and = + dsl.and(typeEnv(), DSL.literal(booleanValue(v1)), DSL.literal(booleanValue(v2))); + assertEquals(ExprType.BOOLEAN, and.type(typeEnv())); + assertEquals(v1 && v2, ExprValueUtils.getBooleanValue(and.valueOf(valueEnv()))); + } + + @Test + public void test_boolean_and_null() { + FunctionExpression and = + dsl.and(typeEnv(), DSL.literal(LITERAL_TRUE), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD)); + assertEquals(ExprType.BOOLEAN, and.type(typeEnv())); + assertEquals(LITERAL_NULL, and.valueOf(valueEnv())); + + and = dsl.and(typeEnv(), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD), DSL.literal(LITERAL_TRUE)); + assertEquals(ExprType.BOOLEAN, and.type(typeEnv())); + assertEquals(LITERAL_NULL, and.valueOf(valueEnv())); + + and = dsl.and(typeEnv(), DSL.literal(LITERAL_FALSE), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD)); + assertEquals(ExprType.BOOLEAN, and.type(typeEnv())); + assertEquals(LITERAL_FALSE, and.valueOf(valueEnv())); + + and = dsl.and(typeEnv(), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD), DSL.literal(LITERAL_FALSE)); + assertEquals(ExprType.BOOLEAN, and.type(typeEnv())); + assertEquals(LITERAL_FALSE, and.valueOf(valueEnv())); + } + + @Test + public void test_boolean_and_missing() { + FunctionExpression and = + dsl.and(typeEnv(), DSL.literal(LITERAL_TRUE), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD)); + assertEquals(ExprType.BOOLEAN, and.type(typeEnv())); + assertEquals(LITERAL_MISSING, and.valueOf(valueEnv())); + + and = dsl.and(typeEnv(), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD), DSL.literal(LITERAL_TRUE)); + assertEquals(ExprType.BOOLEAN, and.type(typeEnv())); + assertEquals(LITERAL_MISSING, and.valueOf(valueEnv())); + + and = dsl.and(typeEnv(), DSL.literal(LITERAL_FALSE), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD)); + assertEquals(ExprType.BOOLEAN, and.type(typeEnv())); + assertEquals(LITERAL_FALSE, and.valueOf(valueEnv())); + + and = dsl.and(typeEnv(), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD), DSL.literal(LITERAL_FALSE)); + assertEquals(ExprType.BOOLEAN, and.type(typeEnv())); + assertEquals(LITERAL_FALSE, and.valueOf(valueEnv())); + } + + @Test + public void test_null_and_missing() { + FunctionExpression and = dsl.and(typeEnv(), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD), + DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD)); + assertEquals(ExprType.BOOLEAN, and.type(typeEnv())); + assertEquals(LITERAL_MISSING, and.valueOf(valueEnv())); + + and = dsl.and(typeEnv(), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD), + DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD)); + assertEquals(ExprType.BOOLEAN, and.type(typeEnv())); + assertEquals(LITERAL_NULL, and.valueOf(valueEnv())); + + and = dsl.and(typeEnv(), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD), + DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD)); + assertEquals(ExprType.BOOLEAN, and.type(typeEnv())); + assertEquals(LITERAL_MISSING, and.valueOf(valueEnv())); + + and = dsl.and(typeEnv(), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD), + DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD)); + assertEquals(ExprType.BOOLEAN, and.type(typeEnv())); + assertEquals(LITERAL_MISSING, and.valueOf(valueEnv())); + } + + @ParameterizedTest(name = "or({0}, {1})") + @MethodSource("binaryPredicateArguments") + public void test_or(Boolean v1, Boolean v2) { + FunctionExpression and = + dsl.or(typeEnv(), DSL.literal(booleanValue(v1)), DSL.literal(booleanValue(v2))); + assertEquals(ExprType.BOOLEAN, and.type(typeEnv())); + assertEquals(v1 || v2, ExprValueUtils.getBooleanValue(and.valueOf(valueEnv()))); + } + + @Test + public void test_boolean_or_null() { + FunctionExpression or = + dsl.or(typeEnv(), DSL.literal(LITERAL_TRUE), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD)); + assertEquals(ExprType.BOOLEAN, or.type(typeEnv())); + assertEquals(LITERAL_TRUE, or.valueOf(valueEnv())); + + or = dsl.or(typeEnv(), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD), DSL.literal(LITERAL_TRUE)); + assertEquals(ExprType.BOOLEAN, or.type(typeEnv())); + assertEquals(LITERAL_TRUE, or.valueOf(valueEnv())); + + or = dsl.or(typeEnv(), DSL.literal(LITERAL_FALSE), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD)); + assertEquals(ExprType.BOOLEAN, or.type(typeEnv())); + assertEquals(LITERAL_NULL, or.valueOf(valueEnv())); + + or = dsl.or(typeEnv(), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD), DSL.literal(LITERAL_FALSE)); + assertEquals(ExprType.BOOLEAN, or.type(typeEnv())); + assertEquals(LITERAL_NULL, or.valueOf(valueEnv())); + } + + @Test + public void test_boolean_or_missing() { + FunctionExpression or = + dsl.or(typeEnv(), DSL.literal(LITERAL_TRUE), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD)); + assertEquals(ExprType.BOOLEAN, or.type(typeEnv())); + assertEquals(LITERAL_TRUE, or.valueOf(valueEnv())); + + or = dsl.or(typeEnv(), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD), DSL.literal(LITERAL_TRUE)); + assertEquals(ExprType.BOOLEAN, or.type(typeEnv())); + assertEquals(LITERAL_TRUE, or.valueOf(valueEnv())); + + or = dsl.or(typeEnv(), DSL.literal(LITERAL_FALSE), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD)); + assertEquals(ExprType.BOOLEAN, or.type(typeEnv())); + assertEquals(LITERAL_MISSING, or.valueOf(valueEnv())); + + or = dsl.or(typeEnv(), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD), DSL.literal(LITERAL_FALSE)); + assertEquals(ExprType.BOOLEAN, or.type(typeEnv())); + assertEquals(LITERAL_MISSING, or.valueOf(valueEnv())); + } + + @Test + public void test_null_or_missing() { + FunctionExpression or = dsl.or(typeEnv(), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD), + DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD)); + assertEquals(ExprType.BOOLEAN, or.type(typeEnv())); + assertEquals(LITERAL_MISSING, or.valueOf(valueEnv())); + + or = + dsl.or(typeEnv(), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD)); + assertEquals(ExprType.BOOLEAN, or.type(typeEnv())); + assertEquals(LITERAL_NULL, or.valueOf(valueEnv())); + + or = dsl.or(typeEnv(), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD), + DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD)); + assertEquals(ExprType.BOOLEAN, or.type(typeEnv())); + assertEquals(LITERAL_NULL, or.valueOf(valueEnv())); + + or = dsl.or(typeEnv(), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD), + DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD)); + assertEquals(ExprType.BOOLEAN, or.type(typeEnv())); + assertEquals(LITERAL_NULL, or.valueOf(valueEnv())); + } + + + @ParameterizedTest(name = "xor({0}, {1})") + @MethodSource("binaryPredicateArguments") + public void test_xor(Boolean v1, Boolean v2) { + FunctionExpression and = + dsl.xor(typeEnv(), DSL.literal(booleanValue(v1)), DSL.literal(booleanValue(v2))); + assertEquals(ExprType.BOOLEAN, and.type(typeEnv())); + assertEquals(v1 ^ v2, ExprValueUtils.getBooleanValue(and.valueOf(valueEnv()))); + } + + @Test + public void test_boolean_xor_null() { + FunctionExpression xor = + dsl.xor(typeEnv(), DSL.literal(LITERAL_TRUE), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD)); + assertEquals(ExprType.BOOLEAN, xor.type(typeEnv())); + assertEquals(LITERAL_TRUE, xor.valueOf(valueEnv())); + + xor = dsl.xor(typeEnv(), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD), DSL.literal(LITERAL_TRUE)); + assertEquals(ExprType.BOOLEAN, xor.type(typeEnv())); + assertEquals(LITERAL_TRUE, xor.valueOf(valueEnv())); + + xor = dsl.xor(typeEnv(), DSL.literal(LITERAL_FALSE), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD)); + assertEquals(ExprType.BOOLEAN, xor.type(typeEnv())); + assertEquals(LITERAL_NULL, xor.valueOf(valueEnv())); + + xor = dsl.xor(typeEnv(), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD), DSL.literal(LITERAL_FALSE)); + assertEquals(ExprType.BOOLEAN, xor.type(typeEnv())); + assertEquals(LITERAL_NULL, xor.valueOf(valueEnv())); + } + + @Test + public void test_boolean_xor_missing() { + FunctionExpression xor = + dsl.xor(typeEnv(), DSL.literal(LITERAL_TRUE), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD)); + assertEquals(ExprType.BOOLEAN, xor.type(typeEnv())); + assertEquals(LITERAL_TRUE, xor.valueOf(valueEnv())); + + xor = dsl.xor(typeEnv(), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD), DSL.literal(LITERAL_TRUE)); + assertEquals(ExprType.BOOLEAN, xor.type(typeEnv())); + assertEquals(LITERAL_TRUE, xor.valueOf(valueEnv())); + + xor = dsl.xor(typeEnv(), DSL.literal(LITERAL_FALSE), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD)); + assertEquals(ExprType.BOOLEAN, xor.type(typeEnv())); + assertEquals(LITERAL_MISSING, xor.valueOf(valueEnv())); + + xor = dsl.xor(typeEnv(), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD), DSL.literal(LITERAL_FALSE)); + assertEquals(ExprType.BOOLEAN, xor.type(typeEnv())); + assertEquals(LITERAL_MISSING, xor.valueOf(valueEnv())); + } + + @Test + public void test_null_xor_missing() { + FunctionExpression xor = dsl.xor(typeEnv(), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD), + DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD)); + assertEquals(ExprType.BOOLEAN, xor.type(typeEnv())); + assertEquals(LITERAL_MISSING, xor.valueOf(valueEnv())); + + xor = dsl.xor(typeEnv(), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD), + DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD)); + assertEquals(ExprType.BOOLEAN, xor.type(typeEnv())); + assertEquals(LITERAL_NULL, xor.valueOf(valueEnv())); + + xor = dsl.xor(typeEnv(), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD), + DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD)); + assertEquals(ExprType.BOOLEAN, xor.type(typeEnv())); + assertEquals(LITERAL_NULL, xor.valueOf(valueEnv())); + + xor = dsl.xor(typeEnv(), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD), + DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD)); + assertEquals(ExprType.BOOLEAN, xor.type(typeEnv())); + assertEquals(LITERAL_NULL, xor.valueOf(valueEnv())); + } + + @ParameterizedTest(name = "equal({0}, {1})") + @MethodSource("testEqualArguments") + public void test_equal(ExprValue v1, ExprValue v2) { + FunctionExpression equal = dsl.equal(typeEnv(), DSL.literal(v1), DSL.literal(v2)); + assertEquals(ExprType.BOOLEAN, equal.type(typeEnv())); + assertEquals(v1.value().equals(v2.value()), + ExprValueUtils.getBooleanValue(equal.valueOf(valueEnv()))); + } + + @Test + public void test_null_equal_missing() { + FunctionExpression equal = dsl.equal(typeEnv(), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD), + DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD)); + assertEquals(ExprType.BOOLEAN, equal.type(typeEnv())); + assertEquals(LITERAL_TRUE, equal.valueOf(valueEnv())); + + equal = dsl.equal(typeEnv(), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD), + DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD)); + assertEquals(ExprType.BOOLEAN, equal.type(typeEnv())); + assertEquals(LITERAL_TRUE, equal.valueOf(valueEnv())); + + equal = dsl.equal(typeEnv(), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD), + DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD)); + assertEquals(ExprType.BOOLEAN, equal.type(typeEnv())); + assertEquals(LITERAL_FALSE, equal.valueOf(valueEnv())); + + equal = dsl.equal(typeEnv(), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD), + DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD)); + assertEquals(ExprType.BOOLEAN, equal.type(typeEnv())); + assertEquals(LITERAL_FALSE, equal.valueOf(valueEnv())); + + equal = dsl.equal(typeEnv(), DSL.literal(LITERAL_TRUE), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD)); + assertEquals(ExprType.BOOLEAN, equal.type(typeEnv())); + assertEquals(LITERAL_FALSE, equal.valueOf(valueEnv())); + + equal = dsl.equal(typeEnv(), DSL.literal(LITERAL_TRUE), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD)); + assertEquals(ExprType.BOOLEAN, equal.type(typeEnv())); + assertEquals(LITERAL_FALSE, equal.valueOf(valueEnv())); + + equal = dsl.equal(typeEnv(), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD), DSL.literal(LITERAL_TRUE)); + assertEquals(ExprType.BOOLEAN, equal.type(typeEnv())); + assertEquals(LITERAL_FALSE, equal.valueOf(valueEnv())); + + equal = dsl.equal(typeEnv(), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD), DSL.literal(LITERAL_TRUE)); + assertEquals(ExprType.BOOLEAN, equal.type(typeEnv())); + assertEquals(LITERAL_FALSE, equal.valueOf(valueEnv())); + } } \ No newline at end of file diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/scalar/predicate/UnaryPredicateFunctionTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/scalar/predicate/UnaryPredicateFunctionTest.java index bfebc16d89..a6c308a5aa 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/scalar/predicate/UnaryPredicateFunctionTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/expression/scalar/predicate/UnaryPredicateFunctionTest.java @@ -15,6 +15,13 @@ package com.amazon.opendistroforelasticsearch.sql.expression.scalar.predicate; +import static com.amazon.opendistroforelasticsearch.sql.config.TestConfig.BOOL_TYPE_MISSING_VALUE_FIELD; +import static com.amazon.opendistroforelasticsearch.sql.config.TestConfig.BOOL_TYPE_NULL_VALUE_FIELD; +import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.LITERAL_MISSING; +import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.LITERAL_NULL; +import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.booleanValue; +import static org.junit.jupiter.api.Assertions.assertEquals; + import com.amazon.opendistroforelasticsearch.sql.data.model.ExprType; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils; import com.amazon.opendistroforelasticsearch.sql.expression.DSL; @@ -24,33 +31,26 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; -import static com.amazon.opendistroforelasticsearch.sql.config.TestConfig.BOOL_TYPE_MISSING_VALUE_FIELD; -import static com.amazon.opendistroforelasticsearch.sql.config.TestConfig.BOOL_TYPE_NULL_VALUE_FIELD; -import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.LITERAL_MISSING; -import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.LITERAL_NULL; -import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.booleanValue; -import static org.junit.jupiter.api.Assertions.assertEquals; - class UnaryPredicateFunctionTest extends ExpressionTestBase { - @ParameterizedTest(name = "not({0})") - @ValueSource(booleans = {true, false}) - public void test_not(Boolean v) { - FunctionExpression and = dsl.not(typeEnv(), DSL.literal(booleanValue(v))); - assertEquals(ExprType.BOOLEAN, and.type(typeEnv())); - assertEquals(!v, ExprValueUtils.getBooleanValue(and.valueOf(valueEnv()))); - } + @ParameterizedTest(name = "not({0})") + @ValueSource(booleans = {true, false}) + public void test_not(Boolean v) { + FunctionExpression and = dsl.not(typeEnv(), DSL.literal(booleanValue(v))); + assertEquals(ExprType.BOOLEAN, and.type(typeEnv())); + assertEquals(!v, ExprValueUtils.getBooleanValue(and.valueOf(valueEnv()))); + } - @Test - public void test_not_null() { - FunctionExpression and = dsl.not(typeEnv(), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD)); - assertEquals(ExprType.BOOLEAN, and.type(typeEnv())); - assertEquals(LITERAL_NULL, and.valueOf(valueEnv())); - } + @Test + public void test_not_null() { + FunctionExpression and = dsl.not(typeEnv(), DSL.ref(BOOL_TYPE_NULL_VALUE_FIELD)); + assertEquals(ExprType.BOOLEAN, and.type(typeEnv())); + assertEquals(LITERAL_NULL, and.valueOf(valueEnv())); + } - @Test - public void test_not_missing() { - FunctionExpression and = dsl.not(typeEnv(), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD)); - assertEquals(ExprType.BOOLEAN, and.type(typeEnv())); - assertEquals(LITERAL_MISSING, and.valueOf(valueEnv())); - } + @Test + public void test_not_missing() { + FunctionExpression and = dsl.not(typeEnv(), DSL.ref(BOOL_TYPE_MISSING_VALUE_FIELD)); + assertEquals(ExprType.BOOLEAN, and.type(typeEnv())); + assertEquals(LITERAL_MISSING, and.valueOf(valueEnv())); + } } \ No newline at end of file diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/PlannerTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/PlannerTest.java index 9b7954bf1d..a9b4a54e39 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/PlannerTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/PlannerTest.java @@ -15,6 +15,10 @@ package com.amazon.opendistroforelasticsearch.sql.planner; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + import com.amazon.opendistroforelasticsearch.sql.data.model.ExprType; import com.amazon.opendistroforelasticsearch.sql.expression.DSL; import com.amazon.opendistroforelasticsearch.sql.planner.logical.LogicalAggregation; @@ -34,100 +38,95 @@ import com.amazon.opendistroforelasticsearch.sql.storage.Table; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import java.util.Map; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import java.util.Map; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; - @ExtendWith(MockitoExtension.class) public class PlannerTest extends PhysicalPlanTestBase { - @Mock - private PhysicalPlan scan; - - @Mock - private StorageEngine storageEngine; + @Mock + private PhysicalPlan scan; + + @Mock + private StorageEngine storageEngine; + + @BeforeEach + public void setUp() { + when(storageEngine.getTable(any())).thenReturn(new MockTable()); + } + + @Test + public void planner_test() { + assertPhysicalPlan( + PhysicalPlanDSL.rename( + PhysicalPlanDSL.agg( + PhysicalPlanDSL.filter( + scan, + dsl.equal(typeEnv(), DSL.ref("response"), DSL.literal(10)) + ), + ImmutableList.of(dsl.avg(typeEnv(), DSL.ref("response"))), + ImmutableList.of() + ), + ImmutableMap.of(DSL.ref("ivalue"), DSL.ref("avg(response)")) + ), + LogicalPlanDSL.rename( + LogicalPlanDSL.aggregation( + LogicalPlanDSL.filter( + LogicalPlanDSL.relation("schema"), + dsl.equal(typeEnv(), DSL.ref("response"), DSL.literal(10)) + ), + ImmutableList.of(dsl.avg(typeEnv(), DSL.ref("response"))), + ImmutableList.of() + ), + ImmutableMap.of(DSL.ref("ivalue"), DSL.ref("avg(response)")) + ) + ); + } + + protected void assertPhysicalPlan(PhysicalPlan expected, LogicalPlan logicalPlan) { + assertEquals(expected, analyze(logicalPlan)); + } + + protected PhysicalPlan analyze(LogicalPlan logicalPlan) { + return new Planner(storageEngine).plan(logicalPlan); + } + + protected class MockTable extends LogicalPlanNodeVisitor implements Table { + + @Override + public Map getFieldTypes() { + throw new UnsupportedOperationException(); + } - @BeforeEach - public void setUp() { - when(storageEngine.getTable(any())).thenReturn(new MockTable()); + @Override + public PhysicalPlan implement(LogicalPlan plan) { + return plan.accept(this, null); } - @Test - public void planner_test() { - assertPhysicalPlan( - PhysicalPlanDSL.rename( - PhysicalPlanDSL.agg( - PhysicalPlanDSL.filter( - scan, - dsl.equal(typeEnv(), DSL.ref("response"), DSL.literal(10)) - ), - ImmutableList.of(dsl.avg(typeEnv(), DSL.ref("response"))), - ImmutableList.of() - ), - ImmutableMap.of(DSL.ref("ivalue"), DSL.ref("avg(response)")) - ), - LogicalPlanDSL.rename( - LogicalPlanDSL.aggregation( - LogicalPlanDSL.filter( - LogicalPlanDSL.relation("schema"), - dsl.equal(typeEnv(), DSL.ref("response"), DSL.literal(10)) - ), - ImmutableList.of(dsl.avg(typeEnv(), DSL.ref("response"))), - ImmutableList.of() - ), - ImmutableMap.of(DSL.ref("ivalue"), DSL.ref("avg(response)")) - ) - ); + @Override + public PhysicalPlan visitRelation(LogicalRelation plan, Object context) { + return scan; } - protected void assertPhysicalPlan(PhysicalPlan expected, LogicalPlan logicalPlan) { - assertEquals(expected, analyze(logicalPlan)); + @Override + public PhysicalPlan visitFilter(LogicalFilter plan, Object context) { + return new FilterOperator(plan.getChild().get(0).accept(this, context), plan.getCondition()); } - protected PhysicalPlan analyze(LogicalPlan logicalPlan) { - return new Planner(storageEngine).plan(logicalPlan); + @Override + public PhysicalPlan visitAggregation(LogicalAggregation plan, Object context) { + return new AggregationOperator(plan.getChild().get(0).accept(this, context), + plan.getAggregatorList(), plan.getGroupByList() + ); } - protected class MockTable extends LogicalPlanNodeVisitor implements Table { - - @Override - public Map getFieldTypes() { - throw new UnsupportedOperationException(); - } - - @Override - public PhysicalPlan implement(LogicalPlan plan) { - return plan.accept(this, null); - } - - @Override - public PhysicalPlan visitRelation(LogicalRelation plan, Object context) { - return scan; - } - - @Override - public PhysicalPlan visitFilter(LogicalFilter plan, Object context) { - return new FilterOperator(plan.getChild().get(0).accept(this, context), plan.getCondition()); - } - - @Override - public PhysicalPlan visitAggregation(LogicalAggregation plan, Object context) { - return new AggregationOperator(plan.getChild().get(0).accept(this, context), - plan.getAggregatorList(), plan.getGroupByList() - ); - } - - @Override - public PhysicalPlan visitRename(LogicalRename plan, Object context) { - return new RenameOperator(plan.getChild().get(0).accept(this, context), - plan.getRenameMap()); - } + @Override + public PhysicalPlan visitRename(LogicalRename plan, Object context) { + return new RenameOperator(plan.getChild().get(0).accept(this, context), + plan.getRenameMap()); } + } } diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalEvalTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalEvalTest.java index 17c86ab061..7081d487f3 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalEvalTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalEvalTest.java @@ -32,7 +32,8 @@ @ExtendWith(MockitoExtension.class) public class LogicalEvalTest extends AnalyzerTestBase { - @Mock private Environment environment; + @Mock + private Environment environment; @Test public void analyze_eval_with_one_field() { diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalPlanNodeVisitorTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalPlanNodeVisitorTest.java index 53157ac01b..4f9dcb2107 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalPlanNodeVisitorTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalPlanNodeVisitorTest.java @@ -31,12 +31,17 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -/** Todo. Temporary added for UT coverage, Will be removed. */ +/** + * Todo. Temporary added for UT coverage, Will be removed. + */ @ExtendWith(MockitoExtension.class) class LogicalPlanNodeVisitorTest { - @Mock Expression expression; - @Mock ReferenceExpression ref; - @Mock Aggregator aggregator; + @Mock + Expression expression; + @Mock + ReferenceExpression ref; + @Mock + Aggregator aggregator; @Test public void logicalPlanShouldTraversable() { @@ -55,26 +60,42 @@ public void logicalPlanShouldTraversable() { @Test public void testAbstractPlanNodeVisitorShouldReturnNull() { LogicalPlan relation = LogicalPlanDSL.relation("schema"); + assertNull(relation.accept(new LogicalPlanNodeVisitor() { + }, null)); + LogicalPlan filter = LogicalPlanDSL.filter(relation, expression); + assertNull(filter.accept(new LogicalPlanNodeVisitor() { + }, null)); + LogicalPlan aggregation = LogicalPlanDSL.aggregation( filter, ImmutableList.of(aggregator), ImmutableList.of(expression)); + assertNull(aggregation.accept(new LogicalPlanNodeVisitor() { + }, null)); + LogicalPlan rename = LogicalPlanDSL.rename(aggregation, ImmutableMap.of(ref, ref)); + assertNull(rename.accept(new LogicalPlanNodeVisitor() { + }, null)); + LogicalPlan project = LogicalPlanDSL.project(relation, ref); + assertNull(project.accept(new LogicalPlanNodeVisitor() { + }, null)); + LogicalPlan remove = LogicalPlanDSL.remove(relation, ref); + assertNull(remove.accept(new LogicalPlanNodeVisitor() { + }, null)); + LogicalPlan eval = LogicalPlanDSL.eval(relation, Pair.of(ref, expression)); + assertNull(eval.accept(new LogicalPlanNodeVisitor() { + }, null)); + LogicalPlan sort = LogicalPlanDSL.sort(relation, 100, Pair.of(SortOption.PPL_ASC, expression)); - LogicalPlan dedup = LogicalPlanDSL.dedupe(relation, 1, false, false, expression); + assertNull(sort.accept(new LogicalPlanNodeVisitor() { + }, null)); - assertNull(relation.accept(new LogicalPlanNodeVisitor() {}, null)); - assertNull(filter.accept(new LogicalPlanNodeVisitor() {}, null)); - assertNull(aggregation.accept(new LogicalPlanNodeVisitor() {}, null)); - assertNull(rename.accept(new LogicalPlanNodeVisitor() {}, null)); - assertNull(project.accept(new LogicalPlanNodeVisitor() {}, null)); - assertNull(remove.accept(new LogicalPlanNodeVisitor() {}, null)); - assertNull(eval.accept(new LogicalPlanNodeVisitor() {}, null)); - assertNull(sort.accept(new LogicalPlanNodeVisitor() {}, null)); - assertNull(dedup.accept(new LogicalPlanNodeVisitor() {}, null)); + LogicalPlan dedup = LogicalPlanDSL.dedupe(relation, 1, false, false, expression); + assertNull(dedup.accept(new LogicalPlanNodeVisitor() { + }, null)); } private static class NodesCount extends LogicalPlanNodeVisitor { @@ -87,24 +108,24 @@ public Integer visitRelation(LogicalRelation plan, Object context) { public Integer visitFilter(LogicalFilter plan, Object context) { return 1 + plan.getChild().stream() - .map(child -> child.accept(this, context)) - .collect(Collectors.summingInt(Integer::intValue)); + .map(child -> child.accept(this, context)) + .collect(Collectors.summingInt(Integer::intValue)); } @Override public Integer visitAggregation(LogicalAggregation plan, Object context) { return 1 + plan.getChild().stream() - .map(child -> child.accept(this, context)) - .collect(Collectors.summingInt(Integer::intValue)); + .map(child -> child.accept(this, context)) + .collect(Collectors.summingInt(Integer::intValue)); } @Override public Integer visitRename(LogicalRename plan, Object context) { return 1 + plan.getChild().stream() - .map(child -> child.accept(this, context)) - .collect(Collectors.summingInt(Integer::intValue)); + .map(child -> child.accept(this, context)) + .collect(Collectors.summingInt(Integer::intValue)); } } } diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalRelationTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalRelationTest.java index b860b45007..543c7a01ac 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalRelationTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/logical/LogicalRelationTest.java @@ -15,15 +15,15 @@ package com.amazon.opendistroforelasticsearch.sql.planner.logical; -import org.junit.jupiter.api.Test; - import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; + class LogicalRelationTest { - @Test - public void logicalRelationHasNoInput() { - LogicalPlan relation = LogicalPlanDSL.relation("index"); - assertEquals(0, relation.getChild().size()); - } + @Test + public void logicalRelationHasNoInput() { + LogicalPlan relation = LogicalPlanDSL.relation("index"); + assertEquals(0, relation.getChild().size()); + } } \ No newline at end of file diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/AggregationOperatorTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/AggregationOperatorTest.java index d703c50577..ad464e190e 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/AggregationOperatorTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/AggregationOperatorTest.java @@ -29,43 +29,46 @@ import org.junit.jupiter.api.Test; class AggregationOperatorTest extends PhysicalPlanTestBase { - @Test - public void avg_with_one_groups() { - PhysicalPlan plan = new AggregationOperator(new TestScan(), - Collections.singletonList(dsl.avg(typeEnv(), DSL.ref("response"))), - Collections.singletonList(DSL.ref("action"))); - List result = execute(plan); - assertEquals(2, result.size()); - assertThat(result, containsInAnyOrder( - ExprValueUtils.tupleValue(ImmutableMap.of("action", "GET", "avg(response)", 268d)), - ExprValueUtils.tupleValue(ImmutableMap.of("action", "POST", "avg(response)", 350d)) - )); - } + @Test + public void avg_with_one_groups() { + PhysicalPlan plan = new AggregationOperator(new TestScan(), + Collections.singletonList(dsl.avg(typeEnv(), DSL.ref("response"))), + Collections.singletonList(DSL.ref("action"))); + List result = execute(plan); + assertEquals(2, result.size()); + assertThat(result, containsInAnyOrder( + ExprValueUtils.tupleValue(ImmutableMap.of("action", "GET", "avg(response)", 268d)), + ExprValueUtils.tupleValue(ImmutableMap.of("action", "POST", "avg(response)", 350d)) + )); + } - @Test - public void avg_with_two_groups() { - PhysicalPlan plan = new AggregationOperator(new TestScan(), - Collections.singletonList(dsl.avg(typeEnv(), DSL.ref("response"))), - Arrays.asList(DSL.ref("action"), DSL.ref("ip"))); - List result = execute(plan); - assertEquals(3, result.size()); - assertThat(result, containsInAnyOrder( - ExprValueUtils.tupleValue(ImmutableMap.of("action", "GET", "ip", "209.160.24.63", "avg(response)", 302d)), - ExprValueUtils.tupleValue(ImmutableMap.of("action", "GET", "ip", "112.111.162.4", "avg(response)", 200d)), - ExprValueUtils.tupleValue(ImmutableMap.of("action", "POST", "ip", "74.125.19.106", "avg(response)", 350d)) - )); - } + @Test + public void avg_with_two_groups() { + PhysicalPlan plan = new AggregationOperator(new TestScan(), + Collections.singletonList(dsl.avg(typeEnv(), DSL.ref("response"))), + Arrays.asList(DSL.ref("action"), DSL.ref("ip"))); + List result = execute(plan); + assertEquals(3, result.size()); + assertThat(result, containsInAnyOrder( + ExprValueUtils.tupleValue( + ImmutableMap.of("action", "GET", "ip", "209.160.24.63", "avg(response)", 302d)), + ExprValueUtils.tupleValue( + ImmutableMap.of("action", "GET", "ip", "112.111.162.4", "avg(response)", 200d)), + ExprValueUtils.tupleValue( + ImmutableMap.of("action", "POST", "ip", "74.125.19.106", "avg(response)", 350d)) + )); + } - @Test - public void sum_with_one_groups() { - PhysicalPlan plan = new AggregationOperator(new TestScan(), - Collections.singletonList(dsl.sum(typeEnv(), DSL.ref("response"))), - Collections.singletonList(DSL.ref("action"))); - List result = execute(plan); - assertEquals(2, result.size()); - assertThat(result, containsInAnyOrder( - ExprValueUtils.tupleValue(ImmutableMap.of("action", "GET", "sum(response)", 804)), - ExprValueUtils.tupleValue(ImmutableMap.of("action", "POST", "sum(response)", 700)) - )); - } + @Test + public void sum_with_one_groups() { + PhysicalPlan plan = new AggregationOperator(new TestScan(), + Collections.singletonList(dsl.sum(typeEnv(), DSL.ref("response"))), + Collections.singletonList(DSL.ref("action"))); + List result = execute(plan); + assertEquals(2, result.size()); + assertThat(result, containsInAnyOrder( + ExprValueUtils.tupleValue(ImmutableMap.of("action", "GET", "sum(response)", 804)), + ExprValueUtils.tupleValue(ImmutableMap.of("action", "POST", "sum(response)", 700)) + )); + } } \ No newline at end of file diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/DedupeOperatorTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/DedupeOperatorTest.java index 7906f89eb2..5bb57a506d 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/DedupeOperatorTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/DedupeOperatorTest.java @@ -34,13 +34,14 @@ @ExtendWith(MockitoExtension.class) class DedupeOperatorTest extends PhysicalPlanTestBase { - @Mock private PhysicalPlan inputPlan; + @Mock + private PhysicalPlan inputPlan; /** * construct the map which contain null value, because {@link ImmutableMap} doesn't support null * value. */ - private Map NULL_MAP = + private static final Map NULL_MAP = new HashMap() { { put("region", null); @@ -190,7 +191,7 @@ public void dedupe_one_field_with_missing_value() { .thenReturn( tupleValue(ImmutableMap.of("region", "us-east-1", "action", "POST", "response", 200))) .thenReturn( - tupleValue(ImmutableMap.of( "action", "POST", "response", 200))) + tupleValue(ImmutableMap.of("action", "POST", "response", 200))) .thenReturn( tupleValue(ImmutableMap.of("region", "us-east-1", "action", "GET", "response", 200))); @@ -209,7 +210,7 @@ public void dedupe_one_field_with_missing_value_keep_empty() { .thenReturn( tupleValue(ImmutableMap.of("region", "us-east-1", "action", "POST", "response", 200))) .thenReturn( - tupleValue(ImmutableMap.of( "action", "POST", "response", 200))) + tupleValue(ImmutableMap.of("action", "POST", "response", 200))) .thenReturn( tupleValue(ImmutableMap.of("region", "us-east-1", "action", "GET", "response", 200))); @@ -217,7 +218,7 @@ public void dedupe_one_field_with_missing_value_keep_empty() { execute(dedupe(inputPlan, 1, true, false, DSL.ref("region"))), contains( tupleValue(ImmutableMap.of("region", "us-east-1", "action", "GET", "response", 200)), - tupleValue(ImmutableMap.of( "action", "POST", "response", 200)))); + tupleValue(ImmutableMap.of("action", "POST", "response", 200)))); } @Test diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/EvalOperatorTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/EvalOperatorTest.java index b81f3039ab..63b676d602 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/EvalOperatorTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/EvalOperatorTest.java @@ -38,8 +38,10 @@ @ExtendWith(MockitoExtension.class) class EvalOperatorTest extends PhysicalPlanTestBase { - @Mock private PhysicalPlan inputPlan; - @Mock private Environment environment; + @Mock + private PhysicalPlan inputPlan; + @Mock + private Environment environment; @Test public void create_new_field_that_contain_the_result_of_a_calculation() { diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/FilterOperatorTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/FilterOperatorTest.java index f3828b3126..8d4d379f43 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/FilterOperatorTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/FilterOperatorTest.java @@ -28,13 +28,15 @@ class FilterOperatorTest extends PhysicalPlanTestBase { - @Test - public void filterTest() { - FilterOperator plan = new FilterOperator(new TestScan(), - dsl.equal(typeEnv(), DSL.ref("response"), DSL.literal(404))); - List result = execute(plan); - assertEquals(1, result.size()); - assertThat(result, containsInAnyOrder(ExprValueUtils - .tupleValue(ImmutableMap.of("ip", "209.160.24.63", "action", "GET", "response", 404, "referer", "www.amazon.com")))); - } + @Test + public void filterTest() { + FilterOperator plan = new FilterOperator(new TestScan(), + dsl.equal(typeEnv(), DSL.ref("response"), DSL.literal(404))); + List result = execute(plan); + assertEquals(1, result.size()); + assertThat(result, containsInAnyOrder(ExprValueUtils + .tupleValue(ImmutableMap + .of("ip", "209.160.24.63", "action", "GET", "response", 404, "referer", + "www.amazon.com")))); + } } \ No newline at end of file diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/PhysicalPlanNodeVisitorTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/PhysicalPlanNodeVisitorTest.java index 01dcd6b788..59f0ff4906 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/PhysicalPlanNodeVisitorTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/PhysicalPlanNodeVisitorTest.java @@ -15,6 +15,9 @@ package com.amazon.opendistroforelasticsearch.sql.planner.physical; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + import com.amazon.opendistroforelasticsearch.sql.ast.tree.Sort.SortOption; import com.amazon.opendistroforelasticsearch.sql.expression.DSL; import com.amazon.opendistroforelasticsearch.sql.expression.ReferenceExpression; @@ -27,14 +30,15 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNull; - -/** Todo, testing purpose, delete later. */ +/** + * Todo, testing purpose, delete later. + */ @ExtendWith(MockitoExtension.class) class PhysicalPlanNodeVisitorTest extends PhysicalPlanTestBase { - @Mock PhysicalPlan plan; - @Mock ReferenceExpression ref; + @Mock + PhysicalPlan plan; + @Mock + ReferenceExpression ref; @Test public void print_physical_plan() { @@ -67,26 +71,40 @@ public void test_PhysicalPlanVisitor_should_return_null() { PhysicalPlan filter = PhysicalPlanDSL.filter( new TestScan(), dsl.equal(typeEnv(), DSL.ref("response"), DSL.literal(10))); + assertNull(filter.accept(new PhysicalPlanNodeVisitor() { + }, null)); + PhysicalPlan aggregation = PhysicalPlanDSL.agg( filter, ImmutableList.of(dsl.avg(typeEnv(), DSL.ref("response"))), ImmutableList.of()); + assertNull(aggregation.accept(new PhysicalPlanNodeVisitor() { + }, null)); + PhysicalPlan rename = PhysicalPlanDSL.rename( aggregation, ImmutableMap.of(DSL.ref("ivalue"), DSL.ref("avg(response)"))); + assertNull(rename.accept(new PhysicalPlanNodeVisitor() { + }, null)); + PhysicalPlan project = PhysicalPlanDSL.project(plan, ref); + assertNull(project.accept(new PhysicalPlanNodeVisitor() { + }, null)); + PhysicalPlan remove = PhysicalPlanDSL.remove(plan, ref); + assertNull(remove.accept(new PhysicalPlanNodeVisitor() { + }, null)); + PhysicalPlan eval = PhysicalPlanDSL.eval(plan, Pair.of(ref, ref)); + assertNull(eval.accept(new PhysicalPlanNodeVisitor() { + }, null)); + PhysicalPlan sort = PhysicalPlanDSL.sort(plan, 100, Pair.of(SortOption.PPL_ASC, ref)); - PhysicalPlan dedupe = PhysicalPlanDSL.dedupe(plan, ref); + assertNull(sort.accept(new PhysicalPlanNodeVisitor() { + }, null)); - assertNull(filter.accept(new PhysicalPlanNodeVisitor() {}, null)); - assertNull(aggregation.accept(new PhysicalPlanNodeVisitor() {}, null)); - assertNull(rename.accept(new PhysicalPlanNodeVisitor() {}, null)); - assertNull(project.accept(new PhysicalPlanNodeVisitor() {}, null)); - assertNull(remove.accept(new PhysicalPlanNodeVisitor() {}, null)); - assertNull(eval.accept(new PhysicalPlanNodeVisitor() {}, null)); - assertNull(sort.accept(new PhysicalPlanNodeVisitor() {}, null)); - assertNull(dedupe.accept(new PhysicalPlanNodeVisitor() {}, null)); + PhysicalPlan dedupe = PhysicalPlanDSL.dedupe(plan, ref); + assertNull(dedupe.accept(new PhysicalPlanNodeVisitor() { + }, null)); } public static class PhysicalPlanPrinter extends PhysicalPlanNodeVisitor { diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/PhysicalPlanTestBase.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/PhysicalPlanTestBase.java index a4a89f8897..33be16490f 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/PhysicalPlanTestBase.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/PhysicalPlanTestBase.java @@ -40,72 +40,81 @@ @ExtendWith(SpringExtension.class) @ContextConfiguration(classes = {ExpressionConfig.class}) public class PhysicalPlanTestBase { - @Autowired - protected DSL dsl; + @Autowired + protected DSL dsl; - private static final List inputs = new ImmutableList.Builder() - .add(ExprValueUtils.tupleValue(ImmutableMap.of("ip", "209.160.24.63", "action", "GET", "response", 200, "referer", "www.amazon.com"))) - .add(ExprValueUtils.tupleValue(ImmutableMap.of("ip", "209.160.24.63", "action", "GET", "response", 404, "referer", "www.amazon.com"))) - .add(ExprValueUtils.tupleValue(ImmutableMap.of("ip", "112.111.162.4", "action", "GET", "response", 200, "referer", "www.amazon.com"))) - .add(ExprValueUtils.tupleValue(ImmutableMap.of("ip", "74.125.19.106", "action", "POST", "response", 200, "referer", "www.google.com"))) - .add(ExprValueUtils.tupleValue(ImmutableMap.of("ip", "74.125.19.106", "action", "POST", "response", 500))) - .build(); + private static final List inputs = new ImmutableList.Builder() + .add(ExprValueUtils.tupleValue(ImmutableMap + .of("ip", "209.160.24.63", "action", "GET", "response", 200, "referer", + "www.amazon.com"))) + .add(ExprValueUtils.tupleValue(ImmutableMap + .of("ip", "209.160.24.63", "action", "GET", "response", 404, "referer", + "www.amazon.com"))) + .add(ExprValueUtils.tupleValue(ImmutableMap + .of("ip", "112.111.162.4", "action", "GET", "response", 200, "referer", + "www.amazon.com"))) + .add(ExprValueUtils.tupleValue(ImmutableMap + .of("ip", "74.125.19.106", "action", "POST", "response", 200, "referer", + "www.google.com"))) + .add(ExprValueUtils + .tupleValue(ImmutableMap.of("ip", "74.125.19.106", "action", "POST", "response", 500))) + .build(); - private static Map typeMapping = new ImmutableMap.Builder() - .put("ip", ExprType.STRING) - .put("action", ExprType.STRING) - .put("response", ExprType.INTEGER) - .put("referer", ExprType.STRING) - .build(); + private static Map typeMapping = new ImmutableMap.Builder() + .put("ip", ExprType.STRING) + .put("action", ExprType.STRING) + .put("response", ExprType.INTEGER) + .put("referer", ExprType.STRING) + .build(); - @Bean - protected Environment typeEnv() { - return var -> { - if (var instanceof ReferenceExpression) { - ReferenceExpression refExpr = (ReferenceExpression) var; - if (typeMapping.containsKey(refExpr.getAttr())) { - return typeMapping.get(refExpr.getAttr()); - } - } - throw new ExpressionEvaluationException("type resolved failed"); - }; - } - - protected List execute(PhysicalPlan plan) { - ImmutableList.Builder builder = new ImmutableList.Builder<>(); - plan.open(); - while (plan.hasNext()) { - builder.add(plan.next()); + @Bean + protected Environment typeEnv() { + return var -> { + if (var instanceof ReferenceExpression) { + ReferenceExpression refExpr = (ReferenceExpression) var; + if (typeMapping.containsKey(refExpr.getAttr())) { + return typeMapping.get(refExpr.getAttr()); } - plan.close(); - return builder.build(); + } + throw new ExpressionEvaluationException("type resolved failed"); + }; + } + + protected List execute(PhysicalPlan plan) { + ImmutableList.Builder builder = new ImmutableList.Builder<>(); + plan.open(); + while (plan.hasNext()) { + builder.add(plan.next()); } + plan.close(); + return builder.build(); + } - protected static class TestScan extends PhysicalPlan { - private final Iterator iterator; + protected static class TestScan extends PhysicalPlan { + private final Iterator iterator; - public TestScan() { - iterator = inputs.iterator(); - } + public TestScan() { + iterator = inputs.iterator(); + } - @Override - public R accept(PhysicalPlanNodeVisitor visitor, C context) { - return null; - } + @Override + public R accept(PhysicalPlanNodeVisitor visitor, C context) { + return null; + } - @Override - public List getChild() { - return ImmutableList.of(); - } + @Override + public List getChild() { + return ImmutableList.of(); + } - @Override - public boolean hasNext() { - return iterator.hasNext(); - } + @Override + public boolean hasNext() { + return iterator.hasNext(); + } - @Override - public ExprValue next() { - return iterator.next(); - } + @Override + public ExprValue next() { + return iterator.next(); } + } } diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/ProjectOperatorTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/ProjectOperatorTest.java index ba961fd89d..a3526459e2 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/ProjectOperatorTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/ProjectOperatorTest.java @@ -35,7 +35,8 @@ @ExtendWith(MockitoExtension.class) class ProjectOperatorTest extends PhysicalPlanTestBase { - @Mock private PhysicalPlan inputPlan; + @Mock + private PhysicalPlan inputPlan; @Test public void project_one_field() { diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/RemoveOperatorTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/RemoveOperatorTest.java index 9a706c4091..1eea059fff 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/RemoveOperatorTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/RemoveOperatorTest.java @@ -34,7 +34,8 @@ @ExtendWith(MockitoExtension.class) class RemoveOperatorTest extends PhysicalPlanTestBase { - @Mock private PhysicalPlan inputPlan; + @Mock + private PhysicalPlan inputPlan; @Test public void remove_one_field() { diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/RenameOperatorTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/RenameOperatorTest.java index ff50d3c9a4..637af9ed3e 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/RenameOperatorTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/RenameOperatorTest.java @@ -33,35 +33,35 @@ @ExtendWith(MockitoExtension.class) public class RenameOperatorTest extends PhysicalPlanTestBase { - @Mock - private PhysicalPlan inputPlan; + @Mock + private PhysicalPlan inputPlan; - @Test - public void avg_aggregation_rename() { - PhysicalPlan plan = new RenameOperator( - new AggregationOperator(new TestScan(), - Collections.singletonList(dsl.avg(typeEnv(), DSL.ref("response"))), - Collections.singletonList(DSL.ref("action"))), - ImmutableMap.of(DSL.ref("avg(response)"), DSL.ref("avg")) - ); - List result = execute(plan); - assertEquals(2, result.size()); - assertThat(result, containsInAnyOrder( - ExprValueUtils.tupleValue(ImmutableMap.of("action", "GET", "avg", 268d)), - ExprValueUtils.tupleValue(ImmutableMap.of("action", "POST", "avg", 350d)) - )); - } + @Test + public void avg_aggregation_rename() { + PhysicalPlan plan = new RenameOperator( + new AggregationOperator(new TestScan(), + Collections.singletonList(dsl.avg(typeEnv(), DSL.ref("response"))), + Collections.singletonList(DSL.ref("action"))), + ImmutableMap.of(DSL.ref("avg(response)"), DSL.ref("avg")) + ); + List result = execute(plan); + assertEquals(2, result.size()); + assertThat(result, containsInAnyOrder( + ExprValueUtils.tupleValue(ImmutableMap.of("action", "GET", "avg", 268d)), + ExprValueUtils.tupleValue(ImmutableMap.of("action", "POST", "avg", 350d)) + )); + } - @Test - public void rename_int_value() { - when(inputPlan.hasNext()).thenReturn(true, false); - when(inputPlan.next()).thenReturn(ExprValueUtils.integerValue(1)); - PhysicalPlan plan = new RenameOperator( - inputPlan, - ImmutableMap.of(DSL.ref("avg(response)"), DSL.ref("avg")) - ); - List result = execute(plan); - assertEquals(1, result.size()); - assertThat(result, containsInAnyOrder(ExprValueUtils.integerValue(1))); - } + @Test + public void rename_int_value() { + when(inputPlan.hasNext()).thenReturn(true, false); + when(inputPlan.next()).thenReturn(ExprValueUtils.integerValue(1)); + PhysicalPlan plan = new RenameOperator( + inputPlan, + ImmutableMap.of(DSL.ref("avg(response)"), DSL.ref("avg")) + ); + List result = execute(plan); + assertEquals(1, result.size()); + assertThat(result, containsInAnyOrder(ExprValueUtils.integerValue(1))); + } } diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/SortOperatorTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/SortOperatorTest.java index d046fe94a1..12550c123c 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/SortOperatorTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/planner/physical/SortOperatorTest.java @@ -35,13 +35,14 @@ @ExtendWith(MockitoExtension.class) class SortOperatorTest extends PhysicalPlanTestBase { - @Mock private PhysicalPlan inputPlan; + @Mock + private PhysicalPlan inputPlan; /** * construct the map which contain null value, because {@link ImmutableMap} doesn't support null * value. */ - private Map NULL_MAP = + private static final Map NULL_MAP = new HashMap() { { put("size", 399); diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/storage/TableScanOperatorTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/storage/TableScanOperatorTest.java index 918a2ff2cc..25869deee9 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/storage/TableScanOperatorTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/storage/TableScanOperatorTest.java @@ -16,47 +16,47 @@ package com.amazon.opendistroforelasticsearch.sql.storage; +import static org.junit.jupiter.api.Assertions.assertTrue; + import com.amazon.opendistroforelasticsearch.sql.data.model.ExprValue; import com.amazon.opendistroforelasticsearch.sql.planner.physical.PhysicalPlan; import com.amazon.opendistroforelasticsearch.sql.planner.physical.PhysicalPlanNodeVisitor; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertTrue; - class TableScanOperatorTest { - private final TableScanOperator tableScan = new TableScanOperator() { - @Override - public boolean hasNext() { - return false; - } - - @Override - public ExprValue next() { - return null; - } - }; - - @Test - public void accept() { - Boolean isVisited = tableScan.accept(new PhysicalPlanNodeVisitor() { - @Override - protected Boolean visitNode(PhysicalPlan node, Object context) { - return (node instanceof TableScanOperator); - } - - @Override - public Boolean visitTableScan(TableScanOperator node, Object context) { - return super.visitTableScan(node, context); - } - }, null); - - assertTrue(isVisited); + private final TableScanOperator tableScan = new TableScanOperator() { + @Override + public boolean hasNext() { + return false; } - @Test - public void getChild() { - assertTrue(tableScan.getChild().isEmpty()); + @Override + public ExprValue next() { + return null; } + }; + + @Test + public void accept() { + Boolean isVisited = tableScan.accept(new PhysicalPlanNodeVisitor() { + @Override + protected Boolean visitNode(PhysicalPlan node, Object context) { + return (node instanceof TableScanOperator); + } + + @Override + public Boolean visitTableScan(TableScanOperator node, Object context) { + return super.visitTableScan(node, context); + } + }, null); + + assertTrue(isVisited); + } + + @Test + public void getChild() { + assertTrue(tableScan.getChild().isEmpty()); + } } \ No newline at end of file diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/storage/bindingtuple/BindingTupleTest.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/storage/bindingtuple/BindingTupleTest.java index 1f8bb9c741..2820608da4 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/storage/bindingtuple/BindingTupleTest.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/storage/bindingtuple/BindingTupleTest.java @@ -25,28 +25,31 @@ import org.junit.jupiter.api.Test; class BindingTupleTest { - @Test - public void resolve_ref_expression() { - BindingTuple bindingTuple = ExprValueUtils.tupleValue(ImmutableMap.of("ip", "209.160.24.63")).bindingTuples(); - assertEquals(ExprValueUtils.stringValue("209.160.24.63"), bindingTuple.resolve(DSL.ref("ip"))); - } + @Test + public void resolve_ref_expression() { + BindingTuple bindingTuple = + ExprValueUtils.tupleValue(ImmutableMap.of("ip", "209.160.24.63")).bindingTuples(); + assertEquals(ExprValueUtils.stringValue("209.160.24.63"), bindingTuple.resolve(DSL.ref("ip"))); + } - @Test - public void resolve_missing_expression() { - BindingTuple bindingTuple = ExprValueUtils.tupleValue(ImmutableMap.of("ip", "209.160.24.63")).bindingTuples(); - assertEquals(ExprValueUtils.LITERAL_MISSING, bindingTuple.resolve(DSL.ref("ip_missing"))); - } + @Test + public void resolve_missing_expression() { + BindingTuple bindingTuple = + ExprValueUtils.tupleValue(ImmutableMap.of("ip", "209.160.24.63")).bindingTuples(); + assertEquals(ExprValueUtils.LITERAL_MISSING, bindingTuple.resolve(DSL.ref("ip_missing"))); + } - @Test - public void resolve_from_empty_tuple() { - assertEquals(ExprValueUtils.LITERAL_MISSING, BindingTuple.EMPTY.resolve(DSL.ref("ip_missing"))); - } + @Test + public void resolve_from_empty_tuple() { + assertEquals(ExprValueUtils.LITERAL_MISSING, BindingTuple.EMPTY.resolve(DSL.ref("ip_missing"))); + } - @Test - public void resolve_literal_expression_throw_exception() { - BindingTuple bindingTuple = ExprValueUtils.tupleValue(ImmutableMap.of("ip", "209.160.24.63")).bindingTuples(); - ExpressionEvaluationException exception = assertThrows - (ExpressionEvaluationException.class, () -> bindingTuple.resolve(DSL.literal(1))); - assertEquals("can resolve expression: 1", exception.getMessage()); - } + @Test + public void resolve_literal_expression_throw_exception() { + BindingTuple bindingTuple = + ExprValueUtils.tupleValue(ImmutableMap.of("ip", "209.160.24.63")).bindingTuples(); + ExpressionEvaluationException exception = assertThrows(ExpressionEvaluationException.class, + () -> bindingTuple.resolve(DSL.literal(1))); + assertEquals("can resolve expression: 1", exception.getMessage()); + } } \ No newline at end of file diff --git a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/utils/MatcherUtils.java b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/utils/MatcherUtils.java index 6fa68c2547..7b2a8d8766 100644 --- a/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/utils/MatcherUtils.java +++ b/core/src/test/java/com/amazon/opendistroforelasticsearch/sql/utils/MatcherUtils.java @@ -15,67 +15,46 @@ package com.amazon.opendistroforelasticsearch.sql.utils; -import com.amazon.opendistroforelasticsearch.sql.data.model.ExprTupleValue; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprType; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprValue; -import com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils; -import com.amazon.opendistroforelasticsearch.sql.expression.DSL; import org.hamcrest.Description; import org.hamcrest.TypeSafeMatcher; -import java.util.Map; - +/** + * Matcher Utils. + */ public class MatcherUtils { - public static TypeSafeMatcher tuple(Map map) { - return new TypeSafeMatcher() { - @Override - public void describeTo(Description description) { - description.appendText(map.toString()); - } - - @Override - protected boolean matchesSafely(ExprValue value) { - if (ExprType.STRUCT == value.type()) { - ExprTupleValue tupleValue = (ExprTupleValue) value; - for (Map.Entry entry : map.entrySet()) { - if (!tupleValue.bindingTuples().resolve(DSL.ref(entry.getKey())) - .equals(ExprValueUtils.fromObjectValue(entry.getValue()))) { - return false; - } - } - return true; - } else { - return false; - } - } - }; - } - - public static TypeSafeMatcher hasType(ExprType type) { - return new TypeSafeMatcher() { - @Override - public void describeTo(Description description) { - description.appendText(type.toString()); - } - - @Override - protected boolean matchesSafely(ExprValue value) { - return type == value.type(); - } - }; - } - - public static TypeSafeMatcher hasValue(Object object) { - return new TypeSafeMatcher() { - @Override - public void describeTo(Description description) { - description.appendText(object.toString()); - } - - @Override - protected boolean matchesSafely(ExprValue value) { - return object.equals(value.value()); - } - }; - } + /** + * Check {@link ExprValue} type equal to {@link ExprType}. + */ + public static TypeSafeMatcher hasType(ExprType type) { + return new TypeSafeMatcher() { + @Override + public void describeTo(Description description) { + description.appendText(type.toString()); + } + + @Override + protected boolean matchesSafely(ExprValue value) { + return type == value.type(); + } + }; + } + + /** + * Check {@link ExprValue} value equal to {@link Object}. + */ + public static TypeSafeMatcher hasValue(Object object) { + return new TypeSafeMatcher() { + @Override + public void describeTo(Description description) { + description.appendText(object.toString()); + } + + @Override + protected boolean matchesSafely(ExprValue value) { + return object.equals(value.value()); + } + }; + } } diff --git a/elasticsearch/build.gradle b/elasticsearch/build.gradle index 6a2688f598..f46fb69390 100644 --- a/elasticsearch/build.gradle +++ b/elasticsearch/build.gradle @@ -11,7 +11,7 @@ repositories { dependencies { compile project(':core') compile group: 'org.elasticsearch', name: 'elasticsearch', version: "${es_version}" - compile group: 'org.elasticsearch.client', name: 'elasticsearch-rest-high-level-client', version:"${es_version}" + compile group: 'org.elasticsearch.client', name: 'elasticsearch-rest-high-level-client', version: "${es_version}" testImplementation('org.junit.jupiter:junit-jupiter:5.6.2') testCompile group: 'org.hamcrest', name: 'hamcrest-library', version: '2.1' @@ -46,7 +46,7 @@ jacocoTestCoverageVerification { rule { element = 'CLASS' excludes = [ - 'com.amazon.opendistroforelasticsearch.sql.elasticsearch.security.SecurityAccess' + 'com.amazon.opendistroforelasticsearch.sql.elasticsearch.security.SecurityAccess' ] limit { minimum = 1.0 diff --git a/elasticsearch/src/main/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/client/ElasticsearchClient.java b/elasticsearch/src/main/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/client/ElasticsearchClient.java index 2b1c06fc18..13a82ac751 100644 --- a/elasticsearch/src/main/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/client/ElasticsearchClient.java +++ b/elasticsearch/src/main/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/client/ElasticsearchClient.java @@ -19,39 +19,41 @@ import com.amazon.opendistroforelasticsearch.sql.elasticsearch.mapping.IndexMapping; import com.amazon.opendistroforelasticsearch.sql.elasticsearch.request.ElasticsearchRequest; import com.amazon.opendistroforelasticsearch.sql.elasticsearch.response.ElasticsearchResponse; - import java.util.Map; /** - * Elasticsearch client abstraction to wrap different Elasticsearch client implementation. - * For example, implementation by node client for ES plugin or by REST client for standalone mode. + * Elasticsearch client abstraction to wrap different Elasticsearch client implementation. For + * example, implementation by node client for ES plugin or by REST client for standalone mode. */ public interface ElasticsearchClient { - /** - * Fetch index mapping(s) according to index expression given - * @param indexExpression index expression - * @return index mapping(s) from index name to its mapping - */ - Map getIndexMappings(String indexExpression); - - /** - * Perform search query in the search request. - * @param request search request - * @return search response - */ - ElasticsearchResponse search(ElasticsearchRequest request); - - /** - * Clean up resources related to the search request, for example scroll context. - * @param request search request - */ - void cleanup(ElasticsearchRequest request); - - /** - * Schedule a task to run. - * @param task task - */ - void schedule(Runnable task); - + /** + * Fetch index mapping(s) according to index expression given. + * + * @param indexExpression index expression + * @return index mapping(s) from index name to its mapping + */ + Map getIndexMappings(String indexExpression); + + /** + * Perform search query in the search request. + * + * @param request search request + * @return search response + */ + ElasticsearchResponse search(ElasticsearchRequest request); + + /** + * Clean up resources related to the search request, for example scroll context. + * + * @param request search request + */ + void cleanup(ElasticsearchRequest request); + + /** + * Schedule a task to run. + * + * @param task task + */ + void schedule(Runnable task); } diff --git a/elasticsearch/src/main/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/client/ElasticsearchNodeClient.java b/elasticsearch/src/main/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/client/ElasticsearchNodeClient.java index 5abfb9f836..2e58fa8809 100644 --- a/elasticsearch/src/main/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/client/ElasticsearchNodeClient.java +++ b/elasticsearch/src/main/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/client/ElasticsearchNodeClient.java @@ -21,6 +21,11 @@ import com.amazon.opendistroforelasticsearch.sql.elasticsearch.response.ElasticsearchResponse; import com.carrotsearch.hppc.cursors.ObjectObjectCursor; import com.google.common.collect.ImmutableMap; +import java.io.IOException; +import java.util.Collections; +import java.util.Map; +import java.util.function.Function; +import java.util.function.Predicate; import lombok.RequiredArgsConstructor; import org.apache.logging.log4j.ThreadContext; import org.elasticsearch.action.search.SearchResponse; @@ -34,127 +39,111 @@ import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.threadpool.ThreadPool; -import java.io.IOException; -import java.util.Collections; -import java.util.Map; -import java.util.function.Function; -import java.util.function.Predicate; - -/** - * Elasticsearch connection by node client. - */ +/** Elasticsearch connection by node client. */ @RequiredArgsConstructor public class ElasticsearchNodeClient implements ElasticsearchClient { - /** - * Default types and field filter to match all - */ - public static final String[] ALL_TYPES = new String[0]; - public static final Function> ALL_FIELDS = (anyIndex -> (anyField -> true)); - - /** - * Current cluster state on local node - */ - private final ClusterService clusterService; - - /** - * Node client provided by Elasticsearch container. - */ - private final NodeClient client; - - /** - * Index name expression resolver to get concrete index name - */ - private final IndexNameExpressionResolver resolver = new IndexNameExpressionResolver(); - - - /** - * Get field mappings of index by an index expression. Majority is copied from legacy LocalClusterState. - * - * For simplicity, removed type (deprecated) and field filter in argument list. - * Also removed mapping cache, cluster state listener (mainly for performance and debugging). - * - * @param indexExpression index name expression - * @return index mapping(s) in our class to isolate Elasticsearch API. - * IndexNotFoundException is thrown if no index matched. - */ - @Override - public Map getIndexMappings(String indexExpression) { - try { - ClusterState state = clusterService.state(); - String[] concreteIndices = resolveIndexExpression(state, new String[]{ indexExpression }); - - return populateIndexMappings(state.metaData().findMappings(concreteIndices, ALL_TYPES, ALL_FIELDS)); - } catch (IOException e) { - throw new IllegalStateException( - "Failed to read mapping in cluster state for index pattern [" + indexExpression + "]", e); - } - } - - /** - * TODO: Scroll doesn't work for aggregation. Support aggregation later. - */ - @Override - public ElasticsearchResponse search(ElasticsearchRequest request) { - SearchResponse esResponse; - if (request.isScrollStarted()) { - esResponse = client.searchScroll(request.scrollRequest()).actionGet(); - } else { - esResponse = client.search(request.searchRequest()).actionGet(); - } - request.setScrollId(esResponse.getScrollId()); - - return new ElasticsearchResponse(esResponse); - } - - @Override - public void cleanup(ElasticsearchRequest request) { - if (request.isScrollStarted()) { - client.prepareClearScroll(). - addScrollId(request.getScrollId()). - get(); - request.reset(); - } + /** Default types and field filter to match all. */ + public static final String[] ALL_TYPES = new String[0]; + + public static final Function> ALL_FIELDS = + (anyIndex -> (anyField -> true)); + + /** Current cluster state on local node. */ + private final ClusterService clusterService; + + /** Node client provided by Elasticsearch container. */ + private final NodeClient client; + + /** Index name expression resolver to get concrete index name. */ + private final IndexNameExpressionResolver resolver = new IndexNameExpressionResolver(); + + /** + * Get field mappings of index by an index expression. Majority is copied from legacy + * LocalClusterState. + * + *

For simplicity, removed type (deprecated) and field filter in argument list. Also removed + * mapping cache, cluster state listener (mainly for performance and debugging). + * + * @param indexExpression index name expression + * @return index mapping(s) in our class to isolate Elasticsearch API. IndexNotFoundException is + * thrown if no index matched. + */ + @Override + public Map getIndexMappings(String indexExpression) { + try { + ClusterState state = clusterService.state(); + String[] concreteIndices = resolveIndexExpression(state, new String[] {indexExpression}); + + return populateIndexMappings( + state.metaData().findMappings(concreteIndices, ALL_TYPES, ALL_FIELDS)); + } catch (IOException e) { + throw new IllegalStateException( + "Failed to read mapping in cluster state for index pattern [" + indexExpression + "]", e); } - - @Override - public void schedule(Runnable task) { - ThreadPool threadPool = client.threadPool(); - threadPool.schedule( - threadPool.preserveContext(withCurrentContext(task)), - new TimeValue(0), - "search" //TODO: use search worker pool for now - ); - } - - private String[] resolveIndexExpression(ClusterState state, String[] indices) { - return resolver.concreteIndexNames(state, IndicesOptions.strictExpandOpen(), indices); + } + + /** TODO: Scroll doesn't work for aggregation. Support aggregation later. */ + @Override + public ElasticsearchResponse search(ElasticsearchRequest request) { + SearchResponse esResponse; + if (request.isScrollStarted()) { + esResponse = client.searchScroll(request.scrollRequest()).actionGet(); + } else { + esResponse = client.search(request.searchRequest()).actionGet(); } + request.setScrollId(esResponse.getScrollId()); - private Map populateIndexMappings( - ImmutableOpenMap> indexMappings) { + return new ElasticsearchResponse(esResponse); + } - ImmutableMap.Builder result = ImmutableMap.builder(); - for (ObjectObjectCursor> cursor : indexMappings) { - result.put(cursor.key, populateIndexMapping(cursor.value)); - } - return result.build(); + @Override + public void cleanup(ElasticsearchRequest request) { + if (request.isScrollStarted()) { + client.prepareClearScroll().addScrollId(request.getScrollId()).get(); + request.reset(); } - - private IndexMapping populateIndexMapping(ImmutableOpenMap indexMapping) { - if (indexMapping.isEmpty()) { - return new IndexMapping(Collections.emptyMap()); - } - return new IndexMapping(indexMapping.iterator().next().value); + } + + @Override + public void schedule(Runnable task) { + ThreadPool threadPool = client.threadPool(); + threadPool.schedule( + threadPool.preserveContext(withCurrentContext(task)), + new TimeValue(0), + "search" // TODO: use search worker pool for now + ); + } + + private String[] resolveIndexExpression(ClusterState state, String[] indices) { + return resolver.concreteIndexNames(state, IndicesOptions.strictExpandOpen(), indices); + } + + private Map populateIndexMappings( + ImmutableOpenMap> indexMappings) { + + ImmutableMap.Builder result = ImmutableMap.builder(); + for (ObjectObjectCursor> cursor : + indexMappings) { + result.put(cursor.key, populateIndexMapping(cursor.value)); } + return result.build(); + } - /** Copy from LogUtils */ - private static Runnable withCurrentContext(final Runnable task) { - final Map currentContext = ThreadContext.getImmutableContext(); - return () -> { - ThreadContext.putAll(currentContext); - task.run(); - }; + private IndexMapping populateIndexMapping( + ImmutableOpenMap indexMapping) { + if (indexMapping.isEmpty()) { + return new IndexMapping(Collections.emptyMap()); } - + return new IndexMapping(indexMapping.iterator().next().value); + } + + /** Copy from LogUtils. */ + private static Runnable withCurrentContext(final Runnable task) { + final Map currentContext = ThreadContext.getImmutableContext(); + return () -> { + ThreadContext.putAll(currentContext); + task.run(); + }; + } } diff --git a/elasticsearch/src/main/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/client/ElasticsearchRestClient.java b/elasticsearch/src/main/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/client/ElasticsearchRestClient.java index 2734a51607..ec66dbca75 100644 --- a/elasticsearch/src/main/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/client/ElasticsearchRestClient.java +++ b/elasticsearch/src/main/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/client/ElasticsearchRestClient.java @@ -19,6 +19,9 @@ import com.amazon.opendistroforelasticsearch.sql.elasticsearch.mapping.IndexMapping; import com.amazon.opendistroforelasticsearch.sql.elasticsearch.request.ElasticsearchRequest; import com.amazon.opendistroforelasticsearch.sql.elasticsearch.response.ElasticsearchResponse; +import java.io.IOException; +import java.util.Map; +import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import org.elasticsearch.action.search.ClearScrollRequest; import org.elasticsearch.action.search.SearchResponse; @@ -27,79 +30,67 @@ import org.elasticsearch.client.indices.GetMappingsRequest; import org.elasticsearch.client.indices.GetMappingsResponse; -import java.io.IOException; -import java.util.Map; -import java.util.stream.Collectors; - /** * Elasticsearch REST client to support standalone mode that runs entire engine from remote. * - * TODO: Support for authN and authZ with AWS Sigv4 or security plugin. + *

TODO: Support for authN and authZ with AWS Sigv4 or security plugin. */ @RequiredArgsConstructor public class ElasticsearchRestClient implements ElasticsearchClient { - /** - * Elasticsearch high level REST client - */ - private final RestHighLevelClient client; - + /** Elasticsearch high level REST client. */ + private final RestHighLevelClient client; - @Override - public Map getIndexMappings(String indexExpression) { - GetMappingsRequest request = new GetMappingsRequest().indices(indexExpression); - try { - GetMappingsResponse response = client.indices().getMapping(request, RequestOptions.DEFAULT); - return response.mappings().entrySet().stream(). - collect(Collectors.toMap( - Map.Entry::getKey, - e -> new IndexMapping(e.getValue())) - ); - } catch (IOException e) { - throw new IllegalStateException( - "Failed to get index mappings for " + indexExpression, e); - } + @Override + public Map getIndexMappings(String indexExpression) { + GetMappingsRequest request = new GetMappingsRequest().indices(indexExpression); + try { + GetMappingsResponse response = client.indices().getMapping(request, RequestOptions.DEFAULT); + return response.mappings().entrySet().stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> new IndexMapping(e.getValue()))); + } catch (IOException e) { + throw new IllegalStateException("Failed to get index mappings for " + indexExpression, e); } + } - @Override - public ElasticsearchResponse search(ElasticsearchRequest request) { - try { - SearchResponse esResponse; - if (request.isScrollStarted()) { - esResponse = client.scroll(request.scrollRequest(), RequestOptions.DEFAULT); - } else { - esResponse = client.search(request.searchRequest(), RequestOptions.DEFAULT); - } - request.setScrollId(esResponse.getScrollId()); + @Override + public ElasticsearchResponse search(ElasticsearchRequest request) { + try { + SearchResponse esResponse; + if (request.isScrollStarted()) { + esResponse = client.scroll(request.scrollRequest(), RequestOptions.DEFAULT); + } else { + esResponse = client.search(request.searchRequest(), RequestOptions.DEFAULT); + } + request.setScrollId(esResponse.getScrollId()); - return new ElasticsearchResponse(esResponse); - } catch (IOException e) { - throw new IllegalStateException( - "Failed to perform search operation with request " + request, e); - } + return new ElasticsearchResponse(esResponse); + } catch (IOException e) { + throw new IllegalStateException( + "Failed to perform search operation with request " + request, e); } + } - @Override - public void cleanup(ElasticsearchRequest request) { - try { - if (!request.isScrollStarted()) { - return; - } - - ClearScrollRequest clearRequest = new ClearScrollRequest(); - clearRequest.addScrollId(request.getScrollId()); - client.clearScroll(clearRequest, RequestOptions.DEFAULT); - } catch (IOException e) { - throw new IllegalStateException( - "Failed to clean up resources for search request " + request, e); - } finally { - request.reset(); - } - } + @Override + public void cleanup(ElasticsearchRequest request) { + try { + if (!request.isScrollStarted()) { + return; + } - @Override - public void schedule(Runnable task) { - task.run(); + ClearScrollRequest clearRequest = new ClearScrollRequest(); + clearRequest.addScrollId(request.getScrollId()); + client.clearScroll(clearRequest, RequestOptions.DEFAULT); + } catch (IOException e) { + throw new IllegalStateException( + "Failed to clean up resources for search request " + request, e); + } finally { + request.reset(); } + } + @Override + public void schedule(Runnable task) { + task.run(); + } } diff --git a/elasticsearch/src/main/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/executor/ElasticsearchExecutionEngine.java b/elasticsearch/src/main/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/executor/ElasticsearchExecutionEngine.java index 308b742b3c..21fc2b467a 100644 --- a/elasticsearch/src/main/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/executor/ElasticsearchExecutionEngine.java +++ b/elasticsearch/src/main/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/executor/ElasticsearchExecutionEngine.java @@ -21,38 +21,35 @@ import com.amazon.opendistroforelasticsearch.sql.elasticsearch.client.ElasticsearchClient; import com.amazon.opendistroforelasticsearch.sql.executor.ExecutionEngine; import com.amazon.opendistroforelasticsearch.sql.planner.physical.PhysicalPlan; -import lombok.RequiredArgsConstructor; - import java.util.ArrayList; import java.util.List; +import lombok.RequiredArgsConstructor; -/** - * Elasticsearch execution engine implementation. - */ +/** Elasticsearch execution engine implementation. */ @RequiredArgsConstructor public class ElasticsearchExecutionEngine implements ExecutionEngine { - private final ElasticsearchClient client; + private final ElasticsearchClient client; - @Override - public void execute(PhysicalPlan plan, ResponseListener listener) { - client.schedule(() -> { - try { - List result = new ArrayList<>(); - plan.open(); + @Override + public void execute(PhysicalPlan plan, ResponseListener listener) { + client.schedule( + () -> { + try { + List result = new ArrayList<>(); + plan.open(); - while (plan.hasNext()) { - result.add(plan.next()); - } - - QueryResponse response = new QueryResponse(result); - listener.onResponse(response); - } catch (Exception e) { - listener.onFailure(e); - } finally { - plan.close(); + while (plan.hasNext()) { + result.add(plan.next()); } - }); - } + QueryResponse response = new QueryResponse(result); + listener.onResponse(response); + } catch (Exception e) { + listener.onFailure(e); + } finally { + plan.close(); + } + }); + } } diff --git a/elasticsearch/src/main/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/mapping/IndexMapping.java b/elasticsearch/src/main/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/mapping/IndexMapping.java index d09f6b35c4..1f986919c9 100644 --- a/elasticsearch/src/main/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/mapping/IndexMapping.java +++ b/elasticsearch/src/main/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/mapping/IndexMapping.java @@ -16,16 +16,15 @@ package com.amazon.opendistroforelasticsearch.sql.elasticsearch.mapping; -import com.google.common.collect.ImmutableMap; -import lombok.ToString; -import org.elasticsearch.cluster.metadata.MappingMetaData; +import static java.util.Collections.emptyMap; +import com.google.common.collect.ImmutableMap; import java.util.Map; import java.util.function.BiConsumer; import java.util.function.Function; import java.util.stream.Collectors; - -import static java.util.Collections.emptyMap; +import lombok.ToString; +import org.elasticsearch.cluster.metadata.MappingMetaData; /** * Elasticsearch index mapping. Because there is no specific behavior for different field types, @@ -34,91 +33,81 @@ @ToString public class IndexMapping { - /** - * Field mappings from field name to field type in Elasticsearch date type system. - */ - private final Map fieldMappings; - - public IndexMapping(Map fieldMappings) { - this.fieldMappings = fieldMappings; - } - - public IndexMapping(MappingMetaData metaData) { - this.fieldMappings = flatMappings(metaData.getSourceAsMap()); - } - - /** - * How many fields in the index (after flatten) - * @return field size - */ - public int size() { - return fieldMappings.size(); - } - - /** - * Return field type by its name. - * @param fieldName field name - * @return field type in string. Or null if not exist. - */ - public String getFieldType(String fieldName) { - return fieldMappings.get(fieldName); - } - - /** - * Get all field types and transform raw string type to expected type. - * @param transform transform function to transform field type in string to another type - * @param expected field type class - * @return mapping from field name to field type - */ - public Map getAllFieldTypes(Function transform) { - return fieldMappings.entrySet(). - stream(). - collect(Collectors.toMap( - Map.Entry::getKey, - e -> transform.apply(e.getValue()) - )); - } - - @SuppressWarnings("unchecked") - private Map flatMappings(Map indexMapping) { - ImmutableMap.Builder builder = new ImmutableMap.Builder<>(); - - flatMappings( - ((Map) indexMapping.getOrDefault("properties", emptyMap())), - "", - builder::put - ); - return builder.build(); - } - - @SuppressWarnings("unchecked") - private void flatMappings(Map mappings, - String path, - BiConsumer func) { - mappings.forEach( - (fieldName, mappingObject) -> { - Map mapping = (Map) mappingObject; - String fullFieldName = path.isEmpty() ? fieldName : path + "." + fieldName; - String type = (String) mapping.getOrDefault("type", "object"); - func.accept(fullFieldName, type); - - if (mapping.containsKey("fields")) { // Multi-field - ((Map>) mapping.get("fields")).forEach( - (innerFieldName, innerMapping) -> - func.accept(fullFieldName + "." + innerFieldName, - (String) innerMapping.getOrDefault("type", "object")) - ); - } - - if (mapping.containsKey("properties")) { // Nested field - flatMappings( - (Map) mapping.get("properties"), - fullFieldName, - func - ); - } - } - ); - } - + /** Field mappings from field name to field type in Elasticsearch date type system. */ + private final Map fieldMappings; + + public IndexMapping(Map fieldMappings) { + this.fieldMappings = fieldMappings; + } + + public IndexMapping(MappingMetaData metaData) { + this.fieldMappings = flatMappings(metaData.getSourceAsMap()); + } + + /** + * How many fields in the index (after flatten). + * + * @return field size + */ + public int size() { + return fieldMappings.size(); + } + + /** + * Return field type by its name. + * + * @param fieldName field name + * @return field type in string. Or null if not exist. + */ + public String getFieldType(String fieldName) { + return fieldMappings.get(fieldName); + } + + /** + * Get all field types and transform raw string type to expected type. + * + * @param transform transform function to transform field type in string to another type + * @param expected field type class + * @return mapping from field name to field type + */ + public Map getAllFieldTypes(Function transform) { + return fieldMappings.entrySet().stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> transform.apply(e.getValue()))); + } + + @SuppressWarnings("unchecked") + private Map flatMappings(Map indexMapping) { + ImmutableMap.Builder builder = new ImmutableMap.Builder<>(); + + flatMappings( + ((Map) indexMapping.getOrDefault("properties", emptyMap())), + "", + builder::put); + return builder.build(); + } + + @SuppressWarnings("unchecked") + private void flatMappings( + Map mappings, String path, BiConsumer func) { + mappings.forEach( + (fieldName, mappingObject) -> { + Map mapping = (Map) mappingObject; + String fullFieldName = path.isEmpty() ? fieldName : path + "." + fieldName; + String type = (String) mapping.getOrDefault("type", "object"); + func.accept(fullFieldName, type); + + if (mapping.containsKey("fields")) { // Multi-field + ((Map>) mapping.get("fields")) + .forEach( + (innerFieldName, innerMapping) -> + func.accept( + fullFieldName + "." + innerFieldName, + (String) innerMapping.getOrDefault("type", "object"))); + } + + if (mapping.containsKey("properties")) { // Nested field + flatMappings((Map) mapping.get("properties"), fullFieldName, func); + } + }); + } } diff --git a/elasticsearch/src/main/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/request/ElasticsearchRequest.java b/elasticsearch/src/main/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/request/ElasticsearchRequest.java index f49d2e6e35..7f2a151044 100644 --- a/elasticsearch/src/main/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/request/ElasticsearchRequest.java +++ b/elasticsearch/src/main/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/request/ElasticsearchRequest.java @@ -16,6 +16,7 @@ package com.amazon.opendistroforelasticsearch.sql.elasticsearch.request; +import java.util.Objects; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.RequiredArgsConstructor; @@ -26,13 +27,11 @@ import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.search.builder.SearchSourceBuilder; -import java.util.Objects; - /** * Elasticsearch search request. This has to be stateful because it needs to: * - * 1) Accumulate search source builder when visiting logical plan to push down operation - * 2) Maintain scroll ID between calls to client search method + *

1) Accumulate search source builder when visiting logical plan to push down operation 2) + * Maintain scroll ID between calls to client search method */ @EqualsAndHashCode @RequiredArgsConstructor @@ -40,62 +39,57 @@ @ToString public class ElasticsearchRequest { - /** - * Default scroll context timeout in minutes - */ - public static final TimeValue DEFAULT_SCROLL_TIMEOUT = TimeValue.timeValueMinutes(1L); - - /** - * Index name. - */ - private final String indexName; + /** Default scroll context timeout in minutes. */ + public static final TimeValue DEFAULT_SCROLL_TIMEOUT = TimeValue.timeValueMinutes(1L); - /** - * Scroll id which is set after first request issued. - * Because ElasticsearchClient is shared by multi-thread so this state has to be maintained here. - */ - @Setter - private String scrollId; + /** Index name. */ + private final String indexName; - /** - * Search request source builder. - */ - private final SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); + /** + * Scroll id which is set after first request issued. Because ElasticsearchClient is shared by + * multi-thread so this state has to be maintained here. + */ + @Setter private String scrollId; - /** - * Generate Elasticsearch search request. - * @return search request - */ - public SearchRequest searchRequest() { - return new SearchRequest().indices(indexName). - scroll(DEFAULT_SCROLL_TIMEOUT). - source(sourceBuilder); - } + /** Search request source builder. */ + private final SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); - /** - * Is scroll started which means pages after first is being requested - * @return true if scroll started - */ - public boolean isScrollStarted() { - return (scrollId != null); - } + /** + * Generate Elasticsearch search request. + * + * @return search request + */ + public SearchRequest searchRequest() { + return new SearchRequest() + .indices(indexName) + .scroll(DEFAULT_SCROLL_TIMEOUT) + .source(sourceBuilder); + } - /** - * Generate Elasticsearch scroll request by scroll id maintained. - * @return scroll request - */ - public SearchScrollRequest scrollRequest() { - Objects.requireNonNull(scrollId, "Scroll id cannot be null"); - return new SearchScrollRequest().scroll(DEFAULT_SCROLL_TIMEOUT). - scrollId(scrollId); - } + /** + * Is scroll started which means pages after first is being requested. + * + * @return true if scroll started + */ + public boolean isScrollStarted() { + return (scrollId != null); + } - /** - * Reset internal state in case any stale data. However, ideally the same instance - * is not supposed to be reused across different physical plan. - */ - public void reset() { - scrollId = null; - } + /** + * Generate Elasticsearch scroll request by scroll id maintained. + * + * @return scroll request + */ + public SearchScrollRequest scrollRequest() { + Objects.requireNonNull(scrollId, "Scroll id cannot be null"); + return new SearchScrollRequest().scroll(DEFAULT_SCROLL_TIMEOUT).scrollId(scrollId); + } + /** + * Reset internal state in case any stale data. However, ideally the same instance is not supposed + * to be reused across different physical plan. + */ + public void reset() { + scrollId = null; + } } diff --git a/elasticsearch/src/main/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/response/ElasticsearchResponse.java b/elasticsearch/src/main/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/response/ElasticsearchResponse.java index ae94eede4c..e3382799ff 100644 --- a/elasticsearch/src/main/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/response/ElasticsearchResponse.java +++ b/elasticsearch/src/main/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/response/ElasticsearchResponse.java @@ -16,47 +16,42 @@ package com.amazon.opendistroforelasticsearch.sql.elasticsearch.response; +import java.util.Iterator; import lombok.EqualsAndHashCode; import lombok.ToString; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.SearchHits; -import java.util.Iterator; - -/** - * Elasticsearch search response - */ +/** Elasticsearch search response. */ @EqualsAndHashCode @ToString public class ElasticsearchResponse implements Iterable { - /** - * Search query result (non-aggregation) - */ - private final SearchHits hits; - - - public ElasticsearchResponse(SearchResponse esResponse) { - this.hits = esResponse.getHits(); //TODO: aggregation result is separate and not in SearchHit[] - } - - /** - * Is response empty. As ES doc says, "Each call to the scroll API returns the next batch of results - * until there are no more results left to return, ie the hits array is empty." - * @return true for empty - */ - public boolean isEmpty() { - return (hits.getHits() == null) || (hits.getHits().length == 0); - } - - /** - * Make response iterable without need to return internal data structure explicitly. - * @return search hit iterator - */ - @Override - public Iterator iterator() { - return hits.iterator(); - } - + /** Search query result (non-aggregation). */ + private final SearchHits hits; + + public ElasticsearchResponse(SearchResponse esResponse) { + this.hits = esResponse.getHits(); // TODO: aggregation result is separate and not in SearchHit[] + } + + /** + * Is response empty. As ES doc says, "Each call to the scroll API returns the next batch of + * results until there are no more results left to return, ie the hits array is empty." + * + * @return true for empty + */ + public boolean isEmpty() { + return (hits.getHits() == null) || (hits.getHits().length == 0); + } + + /** + * Make response iterable without need to return internal data structure explicitly. + * + * @return search hit iterator + */ + @Override + public Iterator iterator() { + return hits.iterator(); + } } diff --git a/elasticsearch/src/main/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/security/SecurityAccess.java b/elasticsearch/src/main/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/security/SecurityAccess.java index f1c7d5e8dc..f42d100393 100644 --- a/elasticsearch/src/main/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/security/SecurityAccess.java +++ b/elasticsearch/src/main/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/security/SecurityAccess.java @@ -15,24 +15,28 @@ package com.amazon.opendistroforelasticsearch.sql.elasticsearch.security; -import org.elasticsearch.SpecialPermission; - import java.io.IOException; import java.security.AccessController; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; +import org.elasticsearch.SpecialPermission; /** - * Ref: https://www.elastic.co/guide/en/elasticsearch/plugins/current/plugin-authors.html#_java_security_permissions + * Ref: + * https://www.elastic.co/guide/en/elasticsearch/plugins/current/plugin-authors.html#_java_security_permissions */ public class SecurityAccess { - - public static T doPrivileged(final PrivilegedExceptionAction operation) throws IOException { - SpecialPermission.check(); - try { - return AccessController.doPrivileged(operation); - } catch (final PrivilegedActionException e) { - throw (IOException) e.getCause(); - } + + /** + * Execute the operation in privileged mode. + */ + public static T doPrivileged(final PrivilegedExceptionAction operation) + throws IOException { + SpecialPermission.check(); + try { + return AccessController.doPrivileged(operation); + } catch (final PrivilegedActionException e) { + throw (IOException) e.getCause(); } + } } diff --git a/elasticsearch/src/main/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/storage/ElasticsearchIndex.java b/elasticsearch/src/main/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/storage/ElasticsearchIndex.java index 569b78fa79..2faeaf66c0 100644 --- a/elasticsearch/src/main/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/storage/ElasticsearchIndex.java +++ b/elasticsearch/src/main/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/storage/ElasticsearchIndex.java @@ -41,125 +41,125 @@ import com.amazon.opendistroforelasticsearch.sql.planner.physical.SortOperator; import com.amazon.opendistroforelasticsearch.sql.storage.Table; import com.google.common.collect.ImmutableMap; -import lombok.RequiredArgsConstructor; - import java.util.HashMap; import java.util.Map; +import lombok.RequiredArgsConstructor; -/** - * Elasticsearch table (index) implementation. - */ +/** Elasticsearch table (index) implementation. */ @RequiredArgsConstructor public class ElasticsearchIndex implements Table { - /** - * Type mapping from Elasticsearch data type to expression type in our type system in query engine. - * TODO: date, geo, ip etc. - */ - private final static Map ES_TYPE_TO_EXPR_TYPE_MAPPING = - ImmutableMap.builder().put("text", ExprType.STRING). - put("keyword", ExprType.STRING). - put("integer", ExprType.INTEGER). - put("long", ExprType.LONG). - put("float", ExprType.FLOAT). - put("double", ExprType.DOUBLE). - put("boolean", ExprType.BOOLEAN). - put("nested", ExprType.ARRAY). - put("object", ExprType.STRUCT). - build(); - - /** - * Elasticsearch client connection. - */ - private final ElasticsearchClient client; - - /** - * Current Elasticsearch index name. - */ - private final String indexName; - - - /* - * TODO: Assume indexName doesn't have wildcard. - * Need to either handle field name conflicts - * or lazy evaluate when query engine pulls field type. - */ - @Override - public Map getFieldTypes() { - Map fieldTypes = new HashMap<>(); - Map indexMappings = client.getIndexMappings(indexName); - for (IndexMapping indexMapping : indexMappings.values()) { - fieldTypes.putAll(indexMapping.getAllFieldTypes(this::transformESTypeToExprType)); - } - return fieldTypes; + /** + * Type mapping from Elasticsearch data type to expression type in our type system in query + * engine. TODO: date, geo, ip etc. + */ + private static final Map ES_TYPE_TO_EXPR_TYPE_MAPPING = + ImmutableMap.builder() + .put("text", ExprType.STRING) + .put("keyword", ExprType.STRING) + .put("integer", ExprType.INTEGER) + .put("long", ExprType.LONG) + .put("float", ExprType.FLOAT) + .put("double", ExprType.DOUBLE) + .put("boolean", ExprType.BOOLEAN) + .put("nested", ExprType.ARRAY) + .put("object", ExprType.STRUCT) + .build(); + + /** Elasticsearch client connection. */ + private final ElasticsearchClient client; + + /** Current Elasticsearch index name. */ + private final String indexName; + + /* + * TODO: Assume indexName doesn't have wildcard. + * Need to either handle field name conflicts + * or lazy evaluate when query engine pulls field type. + */ + @Override + public Map getFieldTypes() { + Map fieldTypes = new HashMap<>(); + Map indexMappings = client.getIndexMappings(indexName); + for (IndexMapping indexMapping : indexMappings.values()) { + fieldTypes.putAll(indexMapping.getAllFieldTypes(this::transformESTypeToExprType)); } + return fieldTypes; + } + + /** TODO: Push down operations to index scan operator as much as possible in future. */ + @Override + public PhysicalPlan implement(LogicalPlan plan) { + ElasticsearchIndexScan indexScan = new ElasticsearchIndexScan(client, indexName); /** - * TODO: Push down operations to index scan operator as much as possible in future. + * Visit logical plan with index scan as context so logical operators visited, such as + * aggregation, filter, will accumulate (push down) Elasticsearch query and aggregation DSL on + * index scan. */ - @Override - public PhysicalPlan implement(LogicalPlan plan) { - ElasticsearchIndexScan indexScan = new ElasticsearchIndexScan(client, indexName); - - /* - * Visit logical plan with index scan as context so logical operators visited, such as aggregation, filter, - * will accumulate (push down) Elasticsearch query and aggregation DSL on index scan. - */ - return plan.accept(new LogicalPlanNodeVisitor() { - @Override - public PhysicalPlan visitDedupe(LogicalDedupe node, ElasticsearchIndexScan context) { - return new DedupeOperator(visitChild(node, context), node.getDedupeList(), - node.getAllowedDuplication(), node.getKeepEmpty(), node.getConsecutive()); - } - - @Override - public PhysicalPlan visitProject(LogicalProject node, ElasticsearchIndexScan context) { - return new ProjectOperator(visitChild(node, context), node.getProjectList()); - } - - @Override - public PhysicalPlan visitRemove(LogicalRemove node, ElasticsearchIndexScan context) { - return new RemoveOperator(visitChild(node, context), node.getRemoveList()); - } - - @Override - public PhysicalPlan visitEval(LogicalEval node, ElasticsearchIndexScan context) { - return new EvalOperator(visitChild(node, context), node.getExpressions()); - } - - @Override - public PhysicalPlan visitSort(LogicalSort node, ElasticsearchIndexScan context) { - return new SortOperator(visitChild(node, context), node.getCount(), node.getSortList()); - } - - @Override - public PhysicalPlan visitRename(LogicalRename node, ElasticsearchIndexScan context) { - return new RenameOperator(visitChild(node, context), node.getRenameMap()); - } - - @Override - public PhysicalPlan visitAggregation(LogicalAggregation node, ElasticsearchIndexScan context) { - return new AggregationOperator(visitChild(node, context), node.getAggregatorList(), node.getGroupByList()); - } - - @Override - public PhysicalPlan visitFilter(LogicalFilter node, ElasticsearchIndexScan context) { - return new FilterOperator(visitChild(node, context), node.getCondition()); - } - - @Override - public PhysicalPlan visitRelation(LogicalRelation node, ElasticsearchIndexScan context) { - return indexScan; - } - - private PhysicalPlan visitChild(LogicalPlan node, ElasticsearchIndexScan context) { - // Logical operators visited here can only have single child. - return node.getChild().get(0).accept(this, context); - } - }, indexScan); - } - - private ExprType transformESTypeToExprType(String esType) { - return ES_TYPE_TO_EXPR_TYPE_MAPPING.getOrDefault(esType, ExprType.UNKNOWN); - } + return plan.accept( + new LogicalPlanNodeVisitor() { + @Override + public PhysicalPlan visitDedupe(LogicalDedupe node, ElasticsearchIndexScan context) { + return new DedupeOperator( + visitChild(node, context), + node.getDedupeList(), + node.getAllowedDuplication(), + node.getKeepEmpty(), + node.getConsecutive()); + } + + @Override + public PhysicalPlan visitProject(LogicalProject node, ElasticsearchIndexScan context) { + return new ProjectOperator(visitChild(node, context), node.getProjectList()); + } + + @Override + public PhysicalPlan visitRemove(LogicalRemove node, ElasticsearchIndexScan context) { + return new RemoveOperator(visitChild(node, context), node.getRemoveList()); + } + + @Override + public PhysicalPlan visitEval(LogicalEval node, ElasticsearchIndexScan context) { + return new EvalOperator(visitChild(node, context), node.getExpressions()); + } + + @Override + public PhysicalPlan visitSort(LogicalSort node, ElasticsearchIndexScan context) { + return new SortOperator(visitChild(node, context), node.getCount(), node.getSortList()); + } + + @Override + public PhysicalPlan visitRename(LogicalRename node, ElasticsearchIndexScan context) { + return new RenameOperator(visitChild(node, context), node.getRenameMap()); + } + + @Override + public PhysicalPlan visitAggregation( + LogicalAggregation node, ElasticsearchIndexScan context) { + return new AggregationOperator( + visitChild(node, context), node.getAggregatorList(), node.getGroupByList()); + } + + @Override + public PhysicalPlan visitFilter(LogicalFilter node, ElasticsearchIndexScan context) { + return new FilterOperator(visitChild(node, context), node.getCondition()); + } + + @Override + public PhysicalPlan visitRelation(LogicalRelation node, ElasticsearchIndexScan context) { + return indexScan; + } + + private PhysicalPlan visitChild(LogicalPlan node, ElasticsearchIndexScan context) { + // Logical operators visited here can only have single child. + return node.getChild().get(0).accept(this, context); + } + }, + indexScan); + } + + private ExprType transformESTypeToExprType(String esType) { + return ES_TYPE_TO_EXPR_TYPE_MAPPING.getOrDefault(esType, ExprType.UNKNOWN); + } } diff --git a/elasticsearch/src/main/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/storage/ElasticsearchIndexScan.java b/elasticsearch/src/main/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/storage/ElasticsearchIndexScan.java index dcda5914c7..e261782700 100644 --- a/elasticsearch/src/main/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/storage/ElasticsearchIndexScan.java +++ b/elasticsearch/src/main/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/storage/ElasticsearchIndexScan.java @@ -23,73 +23,60 @@ import com.amazon.opendistroforelasticsearch.sql.elasticsearch.response.ElasticsearchResponse; import com.amazon.opendistroforelasticsearch.sql.storage.TableScanOperator; import com.google.common.collect.Iterables; -import lombok.EqualsAndHashCode; -import lombok.ToString; -import org.elasticsearch.search.SearchHit; - import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.elasticsearch.search.SearchHit; -/** - * Elasticsearch index scan operator - */ +/** Elasticsearch index scan operator. */ @EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = false) @ToString(onlyExplicitlyIncluded = true) public class ElasticsearchIndexScan extends TableScanOperator { - /** - * Elasticsearch client. - */ - private final ElasticsearchClient client; - - /** - * Search request. - */ - @EqualsAndHashCode.Include - @ToString.Include - private final ElasticsearchRequest request; + /** Elasticsearch client. */ + private final ElasticsearchClient client; - /** - * Search response for current batch. - */ - private Iterator hits; + /** Search request. */ + @EqualsAndHashCode.Include @ToString.Include private final ElasticsearchRequest request; + /** Search response for current batch. */ + private Iterator hits; - public ElasticsearchIndexScan(ElasticsearchClient client, String indexName) { - this.client = client; - this.request = new ElasticsearchRequest(indexName); - } + public ElasticsearchIndexScan(ElasticsearchClient client, String indexName) { + this.client = client; + this.request = new ElasticsearchRequest(indexName); + } - @Override - public void open() { - super.open(); + @Override + public void open() { + super.open(); - // For now pull all results immediately once open - List responses = new ArrayList<>(); - ElasticsearchResponse response = client.search(request); - while (!response.isEmpty()) { - responses.add(response); - response = client.search(request); - } - hits = Iterables.concat(responses.toArray(new ElasticsearchResponse[0])).iterator(); + // For now pull all results immediately once open + List responses = new ArrayList<>(); + ElasticsearchResponse response = client.search(request); + while (!response.isEmpty()) { + responses.add(response); + response = client.search(request); } + hits = Iterables.concat(responses.toArray(new ElasticsearchResponse[0])).iterator(); + } - @Override - public boolean hasNext() { - return hits.hasNext(); - } + @Override + public boolean hasNext() { + return hits.hasNext(); + } - @Override - public ExprValue next() { - return ExprValueUtils.fromObjectValue(hits.next().getSourceAsMap()); - } - - @Override - public void close() { - super.close(); + @Override + public ExprValue next() { + return ExprValueUtils.fromObjectValue(hits.next().getSourceAsMap()); + } - client.cleanup(request); - } + @Override + public void close() { + super.close(); + client.cleanup(request); + } } diff --git a/elasticsearch/src/main/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/storage/ElasticsearchStorageEngine.java b/elasticsearch/src/main/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/storage/ElasticsearchStorageEngine.java index 4d493d77e5..181d55db9c 100644 --- a/elasticsearch/src/main/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/storage/ElasticsearchStorageEngine.java +++ b/elasticsearch/src/main/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/storage/ElasticsearchStorageEngine.java @@ -21,20 +21,15 @@ import com.amazon.opendistroforelasticsearch.sql.storage.Table; import lombok.RequiredArgsConstructor; -/** - * Elasticsearch storage engine implementation - */ +/** Elasticsearch storage engine implementation. */ @RequiredArgsConstructor public class ElasticsearchStorageEngine implements StorageEngine { - /** - * Elasticsearch client connection - */ - private final ElasticsearchClient client; - - @Override - public Table getTable(String name) { - return new ElasticsearchIndex(client, name); - } + /** Elasticsearch client connection. */ + private final ElasticsearchClient client; + @Override + public Table getTable(String name) { + return new ElasticsearchIndex(client, name); + } } diff --git a/elasticsearch/src/test/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/client/ElasticsearchNodeClientTest.java b/elasticsearch/src/test/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/client/ElasticsearchNodeClientTest.java index 51af3225ba..6a23a9476c 100644 --- a/elasticsearch/src/test/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/client/ElasticsearchNodeClientTest.java +++ b/elasticsearch/src/test/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/client/ElasticsearchNodeClientTest.java @@ -16,12 +16,29 @@ package com.amazon.opendistroforelasticsearch.sql.elasticsearch.client; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Answers.RETURNS_DEEP_STUBS; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import com.amazon.opendistroforelasticsearch.sql.elasticsearch.mapping.IndexMapping; import com.amazon.opendistroforelasticsearch.sql.elasticsearch.request.ElasticsearchRequest; import com.amazon.opendistroforelasticsearch.sql.elasticsearch.response.ElasticsearchResponse; import com.google.common.base.Charsets; import com.google.common.collect.ImmutableSortedMap; import com.google.common.io.Resources; +import java.io.IOException; +import java.net.URL; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; import org.apache.lucene.search.TotalHits; import org.elasticsearch.action.search.ClearScrollRequestBuilder; import org.elasticsearch.action.search.SearchResponse; @@ -48,250 +65,239 @@ import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; -import java.io.IOException; -import java.net.URL; -import java.util.Iterator; -import java.util.Map; -import java.util.concurrent.atomic.AtomicBoolean; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.Answers.RETURNS_DEEP_STUBS; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - @ExtendWith(MockitoExtension.class) class ElasticsearchNodeClientTest { - private static final String TEST_MAPPING_FILE = "mappings/accounts.json"; - - @Mock(answer = RETURNS_DEEP_STUBS) - private NodeClient nodeClient; - - @Test - public void getIndexMappings() throws IOException { - URL url = Resources.getResource(TEST_MAPPING_FILE); - String mappings = Resources.toString(url, Charsets.UTF_8); - String indexName = "test"; - ElasticsearchNodeClient client = mockClient(indexName, mappings); - - Map indexMappings = client.getIndexMappings(indexName); - assertEquals(1, indexMappings.size()); - - IndexMapping indexMapping = indexMappings.values().iterator().next(); - assertEquals(20, indexMapping.size()); - assertEquals("text", indexMapping.getFieldType("address")); - assertEquals("integer", indexMapping.getFieldType("age")); - assertEquals("double", indexMapping.getFieldType("balance")); - assertEquals("keyword", indexMapping.getFieldType("city")); - assertEquals("date", indexMapping.getFieldType("birthday")); - assertEquals("geo_point", indexMapping.getFieldType("location")); - assertEquals("some_new_es_type_outside_type_system", indexMapping.getFieldType("new_field")); - assertEquals("text", indexMapping.getFieldType("field with spaces")); - assertEquals("text", indexMapping.getFieldType("employer")); - assertEquals("keyword", indexMapping.getFieldType("employer.raw")); - assertEquals("nested", indexMapping.getFieldType("projects")); - assertEquals("boolean", indexMapping.getFieldType("projects.active")); - assertEquals("date", indexMapping.getFieldType("projects.release")); - assertEquals("nested", indexMapping.getFieldType("projects.members")); - assertEquals("text", indexMapping.getFieldType("projects.members.name")); - assertEquals("object", indexMapping.getFieldType("manager")); - assertEquals("text", indexMapping.getFieldType("manager.name")); - assertEquals("keyword", indexMapping.getFieldType("manager.name.keyword")); - assertEquals("keyword", indexMapping.getFieldType("manager.address")); - assertEquals("long", indexMapping.getFieldType("manager.salary")); + private static final String TEST_MAPPING_FILE = "mappings/accounts.json"; + + @Mock(answer = RETURNS_DEEP_STUBS) + private NodeClient nodeClient; + + @Test + public void getIndexMappings() throws IOException { + URL url = Resources.getResource(TEST_MAPPING_FILE); + String mappings = Resources.toString(url, Charsets.UTF_8); + String indexName = "test"; + ElasticsearchNodeClient client = mockClient(indexName, mappings); + + Map indexMappings = client.getIndexMappings(indexName); + assertEquals(1, indexMappings.size()); + + IndexMapping indexMapping = indexMappings.values().iterator().next(); + assertEquals(20, indexMapping.size()); + assertEquals("text", indexMapping.getFieldType("address")); + assertEquals("integer", indexMapping.getFieldType("age")); + assertEquals("double", indexMapping.getFieldType("balance")); + assertEquals("keyword", indexMapping.getFieldType("city")); + assertEquals("date", indexMapping.getFieldType("birthday")); + assertEquals("geo_point", indexMapping.getFieldType("location")); + assertEquals("some_new_es_type_outside_type_system", indexMapping.getFieldType("new_field")); + assertEquals("text", indexMapping.getFieldType("field with spaces")); + assertEquals("text", indexMapping.getFieldType("employer")); + assertEquals("keyword", indexMapping.getFieldType("employer.raw")); + assertEquals("nested", indexMapping.getFieldType("projects")); + assertEquals("boolean", indexMapping.getFieldType("projects.active")); + assertEquals("date", indexMapping.getFieldType("projects.release")); + assertEquals("nested", indexMapping.getFieldType("projects.members")); + assertEquals("text", indexMapping.getFieldType("projects.members.name")); + assertEquals("object", indexMapping.getFieldType("manager")); + assertEquals("text", indexMapping.getFieldType("manager.name")); + assertEquals("keyword", indexMapping.getFieldType("manager.name.keyword")); + assertEquals("keyword", indexMapping.getFieldType("manager.address")); + assertEquals("long", indexMapping.getFieldType("manager.salary")); + } + + @Test + public void getIndexMappingsWithEmptyMapping() { + String indexName = "test"; + ElasticsearchNodeClient client = mockClient(indexName, ""); + Map indexMappings = client.getIndexMappings(indexName); + assertEquals(1, indexMappings.size()); + + IndexMapping indexMapping = indexMappings.values().iterator().next(); + assertEquals(0, indexMapping.size()); + } + + @Test + public void getIndexMappingsWithIOException() { + String indexName = "test"; + ClusterService clusterService = mockClusterService(indexName, new IOException()); + ElasticsearchNodeClient client = new ElasticsearchNodeClient(clusterService, nodeClient); + + assertThrows(IllegalStateException.class, () -> client.getIndexMappings(indexName)); + } + + @Test + public void getIndexMappingsWithNonExistIndex() { + ElasticsearchNodeClient client = + new ElasticsearchNodeClient(mockClusterService("test"), nodeClient); + + assertThrows(IndexNotFoundException.class, () -> client.getIndexMappings("non_exist_index")); + } + + /** Jacoco enforce this constant lambda be tested. */ + @Test + public void testAllFieldsPredicate() { + assertTrue(ElasticsearchNodeClient.ALL_FIELDS.apply("any_index").test("any_field")); + } + + @Test + public void search() { + ElasticsearchNodeClient client = + new ElasticsearchNodeClient(mock(ClusterService.class), nodeClient); + + // Mock first scroll request + SearchResponse searchResponse = mock(SearchResponse.class); + when(nodeClient.search(any()).actionGet()).thenReturn(searchResponse); + when(searchResponse.getScrollId()).thenReturn("scroll123"); + when(searchResponse.getHits()) + .thenReturn( + new SearchHits( + new SearchHit[] {new SearchHit(1)}, + new TotalHits(1L, TotalHits.Relation.EQUAL_TO), + 1.0F)); + + // Mock second scroll request followed + SearchResponse scrollResponse = mock(SearchResponse.class); + when(nodeClient.searchScroll(any()).actionGet()).thenReturn(scrollResponse); + when(scrollResponse.getScrollId()).thenReturn("scroll456"); + when(scrollResponse.getHits()).thenReturn(SearchHits.empty()); + + // Verify response for first scroll request + ElasticsearchRequest request = new ElasticsearchRequest("test"); + ElasticsearchResponse response1 = client.search(request); + assertFalse(response1.isEmpty()); + + Iterator hits = response1.iterator(); + assertTrue(hits.hasNext()); + assertEquals(new SearchHit(1), hits.next()); + assertFalse(hits.hasNext()); + + // Verify response for second scroll request + ElasticsearchResponse response2 = client.search(request); + assertTrue(response2.isEmpty()); + } + + @Test + void schedule() { + ThreadPool threadPool = mock(ThreadPool.class); + when(threadPool.preserveContext(any())).then(invocation -> invocation.getArgument(0)); + when(nodeClient.threadPool()).thenReturn(threadPool); + + doAnswer( + invocation -> { + Runnable task = invocation.getArgument(0); + task.run(); + return null; + }) + .when(threadPool) + .schedule(any(), any(), any()); + + ElasticsearchNodeClient client = + new ElasticsearchNodeClient(mock(ClusterService.class), nodeClient); + AtomicBoolean isRun = new AtomicBoolean(false); + client.schedule(() -> isRun.set(true)); + assertTrue(isRun.get()); + } + + @Test + void cleanup() { + ClearScrollRequestBuilder requestBuilder = mock(ClearScrollRequestBuilder.class); + when(nodeClient.prepareClearScroll()).thenReturn(requestBuilder); + when(requestBuilder.addScrollId(any())).thenReturn(requestBuilder); + when(requestBuilder.get()).thenReturn(null); + + ElasticsearchNodeClient client = + new ElasticsearchNodeClient(mock(ClusterService.class), nodeClient); + ElasticsearchRequest request = new ElasticsearchRequest("test"); + request.setScrollId("scroll123"); + client.cleanup(request); + assertFalse(request.isScrollStarted()); + + InOrder inOrder = Mockito.inOrder(nodeClient, requestBuilder); + inOrder.verify(nodeClient).prepareClearScroll(); + inOrder.verify(requestBuilder).addScrollId("scroll123"); + inOrder.verify(requestBuilder).get(); + } + + @Test + void cleanupWithoutScrollId() { + ElasticsearchNodeClient client = + new ElasticsearchNodeClient(mock(ClusterService.class), nodeClient); + + ElasticsearchRequest request = new ElasticsearchRequest("test"); + client.cleanup(request); + verify(nodeClient, never()).prepareClearScroll(); + } + + private ElasticsearchNodeClient mockClient(String indexName, String mappings) { + ClusterService clusterService = mockClusterService(indexName, mappings); + return new ElasticsearchNodeClient(clusterService, nodeClient); + } + + /** Mock getAliasAndIndexLookup() only for index name resolve test. */ + public ClusterService mockClusterService(String indexName) { + ClusterService mockService = mock(ClusterService.class); + ClusterState mockState = mock(ClusterState.class); + MetaData mockMetaData = mock(MetaData.class); + + when(mockService.state()).thenReturn(mockState); + when(mockState.metaData()).thenReturn(mockMetaData); + when(mockMetaData.getAliasAndIndexLookup()) + .thenReturn(ImmutableSortedMap.of(indexName, mock(AliasOrIndex.class))); + return mockService; + } + + public ClusterService mockClusterService(String indexName, String mappings) { + ClusterService mockService = mock(ClusterService.class); + ClusterState mockState = mock(ClusterState.class); + MetaData mockMetaData = mock(MetaData.class); + + when(mockService.state()).thenReturn(mockState); + when(mockState.metaData()).thenReturn(mockMetaData); + try { + ImmutableOpenMap.Builder> builder = + ImmutableOpenMap.builder(); + ImmutableOpenMap metadata; + if (mappings.isEmpty()) { + metadata = ImmutableOpenMap.of(); + } else { + metadata = IndexMetaData.fromXContent(createParser(mappings)).getMappings(); + } + builder.put(indexName, metadata); + when(mockMetaData.findMappings(any(), any(), any())).thenReturn(builder.build()); + + // IndexNameExpressionResolver use this method to check if index exists. If not, + // IndexNotFoundException is thrown. + when(mockMetaData.getAliasAndIndexLookup()) + .thenReturn(ImmutableSortedMap.of(indexName, mock(AliasOrIndex.class))); + } catch (IOException e) { + throw new IllegalStateException("Failed to mock cluster service", e); } - - @Test - public void getIndexMappingsWithEmptyMapping() { - String indexName = "test"; - ElasticsearchNodeClient client = mockClient(indexName, ""); - Map indexMappings = client.getIndexMappings(indexName); - assertEquals(1, indexMappings.size()); - - IndexMapping indexMapping = indexMappings.values().iterator().next(); - assertEquals(0, indexMapping.size()); + return mockService; + } + + public ClusterService mockClusterService(String indexName, Throwable t) { + ClusterService mockService = mock(ClusterService.class); + ClusterState mockState = mock(ClusterState.class); + MetaData mockMetaData = mock(MetaData.class); + + when(mockService.state()).thenReturn(mockState); + when(mockState.metaData()).thenReturn(mockMetaData); + try { + when(mockMetaData.findMappings(any(), any(), any())).thenThrow(t); + when(mockMetaData.getAliasAndIndexLookup()) + .thenReturn(ImmutableSortedMap.of(indexName, mock(AliasOrIndex.class))); + } catch (IOException e) { + throw new IllegalStateException("Failed to mock cluster service", e); } - - @Test - public void getIndexMappingsWithIOException() { - String indexName = "test"; - ClusterService clusterService = mockClusterService(indexName, new IOException()); - ElasticsearchNodeClient client = new ElasticsearchNodeClient(clusterService, nodeClient); - - assertThrows(IllegalStateException.class, () -> client.getIndexMappings(indexName)); - } - - @Test - public void getIndexMappingsWithNonExistIndex() { - ElasticsearchNodeClient client = new ElasticsearchNodeClient(mockClusterService("test"), nodeClient); - - assertThrows(IndexNotFoundException.class, () -> client.getIndexMappings("non_exist_index")); - } - - /** Jacoco enforce this constant lambda be tested */ - @Test - public void testAllFieldsPredicate() { - assertTrue(ElasticsearchNodeClient.ALL_FIELDS.apply("any_index").test("any_field")); - } - - @Test - public void search() { - ElasticsearchNodeClient client = new ElasticsearchNodeClient(mock(ClusterService.class), - nodeClient); - - // Mock first scroll request - SearchResponse searchResponse = mock(SearchResponse.class); - when(nodeClient.search(any()).actionGet()).thenReturn(searchResponse); - when(searchResponse.getScrollId()).thenReturn("scroll123"); - when(searchResponse.getHits()).thenReturn(new SearchHits(new SearchHit[]{new SearchHit(1)}, - new TotalHits(1L, TotalHits.Relation.EQUAL_TO), - 1.0F)); - - // Mock second scroll request followed - SearchResponse scrollResponse = mock(SearchResponse.class); - when(nodeClient.searchScroll(any()).actionGet()).thenReturn(scrollResponse); - when(scrollResponse.getScrollId()).thenReturn("scroll456"); - when(scrollResponse.getHits()).thenReturn(SearchHits.empty()); - - // Verify response for first scroll request - ElasticsearchRequest request = new ElasticsearchRequest("test"); - ElasticsearchResponse response1 = client.search(request); - assertFalse(response1.isEmpty()); - - Iterator hits = response1.iterator(); - assertTrue(hits.hasNext()); - assertEquals(new SearchHit(1), hits.next()); - assertFalse(hits.hasNext()); - - // Verify response for second scroll request - ElasticsearchResponse response2 = client.search(request); - assertTrue(response2.isEmpty()); - } - - @Test - void schedule() { - ThreadPool threadPool = mock(ThreadPool.class); - when(threadPool.preserveContext(any())).then(invocation -> invocation.getArgument(0)); - when(nodeClient.threadPool()).thenReturn(threadPool); - - doAnswer(invocation -> { - Runnable task = invocation.getArgument(0); - task.run(); - return null; - }).when(threadPool).schedule(any(), any(), any()); - - ElasticsearchNodeClient client = new ElasticsearchNodeClient(mock(ClusterService.class), - nodeClient); - AtomicBoolean isRun = new AtomicBoolean(false); - client.schedule(() -> isRun.set(true)); - assertTrue(isRun.get()); - } - - @Test - void cleanup() { - ElasticsearchNodeClient client = new ElasticsearchNodeClient(mock(ClusterService.class), - nodeClient); - - ClearScrollRequestBuilder requestBuilder = mock(ClearScrollRequestBuilder.class); - when(nodeClient.prepareClearScroll()).thenReturn(requestBuilder); - when(requestBuilder.addScrollId(any())).thenReturn(requestBuilder); - when(requestBuilder.get()).thenReturn(null); - - ElasticsearchRequest request = new ElasticsearchRequest("test"); - request.setScrollId("scroll123"); - client.cleanup(request); - assertFalse(request.isScrollStarted()); - - InOrder inOrder = Mockito.inOrder(nodeClient, requestBuilder); - inOrder.verify(nodeClient).prepareClearScroll(); - inOrder.verify(requestBuilder).addScrollId("scroll123"); - inOrder.verify(requestBuilder).get(); - } - - @Test - void cleanupWithoutScrollId() { - ElasticsearchNodeClient client = new ElasticsearchNodeClient(mock(ClusterService.class), - nodeClient); - - ElasticsearchRequest request = new ElasticsearchRequest("test"); - client.cleanup(request); - verify(nodeClient, never()).prepareClearScroll(); - } - - private ElasticsearchNodeClient mockClient(String indexName, String mappings) { - ClusterService clusterService = mockClusterService(indexName, mappings); - return new ElasticsearchNodeClient(clusterService, nodeClient); - } - - /** Mock getAliasAndIndexLookup() only for index name resolve test */ - public ClusterService mockClusterService(String indexName) { - ClusterService mockService = mock(ClusterService.class); - ClusterState mockState = mock(ClusterState.class); - MetaData mockMetaData = mock(MetaData.class); - - when(mockService.state()).thenReturn(mockState); - when(mockState.metaData()).thenReturn(mockMetaData); - when(mockMetaData.getAliasAndIndexLookup()).thenReturn(ImmutableSortedMap.of(indexName, mock(AliasOrIndex.class))); - return mockService; - } - - public ClusterService mockClusterService(String indexName, String mappings) { - ClusterService mockService = mock(ClusterService.class); - ClusterState mockState = mock(ClusterState.class); - MetaData mockMetaData = mock(MetaData.class); - - when(mockService.state()).thenReturn(mockState); - when(mockState.metaData()).thenReturn(mockMetaData); - try { - ImmutableOpenMap.Builder> builder = ImmutableOpenMap.builder(); - ImmutableOpenMap metadata; - if (mappings.isEmpty()) { - metadata = ImmutableOpenMap.of(); - } else { - metadata = IndexMetaData.fromXContent(createParser(mappings)).getMappings(); - } - builder.put(indexName, metadata); - when(mockMetaData.findMappings(any(), any(), any())).thenReturn(builder.build()); - - // IndexNameExpressionResolver use this method to check if index exists. If not, IndexNotFoundException is thrown. - when(mockMetaData.getAliasAndIndexLookup()).thenReturn(ImmutableSortedMap.of(indexName, mock(AliasOrIndex.class))); - } - catch (IOException e) { - throw new IllegalStateException("Failed to mock cluster service", e); - } - return mockService; - } - - public ClusterService mockClusterService(String indexName, Throwable t) { - ClusterService mockService = mock(ClusterService.class); - ClusterState mockState = mock(ClusterState.class); - MetaData mockMetaData = mock(MetaData.class); - - when(mockService.state()).thenReturn(mockState); - when(mockState.metaData()).thenReturn(mockMetaData); - try { - when(mockMetaData.findMappings(any(), any(), any())).thenThrow(t); - when(mockMetaData.getAliasAndIndexLookup()).thenReturn(ImmutableSortedMap.of(indexName, mock(AliasOrIndex.class))); - } - catch (IOException e) { - throw new IllegalStateException("Failed to mock cluster service", e); - } - return mockService; - } - - private XContentParser createParser(String mappings) throws IOException { - return XContentType.JSON.xContent().createParser( - NamedXContentRegistry.EMPTY, - DeprecationHandler.THROW_UNSUPPORTED_OPERATION, - mappings - ); - } - -} \ No newline at end of file + return mockService; + } + + private XContentParser createParser(String mappings) throws IOException { + return XContentType.JSON + .xContent() + .createParser( + NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION, mappings); + } +} diff --git a/elasticsearch/src/test/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/client/ElasticsearchRestClientTest.java b/elasticsearch/src/test/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/client/ElasticsearchRestClientTest.java index bd2bf14fb0..95c17a3011 100644 --- a/elasticsearch/src/test/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/client/ElasticsearchRestClientTest.java +++ b/elasticsearch/src/test/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/client/ElasticsearchRestClientTest.java @@ -16,12 +16,28 @@ package com.amazon.opendistroforelasticsearch.sql.elasticsearch.client; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Answers.RETURNS_DEEP_STUBS; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import com.amazon.opendistroforelasticsearch.sql.elasticsearch.mapping.IndexMapping; import com.amazon.opendistroforelasticsearch.sql.elasticsearch.request.ElasticsearchRequest; import com.amazon.opendistroforelasticsearch.sql.elasticsearch.response.ElasticsearchResponse; import com.google.common.base.Charsets; import com.google.common.collect.ImmutableMap; import com.google.common.io.Resources; +import java.io.IOException; +import java.net.URL; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; import org.apache.lucene.search.TotalHits; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.client.RestHighLevelClient; @@ -41,161 +57,151 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import java.io.IOException; -import java.net.URL; -import java.util.Iterator; -import java.util.Map; -import java.util.concurrent.atomic.AtomicBoolean; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.Answers.RETURNS_DEEP_STUBS; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - @ExtendWith(MockitoExtension.class) class ElasticsearchRestClientTest { - private static final String TEST_MAPPING_FILE = "mappings/accounts.json"; - - @Mock(answer = RETURNS_DEEP_STUBS) - private RestHighLevelClient restClient; - - private ElasticsearchRestClient client; - - @BeforeEach - void setUp() { - client = new ElasticsearchRestClient(restClient); - } - - @Test - void getIndexMappings() throws IOException { - URL url = Resources.getResource(TEST_MAPPING_FILE); - String mappings = Resources.toString(url, Charsets.UTF_8); - String indexName = "test"; - - GetMappingsResponse response = mock(GetMappingsResponse.class); - when(response.mappings()).thenReturn(mockFieldMappings(indexName, mappings)); - when(restClient.indices().getMapping(any(GetMappingsRequest.class), any())).thenReturn(response); - - Map indexMappings = client.getIndexMappings(indexName); - assertEquals(1, indexMappings.size()); - - IndexMapping indexMapping = indexMappings.values().iterator().next(); - assertEquals(20, indexMapping.size()); - assertEquals("text", indexMapping.getFieldType("address")); - assertEquals("integer", indexMapping.getFieldType("age")); - assertEquals("double", indexMapping.getFieldType("balance")); - assertEquals("keyword", indexMapping.getFieldType("city")); - assertEquals("date", indexMapping.getFieldType("birthday")); - assertEquals("geo_point", indexMapping.getFieldType("location")); - assertEquals("some_new_es_type_outside_type_system", indexMapping.getFieldType("new_field")); - assertEquals("text", indexMapping.getFieldType("field with spaces")); - assertEquals("text", indexMapping.getFieldType("employer")); - assertEquals("keyword", indexMapping.getFieldType("employer.raw")); - assertEquals("nested", indexMapping.getFieldType("projects")); - assertEquals("boolean", indexMapping.getFieldType("projects.active")); - assertEquals("date", indexMapping.getFieldType("projects.release")); - assertEquals("nested", indexMapping.getFieldType("projects.members")); - assertEquals("text", indexMapping.getFieldType("projects.members.name")); - assertEquals("object", indexMapping.getFieldType("manager")); - assertEquals("text", indexMapping.getFieldType("manager.name")); - assertEquals("keyword", indexMapping.getFieldType("manager.name.keyword")); - assertEquals("keyword", indexMapping.getFieldType("manager.address")); - assertEquals("long", indexMapping.getFieldType("manager.salary")); - } - - @Test - void getIndexMappingsWithIOException() throws IOException { - when(restClient.indices().getMapping(any(GetMappingsRequest.class), any())).thenThrow(new IOException()); - assertThrows(IllegalStateException.class, () -> client.getIndexMappings("test")); - } - - @Test - void search() throws IOException { - // Mock first scroll request - SearchResponse searchResponse = mock(SearchResponse.class); - when(restClient.search(any(), any())).thenReturn(searchResponse); - when(searchResponse.getScrollId()).thenReturn("scroll123"); - when(searchResponse.getHits()).thenReturn(new SearchHits(new SearchHit[]{new SearchHit(1)}, - new TotalHits(1L, TotalHits.Relation.EQUAL_TO), - 1.0F)); - - // Mock second scroll request followed - SearchResponse scrollResponse = mock(SearchResponse.class); - when(restClient.scroll(any(), any())).thenReturn(scrollResponse); - when(scrollResponse.getScrollId()).thenReturn("scroll456"); - when(scrollResponse.getHits()).thenReturn(SearchHits.empty()); - - // Verify response for first scroll request - ElasticsearchRequest request = new ElasticsearchRequest("test"); - ElasticsearchResponse response1 = client.search(request); - assertFalse(response1.isEmpty()); - - Iterator hits = response1.iterator(); - assertTrue(hits.hasNext()); - assertEquals(new SearchHit(1), hits.next()); - assertFalse(hits.hasNext()); - - // Verify response for second scroll request - ElasticsearchResponse response2 = client.search(request); - assertTrue(response2.isEmpty()); - } - - @Test - void searchWithIOException() throws IOException { - when(restClient.search(any(), any())).thenThrow(new IOException()); - assertThrows(IllegalStateException.class, () -> client.search(new ElasticsearchRequest("test"))); - } - - @Test - void schedule() { - AtomicBoolean isRun = new AtomicBoolean(false); - client.schedule(() -> { - isRun.set(true); + private static final String TEST_MAPPING_FILE = "mappings/accounts.json"; + + @Mock(answer = RETURNS_DEEP_STUBS) + private RestHighLevelClient restClient; + + private ElasticsearchRestClient client; + + @BeforeEach + void setUp() { + client = new ElasticsearchRestClient(restClient); + } + + @Test + void getIndexMappings() throws IOException { + URL url = Resources.getResource(TEST_MAPPING_FILE); + String mappings = Resources.toString(url, Charsets.UTF_8); + String indexName = "test"; + + GetMappingsResponse response = mock(GetMappingsResponse.class); + when(response.mappings()).thenReturn(mockFieldMappings(indexName, mappings)); + when(restClient.indices().getMapping(any(GetMappingsRequest.class), any())) + .thenReturn(response); + + Map indexMappings = client.getIndexMappings(indexName); + assertEquals(1, indexMappings.size()); + + IndexMapping indexMapping = indexMappings.values().iterator().next(); + assertEquals(20, indexMapping.size()); + assertEquals("text", indexMapping.getFieldType("address")); + assertEquals("integer", indexMapping.getFieldType("age")); + assertEquals("double", indexMapping.getFieldType("balance")); + assertEquals("keyword", indexMapping.getFieldType("city")); + assertEquals("date", indexMapping.getFieldType("birthday")); + assertEquals("geo_point", indexMapping.getFieldType("location")); + assertEquals("some_new_es_type_outside_type_system", indexMapping.getFieldType("new_field")); + assertEquals("text", indexMapping.getFieldType("field with spaces")); + assertEquals("text", indexMapping.getFieldType("employer")); + assertEquals("keyword", indexMapping.getFieldType("employer.raw")); + assertEquals("nested", indexMapping.getFieldType("projects")); + assertEquals("boolean", indexMapping.getFieldType("projects.active")); + assertEquals("date", indexMapping.getFieldType("projects.release")); + assertEquals("nested", indexMapping.getFieldType("projects.members")); + assertEquals("text", indexMapping.getFieldType("projects.members.name")); + assertEquals("object", indexMapping.getFieldType("manager")); + assertEquals("text", indexMapping.getFieldType("manager.name")); + assertEquals("keyword", indexMapping.getFieldType("manager.name.keyword")); + assertEquals("keyword", indexMapping.getFieldType("manager.address")); + assertEquals("long", indexMapping.getFieldType("manager.salary")); + } + + @Test + void getIndexMappingsWithIOException() throws IOException { + when(restClient.indices().getMapping(any(GetMappingsRequest.class), any())) + .thenThrow(new IOException()); + assertThrows(IllegalStateException.class, () -> client.getIndexMappings("test")); + } + + @Test + void search() throws IOException { + // Mock first scroll request + SearchResponse searchResponse = mock(SearchResponse.class); + when(restClient.search(any(), any())).thenReturn(searchResponse); + when(searchResponse.getScrollId()).thenReturn("scroll123"); + when(searchResponse.getHits()) + .thenReturn( + new SearchHits( + new SearchHit[] {new SearchHit(1)}, + new TotalHits(1L, TotalHits.Relation.EQUAL_TO), + 1.0F)); + + // Mock second scroll request followed + SearchResponse scrollResponse = mock(SearchResponse.class); + when(restClient.scroll(any(), any())).thenReturn(scrollResponse); + when(scrollResponse.getScrollId()).thenReturn("scroll456"); + when(scrollResponse.getHits()).thenReturn(SearchHits.empty()); + + // Verify response for first scroll request + ElasticsearchRequest request = new ElasticsearchRequest("test"); + ElasticsearchResponse response1 = client.search(request); + assertFalse(response1.isEmpty()); + + Iterator hits = response1.iterator(); + assertTrue(hits.hasNext()); + assertEquals(new SearchHit(1), hits.next()); + assertFalse(hits.hasNext()); + + // Verify response for second scroll request + ElasticsearchResponse response2 = client.search(request); + assertTrue(response2.isEmpty()); + } + + @Test + void searchWithIOException() throws IOException { + when(restClient.search(any(), any())).thenThrow(new IOException()); + assertThrows( + IllegalStateException.class, () -> client.search(new ElasticsearchRequest("test"))); + } + + @Test + void schedule() { + AtomicBoolean isRun = new AtomicBoolean(false); + client.schedule( + () -> { + isRun.set(true); }); - assertTrue(isRun.get()); - } - - @Test - void cleanup() throws IOException { - ElasticsearchRequest request = new ElasticsearchRequest("test"); - request.setScrollId("scroll123"); - client.cleanup(request); - verify(restClient).clearScroll(any(), any()); - assertFalse(request.isScrollStarted()); - } - - @Test - void cleanupWithoutScrollId() throws IOException { - ElasticsearchRequest request = new ElasticsearchRequest("test"); - client.cleanup(request); - verify(restClient, never()).clearScroll(any(), any()); - } - - @Test - void cleanupWithIOException() throws IOException { - when(restClient.clearScroll(any(), any())).thenThrow(new IOException()); - - ElasticsearchRequest request = new ElasticsearchRequest("test"); - request.setScrollId("scroll123"); - assertThrows(IllegalStateException.class, () -> client.cleanup(request)); - } - - private Map mockFieldMappings(String indexName, String mappings) throws IOException { - return ImmutableMap.of(indexName, IndexMetaData.fromXContent(createParser(mappings)).mapping()); - } - - private XContentParser createParser(String mappings) throws IOException { - return XContentType.JSON.xContent().createParser( - NamedXContentRegistry.EMPTY, - DeprecationHandler.THROW_UNSUPPORTED_OPERATION, - mappings - ); - } -} \ No newline at end of file + assertTrue(isRun.get()); + } + + @Test + void cleanup() throws IOException { + ElasticsearchRequest request = new ElasticsearchRequest("test"); + request.setScrollId("scroll123"); + client.cleanup(request); + verify(restClient).clearScroll(any(), any()); + assertFalse(request.isScrollStarted()); + } + + @Test + void cleanupWithoutScrollId() throws IOException { + ElasticsearchRequest request = new ElasticsearchRequest("test"); + client.cleanup(request); + verify(restClient, never()).clearScroll(any(), any()); + } + + @Test + void cleanupWithIOException() throws IOException { + when(restClient.clearScroll(any(), any())).thenThrow(new IOException()); + + ElasticsearchRequest request = new ElasticsearchRequest("test"); + request.setScrollId("scroll123"); + assertThrows(IllegalStateException.class, () -> client.cleanup(request)); + } + + private Map mockFieldMappings(String indexName, String mappings) + throws IOException { + return ImmutableMap.of(indexName, IndexMetaData.fromXContent(createParser(mappings)).mapping()); + } + + private XContentParser createParser(String mappings) throws IOException { + return XContentType.JSON + .xContent() + .createParser( + NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION, mappings); + } +} diff --git a/elasticsearch/src/test/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/executor/ElasticsearchExecutionEngineTest.java b/elasticsearch/src/test/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/executor/ElasticsearchExecutionEngineTest.java index 6ccd904256..b14b7f0b06 100644 --- a/elasticsearch/src/test/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/executor/ElasticsearchExecutionEngineTest.java +++ b/elasticsearch/src/test/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/executor/ElasticsearchExecutionEngineTest.java @@ -16,24 +16,6 @@ package com.amazon.opendistroforelasticsearch.sql.elasticsearch.executor; -import com.amazon.opendistroforelasticsearch.sql.common.response.ResponseListener; -import com.amazon.opendistroforelasticsearch.sql.data.model.ExprValue; -import com.amazon.opendistroforelasticsearch.sql.elasticsearch.client.ElasticsearchClient; -import com.amazon.opendistroforelasticsearch.sql.planner.physical.PhysicalPlan; -import com.amazon.opendistroforelasticsearch.sql.storage.TableScanOperator; -import lombok.RequiredArgsConstructor; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; -import java.util.concurrent.atomic.AtomicReference; - import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.tupleValue; import static com.amazon.opendistroforelasticsearch.sql.executor.ExecutionEngine.QueryResponse; import static com.google.common.collect.ImmutableMap.of; @@ -46,99 +28,120 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import com.amazon.opendistroforelasticsearch.sql.common.response.ResponseListener; +import com.amazon.opendistroforelasticsearch.sql.data.model.ExprValue; +import com.amazon.opendistroforelasticsearch.sql.elasticsearch.client.ElasticsearchClient; +import com.amazon.opendistroforelasticsearch.sql.planner.physical.PhysicalPlan; +import com.amazon.opendistroforelasticsearch.sql.storage.TableScanOperator; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; +import lombok.RequiredArgsConstructor; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + @ExtendWith(MockitoExtension.class) class ElasticsearchExecutionEngineTest { - @Mock - private ElasticsearchClient client; - - @BeforeEach - void setUp() { - doAnswer(invocation -> { - // Run task immediately - Runnable task = invocation.getArgument(0); - task.run(); - return null; - }).when(client).schedule(any()); - } - - @Test - void executeSuccessfully() { - List expected = Arrays.asList( - tupleValue(of("name", "John", "age", 20)), - tupleValue(of("name", "Allen", "age", 30)) - ); - FakePhysicalPlan plan = new FakePhysicalPlan(expected.iterator()); - - ElasticsearchExecutionEngine executor = new ElasticsearchExecutionEngine(client); - List actual = new ArrayList<>(); - executor.execute(plan, new ResponseListener() { - @Override - public void onResponse(QueryResponse response) { - actual.addAll(response.getResults()); - } - - @Override - public void onFailure(Exception e) { - fail("Error occurred during execution", e); - } + @Mock private ElasticsearchClient client; + + @BeforeEach + void setUp() { + doAnswer( + invocation -> { + // Run task immediately + Runnable task = invocation.getArgument(0); + task.run(); + return null; + }) + .when(client) + .schedule(any()); + } + + @Test + void executeSuccessfully() { + List expected = + Arrays.asList( + tupleValue(of("name", "John", "age", 20)), tupleValue(of("name", "Allen", "age", 30))); + FakePhysicalPlan plan = new FakePhysicalPlan(expected.iterator()); + + ElasticsearchExecutionEngine executor = new ElasticsearchExecutionEngine(client); + List actual = new ArrayList<>(); + executor.execute( + plan, + new ResponseListener() { + @Override + public void onResponse(QueryResponse response) { + actual.addAll(response.getResults()); + } + + @Override + public void onFailure(Exception e) { + fail("Error occurred during execution", e); + } }); - assertTrue(plan.hasOpen); - assertEquals(expected, actual); - assertTrue(plan.hasClosed); + assertTrue(plan.hasOpen); + assertEquals(expected, actual); + assertTrue(plan.hasClosed); + } + + @Test + void executeWithFailure() { + PhysicalPlan plan = mock(PhysicalPlan.class); + RuntimeException expected = new RuntimeException("Execution error"); + when(plan.hasNext()).thenThrow(expected); + + ElasticsearchExecutionEngine executor = new ElasticsearchExecutionEngine(client); + AtomicReference actual = new AtomicReference<>(); + executor.execute( + plan, + new ResponseListener() { + @Override + public void onResponse(QueryResponse response) { + fail("Expected error didn't happen"); + } + + @Override + public void onFailure(Exception e) { + actual.set(e); + } + }); + assertEquals(expected, actual.get()); + verify(plan).close(); + } + + @RequiredArgsConstructor + private static class FakePhysicalPlan extends TableScanOperator { + private final Iterator it; + private boolean hasOpen; + private boolean hasClosed; + + @Override + public void open() { + super.open(); + hasOpen = true; } - @Test - void executeWithFailure() { - PhysicalPlan plan = mock(PhysicalPlan.class); - RuntimeException expected = new RuntimeException("Execution error"); - when(plan.hasNext()).thenThrow(expected); - - ElasticsearchExecutionEngine executor = new ElasticsearchExecutionEngine(client); - AtomicReference actual = new AtomicReference<>(); - executor.execute(plan, new ResponseListener() { - @Override - public void onResponse(QueryResponse response) { - fail("Expected error didn't happen"); - } - - @Override - public void onFailure(Exception e) { - actual.set(e); - } - }); - assertEquals(expected, actual.get()); - verify(plan).close(); + @Override + public void close() { + super.close(); + hasClosed = true; } - @RequiredArgsConstructor - private static class FakePhysicalPlan extends TableScanOperator { - private final Iterator it; - private boolean hasOpen; - private boolean hasClosed; - - @Override - public void open() { - super.open(); - hasOpen = true; - } - - @Override - public void close() { - super.close(); - hasClosed = true; - } - - @Override - public boolean hasNext() { - return it.hasNext(); - } - - @Override - public ExprValue next() { - return it.next(); - } + @Override + public boolean hasNext() { + return it.hasNext(); } -} \ No newline at end of file + @Override + public ExprValue next() { + return it.next(); + } + } +} diff --git a/elasticsearch/src/test/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/mapping/IndexMappingTest.java b/elasticsearch/src/test/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/mapping/IndexMappingTest.java index 5d82a017db..9dee52341f 100644 --- a/elasticsearch/src/test/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/mapping/IndexMappingTest.java +++ b/elasticsearch/src/test/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/mapping/IndexMappingTest.java @@ -16,11 +16,6 @@ package com.amazon.opendistroforelasticsearch.sql.elasticsearch.mapping; -import com.google.common.collect.ImmutableMap; -import org.junit.jupiter.api.Test; - -import java.util.Map; - import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.aMapWithSize; import static org.hamcrest.Matchers.allOf; @@ -28,27 +23,25 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; -class IndexMappingTest { - - @Test - public void getFieldType() { - IndexMapping indexMapping = new IndexMapping(ImmutableMap.of("name", "text")); - assertEquals("text", indexMapping.getFieldType("name")); - assertNull(indexMapping.getFieldType("not_exist")); - } +import com.google.common.collect.ImmutableMap; +import java.util.Map; +import org.junit.jupiter.api.Test; - @Test - public void getAllFieldTypes() { - IndexMapping indexMapping = new IndexMapping(ImmutableMap.of("name", "text", "age", "int")); - Map fieldTypes = indexMapping.getAllFieldTypes(type -> "our_type"); - assertThat( - fieldTypes, - allOf( - aMapWithSize(2), - hasEntry("name", "our_type"), - hasEntry("age", "our_type") - ) - ); - } +class IndexMappingTest { -} \ No newline at end of file + @Test + public void getFieldType() { + IndexMapping indexMapping = new IndexMapping(ImmutableMap.of("name", "text")); + assertEquals("text", indexMapping.getFieldType("name")); + assertNull(indexMapping.getFieldType("not_exist")); + } + + @Test + public void getAllFieldTypes() { + IndexMapping indexMapping = new IndexMapping(ImmutableMap.of("name", "text", "age", "int")); + Map fieldTypes = indexMapping.getAllFieldTypes(type -> "our_type"); + assertThat( + fieldTypes, + allOf(aMapWithSize(2), hasEntry("name", "our_type"), hasEntry("age", "our_type"))); + } +} diff --git a/elasticsearch/src/test/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/request/ElasticsearchRequestTest.java b/elasticsearch/src/test/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/request/ElasticsearchRequestTest.java index 44fa83a3f1..cd6600d100 100644 --- a/elasticsearch/src/test/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/request/ElasticsearchRequestTest.java +++ b/elasticsearch/src/test/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/request/ElasticsearchRequestTest.java @@ -16,49 +16,47 @@ package com.amazon.opendistroforelasticsearch.sql.elasticsearch.request; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchScrollRequest; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.search.builder.SearchSourceBuilder; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - class ElasticsearchRequestTest { - private final ElasticsearchRequest request = new ElasticsearchRequest("test"); - - @Test - void searchRequest() { - request.getSourceBuilder(). - query(QueryBuilders.termQuery("name", "John")); - - assertEquals( - new SearchRequest().indices("test"). - scroll(ElasticsearchRequest.DEFAULT_SCROLL_TIMEOUT). - source(new SearchSourceBuilder().query(QueryBuilders.termQuery("name", "John"))), - request.searchRequest() - ); - } - - @Test - void isScrollStarted() { - assertFalse(request.isScrollStarted()); - - request.setScrollId("scroll123"); - assertTrue(request.isScrollStarted()); - } - - @Test - void scrollRequest() { - request.setScrollId("scroll123"); - assertEquals( - new SearchScrollRequest().scroll(ElasticsearchRequest.DEFAULT_SCROLL_TIMEOUT). - scrollId("scroll123"), - request.scrollRequest() - ); - } - -} \ No newline at end of file + private final ElasticsearchRequest request = new ElasticsearchRequest("test"); + + @Test + void searchRequest() { + request.getSourceBuilder().query(QueryBuilders.termQuery("name", "John")); + + assertEquals( + new SearchRequest() + .indices("test") + .scroll(ElasticsearchRequest.DEFAULT_SCROLL_TIMEOUT) + .source(new SearchSourceBuilder().query(QueryBuilders.termQuery("name", "John"))), + request.searchRequest()); + } + + @Test + void isScrollStarted() { + assertFalse(request.isScrollStarted()); + + request.setScrollId("scroll123"); + assertTrue(request.isScrollStarted()); + } + + @Test + void scrollRequest() { + request.setScrollId("scroll123"); + assertEquals( + new SearchScrollRequest() + .scroll(ElasticsearchRequest.DEFAULT_SCROLL_TIMEOUT) + .scrollId("scroll123"), + request.scrollRequest()); + } +} diff --git a/elasticsearch/src/test/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/response/ElasticsearchResponseTest.java b/elasticsearch/src/test/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/response/ElasticsearchResponseTest.java index 3a3a52b3e4..68ea1af73d 100644 --- a/elasticsearch/src/test/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/response/ElasticsearchResponseTest.java +++ b/elasticsearch/src/test/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/response/ElasticsearchResponseTest.java @@ -16,6 +16,12 @@ package com.amazon.opendistroforelasticsearch.sql.elasticsearch.response; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import static org.mockito.Mockito.when; + import org.apache.lucene.search.TotalHits; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.search.SearchHit; @@ -26,57 +32,48 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; -import static org.mockito.Mockito.when; - @ExtendWith(MockitoExtension.class) class ElasticsearchResponseTest { - @Mock - private SearchResponse esResponse; + @Mock private SearchResponse esResponse; - @BeforeEach - void setUp() { - when(esResponse.getHits()).thenReturn( + @BeforeEach + void setUp() { + when(esResponse.getHits()) + .thenReturn( new SearchHits( - new SearchHit[]{ new SearchHit(1), new SearchHit(2) }, + new SearchHit[] {new SearchHit(1), new SearchHit(2)}, new TotalHits(2L, TotalHits.Relation.EQUAL_TO), - 1.0F - ) - ); - } + 1.0F)); + } - @Test - void isEmpty() { - ElasticsearchResponse response1 = new ElasticsearchResponse(esResponse); - assertFalse(response1.isEmpty()); + @Test + void isEmpty() { + ElasticsearchResponse response1 = new ElasticsearchResponse(esResponse); + assertFalse(response1.isEmpty()); - when(esResponse.getHits()).thenReturn(SearchHits.empty()); - ElasticsearchResponse response2 = new ElasticsearchResponse(esResponse); - assertTrue(response2.isEmpty()); + when(esResponse.getHits()).thenReturn(SearchHits.empty()); + ElasticsearchResponse response2 = new ElasticsearchResponse(esResponse); + assertTrue(response2.isEmpty()); - when(esResponse.getHits()).thenReturn( - new SearchHits(null, new TotalHits(0, TotalHits.Relation.EQUAL_TO), 0)); - ElasticsearchResponse response3 = new ElasticsearchResponse(esResponse); - assertTrue(response3.isEmpty()); - } + when(esResponse.getHits()) + .thenReturn(new SearchHits(null, new TotalHits(0, TotalHits.Relation.EQUAL_TO), 0)); + ElasticsearchResponse response3 = new ElasticsearchResponse(esResponse); + assertTrue(response3.isEmpty()); + } - @Test - void iterator() { - int i = 0; - for (SearchHit hit : new ElasticsearchResponse(esResponse)) { - if (i == 0) { - assertEquals(new SearchHit(1), hit); - } else if (i == 1) { - assertEquals(new SearchHit(2), hit); - } else { - fail("More search hits returned than expected"); - } - i++; - } + @Test + void iterator() { + int i = 0; + for (SearchHit hit : new ElasticsearchResponse(esResponse)) { + if (i == 0) { + assertEquals(new SearchHit(1), hit); + } else if (i == 1) { + assertEquals(new SearchHit(2), hit); + } else { + fail("More search hits returned than expected"); + } + i++; } - -} \ No newline at end of file + } +} diff --git a/elasticsearch/src/test/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/storage/ElasticsearchIndexScanTest.java b/elasticsearch/src/test/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/storage/ElasticsearchIndexScanTest.java index 38768d5050..12e8caebd3 100644 --- a/elasticsearch/src/test/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/storage/ElasticsearchIndexScanTest.java +++ b/elasticsearch/src/test/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/storage/ElasticsearchIndexScanTest.java @@ -16,10 +16,20 @@ package com.amazon.opendistroforelasticsearch.sql.elasticsearch.storage; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import com.amazon.opendistroforelasticsearch.sql.data.model.ExprValue; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils; import com.amazon.opendistroforelasticsearch.sql.elasticsearch.client.ElasticsearchClient; import com.amazon.opendistroforelasticsearch.sql.elasticsearch.response.ElasticsearchResponse; +import java.util.Arrays; import org.elasticsearch.common.bytes.BytesArray; import org.elasticsearch.search.SearchHit; import org.junit.jupiter.api.Test; @@ -29,94 +39,78 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.stubbing.Answer; -import java.util.Arrays; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - @ExtendWith(MockitoExtension.class) class ElasticsearchIndexScanTest { - @Mock - private ElasticsearchClient client; - - @Test - void queryEmptyResult() { - mockResponse(); - try (ElasticsearchIndexScan indexScan = new ElasticsearchIndexScan(client, "test")) { - indexScan.open(); - assertFalse(indexScan.hasNext()); - } - verify(client).cleanup(any()); + @Mock private ElasticsearchClient client; + + @Test + void queryEmptyResult() { + mockResponse(); + try (ElasticsearchIndexScan indexScan = new ElasticsearchIndexScan(client, "test")) { + indexScan.open(); + assertFalse(indexScan.hasNext()); } + verify(client).cleanup(any()); + } + + @Test + void queryAllResults() { + mockResponse( + new SearchHit[] {employee(1, "John", "IT"), employee(2, "Smith", "HR")}, + new SearchHit[] {employee(3, "Allen", "IT")}); + + try (ElasticsearchIndexScan indexScan = new ElasticsearchIndexScan(client, "employees")) { + indexScan.open(); + + assertTrue(indexScan.hasNext()); + assertEquals(tupleValue(employee(1, "John", "IT")), indexScan.next()); - @Test - void queryAllResults() { - mockResponse( - new SearchHit[]{ - employee(1, "John", "IT"), - employee(2, "Smith", "HR") - }, - new SearchHit[]{ - employee(3, "Allen", "IT") - } - ); - - try (ElasticsearchIndexScan indexScan = new ElasticsearchIndexScan(client, "employees")) { - indexScan.open(); - - assertTrue(indexScan.hasNext()); - assertEquals(tupleValue(employee(1, "John", "IT")), indexScan.next()); - - assertTrue(indexScan.hasNext()); - assertEquals(tupleValue(employee(2, "Smith", "HR")), indexScan.next()); - - assertTrue(indexScan.hasNext()); - assertEquals(tupleValue(employee(3, "Allen", "IT")), indexScan.next()); - - assertFalse(indexScan.hasNext()); - } - verify(client).cleanup(any()); + assertTrue(indexScan.hasNext()); + assertEquals(tupleValue(employee(2, "Smith", "HR")), indexScan.next()); + + assertTrue(indexScan.hasNext()); + assertEquals(tupleValue(employee(3, "Allen", "IT")), indexScan.next()); + + assertFalse(indexScan.hasNext()); } + verify(client).cleanup(any()); + } - private void mockResponse(SearchHit[]... searchHitBatches) { - when(client.search(any())).thenAnswer(new Answer() { - private int batchNum; + private void mockResponse(SearchHit[]... searchHitBatches) { + when(client.search(any())) + .thenAnswer( + new Answer() { + private int batchNum; - @Override - public ElasticsearchResponse answer(InvocationOnMock invocation) { + @Override + public ElasticsearchResponse answer(InvocationOnMock invocation) { ElasticsearchResponse response = mock(ElasticsearchResponse.class); int totalBatch = searchHitBatches.length; if (batchNum < totalBatch) { - when(response.isEmpty()).thenReturn(false); - SearchHit[] searchHit = searchHitBatches[batchNum]; - when(response.iterator()).thenReturn(Arrays.asList(searchHit).iterator()); + when(response.isEmpty()).thenReturn(false); + SearchHit[] searchHit = searchHitBatches[batchNum]; + when(response.iterator()).thenReturn(Arrays.asList(searchHit).iterator()); } else if (batchNum == totalBatch) { - when(response.isEmpty()).thenReturn(true); + when(response.isEmpty()).thenReturn(true); } else { - fail("Search request after empty response returned already"); + fail("Search request after empty response returned already"); } batchNum++; return response; - } - }); - } - - protected SearchHit employee(int docId, String name, String department) { - SearchHit hit = new SearchHit(docId); - hit.sourceRef(new BytesArray("{\"name\":\"" + name + "\",\"department\":\"" + department + "\"}")); - return hit; - } - - private ExprValue tupleValue(SearchHit hit) { - return ExprValueUtils.tupleValue(hit.getSourceAsMap()); - } - -} \ No newline at end of file + } + }); + } + + protected SearchHit employee(int docId, String name, String department) { + SearchHit hit = new SearchHit(docId); + hit.sourceRef( + new BytesArray("{\"name\":\"" + name + "\",\"department\":\"" + department + "\"}")); + return hit; + } + + private ExprValue tupleValue(SearchHit hit) { + return ExprValueUtils.tupleValue(hit.getSourceAsMap()); + } +} diff --git a/elasticsearch/src/test/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/storage/ElasticsearchIndexTest.java b/elasticsearch/src/test/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/storage/ElasticsearchIndexTest.java index 2024e6b0f3..f39d406b18 100644 --- a/elasticsearch/src/test/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/storage/ElasticsearchIndexTest.java +++ b/elasticsearch/src/test/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/storage/ElasticsearchIndexTest.java @@ -16,6 +16,22 @@ package com.amazon.opendistroforelasticsearch.sql.elasticsearch.storage; +import static com.amazon.opendistroforelasticsearch.sql.expression.DSL.literal; +import static com.amazon.opendistroforelasticsearch.sql.expression.DSL.ref; +import static com.amazon.opendistroforelasticsearch.sql.planner.logical.LogicalPlanDSL.aggregation; +import static com.amazon.opendistroforelasticsearch.sql.planner.logical.LogicalPlanDSL.eval; +import static com.amazon.opendistroforelasticsearch.sql.planner.logical.LogicalPlanDSL.filter; +import static com.amazon.opendistroforelasticsearch.sql.planner.logical.LogicalPlanDSL.project; +import static com.amazon.opendistroforelasticsearch.sql.planner.logical.LogicalPlanDSL.relation; +import static com.amazon.opendistroforelasticsearch.sql.planner.logical.LogicalPlanDSL.remove; +import static com.amazon.opendistroforelasticsearch.sql.planner.logical.LogicalPlanDSL.rename; +import static com.amazon.opendistroforelasticsearch.sql.planner.logical.LogicalPlanDSL.sort; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.aMapWithSize; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.hasEntry; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.when; import com.amazon.opendistroforelasticsearch.sql.ast.tree.Sort.SortOption; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprBooleanValue; @@ -31,6 +47,9 @@ import com.amazon.opendistroforelasticsearch.sql.planner.physical.PhysicalPlanDSL; import com.amazon.opendistroforelasticsearch.sql.storage.Table; import com.google.common.collect.ImmutableMap; +import java.util.Arrays; +import java.util.List; +import java.util.Map; import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.Pair; import org.junit.jupiter.api.Test; @@ -38,157 +57,112 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import java.util.Arrays; -import java.util.List; -import java.util.Map; - -import static com.amazon.opendistroforelasticsearch.sql.expression.DSL.literal; -import static com.amazon.opendistroforelasticsearch.sql.expression.DSL.ref; -import static com.amazon.opendistroforelasticsearch.sql.planner.logical.LogicalPlanDSL.aggregation; -import static com.amazon.opendistroforelasticsearch.sql.planner.logical.LogicalPlanDSL.dedupe; -import static com.amazon.opendistroforelasticsearch.sql.planner.logical.LogicalPlanDSL.eval; -import static com.amazon.opendistroforelasticsearch.sql.planner.logical.LogicalPlanDSL.filter; -import static com.amazon.opendistroforelasticsearch.sql.planner.logical.LogicalPlanDSL.project; -import static com.amazon.opendistroforelasticsearch.sql.planner.logical.LogicalPlanDSL.relation; -import static com.amazon.opendistroforelasticsearch.sql.planner.logical.LogicalPlanDSL.remove; -import static com.amazon.opendistroforelasticsearch.sql.planner.logical.LogicalPlanDSL.rename; -import static com.amazon.opendistroforelasticsearch.sql.planner.logical.LogicalPlanDSL.sort; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.aMapWithSize; -import static org.hamcrest.Matchers.allOf; -import static org.hamcrest.Matchers.hasEntry; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.Mockito.when; - @ExtendWith(MockitoExtension.class) class ElasticsearchIndexTest { - @Mock - private ElasticsearchClient client; - - @Test - void getFieldTypes() { - when(client.getIndexMappings("test")).thenReturn( - ImmutableMap.of("test", new IndexMapping( - ImmutableMap.builder(). - put("name", "keyword"). - put("address", "text"). - put("age", "integer"). - put("account_number", "long"). - put("balance1", "float"). - put("balance2", "double"). - put("gender", "boolean"). - put("family", "nested"). - put("employer", "object"). - put("birthday", "date"). - build() - ) - ) - ); - - Table index = new ElasticsearchIndex(client, "test"); - Map fieldTypes = index.getFieldTypes(); - assertThat( - fieldTypes, - allOf( - aMapWithSize(10), - hasEntry("name", ExprType.STRING), - hasEntry("address", ExprType.STRING), - hasEntry("age", ExprType.INTEGER), - hasEntry("account_number", ExprType.LONG), - hasEntry("balance1", ExprType.FLOAT), - hasEntry("balance2", ExprType.DOUBLE), - hasEntry("gender", ExprType.BOOLEAN), - hasEntry("family", ExprType.ARRAY), - hasEntry("employer", ExprType.STRUCT), - hasEntry("birthday", ExprType.UNKNOWN) - ) - ); - } + @Mock private ElasticsearchClient client; - @Test - void implementRelationOperatorOnly() { - String indexName = "test"; - LogicalPlan plan = relation(indexName); - Table index = new ElasticsearchIndex(client, indexName); - assertEquals(new ElasticsearchIndexScan(client, indexName), index.implement(plan)); - } + @Test + void getFieldTypes() { + when(client.getIndexMappings("test")) + .thenReturn( + ImmutableMap.of( + "test", + new IndexMapping( + ImmutableMap.builder() + .put("name", "keyword") + .put("address", "text") + .put("age", "integer") + .put("account_number", "long") + .put("balance1", "float") + .put("balance2", "double") + .put("gender", "boolean") + .put("family", "nested") + .put("employer", "object") + .put("birthday", "date") + .build()))); - @Test - void implementOtherLogicalOperators() { - String indexName = "test"; - ReferenceExpression include = ref("age"); - ReferenceExpression exclude = ref("name"); - ReferenceExpression dedupeField = ref("name"); - Expression filterExpr = literal(ExprBooleanValue.ofTrue()); - List groupByExprs = Arrays.asList(ref("age")); - List aggregators = Arrays.asList(new AvgAggregator(groupByExprs, ExprType.DOUBLE)); - Map mappings = ImmutableMap.of(ref("name"), ref("lastname")); - Pair newEvalField = ImmutablePair.of(ref("name1"), ref("name")); - Integer sortCount = 100; - Pair sortField = ImmutablePair.of(SortOption.PPL_ASC, ref("name1")); + Table index = new ElasticsearchIndex(client, "test"); + Map fieldTypes = index.getFieldTypes(); + assertThat( + fieldTypes, + allOf( + aMapWithSize(10), + hasEntry("name", ExprType.STRING), + hasEntry("address", ExprType.STRING), + hasEntry("age", ExprType.INTEGER), + hasEntry("account_number", ExprType.LONG), + hasEntry("balance1", ExprType.FLOAT), + hasEntry("balance2", ExprType.DOUBLE), + hasEntry("gender", ExprType.BOOLEAN), + hasEntry("family", ExprType.ARRAY), + hasEntry("employer", ExprType.STRUCT), + hasEntry("birthday", ExprType.UNKNOWN))); + } + @Test + void implementRelationOperatorOnly() { + String indexName = "test"; + LogicalPlan plan = relation(indexName); + Table index = new ElasticsearchIndex(client, indexName); + assertEquals(new ElasticsearchIndexScan(client, indexName), index.implement(plan)); + } - LogicalPlan plan = - project( - LogicalPlanDSL.dedupe( - sort( - eval( - remove( - rename( - aggregation( - filter( - relation(indexName), - filterExpr - ), - aggregators, - groupByExprs - ), - mappings - ), - exclude - ), - newEvalField - ), - sortCount, - sortField - ), - dedupeField - ), - include - ); + @Test + void implementOtherLogicalOperators() { + String indexName = "test"; + ReferenceExpression include = ref("age"); + ReferenceExpression exclude = ref("name"); + ReferenceExpression dedupeField = ref("name"); + Expression filterExpr = literal(ExprBooleanValue.ofTrue()); + List groupByExprs = Arrays.asList(ref("age")); + List aggregators = Arrays.asList(new AvgAggregator(groupByExprs, ExprType.DOUBLE)); + Map mappings = + ImmutableMap.of(ref("name"), ref("lastname")); + Pair newEvalField = + ImmutablePair.of(ref("name1"), ref("name")); + Integer sortCount = 100; + Pair sortField = ImmutablePair.of(SortOption.PPL_ASC, ref("name1")); - Table index = new ElasticsearchIndex(client, indexName); - assertEquals( - PhysicalPlanDSL.project( - PhysicalPlanDSL.dedupe( - PhysicalPlanDSL.sort( - PhysicalPlanDSL.eval( - PhysicalPlanDSL.remove( - PhysicalPlanDSL.rename( - PhysicalPlanDSL.agg( - PhysicalPlanDSL.filter( - new ElasticsearchIndexScan(client, indexName), - filterExpr - ), - aggregators, - groupByExprs - ), - mappings - ), - exclude - ), - newEvalField - ), - sortCount, - sortField - ), - dedupeField - ), - include - ), - index.implement(plan) - ); - } + LogicalPlan plan = + project( + LogicalPlanDSL.dedupe( + sort( + eval( + remove( + rename( + aggregation( + filter(relation(indexName), filterExpr), + aggregators, + groupByExprs), + mappings), + exclude), + newEvalField), + sortCount, + sortField), + dedupeField), + include); -} \ No newline at end of file + Table index = new ElasticsearchIndex(client, indexName); + assertEquals( + PhysicalPlanDSL.project( + PhysicalPlanDSL.dedupe( + PhysicalPlanDSL.sort( + PhysicalPlanDSL.eval( + PhysicalPlanDSL.remove( + PhysicalPlanDSL.rename( + PhysicalPlanDSL.agg( + PhysicalPlanDSL.filter( + new ElasticsearchIndexScan(client, indexName), filterExpr), + aggregators, + groupByExprs), + mappings), + exclude), + newEvalField), + sortCount, + sortField), + dedupeField), + include), + index.implement(plan)); + } +} diff --git a/elasticsearch/src/test/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/storage/ElasticsearchStorageEngineTest.java b/elasticsearch/src/test/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/storage/ElasticsearchStorageEngineTest.java index 21fdfcc260..f17455f988 100644 --- a/elasticsearch/src/test/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/storage/ElasticsearchStorageEngineTest.java +++ b/elasticsearch/src/test/java/com/amazon/opendistroforelasticsearch/sql/elasticsearch/storage/ElasticsearchStorageEngineTest.java @@ -16,6 +16,8 @@ package com.amazon.opendistroforelasticsearch.sql.elasticsearch.storage; +import static org.junit.jupiter.api.Assertions.assertNotNull; + import com.amazon.opendistroforelasticsearch.sql.elasticsearch.client.ElasticsearchClient; import com.amazon.opendistroforelasticsearch.sql.storage.Table; import org.junit.jupiter.api.Test; @@ -23,19 +25,15 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import static org.junit.jupiter.api.Assertions.assertNotNull; - @ExtendWith(MockitoExtension.class) class ElasticsearchStorageEngineTest { - @Mock - private ElasticsearchClient client; - - @Test - public void getTable() { - ElasticsearchStorageEngine engine = new ElasticsearchStorageEngine(client); - Table table = engine.getTable("test"); - assertNotNull(table); - } + @Mock private ElasticsearchClient client; -} \ No newline at end of file + @Test + public void getTable() { + ElasticsearchStorageEngine engine = new ElasticsearchStorageEngine(client); + Table table = engine.getTable("test"); + assertNotNull(table); + } +} diff --git a/integ-test/build.gradle b/integ-test/build.gradle index c64cbb8cf6..a461d854f8 100644 --- a/integ-test/build.gradle +++ b/integ-test/build.gradle @@ -17,11 +17,11 @@ configurations.all { } dependencies { - testCompile group: 'org.elasticsearch.test', name: 'framework', version:"${es_version}" - testCompile group: 'org.elasticsearch.client', name: 'elasticsearch-rest-high-level-client', version:"${es_version}" - testCompile group: 'org.elasticsearch.client', name: 'elasticsearch-rest-client', version:"${es_version}" + testCompile group: 'org.elasticsearch.test', name: 'framework', version: "${es_version}" + testCompile group: 'org.elasticsearch.client', name: 'elasticsearch-rest-high-level-client', version: "${es_version}" + testCompile group: 'org.elasticsearch.client', name: 'elasticsearch-rest-client', version: "${es_version}" testCompile group: 'org.hamcrest', name: 'hamcrest', version: '2.1' - testCompile group: 'org.apache.logging.log4j', name: 'log4j-core', version:'2.11.1' + testCompile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.11.1' testCompile project(path: ':', configuration: 'integtest') testCompile project(':plugin') testImplementation('org.junit.jupiter:junit-jupiter-api:5.6.2') @@ -39,7 +39,7 @@ test { tasks.integTest.dependsOn(':plugin:bundlePlugin') testClusters.integTest { - testDistribution='oss' + testDistribution = 'oss' plugin file(tasks.getByPath(':plugin:bundlePlugin').archiveFile) } diff --git a/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/DedupCommandIT.java b/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/DedupCommandIT.java index 4518578883..f23ac8d7a0 100644 --- a/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/DedupCommandIT.java +++ b/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/DedupCommandIT.java @@ -15,48 +15,61 @@ package com.amazon.opendistroforelasticsearch.sql.ppl; -import java.io.IOException; -import org.json.JSONObject; -import org.junit.jupiter.api.Test; import static com.amazon.opendistroforelasticsearch.sql.esintgtest.TestsConstants.TEST_INDEX_BANK; import static com.amazon.opendistroforelasticsearch.sql.esintgtest.TestsConstants.TEST_INDEX_BANK_WITH_NULL_VALUES; import static com.amazon.opendistroforelasticsearch.sql.util.MatcherUtils.rows; import static com.amazon.opendistroforelasticsearch.sql.util.MatcherUtils.verifyDataRows; +import java.io.IOException; +import org.json.JSONObject; +import org.junit.jupiter.api.Test; + public class DedupCommandIT extends PPLIntegTestCase { - @Override - public void init() throws IOException { - loadIndex(Index.BANK); - loadIndex(Index.BANK_WITH_NULL_VALUES); - } - - @Test - public void testDedup() throws IOException { - JSONObject result = executeQuery(String.format("source=%s | dedup male | fields male", TEST_INDEX_BANK)); - verifyDataRows(result, rows(true), rows(false)); - } - - @Test - public void testConsecutiveDedup() throws IOException { - JSONObject result = executeQuery(String.format( + @Override + public void init() throws IOException { + loadIndex(Index.BANK); + loadIndex(Index.BANK_WITH_NULL_VALUES); + } + + @Test + public void testDedup() throws IOException { + JSONObject result = + executeQuery(String.format("source=%s | dedup male | fields male", TEST_INDEX_BANK)); + verifyDataRows(result, rows(true), rows(false)); + } + + @Test + public void testConsecutiveDedup() throws IOException { + JSONObject result = + executeQuery( + String.format( "source=%s | dedup male consecutive=true | fields male", TEST_INDEX_BANK)); - verifyDataRows(result, rows(true), rows(false), rows(true), rows(false)); - } - - @Test - public void testAllowMoreDuplicates() throws IOException { - JSONObject result = executeQuery(String.format( - "source=%s | dedup 2 male | fields male", TEST_INDEX_BANK)); - verifyDataRows(result, rows(true), rows(true), rows(false), rows(false)); - } - - @Test - public void testKeepEmptyDedup() throws IOException { - JSONObject result = executeQuery(String.format( + verifyDataRows(result, rows(true), rows(false), rows(true), rows(false)); + } + + @Test + public void testAllowMoreDuplicates() throws IOException { + JSONObject result = + executeQuery(String.format("source=%s | dedup 2 male | fields male", TEST_INDEX_BANK)); + verifyDataRows(result, rows(true), rows(true), rows(false), rows(false)); + } + + @Test + public void testKeepEmptyDedup() throws IOException { + JSONObject result = + executeQuery( + String.format( "source=%s | dedup balance keepempty=true | fields firstname, balance", TEST_INDEX_BANK_WITH_NULL_VALUES)); - verifyDataRows(result, rows("Amber JOHnny", 39225), rows("Hattie"), rows("Nanette", 32838), - rows("Dale", 4180), rows("Elinor"), rows("Virginia"), rows("Dillard", 48086)); - } + verifyDataRows( + result, + rows("Amber JOHnny", 39225), + rows("Hattie"), + rows("Nanette", 32838), + rows("Dale", 4180), + rows("Elinor"), + rows("Virginia"), + rows("Dillard", 48086)); + } } diff --git a/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/FieldsCommandIT.java b/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/FieldsCommandIT.java index faa4225520..9d46746a5d 100644 --- a/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/FieldsCommandIT.java +++ b/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/FieldsCommandIT.java @@ -15,38 +15,42 @@ package com.amazon.opendistroforelasticsearch.sql.ppl; -import java.io.IOException; -import org.json.JSONObject; -import org.junit.Ignore; -import org.junit.jupiter.api.Test; import static com.amazon.opendistroforelasticsearch.sql.esintgtest.TestsConstants.TEST_INDEX_ACCOUNT; import static com.amazon.opendistroforelasticsearch.sql.util.MatcherUtils.columnName; import static com.amazon.opendistroforelasticsearch.sql.util.MatcherUtils.columnPattern; import static com.amazon.opendistroforelasticsearch.sql.util.MatcherUtils.verifyColumn; +import java.io.IOException; +import org.json.JSONObject; +import org.junit.Ignore; +import org.junit.jupiter.api.Test; + public class FieldsCommandIT extends PPLIntegTestCase { - @Override - public void init() throws IOException { - loadIndex(Index.ACCOUNT); - } - - @Test - public void testFieldsWithOneField() throws IOException { - JSONObject result = executeQuery(String.format("source=%s | fields firstname", TEST_INDEX_ACCOUNT)); - verifyColumn(result, columnName("firstname")); - } - - @Test - public void testFieldsWithMultiFields() throws IOException { - JSONObject result = executeQuery(String.format("source=%s | fields firstname, lastname", TEST_INDEX_ACCOUNT)); - verifyColumn(result, columnName("firstname"), columnName("lastname")); - } - - @Ignore("Cannot resolve wildcard yet") - @Test - public void testFieldsWildCard() throws IOException { - JSONObject result = executeQuery(String.format("source=%s | fields ", TEST_INDEX_ACCOUNT) + "firstnam%"); - verifyColumn(result, columnPattern("^firstnam.*")); - } + @Override + public void init() throws IOException { + loadIndex(Index.ACCOUNT); + } + + @Test + public void testFieldsWithOneField() throws IOException { + JSONObject result = + executeQuery(String.format("source=%s | fields firstname", TEST_INDEX_ACCOUNT)); + verifyColumn(result, columnName("firstname")); + } + + @Test + public void testFieldsWithMultiFields() throws IOException { + JSONObject result = + executeQuery(String.format("source=%s | fields firstname, lastname", TEST_INDEX_ACCOUNT)); + verifyColumn(result, columnName("firstname"), columnName("lastname")); + } + + @Ignore("Cannot resolve wildcard yet") + @Test + public void testFieldsWildCard() throws IOException { + JSONObject result = + executeQuery(String.format("source=%s | fields ", TEST_INDEX_ACCOUNT) + "firstnam%"); + verifyColumn(result, columnPattern("^firstnam.*")); + } } diff --git a/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/PPLIntegTestCase.java b/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/PPLIntegTestCase.java index ac72d51dc2..680d1075bd 100644 --- a/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/PPLIntegTestCase.java +++ b/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/PPLIntegTestCase.java @@ -15,7 +15,12 @@ package com.amazon.opendistroforelasticsearch.sql.ppl; +import static com.amazon.opendistroforelasticsearch.sql.esintgtest.TestUtils.getResponseBody; +import static com.amazon.opendistroforelasticsearch.sql.plugin.rest.RestPPLQueryAction.QUERY_API_ENDPOINT; + import com.amazon.opendistroforelasticsearch.sql.esintgtest.RestIntegTestCase; +import java.io.IOException; +import java.util.Locale; import org.elasticsearch.client.Request; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.Response; @@ -23,46 +28,34 @@ import org.json.JSONObject; import org.junit.Assert; -import java.io.IOException; -import java.util.Locale; - -import static com.amazon.opendistroforelasticsearch.sql.esintgtest.TestUtils.getResponseBody; -import static com.amazon.opendistroforelasticsearch.sql.plugin.rest.RestPPLQueryAction.QUERY_API_ENDPOINT; - -/** - * ES Rest integration test base for PPL testing - */ +/** ES Rest integration test base for PPL testing. */ public abstract class PPLIntegTestCase extends RestIntegTestCase { - protected JSONObject executeQuery(String query) throws IOException { - return jsonify(executeQueryToString(query)); - } - - protected String executeQueryToString(String query) throws IOException { - Response response = client().performRequest(buildRequest(query)); - Assert.assertEquals(200, response.getStatusLine().getStatusCode()); - return getResponseBody(response, true); - } - - protected Request buildRequest(String query) { - Request request = new Request("POST", QUERY_API_ENDPOINT); - request.setJsonEntity(String.format(Locale.ROOT, - "{\n" + - " \"query\": \"%s\"\n" + - "}", query)); - - RequestOptions.Builder restOptionsBuilder = RequestOptions.DEFAULT.toBuilder(); - restOptionsBuilder.addHeader("Content-Type", "application/json"); - request.setOptions(restOptionsBuilder); - return request; + protected JSONObject executeQuery(String query) throws IOException { + return jsonify(executeQueryToString(query)); + } + + protected String executeQueryToString(String query) throws IOException { + Response response = client().performRequest(buildRequest(query)); + Assert.assertEquals(200, response.getStatusLine().getStatusCode()); + return getResponseBody(response, true); + } + + protected Request buildRequest(String query) { + Request request = new Request("POST", QUERY_API_ENDPOINT); + request.setJsonEntity(String.format(Locale.ROOT, "{\n" + " \"query\": \"%s\"\n" + "}", query)); + + RequestOptions.Builder restOptionsBuilder = RequestOptions.DEFAULT.toBuilder(); + restOptionsBuilder.addHeader("Content-Type", "application/json"); + request.setOptions(restOptionsBuilder); + return request; + } + + private JSONObject jsonify(String text) { + try { + return new JSONObject(text); + } catch (JSONException e) { + throw new IllegalStateException(String.format("Failed to transform %s to JSON format", text)); } - - private JSONObject jsonify(String text) { - try { - return new JSONObject(text); - } catch (JSONException e) { - throw new IllegalStateException(String.format("Failed to transform %s to JSON format", text)); - } - } - + } } diff --git a/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/PPLPluginIT.java b/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/PPLPluginIT.java index c49a9bab52..a6eb31f74b 100644 --- a/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/PPLPluginIT.java +++ b/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/PPLPluginIT.java @@ -15,6 +15,10 @@ package com.amazon.opendistroforelasticsearch.sql.ppl; +import static org.hamcrest.Matchers.hasProperty; + +import java.io.IOException; +import java.util.Locale; import org.elasticsearch.client.Request; import org.elasticsearch.client.Response; import org.elasticsearch.client.ResponseException; @@ -24,69 +28,59 @@ import org.junit.Test; import org.junit.rules.ExpectedException; -import java.io.IOException; -import java.util.Locale; - -import static org.hamcrest.Matchers.hasProperty; - public class PPLPluginIT extends PPLIntegTestCase { - @Rule - public ExpectedException exceptionRule = ExpectedException.none(); + @Rule public ExpectedException exceptionRule = ExpectedException.none(); - @Override - protected void init() throws Exception { - wipeAllClusterSettings(); - } + @Override + protected void init() throws Exception { + wipeAllClusterSettings(); + } - @Test - public void testQueryEndpointShouldOK() throws IOException { - Request request = new Request("PUT", "/a/_doc/1?refresh=true"); - request.setJsonEntity("{\"name\": \"hello\"}"); - client().performRequest(request); + @Test + public void testQueryEndpointShouldOK() throws IOException { + Request request = new Request("PUT", "/a/_doc/1?refresh=true"); + request.setJsonEntity("{\"name\": \"hello\"}"); + client().performRequest(request); - String response = executeQueryToString("search source=a"); - assertEquals( - "{\n" + - " \"schema\": [{\n" + - " \"name\": \"name\",\n" + - " \"type\": \"string\"\n" + - " }],\n" + - " \"total\": 1,\n" + - " \"datarows\": [[\"hello\"]],\n" + - " \"size\": 1\n" + - "}\n", - response - ); - } + String response = executeQueryToString("search source=a"); + assertEquals( + "{\n" + + " \"schema\": [{\n" + + " \"name\": \"name\",\n" + + " \"type\": \"string\"\n" + + " }],\n" + + " \"total\": 1,\n" + + " \"datarows\": [[\"hello\"]],\n" + + " \"size\": 1\n" + + "}\n", + response); + } - @Test - public void testQueryEndpointShouldFail() throws IOException { - exceptionRule.expect(ResponseException.class); - exceptionRule.expect(hasProperty("response", statusCode(500))); + @Test + public void testQueryEndpointShouldFail() throws IOException { + exceptionRule.expect(ResponseException.class); + exceptionRule.expect(hasProperty("response", statusCode(500))); - client().performRequest(makeRequest("search invalid")); - } + client().performRequest(makeRequest("search invalid")); + } - protected Request makeRequest(String query) { - Request post = new Request("POST", "/_opendistro/_ppl"); - post.setJsonEntity(String.format(Locale.ROOT, - "{\n" + - " \"query\": \"%s\"\n" + - "}", query)); - return post; - } + protected Request makeRequest(String query) { + Request post = new Request("POST", "/_opendistro/_ppl"); + post.setJsonEntity(String.format(Locale.ROOT, "{\n" + " \"query\": \"%s\"\n" + "}", query)); + return post; + } - private TypeSafeMatcher statusCode(int statusCode) { - return new TypeSafeMatcher() { - @Override - public void describeTo(Description description) { - description.appendText(String.format(Locale.ROOT, "statusCode=%d", statusCode)); - } + private TypeSafeMatcher statusCode(int statusCode) { + return new TypeSafeMatcher() { + @Override + public void describeTo(Description description) { + description.appendText(String.format(Locale.ROOT, "statusCode=%d", statusCode)); + } - @Override - protected boolean matchesSafely(Response resp) { - return resp.getStatusLine().getStatusCode() == statusCode; - } - }; - } + @Override + protected boolean matchesSafely(Response resp) { + return resp.getStatusLine().getStatusCode() == statusCode; + } + }; + } } diff --git a/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/QueryAnalysisIT.java b/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/QueryAnalysisIT.java index a9de5850e9..534ad5fcf5 100644 --- a/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/QueryAnalysisIT.java +++ b/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/QueryAnalysisIT.java @@ -15,110 +15,110 @@ package com.amazon.opendistroforelasticsearch.sql.ppl; +import static com.amazon.opendistroforelasticsearch.sql.esintgtest.TestsConstants.TEST_INDEX_ACCOUNT; + import com.amazon.opendistroforelasticsearch.sql.exception.SemanticCheckException; import java.io.IOException; import org.elasticsearch.client.ResponseException; import org.junit.Ignore; import org.junit.Test; -import static com.amazon.opendistroforelasticsearch.sql.esintgtest.TestsConstants.TEST_INDEX_ACCOUNT; public class QueryAnalysisIT extends PPLIntegTestCase { - @Override - public void init() throws IOException { - loadIndex(Index.ACCOUNT); - } - - /** - * Valid commands should pass semantic check - */ - @Test - public void searchCommandShouldPassSemanticCheck() { - String query = String.format("search source=%s age=20", TEST_INDEX_ACCOUNT); - queryShouldPassSemanticCheck(query); - } - - @Test - public void whereCommandShouldPassSemanticCheck() { - String query = String.format("search source=%s | where age=20", TEST_INDEX_ACCOUNT); - queryShouldPassSemanticCheck(query); + @Override + public void init() throws IOException { + loadIndex(Index.ACCOUNT); + } + + /** Valid commands should pass semantic check. */ + @Test + public void searchCommandShouldPassSemanticCheck() { + String query = String.format("search source=%s age=20", TEST_INDEX_ACCOUNT); + queryShouldPassSemanticCheck(query); + } + + @Test + public void whereCommandShouldPassSemanticCheck() { + String query = String.format("search source=%s | where age=20", TEST_INDEX_ACCOUNT); + queryShouldPassSemanticCheck(query); + } + + @Test + public void fieldsCommandShouldPassSemanticCheck() { + String query = String.format("search source=%s | fields firstname", TEST_INDEX_ACCOUNT); + queryShouldPassSemanticCheck(query); + } + + @Ignore("Can't resolve target field yet") + @Test + public void renameCommandShouldPassSemanticCheck() { + String query = + String.format("search source=%s | rename firstname as first", TEST_INDEX_ACCOUNT); + queryShouldPassSemanticCheck(query); + } + + @Test + public void statsCommandShouldPassSemanticCheck() { + String query = String.format("search source=%s | stats avg(age)", TEST_INDEX_ACCOUNT); + queryShouldPassSemanticCheck(query); + } + + @Test + public void dedupCommandShouldPassSemanticCheck() { + String query = + String.format("search source=%s | dedup firstname, lastname", TEST_INDEX_ACCOUNT); + queryShouldPassSemanticCheck(query); + } + + @Test + public void sortCommandShouldPassSemanticCheck() { + String query = String.format("search source=%s | sort age", TEST_INDEX_ACCOUNT); + queryShouldPassSemanticCheck(query); + } + + @Test + public void evalCommandShouldPassSemanticCheck() { + String query = String.format("search source=%s | eval age=abs(age)", TEST_INDEX_ACCOUNT); + queryShouldPassSemanticCheck(query); + } + + /** + * Commands that fail semantic analysis should throw {@link SemanticCheckException}. + */ + @Test + public void unsupportedAggregationShouldFailSemanticCheck() { + String query = String.format("search source=%s | stats range(age)", TEST_INDEX_ACCOUNT); + queryShouldThrowSemanticException(query, "Unsupported aggregation function range"); + } + + @Test + public void nonexistentFieldShouldFailSemanticCheck() { + String query = String.format("search source=%s | fields name", TEST_INDEX_ACCOUNT); + queryShouldThrowSemanticException(query, "can't resolve expression name in type env"); + } + + private void queryShouldPassSemanticCheck(String query) { + try { + executeQuery(query); + } catch (SemanticCheckException e) { + fail("Expected to pass semantic check but failed for query: " + query); + } catch (IOException e) { + throw new IllegalStateException("Unexpected IOException raised for query: " + query); } - - @Test - public void fieldsCommandShouldPassSemanticCheck() { - String query = String.format("search source=%s | fields firstname", TEST_INDEX_ACCOUNT); - queryShouldPassSemanticCheck(query); - } - - @Ignore("Can't resolve target field yet") - @Test - public void renameCommandShouldPassSemanticCheck() { - String query = String.format("search source=%s | rename firstname as first", TEST_INDEX_ACCOUNT); - queryShouldPassSemanticCheck(query); - } - - @Test - public void statsCommandShouldPassSemanticCheck() { - String query = String.format("search source=%s | stats avg(age)", TEST_INDEX_ACCOUNT); - queryShouldPassSemanticCheck(query); - } - - @Test - public void dedupCommandShouldPassSemanticCheck() { - String query = String.format("search source=%s | dedup firstname, lastname", TEST_INDEX_ACCOUNT); - queryShouldPassSemanticCheck(query); + } + + private void queryShouldThrowSemanticException(String query, String... messages) { + try { + executeQuery(query); + fail("Expected to throw SemanticCheckException, but none was thrown for query: " + query); + } catch (ResponseException e) { + String errorMsg = e.getMessage(); + assertTrue(errorMsg.contains("SemanticCheckException")); + for (String msg : messages) { + assertTrue(errorMsg.contains(msg)); + } + } catch (IOException e) { + throw new IllegalStateException("Unexpected exception raised for query: " + query); } - - @Test - public void sortCommandShouldPassSemanticCheck() { - String query = String.format("search source=%s | sort age", TEST_INDEX_ACCOUNT); - queryShouldPassSemanticCheck(query); - } - - @Test - public void evalCommandShouldPassSemanticCheck() { - String query = String.format("search source=%s | eval age=abs(age)", TEST_INDEX_ACCOUNT); - queryShouldPassSemanticCheck(query); - } - - /** - * Commands that fail semantic analysis should throw {@link SemanticCheckException} - */ - @Test - public void unsupportedAggregationShouldFailSemanticCheck() { - String query = String.format("search source=%s | stats range(age)", TEST_INDEX_ACCOUNT); - queryShouldThrowSemanticException(query, "Unsupported aggregation function range"); - } - - @Test - public void nonexistentFieldShouldFailSemanticCheck() { - String query = String.format("search source=%s | fields name", TEST_INDEX_ACCOUNT); - queryShouldThrowSemanticException(query, "can't resolve expression name in type env"); - } - - private void queryShouldPassSemanticCheck(String query) { - try { - executeQuery(query); - } catch (SemanticCheckException e) { - fail("Expected to pass semantic check but failed for query: " + query); - } catch (IOException e) { - throw new IllegalStateException("Unexpected IOException raised for query: " + query); - } - } - - private void queryShouldThrowSemanticException(String query, String... messages) { - try { - executeQuery(query); - fail("Expected to throw SemanticCheckException, but none was thrown for query: " + query); - } catch (ResponseException e) { - String errorMsg = e.getMessage(); - assertTrue(errorMsg.contains("SemanticCheckException")); - for (String msg: messages) { - assertTrue(errorMsg.contains(msg)); - } - } catch (IOException e) { - throw new IllegalStateException("Unexpected exception raised for query: " + query); - } - } - + } } diff --git a/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/RenameCommandIT.java b/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/RenameCommandIT.java index 441014d953..95917a03e8 100644 --- a/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/RenameCommandIT.java +++ b/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/RenameCommandIT.java @@ -15,34 +15,37 @@ package com.amazon.opendistroforelasticsearch.sql.ppl; -import java.io.IOException; -import org.json.JSONObject; -import org.junit.Ignore; -import org.junit.jupiter.api.Test; - import static com.amazon.opendistroforelasticsearch.sql.esintgtest.TestsConstants.TEST_INDEX_ACCOUNT; import static com.amazon.opendistroforelasticsearch.sql.util.MatcherUtils.columnName; import static com.amazon.opendistroforelasticsearch.sql.util.MatcherUtils.columnPattern; import static com.amazon.opendistroforelasticsearch.sql.util.MatcherUtils.verifyColumn; +import java.io.IOException; +import org.json.JSONObject; +import org.junit.Ignore; +import org.junit.jupiter.api.Test; + @Ignore("Rename target cannot be resolved yet") public class RenameCommandIT extends PPLIntegTestCase { - @Override - public void init() throws IOException { - loadIndex(Index.ACCOUNT); - } + @Override + public void init() throws IOException { + loadIndex(Index.ACCOUNT); + } - @Test - public void testRenameOneField() throws IOException { - JSONObject result = executeQuery(String.format( - "source=%s | fields firstname | rename firstname as first_name", TEST_INDEX_ACCOUNT)); - verifyColumn(result, columnName("first_name")); - } + @Test + public void testRenameOneField() throws IOException { + JSONObject result = + executeQuery( + String.format( + "source=%s | fields firstname | rename firstname as first_name", + TEST_INDEX_ACCOUNT)); + verifyColumn(result, columnName("first_name")); + } - @Test - public void testRenameWildcardFields() throws IOException { - JSONObject result = executeQuery("source=" + TEST_INDEX_ACCOUNT + " | rename %name as %NAME"); - verifyColumn(result, columnPattern(".*name$")); - } + @Test + public void testRenameWildcardFields() throws IOException { + JSONObject result = executeQuery("source=" + TEST_INDEX_ACCOUNT + " | rename %name as %NAME"); + verifyColumn(result, columnPattern(".*name$")); + } } diff --git a/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/SearchCommandIT.java b/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/SearchCommandIT.java index d299143e9c..d294aece0c 100644 --- a/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/SearchCommandIT.java +++ b/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/SearchCommandIT.java @@ -15,10 +15,6 @@ package com.amazon.opendistroforelasticsearch.sql.ppl; -import java.io.IOException; -import org.elasticsearch.client.ResponseException; -import org.json.JSONObject; -import org.junit.jupiter.api.Test; import static com.amazon.opendistroforelasticsearch.sql.esintgtest.TestsConstants.TEST_INDEX_BANK; import static com.amazon.opendistroforelasticsearch.sql.esintgtest.TestsConstants.TEST_INDEX_DOG; import static com.amazon.opendistroforelasticsearch.sql.util.MatcherUtils.columnName; @@ -26,43 +22,49 @@ import static com.amazon.opendistroforelasticsearch.sql.util.MatcherUtils.verifyColumn; import static com.amazon.opendistroforelasticsearch.sql.util.MatcherUtils.verifyDataRows; +import java.io.IOException; +import org.elasticsearch.client.ResponseException; +import org.json.JSONObject; +import org.junit.jupiter.api.Test; + public class SearchCommandIT extends PPLIntegTestCase { - @Override - public void init() throws IOException { - loadIndex(Index.BANK); - loadIndex(Index.DOG); - } + @Override + public void init() throws IOException { + loadIndex(Index.BANK); + loadIndex(Index.DOG); + } - @Test - public void testSearchAllFields() throws IOException { - JSONObject result = executeQuery(String.format("search source=%s", TEST_INDEX_DOG)); - verifyColumn(result, columnName("dog_name"), columnName("holdersName"), columnName("age")); - } + @Test + public void testSearchAllFields() throws IOException { + JSONObject result = executeQuery(String.format("search source=%s", TEST_INDEX_DOG)); + verifyColumn(result, columnName("dog_name"), columnName("holdersName"), columnName("age")); + } - @Test - public void testSearchCommandWithoutSearchKeyword() throws IOException { - assertEquals( - executeQueryToString(String.format("search source=%s", TEST_INDEX_BANK)), - executeQueryToString(String.format("source=%s", TEST_INDEX_BANK)) - ); - } + @Test + public void testSearchCommandWithoutSearchKeyword() throws IOException { + assertEquals( + executeQueryToString(String.format("search source=%s", TEST_INDEX_BANK)), + executeQueryToString(String.format("source=%s", TEST_INDEX_BANK))); + } - @Test - public void testSearchCommandWithLogicalExpression() throws IOException { - JSONObject result = executeQuery(String.format( + @Test + public void testSearchCommandWithLogicalExpression() throws IOException { + JSONObject result = + executeQuery( + String.format( "search source=%s firstname='Hattie' | fields firstname", TEST_INDEX_BANK)); - verifyDataRows(result, rows("Hattie")); - } + verifyDataRows(result, rows("Hattie")); + } - @Test - public void searchCommandWithoutSourceShouldFailToParse() throws IOException { - try { - executeQuery("search firstname='Hattie'"); - fail(); - } catch (ResponseException e) { - assertTrue(e.getMessage().contains("RuntimeException")); - assertTrue(e.getMessage().contains("Failed to parse query due to offending symbol")); - } + @Test + public void searchCommandWithoutSourceShouldFailToParse() throws IOException { + try { + executeQuery("search firstname='Hattie'"); + fail(); + } catch (ResponseException e) { + assertTrue(e.getMessage().contains("RuntimeException")); + assertTrue(e.getMessage().contains("Failed to parse query due to offending symbol")); } + } } diff --git a/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/SortCommandIT.java b/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/SortCommandIT.java index cea4d038c3..868b122ff2 100644 --- a/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/SortCommandIT.java +++ b/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/SortCommandIT.java @@ -15,53 +15,72 @@ package com.amazon.opendistroforelasticsearch.sql.ppl; -import java.io.IOException; -import org.json.JSONObject; -import org.junit.Ignore; -import org.junit.Test; import static com.amazon.opendistroforelasticsearch.sql.esintgtest.TestsConstants.TEST_INDEX_BANK; import static com.amazon.opendistroforelasticsearch.sql.esintgtest.TestsConstants.TEST_INDEX_BANK_WITH_NULL_VALUES; import static com.amazon.opendistroforelasticsearch.sql.esintgtest.TestsConstants.TEST_INDEX_DOG; import static com.amazon.opendistroforelasticsearch.sql.util.MatcherUtils.rows; import static com.amazon.opendistroforelasticsearch.sql.util.MatcherUtils.verifyOrder; -public class SortCommandIT extends PPLIntegTestCase { +import java.io.IOException; +import org.json.JSONObject; +import org.junit.Ignore; +import org.junit.Test; - @Override - public void init() throws IOException { - loadIndex(Index.BANK); - loadIndex(Index.BANK_WITH_NULL_VALUES); - loadIndex(Index.DOG); - } +public class SortCommandIT extends PPLIntegTestCase { - @Test - public void testSortCommand() throws IOException { - JSONObject result = executeQuery(String.format("source=%s | sort age | fields age", TEST_INDEX_BANK)); - verifyOrder(result, rows(28), rows(32), rows(33), - rows(34), rows(36), rows(36),rows(39)); - } + @Override + public void init() throws IOException { + loadIndex(Index.BANK); + loadIndex(Index.BANK_WITH_NULL_VALUES); + loadIndex(Index.DOG); + } + @Test + public void testSortCommand() throws IOException { + JSONObject result = + executeQuery(String.format("source=%s | sort age | fields age", TEST_INDEX_BANK)); + verifyOrder(result, rows(28), rows(32), rows(33), rows(34), rows(36), rows(36), rows(39)); + } - @Ignore("Order with duplicated value") - @Test - public void testSortWithNullValue() throws IOException { - JSONObject result = executeQuery(String.format( - "source=%s | sort balance | fields firstname, balance", TEST_INDEX_BANK_WITH_NULL_VALUES)); - verifyOrder(result, rows("Hattie"), rows("Elinor"), rows("Virginia"), rows("Dale", 4180), - rows("Nanette", 32838), rows("Amber JOHnny", 39225),rows("Dillard", 48086)); - } + @Ignore("Order with duplicated value") + @Test + public void testSortWithNullValue() throws IOException { + JSONObject result = + executeQuery( + String.format( + "source=%s | sort balance | fields firstname, balance", + TEST_INDEX_BANK_WITH_NULL_VALUES)); + verifyOrder( + result, + rows("Hattie"), + rows("Elinor"), + rows("Virginia"), + rows("Dale", 4180), + rows("Nanette", 32838), + rows("Amber JOHnny", 39225), + rows("Dillard", 48086)); + } - @Test - public void testSortStringField() throws IOException { - JSONObject result = executeQuery(String.format("source=%s | sort lastname | fields lastname", TEST_INDEX_BANK)); - verifyOrder(result, rows("Adams"), rows("Ayala"), rows("Bates"), rows("Bond"), - rows("Duke Willmington"), rows("Mcpherson"), rows("Ratliff")); - } + @Test + public void testSortStringField() throws IOException { + JSONObject result = + executeQuery(String.format("source=%s | sort lastname | fields lastname", TEST_INDEX_BANK)); + verifyOrder( + result, + rows("Adams"), + rows("Ayala"), + rows("Bates"), + rows("Bond"), + rows("Duke Willmington"), + rows("Mcpherson"), + rows("Ratliff")); + } - @Test - public void testSortMultipleFields() throws IOException { - JSONObject result = executeQuery(String.format( - "source=%s | sort dog_name, age | fields dog_name, age", TEST_INDEX_DOG)); - verifyOrder(result, rows("rex", 2), rows("snoopy", 4)); - } + @Test + public void testSortMultipleFields() throws IOException { + JSONObject result = + executeQuery( + String.format("source=%s | sort dog_name, age | fields dog_name, age", TEST_INDEX_DOG)); + verifyOrder(result, rows("rex", 2), rows("snoopy", 4)); + } } diff --git a/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/StandaloneIT.java b/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/StandaloneIT.java index 6d665fcd48..8907ebb1e6 100644 --- a/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/StandaloneIT.java +++ b/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/StandaloneIT.java @@ -16,6 +16,8 @@ package com.amazon.opendistroforelasticsearch.sql.ppl; +import static com.amazon.opendistroforelasticsearch.sql.protocol.response.format.JsonResponseFormatter.Style.PRETTY; + import com.amazon.opendistroforelasticsearch.sql.common.response.ResponseListener; import com.amazon.opendistroforelasticsearch.sql.elasticsearch.client.ElasticsearchClient; import com.amazon.opendistroforelasticsearch.sql.elasticsearch.client.ElasticsearchRestClient; @@ -28,6 +30,8 @@ import com.amazon.opendistroforelasticsearch.sql.protocol.response.QueryResult; import com.amazon.opendistroforelasticsearch.sql.protocol.response.format.SimpleJsonResponseFormatter; import com.amazon.opendistroforelasticsearch.sql.storage.StorageEngine; +import java.io.IOException; +import java.util.concurrent.atomic.AtomicReference; import org.elasticsearch.client.Node; import org.elasticsearch.client.Request; import org.elasticsearch.client.RestClient; @@ -36,88 +40,82 @@ import org.junit.jupiter.api.Test; import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import java.io.IOException; -import java.util.concurrent.atomic.AtomicReference; - -import static com.amazon.opendistroforelasticsearch.sql.protocol.response.format.JsonResponseFormatter.Style.PRETTY; - /** - * Run PPL with query engine outside Elasticsearch cluster. This IT doesn't require our plugin installed actually. - * The client application, ex. JDBC driver, needs to initialize all components itself required by ppl service. + * Run PPL with query engine outside Elasticsearch cluster. This IT doesn't require our plugin + * installed actually. The client application, ex. JDBC driver, needs to initialize all components + * itself required by ppl service. */ public class StandaloneIT extends PPLIntegTestCase { - private RestHighLevelClient restClient; - - private PPLService pplService; - - @Override - public void init() { - restClient = new RestHighLevelClient( - RestClient.builder(client().getNodes().toArray(new Node[0]))); - - ElasticsearchClient client = new ElasticsearchRestClient(restClient); - AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); - context.registerBean(StorageEngine.class, () -> new ElasticsearchStorageEngine(client)); - context.registerBean(ExecutionEngine.class, () -> new ElasticsearchExecutionEngine(client)); - context.register(PPLServiceConfig.class); - context.refresh(); - - pplService = context.getBean(PPLService.class); - } - - @AfterEach - public void tearDown() throws Exception { - restClient.close(); - super.tearDown(); - } - - @Test - public void testSourceFieldQuery() throws IOException { - Request request1 = new Request("PUT", "/test/_doc/1?refresh=true"); - request1.setJsonEntity("{\"name\": \"hello\", \"age\": 20}"); - client().performRequest(request1); - Request request2 = new Request("PUT", "/test/_doc/2?refresh=true"); - request2.setJsonEntity("{\"name\": \"world\", \"age\": 30}"); - client().performRequest(request2); - - String actual = executeByStandaloneQueryEngine("source=test | fields name"); - assertEquals( - "{\n" + - " \"schema\": [{\n" + - " \"name\": \"name\",\n" + - " \"type\": \"string\"\n" + - " }],\n" + - " \"total\": 2,\n" + - " \"datarows\": [\n" + - " [\"hello\"],\n" + - " [\"world\"]\n" + - " ],\n" + - " \"size\": 2\n" + - "}", - actual - ); - } - - private String executeByStandaloneQueryEngine(String query) { - AtomicReference actual = new AtomicReference<>(); - pplService.execute( - new PPLQueryRequest(query, null), - new ResponseListener() { - - @Override - public void onResponse(QueryResponse response) { - QueryResult result = new QueryResult(response.getResults()); - String json = new SimpleJsonResponseFormatter(PRETTY).format(result); - actual.set(json); - } - - @Override - public void onFailure(Exception e) { - throw new IllegalStateException("Exception happened during execution", e); - } - }); - return actual.get(); - } - + private RestHighLevelClient restClient; + + private PPLService pplService; + + @Override + public void init() { + restClient = + new RestHighLevelClient(RestClient.builder(client().getNodes().toArray(new Node[0]))); + + ElasticsearchClient client = new ElasticsearchRestClient(restClient); + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + context.registerBean(StorageEngine.class, () -> new ElasticsearchStorageEngine(client)); + context.registerBean(ExecutionEngine.class, () -> new ElasticsearchExecutionEngine(client)); + context.register(PPLServiceConfig.class); + context.refresh(); + + pplService = context.getBean(PPLService.class); + } + + @AfterEach + public void tearDown() throws Exception { + restClient.close(); + super.tearDown(); + } + + @Test + public void testSourceFieldQuery() throws IOException { + Request request1 = new Request("PUT", "/test/_doc/1?refresh=true"); + request1.setJsonEntity("{\"name\": \"hello\", \"age\": 20}"); + client().performRequest(request1); + Request request2 = new Request("PUT", "/test/_doc/2?refresh=true"); + request2.setJsonEntity("{\"name\": \"world\", \"age\": 30}"); + client().performRequest(request2); + + String actual = executeByStandaloneQueryEngine("source=test | fields name"); + assertEquals( + "{\n" + + " \"schema\": [{\n" + + " \"name\": \"name\",\n" + + " \"type\": \"string\"\n" + + " }],\n" + + " \"total\": 2,\n" + + " \"datarows\": [\n" + + " [\"hello\"],\n" + + " [\"world\"]\n" + + " ],\n" + + " \"size\": 2\n" + + "}", + actual); + } + + private String executeByStandaloneQueryEngine(String query) { + AtomicReference actual = new AtomicReference<>(); + pplService.execute( + new PPLQueryRequest(query, null), + new ResponseListener() { + + @Override + public void onResponse(QueryResponse response) { + QueryResult result = new QueryResult(response.getResults()); + String json = new SimpleJsonResponseFormatter(PRETTY).format(result); + actual.set(json); + } + + @Override + public void onFailure(Exception e) { + throw new IllegalStateException("Exception happened during execution", e); + } + }); + return actual.get(); + } } diff --git a/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/StatsCommandIT.java b/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/StatsCommandIT.java index 2b5c1f4c87..6dd1d399ee 100644 --- a/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/StatsCommandIT.java +++ b/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/StatsCommandIT.java @@ -15,21 +15,23 @@ package com.amazon.opendistroforelasticsearch.sql.ppl; +import static com.amazon.opendistroforelasticsearch.sql.esintgtest.TestsConstants.TEST_INDEX_ACCOUNT; + import java.io.IOException; import org.junit.jupiter.api.Test; -import static com.amazon.opendistroforelasticsearch.sql.esintgtest.TestsConstants.TEST_INDEX_ACCOUNT; public class StatsCommandIT extends PPLIntegTestCase { - @Override - public void init() throws IOException { - loadIndex(Index.ACCOUNT); - } + @Override + public void init() throws IOException { + loadIndex(Index.ACCOUNT); + } - @Test - public void testStatsAvg() throws IOException { - String result = executeQueryToString(String.format("source=%s | stats avg(age)", TEST_INDEX_ACCOUNT)); - assertEquals( + @Test + public void testStatsAvg() throws IOException { + String result = + executeQueryToString(String.format("source=%s | stats avg(age)", TEST_INDEX_ACCOUNT)); + assertEquals( "{\n" + " \"schema\": [{\n" + " \"name\": \"avg(age)\",\n" @@ -39,13 +41,14 @@ public void testStatsAvg() throws IOException { + " \"datarows\": [[30.171]],\n" + " \"size\": 1\n" + "}\n", - result); - } + result); + } - @Test - public void testStatsSum() throws IOException { - String result = executeQueryToString(String.format("source=%s | stats sum(balance)", TEST_INDEX_ACCOUNT)); - assertEquals( + @Test + public void testStatsSum() throws IOException { + String result = + executeQueryToString(String.format("source=%s | stats sum(balance)", TEST_INDEX_ACCOUNT)); + assertEquals( "{\n" + " \"schema\": [{\n" + " \"name\": \"sum(balance)\",\n" @@ -55,13 +58,15 @@ public void testStatsSum() throws IOException { + " \"datarows\": [[25714837]],\n" + " \"size\": 1\n" + "}\n", - result); - } + result); + } - @Test - public void testStatsCount() throws IOException { - String result = executeQueryToString(String.format("source=%s | stats count(account_number)", TEST_INDEX_ACCOUNT)); - assertEquals( + @Test + public void testStatsCount() throws IOException { + String result = + executeQueryToString( + String.format("source=%s | stats count(account_number)", TEST_INDEX_ACCOUNT)); + assertEquals( "{\n" + " \"schema\": [{\n" + " \"name\": \"count(account_number)\",\n" @@ -71,8 +76,8 @@ public void testStatsCount() throws IOException { + " \"datarows\": [[1000]],\n" + " \"size\": 1\n" + "}\n", - result); - } + result); + } - //TODO: each stats aggregate function should be tested here when implemented + // TODO: each stats aggregate function should be tested here when implemented } diff --git a/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/WhereCommandIT.java b/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/WhereCommandIT.java index af87eaaa18..17e5d3c1c3 100644 --- a/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/WhereCommandIT.java +++ b/integ-test/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/WhereCommandIT.java @@ -15,40 +15,48 @@ package com.amazon.opendistroforelasticsearch.sql.ppl; -import java.io.IOException; -import org.json.JSONObject; -import org.junit.jupiter.api.Test; import static com.amazon.opendistroforelasticsearch.sql.esintgtest.TestsConstants.TEST_INDEX_ACCOUNT; import static com.amazon.opendistroforelasticsearch.sql.util.MatcherUtils.rows; import static com.amazon.opendistroforelasticsearch.sql.util.MatcherUtils.verifyDataRows; +import java.io.IOException; +import org.json.JSONObject; +import org.junit.jupiter.api.Test; + public class WhereCommandIT extends PPLIntegTestCase { - @Override - public void init() throws IOException { - loadIndex(Index.ACCOUNT); - } - - @Test - public void testWhereWithLogicalExpr() throws IOException { - JSONObject result = executeQuery(String.format( - "source=%s | fields firstname | where firstname='Amber' | fields firstname", TEST_INDEX_ACCOUNT)); - verifyDataRows(result, rows("Amber")); - } - - @Test - public void testWhereWithMultiLogicalExpr() throws IOException { - JSONObject result = executeQuery(String.format( - "source=%s | where firstname='Amber' lastname='Duke' age=32 | fields firstname, lastname, age", + @Override + public void init() throws IOException { + loadIndex(Index.ACCOUNT); + } + + @Test + public void testWhereWithLogicalExpr() throws IOException { + JSONObject result = + executeQuery( + String.format( + "source=%s | fields firstname | where firstname='Amber' | fields firstname", TEST_INDEX_ACCOUNT)); - verifyDataRows(result, rows("Amber", "Duke", 32)); - } - - @Test - public void testWhereEquivalentSortCommand() throws IOException { - assertEquals( - executeQueryToString(String.format("source=%s | where firstname='Amber'", TEST_INDEX_ACCOUNT)), - executeQueryToString(String.format("source=%s firstname='Amber'", TEST_INDEX_ACCOUNT)) - ); - } + verifyDataRows(result, rows("Amber")); + } + + @Test + public void testWhereWithMultiLogicalExpr() throws IOException { + JSONObject result = + executeQuery( + String.format( + "source=%s " + + "| where firstname='Amber' lastname='Duke' age=32 " + + "| fields firstname, lastname, age", + TEST_INDEX_ACCOUNT)); + verifyDataRows(result, rows("Amber", "Duke", 32)); + } + + @Test + public void testWhereEquivalentSortCommand() throws IOException { + assertEquals( + executeQueryToString( + String.format("source=%s | where firstname='Amber'", TEST_INDEX_ACCOUNT)), + executeQueryToString(String.format("source=%s firstname='Amber'", TEST_INDEX_ACCOUNT))); + } } diff --git a/plugin/build.gradle b/plugin/build.gradle index f8f7288cb0..0f48ae0038 100644 --- a/plugin/build.gradle +++ b/plugin/build.gradle @@ -1,6 +1,8 @@ -apply plugin: 'java' -apply plugin: 'idea' -apply plugin: 'elasticsearch.esplugin' +plugins { + id 'java' + id 'jacoco' + id 'elasticsearch.esplugin' +} ext { projectSubstitutions = [:] diff --git a/plugin/src/main/java/com/amazon/opendistroforelasticsearch/sql/plugin/SQLPlugin.java b/plugin/src/main/java/com/amazon/opendistroforelasticsearch/sql/plugin/SQLPlugin.java index 0fec7c03dc..7e276a9e78 100644 --- a/plugin/src/main/java/com/amazon/opendistroforelasticsearch/sql/plugin/SQLPlugin.java +++ b/plugin/src/main/java/com/amazon/opendistroforelasticsearch/sql/plugin/SQLPlugin.java @@ -16,6 +16,11 @@ package com.amazon.opendistroforelasticsearch.sql.plugin; import com.amazon.opendistroforelasticsearch.sql.plugin.rest.RestPPLQueryAction; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.function.Supplier; import org.elasticsearch.client.Client; import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; import org.elasticsearch.cluster.node.DiscoveryNodes; @@ -36,38 +41,38 @@ import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.watcher.ResourceWatcherService; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.Objects; -import java.util.function.Supplier; - public class SQLPlugin extends Plugin implements ActionPlugin { - private ClusterService clusterService; + private ClusterService clusterService; - @Override - public List getRestHandlers(Settings settings, RestController restController, - ClusterSettings clusterSettings, IndexScopedSettings indexScopedSettings, - SettingsFilter settingsFilter, - IndexNameExpressionResolver indexNameExpressionResolver, - Supplier nodesInCluster) { - Objects.requireNonNull(clusterService, "Cluster service is required"); - return Arrays.asList( - new RestPPLQueryAction(restController, clusterService) - ); - } + @Override + public List getRestHandlers(Settings settings, RestController restController, + ClusterSettings clusterSettings, + IndexScopedSettings indexScopedSettings, + SettingsFilter settingsFilter, + IndexNameExpressionResolver indexNameExpressionResolver, + Supplier nodesInCluster) { + Objects.requireNonNull(clusterService, "Cluster service is required"); + return Arrays.asList( + new RestPPLQueryAction(restController, clusterService) + ); + } - @Override - public Collection createComponents(Client client, ClusterService clusterService, ThreadPool threadPool, - ResourceWatcherService resourceWatcherService, ScriptService scriptService, - NamedXContentRegistry xContentRegistry, Environment environment, - NodeEnvironment nodeEnvironment, NamedWriteableRegistry namedWriteableRegistry, - IndexNameExpressionResolver indexNameExpressionResolver) { - this.clusterService = clusterService; - return super.createComponents(client, clusterService, threadPool, resourceWatcherService, scriptService, - xContentRegistry, environment, nodeEnvironment, namedWriteableRegistry, - indexNameExpressionResolver); - } + @Override + public Collection createComponents(Client client, ClusterService clusterService, + ThreadPool threadPool, + ResourceWatcherService resourceWatcherService, + ScriptService scriptService, + NamedXContentRegistry contentRegistry, + Environment environment, + NodeEnvironment nodeEnvironment, + NamedWriteableRegistry namedWriteableRegistry, + IndexNameExpressionResolver resolver) { + this.clusterService = clusterService; + return super + .createComponents(client, clusterService, threadPool, resourceWatcherService, scriptService, + contentRegistry, environment, nodeEnvironment, namedWriteableRegistry, + resolver); + } } diff --git a/plugin/src/main/java/com/amazon/opendistroforelasticsearch/sql/plugin/request/PPLQueryRequestFactory.java b/plugin/src/main/java/com/amazon/opendistroforelasticsearch/sql/plugin/request/PPLQueryRequestFactory.java index f29653b5a5..99eb56e457 100644 --- a/plugin/src/main/java/com/amazon/opendistroforelasticsearch/sql/plugin/request/PPLQueryRequestFactory.java +++ b/plugin/src/main/java/com/amazon/opendistroforelasticsearch/sql/plugin/request/PPLQueryRequestFactory.java @@ -20,39 +20,48 @@ import org.json.JSONException; import org.json.JSONObject; +/** + * Factory of {@link PPLQueryRequest}. + */ public class PPLQueryRequestFactory { - private static final String PPL_URL_PARAM_KEY = "ppl"; - private static final String PPL_FIELD_NAME = "query"; + private static final String PPL_URL_PARAM_KEY = "ppl"; + private static final String PPL_FIELD_NAME = "query"; - public static PPLQueryRequest getPPLRequest(RestRequest request) { - switch (request.method()) { - case GET: - return parsePPLRequestFromUrl(request); - case POST: - return parsePPLRequestFromPayload(request); - default: - throw new IllegalArgumentException("ES PPL doesn't supported HTTP " + request.method().name()); - } + /** + * Build {@link PPLQueryRequest} from {@link RestRequest}. + * @param request {@link PPLQueryRequest} + * @return {@link RestRequest} + */ + public static PPLQueryRequest getPPLRequest(RestRequest request) { + switch (request.method()) { + case GET: + return parsePPLRequestFromUrl(request); + case POST: + return parsePPLRequestFromPayload(request); + default: + throw new IllegalArgumentException( + "ES PPL doesn't supported HTTP " + request.method().name()); } + } - private static PPLQueryRequest parsePPLRequestFromUrl(RestRequest restRequest) { - String ppl; + private static PPLQueryRequest parsePPLRequestFromUrl(RestRequest restRequest) { + String ppl; - ppl = restRequest.param(PPL_URL_PARAM_KEY); - if (ppl == null) { - throw new IllegalArgumentException("Cannot find ppl parameter from the URL"); - } - return new PPLQueryRequest(ppl, null); + ppl = restRequest.param(PPL_URL_PARAM_KEY); + if (ppl == null) { + throw new IllegalArgumentException("Cannot find ppl parameter from the URL"); } + return new PPLQueryRequest(ppl, null); + } - private static PPLQueryRequest parsePPLRequestFromPayload(RestRequest restRequest) { - String content = restRequest.content().utf8ToString(); - JSONObject jsonContent; - try { - jsonContent = new JSONObject(content); - } catch (JSONException e) { - throw new IllegalArgumentException("Failed to parse request payload", e); - } - return new PPLQueryRequest(jsonContent.getString(PPL_FIELD_NAME), jsonContent); + private static PPLQueryRequest parsePPLRequestFromPayload(RestRequest restRequest) { + String content = restRequest.content().utf8ToString(); + JSONObject jsonContent; + try { + jsonContent = new JSONObject(content); + } catch (JSONException e) { + throw new IllegalArgumentException("Failed to parse request payload", e); } + return new PPLQueryRequest(jsonContent.getString(PPL_FIELD_NAME), jsonContent); + } } diff --git a/plugin/src/main/java/com/amazon/opendistroforelasticsearch/sql/plugin/rest/ElasticsearchPluginConfig.java b/plugin/src/main/java/com/amazon/opendistroforelasticsearch/sql/plugin/rest/ElasticsearchPluginConfig.java index 881a88f12e..1fc60b6bbd 100644 --- a/plugin/src/main/java/com/amazon/opendistroforelasticsearch/sql/plugin/rest/ElasticsearchPluginConfig.java +++ b/plugin/src/main/java/com/amazon/opendistroforelasticsearch/sql/plugin/rest/ElasticsearchPluginConfig.java @@ -35,25 +35,25 @@ @Configuration public class ElasticsearchPluginConfig { - @Autowired - private ClusterService clusterService; - - @Autowired - private NodeClient nodeClient; - - @Bean - public ElasticsearchClient client() { - return new ElasticsearchNodeClient(clusterService, nodeClient); - } - - @Bean - public StorageEngine storageEngine() { - return new ElasticsearchStorageEngine(client()); - } - - @Bean - public ExecutionEngine executionEngine() { - return new ElasticsearchExecutionEngine(client()); - } + @Autowired + private ClusterService clusterService; + + @Autowired + private NodeClient nodeClient; + + @Bean + public ElasticsearchClient client() { + return new ElasticsearchNodeClient(clusterService, nodeClient); + } + + @Bean + public StorageEngine storageEngine() { + return new ElasticsearchStorageEngine(client()); + } + + @Bean + public ExecutionEngine executionEngine() { + return new ElasticsearchExecutionEngine(client()); + } } diff --git a/plugin/src/main/java/com/amazon/opendistroforelasticsearch/sql/plugin/rest/RestPPLQueryAction.java b/plugin/src/main/java/com/amazon/opendistroforelasticsearch/sql/plugin/rest/RestPPLQueryAction.java index 18aa1cd742..6785f91237 100644 --- a/plugin/src/main/java/com/amazon/opendistroforelasticsearch/sql/plugin/rest/RestPPLQueryAction.java +++ b/plugin/src/main/java/com/amazon/opendistroforelasticsearch/sql/plugin/rest/RestPPLQueryAction.java @@ -15,6 +15,10 @@ package com.amazon.opendistroforelasticsearch.sql.plugin.rest; +import static com.amazon.opendistroforelasticsearch.sql.protocol.response.format.JsonResponseFormatter.Style.PRETTY; +import static org.elasticsearch.rest.RestStatus.INTERNAL_SERVER_ERROR; +import static org.elasticsearch.rest.RestStatus.OK; + import com.amazon.opendistroforelasticsearch.sql.common.response.ResponseListener; import com.amazon.opendistroforelasticsearch.sql.elasticsearch.security.SecurityAccess; import com.amazon.opendistroforelasticsearch.sql.executor.ExecutionEngine.QueryResponse; @@ -23,6 +27,10 @@ import com.amazon.opendistroforelasticsearch.sql.ppl.config.PPLServiceConfig; import com.amazon.opendistroforelasticsearch.sql.protocol.response.QueryResult; import com.amazon.opendistroforelasticsearch.sql.protocol.response.format.SimpleJsonResponseFormatter; +import java.io.IOException; +import java.security.PrivilegedExceptionAction; +import java.util.Collections; +import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.elasticsearch.client.node.NodeClient; @@ -35,87 +43,80 @@ import org.elasticsearch.rest.RestStatus; import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import java.io.IOException; -import java.security.PrivilegedExceptionAction; -import java.util.Collections; -import java.util.List; - -import static com.amazon.opendistroforelasticsearch.sql.protocol.response.format.JsonResponseFormatter.Style.PRETTY; -import static org.elasticsearch.rest.RestStatus.INTERNAL_SERVER_ERROR; -import static org.elasticsearch.rest.RestStatus.OK; - public class RestPPLQueryAction extends BaseRestHandler { - public static final String QUERY_API_ENDPOINT = "/_opendistro/_ppl"; - - private static final Logger LOG = LogManager.getLogger(); - - /** - * Cluster service required by bean initialization - */ - private final ClusterService clusterService; - - public RestPPLQueryAction(RestController restController, ClusterService clusterService) { - super(); - this.clusterService = clusterService; - } - - @Override - public List routes() { - return Collections.singletonList( - new Route(RestRequest.Method.POST, QUERY_API_ENDPOINT) - ); - } - - @Override - public String getName() { - return "ppl_query_action"; - } - - @Override - protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient nodeClient) { - PPLService pplService = createPPLService(nodeClient); - return channel -> pplService.execute( - PPLQueryRequestFactory.getPPLRequest(request), createListener(channel)); - } - - private PPLService createPPLService(NodeClient client) { - return doPrivileged(() -> { - AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); - context.registerBean(ClusterService.class, () -> clusterService); - context.registerBean(NodeClient.class, () -> client); - context.register(ElasticsearchPluginConfig.class); - context.register(PPLServiceConfig.class); - context.refresh(); - return context.getBean(PPLService.class); - }); - } - - private ResponseListener createListener(RestChannel channel) { - SimpleJsonResponseFormatter formatter = new SimpleJsonResponseFormatter(PRETTY); // TODO: decide format and pretty from URL param - return new ResponseListener() { - @Override - public void onResponse(QueryResponse response) { - sendResponse(OK, formatter.format(new QueryResult(response.getResults()))); - } - - @Override - public void onFailure(Exception e) { - LOG.error("Error happened during query handling", e); - sendResponse(INTERNAL_SERVER_ERROR, formatter.format(e)); - } - - private void sendResponse(RestStatus status, String content) { - channel.sendResponse(new BytesRestResponse(status, "application/json; charset=UTF-8", content)); - } - }; - } - - private T doPrivileged(PrivilegedExceptionAction action) { - try { - return SecurityAccess.doPrivileged(action); - } catch (IOException e) { - throw new IllegalStateException("Failed to perform privileged action", e); - } + public static final String QUERY_API_ENDPOINT = "/_opendistro/_ppl"; + + private static final Logger LOG = LogManager.getLogger(); + + /** + * Cluster service required by bean initialization. + */ + private final ClusterService clusterService; + + public RestPPLQueryAction(RestController restController, ClusterService clusterService) { + super(); + this.clusterService = clusterService; + } + + @Override + public List routes() { + return Collections.singletonList( + new Route(RestRequest.Method.POST, QUERY_API_ENDPOINT) + ); + } + + @Override + public String getName() { + return "ppl_query_action"; + } + + @Override + protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient nodeClient) { + PPLService pplService = createPPLService(nodeClient); + return channel -> pplService.execute( + PPLQueryRequestFactory.getPPLRequest(request), createListener(channel)); + } + + private PPLService createPPLService(NodeClient client) { + return doPrivileged(() -> { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + context.registerBean(ClusterService.class, () -> clusterService); + context.registerBean(NodeClient.class, () -> client); + context.register(ElasticsearchPluginConfig.class); + context.register(PPLServiceConfig.class); + context.refresh(); + return context.getBean(PPLService.class); + }); + } + + private ResponseListener createListener(RestChannel channel) { + SimpleJsonResponseFormatter formatter = + new SimpleJsonResponseFormatter(PRETTY); // TODO: decide format and pretty from URL param + return new ResponseListener() { + @Override + public void onResponse(QueryResponse response) { + sendResponse(OK, formatter.format(new QueryResult(response.getResults()))); + } + + @Override + public void onFailure(Exception e) { + LOG.error("Error happened during query handling", e); + sendResponse(INTERNAL_SERVER_ERROR, formatter.format(e)); + } + + private void sendResponse(RestStatus status, String content) { + channel.sendResponse( + new BytesRestResponse(status, "application/json; charset=UTF-8", content)); + } + }; + } + + private T doPrivileged(PrivilegedExceptionAction action) { + try { + return SecurityAccess.doPrivileged(action); + } catch (IOException e) { + throw new IllegalStateException("Failed to perform privileged action", e); } + } } diff --git a/ppl/build.gradle b/ppl/build.gradle index b3869a4fde..3818d805f4 100644 --- a/ppl/build.gradle +++ b/ppl/build.gradle @@ -25,9 +25,9 @@ dependencies { antlr "org.antlr:antlr4:4.7.1" compile "org.antlr:antlr4-runtime:4.7.1" - compile group: 'com.google.guava', name: 'guava', version:'23.0' - compile group: 'org.elasticsearch', name: 'elasticsearch-x-content', version:"${es_version}" - compile group: 'org.json', name: 'json', version:'20180813' + compile group: 'com.google.guava', name: 'guava', version: '23.0' + compile group: 'org.elasticsearch', name: 'elasticsearch-x-content', version: "${es_version}" + compile group: 'org.json', name: 'json', version: '20180813' compile group: 'org.springframework', name: 'spring-context', version: '5.2.5.RELEASE' compile group: 'org.springframework', name: 'spring-beans', version: '5.2.5.RELEASE' compile project(':common') diff --git a/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/PPLService.java b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/PPLService.java index 88543ab481..0c3e437c68 100644 --- a/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/PPLService.java +++ b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/PPLService.java @@ -15,14 +15,13 @@ package com.amazon.opendistroforelasticsearch.sql.ppl; +import static com.amazon.opendistroforelasticsearch.sql.executor.ExecutionEngine.QueryResponse; + import com.amazon.opendistroforelasticsearch.sql.analysis.AnalysisContext; import com.amazon.opendistroforelasticsearch.sql.analysis.Analyzer; -import com.amazon.opendistroforelasticsearch.sql.analysis.ExpressionAnalyzer; import com.amazon.opendistroforelasticsearch.sql.ast.tree.UnresolvedPlan; import com.amazon.opendistroforelasticsearch.sql.common.response.ResponseListener; import com.amazon.opendistroforelasticsearch.sql.executor.ExecutionEngine; -import com.amazon.opendistroforelasticsearch.sql.expression.DSL; -import com.amazon.opendistroforelasticsearch.sql.expression.function.BuiltinFunctionRepository; import com.amazon.opendistroforelasticsearch.sql.planner.Planner; import com.amazon.opendistroforelasticsearch.sql.planner.logical.LogicalPlan; import com.amazon.opendistroforelasticsearch.sql.planner.physical.PhysicalPlan; @@ -34,36 +33,37 @@ import lombok.RequiredArgsConstructor; import org.antlr.v4.runtime.tree.ParseTree; -import java.util.HashMap; - -import static com.amazon.opendistroforelasticsearch.sql.executor.ExecutionEngine.QueryResponse; - @RequiredArgsConstructor public class PPLService { - private final PPLSyntaxParser parser; + private final PPLSyntaxParser parser; - private final Analyzer analyzer; + private final Analyzer analyzer; - private final StorageEngine storageEngine; + private final StorageEngine storageEngine; - private final ExecutionEngine executionEngine; + private final ExecutionEngine executionEngine; - public void execute(PPLQueryRequest request, ResponseListener listener) { - try { - // 1.Parse query and convert parse tree (CST) to abstract syntax tree (AST) - ParseTree cst = parser.analyzeSyntax(request.getRequest()); - UnresolvedPlan ast = cst.accept(new AstBuilder(new AstExpressionBuilder())); + /** + * Execute the {@link PPLQueryRequest}, using {@link ResponseListener} to get response. + * @param request {@link PPLQueryRequest} + * @param listener {@link ResponseListener} + */ + public void execute(PPLQueryRequest request, ResponseListener listener) { + try { + // 1.Parse query and convert parse tree (CST) to abstract syntax tree (AST) + ParseTree cst = parser.analyzeSyntax(request.getRequest()); + UnresolvedPlan ast = cst.accept(new AstBuilder(new AstExpressionBuilder())); - // 2.Analyze abstract syntax to generate logical plan - LogicalPlan logicalPlan = analyzer.analyze(ast, new AnalysisContext()); + // 2.Analyze abstract syntax to generate logical plan + LogicalPlan logicalPlan = analyzer.analyze(ast, new AnalysisContext()); - // 3.Generate optimal physical plan from logical plan - PhysicalPlan physicalPlan = new Planner(storageEngine).plan(logicalPlan); + // 3.Generate optimal physical plan from logical plan + PhysicalPlan physicalPlan = new Planner(storageEngine).plan(logicalPlan); - // 4.Execute physical plan and send response - executionEngine.execute(physicalPlan, listener); - } catch (Exception e) { - listener.onFailure(e); - } + // 4.Execute physical plan and send response + executionEngine.execute(physicalPlan, listener); + } catch (Exception e) { + listener.onFailure(e); } + } } diff --git a/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/antlr/PPLSyntaxParser.java b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/antlr/PPLSyntaxParser.java index 9bffa41b9d..c638ae7ab1 100644 --- a/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/antlr/PPLSyntaxParser.java +++ b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/antlr/PPLSyntaxParser.java @@ -24,22 +24,25 @@ import org.antlr.v4.runtime.tree.ParseTree; /** - * PPL Syntax Parser + * PPL Syntax Parser. */ public class PPLSyntaxParser { - public ParseTree analyzeSyntax(String query) { - OpenDistroPPLParser parser = createParser(createLexer(query)); - parser.addErrorListener(new SyntaxAnalysisErrorListener()); - return parser.root(); - } + /** + * Analyze the query syntax. + */ + public ParseTree analyzeSyntax(String query) { + OpenDistroPPLParser parser = createParser(createLexer(query)); + parser.addErrorListener(new SyntaxAnalysisErrorListener()); + return parser.root(); + } - private OpenDistroPPLParser createParser(Lexer lexer) { - return new OpenDistroPPLParser( - new CommonTokenStream(lexer)); - } + private OpenDistroPPLParser createParser(Lexer lexer) { + return new OpenDistroPPLParser( + new CommonTokenStream(lexer)); + } - private OpenDistroPPLLexer createLexer(String query) { - return new OpenDistroPPLLexer( - new CaseInsensitiveCharStream(query)); - } + private OpenDistroPPLLexer createLexer(String query) { + return new OpenDistroPPLLexer( + new CaseInsensitiveCharStream(query)); + } } diff --git a/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/config/PPLServiceConfig.java b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/config/PPLServiceConfig.java index 8e5aa33ddc..f1a6e3aae0 100644 --- a/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/config/PPLServiceConfig.java +++ b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/config/PPLServiceConfig.java @@ -32,23 +32,23 @@ @Import({ExpressionConfig.class}) public class PPLServiceConfig { - @Autowired - private StorageEngine storageEngine; + @Autowired + private StorageEngine storageEngine; - @Autowired - private ExecutionEngine executionEngine; + @Autowired + private ExecutionEngine executionEngine; - @Autowired - private BuiltinFunctionRepository functionRepository; + @Autowired + private BuiltinFunctionRepository functionRepository; - @Bean - public Analyzer analyzer() { - return new Analyzer(new ExpressionAnalyzer(functionRepository), storageEngine); - } + @Bean + public Analyzer analyzer() { + return new Analyzer(new ExpressionAnalyzer(functionRepository), storageEngine); + } - @Bean - public PPLService pplService() { - return new PPLService(new PPLSyntaxParser(), analyzer(), storageEngine, executionEngine); - } + @Bean + public PPLService pplService() { + return new PPLService(new PPLSyntaxParser(), analyzer(), storageEngine, executionEngine); + } } diff --git a/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/domain/PPLQueryRequest.java b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/domain/PPLQueryRequest.java index 9b83a8d43d..9bb348fd43 100644 --- a/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/domain/PPLQueryRequest.java +++ b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/domain/PPLQueryRequest.java @@ -15,18 +15,17 @@ package com.amazon.opendistroforelasticsearch.sql.ppl.domain; - import lombok.RequiredArgsConstructor; import org.json.JSONObject; @RequiredArgsConstructor public class PPLQueryRequest { - public static final PPLQueryRequest NULL = new PPLQueryRequest("", null); + public static final PPLQueryRequest NULL = new PPLQueryRequest("", null); - private final String pplQuery; - private final JSONObject jsonContent; + private final String pplQuery; + private final JSONObject jsonContent; - public String getRequest() { - return pplQuery; - } + public String getRequest() { + return pplQuery; + } } diff --git a/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/parser/AstBuilder.java b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/parser/AstBuilder.java index b989539eab..059b28e066 100644 --- a/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/parser/AstBuilder.java +++ b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/parser/AstBuilder.java @@ -15,6 +15,19 @@ package com.amazon.opendistroforelasticsearch.sql.ppl.parser; +import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.DedupCommandContext; +import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.EvalCommandContext; +import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.FieldsCommandContext; +import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.FromClauseContext; +import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.PplStatementContext; +import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.RenameCommandContext; +import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.SearchFilterFromContext; +import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.SearchFromContext; +import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.SearchFromFilterContext; +import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.SortCommandContext; +import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.StatsCommandContext; +import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.WhereCommandContext; + import com.amazon.opendistroforelasticsearch.sql.ast.expression.Field; import com.amazon.opendistroforelasticsearch.sql.ast.expression.Let; import com.amazon.opendistroforelasticsearch.sql.ast.expression.Map; @@ -32,181 +45,187 @@ import com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParserBaseVisitor; import com.amazon.opendistroforelasticsearch.sql.ppl.utils.ArgumentFactory; import com.google.common.collect.ImmutableList; -import lombok.RequiredArgsConstructor; -import org.antlr.v4.runtime.tree.ParseTree; - import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; - -import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.DedupCommandContext; -import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.EvalCommandContext; -import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.FieldsCommandContext; -import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.FromClauseContext; -import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.PplStatementContext; -import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.RenameCommandContext; -import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.SearchFilterFromContext; -import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.SearchFromContext; -import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.SearchFromFilterContext; -import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.SortCommandContext; -import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.StatsCommandContext; -import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.WhereCommandContext; +import lombok.RequiredArgsConstructor; +import org.antlr.v4.runtime.tree.ParseTree; /** - * Class of building the AST + * Class of building the AST. * Refines the visit path and build the AST nodes */ @RequiredArgsConstructor public class AstBuilder extends OpenDistroPPLParserBaseVisitor { - private final AstExpressionBuilder expressionBuilder; - - @Override - public UnresolvedPlan visitPplStatement(PplStatementContext ctx) { - UnresolvedPlan search = visit(ctx.searchCommand()); - return ctx.commands() - .stream() - .map(this::visit) - .reduce(search, (r, e) -> e.attach(r)); - } - - /** Search command */ - @Override - public UnresolvedPlan visitSearchFrom(SearchFromContext ctx) { - return visitFromClause(ctx.fromClause()); - } - - @Override - public UnresolvedPlan visitSearchFromFilter(SearchFromFilterContext ctx) { - return new Filter(visitExpression(ctx.logicalExpression())).attach(visit(ctx.fromClause())); - } - - @Override - public UnresolvedPlan visitSearchFilterFrom(SearchFilterFromContext ctx) { - return new Filter(visitExpression(ctx.logicalExpression())).attach(visit(ctx.fromClause())); - } - - /** Where command */ - @Override - public UnresolvedPlan visitWhereCommand(WhereCommandContext ctx) { - return new Filter(visitExpression(ctx.logicalExpression())); - } - - /** Fields command */ - @Override - public UnresolvedPlan visitFieldsCommand(FieldsCommandContext ctx) { - return new Project( - ctx.wcFieldList() - .wcFieldExpression() - .stream() - .map(this::visitExpression) - .collect(Collectors.toList()), - ArgumentFactory.getArgumentList(ctx) - ); - } - - /** Rename command */ - @Override - public UnresolvedPlan visitRenameCommand(RenameCommandContext ctx) { - return new Rename( - new ArrayList<>( - Collections.singletonList( - new Map( - visitExpression(ctx.orignalField), - visitExpression(ctx.renamedField) - ) - ) + private final AstExpressionBuilder expressionBuilder; + + @Override + public UnresolvedPlan visitPplStatement(PplStatementContext ctx) { + UnresolvedPlan search = visit(ctx.searchCommand()); + return ctx.commands() + .stream() + .map(this::visit) + .reduce(search, (r, e) -> e.attach(r)); + } + + /** + * Search command. + */ + @Override + public UnresolvedPlan visitSearchFrom(SearchFromContext ctx) { + return visitFromClause(ctx.fromClause()); + } + + @Override + public UnresolvedPlan visitSearchFromFilter(SearchFromFilterContext ctx) { + return new Filter(visitExpression(ctx.logicalExpression())).attach(visit(ctx.fromClause())); + } + + @Override + public UnresolvedPlan visitSearchFilterFrom(SearchFilterFromContext ctx) { + return new Filter(visitExpression(ctx.logicalExpression())).attach(visit(ctx.fromClause())); + } + + /** + * Where command. + */ + @Override + public UnresolvedPlan visitWhereCommand(WhereCommandContext ctx) { + return new Filter(visitExpression(ctx.logicalExpression())); + } + + /** + * Fields command. + */ + @Override + public UnresolvedPlan visitFieldsCommand(FieldsCommandContext ctx) { + return new Project( + ctx.wcFieldList() + .wcFieldExpression() + .stream() + .map(this::visitExpression) + .collect(Collectors.toList()), + ArgumentFactory.getArgumentList(ctx) + ); + } + + /** + * Rename command. + */ + @Override + public UnresolvedPlan visitRenameCommand(RenameCommandContext ctx) { + return new Rename( + new ArrayList<>( + Collections.singletonList( + new Map( + visitExpression(ctx.orignalField), + visitExpression(ctx.renamedField) ) - ); - } - - /** Stats command */ - @Override - public UnresolvedPlan visitStatsCommand(StatsCommandContext ctx) { - ImmutableList.Builder aggListBuilder = new ImmutableList.Builder<>(); - ImmutableList.Builder renameListBuilder = new ImmutableList.Builder<>(); - for (OpenDistroPPLParser.StatsAggTermContext aggCtx : ctx.statsAggTerm()) { - UnresolvedExpression aggExpression = visitExpression(aggCtx.statsFunction()); - aggListBuilder.add(aggExpression); - if (aggCtx.alias != null) { - renameListBuilder - .add(new Map(aggExpression, visitExpression(aggCtx.alias))); - } - } - List groupList = ctx.byClause() == null ? Collections.emptyList() : - ctx.byClause() - .fieldList() - .fieldExpression() - .stream() - .map(this::visitExpression) - .collect(Collectors.toList()); - Aggregation aggregation = new Aggregation( - aggListBuilder.build(), - Collections.emptyList(), - groupList, - ArgumentFactory.getArgumentList(ctx) - ); - List renameList = renameListBuilder.build(); - return renameList.isEmpty() ? aggregation : new Rename(renameList, aggregation); - } - - /** Dedup command */ - @Override - public UnresolvedPlan visitDedupCommand(DedupCommandContext ctx) { - return new Dedupe( - ArgumentFactory.getArgumentList(ctx), - ctx.fieldList() - .fieldExpression() - .stream() - .map(field -> (Field) visitExpression(field)) - .collect(Collectors.toList()) - ); - } - - /** Sort command */ - @Override - public UnresolvedPlan visitSortCommand(SortCommandContext ctx) { - return new Sort( - ArgumentFactory.getArgumentList(ctx), - ctx.sortbyClause() - .sortField() - .stream() - .map(sort -> (Field) visitExpression(sort)) - .collect(Collectors.toList()) - ); + ) + ) + ); + } + + /** + * Stats command. + */ + @Override + public UnresolvedPlan visitStatsCommand(StatsCommandContext ctx) { + ImmutableList.Builder aggListBuilder = new ImmutableList.Builder<>(); + ImmutableList.Builder renameListBuilder = new ImmutableList.Builder<>(); + for (OpenDistroPPLParser.StatsAggTermContext aggCtx : ctx.statsAggTerm()) { + UnresolvedExpression aggExpression = visitExpression(aggCtx.statsFunction()); + aggListBuilder.add(aggExpression); + if (aggCtx.alias != null) { + renameListBuilder + .add(new Map(aggExpression, visitExpression(aggCtx.alias))); + } } - - /** Eval command */ - @Override - public UnresolvedPlan visitEvalCommand(EvalCommandContext ctx) { - return new Eval( - ctx.evalExpression() - .stream() - .map(ct -> (Let) visitExpression(ct)) - .collect(Collectors.toList()) - ); - } - - /** From clause */ - @Override - public UnresolvedPlan visitFromClause(FromClauseContext ctx) { - return new Relation(visitExpression(ctx.tableSource().qualifiedName())); - } - - /** Navigate to & build AST expression */ - private UnresolvedExpression visitExpression(ParseTree tree) { - return expressionBuilder.visit(tree); - } - - /** - * Simply return non-default value for now - */ - @Override - protected UnresolvedPlan aggregateResult(UnresolvedPlan aggregate, UnresolvedPlan nextResult) { - if (nextResult != defaultResult()) { - return nextResult; - } - return aggregate; + List groupList = ctx.byClause() == null ? Collections.emptyList() : + ctx.byClause() + .fieldList() + .fieldExpression() + .stream() + .map(this::visitExpression) + .collect(Collectors.toList()); + Aggregation aggregation = new Aggregation( + aggListBuilder.build(), + Collections.emptyList(), + groupList, + ArgumentFactory.getArgumentList(ctx) + ); + List renameList = renameListBuilder.build(); + return renameList.isEmpty() ? aggregation : new Rename(renameList, aggregation); + } + + /** + * Dedup command. + */ + @Override + public UnresolvedPlan visitDedupCommand(DedupCommandContext ctx) { + return new Dedupe( + ArgumentFactory.getArgumentList(ctx), + ctx.fieldList() + .fieldExpression() + .stream() + .map(field -> (Field) visitExpression(field)) + .collect(Collectors.toList()) + ); + } + + /** + * Sort command. + */ + @Override + public UnresolvedPlan visitSortCommand(SortCommandContext ctx) { + return new Sort( + ArgumentFactory.getArgumentList(ctx), + ctx.sortbyClause() + .sortField() + .stream() + .map(sort -> (Field) visitExpression(sort)) + .collect(Collectors.toList()) + ); + } + + /** + * Eval command. + */ + @Override + public UnresolvedPlan visitEvalCommand(EvalCommandContext ctx) { + return new Eval( + ctx.evalExpression() + .stream() + .map(ct -> (Let) visitExpression(ct)) + .collect(Collectors.toList()) + ); + } + + /** + * From clause. + */ + @Override + public UnresolvedPlan visitFromClause(FromClauseContext ctx) { + return new Relation(visitExpression(ctx.tableSource().qualifiedName())); + } + + /** + * Navigate to & build AST expression. + */ + private UnresolvedExpression visitExpression(ParseTree tree) { + return expressionBuilder.visit(tree); + } + + /** + * Simply return non-default value for now. + */ + @Override + protected UnresolvedPlan aggregateResult(UnresolvedPlan aggregate, UnresolvedPlan nextResult) { + if (nextResult != defaultResult()) { + return nextResult; } + return aggregate; + } } diff --git a/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/parser/AstExpressionBuilder.java b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/parser/AstExpressionBuilder.java index c5631ddfdd..05556fbc3f 100644 --- a/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/parser/AstExpressionBuilder.java +++ b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/parser/AstExpressionBuilder.java @@ -15,29 +15,6 @@ package com.amazon.opendistroforelasticsearch.sql.ppl.parser; -import com.amazon.opendistroforelasticsearch.sql.ast.expression.Argument; -import com.amazon.opendistroforelasticsearch.sql.ast.expression.Compare; -import com.amazon.opendistroforelasticsearch.sql.ast.expression.Field; -import com.amazon.opendistroforelasticsearch.sql.ast.expression.Let; -import com.amazon.opendistroforelasticsearch.sql.ast.expression.QualifiedName; -import com.amazon.opendistroforelasticsearch.sql.common.utils.StringUtils; -import com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParserBaseVisitor; -import com.amazon.opendistroforelasticsearch.sql.ast.expression.AggregateFunction; -import com.amazon.opendistroforelasticsearch.sql.ast.expression.And; -import com.amazon.opendistroforelasticsearch.sql.ast.expression.DataType; -import com.amazon.opendistroforelasticsearch.sql.ast.expression.UnresolvedExpression; -import com.amazon.opendistroforelasticsearch.sql.ast.expression.Function; -import com.amazon.opendistroforelasticsearch.sql.ast.expression.In; -import com.amazon.opendistroforelasticsearch.sql.ast.expression.Literal; -import com.amazon.opendistroforelasticsearch.sql.ast.expression.Not; -import com.amazon.opendistroforelasticsearch.sql.ast.expression.Or; -import com.amazon.opendistroforelasticsearch.sql.ppl.utils.ArgumentFactory; - -import java.util.Arrays; -import java.util.Collections; -import java.util.stream.Collectors; -import org.antlr.v4.runtime.ParserRuleContext; - import static com.amazon.opendistroforelasticsearch.sql.common.utils.StringUtils.unquoteIdentifier; import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.BinaryArithmeticContext; import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.BooleanLiteralContext; @@ -59,148 +36,184 @@ import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.WcFieldExpressionContext; import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.WcQualifiedNameContext; +import com.amazon.opendistroforelasticsearch.sql.ast.expression.AggregateFunction; +import com.amazon.opendistroforelasticsearch.sql.ast.expression.And; +import com.amazon.opendistroforelasticsearch.sql.ast.expression.Argument; +import com.amazon.opendistroforelasticsearch.sql.ast.expression.Compare; +import com.amazon.opendistroforelasticsearch.sql.ast.expression.DataType; +import com.amazon.opendistroforelasticsearch.sql.ast.expression.Field; +import com.amazon.opendistroforelasticsearch.sql.ast.expression.Function; +import com.amazon.opendistroforelasticsearch.sql.ast.expression.In; +import com.amazon.opendistroforelasticsearch.sql.ast.expression.Let; +import com.amazon.opendistroforelasticsearch.sql.ast.expression.Literal; +import com.amazon.opendistroforelasticsearch.sql.ast.expression.Not; +import com.amazon.opendistroforelasticsearch.sql.ast.expression.Or; +import com.amazon.opendistroforelasticsearch.sql.ast.expression.QualifiedName; +import com.amazon.opendistroforelasticsearch.sql.ast.expression.UnresolvedExpression; +import com.amazon.opendistroforelasticsearch.sql.common.utils.StringUtils; +import com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParserBaseVisitor; +import com.amazon.opendistroforelasticsearch.sql.ppl.utils.ArgumentFactory; +import java.util.Arrays; +import java.util.Collections; +import java.util.stream.Collectors; +import org.antlr.v4.runtime.ParserRuleContext; + /** - * Class of building AST Expression nodes + * Class of building AST Expression nodes. */ public class AstExpressionBuilder extends OpenDistroPPLParserBaseVisitor { - /** Logical expression excluding boolean, eval, comparison */ - @Override - public UnresolvedExpression visitLogicalNot(LogicalNotContext ctx) { - return new Not(visit(ctx.logicalExpression())); - } - - @Override - public UnresolvedExpression visitLogicalOr(LogicalOrContext ctx) { - return new Or(visit(ctx.left), visit(ctx.right)); - } - - @Override - public UnresolvedExpression visitLogicalAnd(LogicalAndContext ctx) { - return new And(visit(ctx.left), visit(ctx.right)); - } - - - /** Eval expression */ - @Override - public UnresolvedExpression visitEvalExpression(EvalExpressionContext ctx) { - Field field = (Field) visit(ctx.fieldExpression()); - UnresolvedExpression evalFunctionCall = visit(ctx.expression()); - return new Let(field, evalFunctionCall); - } - - /** Comparison expression */ - @Override - public UnresolvedExpression visitCompareExpr(CompareExprContext ctx) { - UnresolvedExpression right = ctx.field != null ? visit(ctx.field) : visit(ctx.literal); - return new Compare(ctx.comparisonOperator().getText(), visit(ctx.left), right); - } - - @Override - public UnresolvedExpression visitInExpr(InExprContext ctx) { - return new In( - visit(ctx.fieldExpression()), - ctx.valueList() - .literalValue() - .stream() - .map(this::visitLiteralValue) - .collect(Collectors.toList())); - } - - @Override - public UnresolvedExpression visitBinaryArithmetic(BinaryArithmeticContext ctx) { - return new Function( - ctx.binaryOperator().getText(), - Arrays.asList( - ctx.leftField != null ? visit(ctx.leftField) : visit(ctx.leftValue), - ctx.rightField != null ? visit(ctx.rightField) : visit(ctx.rightValue) - ) - ); - } - - /** Field expression */ - @Override - public UnresolvedExpression visitFieldExpression(FieldExpressionContext ctx) { - return new Field((QualifiedName) visit(ctx.qualifiedName())); - } - - @Override - public UnresolvedExpression visitWcFieldExpression(WcFieldExpressionContext ctx) { - return new Field((QualifiedName) visit(ctx.wcQualifiedName())); - } - - @Override - public UnresolvedExpression visitSortField(SortFieldContext ctx) { - return new Field( - ctx.sortFieldExpression().fieldExpression().getText(), - ArgumentFactory.getArgumentList(ctx) - ); - } - - /** Aggregation function */ - @Override - public UnresolvedExpression visitStatsFunctionCall(StatsFunctionCallContext ctx) { - return new AggregateFunction(ctx.statsFunctionName().getText(), visit(ctx.fieldExpression())); - } - - @Override - public UnresolvedExpression visitPercentileAggFunction(PercentileAggFunctionContext ctx) { - return new AggregateFunction(ctx.PERCENTILE().getText(), visit(ctx.aggField), - Collections.singletonList(new Argument("rank", (Literal) visit(ctx.value)))); - } - - /** Eval function */ - @Override - public UnresolvedExpression visitEvalFunctionCall(EvalFunctionCallContext ctx) { - return new Function( - ctx.evalFunctionName().getText(), - ctx.functionArgs() - .functionArg() - .stream() - .map(this::visitFunctionArg) - .collect(Collectors.toList())); - } - - /** Literal and value */ - @Override - public UnresolvedExpression visitQualifiedName(QualifiedNameContext ctx) { - return new QualifiedName( - ctx.ident() - .stream() - .map(ParserRuleContext::getText) - .map(StringUtils::unquoteIdentifier) - .collect(Collectors.toList()) - ); - } - - @Override - public UnresolvedExpression visitWcQualifiedName(WcQualifiedNameContext ctx) { - return new QualifiedName( - ctx.wildcard() - .stream() - .map(ParserRuleContext::getText) - .map(StringUtils::unquoteIdentifier) - .collect(Collectors.toList()) - ); - } - - @Override - public UnresolvedExpression visitStringLiteral(StringLiteralContext ctx) { - return new Literal(unquoteIdentifier(ctx.getText()), DataType.STRING); - } - - @Override - public UnresolvedExpression visitIntegerLiteral(IntegerLiteralContext ctx) { - return new Literal(Integer.valueOf(ctx.getText()), DataType.INTEGER); - } - - @Override - public UnresolvedExpression visitDecimalLiteral(DecimalLiteralContext ctx) { - return new Literal(Double.valueOf(ctx.getText()), DataType.DOUBLE); - } - - @Override - public UnresolvedExpression visitBooleanLiteral(BooleanLiteralContext ctx) { - return new Literal(Boolean.valueOf(ctx.getText()), DataType.BOOLEAN); - } + /** + * Logical expression excluding boolean, eval, comparison. + */ + @Override + public UnresolvedExpression visitLogicalNot(LogicalNotContext ctx) { + return new Not(visit(ctx.logicalExpression())); + } + + @Override + public UnresolvedExpression visitLogicalOr(LogicalOrContext ctx) { + return new Or(visit(ctx.left), visit(ctx.right)); + } + + @Override + public UnresolvedExpression visitLogicalAnd(LogicalAndContext ctx) { + return new And(visit(ctx.left), visit(ctx.right)); + } + + + /** + * Eval expression. + */ + @Override + public UnresolvedExpression visitEvalExpression(EvalExpressionContext ctx) { + Field field = (Field) visit(ctx.fieldExpression()); + UnresolvedExpression evalFunctionCall = visit(ctx.expression()); + return new Let(field, evalFunctionCall); + } + + /** + * Comparison expression. + */ + @Override + public UnresolvedExpression visitCompareExpr(CompareExprContext ctx) { + UnresolvedExpression right = ctx.field != null ? visit(ctx.field) : visit(ctx.literal); + return new Compare(ctx.comparisonOperator().getText(), visit(ctx.left), right); + } + + @Override + public UnresolvedExpression visitInExpr(InExprContext ctx) { + return new In( + visit(ctx.fieldExpression()), + ctx.valueList() + .literalValue() + .stream() + .map(this::visitLiteralValue) + .collect(Collectors.toList())); + } + + @Override + public UnresolvedExpression visitBinaryArithmetic(BinaryArithmeticContext ctx) { + return new Function( + ctx.binaryOperator().getText(), + Arrays.asList( + ctx.leftField != null ? visit(ctx.leftField) : visit(ctx.leftValue), + ctx.rightField != null ? visit(ctx.rightField) : visit(ctx.rightValue) + ) + ); + } + + /** + * Field expression. + */ + @Override + public UnresolvedExpression visitFieldExpression(FieldExpressionContext ctx) { + return new Field((QualifiedName) visit(ctx.qualifiedName())); + } + + @Override + public UnresolvedExpression visitWcFieldExpression(WcFieldExpressionContext ctx) { + return new Field((QualifiedName) visit(ctx.wcQualifiedName())); + } + + @Override + public UnresolvedExpression visitSortField(SortFieldContext ctx) { + return new Field( + ctx.sortFieldExpression().fieldExpression().getText(), + ArgumentFactory.getArgumentList(ctx) + ); + } + + /** + * Aggregation function. + */ + @Override + public UnresolvedExpression visitStatsFunctionCall(StatsFunctionCallContext ctx) { + return new AggregateFunction(ctx.statsFunctionName().getText(), visit(ctx.fieldExpression())); + } + + @Override + public UnresolvedExpression visitPercentileAggFunction(PercentileAggFunctionContext ctx) { + return new AggregateFunction(ctx.PERCENTILE().getText(), visit(ctx.aggField), + Collections.singletonList(new Argument("rank", (Literal) visit(ctx.value)))); + } + + /** + * Eval function. + */ + @Override + public UnresolvedExpression visitEvalFunctionCall(EvalFunctionCallContext ctx) { + return new Function( + ctx.evalFunctionName().getText(), + ctx.functionArgs() + .functionArg() + .stream() + .map(this::visitFunctionArg) + .collect(Collectors.toList())); + } + + /** + * Literal and value. + */ + @Override + public UnresolvedExpression visitQualifiedName(QualifiedNameContext ctx) { + return new QualifiedName( + ctx.ident() + .stream() + .map(ParserRuleContext::getText) + .map(StringUtils::unquoteIdentifier) + .collect(Collectors.toList()) + ); + } + + @Override + public UnresolvedExpression visitWcQualifiedName(WcQualifiedNameContext ctx) { + return new QualifiedName( + ctx.wildcard() + .stream() + .map(ParserRuleContext::getText) + .map(StringUtils::unquoteIdentifier) + .collect(Collectors.toList()) + ); + } + + @Override + public UnresolvedExpression visitStringLiteral(StringLiteralContext ctx) { + return new Literal(unquoteIdentifier(ctx.getText()), DataType.STRING); + } + + @Override + public UnresolvedExpression visitIntegerLiteral(IntegerLiteralContext ctx) { + return new Literal(Integer.valueOf(ctx.getText()), DataType.INTEGER); + } + + @Override + public UnresolvedExpression visitDecimalLiteral(DecimalLiteralContext ctx) { + return new Literal(Double.valueOf(ctx.getText()), DataType.DOUBLE); + } + + @Override + public UnresolvedExpression visitBooleanLiteral(BooleanLiteralContext ctx) { + return new Literal(Boolean.valueOf(ctx.getText()), DataType.BOOLEAN); + } } diff --git a/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/utils/ArgumentFactory.java b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/utils/ArgumentFactory.java index 2f4b8e1e52..aaa839d0b2 100644 --- a/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/utils/ArgumentFactory.java +++ b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/utils/ArgumentFactory.java @@ -15,14 +15,6 @@ package com.amazon.opendistroforelasticsearch.sql.ppl.utils; -import com.amazon.opendistroforelasticsearch.sql.ast.expression.Argument; -import com.amazon.opendistroforelasticsearch.sql.ast.expression.DataType; -import com.amazon.opendistroforelasticsearch.sql.ast.expression.Literal; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import org.antlr.v4.runtime.ParserRuleContext; - import static com.amazon.opendistroforelasticsearch.sql.common.utils.StringUtils.unquoteIdentifier; import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.BooleanLiteralContext; import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.DedupCommandContext; @@ -32,103 +24,123 @@ import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.SortFieldContext; import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.StatsCommandContext; +import com.amazon.opendistroforelasticsearch.sql.ast.expression.Argument; +import com.amazon.opendistroforelasticsearch.sql.ast.expression.DataType; +import com.amazon.opendistroforelasticsearch.sql.ast.expression.Literal; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import org.antlr.v4.runtime.ParserRuleContext; + /** - * Util class to get all arguments as a list from the PPL command + * Util class to get all arguments as a list from the PPL command. */ public class ArgumentFactory { - /** - * @param ctx FieldsCommandContext instance - * @return the list of arguments fetched from the fields command - */ - public static List getArgumentList(FieldsCommandContext ctx) { - return Collections.singletonList( - ctx.MINUS() != null - ? new Argument("exclude", new Literal(true, DataType.BOOLEAN)) - : new Argument("exclude", new Literal(false, DataType.BOOLEAN)) - ); - } + /** + * Get list of {@link Argument}. + * + * @param ctx FieldsCommandContext instance + * @return the list of arguments fetched from the fields command + */ + public static List getArgumentList(FieldsCommandContext ctx) { + return Collections.singletonList( + ctx.MINUS() != null + ? new Argument("exclude", new Literal(true, DataType.BOOLEAN)) + : new Argument("exclude", new Literal(false, DataType.BOOLEAN)) + ); + } - /** - * @param ctx StatsCommandContext instance - * @return the list of arguments fetched from the stats command - */ - public static List getArgumentList(StatsCommandContext ctx) { - return Arrays.asList( - ctx.partitions != null - ? new Argument("partitions", getArgumentValue(ctx.partitions)) - : new Argument("partitions", new Literal(1, DataType.INTEGER)), - ctx.allnum != null - ? new Argument("allnum", getArgumentValue(ctx.allnum)) - : new Argument("allnum", new Literal(false, DataType.BOOLEAN)), - ctx.delim != null - ? new Argument("delim", getArgumentValue(ctx.delim)) - : new Argument("delim", new Literal(" ", DataType.STRING)), - ctx.dedupsplit != null - ? new Argument("dedupsplit", getArgumentValue(ctx.dedupsplit)) - : new Argument("dedupsplit", new Literal(false, DataType.BOOLEAN)) - ); - } + /** + * Get list of {@link Argument}. + * + * @param ctx StatsCommandContext instance + * @return the list of arguments fetched from the stats command + */ + public static List getArgumentList(StatsCommandContext ctx) { + return Arrays.asList( + ctx.partitions != null + ? new Argument("partitions", getArgumentValue(ctx.partitions)) + : new Argument("partitions", new Literal(1, DataType.INTEGER)), + ctx.allnum != null + ? new Argument("allnum", getArgumentValue(ctx.allnum)) + : new Argument("allnum", new Literal(false, DataType.BOOLEAN)), + ctx.delim != null + ? new Argument("delim", getArgumentValue(ctx.delim)) + : new Argument("delim", new Literal(" ", DataType.STRING)), + ctx.dedupsplit != null + ? new Argument("dedupsplit", getArgumentValue(ctx.dedupsplit)) + : new Argument("dedupsplit", new Literal(false, DataType.BOOLEAN)) + ); + } - /** - * @param ctx DedupCommandContext instance - * @return the list of arguments fetched from the dedup command - */ - public static List getArgumentList(DedupCommandContext ctx) { - return Arrays.asList( - ctx.number != null - ? new Argument("number", getArgumentValue(ctx.number)) - : new Argument("number", new Literal(1, DataType.INTEGER)), - ctx.keepempty != null - ? new Argument("keepempty", getArgumentValue(ctx.keepempty)) - : new Argument("keepempty", new Literal(false, DataType.BOOLEAN)), - ctx.consecutive != null - ? new Argument("consecutive", getArgumentValue(ctx.consecutive)) - : new Argument("consecutive", new Literal(false, DataType.BOOLEAN)) - ); - } + /** + * Get list of {@link Argument}. + * + * @param ctx DedupCommandContext instance + * @return the list of arguments fetched from the dedup command + */ + public static List getArgumentList(DedupCommandContext ctx) { + return Arrays.asList( + ctx.number != null + ? new Argument("number", getArgumentValue(ctx.number)) + : new Argument("number", new Literal(1, DataType.INTEGER)), + ctx.keepempty != null + ? new Argument("keepempty", getArgumentValue(ctx.keepempty)) + : new Argument("keepempty", new Literal(false, DataType.BOOLEAN)), + ctx.consecutive != null + ? new Argument("consecutive", getArgumentValue(ctx.consecutive)) + : new Argument("consecutive", new Literal(false, DataType.BOOLEAN)) + ); + } - /** - * @param ctx SortCommandContext instance - * @return the list of arguments fetched from the sort command - */ - public static List getArgumentList(SortCommandContext ctx) { - return Arrays.asList( - ctx.count != null - ? new Argument("count", getArgumentValue(ctx.count)) - : new Argument("count", new Literal(1000, DataType.INTEGER)), - ctx.D() != null || ctx.DESC() != null - ? new Argument("desc", new Literal(true, DataType.BOOLEAN)) - : new Argument("desc", new Literal(false, DataType.BOOLEAN)) - ); - } + /** + * Get list of {@link Argument}. + * + * @param ctx SortCommandContext instance + * @return the list of arguments fetched from the sort command + */ + public static List getArgumentList(SortCommandContext ctx) { + return Arrays.asList( + ctx.count != null + ? new Argument("count", getArgumentValue(ctx.count)) + : new Argument("count", new Literal(1000, DataType.INTEGER)), + ctx.D() != null || ctx.DESC() != null + ? new Argument("desc", new Literal(true, DataType.BOOLEAN)) + : new Argument("desc", new Literal(false, DataType.BOOLEAN)) + ); + } - /** - * @param ctx SortFieldContext instance - * @return the list of arguments fetched from the sort field in sort command - */ - public static List getArgumentList(SortFieldContext ctx) { - return Arrays.asList( - ctx.MINUS() != null - ? new Argument("asc", new Literal(false, DataType.BOOLEAN)) - : new Argument("asc", new Literal(true, DataType.BOOLEAN)), - ctx.sortFieldExpression().AUTO() != null - ? new Argument("type", new Literal("auto", DataType.STRING)) - : ctx.sortFieldExpression().IP() != null - ? new Argument("type", new Literal("ip", DataType.STRING)) - : ctx.sortFieldExpression().NUM() != null - ? new Argument("type", new Literal("num", DataType.STRING)) - : ctx.sortFieldExpression().STR() != null - ? new Argument("type", new Literal("str", DataType.STRING)) - : new Argument("type", new Literal(null, DataType.NULL)) - ); - } + /** + * Get list of {@link Argument}. + * + * @param ctx SortFieldContext instance + * @return the list of arguments fetched from the sort field in sort command + */ + public static List getArgumentList(SortFieldContext ctx) { + return Arrays.asList( + ctx.MINUS() != null + ? new Argument("asc", new Literal(false, DataType.BOOLEAN)) + : new Argument("asc", new Literal(true, DataType.BOOLEAN)), + ctx.sortFieldExpression().AUTO() != null + ? new Argument("type", new Literal("auto", DataType.STRING)) + : ctx.sortFieldExpression().IP() != null + ? new Argument("type", new Literal("ip", DataType.STRING)) + : ctx.sortFieldExpression().NUM() != null + ? new Argument("type", new Literal("num", DataType.STRING)) + : ctx.sortFieldExpression().STR() != null + ? new Argument("type", new Literal("str", DataType.STRING)) + : new Argument("type", new Literal(null, DataType.NULL)) + ); + } - private static Literal getArgumentValue(ParserRuleContext ctx) { - return ctx instanceof IntegerLiteralContext ? new Literal(Integer.parseInt(ctx.getText()), DataType.INTEGER) - : ctx instanceof BooleanLiteralContext ? new Literal(Boolean.valueOf(ctx.getText()), DataType.BOOLEAN) - : new Literal(unquoteIdentifier(ctx.getText()), DataType.STRING); - } + private static Literal getArgumentValue(ParserRuleContext ctx) { + return ctx instanceof IntegerLiteralContext + ? new Literal(Integer.parseInt(ctx.getText()), DataType.INTEGER) + : ctx instanceof BooleanLiteralContext + ? new Literal(Boolean.valueOf(ctx.getText()), DataType.BOOLEAN) + : new Literal(unquoteIdentifier(ctx.getText()), DataType.STRING); + } } diff --git a/ppl/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/PPLServiceTest.java b/ppl/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/PPLServiceTest.java index b3176ab18e..b367c15c0a 100644 --- a/ppl/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/PPLServiceTest.java +++ b/ppl/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/PPLServiceTest.java @@ -15,6 +15,10 @@ package com.amazon.opendistroforelasticsearch.sql.ppl; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.when; + import com.amazon.opendistroforelasticsearch.sql.common.response.ResponseListener; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprType; import com.amazon.opendistroforelasticsearch.sql.executor.ExecutionEngine; @@ -25,6 +29,7 @@ import com.amazon.opendistroforelasticsearch.sql.storage.StorageEngine; import com.amazon.opendistroforelasticsearch.sql.storage.Table; import com.google.common.collect.ImmutableMap; +import java.util.Collections; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -33,76 +38,74 @@ import org.mockito.junit.MockitoJUnitRunner; import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import java.util.Collections; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.when; - @RunWith(MockitoJUnitRunner.class) public class PPLServiceTest { - private AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); - - private PPLService pplService; - - @Mock - private StorageEngine storageEngine; - - @Mock - private ExecutionEngine executionEngine; - - @Mock - private Table table; - - @Mock - private PhysicalPlan plan; - - @Before - public void setUp() { - when(table.getFieldTypes()).thenReturn(ImmutableMap.of("a", ExprType.INTEGER)); - when(table.implement(any())).thenReturn(plan); - when(storageEngine.getTable(any())).thenReturn(table); - - context.registerBean(StorageEngine.class, () -> storageEngine); - context.registerBean(ExecutionEngine.class, () -> executionEngine); - context.register(PPLServiceConfig.class); - context.refresh(); - pplService = context.getBean(PPLService.class); - } - - @Test - public void testExecuteShouldPass() { - doAnswer(invocation -> { - ResponseListener listener = invocation.getArgument(1); - listener.onResponse(new QueryResponse(Collections.emptyList())); - return null; - }).when(executionEngine).execute(any(), any()); - - pplService.execute(new PPLQueryRequest("search source=t a=1", null), new ResponseListener() { - @Override - public void onResponse(QueryResponse pplQueryResponse) { - - } - - @Override - public void onFailure(Exception e) { - Assert.fail(); - } - }); - } - - @Test - public void testExecuteWithIllegalQueryShouldBeCaughtByHandler() { - pplService.execute(new PPLQueryRequest("search", null), new ResponseListener() { - @Override - public void onResponse(QueryResponse pplQueryResponse) { - Assert.fail(); - } - - @Override - public void onFailure(Exception e) { - - } + private AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + + private PPLService pplService; + + @Mock + private StorageEngine storageEngine; + + @Mock + private ExecutionEngine executionEngine; + + @Mock + private Table table; + + @Mock + private PhysicalPlan plan; + + /** + * Setup the test context. + */ + @Before + public void setUp() { + when(table.getFieldTypes()).thenReturn(ImmutableMap.of("a", ExprType.INTEGER)); + when(table.implement(any())).thenReturn(plan); + when(storageEngine.getTable(any())).thenReturn(table); + + context.registerBean(StorageEngine.class, () -> storageEngine); + context.registerBean(ExecutionEngine.class, () -> executionEngine); + context.register(PPLServiceConfig.class); + context.refresh(); + pplService = context.getBean(PPLService.class); + } + + @Test + public void testExecuteShouldPass() { + doAnswer(invocation -> { + ResponseListener listener = invocation.getArgument(1); + listener.onResponse(new QueryResponse(Collections.emptyList())); + return null; + }).when(executionEngine).execute(any(), any()); + + pplService.execute(new PPLQueryRequest("search source=t a=1", null), + new ResponseListener() { + @Override + public void onResponse(QueryResponse pplQueryResponse) { + + } + + @Override + public void onFailure(Exception e) { + Assert.fail(); + } }); - } + } + + @Test + public void testExecuteWithIllegalQueryShouldBeCaughtByHandler() { + pplService.execute(new PPLQueryRequest("search", null), new ResponseListener() { + @Override + public void onResponse(QueryResponse pplQueryResponse) { + Assert.fail(); + } + + @Override + public void onFailure(Exception e) { + + } + }); + } } \ No newline at end of file diff --git a/ppl/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/antlr/PPLSyntaxParserTest.java b/ppl/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/antlr/PPLSyntaxParserTest.java index 9933cadddd..a847181847 100644 --- a/ppl/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/antlr/PPLSyntaxParserTest.java +++ b/ppl/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/antlr/PPLSyntaxParserTest.java @@ -15,40 +15,40 @@ package com.amazon.opendistroforelasticsearch.sql.ppl.antlr; +import static org.junit.Assert.assertNotEquals; + import org.antlr.v4.runtime.tree.ParseTree; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import static org.junit.Assert.assertNotEquals; - public class PPLSyntaxParserTest { - @Rule - public ExpectedException exceptionRule = ExpectedException.none(); - - @Test - public void testSearchCommandShouldPass() { - ParseTree tree = new PPLSyntaxParser().analyzeSyntax("search source=t a=1 b=2"); - assertNotEquals(null, tree); - } - - @Test - public void testSearchCommandIgnoreSearchKeywordShouldPass() { - ParseTree tree = new PPLSyntaxParser().analyzeSyntax("source=t a=1 b=2"); - assertNotEquals(null, tree); - } - - @Test - public void testSearchFieldsCommandShouldPass() { - ParseTree tree = new PPLSyntaxParser().analyzeSyntax("search source=t a=1 b=2 | fields a,b"); - assertNotEquals(null, tree); - } - - @Test - public void testSearchCommandWithoutSourceShouldFail() { - exceptionRule.expect(RuntimeException.class); - exceptionRule.expectMessage("Failed to parse query due to offending symbol"); - - new PPLSyntaxParser().analyzeSyntax("search a=1"); - } + @Rule + public ExpectedException exceptionRule = ExpectedException.none(); + + @Test + public void testSearchCommandShouldPass() { + ParseTree tree = new PPLSyntaxParser().analyzeSyntax("search source=t a=1 b=2"); + assertNotEquals(null, tree); + } + + @Test + public void testSearchCommandIgnoreSearchKeywordShouldPass() { + ParseTree tree = new PPLSyntaxParser().analyzeSyntax("source=t a=1 b=2"); + assertNotEquals(null, tree); + } + + @Test + public void testSearchFieldsCommandShouldPass() { + ParseTree tree = new PPLSyntaxParser().analyzeSyntax("search source=t a=1 b=2 | fields a,b"); + assertNotEquals(null, tree); + } + + @Test + public void testSearchCommandWithoutSourceShouldFail() { + exceptionRule.expect(RuntimeException.class); + exceptionRule.expectMessage("Failed to parse query due to offending symbol"); + + new PPLSyntaxParser().analyzeSyntax("search a=1"); + } } \ No newline at end of file diff --git a/ppl/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/config/PPLServiceConfigTest.java b/ppl/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/config/PPLServiceConfigTest.java index c802e20348..15a8d9f537 100644 --- a/ppl/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/config/PPLServiceConfigTest.java +++ b/ppl/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/config/PPLServiceConfigTest.java @@ -15,15 +15,16 @@ package com.amazon.opendistroforelasticsearch.sql.ppl.config; +import static org.junit.Assert.assertNotNull; + import com.amazon.opendistroforelasticsearch.sql.ppl.PPLService; import org.junit.Test; -import static org.junit.Assert.assertNotNull; public class PPLServiceConfigTest { - @Test - public void testConfigPPLServiceShouldPass() { - PPLServiceConfig config = new PPLServiceConfig(); - PPLService service = config.pplService(); - assertNotNull(service); - } + @Test + public void testConfigPPLServiceShouldPass() { + PPLServiceConfig config = new PPLServiceConfig(); + PPLService service = config.pplService(); + assertNotNull(service); + } } diff --git a/ppl/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/domain/PPLQueryRequestTest.java b/ppl/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/domain/PPLQueryRequestTest.java index 70dbf00a0b..0b1e959d22 100644 --- a/ppl/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/domain/PPLQueryRequestTest.java +++ b/ppl/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/domain/PPLQueryRequestTest.java @@ -18,9 +18,9 @@ import org.junit.Test; public class PPLQueryRequestTest { - @Test - public void getRequestShouldPass() { - PPLQueryRequest request = new PPLQueryRequest("source=t a=1", null); - request.getRequest(); - } + @Test + public void getRequestShouldPass() { + PPLQueryRequest request = new PPLQueryRequest("source=t a=1", null); + request.getRequest(); + } } diff --git a/ppl/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/domain/PPLQueryResponseTest.java b/ppl/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/domain/PPLQueryResponseTest.java index df2afc2111..4a721d1aff 100644 --- a/ppl/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/domain/PPLQueryResponseTest.java +++ b/ppl/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/domain/PPLQueryResponseTest.java @@ -18,8 +18,8 @@ import org.junit.Test; public class PPLQueryResponseTest { - @Test - public void testQueryResponse() { - PPLQueryResponse response = new PPLQueryResponse(); - } + @Test + public void testQueryResponse() { + PPLQueryResponse response = new PPLQueryResponse(); + } } diff --git a/ppl/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/parser/AstBuilderTest.java b/ppl/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/parser/AstBuilderTest.java index bdbe772f17..4ed1409311 100644 --- a/ppl/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/parser/AstBuilderTest.java +++ b/ppl/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/parser/AstBuilderTest.java @@ -15,12 +15,6 @@ package com.amazon.opendistroforelasticsearch.sql.ppl.parser; -import com.amazon.opendistroforelasticsearch.sql.ppl.antlr.PPLSyntaxParser; -import com.amazon.opendistroforelasticsearch.sql.ast.Node; -import java.util.Collections; -import org.junit.Ignore; -import org.junit.Test; - import static com.amazon.opendistroforelasticsearch.sql.ast.dsl.AstDSL.agg; import static com.amazon.opendistroforelasticsearch.sql.ast.dsl.AstDSL.aggregate; import static com.amazon.opendistroforelasticsearch.sql.ast.dsl.AstDSL.argument; @@ -29,8 +23,8 @@ import static com.amazon.opendistroforelasticsearch.sql.ast.dsl.AstDSL.dedupe; import static com.amazon.opendistroforelasticsearch.sql.ast.dsl.AstDSL.defaultDedupArgs; import static com.amazon.opendistroforelasticsearch.sql.ast.dsl.AstDSL.defaultFieldsArgs; -import static com.amazon.opendistroforelasticsearch.sql.ast.dsl.AstDSL.defaultSortOptions; import static com.amazon.opendistroforelasticsearch.sql.ast.dsl.AstDSL.defaultSortFieldArgs; +import static com.amazon.opendistroforelasticsearch.sql.ast.dsl.AstDSL.defaultSortOptions; import static com.amazon.opendistroforelasticsearch.sql.ast.dsl.AstDSL.defaultStatsArgs; import static com.amazon.opendistroforelasticsearch.sql.ast.dsl.AstDSL.eval; import static com.amazon.opendistroforelasticsearch.sql.ast.dsl.AstDSL.exprList; @@ -41,7 +35,6 @@ import static com.amazon.opendistroforelasticsearch.sql.ast.dsl.AstDSL.let; import static com.amazon.opendistroforelasticsearch.sql.ast.dsl.AstDSL.map; import static com.amazon.opendistroforelasticsearch.sql.ast.dsl.AstDSL.nullLiteral; -import static com.amazon.opendistroforelasticsearch.sql.ast.dsl.AstDSL.project; import static com.amazon.opendistroforelasticsearch.sql.ast.dsl.AstDSL.projectWithArg; import static com.amazon.opendistroforelasticsearch.sql.ast.dsl.AstDSL.relation; import static com.amazon.opendistroforelasticsearch.sql.ast.dsl.AstDSL.rename; @@ -51,223 +44,230 @@ import static java.util.Collections.emptyList; import static org.junit.Assert.assertEquals; -public class AstBuilderTest { +import com.amazon.opendistroforelasticsearch.sql.ast.Node; +import com.amazon.opendistroforelasticsearch.sql.ppl.antlr.PPLSyntaxParser; +import org.junit.Ignore; +import org.junit.Test; - @Test - public void testSearchCommand() { - assertEqual("search source=t a=1", - filter( - relation("t"), - compare("=", field("a"), intLiteral(1)) - ) - ); - } +public class AstBuilderTest { - @Test - public void testSearchCommandString() { - assertEqual("search source=t a=\"a\"", - filter( - relation("t"), - compare("=", field("a"), stringLiteral("a")) - ) - ); - } + private PPLSyntaxParser parser = new PPLSyntaxParser(); + private AstBuilder astBuilder = new AstBuilder(new AstExpressionBuilder()); - @Test - public void testSearchCommandWithoutSearch() { - assertEqual("source=t a=1", - filter( - relation("t"), - compare("=", field("a"), intLiteral(1)) - ) - ); - } + @Test + public void testSearchCommand() { + assertEqual("search source=t a=1", + filter( + relation("t"), + compare("=", field("a"), intLiteral(1)) + ) + ); + } - @Test - public void testSearchCommandWithFilterBeforeSource() { - assertEqual("search a=1 source=t", - filter( - relation("t"), - compare("=", field("a"), intLiteral(1)) - )); - } + @Test + public void testSearchCommandString() { + assertEqual("search source=t a=\"a\"", + filter( + relation("t"), + compare("=", field("a"), stringLiteral("a")) + ) + ); + } - @Test - public void testWhereCommand() { - assertEqual("search source=t | where a=1", - filter( - relation("t"), - compare("=", field("a"), intLiteral(1)) - ) - ); - } + @Test + public void testSearchCommandWithoutSearch() { + assertEqual("source=t a=1", + filter( + relation("t"), + compare("=", field("a"), intLiteral(1)) + ) + ); + } - @Test - public void testFieldsCommandWithoutArguments() { - assertEqual("source=t | fields f, g", - projectWithArg( - relation("t"), - defaultFieldsArgs(), - field("f"), field("g") - )); - } + @Test + public void testSearchCommandWithFilterBeforeSource() { + assertEqual("search a=1 source=t", + filter( + relation("t"), + compare("=", field("a"), intLiteral(1)) + )); + } - @Test - public void testFieldsCommandWithIncludeArguments() { - assertEqual("source=t | fields + f, g", - projectWithArg( - relation("t"), - defaultFieldsArgs(), - field("f"), field("g") - )); - } + @Test + public void testWhereCommand() { + assertEqual("search source=t | where a=1", + filter( + relation("t"), + compare("=", field("a"), intLiteral(1)) + ) + ); + } - @Test - public void testFieldsCommandWithExcludeArguments() { - assertEqual("source=t | fields - f, g", - projectWithArg( - relation("t"), - exprList(argument("exclude", booleanLiteral(true))), - field("f"), field("g") - )); - } + @Test + public void testFieldsCommandWithoutArguments() { + assertEqual("source=t | fields f, g", + projectWithArg( + relation("t"), + defaultFieldsArgs(), + field("f"), field("g") + )); + } - @Test - public void testRenameCommand() { - assertEqual("source=t | rename f as g", - rename( - relation("t"), - map("f", "g") - )); - } + @Test + public void testFieldsCommandWithIncludeArguments() { + assertEqual("source=t | fields + f, g", + projectWithArg( + relation("t"), + defaultFieldsArgs(), + field("f"), field("g") + )); + } - @Test - public void testStatsCommand() { - assertEqual("source=t | stats count(a)", - agg( - relation("t"), - exprList( - aggregate("count", field("a")) - ), - emptyList(), - emptyList(), - defaultStatsArgs() - )); - } + @Test + public void testFieldsCommandWithExcludeArguments() { + assertEqual("source=t | fields - f, g", + projectWithArg( + relation("t"), + exprList(argument("exclude", booleanLiteral(true))), + field("f"), field("g") + )); + } - @Test - public void testStatsCommandWithByClause() { - assertEqual("source=t | stats count(a) by b DEDUP_SPLITVALUES=false", - agg( - relation("t"), - exprList( - aggregate("count", field("a")) - ), - emptyList(), - exprList(field("b")), - defaultStatsArgs() - )); - } + @Test + public void testRenameCommand() { + assertEqual("source=t | rename f as g", + rename( + relation("t"), + map("f", "g") + )); + } + @Test + public void testStatsCommand() { + assertEqual("source=t | stats count(a)", + agg( + relation("t"), + exprList( + aggregate("count", field("a")) + ), + emptyList(), + emptyList(), + defaultStatsArgs() + )); + } - @Test - public void testStatsCommandWithAlias() { - assertEqual("source=t | stats count(a) as alias", - rename( - agg( - relation("t"), - exprList( - aggregate("count", field("a")) - ), - emptyList(), - emptyList(), - defaultStatsArgs() - ), - map(aggregate("count", field("a")), field("alias")) - ) - ); - } + @Test + public void testStatsCommandWithByClause() { + assertEqual("source=t | stats count(a) by b DEDUP_SPLITVALUES=false", + agg( + relation("t"), + exprList( + aggregate("count", field("a")) + ), + emptyList(), + exprList(field("b")), + defaultStatsArgs() + )); + } - @Test - public void testDedupCommand() { - assertEqual("source=t | dedup f1, f2", - dedupe( - relation("t"), - defaultDedupArgs(), - field("f1"), field("f2") - )); - } + @Test + public void testStatsCommandWithAlias() { + assertEqual("source=t | stats count(a) as alias", + rename( + agg( + relation("t"), + exprList( + aggregate("count", field("a")) + ), + emptyList(), + emptyList(), + defaultStatsArgs() + ), + map(aggregate("count", field("a")), field("alias")) + ) + ); + } - @Ignore(value = "disable sortby from the dedup command syntax") - public void testDedupCommandWithSortby() { - assertEqual("source=t | dedup f1, f2 sortby f3", - agg( - relation("t"), - exprList(field("f1"), field("f2")), - exprList(field("f3", defaultSortFieldArgs())), - null, - defaultDedupArgs() - )); - } + @Test + public void testDedupCommand() { + assertEqual("source=t | dedup f1, f2", + dedupe( + relation("t"), + defaultDedupArgs(), + field("f1"), field("f2") + )); + } - @Test - public void testSortCommand() { - assertEqual("source=t | sort f1, f2", - sort( - relation("t"), - defaultSortOptions(), - field("f1", defaultSortFieldArgs()), - field("f2", defaultSortFieldArgs()) - )); - } + /** + * disable sortby from the dedup command syntax. + */ + @Ignore(value = "disable sortby from the dedup command syntax") + public void testDedupCommandWithSortby() { + assertEqual("source=t | dedup f1, f2 sortby f3", + agg( + relation("t"), + exprList(field("f1"), field("f2")), + exprList(field("f3", defaultSortFieldArgs())), + null, + defaultDedupArgs() + )); + } - @Test - public void testSortCommandWithOptions() { - assertEqual("source=t | sort 100 - f1, + f2", - sort( - relation("t"), - sortOptions(100), - field("f1", exprList(argument("asc", booleanLiteral(false)), - argument("type", nullLiteral()))), - field("f2", defaultSortFieldArgs()) - )); - } + @Test + public void testSortCommand() { + assertEqual("source=t | sort f1, f2", + sort( + relation("t"), + defaultSortOptions(), + field("f1", defaultSortFieldArgs()), + field("f2", defaultSortFieldArgs()) + )); + } - @Test - public void testEvalCommand() { - assertEqual("source=t | eval r=abs(f)", - eval( - relation("t"), - let( - field("r"), - function("abs", field("f")) - ) - )); - } + @Test + public void testSortCommandWithOptions() { + assertEqual("source=t | sort 100 - f1, + f2", + sort( + relation("t"), + sortOptions(100), + field("f1", exprList(argument("asc", booleanLiteral(false)), + argument("type", nullLiteral()))), + field("f2", defaultSortFieldArgs()) + )); + } - @Test - public void testIndexName() { - assertEqual("source=`log.2020.04.20.` a=1", - filter( - relation("log.2020.04.20."), - compare("=", field("a"), intLiteral(1)) - )); - } + @Test + public void testEvalCommand() { + assertEqual("source=t | eval r=abs(f)", + eval( + relation("t"), + let( + field("r"), + function("abs", field("f")) + ) + )); + } - protected void assertEqual(String query, Node expectedPlan) { - Node actualPlan = plan(query); - assertEquals(expectedPlan, actualPlan); - } + @Test + public void testIndexName() { + assertEqual("source=`log.2020.04.20.` a=1", + filter( + relation("log.2020.04.20."), + compare("=", field("a"), intLiteral(1)) + )); + } - protected void assertEqual(String query, String expected) { - Node expectedPlan = plan(expected); - assertEqual(query, expectedPlan); - } + protected void assertEqual(String query, Node expectedPlan) { + Node actualPlan = plan(query); + assertEquals(expectedPlan, actualPlan); + } - private PPLSyntaxParser parser = new PPLSyntaxParser(); - private AstBuilder astBuilder = new AstBuilder(new AstExpressionBuilder()); + protected void assertEqual(String query, String expected) { + Node expectedPlan = plan(expected); + assertEqual(query, expectedPlan); + } - private Node plan(String query) { - return astBuilder.visit(parser.analyzeSyntax(query)); - } + private Node plan(String query) { + return astBuilder.visit(parser.analyzeSyntax(query)); + } } diff --git a/ppl/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/parser/AstExpressionBuilderTest.java b/ppl/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/parser/AstExpressionBuilderTest.java index 2a8cdeb2ac..4d0e2432f1 100644 --- a/ppl/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/parser/AstExpressionBuilderTest.java +++ b/ppl/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/parser/AstExpressionBuilderTest.java @@ -15,8 +15,6 @@ package com.amazon.opendistroforelasticsearch.sql.ppl.parser; -import org.junit.Ignore; -import org.junit.Test; import static com.amazon.opendistroforelasticsearch.sql.ast.dsl.AstDSL.agg; import static com.amazon.opendistroforelasticsearch.sql.ast.dsl.AstDSL.aggregate; import static com.amazon.opendistroforelasticsearch.sql.ast.dsl.AstDSL.and; @@ -24,8 +22,8 @@ import static com.amazon.opendistroforelasticsearch.sql.ast.dsl.AstDSL.booleanLiteral; import static com.amazon.opendistroforelasticsearch.sql.ast.dsl.AstDSL.compare; import static com.amazon.opendistroforelasticsearch.sql.ast.dsl.AstDSL.defaultFieldsArgs; -import static com.amazon.opendistroforelasticsearch.sql.ast.dsl.AstDSL.defaultSortOptions; import static com.amazon.opendistroforelasticsearch.sql.ast.dsl.AstDSL.defaultSortFieldArgs; +import static com.amazon.opendistroforelasticsearch.sql.ast.dsl.AstDSL.defaultSortOptions; import static com.amazon.opendistroforelasticsearch.sql.ast.dsl.AstDSL.defaultStatsArgs; import static com.amazon.opendistroforelasticsearch.sql.ast.dsl.AstDSL.doubleLiteral; import static com.amazon.opendistroforelasticsearch.sql.ast.dsl.AstDSL.equalTo; @@ -47,331 +45,337 @@ import static com.amazon.opendistroforelasticsearch.sql.ast.dsl.AstDSL.stringLiteral; import static java.util.Collections.emptyList; -public class AstExpressionBuilderTest extends AstBuilderTest{ - - @Test - public void testLogicalNotExpr() { - assertEqual("source=t not a=1", - filter( - relation("t"), - not( - compare("=", field("a"), intLiteral(1)) - ) - )); - } - - @Test - public void testLogicalOrExpr() { - assertEqual("source=t a=1 or b=2", - filter( - relation("t"), - or( - compare("=", field("a"), intLiteral(1)), - compare("=", field("b"), intLiteral(2)) - ) - )); - } - - @Test - public void testLogicalAndExpr() { - assertEqual("source=t a=1 and b=2", - filter( - relation("t"), - and( - compare("=", field("a"), intLiteral(1)), - compare("=", field("b"), intLiteral(2)) - ) - )); - } - - @Test - public void testLogicalAndExprWithoutKeywordAnd() { - assertEqual("source=t a=1 b=2", - filter( - relation("t"), - and( - compare("=", field("a"), intLiteral(1)), - compare("=", field("b"), intLiteral(2)) - ) - )); - } - - @Ignore("search operator should not include functionCall, need to change antlr") - public void testEvalExpr() { - assertEqual("source=t f=abs(a)", - filter( - relation("t"), - equalTo( - field("f"), - function("abs", field("a")) - ) - )); - } - - @Test - public void testEvalFunctionExpr() { - assertEqual("source=t | eval f=abs(a)", - eval( - relation("t"), - let( - field("f"), - function("abs", field("a")) - ) - )); - } - - @Test - public void testEvalBinaryOperationExpr() { - assertEqual("source=t | eval f=a+b", - eval( - relation("t"), - let( - field("f"), - function("+", field("a"), field("b")) - ) - )); - } - - @Test - public void testLiteralValueBinaryOperationExpr() { - assertEqual("source=t | eval f=3+2", - eval( - relation("t"), - let( - field("f"), - function("+", intLiteral(3), intLiteral(2)) - ) - )); - } - - @Test - public void testCompareExpr() { - assertEqual("source=t a='b'", - filter( - relation("t"), - compare("=", field("a"), stringLiteral("b")) - )); - } - - @Test - public void testCompareFieldsExpr() { - assertEqual("source=t a>b", - filter( - relation("t"), - compare(">", field("a"), field("b")) - )); - } - - @Test - public void testInExpr() { - assertEqual("source=t f in (1, 2, 3)", - filter( - relation("t"), - in( - field("f"), - intLiteral(1), intLiteral(2), intLiteral(3)) - )); - } - - @Test - public void testFieldExpr() { - assertEqual("source=t | sort + f", - sort( - relation("t"), - defaultSortOptions(), - field("f", defaultSortFieldArgs()) - )); - } - - @Test - public void testSortFieldWithMinusKeyword() { - assertEqual("source=t | sort - f", - sort( - relation("t"), - defaultSortOptions(), - field( - "f", - argument("asc", booleanLiteral(false)), - argument("type", nullLiteral()) - ) - )); - } - - @Test - public void testSortFieldWithAutoKeyword() { - assertEqual("source=t | sort auto(f)", - sort( - relation("t"), - defaultSortOptions(), - field( - "f", - argument("asc", booleanLiteral(true)), - argument("type", stringLiteral("auto")) - ) - )); - } - - @Test - public void testSortFieldWithIpKeyword() { - assertEqual("source=t | sort ip(f)", - sort( - relation("t"), - defaultSortOptions(), - field( - "f", - argument("asc", booleanLiteral(true)), - argument("type", stringLiteral("ip")) - ) - )); - } - - @Test - public void testSortFieldWithNumKeyword() { - assertEqual("source=t | sort num(f)", - sort( - relation("t"), - defaultSortOptions(), - field( - "f", - argument("asc", booleanLiteral(true)), - argument("type", stringLiteral("num")) - ) - )); - } - - @Test - public void testSortFieldWithStrKeyword() { - assertEqual("source=t | sort str(f)", - sort( - relation("t"), - defaultSortOptions(), - field( - "f", - argument("asc", booleanLiteral(true)), - argument("type", stringLiteral("str")) - ) - )); - } - - @Test - public void testAggFuncCallExpr() { - assertEqual("source=t | stats avg(a) by b", - agg( - relation("t"), - exprList( - aggregate("avg", field("a")) - - ), - emptyList(), - exprList(field("b")), - defaultStatsArgs() - )); - } - - @Test - public void testPercentileAggFuncExpr() { - assertEqual("source=t | stats percentile<1>(a)", - agg( - relation("t"), - exprList( - aggregate( - "percentile", - field("a"), - argument("rank", intLiteral(1)) - ) - ), - emptyList(), - emptyList(), - defaultStatsArgs() - )); - } - - @Test - public void testEvalFuncCallExpr() { - assertEqual("source=t | eval f=abs(a)", - eval( - relation("t"), - let( - field("f"), - function("abs", field("a")) - ) - )); - } - - @Test - public void testNestedFieldName() { - assertEqual("source=t | fields field0.field1.field2", - projectWithArg( - relation("t"), - defaultFieldsArgs(), - field( - qualifiedName("field0", "field1", "field2") - ) - )); - } - - @Test - public void testFieldNameWithSpecialChars() { - assertEqual("source=t | fields `field-0`.`field#1`.`field*2`", - projectWithArg( - relation("t"), - defaultFieldsArgs(), - field( - qualifiedName("field-0", "field#1", "field*2") - ) - )); - } - - @Test - public void testStringLiteralExpr() { - assertEqual("source=t a=\"string\"", - filter( - relation("t"), - compare( - "=", - field("a"), - stringLiteral("string") - ) - )); - } - - @Test - public void testIntegerLiteralExpr() { - assertEqual("source=t a=1", - filter( - relation("t"), - compare( - "=", - field("a"), - intLiteral(1) - ) - )); - } - - @Test - public void testDoubleLiteralExpr() { - assertEqual("source=t b=0.1", - filter( - relation("t"), - compare( - "=", - field("b"), - doubleLiteral(0.1) - ) - )); - } - - @Test - public void testBooleanLiteralExpr() { - assertEqual("source=t a=true", - filter( - relation("t"), - compare( - "=", - field("a"), - booleanLiteral(true) - ) - )); - } +import org.junit.Ignore; +import org.junit.Test; + +public class AstExpressionBuilderTest extends AstBuilderTest { + + @Test + public void testLogicalNotExpr() { + assertEqual("source=t not a=1", + filter( + relation("t"), + not( + compare("=", field("a"), intLiteral(1)) + ) + )); + } + + @Test + public void testLogicalOrExpr() { + assertEqual("source=t a=1 or b=2", + filter( + relation("t"), + or( + compare("=", field("a"), intLiteral(1)), + compare("=", field("b"), intLiteral(2)) + ) + )); + } + + @Test + public void testLogicalAndExpr() { + assertEqual("source=t a=1 and b=2", + filter( + relation("t"), + and( + compare("=", field("a"), intLiteral(1)), + compare("=", field("b"), intLiteral(2)) + ) + )); + } + + @Test + public void testLogicalAndExprWithoutKeywordAnd() { + assertEqual("source=t a=1 b=2", + filter( + relation("t"), + and( + compare("=", field("a"), intLiteral(1)), + compare("=", field("b"), intLiteral(2)) + ) + )); + } + + /** + * Todo. search operator should not include functionCall, need to change antlr. + */ + @Ignore("search operator should not include functionCall, need to change antlr") + public void testEvalExpr() { + assertEqual("source=t f=abs(a)", + filter( + relation("t"), + equalTo( + field("f"), + function("abs", field("a")) + ) + )); + } + + @Test + public void testEvalFunctionExpr() { + assertEqual("source=t | eval f=abs(a)", + eval( + relation("t"), + let( + field("f"), + function("abs", field("a")) + ) + )); + } + + @Test + public void testEvalBinaryOperationExpr() { + assertEqual("source=t | eval f=a+b", + eval( + relation("t"), + let( + field("f"), + function("+", field("a"), field("b")) + ) + )); + } + + @Test + public void testLiteralValueBinaryOperationExpr() { + assertEqual("source=t | eval f=3+2", + eval( + relation("t"), + let( + field("f"), + function("+", intLiteral(3), intLiteral(2)) + ) + )); + } + + @Test + public void testCompareExpr() { + assertEqual("source=t a='b'", + filter( + relation("t"), + compare("=", field("a"), stringLiteral("b")) + )); + } + + @Test + public void testCompareFieldsExpr() { + assertEqual("source=t a>b", + filter( + relation("t"), + compare(">", field("a"), field("b")) + )); + } + + @Test + public void testInExpr() { + assertEqual("source=t f in (1, 2, 3)", + filter( + relation("t"), + in( + field("f"), + intLiteral(1), intLiteral(2), intLiteral(3)) + )); + } + + @Test + public void testFieldExpr() { + assertEqual("source=t | sort + f", + sort( + relation("t"), + defaultSortOptions(), + field("f", defaultSortFieldArgs()) + )); + } + + @Test + public void testSortFieldWithMinusKeyword() { + assertEqual("source=t | sort - f", + sort( + relation("t"), + defaultSortOptions(), + field( + "f", + argument("asc", booleanLiteral(false)), + argument("type", nullLiteral()) + ) + )); + } + + @Test + public void testSortFieldWithAutoKeyword() { + assertEqual("source=t | sort auto(f)", + sort( + relation("t"), + defaultSortOptions(), + field( + "f", + argument("asc", booleanLiteral(true)), + argument("type", stringLiteral("auto")) + ) + )); + } + + @Test + public void testSortFieldWithIpKeyword() { + assertEqual("source=t | sort ip(f)", + sort( + relation("t"), + defaultSortOptions(), + field( + "f", + argument("asc", booleanLiteral(true)), + argument("type", stringLiteral("ip")) + ) + )); + } + + @Test + public void testSortFieldWithNumKeyword() { + assertEqual("source=t | sort num(f)", + sort( + relation("t"), + defaultSortOptions(), + field( + "f", + argument("asc", booleanLiteral(true)), + argument("type", stringLiteral("num")) + ) + )); + } + + @Test + public void testSortFieldWithStrKeyword() { + assertEqual("source=t | sort str(f)", + sort( + relation("t"), + defaultSortOptions(), + field( + "f", + argument("asc", booleanLiteral(true)), + argument("type", stringLiteral("str")) + ) + )); + } + + @Test + public void testAggFuncCallExpr() { + assertEqual("source=t | stats avg(a) by b", + agg( + relation("t"), + exprList( + aggregate("avg", field("a")) + + ), + emptyList(), + exprList(field("b")), + defaultStatsArgs() + )); + } + + @Test + public void testPercentileAggFuncExpr() { + assertEqual("source=t | stats percentile<1>(a)", + agg( + relation("t"), + exprList( + aggregate( + "percentile", + field("a"), + argument("rank", intLiteral(1)) + ) + ), + emptyList(), + emptyList(), + defaultStatsArgs() + )); + } + + @Test + public void testEvalFuncCallExpr() { + assertEqual("source=t | eval f=abs(a)", + eval( + relation("t"), + let( + field("f"), + function("abs", field("a")) + ) + )); + } + + @Test + public void testNestedFieldName() { + assertEqual("source=t | fields field0.field1.field2", + projectWithArg( + relation("t"), + defaultFieldsArgs(), + field( + qualifiedName("field0", "field1", "field2") + ) + )); + } + + @Test + public void testFieldNameWithSpecialChars() { + assertEqual("source=t | fields `field-0`.`field#1`.`field*2`", + projectWithArg( + relation("t"), + defaultFieldsArgs(), + field( + qualifiedName("field-0", "field#1", "field*2") + ) + )); + } + + @Test + public void testStringLiteralExpr() { + assertEqual("source=t a=\"string\"", + filter( + relation("t"), + compare( + "=", + field("a"), + stringLiteral("string") + ) + )); + } + + @Test + public void testIntegerLiteralExpr() { + assertEqual("source=t a=1", + filter( + relation("t"), + compare( + "=", + field("a"), + intLiteral(1) + ) + )); + } + + @Test + public void testDoubleLiteralExpr() { + assertEqual("source=t b=0.1", + filter( + relation("t"), + compare( + "=", + field("b"), + doubleLiteral(0.1) + ) + )); + } + + @Test + public void testBooleanLiteralExpr() { + assertEqual("source=t a=true", + filter( + relation("t"), + compare( + "=", + field("a"), + booleanLiteral(true) + ) + )); + } } diff --git a/ppl/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/utils/ArgumentFactoryTest.java b/ppl/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/utils/ArgumentFactoryTest.java index 85caaee74d..f2400b5ade 100644 --- a/ppl/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/utils/ArgumentFactoryTest.java +++ b/ppl/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/utils/ArgumentFactoryTest.java @@ -15,15 +15,13 @@ package com.amazon.opendistroforelasticsearch.sql.ppl.utils; -import com.amazon.opendistroforelasticsearch.sql.ppl.parser.AstBuilderTest; -import org.junit.Test; import static com.amazon.opendistroforelasticsearch.sql.ast.dsl.AstDSL.agg; import static com.amazon.opendistroforelasticsearch.sql.ast.dsl.AstDSL.aggregate; import static com.amazon.opendistroforelasticsearch.sql.ast.dsl.AstDSL.argument; import static com.amazon.opendistroforelasticsearch.sql.ast.dsl.AstDSL.booleanLiteral; import static com.amazon.opendistroforelasticsearch.sql.ast.dsl.AstDSL.dedupe; -import static com.amazon.opendistroforelasticsearch.sql.ast.dsl.AstDSL.defaultSortOptions; import static com.amazon.opendistroforelasticsearch.sql.ast.dsl.AstDSL.defaultSortFieldArgs; +import static com.amazon.opendistroforelasticsearch.sql.ast.dsl.AstDSL.defaultSortOptions; import static com.amazon.opendistroforelasticsearch.sql.ast.dsl.AstDSL.exprList; import static com.amazon.opendistroforelasticsearch.sql.ast.dsl.AstDSL.field; import static com.amazon.opendistroforelasticsearch.sql.ast.dsl.AstDSL.intLiteral; @@ -33,110 +31,114 @@ import static com.amazon.opendistroforelasticsearch.sql.ast.dsl.AstDSL.stringLiteral; import static java.util.Collections.emptyList; +import com.amazon.opendistroforelasticsearch.sql.ppl.parser.AstBuilderTest; +import org.junit.Test; + public class ArgumentFactoryTest extends AstBuilderTest { - @Test - public void testFieldsCommandArgument() { - assertEqual("source=t | fields - a", - projectWithArg( - relation("t"), - exprList(argument("exclude", booleanLiteral(true))), - field("a") - )); - } + @Test + public void testFieldsCommandArgument() { + assertEqual("source=t | fields - a", + projectWithArg( + relation("t"), + exprList(argument("exclude", booleanLiteral(true))), + field("a") + )); + } - @Test - public void testFieldsCommandDefaultArgument() { - assertEqual("source=t | fields + a", "source=t | fields a"); - } + @Test + public void testFieldsCommandDefaultArgument() { + assertEqual("source=t | fields + a", "source=t | fields a"); + } - @Test - public void testStatsCommandArgument() { - assertEqual("source=t | stats partitions=1 allnum=false delim=',' avg(a) dedup_splitvalues=true", - agg( - relation("t"), - exprList(aggregate("avg", field("a"))), - emptyList(), - emptyList(), - exprList( - argument("partitions", intLiteral(1)), - argument("allnum", booleanLiteral(false)), - argument("delim", stringLiteral(",")), - argument("dedupsplit", booleanLiteral(true)) - ) - )); - } + @Test + public void testStatsCommandArgument() { + assertEqual( + "source=t | stats partitions=1 allnum=false delim=',' avg(a) dedup_splitvalues=true", + agg( + relation("t"), + exprList(aggregate("avg", field("a"))), + emptyList(), + emptyList(), + exprList( + argument("partitions", intLiteral(1)), + argument("allnum", booleanLiteral(false)), + argument("delim", stringLiteral(",")), + argument("dedupsplit", booleanLiteral(true)) + ) + )); + } - @Test - public void testStatsCommandDefaultArgument() { - assertEqual( - "source=t | stats partitions=1 allnum=false delim=' ' avg(a) dedup_splitvalues=false", - "source=t | stats avg(a)"); - } + @Test + public void testStatsCommandDefaultArgument() { + assertEqual( + "source=t | stats partitions=1 allnum=false delim=' ' avg(a) dedup_splitvalues=false", + "source=t | stats avg(a)"); + } - @Test - public void testDedupCommandArgument() { - assertEqual("source=t | dedup 3 field0 keepempty=false consecutive=true", - dedupe( - relation("t"), - exprList( - argument("number", intLiteral(3)), - argument("keepempty", booleanLiteral(false)), - argument("consecutive", booleanLiteral(true)) - ), - field("field0") - )); - } + @Test + public void testDedupCommandArgument() { + assertEqual("source=t | dedup 3 field0 keepempty=false consecutive=true", + dedupe( + relation("t"), + exprList( + argument("number", intLiteral(3)), + argument("keepempty", booleanLiteral(false)), + argument("consecutive", booleanLiteral(true)) + ), + field("field0") + )); + } - @Test - public void testDedupCommandDefaultArgument() { - assertEqual( - "source=t | dedup 1 field0 keepempty=false consecutive=false", - "source=t | dedup field0" - ); - } + @Test + public void testDedupCommandDefaultArgument() { + assertEqual( + "source=t | dedup 1 field0 keepempty=false consecutive=false", + "source=t | dedup field0" + ); + } - @Test - public void testSortCommandArgument() { - assertEqual("source=t | sort 3 field0 desc", - sort( - relation("t"), - exprList( - argument("count", intLiteral(3)), - argument("desc", booleanLiteral(true)) - ), - field("field0", defaultSortFieldArgs()) - )); - assertEqual("source=t | sort 3 field0 d", "source=t | sort 3 field0 desc"); - } + @Test + public void testSortCommandArgument() { + assertEqual("source=t | sort 3 field0 desc", + sort( + relation("t"), + exprList( + argument("count", intLiteral(3)), + argument("desc", booleanLiteral(true)) + ), + field("field0", defaultSortFieldArgs()) + )); + assertEqual("source=t | sort 3 field0 d", "source=t | sort 3 field0 desc"); + } - @Test - public void testSortCommandDefaultArgument() { - assertEqual( - "source=t | sort 1000 field0", - "source=t | sort field0" - ); - } + @Test + public void testSortCommandDefaultArgument() { + assertEqual( + "source=t | sort 1000 field0", + "source=t | sort field0" + ); + } - @Test - public void testSortFieldArgument() { - assertEqual("source=t | sort - auto(field0)", - sort( - relation("t"), - defaultSortOptions(), - field( - "field0", - exprList( - argument("asc", booleanLiteral(false)), - argument("type", stringLiteral("auto")) - ) - ) - )); - } + @Test + public void testSortFieldArgument() { + assertEqual("source=t | sort - auto(field0)", + sort( + relation("t"), + defaultSortOptions(), + field( + "field0", + exprList( + argument("asc", booleanLiteral(false)), + argument("type", stringLiteral("auto")) + ) + ) + )); + } - @Test - public void testNoArgConstructorForArgumentFactoryShouldPass() { - new ArgumentFactory(); - } + @Test + public void testNoArgConstructorForArgumentFactoryShouldPass() { + new ArgumentFactory(); + } } diff --git a/protocol/build.gradle b/protocol/build.gradle index 34e93a8353..8a90dea360 100644 --- a/protocol/build.gradle +++ b/protocol/build.gradle @@ -9,8 +9,8 @@ repositories { } dependencies { - compile group: 'com.google.guava', name: 'guava', version:'23.0' - compile group: 'org.json', name: 'json', version:'20180813' //TODO: change to other JSON lib? + compile group: 'com.google.guava', name: 'guava', version: '23.0' + compile group: 'org.json', name: 'json', version: '20180813' //TODO: change to other JSON lib? compile project(':core') testImplementation('org.junit.jupiter:junit-jupiter:5.6.2') diff --git a/protocol/src/main/java/com/amazon/opendistroforelasticsearch/sql/protocol/response/QueryResult.java b/protocol/src/main/java/com/amazon/opendistroforelasticsearch/sql/protocol/response/QueryResult.java index bcb6ca91e2..45dfd5bf88 100644 --- a/protocol/src/main/java/com/amazon/opendistroforelasticsearch/sql/protocol/response/QueryResult.java +++ b/protocol/src/main/java/com/amazon/opendistroforelasticsearch/sql/protocol/response/QueryResult.java @@ -18,79 +18,82 @@ import com.amazon.opendistroforelasticsearch.sql.data.model.ExprValue; import com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils; -import lombok.RequiredArgsConstructor; - import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; +import lombok.RequiredArgsConstructor; /** - * Query response that encapsulates query results and isolate {@link ExprValue} related from formatter implementation. + * Query response that encapsulates query results and isolate {@link ExprValue} + * related from formatter implementation. */ @RequiredArgsConstructor public class QueryResult implements Iterable { - /** - * Results which are collection of expression - */ - private final Collection exprValues; + /** + * Results which are collection of expression. + */ + private final Collection exprValues; - /** - * @return size of results - */ - public int size() { - return exprValues.size(); - } - - /** - * Parse column name from results - * @return mapping from column names to its expression type - */ - public Map columnNameTypes() { - if (exprValues.isEmpty()) { - return Collections.emptyMap(); - } + /** + * size of results. + * @return size of results + */ + public int size() { + return exprValues.size(); + } - // TODO: Need other way to extract header than inferring from data implicitly - Map tupleValue = getFirstTupleValue(); - return populateColumnNameAndTypes(tupleValue); + /** + * Parse column name from results. + * + * @return mapping from column names to its expression type + */ + public Map columnNameTypes() { + if (exprValues.isEmpty()) { + return Collections.emptyMap(); } - @Override - public Iterator iterator() { - // Any chance to avoid copy for json response generation? - return exprValues.stream(). - map(ExprValueUtils::getTupleValue). - map(Map::values). - map(this::convertExprValuesToValues). - iterator(); - } + // TODO: Need other way to extract header than inferring from data implicitly + Map tupleValue = getFirstTupleValue(); + return populateColumnNameAndTypes(tupleValue); + } - private Map getFirstTupleValue() { - // Assume expression is always tuple on first level - // and columns (keys) of all tuple values are exactly same - ExprValue firstValue = exprValues.iterator().next(); - return ExprValueUtils.getTupleValue(firstValue); - } + @Override + public Iterator iterator() { + // Any chance to avoid copy for json response generation? + return exprValues.stream() + .map(ExprValueUtils::getTupleValue) + .map(Map::values) + .map(this::convertExprValuesToValues) + .iterator(); + } - private Map populateColumnNameAndTypes(Map tupleValue) { - // Use linked hashmap to maintain original order in tuple expression - Map colNameTypes = new LinkedHashMap<>(); - tupleValue.forEach((name, expr) -> colNameTypes.put(name, getTypeString(expr))); - return colNameTypes; - } + private Map getFirstTupleValue() { + // Assume expression is always tuple on first level + // and columns (keys) of all tuple values are exactly same + ExprValue firstValue = exprValues.iterator().next(); + return ExprValueUtils.getTupleValue(firstValue); + } - private Object[] convertExprValuesToValues(Collection exprValues) { - return exprValues.stream(). - map(ExprValue::value). - toArray(Object[]::new); - } + private Map populateColumnNameAndTypes(Map tupleValue) { + // Use linked hashmap to maintain original order in tuple expression + Map colNameTypes = new LinkedHashMap<>(); + tupleValue.forEach((name, expr) -> colNameTypes.put(name, getTypeString(expr))); + return colNameTypes; + } - private String getTypeString(ExprValue exprValue) { - return exprValue.type().name().toLowerCase(); - } + private Object[] convertExprValuesToValues(Collection exprValues) { + return exprValues + .stream() + .map(ExprValue::value) + .toArray(Object[]::new); + } + + private String getTypeString(ExprValue exprValue) { + return exprValue.type().name().toLowerCase(); + } } diff --git a/protocol/src/main/java/com/amazon/opendistroforelasticsearch/sql/protocol/response/format/JsonResponseFormatter.java b/protocol/src/main/java/com/amazon/opendistroforelasticsearch/sql/protocol/response/format/JsonResponseFormatter.java index 7730fd9233..7b383dd0ca 100644 --- a/protocol/src/main/java/com/amazon/opendistroforelasticsearch/sql/protocol/response/format/JsonResponseFormatter.java +++ b/protocol/src/main/java/com/amazon/opendistroforelasticsearch/sql/protocol/response/format/JsonResponseFormatter.java @@ -16,61 +16,63 @@ package com.amazon.opendistroforelasticsearch.sql.protocol.response.format; +import static com.amazon.opendistroforelasticsearch.sql.protocol.response.format.JsonResponseFormatter.Style.PRETTY; + import lombok.Getter; import lombok.RequiredArgsConstructor; import org.json.JSONObject; -import static com.amazon.opendistroforelasticsearch.sql.protocol.response.format.JsonResponseFormatter.Style.PRETTY; - /** * Abstract class for all JSON formatter. - * @param response generic type which could be DQL or DML response + * + * @param response generic type which could be DQL or DML response */ @RequiredArgsConstructor -public abstract class JsonResponseFormatter implements ResponseFormatter { +public abstract class JsonResponseFormatter implements ResponseFormatter { - /** - * JSON format styles: pretty format or compact format without indent and space - */ - public enum Style { - PRETTY, COMPACT - } + /** + * JSON format styles: pretty format or compact format without indent and space. + */ + public enum Style { + PRETTY, COMPACT + } - /** - * JSON format style - */ - private final Style style; + /** + * JSON format style. + */ + private final Style style; - @Override - public String format(Response response) { - return jsonify(buildJsonObject(response)); - } + @Override + public String format(R response) { + return jsonify(buildJsonObject(response)); + } - @Override - public String format(Throwable t) { - JsonError error = new JsonError(t.getClass().getSimpleName(), - t.getMessage()); - return jsonify(error); - } + @Override + public String format(Throwable t) { + JsonError error = new JsonError(t.getClass().getSimpleName(), + t.getMessage()); + return jsonify(error); + } - /** - * Build JSON object to generate response json string. - * @param response response - * @return json object for response - */ - protected abstract Object buildJsonObject(Response response); + /** + * Build JSON object to generate response json string. + * + * @param response response + * @return json object for response + */ + protected abstract Object buildJsonObject(R response); - private String jsonify(Object jsonObject) { - JSONObject json = new JSONObject(jsonObject); - return (style == PRETTY) ? json.toString(2) : json.toString(); - } + private String jsonify(Object jsonObject) { + JSONObject json = new JSONObject(jsonObject); + return (style == PRETTY) ? json.toString(2) : json.toString(); + } - @RequiredArgsConstructor - @Getter - public static class JsonError { - private final String type; - private final String reason; - } + @RequiredArgsConstructor + @Getter + public static class JsonError { + private final String type; + private final String reason; + } } diff --git a/protocol/src/main/java/com/amazon/opendistroforelasticsearch/sql/protocol/response/format/ResponseFormatter.java b/protocol/src/main/java/com/amazon/opendistroforelasticsearch/sql/protocol/response/format/ResponseFormatter.java index 0dae00fbcf..4bee88f1c2 100644 --- a/protocol/src/main/java/com/amazon/opendistroforelasticsearch/sql/protocol/response/format/ResponseFormatter.java +++ b/protocol/src/main/java/com/amazon/opendistroforelasticsearch/sql/protocol/response/format/ResponseFormatter.java @@ -19,20 +19,22 @@ /** * Response formatter to format response to different formats. */ -public interface ResponseFormatter { +public interface ResponseFormatter { - /** - * Format response into string in expected format. - * @param response response - * @return string with response content formatted - */ - String format(Response response); + /** + * Format response into string in expected format. + * + * @param response response + * @return string with response content formatted + */ + String format(R response); - /** - * Format an exception into string. - * @param t exception occurred - * @return string with exception content formatted - */ - String format(Throwable t); + /** + * Format an exception into string. + * + * @param t exception occurred + * @return string with exception content formatted + */ + String format(Throwable t); } diff --git a/protocol/src/main/java/com/amazon/opendistroforelasticsearch/sql/protocol/response/format/SimpleJsonResponseFormatter.java b/protocol/src/main/java/com/amazon/opendistroforelasticsearch/sql/protocol/response/format/SimpleJsonResponseFormatter.java index d629baffbd..3a0bad1639 100644 --- a/protocol/src/main/java/com/amazon/opendistroforelasticsearch/sql/protocol/response/format/SimpleJsonResponseFormatter.java +++ b/protocol/src/main/java/com/amazon/opendistroforelasticsearch/sql/protocol/response/format/SimpleJsonResponseFormatter.java @@ -17,13 +17,12 @@ package com.amazon.opendistroforelasticsearch.sql.protocol.response.format; import com.amazon.opendistroforelasticsearch.sql.protocol.response.QueryResult; +import java.util.List; import lombok.Builder; import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.Singular; -import java.util.List; - /** * JSON response format with schema header and data rows. For example, * @@ -46,52 +45,52 @@ */ public class SimpleJsonResponseFormatter extends JsonResponseFormatter { - public SimpleJsonResponseFormatter(Style style) { - super(style); - } + public SimpleJsonResponseFormatter(Style style) { + super(style); + } - @Override - public Object buildJsonObject(QueryResult response) { - JsonResponse.JsonResponseBuilder json = JsonResponse.builder(); + @Override + public Object buildJsonObject(QueryResult response) { + JsonResponse.JsonResponseBuilder json = JsonResponse.builder(); - json.total(response.size()). - size(response.size()); + json.total(response.size()) + .size(response.size()); - response.columnNameTypes().forEach((name, type) -> json.column(new Column(name, type))); + response.columnNameTypes().forEach((name, type) -> json.column(new Column(name, type))); - json.datarows(fetchDataRows(response)); - return json.build(); - } + json.datarows(fetchDataRows(response)); + return json.build(); + } - private Object[][] fetchDataRows(QueryResult response) { - Object[][] rows = new Object[response.size()][]; - int i = 0; - for (Object[] values : response) { - rows[i++] = values; - } - return rows; + private Object[][] fetchDataRows(QueryResult response) { + Object[][] rows = new Object[response.size()][]; + int i = 0; + for (Object[] values : response) { + rows[i++] = values; } + return rows; + } - /** - * org.json requires these inner data classes be public (and static) - */ - @Builder - @Getter - public static class JsonResponse { - @Singular("column") - private final List schema; + /** + * org.json requires these inner data classes be public (and static) + */ + @Builder + @Getter + public static class JsonResponse { + @Singular("column") + private final List schema; - private final Object[][] datarows; + private final Object[][] datarows; - private long total; - private long size; - } + private long total; + private long size; + } - @RequiredArgsConstructor - @Getter - public static class Column { - private final String name; - private final String type; - } + @RequiredArgsConstructor + @Getter + public static class Column { + private final String name; + private final String type; + } } diff --git a/protocol/src/test/java/com/amazon/opendistroforelasticsearch/sql/protocol/response/QueryResultTest.java b/protocol/src/test/java/com/amazon/opendistroforelasticsearch/sql/protocol/response/QueryResultTest.java index b673506365..52cf905d9a 100644 --- a/protocol/src/test/java/com/amazon/opendistroforelasticsearch/sql/protocol/response/QueryResultTest.java +++ b/protocol/src/test/java/com/amazon/opendistroforelasticsearch/sql/protocol/response/QueryResultTest.java @@ -16,81 +16,80 @@ package com.amazon.opendistroforelasticsearch.sql.protocol.response; -import com.google.common.collect.ImmutableMap; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -import java.util.Arrays; -import java.util.Collections; - import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.tupleValue; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; +import com.google.common.collect.ImmutableMap; +import java.util.Arrays; +import java.util.Collections; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + class QueryResultTest { - @Test - void size() { - QueryResult response = new QueryResult(Arrays.asList( - tupleValue(ImmutableMap.of("name", "John", "age", 20)), - tupleValue(ImmutableMap.of("name", "Allen", "age", 30)), - tupleValue(ImmutableMap.of("name", "Smith", "age", 40)) - )); - assertEquals(3, response.size()); - } + @Test + void size() { + QueryResult response = new QueryResult(Arrays.asList( + tupleValue(ImmutableMap.of("name", "John", "age", 20)), + tupleValue(ImmutableMap.of("name", "Allen", "age", 30)), + tupleValue(ImmutableMap.of("name", "Smith", "age", 40)) + )); + assertEquals(3, response.size()); + } - @Test - void columnNameTypes() { - QueryResult response = new QueryResult(Collections.singletonList( - tupleValue(ImmutableMap.of("name", "John", "age", 20)) - )); + @Test + void columnNameTypes() { + QueryResult response = new QueryResult(Collections.singletonList( + tupleValue(ImmutableMap.of("name", "John", "age", 20)) + )); - assertEquals( - ImmutableMap.of("name", "string", "age", "integer"), - response.columnNameTypes() - ); - } + assertEquals( + ImmutableMap.of("name", "string", "age", "integer"), + response.columnNameTypes() + ); + } - @Test - void columnNameTypesFromEmptyExprValues() { - QueryResult response = new QueryResult(Collections.emptyList()); - assertTrue(response.columnNameTypes().isEmpty()); - } + @Test + void columnNameTypesFromEmptyExprValues() { + QueryResult response = new QueryResult(Collections.emptyList()); + assertTrue(response.columnNameTypes().isEmpty()); + } - @Disabled("Need to figure out column headers in some other way than inferring from data implicitly") - @Test - void columnNameTypesFromExprValuesWithMissing() { - QueryResult response = new QueryResult(Arrays.asList( - tupleValue(ImmutableMap.of("name", "John")), - tupleValue(ImmutableMap.of("name", "John", "age", 20)) - )); + @Disabled("Need to figure out column headers in other way than inferring from data implicitly") + @Test + void columnNameTypesFromExprValuesWithMissing() { + QueryResult response = new QueryResult(Arrays.asList( + tupleValue(ImmutableMap.of("name", "John")), + tupleValue(ImmutableMap.of("name", "John", "age", 20)) + )); - assertEquals( - ImmutableMap.of("name", "string", "age", "integer"), - response.columnNameTypes() - ); - } + assertEquals( + ImmutableMap.of("name", "string", "age", "integer"), + response.columnNameTypes() + ); + } - @Test - void iterate() { - QueryResult response = new QueryResult(Arrays.asList( - tupleValue(ImmutableMap.of("name", "John", "age", 20)), - tupleValue(ImmutableMap.of("name", "Allen", "age", 30)) - )); + @Test + void iterate() { + QueryResult response = new QueryResult(Arrays.asList( + tupleValue(ImmutableMap.of("name", "John", "age", 20)), + tupleValue(ImmutableMap.of("name", "Allen", "age", 30)) + )); - int i = 0; - for (Object[] objects : response) { - if (i == 0) { - assertArrayEquals(new Object[]{"John", 20}, objects); - } else if (i == 1) { - assertArrayEquals(new Object[]{"Allen", 30}, objects); - } else { - fail("More rows returned than expected"); - } - i++; - } + int i = 0; + for (Object[] objects : response) { + if (i == 0) { + assertArrayEquals(new Object[] {"John", 20}, objects); + } else if (i == 1) { + assertArrayEquals(new Object[] {"Allen", 30}, objects); + } else { + fail("More rows returned than expected"); + } + i++; } + } } \ No newline at end of file diff --git a/protocol/src/test/java/com/amazon/opendistroforelasticsearch/sql/protocol/response/format/SimpleJsonResponseFormatterTest.java b/protocol/src/test/java/com/amazon/opendistroforelasticsearch/sql/protocol/response/format/SimpleJsonResponseFormatterTest.java index d80c036686..bd9dc9a817 100644 --- a/protocol/src/test/java/com/amazon/opendistroforelasticsearch/sql/protocol/response/format/SimpleJsonResponseFormatterTest.java +++ b/protocol/src/test/java/com/amazon/opendistroforelasticsearch/sql/protocol/response/format/SimpleJsonResponseFormatterTest.java @@ -16,104 +16,102 @@ package com.amazon.opendistroforelasticsearch.sql.protocol.response.format; -import com.amazon.opendistroforelasticsearch.sql.protocol.response.QueryResult; -import com.google.common.collect.ImmutableMap; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -import java.util.Arrays; - import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.tupleValue; import static com.amazon.opendistroforelasticsearch.sql.protocol.response.format.JsonResponseFormatter.Style.COMPACT; import static com.amazon.opendistroforelasticsearch.sql.protocol.response.format.JsonResponseFormatter.Style.PRETTY; import static org.junit.jupiter.api.Assertions.assertEquals; -class SimpleJsonResponseFormatterTest { +import com.amazon.opendistroforelasticsearch.sql.protocol.response.QueryResult; +import com.google.common.collect.ImmutableMap; +import java.util.Arrays; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; - @Test - void formatResponse() { - QueryResult response = new QueryResult(Arrays.asList( - tupleValue(ImmutableMap.of("firstname", "John", "age", 20)), - tupleValue(ImmutableMap.of("firstname", "Smith", "age", 30)) - )); - SimpleJsonResponseFormatter formatter = new SimpleJsonResponseFormatter(COMPACT); - assertEquals( - "{\"schema\":[{\"name\":\"firstname\",\"type\":\"string\"},{\"name\":\"age\",\"type\":\"integer\"}]," + - "\"total\":2,\"datarows\":[[\"John\",20],[\"Smith\",30]],\"size\":2}", - formatter.format(response) - ); - } +class SimpleJsonResponseFormatterTest { - @Test - void formatResponsePretty() { - QueryResult response = new QueryResult(Arrays.asList( - tupleValue(ImmutableMap.of("firstname", "John", "age", 20)), - tupleValue(ImmutableMap.of("firstname", "Smith", "age", 30)) - )); - SimpleJsonResponseFormatter formatter = new SimpleJsonResponseFormatter(PRETTY); - assertEquals( - "{\n" + - " \"schema\": [\n" + - " {\n" + - " \"name\": \"firstname\",\n" + - " \"type\": \"string\"\n" + - " },\n" + - " {\n" + - " \"name\": \"age\",\n" + - " \"type\": \"integer\"\n" + - " }\n" + - " ],\n" + - " \"total\": 2,\n" + - " \"datarows\": [\n" + - " [\n" + - " \"John\",\n" + - " 20\n" + - " ],\n" + - " [\n" + - " \"Smith\",\n" + - " 30\n" + - " ]\n" + - " ],\n" + - " \"size\": 2\n" + - "}", - formatter.format(response) - ); - } + @Test + void formatResponse() { + QueryResult response = + new QueryResult( + Arrays.asList( + tupleValue(ImmutableMap.of("firstname", "John", "age", 20)), + tupleValue(ImmutableMap.of("firstname", "Smith", "age", 30)))); + SimpleJsonResponseFormatter formatter = new SimpleJsonResponseFormatter(COMPACT); + assertEquals( + "{\"schema\":[{\"name\":\"firstname\",\"type\":\"string\"}," + + "{\"name\":\"age\",\"type\":\"integer\"}]," + + "\"total\":2,\"datarows\":[[\"John\",20],[\"Smith\",30]],\"size\":2}", + formatter.format(response)); + } - @Disabled("Need to figure out column headers in some other way than inferring from data implicitly") - @Test - void formatResponseWithMissingValue() { - QueryResult response = new QueryResult(Arrays.asList( - tupleValue(ImmutableMap.of("firstname", "John")), - tupleValue(ImmutableMap.of("firstname", "Smith", "age", 30)) - )); - SimpleJsonResponseFormatter formatter = new SimpleJsonResponseFormatter(COMPACT); - assertEquals( - "{\"schema\":[{\"name\":\"firstname\",\"type\":\"string\"},{\"name\":\"age\",\"type\":\"integer\"}]," + - "\"total\":2,\"datarows\":[{\"row\":[\"John\",null]},{\"row\":[\"Smith\",30]}],\"size\":2}", - formatter.format(response) - ); - } + @Test + void formatResponsePretty() { + QueryResult response = + new QueryResult( + Arrays.asList( + tupleValue(ImmutableMap.of("firstname", "John", "age", 20)), + tupleValue(ImmutableMap.of("firstname", "Smith", "age", 30)))); + SimpleJsonResponseFormatter formatter = new SimpleJsonResponseFormatter(PRETTY); + assertEquals( + "{\n" + + " \"schema\": [\n" + + " {\n" + + " \"name\": \"firstname\",\n" + + " \"type\": \"string\"\n" + + " },\n" + + " {\n" + + " \"name\": \"age\",\n" + + " \"type\": \"integer\"\n" + + " }\n" + + " ],\n" + + " \"total\": 2,\n" + + " \"datarows\": [\n" + + " [\n" + + " \"John\",\n" + + " 20\n" + + " ],\n" + + " [\n" + + " \"Smith\",\n" + + " 30\n" + + " ]\n" + + " ],\n" + + " \"size\": 2\n" + + "}", + formatter.format(response)); + } - @Test - void formatError() { - SimpleJsonResponseFormatter formatter = new SimpleJsonResponseFormatter(COMPACT); - assertEquals( - "{\"reason\":\"This is an exception\",\"type\":\"RuntimeException\"}", - formatter.format(new RuntimeException("This is an exception")) - ); - } + @Disabled("Need to figure out column headers in other way than inferring from data implicitly") + @Test + void formatResponseWithMissingValue() { + QueryResult response = + new QueryResult( + Arrays.asList( + tupleValue(ImmutableMap.of("firstname", "John")), + tupleValue(ImmutableMap.of("firstname", "Smith", "age", 30)))); + SimpleJsonResponseFormatter formatter = new SimpleJsonResponseFormatter(COMPACT); + assertEquals( + "{\"schema\":[{\"name\":\"firstname\",\"type\":\"string\"}," + + "{\"name\":\"age\",\"type\":\"integer\"}],\"total\":2," + + "\"datarows\":[{\"row\":[\"John\",null]},{\"row\":[\"Smith\",30]}],\"size\":2}", + formatter.format(response)); + } - @Test - void formatErrorPretty() { - SimpleJsonResponseFormatter formatter = new SimpleJsonResponseFormatter(PRETTY); - assertEquals( - "{\n" + - " \"reason\": \"This is an exception\",\n" + - " \"type\": \"RuntimeException\"\n" + - "}", - formatter.format(new RuntimeException("This is an exception")) - ); - } + @Test + void formatError() { + SimpleJsonResponseFormatter formatter = new SimpleJsonResponseFormatter(COMPACT); + assertEquals( + "{\"reason\":\"This is an exception\",\"type\":\"RuntimeException\"}", + formatter.format(new RuntimeException("This is an exception"))); + } -} \ No newline at end of file + @Test + void formatErrorPretty() { + SimpleJsonResponseFormatter formatter = new SimpleJsonResponseFormatter(PRETTY); + assertEquals( + "{\n" + + " \"reason\": \"This is an exception\",\n" + + " \"type\": \"RuntimeException\"\n" + + "}", + formatter.format(new RuntimeException("This is an exception"))); + } +}