Skip to content

Instantly share code, notes, and snippets.

@rcd27
Created April 14, 2023 09:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rcd27/a24f0508c532bd698b6a91d19cd79117 to your computer and use it in GitHub Desktop.
Save rcd27/a24f0508c532bd698b6a91d19cd79117 to your computer and use it in GitHub Desktop.
I'm not against Mono<A> + Result<C>, but supsend + Either is also good choice
package com.github.redarmour.pantheon.maxim
import arrow.core.Either
import arrow.core.continuations.either
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.delay
/**
* На самом деле предлагаемый подход - суть то же, что не suspend функции, которые возврашают Mono<Result<T>>
* За тем лишь исключением, что котлинячий Result не "стакается" так же, как Either.Left
*/
suspend fun dataUpdateProcess(unvalidatedUpdateRequest: UnvalidatedDataUpdateRequest): Either<DataUpdateError, SubscriberDataUpdateResponse> =
either {
val validated: ValidatedDataUpdateRequest = ValidatedDataUpdateRequest.emerge(unvalidatedUpdateRequest).bind()
val existingData = findDataWithUpdates(validated).bind() // <-- bind() = flatMap в скоупе Either
/*
...
*/
SubscriberDataUpdateResponse.fromExistingData(existingData)
}
suspend fun findDataWithUpdates(input: ValidatedDataUpdateRequest): Either<NoDataFound, DataUpdate> = coroutineScope {
delay(1000) // <-- Асинхронщина, пожалуйста. Reactive Streams на Mono<T> - аналог suspend функций, как по мне
Either.catch {
throw RuntimeException("No data found for: $input")
}
.mapLeft {
NoDataFound(it)
}
}
data class UnvalidatedDataUpdateRequest(
val x: String?,
val y: String?
)
data class SubscriberDataUpdateResponse internal constructor(val responseBody: String) {
companion object {
fun fromExistingData(source: DataUpdate): SubscriberDataUpdateResponse {
return SubscriberDataUpdateResponse(source.toString())
}
}
}
data class ValidatedDataUpdateRequest internal constructor(
val validatedX: String,
val validatedY: String
) {
companion object {
fun emerge(input: UnvalidatedDataUpdateRequest): Either<ValidationError, ValidatedDataUpdateRequest> {
return Either.catch {
require(input.x != null)
require(input.y != null)
ValidatedDataUpdateRequest(input.x, input.y)
}
.mapLeft {
// TODO: тут описать алгебру валидации
ValidationError(it)
}
}
}
}
/**
* Вообще в принципе любая доменная ошибка
*/
sealed interface DataUpdateError
data class ValidationError(val t: Throwable) : DataUpdateError
/**
* Для быстроты я прокидываю сюда Throwable, но что будет в теле доменной ошибки - не суть важно
*/
data class NoDataFound(val t: Throwable) : DataUpdateError
data class DataUpdate(
val xToUpdate: String,
val yToUpdate: String
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment