2

我想知道具有 id 属性的对象类型是否必须在给定相同 id 的情况下具有相同的内容。目前同一个id可以有不同的内容。

以下查询:

const query = gql`
  query products(
    $priceSelector: PriceSelectorInput!
  ) {
    productProjectionSearch(
      priceSelector: $priceSelector
    ) {
      total
      results {
        masterVariant {
          # If you do the following it will work
          # anythingButId: id
          id
          scopedPrice {
            country
          }
        }
      }
    }
  }
`;

如果PriceSelectorInput是,{currency: "USD", country: "US"}那么结果是:

{
  "productProjectionSearch": {
    "total": 2702,
    "results": [
      {
        "name": "Sweater Pinko white",
        "masterVariant": {
          "id": 1,
          "scopedPrice": {
            "country": "US",
            "__typename": "ScopedPrice"
          },
          "__typename": "ProductSearchVariant"
        },
        "__typename": "ProductProjection"
      }
    ],
    "__typename": "ProductProjectionSearchResult"
  }
}

如果PriceSelectorInput是,{currency: "EUR", country: "DE"}那么结果是:

{
  "productProjectionSearch": {
    "total": 2702,
    "results": [
      {
        "name": "Sweater Pinko white",
        "masterVariant": {
          "id": 1,
          "scopedPrice": {
            "country": "DE",
            "__typename": "ScopedPrice"
          },
          "__typename": "ProductSearchVariant"
        },
        "__typename": "ProductProjection"
      }
    ],
    "__typename": "ProductProjectionSearchResult"
  }
}

我的问题是,ProductSearchVariant 类型的 masterVariant 在这两种情况下的 id 都是 1,但 scopedPrice 的值不同。这会破坏 apollo 缓存 defaultDataIdFromObject 函数,如本 repo中所示。我的问题是;这是 apollo 中的错误还是违反了 ProductSearchVariant 类型定义中的 graphql 标准?

4

1 回答 1

1

TLDR

不,它不会违反规范。该规范在缓存方面绝对没有强制要求。

可能感兴趣的人的文学作品

从概述部分的末尾

由于这些原则,[...] 无需阅读大量文档,也无需或很少接受正式培训即可迅速提高工作效率。为了实现这种体验,必须有那些构建这些服务器和工具的人。

以下正式规范可作为这些构建者的参考。它描述了语言及其语法、类型系统和用于查询它的自省系统,以及执行和验证引擎以及为其提供动力的算法。本规范的目标是为尚未构建的 GraphQL 工具、客户端库和服务器实现的生态系统(跨越组织和平台)提供基础和框架。我们期待与社区合作以实现这一目标。

正如我们刚刚看到的那样,该规范没有提及缓存或实现细节,这些都留给了社区。本文的其余部分继续详细说明应如何处理类型系统、语言、请求和响应。

另请注意,该文档没有提及正在使用哪个底层协议(尽管通常是 HTTP)。您可以通过 USB 设备或红外线有效地运行 GraphQL 通信。

我们在我们的技术会议上举办了一场有趣的演讲,您可能会觉得有趣。这是一个链接:

GraphQL Anywhere - 我们的 GraphQL 网格和模式拼接之旅 • Uri Goldshtein • GOTO 2021

如果我们自己“Ctrl+F”来查找“Cache”或“ID”之类的东西,我们可以找到以下部分,我认为这将有助于在这里得出结论:

ID

ID 标量类型表示唯一标识符,通常用于重新获取对象或作为缓存的键。ID类型的序列化方式与String相同;但是,它并不适合人类阅读。虽然它通常是数字,但它应该始终序列化为字符串。

结果强制

GraphQL 与 ID 格式无关,并序列化为字符串以确保 ID 可以表示的许多格式的一致性,从小的自动增量数字到大的 128 位随机数,再到 base64 编码值或类似格式的字符串值图形用户界面。

GraphQL 服务器应该根据他们期望的 ID 格式进行适当的强制。当强制不可行时,它们必须引发字段错误。

输入强制

当期望作为输入类型时,任何字符串(例如“4”)或整数(例如 4)输入值都应该被强制转换为 ID,以适合给定 GraphQL 服务器期望的 ID 格式。任何其他输入值,包括浮点输入值(例如 4.0),都必须引发查询错误,指示类型不正确。

它提到这样的字段通常用作缓存键(这是 GraphQL 实现的 Apollo 集合的默认缓存键),但它没有告诉我们任何有关“返回数据的一致性”的信息。

这是 GraphQL 的完整规范文档的链接

警告!自以为是 - 我对 ID 的看法

当然我要说的和 GraphQL 规范无关

有时一条ID信息不足以决定是否缓存某些东西。让我们考虑一下用户搜索:

如果我有一个FavouriteSearch实体在我的数据库中有一个 ID 和一个名为textSearch. 我通常希望results: [Result!]!在我的 GraphQL 规范中公开一个属性,引用此特定文本搜索产生的所有结果。

这些结果很可能与我进行搜索的那一刻或五分钟后我重新访问我最喜欢的搜索时有所不同。(考虑在 TikTok 等平台上进行文本搜索,用户可以在该平台上大量上传内容)。

因此,基于实体的这个定义,FavouriteSearch缓存行为是相当出乎意料的。

如果我们从不同的角度考虑问题,我们可能想要一个SearchResults实体,它可以有一个 ID 和一个时间戳,并有一个连接表,我们在其中引用所有与初始文本搜索相关的帖子,在这种情况下,它会为results我们的 GraphQL 模式上的属性返回一致的内容是有意义的。

问题是它取决于我们如何定义我们的实体,它最终与 GraphQL 规范无关

解决您的问题

您可以指定 Apollo 如何生成密钥以供以后用作缓存中的密钥,正如 @Matt 已经在注释中指出的那样。您可能希望利用它并为那些具有__type等于您的masterVariant属性类型的实体覆盖该行为,并为所有实体(或类似的)返回 NO_KEY,以避免从您的 ApolloClient 缓存这些特定字段。

我希望这可以帮到你!

于 2022-02-22T21:19:33.827 回答