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 null
raulraja
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: Errors
drew
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