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

graphql.introspection.IntrospectionResultToSchema Maven / Gradle / Ivy

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

import graphql.ExecutionResult;
import graphql.PublicApi;
import graphql.language.Argument;
import graphql.language.AstValueHelper;
import graphql.language.Comment;
import graphql.language.Directive;
import graphql.language.Document;
import graphql.language.EnumTypeDefinition;
import graphql.language.EnumValueDefinition;
import graphql.language.FieldDefinition;
import graphql.language.InputObjectTypeDefinition;
import graphql.language.InputValueDefinition;
import graphql.language.InterfaceTypeDefinition;
import graphql.language.ListType;
import graphql.language.NonNullType;
import graphql.language.ObjectTypeDefinition;
import graphql.language.OperationTypeDefinition;
import graphql.language.ScalarTypeDefinition;
import graphql.language.SchemaDefinition;
import graphql.language.SourceLocation;
import graphql.language.StringValue;
import graphql.language.Type;
import graphql.language.TypeDefinition;
import graphql.language.TypeName;
import graphql.language.UnionTypeDefinition;
import graphql.language.Value;
import graphql.schema.idl.ScalarInfo;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static graphql.Assert.assertNotNull;
import static graphql.Assert.assertShouldNeverHappen;
import static graphql.Assert.assertTrue;

@SuppressWarnings("unchecked")
@PublicApi
public class IntrospectionResultToSchema {

    /**
     * Returns a IDL Document that represents the schema as defined by the introspection execution result
     *
     * @param introspectionResult the result of an introspection query on a schema
     *
     * @return a IDL Document of the schema
     */
    public Document createSchemaDefinition(ExecutionResult introspectionResult) {
        Map introspectionResultMap = introspectionResult.getData();
        return createSchemaDefinition(introspectionResultMap);
    }


    /**
     * Returns a IDL Document that reprSesents the schema as defined by the introspection result map
     *
     * @param introspectionResult the result of an introspection query on a schema
     *
     * @return a IDL Document of the schema
     */
    @SuppressWarnings("unchecked")
    public Document createSchemaDefinition(Map introspectionResult) {
        assertTrue(introspectionResult.get("__schema") != null, "__schema expected");
        Map schema = (Map) introspectionResult.get("__schema");


        Map queryType = (Map) schema.get("queryType");
        assertNotNull(queryType, "queryType expected");
        TypeName query = new TypeName((String) queryType.get("name"));
        boolean nonDefaultQueryName = !"Query".equals(query.getName());

        SchemaDefinition schemaDefinition = new SchemaDefinition();
        schemaDefinition.getOperationTypeDefinitions().add(new OperationTypeDefinition("query", query));

        Map mutationType = (Map) schema.get("mutationType");
        boolean nonDefaultMutationName = false;
        if (mutationType != null) {
            TypeName mutation = new TypeName((String) mutationType.get("name"));
            nonDefaultMutationName = !"Mutation".equals(mutation.getName());
            schemaDefinition.getOperationTypeDefinitions().add(new OperationTypeDefinition("mutation", mutation));
        }

        Map subscriptionType = (Map) schema.get("subscriptionType");
        boolean nonDefaultSubscriptionName = false;
        if (subscriptionType != null) {
            TypeName subscription = new TypeName((String) subscriptionType.get("name"));
            nonDefaultSubscriptionName = !"Subscription".equals(subscription.getName());
            schemaDefinition.getOperationTypeDefinitions().add(new OperationTypeDefinition("subscription", subscription));
        }

        Document document = new Document();
        if (nonDefaultQueryName || nonDefaultMutationName || nonDefaultSubscriptionName) {
            document.getDefinitions().add(schemaDefinition);
        }

        List> types = (List>) schema.get("types");
        for (Map type : types) {
            TypeDefinition typeDefinition = createTypeDefinition(type);
            if (typeDefinition == null) continue;
            document.getDefinitions().add(typeDefinition);
        }

        return document;
    }

    private TypeDefinition createTypeDefinition(Map type) {
        String kind = (String) type.get("kind");
        String name = (String) type.get("name");
        if (name.startsWith("__")) return null;
        switch (kind) {
            case "INTERFACE":
                return createInterface(type);
            case "OBJECT":
                return createObject(type);
            case "UNION":
                return createUnion(type);
            case "ENUM":
                return createEnum(type);
            case "INPUT_OBJECT":
                return createInputObject(type);
            case "SCALAR":
                return createScalar(type);
            default:
                return assertShouldNeverHappen("unexpected kind %s", kind);
        }
    }

    private TypeDefinition createScalar(Map input) {
        String name = (String) input.get("name");
        if (ScalarInfo.isStandardScalar(name)) {
            return null;
        }
        return new ScalarTypeDefinition(name);
    }


    @SuppressWarnings("unchecked")
    UnionTypeDefinition createUnion(Map input) {
        assertTrue(input.get("kind").equals("UNION"), "wrong input");

        UnionTypeDefinition unionTypeDefinition = new UnionTypeDefinition((String) input.get("name"));
        unionTypeDefinition.setComments(toComment((String) input.get("description")));

        List> possibleTypes = (List>) input.get("possibleTypes");

        for (Map possibleType : possibleTypes) {
            TypeName typeName = new TypeName((String) possibleType.get("name"));
            unionTypeDefinition.getMemberTypes().add(typeName);
        }

        return unionTypeDefinition;
    }

    @SuppressWarnings("unchecked")
    EnumTypeDefinition createEnum(Map input) {
        assertTrue(input.get("kind").equals("ENUM"), "wrong input");

        EnumTypeDefinition enumTypeDefinition = new EnumTypeDefinition((String) input.get("name"));
        enumTypeDefinition.setComments(toComment((String) input.get("description")));

        List> enumValues = (List>) input.get("enumValues");

        for (Map enumValue : enumValues) {

            EnumValueDefinition enumValueDefinition = new EnumValueDefinition((String) enumValue.get("name"));
            enumValueDefinition.setComments(toComment((String) enumValue.get("description")));

            createDeprecatedDirective(enumValue, enumValueDefinition.getDirectives());

            enumTypeDefinition.getEnumValueDefinitions().add(enumValueDefinition);
        }

        return enumTypeDefinition;
    }

    @SuppressWarnings("unchecked")
    InterfaceTypeDefinition createInterface(Map input) {
        assertTrue(input.get("kind").equals("INTERFACE"), "wrong input");

        InterfaceTypeDefinition interfaceTypeDefinition = new InterfaceTypeDefinition((String) input.get("name"));
        interfaceTypeDefinition.setComments(toComment((String) input.get("description")));
        List> fields = (List>) input.get("fields");
        interfaceTypeDefinition.getFieldDefinitions().addAll(createFields(fields));

        return interfaceTypeDefinition;

    }

    @SuppressWarnings("unchecked")
    InputObjectTypeDefinition createInputObject(Map input) {
        assertTrue(input.get("kind").equals("INPUT_OBJECT"), "wrong input");

        InputObjectTypeDefinition inputObjectTypeDefinition = new InputObjectTypeDefinition((String) input.get("name"));
        inputObjectTypeDefinition.setComments(toComment((String) input.get("description")));
        List> fields = (List>) input.get("inputFields");
        List inputValueDefinitions = createInputValueDefinitions(fields);
        inputObjectTypeDefinition.getInputValueDefinitions().addAll(inputValueDefinitions);

        return inputObjectTypeDefinition;
    }

    @SuppressWarnings("unchecked")
    ObjectTypeDefinition createObject(Map input) {
        assertTrue(input.get("kind").equals("OBJECT"), "wrong input");

        ObjectTypeDefinition objectTypeDefinition = new ObjectTypeDefinition((String) input.get("name"));
        objectTypeDefinition.setComments(toComment((String) input.get("description")));
        if (input.containsKey("interfaces")) {
            objectTypeDefinition.getImplements().addAll(
                    ((List>)input.get("interfaces")).stream()
                            .map(this::createTypeIndirection)
                            .collect(Collectors.toList())
            );
        }
        List> fields = (List>) input.get("fields");

        objectTypeDefinition.getFieldDefinitions().addAll(createFields(fields));

        return objectTypeDefinition;
    }

    private List createFields(List> fields) {
        List result = new ArrayList<>();
        for (Map field : fields) {
            FieldDefinition fieldDefinition = new FieldDefinition((String) field.get("name"));
            fieldDefinition.setComments(toComment((String) field.get("description")));
            fieldDefinition.setType(createTypeIndirection((Map) field.get("type")));

            createDeprecatedDirective(field, fieldDefinition.getDirectives());

            List> args = (List>) field.get("args");
            List inputValueDefinitions = createInputValueDefinitions(args);
            fieldDefinition.getInputValueDefinitions().addAll(inputValueDefinitions);
            result.add(fieldDefinition);
        }
        return result;
    }

    private void createDeprecatedDirective(Map field, List directives) {
        if ((Boolean) field.get("isDeprecated")) {
            String reason = (String) field.get("deprecationReason");
            if (reason == null) {
                reason = "No longer supported"; // default according to spec
            }
            Argument reasonArg = new Argument("reason", new StringValue(reason));
            Directive deprecated = new Directive("deprecated", Collections.singletonList(reasonArg));
            directives.add(deprecated);
        }
    }

    @SuppressWarnings("unchecked")
    private List createInputValueDefinitions(List> args) {
        List result = new ArrayList<>();
        for (Map arg : args) {
            Type argType = createTypeIndirection((Map) arg.get("type"));
            InputValueDefinition inputValueDefinition = new InputValueDefinition((String) arg.get("name"), argType);
            inputValueDefinition.setComments(toComment((String) arg.get("description")));

            String valueLiteral = (String) arg.get("defaultValue");
            if (valueLiteral != null) {
                Value defaultValue = AstValueHelper.valueFromAst(valueLiteral);
                inputValueDefinition.setDefaultValue(defaultValue);
            }
            result.add(inputValueDefinition);
        }
        return result;
    }

    @SuppressWarnings("unchecked")
    private Type createTypeIndirection(Map type) {
        String kind = (String) type.get("kind");
        switch (kind) {
            case "INTERFACE":
            case "OBJECT":
            case "UNION":
            case "ENUM":
            case "INPUT_OBJECT":
            case "SCALAR":
                return new TypeName((String) type.get("name"));
            case "NON_NULL":
                return new NonNullType(createTypeIndirection((Map) type.get("ofType")));
            case "LIST":
                return new ListType(createTypeIndirection((Map) type.get("ofType")));
            default:
                return assertShouldNeverHappen("Unknown kind %s", kind);
        }
    }

    private List toComment(String description) {
        if (description == null) return Collections.emptyList();
        Comment comment = new Comment(description, new SourceLocation(1, 1));
        return Collections.singletonList(comment);
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy