I need to address an API which returns chunked data.
val response = server.getChunk(request, chunkNumber)
data class PageInfo(
val pageNumber: Int,
val maxPages: Int
)
data class Response(
val elements: List<Payload>,
val pageInfo: PageInfo
)
I assume this API idempotent.
I can do something like that (take 1):
var i = 0
var maxPages: Int
val payloadTotal = mutableListOf<Payload>()
do {
val response = server.getChunk(request, i++)
maxPages = response.pageInfo.maxPages
payloadTotal.addAll(response.payload)
} while (i < maxPages)
It works, but it's ugly.
take 2:
val partners = IntStream
.iterate(0) { it + 1 }
.asSequence()
.map { server.getChunk(request, it) }
.takeWhile { it.pageInfo.pageNumber < it.pageInfo.maxPages }
.map { it.payload }
.flatten()
.toList()
It looks much nicer, but doesn't quite work as intended: since we check the takeWhile predicate after already requesting the server we will always end up doing one extra request. And since we don't know the maxPages value before we do the first request we can't use something like take(n: Int).
So I ended up going with that code (take 3):
var maxPages = Int.MAX_VALUE
val partners = IntStream
.iterate(0) { it + 1 }
.asSequence()
.takeWhile { it < maxPages }
.map {
server.getChunk(request, it)
.also { response -> maxPages = response.pageInfo.maxPages }
}
.map { it.payload }
.flatten()
.toList()
It works. But then again, we use this extra state which I do not like.
Also, because of the "effectively final" restrictions this won't work in Java at all (and I would like it to as a bonus).
So how do I achieve the required behavior with a functional approach? Is there a way to do it without tracking any addition state outside of the pipeline?
*If such a way exists does it also translate to Java?