com.kenshoo.pl.entity.spi.helpers.UniquenessValidator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of persistence-layer Show documentation
Show all versions of persistence-layer Show documentation
A Java persistence layer based on JOOQ for high performance and business flow support.
package com.kenshoo.pl.entity.spi.helpers;
import com.kenshoo.pl.entity.*;
import com.kenshoo.pl.entity.internal.EntitiesFetcher;
import com.kenshoo.pl.entity.internal.EntityWithNullForMissingField;
import com.kenshoo.pl.entity.spi.ChangesValidator;
import org.apache.commons.lang3.ArrayUtils;
import org.jooq.lambda.Seq;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import java.util.function.BinaryOperator;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static com.kenshoo.pl.entity.ChangeOperation.UPDATE;
import static com.kenshoo.pl.entity.SupportedChangeOperation.CREATE;
import static java.util.Objects.requireNonNull;
import static java.util.function.Function.identity;
import static java.util.stream.Collectors.toMap;
public class UniquenessValidator> implements ChangesValidator {
private final String errorCode;
private final EntitiesFetcher fetcher;
private final UniqueKey uniqueKey;
private final PLCondition condition;
private final SupportedChangeOperation operation;
private UniquenessValidator(EntitiesFetcher fetcher, UniqueKey uniqueKey, SupportedChangeOperation operation, PLCondition condition, String errorCode) {
this.errorCode = errorCode;
this.fetcher = requireNonNull(fetcher, "entity fetcher must be provided");
this.uniqueKey = requireNonNull(uniqueKey, "unique key must be provided");
this.condition = requireNonNull(condition, "condition must be provided");
this.operation = requireNonNull(operation, "operation must be provided");
}
@Override
public SupportedChangeOperation getSupportedChangeOperation() {
return operation;
}
@Override
public void validate(Collection extends EntityChange> commands, ChangeOperation op, ChangeContext ctx) {
final var commandsToValidate = commands.stream().filter(hasChangeInUniqueKeyField()).collect(Collectors.toList());
Map, ? extends EntityChange> commandsByIds = markDuplicatesInCollectionWithErrors(commandsToValidate, ctx);
if (commandsByIds.isEmpty())
return;
UniqueKey pk = uniqueKey.getEntityType().getPrimaryKey();
EntityField[] uniqueKeyAndPK = ArrayUtils.addAll(uniqueKey.getFields(), pk.getFields());
Map, CurrentEntityState> duplicates = fetcher.fetch(uniqueKey.getEntityType(), commandsByIds.keySet(), condition, uniqueKeyAndPK)
.stream()
.collect(toMap(e -> createKeyValue(e, uniqueKey), identity()));
duplicates.forEach((dupKey, dupEntity) -> ctx.addValidationError(commandsByIds.get(dupKey), errorForDatabaseConflict(dupEntity, pk)));
}
private Predicate> hasChangeInUniqueKeyField() {
return cmd -> !UPDATE.equals(cmd.getChangeOperation()) || Arrays.stream(uniqueKey.getFields()).anyMatch(cmd::isFieldChanged);
}
private Map, EntityChange> markDuplicatesInCollectionWithErrors(Collection extends EntityChange> commands, ChangeContext ctx) {
return commands
.stream()
.filter(command -> condition.getPostFetchCondition().test(ctx.getFinalEntity(command)))
.collect(toMap(cmd -> createKeyValue(cmd, ctx, uniqueKey), identity(), fail2ndConflictingCommand(ctx)));
}
private ValidationError errorForDatabaseConflict(CurrentEntityState dupEntity, UniqueKey pk) {
return new ValidationError(errorCode, Seq.of(pk.getFields()).toMap(Object::toString, field -> String.valueOf(dupEntity.get(field))));
}
private BinaryOperator> fail2ndConflictingCommand(ChangeContext ctx) {
return (cmd1, cmd2) -> {
ctx.addValidationError(cmd2, new ValidationError(errorCode));
return cmd1;
};
}
private static > Identifier createKeyValue(EntityChange cmd, ChangeContext ctx, UniqueKey key) {
return key.createIdentifier(new EntityWithNullForMissingField(ctx.getFinalEntity(cmd)));
}
private Identifier createKeyValue(CurrentEntityState currentEntityState, UniqueKey key) {
return key.createIdentifier(currentEntityState);
}
@Override
public Stream extends EntityField, ?>> requiredFields(Collection extends EntityField> fieldsToUpdate, ChangeOperation op) {
return Stream.concat(Stream.of(uniqueKey.getFields()), Stream.of(uniqueKey.getEntityType().getPrimaryKey().getFields()));
}
public static class Builder> {
private String errorCode = "DUPLICATE_ENTITY";
private final EntitiesFetcher fetcher;
private final UniqueKey uniqueKey;
private PLCondition condition = PLCondition.trueCondition();
private SupportedChangeOperation operation = CREATE;
public Builder(EntitiesFetcher fetcher, UniqueKey uniqueKey) {
this.fetcher = fetcher;
this.uniqueKey = uniqueKey;
}
public Builder setOperation(SupportedChangeOperation operation) {
this.operation = operation;
return this;
}
public Builder setCondition(PLCondition condition) {
this.condition = condition;
return this;
}
public Builder setErrorCode(String errorCode) {
this.errorCode = errorCode;
return this;
}
public UniquenessValidator build() {
return new UniquenessValidator<>(fetcher, uniqueKey, operation, condition, errorCode);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy