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