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

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

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

import com.google.common.collect.BiMap;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Multimap;
import com.google.common.collect.Table;
import graphql.Assert;
import graphql.Internal;
import graphql.util.FpKit;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static graphql.schema.diffing.SchemaGraph.APPLIED_ARGUMENT;
import static graphql.schema.diffing.SchemaGraph.APPLIED_DIRECTIVE;
import static graphql.schema.diffing.SchemaGraph.ARGUMENT;
import static graphql.schema.diffing.SchemaGraph.DIRECTIVE;
import static graphql.schema.diffing.SchemaGraph.ENUM;
import static graphql.schema.diffing.SchemaGraph.ENUM_VALUE;
import static graphql.schema.diffing.SchemaGraph.FIELD;
import static graphql.schema.diffing.SchemaGraph.INPUT_FIELD;
import static graphql.schema.diffing.SchemaGraph.INPUT_OBJECT;
import static graphql.schema.diffing.SchemaGraph.INTERFACE;
import static graphql.schema.diffing.SchemaGraph.OBJECT;
import static graphql.schema.diffing.SchemaGraph.SCALAR;
import static graphql.schema.diffing.SchemaGraph.SCHEMA;
import static graphql.schema.diffing.SchemaGraph.UNION;
import static graphql.util.FpKit.concat;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;

@Internal
public class FillupIsolatedVertices {

    SchemaGraph sourceGraph;
    SchemaGraph targetGraph;
    IsolatedVertices isolatedVertices;

    private BiMap toRemove = HashBiMap.create();

    static Map> typeContexts = new LinkedHashMap<>();

    static {
        typeContexts.put(SCHEMA, schemaContext());
        typeContexts.put(FIELD, fieldContext());
        typeContexts.put(ARGUMENT, argumentsContexts());
        typeContexts.put(INPUT_FIELD, inputFieldContexts());
        typeContexts.put(OBJECT, objectContext());
        typeContexts.put(INTERFACE, interfaceContext());
        typeContexts.put(UNION, unionContext());
        typeContexts.put(INPUT_OBJECT, inputObjectContext());
        typeContexts.put(SCALAR, scalarContext());
        typeContexts.put(ENUM, enumContext());
        typeContexts.put(ENUM_VALUE, enumValueContext());
        typeContexts.put(APPLIED_DIRECTIVE, appliedDirectiveContext());
        typeContexts.put(APPLIED_ARGUMENT, appliedArgumentContext());
        typeContexts.put(DIRECTIVE, directiveContext());
    }

    private static List inputFieldContexts() {
        VertexContextSegment inputFieldType = new VertexContextSegment() {
            @Override
            public String idForVertex(Vertex vertex, SchemaGraph schemaGraph) {
                return vertex.getType();
            }

            @Override
            public boolean filter(Vertex vertex, SchemaGraph schemaGraph) {
                return INPUT_FIELD.equals(vertex.getType());
            }
        };
        VertexContextSegment inputObjectContext = new VertexContextSegment() {
            @Override
            public String idForVertex(Vertex inputField, SchemaGraph schemaGraph) {
                Vertex inputObject = schemaGraph.getInputObjectForInputField(inputField);
                return inputObject.getName();
            }

            @Override
            public boolean filter(Vertex vertex, SchemaGraph schemaGraph) {
                return true;
            }
        };
        VertexContextSegment inputFieldName = new VertexContextSegment() {
            @Override
            public String idForVertex(Vertex inputField, SchemaGraph schemaGraph) {
                return inputField.getName();
            }

            @Override
            public boolean filter(Vertex vertex, SchemaGraph schemaGraph) {
                return true;
            }
        };
        List contexts = Arrays.asList(inputFieldType, inputObjectContext, inputFieldName);
        return contexts;
    }


    private static List scalarContext() {
        VertexContextSegment scalar = new VertexContextSegment() {
            @Override
            public String idForVertex(Vertex vertex, SchemaGraph schemaGraph) {
                return vertex.getType();
            }

            @Override
            public boolean filter(Vertex vertex, SchemaGraph schemaGraph) {
                return SCALAR.equals(vertex.getType());
            }
        };
        VertexContextSegment scalarName = new VertexContextSegment() {
            @Override
            public String idForVertex(Vertex vertex, SchemaGraph schemaGraph) {
                return vertex.getName();
            }

            @Override
            public boolean filter(Vertex vertex, SchemaGraph schemaGraph) {
                return true;
            }
        };
        List contexts = Arrays.asList(scalar, scalarName);
        return contexts;
    }

    private static List inputObjectContext() {
        VertexContextSegment inputObject = new VertexContextSegment() {
            @Override
            public String idForVertex(Vertex vertex, SchemaGraph schemaGraph) {
                return vertex.getType();
            }

            @Override
            public boolean filter(Vertex vertex, SchemaGraph schemaGraph) {
                return INPUT_OBJECT.equals(vertex.getType());
            }
        };
        VertexContextSegment inputObjectName = new VertexContextSegment() {
            @Override
            public String idForVertex(Vertex inputObject, SchemaGraph schemaGraph) {
                return inputObject.getName();
            }

            @Override
            public boolean filter(Vertex vertex, SchemaGraph schemaGraph) {
                return true;
            }
        };
        List contexts = Arrays.asList(inputObject, inputObjectName);
        return contexts;
    }

    private static List objectContext() {
        VertexContextSegment objectType = new VertexContextSegment() {
            @Override
            public String idForVertex(Vertex vertex, SchemaGraph schemaGraph) {
                return vertex.getType();
            }

            @Override
            public boolean filter(Vertex vertex, SchemaGraph schemaGraph) {
                return OBJECT.equals(vertex.getType());
            }
        };

        VertexContextSegment objectName = new VertexContextSegment() {
            @Override
            public String idForVertex(Vertex object, SchemaGraph schemaGraph) {
                return object.getName();
            }

            @Override
            public boolean filter(Vertex vertex, SchemaGraph schemaGraph) {
                return true;
            }
        };
        List contexts = Arrays.asList(objectType, objectName);
        return contexts;
    }

    private static List enumContext() {
        VertexContextSegment enumCtxType = new VertexContextSegment() {
            @Override
            public String idForVertex(Vertex vertex, SchemaGraph schemaGraph) {
                return vertex.getType();
            }

            @Override
            public boolean filter(Vertex vertex, SchemaGraph schemaGraph) {
                return ENUM.equals(vertex.getType());
            }
        };
        VertexContextSegment enumName = new VertexContextSegment() {
            @Override
            public String idForVertex(Vertex enumVertex, SchemaGraph schemaGraph) {
                return enumVertex.getName();
            }

            @Override
            public boolean filter(Vertex vertex, SchemaGraph schemaGraph) {
                return true;
            }
        };
        List contexts = Arrays.asList(enumCtxType, enumName);
        return contexts;
    }

    private static List enumValueContext() {
        VertexContextSegment enumValueType = new VertexContextSegment() {
            @Override
            public String idForVertex(Vertex vertex, SchemaGraph schemaGraph) {
                return vertex.getType();
            }

            @Override
            public boolean filter(Vertex vertex, SchemaGraph schemaGraph) {
                return ENUM_VALUE.equals(vertex.getType());
            }
        };
        VertexContextSegment enumName = new VertexContextSegment() {
            @Override
            public String idForVertex(Vertex enumValue, SchemaGraph schemaGraph) {
                return schemaGraph.getEnumForEnumValue(enumValue).getName();
            }

            @Override
            public boolean filter(Vertex vertex, SchemaGraph schemaGraph) {
                return true;
            }
        };
        VertexContextSegment enumValueName = new VertexContextSegment() {
            @Override
            public String idForVertex(Vertex enumValue, SchemaGraph schemaGraph) {
                return enumValue.getName();
            }

            @Override
            public boolean filter(Vertex vertex, SchemaGraph schemaGraph) {
                return true;
            }
        };
        List contexts = Arrays.asList(enumValueType, enumName, enumValueName);
        return contexts;
    }

    private static List interfaceContext() {
        VertexContextSegment interfaceType = new VertexContextSegment() {
            @Override
            public String idForVertex(Vertex vertex, SchemaGraph schemaGraph) {
                return vertex.getType();
            }

            @Override
            public boolean filter(Vertex vertex, SchemaGraph schemaGraph) {
                return INTERFACE.equals(vertex.getType());
            }
        };
        VertexContextSegment interfaceName = new VertexContextSegment() {
            @Override
            public String idForVertex(Vertex interfaceVertex, SchemaGraph schemaGraph) {
                return interfaceVertex.getName();
            }

            @Override
            public boolean filter(Vertex vertex, SchemaGraph schemaGraph) {
                return true;
            }
        };

        List contexts = Arrays.asList(interfaceType, interfaceName);
        return contexts;
    }

    private static List unionContext() {
        VertexContextSegment unionType = new VertexContextSegment() {
            @Override
            public String idForVertex(Vertex vertex, SchemaGraph schemaGraph) {
                return vertex.getType();
            }

            @Override
            public boolean filter(Vertex vertex, SchemaGraph schemaGraph) {
                return UNION.equals(vertex.getType());
            }
        };
        VertexContextSegment unionName = new VertexContextSegment() {
            @Override
            public String idForVertex(Vertex union, SchemaGraph schemaGraph) {
                return union.getName();
            }

            @Override
            public boolean filter(Vertex vertex, SchemaGraph schemaGraph) {
                return true;
            }
        };

        List contexts = Arrays.asList(unionType, unionName);
        return contexts;
    }

    private static List directiveContext() {
        VertexContextSegment directiveType = new VertexContextSegment() {
            @Override
            public String idForVertex(Vertex vertex, SchemaGraph schemaGraph) {
                return vertex.getType();
            }

            @Override
            public boolean filter(Vertex vertex, SchemaGraph schemaGraph) {
                return DIRECTIVE.equals(vertex.getType());
            }
        };
        VertexContextSegment directiveName = new VertexContextSegment() {
            @Override
            public String idForVertex(Vertex directive, SchemaGraph schemaGraph) {
                return directive.getName();
            }

            @Override
            public boolean filter(Vertex vertex, SchemaGraph schemaGraph) {
                return true;
            }
        };

        List contexts = Arrays.asList(directiveType, directiveName);
        return contexts;
    }

    private static List appliedDirectiveContext() {
        VertexContextSegment appliedDirectiveType = new VertexContextSegment() {
            @Override
            public String idForVertex(Vertex vertex, SchemaGraph schemaGraph) {
                return vertex.getType();
            }

            @Override
            public boolean filter(Vertex vertex, SchemaGraph schemaGraph) {
                return APPLIED_DIRECTIVE.equals(vertex.getType());
            }
        };
        VertexContextSegment appliedDirectiveName = new VertexContextSegment() {
            @Override
            public String idForVertex(Vertex appliedDirective, SchemaGraph schemaGraph) {
                int appliedDirectiveIndex = schemaGraph.getAppliedDirectiveIndex(appliedDirective);
                return appliedDirectiveIndex + ":" + appliedDirective.getName();
            }

            @Override
            public boolean filter(Vertex vertex, SchemaGraph schemaGraph) {
                return true;
            }
        };

        VertexContextSegment appliedDirectiveContainer = new VertexContextSegment() {
            @Override
            public String idForVertex(Vertex appliedDirective, SchemaGraph schemaGraph) {
                Vertex appliedDirectiveContainer = schemaGraph.getAppliedDirectiveContainerForAppliedDirective(appliedDirective);
                return appliedDirectiveContainer.getType() + "." + appliedDirectiveContainer.getName();
            }

            @Override
            public boolean filter(Vertex vertex, SchemaGraph schemaGraph) {
                return true;
            }
        };
        VertexContextSegment parentOfContainer = new VertexContextSegment() {
            @Override
            public String idForVertex(Vertex appliedDirective, SchemaGraph schemaGraph) {
                Vertex container = schemaGraph.getAppliedDirectiveContainerForAppliedDirective(appliedDirective);
                switch (container.getType()) {
                    case SCHEMA:
                        return SCHEMA;
                    case FIELD:
                        Vertex fieldsContainer = schemaGraph.getFieldsContainerForField(container);
                        return fieldsContainer.getType() + "." + fieldsContainer.getName();
                    case OBJECT:
                        return OBJECT;
                    case INTERFACE:
                        return INTERFACE;
                    case INPUT_FIELD:
                        Vertex inputObject = schemaGraph.getInputObjectForInputField(container);
                        return inputObject.getType() + "." + inputObject.getName();
                    case ARGUMENT:
                        Vertex fieldOrDirective = schemaGraph.getFieldOrDirectiveForArgument(container);
                        return fieldOrDirective.getType() + "." + fieldOrDirective.getName();
                    case INPUT_OBJECT:
                        return INPUT_OBJECT;
                    case ENUM:
                        return ENUM;
                    case UNION:
                        return UNION;
                    case SCALAR:
                        return SCALAR;
                    case ENUM_VALUE:
                        Vertex enumVertex = schemaGraph.getEnumForEnumValue(container);
                        return enumVertex.getType() + "." + enumVertex.getName();
                    default:
                        throw new IllegalStateException("Unexpected directive container type " + container.getType());
                }
            }

            @Override
            public boolean filter(Vertex vertex, SchemaGraph schemaGraph) {
                return true;
            }
        };

        VertexContextSegment parentOfParentOfContainer = new VertexContextSegment() {
            @Override
            public String idForVertex(Vertex appliedDirective, SchemaGraph schemaGraph) {
                Vertex container = schemaGraph.getAppliedDirectiveContainerForAppliedDirective(appliedDirective);
                switch (container.getType()) {
                    case SCHEMA:
                    case FIELD:
                    case OBJECT:
                    case INTERFACE:
                    case INPUT_FIELD:
                    case INPUT_OBJECT:
                    case ENUM:
                    case ENUM_VALUE:
                    case UNION:
                    case SCALAR:
                        return "";
                    case ARGUMENT:
                        Vertex fieldOrDirective = schemaGraph.getFieldOrDirectiveForArgument(container);
                        switch (fieldOrDirective.getType()) {
                            case FIELD:
                                Vertex fieldsContainer = schemaGraph.getFieldsContainerForField(fieldOrDirective);
                                return fieldsContainer.getType() + "." + fieldsContainer.getName();
                            case DIRECTIVE:
                                return "";
                            default:
                                return Assert.assertShouldNeverHappen();
                        }
                    default:
                        throw new IllegalStateException("Unexpected directive container type " + container.getType());
                }
            }

            @Override
            public boolean filter(Vertex vertex, SchemaGraph schemaGraph) {
                return true;
            }
        };
        List contexts = Arrays.asList(appliedDirectiveType, parentOfParentOfContainer, parentOfContainer, appliedDirectiveContainer, appliedDirectiveName);
        return contexts;
    }


    private static List appliedArgumentContext() {
        VertexContextSegment appliedArgumentType = new VertexContextSegment() {
            @Override
            public String idForVertex(Vertex vertex, SchemaGraph schemaGraph) {
                return vertex.getType();
            }

            @Override
            public boolean filter(Vertex vertex, SchemaGraph schemaGraph) {
                return APPLIED_ARGUMENT.equals(vertex.getType());
            }
        };
        VertexContextSegment appliedDirective = new VertexContextSegment() {
            @Override
            public String idForVertex(Vertex appliedArgument, SchemaGraph schemaGraph) {
                Vertex appliedDirective = schemaGraph.getAppliedDirectiveForAppliedArgument(appliedArgument);
                int appliedDirectiveIndex = schemaGraph.getAppliedDirectiveIndex(appliedDirective);
                return appliedDirectiveIndex + ":" + appliedDirective.getName();
            }

            @Override
            public boolean filter(Vertex vertex, SchemaGraph schemaGraph) {
                return true;
            }
        };

        VertexContextSegment appliedDirectiveContainer = new VertexContextSegment() {
            @Override
            public String idForVertex(Vertex appliedArgument, SchemaGraph schemaGraph) {
                Vertex appliedDirective = schemaGraph.getAppliedDirectiveForAppliedArgument(appliedArgument);
                Vertex appliedDirectiveContainer = schemaGraph.getAppliedDirectiveContainerForAppliedDirective(appliedDirective);
                return appliedDirectiveContainer.getName();
            }

            @Override
            public boolean filter(Vertex vertex, SchemaGraph schemaGraph) {
                return true;
            }
        };
        VertexContextSegment parentOfContainer = new VertexContextSegment() {
            @Override
            public String idForVertex(Vertex appliedArgument, SchemaGraph schemaGraph) {
                Vertex appliedDirective = schemaGraph.getAppliedDirectiveForAppliedArgument(appliedArgument);
                Vertex container = schemaGraph.getAppliedDirectiveContainerForAppliedDirective(appliedDirective);
                switch (container.getType()) {
                    case SCHEMA:
                        return SCHEMA;
                    case FIELD:
                        Vertex fieldsContainer = schemaGraph.getFieldsContainerForField(container);
                        return fieldsContainer.getType() + "." + fieldsContainer.getName();
                    case OBJECT:
                        return OBJECT;
                    case INTERFACE:
                        return INTERFACE;
                    case INPUT_FIELD:
                        Vertex inputObject = schemaGraph.getInputObjectForInputField(container);
                        return inputObject.getType() + "." + inputObject.getName();
                    case ARGUMENT:
                        Vertex fieldOrDirective = schemaGraph.getFieldOrDirectiveForArgument(container);
                        return fieldOrDirective.getType() + "." + fieldOrDirective.getName();
                    case INPUT_OBJECT:
                        return INPUT_OBJECT;
                    case ENUM:
                        return ENUM;
                    case UNION:
                        return UNION;
                    case SCALAR:
                        return SCALAR;
                    case ENUM_VALUE:
                        Vertex enumVertex = schemaGraph.getEnumForEnumValue(container);
                        return enumVertex.getType() + "." + enumVertex.getName();
                    default:
                        throw new IllegalStateException("Unexpected directive container type " + container.getType());
                }
            }

            @Override
            public boolean filter(Vertex vertex, SchemaGraph schemaGraph) {
                return true;
            }
        };

        VertexContextSegment parentOfParentOfContainer = new VertexContextSegment() {
            @Override
            public String idForVertex(Vertex appliedArgument, SchemaGraph schemaGraph) {
                Vertex appliedDirective = schemaGraph.getAppliedDirectiveForAppliedArgument(appliedArgument);
                Vertex container = schemaGraph.getAppliedDirectiveContainerForAppliedDirective(appliedDirective);
                switch (container.getType()) {
                    case SCHEMA:
                    case FIELD:
                    case OBJECT:
                    case INTERFACE:
                    case INPUT_FIELD:
                    case INPUT_OBJECT:
                    case ENUM:
                    case ENUM_VALUE:
                    case UNION:
                    case SCALAR:
                        return "";
                    case ARGUMENT:
                        Vertex fieldOrDirective = schemaGraph.getFieldOrDirectiveForArgument(container);
                        switch (fieldOrDirective.getType()) {
                            case FIELD:
                                Vertex fieldsContainer = schemaGraph.getFieldsContainerForField(fieldOrDirective);
                                return fieldsContainer.getType() + "." + fieldsContainer.getName();
                            case DIRECTIVE:
                                return "";
                            default:
                                return Assert.assertShouldNeverHappen();
                        }
                    default:
                        throw new IllegalStateException("Unexpected directive container type " + container.getType());
                }
            }

            @Override
            public boolean filter(Vertex vertex, SchemaGraph schemaGraph) {
                return true;
            }
        };
        VertexContextSegment appliedArgumentName = new VertexContextSegment() {
            @Override
            public String idForVertex(Vertex appliedArgument, SchemaGraph schemaGraph) {
                return appliedArgument.getName();
            }

            @Override
            public boolean filter(Vertex vertex, SchemaGraph schemaGraph) {
                return true;
            }
        };
        List contexts = Arrays.asList(appliedArgumentType, parentOfParentOfContainer, parentOfContainer, appliedDirectiveContainer, appliedDirective, appliedArgumentName);
        return contexts;
    }

    private static List schemaContext() {
        VertexContextSegment schema = new VertexContextSegment() {
            @Override
            public String idForVertex(Vertex vertex, SchemaGraph schemaGraph) {
                return vertex.getType();
            }

            @Override
            public boolean filter(Vertex vertex, SchemaGraph schemaGraph) {
                return SCHEMA.equals(vertex.getType());
            }
        };
        return singletonList(schema);
    }

    private static List fieldContext() {
        VertexContextSegment field = new VertexContextSegment() {
            @Override
            public String idForVertex(Vertex vertex, SchemaGraph schemaGraph) {
                return vertex.getType();
            }

            @Override
            public boolean filter(Vertex vertex, SchemaGraph schemaGraph) {
                return FIELD.equals(vertex.getType());
            }
        };
        VertexContextSegment container = new VertexContextSegment() {
            @Override
            public String idForVertex(Vertex field, SchemaGraph schemaGraph) {
                Vertex fieldsContainer = schemaGraph.getFieldsContainerForField(field);
                return fieldsContainer.getType() + "." + fieldsContainer.getName();
            }

            @Override
            public boolean filter(Vertex vertex, SchemaGraph schemaGraph) {
                return true;
            }
        };

        VertexContextSegment fieldName = new VertexContextSegment() {
            @Override
            public String idForVertex(Vertex field, SchemaGraph schemaGraph) {
                return field.getName();
            }

            @Override
            public boolean filter(Vertex vertex, SchemaGraph schemaGraph) {
                return true;
            }
        };
        List contexts = Arrays.asList(field, container, fieldName);
        return contexts;
    }

    private static List argumentsContexts() {

        VertexContextSegment argumentType = new VertexContextSegment() {
            @Override
            public String idForVertex(Vertex vertex, SchemaGraph schemaGraph) {
                return vertex.getType();
            }

            @Override
            public boolean filter(Vertex vertex, SchemaGraph schemaGraph) {
                return ARGUMENT.equals(vertex.getType());
            }
        };

        VertexContextSegment fieldOrDirective = new VertexContextSegment() {
            @Override
            public String idForVertex(Vertex argument, SchemaGraph schemaGraph) {
                Vertex fieldOrDirective = schemaGraph.getFieldOrDirectiveForArgument(argument);
                return fieldOrDirective.getType() + "." + fieldOrDirective.getName();
            }

            @Override
            public boolean filter(Vertex argument, SchemaGraph schemaGraph) {
                return true;
            }
        };
        VertexContextSegment containerOrDirectiveHolder = new VertexContextSegment() {
            @Override
            public String idForVertex(Vertex argument, SchemaGraph schemaGraph) {
                Vertex fieldOrDirective = schemaGraph.getFieldOrDirectiveForArgument(argument);
                if (fieldOrDirective.getType().equals(FIELD)) {
                    Vertex fieldsContainer = schemaGraph.getFieldsContainerForField(fieldOrDirective);
                    // can be Interface or Object
                    return fieldsContainer.getType() + "." + fieldsContainer.getName();
                } else {
                    // a directive doesn't have further context
                    return "";
                }
            }

            @Override
            public boolean filter(Vertex argument, SchemaGraph schemaGraph) {
                return true;
            }
        };
        VertexContextSegment argumentName = new VertexContextSegment() {
            @Override
            public String idForVertex(Vertex argument, SchemaGraph schemaGraph) {
                return argument.getName();
            }

            @Override
            public boolean filter(Vertex argument, SchemaGraph schemaGraph) {
                return true;
            }
        };
        List contexts = Arrays.asList(argumentType, containerOrDirectiveHolder, fieldOrDirective, argumentName);
        return contexts;
    }


    public FillupIsolatedVertices(SchemaGraph sourceGraph, SchemaGraph targetGraph) {
        this.sourceGraph = sourceGraph;
        this.targetGraph = targetGraph;
        this.isolatedVertices = new IsolatedVertices();
    }

    public void ensureGraphAreSameSize() {
        calcPossibleMappings(typeContexts.get(SCHEMA), SCHEMA);
        calcPossibleMappings(typeContexts.get(FIELD), FIELD);
        calcPossibleMappings(typeContexts.get(ARGUMENT), ARGUMENT);
        calcPossibleMappings(typeContexts.get(INPUT_FIELD), INPUT_FIELD);
//        calcPossibleMappings(typeContexts.get(DUMMY_TYPE_VERTEX), DUMMY_TYPE_VERTEX);
        calcPossibleMappings(typeContexts.get(OBJECT), OBJECT);
        calcPossibleMappings(typeContexts.get(INTERFACE), INTERFACE);
        calcPossibleMappings(typeContexts.get(UNION), UNION);
        calcPossibleMappings(typeContexts.get(INPUT_OBJECT), INPUT_OBJECT);
        calcPossibleMappings(typeContexts.get(SCALAR), SCALAR);
        calcPossibleMappings(typeContexts.get(ENUM), ENUM);
        calcPossibleMappings(typeContexts.get(ENUM_VALUE), ENUM_VALUE);
        calcPossibleMappings(typeContexts.get(APPLIED_DIRECTIVE), APPLIED_DIRECTIVE);
        calcPossibleMappings(typeContexts.get(APPLIED_ARGUMENT), APPLIED_ARGUMENT);
        calcPossibleMappings(typeContexts.get(DIRECTIVE), DIRECTIVE);


        sourceGraph.addVertices(isolatedVertices.allIsolatedSource);
        targetGraph.addVertices(isolatedVertices.allIsolatedTarget);

        Assert.assertTrue(sourceGraph.size() == targetGraph.size());
    }


    public abstract static class VertexContextSegment {

        private List children;

        public VertexContextSegment(List children) {
            this.children = children;
        }

        public VertexContextSegment() {
            this.children = emptyList();
        }

        public VertexContextSegment(VertexContextSegment child) {
            this.children = singletonList(child);
        }

        public abstract String idForVertex(Vertex vertex, SchemaGraph schemaGraph);

        public abstract boolean filter(Vertex vertex, SchemaGraph schemaGraph);
    }

    public class IsolatedVertices {

        public Set allIsolatedSource = new LinkedHashSet<>();
        public Set allIsolatedTarget = new LinkedHashSet<>();

        public Table, Set, Set> contexts = HashBasedTable.create();

        public Multimap possibleMappings = HashMultimap.create();
        public Mapping mapping = new Mapping();

        public void putPossibleMappings(Collection sourceVertices, Collection targetVertex) {
            for (Vertex sourceVertex : sourceVertices) {
                possibleMappings.putAll(sourceVertex, targetVertex);
            }
        }

        public void addIsolatedSource(Collection isolatedSource) {
            allIsolatedSource.addAll(isolatedSource);
        }

        public void addIsolatedTarget(Collection isolatedTarget) {
            allIsolatedTarget.addAll(isolatedTarget);
        }

        //
        public boolean mappingPossible(Vertex sourceVertex, Vertex targetVertex) {
            return possibleMappings.containsEntry(sourceVertex, targetVertex);
        }

        public void putContext(List contextId, Set source, Set target) {
            if (contexts.containsRow(contextId)) {
                throw new IllegalArgumentException("Already context " + contextId);
            }
            Assert.assertTrue(source.size() == target.size());
            if (source.size() == 1) {
                mapping.add(source.iterator().next(), target.iterator().next());
            }
            contexts.put(contextId, source, target);
        }

    }


    public void calcPossibleMappings(List contexts, String typeNameForDebug) {
        Collection currentSourceVertices = sourceGraph.getVertices();
        Collection currentTargetVertices = targetGraph.getVertices();
        calcPossibleMappingImpl(currentSourceVertices,
                currentTargetVertices,
                Collections.emptyList(),
                0,
                contexts,
                new LinkedHashSet<>(),
                new LinkedHashSet<>(),
                typeNameForDebug);
    }

    /**
     * calc for the provided context
     */
    private void calcPossibleMappingImpl(
            Collection currentSourceVertices,
            Collection currentTargetVertices,
            List contextId,
            int contextIx,
            List contexts,
            Set usedSourceVertices,
            Set usedTargetVertices,
            String typeNameForDebug) {

        VertexContextSegment finalCurrentContext = contexts.get(contextIx);
        Map> sourceGroups = FpKit.filterAndGroupingBy(currentSourceVertices,
                v -> finalCurrentContext.filter(v, sourceGraph),
                v -> finalCurrentContext.idForVertex(v, sourceGraph));
        Map> targetGroups = FpKit.filterAndGroupingBy(currentTargetVertices,
                v -> finalCurrentContext.filter(v, targetGraph),
                v -> finalCurrentContext.idForVertex(v, targetGraph));


        List deletedContexts = new ArrayList<>();
        List insertedContexts = new ArrayList<>();
        List sameContexts = new ArrayList<>();
        Util.diffNamedList(sourceGroups.keySet(), targetGroups.keySet(), deletedContexts, insertedContexts, sameContexts);

        // for each unchanged context we descend recursively into
        for (String sameContext : sameContexts) {
            ImmutableList sourceVerticesInContext = sourceGroups.get(sameContext);
            ImmutableList targetVerticesInContext = targetGroups.get(sameContext);

            List currentContextId = concat(contextId, sameContext);
            if (contexts.size() > contextIx + 1) {
                calcPossibleMappingImpl(sourceVerticesInContext, targetVerticesInContext, currentContextId, contextIx + 1, contexts, usedSourceVertices, usedTargetVertices, typeNameForDebug);
            }
            /**
             * Either there was no context segment left or not all vertices were relevant for
             * Either way: fill up with isolated vertices and record as possible mapping
             */
            Set notUsedSource = new LinkedHashSet<>(sourceVerticesInContext);
            notUsedSource.removeAll(usedSourceVertices);
            Set notUsedTarget = new LinkedHashSet<>(targetVerticesInContext);
            notUsedTarget.removeAll(usedTargetVertices);

            // make sure the current context is the same size
            if (notUsedSource.size() > notUsedTarget.size()) {
                Set newTargetVertices = Vertex.newIsolatedNodes(notUsedSource.size() - notUsedTarget.size(), "target-isolated-" + typeNameForDebug + "-");
                isolatedVertices.addIsolatedTarget(newTargetVertices);
                notUsedTarget.addAll(newTargetVertices);
            } else if (notUsedTarget.size() > notUsedSource.size()) {
                Set newSourceVertices = Vertex.newIsolatedNodes(notUsedTarget.size() - notUsedSource.size(), "source-isolated-" + typeNameForDebug + "-");
                isolatedVertices.addIsolatedSource(newSourceVertices);
                notUsedSource.addAll(newSourceVertices);
            }
            isolatedVertices.putPossibleMappings(notUsedSource, notUsedTarget);
            usedSourceVertices.addAll(notUsedSource);
            usedTargetVertices.addAll(notUsedTarget);
            if (notUsedSource.size() > 0) {
                isolatedVertices.putContext(currentContextId, notUsedSource, notUsedTarget);
            }
        }

        Set possibleTargetVertices = new LinkedHashSet<>();
        for (String insertedContext : insertedContexts) {
            ImmutableList vertices = targetGroups.get(insertedContext);
            for (Vertex targetVertex : vertices) {
                if (!usedTargetVertices.contains(targetVertex)) {
                    possibleTargetVertices.add(targetVertex);
                }
            }
            usedTargetVertices.addAll(vertices);
        }

        Set possibleSourceVertices = new LinkedHashSet<>();
        for (String deletedContext : deletedContexts) {
            ImmutableList vertices = sourceGroups.get(deletedContext);
            for (Vertex sourceVertex : vertices) {
                if (!usedSourceVertices.contains(sourceVertex)) {
                    possibleSourceVertices.add(sourceVertex);
                }
            }
            usedSourceVertices.addAll(vertices);
        }

        if (possibleSourceVertices.size() > possibleTargetVertices.size()) {
            Set newTargetVertices = Vertex.newIsolatedNodes(possibleSourceVertices.size() - possibleTargetVertices.size(), "target-isolated-" + typeNameForDebug + "-");
            isolatedVertices.addIsolatedTarget(newTargetVertices);
            possibleTargetVertices.addAll(newTargetVertices);
        } else if (possibleTargetVertices.size() > possibleSourceVertices.size()) {
            Set newSourceVertices = Vertex.newIsolatedNodes(possibleTargetVertices.size() - possibleSourceVertices.size(), "source-isolated-" + typeNameForDebug + "-");
            isolatedVertices.addIsolatedSource(newSourceVertices);
            possibleSourceVertices.addAll(newSourceVertices);
        }
        // if there are only added or removed vertices in the current context, contextId might be empty
        if (possibleSourceVertices.size() > 0) {
            if (contextId.size() == 0) {
                contextId = singletonList(typeNameForDebug);
            }
            isolatedVertices.putContext(contextId, possibleSourceVertices, possibleTargetVertices);
        }
        isolatedVertices.putPossibleMappings(possibleSourceVertices, possibleTargetVertices);
    }


}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy