From 32bccc3dd7998d5b54650ce1868c9193e621ebc0 Mon Sep 17 00:00:00 2001 From: Par Winzell Date: Wed, 9 Sep 2009 14:39:55 +0000 Subject: [PATCH] Deprecate FunctionExp in favour of explicit support for many common SQL functions, whose convenience factory methods reside in com.samskivert.depot.Funs. The EpochSeconds class is also deprecated in favour of Funs.dateEpoch(). --- src/java/com/samskivert/depot/Exps.java | 43 +- src/java/com/samskivert/depot/Funs.java | 400 ++++++++++++++++++ .../depot/expression/ArgumentExp.java | 47 ++ .../depot/expression/EpochSeconds.java | 1 + .../depot/expression/FunctionExp.java | 1 + .../depot/function/AggregateFun.java | 113 +++++ .../depot/function/ConditionalFun.java | 55 +++ .../samskivert/depot/function/DateFun.java | 76 ++++ .../samskivert/depot/function/NoArgFun.java | 34 ++ .../depot/function/NumericalFun.java | 150 +++++++ .../samskivert/depot/function/OneArgFun.java | 47 ++ .../samskivert/depot/function/StringFun.java | 88 ++++ .../samskivert/depot/function/TwoArgFun.java | 44 ++ .../samskivert/depot/impl/BuildVisitor.java | 257 ++++++++++- .../depot/impl/ExpressionEvaluator.java | 214 +++++++++- .../depot/impl/ExpressionVisitor.java | 82 +++- .../samskivert/depot/impl/HSQLBuilder.java | 88 ++-- .../samskivert/depot/impl/MySQLBuilder.java | 51 ++- .../depot/impl/PostgreSQL4Builder.java | 2 +- .../depot/impl/PostgreSQLBuilder.java | 47 +- .../depot/operator/SQLOperator.java | 41 +- 21 files changed, 1731 insertions(+), 150 deletions(-) create mode 100644 src/java/com/samskivert/depot/Funs.java create mode 100644 src/java/com/samskivert/depot/expression/ArgumentExp.java create mode 100644 src/java/com/samskivert/depot/function/AggregateFun.java create mode 100644 src/java/com/samskivert/depot/function/ConditionalFun.java create mode 100644 src/java/com/samskivert/depot/function/DateFun.java create mode 100644 src/java/com/samskivert/depot/function/NoArgFun.java create mode 100644 src/java/com/samskivert/depot/function/NumericalFun.java create mode 100644 src/java/com/samskivert/depot/function/OneArgFun.java create mode 100644 src/java/com/samskivert/depot/function/StringFun.java create mode 100644 src/java/com/samskivert/depot/function/TwoArgFun.java diff --git a/src/java/com/samskivert/depot/Exps.java b/src/java/com/samskivert/depot/Exps.java index 6db1fad..3c6e258 100644 --- a/src/java/com/samskivert/depot/Exps.java +++ b/src/java/com/samskivert/depot/Exps.java @@ -20,12 +20,7 @@ package com.samskivert.depot; -import com.samskivert.depot.expression.EpochSeconds; -import com.samskivert.depot.expression.FunctionExp; -import com.samskivert.depot.expression.IntervalExp; -import com.samskivert.depot.expression.LiteralExp; -import com.samskivert.depot.expression.SQLExpression; -import com.samskivert.depot.expression.ValueExp; +import com.samskivert.depot.expression.*; /** * Provides static methods for expression construction. For example: {@link #literal}, {@link @@ -101,43 +96,9 @@ public class Exps /** * Creates an expression that converts the supplied expression into seconds since the epoch. */ + @SuppressWarnings("deprecation") public static EpochSeconds epochSeconds (SQLExpression expr) { return new EpochSeconds(expr); } - - /** - * Creates an expression that computes the sum of the supplied expression. This would usually - * be used in a FieldOverride and supplied with a ColumnExp. - */ - public static FunctionExp sum (SQLExpression expr) - { - return new FunctionExp("sum", expr); - } - - /** - * Creates an expression that computes the absolute value of the supplied expression. - */ - public static FunctionExp abs (SQLExpression expr) - { - return new FunctionExp("abs", expr); - } - - /** - * Creates an expression that counts the number of rows that match the supplied expression. - * This would usually be used in a FieldOverride and supplied with a ColumnExp. - */ - public static FunctionExp count (SQLExpression expr) - { - return new FunctionExp("count", expr); - } - - /** - * Creates an expression that counts the number of distinct values that match the supplied - * expression. This would usually be used in a FieldOverride and supplied with a ColumnExp. - */ - public static FunctionExp countDistinct (SQLExpression expr) - { - return new FunctionExp("count", "distinct", expr); - } } diff --git a/src/java/com/samskivert/depot/Funs.java b/src/java/com/samskivert/depot/Funs.java new file mode 100644 index 0000000..9677d7d --- /dev/null +++ b/src/java/com/samskivert/depot/Funs.java @@ -0,0 +1,400 @@ +// +// $Id: Exps.java 505 2009-08-07 01:58:58Z samskivert $ +// +// Depot library - a Java relational persistence library +// Copyright (C) 2006-2009 Michael Bayne and Pär Winzell +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +package com.samskivert.depot; + +import com.samskivert.depot.expression.SQLExpression; +import com.samskivert.depot.function.AggregateFun.*; +import com.samskivert.depot.function.ConditionalFun.*; +import com.samskivert.depot.function.DateFun.*; +import com.samskivert.depot.function.DateFun.DatePart.Part; +import com.samskivert.depot.function.DateFun.DateTruncate.Truncation; +import com.samskivert.depot.function.NumericalFun.*; +import com.samskivert.depot.function.StringFun.*; + +/** + * Provides static methods for function construction. For example: {@link #round}, {@link + * #count} and {@link #length}. + */ +public class Funs +{ + /** + * Creates an expression that computes the absolute value of the supplied expression. + */ + public static Abs abs (SQLExpression expr) + { + return new Abs(expr); + } + + /** + * Creates an expression that computes the integer ceiling of the supplied expression. + */ + public static Ceil ceil (SQLExpression exp) + { + return new Ceil(exp); + } + + /** + * Creates an expression that computes the exponential of the supplied expression. + */ + public static Exp exp (SQLExpression exp) + { + return new Exp(exp); + } + + /** + * Creates an expression that computes the integer floor of the supplied expression. + */ + public static Floor floor (SQLExpression exp) + { + return new Floor(exp); + } + + /** + * Creates an expression that computes the natural logarithm of the supplied expression. + */ + public static Ln ln (SQLExpression exp) + { + return new Ln(exp); + } + + /** + * Creates an expression that computes the base-10 logarithm of the supplied expression. + */ + public static LogN log10 (SQLExpression value) + { + return new LogN(Exps.value(10), value); + } + + /** + * Creates an expression that computes the logarithm of the supplied value expression + * in the supplied base expression. + */ + public static LogN logN (SQLExpression base, SQLExpression value) + { + return new LogN(base, value); + } + + /** + * Creates an expression that evaluates to the constant PI. + */ + public static Pi pi () + { + return new Pi(); + } + + /** + * Creates an expression that computes the value expression to the given power. + */ + public static Power power (SQLExpression value, SQLExpression power) + { + return new Power(value, power); + } + + /** + * Creates an expression that returns a random number between 0.0 and 1.0. + */ + public static Random random () + { + return new Random(); + } + + /** + * Creates an expression that computes the whole number nearest the supplied expression. + */ + public static Round round (SQLExpression exp) + { + return new Round(exp); + } + + /** + * Creates an expression that computes the sign of the supplied expression. + */ + public static Sign sign (SQLExpression exp) + { + return new Sign(exp); + } + + /** + * Creates an expression that computes the square root of the supplied expression. + */ + public static Sqrt sqrt (SQLExpression 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. + */ + public static Trunc trunc (SQLExpression exp) + { + return new Trunc(exp); + } + + /** + * Creates an expression that evaluates to the string length of the supplied expression. + */ + public static Length length (SQLExpression exp) + { + return new Length(exp); + } + + /** + * Creates an expression that down-cases the supplied expression. + */ + public static Lower lower (SQLExpression exp) + { + return new Lower(exp); + } + + /** + * Creates an expression that locates the given substring expression within the given + * string expression and returns the index. + */ + public static Position position (SQLExpression substring, SQLExpression string) + { + return new Position(substring, string); + } + + /** + * 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 Substring substring ( + SQLExpression string, SQLExpression from, SQLExpression count) + { + return new Substring(string, from, count); + } + + /** + * Creates an expression that removes whitespace from the beginning and end of the supplied + * string expression. + */ + public static Trim trim (SQLExpression exp) + { + return new Trim(exp); + } + + /** + * Creates an expression that up-cases the supplied string expression. + */ + public static Upper upper (SQLExpression exp) + { + return new Upper(exp); + } + + /** + * Creates an expression that truncates the given timestamp expression to a date. + */ + public static DateTruncate truncToDay (SQLExpression exp) + { + return new DateTruncate(exp, Truncation.DAY); + } + + /** + * Creates an expression to extract the day-of-month from the the supplied timestamp expression. + */ + public static DatePart dayOfMonth (SQLExpression exp) + { + return new DatePart(exp, Part.DAY_OF_MONTH); + } + + /** + * Creates an expression to extract the day-of-week from the the supplied timestamp expression. + */ + public static DatePart dayOfWeek (SQLExpression exp) + { + return new DatePart(exp, Part.DAY_OF_WEEK); + } + + /** + * Creates an expression to extract the day-of-year from the the supplied timestamp expression. + */ + public static DatePart dayOfYear (SQLExpression exp) + { + return new DatePart(exp, Part.DAY_OF_YEAR); + } + + /** + * Creates an expression to extract the hour of the the supplied timestamp expression. + */ + public static DatePart dateHour (SQLExpression exp) + { + return new DatePart(exp, Part.HOUR); + } + + /** + * Creates an expression to extract the minute of the the supplied timestamp expression. + */ + public static DatePart dateMinute (SQLExpression exp) + { + return new DatePart(exp, Part.MINUTE); + } + + /** + * Creates an expression to extract the month of the the supplied timestamp expression. + */ + public static DatePart dateMonth (SQLExpression exp) + { + return new DatePart(exp, Part.MONTH); + } + + /** + * Creates an expression to extract the second of the the supplied timestamp expression. + */ + public static DatePart dateSecond (SQLExpression exp) + { + return new DatePart(exp, Part.SECOND); + } + + /** + * Creates an expression to extract the week of the the supplied timestamp expression. + */ + public static DatePart dateWeek (SQLExpression exp) + { + return new DatePart(exp, Part.WEEK); + } + + /** + * Creates an expression to extract the year of the the supplied timestamp expression. + */ + public static DatePart dateYear (SQLExpression exp) + { + return new DatePart(exp, Part.YEAR); + } + + /** + * Creates an expression to extract the epoch (aka unix timestamp, aka seconds passed since + * 1970-01-01) of the the supplied timestamp expression. + */ + public static DatePart dateEpoch (SQLExpression exp) + { + return new DatePart(exp, Part.EPOCH); + } + + /** + * Creates an expression for the current timestamp. + */ + public static Now now () + { + return new Now(); + } + + /** + * 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. + */ + public static Average average (SQLExpression 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. + */ + public static Average averageDistinct (SQLExpression expr) + { + return new Average(expr, true); + } + + /** + * Creates an aggregate expression that counts the number of rows from the supplied + * expression. This would usually be used in a FieldOverride and supplied with a ColumnExp. + */ + public static Count count (SQLExpression expr) + { + return new Count(expr); + } + + /** + * Creates an aggregate expression that counts the number of distinct values from the + * supplied expression. This would usually be used in a FieldOverride and supplied with a + * ColumnExp. + */ + public static Count countDistinct (SQLExpression expr) + { + return new Count(expr, true); + } + + /** + * Creates an aggregate expression that evaluates to true iff every value from the supplied + * expression is also true. This would usually be used in a FieldOverride and supplied with + * a ColumnExp. + */ + public static Every every (SQLExpression expr) + { + return new Every(expr); + } + + /** + * Creates an aggregate expression that finds the largest value in the values from the + * supplied expression. This would usually be used in a FieldOverride and supplied with + * a ColumnExp. + */ + public static Max max (SQLExpression expr) + { + return new Max(expr); + } + + /** + * Creates an aggregate expression that finds the largest value in the values from the + * supplied expression. This would usually be used in a FieldOverride and supplied with + * a ColumnExp. + */ + public static Min min (SQLExpression expr) + { + return new Min(expr); + } + + /** + * 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. + */ + public static Sum sum (SQLExpression expr) + { + return new Sum(expr); + } + + /** + * Creates an expression that evaluates to the first supplied expression that is not null. + */ + public static Coalesce coalesce (SQLExpression... args) + { + return new Coalesce(args); + } + + /** + * Creates an expression that evaluates to the largest of the given expressions. + */ + public static Greatest greatest (SQLExpression... args) + { + return new Greatest(args); + } + + /** + * Creates an expression that evaluates to the smallest of the given expressions. + */ + public static Least least (SQLExpression... args) + { + return new Least(args); + } +} diff --git a/src/java/com/samskivert/depot/expression/ArgumentExp.java b/src/java/com/samskivert/depot/expression/ArgumentExp.java new file mode 100644 index 0000000..7b4bba0 --- /dev/null +++ b/src/java/com/samskivert/depot/expression/ArgumentExp.java @@ -0,0 +1,47 @@ +// +// $Id: $ +// +// Depot library - a Java relational persistence library +// Copyright (C) 2006-2009 Michael Bayne and Pär Winzell +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +package com.samskivert.depot.expression; + +import java.util.Collection; + +import com.samskivert.depot.PersistentRecord; + +public abstract class ArgumentExp extends FluentExp +{ + protected ArgumentExp (SQLExpression... args) + { + _args = args; + } + + public void addClasses (Collection> classSet) + { + for (SQLExpression arg : _args) { + arg.addClasses(classSet); + } + } + + public SQLExpression[] getArgs () + { + return _args; + } + + protected SQLExpression[] _args; +} diff --git a/src/java/com/samskivert/depot/expression/EpochSeconds.java b/src/java/com/samskivert/depot/expression/EpochSeconds.java index cdb879b..f939420 100644 --- a/src/java/com/samskivert/depot/expression/EpochSeconds.java +++ b/src/java/com/samskivert/depot/expression/EpochSeconds.java @@ -28,6 +28,7 @@ import com.samskivert.depot.impl.ExpressionVisitor; /** * An expression for extracting the seconds since the epoch from a date expression. */ +@Deprecated public class EpochSeconds extends FluentExp { /** diff --git a/src/java/com/samskivert/depot/expression/FunctionExp.java b/src/java/com/samskivert/depot/expression/FunctionExp.java index a86c6ba..e8939cf 100644 --- a/src/java/com/samskivert/depot/expression/FunctionExp.java +++ b/src/java/com/samskivert/depot/expression/FunctionExp.java @@ -30,6 +30,7 @@ import com.samskivert.depot.impl.ExpressionVisitor; /** * An expression for a function, e.g. FLOOR(blah). */ +@Deprecated public class FunctionExp extends FluentExp { /** diff --git a/src/java/com/samskivert/depot/function/AggregateFun.java b/src/java/com/samskivert/depot/function/AggregateFun.java new file mode 100644 index 0000000..c640d84 --- /dev/null +++ b/src/java/com/samskivert/depot/function/AggregateFun.java @@ -0,0 +1,113 @@ +// +// $Id: $ +// +// Depot library - a Java relational persistence library +// Copyright (C) 2006-2009 Michael Bayne and Pär Winzell +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +package com.samskivert.depot.function; + +import com.samskivert.depot.expression.SQLExpression; +import com.samskivert.depot.impl.ExpressionVisitor; + +public abstract class AggregateFun extends OneArgFun +{ + public static class Average extends AggregateFun { + public Average (SQLExpression argument) { + this(argument, false); + } + public Average (SQLExpression argument, boolean distinct) { + super(argument, distinct); + } + public Object accept (ExpressionVisitor visitor) { + return visitor.visit(this); + } + } + + public static class Count extends AggregateFun { + public Count (SQLExpression argument) { + this(argument, false); + } + public Count (SQLExpression argument, boolean distinct) { + super(argument, distinct); + } + public Object accept (ExpressionVisitor visitor) { + return visitor.visit(this); + } + } + + public static class Every extends AggregateFun { + public Every (SQLExpression argument) { + this(argument, false); + } + public Every (SQLExpression argument, boolean distinct) { + super(argument, distinct); + } + public Object accept (ExpressionVisitor visitor) { + return visitor.visit(this); + } + } + + public static class Max extends AggregateFun { + public Max (SQLExpression argument) { + this(argument, false); + } + public Max (SQLExpression argument, boolean distinct) { + super(argument, distinct); + } + public Object accept (ExpressionVisitor visitor) { + return visitor.visit(this); + } + } + + public static class Min extends AggregateFun { + public Min (SQLExpression argument) { + this(argument, false); + } + public Min (SQLExpression argument, boolean distinct) { + super(argument, distinct); + } + public Object accept (ExpressionVisitor visitor) { + return visitor.visit(this); + } + } + + public static class Sum extends AggregateFun { + public Sum (SQLExpression argument) { + this(argument, false); + } + public Sum (SQLExpression argument, boolean distinct) { + super(argument, distinct); + } + public Object accept (ExpressionVisitor visitor) { + return visitor.visit(this); + } + } + + public AggregateFun (SQLExpression argument, boolean distinct) + { + super(argument); + _distinct = distinct; + } + + public boolean isDistinct () + { + return _distinct; + } + + protected boolean _distinct; + +} diff --git a/src/java/com/samskivert/depot/function/ConditionalFun.java b/src/java/com/samskivert/depot/function/ConditionalFun.java new file mode 100644 index 0000000..d0e7160 --- /dev/null +++ b/src/java/com/samskivert/depot/function/ConditionalFun.java @@ -0,0 +1,55 @@ +// +// $Id: $ +// +// Depot library - a Java relational persistence library +// Copyright (C) 2006-2009 Michael Bayne and Pär Winzell +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +package com.samskivert.depot.function; + +import com.samskivert.depot.expression.ArgumentExp; +import com.samskivert.depot.expression.SQLExpression; +import com.samskivert.depot.impl.ExpressionVisitor; + +public abstract class ConditionalFun +{ + public static class Coalesce extends ArgumentExp { + public Coalesce (SQLExpression... args) { + super(args); + } + public Object accept (ExpressionVisitor visitor) { + return visitor.visit(this); + } + } + + public static class Greatest extends ArgumentExp { + public Greatest (SQLExpression... args) { + super(args); + } + public Object accept (ExpressionVisitor visitor) { + return visitor.visit(this); + } + } + + public static class Least extends ArgumentExp { + public Least (SQLExpression... args) { + super(args); + } + public Object accept (ExpressionVisitor visitor) { + return visitor.visit(this); + } + } +} diff --git a/src/java/com/samskivert/depot/function/DateFun.java b/src/java/com/samskivert/depot/function/DateFun.java new file mode 100644 index 0000000..b1a5a46 --- /dev/null +++ b/src/java/com/samskivert/depot/function/DateFun.java @@ -0,0 +1,76 @@ +// +// $Id: $ +// +// Depot library - a Java relational persistence library +// Copyright (C) 2006-2009 Michael Bayne and Pär Winzell +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +package com.samskivert.depot.function; + +import com.samskivert.depot.expression.SQLExpression; +import com.samskivert.depot.impl.ExpressionVisitor; + +public abstract class DateFun +{ + public static class DatePart extends OneArgFun { + public enum Part { + DAY_OF_MONTH, DAY_OF_WEEK, DAY_OF_YEAR, HOUR, MINUTE, MONTH, + SECOND, WEEK, YEAR, EPOCH + }; + public DatePart (SQLExpression date, Part part) { + super(date); + _part = part; + } + public Object accept (ExpressionVisitor visitor) { + return visitor.visit(this); + } + public Part getPart () { + return _part; + } + protected Part _part; + } + + public static class DateTruncate extends OneArgFun { + /** + * The degree of truncation to perform, in time units. Currently only DAY, due to lacking + * MySQL support, but we hope for future versions to match PostgreSQL. + */ + public enum Truncation { + DAY, + }; + /** + * Truncate a SQL timestamp value, currently only to the nearest day (Truncation.DAY) due + * to lacking MySQL support, but we hope for future versions to match PostgreSQL. + */ + public DateTruncate (SQLExpression date, Truncation truncation) { + super(date); + _truncation= truncation; + } + public Object accept (ExpressionVisitor visitor) { + return visitor.visit(this); + } + public Truncation getTruncation () { + return _truncation; + } + protected Truncation _truncation; + } + + public static class Now extends NoArgFun { + public Object accept (ExpressionVisitor visitor) { + return visitor.visit(this); + } + } +} diff --git a/src/java/com/samskivert/depot/function/NoArgFun.java b/src/java/com/samskivert/depot/function/NoArgFun.java new file mode 100644 index 0000000..5679ef7 --- /dev/null +++ b/src/java/com/samskivert/depot/function/NoArgFun.java @@ -0,0 +1,34 @@ +// +// $Id: $ +// +// Depot library - a Java relational persistence library +// Copyright (C) 2006-2009 Michael Bayne and Pär Winzell +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +package com.samskivert.depot.function; + +import java.util.Collection; + +import com.samskivert.depot.PersistentRecord; +import com.samskivert.depot.expression.FluentExp; + +public abstract class NoArgFun extends FluentExp +{ + public void addClasses (Collection> classSet) + { + // nothing to add + } +} diff --git a/src/java/com/samskivert/depot/function/NumericalFun.java b/src/java/com/samskivert/depot/function/NumericalFun.java new file mode 100644 index 0000000..1cd2179 --- /dev/null +++ b/src/java/com/samskivert/depot/function/NumericalFun.java @@ -0,0 +1,150 @@ +// +// $Id: $ +// +// Depot library - a Java relational persistence library +// Copyright (C) 2006-2009 Michael Bayne and Pär Winzell +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +package com.samskivert.depot.function; + +import com.samskivert.depot.expression.SQLExpression; +import com.samskivert.depot.impl.ExpressionVisitor; + +public abstract class NumericalFun +{ + public static class Abs extends OneArgFun { + public Abs (SQLExpression argument) { + super(argument); + } + public Object accept (ExpressionVisitor visitor) { + return visitor.visit(this); + } + } + + public static class Ceil extends OneArgFun { + public Ceil (SQLExpression argument) { + super(argument); + } + public Object accept (ExpressionVisitor visitor) { + return visitor.visit(this); + } + } + + public static class Exp extends OneArgFun { + public Exp (SQLExpression argument) { + super(argument); + } + public Object accept (ExpressionVisitor visitor) { + return visitor.visit(this); + } + } + + public static class Floor extends OneArgFun { + public Floor (SQLExpression argument) { + super(argument); + } + public Object accept (ExpressionVisitor visitor) { + return visitor.visit(this); + } + } + + public static class Ln extends OneArgFun { + public Ln (SQLExpression argument) { + super(argument); + } + public Object accept (ExpressionVisitor visitor) { + return visitor.visit(this); + } + } + + public static class LogN extends TwoArgFun { + public LogN (SQLExpression base, SQLExpression value) { + super(base, value); + } + public Object accept (ExpressionVisitor visitor) { + return visitor.visit(this); + } + public SQLExpression getBase () { + return _arg1; + } + public SQLExpression getValue () { + return _arg2; + } + } + + public static class Pi extends NoArgFun { + public Object accept (ExpressionVisitor visitor) { + return visitor.visit(this); + } + } + + public static class Power extends TwoArgFun { + public Power (SQLExpression value, SQLExpression power) { + super(value, power); + } + public Object accept (ExpressionVisitor visitor) { + return visitor.visit(this); + } + public SQLExpression getValue () { + return _arg1; + } + public SQLExpression getPower () { + return _arg2; + } + } + + public static class Random extends NoArgFun { + public Object accept (ExpressionVisitor visitor) { + return visitor.visit(this); + } + } + + public static class Round extends OneArgFun { + public Round (SQLExpression argument) { + super(argument); + } + public Object accept (ExpressionVisitor visitor) { + return visitor.visit(this); + } + } + + public static class Sign extends OneArgFun { + public Sign (SQLExpression argument) { + super(argument); + } + public Object accept (ExpressionVisitor visitor) { + return visitor.visit(this); + } + } + + public static class Sqrt extends OneArgFun { + public Sqrt (SQLExpression argument) { + super(argument); + } + public Object accept (ExpressionVisitor visitor) { + return visitor.visit(this); + } + } + + public static class Trunc extends OneArgFun { + public Trunc (SQLExpression argument) { + super(argument); + } + public Object accept (ExpressionVisitor visitor) { + return visitor.visit(this); + } + } +} diff --git a/src/java/com/samskivert/depot/function/OneArgFun.java b/src/java/com/samskivert/depot/function/OneArgFun.java new file mode 100644 index 0000000..2eb7968 --- /dev/null +++ b/src/java/com/samskivert/depot/function/OneArgFun.java @@ -0,0 +1,47 @@ +// +// $Id: $ +// +// Depot library - a Java relational persistence library +// Copyright (C) 2006-2009 Michael Bayne and Pär Winzell +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +package com.samskivert.depot.function; + +import java.util.Collection; + +import com.samskivert.depot.PersistentRecord; +import com.samskivert.depot.expression.FluentExp; +import com.samskivert.depot.expression.SQLExpression; + +public abstract class OneArgFun extends FluentExp +{ + protected OneArgFun (SQLExpression argument) + { + _argument = argument; + } + + public void addClasses (Collection> classSet) + { + _argument.addClasses(classSet); + } + + public SQLExpression getArg () + { + return _argument; + } + + protected SQLExpression _argument; +} diff --git a/src/java/com/samskivert/depot/function/StringFun.java b/src/java/com/samskivert/depot/function/StringFun.java new file mode 100644 index 0000000..3b906e6 --- /dev/null +++ b/src/java/com/samskivert/depot/function/StringFun.java @@ -0,0 +1,88 @@ +// +// $Id: $ +// +// Depot library - a Java relational persistence library +// Copyright (C) 2006-2009 Michael Bayne and Pär Winzell +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +package com.samskivert.depot.function; + +import com.samskivert.depot.expression.ArgumentExp; +import com.samskivert.depot.expression.SQLExpression; +import com.samskivert.depot.impl.ExpressionVisitor; + +public abstract class StringFun +{ + public static class Length extends OneArgFun { + public Length (SQLExpression argument) { + super(argument); + } + public Object accept (ExpressionVisitor visitor) { + return visitor.visit(this); + } + } + + public static class Lower extends OneArgFun { + public Lower (SQLExpression argument) { + super(argument); + } + public Object accept (ExpressionVisitor visitor) { + return visitor.visit(this); + } + } + + public static class Position extends TwoArgFun { + public Position (SQLExpression substring, SQLExpression string) { + super(substring, string); + } + public Object accept (ExpressionVisitor visitor) { + return visitor.visit(this); + } + public SQLExpression getSubString () { + return _arg1; + } + public SQLExpression getString () { + return _arg2; + } + } + + public static class Substring extends ArgumentExp { + public Substring (SQLExpression string, SQLExpression from, SQLExpression count) { + super(string, from, count); + } + public Object accept (ExpressionVisitor visitor) { + return visitor.visit(this); + } + } + + public static class Trim extends OneArgFun { + public Trim (SQLExpression argument) { + super(argument); + } + public Object accept (ExpressionVisitor visitor) { + return visitor.visit(this); + } + } + + public static class Upper extends OneArgFun { + public Upper (SQLExpression argument) { + super(argument); + } + public Object accept (ExpressionVisitor visitor) { + return visitor.visit(this); + } + } +} diff --git a/src/java/com/samskivert/depot/function/TwoArgFun.java b/src/java/com/samskivert/depot/function/TwoArgFun.java new file mode 100644 index 0000000..2312f50 --- /dev/null +++ b/src/java/com/samskivert/depot/function/TwoArgFun.java @@ -0,0 +1,44 @@ +// +// $Id: $ +// +// Depot library - a Java relational persistence library +// Copyright (C) 2006-2009 Michael Bayne and Pär Winzell +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +package com.samskivert.depot.function; + +import java.util.Collection; + +import com.samskivert.depot.PersistentRecord; +import com.samskivert.depot.expression.FluentExp; +import com.samskivert.depot.expression.SQLExpression; + +public abstract class TwoArgFun extends FluentExp +{ + protected TwoArgFun (SQLExpression arg1, SQLExpression arg2) + { + _arg1 = arg1; + _arg2 = arg2; + } + + public void addClasses (Collection> classSet) + { + _arg1.addClasses(classSet); + _arg2.addClasses(classSet); + } + + protected SQLExpression _arg1, _arg2; +} diff --git a/src/java/com/samskivert/depot/impl/BuildVisitor.java b/src/java/com/samskivert/depot/impl/BuildVisitor.java index b1b3c68..d770c15 100644 --- a/src/java/com/samskivert/depot/impl/BuildVisitor.java +++ b/src/java/com/samskivert/depot/impl/BuildVisitor.java @@ -48,13 +48,40 @@ import com.samskivert.depot.clause.OrderBy.Order; import com.samskivert.depot.clause.OrderBy; import com.samskivert.depot.clause.SelectClause; import com.samskivert.depot.clause.WhereClause; -import com.samskivert.depot.expression.ColumnExp; -import com.samskivert.depot.expression.EpochSeconds; -import com.samskivert.depot.expression.FunctionExp; -import com.samskivert.depot.expression.IntervalExp; -import com.samskivert.depot.expression.LiteralExp; -import com.samskivert.depot.expression.SQLExpression; -import com.samskivert.depot.expression.ValueExp; +import com.samskivert.depot.expression.*; +import com.samskivert.depot.function.AggregateFun; +import com.samskivert.depot.function.AggregateFun.Average; +import com.samskivert.depot.function.AggregateFun.Count; +import com.samskivert.depot.function.AggregateFun.Every; +import com.samskivert.depot.function.AggregateFun.Max; +import com.samskivert.depot.function.AggregateFun.Min; +import com.samskivert.depot.function.AggregateFun.Sum; +import com.samskivert.depot.function.ConditionalFun.Coalesce; +import com.samskivert.depot.function.ConditionalFun.Greatest; +import com.samskivert.depot.function.ConditionalFun.Least; +import com.samskivert.depot.function.DateFun.DatePart; +import com.samskivert.depot.function.DateFun.DateTruncate; +import com.samskivert.depot.function.DateFun.Now; +import com.samskivert.depot.function.DateFun.DatePart.Part; +import com.samskivert.depot.function.NumericalFun.Abs; +import com.samskivert.depot.function.NumericalFun.Ceil; +import com.samskivert.depot.function.NumericalFun.Exp; +import com.samskivert.depot.function.NumericalFun.Floor; +import com.samskivert.depot.function.NumericalFun.Ln; +import com.samskivert.depot.function.NumericalFun.LogN; +import com.samskivert.depot.function.NumericalFun.Pi; +import com.samskivert.depot.function.NumericalFun.Power; +import com.samskivert.depot.function.NumericalFun.Random; +import com.samskivert.depot.function.NumericalFun.Round; +import com.samskivert.depot.function.NumericalFun.Sign; +import com.samskivert.depot.function.NumericalFun.Sqrt; +import com.samskivert.depot.function.NumericalFun.Trunc; +import com.samskivert.depot.function.StringFun.Length; +import com.samskivert.depot.function.StringFun.Lower; +import com.samskivert.depot.function.StringFun.Position; +import com.samskivert.depot.function.StringFun.Substring; +import com.samskivert.depot.function.StringFun.Trim; +import com.samskivert.depot.function.StringFun.Upper; import com.samskivert.depot.operator.Case; import com.samskivert.depot.operator.Exists; import com.samskivert.depot.operator.FullText; @@ -142,27 +169,21 @@ public abstract class BuildVisitor implements ExpressionVisitor return null; } + @SuppressWarnings("deprecation") public Void visit (FunctionExp functionExp) { - _builder.append(functionExp.getFunction()); - _builder.append("("); + _builder.append(functionExp.getFunction()).append("("); if (functionExp.getAnnotation() != null) { _builder.append(functionExp.getAnnotation()).append(" "); } - SQLExpression[] arguments = functionExp.getArguments(); - for (int ii = 0; ii < arguments.length; ii ++) { - if (ii > 0) { - _builder.append(", "); - } - arguments[ii].accept(this); - } + appendArguments(functionExp.getArguments()); _builder.append(")"); return null; } public Void visit (MultiOperator multiOperator) { - SQLExpression[] conditions = multiOperator.getOperands(); + SQLExpression[] conditions = multiOperator.getArgs(); for (int ii = 0; ii < conditions.length; ii++) { if (ii > 0) { _builder.append(" ").append(multiOperator.operator()).append(" "); @@ -211,7 +232,10 @@ public abstract class BuildVisitor implements ExpressionVisitor return null; } - public abstract Void visit (EpochSeconds seconds); + @SuppressWarnings("deprecation") + public Void visit (EpochSeconds epochSeconds) { + return visit(new DatePart(epochSeconds.getArgument(), Part.EPOCH)); + } public abstract Void visit (FullText.Match match); public abstract Void visit (FullText.Rank rank); @@ -565,18 +589,211 @@ public abstract class BuildVisitor implements ExpressionVisitor return null; } - protected void bindValue (Object object) + // + // NUMERICAL FUNCTIONS + + public Void visit (Abs exp) + { + return appendFunctionCall("abs", exp.getArg()); + } + + public Void visit (Ceil exp) + { + return appendFunctionCall("ceil", exp.getArg()); + } + + public Void visit (Exp exp) + { + return appendFunctionCall("exp", exp.getArg()); + } + + public Void visit (Floor exp) + { + return appendFunctionCall("floor", exp.getArg()); + } + + public Void visit (Ln exp) + { + return appendFunctionCall("ln", exp.getArg()); + } + + public Void visit (LogN exp) + { + return appendFunctionCall("log", exp.getBase(), exp.getValue()); + } + + public Void visit (Pi exp) + { + return appendFunctionCall("PI"); + } + + public Void visit (Power exp) + { + return appendFunctionCall("power", exp.getPower(), exp.getValue()); + } + + public Void visit (Random exp) + { + return appendFunctionCall("random"); + } + + public Void visit (Round exp) + { + return appendFunctionCall("round", exp.getArg()); + } + + public Void visit (Sign exp) + { + return appendFunctionCall("sign", exp.getArg()); + } + + public Void visit (Sqrt exp) + { + return appendFunctionCall("sqrt", exp.getArg()); + } + + public Void visit (Trunc exp) + { + return appendFunctionCall("trunc", exp.getArg()); + } + + // + // STRING FUNCTIONS + + public Void visit (Length exp) + { + return appendFunctionCall("length", exp.getArg()); + } + + public Void visit (Lower exp) + { + return appendFunctionCall("lower", exp.getArg()); + } + + public Void visit (Position exp) + { + _builder.append(" position(").append(exp.getSubString()).append(" in "). + append(exp.getString()).append(")"); + return null; + } + + public Void visit (Substring exp) + { + return appendFunctionCall("substr", exp.getArgs()); + } + + public Void visit (Trim exp) + { + return appendFunctionCall("trim", exp.getArg()); + } + + public Void visit (Upper exp) + { + return appendFunctionCall("upper", exp.getArg()); + } + + public abstract Void visit (DatePart exp); + + public abstract Void visit (DateTruncate exp); + + public Void visit (Now exp) + { + appendFunctionCall("now"); + return null; + } + + public Void visit (Average exp) + { + return appendAggregateFunctionCall("average", exp); + } + + public Void visit (Count exp) + { + return appendAggregateFunctionCall("count", exp); + } + + public Void visit (Every exp) + { + return appendAggregateFunctionCall("every", exp); + } + + public Void visit (Max exp) + { + return appendAggregateFunctionCall("max", exp); + } + + public Void visit (Min exp) + { + return appendAggregateFunctionCall("min", exp); + } + + public Void visit (Sum exp) + { + return appendAggregateFunctionCall("sum", exp); + } + + // + // CONDITIONAL FUNCTIONS + + public Void visit (Coalesce exp) + { + return appendFunctionCall("coalesce", exp.getArgs()); + } + + public Void visit (Greatest exp) + { + return appendFunctionCall("greatest", exp.getArgs()); + } + + public Void visit (Least exp) + { + return appendFunctionCall("least", exp.getArgs()); + } + + protected Void appendAggregateFunctionCall (String function, AggregateFun exp) + { + _builder.append(" ").append(function).append("("); + if (exp.isDistinct()) { + _builder.append("DISTINCT "); + } + appendArguments(exp.getArg()); + _builder.append(")"); + return null; + } + + protected Void appendFunctionCall (String function, SQLExpression... args) + { + _builder.append(" ").append(function).append("("); + appendArguments(args); + _builder.append(")"); + return null; + } + + protected Void appendArguments (SQLExpression... args) + { + for (int ii = 0; ii < args.length; ii ++) { + if (ii > 0) { + _builder.append(", "); + } + (args[ii]).accept(this); + } + return null; + } + + protected Void bindValue (Object object) { _bindables.add(newBindable(object)); _builder.append("?"); + return null; } - protected void bindField ( + protected Void bindField ( Class pClass, ColumnExp field, Object pojo) { final DepotMarshaller marshaller = _types.getMarshaller(pClass); _bindables.add(newBindable(marshaller, field, pojo)); _builder.append("?"); + return null; } protected abstract void appendIdentifier (String field); diff --git a/src/java/com/samskivert/depot/impl/ExpressionEvaluator.java b/src/java/com/samskivert/depot/impl/ExpressionEvaluator.java index 5b98f10..062ba5d 100644 --- a/src/java/com/samskivert/depot/impl/ExpressionEvaluator.java +++ b/src/java/com/samskivert/depot/impl/ExpressionEvaluator.java @@ -37,14 +37,40 @@ import com.samskivert.depot.clause.OrderBy; import com.samskivert.depot.clause.SelectClause; import com.samskivert.depot.clause.WhereClause; -import com.samskivert.depot.expression.ColumnExp; -import com.samskivert.depot.expression.EpochSeconds; -import com.samskivert.depot.expression.FunctionExp; -import com.samskivert.depot.expression.IntervalExp; -import com.samskivert.depot.expression.LiteralExp; -import com.samskivert.depot.expression.SQLExpression; +import com.samskivert.depot.expression.*; import com.samskivert.depot.expression.SQLExpression.NoValue; -import com.samskivert.depot.expression.ValueExp; + +import com.samskivert.depot.function.AggregateFun.Average; +import com.samskivert.depot.function.AggregateFun.Count; +import com.samskivert.depot.function.AggregateFun.Every; +import com.samskivert.depot.function.AggregateFun.Max; +import com.samskivert.depot.function.AggregateFun.Min; +import com.samskivert.depot.function.AggregateFun.Sum; +import com.samskivert.depot.function.ConditionalFun.Coalesce; +import com.samskivert.depot.function.ConditionalFun.Greatest; +import com.samskivert.depot.function.ConditionalFun.Least; +import com.samskivert.depot.function.DateFun.DatePart; +import com.samskivert.depot.function.DateFun.DateTruncate; +import com.samskivert.depot.function.DateFun.Now; +import com.samskivert.depot.function.NumericalFun.Abs; +import com.samskivert.depot.function.NumericalFun.Ceil; +import com.samskivert.depot.function.NumericalFun.Exp; +import com.samskivert.depot.function.NumericalFun.Floor; +import com.samskivert.depot.function.NumericalFun.Ln; +import com.samskivert.depot.function.NumericalFun.LogN; +import com.samskivert.depot.function.NumericalFun.Pi; +import com.samskivert.depot.function.NumericalFun.Power; +import com.samskivert.depot.function.NumericalFun.Random; +import com.samskivert.depot.function.NumericalFun.Round; +import com.samskivert.depot.function.NumericalFun.Sign; +import com.samskivert.depot.function.NumericalFun.Sqrt; +import com.samskivert.depot.function.NumericalFun.Trunc; +import com.samskivert.depot.function.StringFun.Length; +import com.samskivert.depot.function.StringFun.Lower; +import com.samskivert.depot.function.StringFun.Position; +import com.samskivert.depot.function.StringFun.Substring; +import com.samskivert.depot.function.StringFun.Trim; +import com.samskivert.depot.function.StringFun.Upper; import com.samskivert.depot.operator.Case; import com.samskivert.depot.operator.Exists; @@ -65,7 +91,11 @@ import com.samskivert.util.Tuple; import static com.samskivert.depot.Log.log; /** - * Enumerates visitation methods for every possible SQL expression type. + * Attempts to compute the actual values different SQL constructs would yield if they were + * actually send to the database to operate on rows, rather than on in-memory data objects. + * + * TODO: Many of the classes in com.samskivert.depot.functions.* have excellent implementations + * TODO: that should be written. */ public class ExpressionEvaluator implements ExpressionVisitor @@ -76,6 +106,7 @@ public class ExpressionEvaluator _pRec = pRec; } + @SuppressWarnings("deprecation") public Object visit (FunctionExp functionExp) { SQLExpression[] arguments = functionExp.getArguments(); @@ -94,6 +125,7 @@ public class ExpressionEvaluator return new NoValue("Bad Function: " + functionExp); } + @SuppressWarnings("deprecation") public Object visit (EpochSeconds epochSeconds) { Object result = epochSeconds.getArgument().accept(this); @@ -105,7 +137,7 @@ public class ExpressionEvaluator public Object visit (MultiOperator multiOperator) { - SQLExpression[] operands = multiOperator.getOperands(); + SQLExpression[] operands = multiOperator.getArgs(); Object[] values = new Object[operands.length]; for (int ii = 0; ii < operands.length; ii ++) { values[ii] = operands[ii].accept(this); @@ -329,6 +361,170 @@ public class ExpressionEvaluator throw new IllegalArgumentException("Can't evaluate expression: " + dropIndexClause); } + // + // NUMERICAL FUNCTIONS + + public Void visit (Abs exp) + { + throw new IllegalArgumentException("Can't evaluate expression: " + exp); + } + + public Void visit (Ceil exp) + { + throw new IllegalArgumentException("Can't evaluate expression: " + exp); + } + + public Void visit (Exp exp) + { + throw new IllegalArgumentException("Can't evaluate expression: " + exp); + } + + public Void visit (Floor exp) + { + throw new IllegalArgumentException("Can't evaluate expression: " + exp); + } + + public Void visit (Ln exp) + { + throw new IllegalArgumentException("Can't evaluate expression: " + exp); + } + + public Void visit (LogN exp) + { + throw new IllegalArgumentException("Can't evaluate expression: " + exp); + } + + public Void visit (Pi exp) + { + throw new IllegalArgumentException("Can't evaluate expression: " + exp); + } + + public Void visit (Power exp) + { + throw new IllegalArgumentException("Can't evaluate expression: " + exp); + } + + public Void visit (Random exp) + { + throw new IllegalArgumentException("Can't evaluate expression: " + exp); + } + + public Void visit (Round exp) + { + throw new IllegalArgumentException("Can't evaluate expression: " + exp); + } + + public Void visit (Sign exp) + { + throw new IllegalArgumentException("Can't evaluate expression: " + exp); + } + + public Void visit (Sqrt exp) + { + throw new IllegalArgumentException("Can't evaluate expression: " + exp); + } + + public Void visit (Trunc exp) + { + throw new IllegalArgumentException("Can't evaluate expression: " + exp); + } + + // + // STRING FUNCTIONS + + public Void visit (Length exp) + { + throw new IllegalArgumentException("Can't evaluate expression: " + exp); + } + + public Void visit (Lower exp) + { + throw new IllegalArgumentException("Can't evaluate expression: " + exp); + } + + public Void visit (Position exp) + { + throw new IllegalArgumentException("Can't evaluate expression: " + exp); + } + + public Void visit (Substring exp) + { + throw new IllegalArgumentException("Can't evaluate expression: " + exp); + } + + public Void visit (Trim exp) + { + throw new IllegalArgumentException("Can't evaluate expression: " + exp); + } + + public Void visit (Upper exp) + { + throw new IllegalArgumentException("Can't evaluate expression: " + exp); + } + + public Void visit (DatePart exp) + { + throw new IllegalArgumentException("Can't evaluate expression: " + exp); + } + + public Void visit (DateTruncate exp) + { + throw new IllegalArgumentException("Can't evaluate expression: " + exp); + } + + public Void visit (Now exp) + { + throw new IllegalArgumentException("Can't evaluate expression: " + exp); + } + + public Void visit (Average exp) + { + throw new IllegalArgumentException("Can't evaluate expression: " + exp); + } + + public Void visit (Count exp) + { + throw new IllegalArgumentException("Can't evaluate expression: " + exp); + } + + public Void visit (Every exp) + { + throw new IllegalArgumentException("Can't evaluate expression: " + exp); + } + + public Void visit (Max exp) + { + throw new IllegalArgumentException("Can't evaluate expression: " + exp); + } + + public Void visit (Min exp) + { + throw new IllegalArgumentException("Can't evaluate expression: " + exp); + } + + public Void visit (Sum exp) + { + throw new IllegalArgumentException("Can't evaluate expression: " + exp); + } + + // + // CONDITIONAL FUNCTIONS + + public Void visit (Coalesce exp) + { + throw new IllegalArgumentException("Can't evaluate expression: " + exp); + } + + public Void visit (Greatest exp) + { + throw new IllegalArgumentException("Can't evaluate expression: " + exp); + } + + public Void visit (Least exp) + { + throw new IllegalArgumentException("Can't evaluate expression: " + exp); + } + public static Double numerical (Object o) { return (o instanceof Number) ? ((Number) o).doubleValue() : null; diff --git a/src/java/com/samskivert/depot/impl/ExpressionVisitor.java b/src/java/com/samskivert/depot/impl/ExpressionVisitor.java index d2115eb..dcd9b19 100644 --- a/src/java/com/samskivert/depot/impl/ExpressionVisitor.java +++ b/src/java/com/samskivert/depot/impl/ExpressionVisitor.java @@ -33,13 +33,38 @@ import com.samskivert.depot.clause.OrderBy; import com.samskivert.depot.clause.SelectClause; import com.samskivert.depot.clause.WhereClause; -import com.samskivert.depot.expression.ColumnExp; -import com.samskivert.depot.expression.EpochSeconds; -import com.samskivert.depot.expression.FunctionExp; -import com.samskivert.depot.expression.IntervalExp; -import com.samskivert.depot.expression.LiteralExp; -import com.samskivert.depot.expression.ValueExp; - +import com.samskivert.depot.expression.*; +import com.samskivert.depot.function.AggregateFun.Average; +import com.samskivert.depot.function.AggregateFun.Count; +import com.samskivert.depot.function.AggregateFun.Every; +import com.samskivert.depot.function.AggregateFun.Max; +import com.samskivert.depot.function.AggregateFun.Min; +import com.samskivert.depot.function.AggregateFun.Sum; +import com.samskivert.depot.function.ConditionalFun.Coalesce; +import com.samskivert.depot.function.ConditionalFun.Greatest; +import com.samskivert.depot.function.ConditionalFun.Least; +import com.samskivert.depot.function.DateFun.DatePart; +import com.samskivert.depot.function.DateFun.DateTruncate; +import com.samskivert.depot.function.DateFun.Now; +import com.samskivert.depot.function.NumericalFun.Abs; +import com.samskivert.depot.function.NumericalFun.Ceil; +import com.samskivert.depot.function.NumericalFun.Exp; +import com.samskivert.depot.function.NumericalFun.Floor; +import com.samskivert.depot.function.NumericalFun.Ln; +import com.samskivert.depot.function.NumericalFun.LogN; +import com.samskivert.depot.function.NumericalFun.Pi; +import com.samskivert.depot.function.NumericalFun.Power; +import com.samskivert.depot.function.NumericalFun.Random; +import com.samskivert.depot.function.NumericalFun.Round; +import com.samskivert.depot.function.NumericalFun.Sign; +import com.samskivert.depot.function.NumericalFun.Sqrt; +import com.samskivert.depot.function.NumericalFun.Trunc; +import com.samskivert.depot.function.StringFun.Length; +import com.samskivert.depot.function.StringFun.Lower; +import com.samskivert.depot.function.StringFun.Position; +import com.samskivert.depot.function.StringFun.Substring; +import com.samskivert.depot.function.StringFun.Trim; +import com.samskivert.depot.function.StringFun.Upper; import com.samskivert.depot.operator.Case; import com.samskivert.depot.operator.Exists; import com.samskivert.depot.operator.FullText; @@ -60,7 +85,9 @@ import com.samskivert.depot.impl.clause.UpdateClause; public interface ExpressionVisitor { public T visit (FieldDefinition fieldOverride); + @SuppressWarnings("deprecation") public T visit (FunctionExp functionExp); + @SuppressWarnings("deprecation") public T visit (EpochSeconds epochSeconds); public T visit (FromOverride fromOverride); public T visit (MultiOperator multiOperator); @@ -89,4 +116,45 @@ public interface ExpressionVisitor public T visit (CreateIndexClause createIndexClause); public T visit (DropIndexClause dropIndexClause); public T visit (Case caseExp); + + // Numerical + public T visit (Abs exp); + public T visit (Ceil exp); + public T visit (Exp exp); + public T visit (Floor exp); + public T visit (Ln exp); + public T visit (LogN exp); + public T visit (Pi exp); + public T visit (Power exp); + public T visit (Random exp); + public T visit (Round exp); + public T visit (Sign exp); + public T visit (Sqrt exp); + public T visit (Trunc exp); + + // String + public T visit (Length exp); + public T visit (Lower exp); + public T visit (Position exp); + public T visit (Substring exp); + public T visit (Trim exp); + public T visit (Upper exp); + + // Date + public T visit (DatePart exp); + public T visit (DateTruncate exp); + public T visit (Now exp); + + // Aggregation + public T visit (Average exp); + public T visit (Count exp); + public T visit (Every exp); + public T visit (Max exp); + public T visit (Min exp); + public T visit (Sum exp); + + // Conditional + public T visit (Coalesce exp); + public T visit (Greatest exp); + public T visit (Least exp); } diff --git a/src/java/com/samskivert/depot/impl/HSQLBuilder.java b/src/java/com/samskivert/depot/impl/HSQLBuilder.java index d321829..10f83a0 100644 --- a/src/java/com/samskivert/depot/impl/HSQLBuilder.java +++ b/src/java/com/samskivert/depot/impl/HSQLBuilder.java @@ -43,10 +43,11 @@ import com.samskivert.depot.PersistentRecord; import com.samskivert.depot.annotation.FullTextIndex; import com.samskivert.depot.annotation.GeneratedValue; import com.samskivert.depot.clause.OrderBy.Order; -import com.samskivert.depot.expression.ColumnExp; -import com.samskivert.depot.expression.EpochSeconds; -import com.samskivert.depot.expression.FunctionExp; -import com.samskivert.depot.expression.SQLExpression; +import com.samskivert.depot.expression.*; +import com.samskivert.depot.function.DateFun.DatePart; +import com.samskivert.depot.function.DateFun.DateTruncate; +import com.samskivert.depot.function.DateFun.DatePart.Part; +import com.samskivert.depot.function.StringFun.Lower; import com.samskivert.depot.operator.BitAnd; import com.samskivert.depot.operator.BitOr; import com.samskivert.depot.operator.FullText; @@ -82,11 +83,10 @@ public class HSQLBuilder // now iterate over the cartesian product of the query words & the fields List bits = Lists.newArrayList(); - for (int ii = 0; ii < fields.length; ii ++) { - FunctionExp colexp = new FunctionExp("lower", new ColumnExp(pClass, fields[ii])); - for (int jj = 0; jj < ftsWords.length; jj ++) { + for (String field : fields) { + for (String ftsWord : ftsWords) { // build comparisons between each word and column - bits.add(new Like(colexp, "%" + ftsWords[jj] + "%")); + bits.add(new Like(new Lower(new ColumnExp(pClass, field)), "%" + ftsWord + "%")); } } // then just OR them all together and we have our query @@ -105,38 +105,37 @@ public class HSQLBuilder @Override public Void visit (MultiOperator operator) { - String op; // HSQL doesn't handle & and | operators if (operator instanceof BitAnd) { - op = "bitand"; - - } else if (operator instanceof BitOr) { - op = "bitor"; - - } else { - return super.visit(operator); + return appendFunctionCall("bitand", operator.getArgs()); } - - _builder.append(op).append("("); - boolean virgin = true; - for (SQLExpression bit: operator.getOperands()) { - if (!virgin) { - _builder.append(", "); - } - bit.accept(this); - virgin = false; + if (operator instanceof BitOr) { + return appendFunctionCall("bitor", operator.getArgs()); } - _builder.append(")"); - return null; + return super.visit(operator); + } + + @Override @SuppressWarnings("deprecation") + public Void visit (EpochSeconds epochSeconds) + { + return visit (new DatePart(epochSeconds.getArgument(), Part.EPOCH)); + } + + @Override public Void visit (DatePart exp) { + + if (exp.getPart() == Part.EPOCH) { + _builder.append("datediff('ss', "); + exp.getArg().accept(this); + _builder.append(", '1970-01-01')"); + return null; + } + return appendFunctionCall(getDateFunction(exp.getPart()), exp.getArg()); } @Override - public Void visit (EpochSeconds epochSeconds) + public Void visit (DateTruncate exp) { - _builder.append("datediff('ss', "); - epochSeconds.getArgument().accept(this); - _builder.append(", '1970-01-01')"); - return null; + throw new IllegalArgumentException("HSQL does not have built-in date truncation"); } @Override @@ -158,6 +157,31 @@ public class HSQLBuilder super(types); } + protected String getDateFunction (Part part) + { + switch(part) { + case DAY_OF_MONTH: + return "dayofmonth"; + case DAY_OF_WEEK: + return "dayofweek"; + case DAY_OF_YEAR: + return "dayofyear"; + case HOUR: + return "hour"; + case MINUTE: + return "minute"; + case MONTH: + return "month"; + case SECOND: + return "second"; + case WEEK: + return "week"; + case YEAR: + return "year"; + } + throw new IllegalArgumentException("Unknown date part: " + part); + } + @Override protected void appendIdentifier (String field) { _builder.append("\"").append(field).append("\""); } diff --git a/src/java/com/samskivert/depot/impl/MySQLBuilder.java b/src/java/com/samskivert/depot/impl/MySQLBuilder.java index 35b26e6..c23fda0 100644 --- a/src/java/com/samskivert/depot/impl/MySQLBuilder.java +++ b/src/java/com/samskivert/depot/impl/MySQLBuilder.java @@ -35,8 +35,11 @@ import com.samskivert.depot.PersistentRecord; import com.samskivert.depot.annotation.FullTextIndex; import com.samskivert.depot.clause.OrderBy.Order; import com.samskivert.depot.expression.ColumnExp; -import com.samskivert.depot.expression.EpochSeconds; import com.samskivert.depot.expression.SQLExpression; +import com.samskivert.depot.function.DateFun.DatePart; +import com.samskivert.depot.function.DateFun.DateTruncate; +import com.samskivert.depot.function.DateFun.DatePart.Part; +import com.samskivert.depot.function.NumericalFun.Trunc; import com.samskivert.depot.operator.FullText; import com.samskivert.depot.impl.FieldMarshaller.BooleanMarshaller; @@ -90,13 +93,47 @@ public class MySQLBuilder return null; } - @Override - public Void visit (EpochSeconds epochSeconds) + @Override public Void visit (Trunc exp) { - _builder.append("unix_timestamp("); - epochSeconds.getArgument().accept(this); - _builder.append(")"); - return null; + return appendFunctionCall("truncate", exp.getArg()); + } + + @Override public Void visit (DatePart exp) { + return appendFunctionCall(getDateFunction(exp.getPart()), exp.getArg()); + } + + @Override + public Void visit (DateTruncate exp) + { + // exp.getTruncation() is currently always DAY + return appendFunctionCall("date", exp.getArg()); + } + + protected String getDateFunction (Part part) + { + switch(part) { + case DAY_OF_MONTH: + return "dayofmonth"; + case DAY_OF_WEEK: + return "dayofweek"; + case DAY_OF_YEAR: + return "dayofyear"; + case HOUR: + return "hour"; + case MINUTE: + return "minute"; + case MONTH: + return "month"; + case SECOND: + return "second"; + case WEEK: + return "week"; + case YEAR: + return "year"; + case EPOCH: + return "unix_timestamp"; + } + throw new IllegalArgumentException("Unknown date part: " + part); } @Override diff --git a/src/java/com/samskivert/depot/impl/PostgreSQL4Builder.java b/src/java/com/samskivert/depot/impl/PostgreSQL4Builder.java index 9f5ba52..ab3f6d2 100644 --- a/src/java/com/samskivert/depot/impl/PostgreSQL4Builder.java +++ b/src/java/com/samskivert/depot/impl/PostgreSQL4Builder.java @@ -3,7 +3,7 @@ // // Depot library - a Java relational persistence library // Copyright (C) 2006-2008 Michael Bayne and Pär Winzell -// +// // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation; either version 2.1 of the License, or diff --git a/src/java/com/samskivert/depot/impl/PostgreSQLBuilder.java b/src/java/com/samskivert/depot/impl/PostgreSQLBuilder.java index e5f52b9..a13f0f6 100644 --- a/src/java/com/samskivert/depot/impl/PostgreSQLBuilder.java +++ b/src/java/com/samskivert/depot/impl/PostgreSQLBuilder.java @@ -35,11 +35,14 @@ import com.samskivert.jdbc.LiaisonRegistry; import com.samskivert.util.ArrayUtil; import com.samskivert.util.StringUtil; +import com.samskivert.depot.Exps; import com.samskivert.depot.PersistentRecord; import com.samskivert.depot.annotation.FullTextIndex.Configuration; import com.samskivert.depot.annotation.FullTextIndex; -import com.samskivert.depot.expression.EpochSeconds; import com.samskivert.depot.expression.IntervalExp; +import com.samskivert.depot.function.DateFun.DatePart; +import com.samskivert.depot.function.DateFun.DateTruncate; +import com.samskivert.depot.function.DateFun.DatePart.Part; import com.samskivert.depot.operator.FullText; import static com.samskivert.Log.log; @@ -83,11 +86,43 @@ public class PostgreSQLBuilder return null; } - @Override public Void visit (EpochSeconds epochSeconds) { - _builder.append("date_part('epoch', "); - epochSeconds.getArgument().accept(this); - _builder.append(")"); - return null; + @Override public Void visit (DatePart exp) { + return appendFunctionCall( + "date_part", Exps.value(translateDatePart(exp.getPart())), exp.getArg()); + } + + @Override + public Void visit (DateTruncate exp) + { + // exp.getTruncation() is currently always DAY + return appendFunctionCall("date_trunc", Exps.literal("day"), exp.getArg()); + } + + protected String translateDatePart (Part part) + { + switch(part) { + case DAY_OF_MONTH: + return "day"; + case DAY_OF_WEEK: + return "dow"; + case DAY_OF_YEAR: + return "doy"; + case HOUR: + return "hour"; + case MINUTE: + return "minute"; + case MONTH: + return "month"; + case SECOND: + return "second"; + case WEEK: + return "week"; + case YEAR: + return "year"; + case EPOCH: + return "epoch"; + } + throw new IllegalArgumentException("Unknown date part: " + part); } protected FullTextIndex getFTIndex (FullText definition) diff --git a/src/java/com/samskivert/depot/operator/SQLOperator.java b/src/java/com/samskivert/depot/operator/SQLOperator.java index f64ff6b..42e6439 100644 --- a/src/java/com/samskivert/depot/operator/SQLOperator.java +++ b/src/java/com/samskivert/depot/operator/SQLOperator.java @@ -28,7 +28,7 @@ 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.FluentExp; +import com.samskivert.depot.expression.ArgumentExp; import com.samskivert.depot.expression.SQLExpression; import com.samskivert.depot.expression.ValueExp; import com.samskivert.depot.impl.ExpressionVisitor; @@ -47,7 +47,7 @@ public interface SQLOperator extends SQLExpression { public MultiOperator (SQLExpression ... operands) { - _operands = operands; + super(operands); } // from SQLExpression @@ -59,16 +59,11 @@ public interface SQLOperator extends SQLExpression // from SQLExpression public void addClasses (Collection> classSet) { - for (SQLExpression operand : _operands) { + for (SQLExpression operand : _args) { operand.addClasses(classSet); } } - public SQLExpression[] getOperands () - { - return _operands; - } - /** * Returns the text infix to be used to join expressions together. */ @@ -83,7 +78,7 @@ public interface SQLOperator extends SQLExpression public String toString () { StringBuilder builder = new StringBuilder("("); - for (SQLExpression operand : _operands) { + for (SQLExpression operand : _args) { if (builder.length() > 1) { builder.append(operator()); } @@ -91,8 +86,6 @@ public interface SQLOperator extends SQLExpression } return builder.append(")").toString(); } - - protected SQLExpression[] _operands; } /** @@ -102,8 +95,7 @@ public interface SQLOperator extends SQLExpression { public BinaryOperator (SQLExpression lhs, SQLExpression rhs) { - _lhs = lhs; - _rhs = rhs; + super(lhs, rhs); } public BinaryOperator (SQLExpression lhs, Comparable rhs) @@ -117,13 +109,6 @@ public interface SQLOperator extends SQLExpression return builder.visit(this); } - // from SQLExpression - public void addClasses (Collection> classSet) - { - _lhs.addClasses(classSet); - _rhs.addClasses(classSet); - } - public abstract Object evaluate (Object left, Object right); /** @@ -133,25 +118,22 @@ public interface SQLOperator extends SQLExpression public SQLExpression getLeftHandSide () { - return _lhs; + return _args[0]; } public SQLExpression getRightHandSide () { - return _rhs; + return _args[1]; } @Override // from Object public String toString () { - return "(" + _lhs + operator() + _rhs + ")"; + return "(" + _args[0] + operator() + _args[1] + ")"; } - - protected SQLExpression _lhs; - protected SQLExpression _rhs; } - public static abstract class BaseOperator extends FluentExp + public static abstract class BaseOperator extends ArgumentExp implements SQLOperator { public static Function INTEGRAL = new Function() { @@ -196,6 +178,11 @@ public interface SQLOperator extends SQLExpression return v; } + protected BaseOperator (SQLExpression... operands) + { + super(operands); + } + protected static interface Accumulator { T accumulate (T left, T right);