All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.itsallcode.jdbc.resultset.SimpleResultSet Maven / Gradle / Ivy

There is a newer version: 0.7.1
Show newest version
package org.itsallcode.jdbc.resultset;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
import java.util.stream.*;

import org.itsallcode.jdbc.Context;
import org.itsallcode.jdbc.UncheckedSQLException;

/**
 * This class wraps a {@link ResultSet} and allows easy iteration via
 * {@link Iterator}, {@link List} or {@link Stream}.
 * 
 * @param  row type
 */
public class SimpleResultSet implements AutoCloseable, Iterable {
    private final ResultSet resultSet;
    private final ContextRowMapper rowMapper;
    private final Context context;
    private Iterator iterator;

    /**
     * Create a new instance.
     * 
     * @param context   database context
     * @param resultSet the underlying result set
     * @param rowMapper a row mapper for converting each row
     */
    public SimpleResultSet(final Context context, final ResultSet resultSet, final ContextRowMapper rowMapper) {
        this.context = context;
        this.resultSet = resultSet;
        this.rowMapper = rowMapper;
    }

    /**
     * Get in {@link Iterator} of all rows.
     * 
     * @return an interator with all rows.
     */
    @Override
    public Iterator iterator() {
        if (iterator != null) {
            throw new IllegalStateException("Only one iterator allowed per ResultSet");
        }
        iterator = ResultSetIterator.create(context, this, rowMapper);
        return iterator;
    }

    /**
     * Collect all rows to a list.
     * 
     * @return a list with all rows.
     */
    public List toList() {
        return stream().collect(Collectors.toList());
    }

    /**
     * Get a stream of all rows.
     * 
     * @return a stream with all rows.
     */
    public Stream stream() {
        final Spliterator spliterator = Spliterators.spliteratorUnknownSize(this.iterator(), Spliterator.ORDERED);
        return StreamSupport.stream(spliterator, false)
                .onClose(this::close);
    }

    /**
     * Close the underlying {@link ResultSet}.
     * 
     * @throws UncheckedSQLException if closing fails.
     */
    @Override
    public void close() {
        try {
            resultSet.close();
        } catch (final SQLException e) {
            throw new UncheckedSQLException("Error closing resultset", e);
        }
    }

    private boolean next() {
        try {
            return resultSet.next();
        } catch (final SQLException e) {
            throw new UncheckedSQLException("Error getting next row", e);
        }
    }

    private static class ResultSetIterator implements Iterator {
        private final Context context;
        private final SimpleResultSet resultSet;
        private final ContextRowMapper rowMapper;
        private boolean hasNext;
        private int currentRowIndex = 0;

        private ResultSetIterator(final Context context, final SimpleResultSet simpleResultSet,
                final ContextRowMapper rowMapper,
                final boolean hasNext) {
            this.context = context;
            this.resultSet = simpleResultSet;
            this.rowMapper = rowMapper;
            this.hasNext = hasNext;
        }

        public static  Iterator create(final Context context, final SimpleResultSet simpleResultSet,
                final ContextRowMapper rowMapper) {
            final boolean firstRowExists = simpleResultSet.next();
            return new ResultSetIterator<>(context, simpleResultSet, rowMapper, firstRowExists);
        }

        @Override
        public boolean hasNext() {
            return hasNext;
        }

        @Override
        public T next() {
            if (!hasNext) {
                throw new NoSuchElementException();
            }
            final T row = mapRow();
            hasNext = resultSet.next();
            currentRowIndex++;
            return row;
        }

        private T mapRow() {
            try {
                return rowMapper.mapRow(context, resultSet.resultSet, currentRowIndex);
            } catch (final SQLException e) {
                throw new UncheckedSQLException("Error mapping row " + currentRowIndex, e);
            } catch (final RuntimeException e) {
                throw new IllegalStateException("Error mapping row " + currentRowIndex + ": " + e.getMessage(), e);
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy