Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.landawn.abacus.jdbc.Jdbc Maven / Gradle / Ivy
/*
* Copyright (c) 2022, Haiyang Li.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.landawn.abacus.jdbc;
import java.io.InputStream;
import java.io.Reader;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiConsumer;
import java.util.function.BiPredicate;
import java.util.function.BinaryOperator;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collector;
import com.landawn.abacus.annotation.Beta;
import com.landawn.abacus.annotation.SequentialOnly;
import com.landawn.abacus.annotation.Stateful;
import com.landawn.abacus.parser.ParserUtil;
import com.landawn.abacus.parser.ParserUtil.BeanInfo;
import com.landawn.abacus.parser.ParserUtil.PropInfo;
import com.landawn.abacus.type.Type;
import com.landawn.abacus.util.Array;
import com.landawn.abacus.util.ClassUtil;
import com.landawn.abacus.util.DataSet;
import com.landawn.abacus.util.EntityId;
import com.landawn.abacus.util.Fn;
import com.landawn.abacus.util.Fn.Factory;
import com.landawn.abacus.util.Fn.IntFunctions;
import com.landawn.abacus.util.Fn.Suppliers;
import com.landawn.abacus.util.ImmutableList;
import com.landawn.abacus.util.ListMultimap;
import com.landawn.abacus.util.Multimap;
import com.landawn.abacus.util.N;
import com.landawn.abacus.util.NoCachingNoUpdating.DisposableObjArray;
import com.landawn.abacus.util.ObjectPool;
import com.landawn.abacus.util.ParsedSql;
import com.landawn.abacus.util.Seid;
import com.landawn.abacus.util.Strings;
import com.landawn.abacus.util.Throwables;
import com.landawn.abacus.util.Tuple;
import com.landawn.abacus.util.Tuple.Tuple2;
import com.landawn.abacus.util.Tuple.Tuple3;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
@SuppressWarnings("java:S1192")
public final class Jdbc {
static final ObjectPool, ColumnGetter>> COLUMN_GETTER_POOL = new ObjectPool<>(1024);
static {
COLUMN_GETTER_POOL.put(N.typeOf(boolean.class), ColumnGetter.GET_BOOLEAN);
COLUMN_GETTER_POOL.put(N.typeOf(Boolean.class), ColumnGetter.GET_BOOLEAN);
COLUMN_GETTER_POOL.put(N.typeOf(byte.class), ColumnGetter.GET_BYTE);
COLUMN_GETTER_POOL.put(N.typeOf(Byte.class), ColumnGetter.GET_BYTE);
COLUMN_GETTER_POOL.put(N.typeOf(short.class), ColumnGetter.GET_SHORT);
COLUMN_GETTER_POOL.put(N.typeOf(Short.class), ColumnGetter.GET_SHORT);
COLUMN_GETTER_POOL.put(N.typeOf(int.class), ColumnGetter.GET_INT);
COLUMN_GETTER_POOL.put(N.typeOf(Integer.class), ColumnGetter.GET_INT);
COLUMN_GETTER_POOL.put(N.typeOf(long.class), ColumnGetter.GET_LONG);
COLUMN_GETTER_POOL.put(N.typeOf(Long.class), ColumnGetter.GET_LONG);
COLUMN_GETTER_POOL.put(N.typeOf(float.class), ColumnGetter.GET_FLOAT);
COLUMN_GETTER_POOL.put(N.typeOf(Float.class), ColumnGetter.GET_FLOAT);
COLUMN_GETTER_POOL.put(N.typeOf(double.class), ColumnGetter.GET_DOUBLE);
COLUMN_GETTER_POOL.put(N.typeOf(Double.class), ColumnGetter.GET_DOUBLE);
COLUMN_GETTER_POOL.put(N.typeOf(BigDecimal.class), ColumnGetter.GET_BIG_DECIMAL);
COLUMN_GETTER_POOL.put(N.typeOf(String.class), ColumnGetter.GET_STRING);
COLUMN_GETTER_POOL.put(N.typeOf(java.sql.Date.class), ColumnGetter.GET_DATE);
COLUMN_GETTER_POOL.put(N.typeOf(java.sql.Time.class), ColumnGetter.GET_TIME);
COLUMN_GETTER_POOL.put(N.typeOf(java.sql.Timestamp.class), ColumnGetter.GET_TIMESTAMP);
COLUMN_GETTER_POOL.put(N.typeOf(Object.class), ColumnGetter.GET_OBJECT);
}
private Jdbc() {
// singleton.
}
/**
* The Interface ParametersSetter.
*
* @param
*/
@FunctionalInterface
public interface ParametersSetter extends Throwables.Consumer {
@SuppressWarnings("rawtypes")
ParametersSetter DO_NOTHING = preparedQuery -> {
// Do nothing.
};
/**
*
*
* @param preparedQuery
* @throws SQLException
*/
@Override
void accept(QS preparedQuery) throws SQLException;
}
/**
* The Interface BiParametersSetter.
*
* @param
* @param
* @see Columns.ColumnOne
* @see Columns.ColumnTwo
* @see Columns.ColumnThree
*/
@FunctionalInterface
public interface BiParametersSetter extends Throwables.BiConsumer {
@SuppressWarnings("rawtypes")
BiParametersSetter DO_NOTHING = (preparedQuery, param) -> {
// Do nothing.
};
/**
*
*
* @param preparedQuery
* @param param
* @throws SQLException
*/
@Override
void accept(QS preparedQuery, T param) throws SQLException;
/**
* It's stateful. Don't save or cache the returned instance for reuse or use it in parallel stream.
*
* @param
* @param fieldNameList
* @param entityClass
* @return
*/
@Beta
static BiParametersSetter createForArray(final List fieldNameList, final Class> entityClass) {
N.checkArgNotEmpty(fieldNameList, "'fieldNameList' can't be null or empty");
N.checkArgument(ClassUtil.isBeanClass(entityClass), "{} is not a valid entity class with getter/setter methods", entityClass);
return new BiParametersSetter<>() {
private final int len = fieldNameList.size();
@SuppressWarnings("rawtypes")
private Type[] fieldTypes = null;
@Override
public void accept(PreparedStatement stmt, T[] params) throws SQLException {
if (fieldTypes == null) {
final BeanInfo entityInfo = ParserUtil.getBeanInfo(entityClass);
@SuppressWarnings("rawtypes")
final Type[] localFieldTypes = new Type[len];
for (int i = 0; i < len; i++) {
localFieldTypes[i] = entityInfo.getPropInfo(fieldNameList.get(i)).dbType;
}
this.fieldTypes = localFieldTypes;
}
for (int i = 0; i < len; i++) {
fieldTypes[i].set(stmt, i + 1, params[i]);
}
}
};
}
/**
* It's stateful. Don't save or cache the returned instance for reuse or use it in parallel stream.
*
* @param
* @param fieldNameList
* @param entityClass
* @return
*/
@Beta
static BiParametersSetter> createForList(final List fieldNameList, final Class> entityClass) {
N.checkArgNotEmpty(fieldNameList, "'fieldNameList' can't be null or empty");
N.checkArgument(ClassUtil.isBeanClass(entityClass), "{} is not a valid entity class with getter/setter methods", entityClass);
return new BiParametersSetter<>() {
private final int len = fieldNameList.size();
@SuppressWarnings("rawtypes")
private Type[] fieldTypes = null;
@Override
public void accept(PreparedStatement stmt, List params) throws SQLException {
if (fieldTypes == null) {
final BeanInfo entityInfo = ParserUtil.getBeanInfo(entityClass);
@SuppressWarnings("rawtypes")
final Type[] localFieldTypes = new Type[len];
for (int i = 0; i < len; i++) {
localFieldTypes[i] = entityInfo.getPropInfo(fieldNameList.get(i)).dbType;
}
this.fieldTypes = localFieldTypes;
}
for (int i = 0; i < len; i++) {
fieldTypes[i].set(stmt, i + 1, params.get(i));
}
}
};
}
}
/**
* The Interface TriParametersSetter.
*
* @param
* @param
*/
@FunctionalInterface
public interface TriParametersSetter extends Throwables.TriConsumer {
@SuppressWarnings("rawtypes")
TriParametersSetter DO_NOTHING = new TriParametersSetter<>() {
@Override
public void accept(ParsedSql parsedSql, Object preparedQuery, Object param) throws SQLException {
// Do nothing.
}
};
/**
*
*
* @param parsedSql
* @param preparedQuery
* @param param
* @throws SQLException
*/
@Override
void accept(ParsedSql parsedSql, QS preparedQuery, T param) throws SQLException;
}
/**
* The Interface ResultExtractor.
*
* @param
*/
@FunctionalInterface
public interface ResultExtractor extends Throwables.Function {
ResultExtractor TO_DATA_SET = rs -> {
if (rs == null) {
return N.newEmptyDataSet();
}
return JdbcUtil.extractData(rs);
};
/**
* In a lot of scenarios, including PreparedQuery/Dao/SQLExecutor, the input {@code ResultSet} will be closed after {@code apply(rs)} call. So don't save/return the input {@code ResultSet}.
*
* @param rs
* @return
* @throws SQLException
*/
@Override
T apply(ResultSet rs) throws SQLException;
/**
*
*
* @param
* @param after
* @return
*/
default ResultExtractor andThen(final Throwables.Function super T, ? extends R, SQLException> after) {
N.checkArgNotNull(after);
return rs -> after.apply(apply(rs));
}
/**
*
*
* @return
*/
default BiResultExtractor toBiResultExtractor() {
return (rs, columnLabels) -> this.apply(rs);
}
/**
*
* @param the key type
* @param the value type
* @param keyExtractor
* @param valueExtractor
* @return
*/
static ResultExtractor> toMap(final RowMapper extends K> keyExtractor, final RowMapper extends V> valueExtractor) {
return toMap(keyExtractor, valueExtractor, Suppliers. ofMap());
}
/**
*
* @param the key type
* @param the value type
* @param
* @param keyExtractor
* @param valueExtractor
* @param supplier
* @return
*/
static > ResultExtractor toMap(final RowMapper extends K> keyExtractor, final RowMapper extends V> valueExtractor,
final Supplier extends M> supplier) {
return toMap(keyExtractor, valueExtractor, Fn. throwingMerger(), supplier);
}
/**
*
* @param the key type
* @param the value type
* @param keyExtractor
* @param valueExtractor
* @param mergeFunction
* @return
* @see {@link Fn.throwingMerger()}
* @see {@link Fn.replacingMerger()}
* @see {@link Fn.ignoringMerger()}
*/
static ResultExtractor> toMap(final RowMapper extends K> keyExtractor, final RowMapper extends V> valueExtractor,
final BinaryOperator mergeFunction) {
return toMap(keyExtractor, valueExtractor, mergeFunction, Suppliers. ofMap());
}
/**
*
* @param the key type
* @param the value type
* @param
* @param keyExtractor
* @param valueExtractor
* @param mergeFunction
* @param supplier
* @return
* @see {@link Fn.throwingMerger()}
* @see {@link Fn.replacingMerger()}
* @see {@link Fn.ignoringMerger()}
*/
static > ResultExtractor toMap(final RowMapper extends K> keyExtractor, final RowMapper extends V> valueExtractor,
final BinaryOperator mergeFunction, final Supplier extends M> supplier) {
N.checkArgNotNull(keyExtractor, "keyExtractor");
N.checkArgNotNull(valueExtractor, "valueExtractor");
N.checkArgNotNull(mergeFunction, "mergeFunction");
N.checkArgNotNull(supplier, "supplier");
return rs -> {
final M result = supplier.get();
while (rs.next()) {
Jdbc.merge(result, keyExtractor.apply(rs), valueExtractor.apply(rs), mergeFunction);
}
return result;
};
}
/**
*
*
* @param the key type
* @param the value type
* @param
* @param keyExtractor
* @param valueExtractor
* @param downstream
* @return
* @see #groupTo(RowMapper, RowMapper, Collector)
* @deprecated replaced by {@code groupTo(RowMapper, RowMapper, Collector)}
*/
@Deprecated
static ResultExtractor> toMap(final RowMapper extends K> keyExtractor, final RowMapper extends V> valueExtractor,
final Collector super V, ?, D> downstream) {
return toMap(keyExtractor, valueExtractor, downstream, Suppliers. ofMap());
}
/**
*
*
* @param the key type
* @param the value type
* @param
* @param
* @param keyExtractor
* @param valueExtractor
* @param downstream
* @param supplier
* @return
* @see #groupTo(RowMapper, RowMapper, Collector, Supplier)
* @deprecated replaced by {@code groupTo(RowMapper, RowMapper, Collector, Supplier)}
*/
@Deprecated
static > ResultExtractor toMap(final RowMapper extends K> keyExtractor, final RowMapper extends V> valueExtractor,
final Collector super V, ?, D> downstream, final Supplier extends M> supplier) {
return groupTo(keyExtractor, valueExtractor, downstream, supplier);
}
/**
*
* @param the key type
* @param the value type
* @param keyExtractor
* @param valueExtractor
* @return
*/
static ResultExtractor> toMultimap(final RowMapper extends K> keyExtractor, final RowMapper extends V> valueExtractor) {
return toMultimap(keyExtractor, valueExtractor, Suppliers. ofListMultimap());
}
/**
*
* @param the key type
* @param the value type
* @param
* @param
* @param keyExtractor
* @param valueExtractor
* @param multimapSupplier
* @return
*/
static , M extends Multimap> ResultExtractor toMultimap(final RowMapper extends K> keyExtractor,
final RowMapper extends V> valueExtractor, final Supplier extends M> multimapSupplier) {
N.checkArgNotNull(keyExtractor, "keyExtractor");
N.checkArgNotNull(valueExtractor, "valueExtractor");
N.checkArgNotNull(multimapSupplier, "multimapSupplier");
return rs -> {
final M result = multimapSupplier.get();
while (rs.next()) {
result.put(keyExtractor.apply(rs), valueExtractor.apply(rs));
}
return result;
};
}
/**
*
*
* @param the key type
* @param the value type
* @param keyExtractor
* @param valueExtractor
* @return
*/
static ResultExtractor>> groupTo(final RowMapper extends K> keyExtractor, final RowMapper extends V> valueExtractor) {
return groupTo(keyExtractor, valueExtractor, Suppliers.> ofMap());
}
/**
*
* @param the key type
* @param the value type
* @param
* @param keyExtractor
* @param valueExtractor
* @param supplier
* @return
*/
static >> ResultExtractor groupTo(final RowMapper extends K> keyExtractor,
final RowMapper extends V> valueExtractor, final Supplier extends M> supplier) {
N.checkArgNotNull(keyExtractor, "keyExtractor");
N.checkArgNotNull(valueExtractor, "valueExtractor");
N.checkArgNotNull(supplier, "supplier");
return rs -> {
final M result = supplier.get();
K key = null;
List value = null;
while (rs.next()) {
key = keyExtractor.apply(rs);
value = result.get(key);
if (value == null) {
value = new ArrayList<>();
result.put(key, value);
}
value.add(valueExtractor.apply(rs));
}
return result;
};
}
/**
*
* @param the key type
* @param the value type
* @param
* @param keyExtractor
* @param valueExtractor
* @param downstream
* @return
*/
static ResultExtractor> groupTo(final RowMapper extends K> keyExtractor, final RowMapper extends V> valueExtractor,
final Collector super V, ?, D> downstream) {
return groupTo(keyExtractor, valueExtractor, downstream, Suppliers. ofMap());
}
/**
*
* @param the key type
* @param the value type
* @param
* @param
* @param keyExtractor
* @param valueExtractor
* @param downstream
* @param supplier
* @return
*/
static > ResultExtractor groupTo(final RowMapper extends K> keyExtractor, final RowMapper extends V> valueExtractor,
final Collector super V, ?, D> downstream, final Supplier extends M> supplier) {
N.checkArgNotNull(keyExtractor, "keyExtractor");
N.checkArgNotNull(valueExtractor, "valueExtractor");
N.checkArgNotNull(downstream, "downstream");
N.checkArgNotNull(supplier, "supplier");
return rs -> {
final Supplier downstreamSupplier = (Supplier) downstream.supplier();
final BiConsumer downstreamAccumulator = (BiConsumer) downstream.accumulator();
final Function downstreamFinisher = (Function) downstream.finisher();
final M result = supplier.get();
final Map tmp = (Map) result;
K key = null;
Object container = null;
while (rs.next()) {
key = keyExtractor.apply(rs);
container = tmp.get(key);
if (container == null) {
container = downstreamSupplier.get();
tmp.put(key, container);
}
downstreamAccumulator.accept(container, valueExtractor.apply(rs));
}
for (Map.Entry entry : result.entrySet()) {
entry.setValue(downstreamFinisher.apply(entry.getValue()));
}
return result;
};
}
/**
*
*
* @param
* @param rowMapper
* @return
*/
static ResultExtractor> toList(final RowMapper extends T> rowMapper) {
return toList(RowFilter.ALWAYS_TRUE, rowMapper);
}
/**
*
*
* @param
* @param rowFilter
* @param rowMapper
* @return
*/
static ResultExtractor> toList(final RowFilter rowFilter, RowMapper extends T> rowMapper) {
N.checkArgNotNull(rowFilter, "rowFilter");
N.checkArgNotNull(rowMapper, "rowMapper");
return rs -> {
final List result = new ArrayList<>();
while (rs.next()) {
if (rowFilter.test(rs)) {
result.add(rowMapper.apply(rs));
}
}
return result;
};
}
/**
* @param
* @param targetClass
* @return
*/
static ResultExtractor> toList(final Class extends T> targetClass) {
N.checkArgNotNull(targetClass, "targetClass");
return rs -> {
final BiRowMapper extends T> rowMapper = BiRowMapper.to(targetClass);
final List columnLabels = JdbcUtil.getColumnLabelList(rs);
final List result = new ArrayList<>();
while (rs.next()) {
result.add(rowMapper.apply(rs, columnLabels));
}
return result;
};
}
/**
* @param
* @param targetClass
* @return
* @see DataSet#toMergedEntities(Class)
*/
static ResultExtractor> toMergedList(final Class extends T> targetClass) {
N.checkArgNotNull(targetClass, "targetClass");
return rs -> {
final RowExtractor rowExtractor = RowExtractor.createBy(targetClass);
return JdbcUtil.extractData(rs, 0, Integer.MAX_VALUE, rowExtractor, false).toMergedEntities(targetClass);
};
}
/**
* @param
* @param targetClass
* @param idPropNameForMerge
* @return
* @see DataSet#toMergedEntities(Collection, Collection, Class)
*/
static ResultExtractor> toMergedList(final Class extends T> targetClass, final String idPropNameForMerge) {
N.checkArgNotNull(targetClass, "targetClass");
return rs -> {
final RowExtractor rowExtractor = RowExtractor.createBy(targetClass);
return JdbcUtil.extractData(rs, 0, Integer.MAX_VALUE, rowExtractor, false).toMergedEntities(idPropNameForMerge, targetClass);
};
}
/**
* @param
* @param targetClass
* @param idPropNamesForMerge
* @return
* @see DataSet#toMergedEntities(Collection, Collection, Class)
*/
static ResultExtractor> toMergedList(final Class extends T> targetClass, Collection idPropNamesForMerge) {
N.checkArgNotNull(targetClass, "targetClass");
return rs -> {
final RowExtractor rowExtractor = RowExtractor.createBy(targetClass);
return JdbcUtil.extractData(rs, 0, Integer.MAX_VALUE, rowExtractor, false).toMergedEntities(idPropNamesForMerge, targetClass);
};
}
/**
* @param entityClass
* @return
*/
static ResultExtractor toDataSet(final Class> entityClass) {
return rs -> JdbcUtil.extractData(rs, RowExtractor.createBy(entityClass));
}
/**
*
*
* @param entityClass
* @param prefixAndFieldNameMap
* @return
*/
static ResultExtractor toDataSet(final Class> entityClass, final Map prefixAndFieldNameMap) {
return rs -> JdbcUtil.extractData(rs, RowExtractor.createBy(entityClass, prefixAndFieldNameMap));
}
/**
*
*
* @param rowFilter
* @return
*/
static ResultExtractor toDataSet(final RowFilter rowFilter) {
return rs -> JdbcUtil.extractData(rs, rowFilter);
}
/**
*
*
* @param rowExtractor
* @return
*/
static ResultExtractor toDataSet(final RowExtractor rowExtractor) {
return rs -> JdbcUtil.extractData(rs, rowExtractor);
}
/**
*
*
* @param rowFilter
* @param rowExtractor
* @return
*/
static ResultExtractor toDataSet(final RowFilter rowFilter, final RowExtractor rowExtractor) {
return rs -> JdbcUtil.extractData(rs, 0, Integer.MAX_VALUE, rowFilter, rowExtractor, false);
}
/**
*
*
* @param
* @param after
* @return
*/
static ResultExtractor to(final Throwables.Function after) {
return rs -> after.apply(TO_DATA_SET.apply(rs));
}
}
/**
* The Interface BiResultExtractor.
*
* @param
*/
@FunctionalInterface
public interface BiResultExtractor extends Throwables.BiFunction, T, SQLException> {
BiResultExtractor TO_DATA_SET = (rs, columnLabels) -> {
if (rs == null) {
return N.newEmptyDataSet();
}
return JdbcUtil.extractData(rs);
};
/**
* In a lot of scenarios, including PreparedQuery/Dao/SQLExecutor, the input {@code ResultSet} will be closed after {@code apply(rs)} call. So don't save/return the input {@code ResultSet}.
*
* @param rs
* @param columnLabels
* @return
* @throws SQLException
*/
@Override
T apply(ResultSet rs, List columnLabels) throws SQLException;
/**
*
*
* @param
* @param after
* @return
*/
default BiResultExtractor andThen(final Throwables.Function super T, ? extends R, SQLException> after) {
N.checkArgNotNull(after);
return (rs, columnLabels) -> after.apply(apply(rs, columnLabels));
}
// /**
// *
// *
// * @param
// * @param resultExtractor
// * @return
// */
// static BiResultExtractor from(final ResultExtractor extends R> resultExtractor) {
// N.checkArgNotNull(resultExtractor);
//
// return (rs, columnLabels) -> resultExtractor.apply(rs);
// }
/**
*
* @param the key type
* @param the value type
* @param keyExtractor
* @param valueExtractor
* @return
*/
static BiResultExtractor> toMap(final BiRowMapper extends K> keyExtractor, final BiRowMapper extends V> valueExtractor) {
return toMap(keyExtractor, valueExtractor, Suppliers. ofMap());
}
/**
*
* @param the key type
* @param the value type
* @param
* @param keyExtractor
* @param valueExtractor
* @param supplier
* @return
*/
static > BiResultExtractor toMap(final BiRowMapper extends K> keyExtractor,
final BiRowMapper extends V> valueExtractor, final Supplier extends M> supplier) {
return toMap(keyExtractor, valueExtractor, Fn. throwingMerger(), supplier);
}
/**
*
* @param the key type
* @param the value type
* @param keyExtractor
* @param valueExtractor
* @param mergeFunction
* @return
* @see {@link Fn.throwingMerger()}
* @see {@link Fn.replacingMerger()}
* @see {@link Fn.ignoringMerger()}
*/
static BiResultExtractor> toMap(final BiRowMapper extends K> keyExtractor, final BiRowMapper extends V> valueExtractor,
final BinaryOperator mergeFunction) {
return toMap(keyExtractor, valueExtractor, mergeFunction, Suppliers. ofMap());
}
/**
*
* @param the key type
* @param the value type
* @param
* @param keyExtractor
* @param valueExtractor
* @param mergeFunction
* @param supplier
* @return
* @see {@link Fn.throwingMerger()}
* @see {@link Fn.replacingMerger()}
* @see {@link Fn.ignoringMerger()}
*/
static > BiResultExtractor toMap(final BiRowMapper extends K> keyExtractor,
final BiRowMapper extends V> valueExtractor, final BinaryOperator mergeFunction, final Supplier extends M> supplier) {
N.checkArgNotNull(keyExtractor, "keyExtractor");
N.checkArgNotNull(valueExtractor, "valueExtractor");
N.checkArgNotNull(mergeFunction, "mergeFunction");
N.checkArgNotNull(supplier, "supplier");
return (rs, columnLabels) -> {
final M result = supplier.get();
while (rs.next()) {
Jdbc.merge(result, keyExtractor.apply(rs, columnLabels), valueExtractor.apply(rs, columnLabels), mergeFunction);
}
return result;
};
}
/**
*
*
* @param the key type
* @param the value type
* @param
* @param keyExtractor
* @param valueExtractor
* @param downstream
* @return
* @see #groupTo(BiRowMapper, BiRowMapper, Collector)
* @deprecated replaced by {@code groupTo(BiRowMapper, BiRowMapper, Collector)}
*/
@Deprecated
static BiResultExtractor> toMap(final BiRowMapper extends K> keyExtractor, final BiRowMapper extends V> valueExtractor,
final Collector super V, ?, D> downstream) {
return toMap(keyExtractor, valueExtractor, downstream, Suppliers. ofMap());
}
/**
*
*
* @param the key type
* @param the value type
* @param
* @param
* @param keyExtractor
* @param valueExtractor
* @param downstream
* @param supplier
* @return
* @see #groupTo(BiRowMapper, BiRowMapper, Collector, Supplier)
* @deprecated replaced by {@code groupTo(BiRowMapper, BiRowMapper, Collector, Supplier)}
*/
@Deprecated
static > BiResultExtractor toMap(final BiRowMapper extends K> keyExtractor,
final BiRowMapper extends V> valueExtractor, final Collector super V, ?, D> downstream, final Supplier extends M> supplier) {
return groupTo(keyExtractor, valueExtractor, downstream, supplier);
}
/**
*
* @param the key type
* @param the value type
* @param keyExtractor
* @param valueExtractor
* @return
*/
static BiResultExtractor> toMultimap(final BiRowMapper extends K> keyExtractor,
final BiRowMapper extends V> valueExtractor) {
return toMultimap(keyExtractor, valueExtractor, Suppliers. ofListMultimap());
}
/**
*
* @param the key type
* @param the value type
* @param
* @param
* @param keyExtractor
* @param valueExtractor
* @param multimapSupplier
* @return
*/
static , M extends Multimap> BiResultExtractor toMultimap(final BiRowMapper extends K> keyExtractor,
final BiRowMapper extends V> valueExtractor, final Supplier extends M> multimapSupplier) {
N.checkArgNotNull(keyExtractor, "keyExtractor");
N.checkArgNotNull(valueExtractor, "valueExtractor");
N.checkArgNotNull(multimapSupplier, "multimapSupplier");
return (rs, columnLabels) -> {
final M result = multimapSupplier.get();
while (rs.next()) {
result.put(keyExtractor.apply(rs, columnLabels), valueExtractor.apply(rs, columnLabels));
}
return result;
};
}
/**
*
* @param the key type
* @param the value type
* @param keyExtractor
* @param valueExtractor
* @return
*/
static BiResultExtractor>> groupTo(final BiRowMapper extends K> keyExtractor, final BiRowMapper extends V> valueExtractor) {
return groupTo(keyExtractor, valueExtractor, Suppliers.> ofMap());
}
/**
*
* @param the key type
* @param the value type
* @param
* @param keyExtractor
* @param valueExtractor
* @param supplier
* @return
*/
static >> BiResultExtractor groupTo(final BiRowMapper extends K> keyExtractor,
final BiRowMapper extends V> valueExtractor, final Supplier extends M> supplier) {
N.checkArgNotNull(keyExtractor, "keyExtractor");
N.checkArgNotNull(valueExtractor, "valueExtractor");
N.checkArgNotNull(supplier, "supplier");
return (rs, columnLabels) -> {
final M result = supplier.get();
K key = null;
List value = null;
while (rs.next()) {
key = keyExtractor.apply(rs, columnLabels);
value = result.get(key);
if (value == null) {
value = new ArrayList<>();
result.put(key, value);
}
value.add(valueExtractor.apply(rs, columnLabels));
}
return result;
};
}
/**
*
* @param the key type
* @param the value type
* @param
* @param keyExtractor
* @param valueExtractor
* @param downstream
* @return
*/
static BiResultExtractor> groupTo(final BiRowMapper extends K> keyExtractor, final BiRowMapper extends V> valueExtractor,
final Collector super V, ?, D> downstream) {
return groupTo(keyExtractor, valueExtractor, downstream, Suppliers. ofMap());
}
/**
*
* @param the key type
* @param the value type
* @param
* @param
* @param keyExtractor
* @param valueExtractor
* @param downstream
* @param supplier
* @return
*/
static > BiResultExtractor groupTo(final BiRowMapper extends K> keyExtractor,
final BiRowMapper extends V> valueExtractor, final Collector super V, ?, D> downstream, final Supplier extends M> supplier) {
N.checkArgNotNull(keyExtractor, "keyExtractor");
N.checkArgNotNull(valueExtractor, "valueExtractor");
N.checkArgNotNull(downstream, "downstream");
N.checkArgNotNull(supplier, "supplier");
return (rs, columnLabels) -> {
final Supplier downstreamSupplier = (Supplier) downstream.supplier();
final BiConsumer downstreamAccumulator = (BiConsumer) downstream.accumulator();
final Function downstreamFinisher = (Function) downstream.finisher();
final M result = supplier.get();
final Map tmp = (Map) result;
K key = null;
Object container = null;
while (rs.next()) {
key = keyExtractor.apply(rs, columnLabels);
container = tmp.get(key);
if (container == null) {
container = downstreamSupplier.get();
tmp.put(key, container);
}
downstreamAccumulator.accept(container, valueExtractor.apply(rs, columnLabels));
}
for (Map.Entry entry : result.entrySet()) {
entry.setValue(downstreamFinisher.apply(entry.getValue()));
}
return result;
};
}
/**
*
*
* @param
* @param rowMapper
* @return
*/
static BiResultExtractor> toList(final BiRowMapper extends T> rowMapper) {
return toList(BiRowFilter.ALWAYS_TRUE, rowMapper);
}
/**
*
*
* @param
* @param rowFilter
* @param rowMapper
* @return
*/
static BiResultExtractor> toList(final BiRowFilter rowFilter, final BiRowMapper extends T> rowMapper) {
N.checkArgNotNull(rowFilter, "rowFilter");
N.checkArgNotNull(rowMapper, "rowMapper");
return (rs, columnLabels) -> {
final List result = new ArrayList<>();
while (rs.next()) {
if (rowFilter.test(rs, columnLabels)) {
result.add(rowMapper.apply(rs, columnLabels));
}
}
return result;
};
}
/**
* It's stateful. Don't save or cache the returned instance for reuse or use it in parallel stream.
*
* @param
* @param targetClass
* @return
*/
@SequentialOnly
static BiResultExtractor> toList(final Class extends T> targetClass) {
N.checkArgNotNull(targetClass, "targetClass");
return (rs, columnLabels) -> {
final BiRowMapper extends T> rowMapper = BiRowMapper.to(targetClass);
final List result = new ArrayList<>();
while (rs.next()) {
result.add(rowMapper.apply(rs, columnLabels));
}
return result;
};
}
}
/**
* Don't use {@code RowMapper} in {@link PreparedQuery#list(RowMapper)} or any place where multiple records will be retrieved by it, if column labels/count are used in {@link RowMapper#apply(ResultSet)}.
* Consider using {@code BiRowMapper} instead because it's more efficient to retrieve multiple records when column labels/count are used.
*
* @param
* @see Columns.ColumnOne
* @see Columns.ColumnTwo
* @see Columns.ColumnThree
*/
@FunctionalInterface
public interface RowMapper extends Throwables.Function {
/**
*
*
* @param rs
* @return
* @throws SQLException
*/
@Override
T apply(ResultSet rs) throws SQLException;
/**
*
*
* @param
* @param after
* @return
*/
default RowMapper andThen(final Throwables.Function super T, ? extends R, SQLException> after) {
N.checkArgNotNull(after);
return rs -> after.apply(apply(rs));
}
/**
*
*
* @return
*/
default BiRowMapper toBiRowMapper() {
return (rs, columnLabels) -> this.apply(rs);
}
// /**
// * It's stateful. Don't save or cache the returned instance for reuse or use it in parallel stream.
// *
// * @param
// * @param biRowMapper
// * @return
// * @deprecated because it's stateful and may be misused easily and frequently
// */
// @Beta
// @Deprecated
// @SequentialOnly
// @Stateful
// static RowMapper