Imagine you consume an API that gives you up to 100 elements and allows you to get more elements not by specifying a page number but instead only by telling it which is the last element you received. You would then want to abstract over this quasi-pagination. How would you do that in Scala?
I came up with this probably buggy (= not thoroughly tested) and very stateful piece of code:
abstract class IteratorThatKeepsOnGiving[T] extends Iterator[T] {
private var currentIter: Iterator[T] = _
private var currentElement: T = _
def nextIterator(lastElement: Option[T]): Iterator[T]
fetchNewBatch(None)
def fetchNewBatch(lastElement: Option[T]) = {
currentIter = nextIterator(lastElement)
}
def hasNext: Boolean = currentIter.hasNext || {
fetchNewBatch(Some(currentElement))
currentIter.hasNext
}
def next(): T = {
currentIter.nextOption() match {
case Some(value) =>
currentElement = value
value
case None =>
fetchNewBatch(Some(currentElement))
next()
}
}
}
I don't like it.
Use:
val numberIterator = new IteratorThatKeepsOnGiving[Int] {
def nextIterator(lastElement: Option[Int]): Iterator[Int] = {
val i = lastElement.getOrElse(-1)
((i + 1) to (i + 4)).iterator
}
}
There gotta be a better way to do this. Surely I am not the first one to be bothered by this kind of pagination. What's the correct term for this anyway? And how do I abstract over it?
The API in question is Discord's message list API: https://discord.com/developers/docs/resources/channel#get-channel-messages
Alternatives considered
I have found this question: Making a Scala Iterator for a Paginated API
However, in my case I don't have a total page count. This answer also assumes that the page size is constant and whilst this is given in my case I would really prefer a solution that can do with knowing only "The last element I got was X. How can I get some more elements?" and not "I last got X, how do I get the next Y elements?". Besides, that is irrelevant since I can't specify a page number directly.
There's also flatMapConcat
(and mapConcat
) in Akka Streams which suffers the same problems.