graphql.schema.diffing.SchemaDiffing Maven / Gradle / Ivy
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