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

org.jooq.impl.ResultQueryTrait Maven / Gradle / Ivy

There is a newer version: 3.19.16
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.
 *
 * Other licenses:
 * -----------------------------------------------------------------------------
 * Commercial licenses for this work are available. These replace the above
 * Apache-2.0 license and offer limited warranties, support, maintenance, and
 * commercial database integrations.
 *
 * For more information, please visit: http://www.jooq.org/licenses
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */
package org.jooq.impl;

import static java.util.stream.Collectors.mapping;
import static java.util.stream.Collectors.toList;
import static org.jooq.Records.intoArray;
import static org.jooq.Records.intoGroups;
import static org.jooq.Records.intoList;
import static org.jooq.Records.intoMap;
import static org.jooq.Records.intoResultGroups;
import static org.jooq.Records.intoSet;
import static org.jooq.conf.SettingsTools.fetchIntermediateResult;
import static org.jooq.impl.DelayedArrayCollector.patch;
import static org.jooq.impl.Tools.blocking;
import static org.jooq.impl.Tools.indexOrFail;
import static org.jooq.tools.jdbc.JDBCUtils.safeClose;

import java.lang.reflect.Array;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.Spliterator;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.stream.Collector;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import org.jooq.CloseableResultQuery;
import org.jooq.Configuration;
import org.jooq.Converter;
import org.jooq.Cursor;
import org.jooq.Field;
import org.jooq.Name;
import org.jooq.QueryPartInternal;
import org.jooq.Record;
import org.jooq.Record1;
import org.jooq.Record10;
import org.jooq.Record11;
import org.jooq.Record12;
import org.jooq.Record13;
import org.jooq.Record14;
import org.jooq.Record15;
import org.jooq.Record16;
import org.jooq.Record17;
import org.jooq.Record18;
import org.jooq.Record19;
import org.jooq.Record2;
import org.jooq.Record20;
import org.jooq.Record21;
import org.jooq.Record22;
import org.jooq.Record3;
import org.jooq.Record4;
import org.jooq.Record5;
import org.jooq.Record6;
import org.jooq.Record7;
import org.jooq.Record8;
import org.jooq.Record9;
import org.jooq.RecordHandler;
import org.jooq.RecordMapper;
import org.jooq.Records;
import org.jooq.Result;
import org.jooq.ResultQuery;
import org.jooq.Results;
import org.jooq.Row;
import org.jooq.Select;
import org.jooq.Table;
import org.jooq.exception.DataAccessException;
import org.jooq.impl.R2DBC.BlockingRecordSubscription;
import org.jooq.impl.R2DBC.QuerySubscription;
import org.jooq.impl.R2DBC.ResultSubscriber;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.reactivestreams.Subscriber;

import io.r2dbc.spi.ConnectionFactory;

/**
 * All the common fetch logic of a {@link ResultQuery}.
 *
 * @author Lukas Eder
 */
interface ResultQueryTrait
extends
    QueryPartInternal,
    CloseableResultQuery,
    Mappable,
    FieldsTrait
{

    @Override
    default CloseableResultQuery coerce(Field... fields) {
        return coerce(Arrays.asList(fields));
    }



    @Override
    @SuppressWarnings({ "rawtypes", "unchecked" })
    default  CloseableResultQuery> coerce(Field field1) {
        return (CloseableResultQuery) coerce(new Field[] { field1 });
    }

    @Override
    @SuppressWarnings({ "rawtypes", "unchecked" })
    default  CloseableResultQuery> coerce(Field field1, Field field2) {
        return (CloseableResultQuery) coerce(new Field[] { field1, field2 });
    }

    @Override
    @SuppressWarnings({ "rawtypes", "unchecked" })
    default  CloseableResultQuery> coerce(Field field1, Field field2, Field field3) {
        return (CloseableResultQuery) coerce(new Field[] { field1, field2, field3 });
    }

    @Override
    @SuppressWarnings({ "rawtypes", "unchecked" })
    default  CloseableResultQuery> coerce(Field field1, Field field2, Field field3, Field field4) {
        return (CloseableResultQuery) coerce(new Field[] { field1, field2, field3, field4 });
    }

    @Override
    @SuppressWarnings({ "rawtypes", "unchecked" })
    default  CloseableResultQuery> coerce(Field field1, Field field2, Field field3, Field field4, Field field5) {
        return (CloseableResultQuery) coerce(new Field[] { field1, field2, field3, field4, field5 });
    }

    @Override
    @SuppressWarnings({ "rawtypes", "unchecked" })
    default  CloseableResultQuery> coerce(Field field1, Field field2, Field field3, Field field4, Field field5, Field field6) {
        return (CloseableResultQuery) coerce(new Field[] { field1, field2, field3, field4, field5, field6 });
    }

    @Override
    @SuppressWarnings({ "rawtypes", "unchecked" })
    default  CloseableResultQuery> coerce(Field field1, Field field2, Field field3, Field field4, Field field5, Field field6, Field field7) {
        return (CloseableResultQuery) coerce(new Field[] { field1, field2, field3, field4, field5, field6, field7 });
    }

    @Override
    @SuppressWarnings({ "rawtypes", "unchecked" })
    default  CloseableResultQuery> coerce(Field field1, Field field2, Field field3, Field field4, Field field5, Field field6, Field field7, Field field8) {
        return (CloseableResultQuery) coerce(new Field[] { field1, field2, field3, field4, field5, field6, field7, field8 });
    }

    @Override
    @SuppressWarnings({ "rawtypes", "unchecked" })
    default  CloseableResultQuery> coerce(Field field1, Field field2, Field field3, Field field4, Field field5, Field field6, Field field7, Field field8, Field field9) {
        return (CloseableResultQuery) coerce(new Field[] { field1, field2, field3, field4, field5, field6, field7, field8, field9 });
    }

    @Override
    @SuppressWarnings({ "rawtypes", "unchecked" })
    default  CloseableResultQuery> coerce(Field field1, Field field2, Field field3, Field field4, Field field5, Field field6, Field field7, Field field8, Field field9, Field field10) {
        return (CloseableResultQuery) coerce(new Field[] { field1, field2, field3, field4, field5, field6, field7, field8, field9, field10 });
    }

    @Override
    @SuppressWarnings({ "rawtypes", "unchecked" })
    default  CloseableResultQuery> coerce(Field field1, Field field2, Field field3, Field field4, Field field5, Field field6, Field field7, Field field8, Field field9, Field field10, Field field11) {
        return (CloseableResultQuery) coerce(new Field[] { field1, field2, field3, field4, field5, field6, field7, field8, field9, field10, field11 });
    }

    @Override
    @SuppressWarnings({ "rawtypes", "unchecked" })
    default  CloseableResultQuery> coerce(Field field1, Field field2, Field field3, Field field4, Field field5, Field field6, Field field7, Field field8, Field field9, Field field10, Field field11, Field field12) {
        return (CloseableResultQuery) coerce(new Field[] { field1, field2, field3, field4, field5, field6, field7, field8, field9, field10, field11, field12 });
    }

    @Override
    @SuppressWarnings({ "rawtypes", "unchecked" })
    default  CloseableResultQuery> coerce(Field field1, Field field2, Field field3, Field field4, Field field5, Field field6, Field field7, Field field8, Field field9, Field field10, Field field11, Field field12, Field field13) {
        return (CloseableResultQuery) coerce(new Field[] { field1, field2, field3, field4, field5, field6, field7, field8, field9, field10, field11, field12, field13 });
    }

    @Override
    @SuppressWarnings({ "rawtypes", "unchecked" })
    default  CloseableResultQuery> coerce(Field field1, Field field2, Field field3, Field field4, Field field5, Field field6, Field field7, Field field8, Field field9, Field field10, Field field11, Field field12, Field field13, Field field14) {
        return (CloseableResultQuery) coerce(new Field[] { field1, field2, field3, field4, field5, field6, field7, field8, field9, field10, field11, field12, field13, field14 });
    }

    @Override
    @SuppressWarnings({ "rawtypes", "unchecked" })
    default  CloseableResultQuery> coerce(Field field1, Field field2, Field field3, Field field4, Field field5, Field field6, Field field7, Field field8, Field field9, Field field10, Field field11, Field field12, Field field13, Field field14, Field field15) {
        return (CloseableResultQuery) coerce(new Field[] { field1, field2, field3, field4, field5, field6, field7, field8, field9, field10, field11, field12, field13, field14, field15 });
    }

    @Override
    @SuppressWarnings({ "rawtypes", "unchecked" })
    default  CloseableResultQuery> coerce(Field field1, Field field2, Field field3, Field field4, Field field5, Field field6, Field field7, Field field8, Field field9, Field field10, Field field11, Field field12, Field field13, Field field14, Field field15, Field field16) {
        return (CloseableResultQuery) coerce(new Field[] { field1, field2, field3, field4, field5, field6, field7, field8, field9, field10, field11, field12, field13, field14, field15, field16 });
    }

    @Override
    @SuppressWarnings({ "rawtypes", "unchecked" })
    default  CloseableResultQuery> coerce(Field field1, Field field2, Field field3, Field field4, Field field5, Field field6, Field field7, Field field8, Field field9, Field field10, Field field11, Field field12, Field field13, Field field14, Field field15, Field field16, Field field17) {
        return (CloseableResultQuery) coerce(new Field[] { field1, field2, field3, field4, field5, field6, field7, field8, field9, field10, field11, field12, field13, field14, field15, field16, field17 });
    }

    @Override
    @SuppressWarnings({ "rawtypes", "unchecked" })
    default  CloseableResultQuery> coerce(Field field1, Field field2, Field field3, Field field4, Field field5, Field field6, Field field7, Field field8, Field field9, Field field10, Field field11, Field field12, Field field13, Field field14, Field field15, Field field16, Field field17, Field field18) {
        return (CloseableResultQuery) coerce(new Field[] { field1, field2, field3, field4, field5, field6, field7, field8, field9, field10, field11, field12, field13, field14, field15, field16, field17, field18 });
    }

    @Override
    @SuppressWarnings({ "rawtypes", "unchecked" })
    default  CloseableResultQuery> coerce(Field field1, Field field2, Field field3, Field field4, Field field5, Field field6, Field field7, Field field8, Field field9, Field field10, Field field11, Field field12, Field field13, Field field14, Field field15, Field field16, Field field17, Field field18, Field field19) {
        return (CloseableResultQuery) coerce(new Field[] { field1, field2, field3, field4, field5, field6, field7, field8, field9, field10, field11, field12, field13, field14, field15, field16, field17, field18, field19 });
    }

    @Override
    @SuppressWarnings({ "rawtypes", "unchecked" })
    default  CloseableResultQuery> coerce(Field field1, Field field2, Field field3, Field field4, Field field5, Field field6, Field field7, Field field8, Field field9, Field field10, Field field11, Field field12, Field field13, Field field14, Field field15, Field field16, Field field17, Field field18, Field field19, Field field20) {
        return (CloseableResultQuery) coerce(new Field[] { field1, field2, field3, field4, field5, field6, field7, field8, field9, field10, field11, field12, field13, field14, field15, field16, field17, field18, field19, field20 });
    }

    @Override
    @SuppressWarnings({ "rawtypes", "unchecked" })
    default  CloseableResultQuery> coerce(Field field1, Field field2, Field field3, Field field4, Field field5, Field field6, Field field7, Field field8, Field field9, Field field10, Field field11, Field field12, Field field13, Field field14, Field field15, Field field16, Field field17, Field field18, Field field19, Field field20, Field field21) {
        return (CloseableResultQuery) coerce(new Field[] { field1, field2, field3, field4, field5, field6, field7, field8, field9, field10, field11, field12, field13, field14, field15, field16, field17, field18, field19, field20, field21 });
    }

    @Override
    @SuppressWarnings({ "rawtypes", "unchecked" })
    default  CloseableResultQuery> coerce(Field field1, Field field2, Field field3, Field field4, Field field5, Field field6, Field field7, Field field8, Field field9, Field field10, Field field11, Field field12, Field field13, Field field14, Field field15, Field field16, Field field17, Field field18, Field field19, Field field20, Field field21, Field field22) {
        return (CloseableResultQuery) coerce(new Field[] { field1, field2, field3, field4, field5, field6, field7, field8, field9, field10, field11, field12, field13, field14, field15, field16, field17, field18, field19, field20, field21, field22 });
    }



    @Override
    default Cursor fetchLazy() throws DataAccessException {
        return new ResultAsCursor(fetch());
    }

    @Override
    default Results fetchMany() throws DataAccessException {
        throw new DataAccessException("Attempt to call fetchMany() on " + getClass());
    }

    default Cursor fetchLazyNonAutoClosing() {
        return fetchLazy();
    }

    @Override
    default ResultSet fetchResultSet() {
        if (fetchIntermediateResult(Tools.configuration(this)))
            return fetch().intoResultSet();
        else
            return (@NotNull ResultSet) fetchLazy().resultSet();
    }

    @Override
    default Iterator iterator() {
        return fetch().iterator();
    }

    @Override
    default CompletionStage> fetchAsync() {
        return fetchAsync(Tools.configuration(this).executorProvider().provide());
    }

    @Override
    default CompletionStage> fetchAsync(Executor executor) {
        return ExecutorProviderCompletionStage.of(CompletableFuture.supplyAsync(blocking(this::fetch), executor), () -> executor);
    }

    @Override
    default Stream fetchStream() {
        if (fetchIntermediateResult(Tools.configuration(this)))
            return fetch().stream();

        // [#11895] Don't use the Stream.of(1).flatMap(i -> fetchLazy().stream())
        //          trick, because flatMap() will consume the entire result set
        AtomicReference> r = new AtomicReference<>();

        // [#11895] Don't use the Stream.of(1).flatMap(i -> fetchLazy().stream())
        //          trick, because flatMap() will consume the entire result set
        return StreamSupport.stream(
            () -> {
                Cursor c = fetchLazy();
                r.set(c);
                return c.spliterator();
            },
            Spliterator.IMMUTABLE | Spliterator.NONNULL | Spliterator.ORDERED,
            false
        ).onClose(() -> {
            safeClose(r.get());
        });
    }

    @Override
    default  Stream fetchStreamInto(Class type) {
        return fetchStream().map(mapper(Tools.configuration(this), type));
    }

    @Override
    default  Stream fetchStreamInto(Table table) {
        return fetchStream().map(mapper(table));
    }

    @Override
    default Stream stream() {
        return fetchStream();
    }

    @Override
    default  X collect(Collector collector) {
        if (fetchIntermediateResult(Tools.configuration(this)))
            return patch(collector, fetch()).collect(collector);

        try (Cursor c = fetchLazyNonAutoClosing()) {
            return patch(collector, c).collect(collector);
        }
    }

    @Override
    default void subscribe(Subscriber subscriber) {
        ConnectionFactory cf = configuration().connectionFactory();

        if (!(cf instanceof NoConnectionFactory))
            subscriber.onSubscribe(new QuerySubscription<>(this, subscriber, ResultSubscriber::new));
        else
            subscriber.onSubscribe(new BlockingRecordSubscription<>(this, subscriber));
    }

    @Override
    default  List fetch(Field field) {
        return collect(intoList(mapper(field)));
    }

    @Override
    default  List fetch(Field field, Class type) {
        return collect(intoList(mapper(field, Tools.configuration(this), type)));
    }

    @Override
    default  List fetch(Field field, Converter converter) {
        return collect(intoList(mapper(field, converter)));
    }

    @Override
    default List fetch(int fieldIndex) {
        return collect(intoList(mapper(fieldIndex)));
    }

    @Override
    default  List fetch(int fieldIndex, Class type) {
        return collect(intoList(mapper(fieldIndex, Tools.configuration(this), type)));
    }

    @Override
    default  List fetch(int fieldIndex, Converter converter) {
        return collect(intoList(mapper(fieldIndex, converter)));
    }

    @Override
    default List fetch(String fieldName) {
        return collect(intoList(mapper(fieldName)));
    }

    @Override
    default  List fetch(String fieldName, Class type) {
        return collect(intoList(mapper(fieldName, Tools.configuration(this), type)));
    }

    @Override
    default  List fetch(String fieldName, Converter converter) {
        return collect(intoList(mapper(fieldName, converter)));
    }

    @Override
    default List fetch(Name fieldName) {
        return collect(intoList(mapper(fieldName)));
    }

    @Override
    default  List fetch(Name fieldName, Class type) {
        return collect(intoList(mapper(fieldName, Tools.configuration(this), type)));
    }

    @Override
    default  List fetch(Name fieldName, Converter converter) {
        return collect(intoList(mapper(fieldName, converter)));
    }

    @Override
    default  T fetchOne(Field field) {
        R record = fetchOne();
        return record == null ? null : record.get(field);
    }

    @Override
    default  U fetchOne(Field field, Class type) {
        R record = fetchOne();
        return record == null ? null : record.get(field, type);
    }

    @Override
    default  U fetchOne(Field field, Converter converter) {
        R record = fetchOne();
        return record == null ? null : record.get(field, converter);
    }

    @Override
    default Object fetchOne(int fieldIndex) {
        R record = fetchOne();
        return record == null ? null : record.get(fieldIndex);
    }

    @Override
    default  U fetchOne(int fieldIndex, Class type) {
        R record = fetchOne();
        return record == null ? null : record.get(fieldIndex, type);
    }

    @Override
    default  U fetchOne(int fieldIndex, Converter converter) {
        R record = fetchOne();
        return record == null ? null : record.get(fieldIndex, converter);
    }

    @Override
    default Object fetchOne(String fieldName) {
        R record = fetchOne();
        return record == null ? null : record.get(fieldName);
    }

    @Override
    default  U fetchOne(String fieldName, Class type) {
        R record = fetchOne();
        return record == null ? null : record.get(fieldName, type);
    }

    @Override
    default  U fetchOne(String fieldName, Converter converter) {
        R record = fetchOne();
        return record == null ? null : record.get(fieldName, converter);
    }

    @Override
    default Object fetchOne(Name fieldName) {
        R record = fetchOne();
        return record == null ? null : record.get(fieldName);
    }

    @Override
    default  U fetchOne(Name fieldName, Class type) {
        R record = fetchOne();
        return record == null ? null : record.get(fieldName, type);
    }

    @Override
    default  U fetchOne(Name fieldName, Converter converter) {
        R record = fetchOne();
        return record == null ? null : record.get(fieldName, converter);
    }

    @Override
    default R fetchOne() {
        return Tools.fetchOne(fetchLazyNonAutoClosing(), hasLimit1());
    }

    @Override
    default  E fetchOne(RecordMapper mapper) {
        R record = fetchOne();
        return record == null ? null : mapper.map(record);
    }

    @Override
    default Map fetchOneMap() {
        R record = fetchOne();
        return record == null ? null : record.intoMap();
    }

    @Override
    @Nullable
    default Object @Nullable [] fetchOneArray() {
        R record = fetchOne();
        return record == null ? null : record.intoArray();
    }

    @Override
    default  E fetchOneInto(Class type) {
        R record = fetchOne();
        return record == null ? null : record.into(type);
    }

    @Override
    default  Z fetchOneInto(Table table) {
        R record = fetchOne();
        return record == null ? null : record.into(table);
    }

    @Override
    default  T fetchSingle(Field field) {
        return fetchSingle().get(field);
    }

    @Override
    default  U fetchSingle(Field field, Class type) {
        return fetchSingle().get(field, type);
    }

    @Override
    default  U fetchSingle(Field field, Converter converter) {
        return fetchSingle().get(field, converter);
    }

    @Override
    default Object fetchSingle(int fieldIndex) {
        return fetchSingle().get(fieldIndex);
    }

    @Override
    default  U fetchSingle(int fieldIndex, Class type) {
        return fetchSingle().get(fieldIndex, type);
    }

    @Override
    default  U fetchSingle(int fieldIndex, Converter converter) {
        return fetchSingle().get(fieldIndex, converter);
    }

    @Override
    default Object fetchSingle(String fieldName) {
        return fetchSingle().get(fieldName);
    }

    @Override
    default  U fetchSingle(String fieldName, Class type) {
        return fetchSingle().get(fieldName, type);
    }

    @Override
    default  U fetchSingle(String fieldName, Converter converter) {
        return fetchSingle().get(fieldName, converter);
    }

    @Override
    default Object fetchSingle(Name fieldName) {
        return fetchSingle().get(fieldName);
    }

    @Override
    default  U fetchSingle(Name fieldName, Class type) {
        return fetchSingle().get(fieldName, type);
    }

    @Override
    default  U fetchSingle(Name fieldName, Converter converter) {
        return fetchSingle().get(fieldName, converter);
    }

    @Override
    default R fetchSingle() {
        return Tools.fetchSingle(fetchLazyNonAutoClosing(), hasLimit1());
    }

    @Override
    default  E fetchSingle(RecordMapper mapper) {
        return (@NotNull E) mapper.map(fetchSingle());
    }

    @Override
    default Map fetchSingleMap() {
        return fetchSingle().intoMap();
    }

    @Override
    @Nullable
    default Object @NotNull [] fetchSingleArray() {
        return fetchSingle().intoArray();
    }

    @Override
    default  E fetchSingleInto(Class type) {
        return fetchSingle().into(type);
    }

    @Override
    default  Z fetchSingleInto(Table table) {
        return fetchSingle().into(table);
    }

    @Override
    default  Optional fetchOptional(Field field) {
        return Optional.ofNullable(fetchOne(field));
    }

    @Override
    default  Optional fetchOptional(Field field, Class type) {
        return Optional.ofNullable(fetchOne(field, type));
    }

    @Override
    default  Optional fetchOptional(Field field, Converter converter) {
        return Optional.ofNullable(fetchOne(field, converter));
    }

    @Override
    default Optional fetchOptional(int fieldIndex) {
        return Optional.ofNullable(fetchOne(fieldIndex));
    }

    @Override
    default  Optional fetchOptional(int fieldIndex, Class type) {
        return Optional.ofNullable(fetchOne(fieldIndex, type));
    }

    @Override
    default  Optional fetchOptional(int fieldIndex, Converter converter) {
        return Optional.ofNullable(fetchOne(fieldIndex, converter));
    }

    @Override
    default Optional fetchOptional(String fieldName) {
        return Optional.ofNullable(fetchOne(fieldName));
    }

    @Override
    default  Optional fetchOptional(String fieldName, Class type) {
        return Optional.ofNullable(fetchOne(fieldName, type));
    }

    @Override
    default  Optional fetchOptional(String fieldName, Converter converter) {
        return Optional.ofNullable(fetchOne(fieldName, converter));
    }

    @Override
    default Optional fetchOptional(Name fieldName) {
        return Optional.ofNullable(fetchOne(fieldName));
    }

    @Override
    default  Optional fetchOptional(Name fieldName, Class type) {
        return Optional.ofNullable(fetchOne(fieldName, type));
    }

    @Override
    default  Optional fetchOptional(Name fieldName, Converter converter) {
        return Optional.ofNullable(fetchOne(fieldName, converter));
    }

    @Override
    default Optional fetchOptional() {
        return Optional.ofNullable(fetchOne());
    }

    @Override
    default  Optional fetchOptional(RecordMapper mapper) {
        return Optional.ofNullable(fetchOne(mapper));
    }

    @Override
    default Optional> fetchOptionalMap() {
        return Optional.ofNullable(fetchOneMap());
    }

    @Override
    default Optional fetchOptionalArray() {
        return Optional.ofNullable(fetchOneArray());
    }

    @Override
    default  Optional fetchOptionalInto(Class type) {
        return Optional.ofNullable(fetchOneInto(type));
    }

    @Override
    default  Optional fetchOptionalInto(Table table) {
        return Optional.ofNullable(fetchOneInto(table));
    }

    @Override
    default  T fetchAny(Field field) {
        R record = fetchAny();
        return record == null ? null : record.get(field);
    }

    @Override
    default  U fetchAny(Field field, Class type) {
        R record = fetchAny();
        return record == null ? null : record.get(field, type);
    }

    @Override
    default  U fetchAny(Field field, Converter converter) {
        R record = fetchAny();
        return record == null ? null : record.get(field, converter);
    }

    @Override
    default Object fetchAny(int fieldIndex) {
        R record = fetchAny();
        return record == null ? null : record.get(fieldIndex);
    }

    @Override
    default  U fetchAny(int fieldIndex, Class type) {
        R record = fetchAny();
        return record == null ? null : record.get(fieldIndex, type);
    }

    @Override
    default  U fetchAny(int fieldIndex, Converter converter) {
        R record = fetchAny();
        return record == null ? null : record.get(fieldIndex, converter);
    }

    @Override
    default Object fetchAny(String fieldName) {
        R record = fetchAny();
        return record == null ? null : record.get(fieldName);
    }

    @Override
    default  U fetchAny(String fieldName, Class type) {
        R record = fetchAny();
        return record == null ? null : record.get(fieldName, type);
    }

    @Override
    default  U fetchAny(String fieldName, Converter converter) {
        R record = fetchAny();
        return record == null ? null : record.get(fieldName, converter);
    }

    @Override
    default Object fetchAny(Name fieldName) {
        R record = fetchAny();
        return record == null ? null : record.get(fieldName);
    }

    @Override
    default  U fetchAny(Name fieldName, Class type) {
        R record = fetchAny();
        return record == null ? null : record.get(fieldName, type);
    }

    @Override
    default  U fetchAny(Name fieldName, Converter converter) {
        R record = fetchAny();
        return record == null ? null : record.get(fieldName, converter);
    }

    @Override
    default R fetchAny() {
        try (Cursor c = fetchLazyNonAutoClosing()) {
            return c.fetchNext();
        }
    }

    @Override
    default  E fetchAny(RecordMapper mapper) {
        R record = fetchAny();
        return record == null ? null : mapper.map(record);
    }

    @Override
    default Map fetchAnyMap() {
        R record = fetchAny();
        return record == null ? null : record.intoMap();
    }

    @Override
    @Nullable
    default Object @Nullable [] fetchAnyArray() {
        R record = fetchAny();
        return record == null ? null : record.intoArray();
    }

    @Override
    default  E fetchAnyInto(Class type) {
        R record = fetchAny();
        return record == null ? null : record.into(type);
    }

    @Override
    default  Z fetchAnyInto(Table table) {
        R record = fetchAny();
        return record == null ? null : record.into(table);
    }

    @Override
    default  Map fetchMap(Field key) {
        return collect(intoMap(mapper(key)));
    }

    @Override
    default Map fetchMap(int keyFieldIndex) {
        return collect(intoMap(mapper(keyFieldIndex)));
    }

    @Override
    default Map fetchMap(String keyFieldName) {
        return collect(intoMap(mapper(keyFieldName)));
    }

    @Override
    default Map fetchMap(Name keyFieldName) {
        return collect(intoMap(mapper(keyFieldName)));
    }

    @Override
    default  Map fetchMap(Field key, Field value) {
        return collect(intoMap(mapper(key), mapper(value)));
    }

    @Override
    default Map fetchMap(int keyFieldIndex, int valueFieldIndex) {
        return collect(intoMap(mapper(keyFieldIndex), mapper(valueFieldIndex)));
    }

    @Override
    default Map fetchMap(String keyFieldName, String valueFieldName) {
        return collect(intoMap(mapper(keyFieldName), mapper(valueFieldName)));
    }

    @Override
    default Map fetchMap(Name keyFieldName, Name valueFieldName) {
        return collect(intoMap(mapper(keyFieldName), mapper(valueFieldName)));
    }

    @Override
    default  Map fetchMap(Field key, Class type) {
        return collect(intoMap(mapper(key), mapper(Tools.configuration(this), type)));
    }

    @Override
    default  Map fetchMap(int keyFieldIndex, Class type) {
        return collect(intoMap(mapper(keyFieldIndex), mapper(Tools.configuration(this), type)));
    }

    @Override
    default  Map fetchMap(String keyFieldName, Class type) {
        return collect(intoMap(mapper(keyFieldName), mapper(Tools.configuration(this), type)));
    }

    @Override
    default  Map fetchMap(Name keyFieldName, Class type) {
        return collect(intoMap(mapper(keyFieldName), mapper(Tools.configuration(this), type)));
    }

    @Override
    default  Map fetchMap(Field key, RecordMapper mapper) {
        return collect(intoMap(mapper(key), mapper));
    }

    @Override
    default  Map fetchMap(int keyFieldIndex, RecordMapper mapper) {
        return collect(intoMap(mapper(keyFieldIndex), mapper));
    }

    @Override
    default  Map fetchMap(String keyFieldName, RecordMapper mapper) {
        return collect(intoMap(mapper(keyFieldName), mapper));
    }

    @Override
    default  Map fetchMap(Name keyFieldName, RecordMapper mapper) {
        return collect(intoMap(mapper(keyFieldName), mapper));
    }

    @Override
    default Map fetchMap(Field[] keys) {
        return collect(intoMap(mapper(keys)));
    }

    @Override
    default Map fetchMap(int[] keyFieldIndexes) {
        return collect(intoMap(mapper(keyFieldIndexes)));
    }

    @Override
    default Map fetchMap(String[] keyFieldNames) {
        return collect(intoMap(mapper(keyFieldNames)));
    }

    @Override
    default Map fetchMap(Name[] keyFieldNames) {
        return collect(intoMap(mapper(keyFieldNames)));
    }

    @Override
    default Map fetchMap(Field[] keys, Field[] values) {
        return collect(intoMap(mapper(keys), mapper(values)));
    }

    @Override
    default Map fetchMap(int[] keyFieldIndexes, int[] valueFieldIndexes) {
        return collect(intoMap(mapper(keyFieldIndexes), mapper(valueFieldIndexes)));
    }

    @Override
    default Map fetchMap(String[] keyFieldNames, String[] valueFieldNames) {
        return collect(intoMap(mapper(keyFieldNames), mapper(valueFieldNames)));
    }

    @Override
    default Map fetchMap(Name[] keyFieldNames, Name[] valueFieldNames) {
        return collect(intoMap(mapper(keyFieldNames), mapper(valueFieldNames)));
    }

    @Override
    default  Map, E> fetchMap(Field[] keys, Class type) {
        return collect(intoMap(mapper(keys).andThen(Record::intoList), mapper(Tools.configuration(this), type)));
    }

    @Override
    default  Map, E> fetchMap(int[] keyFieldIndexes, Class type) {
        return collect(intoMap(mapper(keyFieldIndexes).andThen(Record::intoList), mapper(Tools.configuration(this), type)));
    }

    @Override
    default  Map, E> fetchMap(String[] keyFieldNames, Class type) {
        return collect(intoMap(mapper(keyFieldNames).andThen(Record::intoList), mapper(Tools.configuration(this), type)));
    }

    @Override
    default  Map, E> fetchMap(Name[] keyFieldNames, Class type) {
        return collect(intoMap(mapper(keyFieldNames).andThen(Record::intoList), mapper(Tools.configuration(this), type)));
    }

    @Override
    default  Map, E> fetchMap(Field[] keys, RecordMapper mapper) {
        return collect(intoMap(mapper(keys).andThen(Record::intoList), mapper));
    }

    @Override
    default  Map, E> fetchMap(int[] keyFieldIndexes, RecordMapper mapper) {
        return collect(intoMap(mapper(keyFieldIndexes).andThen(Record::intoList), mapper));
    }

    @Override
    default  Map, E> fetchMap(String[] keyFieldNames, RecordMapper mapper) {
        return collect(intoMap(mapper(keyFieldNames).andThen(Record::intoList), mapper));
    }

    @Override
    default  Map, E> fetchMap(Name[] keyFieldNames, RecordMapper mapper) {
        return collect(intoMap(mapper(keyFieldNames).andThen(Record::intoList), mapper));
    }

    @Override
    default  Map fetchMap(Class keyType) {
        return collect(intoMap(mapper(Tools.configuration(this), keyType)));
    }

    @Override
    default  Map fetchMap(Class keyType, Class valueType) {
        return collect(intoMap(mapper(Tools.configuration(this), keyType), mapper(Tools.configuration(this), valueType)));
    }

    @Override
    default  Map fetchMap(Class keyType, RecordMapper valueMapper) {
        return collect(intoMap(mapper(Tools.configuration(this), keyType), valueMapper));
    }

    @Override
    default  Map fetchMap(RecordMapper keyMapper) {
        return collect(intoMap(keyMapper));
    }

    @Override
    default  Map fetchMap(RecordMapper keyMapper, Class valueType) {
        return collect(intoMap(keyMapper, mapper(Tools.configuration(this), valueType)));
    }

    @Override
    default  Map fetchMap(RecordMapper keyMapper, RecordMapper valueMapper) {
        return collect(intoMap(keyMapper, valueMapper));
    }

    @Override
    default  Map fetchMap(Table table) {
        return collect(intoMap(mapper(table)));
    }

    @Override
    default  Map fetchMap(Table keyTable, Table valueTable) {
        return collect(intoMap(mapper(keyTable), mapper(valueTable)));
    }

    @Override
    default  Map fetchMap(Table table, Class type) {
        return collect(intoMap(mapper(table), mapper(Tools.configuration(this), type)));
    }

    @Override
    default  Map fetchMap(Table table, RecordMapper mapper) {
        return collect(intoMap(mapper(table), mapper));
    }

    @Override
    default List> fetchMaps() {
        if (fetchIntermediateResult(Tools.configuration(this))) {
            return fetch().intoMaps();
        }
        else try (Cursor c = fetchLazy()) {
            return c.stream().collect(ArrayList::new, (l, r) -> l.add(r.intoMap()), ArrayList::addAll);
        }
    }

    @Override
    default  Map> fetchGroups(Field key) {
        return collect(intoResultGroups(mapper(key)));
    }

    @Override
    default Map> fetchGroups(int keyFieldIndex) {
        return collect(intoResultGroups(mapper(keyFieldIndex)));
    }

    @Override
    default Map> fetchGroups(String keyFieldName) {
        return collect(intoResultGroups(mapper(keyFieldName)));
    }

    @Override
    default Map> fetchGroups(Name keyFieldName) {
        return collect(intoResultGroups(mapper(keyFieldName)));
    }

    @Override
    default  Map> fetchGroups(Field key, Field value) {
        return collect(intoGroups(mapper(key), mapper(value)));
    }

    @Override
    default Map> fetchGroups(int keyFieldIndex, int valueFieldIndex) {
        return (Map) collect(intoGroups(mapper(keyFieldIndex), mapper(valueFieldIndex)));
    }

    @Override
    default Map> fetchGroups(String keyFieldName, String valueFieldName) {
        return (Map) collect(intoGroups(mapper(keyFieldName), mapper(valueFieldName)));
    }

    @Override
    default Map> fetchGroups(Name keyFieldName, Name valueFieldName) {
        return (Map) collect(intoGroups(mapper(keyFieldName), mapper(valueFieldName)));
    }

    @Override
    default  Map> fetchGroups(Field key, Class type) {
        return collect(intoGroups(mapper(key), mapper(Tools.configuration(this), type)));
    }

    @Override
    default  Map> fetchGroups(int keyFieldIndex, Class type) {
        return collect(intoGroups(mapper(keyFieldIndex), mapper(Tools.configuration(this), type)));
    }

    @Override
    default  Map> fetchGroups(String keyFieldName, Class type) {
        return collect(intoGroups(mapper(keyFieldName), mapper(Tools.configuration(this), type)));
    }

    @Override
    default  Map> fetchGroups(Name keyFieldName, Class type) {
        return collect(intoGroups(mapper(keyFieldName), mapper(Tools.configuration(this), type)));
    }

    @Override
    default  Map> fetchGroups(Field key, RecordMapper mapper) {
        return collect(intoGroups(mapper(key), mapper));
    }

    @Override
    default  Map> fetchGroups(int keyFieldIndex, RecordMapper mapper) {
        return collect(intoGroups(mapper(keyFieldIndex), mapper));
    }

    @Override
    default  Map> fetchGroups(String keyFieldName, RecordMapper mapper) {
        return collect(intoGroups(mapper(keyFieldName), mapper));
    }

    @Override
    default  Map> fetchGroups(Name keyFieldName, RecordMapper mapper) {
        return collect(intoGroups(mapper(keyFieldName), mapper));
    }

    @Override
    default Map> fetchGroups(Field[] keys) {
        return collect(intoResultGroups(mapper(keys)));
    }

    @Override
    default Map> fetchGroups(int[] keyFieldIndexes) {
        return collect(intoResultGroups(mapper(keyFieldIndexes)));
    }

    @Override
    default Map> fetchGroups(String[] keyFieldNames) {
        return collect(intoResultGroups(mapper(keyFieldNames)));
    }

    @Override
    default Map> fetchGroups(Name[] keyFieldNames) {
        return collect(intoResultGroups(mapper(keyFieldNames)));
    }

    @Override
    default Map> fetchGroups(Field[] keys, Field[] values) {
        return collect(intoResultGroups(mapper(keys), mapper(values)));
    }

    @Override
    default Map> fetchGroups(int[] keyFieldIndexes, int[] valueFieldIndexes) {
        return collect(intoResultGroups(mapper(keyFieldIndexes), mapper(valueFieldIndexes)));
    }

    @Override
    default Map> fetchGroups(String[] keyFieldNames, String[] valueFieldNames) {
        return collect(intoResultGroups(mapper(keyFieldNames), mapper(valueFieldNames)));
    }

    @Override
    default Map> fetchGroups(Name[] keyFieldNames, Name[] valueFieldNames) {
        return collect(intoResultGroups(mapper(keyFieldNames), mapper(valueFieldNames)));
    }

    @Override
    default  Map> fetchGroups(Field[] keys, Class type) {
        return collect(intoGroups(mapper(keys), mapper(Tools.configuration(this), type)));
    }

    @Override
    default  Map> fetchGroups(int[] keyFieldIndexes, Class type) {
        return collect(intoGroups(mapper(keyFieldIndexes), mapper(Tools.configuration(this), type)));
    }

    @Override
    default  Map> fetchGroups(String[] keyFieldNames, Class type) {
        return collect(intoGroups(mapper(keyFieldNames), mapper(Tools.configuration(this), type)));
    }

    @Override
    default  Map> fetchGroups(Name[] keyFieldNames, Class type) {
        return collect(intoGroups(mapper(keyFieldNames), mapper(Tools.configuration(this), type)));
    }

    @Override
    default  Map> fetchGroups(int[] keyFieldIndexes, RecordMapper mapper) {
        return collect(intoGroups(mapper(keyFieldIndexes), mapper));
    }

    @Override
    default  Map> fetchGroups(String[] keyFieldNames, RecordMapper mapper) {
        return collect(intoGroups(mapper(keyFieldNames), mapper));
    }

    @Override
    default  Map> fetchGroups(Name[] keyFieldNames, RecordMapper mapper) {
        return collect(intoGroups(mapper(keyFieldNames), mapper));
    }

    @Override
    default  Map> fetchGroups(Field[] keys, RecordMapper mapper) {
        return collect(intoGroups(mapper(keys), mapper));
    }

    @Override
    default  Map> fetchGroups(Class keyType) {
        return collect(intoResultGroups(mapper(Tools.configuration(this), keyType)));
    }

    @Override
    default  Map> fetchGroups(Class keyType, Class valueType) {
        return collect(intoGroups(mapper(Tools.configuration(this), keyType), mapper(Tools.configuration(this), valueType)));
    }

    @Override
    default  Map> fetchGroups(Class keyType, RecordMapper valueMapper) {
        return collect(intoGroups(mapper(Tools.configuration(this), keyType), valueMapper));
    }

    @Override
    default  Map> fetchGroups(RecordMapper keyMapper) {
        return collect(intoResultGroups(keyMapper));
    }

    @Override
    default  Map> fetchGroups(RecordMapper keyMapper, Class valueType) {
        return collect(intoGroups(keyMapper, mapper(Tools.configuration(this), valueType)));
    }

    @Override
    default  Map> fetchGroups(RecordMapper keyMapper, RecordMapper valueMapper) {
        return collect(intoGroups(keyMapper, valueMapper));
    }

    @Override
    default  Map> fetchGroups(Table table) {
        return collect(intoResultGroups(mapper(table)));
    }

    @Override
    default  Map> fetchGroups(Table keyTable, Table valueTable) {
        return collect(intoResultGroups(mapper(keyTable), mapper(valueTable)));
    }

    @Override
    default  Map> fetchGroups(Table table, Class type) {
        return collect(intoGroups(mapper(table), mapper(Tools.configuration(this), type)));
    }

    @Override
    default  Map> fetchGroups(Table table, RecordMapper mapper) {
        return collect(intoGroups(mapper(table), mapper));
    }

    @Override
    @Nullable
    default Object @NotNull [] @NotNull [] fetchArrays() {
        return collect(intoArray(new Object[0][], R::intoArray));
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    @Override
    @NotNull
    default R @NotNull [] fetchArray() {
        // [#9288] TODO: Create a delayed Collector that can delay the array type lookup until it's available
        Result r = fetch();

        if (r.isNotEmpty())
            return r.toArray((R[]) Array.newInstance(r.get(0).getClass(), r.size()));

        Class recordType;

        // TODO [#3185] Pull up getRecordType()
        if (this instanceof AbstractResultQuery a)
            recordType = a.getRecordType();
        else if (this instanceof SelectImpl s)
            recordType = s.getRecordType();
        else
            throw new DataAccessException("Attempt to call fetchArray() on " + getClass());

        return r.toArray((R[]) Array.newInstance(recordType, r.size()));
    }

    @SuppressWarnings("unchecked")
    @Override
    @Nullable
    default Object @NotNull [] fetchArray(int fieldIndex) {
        return collect(new DelayedArrayCollector<>(
            fields -> (Object[]) Array.newInstance(fields.field(indexOrFail(fields, fieldIndex)).getType(), 0),
            (RecordMapper) mapper(fieldIndex)
        ));
    }

    @Override
    default  U @NotNull [] fetchArray(int fieldIndex, Class type) {
        return collect(Records.intoArray(type, mapper(fieldIndex, Tools.configuration(this), type)));
    }

    @Override
    default  U @NotNull [] fetchArray(int fieldIndex, Converter converter) {
        return collect(Records.intoArray(converter.toType(), mapper(fieldIndex, converter)));
    }

    @SuppressWarnings("unchecked")
    @Override
    @Nullable
    default Object @NotNull [] fetchArray(String fieldName) {
        return collect(new DelayedArrayCollector<>(
            fields -> (Object[]) Array.newInstance(fields.field(indexOrFail(fields, fieldName)).getType(), 0),
            (RecordMapper) mapper(fieldName)
        ));
    }

    @Override
    default  U @NotNull [] fetchArray(String fieldName, Class type) {
        return collect(Records.intoArray(type, mapper(fieldName, Tools.configuration(this), type)));
    }

    @Override
    default  U @NotNull [] fetchArray(String fieldName, Converter converter) {
        return collect(Records.intoArray(converter.toType(), mapper(fieldName, converter)));
    }

    @SuppressWarnings("unchecked")
    @Override
    @Nullable
    default Object @NotNull [] fetchArray(Name fieldName) {
        return collect(new DelayedArrayCollector<>(
            fields -> (Object[]) Array.newInstance(fields.field(indexOrFail(fields, fieldName)).getType(), 0),
            (RecordMapper) mapper(fieldName)
        ));
    }

    @Override
    default  U @NotNull [] fetchArray(Name fieldName, Class type) {
        return collect(Records.intoArray(type, mapper(fieldName, Tools.configuration(this), type)));
    }

    @Override
    default  U @NotNull [] fetchArray(Name fieldName, Converter converter) {
        return collect(Records.intoArray(converter.toType(), mapper(fieldName, converter)));
    }

    @Override
    default  T @NotNull [] fetchArray(Field field) {
        return collect(Records.intoArray(field.getType(), mapper(field)));
    }

    @Override
    default  U @NotNull [] fetchArray(Field field, Class type) {
        return collect(Records.intoArray(type, mapper(field, Tools.configuration(this), type)));
    }

    @Override
    default  U @NotNull [] fetchArray(Field field, Converter converter) {
        return collect(Records.intoArray(converter.toType(), mapper(field, converter)));
    }

    @Override
    default  Set fetchSet(RecordMapper mapper) {
        return collect(intoSet(mapper));
    }

    @Override
    default Set fetchSet(int fieldIndex) {
        return collect(intoSet(mapper(fieldIndex)));
    }

    @Override
    default  Set fetchSet(int fieldIndex, Class type) {
        return collect(intoSet(mapper(fieldIndex, Tools.configuration(this), type)));
    }

    @Override
    default  Set fetchSet(int fieldIndex, Converter converter) {
        return collect(intoSet(mapper(fieldIndex, converter)));
    }

    @Override
    default Set fetchSet(String fieldName) {
        return collect(intoSet(mapper(fieldName)));
    }

    @Override
    default  Set fetchSet(String fieldName, Class type) {
        return collect(intoSet(mapper(fieldName, Tools.configuration(this), type)));
    }

    @Override
    default  Set fetchSet(String fieldName, Converter converter) {
        return collect(intoSet(mapper(fieldName, converter)));
    }

    @Override
    default Set fetchSet(Name fieldName) {
        return collect(intoSet(mapper(fieldName)));
    }

    @Override
    default  Set fetchSet(Name fieldName, Class type) {
        return collect(intoSet(mapper(fieldName, Tools.configuration(this), type)));
    }

    @Override
    default  Set fetchSet(Name fieldName, Converter converter) {
        return collect(intoSet(mapper(fieldName, converter)));
    }

    @Override
    default  Set fetchSet(Field field) {
        return collect(intoSet(mapper(field)));
    }

    @Override
    default  Set fetchSet(Field field, Class type) {
        return collect(intoSet(mapper(field, Tools.configuration(this), type)));
    }

    @Override
    default  Set fetchSet(Field field, Converter converter) {
        return collect(intoSet(mapper(field, converter)));
    }
    @Override
    default  List fetchInto(Class type) {
        return collect(intoList(mapper(Tools.configuration(this), type)));
    }

    @Override
    default  Result fetchInto(Table table) {
        if (fetchIntermediateResult(Tools.configuration(this))) {
            return fetch().into(table);
        }
        else try (Cursor c = fetchLazy()) {
            return c.fetchInto(table);
        }
    }

    @Override
    default > H fetchInto(H handler) {
        forEach(handler);
        return handler;
    }

    @Override
    default void forEach(Consumer action) {
        if (fetchIntermediateResult(Tools.configuration(this))) {
            fetch().forEach(action);
        }
        else try (Cursor c = fetchLazy()) {
            c.forEach(action);
        }
    }

    @Override
    default  List fetch(RecordMapper mapper) {
        return collect(mapping(mapper, toList()));
    }

    default boolean hasLimit1() {
        if (this instanceof Select q) {
            SelectQueryImpl s = Tools.selectQueryImpl(q);

            if (s != null) {
                Limit l = s.getLimit();
                return !l.withTies() && !l.percent() && l.limitOne();
            }
        }

        return false;
    }

    @Override
    default RecordMapper mapper(int fieldIndex) {
        return new DelayedRecordMapper<>(t -> t.mapper(fieldIndex));
    }

    @Override
    default  RecordMapper mapper(int fieldIndex, Configuration configuration, Class type) {
        return new DelayedRecordMapper<>(t -> t.mapper(fieldIndex, configuration, type));
    }

    @Override
    default  RecordMapper mapper(int fieldIndex, Converter converter) {
        return new DelayedRecordMapper<>(t -> t.mapper(fieldIndex, converter));
    }

    @Override
    default RecordMapper mapper(int[] fieldIndexes) {
        return new DelayedRecordMapper<>(t -> t.mapper(fieldIndexes));
    }

    @Override
    default RecordMapper mapper(String fieldName) {
        return new DelayedRecordMapper<>(t -> t.mapper(fieldName));
    }

    @Override
    default  RecordMapper mapper(String fieldName, Configuration configuration, Class type) {
        return new DelayedRecordMapper<>(t -> t.mapper(fieldName, configuration, type));
    }

    @Override
    default  RecordMapper mapper(String fieldName, Converter converter) {
        return new DelayedRecordMapper<>(t -> t.mapper(fieldName, converter));
    }

    @Override
    default RecordMapper mapper(String[] fieldNames) {
        return new DelayedRecordMapper<>(t -> t.mapper(fieldNames));
    }

    @Override
    default RecordMapper mapper(Name fieldName) {
        return new DelayedRecordMapper<>(t -> t.mapper(fieldName));
    }

    @Override
    default  RecordMapper mapper(Name fieldName, Configuration configuration, Class type) {
        return new DelayedRecordMapper<>(t -> t.mapper(fieldName, configuration, type));
    }

    @Override
    default  RecordMapper mapper(Name fieldName, Converter converter) {
        return new DelayedRecordMapper<>(t -> t.mapper(fieldName, converter));
    }

    @Override
    default RecordMapper mapper(Name[] fieldNames) {
        return new DelayedRecordMapper<>(t -> t.mapper(fieldNames));
    }

    @Override
    default  RecordMapper mapper(Field field) {
        return new DelayedRecordMapper<>(t -> t.mapper(field));
    }

    @Override
    default  RecordMapper mapper(Field field, Configuration configuration, Class type) {
        return new DelayedRecordMapper<>(t -> t.mapper(field, configuration, type));
    }

    @Override
    default  RecordMapper mapper(Field field, Converter converter) {
        return new DelayedRecordMapper<>(t -> t.mapper(field, converter));
    }

    @Override
    default RecordMapper mapper(Field[] fields) {
        return new DelayedRecordMapper<>(t -> t.mapper(fields));
    }

    @Override
    default  RecordMapper mapper(Table table) {
        return new DelayedRecordMapper<>(t -> t.mapper(table));
    }

    @Override
    default  RecordMapper mapper(Configuration configuration, Class type) {
        return new DelayedRecordMapper<>(t -> t.mapper(configuration, type));
    }

    // -------------------------------------------------------------------------
    // XXX: Fields API
    // -------------------------------------------------------------------------

    /**
     * Get a list of fields provided a result set.
     *
     * @throws SQLException If something goes wrong when accessing
     *             {@link ResultSetMetaData}.
     */
    default Field[] getFields(ThrowingSupplier rs) throws SQLException {
        return getFields();
    }

    /**
     * Get a list of fields if we don't have a result set.
     */
    Field[] getFields();

    @Override
    default Row fieldsRow() {
        return Tools.row0(getFields());
    }
}