fix #8287 implementing support for null type status as filter value in Registration...
[cdmlib.git] / cdmlib-persistence / src / main / java / eu / etaxonomy / cdm / persistence / dao / hibernate / name / RegistrationDaoHibernateImpl.java
index 5a6723e75ff8030cd773c40e4ddcab3dd83973f9..c191eade47167232500943b2c38c0d1026ed6fd7 100644 (file)
@@ -10,9 +10,13 @@ package eu.etaxonomy.cdm.persistence.dao.hibernate.name;
 
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Optional;
+import java.util.UUID;
 
+import org.apache.commons.lang3.StringUtils;
 import org.apache.log4j.Logger;
 import org.hibernate.Query;
 import org.springframework.stereotype.Repository;
@@ -20,8 +24,11 @@ import org.springframework.stereotype.Repository;
 import eu.etaxonomy.cdm.model.name.Registration;
 import eu.etaxonomy.cdm.model.name.RegistrationStatus;
 import eu.etaxonomy.cdm.model.reference.Reference;
+import eu.etaxonomy.cdm.model.reference.ReferenceType;
 import eu.etaxonomy.cdm.persistence.dao.hibernate.common.AnnotatableDaoImpl;
 import eu.etaxonomy.cdm.persistence.dao.name.IRegistrationDao;
+import eu.etaxonomy.cdm.persistence.query.MatchMode;
+import eu.etaxonomy.cdm.persistence.query.OrderHint;
 
 /**
  * @author a.kohlbecker
@@ -113,18 +120,26 @@ public class RegistrationDaoHibernateImpl
         String where = " WHERE (1=1) ";
         String orderBy = isCount ? "" : " ORDER BY r.id ";
 
+        ReferenceType refTypeParameter = null;
+
         if (reference == null){
             //do nothing
         }else if (reference.isPresent()){
-           where += " AND ((n IS NOT NULL AND n.nomenclaturalReference =:ref)"
-                    + "     OR desig.citation =:ref "
-                    + ")";
+           from += "   LEFT JOIN n.nomenclaturalReference nomRef "
+                   + " LEFT JOIN desig.citation desigRef ";
+           where += " AND ("
+                   + "     nomRef =:ref "
+                   + "     OR (nomRef.type =:refType AND nomRef.inReference =:ref) "
+                   + "     OR desigRef =:ref "
+                   + "     OR (desigRef.type =:refType AND desigRef.inReference =:ref)"
+                   + ")";
+           refTypeParameter = ReferenceType.Section;
         }else{  //ref is null
-            where += " AND ((r.name IS NULL AND size(r.typeDesignations) = 0 ) "
-                    + "     OR (n IS NOT NULL AND r.name.nomenclaturalReference IS NULL ) "
-                    + "     OR (size(r.typeDesignations) > 0 AND desig.citation IS NULL )"
-                    + ") "
-                    ;
+           where += " AND ((r.name IS NULL AND size(r.typeDesignations) = 0 ) "
+                   + "     OR (n IS NOT NULL AND r.name.nomenclaturalReference IS NULL ) "
+                   + "     OR (size(r.typeDesignations) > 0 AND desig.citation IS NULL )"
+                   + ") "
+                   ;
         }
         boolean hasStatus = includedStatus != null && !includedStatus.isEmpty();
         if (hasStatus){
@@ -136,6 +151,9 @@ public class RegistrationDaoHibernateImpl
         if (reference != null && reference.isPresent()){
             query.setParameter("ref", reference.get());
         }
+        if(refTypeParameter != null){
+            query.setParameter("refType", refTypeParameter);
+        }
         if (hasStatus){
             query.setParameterList("status", includedStatus);
         }
@@ -143,4 +161,133 @@ public class RegistrationDaoHibernateImpl
     }
 
 
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public long count(UUID submitterUuid, Collection<RegistrationStatus> includedStatus, String identifierFilterPattern,
+            String taxonNameFilterPattern, String referenceFilterPattern, Collection<UUID> typeDesignationStatusUuids) {
+        Query query = makeFilteredSearchQuery(submitterUuid, includedStatus, identifierFilterPattern,
+                taxonNameFilterPattern, referenceFilterPattern, typeDesignationStatusUuids, true, null);
+        //Logger.getLogger("org.hibernate.SQL").setLevel(Level.DEBUG);
+        @SuppressWarnings("unchecked")
+        List<Long> list = query.list();
+        //Logger.getLogger("org.hibernate.SQL").setLevel(Level.WARN);
+        return list.isEmpty()? Long.valueOf(0) : list.get(0);
+    }
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public List<Registration> list(UUID submitterUuid, Collection<RegistrationStatus> includedStatus, String identifierFilterPattern,
+            String taxonNameFilterPattern, String referenceFilterPattern, Collection<UUID> typeDesignationStatusUuids, Integer limit, Integer start,
+            List<OrderHint> orderHints, List<String> propertyPaths) {
+
+        Query query = makeFilteredSearchQuery(submitterUuid, includedStatus, identifierFilterPattern,
+                taxonNameFilterPattern, referenceFilterPattern, typeDesignationStatusUuids, false, orderHints);
+
+        if(limit != null /*&&  !doCount*/) {
+            query.setMaxResults(limit);
+            if(start != null) {
+                query.setFirstResult(start);
+            }
+        }
+
+        //Logger.getLogger("org.hibernate.SQL").setLevel(Level.DEBUG);
+        @SuppressWarnings("unchecked")
+        List<Registration> results = query.list();
+        //Logger.getLogger("org.hibernate.SQL").setLevel(Level.WARN);
+        defaultBeanInitializer.initializeAll(results, propertyPaths);
+
+        return results;
+    }
+
+
+    /**
+     * @param submitterUuid
+     * @param includedStatus
+     * @param identifierFilterPattern
+     * @param taxonNameFilterPattern
+     * @param typeDesignationStatusUuids
+     * @param isCount
+     * @return
+     */
+    private Query makeFilteredSearchQuery(UUID submitterUuid, Collection<RegistrationStatus> includedStatus,
+            String identifierFilterPattern, String taxonNameFilterPattern, String referenceFilterPattern,
+            Collection<UUID> typeDesignationStatusUuids, boolean isCount, List<OrderHint> orderHints) {
+
+        Map<String, Object> parameters = new HashMap<>();
+
+        boolean doNameFilter = StringUtils.isNoneBlank(taxonNameFilterPattern);
+        boolean doReferenceFilter = StringUtils.isNoneBlank(referenceFilterPattern);
+        boolean doTypeStatusFilter = typeDesignationStatusUuids != null && typeDesignationStatusUuids.size() > 0;
+
+        String select = "SELECT " + (isCount? " count(DISTINCT r) as cn ": "DISTINCT r ");
+        String from = " FROM Registration r "
+                + "     LEFT JOIN r.typeDesignations desig "
+                + "     LEFT JOIN r.name n "
+                + (doNameFilter ?  " LEFT JOIN desig.typifiedNames typifiedNames ":"")
+                + (doTypeStatusFilter ? " LEFT JOIN desig.typeStatus typeStatus":"")  // without this join hibernate would make a cross join here
+                + (doReferenceFilter ? " LEFT JOIN desig.citation typeDesignationCitation LEFT JOIN n.nomenclaturalReference nomRef":"")
+            ;
+        // further JOIN
+        String where = " WHERE (1=1) ";
+        String orderBy = "";
+        if(!isCount){
+            orderBy = orderByClause("r", orderHints).toString();
+        }
+
+        if(submitterUuid != null){
+            from += " LEFT JOIN r.submitter submitter "; // without this join hibernate would make a cross join here
+            where += " AND submitter.uuid =:submitterUuid";
+            parameters.put("submitterUuid", submitterUuid);
+        }
+        if(includedStatus != null && includedStatus.size() > 0) {
+            where += " AND r.status in (:includedStatus)";
+            parameters.put("includedStatus", includedStatus);
+        }
+        if(StringUtils.isNoneBlank(identifierFilterPattern)){
+            where += " AND r.identifier LIKE :identifierFilterPattern";
+            parameters.put("identifierFilterPattern", MatchMode.ANYWHERE.queryStringFrom(identifierFilterPattern));
+        }
+        if(doNameFilter){
+            where += " AND (r.name.titleCache LIKE :taxonNameFilterPattern OR typifiedNames.titleCache LIKE :taxonNameFilterPattern)";
+            parameters.put("taxonNameFilterPattern", MatchMode.ANYWHERE.queryStringFrom(taxonNameFilterPattern));
+        }
+        if(doReferenceFilter){
+            where += " AND (typeDesignationCitation.titleCache LIKE :referenceFilterPattern OR nomRef.titleCache LIKE :referenceFilterPattern)";
+            parameters.put("referenceFilterPattern", MatchMode.ANYWHERE.queryStringFrom(referenceFilterPattern));
+        }
+        if(doTypeStatusFilter){
+            boolean addNullFilter = false;
+            while(typeDesignationStatusUuids.contains(null)){
+                addNullFilter = true;
+                typeDesignationStatusUuids.remove(null);
+            }
+            String typeStatusWhere = "";
+            if(!typeDesignationStatusUuids.isEmpty()){
+                typeStatusWhere += " typeStatus.uuid in (:typeDesignationStatusUuids)";
+                parameters.put("typeDesignationStatusUuids", typeDesignationStatusUuids);
+            }
+            if(addNullFilter){
+                typeStatusWhere += (!typeStatusWhere.isEmpty() ? " OR ":"") + "typeStatus is null";
+            }
+            where += " AND ( " +  typeStatusWhere + ")";
+        }
+        String hql = select + from + where + orderBy;
+        Query query = getSession().createQuery(hql);
+
+        for(String paramName : parameters.keySet()){
+            Object value = parameters.get(paramName);
+            if(value instanceof Collection){
+                query.setParameterList(paramName, (Collection)value);
+            } else {
+                query.setParameter(paramName, value);
+            }
+        }
+
+        return query;
+    }
+
+
 }