Added a bunch of tests for the various functions appearing in a projection.
This uncovered a lot of loose geese as far as the database was concerned, which necessitated turning a bunch of functions which had specific type into functions which have type Number. In general, I made the Funcs/StringFuncs/MathFuncs factory methods provide an expression typed Number and I left the underlying SQLExpression derivations able to be more precisely typed. So if you know that your database does not magically promote an integer column to long when calling sum() on it, you can force a more specific type. But really, I don't see why you would go to the trouble. You can just call intValue() on your result and get the int you were looking for regardless of what the database thought it would be fun to provide. I also fixed a few HSQLDB variants (average -> avg, round(a) -> round(a, 0), etc.) and made notes about a few things that just plain don't work in HSQLDB. Awesome! Fortunately they're things like log-base-10, rather than more critical functionality.
This commit is contained in:
@@ -32,21 +32,25 @@ import com.samskivert.depot.impl.expression.StringFun.*;
|
|||||||
public class Funcs
|
public class Funcs
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Creates an aggregate expression that averages all values from the supplied expression.
|
* Creates an aggregate expression that averages all values from the supplied expression. Note
|
||||||
* This would usually be used in a FieldOverride and supplied with a ColumnExp.
|
* that this method forces the result to type {@link Number} because databases may perform
|
||||||
|
* widening under the hood, and using Number allows the application to do the appropriate
|
||||||
|
* conversion at runtime.
|
||||||
*/
|
*/
|
||||||
public static <T extends Number> FluentExp<T> average (SQLExpression<T> expr)
|
public static FluentExp<Number> average (SQLExpression<? extends Number> expr)
|
||||||
{
|
{
|
||||||
return new Average<T>(expr);
|
return new Average<Number>(expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an expression that averages all distinct values from the supplied expression.
|
* Creates an expression that averages all distinct values from the supplied expression. Note
|
||||||
* This would usually be used in a FieldOverride and supplied with a ColumnExp.
|
* that this method forces the result to type {@link Number} because databases may perform
|
||||||
|
* widening under the hood, and using Number allows the application to do the appropriate
|
||||||
|
* conversion at runtime.
|
||||||
*/
|
*/
|
||||||
public static <T extends Number> FluentExp<T> averageDistinct (SQLExpression<T> expr)
|
public static FluentExp<Number> averageDistinct (SQLExpression<? extends Number> expr)
|
||||||
{
|
{
|
||||||
return new Average<T>(expr, true);
|
return new Average<Number>(expr, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -99,12 +103,14 @@ public class Funcs
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an aggregate expression that sums all the values from the supplied expression.
|
* Creates an aggregate expression that sums all the values from the supplied expression. Note
|
||||||
* This would usually be used in a FieldOverride and supplied with a ColumnExp.
|
* that this method forces the result to type {@link Number} because databases may perform
|
||||||
|
* widening under the hood, and using Number allows the application to do the appropriate
|
||||||
|
* conversion at runtime.
|
||||||
*/
|
*/
|
||||||
public static <T extends Number> FluentExp<T> sum (SQLExpression<T> expr)
|
public static FluentExp<Number> sum (SQLExpression<? extends Number> expr)
|
||||||
{
|
{
|
||||||
return new Sum<T>(expr);
|
return new Sum<Number>(expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -161,7 +167,7 @@ public class Funcs
|
|||||||
/**
|
/**
|
||||||
* Creates an expression that evaluates to the length of the supplied array column.
|
* Creates an expression that evaluates to the length of the supplied array column.
|
||||||
*/
|
*/
|
||||||
public static FluentExp<Integer> arrayLength (SQLExpression<?> exp)
|
public static FluentExp<Number> arrayLength (SQLExpression<?> exp)
|
||||||
{
|
{
|
||||||
return new Length(exp);
|
return new Length(exp);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,47 +38,63 @@ public class MathFuncs
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an expression that computes the integer ceiling of the supplied expression.
|
* Creates an expression that computes the integer ceiling of the supplied expression. Note
|
||||||
|
* that this method forces the result to type {@link Number} because databases may perform
|
||||||
|
* widening or conversion under the hood, and using Number allows the application to do the
|
||||||
|
* appropriate conversion at runtime.
|
||||||
*/
|
*/
|
||||||
public static <T extends Number> FluentExp<T> ceil (SQLExpression<T> exp)
|
public static FluentExp<Number> ceil (SQLExpression<? extends Number> exp)
|
||||||
{
|
{
|
||||||
return new Ceil<T>(exp);
|
return new Ceil<Number>(exp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an expression that computes the exponential of the supplied expression.
|
* Creates an expression that computes the integer floor of the supplied expression. Note that
|
||||||
|
* this method forces the result to type {@link Number} because databases may perform widening
|
||||||
|
* or conversion under the hood, and using Number allows the application to do the appropriate
|
||||||
|
* conversion at runtime.
|
||||||
*/
|
*/
|
||||||
public static <T extends Number> FluentExp<T> exp (SQLExpression<T> exp)
|
public static FluentExp<Number> floor (SQLExpression<? extends Number> exp)
|
||||||
{
|
{
|
||||||
return new Exp<T>(exp);
|
return new Floor<Number>(exp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an expression that computes the integer floor of the supplied expression.
|
* Creates an expression that computes the exponential of the supplied expression. Note that
|
||||||
|
* this method forces the result to type {@link Number} because databases may perform widening
|
||||||
|
* or conversion under the hood, and using Number allows the application to do the appropriate
|
||||||
|
* conversion at runtime.
|
||||||
*/
|
*/
|
||||||
public static <T extends Number> FluentExp<T> floor (SQLExpression<T> exp)
|
public static FluentExp<Number> exp (SQLExpression<? extends Number> exp)
|
||||||
{
|
{
|
||||||
return new Floor<T>(exp);
|
return new Exp<Number>(exp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an expression that computes the natural logarithm of the supplied expression.
|
* Creates an expression that computes the natural logarithm of the supplied expression. Note
|
||||||
|
* that this method forces the result to type {@link Number} because databases may perform
|
||||||
|
* widening or conversion under the hood, and using Number allows the application to do the
|
||||||
|
* appropriate conversion at runtime.
|
||||||
*/
|
*/
|
||||||
public static <T extends Number> FluentExp<T> ln (SQLExpression<T> exp)
|
public static FluentExp<Number> ln (SQLExpression<? extends Number> exp)
|
||||||
{
|
{
|
||||||
return new Ln<T>(exp);
|
return new Ln<Number>(exp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an expression that computes the base-10 logarithm of the supplied expression.
|
* Creates an expression that computes the base-10 logarithm of the supplied expression. Note
|
||||||
|
* that this method forces the result to type {@link Number} because databases may perform
|
||||||
|
* widening or conversion under the hood, and using Number allows the application to do the
|
||||||
|
* appropriate conversion at runtime.
|
||||||
*/
|
*/
|
||||||
public static <T extends Number> FluentExp<T> log10 (SQLExpression<T> value)
|
public static FluentExp<Number> log10 (SQLExpression<? extends Number> value)
|
||||||
{
|
{
|
||||||
return new Log10<T>(value);
|
return new Log10<Number>(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an expression that evaluates to the constant PI.
|
* Creates an expression that evaluates to the constant PI. You will need to manually specify
|
||||||
|
* the type your database returns for PI if you plan on actually selecting this value.
|
||||||
*/
|
*/
|
||||||
public static <T extends Number> FluentExp<T> pi ()
|
public static <T extends Number> FluentExp<T> pi ()
|
||||||
{
|
{
|
||||||
@@ -86,16 +102,21 @@ public class MathFuncs
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an expression that computes the value expression to the given power.
|
* Creates an expression that computes the value expression to the given power. Note that this
|
||||||
|
* method forces the result to type {@link Number} because databases may perform widening or
|
||||||
|
* conversion under the hood, and using Number allows the application to do the appropriate
|
||||||
|
* conversion at runtime.
|
||||||
*/
|
*/
|
||||||
public static <R extends Number, P extends Number> FluentExp<R> power (SQLExpression<R> value,
|
public static FluentExp<Number> power (SQLExpression<? extends Number> value,
|
||||||
SQLExpression<P> power)
|
SQLExpression<? extends Number> power)
|
||||||
{
|
{
|
||||||
return new Power<R, P>(value, power);
|
return new Power<Number>(value, power);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an expression that returns a random number between 0.0 and 1.0.
|
* Creates an expression that returns a random number between 0.0 and 1.0. You will need to
|
||||||
|
* manually specify the type your database returns for random values if you plan on actually
|
||||||
|
* selecting this value.
|
||||||
*/
|
*/
|
||||||
public static <T extends Number> FluentExp<T> random ()
|
public static <T extends Number> FluentExp<T> random ()
|
||||||
{
|
{
|
||||||
@@ -103,35 +124,46 @@ public class MathFuncs
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an expression that computes the whole number nearest the supplied expression.
|
* Creates an expression that computes the whole number nearest the supplied expression. Note
|
||||||
|
* that this method forces the result to type {@link Number} because databases may perform
|
||||||
|
* widening or conversion under the hood, and using Number allows the application to do the
|
||||||
|
* appropriate conversion at runtime.
|
||||||
*/
|
*/
|
||||||
public static <T extends Number> FluentExp<T> round (SQLExpression<T> exp)
|
public static FluentExp<Number> round (SQLExpression<? extends Number> exp)
|
||||||
{
|
{
|
||||||
return new Round<T>(exp);
|
return new Round<Number>(exp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an expression that computes the sign of the supplied expression.
|
* Creates an expression that computes the sign of the supplied expression. Note that this
|
||||||
|
* method forces the result to type {@link Number} because databases may perform widening or
|
||||||
|
* conversion under the hood, and using Number allows the application to do the appropriate
|
||||||
|
* conversion at runtime.
|
||||||
*/
|
*/
|
||||||
public static <T extends Number> FluentExp<T> sign (SQLExpression<T> exp)
|
public static FluentExp<Number> sign (SQLExpression<? extends Number> exp)
|
||||||
{
|
{
|
||||||
return new Sign<T>(exp);
|
return new Sign<Number>(exp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an expression that computes the square root of the supplied expression.
|
* Creates an expression that computes the square root of the supplied expression. Note that
|
||||||
|
* this method forces the result to type {@link Number} because databases may perform widening
|
||||||
|
* or conversion under the hood, and using Number allows the application to do the appropriate
|
||||||
|
* conversion at runtime.
|
||||||
*/
|
*/
|
||||||
public static <T extends Number> FluentExp<T> sqrt (SQLExpression<T> exp)
|
public static FluentExp<Number> sqrt (SQLExpression<? extends Number> exp)
|
||||||
{
|
{
|
||||||
return new Sqrt<T>(exp);
|
return new Sqrt<Number>(exp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an expression that computes the truncation of the supplied expression,
|
* Creates an expression that computes the truncation of the supplied expression, i.e. the next
|
||||||
* i.e. the next closest whole number to zero.
|
* closest whole number to zero. Note that this method forces the result to type {@link Number}
|
||||||
|
* because databases may perform widening or conversion under the hood, and using Number allows
|
||||||
|
* the application to do the appropriate conversion at runtime.
|
||||||
*/
|
*/
|
||||||
public static <T extends Number> FluentExp<T> trunc (SQLExpression<T> exp)
|
public static FluentExp<Number> trunc (SQLExpression<? extends Number> exp)
|
||||||
{
|
{
|
||||||
return new Trunc<T>(exp);
|
return new Trunc<Number>(exp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ public class StringFuncs
|
|||||||
/**
|
/**
|
||||||
* Creates an expression that evaluates to the string length of the supplied expression.
|
* Creates an expression that evaluates to the string length of the supplied expression.
|
||||||
*/
|
*/
|
||||||
public static FluentExp<Integer> length (SQLExpression<String> exp)
|
public static FluentExp<Number> length (SQLExpression<String> exp)
|
||||||
{
|
{
|
||||||
return new Length(exp);
|
return new Length(exp);
|
||||||
}
|
}
|
||||||
@@ -49,8 +49,8 @@ public class StringFuncs
|
|||||||
* Creates an expression that locates the given substring expression within the given
|
* Creates an expression that locates the given substring expression within the given
|
||||||
* string expression and returns the index.
|
* string expression and returns the index.
|
||||||
*/
|
*/
|
||||||
public static FluentExp<Integer> position (SQLExpression<String> substring,
|
public static FluentExp<Number> position (SQLExpression<String> substring,
|
||||||
SQLExpression<String> string)
|
SQLExpression<String> string)
|
||||||
{
|
{
|
||||||
return new Position(substring, string);
|
return new Position(substring, string);
|
||||||
}
|
}
|
||||||
@@ -59,8 +59,18 @@ public class StringFuncs
|
|||||||
* Creates an expression that evaluates to a substring of the given string expression,
|
* Creates an expression that evaluates to a substring of the given string expression,
|
||||||
* starting at the given index and of the given length.
|
* starting at the given index and of the given length.
|
||||||
*/
|
*/
|
||||||
public static FluentExp<String> substring (
|
public static FluentExp<String> substring (SQLExpression<String> string, int from, int count)
|
||||||
SQLExpression<String> string, SQLExpression<String> from, SQLExpression<Integer> count)
|
{
|
||||||
|
return new Substring(string, Exps.value(from), Exps.value(count));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an expression that evaluates to a substring of the given string expression,
|
||||||
|
* starting at the given index and of the given length.
|
||||||
|
*/
|
||||||
|
public static FluentExp<String> substring (SQLExpression<String> string,
|
||||||
|
SQLExpression<Integer> from,
|
||||||
|
SQLExpression<Integer> count)
|
||||||
{
|
{
|
||||||
return new Substring(string, from, count);
|
return new Substring(string, from, count);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -594,7 +594,7 @@ public abstract class BuildVisitor implements FragmentVisitor<Void>
|
|||||||
return appendFunctionCall("PI");
|
return appendFunctionCall("PI");
|
||||||
}
|
}
|
||||||
|
|
||||||
public Void visit (Power<?,?> exp)
|
public Void visit (Power<?> exp)
|
||||||
{
|
{
|
||||||
return appendFunctionCall("power", exp.getValue(), exp.getPower());
|
return appendFunctionCall("power", exp.getValue(), exp.getPower());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -371,7 +371,7 @@ public class ExpressionEvaluator
|
|||||||
throw new IllegalArgumentException("Can't evaluate expression: " + exp);
|
throw new IllegalArgumentException("Can't evaluate expression: " + exp);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Void visit (Power<?,?> exp)
|
public Void visit (Power<?> exp)
|
||||||
{
|
{
|
||||||
throw new IllegalArgumentException("Can't evaluate expression: " + exp);
|
throw new IllegalArgumentException("Can't evaluate expression: " + exp);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ public interface FragmentVisitor<T>
|
|||||||
public T visit (Ln<?> exp);
|
public T visit (Ln<?> exp);
|
||||||
public T visit (Log10<?> exp);
|
public T visit (Log10<?> exp);
|
||||||
public T visit (Pi<?> exp);
|
public T visit (Pi<?> exp);
|
||||||
public T visit (Power<?,?> exp);
|
public T visit (Power<?> exp);
|
||||||
public T visit (Random<?> exp);
|
public T visit (Random<?> exp);
|
||||||
public T visit (Round<?> exp);
|
public T visit (Round<?> exp);
|
||||||
public T visit (Sign<?> exp);
|
public T visit (Sign<?> exp);
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ import com.google.common.collect.Lists;
|
|||||||
|
|
||||||
import com.samskivert.jdbc.ColumnDefinition;
|
import com.samskivert.jdbc.ColumnDefinition;
|
||||||
import com.samskivert.util.ArrayUtil;
|
import com.samskivert.util.ArrayUtil;
|
||||||
|
|
||||||
|
import com.samskivert.depot.Exps;
|
||||||
import com.samskivert.depot.Ops;
|
import com.samskivert.depot.Ops;
|
||||||
import com.samskivert.depot.PersistentRecord;
|
import com.samskivert.depot.PersistentRecord;
|
||||||
import com.samskivert.depot.annotation.FullTextIndex;
|
import com.samskivert.depot.annotation.FullTextIndex;
|
||||||
@@ -37,10 +39,14 @@ import com.samskivert.depot.annotation.GeneratedValue;
|
|||||||
import com.samskivert.depot.expression.*;
|
import com.samskivert.depot.expression.*;
|
||||||
import com.samskivert.depot.operator.FullText;
|
import com.samskivert.depot.operator.FullText;
|
||||||
|
|
||||||
|
import com.samskivert.depot.impl.expression.AggregateFun;
|
||||||
import com.samskivert.depot.impl.expression.DateFun.DatePart.Part;
|
import com.samskivert.depot.impl.expression.DateFun.DatePart.Part;
|
||||||
import com.samskivert.depot.impl.expression.DateFun.DatePart;
|
import com.samskivert.depot.impl.expression.DateFun.DatePart;
|
||||||
import com.samskivert.depot.impl.expression.DateFun.DateTruncate;
|
import com.samskivert.depot.impl.expression.DateFun.DateTruncate;
|
||||||
|
import com.samskivert.depot.impl.expression.LiteralExp;
|
||||||
|
import com.samskivert.depot.impl.expression.NumericalFun;
|
||||||
import com.samskivert.depot.impl.expression.StringFun.Lower;
|
import com.samskivert.depot.impl.expression.StringFun.Lower;
|
||||||
|
import com.samskivert.depot.impl.expression.ValueExp;
|
||||||
import com.samskivert.depot.impl.operator.BitAnd;
|
import com.samskivert.depot.impl.operator.BitAnd;
|
||||||
import com.samskivert.depot.impl.operator.BitOr;
|
import com.samskivert.depot.impl.operator.BitOr;
|
||||||
import com.samskivert.depot.impl.operator.Like;
|
import com.samskivert.depot.impl.operator.Like;
|
||||||
@@ -51,6 +57,41 @@ public class HSQLBuilder
|
|||||||
{
|
{
|
||||||
public class HBuildVisitor extends BuildVisitor
|
public class HBuildVisitor extends BuildVisitor
|
||||||
{
|
{
|
||||||
|
@Override public Void visit (AggregateFun.Average<?> exp)
|
||||||
|
{
|
||||||
|
return appendAggregateFunctionCall("avg", exp);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public Void visit (NumericalFun.Round<?> exp)
|
||||||
|
{
|
||||||
|
// HSQLDB requires a number of digits after the decimal place argument, so we supply
|
||||||
|
// zero to emulate round on other databases
|
||||||
|
return appendFunctionCall("round", exp.getArg(), Exps.value(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public Void visit (NumericalFun.Trunc<?> exp)
|
||||||
|
{
|
||||||
|
// TODO: this would work if HSQLDB truncate actually worked, but it doesn't; we'll
|
||||||
|
// leave it in here in case some future bug fixed version of HSQLDB does work
|
||||||
|
return appendFunctionCall("truncate", exp.getArg(), Exps.value(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public Void visit (NumericalFun.Random<?> exp)
|
||||||
|
{
|
||||||
|
return appendFunctionCall("rand");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public Void visit (NumericalFun.Power<?> exp)
|
||||||
|
{
|
||||||
|
// HSQLDB can't handle a value argument to power(a, b), so we turn the ValueExp into a
|
||||||
|
// LiteralExp
|
||||||
|
SQLExpression<?> power = exp.getPower();
|
||||||
|
if (power instanceof ValueExp<?>) {
|
||||||
|
power = new LiteralExp<String>(((ValueExp<?>)power).getValue().toString());
|
||||||
|
}
|
||||||
|
return appendFunctionCall("power", exp.getValue(), power);
|
||||||
|
}
|
||||||
|
|
||||||
@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
|
// HSQL doesn't have real full text search, so we fake it by creating a condition like
|
||||||
|
|||||||
@@ -27,10 +27,10 @@ import com.samskivert.depot.impl.expression.Function.OneArgFun;
|
|||||||
public abstract class AggregateFun<T> extends OneArgFun<T>
|
public abstract class AggregateFun<T> extends OneArgFun<T>
|
||||||
{
|
{
|
||||||
public static class Average<T extends Number> extends AggregateFun<T> {
|
public static class Average<T extends Number> extends AggregateFun<T> {
|
||||||
public Average (SQLExpression<T> argument) {
|
public Average (SQLExpression<? extends T> argument) {
|
||||||
this(argument, false);
|
this(argument, false);
|
||||||
}
|
}
|
||||||
public Average (SQLExpression<T> argument, boolean distinct) {
|
public Average (SQLExpression<? extends T> argument, boolean distinct) {
|
||||||
super(argument, distinct);
|
super(argument, distinct);
|
||||||
}
|
}
|
||||||
public Object accept (FragmentVisitor<?> visitor) {
|
public Object accept (FragmentVisitor<?> visitor) {
|
||||||
@@ -72,10 +72,10 @@ public abstract class AggregateFun<T> extends OneArgFun<T>
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class Max<T extends Number> extends AggregateFun<T> {
|
public static class Max<T extends Number> extends AggregateFun<T> {
|
||||||
public Max (SQLExpression<T> argument) {
|
public Max (SQLExpression<? extends T> argument) {
|
||||||
this(argument, false);
|
this(argument, false);
|
||||||
}
|
}
|
||||||
public Max (SQLExpression<T> argument, boolean distinct) {
|
public Max (SQLExpression<? extends T> argument, boolean distinct) {
|
||||||
super(argument, distinct);
|
super(argument, distinct);
|
||||||
}
|
}
|
||||||
public Object accept (FragmentVisitor<?> visitor) {
|
public Object accept (FragmentVisitor<?> visitor) {
|
||||||
@@ -87,10 +87,10 @@ public abstract class AggregateFun<T> extends OneArgFun<T>
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class Min<T extends Number> extends AggregateFun<T> {
|
public static class Min<T extends Number> extends AggregateFun<T> {
|
||||||
public Min (SQLExpression<T> argument) {
|
public Min (SQLExpression<? extends T> argument) {
|
||||||
this(argument, false);
|
this(argument, false);
|
||||||
}
|
}
|
||||||
public Min (SQLExpression<T> argument, boolean distinct) {
|
public Min (SQLExpression<? extends T> argument, boolean distinct) {
|
||||||
super(argument, distinct);
|
super(argument, distinct);
|
||||||
}
|
}
|
||||||
public Object accept (FragmentVisitor<?> visitor) {
|
public Object accept (FragmentVisitor<?> visitor) {
|
||||||
@@ -102,10 +102,10 @@ public abstract class AggregateFun<T> extends OneArgFun<T>
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class Sum<T extends Number> extends AggregateFun<T> {
|
public static class Sum<T extends Number> extends AggregateFun<T> {
|
||||||
public Sum (SQLExpression<T> argument) {
|
public Sum (SQLExpression<? extends T> argument) {
|
||||||
this(argument, false);
|
this(argument, false);
|
||||||
}
|
}
|
||||||
public Sum (SQLExpression<T> argument, boolean distinct) {
|
public Sum (SQLExpression<? extends T> argument, boolean distinct) {
|
||||||
super(argument, distinct);
|
super(argument, distinct);
|
||||||
}
|
}
|
||||||
public Object accept (FragmentVisitor<?> visitor) {
|
public Object accept (FragmentVisitor<?> visitor) {
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import com.samskivert.depot.impl.expression.Function.TwoArgFun;
|
|||||||
public abstract class NumericalFun
|
public abstract class NumericalFun
|
||||||
{
|
{
|
||||||
public static class Abs<T extends Number> extends OneArgFun<T> {
|
public static class Abs<T extends Number> extends OneArgFun<T> {
|
||||||
public Abs (SQLExpression<T> argument) {
|
public Abs (SQLExpression<? extends T> argument) {
|
||||||
super(argument);
|
super(argument);
|
||||||
}
|
}
|
||||||
public Object accept (FragmentVisitor<?> visitor) {
|
public Object accept (FragmentVisitor<?> visitor) {
|
||||||
@@ -41,7 +41,7 @@ public abstract class NumericalFun
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class Ceil<T extends Number> extends OneArgFun<T> {
|
public static class Ceil<T extends Number> extends OneArgFun<T> {
|
||||||
public Ceil (SQLExpression<T> argument) {
|
public Ceil (SQLExpression<? extends T> argument) {
|
||||||
super(argument);
|
super(argument);
|
||||||
}
|
}
|
||||||
public Object accept (FragmentVisitor<?> visitor) {
|
public Object accept (FragmentVisitor<?> visitor) {
|
||||||
@@ -53,7 +53,7 @@ public abstract class NumericalFun
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class Exp<T extends Number> extends OneArgFun<T> {
|
public static class Exp<T extends Number> extends OneArgFun<T> {
|
||||||
public Exp (SQLExpression<T> argument) {
|
public Exp (SQLExpression<? extends T> argument) {
|
||||||
super(argument);
|
super(argument);
|
||||||
}
|
}
|
||||||
public Object accept (FragmentVisitor<?> visitor) {
|
public Object accept (FragmentVisitor<?> visitor) {
|
||||||
@@ -65,7 +65,7 @@ public abstract class NumericalFun
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class Floor<T extends Number> extends OneArgFun<T> {
|
public static class Floor<T extends Number> extends OneArgFun<T> {
|
||||||
public Floor (SQLExpression<T> argument) {
|
public Floor (SQLExpression<? extends T> argument) {
|
||||||
super(argument);
|
super(argument);
|
||||||
}
|
}
|
||||||
public Object accept (FragmentVisitor<?> visitor) {
|
public Object accept (FragmentVisitor<?> visitor) {
|
||||||
@@ -77,7 +77,7 @@ public abstract class NumericalFun
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class Ln<T extends Number> extends OneArgFun<T> {
|
public static class Ln<T extends Number> extends OneArgFun<T> {
|
||||||
public Ln (SQLExpression<T> argument) {
|
public Ln (SQLExpression<? extends T> argument) {
|
||||||
super(argument);
|
super(argument);
|
||||||
}
|
}
|
||||||
public Object accept (FragmentVisitor<?> visitor) {
|
public Object accept (FragmentVisitor<?> visitor) {
|
||||||
@@ -89,7 +89,7 @@ public abstract class NumericalFun
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class Log10<T extends Number> extends OneArgFun<T> {
|
public static class Log10<T extends Number> extends OneArgFun<T> {
|
||||||
public Log10 (SQLExpression<T> value) {
|
public Log10 (SQLExpression<? extends T> value) {
|
||||||
super(value);
|
super(value);
|
||||||
}
|
}
|
||||||
public Object accept (FragmentVisitor<?> visitor) {
|
public Object accept (FragmentVisitor<?> visitor) {
|
||||||
@@ -109,8 +109,8 @@ public abstract class NumericalFun
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Power<R extends Number,P extends Number> extends TwoArgFun<R> {
|
public static class Power<T extends Number> extends TwoArgFun<T> {
|
||||||
public Power (SQLExpression<R> value, SQLExpression<P> power) {
|
public Power (SQLExpression<? extends T> value, SQLExpression<? extends Number> power) {
|
||||||
super(value, power);
|
super(value, power);
|
||||||
}
|
}
|
||||||
public Object accept (FragmentVisitor<?> visitor) {
|
public Object accept (FragmentVisitor<?> visitor) {
|
||||||
@@ -137,7 +137,7 @@ public abstract class NumericalFun
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class Round<T extends Number> extends OneArgFun<T> {
|
public static class Round<T extends Number> extends OneArgFun<T> {
|
||||||
public Round (SQLExpression<T> argument) {
|
public Round (SQLExpression<? extends T> argument) {
|
||||||
super(argument);
|
super(argument);
|
||||||
}
|
}
|
||||||
public Object accept (FragmentVisitor<?> visitor) {
|
public Object accept (FragmentVisitor<?> visitor) {
|
||||||
@@ -149,7 +149,7 @@ public abstract class NumericalFun
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class Sign<T extends Number> extends OneArgFun<T> {
|
public static class Sign<T extends Number> extends OneArgFun<T> {
|
||||||
public Sign (SQLExpression<T> argument) {
|
public Sign (SQLExpression<? extends T> argument) {
|
||||||
super(argument);
|
super(argument);
|
||||||
}
|
}
|
||||||
public Object accept (FragmentVisitor<?> visitor) {
|
public Object accept (FragmentVisitor<?> visitor) {
|
||||||
@@ -161,7 +161,7 @@ public abstract class NumericalFun
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class Sqrt<T extends Number> extends OneArgFun<T> {
|
public static class Sqrt<T extends Number> extends OneArgFun<T> {
|
||||||
public Sqrt (SQLExpression<T> argument) {
|
public Sqrt (SQLExpression<? extends T> argument) {
|
||||||
super(argument);
|
super(argument);
|
||||||
}
|
}
|
||||||
public Object accept (FragmentVisitor<?> visitor) {
|
public Object accept (FragmentVisitor<?> visitor) {
|
||||||
@@ -173,7 +173,7 @@ public abstract class NumericalFun
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class Trunc<T extends Number> extends OneArgFun<T> {
|
public static class Trunc<T extends Number> extends OneArgFun<T> {
|
||||||
public Trunc (SQLExpression<T> argument) {
|
public Trunc (SQLExpression<? extends T> argument) {
|
||||||
super(argument);
|
super(argument);
|
||||||
}
|
}
|
||||||
public Object accept (FragmentVisitor<?> visitor) {
|
public Object accept (FragmentVisitor<?> visitor) {
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import com.samskivert.depot.impl.expression.Function.TwoArgFun;
|
|||||||
|
|
||||||
public abstract class StringFun
|
public abstract class StringFun
|
||||||
{
|
{
|
||||||
public static class Length extends OneArgFun<Integer> {
|
public static class Length extends OneArgFun<Number> {
|
||||||
// can take both String or array types (anything that turns into byte[])
|
// can take both String or array types (anything that turns into byte[])
|
||||||
public Length (SQLExpression<?> argument) {
|
public Length (SQLExpression<?> argument) {
|
||||||
super(argument);
|
super(argument);
|
||||||
@@ -53,7 +53,7 @@ public abstract class StringFun
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Position extends TwoArgFun<Integer> {
|
public static class Position extends TwoArgFun<Number> {
|
||||||
public Position (SQLExpression<String> substring, SQLExpression<String> string) {
|
public Position (SQLExpression<String> substring, SQLExpression<String> string) {
|
||||||
super(substring, string);
|
super(substring, string);
|
||||||
}
|
}
|
||||||
@@ -72,8 +72,8 @@ public abstract class StringFun
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class Substring extends ManyArgFun<String> {
|
public static class Substring extends ManyArgFun<String> {
|
||||||
public Substring (SQLExpression<String> string, SQLExpression<String> from,
|
public Substring (SQLExpression<String> string,
|
||||||
SQLExpression<Integer> count) {
|
SQLExpression<Integer> from, SQLExpression<Integer> count) {
|
||||||
super(string, from, count);
|
super(string, from, count);
|
||||||
}
|
}
|
||||||
public Object accept (FragmentVisitor<?> visitor) {
|
public Object accept (FragmentVisitor<?> visitor) {
|
||||||
|
|||||||
@@ -108,13 +108,6 @@ public class ProjectionTest extends TestBase
|
|||||||
|
|
||||||
@Test public void testAggregates ()
|
@Test public void testAggregates ()
|
||||||
{
|
{
|
||||||
// test computed expressions on the RHS (the casts are just to cope with JUnit's overloads)
|
|
||||||
assertEquals(9, (int)_repo.from(TestRecord.class).load(Funcs.max(TestRecord.RECORD_ID)));
|
|
||||||
assertEquals(10, (int)_repo.from(TestRecord.class).load(Funcs.count(TestRecord.RECORD_ID)));
|
|
||||||
assertEquals(0, (int)_repo.from(TestRecord.class).load(Funcs.min(TestRecord.RECORD_ID)));
|
|
||||||
assertEquals(Tuple2.create(9, 0), _repo.from(TestRecord.class).load(
|
|
||||||
Funcs.max(TestRecord.RECORD_ID), Funcs.min(TestRecord.RECORD_ID)));
|
|
||||||
|
|
||||||
List<Tuple2<String, Integer>> ewant = Lists.newArrayList();
|
List<Tuple2<String, Integer>> ewant = Lists.newArrayList();
|
||||||
ewant.add(Tuple2.create("Abraham", 1));
|
ewant.add(Tuple2.create("Abraham", 1));
|
||||||
ewant.add(Tuple2.create("Elvis", 2));
|
ewant.add(Tuple2.create("Elvis", 2));
|
||||||
@@ -124,6 +117,84 @@ public class ProjectionTest extends TestBase
|
|||||||
select(EnumKeyRecord.NAME, Funcs.count(EnumKeyRecord.TYPE)));
|
select(EnumKeyRecord.NAME, Funcs.count(EnumKeyRecord.TYPE)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test public void testFuncs ()
|
||||||
|
{
|
||||||
|
Query<TestRecord> query = _repo.from(TestRecord.class);
|
||||||
|
|
||||||
|
assertEquals(4, query.load(Funcs.average(TestRecord.RECORD_ID)).intValue());
|
||||||
|
assertEquals(4, query.load(Funcs.averageDistinct(TestRecord.RECORD_ID)).intValue());
|
||||||
|
|
||||||
|
assertEquals(10, query.load(Funcs.count(TestRecord.RECORD_ID)).intValue());
|
||||||
|
assertEquals(false, query.load(Funcs.every(TestRecord.RECORD_ID.greaterThan(5))));
|
||||||
|
assertEquals(true, query.load(Funcs.every(TestRecord.RECORD_ID.lessThan(100))));
|
||||||
|
|
||||||
|
assertEquals(9, query.load(Funcs.max(TestRecord.RECORD_ID)).intValue());
|
||||||
|
assertEquals(0, query.load(Funcs.min(TestRecord.RECORD_ID)).intValue());
|
||||||
|
assertEquals(45, query.load(Funcs.sum(TestRecord.RECORD_ID)).intValue());
|
||||||
|
|
||||||
|
// TODO: not sure what a good test for Funcs.coalesce() is...
|
||||||
|
|
||||||
|
List<Integer> greatest = Lists.newArrayList(99, 99, 99, 99, 99, 99, 99, 99, 99, 99);
|
||||||
|
assertEquals(greatest, query.select(Funcs.greatest(TestRecord.RECORD_ID, TestRecord.AGE)));
|
||||||
|
|
||||||
|
List<Integer> least = Lists.newArrayList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
|
||||||
|
assertEquals(least, query.select(Funcs.least(TestRecord.RECORD_ID, TestRecord.AGE)));
|
||||||
|
|
||||||
|
// length(blob) not supported by HSQLDB
|
||||||
|
// assertEquals(4*5, (int)query.select(Funcs.arrayLength(TestRecord.NUMBERS)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void testStringFuncs ()
|
||||||
|
{
|
||||||
|
Query<TestRecord> first = _repo.from(TestRecord.class).where(TestRecord.RECORD_ID.eq(1));
|
||||||
|
|
||||||
|
assertEquals(5, first.load(StringFuncs.length(TestRecord.NAME)).intValue());
|
||||||
|
assertEquals("elvis", first.load(StringFuncs.lower(TestRecord.NAME)));
|
||||||
|
assertEquals(3, first.load(StringFuncs.position(
|
||||||
|
Exps.value("vis"), TestRecord.NAME)).intValue());
|
||||||
|
assertEquals("lvi", first.load(StringFuncs.substring(TestRecord.NAME, 2, 3)));
|
||||||
|
assertEquals("Elvis", first.load(StringFuncs.trim(TestRecord.NAME)));
|
||||||
|
assertEquals("ELVIS", first.load(StringFuncs.upper(TestRecord.NAME)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void testMathFuncs ()
|
||||||
|
{
|
||||||
|
Query<TestRecord> first = _repo.from(TestRecord.class).where(TestRecord.RECORD_ID.eq(1));
|
||||||
|
|
||||||
|
assertEquals(99, first.load(MathFuncs.abs(TestRecord.AGE)).intValue());
|
||||||
|
assertEquals(1f, first.load(MathFuncs.ceil(TestRecord.AWESOMENESS)).floatValue(), 0);
|
||||||
|
assertEquals(0f, first.load(MathFuncs.floor(TestRecord.AWESOMENESS)).floatValue(), 0);
|
||||||
|
|
||||||
|
assertEquals(Math.exp(0.75), first.load(
|
||||||
|
MathFuncs.exp(TestRecord.AWESOMENESS)).doubleValue(), 0.0001);
|
||||||
|
|
||||||
|
assertEquals(Math.log(0.75), first.load(
|
||||||
|
MathFuncs.ln(TestRecord.AWESOMENESS)).doubleValue(), 0.0001);
|
||||||
|
|
||||||
|
assertEquals(Math.PI, first.load(MathFuncs.<Double>pi()), 0.0001);
|
||||||
|
|
||||||
|
assertTrue(first.load(MathFuncs.<Double>random()) < 1.0);
|
||||||
|
|
||||||
|
assertEquals(1, first.load(MathFuncs.round(TestRecord.AWESOMENESS)).intValue());
|
||||||
|
assertEquals(1, first.load(MathFuncs.sign(TestRecord.AWESOMENESS)).intValue());
|
||||||
|
assertEquals(Math.sqrt(0.75), first.load(
|
||||||
|
MathFuncs.sqrt(TestRecord.AWESOMENESS)).doubleValue(), 0.0001);
|
||||||
|
|
||||||
|
assertEquals(Math.pow(0.75f, 10), first.load(
|
||||||
|
MathFuncs.power(TestRecord.AWESOMENESS, Exps.value(10))).doubleValue(),
|
||||||
|
0.0001);
|
||||||
|
|
||||||
|
// HSQLDB log10 seems not to work either, it returns some wildly incorrect value
|
||||||
|
// assertEquals(Math.log10(0.75), first.load(
|
||||||
|
// MathFuncs.log10(TestRecord.AWESOMENESS)).doubleValue(), 0.0001);
|
||||||
|
|
||||||
|
// HSQLDB truncate(a,b) simply doesn't work, if you supply trunacte(a, >=0) then you get
|
||||||
|
// back a regardless of the number of decimal places a contains or the number you requested
|
||||||
|
// to truncate to, and if you supply truncate(a, <0) you get back 0 regardless of a
|
||||||
|
// assertEquals(0, first.load(
|
||||||
|
// MathFuncs.trunc(TestRecord.AWESOMENESS)).doubleValue(), 0.0001);
|
||||||
|
}
|
||||||
|
|
||||||
// the HSQL in-memory database persists for the lifetime of the VM, which means we have to
|
// the HSQL in-memory database persists for the lifetime of the VM, which means we have to
|
||||||
// clean up after ourselves in every test; thus we go ahead and share a repository
|
// clean up after ourselves in every test; thus we go ahead and share a repository
|
||||||
protected TestRepository _repo = createTestRepository();
|
protected TestRepository _repo = createTestRepository();
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ public abstract class TestBase
|
|||||||
rec.recordId = recordId;
|
rec.recordId = recordId;
|
||||||
rec.name = "Elvis";
|
rec.name = "Elvis";
|
||||||
rec.age = 99;
|
rec.age = 99;
|
||||||
|
rec.awesomeness = 0.75f;
|
||||||
rec.created = now;
|
rec.created = now;
|
||||||
rec.homeTown = "Right here";
|
rec.homeTown = "Right here";
|
||||||
rec.type = EnumKeyRecord.Type.A;
|
rec.type = EnumKeyRecord.Type.A;
|
||||||
@@ -89,6 +90,7 @@ public abstract class TestBase
|
|||||||
assertEquals(expect.recordId, got.recordId);
|
assertEquals(expect.recordId, got.recordId);
|
||||||
assertEquals(expect.name, got.name);
|
assertEquals(expect.name, got.name);
|
||||||
assertEquals(expect.age, got.age);
|
assertEquals(expect.age, got.age);
|
||||||
|
assertEquals(expect.awesomeness, got.awesomeness, 0);
|
||||||
assertEquals(expect.created, got.created);
|
assertEquals(expect.created, got.created);
|
||||||
assertEquals(expect.homeTown, got.homeTown);
|
assertEquals(expect.homeTown, got.homeTown);
|
||||||
assertEquals(expect.type, got.type);
|
assertEquals(expect.type, got.type);
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ public class TestRecord extends PersistentRecord
|
|||||||
public static final ColumnExp<Integer> RECORD_ID = colexp(_R, "recordId");
|
public static final ColumnExp<Integer> RECORD_ID = colexp(_R, "recordId");
|
||||||
public static final ColumnExp<String> NAME = colexp(_R, "name");
|
public static final ColumnExp<String> NAME = colexp(_R, "name");
|
||||||
public static final ColumnExp<Integer> AGE = colexp(_R, "age");
|
public static final ColumnExp<Integer> AGE = colexp(_R, "age");
|
||||||
|
public static final ColumnExp<Float> AWESOMENESS = colexp(_R, "awesomeness");
|
||||||
public static final ColumnExp<String> HOME_TOWN = colexp(_R, "homeTown");
|
public static final ColumnExp<String> HOME_TOWN = colexp(_R, "homeTown");
|
||||||
public static final ColumnExp<EnumKeyRecord.Type> TYPE = colexp(_R, "type");
|
public static final ColumnExp<EnumKeyRecord.Type> TYPE = colexp(_R, "type");
|
||||||
public static final ColumnExp<Date> CREATED = colexp(_R, "created");
|
public static final ColumnExp<Date> CREATED = colexp(_R, "created");
|
||||||
@@ -57,6 +58,8 @@ public class TestRecord extends PersistentRecord
|
|||||||
|
|
||||||
public int age;
|
public int age;
|
||||||
|
|
||||||
|
public float awesomeness;
|
||||||
|
|
||||||
public String homeTown;
|
public String homeTown;
|
||||||
|
|
||||||
public EnumKeyRecord.Type type;
|
public EnumKeyRecord.Type type;
|
||||||
|
|||||||
Reference in New Issue
Block a user