Project

General

Profile

Revision e0dcd1d7

IDe0dcd1d7c191495e40cce572f5ed98bf01b201e1
Parent 240bf2da
Child c696d82c

Added by Andreas Kohlbecker over 2 years ago

ref #7590 implementing AND and OR operator for restrictions and harmonizing code

View differences:

cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/dao/common/Restriction.java
23 23
 */
24 24
public class Restriction<T extends Object> {
25 25

  
26
    public enum Operator {
27
        AND,
28
        OR;
29
    }
30

  
26 31
    private String propertyName;
27 32

  
28 33
    private MatchMode matchMode;
29 34

  
30 35
    private boolean not = false;
31 36

  
37
    private Operator operator = Operator.AND;
38

  
32 39
    private List<T> values = null;
33 40

  
34 41
    /**
......
39 46
        this(propertyName, false, matchMode, values);
40 47
    }
41 48

  
42
    public Restriction(String propertyName, boolean not , MatchMode matchMode, T ... values ) {
49
    public Restriction(String propertyName, boolean not, MatchMode matchMode, T ... values ) {
50
        this(propertyName, false, Operator.AND, matchMode, values);
51
    }
52

  
53
    public Restriction(String propertyName, boolean not, Operator operator, MatchMode matchMode, T ... values ) {
43 54
        this.propertyName = propertyName;
44 55
        this.not = not;
56
        this.operator = operator;
45 57
        if(values.length > 0){
46 58
            this.setValues(Arrays.asList(values));
47 59
            if(values[0] != null && values[0] instanceof String){
......
118 130
        this.not = not;
119 131
    }
120 132

  
133
    /**
134
     * @return the operator
135
     */
136
    public Operator getOperator() {
137
        return operator;
138
    }
139

  
140
    /**
141
     * @param operator the operator to set
142
     */
143
    public void setOperator(Operator operator) {
144
        this.operator = operator;
145
    }
121 146

  
122 147
}
cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/dao/hibernate/common/CdmEntityDaoBase.java
32 32
import org.hibernate.criterion.DetachedCriteria;
33 33
import org.hibernate.criterion.Example;
34 34
import org.hibernate.criterion.Example.PropertySelector;
35
import org.hibernate.criterion.LogicalExpression;
35 36
import org.hibernate.criterion.Order;
36 37
import org.hibernate.criterion.ProjectionList;
37 38
import org.hibernate.criterion.Projections;
......
59 60
import eu.etaxonomy.cdm.model.view.AuditEvent;
60 61
import eu.etaxonomy.cdm.persistence.dao.common.ICdmEntityDao;
61 62
import eu.etaxonomy.cdm.persistence.dao.common.Restriction;
63
import eu.etaxonomy.cdm.persistence.dao.common.Restriction.Operator;
62 64
import eu.etaxonomy.cdm.persistence.dao.initializer.IBeanInitializer;
63 65
import eu.etaxonomy.cdm.persistence.dto.MergeResult;
64 66
import eu.etaxonomy.cdm.persistence.hibernate.PostMergeEntityListener;
......
519 521
            return ;
520 522
        }
521 523

  
522
        List<Criterion> perProperty = new ArrayList<>(restrictions.size());
524
        List<CriterionWithOperator> perProperty = new ArrayList<>(restrictions.size());
523 525
        Map<String, String> aliases = new HashMap<>();
524 526

  
525 527
        for(Restriction<?> restriction : restrictions){
......
569 571
                        logger.debug("addRestrictions() predicate with " + propertyName + " " + (restriction.getMatchMode() == null ? "=" : restriction.getMatchMode().name()) + " " + v.toString());
570 572
                    }
571 573
                }
572
                perProperty.add(Restrictions.or(predicates));
573
            }
574
        }
574
                perProperty.add(new CriterionWithOperator(restriction.getOperator(), Restrictions.or(predicates)));
575
            } // check has values
576
        } // loop over restrictions
575 577

  
578
        Restriction.Operator firstOperator = null;
576 579
        if(!perProperty.isEmpty()){
577
            criteria.add(Restrictions.and(perProperty.toArray(new Criterion[perProperty.size()])));
580
            LogicalExpression logicalExpression = null;
581
            for(CriterionWithOperator cwo : perProperty){
582
                if(logicalExpression == null){
583
                    firstOperator = cwo.operator;
584
                    logicalExpression = Restrictions.and(Restrictions.sqlRestriction("1=1"), cwo.criterion);
585
                } else {
586
                    switch(cwo.operator){
587
                        case AND:
588
                            logicalExpression = Restrictions.and(logicalExpression, cwo.criterion);
589
                            break;
590
                        case OR:
591
                            logicalExpression = Restrictions.or(logicalExpression, cwo.criterion);
592
                            break;
593
                        default:
594
                            throw new RuntimeException("Unsupported Operator");
595
                    }
596
                }
597

  
598
            }
599

  
600

  
601
            criteria.add(logicalExpression);
602
//            if(firstOperator == Operator.OR){
603
//                // OR
604
//            } else {
605
//                // AND
606
//                criteria.add(Restrictions.and(queryStringCriterion, logicalExpression));
607
//            }
578 608
        }
579 609
        if(logger.isDebugEnabled()){
580 610
            logger.debug("addRestrictions() final criteria: " + criteria.toString());
......
1061 1091
     * @return
1062 1092
     */
1063 1093
    protected Criteria createCriteria(Class<? extends T> type, List<Restriction<?>> restrictions, boolean doCount) {
1064
        Criteria criteria = criterionForType(type);
1065

  
1066
        if(restrictions != null  && !restrictions.isEmpty()){
1067
            DetachedCriteria idsOnlyCriteria = DetachedCriteria.forClass(entityType(type));
1068
            addRestrictions(restrictions, idsOnlyCriteria);
1069
            criteria.add(Subqueries.propertyIn("id", idsOnlyCriteria));
1070

  
1071
            if(doCount){
1072
                criteria.setProjection(Projections.rowCount());
1073
            } else {
1074
                idsOnlyCriteria.setProjection(Projections.distinct(Projections.property("id")));
1075
            }
1076
        }
1077
        return criteria;
1078
    }
1079

  
1080
    /**
1081
     * @param clazz
1082
     * @param param
1083
     * @param queryString
1084
     * @param matchmode
1085
     * @param restrictions
1086
     * @return
1087
     */
1088
    protected Criteria createCriteria(Class<? extends T> clazz, String param, String queryString, MatchMode matchmode,
1089
            List<Restriction<?>> restrictions, boolean doCount) {
1090 1094

  
1091
        DetachedCriteria idsOnlyCriteria = DetachedCriteria.forClass(entityType(clazz));
1095
        DetachedCriteria idsOnlyCriteria = DetachedCriteria.forClass(entityType(type));
1092 1096
        idsOnlyCriteria.setProjection(Projections.distinct(Projections.id()));
1093 1097

  
1098
        //if(restrictions != null  && !restrictions.isEmpty()){
1099
            addRestrictions(restrictions, idsOnlyCriteria);
1094 1100

  
1095
        if (queryString != null) {
1096
            if (matchmode == null) {
1097
                idsOnlyCriteria.add(Restrictions.ilike(param, queryString));
1098
            } else if (matchmode == MatchMode.BEGINNING) {
1099
                idsOnlyCriteria.add(Restrictions.ilike(param, queryString, org.hibernate.criterion.MatchMode.START));
1100
            } else if (matchmode == MatchMode.END) {
1101
                idsOnlyCriteria.add(Restrictions.ilike(param, queryString, org.hibernate.criterion.MatchMode.END));
1102
            } else if (matchmode == MatchMode.EXACT) {
1103
                idsOnlyCriteria.add(Restrictions.ilike(param, queryString, org.hibernate.criterion.MatchMode.EXACT));
1104
            } else {
1105
                idsOnlyCriteria.add(Restrictions.ilike(param, queryString, org.hibernate.criterion.MatchMode.ANYWHERE));
1106
            }
1107
        }
1108

  
1109
        addRestrictions(restrictions, idsOnlyCriteria);
1110

  
1111
        Criteria criteria = criterionForType(clazz);
1112
        criteria.add(Subqueries.propertyIn("id", idsOnlyCriteria));
1113

  
1101
            Criteria criteria = criterionForType(type);
1102
            criteria.add(Subqueries.propertyIn("id", idsOnlyCriteria));
1103
        //}
1114 1104
        if(doCount){
1115 1105
            criteria.setProjection(Projections.rowCount());
1116 1106
        } else {
1117 1107
            idsOnlyCriteria.setProjection(Projections.distinct(Projections.property("id")));
1118 1108
        }
1119

  
1120 1109
        return criteria;
1121 1110
    }
1122 1111

  
1123 1112

  
1124

  
1125 1113
    @Override
1126 1114
    public List<T> findByParamWithRestrictions(Class<? extends T> clazz, String param, String queryString,
1127 1115
            MatchMode matchmode, List<Restriction<?>> restrictions, Integer pageSize, Integer pageNumber,
1128 1116
            List<OrderHint> orderHints, List<String> propertyPaths) {
1129 1117

  
1130
        Criteria criteria = createCriteria(clazz, param, queryString, matchmode, restrictions, false);
1118
        List<Restriction<?>> allRestrictions = new ArrayList<>();
1119
        allRestrictions.add(new Restriction<String>(param, matchmode, queryString));
1120
        if(restrictions != null){
1121
            allRestrictions.addAll(restrictions);
1122
        }
1123
        Criteria criteria = createCriteria(clazz, allRestrictions, false);
1131 1124

  
1132 1125
        if (pageSize != null) {
1133 1126
            criteria.setMaxResults(pageSize);
......
1151 1144
    public long countByParamWithRestrictions(Class<? extends T> clazz, String param, String queryString,
1152 1145
            MatchMode matchmode, List<Restriction<?>> restrictions) {
1153 1146

  
1154
        Criteria criteria = createCriteria(clazz, param, queryString, matchmode, restrictions, true);
1147
        List<Restriction<?>> allRestrictions = new ArrayList<>();
1148
        allRestrictions.add(new Restriction<String>(param, matchmode, queryString));
1149
        if(restrictions != null){
1150
            allRestrictions.addAll(restrictions);
1151
        }
1152
        Criteria criteria = createCriteria(clazz, allRestrictions, true);
1155 1153

  
1156 1154
        return (Long) criteria.uniqueResult();
1157 1155
    }
......
1195 1193

  
1196 1194
    }
1197 1195

  
1196
    private class CriterionWithOperator {
1197

  
1198
        Restriction.Operator operator;
1199
        Criterion criterion;
1200

  
1201

  
1202
        public CriterionWithOperator(Operator operator, Criterion criterion) {
1203
            super();
1204
            this.operator = operator;
1205
            this.criterion = criterion;
1206
        }
1207

  
1208

  
1209
    }
1210

  
1198 1211
    /**
1199 1212
     * Returns a Criteria for the given {@link Class class} or, if
1200 1213
     * <code>null</code>, for the base {@link Class class} of this DAO.
cdmlib-services/src/test/java/eu/etaxonomy/cdm/api/service/NameServiceImplTest.java
885 885

  
886 886
    @Test
887 887
    @DataSet
888
    public void testFindByTitle(){
888
    public void findByTitleWithRestrictions(){
889 889

  
890
        // The following typedesigbnations per name are assumed:
890
        // The following typeDesignations per name are assumed:
891 891
        // Name1 -> SpecimenTypeDesignation -> Specimen1
892 892
        //       -> SpecimenTypeDesignation -> Specimen2
893 893
        // Name2 -> SpecimenTypeDesignation -> Specimen2
894 894

  
895
        // Logger.getLogger("org.hibernate.SQL").setLevel(Level.TRACE);
896

  
895 897

  
896 898
        List<Restriction<?>> restrictions;
897 899
        Pager<TaxonName> result;
......
926 928
        result = nameService.findByTitleWithRestrictions(null, "Name2", MatchMode.EXACT, restrictions, null, null, null, null);
927 929
        assertEquals(0l, result.getCount().longValue());
928 930

  
931
        restrictions = Arrays.asList(new Restriction<String>("typeDesignations.typeSpecimen.titleCache", false, Restriction.Operator.OR, MatchMode.EXACT, "Specimen1"));
932
        result = nameService.findByTitleWithRestrictions(null, "Name2", MatchMode.EXACT, restrictions, null, null, null, null);
933
        assertEquals(2l, result.getCount().longValue());
934

  
929 935
        restrictions = Arrays.asList(new Restriction<String>("typeDesignations.typeSpecimen.titleCache", MatchMode.BEGINNING, "Specimen"));
930 936
        result = nameService.findByTitleWithRestrictions(null, "Name1", MatchMode.EXACT, restrictions, null, null, null, null);
931 937
        assertEquals("names with multiple matching typeSpecimens must be deduplicated", 1l, result.getCount().longValue());
......
939 945

  
940 946
    @Test
941 947
    @DataSet
942
    public void testFindByTitleMultiValue(){
948
    public void testFindByTitleTitleWithRestrictionsMultiValue(){
943 949

  
944 950
        // The following typedesigbnations per name are assumed:
945 951
        // Name1 -> SpecimenTypeDesignation -> Specimen1

Also available in: Unified diff

Add picture from clipboard (Maximum size: 40 MB)