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

com.kenshoo.pl.entity.internal.fetch.ExecutionPlan Maven / Gradle / Ivy

Go to download

A Java persistence layer based on JOOQ for high performance and business flow support.

There is a newer version: 0.1.121-jooq-3.16.3
Show newest version
package com.kenshoo.pl.entity.internal.fetch;

import com.google.common.collect.Lists;
import com.kenshoo.jooq.DataTable;
import com.kenshoo.pl.entity.EntityField;
import com.kenshoo.pl.entity.EntityType;
import org.jooq.lambda.Seq;
import org.jooq.lambda.tuple.Tuple2;

import java.util.*;
import java.util.function.Predicate;

import static java.util.stream.Collectors.toSet;
import static org.jooq.lambda.Seq.seq;
import static org.jooq.lambda.function.Functions.not;

public class ExecutionPlan {

    private final OneToOnePlan oneToOnePlan;
    private final List> manyToOnePlans;


    public ExecutionPlan(DataTable startingTable, Collection> fieldsToFetch) {
        final Map>> remainingPrimaryTables = targetTableToFieldsOf(fieldsToFetch, startingTable);

        final TreeEdge startingEdge = new TreeEdge(null, startingTable);
        final List oneToOnePaths = Lists.newArrayList();
        final List> manyToOneCandidates = Lists.newArrayList();

        BFS.visit(startingEdge, this::edgesComingOutOf)
                .limitUntil(__ -> remainingPrimaryTables.isEmpty())
                .forEach(currentEdge -> {
                    final DataTable table = currentEdge.target.table;

                    List fields = remainingPrimaryTables.get(table);
                    if (currentEdge != startingEdge && fields != null) {
                        remainingPrimaryTables.remove(table);
                        oneToOnePaths.add(currentEdge);
                    }
                    seq(remainingPrimaryTables).filter(referencing(table)).forEach(manyToOneEntry -> {
                        final TreeEdge sourceEdge = currentEdge == startingEdge ? null : currentEdge;
                        manyToOneCandidates.add(new ManyToOnePlan(new TreeEdge(new TreeNode(sourceEdge, table), manyToOneEntry.v1), manyToOneEntry.v2));
                    });
                });

        if (seq(remainingPrimaryTables.keySet()).anyMatch(notMany(manyToOneCandidates))) {
            throw new IllegalStateException("Some tables " + remainingPrimaryTables + " could not be reached via joins");
        }

        final List> oneToOneFields = seq(fieldsToFetch).filter(tableIn(oneToOnePaths).or(tableEqual(startingTable))).toList();
        this.oneToOnePlan = new OneToOnePlan(oneToOnePaths, oneToOneFields, oneToOneSecondaryTablesOf(fieldsToFetch));
        this.manyToOnePlans = seq(manyToOneCandidates).filter(notIn(oneToOnePaths)).toList();
    }

    public OneToOnePlan getOneToOnePlan() {
        return oneToOnePlan;
    }

    public List> getManyToOnePlans() {
        return manyToOnePlans;
    }


    private Map>> targetTableToFieldsOf(Collection> fieldsToFetch, DataTable startingTable) {
        return seq(fieldsToFetch)
                .filter(field -> !field.getEntityType().getPrimaryTable().equals(startingTable))
                .groupBy(this::parimaryTableOf);
    }

    private Set oneToOneSecondaryTablesOf(Collection> fields) {
        return fields.stream()
                .filter(not(isOfPrimaryTable()))
                .map(field -> com.kenshoo.pl.entity.internal.fetch.OneToOneTableRelation.builder()
                        .secondary(field.getDbAdapter().getTable())
                        .primary(field.getEntityType().getPrimaryTable())
                        .build())
                .collect(toSet());
    }

    private Predicate> isOfPrimaryTable() {
        return field -> field.getDbAdapter().getTable().equals(field.getEntityType().getPrimaryTable());
    }

    private DataTable parimaryTableOf(EntityField field) {
        return field.getEntityType().getPrimaryTable();
    }

    private Predicate>>> referencing(DataTable table) {
        return entry -> entry.v1.getReferencesTo(table).size() == 1;
    }

    private Predicate> tableIn(List oneToOnePaths) {
        return field -> seq(oneToOnePaths).anyMatch(path -> field.getEntityType().getPrimaryTable().equals(path.target.table));
    }

    private Predicate> tableEqual(DataTable table) {
        return field -> table.equals(field.getEntityType().getPrimaryTable());
    }

    private Predicate notMany(List> manyToOnePlans) {
        return table -> seq(manyToOnePlans).noneMatch(plan -> table.equals(plan.getPath().target.table));
    }

    private Predicate> notIn(List oneToOnePaths) {
        return plan -> seq(oneToOnePaths).noneMatch(path -> plan.getPath().target.table.equals(path.target.table));
    }

    private Seq edgesComingOutOf(TreeEdge edge) {
        return seq(edge.target.table.getReferences()).map(new ToEdgesOf(edge.target));
    }

    public static class ManyToOnePlan> {
        private final TreeEdge path;
        private final List> fields;

        ManyToOnePlan(TreeEdge path, List> fields) {
            this.path = path;
            this.fields = fields;
        }

        public TreeEdge getPath() {
            return path;
        }

        public List> getFields() {
            return fields;
        }
    }

    public static class OneToOnePlan {
        private final List paths;
        private final List> fields;
        private final Set secondaryTableRelations;

        OneToOnePlan(List paths, List> fields, Set secondaryTableRelations) {
            this.paths = paths;
            this.fields = fields;
            this.secondaryTableRelations = secondaryTableRelations;
        }

        public List getPaths() {
            return paths;
        }

        public List> getFields() {
            return fields;
        }

        public Set getSecondaryTableRelations() {
            return secondaryTableRelations;
        }
    }
}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy