Hi Peter,
Great that you are making progress! You are right deferred resolver can be very useful here and it will greatly improve the `Vertex` loading from DB (generally, it will ensure that for every GraphQL query nesting level only one single request is executed against the DB). You can also use Fetch API for this. I will demonstrate it in an example below.
I would suggest to continue with my previous example and define 2 resolve functions which I already used but haven't defined yet.
To make everything a bit more explicit and free of hidden assumptions, I first will define the basic setup that I will use for this example. Let me know whether it is very different from the way DSE models the graph and metadata about it:
// basic setup: the vertex itself
// just to make example a bit more clear, I created these simple types for IDs
case class VertexId(id: String)
case class VertexTypeId(id: String)
case class Vertex(
id: VertexId,
vertexTypeId: VertexTypeId,
properties: Map[String, Any],
outgoingEdgesToOtherVertices: Map[VertexTypeId, VertexId])
// basic setup: the meta-information about it (the connection between these is through `vertexTypeId`)
case class VertexMetaInfo(id: VertexTypeId, propertiesMetaInfo: List[PropertyMetaInfo])
object PropertyType extends Enumeration {
val CassandraInteger, CassandraString = Value
}
case class PropertyMetaInfo(name: String, propertyType: PropertyType.Value)
How that we have a basic setup, let's define the resolve functions. I also would like to point out the assumption that cassandra loads all data as a `Vertex`. this would also mean, that all of these `ObjectType`s that have defined for your schema are of type `ObjectType[DseContext, Vertex]`.
// The resolve function that you will use for normal properties
def resolvePropWithDBObject(propertyMetaInfo: PropertyMetaInfo, c: Context[DseContext, Vertex]) = {
val vertexProperties = c.value.properties
val propertyValue = vertexProperties(propertyMetaInfo.name)
// here you may or may not need to do this kind of transformations
// in the most simple scenario, you can just return `propertyValue`, I guess
propertyMetaInfo.propertyType match {
case PropertyType.CassandraString ⇒
transformCassandraStringToScalaString(propertyValue)
case PropertyType.CassandraInteger ⇒
transformCassandraIntegerToScalaInt(propertyValue)
}
}
// The resolve function that you will use edges between vertices
val vertexFetcher = Fetcher.caching[DseContext, Vertex, VertexId](
(ctx: DseContext, vertexIds: Seq[VertexId]) ⇒ {
val loadedVertices: Future[Vertex] = ctx.loadVerticesByIds(vertexIds)
loadedVertices
})
def resolveRelationWithDBObject(otherVertex: VertexMetaInfo, c: Context[DseContext, Vertex]) = {
val otherVertexId = c.value.outgoingEdgesToOtherVertices.get(otherVertex.id)
vertexFetcher.defer(otherVertexId)
}
// at some point when you are about to execute the query,
// you also need to provide a deferred resolver
Executor.execute(schema, query,
deferredResolver = DeferredResolver.fetchers(vertexFetcher))
I made code and all types very explicit just to make it clear which types are involved. In the actual application you probably can relay on type inference more :)
Let me know whether this example is helpful.
Cheers,
Oleg