scalagraphqlsangria

Fetching relations with different types


I have following structures:

ObjectX:

(id: UUID, name: String, title: String)

ObjectY (mapping table):

(objectZId: UUID, objectXId: UUID) 

And i'm trying to fetch ObjectX by objectZId with following code:

val objectXByZ = RelationIds[ObjectY, UUID]("byObjectZId", c => Seq(c.objectZId))
implicit val objectXId = HasId[ObjectX, UUID](_.id)

val objectX = Fetcher.rel[GraphQLContext, ObjectX, ObjectY, UUID](
    (ctx: GraphQLContext, objectXIds: Seq[UUID]) =>
      ctx.app.service.Service.getObjectXByIds(objectXIds)(ctx.trace),
    (ctx: GraphQLContext, rels: RelationIds[XobjectX]) =>
      ctx.app.service.Service.getObjectYByX(rels(objectXByZ))(ctx.trace)
  )

and then using it here:

...

implicit val textX: ObjectType[GraphQLContext, ObjectX] = deriveObjectType(AddFields(
  Field(
    name = "objectX",
    fieldType = ListType(objectXType),
    resolve = c => TestFetchers.objectX.deferRelSeq(
      TestFetchers.objectXByZ, c.value.id
    )
)

...

But getting errors:

[error]  found   : scala.concurrent.Future[Seq[com.fevo.coco.nut.models.ObjectX]]
[error]  required: scala.concurrent.Future[Seq[com.fevo.coco.nut.models.ObjectY]]
[error] Error occurred in an application involving default arguments.
[error]       ctx.app.service.Service.getObjectYByX(rels(objectXByZ))(ctx.trace)
[error]                                                    ^
[info] scala.concurrent.Future[Seq[com.fevo.coco.nut.models.ObjectX]] <: scala.concurrent.Future[Seq[com.fevo.coco.nut.models.ObjectY]]?
[info] false

According to this answer I need to use same types in fetcher, but is there a way to use different types?


Another problem is when I use same type in fetcher:

val objectX = Fetcher.rel[GraphQLContext, ObjectX, ObjectX, UUID](
  (ctx: GraphQLContext, objectXIds: Seq[UUID]) =>
    ctx.app.service.Service.getObjectXByIds(objectXIds)(ctx.trace),
  (ctx: GraphQLContext, rels: RelationIds[XobjectX]) =>
    ctx.app.service.Service.getObjectYByX(rels(objectXByZ))(ctx.trace)
  )

i'm not getting any results (getObjectYByX executes, but getObjectXByIds does not).


Solution

  • Fetchers have support for intermediate data structures when you are loading relation data from the database. The type of this intermediate data structure is provided via RelRes type parameter.

    In your case, when you are loading ObjectX from the database based on the objectZId, you also need to tell fetcher how loaded ObjectX relates to one (or several) of the provided objectZIds (since you are loading multiple relations at once). This is where the intermediate data structure comes into play. In your case, it can be as simple as a tuple (ObjectY, ObjectX):

    val objectXByZ = Relation[ObjectX, (ObjectY, ObjectX), UUID]("byObjectZId", 
      intermediate ⇒ Seq(intermediate._1.objectZId),
      intermediate ⇒ intermediate._2)
    
    val objectX = Fetcher.rel[GraphQLContext, ObjectX, (ObjectY, ObjectX), UUID](
      (ctx, objectXIds) ⇒ ctx.app.service.Service.getObjectXByIds(objectXIds)(ctx.trace),
      // returns list of tuples: Future[Seq[(ObjectY, ObjectX)]]
      (ctx, rels) ⇒ ctx.app.service.Service.getObjectXRelationsByZIds(rels(objectXByZ))(ctx.trace))