ValueMapper.java 6.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
package com.kobylynskyi.graphql.codegen.mapper;

import com.kobylynskyi.graphql.codegen.model.MappingContext;
import graphql.language.ArrayValue;
import graphql.language.BooleanValue;
import graphql.language.EnumValue;
import graphql.language.FloatValue;
import graphql.language.IntValue;
import graphql.language.ListType;
import graphql.language.NonNullType;
import graphql.language.NullValue;
import graphql.language.ObjectValue;
import graphql.language.StringValue;
import graphql.language.Type;
import graphql.language.TypeName;
import graphql.language.Value;

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

22 23 24
/**
 * A class for mapping GraphQL value to a java value
 */
25 26 27 28
public class ValueMapper {

    private static final String NULL_STRING = "null";

29 30 31 32 33 34 35 36 37 38 39 40 41
    private final ValueFormatter valueFormatter;
    private final DataModelMapper dataModelMapper;

    public ValueMapper(ValueFormatter valueFormatter,
                       DataModelMapper dataModelMapper) {
        this.valueFormatter = valueFormatter;
        this.dataModelMapper = dataModelMapper;
    }

    private static String mapBoolean(BooleanValue value) {
        return value.isValue() ? "true" : "false";
    }

42 43 44 45 46 47 48 49 50
    /**
     * Map value of GraphQL Int type to a value that will be present in a generated code.
     * TODO: should also be abstracted because different languages have different default values
     *
     * @param mappingContext Global mapping context
     * @param value          GraphQL Value
     * @param graphQLType    GraphQL Type
     * @return formatted value
     */
51
    private static String mapInt(MappingContext mappingContext, IntValue value, Type<?> graphQLType) {
52
        // default java basic type is `int`. so, default value like 123 that must wrap or append suffix `L` when it be
53
        // defined as `int` in graphql schema.
54 55
        // `int` cannot assign to `Long`, also `double` cannot assign to `Float`, but graphql Float default mapping is
        //  Double in java, so, not modify `mapFloat`.
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
        if (graphQLType instanceof TypeName) {
            String customType = mappingContext.getCustomTypesMapping().get("Long");
            String typeName = ((TypeName) graphQLType).getName();
            if ("Long".equals(typeName) && ("java.lang.Long".equals(customType) || "Long".equals(customType))) {
                return String.valueOf(value.getValue()).concat("L");
            }
        }

        if (graphQLType instanceof NonNullType) {
            // unwrapping NonNullType
            return mapInt(mappingContext, value, ((NonNullType) graphQLType).getType());
        }
        return String.valueOf(value.getValue());
    }

    private static String mapFloat(FloatValue value) {
        return String.valueOf(value.getValue());
    }

    private static String mapString(StringValue value) {
        return "\"" + value.getValue() + "\"";
77 78
    }

79
    public String map(MappingContext mappingContext, Value<?> value, Type<?> graphQLType) {
80 81 82
        return map(mappingContext, value, graphQLType, null);
    }

83 84 85 86 87 88 89 90 91
    /**
     * Map GraphQL value of a given type according to a formatter
     *
     * @param mappingContext Global mapping context
     * @param value          GraphQL Value
     * @param graphQLType    GraphQL Type
     * @param formatter      value formatter
     * @return formatted value
     */
92 93
    public String map(MappingContext mappingContext, Value<?> value, Type<?> graphQLType,
                      String formatter) {
94 95 96 97 98 99 100
        if (value instanceof NullValue) {
            return ValueFormatter.format(NULL_STRING, formatter);
        }
        if (value instanceof BooleanValue) {
            return ValueFormatter.format(mapBoolean((BooleanValue) value), formatter);
        }
        if (value instanceof IntValue) {
101
            return ValueFormatter.format(mapInt(mappingContext, (IntValue) value, graphQLType), formatter);
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
        }
        if (value instanceof FloatValue) {
            return ValueFormatter.format(mapFloat((FloatValue) value), formatter);
        }
        if (value instanceof StringValue) {
            return ValueFormatter.format(mapString((StringValue) value), formatter);
        }
        if (value instanceof EnumValue) {
            return ValueFormatter.format(mapEnum(mappingContext, (EnumValue) value, graphQLType), formatter);
        }
        if (value instanceof ObjectValue) {
            // default object values are not supported yet, same behaviour as before for those
            return null;
        }
        if (value instanceof ArrayValue) {
            return mapArray(mappingContext, (ArrayValue) value, graphQLType, formatter);
        }
        // no value, or not a known type
        return null;
    }

123
    private String mapEnum(MappingContext mappingContext, EnumValue value, Type<?> graphQLType) {
124 125
        if (graphQLType instanceof TypeName) {
            String typeName = ((TypeName) graphQLType).getName();
126 127
            typeName = DataModelMapper.getModelClassNameWithPrefixAndSuffix(mappingContext, typeName);
            return typeName + "." + dataModelMapper.capitalizeIfRestricted(mappingContext, value.getName());
128 129 130 131 132 133 134 135
        }
        if (graphQLType instanceof NonNullType) {
            return mapEnum(mappingContext, value, ((NonNullType) graphQLType).getType());
        }
        throw new IllegalArgumentException("Unexpected Enum value for list type");
    }

    @SuppressWarnings({"rawtypes", "java:S3740"})
136 137
    private String mapArray(MappingContext mappingContext, ArrayValue value, Type<?> graphQLType,
                            String formatter) {
138 139 140
        if (graphQLType == null || graphQLType instanceof ListType) {
            List<Value> values = value.getValues();
            if (values.isEmpty()) {
141
                return valueFormatter.formatList(Collections.emptyList(), formatter);
142 143 144 145 146 147
            }
            Type<?> elementType = null;
            if (graphQLType != null) {
                elementType = ((ListType) graphQLType).getType();
            }
            Type<?> listElementType = elementType;
148
            return valueFormatter.formatList(values.stream()
149 150 151 152 153 154 155 156 157 158
                    .map(v -> map(mappingContext, v, listElementType, formatter))
                    .collect(Collectors.toList()), formatter);
        }
        if (graphQLType instanceof NonNullType) {
            return mapArray(mappingContext, value, ((NonNullType) graphQLType).getType(), formatter);
        }
        throw new IllegalArgumentException("Unexpected array default value for non-list type");
    }

}