Vavr validation - kilka sprawdzeń pojedynczego elementu

0

Wróciłem do zabawy z Vavrem i pisze sobie prostą klase odpowiedzialną za walidację jakiegoś obiektu.

@Component
public class QuestionValidator {

    public Validation<Seq<Problem>, CreateQuestionCommand> validateCreateQuestionCommand(final CreateQuestionCommand command) {
        return Validation.combine(
                isNotBlank(command.getAnswer(), Problem.BLANK_ANSWER),
                isNotBlank(command.getContent(), Problem.BLANK_CONTENT),
                hasAtLeastOneElement(command.getTags())
                ).ap(CreateQuestionCommand::new);
    }

    private Validation<Problem, String> isNotBlank(final String value, final Problem problem) {
        return value != null && !value.isBlank() ? Validation.valid(value) : Validation.invalid(problem);
    }

    private Validation<Problem, Set<String> > hasAtLeastOneElement(final Set<String> tags) {
        return tags != null && !tags.isEmpty() ? Validation.valid(tags) : Validation.invalid(Problem.TOO_FEW_TAG);
    }
}

No i ok, działa to tak jak chce. problem jest w tym, że chce dodac jedną regułę więcej, mianowicie - maksymalna liczba tagów to 5.

private Validation<Problem, Set<String> > hasNoMoreThanFiveElements(final Set<String> tags) {
        return tags != null && tags.size() <= 5 ? Validation.valid(tags) : Validation.invalid(Problem.TOO_MANY_TAGS);
    }

Tyle, że jak to dodam do środka metody combine, oznaczać będzie że wewnątrz metody ap() będe musiał podać Function4.
screenshot-20200910211133.png
Czyli wyjściowy obiekt będzie musiał mieć 4 pola. Co jest czywiście bez sensu, z racji tego że 2x waliduje to samo pole, czyli tags, nie oznacza że chce je 2x trzymać w wyjściowym obiekcie.

Próbowałem też w ten sposób

    private Validation<Seq<Problem>, Set<String>> hasValidNumberOfElements(final Set<String> tags) {
        return Validation.combine(hasAtLeastOneElement(tags), hasNoMoreThanFiveElements(tags)).ap((i, j) -> new HashSet<>(i));
    }

Metoda ap() znów wymaga dwóch parametrów, ale w tym przypadku dało się to rozwiązać w co prawda średnio elegancki sposób. Użycie jednak tego w metodzie combine o której mowa na początku jest jednak nie możliwe,
screenshot-20200910211927.png

No i nie bardzo wiem jak wybrnąć... zaznaczę od razu, że zdaje sobie sprawę, że w tym konkrentym przypadku nie możliwe jest że wystąpią obydwa błędy walidacji (< 1 i > 5 elementów), jednak chyba każdy może sobie wyobrazić taki przypadek.

Edit#

Ok, zaćmienie umysłu.... mogę zrobić coś takiego

    public Validation<Seq<Problem>, CreateQuestionCommand> validateCreateQuestionRequest(final CreateQuestionCommand command) {
        return Validation.combine(
                isNotBlank(command.getAnswer(), Problem.BLANK_ANSWER),
                isNotBlank(command.getContent(), Problem.BLANK_CONTENT),
                hasAtLeastOneElement(command.getTags()),
                hasNoMoreThanFiveElements(command.getTags())
                ).ap((a, b, c, d) -> new CreateQuestionCommand(a, b, c));
    }

Mimo wszystko, jakoś nie jestem do tego przekonany

1
    private Validation<Problem, Set<String>> hasValidNumberOfElements(Set<String> tags) {
        return tagsValidationError(tags).getOrElse(Validation.valid(tags));
    }

    private Option<Validation<Problem, Set<String>>> tagsValidationError(Set<String> tags) {
        return Match(tags).option(
                Case($(Objects::isNull), Problem.CANNOT_BE_NULL),
                Case($(Set::isEmpty), Problem.TOO_FEW_TAG),
                Case($(t -> t.size() > 5), Problem.TOO_MANY_TAGS)
        ).map(Validation::invalid);
    }

1 użytkowników online, w tym zalogowanych: 0, gości: 1