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

org.httprpc.kilo.sql.ResultSetAdapter Maven / Gradle / Ivy

There is a newer version: 4.9
Show newest version
/*
 * 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.httprpc.kilo.sql;

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.function.Function;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

/**
 * Provides access to the contents of a JDBC result set via the
 * {@link Iterable} interface. Individual rows are represented by mutable map
 * instances produced by the adapter's iterator.
 */
public class ResultSetAdapter implements Iterable>, AutoCloseable {
    private ResultSet resultSet;
    private Map> transforms;

    private ResultSetMetaData resultSetMetaData;

    private Iterator> iterator = new Iterator<>() {
        Boolean hasNext = null;

        @Override
        public boolean hasNext() {
            if (hasNext == null) {
                try {
                    hasNext = resultSet.next() ? Boolean.TRUE : Boolean.FALSE;
                } catch (SQLException exception) {
                    throw new RuntimeException(exception);
                }
            }

            return hasNext;
        }

        @Override
        public Map next() {
            if (!hasNext()) {
                throw new NoSuchElementException();
            }

            Map row = new LinkedHashMap<>();

            try {
                for (int i = 1, n = resultSetMetaData.getColumnCount(); i <= n; i++) {
                    var key = resultSetMetaData.getColumnLabel(i);

                    var value = resultSet.getObject(i);

                    if (value instanceof java.sql.Date date) {
                        value = date.toLocalDate();
                    } else if (value instanceof java.sql.Time time) {
                        value = time.toLocalTime();
                    } else if (value instanceof java.sql.Timestamp timestamp) {
                        value = timestamp.toInstant();
                    } else {
                        var transform = transforms.get(key);

                        if (transform != null && value != null) {
                            value = transform.apply(value);
                        }
                    }

                    row.put(key, value);
                }
            } catch (SQLException exception) {
                throw new RuntimeException(exception);
            }

            hasNext = null;

            return row;
        }
    };

    ResultSetAdapter(ResultSet resultSet, Map> transforms) {
        this.resultSet = resultSet;
        this.transforms = transforms;

        try {
            resultSetMetaData = resultSet.getMetaData();
        } catch (SQLException exception) {
            throw new RuntimeException(exception);
        }
    }

    /**
     * 

Returns an iterator over the results.

* *

Temporal values are converted as follows:

* *
    *
  • {@link java.sql.Date} - {@link java.time.LocalDate}
  • *
  • {@link java.sql.Time} - {@link java.time.LocalTime}
  • *
  • {@link java.sql.Timestamp} - {@link java.time.Instant}
  • *
* *

All other values are returned as is, or transformed as specified by * {@link QueryBuilder#select(Class[])}.

* * {@inheritDoc} */ @Override public Iterator> iterator() { return iterator; } /** * Closes the underlying result set. * {@inheritDoc} */ @Override public void close() throws SQLException { resultSet.close(); } /** * Returns a stream over the results. Closing the returned stream closes * the adapter along with the underlying result set. * * @return * A stream over the results. */ public Stream> stream() { return StreamSupport.stream(spliterator(), false).onClose(() -> { try { close(); } catch (SQLException exception) { throw new RuntimeException(exception); } }); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy