Skip to content

Commit

Permalink
add SqlQuery#select() API and SqlQuery#strteam(Class) allowed primiti…
Browse files Browse the repository at this point in the history
…ve type.
  • Loading branch information
HidekiSugimoto189 committed Aug 18, 2022
1 parent 1742075 commit 0dac15e
Show file tree
Hide file tree
Showing 5 changed files with 468 additions and 9 deletions.
39 changes: 37 additions & 2 deletions src/main/java/jp/co/future/uroborosql/SqlQueryImpl.java
Expand Up @@ -18,6 +18,7 @@
import jp.co.future.uroborosql.converter.EntityResultSetConverter;
import jp.co.future.uroborosql.converter.MapResultSetConverter;
import jp.co.future.uroborosql.converter.ResultSetConverter;
import jp.co.future.uroborosql.converter.SingleColumnResultSetConverter;
import jp.co.future.uroborosql.exception.DataNonUniqueException;
import jp.co.future.uroborosql.exception.DataNotFoundException;
import jp.co.future.uroborosql.exception.UroborosqlSQLException;
Expand Down Expand Up @@ -258,8 +259,42 @@ public Stream<Map<String, Object>> stream(final CaseFormat caseFormat) {
*/
@Override
public <T> Stream<T> stream(final Class<T> type) {
return stream(
new EntityResultSetConverter<>(type, new PropertyMapperManager(this.agent.getSqlConfig().getClock())));
if (type == null) {
throw new IllegalArgumentException("Argument 'type' is required.");
}
PropertyMapperManager manager = new PropertyMapperManager(this.agent.getSqlConfig().getClock());
if (SingleColumnResultSetConverter.accept(type)) {
return stream(new SingleColumnResultSetConverter<>(null, type, manager));
} else {
return stream(new EntityResultSetConverter<>(type, manager));
}
}

/**
* {@inheritDoc}
*
* @see jp.co.future.uroborosql.fluent.SqlQuery#select(java.lang.Class)
*/
@Override
public <T> Stream<T> select(Class<T> type) {
return select(null, type);
}

/**
* {@inheritDoc}
*
* @see jp.co.future.uroborosql.fluent.SqlQuery#select(java.lang.String, java.lang.Class)
*/
@Override
public <T> Stream<T> select(String col, Class<T> type) {
if (type == null) {
throw new IllegalArgumentException("Argument 'type' is required.");
}
if (!SingleColumnResultSetConverter.accept(type)) {
throw new IllegalArgumentException(type.getName() + " is not supported.");
}
return stream(new SingleColumnResultSetConverter<>(col, type,
new PropertyMapperManager(this.agent.getSqlConfig().getClock())));
}

}
Expand Up @@ -54,7 +54,7 @@ public EntityResultSetConverter(final Class<? extends E> entityType, final Prope
try {
this.constructor = (Constructor<E>) entityType.getConstructor();
} catch (NoSuchMethodException e) {
throw new UroborosqlRuntimeException(e);
throw new UroborosqlRuntimeException("EntityType should have a default constructor.", e);
}

this.mappingColumnMap = Arrays.stream(MappingUtils.getMappingColumns(entityType))
Expand Down
@@ -0,0 +1,153 @@
/**
* Copyright (c) 2017-present, Future Corporation
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package jp.co.future.uroborosql.converter;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Month;
import java.time.MonthDay;
import java.time.OffsetDateTime;
import java.time.OffsetTime;
import java.time.Year;
import java.time.YearMonth;
import java.time.ZonedDateTime;
import java.util.Date;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import jp.co.future.uroborosql.exception.UroborosqlRuntimeException;
import jp.co.future.uroborosql.mapping.JavaType;
import jp.co.future.uroborosql.mapping.mapper.PropertyMapperManager;
import jp.co.future.uroborosql.utils.CaseFormat;
import jp.co.future.uroborosql.utils.StringUtils;

/**
* 検索結果の1行をプリミティブ型(のラッパークラス)に変換する変換器
*
* @param <E> プリミティブ型のラッパークラス、またはString型
* @author H.Sugimoto
*
*/
public class SingleColumnResultSetConverter<E> implements ResultSetConverter<E> {
/** ロガー */
private static final Logger LOG = LoggerFactory.getLogger(SingleColumnResultSetConverter.class);

private final String col;
private final JavaType javaType;
private final PropertyMapperManager mapperManager;
private int columnPosition;

/**
* 受付可能な型かどうかを判定する.
*
* @param type 判定対象の型
* @return 受付可能な場合<code>true</code> を返す.
*/
public static final boolean accept(Class<?> type) {
if (type == null) {
return false;
} else if (String.class.equals(type) ||
boolean.class.equals(type) ||
Boolean.class.equals(type) ||
byte.class.equals(type) ||
Byte.class.equals(type) ||
short.class.equals(type) ||
Short.class.equals(type) ||
int.class.equals(type) ||
Integer.class.equals(type) ||
long.class.equals(type) ||
Long.class.equals(type) ||
float.class.equals(type) ||
Float.class.equals(type) ||
double.class.equals(type) ||
Double.class.equals(type) ||
BigInteger.class.equals(type) ||
BigDecimal.class.equals(type)) {
// 基本的な型は受付可能とする
return true;
} else if (Date.class.isAssignableFrom(type)) {
// Date型かDate型を継承するクラス(Timestampなど)は受付可能とする
return true;
} else if (LocalDateTime.class.equals(type) ||
OffsetDateTime.class.equals(type) ||
ZonedDateTime.class.equals(type) ||
LocalDate.class.equals(type) ||
LocalTime.class.equals(type) ||
OffsetTime.class.equals(type) ||
Year.class.equals(type) ||
YearMonth.class.equals(type) ||
MonthDay.class.equals(type) ||
Month.class.equals(type) ||
DayOfWeek.class.equals(type)) {
// java.time配下の時間オブジェクトは受付可能とする
return true;
} else if (Object[].class.equals(type) ||
byte[].class.equals(type)) {
// 配列型でコンポーネント型が受入対象の型である場合は受入可能とする
return true;
} else {
return false;
}
}

/**
* コンストラクタ
*
* @param col 取得対象のカラム名. null の場合は先頭カラムを取得
* @param columnType カラムの型
* @param mapperManager PropertyMapperManager
*/
public SingleColumnResultSetConverter(String col, final Class<? extends E> columnType,
final PropertyMapperManager mapperManager) {
this.col = CaseFormat.UPPER_SNAKE_CASE.convert(col);
this.javaType = JavaType.of(columnType);
this.mapperManager = mapperManager;
this.columnPosition = StringUtils.isEmpty(col) ? 1 : -1;
}

/**
* {@inheritDoc}
*
* @see jp.co.future.uroborosql.converter.ResultSetConverter#createRecord(java.sql.ResultSet)
*/
@SuppressWarnings("unchecked")
@Override
public E createRecord(final ResultSet rs) throws SQLException {
try {
if (this.columnPosition == -1) {
ResultSetMetaData rsmd = rs.getMetaData();
int columnCount = rsmd.getColumnCount();

// 指定されたカラムのpositionを取得
for (int i = 1; i <= columnCount; i++) {
String columnLabel = CaseFormat.UPPER_SNAKE_CASE.convert(rsmd.getColumnLabel(i));
if (col.equalsIgnoreCase(columnLabel)) {
this.columnPosition = i;
break;
}
}
if (this.columnPosition == -1) {
// 指定されたカラムが見つからない場合は例外をスローする
throw new UroborosqlRuntimeException(col + " not found in query result.");
}
}

return (E) mapperManager.getValue(this.javaType, rs, this.columnPosition);
} catch (SQLException | RuntimeException | Error e) {
LOG.error("Error!!", e);
throw e;
}
}
}
28 changes: 24 additions & 4 deletions src/main/java/jp/co/future/uroborosql/fluent/SqlQuery.java
Expand Up @@ -173,7 +173,7 @@ public interface SqlQuery extends SqlFluent<SqlQuery> {
<T> List<T> collect(Class<T> type);

/**
* 検索結果をStreamとして取得(終端処理)
* 検索結果をStreamとして取得
*
* @param <T> Streamの型
* @param converter ResultSetの各行を変換するための変換器
Expand All @@ -182,26 +182,46 @@ public interface SqlQuery extends SqlFluent<SqlQuery> {
<T> Stream<T> stream(ResultSetConverter<T> converter);

/**
* 検索結果をMapのStreamとして取得(終端処理)
* 検索結果をMapのStreamとして取得
*
* @return 検索結果を順次取得するStream
*/
Stream<Map<String, Object>> stream();

/**
* 検索結果をMapのStreamとして取得(終端処理)
* 検索結果をMapのStreamとして取得
*
* @param caseFormat Mapのキーの変換書式
* @return 検索結果を順次取得するStream
*/
Stream<Map<String, Object>> stream(CaseFormat caseFormat);

/**
* 検索結果をEntityのStreamとして取得(終端処理)
* 検索結果をEntityのStreamとして取得
*
* @param <T> Streamの型
* @param type 受け取りたいEntityの型
* @return 検索結果を順次取得するStream
*/
<T> Stream<T> stream(Class<T> type);

/**
* 検索結果の先頭カラムをStreamとして取得
*
* @param <T> Streamの型
* @param type 取得するカラムの型
* @return 検索結果を順次取得するStream
*/
<T> Stream<T> select(Class<T> type);

/**
* 検索結果の指定したカラムをStreamとして取得
*
* @param <T> Streamの型
* @param col 取得するカラムの名前
* @param type 取得するカラムの型
* @return 検索結果を順次取得するStream
*/
<T> Stream<T> select(String col, Class<T> type);

}

0 comments on commit 0dac15e

Please sign in to comment.