<commit_before>package com.googlecode.totallylazy.records.sql;

import com.googlecode.totallylazy.Option;
import com.googlecode.totallylazy.Predicate;
import com.googlecode.totallylazy.Predicates;
import com.googlecode.totallylazy.Sequence;
import com.googlecode.totallylazy.iterators.StatefulIterator;
import com.googlecode.totallylazy.predicates.LogicalPredicate;
import com.googlecode.totallylazy.records.Keyword;
import com.googlecode.totallylazy.records.Record;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.Date;
import java.util.concurrent.Callable;

import static com.googlecode.totallylazy.Option.none;
import static com.googlecode.totallylazy.Option.some;
import static com.googlecode.totallylazy.Sequences.iterate;
import static com.googlecode.totallylazy.callables.LazyCallable.lazy;
import static com.googlecode.totallylazy.numbers.Numbers.increment;
import static com.googlecode.totallylazy.records.Keyword.keyword;
import static com.googlecode.totallylazy.records.MapRecord.record;

public class RecordIterator extends StatefulIterator<Record> {
    private final Callable<PreparedStatement> preparedStatement;
    private final Query query;
    private ResultSet resultSet;

    public RecordIterator(final Query query, final Callable<PreparedStatement> preparedStatement) {
        this.query = query;
        this.preparedStatement = lazy(preparedStatement);
    }

    @Override
    protected Option<Record> getNext() throws Exception {
        ResultSet resultSet = getResultSet();
        boolean hasNext = resultSet.next();
        if (!hasNext) {
            preparedStatement().close();
            return none();
        }

        final Record record = record();
        final ResultSetMetaData metaData = resultSet.getMetaData();
        for (Integer columnIndex : iterate(increment(), 1).take(metaData.getColumnCount()).safeCast(Integer.class)) {
            final String name = metaData.getColumnName(columnIndex);
            final Object value = getValue(resultSet, columnIndex, name);
            final Keyword keyword = keyword(name, value == null ? Object.class : value.getClass());
            record.set(keyword, value);
        }

        return some(record);
    }

    private Object getValue(ResultSet resultSet, Integer columnIndex, String name) throws SQLException {
        Sequence<Keyword> keywords = query.select();
        Option<Keyword> option = keywords.find(Predicates.<Keyword>equalTo(keyword(name)));
        if(!option.isEmpty()){
            Keyword keyword = option.get();
            Class aClass = keyword.forClass();
            if(aClass.equals(Date.class)){
                return resultSet.getDate(name);
            }
        }
        return resultSet.getObject(columnIndex);
    }

    public PreparedStatement preparedStatement() throws Exception {
        return preparedStatement.call();
    }

    private ResultSet getResultSet() throws Exception {
        if(resultSet == null){
            resultSet = preparedStatement().executeQuery();
        }
        return resultSet;
    }
}
<commit_msg>Made sure that java Date returned from SQL actually be a normal java.util.Date - so dropping the nanos. Also provided java.sql.Timestamp if you do care about nanos<commit_after>package com.googlecode.totallylazy.records.sql;

import com.googlecode.totallylazy.Option;
import com.googlecode.totallylazy.Predicate;
import com.googlecode.totallylazy.Predicates;
import com.googlecode.totallylazy.Sequence;
import com.googlecode.totallylazy.iterators.StatefulIterator;
import com.googlecode.totallylazy.predicates.LogicalPredicate;
import com.googlecode.totallylazy.records.Keyword;
import com.googlecode.totallylazy.records.Record;

import java.sql.*;
import java.util.Date;
import java.util.concurrent.Callable;

import static com.googlecode.totallylazy.Option.none;
import static com.googlecode.totallylazy.Option.some;
import static com.googlecode.totallylazy.Sequences.iterate;
import static com.googlecode.totallylazy.callables.LazyCallable.lazy;
import static com.googlecode.totallylazy.numbers.Numbers.increment;
import static com.googlecode.totallylazy.records.Keyword.keyword;
import static com.googlecode.totallylazy.records.MapRecord.record;

public class RecordIterator extends StatefulIterator<Record> {
    private final Callable<PreparedStatement> preparedStatement;
    private final Query query;
    private ResultSet resultSet;

    public RecordIterator(final Query query, final Callable<PreparedStatement> preparedStatement) {
        this.query = query;
        this.preparedStatement = lazy(preparedStatement);
    }

    @Override
    protected Option<Record> getNext() throws Exception {
        ResultSet resultSet = getResultSet();
        boolean hasNext = resultSet.next();
        if (!hasNext) {
            preparedStatement().close();
            return none();
        }

        final Record record = record();
        final ResultSetMetaData metaData = resultSet.getMetaData();
        for (Integer columnIndex : iterate(increment(), 1).take(metaData.getColumnCount()).safeCast(Integer.class)) {
            final String name = metaData.getColumnName(columnIndex);
            final Object value = getValue(resultSet, columnIndex, name);
            final Keyword keyword = keyword(name, value == null ? Object.class : value.getClass());
            record.set(keyword, value);
        }

        return some(record);
    }

    private Object getValue(ResultSet resultSet, Integer columnIndex, String name) throws SQLException {
        Sequence<Keyword> keywords = query.select();
        Option<Keyword> option = keywords.find(Predicates.<Keyword>equalTo(keyword(name)));
        if(!option.isEmpty()){
            Keyword keyword = option.get();
            Class aClass = keyword.forClass();
            if(aClass.equals(Date.class)){
                return new Date(resultSet.getTimestamp(name).getTime());
            }
            if(aClass.equals(Timestamp.class)){
                return resultSet.getTimestamp(name);
            }
        }
        return resultSet.getObject(columnIndex);
    }

    public PreparedStatement preparedStatement() throws Exception {
        return preparedStatement.call();
    }

    private ResultSet getResultSet() throws Exception {
        if(resultSet == null){
            resultSet = preparedStatement().executeQuery();
        }
        return resultSet;
    }
}

{'fraction_non_alphanumeric': 0.09566953316953317, 'fraction_numerical': 0.0003071253071253071, 'mean_word_length': 3.4855371900826446, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '416580', 'n_tokens_mistral': 1743, 'n_tokens_neox': 1725, 'n_words': 375}