From 92995b807eb38c61c7a926f078b5ac3a589432fe Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Sat, 22 Feb 2020 10:09:44 +1300 Subject: [PATCH] #1955 - mapToScalar - Add SqlQuery.mapToScalar( ).findOne() / findList() ... to deprecate findSingleAttribute() --- src/main/java/io/ebean/SqlQuery.java | 89 ++++++++++++++----- .../querydefn/DefaultRelationalQuery.java | 29 ++++++ .../java/org/tests/basic/TestTransient.java | 15 ++-- .../org/tests/basic/type/TestSqlRowUUID.java | 2 +- .../tests/query/sqlquery/SqlQueryTests.java | 16 ++-- .../tests/update/TestSqlUpdateExceptions.java | 3 +- 6 files changed, 116 insertions(+), 38 deletions(-) diff --git a/src/main/java/io/ebean/SqlQuery.java b/src/main/java/io/ebean/SqlQuery.java index e0a834867..634538610 100644 --- a/src/main/java/io/ebean/SqlQuery.java +++ b/src/main/java/io/ebean/SqlQuery.java @@ -125,39 +125,36 @@ public interface SqlQuery extends Serializable { Optional findOneOrEmpty(); /** - * Execute the query returning a single scalar attribute. - *
@{code
+   * Deprecated - migrate to .mapToScalar(attributeType).findOne().
+   * 
{@code
    *
-   *   String sql = "select max(unit_price) from o_order_detail where order_qty > ?";
-   *
-   *   BigDecimal maxPrice = DB.sqlQuery(sql)
-   *     .setParameter(42)
-   *     .findSingleAttribute(BigDecimal.class);
-   *
-   * }
- * - *

- * The attributeType can be any scalar type that Ebean supports (includes javax time types, Joda types etc). - *

- * - * @param attributeType The type of the returned value + * .mapToScalar(BigDecimal.class) + * .findOne(); + * } */ + @Deprecated T findSingleAttribute(Class attributeType); /** - * Execute the query returning a single BigDecimal value. - *

- * This is an alias for findSingleAttribute(BigDecimal.class) - *

+ * Deprecated - migrate to .mapToScalar(BigDecimal.class).findOne(). + *
{@code
+   *
+   *    .mapToScalar(BigDecimal.class)
+   *    .findOne();
+   * }
    */
+  @Deprecated
   BigDecimal findSingleDecimal();
 
   /**
-   * Execute the query returning a single Long value.
-   * 

- * This is an alias for findSingleAttribute(Long.class) - *

+ * Deprecated - migrate to .mapToScalar(Long.class).findOne(). + *
{@code
+   *
+   *    .mapToScalar(Long.class)
+   *    .findOne();
+   * }
    */
+  @Deprecated
   Long findSingleLong();
 
   /**
@@ -293,4 +290,50 @@ public interface SqlQuery extends Serializable {
    */
   SqlQuery setBufferFetchSizeHint(int bufferFetchSizeHint);
 
+  /**
+   * The query result maps to a single scalar value like Long, BigDecimal,
+   * String, UUID, OffsetDateTime etc.
+   * 

+ * Any scalar type Ebean is aware of can be used including java time + * types like Instant, LocalDate, OffsetDateTime, UUID, Inet, Cdir etc. + * + *

{@code
+   *
+   *   String sql = " select min(updtime) from o_order_detail " +
+   *                " where unit_price > ? and updtime is not null ";
+   *
+   *   OffsetDateTime minCreated = DB.sqlQuery(sql)
+   *     .setParameter(42)
+   *     .mapToScalar(OffsetDateTime.class)
+   *     .findOne();
+   *
+   * }
+ * + * @param attributeType The type the result is returned as + * @return The query to execute via findOne() findList() etc + */ + ScalarQuery mapToScalar(Class attributeType); + + /** + * Query mapping to single scalar values. + * + * @param The type of the scalar values + */ + interface ScalarQuery { + + /** + * Return the single value. + */ + T findOne(); + + /** + * Return the single value that is optional. + */ + Optional findOneOrEmpty(); + + /** + * Return the list of values. + */ + List findList(); + } } diff --git a/src/main/java/io/ebeaninternal/server/querydefn/DefaultRelationalQuery.java b/src/main/java/io/ebeaninternal/server/querydefn/DefaultRelationalQuery.java index 2c21b7b18..aa29bce24 100644 --- a/src/main/java/io/ebeaninternal/server/querydefn/DefaultRelationalQuery.java +++ b/src/main/java/io/ebeaninternal/server/querydefn/DefaultRelationalQuery.java @@ -2,6 +2,7 @@ package io.ebeaninternal.server.querydefn; import io.ebean.RowConsumer; import io.ebean.RowMapper; +import io.ebean.SqlQuery; import io.ebean.SqlRow; import io.ebeaninternal.api.BindParams; import io.ebeaninternal.api.SpiEbeanServer; @@ -207,4 +208,32 @@ public class DefaultRelationalQuery implements SpiSqlQuery { return query; } + @Override + public ScalarQuery mapToScalar(Class attributeType) { + return new Scalar(attributeType); + } + + private class Scalar implements SqlQuery.ScalarQuery { + + private final Class type; + + Scalar(Class type) { + this.type = type; + } + + @Override + public T findOne() { + return findSingleAttribute(type); + } + + @Override + public Optional findOneOrEmpty() { + return Optional.ofNullable(findOne()); + } + + @Override + public List findList() { + return findSingleAttributeList(type); + } + } } diff --git a/src/test/java/org/tests/basic/TestTransient.java b/src/test/java/org/tests/basic/TestTransient.java index 886695bae..428896ac1 100644 --- a/src/test/java/org/tests/basic/TestTransient.java +++ b/src/test/java/org/tests/basic/TestTransient.java @@ -7,11 +7,12 @@ import org.junit.Test; import org.tests.model.basic.Customer; import java.sql.Types; +import java.util.Optional; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; public class TestTransient extends BaseTestCase { @@ -65,34 +66,34 @@ public class TestTransient extends BaseTestCase { int rows = DB.createUpdate(Customer.class, updateStmt) .setParameter("id", custId).execute(); assertEquals(1, rows); - assertEquals("testTrans2", findNote(custId)); + assertEquals("testTrans2", findNote(custId).get()); rows = DB.createUpdate(Customer.class, "update customer set smallnote = ? where id = ?") .setNull(1, Types.VARCHAR) .setParameter(2, custId).execute(); assertEquals(1, rows); - assertNull(findNote(custId)); + assertThat(findNote(custId)).isEmpty(); rows = DB.createUpdate(Customer.class, "update customer set smallnote = ? where id = ?") .setParameter(1, "Foo") .setParameter(2, custId).execute(); assertEquals(1, rows); - assertEquals("Foo", findNote(custId)); + assertEquals("Foo", findNote(custId).get()); rows = DB.createUpdate(Customer.class, "update customer set smallnote = :name where id = :id") .setNullParameter("name", Types.VARCHAR) .setParameter("id", custId).execute(); assertEquals(1, rows); - assertNull(findNote(custId)); + assertThat(findNote(custId)).isEmpty(); // cleanup DB.delete(Customer.class, custId); } - private String findNote(Integer custId) { + private Optional findNote(Integer custId) { return DB.sqlQuery("select smallnote from o_customer where id = ?") .setParameter(custId) - .findSingleAttribute(String.class); + .mapToScalar(String.class).findOneOrEmpty(); } } diff --git a/src/test/java/org/tests/basic/type/TestSqlRowUUID.java b/src/test/java/org/tests/basic/type/TestSqlRowUUID.java index f2e60c16b..77b67724a 100644 --- a/src/test/java/org/tests/basic/type/TestSqlRowUUID.java +++ b/src/test/java/org/tests/basic/type/TestSqlRowUUID.java @@ -39,7 +39,7 @@ public class TestSqlRowUUID extends BaseTestCase { SqlQuery q2 = DB.sqlQuery("select id from tuuid_entity where id = :id"); q2.setParameter("id", e.getId()); - UUID value = q2.findSingleAttribute(UUID.class); + UUID value = q2.mapToScalar(UUID.class).findOne(); assertThat(value).isEqualTo(e.getId()); diff --git a/src/test/java/org/tests/query/sqlquery/SqlQueryTests.java b/src/test/java/org/tests/query/sqlquery/SqlQueryTests.java index 2631cf405..308e350ff 100644 --- a/src/test/java/org/tests/query/sqlquery/SqlQueryTests.java +++ b/src/test/java/org/tests/query/sqlquery/SqlQueryTests.java @@ -34,7 +34,8 @@ public class SqlQueryTests extends BaseTestCase { List lineAmounts = DB.sqlQuery(sql) .setParameter(3) - .findSingleAttributeList(BigDecimal.class); + .mapToScalar(BigDecimal.class) + .findList(); assertThat(lineAmounts).isNotEmpty(); } @@ -48,7 +49,8 @@ public class SqlQueryTests extends BaseTestCase { BigDecimal maxPrice = DB.sqlQuery(sql) .setParameter(1, 2) - .findSingleDecimal(); + .mapToScalar(BigDecimal.class) + .findOne(); assertThat(maxPrice).isNotNull(); } @@ -62,7 +64,8 @@ public class SqlQueryTests extends BaseTestCase { BigDecimal maxPrice = DB.sqlQuery(sql) .setParameter(2) - .findSingleAttribute(BigDecimal.class); + .mapToScalar(BigDecimal.class) + .findOne(); assertThat(maxPrice).isNotNull(); } @@ -76,7 +79,8 @@ public class SqlQueryTests extends BaseTestCase { long count = DB.sqlQuery(sql) .setParameter(1, 2) - .findSingleLong(); + .mapToScalar(Long.class) + .findOne(); assertThat(count).isGreaterThan(0); } @@ -91,7 +95,7 @@ public class SqlQueryTests extends BaseTestCase { long count = DB.sqlQuery(sql) .setParameter(1, 2) - .findSingleAttribute(Long.class); + .mapToScalar(Long.class).findOne(); assertThat(count).isGreaterThan(0); } @@ -105,7 +109,7 @@ public class SqlQueryTests extends BaseTestCase { OffsetDateTime minCreated = DB.sqlQuery(sql) .setParameter(1, 2) - .findSingleAttribute(OffsetDateTime.class); + .mapToScalar(OffsetDateTime.class).findOne(); assertThat(minCreated).isBefore(OffsetDateTime.now()); } diff --git a/src/test/java/org/tests/update/TestSqlUpdateExceptions.java b/src/test/java/org/tests/update/TestSqlUpdateExceptions.java index 4bca88ea3..8632a9778 100644 --- a/src/test/java/org/tests/update/TestSqlUpdateExceptions.java +++ b/src/test/java/org/tests/update/TestSqlUpdateExceptions.java @@ -27,7 +27,8 @@ public class TestSqlUpdateExceptions extends BaseTestCase { UUID foundId = DB.sqlQuery("select id from uuone where id = ?") .setParameters(id) - .findSingleAttribute(UUID.class); + .mapToScalar(UUID.class) + .findOne(); assertThat(foundId).isEqualTo(id); }