org.jooq.lambda.SQL Maven / Gradle / Ivy
/**
* Copyright (c) 2014-2015, Data Geekery GmbH, [email protected]
*
* 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.jooq.lambda;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Spliterators;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
/**
* Simplifications for the JDBC APIs when used with Java 8.
*
* @author Lukas Eder
*/
public final class SQL {
/**
* Obtain a stream from a JDBC {@link ResultSet} that is obtained from a {@link PreparedStatement} with a row
* mapping function.
*
* Clients are responsible themselves for closing the ResultSet
.
*
* @param stmt The JDBC PreparedStatement
that generates a ResultSet
to be wrapped
* in a {@link Stream}
* @param rowFunction The row mapping function that maps ResultSet
rows to a custom type.
* @param The custom type.
* @return A Stream
wrapping the ResultSet
*/
public static Seq seq(PreparedStatement stmt, Function rowFunction) {
return seq(Unchecked.supplier(stmt::executeQuery), rowFunction, Unchecked.THROWABLE_TO_RUNTIME_EXCEPTION);
}
/**
* Obtain a stream from a JDBC {@link ResultSet} that is obtained from a {@link PreparedStatement} with a row
* mapping function.
*
* Clients are responsible themselves for closing the ResultSet
.
*
* @param stmt The JDBC PreparedStatement
that generates a ResultSet
to be
* wrapped in a {@link Stream}
* @param rowFunction The row mapping function that maps ResultSet
rows to a custom type.
* @param exceptionTranslator A custom exception translator.
* @param The custom type.
* @return A Stream
wrapping the ResultSet
*/
public static Seq seq(PreparedStatement stmt, Function rowFunction, Consumer super SQLException> exceptionTranslator) {
return seq(Unchecked.supplier(
stmt::executeQuery,
e -> exceptionTranslator.accept((SQLException) e)
), rowFunction, exceptionTranslator);
}
/**
* Obtain a stream from a JDBC {@link ResultSet} with a row mapping function.
*
* Clients are responsible themselves for closing the ResultSet
.
*
* @param rs The JDBC ResultSet
to wrap in a {@link Stream}
* @param rowFunction The row mapping function that maps ResultSet
rows to a custom type.
* @param The custom type.
* @return A Stream
wrapping the ResultSet
*/
public static Seq seq(ResultSet rs, Function rowFunction) {
return seq(() -> rs, rowFunction, Unchecked.THROWABLE_TO_RUNTIME_EXCEPTION);
}
/**
* Obtain a stream from a JDBC {@link ResultSet} with a row mapping function.
*
* Clients are responsible themselves for closing the ResultSet
.
*
* @param rs The JDBC ResultSet
to wrap in a {@link Stream}
* @param rowFunction The row mapping function that maps ResultSet
rows to a custom type.
* @param exceptionTranslator A custom exception translator.
* @param The custom type.
* @return A Stream
wrapping the ResultSet
*/
public static Seq seq(ResultSet rs, Function rowFunction, Consumer super SQLException> exceptionTranslator) {
return seq(() -> rs, rowFunction, exceptionTranslator);
}
/**
* Obtain a stream from a JDBC {@link ResultSet} {@link Supplier} with a row mapping function.
*
* Clients are responsible themselves for closing the ResultSet
.
*
* @param supplier The JDBC ResultSet
Supplier
to wrap in a {@link Stream}
* @param rowFunction The row mapping function that maps ResultSet
rows to a custom type.
* @param The custom type.
* @return A Stream
wrapping the ResultSet
*/
public static Seq seq(Supplier extends ResultSet> supplier, Function rowFunction) {
return seq(supplier, rowFunction, Unchecked.THROWABLE_TO_RUNTIME_EXCEPTION);
}
/**
* Obtain a stream from a JDBC {@link ResultSet} {@link Supplier} with a row mapping function.
*
* Clients are responsible themselves for closing the ResultSet
.
*
* @param supplier The JDBC ResultSet
Supplier
to wrap in a {@link Stream}
* @param rowFunction The row mapping function that maps ResultSet
rows to a custom type.
* @param exceptionTranslator A custom exception translator.
* @param The custom type.
* @return A Stream
wrapping the ResultSet
*/
public static Seq seq(Supplier extends ResultSet> supplier, Function rowFunction, Consumer super SQLException> exceptionTranslator) {
return Seq.seq(new ResultSetIterator<>(supplier, rowFunction, exceptionTranslator));
}
static class ResultSetIterator implements Iterator {
private final Supplier extends ResultSet> supplier;
private final Function rowFunction;
private final Consumer super SQLException> exceptionTranslator;
private ResultSet rs;
/**
* Whether the underlying {@link ResultSet} has a next row. This
* boolean has three states:
*
* - null: it's not known whether there is a next row
* - true: there is a next row, and it has been pre-fetched
* - false: there aren't any next rows
*
*/
private Boolean hasNext;
ResultSetIterator(Supplier extends ResultSet> supplier, Function rowFunction, Consumer super SQLException> exceptionTranslator) {
this.supplier = supplier;
this.rowFunction = rowFunction;
this.exceptionTranslator = exceptionTranslator;
}
private ResultSet rs() {
return (rs == null) ? (rs = supplier.get()) : rs;
}
@Override
public boolean hasNext() {
try {
if (hasNext == null) {
hasNext = rs().next();
}
if (!hasNext)
rs().close();
return hasNext;
}
catch (SQLException e) {
exceptionTranslator.accept(e);
throw new IllegalStateException("Must throw an exception in exceptionTranslator", e);
}
}
@Override
public T next() {
try {
if (!hasNext())
throw new NoSuchElementException();
return rowFunction.apply(rs());
}
finally {
hasNext = null;
}
}
}
private SQL() {
}
}