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

org.babyfish.jimmer.sql.fetcher.impl.FetcherUtil Maven / Gradle / Ivy

There is a newer version: 0.9.19
Show newest version
package org.babyfish.jimmer.sql.fetcher.impl;

import org.babyfish.jimmer.meta.ImmutableProp;
import org.babyfish.jimmer.meta.ImmutableType;
import org.babyfish.jimmer.runtime.DraftSpi;
import org.babyfish.jimmer.runtime.Internal;
import org.babyfish.jimmer.sql.ast.Selection;
import org.babyfish.jimmer.sql.fetcher.Fetcher;
import org.babyfish.jimmer.sql.runtime.JSqlClientImplementor;
import org.jetbrains.annotations.Nullable;

import java.sql.Connection;
import java.util.*;
import java.util.function.Function;

public class FetcherUtil {

    private FetcherUtil() {}

    @SuppressWarnings("unchecked")
    public static void fetch(
            JSqlClientImplementor sqlClient,
            Connection con,
            List> selections,
            List rows
    ) {

        if (rows.isEmpty()) {
            return;
        }

        Map> columnMap = new LinkedHashMap<>();
        for (int i = 0; i < selections.size(); i++) {
            Selection selection = selections.get(i);
            if (selection instanceof FetcherSelection) {
                FetcherSelection fetcherSelection = (FetcherSelection) selection;
                Fetcher fetcher = fetcherSelection.getFetcher();
                if (!((FetcherImplementor)fetcher).__isSimpleFetcher() ||
                        hasReferenceFilter(fetcher.getImmutableType(), sqlClient) ||
                        fetcherSelection.getConverter() != null) {
                    columnMap.put(i, new ArrayList<>());
                }
            }
        }
        if (columnMap.isEmpty()) {
            return;
        }

        for (Object row : rows) {
            for (Map.Entry> e : columnMap.entrySet()) {
                int columnIndex = e.getKey();
                List columnValues = e.getValue();
                columnValues.add(ColumnAccessors.get(row, columnIndex));
            }
        }

        for (Map.Entry> e : columnMap.entrySet()) {
            int columnIndex = e.getKey();
            List fetchedList = e.getValue();
            FetcherSelection selection = (FetcherSelection) selections.get(columnIndex);
            Fetcher fetcher = selection.getFetcher();
            if (!((FetcherImplementor)fetcher).__isSimpleFetcher() || hasReferenceFilter(fetcher.getImmutableType(), sqlClient)) {
                fetchedList = Internal.produceList(
                        selection.getFetcher().getImmutableType(),
                        fetchedList,
                        values -> {
                            fetch(
                                    sqlClient,
                                    con,
                                    selection.getPath(),
                                    selection.getFetcher(),
                                    (List) values
                            );
                        }
                );
            }
            Function converter = (Function) selection.getConverter();
            if (converter != null) {
                List list = new ArrayList<>(fetchedList.size());
                for (Object fetched : fetchedList) {
                    list.add(fetched != null ? converter.apply(fetched) : null);
                }
                fetchedList = list;
            }
            e.setValue(fetchedList);
        }

        Map indexValueMap = new HashMap<>();
        ListIterator itr = (ListIterator) rows.listIterator();
        int rowIndex = 0;
        while (itr.hasNext()) {
            for (Map.Entry> e : columnMap.entrySet()) {
                int colIndex = e.getKey();
                Object value = e.getValue().get(rowIndex);
                indexValueMap.put(colIndex, value);
            }
            itr.set(ColumnAccessors.set(itr.next(), indexValueMap));
            rowIndex++;
        }
    }

    private static void fetch(
            JSqlClientImplementor sqlClient,
            Connection con,
            FetchPath path,
            Fetcher fetcher,
            List<@Nullable DraftSpi> drafts
    ) {
        FetcherContext.using(sqlClient, con, (ctx, isRoot) -> {
            ctx.addAll(path, fetcher, drafts);
            if (isRoot) {
                ctx.execute();
            }
        });
    }

    private static boolean hasReferenceFilter(ImmutableType type, JSqlClientImplementor sqlClient) {
        for (ImmutableProp prop : type.getSelectableReferenceProps().values()) {
            if (sqlClient.getFilters().getTargetFilter(prop) != null) {
                return true;
            }
        }
        return false;
    }
}