Forgot the main evaluator class in the previous commit. Hee.

This commit is contained in:
Par Winzell
2009-04-13 17:27:51 +00:00
parent 859b357d7b
commit d860091612
@@ -0,0 +1,338 @@
//
// $Id: ExpressionEvaluator.java 377 2009-01-08 02:31:28Z samskivert $
//
// Depot library - a Java relational persistence library
// Copyright (C) 2006-2008 Michael Bayne and Pär Winzell
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.samskivert.depot.impl;
import java.lang.reflect.Field;
import java.util.Date;
import com.samskivert.depot.Key;
import com.samskivert.depot.PersistentRecord;
import com.samskivert.depot.clause.FieldDefinition;
import com.samskivert.depot.clause.ForUpdate;
import com.samskivert.depot.clause.FromOverride;
import com.samskivert.depot.clause.GroupBy;
import com.samskivert.depot.clause.InsertClause;
import com.samskivert.depot.clause.Join;
import com.samskivert.depot.clause.Limit;
import com.samskivert.depot.clause.OrderBy;
import com.samskivert.depot.clause.SelectClause;
import com.samskivert.depot.clause.WhereClause;
import com.samskivert.depot.expression.ColumnExp;
import com.samskivert.depot.expression.EpochSeconds;
import com.samskivert.depot.expression.FunctionExp;
import com.samskivert.depot.expression.LiteralExp;
import com.samskivert.depot.expression.SQLExpression;
import com.samskivert.depot.expression.SQLExpression.NoValue;
import com.samskivert.depot.expression.ValueExp;
import com.samskivert.depot.operator.Conditionals.Case;
import com.samskivert.depot.operator.Conditionals.Exists;
import com.samskivert.depot.operator.Conditionals.FullText;
import com.samskivert.depot.operator.Conditionals.In;
import com.samskivert.depot.operator.Conditionals.IsNull;
import com.samskivert.depot.operator.Logic.Not;
import com.samskivert.depot.operator.SQLOperator.BinaryOperator;
import com.samskivert.depot.operator.SQLOperator.MultiOperator;
import com.samskivert.depot.impl.clause.CreateIndexClause;
import com.samskivert.depot.impl.clause.DeleteClause;
import com.samskivert.depot.impl.clause.DropIndexClause;
import com.samskivert.depot.impl.clause.UpdateClause;
import com.samskivert.util.ArrayUtil;
import com.samskivert.util.Tuple;
import static com.samskivert.depot.Log.log;
/**
* Enumerates visitation methods for every possible SQL expression type.
*/
public class ExpressionEvaluator
implements ExpressionVisitor<Object>
{
public <T extends PersistentRecord> ExpressionEvaluator (Class<T> pClass, T pRec)
{
_pClass = pClass;
_pRec = pRec;
}
public Object visit (FunctionExp functionExp)
{
SQLExpression[] arguments = functionExp.getArguments();
Object[] values = new Object[functionExp.getArguments().length];
for (int ii = 0; ii < values.length; ii ++) {
values[ii] = arguments[ii].accept(this);
if (values[ii] instanceof NoValue) {
return values[ii];
}
}
if ("lower".equalsIgnoreCase(functionExp.getFunction())) {
if (values.length == 1 && values[0] instanceof String) {
return ((String) values[0]).toLowerCase();
}
}
return new NoValue("Bad Function: " + functionExp);
}
public Object visit (EpochSeconds epochSeconds)
{
Object result = epochSeconds.getArgument().accept(this);
if (result instanceof Date) {
return ((Date) result).getTime();
}
return new NoValue("Bad EpochSeconds: " + epochSeconds);
}
public Object visit (MultiOperator multiOperator)
{
SQLExpression[] operands = multiOperator.getOperands();
Object[] values = new Object[operands.length];
for (int ii = 0; ii < operands.length; ii ++) {
values[ii] = operands[ii].accept(this);
if (values[ii] instanceof NoValue) {
return values[ii];
}
}
return multiOperator.evaluate(values);
}
public Object visit (BinaryOperator binaryOperator)
{
Object left = binaryOperator.getLeftHandSide().accept(this);
Object right = binaryOperator.getRightHandSide().accept(this);
if (left instanceof NoValue) {
return left;
}
if (right instanceof NoValue) {
return right;
}
return binaryOperator.evaluate(left, right);
}
public Object visit (IsNull isNull)
{
Object operand = isNull.getColumn().accept(this);
return (operand instanceof NoValue) ? operand : operand != null;
}
public Object visit (In in)
{
Object operand = in.getColumn().accept(this);
return (operand instanceof NoValue) ? operand :
-1 != ArrayUtil.indexOf(in.getValues(), operand);
}
public Object visit (FullText.Match match)
{
return new NoValue("Full Text Match not implemented");
}
public Object visit (FullText.Rank rank)
{
return new NoValue("Full Text Match not implemented");
}
public Object visit (Case caseExp)
{
for (Tuple<SQLExpression, SQLExpression> exp : caseExp.getWhenExps()) {
Object result = exp.left.accept(this);
if (result instanceof NoValue || !(result instanceof Boolean)) {
return new NoValue("Failed to evaluate case: " + exp.left + " -> " + result);
}
if (((Boolean) result).booleanValue()) {
return exp.right.accept(this);
}
}
SQLExpression elseExp = caseExp.getElseExp();
if (elseExp != null) {
return elseExp.accept(this);
}
return null;
}
public Object visit (ColumnExp columnExp)
{
Class<? extends PersistentRecord> pClass = columnExp.getPersistentClass();
if (pClass != _pClass) {
// TODO: Accept Class -> Record mapping
return new NoValue("Column lookup on unknown persistent class: " + pClass);
}
try {
Field field = pClass.getField(columnExp.getField());
if (field == null) {
log.warning("Couldn't locate field on class", "field", columnExp.getField(),
"class", pClass);
return new NoValue("Internal Error");
}
return field.get(_pRec);
} catch (Exception e) {
log.warning("Failed to retrieve field value", "field", columnExp.getField(), e);
return new NoValue("Internal Error");
}
}
public Object visit (Not not)
{
Object result = not.getCondition().accept(this);
if (result instanceof NoValue) {
return result;
}
if (result instanceof Boolean) {
return !((Boolean) result).booleanValue();
}
return new NoValue("Boolean negation of non-boolean value: " + result);
}
public Object visit (LiteralExp literalExp)
{
return new NoValue("Cannot evaluate LiteralExp: " + literalExp);
}
public Object visit (ValueExp valueExp)
{
return valueExp.getValue();
}
public Object visit (WhereClause where)
{
Object result = where.getWhereExpression().accept(this);
if (result instanceof NoValue || result instanceof Boolean) {
return result;
}
return new NoValue("Non-boolean result from Where expression: " + result);
}
public Object visit (Key.Expression<? extends PersistentRecord> key)
{
Class<? extends PersistentRecord> pClass = key.getPersistentClass();
if (pClass != _pClass) {
// TODO: Accept Class -> Record mapping
return new NoValue("Column lookup on unknown persistent class: " + pClass);
}
String[] keyFields = DepotUtil.getKeyFields(pClass);
Comparable<?>[] values = key.getValues();
for (int ii = 0; ii < keyFields.length; ii ++) {
Object value;
try {
value = pClass.getDeclaredField(keyFields[ii]).get(_pRec);
} catch (Exception e) {
log.warning("Failed to retrieve field value", "field", keyFields[ii], e);
return new NoValue("Internal Error");
}
if (value == null) {
if (values[ii] != null) {
return false;
}
} else if (!value.equals(values[ii])) {
return false;
}
}
return true;
}
public Object visit (Exists<? extends PersistentRecord> exists)
{
throw new IllegalArgumentException("Can't evaluate expression: " + exists);
}
public Object visit (GroupBy groupBy)
{
throw new IllegalArgumentException("Can't evaluate expression: " + groupBy);
}
public Object visit (ForUpdate forUpdate)
{
throw new IllegalArgumentException("Can't evaluate expression: " + forUpdate);
}
public Object visit (OrderBy orderBy)
{
throw new IllegalArgumentException("Can't evaluate expression: " + orderBy);
}
public Object visit (Join join)
{
throw new IllegalArgumentException("Can't evaluate expression: " + join);
}
public Object visit (Limit limit)
{
throw new IllegalArgumentException("Can't evaluate expression: " + limit);
}
public Object visit (FieldDefinition fieldOverride)
{
throw new IllegalArgumentException("Can't evaluate expression: " + fieldOverride);
}
public Object visit (FromOverride fromOverride)
{
throw new IllegalArgumentException("Can't evaluate expression: " + fromOverride);
}
public Object visit (SelectClause<? extends PersistentRecord> selectClause)
{
throw new IllegalArgumentException("Can't evaluate expression: " + selectClause);
}
public Object visit (UpdateClause<? extends PersistentRecord> updateClause)
{
throw new IllegalArgumentException("Can't evaluate expression: " + updateClause);
}
public Object visit (DeleteClause deleteClause)
{
throw new IllegalArgumentException("Can't evaluate expression: " + deleteClause);
}
public Object visit (InsertClause insertClause)
{
throw new IllegalArgumentException("Can't evaluate expression: " + insertClause);
}
public Object visit (CreateIndexClause createIndexClause)
{
throw new IllegalArgumentException("Can't evaluate expression: " + createIndexClause);
}
public Object visit (DropIndexClause<? extends PersistentRecord> dropIndexClause)
{
throw new IllegalArgumentException("Can't evaluate expression: " + dropIndexClause);
}
public static Double numerical (Object o)
{
return (o instanceof Number) ? ((Number) o).doubleValue() : null;
}
public static Long integral (Object o)
{
return ((o instanceof Integer) || (o instanceof Long)) ? ((Number) o).longValue() : null;
}
protected Class<? extends PersistentRecord> _pClass;
protected PersistentRecord _pRec;
}