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

graphql.schema.diffing.SchemaDiffing Maven / Gradle / Ivy

There is a newer version: 230521-nf-execution
Show newest version
package graphql.schema.diffing;

import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimaps;
import graphql.Internal;
import graphql.schema.GraphQLSchema;
import graphql.schema.diffing.ana.EditOperationAnalysisResult;
import graphql.schema.diffing.ana.EditOperationAnalyzer;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

import static graphql.Assert.assertTrue;
import static graphql.schema.diffing.EditorialCostForMapping.baseEditorialCostForMapping;

@Internal
public class SchemaDiffing {
    private final SchemaDiffingRunningCheck runningCheck = new SchemaDiffingRunningCheck();

    SchemaGraph sourceGraph;
    SchemaGraph targetGraph;

    /**
     * Tries to stop the algorithm from execution ASAP by throwing a
     * {@link SchemaDiffingCancelledException}.
     */
    public void stop() {
        runningCheck.stop();
    }

    public List diffGraphQLSchema(GraphQLSchema graphQLSchema1, GraphQLSchema graphQLSchema2) throws Exception {
        sourceGraph = new SchemaGraphFactory("source-").createGraph(graphQLSchema1);
        targetGraph = new SchemaGraphFactory("target-").createGraph(graphQLSchema2);
        return diffImpl(sourceGraph, targetGraph, new AtomicInteger()).getListOfEditOperations();
    }

    public EditOperationAnalysisResult diffAndAnalyze(GraphQLSchema graphQLSchema1, GraphQLSchema graphQLSchema2) throws Exception {
        sourceGraph = new SchemaGraphFactory("source-").createGraph(graphQLSchema1);
        targetGraph = new SchemaGraphFactory("target-").createGraph(graphQLSchema2);
        DiffImpl.OptimalEdit optimalEdit = diffImpl(sourceGraph, targetGraph, new AtomicInteger());
        EditOperationAnalyzer editOperationAnalyzer = new EditOperationAnalyzer(graphQLSchema1, graphQLSchema1, sourceGraph, targetGraph);
        return editOperationAnalyzer.analyzeEdits(optimalEdit.getListOfEditOperations(), optimalEdit.mapping);
    }

    public DiffImpl.OptimalEdit diffGraphQLSchemaAllEdits(GraphQLSchema graphQLSchema1, GraphQLSchema graphQLSchema2, AtomicInteger algoIterationCount) throws Exception {
        sourceGraph = new SchemaGraphFactory("source-").createGraph(graphQLSchema1);
        targetGraph = new SchemaGraphFactory("target-").createGraph(graphQLSchema2);
        return diffImpl(sourceGraph, targetGraph, algoIterationCount);
    }


    private DiffImpl.OptimalEdit diffImpl(SchemaGraph sourceGraph, SchemaGraph targetGraph, AtomicInteger algoIterationCount) throws Exception {
        PossibleMappingsCalculator possibleMappingsCalculator = new PossibleMappingsCalculator(sourceGraph, targetGraph, runningCheck);
        PossibleMappingsCalculator.PossibleMappings possibleMappings = possibleMappingsCalculator.calculate();

        Mapping startMapping = Mapping.newMapping(
                possibleMappingsCalculator.getFixedParentRestrictions(),
                possibleMappings.fixedOneToOneMappings,
                possibleMappings.fixedOneToOneSources,
                possibleMappings.fixedOneToOneTargets);

        assertTrue(sourceGraph.size() == targetGraph.size());
        if (possibleMappings.fixedOneToOneMappings.size() == sourceGraph.size()) {
            return new DiffImpl.OptimalEdit(sourceGraph, targetGraph, startMapping, baseEditorialCostForMapping(startMapping, sourceGraph, targetGraph));
        }

        List nonMappedSource = new ArrayList<>(sourceGraph.getVertices());
        nonMappedSource.removeAll(possibleMappings.fixedOneToOneSources);

        List nonMappedTarget = new ArrayList<>(targetGraph.getVertices());
        nonMappedTarget.removeAll(possibleMappings.fixedOneToOneTargets);

        runningCheck.check();

        int isolatedSourceCount = (int) nonMappedSource.stream().filter(Vertex::isIsolated).count();
        int isolatedTargetCount = (int) nonMappedTarget.stream().filter(Vertex::isIsolated).count();
        if (isolatedTargetCount > isolatedSourceCount) {
            // we flip source and target because the algo works much faster with
            // this way for delete heavy graphs
            BiMap fixedOneToOneInverted = HashBiMap.create();
            for (Vertex s : possibleMappings.fixedOneToOneMappings.keySet()) {
                Vertex t = possibleMappings.fixedOneToOneMappings.get(s);
                fixedOneToOneInverted.put(t, s);
            }
            Mapping startMappingInverted = Mapping.newMapping(
                    possibleMappingsCalculator.getFixedParentRestrictionsInverse(fixedOneToOneInverted),
                    fixedOneToOneInverted,
                    possibleMappings.fixedOneToOneTargets,
                    possibleMappings.fixedOneToOneSources
            );
            HashMultimap invertedPossibleOnes = HashMultimap.create();
            Multimaps.invertFrom(possibleMappings.possibleMappings, invertedPossibleOnes);
            possibleMappings.possibleMappings = invertedPossibleOnes;

            sortVertices(nonMappedTarget, targetGraph, possibleMappings);

            List sourceVertices = new ArrayList<>();
            sourceVertices.addAll(possibleMappings.fixedOneToOneSources);
            sourceVertices.addAll(nonMappedSource);


            List targetVertices = new ArrayList<>();
            targetVertices.addAll(possibleMappings.fixedOneToOneTargets);
            targetVertices.addAll(nonMappedTarget);


            DiffImpl diffImpl = new DiffImpl(possibleMappingsCalculator, targetGraph, sourceGraph, possibleMappings, runningCheck);
            DiffImpl.OptimalEdit optimalEdit = diffImpl.diffImpl(startMappingInverted, targetVertices, sourceVertices, algoIterationCount);
            DiffImpl.OptimalEdit invertedBackOptimalEdit = new DiffImpl.OptimalEdit(sourceGraph, targetGraph, optimalEdit.mapping.invert(), optimalEdit.ged);
            return invertedBackOptimalEdit;
        } else {
            sortVertices(nonMappedSource, sourceGraph, possibleMappings);

            List sourceVertices = new ArrayList<>();
            sourceVertices.addAll(possibleMappings.fixedOneToOneSources);
            sourceVertices.addAll(nonMappedSource);

            List targetVertices = new ArrayList<>();
            targetVertices.addAll(possibleMappings.fixedOneToOneTargets);
            targetVertices.addAll(nonMappedTarget);

            DiffImpl diffImpl = new DiffImpl(possibleMappingsCalculator, sourceGraph, targetGraph, possibleMappings, runningCheck);
            DiffImpl.OptimalEdit optimalEdit = diffImpl.diffImpl(startMapping, sourceVertices, targetVertices, algoIterationCount);
            return optimalEdit;
        }
    }


    private void sortVertices(List vertices, SchemaGraph schemaGraph, PossibleMappingsCalculator.PossibleMappings possibleMappings) {
        Comparator vertexComparator = Comparator.comparing(schemaGraph::adjacentEdgesAndInverseCount).reversed();
        vertices.sort(vertexComparator);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy