From 8565f5f8077c11d7090213e0a192ec10241af7c9 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 3 Nov 2022 17:33:11 +1300 Subject: [PATCH] Rename TQColumn -> Query.Property and move to api + use with UpdateQuery.set() - Refactor rename TQColumn to Query.Property and move to ebean-api module - Add UpdateQuery.set() methods to use Query.Property (as per #2849) --- ebean-api/src/main/java/io/ebean/Query.java | 7 +++ .../src/main/java/io/ebean/UpdateQuery.java | 48 +++++++++++++++++-- .../server/querydefn/DefaultUpdateQuery.java | 11 +++++ .../io/ebean/typequery/StdExpressions.java | 15 +++--- .../java/io/ebean/typequery/StdFunctions.java | 14 +++--- .../java/io/ebean/typequery/TQColumn.java | 7 --- .../java/io/ebean/typequery/TQProperty.java | 3 +- .../java/io/ebean/typequery/TQRootBean.java | 8 ++-- .../test/java/org/querytest/QOrderTest.java | 17 ++++++- 9 files changed, 101 insertions(+), 29 deletions(-) delete mode 100644 ebean-querybean/src/main/java/io/ebean/typequery/TQColumn.java diff --git a/ebean-api/src/main/java/io/ebean/Query.java b/ebean-api/src/main/java/io/ebean/Query.java index 0d0fe1e5e..495da5977 100644 --- a/ebean-api/src/main/java/io/ebean/Query.java +++ b/ebean-api/src/main/java/io/ebean/Query.java @@ -1768,4 +1768,11 @@ public interface Query extends CancelableQuery { */ Query orderById(boolean orderById); + /** + * Type safe query bean properties and expressions (marker interface). + *

+ * Implemented by query bean properties and expressions based on those properties. + */ + interface Property { + } } diff --git a/ebean-api/src/main/java/io/ebean/UpdateQuery.java b/ebean-api/src/main/java/io/ebean/UpdateQuery.java index 1860fffe9..a7abe00ea 100644 --- a/ebean-api/src/main/java/io/ebean/UpdateQuery.java +++ b/ebean-api/src/main/java/io/ebean/UpdateQuery.java @@ -14,7 +14,7 @@ package io.ebean; * * int rows = DB.update(Customer.class) * .set("status", Customer.Status.ACTIVE) - * .set("updtime", new Timestamp(System.currentTimeMillis())) + * .set("whenUpdated", Instant.now()) * .where() * .gt("id", 1000) * .update(); @@ -25,6 +25,20 @@ package io.ebean; * update o_customer set status=?, updtime=? where id > ? * * } + * + *

Example: Using query bean

+ *
{@code
+ *
+ *   var cust = QCustomer.alias();
+ *
+ *   int rows = new QCustomer()
+ *       .id.gt(1000)
+ *       .asUpdate()
+ *       .set(cust.status, Customer.Status.COMPLETE)
+ *       .set(cust.whenUpdated, Instant.now())
+ *       .update();
+ *
+ * }
*

* Note that if the where() clause contains a join then the SQL update changes to use a * WHERE ID IN () form. @@ -40,7 +54,7 @@ package io.ebean; * * int rows = DB.update(Customer.class) * .set("status", Customer.Status.ACTIVE) - * .set("updtime", new Timestamp(System.currentTimeMillis())) + * .set("whenUpdated", Instant.now()) * .where() * .eq("status", Customer.Status.NEW) * .eq("billingAddress.country", nz) @@ -73,7 +87,7 @@ public interface UpdateQuery { * * int rows = DB.update(Customer.class) * .set("status", Customer.Status.ACTIVE) - * .set("updtime", new Timestamp(System.currentTimeMillis())) + * .set("whenUpdated", Instant.now()) * .where() * .gt("id", 1000) * .update(); @@ -85,6 +99,27 @@ public interface UpdateQuery { */ UpdateQuery set(String property, Object value); + /** + * Set the value of a property. + *

+ *

{@code
+   *
+   *   var cust = QCustomer.alias();
+   *
+   *   int rows = new QCustomer()
+   *       .id.gt(1000)
+   *       .asUpdate()
+   *       .set(cust.status, Customer.Status.COMPLETE)
+   *       .set(cust.whenUpdated, Instant.now())
+   *       .update();
+   *
+   * }
+ * + * @param property The bean property to be set + * @param value The value to set the property to + */ + UpdateQuery set(Query.Property property, Object value); + /** * Set the property to be null. *

@@ -102,6 +137,13 @@ public interface UpdateQuery { */ UpdateQuery setNull(String property); + /** + * Set the property to be null. + * + * @param property The bean property to be set + */ + UpdateQuery setNull(Query.Property property); + /** * Set using a property expression that does not need any bind values. *

diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultUpdateQuery.java b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultUpdateQuery.java index 494f4227a..9b67c22dd 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultUpdateQuery.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultUpdateQuery.java @@ -2,6 +2,7 @@ package io.ebeaninternal.server.querydefn; import io.ebean.ExpressionList; import io.ebean.ProfileLocation; +import io.ebean.Query; import io.ebean.UpdateQuery; import io.ebean.core.type.ScalarType; import io.ebeaninternal.server.deploy.BeanDescriptor; @@ -34,6 +35,16 @@ public final class DefaultUpdateQuery implements UpdateQuery { return this; } + @Override + public UpdateQuery set(Query.Property property, Object value) { + return set(property.toString(), value); + } + + @Override + public UpdateQuery setNull(Query.Property property) { + return setNull(property.toString()); + } + @Override public UpdateQuery setNull(String property) { values.setNull(property); diff --git a/ebean-querybean/src/main/java/io/ebean/typequery/StdExpressions.java b/ebean-querybean/src/main/java/io/ebean/typequery/StdExpressions.java index 8a0b5233c..13498f41b 100644 --- a/ebean-querybean/src/main/java/io/ebean/typequery/StdExpressions.java +++ b/ebean-querybean/src/main/java/io/ebean/typequery/StdExpressions.java @@ -2,34 +2,35 @@ package io.ebean.typequery; import io.ebean.Expr; import io.ebean.Expression; +import io.ebean.Query; public class StdExpressions { - public static Expression gt(TQColumn property, Object value) { + public static Expression gt(Query.Property property, Object value) { return Expr.gt(property.toString(), value); } - public static Expression like(TQColumn property, String value) { + public static Expression like(Query.Property property, String value) { return Expr.like(property.toString(), value); } - public static Expression ilike(TQColumn property, String value) { + public static Expression ilike(Query.Property property, String value) { return Expr.ilike(property.toString(), value); } - public static Expression startsWith(TQColumn property, String value) { + public static Expression startsWith(Query.Property property, String value) { return Expr.startsWith(property.toString(), value); } - public static Expression istartsWith(TQColumn property, String value) { + public static Expression istartsWith(Query.Property property, String value) { return Expr.istartsWith(property.toString(), value); } - public static Expression contains(TQColumn property, String value) { + public static Expression contains(Query.Property property, String value) { return Expr.contains(property.toString(), value); } - public static Expression icontains(TQColumn property, String value) { + public static Expression icontains(Query.Property property, String value) { return Expr.icontains(property.toString(), value); } } diff --git a/ebean-querybean/src/main/java/io/ebean/typequery/StdFunctions.java b/ebean-querybean/src/main/java/io/ebean/typequery/StdFunctions.java index d370c967a..b9c295a22 100644 --- a/ebean-querybean/src/main/java/io/ebean/typequery/StdFunctions.java +++ b/ebean-querybean/src/main/java/io/ebean/typequery/StdFunctions.java @@ -1,16 +1,18 @@ package io.ebean.typequery; +import io.ebean.Query.Property; + public final class StdFunctions { - public static TQColumn max(TQColumn property) { + public static Property max(Property property) { return new Standard("max(" + property + ")"); } - public static TQColumn sum(TQColumn property) { + public static Property sum(Property property) { return new Standard("sum(" + property + ")"); } - public static TQColumn concat(TQColumn property, Object... values) { + public static Property concat(Property property, Object... values) { StringBuilder expression = new StringBuilder(50); expression.append("concat(").append(property.toString()); for (Object value : values) { @@ -20,7 +22,7 @@ public final class StdFunctions { return new Standard(expression.toString()); } - public static TQColumn coalesce(TQColumn property, Object value) { + public static Property coalesce(Property property, Object value) { StringBuilder expression = new StringBuilder(50); expression.append("coalesce(").append(property.toString()).append(","); expression.append(sqlStringExpression(value)); @@ -29,14 +31,14 @@ public final class StdFunctions { } private static String sqlStringExpression(Object value) { - if (value instanceof TQColumn || value instanceof Number) { + if (value instanceof Property || value instanceof Number) { return value.toString(); } else { return "'" + value + "'"; } } - private static class Standard implements TQColumn { + private static class Standard implements Property { private final String expression; diff --git a/ebean-querybean/src/main/java/io/ebean/typequery/TQColumn.java b/ebean-querybean/src/main/java/io/ebean/typequery/TQColumn.java deleted file mode 100644 index dfe5fd9d1..000000000 --- a/ebean-querybean/src/main/java/io/ebean/typequery/TQColumn.java +++ /dev/null @@ -1,7 +0,0 @@ -package io.ebean.typequery; - -/** - * Marker interface for type safe properties and expressions. - */ -public interface TQColumn { -} diff --git a/ebean-querybean/src/main/java/io/ebean/typequery/TQProperty.java b/ebean-querybean/src/main/java/io/ebean/typequery/TQProperty.java index f5d6bfd2e..8cc0e6465 100644 --- a/ebean-querybean/src/main/java/io/ebean/typequery/TQProperty.java +++ b/ebean-querybean/src/main/java/io/ebean/typequery/TQProperty.java @@ -1,13 +1,14 @@ package io.ebean.typequery; import io.ebean.ExpressionList; +import io.ebean.Query; /** * A property used in type query. * * @param The type of the owning root bean */ -public class TQProperty implements TQColumn { +public class TQProperty implements Query.Property { protected final String _name; diff --git a/ebean-querybean/src/main/java/io/ebean/typequery/TQRootBean.java b/ebean-querybean/src/main/java/io/ebean/typequery/TQRootBean.java index 4a98d0c0e..e9dc8d590 100644 --- a/ebean-querybean/src/main/java/io/ebean/typequery/TQRootBean.java +++ b/ebean-querybean/src/main/java/io/ebean/typequery/TQRootBean.java @@ -268,9 +268,9 @@ public abstract class TQRootBean { return root; } - private Set properties(TQColumn[] properties) { + private Set properties(Query.Property[] properties) { Set props = new LinkedHashSet<>(); - for (TQColumn property : properties) { + for (Query.Property property : properties) { props.add(property.toString()); } return props; @@ -278,11 +278,11 @@ public abstract class TQRootBean { /** * Specify the properties to be loaded on the 'main' root level entity bean - * also allowing for functions to be used like {@link StdFunctions#max(TQColumn)}. + * also allowing for functions to be used like {@link StdFunctions#max(Query.Property)}. * * @param properties the list of properties to fetch */ - public final R select(TQColumn... properties) { + public final R select(Query.Property... properties) { ((SpiQueryFetch) query).selectProperties(properties(properties)); return root; } diff --git a/ebean-querybean/src/test/java/org/querytest/QOrderTest.java b/ebean-querybean/src/test/java/org/querytest/QOrderTest.java index 2d9d88e29..24eda0518 100644 --- a/ebean-querybean/src/test/java/org/querytest/QOrderTest.java +++ b/ebean-querybean/src/test/java/org/querytest/QOrderTest.java @@ -4,7 +4,6 @@ import io.ebean.DB; import io.ebean.FetchGroup; import io.ebean.Query; import io.ebean.test.LoggedSql; -import io.ebean.typequery.StdExpressions; import org.example.domain.Customer; import org.example.domain.Order; import org.example.domain.OrderDetail; @@ -221,6 +220,22 @@ public class QOrderTest { } + @Test + public void updateQuery() { + LoggedSql.start(); + new QOrder() + .status.eq(Order.Status.COMPLETE) + .orderDate.gt(new java.sql.Date(System.currentTimeMillis())) + .asUpdate() + .set(QOrder.Alias.version, 42L) + .setNull(QOrder.Alias.orderDate) + .update(); + + List sql = LoggedSql.stop(); + assertThat(sql).hasSize(1); + assertThat(sql.get(0)).contains("update o_order set version=?, order_date=null where status = ? and order_date > ?"); + } + @Test public void stdExpression_iLikeConcatCoalesce() { QOrder o = QOrder.alias();