TypeDefinitionToDataModelMapper.java 9.0 KB
Newer Older
1 2 3
package com.kobylynskyi.graphql.codegen.mapper;

import com.kobylynskyi.graphql.codegen.model.MappingConfig;
4
import com.kobylynskyi.graphql.codegen.model.ParameterDefinition;
5
import com.kobylynskyi.graphql.codegen.model.ProjectionParameterDefinition;
6 7 8 9
import com.kobylynskyi.graphql.codegen.model.definitions.ExtendedDocument;
import com.kobylynskyi.graphql.codegen.model.definitions.ExtendedInterfaceTypeDefinition;
import com.kobylynskyi.graphql.codegen.model.definitions.ExtendedObjectTypeDefinition;
import com.kobylynskyi.graphql.codegen.model.definitions.ExtendedUnionTypeDefinition;
10
import com.kobylynskyi.graphql.codegen.utils.Utils;
11
import graphql.language.TypeName;
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27

import java.util.*;
import java.util.stream.Collectors;

import static com.kobylynskyi.graphql.codegen.model.DataModelFields.*;

/**
 * Map type definition to a Freemarker data model
 *
 * @author kobylynskyi
 */
public class TypeDefinitionToDataModelMapper {

    /**
     * Map type definition to a Freemarker data model
     *
28 29 30
     * @param mappingConfig Global mapping configuration
     * @param definition    Definition of object type including base definition and its extensions
     * @param document      GraphQL Document
31 32
     * @return Freemarker data model of the GraphQL type
     */
33 34
    public static Map<String, Object> map(MappingConfig mappingConfig,
                                          ExtendedObjectTypeDefinition definition,
35
                                          ExtendedDocument document) {
36
        Map<String, Object> dataModel = new HashMap<>();
37 38
        // type/enum/input/interface/union classes do not require any imports
        dataModel.put(PACKAGE, MapperUtils.getModelPackageName(mappingConfig));
39
        dataModel.put(CLASS_NAME, MapperUtils.getClassNameWithPrefixAndSuffix(mappingConfig, definition));
40
        dataModel.put(JAVA_DOC, definition.getJavaDoc());
41 42
        dataModel.put(IMPLEMENTS, getInterfaces(mappingConfig, definition, document));
        dataModel.put(FIELDS, getFields(mappingConfig, definition, document));
43
        dataModel.put(BUILDER, mappingConfig.getGenerateBuilder());
A
Alberto Valiña 已提交
44 45
        dataModel.put(EQUALS_AND_HASH_CODE, mappingConfig.getGenerateEqualsAndHashCode());
        dataModel.put(TO_STRING, mappingConfig.getGenerateToString());
46
        dataModel.put(TO_STRING_ESCAPE_JSON, mappingConfig.getGenerateRequests());
47 48
        return dataModel;
    }
A
Alberto Valiña 已提交
49

50 51 52 53 54 55 56 57 58 59
    /**
     * Map type definition to a Freemarker data model of Response Projection.
     *
     * @param mappingConfig  Global mapping configuration
     * @param typeDefinition GraphQL type definition
     * @param document       Parent GraphQL document
     * @param typeNames      Names of all GraphQL types
     * @return Freemarker data model of the GraphQL Response Projection
     */
    public static Map<String, Object> mapResponseProjection(MappingConfig mappingConfig,
60 61
                                                            ExtendedObjectTypeDefinition typeDefinition,
                                                            ExtendedDocument document,
62 63
                                                            Set<String> typeNames) {
        Map<String, Object> dataModel = new HashMap<>();
64 65
        // ResponseProjection classes are sharing the package with the model classes, so no imports are needed
        dataModel.put(PACKAGE, MapperUtils.getModelPackageName(mappingConfig));
66
        dataModel.put(CLASS_NAME, Utils.capitalize(typeDefinition.getName()) + mappingConfig.getResponseProjectionSuffix());
67
        dataModel.put(JAVA_DOC, Collections.singletonList("Response projection for " + typeDefinition.getName()));
68
        dataModel.put(FIELDS, getProjectionFields(mappingConfig, typeDefinition, document, typeNames));
69
        dataModel.put(BUILDER, mappingConfig.getGenerateBuilder());
70
        dataModel.put(EQUALS_AND_HASH_CODE, mappingConfig.getGenerateEqualsAndHashCode());
71
        // dataModel.put(TO_STRING, mappingConfig.getGenerateToString()); always generated for serialization purposes
72 73 74
        return dataModel;
    }

75 76 77 78 79 80 81 82
    /**
     * Get merged attributes from the type and attributes from the interface.
     *
     * @param mappingConfig  Global mapping configuration
     * @param typeDefinition GraphQL type definition
     * @param document       Parent GraphQL document
     * @return Freemarker data model of the GraphQL type
     */
83 84 85 86
    private static Set<ParameterDefinition> getFields(MappingConfig mappingConfig,
                                                      ExtendedObjectTypeDefinition typeDefinition,
                                                      ExtendedDocument document) {
        // this includes parameters from base definition and extensions
87 88
        List<ParameterDefinition> typeParameters = FieldDefinitionToParameterMapper.mapFields(mappingConfig,
                typeDefinition.getFieldDefinitions(), typeDefinition.getName());
89
        List<ParameterDefinition> typeParametersFromInterfaces = getInterfacesOfType(typeDefinition, document)
90 91 92 93 94
                .stream()
                .map(i -> FieldDefinitionToParameterMapper.mapFields(mappingConfig, i.getFieldDefinitions(), i.getName()))
                .flatMap(Collection::stream)
                .collect(Collectors.toList());

95
        Set<ParameterDefinition> allParameters = new LinkedHashSet<>();
96 97
        allParameters.addAll(typeParameters);
        allParameters.addAll(typeParametersFromInterfaces);
98 99 100 101 102 103 104 105 106 107 108 109
        return allParameters;
    }

    /**
     * Get merged attributes from the type and attributes from the interface.
     *
     * @param mappingConfig  Global mapping configuration
     * @param typeDefinition GraphQL type definition
     * @param document       Parent GraphQL document
     * @param typeNames      Names of all GraphQL types
     * @return Freemarker data model of the GraphQL type
     */
110 111 112 113 114 115
    private static Set<ProjectionParameterDefinition> getProjectionFields(MappingConfig mappingConfig,
                                                                          ExtendedObjectTypeDefinition typeDefinition,
                                                                          ExtendedDocument document,
                                                                          Set<String> typeNames) {
        // this includes parameters from base definition and extensions
        List<ProjectionParameterDefinition> typeParameters = FieldDefinitionToParameterMapper.mapProjectionFields(
116
                mappingConfig, typeDefinition.getFieldDefinitions(), typeNames);
117
        List<ProjectionParameterDefinition> typeParametersFromInterfaces = getInterfacesOfType(typeDefinition, document)
118
                .stream()
119
                .map(i -> FieldDefinitionToParameterMapper.mapProjectionFields(mappingConfig, i.getFieldDefinitions(), typeNames))
120 121 122
                .flatMap(Collection::stream)
                .collect(Collectors.toList());

123
        Set<ProjectionParameterDefinition> allParameters = new LinkedHashSet<>();
124 125
        allParameters.addAll(typeParameters);
        allParameters.addAll(typeParametersFromInterfaces);
126 127 128
        return allParameters;
    }

129 130 131
    /**
     * Scan document and return all interfaces that given type implements.
     *
132 133
     * @param definition GraphQL type definition
     * @param document   GraphQL document
134 135
     * @return all interfaces that given type implements.
     */
136 137
    private static List<ExtendedInterfaceTypeDefinition> getInterfacesOfType(ExtendedObjectTypeDefinition definition,
                                                                             ExtendedDocument document) {
138 139 140
        if (definition.getImplements().isEmpty()) {
            return Collections.emptyList();
        }
141 142 143 144 145
        Set<String> typeImplements = definition.getImplements()
                .stream()
                .filter(type -> TypeName.class.isAssignableFrom(type.getClass()))
                .map(TypeName.class::cast)
                .map(TypeName::getName)
146
                .collect(Collectors.toSet());
147 148
        return document.getInterfaceDefinitions()
                .stream()
149 150 151 152
                .filter(def -> typeImplements.contains(def.getName()))
                .collect(Collectors.toList());
    }

153 154 155 156 157 158 159 160 161 162 163
    private static Set<String> getInterfaces(MappingConfig mappingConfig,
                                             ExtendedObjectTypeDefinition definition,
                                             ExtendedDocument document) {
        List<String> unionsNames = document.getUnionDefinitions()
                .stream()
                .filter(union -> union.isDefinitionPartOfUnion(definition))
                .map(ExtendedUnionTypeDefinition::getName)
                .map(unionName -> MapperUtils.getClassNameWithPrefixAndSuffix(mappingConfig, unionName))
                .collect(Collectors.toList());
        Set<String> interfaceNames = definition.getImplements()
                .stream()
164
                .map(anImplement -> GraphqlTypeToJavaTypeMapper.getJavaType(mappingConfig, anImplement))
165 166 167 168 169
                .collect(Collectors.toSet());

        Set<String> allInterfaces = new LinkedHashSet<>();
        allInterfaces.addAll(unionsNames);
        allInterfaces.addAll(interfaceNames);
170 171 172
        return allInterfaces;
    }

173
}