package io.crate.analyze;
import com.google.common.collect.ImmutableList;
import io.crate.action.sql.SessionContext;
import io.crate.analyze.symbol.Function;
import io.crate.analyze.symbol.Literal;
import io.crate.analyze.symbol.Symbol;
import io.crate.metadata.*;
import io.crate.operation.operator.AndOperator;
import io.crate.operation.operator.EqOperator;
import io.crate.operation.operator.OrOperator;
import io.crate.operation.predicate.NotPredicate;
import io.crate.operation.reference.sys.shard.LiteralReferenceImplementation;
import io.crate.test.integration.CrateUnitTest;
import io.crate.types.DataType;
import io.crate.types.DataTypes;
import org.junit.Before;
import org.junit.Test;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import static io.crate.testing.SymbolMatchers.isLiteral;
import static io.crate.testing.TestingHelpers.getFunctions;
import static org.hamcrest.CoreMatchers.instanceOf;
public class EvaluatingNormalizerTest extends CrateUnitTest {
private ClusterReferenceResolver referenceResolver;
private Functions functions;
private Reference dummyLoadInfo;
private final TransactionContext transactionContext = new TransactionContext(SessionContext.SYSTEM_SESSION);
@Before
public void prepare() throws Exception {
Map<ReferenceIdent, ReferenceImplementation> referenceImplementationMap = new HashMap<>(1, 1);
ReferenceIdent dummyLoadIdent = new ReferenceIdent(new TableIdent("test", "dummy"), "load");
dummyLoadInfo = new Reference(dummyLoadIdent, RowGranularity.NODE, DataTypes.DOUBLE);
referenceImplementationMap.put(dummyLoadIdent, new LiteralReferenceImplementation<>(0.08d));
functions = getFunctions();
referenceResolver = new ClusterReferenceResolver(referenceImplementationMap);
}
/**
* prepare the following where clause as function symbol tree:
* <p>
* where test.dummy.load = 0.08 or name != 'x' and name != 'y'
* <p>
* test.dummy.load is a expression that can be evaluated on node level
* name would be a doc level reference and is untouched
*/
private Function prepareFunctionTree() {
Reference load_1 = dummyLoadInfo;
Literal<Double> d01 = Literal.of(0.08);
Function load_eq_01 = new Function(
functionInfo(EqOperator.NAME, DataTypes.DOUBLE), Arrays.<Symbol>asList(load_1, d01));
Symbol name_ref = new Reference(
new ReferenceIdent(new TableIdent(null, "foo"), "name"),
RowGranularity.DOC,
DataTypes.STRING);
Symbol x_literal = Literal.of("x");
Symbol y_literal = Literal.of("y");
Function name_eq_x = new Function(
functionInfo(EqOperator.NAME, DataTypes.STRING), Arrays.<Symbol>asList(name_ref, x_literal));
Function name_neq_x = new Function(
functionInfo(NotPredicate.NAME, DataTypes.BOOLEAN, true), Arrays.<Symbol>asList(name_eq_x));
Function name_eq_y = new Function(
functionInfo(EqOperator.NAME, DataTypes.STRING), Arrays.<Symbol>asList(name_ref, y_literal));
Function name_neq_y = new Function(
functionInfo(NotPredicate.NAME, DataTypes.BOOLEAN, true), Arrays.<Symbol>asList(name_eq_y));
Function op_and = new Function(
functionInfo(AndOperator.NAME, DataTypes.BOOLEAN), Arrays.<Symbol>asList(name_neq_x, name_neq_y));
return new Function(
functionInfo(OrOperator.NAME, DataTypes.BOOLEAN), Arrays.<Symbol>asList(load_eq_01, op_and));
}
@Test
public void testEvaluation() {
EvaluatingNormalizer visitor = new EvaluatingNormalizer(
functions, RowGranularity.NODE, ReplaceMode.MUTATE, referenceResolver, null);
Function op_or = prepareFunctionTree();
// the dummy reference load == 0.08 evaluates to true,
// so the whole query can be normalized to a single boolean literal
Symbol query = visitor.normalize(op_or, transactionContext);
assertThat(query, isLiteral(true));
}
@Test
public void testEvaluationClusterGranularity() {
EvaluatingNormalizer visitor = new EvaluatingNormalizer(
functions, RowGranularity.CLUSTER, ReplaceMode.COPY, referenceResolver, null);
Function op_or = prepareFunctionTree();
Symbol query = visitor.normalize(op_or, transactionContext);
assertThat(query, instanceOf(Function.class));
}
private FunctionInfo functionInfo(String name, DataType dataType, boolean isPredicate) {
ImmutableList dataTypes = null;
if (isPredicate) {
dataTypes = ImmutableList.of(dataType);
} else {
dataTypes = ImmutableList.of(dataType, dataType);
}
return functions.getBuiltin(name, dataTypes).info();
}
private FunctionInfo functionInfo(String name, DataType dataType) {
return functionInfo(name, dataType, false);
}
}