我有一个关于架构/查询设计的问题。
让我们假设有一个Study
模型。
Study
可以有多个后继者,所以显然有parentId
字段。
case class Study(id: StudyId, name: String, parentId: Option[StudyId])
User
from context 可以访问研究,因此我们希望将所有可访问的研究作为树返回到 UI。所以查询字段可以是这样的
Field(name = "accessibleStudies",
fieldType = ListType(StudyNode.Type),
resolve = implicit ctx => inject[StudyQueries].accessibleStudies(ctx))
在该accessibleStudies
方法中,我们向 DB 请求数据并准备可以在 UI 上作为树查看的列表。
class StudyQueries {
def accessibleStudies(ctx: Ctx): Future[Seq[StudyNode]] = {
// 50 lines of data fetching and transformation
}
}
现在有趣的部分。
StudyNode
应该有额外的字段 - progress
,它可以计算为所有后继者进度的递归总和,所以我们每次都需要整个progress
可访问的研究列表来获取单个节点。如此简单的方法
case class StudyNode(entity: Study)
object StudyNode {
val Type = ObjectType[Ctx, StudyNode](
...
Field(name = "progress",
fieldType = ProgressType,
resolve = implicit ctx => inject[ProgressService].progressOfStudy(...))
)
}
将导致巨大的开销,因为我们需要一次又一次地为每个节点获取可访问的研究。不过好像里面计算进度比较方便StudyQueries.accessibleStudies
,所以我们会有类似prepare的东西Map[EntityId, Progress]
,StudyNode
现在定义可以这样修改
case class StudyNode(entity: Study,
progresses: Map[EntityId, Progress])
object StudyNode {
val Type = ObjectType[Ctx, StudyNode](
...
Field(name = "progress",
fieldType = ProgressType,
resolve = implicit ctx => progresses(ctx.value.entity.getId))
)
}
但这对我来说似乎不是一个干净的解决方案。此外,我必须手动检查ctx.astFields
以验证是否progress
正在调用该字段。现在我想知道是否有更好的方法来处理这种情况。