2016-08-11 59 views
0

我使用sangria作为GraphQL服务器。该方案的相关部分是:sangria graphql查询返回1个元素列表

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

所以 - 这是正确的,我可以看到在后端列表中的所有元素都被加载,但他们似乎没有被返回。

回答

2

问题是,您正在使用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来改善这种情况下的错误报告。