From d3f7207f44fb1f3d33f568d2404117fe7d75bb2e Mon Sep 17 00:00:00 2001 From: philippe tcheriatinsky <philippe.tcherniatinsky@inrae.fr> Date: Tue, 3 Dec 2024 08:54:52 +0100 Subject: [PATCH 1/2] =?UTF-8?q?Identification=20du=20probl=C3=A8me?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/fr/inra/oresing/domain/checker/LineChecker.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/fr/inra/oresing/domain/checker/LineChecker.java b/src/main/java/fr/inra/oresing/domain/checker/LineChecker.java index ece8a8a..02e223e 100644 --- a/src/main/java/fr/inra/oresing/domain/checker/LineChecker.java +++ b/src/main/java/fr/inra/oresing/domain/checker/LineChecker.java @@ -338,6 +338,9 @@ public sealed interface LineChecker<FT extends FieldType> permits LineChecker.Ma final DataDatum transformedReferenceDatum = transformer().transform(referenceDatum, context); DataColumn column = (DataColumn) target(); FieldType valuesToCheck = transformedReferenceDatum.getValuesToCheck(column); + /*TODO #313 Philippe + cas d'un __value__ ici dans un pattern la valeur est MapType mais la valeur à tester est le __VALUE__ + */ CheckerValidationCheckResult validationCheckResults = Optional.ofNullable(valuesToCheck) .map(Object::toString) .map(this::checkRequiredThenCheck) -- GitLab From 514e4185a0b9081f63d9c3304c97e4545ed1286c Mon Sep 17 00:00:00 2001 From: philippe tcheriatinsky <philippe.tcherniatinsky@inrae.fr> Date: Sat, 7 Dec 2024 15:38:08 +0100 Subject: [PATCH 2/2] Correction de l'enregistrement des valuers de PAttern --- .../oresing/domain/checker/LineChecker.java | 6 +- .../domain/checker/type/FieldType.java | 10 +- .../domain/checker/type/PatternType.java | 151 ++++++++++++++++++ .../domain/data/DataColumnPatternValue.java | 24 ++- .../domain/data/deposit/DataImporter.java | 49 +++--- .../CheckerValidationCheckResult.java | 2 +- .../PatternValidationCheckResult.java | 34 ++++ 7 files changed, 243 insertions(+), 33 deletions(-) create mode 100644 src/main/java/fr/inra/oresing/domain/checker/type/PatternType.java create mode 100644 src/main/java/fr/inra/oresing/domain/data/deposit/validation/validationcheckresults/PatternValidationCheckResult.java diff --git a/src/main/java/fr/inra/oresing/domain/checker/LineChecker.java b/src/main/java/fr/inra/oresing/domain/checker/LineChecker.java index 02e223e..cbea1b3 100644 --- a/src/main/java/fr/inra/oresing/domain/checker/LineChecker.java +++ b/src/main/java/fr/inra/oresing/domain/checker/LineChecker.java @@ -338,12 +338,10 @@ public sealed interface LineChecker<FT extends FieldType> permits LineChecker.Ma final DataDatum transformedReferenceDatum = transformer().transform(referenceDatum, context); DataColumn column = (DataColumn) target(); FieldType valuesToCheck = transformedReferenceDatum.getValuesToCheck(column); - /*TODO #313 Philippe - cas d'un __value__ ici dans un pattern la valeur est MapType mais la valeur à tester est le __VALUE__ - */ CheckerValidationCheckResult validationCheckResults = Optional.ofNullable(valuesToCheck) - .map(Object::toString) + .map(FieldType::toStringForComponentValue) .map(this::checkRequiredThenCheck) + .map(valuesToCheck::postTreatment) .orElseThrow(() -> new NotImplementedException("I don't know")); return validationCheckResults; } diff --git a/src/main/java/fr/inra/oresing/domain/checker/type/FieldType.java b/src/main/java/fr/inra/oresing/domain/checker/type/FieldType.java index 2b44a96..23da308 100644 --- a/src/main/java/fr/inra/oresing/domain/checker/type/FieldType.java +++ b/src/main/java/fr/inra/oresing/domain/checker/type/FieldType.java @@ -12,7 +12,7 @@ import fr.inra.oresing.persistence.SqlPrimitiveType; import java.io.IOException; import java.util.Map; -public sealed interface FieldType<T> extends SomethingToBeStoredAsJsonInDatabase, SomethingToBeSentToFrontend +public sealed interface FieldType<T> extends SomethingToBeStoredAsJsonInDatabase, SomethingToBeSentToFrontend permits AbstractType, BooleanType, DateType, @@ -20,6 +20,7 @@ public sealed interface FieldType<T> extends SomethingToBeStoredAsJsonInDatabas IntegerType, ListType, MapType, + PatternType, NullType, StringType { T getValue(); @@ -47,4 +48,11 @@ public sealed interface FieldType<T> extends SomethingToBeStoredAsJsonInDatabas void serializeAddArray(ArrayNode arrayNode); + default String toStringForComponentValue(){ + return toString(); + }; + + default CheckerValidationCheckResult postTreatment(CheckerValidationCheckResult checkerValidationCheckResult){ + return checkerValidationCheckResult; + }; } diff --git a/src/main/java/fr/inra/oresing/domain/checker/type/PatternType.java b/src/main/java/fr/inra/oresing/domain/checker/type/PatternType.java new file mode 100644 index 0000000..f843248 --- /dev/null +++ b/src/main/java/fr/inra/oresing/domain/checker/type/PatternType.java @@ -0,0 +1,151 @@ +package fr.inra.oresing.domain.checker.type; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.NullNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.fasterxml.jackson.databind.node.TextNode; +import fr.inra.oresing.domain.checker.LineChecker; +import fr.inra.oresing.domain.data.SomethingToBeSentToFrontend; +import fr.inra.oresing.domain.data.deposit.context.column.Column; +import fr.inra.oresing.domain.data.deposit.validation.validationcheckresults.CheckerValidationCheckResult; +import fr.inra.oresing.domain.data.deposit.validation.validationcheckresults.PatternValidationCheckResult; +import fr.inra.oresing.persistence.SqlPrimitiveType; +import org.apache.logging.log4j.util.Supplier; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +public non-sealed class PatternType<K, V> implements FieldType<Map<K, V>> { + Map<K, V> value = new HashMap<>(); + final Supplier<PatternType> clone; + + public PatternType(final Map<K, V> map) { + clone = () -> new PatternType(map); + value = map; + } + + @Override + public Map<K, V> getValue() { + return value; + } + + @Override + public SqlPrimitiveType getSqlType() { + return SqlPrimitiveType.JSONB; + } + + @Override + public CheckerValidationCheckResult check(final String value, final LineChecker lineChecker) { + return null; + } + + /* @Override + public ValidationCheckResult check(String value, LineChecker lineChecker) { + throw new NotImplementedException("No check for map"); + } + + @Override + public ValidationCheckResult check(String value, LineCheckerWarper lineCheckerWarper) { + throw new NotImplementedException("No check for map"); + }*/ + + @Override + public FieldType toJsonForDatabase() { + return this; + } + + @Override + public FieldType copy() { + final PatternType mapType = clone.get(); + mapType.value = value; + return mapType; + } + + @Override + public void serialize(final JsonGenerator gen) { + throw new IllegalArgumentException(); + } + + @Override + public Object toJsonForFrontend() { + final Map<K, Object> returnMap = new HashMap<>(); + for (final Map.Entry<K, V> kvEntry : value.entrySet()) { + final V value1 = kvEntry.getValue(); + final K key = kvEntry.getKey(); + if (value1 instanceof SomethingToBeSentToFrontend) { + final Object jsonForFrontend = ((SomethingToBeSentToFrontend) value1).toJsonForFrontend(); + returnMap.put(key, jsonForFrontend); + } else { + returnMap.put(key, value1); + } + } + + return returnMap; + } + + @Override + public void serialize(final JsonGenerator gen, final String key) throws IOException { + final ObjectMapper mapper = new ObjectMapper(); + final ObjectNode mapNode = mapper.createObjectNode(); + for (final Map.Entry<K, V> kvEntry : value.entrySet()) { + switch (kvEntry.getValue()) { + case null -> mapNode.put((String) kvEntry.getKey(), NullNode.getInstance()); + case Integer integer -> mapNode.put((String) kvEntry.getKey(), integer); + case IntegerType integerType -> mapNode.put((String) kvEntry.getKey(), integerType.getValue()); + case Float floating -> mapNode.put((String) kvEntry.getKey(), floating); + case FloatType floatType -> mapNode.put((String) kvEntry.getKey(), floatType.getValue()); + case Boolean bool -> mapNode.put((String) kvEntry.getKey(), bool); + case BooleanType booleanType -> mapNode.put((String) kvEntry.getKey(), booleanType.getValue()); + case NullType fieldType -> mapNode.put((String) kvEntry.getKey(), NullNode.getInstance()); + case FieldType fieldType -> mapNode.put((String) kvEntry.getKey(), fieldType.toString()); + default -> mapNode.put((String) kvEntry.getKey(), kvEntry.getValue().toString()); + } + ; + } + gen.writeFieldName(key); + mapper.writeValue(gen, mapNode); + } + + @Override + public void serialize(final ObjectNode node, final ObjectMapper mapper, final String key) { + final ObjectNode mapNode = mapper.createObjectNode(); + for (final Map.Entry<K, V> kvEntry : value.entrySet()) { + mapNode.put((String) kvEntry.getKey(), kvEntry.getValue() instanceof JsonNode ? (JsonNode) kvEntry.getValue() : new TextNode(kvEntry.getValue().toString())); + } + node.put(key, mapNode); + + } + + @Override + public void serializeAddArray(final ArrayNode arrayNode) { + final ObjectMapper mapper = new ObjectMapper(); + final ObjectNode mapNode = mapper.createObjectNode(); + for (final Map.Entry<K, V> kvEntry : value.entrySet()) { + mapNode.put((String) kvEntry.getKey(), (JsonNode) kvEntry.getValue()); + } + arrayNode.add(mapNode); + } + + @Override + public String toStringForComponentValue() { + V v = value.get(Column.__VALUE__); + return v == null ? "" : v.toString(); + } + + @Override + public CheckerValidationCheckResult postTreatment(CheckerValidationCheckResult checkerValidationCheckResult) { + return PatternValidationCheckResult.of(checkerValidationCheckResult, this); + } + + public FieldType getColumnValue() { + return Optional.ofNullable(value) + .map(map->map.get(Column.__VALUE__)) + .map(FieldType.class::cast) + .orElseGet(NullType::new); + } +} diff --git a/src/main/java/fr/inra/oresing/domain/data/DataColumnPatternValue.java b/src/main/java/fr/inra/oresing/domain/data/DataColumnPatternValue.java index b8841ec..d03dc14 100644 --- a/src/main/java/fr/inra/oresing/domain/data/DataColumnPatternValue.java +++ b/src/main/java/fr/inra/oresing/domain/data/DataColumnPatternValue.java @@ -4,6 +4,7 @@ import fr.inra.oresing.domain.application.configuration.Ltree; import fr.inra.oresing.domain.checker.type.*; import fr.inra.oresing.domain.data.deposit.context.DataImporterContext; +import java.util.HashMap; import java.util.Map; import java.util.function.Function; import java.util.stream.Collectors; @@ -11,17 +12,24 @@ import java.util.stream.Collectors; public record DataColumnPatternValue( Map<DataColumn, DataColumnValue> values) implements DataColumnValue<Map<String, Object>, Map<String, Object>> { + public DataColumnPatternValue(FieldType valuesToCheck) { + this(switch (valuesToCheck) { + case PatternType patternType -> patternType.getValue(); + case null, default -> new HashMap<>(); + }); + } + @Override - public MapType getValuesToCheck() { + public PatternType getValuesToCheck() { Map<String, FieldType> valuesToCheck = values().entrySet() .stream().collect(Collectors.toMap(e -> e.getKey().column(), e -> e.getValue().getValuesToCheck())); - return new MapType<String, FieldType>(valuesToCheck); + return new PatternType<String, FieldType>(valuesToCheck); } @Override public DataColumnPatternValue transform(final Function<FieldType, FieldType> transformation) { final Map<Ltree, String> transformedValues = null;//Maps.transformValues(values, transformation::apply); - return new DataColumnPatternValue(null); + return new DataColumnPatternValue((FieldType) null); } @Override @@ -38,14 +46,14 @@ public record DataColumnPatternValue( @Override public Map<String, Object> toJsonForDatabase() { - return toStringStringMap(); + return toStringStringMap(); } private Map<String, Object> toStringStringMap() { final Map<String, Object> jsonForDatabase = values.entrySet().stream() - .collect(Collectors.toMap(entry -> entry.getKey().column(), entry-> { + .collect(Collectors.toMap(entry -> entry.getKey().column(), entry -> { Object value = entry.getValue().toJsonForDatabase(); - return switch (value){ + return switch (value) { case IntegerType integerType -> integerType.getValue(); case BooleanType booleanType -> booleanType.getValue(); case FloatType floatType -> floatType.getValue(); @@ -55,4 +63,8 @@ public record DataColumnPatternValue( })); return jsonForDatabase; } + + public void put(DataColumn secondPatternOfColumn, DataColumnValue valueToStoreInDatabase) { + values().put(secondPatternOfColumn, valueToStoreInDatabase); + } } \ No newline at end of file diff --git a/src/main/java/fr/inra/oresing/domain/data/deposit/DataImporter.java b/src/main/java/fr/inra/oresing/domain/data/deposit/DataImporter.java index 21a7d85..6b91745 100644 --- a/src/main/java/fr/inra/oresing/domain/data/deposit/DataImporter.java +++ b/src/main/java/fr/inra/oresing/domain/data/deposit/DataImporter.java @@ -22,6 +22,7 @@ import fr.inra.oresing.domain.data.deposit.context.column.Column; import fr.inra.oresing.domain.data.deposit.context.column.OneValueStaticPatternColumn; import fr.inra.oresing.domain.data.deposit.validation.*; import fr.inra.oresing.domain.data.deposit.validation.validationcheckresults.CheckerValidationCheckResult; +import fr.inra.oresing.domain.data.deposit.validation.validationcheckresults.PatternValidationCheckResult; import fr.inra.oresing.domain.data.menu.ReferenceScope; import fr.inra.oresing.domain.data.read.DataHeaderReader; import fr.inra.oresing.domain.exceptions.ReportErrors; @@ -161,26 +162,32 @@ public class DataImporter { Optional.ofNullable(validationCheckResults) .filter(ValidationCheckResult::isSuccess) .ifPresent(validationCheckResult -> { - final DataColumn dataColumn = (DataColumn) validationCheckResult.target(); - final DataColumnValue referenceColumnRawValue = referenceDatumBeforeChecking.get(dataColumn); - DataColumnValue valueToStoreInDatabase = - validationCheckResults.transform( - lineChecker, - referenceColumnRawValue, - dataColumn, - refsLinkedTo); - List<DataColumn> patternOfColumn = Arrays.stream(dataColumn.column().split(Column.COLUMN_IN_COLUMN_SEPARATOR)) - .map(DataColumn::new) - .toList(); - DataColumn firstPatternOfColumn = patternOfColumn.get(0); - DataColumnValue columnValue = referenceDatum.get(firstPatternOfColumn); - if (columnValue instanceof DataColumnPatternValue dataColumnPatternValue) { - DataColumn secondPatternOfColumn = patternOfColumn.get(1); - dataColumnPatternValue.values().put(secondPatternOfColumn, valueToStoreInDatabase); - valueToStoreInDatabase = columnValue; - } - referenceDatum.put(firstPatternOfColumn, valueToStoreInDatabase); - }); + final DataColumn dataColumn = (DataColumn) validationCheckResult.target(); + final DataColumnValue referenceColumnRawValue = referenceDatumBeforeChecking.get(dataColumn); + DataColumnValue valueToStoreInDatabase = + validationCheckResults.transform( + lineChecker, + referenceColumnRawValue, + dataColumn, + refsLinkedTo); + List<DataColumn> patternOfColumn = Arrays.stream(dataColumn.column().split(Column.COLUMN_IN_COLUMN_SEPARATOR)) + .map(DataColumn::new) + .toList(); + DataColumn firstPatternOfColumn = patternOfColumn.get(0); + DataColumnValue columnValue = referenceDatum.get(firstPatternOfColumn); + if (columnValue instanceof DataColumnPatternValue dataColumnPatternValue) { + if (patternOfColumn.size() > 1) { + DataColumn secondPatternOfColumn = patternOfColumn.get(1); + dataColumnPatternValue.values().put(secondPatternOfColumn, valueToStoreInDatabase); + valueToStoreInDatabase = columnValue; + } else { + firstPatternOfColumn = new DataColumn(Column.__VALUE__); + valueToStoreInDatabase = new DataColumnSingleValue(((PatternValidationCheckResult) validationCheckResults).value().getColumnValue()); + } + } + referenceDatum.put(firstPatternOfColumn, valueToStoreInDatabase); + } + ); Optional.ofNullable(validationCheckResults) .filter(validationCheckResult -> !validationCheckResult.isSuccess()) @@ -473,7 +480,7 @@ public class DataImporter { private fr.inra.oresing.domain.Authorization getLineAuthorization(DataDatum referenceDatum, long lineNumber, ReportErrors errors) { final Authorization authorization = dataImporterContext.getAuthorization(); - if(authorization==null){ + if (authorization == null) { return new fr.inra.oresing.domain.Authorization(); } diff --git a/src/main/java/fr/inra/oresing/domain/data/deposit/validation/validationcheckresults/CheckerValidationCheckResult.java b/src/main/java/fr/inra/oresing/domain/data/deposit/validation/validationcheckresults/CheckerValidationCheckResult.java index 191089a..16cce51 100644 --- a/src/main/java/fr/inra/oresing/domain/data/deposit/validation/validationcheckresults/CheckerValidationCheckResult.java +++ b/src/main/java/fr/inra/oresing/domain/data/deposit/validation/validationcheckresults/CheckerValidationCheckResult.java @@ -13,7 +13,7 @@ import java.util.Set; import java.util.UUID; public sealed interface CheckerValidationCheckResult<T extends FieldType> extends ValidationCheckResult - permits DefaultManyValidationCheckResult, GroovyValidationCheckResult, BooleanValidationCheckResult, DateValidationCheckResult, DefaultCheckerValidationCheckResult, FloatValidationCheckResult, IntegerValidationCheckResult, ReferenceValidationCheckResult, StringValidationCheckResult { + permits BooleanValidationCheckResult, DateValidationCheckResult, DefaultCheckerValidationCheckResult, DefaultManyValidationCheckResult, FloatValidationCheckResult, GroovyValidationCheckResult, IntegerValidationCheckResult, PatternValidationCheckResult, ReferenceValidationCheckResult, StringValidationCheckResult { T value(); default DataColumnValue transform(final LineChecker lineChecker, final DataColumnValue referenceColumnRawValue, final DataColumn dataColumn, final Map<String, Map<String, Set<UUID>>> refsLinkedTo) { diff --git a/src/main/java/fr/inra/oresing/domain/data/deposit/validation/validationcheckresults/PatternValidationCheckResult.java b/src/main/java/fr/inra/oresing/domain/data/deposit/validation/validationcheckresults/PatternValidationCheckResult.java new file mode 100644 index 0000000..9296545 --- /dev/null +++ b/src/main/java/fr/inra/oresing/domain/data/deposit/validation/validationcheckresults/PatternValidationCheckResult.java @@ -0,0 +1,34 @@ +package fr.inra.oresing.domain.data.deposit.validation.validationcheckresults; + +import com.google.common.collect.ImmutableMap; +import fr.inra.oresing.ValidationLevel; +import fr.inra.oresing.domain.checker.CheckerTarget; +import fr.inra.oresing.domain.checker.type.PatternType; +import fr.inra.oresing.domain.checker.type.StringType; +import fr.inra.oresing.domain.data.deposit.context.column.Column; + +import java.util.Map; + + +public record PatternValidationCheckResult( + ValidationLevel level, + String message, + Map<String, Object> messageParams, + CheckerTarget target, + PatternType value +) implements CheckerValidationCheckResult<PatternType> { + + public static CheckerValidationCheckResult of(CheckerValidationCheckResult checkerValidationCheckResult, PatternType patternType){ + if(checkerValidationCheckResult.isError()){ + return checkerValidationCheckResult; + } + patternType.getValue().put(Column.__VALUE__, checkerValidationCheckResult.value()); + return new PatternValidationCheckResult( + checkerValidationCheckResult.level(), + checkerValidationCheckResult.message(), + checkerValidationCheckResult.messageParams(), + checkerValidationCheckResult.target(), + patternType + ); + } +} \ No newline at end of file -- GitLab