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:
@@ -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 ()
|
||||
|
||||
Reference in New Issue
Block a user