接力突变:改变分页关联

时间:2017-02-22 19:07:44

标签: graphql relayjs

在很多情况下,我们有突变,其中存在我们需要变异的一对多或多对多关联,以及将关联作为分页列表暴露给查询的位置。

有一些关键要求:

  • 客户端必须能够删除,添加和更新关联元素
  • 在某些情况下,关联的顺序很重要,在这种情况下,客户必须能够重新排序元素

不太重要:

  • 客户应该能够在创建父级时指定关联(例如,在创建产品的同时创建一组有序的变体)
  • 客户端应该能够使用某种形式的事务原子性一次删除,添加,更新和重新排序关联的元素
  • 客户端不应该对整个当前关联进行分页以添加或删除单个元素

这个问题有很多可能的解决方案:

选项1 - 单输入字段,无附加突变

输入类型有一个数组输入字段,表示关联的总真实性(添加新元素,更新现有元素,删除缺少的元素,并在必要时保留顺序)。

缺点:删除非常隐含。客户端必须通过关联的整个当前状态进行分页。不精细。

选项2 - 具有位置的单个输入字段,删除突变

输入类型有一个数组输入字段,用于更新现有元素并添加新元素(忽略缺少的元素)。可以在元素上指定位置或索引值以对其重新排序。单独的变异用于删除元素。

缺点:删除在变异中自行关闭是不一致的,而所有其他操作都在父变体上。不太精细。

选项3 - 单输入字段,删除和重新排序变异

输入类型有一个数组输入字段,用于更新现有元素并添加新元素(忽略缺少的元素)。单独的突变用于删除和重新排序元素。

缺点:客户端无法将新元素添加到关联中的特定位置,必须添加它们,然后单独重新排序。不太精细。

选项4 - 单输入字段,添加/删除/重新排序突变

与选项3类似,但输入字段仅用于更新;单独的变异用于添加新元素。

缺点:客户必须进行多次突变才能执行复杂的更新。客户端无法使用初始关联创建父级。

选项5 - 完全独立的突变

父输入类型没有相关字段,所有内容都是通过四个单独的突变完成的,用于添加/删除/更新/重新排序。

优点:非常明确和精细,将不同的数据模型对象分开。 缺点:客户必须进行多次突变才能执行复杂的更新。客户端无法使用初始关联创建父级。

选项6 - 具有位置的两个输入字段

输入类型有两个数组字段:一个用于更新,添加和重新排序元素(参见选项2),另一个用于删除。

缺点:感觉我们正在污染父母突变;不精细。

选项7 - 两个输入字段,重新排序变异

与选项6类似,除了使用单独的重新排序变异而不是位置参数。

缺点:重新订购自行关闭不一致。另见选项6的缺点。

所有这些选项似乎都有缺点。选项5似乎是最明确的,但要求用户同时使用多个突变,其中操作不再是原子的。

Facebook处理这些类型突变的方式是什么?你的方式是什么?谢谢!

1 个答案:

答案 0 :(得分:5)

所有这些方法之间肯定存在权衡,所以选择一种方法实际上取决于我想要构建的方法。

Facebook模式中最常见的情况有两个很好的约束:

  • 没有重新排序
  • 无批量操作

Facebook上的评论是这里的典型例子。对于这样的情况,我们已经使用了Option 5并取得了巨大的成功,我可以自信地推荐它。对于评论,我们只有三个突变; commentCreatecommentEditcommentDelete

对于这样的情况,我们最终得到了常见的模式:

  • 对于createedit(或update)突变,突变解析的对象通常包含已修改的边缘(我使用的地方)我们在Pagination Best Practice doc中使用边缘的意义相同的边缘。从那个边缘,您可以轻松获取修改后的对象...但您也可以获得可能需要的任何边缘数据。
  • delete突变通常只返回已删除对象的ID;如果客户端在输入中提供了ID,那么这对客户端来说是一种纯粹的便利,但如果删除输入获取了一些其他信息并且服务器将其转换为ID,则可能非常有用,在这种情况下,返回已删除的ID允许客户端知道删除了哪个对象。
  

选项5 [...]客户端无法创建具有初始关联的父级。

我不完全确定我会这样做;我的评论示例在这里没有一个很好的例子(因为它不存在于产品中),但假设我想同时发表评论回复该评论,我可以想象做类似的事情:

commentCreate(input: {text:"Hello World", replies:[{text:"Reply 1"}, {text:"Reply 2"}]})

我正在重复使用commentCreate作为replies接受的复数输入类型的输入类型。

对于需要重新排序或批量操作的情况,这听起来像是你正在看的主要情况,我没有那么好的答案,而且这肯定是一个棘手的案例,如你所说。我不认为我已经看到足够的例子来自信地推荐一个选项而不是另一个选项,我认为哪个选项最好可能最终取决于具体的用例。但是,要考虑的另一个选择是使用单个突变,其中输入是操作列表。因此,如果我们有一个“最喜欢的照片”列表,我们想进行批量更新,我们可以做类似的事情:

favoritePhotosUpdate({operations: {operation:ADD, addedId:1234}, {operation:REMOVE, addedId:5678}, {operation:UPDATE, oldId:4321, newId:8765}, {operation:SWAP, oldId:32, newId:76}

不确定这实际上是否比上面的选项更好,但它是我们过去讨论过的另一种选择(虽然我不确定我们是否已将其付诸实践),所以至少值得添加到清单。

希望这有帮助!