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
*/
@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
@Stateful
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(final PreparedStatement stmt, final 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;
}
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
@Stateful
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(final PreparedStatement stmt, final 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;
}
fieldTypes = localFieldTypes;
}
for (int i = 0; i < len; i++) {
fieldTypes[i].set(stmt, i + 1, params.get(i));
}
}
};
}
}
/**
* The Interface TriParametersSetter.
*
* @param
* @param
*/
@SuppressWarnings("RedundantThrows")
@FunctionalInterface
public interface TriParametersSetter extends Throwables.TriConsumer {
@SuppressWarnings("rawtypes")
TriParametersSetter DO_NOTHING = (TriParametersSetter) (parsedSql, preparedQuery, param) -> {
// 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);
}
/**
* Converts the result set into a map using the provided key and value extractors.
*
* @param The type of keys maintained by the map.
* @param The type of mapped values.
* @param keyExtractor The function to extract keys from the result set.
* @param valueExtractor The function to extract values from the result set.
* @return A map containing the extracted keys and values.
*/
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());
}
/**
* Converts the result set into a map using the provided key and value extractors,
* merge function, and map supplier.
*
* @param The type of keys maintained by the map.
* @param The type of mapped values.
* @param The type of the map.
* @param keyExtractor The function to extract keys from the result set.
* @param valueExtractor The function to extract values from the result set.
* @param mergeFunction The function to merge values if the same key is encountered.
* @param supplier The supplier to provide a new map instance.
* @return A map containing the extracted keys and values.
* @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, s.keyExtractor);
N.checkArgNotNull(valueExtractor, s.valueExtractor);
N.checkArgNotNull(mergeFunction, s.mergeFunction);
N.checkArgNotNull(supplier, s.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, s.keyExtractor);
N.checkArgNotNull(valueExtractor, s.valueExtractor);
N.checkArgNotNull(multimapSupplier, s.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, s.keyExtractor);
N.checkArgNotNull(valueExtractor, s.valueExtractor);
N.checkArgNotNull(supplier, s.supplier);
return rs -> {
final M result = supplier.get();
K key = null;
List value = null;
while (rs.next()) {
key = keyExtractor.apply(rs);
value = result.computeIfAbsent(key, k -> new ArrayList<>());
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, s.keyExtractor);
N.checkArgNotNull(valueExtractor, s.valueExtractor);
N.checkArgNotNull(downstream, s.downstream);
N.checkArgNotNull(supplier, s.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 (final 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, final RowMapper extends T> rowMapper) {
N.checkArgNotNull(rowFilter, s.rowFilter);
N.checkArgNotNull(rowMapper, s.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
* @see BiResultExtractor#toList(Class)
*/
static ResultExtractor> toList(final Class extends T> targetClass) {
N.checkArgNotNull(targetClass, s.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, s.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, s.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, final Collection idPropNamesForMerge) {
N.checkArgNotNull(targetClass, s.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, s.keyExtractor);
N.checkArgNotNull(valueExtractor, s.valueExtractor);
N.checkArgNotNull(mergeFunction, s.mergeFunction);
N.checkArgNotNull(supplier, s.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, s.keyExtractor);
N.checkArgNotNull(valueExtractor, s.valueExtractor);
N.checkArgNotNull(multimapSupplier, s.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, s.keyExtractor);
N.checkArgNotNull(valueExtractor, s.valueExtractor);
N.checkArgNotNull(supplier, s.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.computeIfAbsent(key, k -> new ArrayList<>());
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());
}
/**
* Groups the result set into a map using the provided key and value extractors,
* downstream collector, and map supplier.
*
* @param The type of keys maintained by the map.
* @param The type of mapped values.
* @param The type of the result of the downstream collector.
* @param The type of the map.
* @param keyExtractor The function to extract keys from the result set.
* @param valueExtractor The function to extract values from the result set.
* @param downstream The collector to accumulate values associated with a key.
* @param supplier The supplier to provide a new map instance.
* @return A map containing the grouped keys and collected values.
*/
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, s.keyExtractor);
N.checkArgNotNull(valueExtractor, s.valueExtractor);
N.checkArgNotNull(downstream, s.downstream);
N.checkArgNotNull(supplier, s.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 (final 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, s.rowFilter);
N.checkArgNotNull(rowMapper, s.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
* @see ResultExtractor#toList(Class)
*/
@SequentialOnly
@Stateful
static BiResultExtractor> toList(final Class extends T> targetClass) {
N.checkArgNotNull(targetClass, s.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
*/
@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 from(final BiRowMapper extends T> biRowMapper) {
// N.checkArgNotNull(biRowMapper, "biRowMapper");
//
// return new RowMapper<>() {
// private List cls = null;
//
// @Override
// public T apply(ResultSet rs) throws SQLException {
// if (cls == null) {
// cls = JdbcUtil.getColumnLabelList(rs);
// }
//
// return biRowMapper.apply(rs, cls);
// }
// };
// }
/**
*
*
* @param
* @param
* @param rowMapper1
* @param rowMapper2
* @return
*/
static RowMapper> combine(final RowMapper extends T> rowMapper1, final RowMapper extends U> rowMapper2) {
N.checkArgNotNull(rowMapper1, s.rowMapper1);
N.checkArgNotNull(rowMapper2, s.rowMapper2);
return rs -> Tuple.of(rowMapper1.apply(rs), rowMapper2.apply(rs));
}
/**
*
*
* @param
* @param
* @param
* @param rowMapper1
* @param rowMapper2
* @param rowMapper3
* @return
*/
static RowMapper> combine(final RowMapper extends A> rowMapper1, final RowMapper extends B> rowMapper2,
final RowMapper extends C> rowMapper3) {
N.checkArgNotNull(rowMapper1, s.rowMapper1);
N.checkArgNotNull(rowMapper2, s.rowMapper2);
N.checkArgNotNull(rowMapper3, s.rowMapper3);
return rs -> Tuple.of(rowMapper1.apply(rs), rowMapper2.apply(rs), rowMapper3.apply(rs));
}
/**
*
*
* @param columnGetterForAll
* @return
*/
@Beta
@SequentialOnly
@Stateful
static RowMapper toArray(final ColumnGetter> columnGetterForAll) {
return new RowMapper<>() {
private int columnCount = -1;
@Override
public Object[] apply(final ResultSet rs) throws SQLException {
if (columnCount < 0) {
columnCount = JdbcUtil.getColumnCount(rs);
}
final Object[] result = new Object[columnCount];
for (int i = 0; i < columnCount; i++) {
result[i] = columnGetterForAll.apply(rs, i + 1);
}
return result;
}
};
}
/**
*
*
* @param columnGetterForAll
* @return
*/
@Beta
@SequentialOnly
@Stateful
static RowMapper> toList(final ColumnGetter> columnGetterForAll) {
return toCollection(columnGetterForAll, Factory.ofList());
}
/**
*
*
* @param