/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.drill.exec.store.mapr.db.json;
import org.apache.drill.common.expression.BooleanOperator;
import org.apache.drill.common.expression.FunctionCall;
import org.apache.drill.common.expression.LogicalExpression;
import org.apache.drill.common.expression.SchemaPath;
import org.apache.drill.common.expression.visitors.AbstractExprVisitor;
import org.apache.drill.exec.store.hbase.DrillHBaseConstants;
import org.ojai.Value;
import org.ojai.store.QueryCondition;
import org.ojai.store.QueryCondition.Op;
import com.google.common.collect.ImmutableList;
import com.mapr.db.MapRDB;
public class JsonConditionBuilder extends AbstractExprVisitor<JsonScanSpec, Void, RuntimeException> implements DrillHBaseConstants {
final private JsonTableGroupScan groupScan;
final private LogicalExpression le;
private boolean allExpressionsConverted = true;
public JsonConditionBuilder(JsonTableGroupScan groupScan,
LogicalExpression conditionExp) {
this.groupScan = groupScan;
this.le = conditionExp;
}
public JsonScanSpec parseTree() {
JsonScanSpec parsedSpec = le.accept(this, null);
if (parsedSpec != null) {
parsedSpec.mergeScanSpec("booleanAnd", this.groupScan.getScanSpec());
}
return parsedSpec;
}
public boolean isAllExpressionsConverted() {
// TODO Auto-generated method stub
return allExpressionsConverted;
}
@Override
public JsonScanSpec visitUnknown(LogicalExpression e, Void value) throws RuntimeException {
allExpressionsConverted = false;
return null;
}
@Override
public JsonScanSpec visitBooleanOperator(BooleanOperator op, Void value) throws RuntimeException {
return visitFunctionCall(op, value);
}
@Override
public JsonScanSpec visitFunctionCall(FunctionCall call, Void value) throws RuntimeException {
JsonScanSpec nodeScanSpec = null;
String functionName = call.getName();
ImmutableList<LogicalExpression> args = call.args;
if (CompareFunctionsProcessor.isCompareFunction(functionName)) {
CompareFunctionsProcessor processor = CompareFunctionsProcessor.process(call);
if (processor.isSuccess()) {
nodeScanSpec = createJsonScanSpec(call, processor);
}
} else {
switch(functionName) {
case "booleanAnd":
case "booleanOr":
nodeScanSpec = args.get(0).accept(this, null);
for (int i = 1; i < args.size(); ++i) {
JsonScanSpec nextScanSpec = args.get(i).accept(this, null);
if (nodeScanSpec != null && nextScanSpec != null) {
nodeScanSpec.mergeScanSpec(functionName, nextScanSpec);
} else {
allExpressionsConverted = false;
if ("booleanAnd".equals(functionName)) {
nodeScanSpec = nodeScanSpec == null ? nextScanSpec : nodeScanSpec;
}
}
}
break;
}
}
if (nodeScanSpec == null) {
allExpressionsConverted = false;
}
return nodeScanSpec;
}
private void setIsCondition(QueryCondition c,
String str,
QueryCondition.Op op,
Value v) {
switch (v.getType()) {
case BOOLEAN:
c.is(str, op, v.getBoolean());
break;
case STRING:
c.is(str, op, v.getString());
break;
case BYTE:
c.is(str, op, v.getByte());
break;
case SHORT:
c.is(str, op, v.getShort());
break;
case INT:
c.is(str, op, v.getInt());
break;
case LONG:
c.is(str, op, v.getLong());
break;
case FLOAT:
c.is(str, op, v.getFloat());
break;
case DOUBLE:
c.is(str, op, v.getDouble());
break;
case DECIMAL:
c.is(str, op, v.getDecimal());
break;
case DATE:
c.is(str, op, v.getDate());
break;
case TIME:
c.is(str, op, v.getTime());
break;
case TIMESTAMP:
c.is(str, op, v.getTimestamp());
break;
case BINARY:
c.is(str, op, v.getBinary());
break;
// XXX/TODO: Map, Array?
default:
break;
}
}
private JsonScanSpec createJsonScanSpec(FunctionCall call,
CompareFunctionsProcessor processor) {
String functionName = processor.getFunctionName();
SchemaPath field = processor.getPath();
Value fieldValue = processor.getValue();
QueryCondition cond = null;
switch (functionName) {
case "equal":
cond = MapRDB.newCondition();
setIsCondition(cond, field.getAsUnescapedPath(), Op.EQUAL, fieldValue);
cond.build();
break;
case "not_equal":
cond = MapRDB.newCondition();
setIsCondition(cond, field.getAsUnescapedPath(), Op.NOT_EQUAL, fieldValue);
cond.build();
break;
case "less_than":
cond = MapRDB.newCondition();
setIsCondition(cond, field.getAsUnescapedPath(), Op.LESS, fieldValue);
cond.build();
break;
case "less_than_or_equal_to":
cond = MapRDB.newCondition();
setIsCondition(cond, field.getAsUnescapedPath(), Op.LESS_OR_EQUAL, fieldValue);
cond.build();
break;
case "greater_than":
cond = MapRDB.newCondition();
setIsCondition(cond, field.getAsUnescapedPath(), Op.GREATER, fieldValue);
cond.build();
break;
case "greater_than_or_equal_to":
cond = MapRDB.newCondition();
setIsCondition(cond, field.getAsUnescapedPath(), Op.GREATER_OR_EQUAL, fieldValue);
cond.build();
break;
case "isnull":
cond = MapRDB.newCondition().notExists(field.getAsUnescapedPath()).build();
break;
case "isnotnull":
cond = MapRDB.newCondition().exists(field.getAsUnescapedPath()).build();
break;
case "istrue":
cond = MapRDB.newCondition().is(field.getAsUnescapedPath(), Op.EQUAL, true).build();
break;
case "isnotfalse":
cond = MapRDB.newCondition().is(field.getAsUnescapedPath(), Op.NOT_EQUAL, false).build();
break;
case "isfalse":
cond = MapRDB.newCondition().is(field.getAsUnescapedPath(), Op.EQUAL, false).build();
break;
case "isnottrue":
cond = MapRDB.newCondition().is(field.getAsUnescapedPath(), Op.NOT_EQUAL, true).build();
break;
case "like":
cond = MapRDB.newCondition().like(field.getAsUnescapedPath(), fieldValue.getString()).build();
break;
default:
}
if (cond != null) {
return new JsonScanSpec(groupScan.getTableName(), cond);
}
return null;
}
}