Give Depot the ability to evaluate SQL expressions without contacting the database. This code is not yet tied into anything, but possible applications, in increasing order of amazingness:
*) We do not currently invalidate cached keysets even when we know for a fact that the associated records have changed (and exactly how they've changed). By storing along with each cached keyset the query datastructure that was used to fetch the keys, we can use the SQLExpression evaluator to do a secondary invalidation sweep over the records when they're requested and make sure they still match the WHERE clause of the original query. If they don't, we toss'em from the cached keyset. This basically means we can trust our cached keysets much more and increase the amount of time we keep them around in the cache. *) Extending the first idea, we can do more than lazily invalidate parts of cached collections. We can, in fact, automatically adjust every relevant cached collection each time a record is deleted, inserted or modified. In theory, we could guarantee perpetual veracity of all cached collection queries. It's not a given that this is in every way a good idea, but it's a very interesting one to investigate. As part of this change, ExpressionVisitor methods have to return a value. Slightly less elegant, but of greater general utility.
This commit is contained in:
@@ -46,7 +46,7 @@ public class Key<T extends PersistentRecord> extends WhereClause
|
||||
implements SQLExpression, CacheKey, ValidatingCacheInvalidator, Serializable
|
||||
{
|
||||
/** Handles the matching of the key columns to its bound values. This is needed so that we can
|
||||
* combine a buncy of keys into a {@link KeySet}. */
|
||||
* combine a bunch of keys into a {@link KeySet}. */
|
||||
public static class Expression<U extends PersistentRecord> implements SQLExpression
|
||||
{
|
||||
public Expression (Class<U> pClass, Comparable<?>[] values) {
|
||||
@@ -59,8 +59,8 @@ public class Key<T extends PersistentRecord> extends WhereClause
|
||||
public Comparable<?>[] getValues () {
|
||||
return _values;
|
||||
}
|
||||
public void accept (ExpressionVisitor builder) {
|
||||
builder.visit(this);
|
||||
public Object accept (ExpressionVisitor<?> builder) {
|
||||
return builder.visit(this);
|
||||
}
|
||||
public void addClasses (Collection<Class<? extends PersistentRecord>> classSet) {
|
||||
classSet.add(getPersistentClass());
|
||||
@@ -186,9 +186,9 @@ public class Key<T extends PersistentRecord> extends WhereClause
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public void accept (ExpressionVisitor builder)
|
||||
public Object accept (ExpressionVisitor<?> builder)
|
||||
{
|
||||
builder.visit(this);
|
||||
return builder.visit(this);
|
||||
}
|
||||
|
||||
// from CacheKey
|
||||
|
||||
@@ -294,9 +294,9 @@ public abstract class KeySet<T extends PersistentRecord> extends WhereClause
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public void accept (ExpressionVisitor builder)
|
||||
public Object accept (ExpressionVisitor<?> builder)
|
||||
{
|
||||
builder.visit(this);
|
||||
return builder.visit(this);
|
||||
}
|
||||
|
||||
// from ValidatingCacheInvalidator
|
||||
|
||||
@@ -81,9 +81,9 @@ public class FieldDefinition implements QueryClause
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public void accept (ExpressionVisitor visitor)
|
||||
public Object accept (ExpressionVisitor<?> visitor)
|
||||
{
|
||||
visitor.visit(this);
|
||||
return visitor.visit(this);
|
||||
}
|
||||
|
||||
/** The name of the field on the persistent object to override. */
|
||||
|
||||
@@ -31,9 +31,9 @@ import com.samskivert.depot.impl.ExpressionVisitor;
|
||||
public class ForUpdate implements QueryClause
|
||||
{
|
||||
// from SQLExpression
|
||||
public void accept (ExpressionVisitor builder)
|
||||
public Object accept (ExpressionVisitor<?> builder)
|
||||
{
|
||||
builder.visit(this);
|
||||
return builder.visit(this);
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
|
||||
@@ -63,9 +63,9 @@ public class FromOverride implements QueryClause
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public void accept (ExpressionVisitor builder)
|
||||
public Object accept (ExpressionVisitor<?> builder)
|
||||
{
|
||||
builder.visit(this);
|
||||
return builder.visit(this);
|
||||
}
|
||||
|
||||
@Override // from Object
|
||||
|
||||
@@ -42,15 +42,14 @@ public class GroupBy implements QueryClause
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public void accept (ExpressionVisitor builder)
|
||||
public Object accept (ExpressionVisitor<?> builder)
|
||||
{
|
||||
builder.visit(this);
|
||||
return builder.visit(this);
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public void addClasses (Collection<Class<? extends PersistentRecord>> classSet)
|
||||
{
|
||||
// I can't imagine a GROUP BY clause bringing in new tables... ?
|
||||
}
|
||||
|
||||
/** The expressions that are generated for the clause. */
|
||||
|
||||
@@ -62,9 +62,9 @@ public class InsertClause implements QueryClause
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public void accept (ExpressionVisitor builder)
|
||||
public Object accept (ExpressionVisitor<?> builder)
|
||||
{
|
||||
builder.visit(this);
|
||||
return builder.visit(this);
|
||||
}
|
||||
|
||||
protected Class<? extends PersistentRecord> _pClass;
|
||||
|
||||
@@ -74,9 +74,9 @@ public class Join implements QueryClause
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public void accept (ExpressionVisitor builder)
|
||||
public Object accept (ExpressionVisitor<?> builder)
|
||||
{
|
||||
builder.visit(this);
|
||||
return builder.visit(this);
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
|
||||
@@ -47,9 +47,9 @@ public class Limit implements QueryClause
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public void accept (ExpressionVisitor builder)
|
||||
public Object accept (ExpressionVisitor<?> builder)
|
||||
{
|
||||
builder.visit(this);
|
||||
return builder.visit(this);
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
|
||||
@@ -76,9 +76,9 @@ public class OrderBy implements QueryClause
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public void accept (ExpressionVisitor builder)
|
||||
public Object accept (ExpressionVisitor<?> builder)
|
||||
{
|
||||
builder.visit(this);
|
||||
return builder.visit(this);
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
|
||||
@@ -189,9 +189,9 @@ public class SelectClause<T extends PersistentRecord> implements QueryClause
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public void accept (ExpressionVisitor builder)
|
||||
public Object accept (ExpressionVisitor<?> builder)
|
||||
{
|
||||
builder.visit(this);
|
||||
return builder.visit(this);
|
||||
}
|
||||
|
||||
@Override // from Object
|
||||
|
||||
@@ -73,9 +73,9 @@ public class Where extends WhereClause
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public void accept (ExpressionVisitor builder)
|
||||
public Object accept (ExpressionVisitor<?> builder)
|
||||
{
|
||||
builder.visit(this);
|
||||
return builder.visit(this);
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
|
||||
@@ -52,9 +52,9 @@ public class ColumnExp
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public void accept (ExpressionVisitor builder)
|
||||
public Object accept (ExpressionVisitor<?> builder)
|
||||
{
|
||||
builder.visit(this);
|
||||
return builder.visit(this);
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
|
||||
@@ -39,9 +39,9 @@ public class EpochSeconds implements SQLExpression
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public void accept (ExpressionVisitor builder)
|
||||
public Object accept (ExpressionVisitor<?> builder)
|
||||
{
|
||||
builder.visit(this);
|
||||
return builder.visit(this);
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
|
||||
@@ -20,10 +20,10 @@
|
||||
|
||||
package com.samskivert.depot.expression;
|
||||
|
||||
import com.samskivert.util.StringUtil;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import com.samskivert.util.StringUtil;
|
||||
|
||||
import com.samskivert.depot.PersistentRecord;
|
||||
import com.samskivert.depot.impl.ExpressionVisitor;
|
||||
|
||||
@@ -42,9 +42,9 @@ public class FunctionExp implements SQLExpression
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public void accept (ExpressionVisitor builder)
|
||||
public Object accept (ExpressionVisitor<?> builder)
|
||||
{
|
||||
builder.visit(this);
|
||||
return builder.visit(this);
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
|
||||
@@ -38,9 +38,9 @@ public class LiteralExp
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public void accept (ExpressionVisitor builder)
|
||||
public Object accept (ExpressionVisitor<?> builder)
|
||||
{
|
||||
builder.visit(this);
|
||||
return builder.visit(this);
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
|
||||
@@ -31,13 +31,27 @@ import com.samskivert.depot.impl.SQLBuilder;
|
||||
*/
|
||||
public interface SQLExpression
|
||||
{
|
||||
public static final class NoValue
|
||||
{
|
||||
public NoValue (String reason)
|
||||
{
|
||||
_reason = reason;
|
||||
}
|
||||
|
||||
public String toString () {
|
||||
return "[unknown value, reason=" + _reason + "]";
|
||||
}
|
||||
|
||||
protected String _reason;
|
||||
}
|
||||
|
||||
/**
|
||||
* Most uses of this class have been implemented with a visitor pattern. Create your own
|
||||
* {@link ExpressionVisitor} and call this method with it.
|
||||
*
|
||||
* @see SQLBuilder
|
||||
*/
|
||||
public void accept (ExpressionVisitor builder);
|
||||
public Object accept (ExpressionVisitor<?> visitor);
|
||||
|
||||
/**
|
||||
* Adds all persistent classes that are brought into the SQL context by this clause: FROM
|
||||
|
||||
@@ -31,15 +31,15 @@ import com.samskivert.depot.impl.ExpressionVisitor;
|
||||
public class ValueExp
|
||||
implements SQLExpression
|
||||
{
|
||||
public ValueExp (Object _value)
|
||||
public ValueExp (Object value)
|
||||
{
|
||||
this._value = _value;
|
||||
_value = value;
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public void accept (ExpressionVisitor builder)
|
||||
public Object accept (ExpressionVisitor<?> builder)
|
||||
{
|
||||
builder.visit(this);
|
||||
return builder.visit(this);
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
|
||||
@@ -71,7 +71,7 @@ import com.samskivert.depot.impl.clause.UpdateClause;
|
||||
* Implements the base functionality of the SQL-building pass of {@link SQLBuilder}. Dialectal
|
||||
* subclasses of this should be created and returned from {@link SQLBuilder#getBuildVisitor()}.
|
||||
*/
|
||||
public abstract class BuildVisitor implements ExpressionVisitor
|
||||
public abstract class BuildVisitor implements ExpressionVisitor<Void>
|
||||
{
|
||||
public String getQuery ()
|
||||
{
|
||||
@@ -83,7 +83,7 @@ public abstract class BuildVisitor implements ExpressionVisitor
|
||||
return _bindables;
|
||||
}
|
||||
|
||||
public void visit (FromOverride override)
|
||||
public Void visit (FromOverride override)
|
||||
{
|
||||
_builder.append(" from " );
|
||||
List<Class<? extends PersistentRecord>> from = override.getFromClasses();
|
||||
@@ -95,24 +95,27 @@ public abstract class BuildVisitor implements ExpressionVisitor
|
||||
_builder.append(" as ");
|
||||
appendTableAbbreviation(from.get(ii));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void visit (FieldDefinition definition)
|
||||
public Void visit (FieldDefinition definition)
|
||||
{
|
||||
definition.getDefinition().accept(this);
|
||||
if (_enableAliasing) {
|
||||
_builder.append(" as ");
|
||||
appendIdentifier(definition.getField());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void visit (WhereClause where)
|
||||
public Void visit (WhereClause where)
|
||||
{
|
||||
_builder.append(" where ");
|
||||
where.getWhereExpression().accept(this);
|
||||
return null;
|
||||
}
|
||||
|
||||
public void visit (Key.Expression<? extends PersistentRecord> key)
|
||||
public Void visit (Key.Expression<? extends PersistentRecord> key)
|
||||
{
|
||||
Class<? extends PersistentRecord> pClass = key.getPersistentClass();
|
||||
String[] keyFields = DepotUtil.getKeyFields(pClass);
|
||||
@@ -134,9 +137,10 @@ public abstract class BuildVisitor implements ExpressionVisitor
|
||||
bindValue(values[ii]);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void visit (FunctionExp functionExp)
|
||||
public Void visit (FunctionExp functionExp)
|
||||
{
|
||||
_builder.append(functionExp.getFunction());
|
||||
_builder.append("(");
|
||||
@@ -148,11 +152,12 @@ public abstract class BuildVisitor implements ExpressionVisitor
|
||||
arguments[ii].accept(this);
|
||||
}
|
||||
_builder.append(")");
|
||||
return null;
|
||||
}
|
||||
|
||||
public void visit (MultiOperator multiOperator)
|
||||
public Void visit (MultiOperator multiOperator)
|
||||
{
|
||||
SQLExpression[] conditions = multiOperator.getConditions();
|
||||
SQLExpression[] conditions = multiOperator.getOperands();
|
||||
for (int ii = 0; ii < conditions.length; ii++) {
|
||||
if (ii > 0) {
|
||||
_builder.append(" ").append(multiOperator.operator()).append(" ");
|
||||
@@ -161,29 +166,32 @@ public abstract class BuildVisitor implements ExpressionVisitor
|
||||
conditions[ii].accept(this);
|
||||
_builder.append(")");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void visit (BinaryOperator binaryOperator)
|
||||
public Void visit (BinaryOperator binaryOperator)
|
||||
{
|
||||
_builder.append('(');
|
||||
binaryOperator.getLeftHandSide().accept(this);
|
||||
_builder.append(binaryOperator.operator());
|
||||
binaryOperator.getRightHandSide().accept(this);
|
||||
_builder.append(')');
|
||||
return null;
|
||||
}
|
||||
|
||||
public void visit (IsNull isNull)
|
||||
public Void visit (IsNull isNull)
|
||||
{
|
||||
isNull.getColumn().accept(this);
|
||||
_builder.append(" is null");
|
||||
return null;
|
||||
}
|
||||
|
||||
public void visit (In in)
|
||||
public Void visit (In in)
|
||||
{
|
||||
// if the In() expression is empty, replace it with a 'false'
|
||||
if (in.getValues().length == 0) {
|
||||
new ValueExp(false).accept(this);
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
in.getColumn().accept(this);
|
||||
_builder.append(" in (");
|
||||
@@ -195,14 +203,15 @@ public abstract class BuildVisitor implements ExpressionVisitor
|
||||
bindValue(values[ii]);
|
||||
}
|
||||
_builder.append(")");
|
||||
return null;
|
||||
}
|
||||
|
||||
public abstract void visit (EpochSeconds seconds);
|
||||
public abstract Void visit (EpochSeconds seconds);
|
||||
|
||||
public abstract void visit (FullText.Match match);
|
||||
public abstract void visit (FullText.Rank rank);
|
||||
public abstract Void visit (FullText.Match match);
|
||||
public abstract Void visit (FullText.Rank rank);
|
||||
|
||||
public void visit (Case caseExp)
|
||||
public Void visit (Case caseExp)
|
||||
{
|
||||
_builder.append("(case ");
|
||||
for (Tuple<SQLExpression, SQLExpression> tuple : caseExp.getWhenExps()) {
|
||||
@@ -217,21 +226,24 @@ public abstract class BuildVisitor implements ExpressionVisitor
|
||||
elseExp.accept(this);
|
||||
}
|
||||
_builder.append(" end)");
|
||||
return null;
|
||||
}
|
||||
|
||||
public void visit (ColumnExp columnExp)
|
||||
public Void visit (ColumnExp columnExp)
|
||||
{
|
||||
appendRhsColumn(columnExp.getPersistentClass(), columnExp.getField());
|
||||
return null;
|
||||
}
|
||||
|
||||
public void visit (Not not)
|
||||
public Void visit (Not not)
|
||||
{
|
||||
_builder.append(" not (");
|
||||
not.getCondition().accept(this);
|
||||
_builder.append(")");
|
||||
return null;
|
||||
}
|
||||
|
||||
public void visit (GroupBy groupBy)
|
||||
public Void visit (GroupBy groupBy)
|
||||
{
|
||||
_builder.append(" group by ");
|
||||
|
||||
@@ -242,14 +254,16 @@ public abstract class BuildVisitor implements ExpressionVisitor
|
||||
}
|
||||
values[ii].accept(this);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void visit (ForUpdate forUpdate)
|
||||
public Void visit (ForUpdate forUpdate)
|
||||
{
|
||||
_builder.append(" for update ");
|
||||
return null;
|
||||
}
|
||||
|
||||
public void visit (OrderBy orderBy)
|
||||
public Void visit (OrderBy orderBy)
|
||||
{
|
||||
_builder.append(" order by ");
|
||||
|
||||
@@ -262,9 +276,10 @@ public abstract class BuildVisitor implements ExpressionVisitor
|
||||
values[ii].accept(this);
|
||||
_builder.append(" ").append(orders[ii]);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void visit (Join join)
|
||||
public Void visit (Join join)
|
||||
{
|
||||
switch (join.getType()) {
|
||||
case INNER:
|
||||
@@ -282,31 +297,36 @@ public abstract class BuildVisitor implements ExpressionVisitor
|
||||
appendTableAbbreviation(join.getJoinClass());
|
||||
_builder.append(" on ");
|
||||
join.getJoinCondition().accept(this);
|
||||
return null;
|
||||
}
|
||||
|
||||
public void visit (Limit limit)
|
||||
public Void visit (Limit limit)
|
||||
{
|
||||
_builder.append(" limit ").append(limit.getCount()).
|
||||
append(" offset ").append(limit.getOffset());
|
||||
return null;
|
||||
}
|
||||
|
||||
public void visit (LiteralExp literalExp)
|
||||
public Void visit (LiteralExp literalExp)
|
||||
{
|
||||
_builder.append(literalExp.getText());
|
||||
return null;
|
||||
}
|
||||
|
||||
public void visit (ValueExp valueExp)
|
||||
public Void visit (ValueExp valueExp)
|
||||
{
|
||||
bindValue(valueExp.getValue());
|
||||
return null;
|
||||
}
|
||||
|
||||
public void visit (Exists<? extends PersistentRecord> exists)
|
||||
public Void visit (Exists<? extends PersistentRecord> exists)
|
||||
{
|
||||
_builder.append("exists ");
|
||||
exists.getSubClause().accept(this);
|
||||
return null;
|
||||
}
|
||||
|
||||
public void visit (SelectClause<? extends PersistentRecord> selectClause)
|
||||
public Void visit (SelectClause<? extends PersistentRecord> selectClause)
|
||||
{
|
||||
Class<? extends PersistentRecord> pClass = selectClause.getPersistentClass();
|
||||
boolean isInner = _innerClause;
|
||||
@@ -401,9 +421,10 @@ public abstract class BuildVisitor implements ExpressionVisitor
|
||||
if (isInner) {
|
||||
_builder.append(")");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void visit (UpdateClause<? extends PersistentRecord> updateClause)
|
||||
public Void visit (UpdateClause<? extends PersistentRecord> updateClause)
|
||||
{
|
||||
if (updateClause.getWhereClause() == null) {
|
||||
throw new IllegalArgumentException(
|
||||
@@ -436,9 +457,10 @@ public abstract class BuildVisitor implements ExpressionVisitor
|
||||
}
|
||||
}
|
||||
updateClause.getWhereClause().accept(this);
|
||||
return null;
|
||||
}
|
||||
|
||||
public void visit (DeleteClause deleteClause)
|
||||
public Void visit (DeleteClause deleteClause)
|
||||
{
|
||||
_builder.append("delete from ");
|
||||
appendTableName(deleteClause.getPersistentClass());
|
||||
@@ -446,9 +468,10 @@ public abstract class BuildVisitor implements ExpressionVisitor
|
||||
appendTableAbbreviation(deleteClause.getPersistentClass());
|
||||
_builder.append(" ");
|
||||
deleteClause.getWhereClause().accept(this);
|
||||
return null;
|
||||
}
|
||||
|
||||
public void visit (InsertClause insertClause)
|
||||
public Void visit (InsertClause insertClause)
|
||||
{
|
||||
Class<? extends PersistentRecord> pClass = insertClause.getPersistentClass();
|
||||
Object pojo = insertClause.getPojo();
|
||||
@@ -487,9 +510,10 @@ public abstract class BuildVisitor implements ExpressionVisitor
|
||||
bindField(pClass, field, pojo);
|
||||
}
|
||||
_builder.append(")");
|
||||
return null;
|
||||
}
|
||||
|
||||
public void visit (CreateIndexClause createIndexClause)
|
||||
public Void visit (CreateIndexClause createIndexClause)
|
||||
{
|
||||
_builder.append("create ");
|
||||
if (createIndexClause.isUnique()) {
|
||||
@@ -520,12 +544,14 @@ public abstract class BuildVisitor implements ExpressionVisitor
|
||||
_defaultType = null;
|
||||
|
||||
_builder.append(")");
|
||||
return null;
|
||||
}
|
||||
|
||||
public void visit (DropIndexClause<? extends PersistentRecord> dropIndexClause)
|
||||
public Void visit (DropIndexClause<? extends PersistentRecord> dropIndexClause)
|
||||
{
|
||||
_builder.append("drop index ");
|
||||
appendIdentifier(dropIndexClause.getName());
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void bindValue (Object object)
|
||||
|
||||
@@ -57,35 +57,35 @@ import com.samskivert.depot.impl.clause.UpdateClause;
|
||||
/**
|
||||
* Enumerates visitation methods for every possible SQL expression type.
|
||||
*/
|
||||
public interface ExpressionVisitor
|
||||
public interface ExpressionVisitor<T>
|
||||
{
|
||||
public void visit (FieldDefinition fieldOverride);
|
||||
public void visit (FunctionExp functionExp);
|
||||
public void visit (EpochSeconds epochSeconds);
|
||||
public void visit (FromOverride fromOverride);
|
||||
public void visit (MultiOperator multiOperator);
|
||||
public void visit (BinaryOperator binaryOperator);
|
||||
public void visit (IsNull isNull);
|
||||
public void visit (In in);
|
||||
public void visit (FullText.Match match);
|
||||
public void visit (FullText.Rank rank);
|
||||
public void visit (ColumnExp columnExp);
|
||||
public void visit (Not not);
|
||||
public void visit (GroupBy groupBy);
|
||||
public void visit (ForUpdate forUpdate);
|
||||
public void visit (OrderBy orderBy);
|
||||
public void visit (Join join);
|
||||
public void visit (Limit limit);
|
||||
public void visit (LiteralExp literalExp);
|
||||
public void visit (ValueExp valueExp);
|
||||
public void visit (WhereClause where);
|
||||
public void visit (Key.Expression<? extends PersistentRecord> key);
|
||||
public void visit (Exists<? extends PersistentRecord> exists);
|
||||
public void visit (SelectClause<? extends PersistentRecord> selectClause);
|
||||
public void visit (UpdateClause<? extends PersistentRecord> updateClause);
|
||||
public void visit (DeleteClause deleteClause);
|
||||
public void visit (InsertClause insertClause);
|
||||
public void visit (CreateIndexClause createIndexClause);
|
||||
public void visit (DropIndexClause<? extends PersistentRecord> dropIndexClause);
|
||||
public void visit (Case caseExp);
|
||||
public T visit (FieldDefinition fieldOverride);
|
||||
public T visit (FunctionExp functionExp);
|
||||
public T visit (EpochSeconds epochSeconds);
|
||||
public T visit (FromOverride fromOverride);
|
||||
public T visit (MultiOperator multiOperator);
|
||||
public T visit (BinaryOperator binaryOperator);
|
||||
public T visit (IsNull isNull);
|
||||
public T visit (In in);
|
||||
public T visit (FullText.Match match);
|
||||
public T visit (FullText.Rank match);
|
||||
public T visit (ColumnExp columnExp);
|
||||
public T visit (Not not);
|
||||
public T visit (GroupBy groupBy);
|
||||
public T visit (ForUpdate forUpdate);
|
||||
public T visit (OrderBy orderBy);
|
||||
public T visit (Join join);
|
||||
public T visit (Limit limit);
|
||||
public T visit (LiteralExp literalExp);
|
||||
public T visit (ValueExp valueExp);
|
||||
public T visit (WhereClause where);
|
||||
public T visit (Key.Expression<? extends PersistentRecord> key);
|
||||
public T visit (Exists<? extends PersistentRecord> exists);
|
||||
public T visit (SelectClause<? extends PersistentRecord> selectClause);
|
||||
public T visit (UpdateClause<? extends PersistentRecord> updateClause);
|
||||
public T visit (DeleteClause deleteClause);
|
||||
public T visit (InsertClause insertClause);
|
||||
public T visit (CreateIndexClause createIndexClause);
|
||||
public T visit (DropIndexClause<? extends PersistentRecord> dropIndexClause);
|
||||
public T visit (Case caseExp);
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ public class HSQLBuilder
|
||||
{
|
||||
public class HBuildVisitor extends BuildVisitor
|
||||
{
|
||||
@Override public void visit (FullText.Match match)
|
||||
@Override public Void visit (FullText.Match match)
|
||||
{
|
||||
// HSQL doesn't have real full text search, so we fake it by creating a condition like
|
||||
// (lower(COL1) like '%foo%') OR (lower(COL1) like '%bar%') OR ...
|
||||
@@ -92,16 +92,17 @@ public class HSQLBuilder
|
||||
// then just OR them all together and we have our query
|
||||
_ftsCondition = new Or(bits);
|
||||
_ftsCondition.accept(this);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override public void visit (FullText.Rank rank)
|
||||
@Override public Void visit (FullText.Rank rank)
|
||||
{
|
||||
// not implemented for HSQL
|
||||
_builder.append("0");
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit (MultiOperator operator)
|
||||
public Void visit (MultiOperator operator)
|
||||
{
|
||||
String op;
|
||||
// HSQL doesn't handle & and | operators
|
||||
@@ -112,13 +113,12 @@ public class HSQLBuilder
|
||||
op = "bitor";
|
||||
|
||||
} else {
|
||||
super.visit(operator);
|
||||
return;
|
||||
return super.visit(operator);
|
||||
}
|
||||
|
||||
_builder.append(op).append("(");
|
||||
boolean virgin = true;
|
||||
for (SQLExpression bit: operator.getConditions()) {
|
||||
for (SQLExpression bit: operator.getOperands()) {
|
||||
if (!virgin) {
|
||||
_builder.append(", ");
|
||||
}
|
||||
@@ -126,26 +126,29 @@ public class HSQLBuilder
|
||||
virgin = false;
|
||||
}
|
||||
_builder.append(")");
|
||||
return null;
|
||||
}
|
||||
|
||||
public void visit (EpochSeconds epochSeconds)
|
||||
public Void visit (EpochSeconds epochSeconds)
|
||||
{
|
||||
_builder.append("datediff('ss', ");
|
||||
epochSeconds.getArgument().accept(this);
|
||||
_builder.append(", '1970-01-01')");
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit (CreateIndexClause createIndexClause)
|
||||
public Void visit (CreateIndexClause createIndexClause)
|
||||
{
|
||||
for (Tuple<SQLExpression, Order> field : createIndexClause.getFields()) {
|
||||
if (!(field.left instanceof ColumnExp)) {
|
||||
log.warning("This database can't handle complex indexes. Aborting creation.",
|
||||
"ixName", createIndexClause.getName());
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
super.visit(createIndexClause);
|
||||
return null;
|
||||
}
|
||||
|
||||
protected HBuildVisitor (DepotTypes types)
|
||||
|
||||
@@ -63,17 +63,19 @@ public class MySQLBuilder
|
||||
{
|
||||
public class MSBuildVisitor extends BuildVisitor
|
||||
{
|
||||
@Override public void visit (FullText.Match match)
|
||||
@Override public Void visit (FullText.Match match)
|
||||
{
|
||||
renderMatch(match.getDefinition());
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override public void visit (FullText.Rank rank)
|
||||
@Override public Void visit (FullText.Rank rank)
|
||||
{
|
||||
renderMatch(rank.getDefinition());
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override public void visit (DeleteClause deleteClause)
|
||||
@Override public Void visit (DeleteClause deleteClause)
|
||||
{
|
||||
_builder.append("delete from ");
|
||||
appendTableName(deleteClause.getPersistentClass());
|
||||
@@ -87,30 +89,33 @@ public class MySQLBuilder
|
||||
} finally {
|
||||
_types.setUseTableAbbreviations(savedFlag);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void visit (EpochSeconds epochSeconds)
|
||||
public Void visit (EpochSeconds epochSeconds)
|
||||
{
|
||||
_builder.append("unix_timestamp(");
|
||||
epochSeconds.getArgument().accept(this);
|
||||
_builder.append(")");
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit (CreateIndexClause createIndexClause)
|
||||
public Void visit (CreateIndexClause createIndexClause)
|
||||
{
|
||||
for (Tuple<SQLExpression, Order> field : createIndexClause.getFields()) {
|
||||
if (!(field.left instanceof ColumnExp)) {
|
||||
log.warning("This database can't handle complex indexes. Aborting creation.",
|
||||
"ixName", createIndexClause.getName());
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
super.visit(createIndexClause);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit (DropIndexClause<? extends PersistentRecord> dropIndexClause)
|
||||
public Void visit (DropIndexClause<? extends PersistentRecord> dropIndexClause)
|
||||
{
|
||||
// MySQL's indexes are scoped on the table, not on the database, and the
|
||||
// SQL syntax reflects it: DROP INDEX fooIx on fooTable
|
||||
@@ -118,6 +123,7 @@ public class MySQLBuilder
|
||||
appendIdentifier(dropIndexClause.getName());
|
||||
_builder.append(" on ");
|
||||
appendTableName(dropIndexClause.getPersistentClass());
|
||||
return null;
|
||||
}
|
||||
|
||||
protected MSBuildVisitor (DepotTypes types)
|
||||
|
||||
@@ -53,16 +53,17 @@ public class PostgreSQLBuilder
|
||||
|
||||
public class PGBuildVisitor extends BuildVisitor
|
||||
{
|
||||
@Override public void visit (FullText.Match match) {
|
||||
@Override public Void visit (FullText.Match match) {
|
||||
appendIdentifier("ftsCol_" + match.getDefinition().getName());
|
||||
_builder.append(" @@ to_tsquery('").
|
||||
append(translateFTConfig(getFTIndex(match.getDefinition()).configuration())).
|
||||
append("', ");
|
||||
bindValue(massageFTQuery(match.getDefinition()));
|
||||
_builder.append(")");
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override public void visit (FullText.Rank rank) {
|
||||
@Override public Void visit (FullText.Rank rank) {
|
||||
_builder.append(PG83 ? "ts_rank" : "rank").append("(");
|
||||
appendIdentifier("ftsCol_" + rank.getDefinition().getName());
|
||||
_builder.append(", to_tsquery('").
|
||||
@@ -73,12 +74,14 @@ public class PostgreSQLBuilder
|
||||
append("', ");
|
||||
bindValue(massageFTQuery(rank.getDefinition()));
|
||||
_builder.append("), 1)");
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override public void visit (EpochSeconds epochSeconds) {
|
||||
@Override public Void visit (EpochSeconds epochSeconds) {
|
||||
_builder.append("date_part('epoch', ");
|
||||
epochSeconds.getArgument().accept(this);
|
||||
_builder.append(")");
|
||||
return null;
|
||||
}
|
||||
|
||||
// TODO: enable when we can require 1.6 support
|
||||
@@ -120,13 +123,12 @@ public class PostgreSQLBuilder
|
||||
_builder.append("\"").append(field).append("\"");
|
||||
}
|
||||
|
||||
// TODO: enable when we can require 1.6 support
|
||||
protected PGBuildVisitor (DepotTypes types) {
|
||||
protected PGBuildVisitor (DepotTypes types)
|
||||
{
|
||||
super(types);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public PostgreSQLBuilder (DepotTypes types)
|
||||
{
|
||||
super(types);
|
||||
|
||||
@@ -78,9 +78,9 @@ public class CreateIndexClause
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public void accept (ExpressionVisitor builder)
|
||||
public Object accept (ExpressionVisitor<?> builder)
|
||||
{
|
||||
builder.visit(this);
|
||||
return builder.visit(this);
|
||||
}
|
||||
|
||||
protected Class<? extends PersistentRecord> _pClass;
|
||||
|
||||
@@ -57,9 +57,9 @@ public class DeleteClause
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public void accept (ExpressionVisitor builder)
|
||||
public Object accept (ExpressionVisitor<?> builder)
|
||||
{
|
||||
builder.visit(this);
|
||||
return builder.visit(this);
|
||||
}
|
||||
|
||||
/** The type of persistent record on which we operate. */
|
||||
|
||||
@@ -56,9 +56,9 @@ public class DropIndexClause<T extends PersistentRecord>
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public void accept (ExpressionVisitor builder)
|
||||
public Object accept (ExpressionVisitor<?> builder)
|
||||
{
|
||||
builder.visit(this);
|
||||
return builder.visit(this);
|
||||
}
|
||||
|
||||
protected Class<? extends PersistentRecord> _pClass;
|
||||
|
||||
@@ -95,9 +95,9 @@ public class UpdateClause<T extends PersistentRecord>
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public void accept (ExpressionVisitor builder)
|
||||
public Object accept (ExpressionVisitor<?> builder)
|
||||
{
|
||||
builder.visit(this);
|
||||
return builder.visit(this);
|
||||
}
|
||||
|
||||
/** The class we're updating. */
|
||||
|
||||
@@ -23,15 +23,16 @@ package com.samskivert.depot.operator;
|
||||
import com.samskivert.depot.expression.SQLExpression;
|
||||
import com.samskivert.depot.expression.ValueExp;
|
||||
import com.samskivert.depot.operator.SQLOperator.MultiOperator;
|
||||
import com.samskivert.util.StringUtil;
|
||||
|
||||
/**
|
||||
* A convenient container for implementations of arithmetic operators. Classes that value brevity
|
||||
* that feel otherwise will use Arithmetic.Add() and Arithmetic.Sub().
|
||||
*/
|
||||
public abstract class Arithmetic
|
||||
public abstract class Arithmetic extends MultiOperator
|
||||
{
|
||||
/** The SQL '+' operator. */
|
||||
public static class Add extends MultiOperator
|
||||
public static class Add extends Arithmetic
|
||||
{
|
||||
public Add (SQLExpression column, Comparable<?> value)
|
||||
{
|
||||
@@ -47,10 +48,22 @@ public abstract class Arithmetic
|
||||
{
|
||||
return "+";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object evaluate (Object[] operands)
|
||||
{
|
||||
return evaluate(operands, "+", new Accumulator<Double>() {
|
||||
@Override public Double accumulate (Double left, Double right) {
|
||||
return left + right;
|
||||
}}, new Accumulator<Long>() {
|
||||
@Override public Long accumulate (Long left, Long right) {
|
||||
return left + right;
|
||||
}});
|
||||
}
|
||||
}
|
||||
|
||||
/** The SQL '-' operator. */
|
||||
public static class Sub extends MultiOperator
|
||||
public static class Sub extends Arithmetic
|
||||
{
|
||||
public Sub (SQLExpression column, Comparable<?> value)
|
||||
{
|
||||
@@ -66,10 +79,22 @@ public abstract class Arithmetic
|
||||
{
|
||||
return "-";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object evaluate (Object[] operands)
|
||||
{
|
||||
return evaluate(operands, "-", new Accumulator<Double>() {
|
||||
@Override public Double accumulate (Double left, Double right) {
|
||||
return left - right;
|
||||
}}, new Accumulator<Long>() {
|
||||
@Override public Long accumulate (Long left, Long right) {
|
||||
return left - right;
|
||||
}});
|
||||
}
|
||||
}
|
||||
|
||||
/** The SQL '*' operator. */
|
||||
public static class Mul extends MultiOperator
|
||||
public static class Mul extends Arithmetic
|
||||
{
|
||||
public Mul (SQLExpression column, Comparable<?> value)
|
||||
{
|
||||
@@ -85,10 +110,22 @@ public abstract class Arithmetic
|
||||
{
|
||||
return "*";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object evaluate (Object[] operands)
|
||||
{
|
||||
return evaluate(operands, "*", new Accumulator<Double>() {
|
||||
@Override public Double accumulate (Double left, Double right) {
|
||||
return left * right;
|
||||
}}, new Accumulator<Long>() {
|
||||
@Override public Long accumulate (Long left, Long right) {
|
||||
return left * right;
|
||||
}});
|
||||
}
|
||||
}
|
||||
|
||||
/** The SQL '/' operator. */
|
||||
public static class Div extends MultiOperator
|
||||
public static class Div extends Arithmetic
|
||||
{
|
||||
public Div (SQLExpression column, Comparable<?> value)
|
||||
{
|
||||
@@ -104,10 +141,27 @@ public abstract class Arithmetic
|
||||
{
|
||||
return " / "; // Pad with spaces to work-around a MySQL bug.
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object evaluate (Object[] operands)
|
||||
{
|
||||
for (int i = 1; i < operands.length; i ++) {
|
||||
if (NUMERICAL.apply(operands[i]) == Double.valueOf(0)) {
|
||||
return new NoValue("Division by zero in: " + StringUtil.toString(operands));
|
||||
}
|
||||
}
|
||||
return evaluate(operands, "/", new Accumulator<Double>() {
|
||||
@Override public Double accumulate (Double left, Double right) {
|
||||
return left / right;
|
||||
}}, new Accumulator<Long>() {
|
||||
@Override public Long accumulate (Long left, Long right) {
|
||||
return left / right;
|
||||
}});
|
||||
}
|
||||
}
|
||||
|
||||
/** The SQL '&' operator. */
|
||||
public static class BitAnd extends MultiOperator
|
||||
public static class BitAnd extends Arithmetic
|
||||
{
|
||||
public BitAnd (SQLExpression column, Comparable<?> value)
|
||||
{
|
||||
@@ -123,10 +177,19 @@ public abstract class Arithmetic
|
||||
{
|
||||
return "&";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object evaluate (Object[] operands)
|
||||
{
|
||||
return evaluate(operands, "&", null, new Accumulator<Long>() {
|
||||
@Override public Long accumulate (Long left, Long right) {
|
||||
return left & right;
|
||||
}});
|
||||
}
|
||||
}
|
||||
|
||||
/** The SQL '|' operator. */
|
||||
public static class BitOr extends MultiOperator
|
||||
public static class BitOr extends Arithmetic
|
||||
{
|
||||
public BitOr (SQLExpression column, Comparable<?> value)
|
||||
{
|
||||
@@ -142,5 +205,37 @@ public abstract class Arithmetic
|
||||
{
|
||||
return "|";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object evaluate (Object[] operands)
|
||||
{
|
||||
return evaluate(operands, "|", null, new Accumulator<Long>() {
|
||||
@Override public Long accumulate (Long left, Long right) {
|
||||
return left | right;
|
||||
}});
|
||||
}
|
||||
}
|
||||
|
||||
public Arithmetic (SQLExpression column, Comparable<?> value)
|
||||
{
|
||||
super(column, new ValueExp(value));
|
||||
}
|
||||
|
||||
public Arithmetic (SQLExpression... values)
|
||||
{
|
||||
super(values);
|
||||
}
|
||||
|
||||
protected Object evaluate (
|
||||
Object[] ops, String name, Accumulator<Double> dAcc, Accumulator<Long> iAcc)
|
||||
{
|
||||
if (dAcc != null && all(NUMERICAL, ops)) {
|
||||
return accumulate(NUMERICAL, ops, 0.0, dAcc);
|
||||
}
|
||||
|
||||
if (iAcc != null && all(INTEGRAL, ops)) {
|
||||
return accumulate(INTEGRAL, ops, 0L, iAcc);
|
||||
}
|
||||
return new NoValue("Non-numeric operand for '" + name + "' (" + ops + ")");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,9 +54,9 @@ public abstract class Conditionals
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public void accept (ExpressionVisitor builder)
|
||||
public Object accept (ExpressionVisitor<?> builder)
|
||||
{
|
||||
builder.visit(this);
|
||||
return builder.visit(this);
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
@@ -90,6 +90,15 @@ public abstract class Conditionals
|
||||
{
|
||||
return "=";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object evaluate (Object left, Object right)
|
||||
{
|
||||
if (left == null || right == null) {
|
||||
return new NoValue("Null operand to '=': (" + left + ", " + right + ")");
|
||||
}
|
||||
return left.equals(right);
|
||||
}
|
||||
}
|
||||
|
||||
/** The SQL '!=' operator. */
|
||||
@@ -109,6 +118,15 @@ public abstract class Conditionals
|
||||
{
|
||||
return "!=";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object evaluate (Object left, Object right)
|
||||
{
|
||||
if (left == null || right == null) {
|
||||
return new NoValue("Null operand to '!=': (" + left + ", " + right + ")");
|
||||
}
|
||||
return !left.equals(right);
|
||||
}
|
||||
}
|
||||
|
||||
/** The SQL '<' operator. */
|
||||
@@ -128,6 +146,18 @@ public abstract class Conditionals
|
||||
{
|
||||
return "<";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object evaluate (Object left, Object right)
|
||||
{
|
||||
if (all(NUMERICAL, left, right)) {
|
||||
return NUMERICAL.apply(left) < NUMERICAL.apply(right);
|
||||
}
|
||||
if (all(STRING, left, right) || all(DATE, left, right)) {
|
||||
return compare(STRING, left, right) < 0;
|
||||
}
|
||||
return new NoValue("Non-comparable operand to '<': (" + left + ", " + right + ")");
|
||||
}
|
||||
}
|
||||
|
||||
/** The SQL '<=' operator. */
|
||||
@@ -147,7 +177,19 @@ public abstract class Conditionals
|
||||
{
|
||||
return "<=";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object evaluate (Object left, Object right)
|
||||
{
|
||||
if (all(NUMERICAL, left, right)) {
|
||||
return NUMERICAL.apply(left) <= NUMERICAL.apply(right);
|
||||
}
|
||||
if (all(STRING, left, right) || all(DATE, left, right)) {
|
||||
return compare(STRING, left, right) <= 0;
|
||||
}
|
||||
return new NoValue("Non-comparable operand to '<=': (" + left + ", " + right + ")");
|
||||
}
|
||||
}
|
||||
|
||||
/** The SQL '>' operator. */
|
||||
public static class GreaterThan extends SQLOperator.BinaryOperator
|
||||
@@ -166,6 +208,18 @@ public abstract class Conditionals
|
||||
{
|
||||
return ">";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object evaluate (Object left, Object right)
|
||||
{
|
||||
if (all(NUMERICAL, left, right)) {
|
||||
return NUMERICAL.apply(left) > NUMERICAL.apply(right);
|
||||
}
|
||||
if (all(STRING, left, right) || all(DATE, left, right)) {
|
||||
return compare(STRING, left, right) > 0;
|
||||
}
|
||||
return new NoValue("Non-comparable operand to '>': (" + left + ", " + right + ")");
|
||||
}
|
||||
}
|
||||
|
||||
/** The SQL '>=' operator. */
|
||||
@@ -185,6 +239,18 @@ public abstract class Conditionals
|
||||
{
|
||||
return ">=";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object evaluate (Object left, Object right)
|
||||
{
|
||||
if (all(NUMERICAL, left, right)) {
|
||||
return NUMERICAL.apply(left) >= NUMERICAL.apply(right);
|
||||
}
|
||||
if (all(STRING, left, right) || all(DATE, left, right)) {
|
||||
return compare(STRING, left, right) >= 0;
|
||||
}
|
||||
return new NoValue("Non-comparable operand to '>=': (" + left + ", " + right + ")");
|
||||
}
|
||||
}
|
||||
|
||||
/** The SQL 'in (...)' operator. */
|
||||
@@ -219,9 +285,9 @@ public abstract class Conditionals
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public void accept (ExpressionVisitor builder)
|
||||
public Object accept (ExpressionVisitor<?> builder)
|
||||
{
|
||||
builder.visit(this);
|
||||
return builder.visit(this);
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
@@ -265,6 +331,12 @@ public abstract class Conditionals
|
||||
{
|
||||
return " like ";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object evaluate (Object left, Object right)
|
||||
{
|
||||
return new NoValue("Like operator not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
/** The SQL ' exists' operator. */
|
||||
@@ -275,13 +347,11 @@ public abstract class Conditionals
|
||||
_clause = clause;
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public void accept (ExpressionVisitor builder)
|
||||
public Object accept (ExpressionVisitor<?> builder)
|
||||
{
|
||||
builder.visit(this);
|
||||
return builder.visit(this);
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public void addClasses (Collection<Class<? extends PersistentRecord>> classSet)
|
||||
{
|
||||
_clause.addClasses(classSet);
|
||||
@@ -314,9 +384,9 @@ public abstract class Conditionals
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public void accept (ExpressionVisitor builder)
|
||||
public Object accept (ExpressionVisitor<?> builder)
|
||||
{
|
||||
builder.visit(this);
|
||||
return builder.visit(this);
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
@@ -370,9 +440,9 @@ public abstract class Conditionals
|
||||
implements SQLOperator
|
||||
{
|
||||
// from SQLExpression
|
||||
public void accept (ExpressionVisitor builder)
|
||||
public Object accept (ExpressionVisitor<?> builder)
|
||||
{
|
||||
builder.visit(this);
|
||||
return builder.visit(this);
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
@@ -396,9 +466,9 @@ public abstract class Conditionals
|
||||
implements SQLOperator
|
||||
{
|
||||
// from SQLExpression
|
||||
public void accept (ExpressionVisitor builder)
|
||||
public Object accept (ExpressionVisitor<?> builder)
|
||||
{
|
||||
builder.visit(this);
|
||||
return builder.visit(this);
|
||||
}
|
||||
|
||||
public FullText getDefinition ()
|
||||
|
||||
@@ -51,6 +51,23 @@ public abstract class Logic
|
||||
{
|
||||
return " or ";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object evaluate (Object[] values)
|
||||
{
|
||||
boolean anyTrue = false;
|
||||
for (Object value : values) {
|
||||
if (value instanceof NoValue) {
|
||||
return value;
|
||||
}
|
||||
if (Boolean.TRUE.equals(value)) {
|
||||
anyTrue = true;
|
||||
} else if (!Boolean.FALSE.equals(value)) {
|
||||
return new NoValue("Non-boolean operand to OR: " + value);
|
||||
}
|
||||
}
|
||||
return anyTrue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -72,6 +89,25 @@ public abstract class Logic
|
||||
{
|
||||
return " and ";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object evaluate (Object[] values)
|
||||
{
|
||||
// if all operands are true, return true, else if all operands are boolean, return
|
||||
// false, else return NO_VALUE
|
||||
boolean allTrue = true;
|
||||
for (Object value : values) {
|
||||
if (value instanceof NoValue) {
|
||||
return value;
|
||||
}
|
||||
if (Boolean.FALSE.equals(value)) {
|
||||
allTrue = false;
|
||||
} else if (!Boolean.TRUE.equals(value)) {
|
||||
return new NoValue("Non-boolean operand to AND: " + value);
|
||||
}
|
||||
}
|
||||
return allTrue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -91,9 +127,9 @@ public abstract class Logic
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public void accept (ExpressionVisitor builder)
|
||||
public Object accept (ExpressionVisitor<?> builder)
|
||||
{
|
||||
builder.visit(this);
|
||||
return builder.visit(this);
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
|
||||
@@ -20,8 +20,13 @@
|
||||
|
||||
package com.samskivert.depot.operator;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.samskivert.depot.PersistentRecord;
|
||||
import com.samskivert.depot.expression.SQLExpression;
|
||||
import com.samskivert.depot.expression.ValueExp;
|
||||
@@ -37,31 +42,30 @@ public interface SQLOperator extends SQLExpression
|
||||
/**
|
||||
* Represents an operator with any number of operands.
|
||||
*/
|
||||
public abstract static class MultiOperator
|
||||
implements SQLOperator
|
||||
public abstract static class MultiOperator extends BaseOperator
|
||||
{
|
||||
public MultiOperator (SQLExpression ... conditions)
|
||||
public MultiOperator (SQLExpression ... operands)
|
||||
{
|
||||
_conditions = conditions;
|
||||
_operands = operands;
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public void accept (ExpressionVisitor builder)
|
||||
public Object accept (ExpressionVisitor<?> builder)
|
||||
{
|
||||
builder.visit(this);
|
||||
return builder.visit(this);
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public void addClasses (Collection<Class<? extends PersistentRecord>> classSet)
|
||||
{
|
||||
for (int ii = 0; ii < _conditions.length; ii ++) {
|
||||
_conditions[ii].addClasses(classSet);
|
||||
for (int ii = 0; ii < _operands.length; ii ++) {
|
||||
_operands[ii].addClasses(classSet);
|
||||
}
|
||||
}
|
||||
|
||||
public SQLExpression[] getConditions ()
|
||||
public SQLExpression[] getOperands ()
|
||||
{
|
||||
return _conditions;
|
||||
return _operands;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -69,26 +73,31 @@ public interface SQLOperator extends SQLExpression
|
||||
*/
|
||||
public abstract String operator ();
|
||||
|
||||
/**
|
||||
* Calculates a value
|
||||
*/
|
||||
public abstract Object evaluate (Object[] values);
|
||||
|
||||
@Override // from Object
|
||||
public String toString ()
|
||||
{
|
||||
StringBuilder builder = new StringBuilder("(");
|
||||
for (SQLExpression condition : _conditions) {
|
||||
for (SQLExpression operand : _operands) {
|
||||
if (builder.length() > 1) {
|
||||
builder.append(operator());
|
||||
}
|
||||
builder.append(condition);
|
||||
builder.append(operand);
|
||||
}
|
||||
return builder.append(")").toString();
|
||||
}
|
||||
|
||||
protected SQLExpression[] _conditions;
|
||||
protected SQLExpression[] _operands;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the real work for simple binary operators such as Equals.
|
||||
*/
|
||||
public abstract static class BinaryOperator implements SQLOperator
|
||||
public abstract static class BinaryOperator extends BaseOperator
|
||||
{
|
||||
public BinaryOperator (SQLExpression lhs, SQLExpression rhs)
|
||||
{
|
||||
@@ -102,9 +111,9 @@ public interface SQLOperator extends SQLExpression
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public void accept (ExpressionVisitor builder)
|
||||
public Object accept (ExpressionVisitor<?> builder)
|
||||
{
|
||||
builder.visit(this);
|
||||
return builder.visit(this);
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
@@ -114,6 +123,8 @@ public interface SQLOperator extends SQLExpression
|
||||
_rhs.addClasses(classSet);
|
||||
}
|
||||
|
||||
public abstract Object evaluate (Object left, Object right);
|
||||
|
||||
/**
|
||||
* Returns the string representation of the operator.
|
||||
*/
|
||||
@@ -138,4 +149,54 @@ public interface SQLOperator extends SQLExpression
|
||||
protected SQLExpression _lhs;
|
||||
protected SQLExpression _rhs;
|
||||
}
|
||||
|
||||
public static abstract class BaseOperator implements SQLOperator
|
||||
{
|
||||
public static Function<Object, Long> INTEGRAL = new Function<Object, Long>() {
|
||||
@Override public Long apply (Object o) {
|
||||
if ((o instanceof Integer) || (o instanceof Long)) {
|
||||
return ((Number) o).longValue();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
public static Function<Object, Double> NUMERICAL = new Function<Object, Double>() {
|
||||
@Override public Double apply (Object o) {
|
||||
return (o instanceof Number) ? ((Number) o).doubleValue() : null;
|
||||
}
|
||||
};
|
||||
|
||||
public static Function<Object, String> STRING = new Function<Object, String>() {
|
||||
@Override public String apply (Object o) {
|
||||
return (o instanceof String) ? (String) o : null;
|
||||
}
|
||||
};
|
||||
|
||||
public static Function<Object, Date> DATE = new Function<Object, Date>() {
|
||||
@Override public Date apply (Object o) {
|
||||
return (o instanceof Date) ? (Date) o : null;
|
||||
}
|
||||
};
|
||||
|
||||
public static <S, T> boolean all (Function<S, T> fun, S... obj) {
|
||||
return Iterables.all(Arrays.asList(obj), Predicates.compose(Predicates.isNull(), fun));
|
||||
}
|
||||
|
||||
public static <S, T extends Comparable<T>> int compare (Function<S, T> fun, S lhs, S rhs) {
|
||||
return fun.apply(lhs).compareTo(fun.apply(rhs));
|
||||
}
|
||||
|
||||
public static <S, T> T accumulate (Function<S, T> fun, S[] ops, T v, Accumulator<T> acc) {
|
||||
for (S op : ops) {
|
||||
v = acc.accumulate(v, fun.apply(op));
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
protected static interface Accumulator<T>
|
||||
{
|
||||
T accumulate (T left, T right);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user