1

I have an object, Bill, with a number of fields. In the method below, I get the bill with a function. I want to validate it with a list of Predicate<Bill>, which are paired with the appropriate error message to be applied if the predicate test fails. How can I accumulate the error messages given a list of tests, given that I can have more than eight conditions, and therefore won't be able to use Validation.combine?

default Validation<Seq<String>, Long> validate(
                 Long id,
                 Long, Bill> getBill, 
                 List<Pair<Predicate<Bill>,String>> tests){
        Bill bill = getBill.apply(id);

        //I want to do the same thing 
        //but using the list I passed in, 
        //without the limitation of eight validations.
        return Validation.combine(
                validateBill(bill, Pair.of(hasDateInsurerReceivedBill, "Date Insurer Received Bill absent")),
                validateBill(bill, Pair.of(EventValidation.hasEmployeeIdNumber, "Employee ID Number absent"))
        ).ap((x, y) -> id);
    }
default Validation<String,Long> validateBill(
Bill bill, Pair<Predicate<Bill>, String> condition)
{
        return condition.getFirst().test(bill) ?
                Validation.valid(bill.getIntId())
                : Validation.invalid(condition.getSecond());
}

I'm brand new to this library and I'm not terribly familiar with functional programming yet, so please use examples and the simplest terminology possible in any explanations.

FaraBara
  • 115
  • 7

1 Answers1

0

I would do a nested combine and then flatten the results.

In our project we always have Seq<ValidationError> on the left side of a Validation, you don't have to but it is good to understand the code I'll show you.

With the first 8 Validations you return a new Validation in the .ap When you return a Validation inside .ap you will end up with something like this:

Validation<Seq<ValidationError>, Validation<Seq<ValidationError>, String>> x  = ...

The needs to be flattened with the following piece of code:

Validation
        .combine(step1, step2, step3, step4, step5, step6, step7, step8)
        .ap((a, b, c, d, e, f ,g, h) -> {
            // do important stuff and
            return Validation......
        })
        .mapError(Util::flattenErrors)
        .fold(Validation::invalid, Function.identity());

The Util class:

public static Seq<ValidationError> flattenErrors(final Seq<Seq<ValidationError>> nested) {
    return nested
            .flatMap(Function.identity())
            .distinct(); //optional duplicate filtering
}

With this new validation you can do the same trick again (you can add 7 new validations every time or create a few and do another combine, depends a bit on the number of validations you have).

jvwilge
  • 2,474
  • 2
  • 16
  • 21