drew
04/20/2021, 8:55 PMnull, i want to return an error. if not, i want to run several validations against the non-null data. how would i go about this? .withEither doesn’t seem correct, because i want to operate with Validated, not Either.raulraja
04/20/2021, 9:14 PMraulraja
04/20/2021, 9:15 PMraulraja
04/20/2021, 9:15 PMA there is not constrained to Any so it really works on nullable types too. If you want something more concrete and expicitly target nullable types you may want to have an error ADT where NotFound is an optionraulraja
04/20/2021, 9:16 PMraulraja
04/20/2021, 9:16 PMdrew
04/20/2021, 9:16 PM1 is instead nullraulraja
04/20/2021, 9:17 PMraulraja
04/20/2021, 9:17 PMsealed class Errors
object NullOrNotFound : Errors()
...drew
04/20/2021, 9:18 PMraulraja
04/20/2021, 9:18 PME: Errorsdrew
04/20/2021, 9:18 PMfun validateAge(age: Int?): Validated<PersonError, Int> =
age?.let {
if (it < 11) {
Invalid(IsTooSmall(10))
} else {
Valid(it)
}
} ?: Invalid(IsNull("age"))drew
04/20/2021, 9:18 PMlet could actually be zip ing several validationsraulraja
04/20/2021, 9:20 PMraulraja
04/20/2021, 9:21 PMdrew
04/20/2021, 9:21 PMdrew
04/20/2021, 9:21 PMdrew
04/20/2021, 9:22 PMdrew
04/20/2021, 9:22 PMraulraja
04/20/2021, 9:23 PMraulraja
04/20/2021, 9:23 PMraulraja
04/20/2021, 9:23 PMeither {
val result = validationValue.bind()
}raulraja
04/20/2021, 9:25 PMraulraja
04/20/2021, 9:26 PMdrew
04/20/2021, 9:27 PMdrew
04/20/2021, 9:47 PMdrew
04/20/2021, 9:47 PMimport arrow.core.*
import arrow.core.computations.either
sealed class PersonError(message: String) {
data class IsNull(val field: String): PersonError("$field is null")
data class IsTooSmall(val limit: Int): PersonError("must be larger than $limit")
}
data class Person(val name: String, val age: Int)
typealias IsNull = PersonError.IsNull
typealias IsTooSmall = PersonError.IsTooSmall
fun <A>validateNotNull(value: A?, field: String): Validated<PersonError, A> =
value?.let(::Valid) ?: Invalid(IsNull(field))
fun validateName(name: String?): Validated<PersonError, String> =
validateNotNull(name, "name")
fun validateAgeFields(age: Int): ValidatedNel<PersonError, Int> =
if (age < 10) {
Invalid(IsTooSmall(10))
} else {
Valid(age)
}.toValidatedNel()
suspend fun validateAge(age: Int?): ValidatedNel<PersonError, Int> =
Validated.fromEither(either {
val goodAge = validateNotNull(age, "age").toValidatedNel().bind()
validateAgeFields(goodAge).bind()
})
suspend fun validatePerson(name: String?, age: Int?): ValidatedNel<PersonError, Person> =
validateName(name)
.toValidatedNel()
.zip(validateAge(age))
{ goodName, goodAge -> Person(goodName, goodAge) }raulraja
04/21/2021, 7:57 AM