sangria graphql 查询返回 1 个元素列表
Posted
技术标签:
【中文标题】sangria graphql 查询返回 1 个元素列表【英文标题】:sangria graphql query returning 1 element list 【发布时间】:2016-12-18 19:49:37 【问题描述】:我使用 sangria 作为 GraphQL 服务器。架构的相关部分是:
val Account =
ObjectType(
"Account",
"An account with a municipal unit",
fields[Unit, Account](
Field("id", StringType, Some("The account id"), resolve = _.value.id),
Field("mu", OptionType(MunicipalUnit), Some("The municipal unit this account is with"), resolve = ctx => ctx.ctx.asInstanceOf[ObjectResolver].resolve[MunicipalUnit](ctx.value.mu)),
Field("eu", OptionType(EconomicUnit), Some("The economic unit this account belongs to"), resolve = ctx => ctx.ctx.asInstanceOf[ObjectResolver].resolve[EconomicUnit](ctx.value.eu)),
Field("location", OptionType(Location), Some("The physical location associated with this account"), resolve = ctx => ctx.ctx.asInstanceOf[ObjectResolver].resolve[Location](ctx.value.location)),
Field("amountDue", BigDecimalType, Some("The amount currently due"), resolve = _.value.amountDue)
))
val Citizen =
ObjectType(
"Citizen",
"A Citizen",
interfaces[Unit, Citizen](EconomicUnit),
fields[Unit, Citizen](
Field("id", StringType, Some("The ID of the citizen"), resolve = _.value.id),
Field("name", StringType, Some("The name of the citizen"), resolve = _.value.id),
Field("delegates", OptionType(ListType(OptionType(EconomicUnit))), Some("The delegates of the citizen"), resolve = ctx => DeferDelegates(ctx.value.delegates)),
Field("locations", OptionType(ListType(OptionType(Location))), Some("The locations of the citizen"), resolve = ctx => DeferLocations(ctx.value.locations)),
Field("accounts", OptionType(ListType(OptionType(Account))), Some("The accounts of the citizen"), resolve = ctx => DeferAccounts(ctx.value.accounts))
)
)
延期代码是
def resolveByType[T](ids: List[Any])(implicit m: Manifest[T]) = ids map (id => resolver.resolve[T](id))
override def resolve(deferred: Vector[Deferred[Any]], ctx: Any) = deferred flatMap
case DeferAccounts(ids) => resolveByType[Account](ids)
case DeferLocations(ids) => resolveByType[Location](ids)
case DeferDelegates(ids) => resolveByType[EconomicUnit](ids)
case DeferMUs(ids) => resolveByType[MunicipalUnit](ids)
case _ =>
List(Future.fromTry(Try(List[Any]())))
一切都适用于单个对象,但是当我尝试请求一个对象及其子对象时,我只会得到一个孩子回来
查询:
citizen(id: "12345")
name
accounts
id
amountDue
回复:
"data":
"citizen":
"name": "12345",
"accounts": [
"id": "12345",
"amountDue": 12.34
]
所以 - 这是正确的,我可以在后端看到列表的所有元素都在加载,但它们似乎没有被返回。
【问题讨论】:
【参考方案1】:问题是您正在使用flatMap
并将不相关列表的所有元素合并到一个结果列表中。
我认为这些小改动会达到理想的效果:
def resolveByType[T](ids: List[Any])(implicit m: Manifest[T]): Future[Seq[T]] =
Future.sequence(ids map (id => resolver.resolve[T](id)))
override def resolve(deferred: Vector[Deferred[Any]], ctx: Any) = deferred map
case DeferAccounts(ids) => resolveByType[Account](ids)
case DeferLocations(ids) => resolveByType[Location](ids)
case DeferDelegates(ids) => resolveByType[EconomicUnit](ids)
case DeferMUs(ids) => resolveByType[MunicipalUnit](ids)
case _ =>
List(Future.fromTry(Try(List[Any]())))
重要的是要确保对于deferred
向量中的每个Deferred
值,结果列表中只有一个Future
元素(并且它应该在列表中的相同位置)。
它是针对性能进行了优化的低级 API,因此resolve
方法的签名中没有太多类型安全性。在这种情况下,我只是 created an issue 来改进错误报告。
【讨论】:
以上是关于sangria graphql 查询返回 1 个元素列表的主要内容,如果未能解决你的问题,请参考以下文章
了解 GraphQL / Sangria-Graphql 中服务器端的特定字段
如何知道 Sangria GraphQL 中对象解析器中的请求字段