在GraphQL模式中定义Map对象的最佳方法是什么?

26

我试图将一个键字符串与对象数组进行映射。

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

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

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

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

1
Related - Daniel Rearden
3个回答

33

GraphQL默认不提供任何类型的映射(map)。一个键值对的JSON Blob没有强烈的模式,所以你不能像这样做:

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

然而,您可以定义一个GraphQL模式,使其具有键值对类型,并将属性定义为返回这些元组数组。

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}
    },
]

61
GraphQL是一种强类型语言,但它没有内置任何类型的映射。这并不意味着没有强类型语言提供映射类型。第一半和第二半句子之间没有关联。 - Andrey
7
或许我应该澄清一下 - GraphQL 是一种强类型语言,但它不会默认提供任何类型的映射类型。因此,您需要自己定义。 - user3126362
3
@gacharya 缺少 Map 类型与强类型并没有任何关系。Map 用于表示本质上是映射的数据非常有用。如果用于表示对象的属性,则这样做相当糟糕,会破坏类型定义的目的,但这不是 Map 的主要目标。 - Joffrey
4
每种强类型编程语言都支持地图结构。 - Mark Aquino
5
地图最重要的一点是每个“键”都是相同的类型,每个“值”也是相同的类型,因此 Map 也是一种强类型结构。 - HubertNNN
我刚刚更新了答案并删除了不必要的“是强类型语言”的引用,这引起了更多的混乱。 - GMaiolo

4
你可以使用这个包 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中,该库包含了许多其他有用的标量类型。 - David Harkness

3

GraphQL本身不支持Map类型。你可以创建自己的标量(scalar)用于处理Map类型或使用已经定义在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
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接