package com.codepoetics.octarine.jdbc; import com.codepoetics.octarine.records.*; import java.sql.ResultSet; import java.util.LinkedList; import java.util.List; import java.util.Optional; public interface RecordRowMapper extends RowMapper<Record> { ColumnMappings configure(ColumnMappings empty); default String columnNames() { StringBuilder sb = new StringBuilder(); configure(new ColumnMappings() { @Override public <T> ColumnMappings add(Key<? super T> key, String columnName, ColumnMapper<? extends T> columnMapper) { if (sb.length() != 0) { sb.append(", "); } sb.append(columnName); return this; } }); return sb.toString(); } @Override default Record map(ResultSet resultSet) { List<Value> columnValues = new LinkedList<>(); configure(new ColumnMappings() { private int index = 1; @Override public <T> ColumnMappings add(Key<? super T> key, String columnName, ColumnMapper<? extends T> columnMapper) { Optional<T> maybeColumnValue = Optional.ofNullable(columnMapper.apply(resultSet, index)); index += 1; maybeColumnValue.ifPresent(columnValue -> columnValues.add(key.of(columnValue))); return this; } }); return Record.of(columnValues); } default <T> RowMapper<Valid<T>> validAgainst(Schema<T> schema) { return resultSet -> schema.extract(RecordRowMapper.this.map(resultSet)); } interface ColumnMappings { <T> ColumnMappings add(Key<? super T> key, String columnName, ColumnMapper<? extends T> columnMapper); default <T> ColumnMappings add(Key<? super T> key, ColumnMapper<? extends T> columnMapper) { return add(key, key.name(), columnMapper); } } }