#1405 - ENH: Add SqlQuery.findSingleAttribute() ... for returning single scalar values via SqlQuery

This commit is contained in:
rob bygrave
2018-06-07 22:17:01 +12:00
parent eba1003c19
commit ffa8268125
12 changed files with 162 additions and 13 deletions
+17
View File
@@ -83,6 +83,23 @@ public interface SqlQuery extends Serializable {
@Nonnull
Optional<SqlRow> findOneOrEmpty();
/**
* Execute the query returning a single scalar attribute.
* <pre>@{code
*
* String sql = "select max(unit_price) from o_order_detail where order_qty > ?";
*
* BigDecimal maxPrice = Ebean.createSqlQuery(sql)
* .setParameter(1, 2)
* .findSingleAttribute(BigDecimal.class);
*
*
* }</pre>
*
* @param attributeType The type of the returned value
*/
<T> T findSingleAttribute(Class<T> attributeType);
/**
* The same as bind for named parameters.
*/
@@ -234,6 +234,11 @@ public interface SpiEbeanServer extends EbeanServer, BeanLoader, BeanCollectionL
*/
void scopedTransactionExit(Object returnOrThrowable, int opCode);
/**
* SqlQuery find single attribute.
*/
<T> T findSingleAttribute(SpiSqlQuery query, Class<T> cls);
/**
* DTO findList query.
*/
@@ -67,6 +67,7 @@ import io.ebeaninternal.api.SpiJsonContext;
import io.ebeaninternal.api.SpiLogManager;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.api.SpiQuery.Type;
import io.ebeaninternal.api.SpiSqlQuery;
import io.ebeaninternal.api.SpiSqlUpdate;
import io.ebeaninternal.api.SpiTransaction;
import io.ebeaninternal.api.SpiTransactionManager;
@@ -1585,6 +1586,19 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
}
}
@Override
public <T> T findSingleAttribute(SpiSqlQuery query, Class<T> cls) {
RelationalQueryRequest request = new RelationalQueryRequest(this, relationalQueryEngine, query, null);
try {
request.initTransIfRequired();
return request.findSingleAttribute(cls);
} finally {
request.endTransIfRequired();
}
}
@Override
public <T> void findDtoEach(SpiDtoQuery<T> query, Consumer<T> consumer) {
DtoQueryRequest<T> request = new DtoQueryRequest<>(this, dtoQueryEngine, query);
@@ -30,6 +30,11 @@ public interface RelationalQueryEngine {
*/
void findEach(RelationalQueryRequest request, Predicate<SqlRow> consumer);
/**
* Find single attribute.
*/
<T> T findSingleAttribute(RelationalQueryRequest request, Class<T> cls);
/**
* Collect SQL query execution statistics.
*/
@@ -53,6 +53,10 @@ public final class RelationalQueryRequest extends AbstractSqlQueryRequest {
}
}
public <T> T findSingleAttribute(Class<T> cls) {
return queryEngine.findSingleAttribute(this, cls);
}
public void findEach(Consumer<SqlRow> consumer) {
queryEngine.findEach(this, consumer);
}
@@ -104,4 +108,11 @@ public final class RelationalQueryRequest extends AbstractSqlQueryRequest {
}
}
public ResultSet getResultSet() {
return resultSet;
}
public void incrementRows() {
rows++;
}
}
@@ -8,6 +8,8 @@ import io.ebeaninternal.server.core.timezone.DataTimeZone;
import io.ebeaninternal.server.expression.platform.DbExpressionHandler;
import io.ebeaninternal.server.persist.platform.MultiValueBind;
import io.ebeaninternal.server.type.DataBind;
import io.ebeaninternal.server.type.DataReader;
import io.ebeaninternal.server.type.RsetDataReader;
import io.ebeaninternal.server.type.ScalarType;
import io.ebeaninternal.server.type.TypeManager;
import org.slf4j.Logger;
@@ -18,6 +20,7 @@ import java.math.BigDecimal;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;
@@ -196,7 +199,7 @@ public class Binder {
}
}
private ScalarType<?> getScalarType(Class<?> clazz) {
public ScalarType<?> getScalarType(Class<?> clazz) {
ScalarType<?> type = typeManager.getScalarType(clazz);
if (type == null) {
throw new PersistenceException("No ScalarType registered for " + clazz);
@@ -457,4 +460,8 @@ public class Binder {
public DataBind dataBind(PreparedStatement stmt, Connection connection) {
return new DataBind(dataTimeZone, stmt, connection);
}
public DataReader createDataReader(ResultSet resultSet) {
return new RsetDataReader(dataTimeZone, resultSet);
}
}
@@ -10,6 +10,7 @@ import io.ebeaninternal.server.core.Message;
import io.ebeaninternal.server.core.RelationalQueryEngine;
import io.ebeaninternal.server.core.RelationalQueryRequest;
import io.ebeaninternal.server.persist.Binder;
import io.ebeaninternal.server.type.ScalarType;
import javax.persistence.PersistenceException;
import java.sql.SQLException;
@@ -91,6 +92,35 @@ public class DefaultRelationalQueryEngine implements RelationalQueryEngine {
}
}
@SuppressWarnings("unchecked")
@Override
public <T> T findSingleAttribute(RelationalQueryRequest request, Class<T> cls) {
ScalarType<T> scalarType = (ScalarType<T>) binder.getScalarType(cls);
return findScalar(request, scalarType);
}
private <T> T findScalar(RelationalQueryRequest request, ScalarType<T> scalarType) {
try {
request.executeSql(binder, SpiQuery.Type.ATTRIBUTE);
T value = null;
if (request.next()) {
request.incrementRows();
value = scalarType.read(binder.createDataReader(request.getResultSet()));
}
request.logSummary();
return value;
} catch (Exception e) {
throw new PersistenceException(Message.msg("fetch.error", e.getMessage(), request.getSql()), e);
} finally {
request.close();
}
}
@Override
public List<SqlRow> findList(RelationalQueryRequest request) {
@@ -1,8 +1,8 @@
package io.ebeaninternal.server.querydefn;
import io.ebean.EbeanServer;
import io.ebean.SqlRow;
import io.ebeaninternal.api.BindParams;
import io.ebeaninternal.api.SpiEbeanServer;
import io.ebeaninternal.api.SpiSqlQuery;
import java.util.List;
@@ -17,7 +17,7 @@ public class DefaultRelationalQuery implements SpiSqlQuery {
private static final long serialVersionUID = -1098305779779591068L;
private final transient EbeanServer server;
private final transient SpiEbeanServer server;
private String label;
@@ -39,16 +39,11 @@ public class DefaultRelationalQuery implements SpiSqlQuery {
/**
* Additional supply a query detail object.
*/
public DefaultRelationalQuery(EbeanServer server, String query) {
public DefaultRelationalQuery(SpiEbeanServer server, String query) {
this.server = server;
this.query = query;
}
public DefaultRelationalQuery setQuery(String query) {
this.query = query;
return this;
}
@Override
public void findEach(Consumer<SqlRow> consumer) {
server.findEach(this, consumer, null);
@@ -64,6 +59,11 @@ public class DefaultRelationalQuery implements SpiSqlQuery {
return server.findList(this, null);
}
@Override
public <T> T findSingleAttribute(Class<T> cls) {
return server.findSingleAttribute(this, cls);
}
@Override
public SqlRow findOne() {
return server.findOne(this, null);
@@ -32,7 +32,6 @@ public class ScalarTypeBigDecimal extends ScalarTypeBase<BigDecimal> {
@Override
public BigDecimal read(DataReader dataReader) throws SQLException {
return dataReader.getBigDecimal();
}