/*
* 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 org.jdbi.v3.core.result;
import static java.util.Spliterators.spliteratorUnknownSize;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Optional;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import org.jdbi.v3.core.mapper.RowMapper;
import org.jdbi.v3.core.statement.StatementContext;
An Iterable
of values, usually mapped from a ResultSet
. Generally, ResultIterables may only be traversed once. Type parameters: - <T> – iterable element type
/**
* An {@link Iterable} of values, usually mapped from a {@link java.sql.ResultSet}. Generally, ResultIterables may only
* be traversed once.
*
* @param <T> iterable element type
*/
@FunctionalInterface
public interface ResultIterable<T> extends Iterable<T> {
Returns a ResultIterable backed by the given result set supplier, mapper, and context.
Params: - supplier – result set supplier
- mapper – row mapper
- ctx – statement context
Type parameters: - <T> – the mapped type
Returns: the result iterable
/**
* Returns a ResultIterable backed by the given result set supplier, mapper, and context.
*
* @param supplier result set supplier
* @param mapper row mapper
* @param ctx statement context
* @param <T> the mapped type
* @return the result iterable
*/
static <T> ResultIterable<T> of(Supplier<ResultSet> supplier, RowMapper<T> mapper, StatementContext ctx) {
return () -> {
try {
return new ResultSetResultIterator<>(supplier.get(), mapper, ctx);
} catch (SQLException e) {
try {
ctx.close();
} catch (Exception e1) {
e.addSuppressed(e1);
}
throw new ResultSetException("Unable to iterator result set", e, ctx);
}
};
}
Returns a ResultIterable backed by the given iterator.
Params: - iterator – the result iterator
Type parameters: - <T> – iterator element type
Returns: a ResultIterable
/**
* Returns a ResultIterable backed by the given iterator.
* @param iterator the result iterator
* @param <T> iterator element type
* @return a ResultIterable
*/
static <T> ResultIterable<T> of(ResultIterator<T> iterator) {
return () -> iterator;
}
Stream all the rows of the result set out with an Iterator
. The Iterator
must be closed to release database resources. Returns: the results as a streaming Iterator
/**
* Stream all the rows of the result set out
* with an {@code Iterator}. The {@code Iterator} must be
* closed to release database resources.
* @return the results as a streaming Iterator
*/
@Override
ResultIterator<T> iterator();
@Override
default void forEach(Consumer<? super T> action) {
try (ResultIterator<T> iterator = iterator()) {
iterator.forEachRemaining(action);
}
}
Get the only row in the result set.
Throws: - IllegalStateException – if zero or multiple rows are returned
Returns: the object mapped from the singular row in the results
/**
* Get the only row in the result set.
* @throws IllegalStateException if zero or multiple rows are returned
* @return the object mapped from the singular row in the results
*/
default T findOnly() {
try (ResultIterator<T> iter = iterator()) {
if (!iter.hasNext()) {
throw new IllegalStateException("No element found in 'only'");
}
final T r = iter.next();
if (iter.hasNext()) {
throw new IllegalStateException("Multiple elements found in 'only'");
}
return r;
}
}
Returns: the first row in the result set, if present.
/**
* @return the first row in the result set, if present.
*/
default Optional<T> findFirst() {
try (ResultIterator<T> iter = iterator()) {
return iter.hasNext() ? Optional.ofNullable(iter.next()) : Optional.empty();
}
}
Returns the stream of results.
Note: the returned stream owns database resources, and must be closed via a call to BaseStream.close()
, or by using the stream in a try-with-resources block:
try (Stream<T> stream = query.stream()) {
// do stuff with stream
}
See Also: Returns: the stream of results.
/**
* Returns the stream of results.
*
* <p>
* Note: the returned stream owns database resources, and must be closed via a call to {@link Stream#close()}, or
* by using the stream in a try-with-resources block:
* </p>
*
* <pre>
* try (Stream<T> stream = query.stream()) {
* // do stuff with stream
* }
* </pre>
*
* @return the stream of results.
*
* @see #useStream(StreamConsumer)
* @see #withStream(StreamCallback)
*/
default Stream<T> stream() {
ResultIterator<T> iterator = iterator();
return StreamSupport.stream(spliteratorUnknownSize(iterator, 0), false)
.onClose(iterator::close);
}
Passes the stream of results to the consumer. Database resources owned by the query are
released before this method returns.
Params: - consumer – a consumer which receives the stream of results.
Type parameters: - <X> – the exception type thrown by the callback, if any
Throws: - X – any exception thrown by the callback
/**
* Passes the stream of results to the consumer. Database resources owned by the query are
* released before this method returns.
*
* @param consumer a consumer which receives the stream of results.
* @param <X> the exception type thrown by the callback, if any
*
* @throws X any exception thrown by the callback
*/
default <X extends Exception> void useStream(StreamConsumer<T, X> consumer) throws X {
withStream(stream -> {
consumer.useStream(stream);
return null;
});
}
Passes the stream of results to the callback. Database resources owned by the query are
released before this method returns.
Params: - callback – a callback which receives the stream of results, and returns some result.
Type parameters: Throws: - X – any exception thrown by the callback
Returns: the value returned by the callback.
/**
* Passes the stream of results to the callback. Database resources owned by the query are
* released before this method returns.
*
* @param callback a callback which receives the stream of results, and returns some result.
* @param <R> the type returned by the callback
* @param <X> the exception type thrown by the callback, if any
*
* @return the value returned by the callback.
*
* @throws X any exception thrown by the callback
*/
default <R, X extends Exception> R withStream(StreamCallback<T, R, X> callback) throws X {
try (Stream<T> stream = stream()) {
return callback.withStream(stream);
}
}
Returns results in a List
. Returns: results in a List
.
/**
* Returns results in a {@link List}.
*
* @return results in a {@link List}.
*/
default List<T> list() {
return collect(Collectors.toList());
}
Collect the results into a container specified by a collector.
Params: - collector – the collector
Type parameters: - <R> – the generic type of the container
Returns: the container with the query result
/**
* Collect the results into a container specified by a collector.
*
* @param collector the collector
* @param <R> the generic type of the container
* @return the container with the query result
*/
default <R> R collect(Collector<T, ?, R> collector) {
try (Stream<T> stream = stream()) {
return stream.collect(collector);
}
}
Reduce the results. Using a BiFunction<U, T, U>
, repeatedly combine query results until only a single value remains. Params: - identity – the
U
to combine with the first result - accumulator – the function to apply repeatedly
Type parameters: - <U> – the accumulator type
Returns: the final U
/**
* Reduce the results. Using a {@code BiFunction<U, T, U>}, repeatedly
* combine query results until only a single value remains.
*
* @param <U> the accumulator type
* @param identity the {@code U} to combine with the first result
* @param accumulator the function to apply repeatedly
* @return the final {@code U}
*/
default <U> U reduce(U identity, BiFunction<U, T, U> accumulator) {
try (Stream<T> stream = stream()) {
return stream.reduce(identity, accumulator,
(u, v) -> {
throw new UnsupportedOperationException("parallel operation not supported");
});
}
}
}