From b6088302d5171c8d4cd9286880bab9d457bcae59 Mon Sep 17 00:00:00 2001 From: Michael Bayne Date: Fri, 10 Dec 2010 00:48:52 +0000 Subject: [PATCH] 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. --- src/main/java/com/samskivert/depot/Funcs.java | 32 +++--- .../java/com/samskivert/depot/MathFuncs.java | 100 ++++++++++++------ .../com/samskivert/depot/StringFuncs.java | 20 +++- .../samskivert/depot/impl/BuildVisitor.java | 2 +- .../depot/impl/ExpressionEvaluator.java | 2 +- .../depot/impl/FragmentVisitor.java | 2 +- .../samskivert/depot/impl/HSQLBuilder.java | 41 +++++++ .../depot/impl/expression/AggregateFun.java | 16 +-- .../depot/impl/expression/NumericalFun.java | 24 ++--- .../depot/impl/expression/StringFun.java | 8 +- .../com/samskivert/depot/ProjectionTest.java | 85 +++++++++++++-- .../java/com/samskivert/depot/TestBase.java | 2 + .../java/com/samskivert/depot/TestRecord.java | 3 + 13 files changed, 251 insertions(+), 86 deletions(-) diff --git a/src/main/java/com/samskivert/depot/Funcs.java b/src/main/java/com/samskivert/depot/Funcs.java index 0ca46e3..e40076a 100644 --- a/src/main/java/com/samskivert/depot/Funcs.java +++ b/src/main/java/com/samskivert/depot/Funcs.java @@ -32,21 +32,25 @@ import com.samskivert.depot.impl.expression.StringFun.*; public class Funcs { /** - * Creates an aggregate expression that averages all values from the supplied expression. - * This would usually be used in a FieldOverride and supplied with a ColumnExp. + * Creates an aggregate expression that averages all values from the supplied expression. Note + * 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 FluentExp average (SQLExpression expr) + public static FluentExp average (SQLExpression expr) { - return new Average(expr); + return new Average(expr); } /** - * Creates an expression that averages all distinct values from the supplied expression. - * This would usually be used in a FieldOverride and supplied with a ColumnExp. + * Creates an expression that averages all distinct values from the supplied expression. Note + * 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 FluentExp averageDistinct (SQLExpression expr) + public static FluentExp averageDistinct (SQLExpression expr) { - return new Average(expr, true); + return new Average(expr, true); } /** @@ -99,12 +103,14 @@ public class Funcs } /** - * Creates an aggregate expression that sums all the values from the supplied expression. - * This would usually be used in a FieldOverride and supplied with a ColumnExp. + * Creates an aggregate expression that sums all the values from the supplied expression. Note + * 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 FluentExp sum (SQLExpression expr) + public static FluentExp sum (SQLExpression expr) { - return new Sum(expr); + return new Sum(expr); } /** @@ -161,7 +167,7 @@ public class Funcs /** * Creates an expression that evaluates to the length of the supplied array column. */ - public static FluentExp arrayLength (SQLExpression exp) + public static FluentExp arrayLength (SQLExpression exp) { return new Length(exp); } diff --git a/src/main/java/com/samskivert/depot/MathFuncs.java b/src/main/java/com/samskivert/depot/MathFuncs.java index 7e8c0d3..417d95f 100644 --- a/src/main/java/com/samskivert/depot/MathFuncs.java +++ b/src/main/java/com/samskivert/depot/MathFuncs.java @@ -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 FluentExp ceil (SQLExpression exp) + public static FluentExp ceil (SQLExpression exp) { - return new Ceil(exp); + return new Ceil(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 FluentExp exp (SQLExpression exp) + public static FluentExp floor (SQLExpression exp) { - return new Exp(exp); + return new Floor(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 FluentExp floor (SQLExpression exp) + public static FluentExp exp (SQLExpression exp) { - return new Floor(exp); + return new Exp(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 FluentExp ln (SQLExpression exp) + public static FluentExp ln (SQLExpression exp) { - return new Ln(exp); + return new Ln(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 FluentExp log10 (SQLExpression value) + public static FluentExp log10 (SQLExpression value) { - return new Log10(value); + return new Log10(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 FluentExp 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 FluentExp power (SQLExpression value, - SQLExpression

power) + public static FluentExp power (SQLExpression value, + SQLExpression power) { - return new Power(value, power); + return new Power(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 FluentExp 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 FluentExp round (SQLExpression exp) + public static FluentExp round (SQLExpression exp) { - return new Round(exp); + return new Round(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 FluentExp sign (SQLExpression exp) + public static FluentExp sign (SQLExpression exp) { - return new Sign(exp); + return new Sign(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 FluentExp sqrt (SQLExpression exp) + public static FluentExp sqrt (SQLExpression exp) { - return new Sqrt(exp); + return new Sqrt(exp); } /** - * Creates an expression that computes the truncation of the supplied expression, - * i.e. the next closest whole number to zero. + * Creates an expression that computes the truncation of the supplied expression, i.e. the next + * 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 FluentExp trunc (SQLExpression exp) + public static FluentExp trunc (SQLExpression exp) { - return new Trunc(exp); + return new Trunc(exp); } } diff --git a/src/main/java/com/samskivert/depot/StringFuncs.java b/src/main/java/com/samskivert/depot/StringFuncs.java index 38348c3..8d03c95 100644 --- a/src/main/java/com/samskivert/depot/StringFuncs.java +++ b/src/main/java/com/samskivert/depot/StringFuncs.java @@ -32,7 +32,7 @@ public class StringFuncs /** * Creates an expression that evaluates to the string length of the supplied expression. */ - public static FluentExp length (SQLExpression exp) + public static FluentExp length (SQLExpression exp) { return new Length(exp); } @@ -49,8 +49,8 @@ public class StringFuncs * Creates an expression that locates the given substring expression within the given * string expression and returns the index. */ - public static FluentExp position (SQLExpression substring, - SQLExpression string) + public static FluentExp position (SQLExpression substring, + SQLExpression 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, * starting at the given index and of the given length. */ - public static FluentExp substring ( - SQLExpression string, SQLExpression from, SQLExpression count) + public static FluentExp substring (SQLExpression string, int from, int 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 substring (SQLExpression string, + SQLExpression from, + SQLExpression count) { return new Substring(string, from, count); } diff --git a/src/main/java/com/samskivert/depot/impl/BuildVisitor.java b/src/main/java/com/samskivert/depot/impl/BuildVisitor.java index 26dcd24..635263a 100644 --- a/src/main/java/com/samskivert/depot/impl/BuildVisitor.java +++ b/src/main/java/com/samskivert/depot/impl/BuildVisitor.java @@ -594,7 +594,7 @@ public abstract class BuildVisitor implements FragmentVisitor return appendFunctionCall("PI"); } - public Void visit (Power exp) + public Void visit (Power exp) { return appendFunctionCall("power", exp.getValue(), exp.getPower()); } diff --git a/src/main/java/com/samskivert/depot/impl/ExpressionEvaluator.java b/src/main/java/com/samskivert/depot/impl/ExpressionEvaluator.java index 96744b9..b7c6e6e 100644 --- a/src/main/java/com/samskivert/depot/impl/ExpressionEvaluator.java +++ b/src/main/java/com/samskivert/depot/impl/ExpressionEvaluator.java @@ -371,7 +371,7 @@ public class ExpressionEvaluator 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); } diff --git a/src/main/java/com/samskivert/depot/impl/FragmentVisitor.java b/src/main/java/com/samskivert/depot/impl/FragmentVisitor.java index 67ffa95..1bb5e16 100644 --- a/src/main/java/com/samskivert/depot/impl/FragmentVisitor.java +++ b/src/main/java/com/samskivert/depot/impl/FragmentVisitor.java @@ -124,7 +124,7 @@ public interface FragmentVisitor public T visit (Ln exp); public T visit (Log10 exp); public T visit (Pi exp); - public T visit (Power exp); + public T visit (Power exp); public T visit (Random exp); public T visit (Round exp); public T visit (Sign exp); diff --git a/src/main/java/com/samskivert/depot/impl/HSQLBuilder.java b/src/main/java/com/samskivert/depot/impl/HSQLBuilder.java index dc9c23e..c740fd6 100644 --- a/src/main/java/com/samskivert/depot/impl/HSQLBuilder.java +++ b/src/main/java/com/samskivert/depot/impl/HSQLBuilder.java @@ -30,6 +30,8 @@ import com.google.common.collect.Lists; import com.samskivert.jdbc.ColumnDefinition; import com.samskivert.util.ArrayUtil; + +import com.samskivert.depot.Exps; import com.samskivert.depot.Ops; import com.samskivert.depot.PersistentRecord; 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.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; 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.ValueExp; import com.samskivert.depot.impl.operator.BitAnd; import com.samskivert.depot.impl.operator.BitOr; import com.samskivert.depot.impl.operator.Like; @@ -51,6 +57,41 @@ public class HSQLBuilder { 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(((ValueExp)power).getValue().toString()); + } + return appendFunctionCall("power", exp.getValue(), power); + } + @Override public Void visit (FullText.Match match) { // HSQL doesn't have real full text search, so we fake it by creating a condition like diff --git a/src/main/java/com/samskivert/depot/impl/expression/AggregateFun.java b/src/main/java/com/samskivert/depot/impl/expression/AggregateFun.java index 4838123..0cad4e1 100644 --- a/src/main/java/com/samskivert/depot/impl/expression/AggregateFun.java +++ b/src/main/java/com/samskivert/depot/impl/expression/AggregateFun.java @@ -27,10 +27,10 @@ import com.samskivert.depot.impl.expression.Function.OneArgFun; public abstract class AggregateFun extends OneArgFun { public static class Average extends AggregateFun { - public Average (SQLExpression argument) { + public Average (SQLExpression argument) { this(argument, false); } - public Average (SQLExpression argument, boolean distinct) { + public Average (SQLExpression argument, boolean distinct) { super(argument, distinct); } public Object accept (FragmentVisitor visitor) { @@ -72,10 +72,10 @@ public abstract class AggregateFun extends OneArgFun } public static class Max extends AggregateFun { - public Max (SQLExpression argument) { + public Max (SQLExpression argument) { this(argument, false); } - public Max (SQLExpression argument, boolean distinct) { + public Max (SQLExpression argument, boolean distinct) { super(argument, distinct); } public Object accept (FragmentVisitor visitor) { @@ -87,10 +87,10 @@ public abstract class AggregateFun extends OneArgFun } public static class Min extends AggregateFun { - public Min (SQLExpression argument) { + public Min (SQLExpression argument) { this(argument, false); } - public Min (SQLExpression argument, boolean distinct) { + public Min (SQLExpression argument, boolean distinct) { super(argument, distinct); } public Object accept (FragmentVisitor visitor) { @@ -102,10 +102,10 @@ public abstract class AggregateFun extends OneArgFun } public static class Sum extends AggregateFun { - public Sum (SQLExpression argument) { + public Sum (SQLExpression argument) { this(argument, false); } - public Sum (SQLExpression argument, boolean distinct) { + public Sum (SQLExpression argument, boolean distinct) { super(argument, distinct); } public Object accept (FragmentVisitor visitor) { diff --git a/src/main/java/com/samskivert/depot/impl/expression/NumericalFun.java b/src/main/java/com/samskivert/depot/impl/expression/NumericalFun.java index 8997c7c..dfdc7fa 100644 --- a/src/main/java/com/samskivert/depot/impl/expression/NumericalFun.java +++ b/src/main/java/com/samskivert/depot/impl/expression/NumericalFun.java @@ -29,7 +29,7 @@ import com.samskivert.depot.impl.expression.Function.TwoArgFun; public abstract class NumericalFun { public static class Abs extends OneArgFun { - public Abs (SQLExpression argument) { + public Abs (SQLExpression argument) { super(argument); } public Object accept (FragmentVisitor visitor) { @@ -41,7 +41,7 @@ public abstract class NumericalFun } public static class Ceil extends OneArgFun { - public Ceil (SQLExpression argument) { + public Ceil (SQLExpression argument) { super(argument); } public Object accept (FragmentVisitor visitor) { @@ -53,7 +53,7 @@ public abstract class NumericalFun } public static class Exp extends OneArgFun { - public Exp (SQLExpression argument) { + public Exp (SQLExpression argument) { super(argument); } public Object accept (FragmentVisitor visitor) { @@ -65,7 +65,7 @@ public abstract class NumericalFun } public static class Floor extends OneArgFun { - public Floor (SQLExpression argument) { + public Floor (SQLExpression argument) { super(argument); } public Object accept (FragmentVisitor visitor) { @@ -77,7 +77,7 @@ public abstract class NumericalFun } public static class Ln extends OneArgFun { - public Ln (SQLExpression argument) { + public Ln (SQLExpression argument) { super(argument); } public Object accept (FragmentVisitor visitor) { @@ -89,7 +89,7 @@ public abstract class NumericalFun } public static class Log10 extends OneArgFun { - public Log10 (SQLExpression value) { + public Log10 (SQLExpression value) { super(value); } public Object accept (FragmentVisitor visitor) { @@ -109,8 +109,8 @@ public abstract class NumericalFun } } - public static class Power extends TwoArgFun { - public Power (SQLExpression value, SQLExpression

power) { + public static class Power extends TwoArgFun { + public Power (SQLExpression value, SQLExpression power) { super(value, power); } public Object accept (FragmentVisitor visitor) { @@ -137,7 +137,7 @@ public abstract class NumericalFun } public static class Round extends OneArgFun { - public Round (SQLExpression argument) { + public Round (SQLExpression argument) { super(argument); } public Object accept (FragmentVisitor visitor) { @@ -149,7 +149,7 @@ public abstract class NumericalFun } public static class Sign extends OneArgFun { - public Sign (SQLExpression argument) { + public Sign (SQLExpression argument) { super(argument); } public Object accept (FragmentVisitor visitor) { @@ -161,7 +161,7 @@ public abstract class NumericalFun } public static class Sqrt extends OneArgFun { - public Sqrt (SQLExpression argument) { + public Sqrt (SQLExpression argument) { super(argument); } public Object accept (FragmentVisitor visitor) { @@ -173,7 +173,7 @@ public abstract class NumericalFun } public static class Trunc extends OneArgFun { - public Trunc (SQLExpression argument) { + public Trunc (SQLExpression argument) { super(argument); } public Object accept (FragmentVisitor visitor) { diff --git a/src/main/java/com/samskivert/depot/impl/expression/StringFun.java b/src/main/java/com/samskivert/depot/impl/expression/StringFun.java index cbf48b8..ab94515 100644 --- a/src/main/java/com/samskivert/depot/impl/expression/StringFun.java +++ b/src/main/java/com/samskivert/depot/impl/expression/StringFun.java @@ -28,7 +28,7 @@ import com.samskivert.depot.impl.expression.Function.TwoArgFun; public abstract class StringFun { - public static class Length extends OneArgFun { + public static class Length extends OneArgFun { // can take both String or array types (anything that turns into byte[]) public Length (SQLExpression argument) { super(argument); @@ -53,7 +53,7 @@ public abstract class StringFun } } - public static class Position extends TwoArgFun { + public static class Position extends TwoArgFun { public Position (SQLExpression substring, SQLExpression string) { super(substring, string); } @@ -72,8 +72,8 @@ public abstract class StringFun } public static class Substring extends ManyArgFun { - public Substring (SQLExpression string, SQLExpression from, - SQLExpression count) { + public Substring (SQLExpression string, + SQLExpression from, SQLExpression count) { super(string, from, count); } public Object accept (FragmentVisitor visitor) { diff --git a/src/test/java/com/samskivert/depot/ProjectionTest.java b/src/test/java/com/samskivert/depot/ProjectionTest.java index be1cb53..f060d15 100644 --- a/src/test/java/com/samskivert/depot/ProjectionTest.java +++ b/src/test/java/com/samskivert/depot/ProjectionTest.java @@ -108,13 +108,6 @@ public class ProjectionTest extends TestBase @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> ewant = Lists.newArrayList(); ewant.add(Tuple2.create("Abraham", 1)); ewant.add(Tuple2.create("Elvis", 2)); @@ -124,6 +117,84 @@ public class ProjectionTest extends TestBase select(EnumKeyRecord.NAME, Funcs.count(EnumKeyRecord.TYPE))); } + @Test public void testFuncs () + { + Query 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 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 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 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 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.pi()), 0.0001); + + assertTrue(first.load(MathFuncs.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 // clean up after ourselves in every test; thus we go ahead and share a repository protected TestRepository _repo = createTestRepository(); diff --git a/src/test/java/com/samskivert/depot/TestBase.java b/src/test/java/com/samskivert/depot/TestBase.java index 4e939d9..1470017 100644 --- a/src/test/java/com/samskivert/depot/TestBase.java +++ b/src/test/java/com/samskivert/depot/TestBase.java @@ -73,6 +73,7 @@ public abstract class TestBase rec.recordId = recordId; rec.name = "Elvis"; rec.age = 99; + rec.awesomeness = 0.75f; rec.created = now; rec.homeTown = "Right here"; rec.type = EnumKeyRecord.Type.A; @@ -89,6 +90,7 @@ public abstract class TestBase assertEquals(expect.recordId, got.recordId); assertEquals(expect.name, got.name); assertEquals(expect.age, got.age); + assertEquals(expect.awesomeness, got.awesomeness, 0); assertEquals(expect.created, got.created); assertEquals(expect.homeTown, got.homeTown); assertEquals(expect.type, got.type); diff --git a/src/test/java/com/samskivert/depot/TestRecord.java b/src/test/java/com/samskivert/depot/TestRecord.java index 27513e5..d9bda9d 100644 --- a/src/test/java/com/samskivert/depot/TestRecord.java +++ b/src/test/java/com/samskivert/depot/TestRecord.java @@ -41,6 +41,7 @@ public class TestRecord extends PersistentRecord public static final ColumnExp RECORD_ID = colexp(_R, "recordId"); public static final ColumnExp NAME = colexp(_R, "name"); public static final ColumnExp AGE = colexp(_R, "age"); + public static final ColumnExp AWESOMENESS = colexp(_R, "awesomeness"); public static final ColumnExp HOME_TOWN = colexp(_R, "homeTown"); public static final ColumnExp TYPE = colexp(_R, "type"); public static final ColumnExp CREATED = colexp(_R, "created"); @@ -57,6 +58,8 @@ public class TestRecord extends PersistentRecord public int age; + public float awesomeness; + public String homeTown; public EnumKeyRecord.Type type;