From f0066e059ee154eb47f558effad940c93bff1e2f Mon Sep 17 00:00:00 2001
From: Hicham Barhoumi <hicham.barhoumi@archiveco.fr>
Date: Tue, 28 Jul 2020 12:06:22 +0200
Subject: [PATCH] [FENIX-66] add elemMatch support for criteria

---
 .../commons/api/domain/CriterionOperator.java |  3 +-
 .../commons/mongo/utils/MongoUtils.java       | 38 +++++++++++++++++++
 2 files changed, 40 insertions(+), 1 deletion(-)

diff --git a/commons/commons-api/src/main/java/fr/gouv/vitamui/commons/api/domain/CriterionOperator.java b/commons/commons-api/src/main/java/fr/gouv/vitamui/commons/api/domain/CriterionOperator.java
index dade63f3..0afca983 100644
--- a/commons/commons-api/src/main/java/fr/gouv/vitamui/commons/api/domain/CriterionOperator.java
+++ b/commons/commons-api/src/main/java/fr/gouv/vitamui/commons/api/domain/CriterionOperator.java
@@ -49,5 +49,6 @@ public enum CriterionOperator {
     CONTAINS,
     CONTAINSIGNORECASE,
     BETWEEN,
-    STARTWITH;
+    STARTWITH,
+    ELEMMATCH
 }
diff --git a/commons/commons-mongo/src/main/java/fr/gouv/vitamui/commons/mongo/utils/MongoUtils.java b/commons/commons-mongo/src/main/java/fr/gouv/vitamui/commons/mongo/utils/MongoUtils.java
index 4b6f344e..740963ba 100644
--- a/commons/commons-mongo/src/main/java/fr/gouv/vitamui/commons/mongo/utils/MongoUtils.java
+++ b/commons/commons-mongo/src/main/java/fr/gouv/vitamui/commons/mongo/utils/MongoUtils.java
@@ -39,6 +39,7 @@ package fr.gouv.vitamui.commons.mongo.utils;
 import java.lang.reflect.Type;
 import java.time.Duration;
 import java.time.OffsetDateTime;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
@@ -46,6 +47,9 @@ import java.util.Optional;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 
+import fr.gouv.vitamui.commons.api.domain.QueryDto;
+import fr.gouv.vitamui.commons.api.domain.QueryOperator;
+import fr.gouv.vitamui.commons.utils.JsonUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.data.mongodb.core.query.Criteria;
 import org.springframework.data.mongodb.core.query.CriteriaDefinition;
@@ -185,6 +189,8 @@ public final class MongoUtils {
                 mapValue.put(BETWEEN_OPERATOR_KEY_START, convertValue(parametrizedClazz, mapValue.get(BETWEEN_OPERATOR_KEY_START)));
                 mapValue.put(BETWEEN_OPEARTOR_KEY_END, convertValue(parametrizedClazz, mapValue.get(BETWEEN_OPEARTOR_KEY_END)));
                 return mapValue;
+            case ELEMMATCH:
+                return convertValue(QueryDto.class, value);
             default :
                 return convertValue(parametrizedClazz, value);
         }
@@ -209,6 +215,14 @@ public final class MongoUtils {
             return Boolean.parseBoolean(value.toString());
         } else if (VitamUIUtils.canBeCastByClass(value, List.class)) {
             return value;
+        } else if (clazz.equals(QueryDto.class)) {
+            try {
+                // we convert the linked hash map to json to re-convert it properly to query dto
+                return QueryDto.fromJson(JsonUtils.toJson(value));
+            }
+            catch (Exception e) {
+                throw new InvalidFormatException(e.getMessage(), e);
+            }
         }
 
         return CastUtils.castValue(value, clazz);
@@ -275,12 +289,36 @@ public final class MongoUtils {
                 final Criteria endCriteria = Criteria.where(key).lte(mapVal.get(BETWEEN_OPEARTOR_KEY_END));
                 criteria = buildAndOperator(startCriteria, endCriteria);
                 break;
+            case ELEMMATCH :
+                criteria = Criteria.where(key).elemMatch(queryDTOToCriterion((QueryDto)val));
+                break;
             default :
                 throw new IllegalArgumentException("Operator " + operator + " is not supported");
         }
         return criteria;
     }
 
+    public static Criteria queryDTOToCriterion(QueryDto queryDto) {
+        Collection<CriteriaDefinition> criteria = new ArrayList<>();
+        queryDto.getCriterionList().forEach(criterion -> {
+            criteria.add(MongoUtils.getCriteria(criterion.getKey(), criterion.getValue(), criterion.getOperator()));
+        });
+
+        // if the criteria contains subQueries, a recursive call is made for each subQuery
+        queryDto.getSubQueries().forEach(queryDtoItem -> {
+            criteria.add(queryDTOToCriterion(queryDtoItem));
+        });
+
+        final Criteria commonCustomCriteria = new Criteria();
+        if (queryDto.getQueryOperator() == QueryOperator.AND) {
+            commonCustomCriteria.andOperator(criteria.stream().map(c -> (Criteria) c).toArray(Criteria[]::new));
+        } else if (queryDto.getQueryOperator() == QueryOperator.OR) {
+            commonCustomCriteria.orOperator(criteria.stream().map(c -> (Criteria) c).toArray(Criteria[]::new));
+        }
+        return commonCustomCriteria;
+    }
+
+
     public static Type getTypeOfField(final Class<?> entityClass, final String fieldName) {
         try {
             return ReflectionUtils.getTypeOfField(entityClass, fieldName);
-- 
GitLab