diff options
Diffstat (limited to 'src/main/java/org/pacien/lemonad')
3 files changed, 110 insertions, 109 deletions
diff --git a/src/main/java/org/pacien/lemonad/validation/Validation.java b/src/main/java/org/pacien/lemonad/validation/Validation.java index 04c1ed0..98a4496 100644 --- a/src/main/java/org/pacien/lemonad/validation/Validation.java +++ b/src/main/java/org/pacien/lemonad/validation/Validation.java | |||
@@ -20,17 +20,17 @@ package org.pacien.lemonad.validation; | |||
20 | 20 | ||
21 | import org.pacien.lemonad.attempt.Attempt; | 21 | import org.pacien.lemonad.attempt.Attempt; |
22 | 22 | ||
23 | import java.util.Arrays; | 23 | import java.util.ArrayList; |
24 | import java.util.Collection; | ||
24 | import java.util.List; | 25 | import java.util.List; |
25 | import java.util.Objects; | ||
26 | import java.util.function.BiConsumer; | 26 | import java.util.function.BiConsumer; |
27 | import java.util.function.Consumer; | 27 | import java.util.function.Consumer; |
28 | import java.util.function.Function; | 28 | import java.util.function.Function; |
29 | import java.util.stream.Stream; | 29 | import java.util.function.Predicate; |
30 | 30 | ||
31 | import lombok.NonNull; | 31 | import lombok.NonNull; |
32 | 32 | ||
33 | import static java.util.stream.Collectors.toUnmodifiableList; | 33 | import static java.util.function.Function.identity; |
34 | import static org.pacien.lemonad.attempt.Attempt.failure; | 34 | import static org.pacien.lemonad.attempt.Attempt.failure; |
35 | import static org.pacien.lemonad.attempt.Attempt.success; | 35 | import static org.pacien.lemonad.attempt.Attempt.success; |
36 | 36 | ||
@@ -72,58 +72,133 @@ public interface Validation<S, E> { | |||
72 | } | 72 | } |
73 | 73 | ||
74 | /** | 74 | /** |
75 | * @param consumer the consumer called with the validation subject and reported errors if the validation is failed. | 75 | * @param consumer the consumer called with the validation subject and reported errors if the validation has failed. |
76 | * @return the current object. | 76 | * @return the current object. |
77 | */ | 77 | */ |
78 | default Validation<S, E> ifInvalid(@NonNull BiConsumer<? super S, ? super List<? super E>> consumer) { | 78 | default Validation<S, E> ifInvalid(@NonNull BiConsumer<? super S, ? super List<? super E>> consumer) { |
79 | if (!isValid()) consumer.accept(getSubject(), getErrors()); | 79 | if (isInvalid()) consumer.accept(getSubject(), getErrors()); |
80 | return this; | 80 | return this; |
81 | } | 81 | } |
82 | 82 | ||
83 | /** | 83 | /** |
84 | * @return an {@link Attempt} with a state corresponding to the one of the validation. | 84 | * @param predicate the validation predicate testing the validity of a subject. |
85 | * @param error the error to return if the subject does not pass the test. | ||
86 | * @return an updated {@link Validation}. | ||
85 | */ | 87 | */ |
86 | default Attempt<S, List<E>> toAttempt() { | 88 | default Validation<S, E> validate(@NonNull Predicate<? super S> predicate, @NonNull E error) { |
87 | return isValid() ? success(getSubject()) : failure(getErrors()); | 89 | return validate(identity(), predicate, error); |
90 | } | ||
91 | |||
92 | /** | ||
93 | * @param mapper the field getter mapping the validation subject. | ||
94 | * @param predicate the validation predicate testing the validity of a subject. | ||
95 | * @param error the error to return if the subject does not pass the test. | ||
96 | * @return an updated {@link Validation}. | ||
97 | */ | ||
98 | default <F> Validation<S, E> validate( | ||
99 | @NonNull Function<? super S, ? extends F> mapper, | ||
100 | @NonNull Predicate<? super F> predicate, | ||
101 | E error | ||
102 | ) { | ||
103 | return validate(mapper, field -> predicate.test(field) ? List.of() : List.of(error)); | ||
104 | } | ||
105 | |||
106 | /** | ||
107 | * @param validator the validating function to use, returning a potentially empty list of errors. | ||
108 | * @return an updated {@link Validation}. | ||
109 | */ | ||
110 | default Validation<S, E> validate(@NonNull Function<? super S, ? extends List<? extends E>> validator) { | ||
111 | var errors = validator.apply(getSubject()); | ||
112 | return errors.isEmpty() ? this : merge(errors); | ||
113 | } | ||
114 | |||
115 | /** | ||
116 | * @param mapper the field getter mapping the validation subject. | ||
117 | * @param validator the validating function to use, returning a potentially empty list of errors. | ||
118 | * @return an updated {@link Validation}. | ||
119 | */ | ||
120 | default <F> Validation<S, E> validate( | ||
121 | @NonNull Function<? super S, ? extends F> mapper, | ||
122 | @NonNull Function<? super F, ? extends List<? extends E>> validator | ||
123 | ) { | ||
124 | return validate(validator.compose(mapper)); | ||
125 | } | ||
126 | |||
127 | /** | ||
128 | * @param validator a subject validating function returning a {@link Validation}. | ||
129 | * @return an updated {@link Validation}. | ||
130 | */ | ||
131 | default Validation<S, E> merge(@NonNull Function<? super S, ? extends Validation<?, ? extends E>> validator) { | ||
132 | return merge(validator.apply(getSubject())); | ||
133 | } | ||
134 | |||
135 | /** | ||
136 | * @param mapper the field getter mapping the validation subject. | ||
137 | * @param validator a subject validating function returning a {@link Validation}. | ||
138 | * @return an updated {@link Validation}. | ||
139 | */ | ||
140 | default <F> Validation<S, E> merge( | ||
141 | @NonNull Function<? super S, ? extends F> mapper, | ||
142 | @NonNull Function<? super F, ? extends Validation<?, ? extends E>> validator | ||
143 | ) { | ||
144 | return merge(validator.compose(mapper)); | ||
145 | } | ||
146 | |||
147 | /** | ||
148 | * @param validation another validation to merge into the current one. | ||
149 | * @return an updated {@link Validation}. | ||
150 | */ | ||
151 | @SuppressWarnings("unchecked") | ||
152 | default Validation<S, E> merge(@NonNull Validation<?, ? extends E> validation) { | ||
153 | if (validation.isValid()) return this; | ||
154 | if (this.isValid()) return Validation.of(this.getSubject(), (List<E>) validation.getErrors()); | ||
155 | return merge(validation.getErrors()); | ||
156 | } | ||
157 | |||
158 | /** | ||
159 | * @param errors a potentially empty list of additional errors to take into account. | ||
160 | * @return an updated {@link Validation}. | ||
161 | */ | ||
162 | default Validation<S, E> merge(@NonNull Collection<? extends E> errors) { | ||
163 | var combinedErrors = new ArrayList<E>(getErrors().size() + errors.size()); | ||
164 | combinedErrors.addAll(getErrors()); | ||
165 | combinedErrors.addAll(errors); | ||
166 | return new ValidationContainer<>(getSubject(), combinedErrors); | ||
88 | } | 167 | } |
89 | 168 | ||
90 | /** | 169 | /** |
91 | * @param mapper a function transforming a {@link Validation}. | 170 | * @param mapper a function transforming a {@link Validation}. |
92 | * @return the transformed {@link Validation}. | 171 | * @return the transformed {@link Validation}. |
93 | */ | 172 | */ |
94 | default <SS, EE> Validation<SS, EE> flatMap(@NonNull Function<? super Validation<? super S, ? super E>, ? extends Validation<? extends SS, ? extends EE>> mapper) { | 173 | default <SS, EE> Validation<SS, EE> flatMap( |
174 | @NonNull Function<? super Validation<? super S, ? super E>, ? extends Validation<? extends SS, ? extends EE>> mapper | ||
175 | ) { | ||
95 | //noinspection unchecked | 176 | //noinspection unchecked |
96 | return (Validation<SS, EE>) mapper.apply(this); | 177 | return (Validation<SS, EE>) mapper.apply(this); |
97 | } | 178 | } |
98 | 179 | ||
99 | /** | 180 | /** |
100 | * @param subject an overriding subject. | 181 | * @return an {@link Attempt} with a state corresponding to the one of the validation. |
101 | * @param validationResults a {@link Stream} of {@link Validation}s to merge. | ||
102 | * @return the merged {@link Validation} containing all errors from the supplied ones. | ||
103 | */ | 182 | */ |
104 | static <S, E> Validation<S, E> merge(S subject, @NonNull Stream<? extends Validation<?, ? extends E>> validationResults) { | 183 | default Attempt<S, List<E>> toAttempt() { |
105 | return new ValidationContainer<>( | 184 | return isValid() ? success(getSubject()) : failure(getErrors()); |
106 | subject, | ||
107 | validationResults.flatMap(res -> res.getErrors().stream()).collect(toUnmodifiableList())); | ||
108 | } | 185 | } |
109 | 186 | ||
110 | /** | 187 | /** |
111 | * @param subject the suject of the validation. | 188 | * @param subject the subject of the validation. |
112 | * @return a successful {@link Validation}. | 189 | * @param errors some optional validation errors. |
190 | * @return a {@link Validation}. | ||
113 | */ | 191 | */ |
114 | static <S, E> Validation<S, E> valid(S subject) { | 192 | @SafeVarargs static <S, E> Validation<S, E> of(S subject, E... errors) { |
115 | return new ValidationContainer<>(subject, List.of()); | 193 | return Validation.of(subject, List.of(errors)); |
116 | } | 194 | } |
117 | 195 | ||
118 | /** | 196 | /** |
119 | * @param subject the suject of the validation. | 197 | * @param subject the subject of the validation. |
120 | * @param error a validation error. | 198 | * @param errors some optional validation errors. |
121 | * @param errors additional validation errors. | 199 | * @return a {@link Validation}. |
122 | * @return a failed {@link Validation} for the supplied subject. | ||
123 | */ | 200 | */ |
124 | @SafeVarargs static <S, E> Validation<S, E> invalid(S subject, E error, E... errors) { | 201 | static <S, E> Validation<S, E> of(S subject, @NonNull List<E> errors) { |
125 | return new ValidationContainer<>( | 202 | return new ValidationContainer<>(subject, errors); |
126 | subject, | ||
127 | Stream.concat(Stream.of(error), Arrays.stream(errors)).map(Objects::requireNonNull).collect(toUnmodifiableList())); | ||