in s2core/src/main/scala/org/apache/s2graph/core/PostProcess.scala [196:283]
def toJson(orgQuery: Option[JsValue])(graph: S2GraphLike,
queryOption: QueryOption,
stepResult: StepResult): JsValue = {
// [[cursor, cursor], [cursor]]
lazy val cursors: Seq[Seq[String]] = stepResult.accumulatedCursors.map { stepCursors =>
stepCursors.map { cursor => new String(Base64.getEncoder.encode(cursor)) }
}
lazy val cursorJson: JsValue = Json.toJson(cursors)
// build nextQuery with (original query + cursors)
lazy val nextQuery: Option[JsValue] = {
if (cursors.exists { stepCursors => stepCursors.exists(_ != "") }) {
val cursorIter = cursors.iterator
orgQuery.map { query =>
buildJsonWith(query) { (key, js) =>
if (key == "step") {
val currentCursor = cursorIter.next
val res = js.as[Seq[JsObject]].toStream.zip(currentCursor).filterNot(_._2 == "").map { case (obj, cursor) =>
val label = (obj \ "label").as[String]
if (Label.findByName(label).get.schemaVersion == "v4") obj + ("cursor" -> JsString(cursor))
else {
val limit = (obj \ "limit").asOpt[Int].getOrElse(RequestParser.defaultLimit)
val offset = (obj \ "offset").asOpt[Int].getOrElse(0)
obj + ("offset" -> JsNumber(offset + limit))
}
}
JsArray(res)
} else js
}
}
} else Option(JsNull)
}
val limitOpt = queryOption.limitOpt
val selectColumns = queryOption.selectColumnsMap
val degrees =
if (queryOption.returnDegree) stepResult.degreeEdges.map(t => s2EdgeToJsValue(queryOption, t, true, JsNull))
else emptyDegrees
if (queryOption.groupBy.keys.isEmpty) {
// no group by specified on query.
val results = if (limitOpt.isDefined) stepResult.edgeWithScores.take(limitOpt.get) else stepResult.edgeWithScores
val ls = results.map { t =>
val parents = if (queryOption.returnTree) s2EdgeParent(graph, queryOption, t.edge.getParentEdges()) else JsNull
s2EdgeToJsValue(queryOption, t, false, parents)
}
withOptionalFields(queryOption, ls.size, degrees, ls, stepResult.failCount, cursorJson, nextQuery)
} else {
val grouped = if (limitOpt.isDefined) stepResult.grouped.take(limitOpt.get) else stepResult.grouped
val results =
for {
(groupByValues, (scoreSum, edges)) <- grouped
} yield {
val groupByKeyValues = queryOption.groupBy.keys.zip(groupByValues).map { case (k, valueOpt) =>
k -> valueOpt.flatMap(anyValToJsValue).getOrElse(JsNull)
}
val groupByValuesJson = Json.toJson(groupByKeyValues.toMap)
if (!queryOption.returnAgg) {
Json.obj(
"groupBy" -> groupByValuesJson,
"scoreSum" -> scoreSum,
"agg" -> Json.arr()
)
} else {
val agg = edges.map { t =>
val parents = if (queryOption.returnTree) s2EdgeParent(graph, queryOption, t.edge.getParentEdges()) else JsNull
s2EdgeToJsValue(queryOption, t, false, parents)
}
val aggJson = Json.toJson(agg)
Json.obj(
"groupBy" -> groupByValuesJson,
"scoreSum" -> scoreSum,
"agg" -> aggJson
)
}
}
withOptionalFields(queryOption, results.size, degrees, results, stepResult.failCount, cursorJson, nextQuery)
}
}