001package org.itsallcode.jdbc.resultset;
002
003import java.sql.ResultSet;
004import java.sql.SQLException;
005import java.util.List;
006
007import org.itsallcode.jdbc.Context;
008import org.itsallcode.jdbc.dialect.DbDialect;
009import org.itsallcode.jdbc.resultset.generic.*;
010import org.itsallcode.jdbc.resultset.generic.GenericRowMapper.ColumnValuesConverter;
011
012/**
013 * Converts a single row from a {@link ResultSet} to a generic row type.
014 * 
015 * @param <T> generic row type
016 */
017@FunctionalInterface
018public interface ContextRowMapper<T> {
019
020    /**
021     * Converts a single row from a {@link ResultSet} to a generic row type.
022     * 
023     * @param context   database context
024     * @param resultSet result set
025     * @param rowNum    the current row number (zero based)
026     * @return the converted row
027     * @throws SQLException if accessing the result set fails
028     */
029    T mapRow(Context context, ResultSet resultSet, int rowNum) throws SQLException;
030
031    /**
032     * Create a {@link RowMapper} that creates generic {@link Row} objects.
033     * 
034     * @param dialect DB dialect
035     * @return a new row mapper
036     */
037    static RowMapper<Row> generic(final DbDialect dialect) {
038        return generic(dialect, row -> row);
039    }
040
041    /**
042     * Create a {@link RowMapper} that creates {@link List}s of simple column
043     * objects.
044     * 
045     * @param dialect DB dialect
046     * @return a new row mapper
047     */
048    static RowMapper<List<Object>> columnValueList(final DbDialect dialect) {
049        return generic(dialect, row -> row.columnValues().stream().map(ColumnValue::value).toList());
050    }
051
052    private static <T> RowMapper<T> generic(final DbDialect dialect, final ColumnValuesConverter<T> converter) {
053        return new GenericRowMapper<>(dialect, converter);
054    }
055
056    /**
057     * Creates a new new {@link ContextRowMapper} from a {@link SimpleRowMapper}.
058     * <p>
059     * Use this if the mapper doesn't need the {@link Context}.
060     * 
061     * @param <T>    generic row type
062     * @param mapper the simple row mapper
063     * @return a new {@link ContextRowMapper}
064     */
065    static <T> ContextRowMapper<T> create(final SimpleRowMapper<T> mapper) {
066        return (context, resultSet, rowNum) -> mapper.mapRow(resultSet);
067    }
068
069    /**
070     * Creates a new new {@link ContextRowMapper} from a {@link RowMapper}.
071     * <p>
072     * Use this if the mapper doesn't need the {@link Context}.
073     * 
074     * @param <T>    generic row type
075     * @param mapper the simple row mapper
076     * @return a new {@link ContextRowMapper}
077     */
078    static <T> ContextRowMapper<T> create(final RowMapper<T> mapper) {
079        return (context, resultSet, rowNum) -> mapper.mapRow(resultSet, rowNum);
080    }
081}