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

graphql.schema.diffing.ana.EditOperationAnalyzer Maven / Gradle / Ivy

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

import graphql.Assert;
import graphql.Internal;
import graphql.VisibleForTesting;
import graphql.schema.GraphQLSchema;
import graphql.schema.diffing.Edge;
import graphql.schema.diffing.EditOperation;
import graphql.schema.diffing.Mapping;
import graphql.schema.diffing.SchemaGraph;
import graphql.schema.diffing.Vertex;
import graphql.schema.diffing.ana.SchemaDifference.AppliedDirectiveArgumentAddition;
import graphql.schema.idl.ScalarInfo;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;

import static graphql.Assert.assertShouldNeverHappen;
import static graphql.Assert.assertTrue;
import static graphql.schema.diffing.ana.SchemaDifference.AppliedDirectiveAddition;
import static graphql.schema.diffing.ana.SchemaDifference.AppliedDirectiveArgumentDeletion;
import static graphql.schema.diffing.ana.SchemaDifference.AppliedDirectiveArgumentRename;
import static graphql.schema.diffing.ana.SchemaDifference.AppliedDirectiveArgumentValueModification;
import static graphql.schema.diffing.ana.SchemaDifference.AppliedDirectiveDeletion;
import static graphql.schema.diffing.ana.SchemaDifference.AppliedDirectiveDirectiveArgumentLocation;
import static graphql.schema.diffing.ana.SchemaDifference.AppliedDirectiveEnumLocation;
import static graphql.schema.diffing.ana.SchemaDifference.AppliedDirectiveEnumValueLocation;
import static graphql.schema.diffing.ana.SchemaDifference.AppliedDirectiveInputObjectFieldLocation;
import static graphql.schema.diffing.ana.SchemaDifference.AppliedDirectiveInputObjectLocation;
import static graphql.schema.diffing.ana.SchemaDifference.AppliedDirectiveInterfaceFieldArgumentLocation;
import static graphql.schema.diffing.ana.SchemaDifference.AppliedDirectiveInterfaceFieldLocation;
import static graphql.schema.diffing.ana.SchemaDifference.AppliedDirectiveInterfaceLocation;
import static graphql.schema.diffing.ana.SchemaDifference.AppliedDirectiveObjectFieldArgumentLocation;
import static graphql.schema.diffing.ana.SchemaDifference.AppliedDirectiveObjectFieldLocation;
import static graphql.schema.diffing.ana.SchemaDifference.AppliedDirectiveObjectLocation;
import static graphql.schema.diffing.ana.SchemaDifference.AppliedDirectiveScalarLocation;
import static graphql.schema.diffing.ana.SchemaDifference.AppliedDirectiveUnionLocation;
import static graphql.schema.diffing.ana.SchemaDifference.DirectiveAddition;
import static graphql.schema.diffing.ana.SchemaDifference.DirectiveArgumentAddition;
import static graphql.schema.diffing.ana.SchemaDifference.DirectiveArgumentDefaultValueModification;
import static graphql.schema.diffing.ana.SchemaDifference.DirectiveArgumentDeletion;
import static graphql.schema.diffing.ana.SchemaDifference.DirectiveArgumentRename;
import static graphql.schema.diffing.ana.SchemaDifference.DirectiveArgumentTypeModification;
import static graphql.schema.diffing.ana.SchemaDifference.DirectiveDeletion;
import static graphql.schema.diffing.ana.SchemaDifference.DirectiveDifference;
import static graphql.schema.diffing.ana.SchemaDifference.DirectiveModification;
import static graphql.schema.diffing.ana.SchemaDifference.EnumAddition;
import static graphql.schema.diffing.ana.SchemaDifference.EnumDeletion;
import static graphql.schema.diffing.ana.SchemaDifference.EnumDifference;
import static graphql.schema.diffing.ana.SchemaDifference.EnumModification;
import static graphql.schema.diffing.ana.SchemaDifference.EnumValueAddition;
import static graphql.schema.diffing.ana.SchemaDifference.EnumValueDeletion;
import static graphql.schema.diffing.ana.SchemaDifference.EnumValueRenamed;
import static graphql.schema.diffing.ana.SchemaDifference.InputObjectAddition;
import static graphql.schema.diffing.ana.SchemaDifference.InputObjectDeletion;
import static graphql.schema.diffing.ana.SchemaDifference.InputObjectDifference;
import static graphql.schema.diffing.ana.SchemaDifference.InputObjectFieldAddition;
import static graphql.schema.diffing.ana.SchemaDifference.InputObjectFieldDefaultValueModification;
import static graphql.schema.diffing.ana.SchemaDifference.InputObjectFieldDeletion;
import static graphql.schema.diffing.ana.SchemaDifference.InputObjectFieldRename;
import static graphql.schema.diffing.ana.SchemaDifference.InputObjectFieldTypeModification;
import static graphql.schema.diffing.ana.SchemaDifference.InputObjectModification;
import static graphql.schema.diffing.ana.SchemaDifference.InterfaceAddition;
import static graphql.schema.diffing.ana.SchemaDifference.InterfaceDeletion;
import static graphql.schema.diffing.ana.SchemaDifference.InterfaceDifference;
import static graphql.schema.diffing.ana.SchemaDifference.InterfaceFieldAddition;
import static graphql.schema.diffing.ana.SchemaDifference.InterfaceFieldArgumentAddition;
import static graphql.schema.diffing.ana.SchemaDifference.InterfaceFieldArgumentDefaultValueModification;
import static graphql.schema.diffing.ana.SchemaDifference.InterfaceFieldArgumentDeletion;
import static graphql.schema.diffing.ana.SchemaDifference.InterfaceFieldArgumentRename;
import static graphql.schema.diffing.ana.SchemaDifference.InterfaceFieldArgumentTypeModification;
import static graphql.schema.diffing.ana.SchemaDifference.InterfaceFieldDeletion;
import static graphql.schema.diffing.ana.SchemaDifference.InterfaceFieldRename;
import static graphql.schema.diffing.ana.SchemaDifference.InterfaceFieldTypeModification;
import static graphql.schema.diffing.ana.SchemaDifference.InterfaceInterfaceImplementationAddition;
import static graphql.schema.diffing.ana.SchemaDifference.InterfaceInterfaceImplementationDeletion;
import static graphql.schema.diffing.ana.SchemaDifference.InterfaceModification;
import static graphql.schema.diffing.ana.SchemaDifference.ObjectAddition;
import static graphql.schema.diffing.ana.SchemaDifference.ObjectDeletion;
import static graphql.schema.diffing.ana.SchemaDifference.ObjectDifference;
import static graphql.schema.diffing.ana.SchemaDifference.ObjectFieldAddition;
import static graphql.schema.diffing.ana.SchemaDifference.ObjectFieldArgumentAddition;
import static graphql.schema.diffing.ana.SchemaDifference.ObjectFieldArgumentDefaultValueModification;
import static graphql.schema.diffing.ana.SchemaDifference.ObjectFieldArgumentDeletion;
import static graphql.schema.diffing.ana.SchemaDifference.ObjectFieldArgumentRename;
import static graphql.schema.diffing.ana.SchemaDifference.ObjectFieldArgumentTypeModification;
import static graphql.schema.diffing.ana.SchemaDifference.ObjectFieldDeletion;
import static graphql.schema.diffing.ana.SchemaDifference.ObjectFieldRename;
import static graphql.schema.diffing.ana.SchemaDifference.ObjectFieldTypeModification;
import static graphql.schema.diffing.ana.SchemaDifference.ObjectInterfaceImplementationAddition;
import static graphql.schema.diffing.ana.SchemaDifference.ObjectInterfaceImplementationDeletion;
import static graphql.schema.diffing.ana.SchemaDifference.ObjectModification;
import static graphql.schema.diffing.ana.SchemaDifference.ScalarAddition;
import static graphql.schema.diffing.ana.SchemaDifference.ScalarDeletion;
import static graphql.schema.diffing.ana.SchemaDifference.ScalarDifference;
import static graphql.schema.diffing.ana.SchemaDifference.ScalarModification;
import static graphql.schema.diffing.ana.SchemaDifference.UnionAddition;
import static graphql.schema.diffing.ana.SchemaDifference.UnionDeletion;
import static graphql.schema.diffing.ana.SchemaDifference.UnionDifference;
import static graphql.schema.diffing.ana.SchemaDifference.UnionMemberAddition;
import static graphql.schema.diffing.ana.SchemaDifference.UnionMemberDeletion;
import static graphql.schema.diffing.ana.SchemaDifference.UnionModification;

/**
 * Higher level GraphQL semantic assigned to
 */
@Internal
public class EditOperationAnalyzer {

    private final GraphQLSchema oldSchema;
    private final GraphQLSchema newSchema;
    private final SchemaGraph oldSchemaGraph;
    private final SchemaGraph newSchemaGraph;

    private final Map objectDifferences = new LinkedHashMap<>();
    private final Map interfaceDifferences = new LinkedHashMap<>();
    private final Map unionDifferences = new LinkedHashMap<>();
    private final Map enumDifferences = new LinkedHashMap<>();
    private final Map inputObjectDifferences = new LinkedHashMap<>();
    private final Map scalarDifferences = new LinkedHashMap<>();

    private final Map directiveDifferences = new LinkedHashMap<>();

    public EditOperationAnalyzer(GraphQLSchema oldSchema,
                                 GraphQLSchema newSchema,
                                 SchemaGraph oldSchemaGraph,
                                 SchemaGraph newSchemaGraph
    ) {
        this.oldSchema = oldSchema;
        this.newSchema = newSchema;
        this.oldSchemaGraph = oldSchemaGraph;
        this.newSchemaGraph = newSchemaGraph;
    }

    public EditOperationAnalysisResult analyzeEdits(List editOperations, Mapping mapping) {
        editOperations = getTraversalOrder(editOperations);

        handleTypeVertexChanges(editOperations);

        for (EditOperation editOperation : editOperations) {
            switch (editOperation.getOperation()) {
                case CHANGE_VERTEX:
                    if (editOperation.getTargetVertex().isOfType(SchemaGraph.FIELD)) {
                        fieldChanged(editOperation);
                    } else if (editOperation.getTargetVertex().isOfType(SchemaGraph.ARGUMENT)) {
                        handleArgumentChange(editOperation, mapping);
                    } else if (editOperation.getTargetVertex().isOfType(SchemaGraph.INPUT_FIELD)) {
                        handleInputFieldChange(editOperation);
                    }
                    break;
                case INSERT_VERTEX:
                    if (editOperation.getTargetVertex().isOfType(SchemaGraph.FIELD)) {
                        fieldAdded(editOperation);
                    } else if (editOperation.getTargetVertex().isOfType(SchemaGraph.ARGUMENT)) {
                        argumentAdded(editOperation);
                    } else if (editOperation.getTargetVertex().isOfType(SchemaGraph.INPUT_FIELD)) {
                        inputFieldAdded(editOperation);
                    }
                    break;
                case DELETE_VERTEX:
                    if (editOperation.getSourceVertex().isOfType(SchemaGraph.ARGUMENT)) {
                        argumentDeleted(editOperation);
                    } else if (editOperation.getSourceVertex().isOfType(SchemaGraph.FIELD)) {
                        fieldDeleted(editOperation);
                    } else if (editOperation.getSourceVertex().isOfType(SchemaGraph.INPUT_FIELD)) {
                        inputFieldDeleted(editOperation);
                    }
            }
        }

        handleTypeChanges(editOperations, mapping);
        handleImplementsChanges(editOperations, mapping);
        handleUnionMemberChanges(editOperations, mapping);
        handleEnumValuesChanges(editOperations, mapping);
        handleAppliedDirectives(editOperations, mapping);
        handleArgumentChanges(editOperations, mapping);

        return new EditOperationAnalysisResult(
                objectDifferences,
                interfaceDifferences,
                unionDifferences,
                enumDifferences,
                inputObjectDifferences,
                scalarDifferences,
                directiveDifferences);
    }

    private void handleArgumentChanges(List editOperations, Mapping mapping) {
        for (EditOperation editOperation : editOperations) {
            switch (editOperation.getOperation()) {
                case INSERT_EDGE:
                    if (editOperation.getTargetEdge().getTo().isOfType(SchemaGraph.ARGUMENT)) {
                        argumentAdded(editOperation);
                    }
                    break;
                case DELETE_EDGE:
                    if (editOperation.getSourceEdge().getTo().isOfType(SchemaGraph.ARGUMENT)) {
                        argumentDeleted(editOperation);
                    }
                    break;
            }
        }
    }


    private void handleAppliedDirectives(List editOperations, Mapping mapping) {

        // first the applied directives itself and then all the applied arguments changes
        // for the applied directives, so that we check for example if the applied directive is
        // deleted before we check for the applied directive argument changes
        for (EditOperation editOperation : editOperations) {
            switch (editOperation.getOperation()) {
                case INSERT_VERTEX:
                    if (editOperation.getTargetVertex().isOfType(SchemaGraph.APPLIED_DIRECTIVE)) {
                        appliedDirectiveAdded(editOperation);
                    }
                    break;
                case CHANGE_VERTEX:
                    // TODO: handle applied directive changes
                    break;
                case DELETE_VERTEX:
                    if (editOperation.getSourceVertex().isOfType(SchemaGraph.APPLIED_DIRECTIVE)) {
                        appliedDirectiveDeleted(editOperation);
                    }
                    break;

            }
        }
        for (EditOperation editOperation : editOperations) {
            switch (editOperation.getOperation()) {
                case INSERT_VERTEX:
                    if (editOperation.getTargetVertex().isOfType(SchemaGraph.APPLIED_ARGUMENT)) {
                        appliedDirectiveArgumentAdded(editOperation);
                    }
                    break;
                case CHANGE_VERTEX:
                    if (editOperation.getTargetVertex().isOfType(SchemaGraph.APPLIED_ARGUMENT)) {
                        appliedDirectiveArgumentChanged(editOperation);
                    }
                    break;
                case DELETE_VERTEX:
                    if (editOperation.getSourceVertex().isOfType(SchemaGraph.APPLIED_ARGUMENT)) {
                        appliedDirectiveArgumentDeleted(editOperation);
                    }
                    break;

            }
        }

    }

    private void appliedDirectiveDeleted(EditOperation editOperation) {
        Vertex appliedDirective = editOperation.getSourceVertex();
        Vertex container = oldSchemaGraph.getAppliedDirectiveContainerForAppliedDirective(appliedDirective);
        if (container.isOfType(SchemaGraph.FIELD)) {
            appliedDirectiveDeletedFromField(appliedDirective, container);
        } else if (container.isOfType(SchemaGraph.ARGUMENT)) {
            appliedDirectiveDeletedFromArgument(appliedDirective, container);
        } else if (container.isOfType(SchemaGraph.OBJECT)) {
            Vertex object = container;
            if (isObjectDeleted(object.getName())) {
                return;
            }
            AppliedDirectiveObjectLocation location = new AppliedDirectiveObjectLocation(object.getName(), appliedDirective.getName());
            AppliedDirectiveDeletion appliedDirectiveDeletion = new AppliedDirectiveDeletion(location, appliedDirective.getName());
            getObjectModification(object.getName()).getDetails().add(appliedDirectiveDeletion);
        } else if (container.isOfType(SchemaGraph.INTERFACE)) {
            Vertex interfaze = container;
            if (isInterfaceDeleted(interfaze.getName())) {
                return;
            }
            AppliedDirectiveInterfaceLocation location = new AppliedDirectiveInterfaceLocation(interfaze.getName(), appliedDirective.getName());
            AppliedDirectiveDeletion appliedDirectiveDeletion = new AppliedDirectiveDeletion(location, appliedDirective.getName());
            getInterfaceModification(interfaze.getName()).getDetails().add(appliedDirectiveDeletion);
        } else if (container.isOfType(SchemaGraph.SCALAR)) {
            Vertex scalar = container;
            if (isScalarDeleted(scalar.getName())) {
                return;
            }
            AppliedDirectiveScalarLocation location = new AppliedDirectiveScalarLocation(scalar.getName(), appliedDirective.getName());
            AppliedDirectiveDeletion appliedDirectiveDeletion = new AppliedDirectiveDeletion(location, appliedDirective.getName());
            getScalarModification(scalar.getName()).getDetails().add(appliedDirectiveDeletion);
        } else if (container.isOfType(SchemaGraph.ENUM)) {
            Vertex enumVertex = container;
            if (isEnumDeleted(enumVertex.getName())) {
                return;
            }
            AppliedDirectiveEnumLocation location = new AppliedDirectiveEnumLocation(enumVertex.getName(), appliedDirective.getName());
            AppliedDirectiveDeletion appliedDirectiveDeletion = new AppliedDirectiveDeletion(location, appliedDirective.getName());
            getEnumModification(enumVertex.getName()).getDetails().add(appliedDirectiveDeletion);
        } else if (container.isOfType(SchemaGraph.ENUM_VALUE)) {
            Vertex enumValue = container;
            Vertex enumVertex = oldSchemaGraph.getEnumForEnumValue(enumValue);
            if (isEnumDeleted(enumVertex.getName())) {
                return;
            }
            if (isEnumValueDeletedFromExistingEnum(enumVertex.getName(), enumValue.getName())) {
                return;
            }
            AppliedDirectiveEnumValueLocation location = new AppliedDirectiveEnumValueLocation(enumVertex.getName(), enumValue.getName(), appliedDirective.getName());
            AppliedDirectiveDeletion appliedDirectiveDeletion = new AppliedDirectiveDeletion(location, appliedDirective.getName());
            getEnumModification(enumVertex.getName()).getDetails().add(appliedDirectiveDeletion);
        } else if (container.isOfType(SchemaGraph.INPUT_OBJECT)) {
            Vertex inputObject = container;
            if (isInputObjectDeleted(inputObject.getName())) {
                return;
            }
            AppliedDirectiveInputObjectLocation location = new AppliedDirectiveInputObjectLocation(inputObject.getName(), appliedDirective.getName());
            AppliedDirectiveDeletion appliedDirectiveDeletion = new AppliedDirectiveDeletion(location, appliedDirective.getName());
            getInputObjectModification(inputObject.getName()).getDetails().add(appliedDirectiveDeletion);
        } else if (container.isOfType(SchemaGraph.INPUT_FIELD)) {
            Vertex inputField = container;
            Vertex inputObject = oldSchemaGraph.getInputObjectForInputField(inputField);
            if (isInputObjectDeleted(inputObject.getName())) {
                return;
            }
            if (isInputFieldDeletedFromExistingInputObject(inputObject.getName(), inputField.getName())) {
                return;
            }
            AppliedDirectiveInputObjectFieldLocation location = new AppliedDirectiveInputObjectFieldLocation(inputObject.getName(), inputField.getName(), appliedDirective.getName());
            AppliedDirectiveDeletion appliedDirectiveDeletion = new AppliedDirectiveDeletion(location, appliedDirective.getName());
            getInputObjectModification(inputObject.getName()).getDetails().add(appliedDirectiveDeletion);
        } else if (container.isOfType(SchemaGraph.UNION)) {
            Vertex union = container;
            if (isUnionDeleted(union.getName())) {
                return;
            }
            AppliedDirectiveUnionLocation location = new AppliedDirectiveUnionLocation(union.getName(), appliedDirective.getName());
            AppliedDirectiveDeletion appliedDirectiveDeletion = new AppliedDirectiveDeletion(location, appliedDirective.getName());
            getUnionModification(union.getName()).getDetails().add(appliedDirectiveDeletion);
        }
    }

    private void appliedDirectiveArgumentDeleted(EditOperation editOperation) {
        Vertex deletedArgument = editOperation.getSourceVertex();
        Vertex appliedDirective = oldSchemaGraph.getAppliedDirectiveForAppliedArgument(deletedArgument);
        Vertex container = oldSchemaGraph.getAppliedDirectiveContainerForAppliedDirective(appliedDirective);

        if (container.isOfType(SchemaGraph.ARGUMENT)) {
            Vertex argument = container;
            Vertex fieldOrDirective = oldSchemaGraph.getFieldOrDirectiveForArgument(argument);
            if (fieldOrDirective.isOfType(SchemaGraph.FIELD)) {
                Vertex field = fieldOrDirective;
                Vertex fieldsContainer = oldSchemaGraph.getFieldsContainerForField(field);
                if (fieldsContainer.isOfType(SchemaGraph.OBJECT)) {
                    Vertex object = fieldsContainer;
                    if (isObjectDeleted(object.getName())) {
                        return;
                    }
                    if (isFieldDeletedFromExistingObject(object.getName(), field.getName())) {
                        return;
                    }
                    if (isArgumentDeletedFromExistingObjectField(object.getName(), field.getName(), argument.getName())) {
                        return;
                    }
                    if (isAppliedDirectiveDeleted(object, appliedDirective.getName())) {
                        return;
                    }
                    AppliedDirectiveObjectFieldArgumentLocation location = new AppliedDirectiveObjectFieldArgumentLocation(object.getName(), field.getName(), argument.getName(), appliedDirective.getName());
                    getObjectModification(object.getName()).getDetails().add(new AppliedDirectiveArgumentDeletion(location, deletedArgument.getName()));
                } else if (fieldsContainer.isOfType(SchemaGraph.INTERFACE)) {
                    Vertex interfaze = fieldsContainer;
                    if (isInterfaceDeleted(interfaze.getName())) {
                        return;
                    }
                    if (isFieldNewForExistingInterface(interfaze.getName(), field.getName())) {
                        return;
                    }
                    if (isArgumentDeletedFromExistingInterfaceField(interfaze.getName(), field.getName(), argument.getName())) {
                        return;
                    }
                    if (isAppliedDirectiveDeleted(interfaze, appliedDirective.getName())) {
                        return;
                    }
                    AppliedDirectiveInterfaceFieldArgumentLocation location = new AppliedDirectiveInterfaceFieldArgumentLocation(interfaze.getName(), field.getName(), argument.getName(), appliedDirective.getName());
                    getInterfaceModification(interfaze.getName()).getDetails().add(new AppliedDirectiveArgumentDeletion(location, deletedArgument.getName()));
                }
            } else if (fieldOrDirective.isOfType(SchemaGraph.DIRECTIVE)) {
                Vertex directive = fieldOrDirective;
                if (isDirectiveDeleted(directive.getName())) {
                    return;
                }
                if (isArgumentDeletedFromExistingDirective(directive.getName(), argument.getName())) {
                    return;
                }
                if (isAppliedDirectiveDeleted(fieldOrDirective, appliedDirective.getName())) {
                    return;
                }
                AppliedDirectiveDirectiveArgumentLocation location = new AppliedDirectiveDirectiveArgumentLocation(directive.getName(), argument.getName(), appliedDirective.getName());
                getDirectiveModification(directive.getName()).getDetails().add(new AppliedDirectiveArgumentDeletion(location, deletedArgument.getName()));
            }
        } else if (container.isOfType(SchemaGraph.FIELD)) {
            Vertex field = container;
            Vertex interfaceOrObjective = oldSchemaGraph.getFieldsContainerForField(field);
            if (interfaceOrObjective.isOfType(SchemaGraph.OBJECT)) {
                Vertex object = interfaceOrObjective;
                if (isObjectDeleted(object.getName())) {
                    return;
                }
                if (isFieldDeletedFromExistingObject(object.getName(), field.getName())) {
                    return;
                }
                if (isAppliedDirectiveDeleted(object, appliedDirective.getName())) {
                    return;
                }

                AppliedDirectiveObjectFieldLocation location = new AppliedDirectiveObjectFieldLocation(object.getName(), field.getName(), appliedDirective.getName());
                getObjectModification(object.getName()).getDetails().add(new AppliedDirectiveArgumentDeletion(location, deletedArgument.getName()));
            } else {
                assertTrue(interfaceOrObjective.isOfType(SchemaGraph.INTERFACE));
                Vertex interfaze = interfaceOrObjective;
                if (isInterfaceDeleted(interfaze.getName())) {
                    return;
                }
                if (isFieldDeletedFromExistingInterface(interfaze.getName(), field.getName())) {
                    return;
                }
                if (isAppliedDirectiveDeleted(interfaze, appliedDirective.getName())) {
                    return;
                }

                AppliedDirectiveInterfaceFieldLocation location = new AppliedDirectiveInterfaceFieldLocation(interfaze.getName(), field.getName(), appliedDirective.getName());
                getInterfaceModification(interfaze.getName()).getDetails().add(new AppliedDirectiveArgumentDeletion(location, deletedArgument.getName()));
            }
        } else if (container.isOfType(SchemaGraph.SCALAR)) {
            Vertex scalar = container;
            if (isScalarDeleted(scalar.getName())) {
                return;
            }
            if (isAppliedDirectiveDeleted(scalar, appliedDirective.getName())) {
                return;
            }

            AppliedDirectiveScalarLocation location = new AppliedDirectiveScalarLocation(scalar.getName(), appliedDirective.getName());
            getScalarModification(scalar.getName()).getDetails().add(new AppliedDirectiveArgumentDeletion(location, deletedArgument.getName()));
        } else if (container.isOfType(SchemaGraph.ENUM)) {
            Vertex enumVertex = container;
            if (isEnumDeleted(enumVertex.getName())) {
                return;
            }
            if (isAppliedDirectiveDeleted(enumVertex, appliedDirective.getName())) {
                return;
            }
            AppliedDirectiveEnumLocation location = new AppliedDirectiveEnumLocation(enumVertex.getName(), appliedDirective.getName());
            getEnumModification(enumVertex.getName()).getDetails().add(new AppliedDirectiveArgumentDeletion(location, deletedArgument.getName()));
        } else if (container.isOfType(SchemaGraph.ENUM_VALUE)) {
            Vertex enumValue = container;
            Vertex enumVertex = oldSchemaGraph.getEnumForEnumValue(enumValue);
            if (isEnumDeleted(enumVertex.getName())) {
                return;
            }
            if (isNewEnumValueForExistingEnum(enumVertex.getName(), enumValue.getName())) {
                return;
            }
            AppliedDirectiveEnumValueLocation location = new AppliedDirectiveEnumValueLocation(enumVertex.getName(), enumValue.getName(), appliedDirective.getName());
            getEnumModification(enumVertex.getName()).getDetails().add(new AppliedDirectiveArgumentDeletion(location, deletedArgument.getName()));
        } else if (container.isOfType(SchemaGraph.UNION)) {
            Vertex union = container;
            if (isUnionDeleted(union.getName())) {
                return;
            }
            if (isAppliedDirectiveDeleted(union, appliedDirective.getName())) {
                return;
            }

            AppliedDirectiveUnionLocation location = new AppliedDirectiveUnionLocation(union.getName(), appliedDirective.getName());
            getUnionModification(union.getName()).getDetails().add(new AppliedDirectiveArgumentDeletion(location, deletedArgument.getName()));
        } else if (container.isOfType(SchemaGraph.OBJECT)) {
            Vertex object = container;
            if (isObjectDeleted(object.getName())) {
                return;
            }
            if (isAppliedDirectiveDeleted(object, appliedDirective.getName())) {
                return;
            }

            AppliedDirectiveObjectLocation location = new AppliedDirectiveObjectLocation(object.getName(), appliedDirective.getName());
            getObjectModification(object.getName()).getDetails().add(new AppliedDirectiveArgumentDeletion(location, deletedArgument.getName()));
        } else if (container.isOfType(SchemaGraph.INTERFACE)) {
            Vertex interfaze = container;
            if (isInterfaceDeleted(interfaze.getName())) {
                return;
            }
            if (isAppliedDirectiveDeleted(interfaze, appliedDirective.getName())) {
                return;
            }

            AppliedDirectiveInterfaceLocation location = new AppliedDirectiveInterfaceLocation(interfaze.getName(), appliedDirective.getName());
            getInterfaceModification(interfaze.getName()).getDetails().add(new AppliedDirectiveArgumentDeletion(location, deletedArgument.getName()));
        } else if (container.isOfType(SchemaGraph.INPUT_OBJECT)) {
            Vertex inputObject = container;
            if (isInputObjectDeleted(inputObject.getName())) {
                return;
            }
            if (isAppliedDirectiveDeleted(inputObject, appliedDirective.getName())) {
                return;
            }
            AppliedDirectiveInputObjectLocation location = new AppliedDirectiveInputObjectLocation(inputObject.getName(), appliedDirective.getName());
            getInputObjectModification(inputObject.getName()).getDetails().add(new AppliedDirectiveArgumentDeletion(location, deletedArgument.getName()));
        } else if (container.isOfType(SchemaGraph.INPUT_FIELD)) {
            Vertex inputField = container;
            Vertex inputObject = oldSchemaGraph.getInputObjectForInputField(inputField);
            if (isInputObjectDeleted(inputObject.getName())) {
                return;
            }
            if (isNewInputFieldExistingInputObject(inputObject.getName(), inputField.getName())) {
                return;
            }
            if (isAppliedDirectiveDeleted(inputField, appliedDirective.getName())) {
                return;
            }
            AppliedDirectiveInputObjectFieldLocation location = new AppliedDirectiveInputObjectFieldLocation(inputObject.getName(), inputField.getName(), appliedDirective.getName());
            getInputObjectModification(inputObject.getName()).getDetails().add(new AppliedDirectiveArgumentDeletion(location, deletedArgument.getName()));
        } else {
            assertShouldNeverHappen("Unexpected container " + container);
        }
    }

    private void appliedDirectiveArgumentAdded(EditOperation editOperation) {
        Vertex addedArgument = editOperation.getTargetVertex();
        Vertex appliedDirective = newSchemaGraph.getAppliedDirectiveForAppliedArgument(addedArgument);
        Vertex container = newSchemaGraph.getAppliedDirectiveContainerForAppliedDirective(appliedDirective);

        if (container.isOfType(SchemaGraph.ARGUMENT)) {
            Vertex argument = container;
            Vertex fieldOrDirective = newSchemaGraph.getFieldOrDirectiveForArgument(argument);
            if (fieldOrDirective.isOfType(SchemaGraph.FIELD)) {
                Vertex field = fieldOrDirective;
                Vertex fieldsContainer = newSchemaGraph.getFieldsContainerForField(field);
                if (fieldsContainer.isOfType(SchemaGraph.OBJECT)) {
                    Vertex object = fieldsContainer;
                    if (isObjectAdded(object.getName())) {
                        return;
                    }
                    if (isFieldNewForExistingObject(object.getName(), field.getName())) {
                        return;
                    }
                    if (isArgumentNewForExistingObjectField(object.getName(), field.getName(), argument.getName())) {
                        return;
                    }
                    if (isAppliedDirectiveAdded(object, appliedDirective.getName())) {
                        return;
                    }
                    AppliedDirectiveObjectFieldArgumentLocation location = new AppliedDirectiveObjectFieldArgumentLocation(object.getName(), field.getName(), argument.getName(), appliedDirective.getName());
                    getObjectModification(object.getName()).getDetails().add(new AppliedDirectiveArgumentAddition(location, addedArgument.getName()));
                } else if (fieldsContainer.isOfType(SchemaGraph.INTERFACE)) {
                    Vertex interfaze = fieldsContainer;
                    if (isInterfaceAdded(interfaze.getName())) {
                        return;
                    }
                    if (isFieldNewForExistingInterface(interfaze.getName(), field.getName())) {
                        return;
                    }
                    if (isArgumentNewForExistingInterfaceField(interfaze.getName(), field.getName(), argument.getName())) {
                        return;
                    }

                    if (isAppliedDirectiveAdded(interfaze, appliedDirective.getName())) {
                        return;
                    }
                    AppliedDirectiveInterfaceFieldArgumentLocation location = new AppliedDirectiveInterfaceFieldArgumentLocation(interfaze.getName(), field.getName(), argument.getName(), appliedDirective.getName());
                    getInterfaceModification(interfaze.getName()).getDetails().add(new AppliedDirectiveArgumentAddition(location, addedArgument.getName()));
                }
            } else if (fieldOrDirective.isOfType(SchemaGraph.DIRECTIVE)) {
                Vertex directive = fieldOrDirective;
                if (isAppliedDirectiveAdded(directive, appliedDirective.getName())) {
                    return;
                }
                AppliedDirectiveDirectiveArgumentLocation location = new AppliedDirectiveDirectiveArgumentLocation(directive.getName(), argument.getName(), appliedDirective.getName());
                getDirectiveModification(directive.getName()).getDetails().add(new AppliedDirectiveArgumentAddition(location, addedArgument.getName()));
            }
        } else if (container.isOfType(SchemaGraph.FIELD)) {
            Vertex field = container;
            Vertex interfaceOrObjective = newSchemaGraph.getFieldsContainerForField(field);
            if (interfaceOrObjective.isOfType(SchemaGraph.OBJECT)) {
                Vertex object = interfaceOrObjective;
                if (isObjectAdded(object.getName())) {
                    return;
                }
                if (isFieldNewForExistingObject(object.getName(), field.getName())) {
                    return;
                }
                if (isAppliedDirectiveAdded(container, appliedDirective.getName())) {
                    return;
                }

                AppliedDirectiveObjectFieldLocation location = new AppliedDirectiveObjectFieldLocation(object.getName(), field.getName(), appliedDirective.getName());
                getObjectModification(object.getName()).getDetails().add(new AppliedDirectiveArgumentAddition(location, addedArgument.getName()));
            } else if (interfaceOrObjective.isOfType(SchemaGraph.INTERFACE)) {
                Vertex interfaze = interfaceOrObjective;
                if (isInterfaceAdded(interfaze.getName())) {
                    return;
                }
                if (isFieldNewForExistingInterface(interfaze.getName(), field.getName())) {
                    return;
                }
                if (isAppliedDirectiveAdded(container, appliedDirective.getName())) {
                    return;
                }

                AppliedDirectiveInterfaceFieldLocation location = new AppliedDirectiveInterfaceFieldLocation(interfaze.getName(), field.getName(), appliedDirective.getName());
                getInterfaceModification(interfaze.getName()).getDetails().add(new AppliedDirectiveArgumentAddition(location, addedArgument.getName()));
            } else {
                assertShouldNeverHappen("Unexpected field container " + interfaceOrObjective);
            }
        } else if (container.isOfType(SchemaGraph.SCALAR)) {
            Vertex scalar = container;
            if (isScalarAdded(scalar.getName())) {
                return;
            }
            if (isAppliedDirectiveAdded(container, appliedDirective.getName())) {
                return;
            }
            AppliedDirectiveScalarLocation location = new AppliedDirectiveScalarLocation(scalar.getName(), appliedDirective.getName());
            getScalarModification(scalar.getName()).getDetails().add(new AppliedDirectiveArgumentAddition(location, addedArgument.getName()));
        } else if (container.isOfType(SchemaGraph.ENUM)) {
            Vertex enumVertex = container;
            if (isEnumAdded(enumVertex.getName())) {
                return;
            }
            if (isAppliedDirectiveAdded(container, appliedDirective.getName())) {
                return;
            }
            AppliedDirectiveEnumLocation location = new AppliedDirectiveEnumLocation(enumVertex.getName(), appliedDirective.getName());
            getEnumModification(enumVertex.getName()).getDetails().add(new AppliedDirectiveArgumentAddition(location, addedArgument.getName()));
        } else if (container.isOfType(SchemaGraph.ENUM_VALUE)) {
            Vertex enumValue = container;
            Vertex enumVertex = newSchemaGraph.getEnumForEnumValue(enumValue);
            if (isEnumAdded(enumVertex.getName())) {
                return;
            }
            if (isNewEnumValueForExistingEnum(enumVertex.getName(), enumValue.getName())) {
                return;
            }
            if (isAppliedDirectiveAdded(container, appliedDirective.getName())) {
                return;
            }
            AppliedDirectiveEnumValueLocation location = new AppliedDirectiveEnumValueLocation(enumVertex.getName(), enumValue.getName(), appliedDirective.getName());
            getEnumModification(enumVertex.getName()).getDetails().add(new AppliedDirectiveArgumentAddition(location, addedArgument.getName()));
        } else if (container.isOfType(SchemaGraph.UNION)) {
            Vertex union = container;
            if (isUnionAdded(union.getName())) {
                return;
            }
            if (isAppliedDirectiveAdded(container, appliedDirective.getName())) {
                return;
            }
            AppliedDirectiveUnionLocation location = new AppliedDirectiveUnionLocation(union.getName(), appliedDirective.getName());
            getUnionModification(union.getName()).getDetails().add(new AppliedDirectiveArgumentAddition(location, addedArgument.getName()));
        } else if (container.isOfType(SchemaGraph.INTERFACE)) {
            Vertex interfaze = container;
            if (isInterfaceAdded(interfaze.getName())) {
                return;
            }
            if (isAppliedDirectiveAdded(container, appliedDirective.getName())) {
                return;
            }
            AppliedDirectiveInterfaceLocation location = new AppliedDirectiveInterfaceLocation(interfaze.getName(), appliedDirective.getName());
            getInterfaceModification(interfaze.getName()).getDetails().add(new AppliedDirectiveArgumentAddition(location, addedArgument.getName()));
        } else if (container.isOfType(SchemaGraph.OBJECT)) {
            Vertex interfaze = container;
            if (isObjectAdded(interfaze.getName())) {
                return;
            }
            if (isAppliedDirectiveAdded(container, appliedDirective.getName())) {
                return;
            }
            AppliedDirectiveObjectLocation location = new AppliedDirectiveObjectLocation(interfaze.getName(), appliedDirective.getName());
            getObjectModification(interfaze.getName()).getDetails().add(new AppliedDirectiveArgumentAddition(location, addedArgument.getName()));
        } else if (container.isOfType(SchemaGraph.INPUT_OBJECT)) {
            Vertex inputObject = container;
            if (isInputObjectAdded(inputObject.getName())) {
                return;
            }
            if (isAppliedDirectiveAdded(container, appliedDirective.getName())) {
                return;
            }
            AppliedDirectiveInputObjectLocation location = new AppliedDirectiveInputObjectLocation(inputObject.getName(), appliedDirective.getName());
            getInputObjectModification(inputObject.getName()).getDetails().add(new AppliedDirectiveArgumentAddition(location, addedArgument.getName()));
        } else if (container.isOfType(SchemaGraph.INPUT_FIELD)) {
            Vertex inputField = container;
            Vertex inputObject = newSchemaGraph.getInputObjectForInputField(inputField);
            if (isInputObjectAdded(inputObject.getName())) {
                return;
            }
            if (isNewInputFieldExistingInputObject(inputObject.getName(), inputField.getName())) {
                return;
            }
            if (isAppliedDirectiveAdded(container, appliedDirective.getName())) {
                return;
            }
            AppliedDirectiveInputObjectFieldLocation location = new AppliedDirectiveInputObjectFieldLocation(inputObject.getName(), inputField.getName(), appliedDirective.getName());
            getInputObjectModification(inputObject.getName()).getDetails().add(new AppliedDirectiveArgumentAddition(location, addedArgument.getName()));
        } else {
            assertShouldNeverHappen("Unexpected applied argument container " + container);
        }
    }


    private void appliedDirectiveArgumentChanged(EditOperation editOperation) {
        Vertex appliedArgument = editOperation.getTargetVertex();
        String oldArgumentName = editOperation.getSourceVertex().getName();
        String newArgumentName = editOperation.getTargetVertex().getName();
        boolean nameChanged = !oldArgumentName.equals(newArgumentName);

        String oldValue = editOperation.getSourceVertex().get("value");
        String newValue = editOperation.getTargetVertex().get("value");
        boolean valueChanged = !oldValue.equals(newValue);


        Vertex appliedDirective = newSchemaGraph.getAppliedDirectiveForAppliedArgument(appliedArgument);
        Vertex container = newSchemaGraph.getAppliedDirectiveContainerForAppliedDirective(appliedDirective);
        if (container.isOfType(SchemaGraph.FIELD)) {
            Vertex field = container;
            Vertex interfaceOrObjective = newSchemaGraph.getFieldsContainerForField(field);
            if (interfaceOrObjective.isOfType(SchemaGraph.OBJECT)) {
                Vertex object = interfaceOrObjective;
                AppliedDirectiveObjectFieldLocation location = new AppliedDirectiveObjectFieldLocation(object.getName(), field.getName(), appliedDirective.getName());
                if (valueChanged) {
                    AppliedDirectiveArgumentValueModification argumentValueModification = new AppliedDirectiveArgumentValueModification(location, newArgumentName, oldValue, newValue);
                    getObjectModification(object.getName()).getDetails().add(argumentValueModification);
                }
                if (nameChanged) {
                    AppliedDirectiveArgumentRename argumentRename = new AppliedDirectiveArgumentRename(location, oldArgumentName, newArgumentName);
                    getObjectModification(object.getName()).getDetails().add(argumentRename);
                }
            } else if (interfaceOrObjective.isOfType(SchemaGraph.INTERFACE)) {
                Vertex interfaze = interfaceOrObjective;
                AppliedDirectiveInterfaceFieldLocation location = new AppliedDirectiveInterfaceFieldLocation(interfaze.getName(), field.getName(), appliedDirective.getName());
                if (valueChanged) {
                    AppliedDirectiveArgumentValueModification argumentValueModification = new AppliedDirectiveArgumentValueModification(location, newArgumentName, oldValue, newValue);
                    getInterfaceModification(interfaze.getName()).getDetails().add(argumentValueModification);
                }
                if (nameChanged) {

                }
            }
        } else if (container.isOfType(SchemaGraph.ARGUMENT)) {
            Vertex argument = container;
            Vertex fieldOrDirective = newSchemaGraph.getFieldOrDirectiveForArgument(argument);
            if (fieldOrDirective.isOfType(SchemaGraph.FIELD)) {
                Vertex field = fieldOrDirective;
                Vertex fieldsContainer = newSchemaGraph.getFieldsContainerForField(field);
                if (fieldsContainer.isOfType(SchemaGraph.OBJECT)) {
                    Vertex object = fieldsContainer;
                    AppliedDirectiveObjectFieldArgumentLocation location = new AppliedDirectiveObjectFieldArgumentLocation(object.getName(), field.getName(), argument.getName(), appliedDirective.getName());

                    if (valueChanged) {
                        AppliedDirectiveArgumentValueModification argumentValueModification = new AppliedDirectiveArgumentValueModification(location, newArgumentName, oldValue, newValue);
                        getObjectModification(object.getName()).getDetails().add(argumentValueModification);
                    }
                    if (nameChanged) {

                    }
                } else if (fieldsContainer.isOfType(SchemaGraph.INTERFACE)) {
                    Vertex interfaze = fieldsContainer;
                    AppliedDirectiveInterfaceFieldArgumentLocation location = new AppliedDirectiveInterfaceFieldArgumentLocation(interfaze.getName(), field.getName(), argument.getName(), appliedDirective.getName());

                    if (valueChanged) {
                        AppliedDirectiveArgumentValueModification argumentValueModification = new AppliedDirectiveArgumentValueModification(location, newArgumentName, oldValue, newValue);
                        getInterfaceModification(interfaze.getName()).getDetails().add(argumentValueModification);
                    }
                    if (nameChanged) {

                    }
                }
            } else if (fieldOrDirective.isOfType(SchemaGraph.DIRECTIVE)) {
                Vertex directive = fieldOrDirective;
                AppliedDirectiveDirectiveArgumentLocation location = new AppliedDirectiveDirectiveArgumentLocation(directive.getName(), argument.getName(), appliedDirective.getName());
                if (valueChanged) {
                    AppliedDirectiveArgumentValueModification argumentValueModification = new AppliedDirectiveArgumentValueModification(location, newArgumentName, oldValue, newValue);
                    getDirectiveModification(directive.getName()).getDetails().add(argumentValueModification);
                }

            }
        } else if (container.isOfType(SchemaGraph.INPUT_FIELD)) {
            Vertex inputField = container;
            Vertex inputObject = newSchemaGraph.getInputObjectForInputField(inputField);
            AppliedDirectiveInputObjectFieldLocation location = new AppliedDirectiveInputObjectFieldLocation(inputObject.getName(), inputField.getName(), appliedDirective.getName());
            if (valueChanged) {
                AppliedDirectiveArgumentValueModification argumentValueModification = new AppliedDirectiveArgumentValueModification(location, newArgumentName, oldValue, newValue);
                getInputObjectModification(inputObject.getName()).getDetails().add(argumentValueModification);
            }
            if (nameChanged) {
//                AppliedDirectiveArgumentRename argumentRename = new AppliedDirectiveArgumentRename(location, oldArgumentName, newArgumentName);
//                getInputObjectModification(inputObject.getName()).getDetails().add(argumentRename);
            }
        } else if (container.isOfType(SchemaGraph.OBJECT)) {
            Vertex object = container;
            AppliedDirectiveObjectLocation location = new AppliedDirectiveObjectLocation(object.getName(), appliedDirective.getName());
            if (valueChanged) {
                AppliedDirectiveArgumentValueModification argumentValueModification = new AppliedDirectiveArgumentValueModification(location, newArgumentName, oldValue, newValue);
                getObjectModification(object.getName()).getDetails().add(argumentValueModification);
            }
            if (nameChanged) {
            }
        } else if (container.isOfType(SchemaGraph.INTERFACE)) {
            Vertex interfaze = container;
            AppliedDirectiveInterfaceLocation location = new AppliedDirectiveInterfaceLocation(interfaze.getName(), appliedDirective.getName());
            if (valueChanged) {
                AppliedDirectiveArgumentValueModification argumentValueModification = new AppliedDirectiveArgumentValueModification(location, newArgumentName, oldValue, newValue);
                getInterfaceModification(interfaze.getName()).getDetails().add(argumentValueModification);
            }
            if (nameChanged) {

            }

        } else if (container.isOfType(SchemaGraph.INPUT_OBJECT)) {
            Vertex inputObject = container;
            AppliedDirectiveInputObjectLocation location = new AppliedDirectiveInputObjectLocation(inputObject.getName(), appliedDirective.getName());
            if (valueChanged) {
                AppliedDirectiveArgumentValueModification argumentValueModification = new AppliedDirectiveArgumentValueModification(location, newArgumentName, oldValue, newValue);
                getInputObjectModification(inputObject.getName()).getDetails().add(argumentValueModification);
            }
            if (nameChanged) {

            }

        } else if (container.isOfType(SchemaGraph.ENUM)) {
            Vertex enumVertex = container;
            AppliedDirectiveEnumLocation location = new AppliedDirectiveEnumLocation(enumVertex.getName(), appliedDirective.getName());
            if (valueChanged) {
                AppliedDirectiveArgumentValueModification argumentValueModification = new AppliedDirectiveArgumentValueModification(location, newArgumentName, oldValue, newValue);
                getEnumModification(enumVertex.getName()).getDetails().add(argumentValueModification);
            }
            if (nameChanged) {

            }
        } else if (container.isOfType(SchemaGraph.ENUM_VALUE)) {
            Vertex enumValue = container;
            Vertex enumVertex = newSchemaGraph.getEnumForEnumValue(enumValue);
            AppliedDirectiveEnumValueLocation location = new AppliedDirectiveEnumValueLocation(enumVertex.getName(), enumValue.getName(), appliedDirective.getName());
            if (valueChanged) {
                AppliedDirectiveArgumentValueModification argumentValueModification = new AppliedDirectiveArgumentValueModification(location, newArgumentName, oldValue, newValue);
                getEnumModification(enumVertex.getName()).getDetails().add(argumentValueModification);
            }
            if (nameChanged) {

            }

        } else if (container.isOfType(SchemaGraph.UNION)) {
            Vertex union = container;
            AppliedDirectiveUnionLocation location = new AppliedDirectiveUnionLocation(union.getName(), appliedDirective.getName());
            if (valueChanged) {
                AppliedDirectiveArgumentValueModification argumentValueModification = new AppliedDirectiveArgumentValueModification(location, newArgumentName, oldValue, newValue);
                getUnionModification(union.getName()).getDetails().add(argumentValueModification);
            }
            if (nameChanged) {

            }
        } else if (container.isOfType(SchemaGraph.SCALAR)) {
            Vertex scalar = container;
            AppliedDirectiveScalarLocation location = new AppliedDirectiveScalarLocation(scalar.getName(), appliedDirective.getName());
            if (valueChanged) {
                AppliedDirectiveArgumentValueModification argumentValueModification = new AppliedDirectiveArgumentValueModification(location, newArgumentName, oldValue, newValue);
                getScalarModification(scalar.getName()).getDetails().add(argumentValueModification);
            }
            if (nameChanged) {

            }
        } else {
            assertShouldNeverHappen("Unexpected applied argument container " + container);
        }
    }

    private void appliedDirectiveAdded(EditOperation editOperation) {
        Vertex appliedDirective = editOperation.getTargetVertex();
        Vertex container = newSchemaGraph.getAppliedDirectiveContainerForAppliedDirective(appliedDirective);
        if (container.isOfType(SchemaGraph.FIELD)) {
            appliedDirectiveAddedToField(appliedDirective, container);
        } else if (container.isOfType(SchemaGraph.ARGUMENT)) {
            appliedDirectiveAddedToArgument(appliedDirective, container);

        } else if (container.isOfType(SchemaGraph.OBJECT)) {
            Vertex object = container;
            if (isObjectAdded(object.getName())) {
                return;
            }
            AppliedDirectiveObjectLocation location = new AppliedDirectiveObjectLocation(object.getName(), appliedDirective.getName());
            AppliedDirectiveAddition appliedDirectiveAddition = new AppliedDirectiveAddition(location, appliedDirective.getName());
            getObjectModification(object.getName()).getDetails().add(appliedDirectiveAddition);
        } else if (container.isOfType(SchemaGraph.INTERFACE)) {
            Vertex interfaze = container;
            if (isInterfaceAdded(interfaze.getName())) {
                return;
            }
            AppliedDirectiveInterfaceLocation location = new AppliedDirectiveInterfaceLocation(interfaze.getName(), appliedDirective.getName());
            AppliedDirectiveAddition appliedDirectiveAddition = new AppliedDirectiveAddition(location, appliedDirective.getName());
            getInterfaceModification(interfaze.getName()).getDetails().add(appliedDirectiveAddition);
        } else if (container.isOfType(SchemaGraph.SCALAR)) {
            Vertex scalar = container;
            if (isScalarAdded(scalar.getName())) {
                return;
            }
            AppliedDirectiveScalarLocation location = new AppliedDirectiveScalarLocation(scalar.getName(), appliedDirective.getName());
            AppliedDirectiveAddition appliedDirectiveAddition = new AppliedDirectiveAddition(location, appliedDirective.getName());
            getScalarModification(scalar.getName()).getDetails().add(appliedDirectiveAddition);
        } else if (container.isOfType(SchemaGraph.ENUM)) {
            Vertex enumVertex = container;
            if (isEnumAdded(enumVertex.getName())) {
                return;
            }
            AppliedDirectiveEnumLocation location = new AppliedDirectiveEnumLocation(enumVertex.getName(), appliedDirective.getName());
            AppliedDirectiveAddition appliedDirectiveAddition = new AppliedDirectiveAddition(location, appliedDirective.getName());
            getEnumModification(enumVertex.getName()).getDetails().add(appliedDirectiveAddition);
        } else if (container.isOfType(SchemaGraph.ENUM_VALUE)) {
            Vertex enumValue = container;
            Vertex enumVertex = newSchemaGraph.getEnumForEnumValue(enumValue);
            if (isEnumAdded(enumVertex.getName())) {
                return;
            }
            if (isNewEnumValueForExistingEnum(enumVertex.getName(), enumValue.getName())) {
                return;
            }
            AppliedDirectiveEnumValueLocation location = new AppliedDirectiveEnumValueLocation(enumVertex.getName(), enumValue.getName(), appliedDirective.getName());
            AppliedDirectiveAddition appliedDirectiveAddition = new AppliedDirectiveAddition(location, appliedDirective.getName());
            getEnumModification(enumVertex.getName()).getDetails().add(appliedDirectiveAddition);
        } else if (container.isOfType(SchemaGraph.INPUT_OBJECT)) {
            Vertex inputObject = container;
            if (isInputObjectAdded(inputObject.getName())) {
                return;
            }
            AppliedDirectiveInputObjectLocation location = new AppliedDirectiveInputObjectLocation(inputObject.getName(), appliedDirective.getName());
            AppliedDirectiveAddition appliedDirectiveAddition = new AppliedDirectiveAddition(location, appliedDirective.getName());
            getInputObjectModification(inputObject.getName()).getDetails().add(appliedDirectiveAddition);
        } else if (container.isOfType(SchemaGraph.INPUT_FIELD)) {
            Vertex inputField = container;
            Vertex inputObject = newSchemaGraph.getInputObjectForInputField(inputField);
            if (isInputObjectAdded(inputObject.getName())) {
                return;
            }
            if (isNewInputFieldExistingInputObject(inputObject.getName(), inputField.getName())) {
                return;
            }
            AppliedDirectiveInputObjectFieldLocation location = new AppliedDirectiveInputObjectFieldLocation(inputObject.getName(), inputField.getName(), appliedDirective.getName());
            AppliedDirectiveAddition appliedDirectiveAddition = new AppliedDirectiveAddition(location, appliedDirective.getName());
            getInputObjectModification(inputObject.getName()).getDetails().add(appliedDirectiveAddition);
        } else if (container.isOfType(SchemaGraph.UNION)) {
            Vertex union = container;
            if (isUnionAdded(union.getName())) {
                return;
            }
            AppliedDirectiveUnionLocation location = new AppliedDirectiveUnionLocation(union.getName(), appliedDirective.getName());
            AppliedDirectiveAddition appliedDirectiveAddition = new AppliedDirectiveAddition(location, appliedDirective.getName());
            getUnionModification(union.getName()).getDetails().add(appliedDirectiveAddition);
        }
    }

    private void appliedDirectiveDeletedFromField(Vertex appliedDirective, Vertex container) {
        Vertex field = container;
        Vertex interfaceOrObjective = oldSchemaGraph.getFieldsContainerForField(field);
        if (interfaceOrObjective.isOfType(SchemaGraph.OBJECT)) {
            Vertex object = interfaceOrObjective;

            if (isObjectDeleted(object.getName())) {
                return;
            }
            if (isFieldDeletedFromExistingObject(object.getName(), field.getName())) {
                return;
            }
            AppliedDirectiveObjectFieldLocation location = new AppliedDirectiveObjectFieldLocation(object.getName(), field.getName(), appliedDirective.getName());
            AppliedDirectiveDeletion appliedDirectiveDeletion = new AppliedDirectiveDeletion(location, appliedDirective.getName());
            getObjectModification(object.getName()).getDetails().add(appliedDirectiveDeletion);
        }
    }

    private void appliedDirectiveAddedToField(Vertex appliedDirective, Vertex container) {
        Vertex field = container;
        Vertex interfaceOrObjective = newSchemaGraph.getFieldsContainerForField(field);
        if (interfaceOrObjective.isOfType(SchemaGraph.OBJECT)) {
            Vertex object = interfaceOrObjective;

            if (isObjectAdded(object.getName())) {
                return;
            }
            if (isFieldNewForExistingObject(object.getName(), field.getName())) {
                return;
            }
            AppliedDirectiveObjectFieldLocation location = new AppliedDirectiveObjectFieldLocation(object.getName(), field.getName(), appliedDirective.getName());
            AppliedDirectiveAddition appliedDirectiveAddition = new AppliedDirectiveAddition(location, appliedDirective.getName());
            getObjectModification(object.getName()).getDetails().add(appliedDirectiveAddition);
        }
    }

    private void appliedDirectiveDeletedFromArgument(Vertex appliedDirective, Vertex container) {
        Vertex argument = container;
        Vertex fieldOrDirective = oldSchemaGraph.getFieldOrDirectiveForArgument(argument);
        if (fieldOrDirective.isOfType(SchemaGraph.FIELD)) {
            Vertex field = fieldOrDirective;
            Vertex interfaceOrObjective = oldSchemaGraph.getFieldsContainerForField(field);
            if (interfaceOrObjective.isOfType(SchemaGraph.OBJECT)) {
                Vertex object = interfaceOrObjective;
                if (isObjectDeleted(object.getName())) {
                    return;
                }
                if (isFieldDeletedFromExistingObject(object.getName(), field.getName())) {
                    return;
                }
                if (isArgumentDeletedFromExistingObjectField(object.getName(), field.getName(), argument.getName())) {
                    return;
                }
                AppliedDirectiveObjectFieldArgumentLocation location = new AppliedDirectiveObjectFieldArgumentLocation(object.getName(), field.getName(), argument.getName(), appliedDirective.getName());
                AppliedDirectiveDeletion appliedDirectiveDeletion = new AppliedDirectiveDeletion(location, appliedDirective.getName());
                getObjectModification(object.getName()).getDetails().add(appliedDirectiveDeletion);
            } else {
                assertTrue(interfaceOrObjective.isOfType(SchemaGraph.INTERFACE));
                Vertex interfaze = interfaceOrObjective;
                if (isInterfaceDeleted(interfaze.getName())) {
                    return;
                }
                if (isFieldDeletedFromExistingInterface(interfaze.getName(), field.getName())) {
                    return;
                }
                if (isArgumentDeletedFromExistingInterfaceField(interfaze.getName(), field.getName(), argument.getName())) {
                    return;
                }
                AppliedDirectiveInterfaceFieldArgumentLocation location = new AppliedDirectiveInterfaceFieldArgumentLocation(interfaze.getName(), field.getName(), argument.getName(), appliedDirective.getName());
                AppliedDirectiveDeletion appliedDirectiveDeletion = new AppliedDirectiveDeletion(location, appliedDirective.getName());
                getInterfaceModification(interfaze.getName()).getDetails().add(appliedDirectiveDeletion);
            }
        } else {
            assertTrue(fieldOrDirective.isOfType(SchemaGraph.DIRECTIVE));
            Vertex directive = fieldOrDirective;
            if (isDirectiveDeleted(directive.getName())) {
                return;
            }
            if (isArgumentDeletedFromExistingDirective(directive.getName(), argument.getName())) {
                return;
            }
            AppliedDirectiveDirectiveArgumentLocation location = new AppliedDirectiveDirectiveArgumentLocation(directive.getName(), argument.getName(), appliedDirective.getName());
            AppliedDirectiveDeletion appliedDirectiveDeletion = new AppliedDirectiveDeletion(location, appliedDirective.getName());
            getDirectiveModification(directive.getName()).getDetails().add(appliedDirectiveDeletion);
        }
    }

    private void appliedDirectiveAddedToArgument(Vertex appliedDirective, Vertex container) {
        Vertex argument = container;
        Vertex fieldOrDirective = newSchemaGraph.getFieldOrDirectiveForArgument(argument);
        if (fieldOrDirective.isOfType(SchemaGraph.FIELD)) {
            Vertex field = fieldOrDirective;
            Vertex interfaceOrObjective = newSchemaGraph.getFieldsContainerForField(field);
            if (interfaceOrObjective.isOfType(SchemaGraph.OBJECT)) {
                Vertex object = interfaceOrObjective;
                if (isObjectAdded(object.getName())) {
                    return;
                }
                if (isFieldNewForExistingObject(object.getName(), field.getName())) {
                    return;
                }
                if (isArgumentNewForExistingObjectField(object.getName(), field.getName(), argument.getName())) {
                    return;
                }
                AppliedDirectiveObjectFieldArgumentLocation location = new AppliedDirectiveObjectFieldArgumentLocation(object.getName(), field.getName(), argument.getName(), appliedDirective.getName());
                AppliedDirectiveAddition appliedDirectiveAddition = new AppliedDirectiveAddition(location, appliedDirective.getName());
                getObjectModification(object.getName()).getDetails().add(appliedDirectiveAddition);
            } else {
                assertTrue(interfaceOrObjective.isOfType(SchemaGraph.INTERFACE));
                Vertex interfaze = interfaceOrObjective;
                if (isInterfaceAdded(interfaze.getName())) {
                    return;
                }
                if (isFieldNewForExistingInterface(interfaze.getName(), field.getName())) {
                    return;
                }
                if (isArgumentNewForExistingInterfaceField(interfaze.getName(), field.getName(), argument.getName())) {
                    return;
                }
                AppliedDirectiveInterfaceFieldArgumentLocation location = new AppliedDirectiveInterfaceFieldArgumentLocation(interfaze.getName(), field.getName(), argument.getName(), appliedDirective.getName());
                AppliedDirectiveAddition appliedDirectiveAddition = new AppliedDirectiveAddition(location, appliedDirective.getName());
                getInterfaceModification(interfaze.getName()).getDetails().add(appliedDirectiveAddition);
            }
        } else {
            assertTrue(fieldOrDirective.isOfType(SchemaGraph.DIRECTIVE));
            Vertex directive = fieldOrDirective;
            if (isDirectiveAdded(directive.getName())) {
                return;
            }
            if (isArgumentNewForExistingDirective(directive.getName(), argument.getName())) {
                return;
            }
            AppliedDirectiveDirectiveArgumentLocation location = new AppliedDirectiveDirectiveArgumentLocation(directive.getName(), argument.getName(), appliedDirective.getName());
            AppliedDirectiveAddition appliedDirectiveAddition = new AppliedDirectiveAddition(location, appliedDirective.getName());
            getDirectiveModification(directive.getName()).getDetails().add(appliedDirectiveAddition);
        }
    }

    private void handleTypeChanges(List editOperations, Mapping mapping) {
        for (EditOperation editOperation : editOperations) {
            Edge newEdge = editOperation.getTargetEdge();
            switch (editOperation.getOperation()) {
                case INSERT_EDGE:
                    if (newEdge.getLabel().startsWith("type=")) {
                        typeEdgeInserted(editOperation, editOperations, mapping);
                    }
                    break;
                case CHANGE_EDGE:
                    if (newEdge.getLabel().startsWith("type=")) {
                        typeEdgeChanged(editOperation, mapping);
                    }
                    break;
            }
        }
    }

    private void handleUnionMemberChanges(List editOperations, Mapping mapping) {
        for (EditOperation editOperation : editOperations) {
            switch (editOperation.getOperation()) {
                case INSERT_EDGE:
                    Edge newEdge = editOperation.getTargetEdge();
                    if (newEdge.getFrom().isOfType(SchemaGraph.UNION)) {
                        handleUnionMemberAdded(editOperation);
                    }
                    break;
                case DELETE_EDGE:
                    Edge oldEdge = editOperation.getSourceEdge();
                    if (oldEdge.getFrom().isOfType(SchemaGraph.UNION) && !oldEdge.getTo().isOfType(SchemaGraph.APPLIED_DIRECTIVE)) {
                        handleUnionMemberDeleted(editOperation);
                    }
                    break;
            }
        }
    }

    private void handleEnumValuesChanges(List editOperations, Mapping mapping) {
        for (EditOperation editOperation : editOperations) {
            switch (editOperation.getOperation()) {
                case INSERT_EDGE:
                    Edge newEdge = editOperation.getTargetEdge();
                    if (newEdge.getFrom().isOfType(SchemaGraph.ENUM) && newEdge.getTo().isOfType(SchemaGraph.ENUM_VALUE)) {
                        handleEnumValueAdded(editOperation);
                    }
                    break;
                case DELETE_EDGE:
                    Edge oldEdge = editOperation.getSourceEdge();
                    if (oldEdge.getFrom().isOfType(SchemaGraph.ENUM) && oldEdge.getTo().isOfType(SchemaGraph.ENUM_VALUE)) {
                        handleEnumValueDeleted(editOperation);
                    }
                    break;
                case CHANGE_VERTEX:
                    if (editOperation.getSourceVertex().isOfType(SchemaGraph.ENUM_VALUE) && editOperation.getTargetVertex().isOfType(SchemaGraph.ENUM_VALUE)) {
                        handleEnumValueChanged(editOperation);
                    }
                    break;
            }
        }
    }

    private void handleInputFieldChange(EditOperation editOperation) {
        Vertex inputField = editOperation.getTargetVertex();
        Vertex inputObject = newSchemaGraph.getInputObjectForInputField(inputField);

        String oldName = editOperation.getSourceVertex().getName();
        String newName = inputField.getName();

        if (oldName.equals(newName)) {
            // Something else like description could have changed
            return;
        }

        if (isInputObjectAdded(inputObject.getName())) {
            return;
        }

        getInputObjectModification(inputObject.getName()).getDetails().add(new InputObjectFieldRename(oldName, newName));
    }

    private void handleArgumentChange(EditOperation editOperation, Mapping mapping) {
        Vertex oldArgument = editOperation.getSourceVertex();
        Vertex argument = editOperation.getTargetVertex();

        String oldName = oldArgument.getName();
        String newName = argument.getName();

        if (oldName.equals(newName)) {
            // Something else like description could have changed
            return;
        }

        if (!doesArgumentChangeMakeSense(oldArgument, argument, mapping)) {
            return;
        }

        Vertex fieldOrDirective = newSchemaGraph.getFieldOrDirectiveForArgument(argument);
        if (fieldOrDirective.isOfType(SchemaGraph.DIRECTIVE)) {
            Vertex directive = fieldOrDirective;
            DirectiveModification directiveModification = getDirectiveModification(directive.getName());
            directiveModification.getDetails().add(new DirectiveArgumentRename(oldName, newName));
        } else {
            assertTrue(fieldOrDirective.isOfType(SchemaGraph.FIELD));
            Vertex field = fieldOrDirective;
            String fieldName = field.getName();
            Vertex fieldsContainerForField = newSchemaGraph.getFieldsContainerForField(field);
            if (fieldsContainerForField.isOfType(SchemaGraph.OBJECT)) {
                Vertex object = fieldsContainerForField;
                ObjectModification objectModification = getObjectModification(object.getName());
                objectModification.getDetails().add(new ObjectFieldArgumentRename(fieldName, oldName, newName));
            } else {
                assertTrue(fieldsContainerForField.isOfType(SchemaGraph.INTERFACE));
                Vertex interfaze = fieldsContainerForField;
                InterfaceModification interfaceModification = getInterfaceModification(interfaze.getName());
                interfaceModification.getDetails().add(new InterfaceFieldArgumentRename(fieldName, oldName, newName));
            }
        }
    }

    private void handleImplementsChanges(List editOperations, Mapping mapping) {
        for (EditOperation editOperation : editOperations) {
            switch (editOperation.getOperation()) {
                case INSERT_EDGE:
                    Edge newEdge = editOperation.getTargetEdge();
                    if (newEdge.getLabel().startsWith("implements ")) {
                        newInterfaceAddedToInterfaceOrObject(newEdge);
                    }
                    break;
                case DELETE_EDGE:
                    Edge oldEdge = editOperation.getSourceEdge();
                    if (oldEdge.getLabel().startsWith("implements ")) {
                        interfaceImplementationDeleted(oldEdge);
                    }
                    break;
            }
        }
    }

    private void handleUnionMemberAdded(EditOperation editOperation) {
        Edge newEdge = editOperation.getTargetEdge();
        Vertex union = newEdge.getFrom();
        if (isUnionAdded(union.getName())) {
            return;
        }
        Vertex newMemberObject = newEdge.getTo();
        UnionModification unionModification = getUnionModification(union.getName());
        unionModification.getDetails().add(new UnionMemberAddition(newMemberObject.getName()));
    }

    private void handleUnionMemberDeleted(EditOperation editOperation) {
        Edge deletedEdge = editOperation.getSourceEdge();
        Vertex union = deletedEdge.getFrom();
        if (isUnionDeleted(union.getName())) {
            return;
        }
        Vertex memberObject = deletedEdge.getTo();
        UnionModification unionModification = getUnionModification(union.getName());
        unionModification.getDetails().add(new UnionMemberDeletion(memberObject.getName()));
    }

    private void handleEnumValueAdded(EditOperation editOperation) {
        Edge newEdge = editOperation.getTargetEdge();
        Vertex enumVertex = newEdge.getFrom();
        if (isEnumAdded(enumVertex.getName())) {
            return;
        }
        Vertex newValue = newEdge.getTo();
        EnumModification enumModification = getEnumModification(enumVertex.getName());
        enumModification.getDetails().add(new EnumValueAddition(newValue.getName()));
    }

    private void handleEnumValueDeleted(EditOperation editOperation) {
        Edge deletedEdge = editOperation.getSourceEdge();
        Vertex enumVertex = deletedEdge.getFrom();
        if (isEnumDeleted(enumVertex.getName())) {
            return;
        }
        Vertex value = deletedEdge.getTo();
        EnumModification enumModification = getEnumModification(enumVertex.getName());
        enumModification.getDetails().add(new EnumValueDeletion(value.getName()));
    }

    private void handleEnumValueChanged(EditOperation editOperation) {
        Vertex enumVertex = newSchemaGraph.getEnumForEnumValue(editOperation.getTargetVertex());
        EnumModification enumModification = getEnumModification(enumVertex.getName());
        String oldName = editOperation.getSourceVertex().getName();
        String newName = editOperation.getTargetVertex().getName();
        enumModification.getDetails().add(new EnumValueRenamed(oldName, newName));
    }

    private void fieldChanged(EditOperation editOperation) {
        Vertex field = editOperation.getTargetVertex();
        Vertex fieldsContainerForField = newSchemaGraph.getFieldsContainerForField(field);

        String oldName = editOperation.getSourceVertex().getName();
        String newName = field.getName();
        if (oldName.equals(newName)) {
            // Something else like description could have changed
            return;
        }

        if (fieldsContainerForField.isOfType(SchemaGraph.OBJECT)) {
            Vertex object = fieldsContainerForField;

            if (isObjectAdded(object.getName())) {
                return;
            }

            ObjectModification objectModification = getObjectModification(object.getName());
            objectModification.getDetails().add(new ObjectFieldRename(oldName, newName));
        } else {
            assertTrue(fieldsContainerForField.isOfType(SchemaGraph.INTERFACE));
            Vertex interfaze = fieldsContainerForField;

            if (isInterfaceAdded(interfaze.getName())) {
                return;
            }

            InterfaceModification interfaceModification = getInterfaceModification(interfaze.getName());
            interfaceModification.getDetails().add(new InterfaceFieldRename(oldName, newName));
        }
    }

    private void inputFieldAdded(EditOperation editOperation) {
        Vertex inputField = editOperation.getTargetVertex();
        Vertex inputObject = newSchemaGraph.getInputObjectForInputField(inputField);
        if (isInputObjectAdded(inputObject.getName())) {
            return;
        }
        InputObjectModification modification = getInputObjectModification(inputObject.getName());
        modification.getDetails().add(new InputObjectFieldAddition(inputField.getName()));
    }

    private void fieldAdded(EditOperation editOperation) {
        Vertex field = editOperation.getTargetVertex();
        Vertex fieldsContainerForField = newSchemaGraph.getFieldsContainerForField(field);
        if (fieldsContainerForField.isOfType(SchemaGraph.OBJECT)) {
            Vertex object = fieldsContainerForField;
            if (isObjectAdded(object.getName())) {
                return;
            }
            ObjectModification objectModification = getObjectModification(object.getName());
            String name = field.getName();
            objectModification.getDetails().add(new ObjectFieldAddition(name));
        } else {
            assertTrue(fieldsContainerForField.isOfType(SchemaGraph.INTERFACE));
            Vertex interfaze = fieldsContainerForField;
            if (isInterfaceAdded(interfaze.getName())) {
                return;
            }
            InterfaceModification interfaceModification = getInterfaceModification(interfaze.getName());
            String name = field.getName();
            interfaceModification.getDetails().add(new InterfaceFieldAddition(name));
        }
    }

    private void inputFieldDeleted(EditOperation editOperation) {
        Vertex inputField = editOperation.getSourceVertex();
        Vertex inputObject = oldSchemaGraph.getInputObjectForInputField(inputField);
        if (isInputObjectDeleted(inputObject.getName())) {
            return;
        }
        getInputObjectModification(inputObject.getName()).getDetails().add(new InputObjectFieldDeletion(inputField.getName()));
    }

    private void fieldDeleted(EditOperation editOperation) {
        Vertex deletedField = editOperation.getSourceVertex();
        Vertex fieldsContainerForField = oldSchemaGraph.getFieldsContainerForField(deletedField);
        if (fieldsContainerForField.isOfType(SchemaGraph.OBJECT)) {
            Vertex object = fieldsContainerForField;
            if (isObjectDeleted(object.getName())) {
                return;
            }
            ObjectModification objectModification = getObjectModification(object.getName());
            String name = deletedField.getName();
            objectModification.getDetails().add(new ObjectFieldDeletion(name));
        } else {
            assertTrue(fieldsContainerForField.isOfType(SchemaGraph.INTERFACE));
            Vertex interfaze = fieldsContainerForField;
            if (isInterfaceDeleted(interfaze.getName())) {
                return;
            }
            InterfaceModification interfaceModification = getInterfaceModification(interfaze.getName());
            String name = deletedField.getName();
            interfaceModification.getDetails().add(new InterfaceFieldDeletion(name));
        }
    }


    private void handleTypeVertexChanges(List editOperations) {
        for (EditOperation editOperation : editOperations) {
            switch (editOperation.getOperation()) {
                case INSERT_VERTEX:
                    insertedTypeVertex(editOperation);
                    break;
                case DELETE_VERTEX:
                    deletedTypeVertex(editOperation);
                    break;
                case CHANGE_VERTEX:
                    changedTypeVertex(editOperation);
                    break;
            }
        }
    }

    private void insertedTypeVertex(EditOperation editOperation) {
        switch (editOperation.getTargetVertex().getType()) {
            case SchemaGraph.OBJECT:
                addedObject(editOperation);
                break;
            case SchemaGraph.INTERFACE:
                addedInterface(editOperation);
                break;
            case SchemaGraph.UNION:
                addedUnion(editOperation);
                break;
            case SchemaGraph.INPUT_OBJECT:
                addedInputObject(editOperation);
                break;
            case SchemaGraph.ENUM:
                addedEnum(editOperation);
                break;
            case SchemaGraph.SCALAR:
                addedScalar(editOperation);
                break;
            case SchemaGraph.DIRECTIVE:
                addedDirective(editOperation);
                break;
        }

    }

    private void deletedTypeVertex(EditOperation editOperation) {
        switch (editOperation.getSourceVertex().getType()) {
            case SchemaGraph.OBJECT:
                removedObject(editOperation);
                break;
            case SchemaGraph.INTERFACE:
                removedInterface(editOperation);
                break;
            case SchemaGraph.UNION:
                removedUnion(editOperation);
                break;
            case SchemaGraph.INPUT_OBJECT:
                removedInputObject(editOperation);
                break;
            case SchemaGraph.ENUM:
                removedEnum(editOperation);
                break;
            case SchemaGraph.SCALAR:
                deletedScalar(editOperation);
                break;
            case SchemaGraph.DIRECTIVE:
                deletedDirective(editOperation);
                break;
        }
    }

    private void changedTypeVertex(EditOperation editOperation) {
        switch (editOperation.getTargetVertex().getType()) {
            case SchemaGraph.OBJECT:
                changedObject(editOperation);
                break;
            case SchemaGraph.INTERFACE:
                changedInterface(editOperation);
                break;
            case SchemaGraph.UNION:
                changedUnion(editOperation);
                break;
            case SchemaGraph.INPUT_OBJECT:
                changedInputObject(editOperation);
                break;
            case SchemaGraph.ENUM:
                changedEnum(editOperation);
                break;
            case SchemaGraph.SCALAR:
                changedScalar(editOperation);
                break;
            case SchemaGraph.DIRECTIVE:
                changedDirective(editOperation);
                break;
        }
    }


    private void typeEdgeInserted(EditOperation editOperation, List editOperations, Mapping
            mapping) {
        Edge newEdge = editOperation.getTargetEdge();
        Vertex from = newEdge.getFrom();
        if (from.isOfType(SchemaGraph.FIELD)) {
            typeEdgeInsertedForField(editOperation, editOperations, mapping);
        } else if (from.isOfType(SchemaGraph.ARGUMENT)) {
            typeEdgeInsertedForArgument(editOperation, editOperations, mapping);
        } else if (from.isOfType(SchemaGraph.INPUT_FIELD)) {
            typeEdgeInsertedForInputField(editOperation, editOperations, mapping);
        }

    }

    private void typeEdgeInsertedForInputField(EditOperation editOperation,
                                               List editOperations,
                                               Mapping mapping) {
        Vertex inputField = editOperation.getTargetEdge().getFrom();
        Vertex inputObject = newSchemaGraph.getInputObjectForInputField(inputField);
        if (isInputObjectAdded(inputObject.getName())) {
            return;
        }
        if (isNewInputFieldExistingInputObject(inputObject.getName(), inputField.getName())) {
            return;
        }
        String newType = getTypeFromEdgeLabel(editOperation.getTargetEdge());
        EditOperation deletedTypeEdgeOperation = findDeletedEdge(inputField, editOperations, mapping, this::isTypeEdge);
        String oldType = getTypeFromEdgeLabel(deletedTypeEdgeOperation.getSourceEdge());
        InputObjectFieldTypeModification inputObjectFieldTypeModification = new InputObjectFieldTypeModification(inputField.getName(), oldType, newType);
        getInputObjectModification(inputObject.getName()).getDetails().add(inputObjectFieldTypeModification);
    }

    private void typeEdgeInsertedForArgument(EditOperation editOperation,
                                             List editOperations,
                                             Mapping mapping) {
        Vertex argument = editOperation.getTargetEdge().getFrom();
        Vertex fieldOrDirective = newSchemaGraph.getFieldOrDirectiveForArgument(argument);
        if (fieldOrDirective.isOfType(SchemaGraph.FIELD)) {
            Vertex field = fieldOrDirective;
            Vertex objectOrInterface = newSchemaGraph.getFieldsContainerForField(field);

            if (objectOrInterface.isOfType(SchemaGraph.OBJECT)) {
                Vertex object = objectOrInterface;

                // if the whole object is new we are done
                if (isObjectAdded(object.getName())) {
                    return;
                }
                // if the field is new, we are done too
                if (isFieldNewForExistingObject(object.getName(), field.getName())) {
                    return;
                }
                // if the argument is new, we are done too
                if (isArgumentNewForExistingObjectField(object.getName(), field.getName(), argument.getName())) {
                    return;
                }

                String newType = getTypeFromEdgeLabel(editOperation.getTargetEdge());
                // this means we have an existing object changed its type
                // and there must be a deleted edge with the old type information
                EditOperation deletedTypeEdgeOperation = findDeletedEdge(argument, editOperations, mapping, this::isTypeEdge);
                String oldType = getTypeFromEdgeLabel(deletedTypeEdgeOperation.getSourceEdge());
                ObjectFieldArgumentTypeModification objectFieldArgumentTypeModification = new ObjectFieldArgumentTypeModification(field.getName(), argument.getName(), oldType, newType);
                getObjectModification(object.getName()).getDetails().add(objectFieldArgumentTypeModification);

                String oldDefaultValue = getDefaultValueFromEdgeLabel(deletedTypeEdgeOperation.getSourceEdge());
                String newDefaultValue = getDefaultValueFromEdgeLabel(editOperation.getTargetEdge());
                if (!oldDefaultValue.equals(newDefaultValue)) {
                    getObjectModification(object.getName()).getDetails().add(new ObjectFieldArgumentDefaultValueModification(field.getName(), argument.getName(), oldDefaultValue, newDefaultValue));
                }
            } else {
                assertTrue(objectOrInterface.isOfType(SchemaGraph.INTERFACE));
                Vertex interfaze = objectOrInterface;

                // if the whole object is new we are done
                if (isInterfaceAdded(interfaze.getName())) {
                    return;
                }
                // if the field is new, we are done too
                if (isFieldNewForExistingInterface(interfaze.getName(), field.getName())) {
                    return;
                }
                // if the argument is new, we are done too
                if (isArgumentNewForExistingInterfaceField(interfaze.getName(), field.getName(), argument.getName())) {
                    return;
                }

                String newType = getTypeFromEdgeLabel(editOperation.getTargetEdge());
                // this means we have an existing object changed its type
                // and there must be a deleted edge with the old type information
                EditOperation deletedTypeEdgeOperation = findDeletedEdge(argument, editOperations, mapping, this::isTypeEdge);
                String oldType = getTypeFromEdgeLabel(deletedTypeEdgeOperation.getSourceEdge());
                InterfaceFieldArgumentTypeModification interfaceFieldArgumentTypeModification = new InterfaceFieldArgumentTypeModification(field.getName(), argument.getName(), oldType, newType);
                getInterfaceModification(interfaze.getName()).getDetails().add(interfaceFieldArgumentTypeModification);

                String oldDefaultValue = getDefaultValueFromEdgeLabel(deletedTypeEdgeOperation.getSourceEdge());
                String newDefaultValue = getDefaultValueFromEdgeLabel(editOperation.getTargetEdge());
                if (!oldDefaultValue.equals(newDefaultValue)) {
                    getInterfaceModification(interfaze.getName()).getDetails().add(new InterfaceFieldArgumentDefaultValueModification(field.getName(), argument.getName(), oldDefaultValue, newDefaultValue));
                }
            }
        } else {
            assertTrue(fieldOrDirective.isOfType(SchemaGraph.DIRECTIVE));
            Vertex directive = fieldOrDirective;

            if (isDirectiveAdded(directive.getName())) {
                return;
            }
            if (isArgumentNewForExistingDirective(directive.getName(), argument.getName())) {
                return;
            }

            String newType = getTypeFromEdgeLabel(editOperation.getTargetEdge());
            EditOperation deletedTypeEdgeOperation = findDeletedEdge(argument, editOperations, mapping, this::isTypeEdge);
            String oldType = getTypeFromEdgeLabel(deletedTypeEdgeOperation.getSourceEdge());
            DirectiveArgumentTypeModification directiveArgumentTypeModification = new DirectiveArgumentTypeModification(argument.getName(), oldType, newType);
            getDirectiveModification(directive.getName()).getDetails().add(directiveArgumentTypeModification);

            String oldDefaultValue = getDefaultValueFromEdgeLabel(deletedTypeEdgeOperation.getSourceEdge());
            String newDefaultValue = getDefaultValueFromEdgeLabel(editOperation.getTargetEdge());
            if (!oldDefaultValue.equals(newDefaultValue)) {
                getDirectiveModification(directive.getName()).getDetails().add(new DirectiveArgumentDefaultValueModification(argument.getName(), oldDefaultValue, newDefaultValue));
            }
        }
    }

    private void typeEdgeInsertedForField(EditOperation editOperation,
                                          List editOperations,
                                          Mapping mapping) {
        Vertex field = editOperation.getTargetEdge().getFrom();
        Vertex objectOrInterface = newSchemaGraph.getFieldsContainerForField(field);
        if (objectOrInterface.isOfType(SchemaGraph.OBJECT)) {
            Vertex object = objectOrInterface;
            // if the whole object is new we are done
            if (isObjectAdded(object.getName())) {
                return;
            }
            // if the field is new, we are done too
            if (isFieldNewForExistingObject(object.getName(), field.getName())) {
                return;
            }
            String newType = getTypeFromEdgeLabel(editOperation.getTargetEdge());
            // this means we have an existing object changed its type
            // and there must be a deleted edge with the old type information
            EditOperation deletedTypeEdgeOperation = findDeletedEdge(field, editOperations, mapping, this::isTypeEdge);
            String oldType = getTypeFromEdgeLabel(deletedTypeEdgeOperation.getSourceEdge());
            ObjectFieldTypeModification objectFieldTypeModification = new ObjectFieldTypeModification(field.getName(), oldType, newType);
            getObjectModification(object.getName()).getDetails().add(objectFieldTypeModification);
        } else {
            assertTrue(objectOrInterface.isOfType(SchemaGraph.INTERFACE));
            Vertex interfaze = objectOrInterface;
            if (isInterfaceAdded(interfaze.getName())) {
                return;
            }
            if (isFieldNewForExistingInterface(interfaze.getName(), field.getName())) {
                return;
            }
            String newType = getTypeFromEdgeLabel(editOperation.getTargetEdge());
            // this means we have an existing object changed its type
            // and there must be a deleted edge with the old type information
            EditOperation deletedTypeEdgeOperation = findDeletedEdge(field, editOperations, mapping, this::isTypeEdge);
            String oldType = getTypeFromEdgeLabel(deletedTypeEdgeOperation.getSourceEdge());
            InterfaceFieldTypeModification interfaceFieldTypeModification = new InterfaceFieldTypeModification(field.getName(), oldType, newType);
            getInterfaceModification(interfaze.getName()).getDetails().add(interfaceFieldTypeModification);
        }
    }


    private EditOperation findDeletedEdge(Vertex targetVertexFrom,
                                          List editOperations,
                                          Mapping mapping,
                                          Predicate edgePredicate) {
        Vertex sourceVertexFrom = mapping.getSource(targetVertexFrom);
        for (EditOperation editOperation : editOperations) {
            if (editOperation.getOperation() == EditOperation.Operation.DELETE_EDGE) {
                Edge deletedEdge = editOperation.getSourceEdge();
                if (deletedEdge.getFrom() == sourceVertexFrom && edgePredicate.test(deletedEdge)) {
                    return editOperation;
                }
            }
        }
        return Assert.assertShouldNeverHappen();
    }


    private void typeEdgeChanged(EditOperation editOperation, Mapping mapping) {
        Edge targetEdge = editOperation.getTargetEdge();
        Vertex from = targetEdge.getFrom();
        if (from.isOfType(SchemaGraph.FIELD)) {
            outputFieldTypeChanged(editOperation);
        } else if (from.isOfType(SchemaGraph.ARGUMENT)) {
            argumentTypeOrDefaultValueChanged(editOperation, mapping);
        } else if (from.isOfType(SchemaGraph.INPUT_FIELD)) {
            inputFieldTypeOrDefaultValueChanged(editOperation);
        }
    }

    private void inputFieldTypeOrDefaultValueChanged(EditOperation editOperation) {
        Edge targetEdge = editOperation.getTargetEdge();
        Vertex inputField = targetEdge.getFrom();
        Vertex inputObject = newSchemaGraph.getInputObjectForInputField(inputField);

        if (isInputObjectAdded(inputObject.getName())) {
            return;
        }

        String oldDefaultValue = getDefaultValueFromEdgeLabel(editOperation.getSourceEdge());
        String newDefaultValue = getDefaultValueFromEdgeLabel(editOperation.getTargetEdge());
        if (!oldDefaultValue.equals(newDefaultValue)) {
            InputObjectFieldDefaultValueModification modification = new InputObjectFieldDefaultValueModification(inputField.getName(), oldDefaultValue, newDefaultValue);
            getInputObjectModification(inputObject.getName()).getDetails().add(modification);
        }
        String oldType = getTypeFromEdgeLabel(editOperation.getSourceEdge());
        String newType = getTypeFromEdgeLabel(editOperation.getTargetEdge());
        if (!oldType.equals(newType)) {
            InputObjectFieldTypeModification inputObjectFieldTypeModification = new InputObjectFieldTypeModification(inputField.getName(), oldType, newType);
            getInputObjectModification(inputObject.getName()).getDetails().add(inputObjectFieldTypeModification);
        }
    }

    private void argumentTypeOrDefaultValueChanged(EditOperation editOperation, Mapping mapping) {
        Vertex oldArgument = editOperation.getSourceEdge().getFrom();
        Vertex argument = editOperation.getTargetEdge().getFrom();

        if (!doesArgumentChangeMakeSense(oldArgument, argument, mapping)) {
            return;
        }

        Vertex fieldOrDirective = newSchemaGraph.getFieldOrDirectiveForArgument(argument);
        if (fieldOrDirective.isOfType(SchemaGraph.FIELD)) {
            Vertex field = fieldOrDirective;
            Vertex objectOrInterface = newSchemaGraph.getFieldsContainerForField(field);

            String oldDefaultValue = getDefaultValueFromEdgeLabel(editOperation.getSourceEdge());
            String newDefaultValue = getDefaultValueFromEdgeLabel(editOperation.getTargetEdge());
            if (!oldDefaultValue.equals(newDefaultValue)) {
                if (objectOrInterface.isOfType(SchemaGraph.OBJECT)) {
                    ObjectFieldArgumentDefaultValueModification defaultValueModification = new ObjectFieldArgumentDefaultValueModification(
                            field.getName(),
                            argument.getName(),
                            oldDefaultValue,
                            newDefaultValue);
                    getObjectModification(objectOrInterface.getName()).getDetails().add(defaultValueModification);
                } else {
                    assertTrue(objectOrInterface.isOfType(SchemaGraph.INTERFACE));
                    InterfaceFieldArgumentDefaultValueModification defaultValueModification = new InterfaceFieldArgumentDefaultValueModification(
                            field.getName(),
                            argument.getName(),
                            oldDefaultValue,
                            newDefaultValue);
                    getInterfaceModification(objectOrInterface.getName()).getDetails().add(defaultValueModification);
                }
            }

            String oldType = getTypeFromEdgeLabel(editOperation.getSourceEdge());
            String newType = getTypeFromEdgeLabel(editOperation.getTargetEdge());
            if (!oldType.equals(newType)) {
                if (objectOrInterface.isOfType(SchemaGraph.OBJECT)) {
                    ObjectFieldArgumentTypeModification objectFieldArgumentTypeModification = new ObjectFieldArgumentTypeModification(field.getName(), argument.getName(), oldType, newType);
                    getObjectModification(objectOrInterface.getName()).getDetails().add(objectFieldArgumentTypeModification);
                } else {
                    assertTrue(objectOrInterface.isOfType(SchemaGraph.INTERFACE));
                    InterfaceFieldArgumentTypeModification interfaceFieldArgumentTypeModification = new InterfaceFieldArgumentTypeModification(field.getName(), argument.getName(), oldType, newType);
                    getInterfaceModification(objectOrInterface.getName()).getDetails().add(interfaceFieldArgumentTypeModification);
                }
            }
        } else {
            assertTrue(fieldOrDirective.isOfType(SchemaGraph.DIRECTIVE));
            Vertex directive = fieldOrDirective;

            String oldDefaultValue = getDefaultValueFromEdgeLabel(editOperation.getSourceEdge());
            String newDefaultValue = getDefaultValueFromEdgeLabel(editOperation.getTargetEdge());
            if (!oldDefaultValue.equals(newDefaultValue)) {
                getDirectiveModification(directive.getName()).getDetails().add(new DirectiveArgumentDefaultValueModification(argument.getName(), oldDefaultValue, newDefaultValue));
            }
            String oldType = getTypeFromEdgeLabel(editOperation.getSourceEdge());
            String newType = getTypeFromEdgeLabel(editOperation.getTargetEdge());

            if (!oldType.equals(newType)) {
                getDirectiveModification(directive.getName()).getDetails().add(new DirectiveArgumentTypeModification(argument.getName(), oldType, newType));
            }
        }
    }

    /**
     * Sometimes the diffing algorithm will give us an argument change when the argument container
     * changed i.e. the argument was "moved" around because the deleted and newly added arguments
     * look similar.
     * 

* We only want to report argument type changes if it makes sense i.e. if the argument container was the same. */ private boolean doesArgumentChangeMakeSense(Vertex oldArgument, Vertex newArgument, Mapping mapping) { // Container for an argument in this case should be a field or directive Vertex oldContainer = oldSchemaGraph.getFieldOrDirectiveForArgument(oldArgument); Vertex newContainer = newSchemaGraph.getFieldOrDirectiveForArgument(newArgument); // Make sure the container is the same return mapping.getTarget(oldContainer) == newContainer; } private void outputFieldTypeChanged(EditOperation editOperation) { Edge targetEdge = editOperation.getTargetEdge(); Vertex field = targetEdge.getFrom(); Vertex container = newSchemaGraph.getFieldsContainerForField(field); if (container.isOfType(SchemaGraph.OBJECT)) { Vertex object = container; ObjectModification objectModification = getObjectModification(object.getName()); String fieldName = field.getName(); String oldType = getTypeFromEdgeLabel(editOperation.getSourceEdge()); String newType = getTypeFromEdgeLabel(editOperation.getTargetEdge()); objectModification.getDetails().add(new ObjectFieldTypeModification(fieldName, oldType, newType)); } else { assertTrue(container.isOfType(SchemaGraph.INTERFACE)); Vertex interfaze = container; InterfaceModification interfaceModification = getInterfaceModification(interfaze.getName()); String fieldName = field.getName(); String oldType = getTypeFromEdgeLabel(editOperation.getSourceEdge()); String newType = getTypeFromEdgeLabel(editOperation.getTargetEdge()); interfaceModification.getDetails().add(new InterfaceFieldTypeModification(fieldName, oldType, newType)); } } // TODO: this is not great, we should avoid parsing the label like that private String getTypeFromEdgeLabel(Edge edge) { String label = edge.getLabel(); assertTrue(label.startsWith("type=")); String type = label.substring("type=".length(), label.indexOf(";")); return type; } private String getDefaultValueFromEdgeLabel(Edge edge) { String label = edge.getLabel(); assertTrue(label.startsWith("type=")); String defaultValue = label.substring(label.indexOf(";defaultValue=") + ";defaultValue=".length()); return defaultValue; } private boolean isTypeEdge(Edge edge) { String label = edge.getLabel(); return label.startsWith("type="); } private void interfaceImplementationDeleted(Edge deletedEdge) { Vertex from = deletedEdge.getFrom(); if (from.isOfType(SchemaGraph.OBJECT)) { if (isObjectDeleted(from.getName())) { return; } Vertex objectVertex = deletedEdge.getFrom(); Vertex interfaceVertex = deletedEdge.getTo(); ObjectInterfaceImplementationDeletion deletion = new ObjectInterfaceImplementationDeletion(interfaceVertex.getName()); getObjectModification(objectVertex.getName()).getDetails().add(deletion); } else { assertTrue(from.isOfType(SchemaGraph.INTERFACE)); if (isInterfaceDeleted(from.getName())) { return; } Vertex interfaceFromVertex = deletedEdge.getFrom(); Vertex interfaceVertex = deletedEdge.getTo(); InterfaceInterfaceImplementationDeletion deletion = new InterfaceInterfaceImplementationDeletion(interfaceVertex.getName()); getInterfaceModification(interfaceFromVertex.getName()).getDetails().add(deletion); } } private void newInterfaceAddedToInterfaceOrObject(Edge newEdge) { Vertex from = newEdge.getFrom(); if (from.isOfType(SchemaGraph.OBJECT)) { if (isObjectAdded(from.getName())) { return; } Vertex objectVertex = newEdge.getFrom(); Vertex interfaceVertex = newEdge.getTo(); ObjectInterfaceImplementationAddition objectInterfaceImplementationAddition = new ObjectInterfaceImplementationAddition(interfaceVertex.getName()); getObjectModification(objectVertex.getName()).getDetails().add(objectInterfaceImplementationAddition); } else { assertTrue(from.isOfType(SchemaGraph.INTERFACE)); if (isInterfaceAdded(from.getName())) { return; } Vertex interfaceFromVertex = newEdge.getFrom(); Vertex interfaceVertex = newEdge.getTo(); InterfaceInterfaceImplementationAddition addition = new InterfaceInterfaceImplementationAddition(interfaceVertex.getName()); getInterfaceModification(interfaceFromVertex.getName()).getDetails().add(addition); } } private boolean isDirectiveAdded(String name) { return directiveDifferences.containsKey(name) && directiveDifferences.get(name) instanceof DirectiveAddition; } private boolean isDirectiveDeleted(String name) { return directiveDifferences.containsKey(name) && directiveDifferences.get(name) instanceof DirectiveDeletion; } private boolean isObjectAdded(String name) { return objectDifferences.containsKey(name) && objectDifferences.get(name) instanceof ObjectAddition; } private boolean isUnionAdded(String name) { return unionDifferences.containsKey(name) && unionDifferences.get(name) instanceof UnionAddition; } private boolean isUnionDeleted(String name) { return unionDifferences.containsKey(name) && unionDifferences.get(name) instanceof UnionDeletion; } private boolean isEnumDeleted(String name) { return enumDifferences.containsKey(name) && enumDifferences.get(name) instanceof EnumDeletion; } private boolean isEnumAdded(String name) { return enumDifferences.containsKey(name) && enumDifferences.get(name) instanceof EnumAddition; } private boolean isInputObjectAdded(String name) { return inputObjectDifferences.containsKey(name) && inputObjectDifferences.get(name) instanceof InputObjectAddition; } private boolean isInputObjectDeleted(String name) { return inputObjectDifferences.containsKey(name) && inputObjectDifferences.get(name) instanceof InputObjectDeletion; } private boolean isInputFieldAdded(String name) { return inputObjectDifferences.containsKey(name) && inputObjectDifferences.get(name) instanceof InputObjectAddition; } private boolean isAppliedDirectiveAdded(Vertex container, String appliedDirectiveName) { if (container.isOfType(SchemaGraph.SCALAR)) { if (scalarDifferences.containsKey(container.getName())) { ScalarDifference scalarDifference = scalarDifferences.get(container.getName()); if (scalarDifference instanceof ScalarModification) { ScalarModification scalarModification = (ScalarModification) scalarDifference; List appliedDirectiveAdditions = scalarModification.getDetails(AppliedDirectiveAddition.class); return appliedDirectiveAdditions.stream().anyMatch(addition -> addition.getName().equals(appliedDirectiveName)); } } } else if (container.isOfType(SchemaGraph.ENUM)) { if (enumDifferences.containsKey(container.getName())) { EnumDifference enumDifference = enumDifferences.get(container.getName()); if (enumDifference instanceof EnumModification) { EnumModification enumModification = (EnumModification) enumDifference; List appliedDirectiveAdditions = enumModification.getDetails(AppliedDirectiveAddition.class); return appliedDirectiveAdditions.stream().anyMatch(addition -> addition.getName().equals(appliedDirectiveName)); } } } else if (container.isOfType(SchemaGraph.OBJECT)) { if (objectDifferences.containsKey(container.getName())) { ObjectDifference objectDifference = objectDifferences.get(container.getName()); if (objectDifference instanceof ObjectModification) { ObjectModification objectModification = (ObjectModification) objectDifference; List appliedDirectiveAdditions = objectModification.getDetails(AppliedDirectiveAddition.class); return appliedDirectiveAdditions.stream().anyMatch(addition -> addition.getName().equals(appliedDirectiveName)); } } } else if (container.isOfType(SchemaGraph.INTERFACE)) { if (interfaceDifferences.containsKey(container.getName())) { InterfaceDifference interfaceDifference = interfaceDifferences.get(container.getName()); if (interfaceDifference instanceof InterfaceModification) { InterfaceModification interfaceModification = (InterfaceModification) interfaceDifference; List appliedDirectiveAdditions = interfaceModification.getDetails(AppliedDirectiveAddition.class); return appliedDirectiveAdditions.stream().anyMatch(addition -> addition.getName().equals(appliedDirectiveName)); } } } else if (container.isOfType(SchemaGraph.INPUT_OBJECT)) { if (inputObjectDifferences.containsKey(container.getName())) { InputObjectDifference inputObjectDifference = inputObjectDifferences.get(container.getName()); if (inputObjectDifference instanceof InputObjectModification) { InputObjectModification inputObjectModification = (InputObjectModification) inputObjectDifference; List appliedDirectiveAdditions = inputObjectModification.getDetails(AppliedDirectiveAddition.class); return appliedDirectiveAdditions.stream().anyMatch(addition -> addition.getName().equals(appliedDirectiveName)); } } } else if (container.isOfType(SchemaGraph.UNION)) { if (unionDifferences.containsKey(container.getName())) { UnionDifference unionDifference = unionDifferences.get(container.getName()); if (unionDifference instanceof UnionModification) { UnionModification unionModification = (UnionModification) unionDifference; List appliedDirectiveAdditions = unionModification.getDetails(AppliedDirectiveAddition.class); return appliedDirectiveAdditions.stream().anyMatch(addition -> addition.getName().equals(appliedDirectiveName)); } } } else if (container.isOfType(SchemaGraph.DIRECTIVE)) { if (directiveDifferences.containsKey(container.getName())) { DirectiveDifference directiveDifference = directiveDifferences.get(container.getName()); if (directiveDifference instanceof DirectiveModification) { DirectiveModification directiveModification = (DirectiveModification) directiveDifference; List appliedDirectiveAdditions = directiveModification.getDetails(AppliedDirectiveAddition.class); return appliedDirectiveAdditions.stream().anyMatch(addition -> addition.getName().equals(appliedDirectiveName)); } } } return false; } private boolean isAppliedDirectiveDeleted(Vertex rootContainer, String appliedDirectiveName) { // if (rootContainer.isOfType(SchemaGraph.ARGUMENT)) { // Vertex argument = rootContainer; // Vertex fieldOrDirective = oldSchemaGraph.getFieldOrDirectiveForArgument(argument); // if (fieldOrDirective.isOfType(SchemaGraph.DIRECTIVE)) { // return isArgumentDeletedFromExistingDirective(fieldOrDirective.getName(), argument.getName()); // } // } if (rootContainer.isOfType(SchemaGraph.SCALAR)) { if (scalarDifferences.containsKey(rootContainer.getName())) { ScalarDifference scalarDifference = scalarDifferences.get(rootContainer.getName()); if (scalarDifference instanceof ScalarModification) { ScalarModification scalarModification = (ScalarModification) scalarDifference; List appliedDirectiveDeletions = scalarModification.getDetails(AppliedDirectiveDeletion.class); return appliedDirectiveDeletions.stream().anyMatch(deletion -> deletion.getName().equals(appliedDirectiveName)); } } } else if (rootContainer.isOfType(SchemaGraph.ENUM)) { if (enumDifferences.containsKey(rootContainer.getName())) { EnumDifference enumDifference = enumDifferences.get(rootContainer.getName()); if (enumDifference instanceof EnumModification) { EnumModification enumModification = (EnumModification) enumDifference; List appliedDirectiveDeletions = enumModification.getDetails(AppliedDirectiveDeletion.class); return appliedDirectiveDeletions.stream().anyMatch(deletion -> deletion.getName().equals(appliedDirectiveName)); } } } else if (rootContainer.isOfType(SchemaGraph.OBJECT)) { if (objectDifferences.containsKey(rootContainer.getName())) { ObjectDifference objectDifference = objectDifferences.get(rootContainer.getName()); if (objectDifference instanceof ObjectModification) { ObjectModification objectModification = (ObjectModification) objectDifference; List appliedDirectiveDeletions = objectModification.getDetails(AppliedDirectiveDeletion.class); return appliedDirectiveDeletions.stream().anyMatch(deletion -> deletion.getName().equals(appliedDirectiveName)); } } } else if (rootContainer.isOfType(SchemaGraph.INTERFACE)) { if (interfaceDifferences.containsKey(rootContainer.getName())) { InterfaceDifference interfaceDifference = interfaceDifferences.get(rootContainer.getName()); if (interfaceDifference instanceof InterfaceModification) { InterfaceModification interfaceModification = (InterfaceModification) interfaceDifference; List appliedDirectiveDeletions = interfaceModification.getDetails(AppliedDirectiveDeletion.class); return appliedDirectiveDeletions.stream().anyMatch(deletion -> deletion.getName().equals(appliedDirectiveName)); } } } else if (rootContainer.isOfType(SchemaGraph.INPUT_OBJECT)) { if (inputObjectDifferences.containsKey(rootContainer.getName())) { InputObjectDifference inputObjectDifference = inputObjectDifferences.get(rootContainer.getName()); if (inputObjectDifference instanceof InputObjectModification) { InputObjectModification inputObjectModification = (InputObjectModification) inputObjectDifference; List appliedDirectiveDeletions = inputObjectModification.getDetails(AppliedDirectiveDeletion.class); return appliedDirectiveDeletions.stream().anyMatch(deletion -> deletion.getName().equals(appliedDirectiveName)); } } } else if (rootContainer.isOfType(SchemaGraph.UNION)) { if (unionDifferences.containsKey(rootContainer.getName())) { UnionDifference unionDifference = unionDifferences.get(rootContainer.getName()); if (unionDifference instanceof UnionModification) { UnionModification unionModification = (UnionModification) unionDifference; List appliedDirectiveDeletions = unionModification.getDetails(AppliedDirectiveDeletion.class); return appliedDirectiveDeletions.stream().anyMatch(deletion -> deletion.getName().equals(appliedDirectiveName)); } } } else if (rootContainer.isOfType(SchemaGraph.DIRECTIVE)) { if (directiveDifferences.containsKey(rootContainer.getName())) { DirectiveDifference directiveDifference = directiveDifferences.get(rootContainer.getName()); if (directiveDifference instanceof DirectiveModification) { DirectiveModification directiveModification = (DirectiveModification) directiveDifference; List appliedDirectiveDeletions = directiveModification.getDetails(AppliedDirectiveDeletion.class); return appliedDirectiveDeletions.stream().anyMatch(deletion -> deletion.getName().equals(appliedDirectiveName)); } } } return false; } private boolean isNewInputFieldExistingInputObject(String inputObjectName, String fieldName) { if (!inputObjectDifferences.containsKey(inputObjectName)) { return false; } if (!(inputObjectDifferences.get(inputObjectName) instanceof InputObjectModification)) { return false; } InputObjectModification modification = (InputObjectModification) inputObjectDifferences.get(inputObjectName); List newFields = modification.getDetails(InputObjectFieldAddition.class); return newFields.stream().anyMatch(detail -> detail.getName().equals(fieldName)); } private boolean isInputFieldDeletedFromExistingInputObject(String inputObjectName, String fieldName) { if (!inputObjectDifferences.containsKey(inputObjectName)) { return false; } if (!(inputObjectDifferences.get(inputObjectName) instanceof InputObjectModification)) { return false; } InputObjectModification modification = (InputObjectModification) inputObjectDifferences.get(inputObjectName); List deletedFields = modification.getDetails(InputObjectFieldDeletion.class); return deletedFields.stream().anyMatch(detail -> detail.getName().equals(fieldName)); } private boolean isArgumentNewForExistingDirective(String directiveName, String argumentName) { if (!directiveDifferences.containsKey(directiveName)) { return false; } if (!(directiveDifferences.get(directiveName) instanceof DirectiveModification)) { return false; } DirectiveModification directiveModification = (DirectiveModification) directiveDifferences.get(directiveName); List newArgs = directiveModification.getDetails(DirectiveArgumentAddition.class); return newArgs.stream().anyMatch(detail -> detail.getName().equals(argumentName)); } private boolean isArgumentDeletedFromExistingDirective(String directiveName, String argumentName) { if (!directiveDifferences.containsKey(directiveName)) { return false; } if (!(directiveDifferences.get(directiveName) instanceof DirectiveModification)) { return false; } DirectiveModification directiveModification = (DirectiveModification) directiveDifferences.get(directiveName); List deletedArgs = directiveModification.getDetails(DirectiveArgumentDeletion.class); return deletedArgs.stream().anyMatch(detail -> detail.getName().equals(argumentName)); } private boolean isArgumentNewForExistingObjectField(String objectName, String fieldName, String argumentName) { if (!objectDifferences.containsKey(objectName)) { return false; } if (!(objectDifferences.get(objectName) instanceof ObjectModification)) { return false; } // finding out if the field was just added ObjectModification objectModification = (ObjectModification) objectDifferences.get(objectName); List newFields = objectModification.getDetails(ObjectFieldAddition.class); boolean newField = newFields.stream().anyMatch(detail -> detail.getName().equals(fieldName)); if (newField) { return false; } // now finding out if the argument is new List newArgs = objectModification.getDetails(ObjectFieldArgumentAddition.class); return newArgs.stream().anyMatch(detail -> detail.getFieldName().equals(fieldName) && detail.getName().equals(argumentName)); } private boolean isArgumentDeletedFromExistingObjectField(String objectName, String fieldName, String argumentName) { if (!objectDifferences.containsKey(objectName)) { return false; } if (!(objectDifferences.get(objectName) instanceof ObjectModification)) { return false; } // finding out if the field was just added ObjectModification objectModification = (ObjectModification) objectDifferences.get(objectName); List deletedFields = objectModification.getDetails(ObjectFieldDeletion.class); boolean deletedField = deletedFields.stream().anyMatch(detail -> detail.getName().equals(fieldName)); if (deletedField) { return false; } // now finding out if the argument is deleted List deletedArgs = objectModification.getDetails(ObjectFieldArgumentDeletion.class); return deletedArgs.stream().anyMatch(detail -> detail.getFieldName().equals(fieldName) && detail.getName().equals(argumentName)); } private boolean isArgumentDeletedFromExistingInterfaceField(String interfaceName, String fieldName, String argumentName) { if (!interfaceDifferences.containsKey(interfaceName)) { return false; } if (!(interfaceDifferences.get(interfaceName) instanceof InterfaceModification)) { return false; } // finding out if the field was just added InterfaceModification interfaceModification = (InterfaceModification) interfaceDifferences.get(interfaceName); List deletedFields = interfaceModification.getDetails(InterfaceFieldDeletion.class); boolean deletedField = deletedFields.stream().anyMatch(detail -> detail.getName().equals(fieldName)); if (deletedField) { return false; } // now finding out if the argument is deleted List deletedArgs = interfaceModification.getDetails(InterfaceFieldArgumentDeletion.class); return deletedArgs.stream().anyMatch(detail -> detail.getFieldName().equals(fieldName) && detail.getName().equals(argumentName)); } private boolean isArgumentNewForExistingInterfaceField(String objectName, String fieldName, String argumentName) { if (!interfaceDifferences.containsKey(objectName)) { return false; } if (!(interfaceDifferences.get(objectName) instanceof InterfaceModification)) { return false; } // finding out if the field was just added InterfaceModification interfaceModification = (InterfaceModification) interfaceDifferences.get(objectName); List newFields = interfaceModification.getDetails(InterfaceFieldAddition.class); boolean newField = newFields.stream().anyMatch(detail -> detail.getName().equals(fieldName)); if (newField) { return false; } // now finding out if the argument is new List newArgs = interfaceModification.getDetails(InterfaceFieldArgumentAddition.class); return newArgs.stream().anyMatch(detail -> detail.getFieldName().equals(fieldName) && detail.getName().equals(argumentName)); } private boolean isFieldNewForExistingObject(String objectName, String fieldName) { if (!objectDifferences.containsKey(objectName)) { return false; } if (!(objectDifferences.get(objectName) instanceof ObjectModification)) { return false; } ObjectModification objectModification = (ObjectModification) objectDifferences.get(objectName); List newFields = objectModification.getDetails(ObjectFieldAddition.class); return newFields.stream().anyMatch(detail -> detail.getName().equals(fieldName)); } private boolean isFieldDeletedFromExistingInterface(String interfaceName, String fieldName) { if (!interfaceDifferences.containsKey(interfaceName)) { return false; } if (!(interfaceDifferences.get(interfaceName) instanceof InterfaceModification)) { return false; } InterfaceModification interfaceModification = (InterfaceModification) interfaceDifferences.get(interfaceName); List deletedFields = interfaceModification.getDetails(InterfaceFieldDeletion.class); return deletedFields.stream().anyMatch(detail -> detail.getName().equals(fieldName)); } private boolean isFieldDeletedFromExistingObject(String objectName, String fieldName) { if (!objectDifferences.containsKey(objectName)) { return false; } if (!(objectDifferences.get(objectName) instanceof ObjectModification)) { return false; } ObjectModification objectModification = (ObjectModification) objectDifferences.get(objectName); List deletedFields = objectModification.getDetails(ObjectFieldDeletion.class); return deletedFields.stream().anyMatch(detail -> detail.getName().equals(fieldName)); } private boolean isNewEnumValueForExistingEnum(String enumName, String valueName) { if (!enumDifferences.containsKey(enumName)) { return false; } if (!(enumDifferences.get(enumName) instanceof EnumModification)) { return false; } EnumModification enumModification = (EnumModification) enumDifferences.get(enumName); List newValues = enumModification.getDetails(EnumValueAddition.class); return newValues.stream().anyMatch(detail -> detail.getName().equals(valueName)); } private boolean isEnumValueDeletedFromExistingEnum(String enumName, String valueName) { if (!enumDifferences.containsKey(enumName)) { return false; } if (!(enumDifferences.get(enumName) instanceof EnumModification)) { return false; } EnumModification enumModification = (EnumModification) enumDifferences.get(enumName); List deletedValues = enumModification.getDetails(EnumValueDeletion.class); return deletedValues.stream().anyMatch(detail -> detail.getName().equals(valueName)); } private boolean isFieldNewForExistingInterface(String interfaceName, String fieldName) { if (!interfaceDifferences.containsKey(interfaceName)) { return false; } if (!(interfaceDifferences.get(interfaceName) instanceof InterfaceModification)) { return false; } InterfaceModification interfaceModification = (InterfaceModification) interfaceDifferences.get(interfaceName); List newFields = interfaceModification.getDetails(InterfaceFieldAddition.class); return newFields.stream().anyMatch(detail -> detail.getName().equals(fieldName)); } private boolean isObjectDeleted(String name) { return objectDifferences.containsKey(name) && objectDifferences.get(name) instanceof ObjectDeletion; } private boolean isInterfaceDeleted(String name) { return interfaceDifferences.containsKey(name) && interfaceDifferences.get(name) instanceof InterfaceDeletion; } private boolean isInterfaceAdded(String name) { return interfaceDifferences.containsKey(name) && interfaceDifferences.get(name) instanceof InterfaceAddition; } private boolean isScalarAdded(String name) { return scalarDifferences.containsKey(name) && scalarDifferences.get(name) instanceof ScalarAddition; } private boolean isScalarDeleted(String name) { return scalarDifferences.containsKey(name) && scalarDifferences.get(name) instanceof ScalarDeletion; } private ObjectModification getObjectModification(String newName) { if (!objectDifferences.containsKey(newName)) { objectDifferences.put(newName, new ObjectModification(newName)); } assertTrue(objectDifferences.get(newName) instanceof ObjectModification); return (ObjectModification) objectDifferences.get(newName); } private UnionModification getUnionModification(String newName) { if (!unionDifferences.containsKey(newName)) { unionDifferences.put(newName, new UnionModification(newName)); } assertTrue(unionDifferences.get(newName) instanceof UnionModification); return (UnionModification) unionDifferences.get(newName); } private EnumModification getEnumModification(String newName) { if (!enumDifferences.containsKey(newName)) { enumDifferences.put(newName, new EnumModification(newName)); } assertTrue(enumDifferences.get(newName) instanceof EnumModification); return (EnumModification) enumDifferences.get(newName); } private InputObjectModification getInputObjectModification(String newName) { if (!inputObjectDifferences.containsKey(newName)) { inputObjectDifferences.put(newName, new InputObjectModification(newName)); } assertTrue(inputObjectDifferences.get(newName) instanceof InputObjectModification); return (InputObjectModification) inputObjectDifferences.get(newName); } private DirectiveModification getDirectiveModification(String newName) { if (!directiveDifferences.containsKey(newName)) { directiveDifferences.put(newName, new DirectiveModification(newName)); } assertTrue(directiveDifferences.get(newName) instanceof DirectiveModification); return (DirectiveModification) directiveDifferences.get(newName); } private InterfaceModification getInterfaceModification(String newName) { if (!interfaceDifferences.containsKey(newName)) { interfaceDifferences.put(newName, new InterfaceModification(newName)); } assertTrue(interfaceDifferences.get(newName) instanceof InterfaceModification); return (InterfaceModification) interfaceDifferences.get(newName); } private ScalarModification getScalarModification(String newName) { if (!scalarDifferences.containsKey(newName)) { scalarDifferences.put(newName, new ScalarModification(newName)); } assertTrue(scalarDifferences.get(newName) instanceof ScalarModification); return (ScalarModification) scalarDifferences.get(newName); } private void addedObject(EditOperation editOperation) { String objectName = editOperation.getTargetVertex().getName(); ObjectAddition objectAddition = new ObjectAddition(objectName); objectDifferences.put(objectName, objectAddition); } private void addedInterface(EditOperation editOperation) { String objectName = editOperation.getTargetVertex().getName(); InterfaceAddition interfaceAddition = new InterfaceAddition(objectName); interfaceDifferences.put(objectName, interfaceAddition); } private void addedUnion(EditOperation editOperation) { String unionName = editOperation.getTargetVertex().getName(); UnionAddition addition = new UnionAddition(unionName); unionDifferences.put(unionName, addition); } private void addedInputObject(EditOperation editOperation) { String inputObjectName = editOperation.getTargetVertex().getName(); InputObjectAddition addition = new InputObjectAddition(inputObjectName); inputObjectDifferences.put(inputObjectName, addition); } private void addedEnum(EditOperation editOperation) { String enumName = editOperation.getTargetVertex().getName(); EnumAddition enumAddition = new EnumAddition(enumName); enumDifferences.put(enumName, enumAddition); } private void addedScalar(EditOperation editOperation) { String scalarName = editOperation.getTargetVertex().getName(); // build in scalars can appear as added when not used in the old schema, but // we don't want to register them as new Scalars if (ScalarInfo.isGraphqlSpecifiedScalar(scalarName)) { return; } ScalarAddition addition = new ScalarAddition(scalarName); scalarDifferences.put(scalarName, addition); } private void addedDirective(EditOperation editOperation) { String directiveName = editOperation.getTargetVertex().getName(); DirectiveAddition addition = new DirectiveAddition(directiveName); directiveDifferences.put(directiveName, addition); } private void removedObject(EditOperation editOperation) { String objectName = editOperation.getSourceVertex().getName(); ObjectDeletion change = new ObjectDeletion(objectName); objectDifferences.put(objectName, change); } private void removedInterface(EditOperation editOperation) { String interfaceName = editOperation.getSourceVertex().getName(); InterfaceDeletion change = new InterfaceDeletion(interfaceName); interfaceDifferences.put(interfaceName, change); } private void removedUnion(EditOperation editOperation) { String unionName = editOperation.getSourceVertex().getName(); UnionDeletion change = new UnionDeletion(unionName); unionDifferences.put(unionName, change); } private void removedInputObject(EditOperation editOperation) { String name = editOperation.getSourceVertex().getName(); InputObjectDeletion change = new InputObjectDeletion(name); inputObjectDifferences.put(name, change); } private void removedEnum(EditOperation editOperation) { String enumName = editOperation.getSourceVertex().getName(); EnumDeletion deletion = new EnumDeletion(enumName); enumDifferences.put(enumName, deletion); } private void deletedScalar(EditOperation editOperation) { String scalarName = editOperation.getSourceVertex().getName(); ScalarDeletion change = new ScalarDeletion(scalarName); scalarDifferences.put(scalarName, change); } private void deletedDirective(EditOperation editOperation) { String directiveName = editOperation.getSourceVertex().getName(); DirectiveDeletion change = new DirectiveDeletion(directiveName); directiveDifferences.put(directiveName, change); } private void argumentDeleted(EditOperation editOperation) { // Note: sometimes the edit operation is the argument vertex itself being deleted // Other times, it is the edge to the argument type being deleted Vertex deletedArgument = editOperation.getSourceVertex(); if (deletedArgument == null) { deletedArgument = editOperation.getSourceEdge().getTo(); } Vertex fieldOrDirective = oldSchemaGraph.getFieldOrDirectiveForArgument(deletedArgument); if (fieldOrDirective.isOfType(SchemaGraph.FIELD)) { Vertex field = fieldOrDirective; Vertex fieldsContainerForField = oldSchemaGraph.getFieldsContainerForField(field); if (fieldsContainerForField.isOfType(SchemaGraph.OBJECT)) { Vertex object = fieldsContainerForField; if (isObjectDeleted(object.getName())) { return; } if (isFieldDeletedFromExistingObject(object.getName(), field.getName())) { return; } if (isArgumentDeletedFromExistingObjectField(object.getName(), field.getName(), deletedArgument.getName())) { return; } getObjectModification(object.getName()).getDetails().add(new ObjectFieldArgumentDeletion(field.getName(), deletedArgument.getName())); } else { assertTrue(fieldsContainerForField.isOfType(SchemaGraph.INTERFACE)); Vertex interfaze = fieldsContainerForField; if (isInterfaceDeleted(interfaze.getName())) { return; } if (isFieldDeletedFromExistingInterface(interfaze.getName(), field.getName())) { return; } if (isArgumentDeletedFromExistingInterfaceField(interfaze.getName(), field.getName(), deletedArgument.getName())) { return; } getInterfaceModification(interfaze.getName()).getDetails().add(new InterfaceFieldArgumentDeletion(field.getName(), deletedArgument.getName())); } } else { assertTrue(fieldOrDirective.isOfType(SchemaGraph.DIRECTIVE)); Vertex directive = fieldOrDirective; if (isDirectiveDeleted(directive.getName())) { return; } if (isArgumentDeletedFromExistingDirective(directive.getName(), deletedArgument.getName())) { return; } getDirectiveModification(directive.getName()).getDetails().add(new DirectiveArgumentDeletion(deletedArgument.getName())); } } private void argumentAdded(EditOperation editOperation) { Vertex addedArgument = editOperation.getTargetVertex(); if (addedArgument == null) { addedArgument = editOperation.getTargetEdge().getTo(); } Vertex fieldOrDirective = newSchemaGraph.getFieldOrDirectiveForArgument(addedArgument); if (fieldOrDirective.isOfType(SchemaGraph.FIELD)) { Vertex field = fieldOrDirective; Vertex fieldsContainerForField = newSchemaGraph.getFieldsContainerForField(field); if (fieldsContainerForField.isOfType(SchemaGraph.OBJECT)) { Vertex object = fieldsContainerForField; if (isObjectAdded(object.getName())) { return; } if (isFieldNewForExistingObject(object.getName(), field.getName())) { return; } if (isArgumentNewForExistingObjectField(object.getName(), field.getName(), addedArgument.getName())) { return; } getObjectModification(object.getName()).getDetails().add(new ObjectFieldArgumentAddition(field.getName(), addedArgument.getName())); } else { assertTrue(fieldsContainerForField.isOfType(SchemaGraph.INTERFACE)); Vertex interfaze = fieldsContainerForField; if (isInterfaceAdded(interfaze.getName())) { return; } if (isFieldNewForExistingInterface(interfaze.getName(), field.getName())) { return; } if (isArgumentNewForExistingInterfaceField(interfaze.getName(), field.getName(), addedArgument.getName())) { return; } getInterfaceModification(interfaze.getName()).getDetails().add(new InterfaceFieldArgumentAddition(field.getName(), addedArgument.getName())); } } else { assertTrue(fieldOrDirective.isOfType(SchemaGraph.DIRECTIVE)); Vertex directive = fieldOrDirective; if (isDirectiveAdded(directive.getName())) { return; } if (isArgumentNewForExistingDirective(directive.getName(), addedArgument.getName())) { return; } getDirectiveModification(directive.getName()).getDetails().add(new DirectiveArgumentAddition(addedArgument.getName())); } } private void changedEnum(EditOperation editOperation) { String oldName = editOperation.getSourceVertex().getName(); String newName = editOperation.getTargetVertex().getName(); if (oldName.equals(newName)) { // Something else like description could have changed return; } EnumModification modification = new EnumModification(oldName, newName); enumDifferences.put(oldName, modification); enumDifferences.put(newName, modification); } private void changedScalar(EditOperation editOperation) { String oldName = editOperation.getSourceVertex().getName(); String newName = editOperation.getTargetVertex().getName(); if (oldName.equals(newName)) { // Something else like description could have changed return; } ScalarModification modification = new ScalarModification(oldName, newName); scalarDifferences.put(oldName, modification); scalarDifferences.put(newName, modification); } private void changedInputObject(EditOperation editOperation) { String oldName = editOperation.getSourceVertex().getName(); String newName = editOperation.getTargetVertex().getName(); if (oldName.equals(newName)) { // Something else like description could have changed return; } InputObjectModification modification = new InputObjectModification(oldName, newName); inputObjectDifferences.put(oldName, modification); inputObjectDifferences.put(newName, modification); } private void changedDirective(EditOperation editOperation) { String oldName = editOperation.getSourceVertex().getName(); String newName = editOperation.getTargetVertex().getName(); if (oldName.equals(newName)) { // Something else like description could have changed return; } DirectiveModification modification = new DirectiveModification(oldName, newName); directiveDifferences.put(oldName, modification); directiveDifferences.put(newName, modification); } private void changedObject(EditOperation editOperation) { String oldName = editOperation.getSourceVertex().getName(); String newName = editOperation.getTargetVertex().getName(); if (oldName.equals(newName)) { // Something else like description could have changed return; } ObjectModification objectModification = new ObjectModification(oldName, newName); objectDifferences.put(oldName, objectModification); objectDifferences.put(newName, objectModification); } private void changedInterface(EditOperation editOperation) { String oldName = editOperation.getSourceVertex().getName(); String newName = editOperation.getTargetVertex().getName(); if (oldName.equals(newName)) { // Something else like description could have changed return; } InterfaceModification interfaceModification = new InterfaceModification(oldName, newName); interfaceDifferences.put(oldName, interfaceModification); interfaceDifferences.put(newName, interfaceModification); } private void changedUnion(EditOperation editOperation) { String newName = editOperation.getTargetVertex().getName(); String oldName = editOperation.getSourceVertex().getName(); if (oldName.equals(newName)) { // Something else like description could have changed return; } UnionModification objectModification = new UnionModification(oldName, newName); unionDifferences.put(oldName, objectModification); unionDifferences.put(newName, objectModification); } /** * The order to traverse edit operations according to the operation. * * @see #getTraversalOrder(List) */ private static final List OPERATION_TRAVERSAL_ORDER = List.of( EditOperation.Operation.CHANGE_VERTEX, EditOperation.Operation.INSERT_VERTEX, EditOperation.Operation.DELETE_VERTEX, EditOperation.Operation.CHANGE_EDGE, EditOperation.Operation.INSERT_EDGE, EditOperation.Operation.DELETE_EDGE ); /** * The order to traverse edit operations according to the vertex types involved. * * @see #getTraversalOrder(List) */ private static final List TYPE_TRAVERSAL_ORDER = List.of( // These are all top level declarations SchemaGraph.SCHEMA, SchemaGraph.OBJECT, SchemaGraph.INTERFACE, SchemaGraph.UNION, SchemaGraph.SCALAR, SchemaGraph.ENUM, SchemaGraph.INPUT_OBJECT, SchemaGraph.DIRECTIVE, // These are all direct descendants of top level declarations SchemaGraph.FIELD, SchemaGraph.INPUT_FIELD, SchemaGraph.ENUM_VALUE, // Everything else SchemaGraph.ARGUMENT, SchemaGraph.APPLIED_DIRECTIVE, SchemaGraph.APPLIED_ARGUMENT, SchemaGraph.ISOLATED ); /** * The input list of {@link EditOperation}s does not conform to any order. *

* We need to sort it as we sometimes rely on the parents being processed first. *

* e.g. we ignore a new argument if the parent of the argument is new. * However, if the argument addition is processed before the */ @VisibleForTesting static List getTraversalOrder(List editOperations) { ArrayList sorted = new ArrayList<>(editOperations); sorted.sort( Comparator .comparingInt((editOperation) -> { int i = OPERATION_TRAVERSAL_ORDER.indexOf(editOperation.getOperation()); if (i < 0) { return Assert.assertShouldNeverHappen("Unknown operation: " + editOperation.getOperation()); } return i; }) .thenComparing((editOperation) -> { // Converts this editOperation into an index from the order // The lower the index, the earlier it appears in the sorted list for (int i = 0; i < TYPE_TRAVERSAL_ORDER.size(); i++) { String type = TYPE_TRAVERSAL_ORDER.get(i); if (isAnyVertexOfType(editOperation, type)) { return i; } } return Assert.assertShouldNeverHappen("Unable to determine edit operation subject for: " + editOperation); }) ); return sorted; } private static boolean isAnyVertexOfType(EditOperation edit, String type) { return (edit.getSourceVertex() != null && edit.getSourceVertex().isOfType(type)) || (edit.getTargetVertex() != null && edit.getTargetVertex().isOfType(type)) || (edit.getSourceEdge() != null && isAnyVertexOfType(edit.getSourceEdge(), type)) || (edit.getTargetEdge() != null && isAnyVertexOfType(edit.getTargetEdge(), type)); } private static boolean isAnyVertexOfType(Edge edge, String type) { return edge.getFrom().isOfType(type) || edge.getTo().isOfType(type); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy