diff --git a/pom.xml b/pom.xml index ac673ed79..19cda5e30 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.29.2-SNAPSHOT + 11.30.1-SNAPSHOT jar ebean diff --git a/src/main/java/io/ebean/ExpressionList.java b/src/main/java/io/ebean/ExpressionList.java index 5a68a6308..a001bcfdb 100644 --- a/src/main/java/io/ebean/ExpressionList.java +++ b/src/main/java/io/ebean/ExpressionList.java @@ -128,6 +128,38 @@ public interface ExpressionList { */ DtoQuery asDto(Class dtoClass); + /** + * Return the underlying query as an UpdateQuery. + *

+ * Typically this is used with query beans to covert a query bean + * query into an UpdateQuery like the examples below. + *

+ * + *
{@code
+   *
+   *  int rowsUpdated = new QCustomer()
+   *       .name.startsWith("Rob")
+   *       .asUpdate()
+   *       .set("active", false)
+   *       .update();;
+   *
+   * }
+ * + *
{@code
+   *
+   *   int rowsUpdated = new QContact()
+   *       .notes.note.startsWith("Make Inactive")
+   *       .email.endsWith("@foo.com")
+   *       .customer.id.equalTo(42)
+   *       .asUpdate()
+   *       .set("inactive", true)
+   *       .setRaw("email = lower(email)")
+   *       .update();
+   *
+   * }
+ */ + UpdateQuery asUpdate(); + /** * Execute using "for update" clause which results in the DB locking the record. */ diff --git a/src/main/java/io/ebean/Query.java b/src/main/java/io/ebean/Query.java index a1d34375d..eb4e0daa4 100644 --- a/src/main/java/io/ebean/Query.java +++ b/src/main/java/io/ebean/Query.java @@ -244,6 +244,38 @@ public interface Query { */ DtoQuery asDto(Class dtoClass); + /** + * Convert the query to a UpdateQuery. + *

+ * Typically this is used with query beans to covert a query bean + * query into an UpdateQuery like the examples below. + *

+ * + *
{@code
+   *
+   *  int rowsUpdated = new QCustomer()
+   *       .name.startsWith("Rob")
+   *       .asUpdate()
+   *       .set("active", false)
+   *       .update();;
+   *
+   * }
+ * + *
{@code
+   *
+   *   int rowsUpdated = new QContact()
+   *       .notes.note.startsWith("Make Inactive")
+   *       .email.endsWith("@foo.com")
+   *       .customer.id.equalTo(42)
+   *       .asUpdate()
+   *       .set("inactive", true)
+   *       .setRaw("email = lower(email)")
+   *       .update();
+   *
+   * }
+ */ + UpdateQuery asUpdate(); + /** * Cancel the query execution if supported by the underlying database and * driver. @@ -1329,7 +1361,6 @@ public interface Query { * count:1 orderStatus:COMPLETE * * } - * */ Query setCountDistinct(CountDistinctOrder orderBy); diff --git a/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionList.java b/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionList.java index 6a64b1b1b..85a8ffb26 100644 --- a/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionList.java +++ b/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionList.java @@ -18,6 +18,7 @@ import io.ebean.Pairs; import io.ebean.Query; import io.ebean.QueryIterator; import io.ebean.Transaction; +import io.ebean.UpdateQuery; import io.ebean.Version; import io.ebean.event.BeanQueryRequest; import io.ebean.search.Match; @@ -302,6 +303,11 @@ public class DefaultExpressionList implements SpiExpressionList { return query.asDto(dtoClass); } + @Override + public UpdateQuery asUpdate() { + return query.asUpdate(); + } + @Override public Query setIncludeSoftDeletes() { return query.setIncludeSoftDeletes(); diff --git a/src/main/java/io/ebeaninternal/server/expression/JunctionExpression.java b/src/main/java/io/ebeaninternal/server/expression/JunctionExpression.java index a4c2206db..e1c5a5a79 100644 --- a/src/main/java/io/ebeaninternal/server/expression/JunctionExpression.java +++ b/src/main/java/io/ebeaninternal/server/expression/JunctionExpression.java @@ -17,6 +17,7 @@ import io.ebean.Pairs; import io.ebean.Query; import io.ebean.QueryIterator; import io.ebean.Transaction; +import io.ebean.UpdateQuery; import io.ebean.Version; import io.ebean.event.BeanQueryRequest; import io.ebean.search.Match; @@ -349,6 +350,11 @@ class JunctionExpression implements SpiJunction, SpiExpression, Expression return exprList.asDto(dtoClass); } + @Override + public UpdateQuery asUpdate() { + return exprList.asUpdate(); + } + @Override public Query setIncludeSoftDeletes() { return exprList.setIncludeSoftDeletes(); diff --git a/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java b/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java index 1f9056c3e..fc43615b3 100644 --- a/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java +++ b/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java @@ -22,6 +22,7 @@ import io.ebean.QueryIterator; import io.ebean.QueryType; import io.ebean.RawSql; import io.ebean.Transaction; +import io.ebean.UpdateQuery; import io.ebean.Version; import io.ebean.bean.CallStack; import io.ebean.bean.ObjectGraphNode; @@ -296,6 +297,11 @@ public class DefaultOrmQuery implements SpiQuery { return server.findDto(dtoClass, this); } + @Override + public UpdateQuery asUpdate() { + return new DefaultUpdateQuery<>(this); + } + @Override public BeanDescriptor getBeanDescriptor() { return beanDescriptor; diff --git a/src/test/java/io/ebean/UpdateQueryTest.java b/src/test/java/io/ebean/UpdateQueryTest.java index 545712bc6..5a5d9b698 100644 --- a/src/test/java/io/ebean/UpdateQueryTest.java +++ b/src/test/java/io/ebean/UpdateQueryTest.java @@ -75,6 +75,29 @@ public class UpdateQueryTest extends BaseTestCase { assertThat(ormQueryMetrics.get(0).getLabel()).isEqualTo("updateAll"); } + @Test + public void query_asUpdate() { + + ResetBasicData.reset(); + + LoggedSqlCollector.start(); + + int rows = server().find(Customer.class) + .where() + .gt("id", 1000) + .asUpdate() + .setRaw("status = status") + .setLabel("asUpdate") + .update(); + + + List sql = LoggedSqlCollector.stop(); + assertThat(sql).hasSize(1); + assertThat(rows).isEqualTo(0); + + assertThat(sql.get(0)).contains("update o_customer set status = status where id > ?"); + } + @Test public void update_withTransactionBatch() {