【问题标题】:Best way to define a Map Object in GraphQL Schema?在 GraphQL Schema 中定义地图对象的最佳方式?
【发布时间】:2021-08-22 16:30:26
【问题描述】:

我尝试用对象数组映射一个键字符串。

我可以创建一个简单的对象,但我想在这些数组中轻松添加一个对象。地图对象非常适合执行此操作。

问题:我不知道如何为 GraphQL 定义类型映射 :'(

@ObjectType()
export class Inventaire
  @Field()
  _id: string;

 @Field()
  stocks: Map<string, Article[]>;
}

【问题讨论】:

标签: node.js typescript graphql nestjs


【解决方案1】:

GraphQL 本身不支持 Map 类型。您可以为 Map 创建自己的标量或使用在 repo https://github.com/graphql-java/graphql-java-extended-scalars 中定义的现有 ObjectScalar

import graphql.Assert;
import graphql.language.ArrayValue;
import graphql.language.BooleanValue;
import graphql.language.EnumValue;
import graphql.language.FloatValue;
import graphql.language.IntValue;
import graphql.language.NullValue;
import graphql.language.ObjectValue;
import graphql.language.StringValue;
import graphql.language.Value;
import graphql.language.VariableReference;
import graphql.language.ObjectField;
import graphql.scalars.util.Kit;
import graphql.schema.Coercing;
import graphql.schema.CoercingParseLiteralException;
import graphql.schema.CoercingParseValueException;
import graphql.schema.CoercingSerializeException;
import graphql.schema.GraphQLScalarType;
import org.springframework.stereotype.Component;

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

@Component
public class ObjectScalar extends GraphQLScalarType {
    public ObjectScalar() {
        this("Object", "An object scalar");
    }

    ObjectScalar(String name, String description) {
        super(name, description, new Coercing<Object, Object>() {
            public Object serialize(Object input) throws CoercingSerializeException {
                return input;
            }

            public Object parseValue(Object input) throws CoercingParseValueException {
                return input;
            }

            public Object parseLiteral(Object input) throws CoercingParseLiteralException {
                return this.parseLiteral(input, Collections.emptyMap());
            }

            public Object parseLiteral(Object input, Map<String, Object> variables)
                    throws CoercingParseLiteralException {
                if (!(input instanceof Value)) {
                    throw new CoercingParseLiteralException("Expected AST type 'StringValue' but" +
                            " was '" + Kit.typeName(input) + "'.");
                } else if (input instanceof NullValue) {
                    return null;
                } else if (input instanceof FloatValue) {
                    return ((FloatValue)input).getValue();
                } else if (input instanceof StringValue) {
                    return ((StringValue)input).getValue();
                } else if (input instanceof IntValue) {
                    return ((IntValue)input).getValue();
                } else if (input instanceof BooleanValue) {
                    return ((BooleanValue)input).isValue();
                } else if (input instanceof EnumValue) {
                    return ((EnumValue)input).getName();
                } else if (input instanceof VariableReference) {
                    String varName = ((VariableReference)input).getName();
                    return variables.get(varName);
                } else {
                    List values;
                    if (input instanceof ArrayValue) {
                        values = ((ArrayValue)input).getValues();
                        return values.stream().map((v) -> {
                            return this.parseLiteral(v, variables);
                        }).collect(Collectors.toList());
                    } else if (input instanceof ObjectValue) {
                        values = ((ObjectValue)input).getObjectFields();
                        Map<String, Object> parsedValues = new LinkedHashMap();
                        values.forEach((fld) -> {
                            Object parsedValue = this.parseLiteral(((ObjectField)fld).getValue(),
                                    variables);
                            parsedValues.put(((ObjectField)fld).getName(), parsedValue);
                        });
                        return parsedValues;
                    } else {
                        return Assert.assertShouldNeverHappen("We have covered all Value types",
                                new Object[0]);
                    }
                }
            }
        });
    }
}

scalar Object

type Result {
 value : Object
}

【讨论】:

    【解决方案2】:

    你可以使用这个包https://www.npmjs.com/package/graphql-type-json

    例子:

    import { makeExecutableSchema } from 'graphql-tools';
    import GraphQLJSON, { GraphQLJSONObject } from 'graphql-type-json';
     
    const typeDefs = `
    scalar JSON
    scalar JSONObject
     
    type MyType {
      myValue: JSON
      myObject: JSONObject
    }
     
    # ...
    `;
     
    const resolvers = {
      JSON: GraphQLJSON,
      JSONObject: GraphQLJSONObject,
    };
     
    export default makeExecutableSchema({ typeDefs, resolvers });
    

    【讨论】:

    • 这个包被包含在graphql-scalars 的许可中,它包含了一堆其他有用的标量类型。
    【解决方案3】:

    GraphQL 是一种强类型语言,不提供任何开箱即用的 map 类型。 JSON blob 的键值对没有强大的架构,所以你不能有这样的东西:

    {
        key1: val1,
        key2: val2,
        key3: val3,
        ...
    }
    

    但是,您可以将 GraphQL Schema 定义为具有键值元组类型,然后定义您的属性以返回这些元组的数组。

    type articleMapTuple {
         key: String
         value: Article
    }
    
    type Inventaire {
         stocks: [articleMapTuple]
    }
    

    那么您的返回类型将如下所示:

        data [
        {
            key: foo1,
            value: { some Article Object}
        },
        {
            key: foo2,
            value: { some Article Object}
        },
        {
            key: foo3,
            value: { some Article Object}
        },
    ]
    

    【讨论】:

    • "GraphQL 是一种强类型语言,不提供任何开箱即用的地图类型。"就像没有提供地图类型的强类型语言一样?前半句和后半句之间没有联系。
    • 也许我应该澄清一下 - GraphQL 是一种强类型语言 不提供任何开箱即用的地图类型。因此,您需要自己定义。
    • @gacharya 缺少 Map 类型仍然与强类型无关。映射对于表示本质上是映射的数据很有用。如果用于表示对象的属性,这是非常糟糕的,并且违背了打字的目的,但这不是地图的主要目标。
    • 每个强类型语言都支持映射结构。
    • map的关键是每个key都是同一个类型,每个value都是同一个类型,所以Map也是一个强类型结构。
    猜你喜欢
    • 2013-09-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-06
    • 2013-01-30
    • 2012-05-11
    • 1970-01-01
    相关资源
    最近更新 更多