aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/org/pacien/lemonad/validation/Validation.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/pacien/lemonad/validation/Validation.java')
-rw-r--r--src/main/java/org/pacien/lemonad/validation/Validation.java133
1 files changed, 104 insertions, 29 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
21import org.pacien.lemonad.attempt.Attempt; 21import org.pacien.lemonad.attempt.Attempt;
22 22
23import java.util.Arrays; 23import java.util.ArrayList;
24import java.util.Collection;
24import java.util.List; 25import java.util.List;
25import java.util.Objects;
26import java.util.function.BiConsumer; 26import java.util.function.BiConsumer;
27import java.util.function.Consumer; 27import java.util.function.Consumer;
28import java.util.function.Function; 28import java.util.function.Function;
29import java.util.stream.Stream; 29import java.util.function.Predicate;
30 30
31import lombok.NonNull; 31import lombok.NonNull;
32 32
33import static java.util.stream.Collectors.toUnmodifiableList; 33import static java.util.function.Function.identity;
34import static org.pacien.lemonad.attempt.Attempt.failure; 34import static org.pacien.lemonad.attempt.Attempt.failure;
35import static org.pacien.lemonad.attempt.Attempt.success; 35import 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()));
128 } 203 }