0

I am currently learning to use ArrowKT and I have the following code for validating an input. I tried to collect all the errors at once and execute the validations in parallel since most of them are done against the database.

return Validated.applicativeNel<ValidationError>()
    .tupledN(
        validateA(input).toValidatedNel(),
        validateB(input).toValidatedNel(),
        validateC(input).toValidatedNel(),
        validateSlotIsFree(input).toValidatedNel(),
    )
    .fix()
    .map { (a, b, c, _) ->
        ...
    }

private suspend fun validateSlotIsFree(input: CreateDto): Validated<ValidationError.SlotUnavailable, Boolean> {
    val exists = appointmentRepository.existsBy...()
    return if (exists) true.valid() else ValidationError.SlotUnavailable.invalid()
}

Is there any better way to handle the validation inside validateSlotIsFree? It looks like I am forced to return something on the right side in case of valid but I would not want to. I was looking for something like an Option where the value would be the Error and empty would mean that the validation has passed. The problem with this is that Validated.fromOption(...) would take the value and apply it to the Right and I need the opposite.

tzortzik
  • 4,993
  • 9
  • 57
  • 88
  • 2
    You might find this useful: https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/ – LordRaydenMK Mar 02 '21 at 21:05
  • 1
    Why use `Boolean` when you have `Unit`? In any case, `validated.fold({ it.some() }, Option::none)` should do the trick. – MLProgrammer-CiM Mar 02 '21 at 23:52
  • @LordRaydenMK thanks for the article, much useful perspective there; although I wouldn't help in my case because I still need to collect that error. @MLProgrammer-CiM I guess the APIs do not allow me to do it that way. I tried using `Validated` and `Either` but I don't know to resolve the `Nothing` case since the API for `Valid(A)` and `Right(A)` expects a non nullable object. – tzortzik Mar 03 '21 at 08:37
  • @MLProgrammer-CiM it looks like I misunderstood your suggestion. I made it work with Unit – tzortzik Mar 03 '21 at 09:17

1 Answers1

0

Using the answers of both @LordRaydenMK and @MLProgrammer-CiM I found two solutions

private suspend fun validateSlotIsFree(input: CreateAppointmentDto): Validated<ValidationError.SlotUnavailable, Unit> {
    val exists = appointmentRepository.existsBy...()
    return if (exists) Valid(Unit) else ValidationError.SlotUnavailable.invalid()
}

Previously I have tried with Nothing and it didn't work. The reason for that is that Nothing has no possible value and that is why using null didn't work. In order for it to work with null I had to use Nothing?.

The first solution is preferred since using Nothing? would be incorrect because it actually says that this function does not return anything and at the same time it can return null.

tzortzik
  • 4,993
  • 9
  • 57
  • 88