org.http4k.connect.Paged.kt Maven / Gradle / Ivy
package org.http4k.connect
import dev.forkhandles.result4k.Failure
import dev.forkhandles.result4k.Result
import dev.forkhandles.result4k.Success
import dev.forkhandles.result4k.map
import dev.forkhandles.result4k.peekFailure
import org.http4k.core.Response
import org.http4k.format.AutoMarshalling
import org.http4k.lens.LensExtractor
import kotlin.reflect.KClass
/**
* Represents a Paged response
*/
interface Paged : Iterable {
fun token(): Token?
val items: List
override fun iterator() = items.iterator()
}
/**
* Superclass for all Paged actions
*/
interface PagedAction, Self : PagedAction> :
Action> {
fun next(token: Token): Self
}
/**
* Paginate the response of the passed action
*/
fun , Rsp : Paged> paginated(
fn: (Action) -> Result, action: Action
): Sequence, RemoteFailure>> {
var nextRequest: Action? = action
return generateSequence {
nextRequest
?.let {
fn(it).map { rsp ->
nextRequest = rsp.token()?.let(it::next)
rsp.items
}
}
}.map { it.peekFailure { nextRequest = null } }
}
/**
* Superclass for paged actions where the response can be auto-marshalled
*/
abstract class AutomarshalledPagedAction<
Token,
ItemType : Any,
PageType : Paged,
Self : AutomarshalledPagedAction
>(
private val toResult: (List, Token?) -> PageType,
private val autoMarshalling: AutoMarshalling,
private val kClass: KClass
) : PagedAction,
LensExtractor {
override fun toResult(response: Response): Result = with(response) {
when {
status.successful -> {
val itemsAsListEvenWhenTheyAreNot =
bodyString().let { if (it.trimStart().startsWith("[")) it else """[$it]""" }
Success(
toResult(
autoMarshalling
.asA(
"""{"items":$itemsAsListEvenWhenTheyAreNot}""".trimIndent(),
kClass
).items,
this@AutomarshalledPagedAction(this)
)
)
}
else -> Failure(asRemoteFailure(this))
}
}
override fun equals(other: Any?) = when {
this === other -> true
javaClass != other?.javaClass -> false
else -> toRequest() == (other as Action<*>).toRequest()
}
override fun hashCode() = toRequest().hashCode()
}