• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

openmrs / openmrs-core / 26783948908

01 Jun 2026 09:39PM UTC coverage: 65.695% (+0.03%) from 65.663%
26783948908

push

github

chibongho
TRUNK-6633 Add a way to search Concepts by ConceptSearchCriteria

136 of 158 new or added lines in 4 files covered. (86.08%)

6 existing lines in 4 files now uncovered.

24083 of 36659 relevant lines covered (65.69%)

0.66 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.32
/api/src/main/java/org/openmrs/api/db/hibernate/HibernateConceptDAO.java
1
/**
2
 * This Source Code Form is subject to the terms of the Mozilla Public License,
3
 * v. 2.0. If a copy of the MPL was not distributed with this file, You can
4
 * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under
5
 * the terms of the Healthcare Disclaimer located at http://openmrs.org/license.
6
 *
7
 * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS
8
 * graphic logo is a trademark of OpenMRS Inc.
9
 */
10
package org.openmrs.api.db.hibernate;
11

12
import static java.util.stream.Collectors.toList;
13

14
import javax.persistence.Query;
15
import javax.persistence.TypedQuery;
16
import javax.persistence.criteria.CriteriaBuilder;
17
import javax.persistence.criteria.CriteriaQuery;
18
import javax.persistence.criteria.Join;
19
import javax.persistence.criteria.Predicate;
20
import javax.persistence.criteria.Root;
21
import java.util.ArrayList;
22
import java.util.Arrays;
23
import java.util.Collection;
24
import java.util.Collections;
25
import java.util.HashMap;
26
import java.util.HashSet;
27
import java.util.Iterator;
28
import java.util.LinkedHashSet;
29
import java.util.List;
30
import java.util.Locale;
31
import java.util.Map;
32
import java.util.Optional;
33
import java.util.Set;
34

35
import javax.persistence.criteria.Subquery;
36

37
import org.apache.commons.lang3.StringUtils;
38
import org.hibernate.FlushMode;
39
import org.hibernate.Session;
40
import org.hibernate.SessionFactory;
41
import org.hibernate.search.engine.search.predicate.SearchPredicate;
42
import org.hibernate.search.engine.search.predicate.dsl.BooleanPredicateClausesStep;
43
import org.hibernate.search.engine.search.predicate.dsl.SearchPredicateFactory;
44
import org.hibernate.search.engine.search.query.SearchQuery;
45
import org.hibernate.search.mapper.orm.scope.SearchScope;
46
import org.hibernate.search.mapper.orm.session.SearchSession;
47
import org.openmrs.Concept;
48
import org.openmrs.ConceptAnswer;
49
import org.openmrs.ConceptAttribute;
50
import org.openmrs.ConceptAttributeType;
51
import org.openmrs.ConceptClass;
52
import org.openmrs.ConceptComplex;
53
import org.openmrs.ConceptDatatype;
54
import org.openmrs.ConceptDescription;
55
import org.openmrs.ConceptMap;
56
import org.openmrs.ConceptMapType;
57
import org.openmrs.ConceptName;
58
import org.openmrs.ConceptNameTag;
59
import org.openmrs.ConceptNumeric;
60
import org.openmrs.ConceptProposal;
61
import org.openmrs.ConceptReferenceRange;
62
import org.openmrs.ConceptReferenceTerm;
63
import org.openmrs.ConceptReferenceTermMap;
64
import org.openmrs.ConceptSearchResult;
65
import org.openmrs.ConceptSet;
66
import org.openmrs.ConceptSource;
67
import org.openmrs.ConceptStopWord;
68
import org.openmrs.Drug;
69
import org.openmrs.DrugIngredient;
70
import org.openmrs.DrugReferenceMap;
71
import org.openmrs.api.APIException;
72
import org.openmrs.api.ConceptService;
73
import org.openmrs.api.context.Context;
74
import org.openmrs.api.db.ConceptDAO;
75
import org.openmrs.api.db.DAOException;
76
import org.openmrs.api.db.hibernate.search.SearchQueryUnique;
77
import org.openmrs.api.db.hibernate.search.session.SearchSessionFactory;
78
import org.openmrs.parameter.ConceptSearchCriteria;
79
import org.openmrs.util.ConceptMapTypeComparator;
80
import org.openmrs.util.OpenmrsConstants;
81
import org.slf4j.Logger;
82
import org.slf4j.LoggerFactory;
83
import org.springframework.util.CollectionUtils;
84

85
/**
86
 * The Hibernate class for Concepts, Drugs, and related classes. <br>
87
 * <br>
88
 * Use the {@link ConceptService} to access these methods
89
 * 
90
 * @see ConceptService
91
 */
92
public class HibernateConceptDAO implements ConceptDAO {
1✔
93
        
94
        private static final Logger log = LoggerFactory.getLogger(HibernateConceptDAO.class);
1✔
95

96
        private static final String CONCEPT_REFERENCE_TERM = "conceptReferenceTerm";
97

98
        private static final String CONCEPT_SOURCE = "conceptSource";
99

100
        private static final String HL7_CODE = "hl7Code";
101

102
        private SessionFactory sessionFactory;
103

104
        private SearchSessionFactory searchSessionFactory;
105

106
        /**
107
         * Sets the session factory
108
         *
109
         * @param sessionFactory
110
         */
111
        public void setSessionFactory(SessionFactory sessionFactory) {
112
                this.sessionFactory = sessionFactory;
1✔
113
        }
1✔
114

115
        /**
116
         * Sets the search session factory
117
         * 
118
         * @param searchSessionFactory
119
         */
120
        public void setSearchSessionFactory(SearchSessionFactory searchSessionFactory) {
121
                this.searchSessionFactory = searchSessionFactory;
1✔
122
        }
1✔
123

124
        /**
125
         * @see org.openmrs.api.db.ConceptDAO#getConceptComplex(java.lang.Integer)
126
         */
127
        @Override
128
        public ConceptComplex getConceptComplex(Integer conceptId) {
129
                ConceptComplex cc;
130
                Session session = sessionFactory.getCurrentSession();
1✔
131
                Object obj = session.get(ConceptComplex.class, conceptId);
1✔
132
                // If Concept has already been read & cached, we may get back a Concept instead of
133
                // ConceptComplex.  If this happens, we need to clear the object from the cache
134
                // and re-fetch it as a ConceptComplex
135
                if (obj != null && !obj.getClass().equals(ConceptComplex.class)) {
1✔
136
                        // remove from cache
137
                        session.detach(obj);
×
138

139
                        // session.get() did not work here, we need to perform a query to get a ConceptComplex
140
                        CriteriaBuilder cb = session.getCriteriaBuilder();
×
141
                        CriteriaQuery<ConceptComplex> cq = cb.createQuery(ConceptComplex.class);
×
142
                        Root<ConceptComplex> root = cq.from(ConceptComplex.class);
×
143

144
                        cq.where(cb.equal(root.get("conceptId"), conceptId));
×
145

146
                        obj = session.createQuery(cq).uniqueResult();
×
147
                }
148
                cc = (ConceptComplex) obj;
1✔
149

150
                return cc;
1✔
151
        }
152
        
153
        /**
154
         * @see org.openmrs.api.db.ConceptDAO#saveConcept(org.openmrs.Concept)
155
         */
156
        @Override
157
        public Concept saveConcept(Concept concept) throws DAOException {
158
                if ((concept.getConceptId() != null) && (concept.getConceptId() > 0)) {
1✔
159
                        // this method checks the concept_numeric, concept_derived, etc tables
160
                        // to see if a row exists there or not.  This is needed because hibernate
161
                        // doesn't like to insert into concept_numeric but update concept in the
162
                        // same go.  It assumes that its either in both tables or no tables
163
                        insertRowIntoSubclassIfNecessary(concept);
1✔
164
                }
165
                
166
                sessionFactory.getCurrentSession().saveOrUpdate(concept);
1✔
167
                return concept;
1✔
168
        }
169
        
170
        /**
171
         * Convenience method that will check this concept for subtype values (ConceptNumeric,
172
         * ConceptDerived, etc) and insert a line into that subtable if needed. This prevents a
173
         * hibernate ConstraintViolationException
174
         * 
175
         * @param concept the concept that will be inserted
176
         */
177
        private void insertRowIntoSubclassIfNecessary(Concept concept) {
178
                
179
                // check the concept_numeric table
180
                if (concept instanceof ConceptNumeric) {
1✔
181
                        
182
                        String select = "SELECT 1 from concept_numeric WHERE concept_id = :conceptId";
1✔
183
                        Query query = sessionFactory.getCurrentSession().createSQLQuery(select);
1✔
184
                        query.setParameter("conceptId", concept.getConceptId());
1✔
185
                        
186
                        // Converting to concept numeric:  A single concept row exists, but concept numeric has not been populated yet.
187
                        if (JpaUtils.getSingleResultOrNull(query) == null) {
1✔
188
                                // we have to evict the current concept out of the session because
189
                                // the user probably had to change the class of this object to get it
190
                                // to now be a numeric
191
                                // (must be done before the "insert into...")
192
                                sessionFactory.getCurrentSession().clear();
1✔
193
                                
194
                                //Just in case this was changed from concept_complex to numeric
195
                                //We need to add a delete line for each concept sub class that is not concept_numeric
196
                                deleteSubclassConcept("concept_complex", concept.getConceptId());
1✔
197
                                
198
                                String insert = "INSERT INTO concept_numeric (concept_id, allow_decimal) VALUES (:conceptId, false)";
1✔
199
                                query = sessionFactory.getCurrentSession().createSQLQuery(insert);
1✔
200
                                query.setParameter("conceptId", concept.getConceptId());
1✔
201
                                query.executeUpdate();
1✔
202
                                
203
                        } else {
1✔
204
                                // Converting from concept numeric:  The concept and concept numeric rows both exist, so we need to delete concept_numeric.
205
                                
206
                                // concept is changed from numeric to something else
207
                                // hence row should be deleted from the concept_numeric
208
                                if (!concept.isNumeric()) {
1✔
209
                                        deleteSubclassConcept("concept_numeric", concept.getConceptId());
1✔
210
                                }
211
                        }
212
                }
1✔
213
                // check the concept complex table
214
                else if (concept instanceof ConceptComplex) {
1✔
215
                        
216
                        String select = "SELECT 1 FROM concept_complex WHERE concept_id = :conceptId";
1✔
217
                        Query query = sessionFactory.getCurrentSession().createSQLQuery(select);
1✔
218
                        query.setParameter("conceptId", concept.getConceptId());
1✔
219
                        
220
                        // Converting to concept complex:  A single concept row exists, but concept complex has not been populated yet.
221
                        if (JpaUtils.getSingleResultOrNull(query) == null) {
1✔
222
                                // we have to evict the current concept out of the session because
223
                                // the user probably had to change the class of this object to get it
224
                                // to now be a ConceptComplex
225
                                // (must be done before the "insert into...")
226
                                sessionFactory.getCurrentSession().clear();
1✔
227
                                
228
                                //Just in case this was changed from concept_numeric to complex
229
                                //We need to add a delete line for each concept sub class that is not concept_complex
230
                                deleteSubclassConcept("concept_numeric", concept.getConceptId());
1✔
231
                                
232
                                // Add an empty row into the concept_complex table
233
                                String insert = "INSERT INTO concept_complex (concept_id) VALUES (:conceptId)";
1✔
234
                                query = sessionFactory.getCurrentSession().createSQLQuery(insert);
1✔
235
                                query.setParameter("conceptId", concept.getConceptId());
1✔
236
                                query.executeUpdate();
1✔
237
                                
238
                        } else {
1✔
239
                                // Converting from concept complex:  The concept and concept complex rows both exist, so we need to delete the concept_complex row.
240
                                // no stub insert is needed because either a concept row doesn't exist OR a concept_complex row does exist
241
                                
242
                                // concept is changed from complex to something else
243
                                // hence row should be deleted from the concept_complex
244
                                if (!concept.isComplex()) {
×
245
                                        deleteSubclassConcept("concept_complex", concept.getConceptId());
×
246
                                }
247
                        }
248
                }
249
        }
1✔
250
        
251
        /**
252
         * Deletes a concept from a sub class table
253
         * 
254
         * @param tableName the sub class table name
255
         * @param conceptId the concept id
256
         */
257
        private void deleteSubclassConcept(String tableName, Integer conceptId) {
258
                String delete = "DELETE FROM " + tableName + " WHERE concept_id = :conceptId";
1✔
259
                Query query = sessionFactory.getCurrentSession().createSQLQuery(delete);
1✔
260
                query.setParameter("conceptId", conceptId);
1✔
261
                query.executeUpdate();
1✔
262
        }
1✔
263
        
264
        /**
265
         * @see org.openmrs.api.db.ConceptDAO#purgeConcept(org.openmrs.Concept)
266
         */
267
        @Override
268
        public void purgeConcept(Concept concept) throws DAOException {
269
                sessionFactory.getCurrentSession().delete(concept);
1✔
270
        }
1✔
271
        
272
        /**
273
         * @see org.openmrs.api.db.ConceptDAO#getConcept(java.lang.Integer)
274
         */
275
        @Override
276
        public Concept getConcept(Integer conceptId) throws DAOException {
277
                return sessionFactory.getCurrentSession().get(Concept.class, conceptId);
1✔
278
        }
279
        
280
        /**
281
         * @see org.openmrs.api.db.ConceptDAO#getConceptName(java.lang.Integer)
282
         */
283
        @Override
284
        public ConceptName getConceptName(Integer conceptNameId) throws DAOException {
285
                return sessionFactory.getCurrentSession().get(ConceptName.class, conceptNameId);
1✔
286
        }
287
        
288
        /**
289
         * @see org.openmrs.api.db.ConceptDAO#getConceptAnswer(java.lang.Integer)
290
         */
291
        @Override
292
        public ConceptAnswer getConceptAnswer(Integer conceptAnswerId) throws DAOException {
293
                return sessionFactory.getCurrentSession().get(ConceptAnswer.class, conceptAnswerId);
1✔
294
        }
295
        
296
        /**
297
         * @see org.openmrs.api.db.ConceptDAO#getAllConcepts(java.lang.String, boolean, boolean)
298
         */
299
        @Override
300
        @SuppressWarnings("unchecked")
301
        public List<Concept> getAllConcepts(String sortBy, boolean asc, boolean includeRetired) throws DAOException {
302
                
303
                boolean isNameField = false;
1✔
304
                
305
                try {
306
                        Concept.class.getDeclaredField(sortBy);
1✔
307
                }
308
                catch (NoSuchFieldException e) {
1✔
309
                        try {
310
                                ConceptName.class.getDeclaredField(sortBy);
1✔
311
                                isNameField = true;
1✔
312
                        }
313
                        catch (NoSuchFieldException e2) {
×
314
                                sortBy = "conceptId";
×
315
                        }
1✔
316
                }
1✔
317
                
318
                String hql = "";
1✔
319
                if (isNameField) {
1✔
320
                        hql += "select concept";
1✔
321
                }
322
                
323
                hql += " from Concept as concept";
1✔
324
                boolean hasWhereClause = false;
1✔
325
                if (isNameField) {
1✔
326
                        hasWhereClause = true;
1✔
327
                        //This assumes every concept has a unique(avoid duplicates) fully specified name
328
                        //which should be true for a clean concept dictionary
329
                        hql += " left join concept.names as names where names.conceptNameType = 'FULLY_SPECIFIED'";
1✔
330
                }
331
                
332
                if (!includeRetired) {
1✔
333
                        if (hasWhereClause) {
1✔
334
                                hql += " and";
1✔
335
                        } else {
336
                                hql += " where";
1✔
337
                        }
338
                        hql += " concept.retired = false";
1✔
339
                        
340
                }
341
                
342
                if (isNameField) {
1✔
343
                        hql += " order by names." + sortBy;
1✔
344
                } else {
345
                        hql += " order by concept." + sortBy;
1✔
346
                }
347
                
348
                hql += asc ? " asc" : " desc";
1✔
349
                Query query = sessionFactory.getCurrentSession().createQuery(hql);
1✔
350
                return (List<Concept>) query.getResultList();
1✔
351
        }
352
        
353
        /**
354
         * @see org.openmrs.api.db.ConceptDAO#saveDrug(org.openmrs.Drug)
355
         */
356
        @Override
357
        public Drug saveDrug(Drug drug) throws DAOException {
358
                sessionFactory.getCurrentSession().saveOrUpdate(drug);
1✔
359
                return drug;
1✔
360
        }
361
        
362
        /**
363
         * @see org.openmrs.api.db.ConceptDAO#getDrug(java.lang.Integer)
364
         */
365
        @Override
366
        public Drug getDrug(Integer drugId) throws DAOException {
367
                return sessionFactory.getCurrentSession().get(Drug.class, drugId);
1✔
368
        }
369
        
370
        /**
371
         * @see org.openmrs.api.db.ConceptDAO#getDrugs(java.lang.String, org.openmrs.Concept, boolean)
372
         */
373
        @Override
374
        public List<Drug> getDrugs(String drugName, Concept concept, boolean includeRetired) throws DAOException {
375
                Session session = sessionFactory.getCurrentSession();
1✔
376
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
377
                CriteriaQuery<Drug> cq = cb.createQuery(Drug.class);
1✔
378
                Root<Drug> drugRoot = cq.from(Drug.class);
1✔
379

380
                List<Predicate> predicates = new ArrayList<>();
1✔
381

382
                if (!includeRetired) {
1✔
383
                        predicates.add(cb.isFalse(drugRoot.get("retired")));
1✔
384
                }
385

386
                if (concept != null) {
1✔
387
                        predicates.add(cb.equal(drugRoot.get("concept"), concept));
1✔
388
                }
389

390
                if (drugName != null) {
1✔
391
                        if (Context.getAdministrationService().isDatabaseStringComparisonCaseSensitive()) {
1✔
392
                                predicates.add(cb.equal(cb.lower(drugRoot.get("name")), MatchMode.EXACT.toLowerCasePattern(drugName)));
1✔
393
                        } else {
394
                                predicates.add(cb.equal(drugRoot.get("name"), MatchMode.EXACT.toCaseSensitivePattern(drugName)));
×
395
                        }
396
                }
397

398
                cq.where(predicates.toArray(new Predicate[]{}));
1✔
399

400
                return session.createQuery(cq).getResultList();
1✔
401
        }
402

403
        /**
404
         * @see org.openmrs.api.db.ConceptDAO#getDrugsByIngredient(org.openmrs.Concept)
405
         */
406
        @Override
407
        public List<Drug> getDrugsByIngredient(Concept ingredient) {
408
                Session session = sessionFactory.getCurrentSession();
1✔
409
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
410
                CriteriaQuery<Drug> cq = cb.createQuery(Drug.class);
1✔
411
                Root<Drug> drugRoot = cq.from(Drug.class);
1✔
412
                
413
                Join<Drug, DrugIngredient> ingredientJoin = drugRoot.join("ingredients");
1✔
414

415
                Predicate rhs = cb.equal(drugRoot.get("concept"), ingredient);
1✔
416
                Predicate lhs = cb.equal(ingredientJoin.get("ingredient"), ingredient);
1✔
417

418
                cq.where(cb.or(lhs, rhs));
1✔
419

420
                return session.createQuery(cq).getResultList();
1✔
421
        }
422
        
423
        /**
424
         * @see org.openmrs.api.db.ConceptDAO#getDrugs(java.lang.String)
425
         */
426
        @Override
427
        public List<Drug> getDrugs(final String phrase) throws DAOException {
428
                SearchQuery<Drug> drugQuery = newDrugQuery(phrase, true, false, Context.getLocale(), false, null, false);
1✔
429
                
430
                if (drugQuery == null) {
1✔
431
                        return Collections.emptyList();
×
432
                }
433
                
434
                return drugQuery.fetchAllHits();
1✔
435
        }
436
        
437
        /**
438
         * @see org.openmrs.api.db.ConceptDAO#getConceptClass(java.lang.Integer)
439
         */
440
        @Override
441
        public ConceptClass getConceptClass(Integer i) throws DAOException {
442
                return sessionFactory.getCurrentSession().get(ConceptClass.class, i);
1✔
443
        }
444
        
445
        /**
446
         * @see org.openmrs.api.db.ConceptDAO#getConceptClasses(java.lang.String)
447
         */
448
        @Override
449
        public List<ConceptClass> getConceptClasses(String name) throws DAOException {
450
                Session session = sessionFactory.getCurrentSession();
1✔
451
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
452
                CriteriaQuery<ConceptClass> cq = cb.createQuery(ConceptClass.class);
1✔
453
                Root<ConceptClass> root = cq.from(ConceptClass.class);
1✔
454

455
                if (name != null) {
1✔
456
                        cq.where(cb.equal(root.get("name"), name));
1✔
457
                }
458

459
                return session.createQuery(cq).getResultList();
1✔
460
        }
461
        
462
        /**
463
         * @see org.openmrs.api.db.ConceptDAO#getAllConceptClasses(boolean)
464
         */
465
        @Override
466
        public List<ConceptClass> getAllConceptClasses(boolean includeRetired) throws DAOException {
467
                Session session = sessionFactory.getCurrentSession();
1✔
468
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
469
                CriteriaQuery<ConceptClass> cq = cb.createQuery(ConceptClass.class);
1✔
470
                Root<ConceptClass> root = cq.from(ConceptClass.class);
1✔
471

472
                // Minor bug - was assigning includeRetired instead of evaluating
473
                if (!includeRetired) {
1✔
474
                        cq.where(cb.isFalse(root.get("retired")));
1✔
475
                }
476

477
                return session.createQuery(cq).getResultList();
1✔
478
        }
479
        
480
        /**
481
         * @see org.openmrs.api.db.ConceptDAO#saveConceptClass(org.openmrs.ConceptClass)
482
         */
483
        @Override
484
        public ConceptClass saveConceptClass(ConceptClass cc) throws DAOException {
485
                sessionFactory.getCurrentSession().saveOrUpdate(cc);
1✔
486
                return cc;
1✔
487
        }
488
        
489
        /**
490
         * @see org.openmrs.api.db.ConceptDAO#purgeConceptClass(org.openmrs.ConceptClass)
491
         */
492
        @Override
493
        public void purgeConceptClass(ConceptClass cc) throws DAOException {
494
                sessionFactory.getCurrentSession().delete(cc);
1✔
495
        }
1✔
496
        
497
        /**
498
         * @see org.openmrs.api.db.ConceptDAO#deleteConceptNameTag(ConceptNameTag)
499
         */
500
        @Override
501
        public void deleteConceptNameTag(ConceptNameTag cnt) throws DAOException {
502
                sessionFactory.getCurrentSession().delete(cnt);
1✔
503
        }
1✔
504
        
505
        /**
506
         * @see org.openmrs.api.db.ConceptDAO#getConceptDatatype(java.lang.Integer)
507
         */
508
        @Override
509
        public ConceptDatatype getConceptDatatype(Integer i) {
510
                return sessionFactory.getCurrentSession().get(ConceptDatatype.class, i);
1✔
511
        }
512
        
513
        @Override
514
        public List<ConceptDatatype> getAllConceptDatatypes(boolean includeRetired) throws DAOException {
515
                Session session = sessionFactory.getCurrentSession();
1✔
516
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
517
                CriteriaQuery<ConceptDatatype> cq = cb.createQuery(ConceptDatatype.class);
1✔
518
                Root<ConceptDatatype> root = cq.from(ConceptDatatype.class);
1✔
519

520
                if (!includeRetired) {
1✔
521
                        cq.where(cb.isFalse(root.get("retired")));
1✔
522
                }
523

524
                return session.createQuery(cq).getResultList();
1✔
525
        }
526

527
        /**
528
         * @param name the name of the ConceptDatatype
529
         * @return a List of ConceptDatatype whose names start with the passed name
530
         */
531
        public List<ConceptDatatype> getConceptDatatypes(String name) throws DAOException {
532
                Session session = sessionFactory.getCurrentSession();
1✔
533
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
534
                CriteriaQuery<ConceptDatatype> cq = cb.createQuery(ConceptDatatype.class);
1✔
535
                Root<ConceptDatatype> root = cq.from(ConceptDatatype.class);
1✔
536

537
                if (name != null) {
1✔
538
                        cq.where(cb.like(root.get("name"), MatchMode.START.toCaseSensitivePattern(name)));
1✔
539
                }
540

541
                return session.createQuery(cq).getResultList();
1✔
542
        }
543

544
        /**
545
         * @see org.openmrs.api.db.ConceptDAO#getConceptDatatypeByName(String)
546
         */
547
        @Override
548
        public ConceptDatatype getConceptDatatypeByName(String name) throws DAOException {
549
                Session session = sessionFactory.getCurrentSession();
1✔
550
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
551
                CriteriaQuery<ConceptDatatype> cq = cb.createQuery(ConceptDatatype.class);
1✔
552
                Root<ConceptDatatype> root = cq.from(ConceptDatatype.class);
1✔
553

554
                if (name != null) {
1✔
555
                        cq.where(cb.equal(root.get("name"), name));
1✔
556
                }
557
                return session.createQuery(cq).uniqueResult();
1✔
558
        }
559
        
560
        /**
561
         * @see org.openmrs.api.db.ConceptDAO#saveConceptDatatype(org.openmrs.ConceptDatatype)
562
         */
563
        @Override
564
        public ConceptDatatype saveConceptDatatype(ConceptDatatype cd) throws DAOException {
565
                sessionFactory.getCurrentSession().saveOrUpdate(cd);
×
566
                return cd;
×
567
        }
568
        
569
        /**
570
         * @see org.openmrs.api.db.ConceptDAO#purgeConceptDatatype(org.openmrs.ConceptDatatype)
571
         */
572
        @Override
573
        public void purgeConceptDatatype(ConceptDatatype cd) throws DAOException {
574
                sessionFactory.getCurrentSession().delete(cd);
×
575
        }
×
576
        
577
        /**
578
         * @see org.openmrs.api.db.ConceptDAO#getConceptNumeric(java.lang.Integer)
579
         */
580
        @Override
581
        public ConceptNumeric getConceptNumeric(Integer i) {
582
                ConceptNumeric cn;
583
                Object obj = sessionFactory.getCurrentSession().get(ConceptNumeric.class, i);
1✔
584
                // If Concept has already been read & cached, we may get back a Concept instead of
585
                // ConceptNumeric.  If this happens, we need to clear the object from the cache
586
                // and re-fetch it as a ConceptNumeric
587
                if (obj != null && !obj.getClass().equals(ConceptNumeric.class)) {
1✔
588
                        // remove from cache
589
                        sessionFactory.getCurrentSession().evict(obj);
×
590
                        // session.get() did not work here, we need to perform a query to get a ConceptNumeric
591
                        Query query = sessionFactory.getCurrentSession().createQuery("from ConceptNumeric where conceptId = :conceptId")
×
592
                                .setParameter("conceptId", i);
×
593
                        obj = JpaUtils.getSingleResultOrNull(query);
×
594
                }
595
                cn = (ConceptNumeric) obj;
1✔
596
                
597
                return cn;
1✔
598
        }
599
        
600
        /**
601
         * @see org.openmrs.api.db.ConceptDAO#getConcepts(java.lang.String, java.util.Locale, boolean,
602
         *      java.util.List, java.util.List)
603
         */
604
        @Override
605
        public List<Concept> getConcepts(final String name, final Locale loc, final boolean searchOnPhrase,
606
                final List<ConceptClass> classes, final List<ConceptDatatype> datatypes) throws DAOException {
607
                
608
                final Locale locale;
609
                if (loc == null) {
1✔
610
                        locale = Context.getLocale();
1✔
611
                } else {
612
                        locale = loc;
1✔
613
                }
614

615
                return SearchQueryUnique.search(searchSessionFactory, SearchQueryUnique.newQuery(ConceptName.class, f -> 
1✔
616
                        newConceptNamePredicate(f, name, !searchOnPhrase, Collections.singletonList(locale),
1✔
617
                                false, false, classes, null, datatypes, null, null),
618
                        "concept.conceptId", ConceptName::getConcept));
619
        }
620
        
621
        private LinkedHashSet<Concept> transformNamesToConcepts(List<ConceptName> names) {
622
                LinkedHashSet<Concept> concepts = new LinkedHashSet<>();
1✔
623
                
624
                for (ConceptName name : names) {
1✔
625
                        concepts.add(name.getConcept());
1✔
626
                }
1✔
627
                
628
                return concepts;
1✔
629
        }
630
        
631
        private SearchPredicate newConceptNameQuery(SearchPredicateFactory f, final String name, final boolean searchKeywords, 
632
                                                                                                final Collection<Locale> locales, final boolean searchExactLocale) {
633
                return f.bool().with(b -> {
1✔
634
                        if (searchExactLocale) {
1✔
635
                                b.must(f.terms().field("locale").matchingAny(locales));
1✔
636
                        } else {
637
                                b.must(f.bool().with(bb -> {
1✔
638
                                        for (Locale locale : locales) {
1✔
639
                                                bb.should(f.wildcard().field("locale").matching(locale.getLanguage() + "*"));
1✔
640
                                                if (!StringUtils.isBlank(locale.getCountry())) {
1✔
641
                                                        bb.should(f.match().field("locale").matching(locale).boost(2f));
1✔
642
                                                }
643
                                        }
1✔
644
                                }));
1✔
645
                        }
646
                        b.filter(f.match().field("voided").matching(false));
1✔
647
                        
648
                        b.must(f.bool().with(bb -> {
1✔
649
                                List<String> tokenizedName = tokenizeName(name, locales);
1✔
650
                                BooleanPredicateClausesStep<?> nameQuery = newNameQuery(f, tokenizedName, name, searchKeywords);
1✔
651

652
                                bb.should(f.match().field("concept.conceptMappings.conceptReferenceTerm.code").matching(name).boost(10f));
1✔
653
                                bb.should(f.and()
1✔
654
                                        .add(nameQuery)
1✔
655
                                        .add(f.match().field("localePreferred").matching(true)).boost(2f));
1✔
656
                                bb.should(nameQuery);
1✔
657
                        }));
1✔
658
                }).toPredicate();
1✔
659
        }
660
        
661
        private BooleanPredicateClausesStep<?> newNameQuery(SearchPredicateFactory f, final List<String> tokenizedName, final String name,
662
                                                                                                                final boolean searchKeywords) {
663
                return f.bool().with(b -> {
1✔
664
                        b.minimumShouldMatchNumber(1);
1✔
665
                        b.should(f.phrase().field("name").matching(name).boost(8f));
1✔
666
                        if (searchKeywords) {
1✔
667
                                if (!tokenizedName.isEmpty()) {
1✔
668
                                        b.should(f.bool().with(bb -> {
1✔
669
                                                for (String token : tokenizedName) {
1✔
670
                                                        bb.must(f.bool().with(bbb -> {
1✔
671
                                                                bbb.minimumShouldMatchNumber(1);
1✔
672
                                                                bbb.should(f.match().field("name").matching(token).boost(3f));
1✔
673
                                                                bbb.should(f.wildcard().field("name").matching(token + "*").boost(2f));
1✔
674
                                                                bbb.should(f.match().field("name").matching(token).fuzzy(1, 3));
1✔
675
                                                        }));
1✔
676
                                                }
1✔
677
                                        }));
1✔
678
                                }
679
                        }
680
                });
1✔
681
        }
682
        
683
        private List<String> tokenizeName(final String escapedName, final Collection<Locale> locales) {
684
                List<String> words = new ArrayList<>(Arrays.asList(escapedName.trim().split(" ")));
1✔
685
                
686
                Set<String> stopWords = new HashSet<>();
1✔
687
                for (Locale locale : locales) {
1✔
688
                        stopWords.addAll(Context.getConceptService().getConceptStopWords(locale));
1✔
689
                }
1✔
690
                
691
                List<String> tokenizedName = new ArrayList<>();
1✔
692
                
693
                for (String word : words) {
1✔
694
                        word = word.trim();
1✔
695
                        
696
                        if (!word.isEmpty() && !stopWords.contains(word.toUpperCase())) {
1✔
697
                                tokenizedName.add(word);
1✔
698
                        }
699
                }
1✔
700
                
701
                return tokenizedName;
1✔
702
        }
703
        
704
        /**
705
         * gets questions for the given answer concept
706
         * 
707
         * @see org.openmrs.api.db.ConceptDAO#getConceptsByAnswer(org.openmrs.Concept)
708
         */
709
        @Override
710
        @SuppressWarnings("unchecked")
711
        public List<Concept> getConceptsByAnswer(Concept concept) {
712
                String q = "select c from Concept c join c.answers ca where ca.answerConcept = :answer";
1✔
713
                Query query = sessionFactory.getCurrentSession().createQuery(q);
1✔
714
                query.setParameter("answer", concept);
1✔
715
                
716
                return query.getResultList();
1✔
717
        }
718

719
        /**
720
         * @see org.openmrs.api.db.ConceptDAO#getPrevConcept(org.openmrs.Concept)
721
         */
722
        @Override
723
        public Concept getPrevConcept(Concept c) {
724
                Session session = sessionFactory.getCurrentSession();
1✔
725
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
726
                CriteriaQuery<Concept> cq = cb.createQuery(Concept.class);
1✔
727
                Root<Concept> root = cq.from(Concept.class);
1✔
728

729
                Integer i = c.getConceptId();
1✔
730

731
                cq.where(cb.lessThan(root.get("conceptId"), i));
1✔
732
                cq.orderBy(cb.desc(root.get("conceptId")));
1✔
733

734
                List<Concept> concepts = session.createQuery(cq).setMaxResults(1).getResultList();
1✔
735

736
                if (concepts.isEmpty()) {
1✔
737
                        return null;
1✔
738
                }
739

740
                return concepts.get(0);
1✔
741
        }
742

743
        /**
744
         * @see org.openmrs.api.db.ConceptDAO#getNextConcept(org.openmrs.Concept)
745
         */
746
        @Override
747
        public Concept getNextConcept(Concept c) {
748
                Session session = sessionFactory.getCurrentSession();
1✔
749
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
750
                CriteriaQuery<Concept> cq = cb.createQuery(Concept.class);
1✔
751
                Root<Concept> root = cq.from(Concept.class);
1✔
752

753
                Integer i = c.getConceptId();
1✔
754

755
                cq.where(cb.greaterThan(root.get("conceptId"), i));
1✔
756
                cq.orderBy(cb.asc(root.get("conceptId")));
1✔
757

758
                List<Concept> concepts = session.createQuery(cq).setMaxResults(1).getResultList();
1✔
759

760
                if (concepts.isEmpty()) {
1✔
761
                        return null;
1✔
762
                }
763

764
                return concepts.get(0);
1✔
765
        }
766
        
767
        /**
768
         * @see org.openmrs.api.db.ConceptDAO#getConceptsWithDrugsInFormulary()
769
         */
770
        @Override
771
        @SuppressWarnings("unchecked")
772
        public List<Concept> getConceptsWithDrugsInFormulary() {
773
                Query query = sessionFactory.getCurrentSession().createQuery(
1✔
774
                    "select distinct concept from Drug d where d.retired = false");
775
                return query.getResultList();
1✔
776
        }
777
        
778
        /**
779
         * @see org.openmrs.api.db.ConceptDAO#purgeDrug(org.openmrs.Drug)
780
         */
781
        @Override
782
        public void purgeDrug(Drug drug) throws DAOException {
783
                sessionFactory.getCurrentSession().delete(drug);
1✔
784
        }
1✔
785
        
786
        /**
787
         * @see org.openmrs.api.db.ConceptDAO#saveConceptProposal(org.openmrs.ConceptProposal)
788
         */
789
        @Override
790
        public ConceptProposal saveConceptProposal(ConceptProposal cp) throws DAOException {
791
                sessionFactory.getCurrentSession().saveOrUpdate(cp);
1✔
792
                return cp;
1✔
793
        }
794
        
795
        /**
796
         * @see org.openmrs.api.db.ConceptDAO#purgeConceptProposal(org.openmrs.ConceptProposal)
797
         */
798
        @Override
799
        public void purgeConceptProposal(ConceptProposal cp) throws DAOException {
800
                sessionFactory.getCurrentSession().delete(cp);
1✔
801
        }
1✔
802

803
        /**
804
         * @see org.openmrs.api.db.ConceptDAO#getAllConceptProposals(boolean)
805
         */
806
        @Override
807
        public List<ConceptProposal> getAllConceptProposals(boolean includeCompleted) throws DAOException {
808
                Session session = sessionFactory.getCurrentSession();
1✔
809
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
810
                CriteriaQuery<ConceptProposal> cq = cb.createQuery(ConceptProposal.class);
1✔
811
                Root<ConceptProposal> root = cq.from(ConceptProposal.class);
1✔
812

813
                if (!includeCompleted) {
1✔
814
                        cq.where(cb.equal(root.get("state"), OpenmrsConstants.CONCEPT_PROPOSAL_UNMAPPED));
1✔
815
                }
816
                cq.orderBy(cb.asc(root.get("originalText")));
1✔
817
                return session.createQuery(cq).getResultList();
1✔
818
        }
819
        
820
        /**
821
         * @see org.openmrs.api.db.ConceptDAO#getConceptProposal(java.lang.Integer)
822
         */
823
        @Override
824
        public ConceptProposal getConceptProposal(Integer conceptProposalId) throws DAOException {
825
                return sessionFactory.getCurrentSession().get(ConceptProposal.class, conceptProposalId);
1✔
826
        }
827
        
828
        /**
829
         * @see org.openmrs.api.db.ConceptDAO#getConceptProposals(java.lang.String)
830
         */
831
        @Override
832
        public List<ConceptProposal> getConceptProposals(String text) throws DAOException {
833
                Session session = sessionFactory.getCurrentSession();
1✔
834
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
835
                CriteriaQuery<ConceptProposal> cq = cb.createQuery(ConceptProposal.class);
1✔
836
                Root<ConceptProposal> root = cq.from(ConceptProposal.class);
1✔
837

838
                Predicate stateCondition = cb.equal(root.get("state"), OpenmrsConstants.CONCEPT_PROPOSAL_UNMAPPED);
1✔
839
                Predicate textCondition = cb.equal(root.get("originalText"), text);
1✔
840

841
                cq.where(cb.and(stateCondition, textCondition));
1✔
842

843
                return session.createQuery(cq).getResultList();
1✔
844
        }
845

846
        /**
847
         * @see org.openmrs.api.db.ConceptDAO#getProposedConcepts(java.lang.String)
848
         */
849
        @Override
850
        public List<Concept> getProposedConcepts(String text) throws DAOException {
851
                Session session = sessionFactory.getCurrentSession();
1✔
852
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
853
                CriteriaQuery<Concept> cq = cb.createQuery(Concept.class);
1✔
854
                Root<ConceptProposal> root = cq.from(ConceptProposal.class);
1✔
855

856
                Predicate stateNotEqual = cb.notEqual(root.get("state"), OpenmrsConstants.CONCEPT_PROPOSAL_UNMAPPED);
1✔
857
                Predicate originalTextEqual = cb.equal(root.get("originalText"), text);
1✔
858
                Predicate mappedConceptNotNull = cb.isNotNull(root.get("mappedConcept"));
1✔
859

860
                cq.select(root.get("mappedConcept")).distinct(true);
1✔
861
                cq.where(stateNotEqual, originalTextEqual, mappedConceptNotNull);
1✔
862

863
                return session.createQuery(cq).getResultList();
1✔
864
        }
865

866
        /**
867
         * @see org.openmrs.api.db.ConceptDAO#getConceptSetsByConcept(org.openmrs.Concept)
868
         */
869
        @Override
870
        public List<ConceptSet> getConceptSetsByConcept(Concept concept) {
871
                Session session = sessionFactory.getCurrentSession();
1✔
872
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
873
                CriteriaQuery<ConceptSet> cq = cb.createQuery(ConceptSet.class);
1✔
874
                Root<ConceptSet> root = cq.from(ConceptSet.class);
1✔
875

876
                cq.where(cb.equal(root.get("conceptSet"), concept));
1✔
877
                cq.orderBy(cb.asc(root.get("sortWeight")));
1✔
878

879
                return session.createQuery(cq).getResultList();
1✔
880
        }
881

882
        /**
883
         * @see org.openmrs.api.db.ConceptDAO#getSetsContainingConcept(org.openmrs.Concept)
884
         */
885
        @Override
886
        public List<ConceptSet> getSetsContainingConcept(Concept concept) {
887
                Session session = sessionFactory.getCurrentSession();
1✔
888
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
889
                CriteriaQuery<ConceptSet> cq = cb.createQuery(ConceptSet.class);
1✔
890
                Root<ConceptSet> root = cq.from(ConceptSet.class);
1✔
891

892
                cq.where(cb.equal(root.get("concept"), concept));
1✔
893

894
                return session.createQuery(cq).getResultList();
1✔
895
        }
896
        
897
        /**
898
         * returns a list of n-generations of parents of a concept in a concept set
899
         * 
900
         * @param current
901
         * @return List&lt;Concept&gt;
902
         * @throws DAOException
903
         */
904
        @SuppressWarnings("unchecked")
905
        private List<Concept> getParents(Concept current) throws DAOException {
906
                List<Concept> parents = new ArrayList<>();
×
907
                if (current != null) {
×
908
                        Query query = sessionFactory.getCurrentSession().createQuery(
×
909
                            "from Concept c join c.conceptSets sets where sets.concept = ?").setParameter(0, current);
×
910
                        List<Concept> immedParents = query.getResultList();
×
911
                        for (Concept c : immedParents) {
×
912
                                parents.addAll(getParents(c));
×
913
                        }
×
914
                        parents.add(current);
×
915
                        if (log.isDebugEnabled()) {
×
916
                                log.debug("parents found: ");
×
917
                                for (Concept c : parents) {
×
918
                                        log.debug("id: {}", c.getConceptId());
×
919
                                }
×
920
                        }        
921
                }
922
                return parents;
×
923
        }
924
        
925
        /**
926
         * @see org.openmrs.api.db.ConceptDAO#getLocalesOfConceptNames()
927
         */
928
        @Override
929
        public Set<Locale> getLocalesOfConceptNames() {
930
                Set<Locale> locales = new HashSet<>();
1✔
931
                
932
                Query query = sessionFactory.getCurrentSession().createQuery("select distinct locale from ConceptName");
1✔
933
                
934
                for (Object locale : query.getResultList()) {
1✔
935
                        locales.add((Locale) locale);
1✔
936
                }
1✔
937
                
938
                return locales;
1✔
939
        }
940
        
941
        /**
942
         * @see org.openmrs.api.db.ConceptDAO#getConceptNameTag(java.lang.Integer)
943
         */
944
        @Override
945
        public ConceptNameTag getConceptNameTag(Integer i) {
946
                return sessionFactory.getCurrentSession().get(ConceptNameTag.class, i);
1✔
947
        }
948

949
        /**
950
         * @see org.openmrs.api.db.ConceptDAO#getConceptNameTagByName(java.lang.String)
951
         */
952
        @Override
953
        public ConceptNameTag getConceptNameTagByName(String name) {
954
                Session session = sessionFactory.getCurrentSession();
1✔
955
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
956
                CriteriaQuery<ConceptNameTag> cq = cb.createQuery(ConceptNameTag.class);
1✔
957
                Root<ConceptNameTag> root = cq.from(ConceptNameTag.class);
1✔
958

959
                cq.where(cb.equal(root.get("tag"), name));
1✔
960

961
                List<ConceptNameTag> conceptNameTags = session.createQuery(cq).getResultList();
1✔
962
                if (conceptNameTags.isEmpty()) {
1✔
963
                        return null;
1✔
964
                }
965

966
                return conceptNameTags.get(0);
1✔
967
        }
968
        
969
        /**
970
         * @see org.openmrs.api.db.ConceptDAO#getAllConceptNameTags()
971
         */
972
        @Override
973
        @SuppressWarnings("unchecked")
974
        public List<ConceptNameTag> getAllConceptNameTags() {
975
                return sessionFactory.getCurrentSession().createQuery("from ConceptNameTag cnt order by cnt.tag").list();
1✔
976
        }
977
        
978
        /**
979
         * @see org.openmrs.api.db.ConceptDAO#getConceptSource(java.lang.Integer)
980
         */
981
        @Override
982
        public ConceptSource getConceptSource(Integer conceptSourceId) {
983
                return sessionFactory.getCurrentSession().get(ConceptSource.class, conceptSourceId);
1✔
984
        }
985
        
986
        /**
987
         * @see org.openmrs.api.db.ConceptDAO#getAllConceptSources(boolean)
988
         */
989
        @Override
990
        public List<ConceptSource> getAllConceptSources(boolean includeRetired) throws DAOException {
991
                Session session = sessionFactory.getCurrentSession();
1✔
992
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
993
                CriteriaQuery<ConceptSource> cq = cb.createQuery(ConceptSource.class);
1✔
994
                Root<ConceptSource> root = cq.from(ConceptSource.class);
1✔
995

996
                if (!includeRetired) {
1✔
997
                        cq.where(cb.isFalse(root.get("retired")));
1✔
998
                }
999

1000
                return session.createQuery(cq).getResultList();
1✔
1001
        }
1002
        
1003
        /**
1004
         * @see org.openmrs.api.db.ConceptDAO#deleteConceptSource(org.openmrs.ConceptSource)
1005
         */
1006
        @Override
1007
        public ConceptSource deleteConceptSource(ConceptSource cs) throws DAOException {
1008
                sessionFactory.getCurrentSession().delete(cs);
1✔
1009
                return cs;
1✔
1010
        }
1011
        
1012
        /**
1013
         * @see org.openmrs.api.db.ConceptDAO#saveConceptSource(org.openmrs.ConceptSource)
1014
         */
1015
        @Override
1016
        public ConceptSource saveConceptSource(ConceptSource conceptSource) throws DAOException {
1017
                sessionFactory.getCurrentSession().saveOrUpdate(conceptSource);
1✔
1018
                return conceptSource;
1✔
1019
        }
1020
        
1021
        /**
1022
         * @see org.openmrs.api.db.ConceptDAO#saveConceptNameTag(org.openmrs.ConceptNameTag)
1023
         */
1024
        @Override
1025
        public ConceptNameTag saveConceptNameTag(ConceptNameTag nameTag) {
1026
                if (nameTag == null) {
1✔
1027
                        return null;
×
1028
                }
1029
                
1030
                sessionFactory.getCurrentSession().saveOrUpdate(nameTag);
1✔
1031
                return nameTag;
1✔
1032
        }
1033
        
1034
        /**
1035
         * @see org.openmrs.api.db.ConceptDAO#getMaxConceptId()
1036
         */
1037
        public Integer getMinConceptId() {
1038
                Query query = sessionFactory.getCurrentSession().createQuery("select min(conceptId) from Concept");
1✔
1039
                return JpaUtils.getSingleResultOrNull(query);
1✔
1040
        }
1041
        
1042
        /**
1043
         * @see org.openmrs.api.db.ConceptDAO#getMaxConceptId()
1044
         */
1045
        @Override
1046
        public Integer getMaxConceptId() {
1047
                Query query = sessionFactory.getCurrentSession().createQuery("select max(conceptId) from Concept");
1✔
1048
                return JpaUtils.getSingleResultOrNull(query);
1✔
1049
        }
1050
        
1051
        /**
1052
         * @see org.openmrs.api.db.ConceptDAO#conceptIterator()
1053
         */
1054
        @Override
1055
        public Iterator<Concept> conceptIterator() {
1056
                return new ConceptIterator();
1✔
1057
        }
1058
        
1059
        /**
1060
         * An iterator that loops over all concepts in the dictionary one at a time
1061
         */
1062
        private class ConceptIterator implements Iterator<Concept> {
1063
                
1064
                Concept currentConcept = null;
1✔
1065
                
1066
                Concept nextConcept;
1067
                
1068
                public ConceptIterator() {
1✔
1069
                        final int firstConceptId = getMinConceptId();
1✔
1070
                        nextConcept = getConcept(firstConceptId);
1✔
1071
                }
1✔
1072
                
1073
                /**
1074
                 * @see java.util.Iterator#hasNext()
1075
                 */
1076
                @Override
1077
                public boolean hasNext() {
1078
                        return nextConcept != null;
1✔
1079
                }
1080
                
1081
                /**
1082
                 * @see java.util.Iterator#next()
1083
                 */
1084
                @Override
1085
                public Concept next() {
1086
                        if (currentConcept != null) {
1✔
1087
                                sessionFactory.getCurrentSession().evict(currentConcept);
1✔
1088
                        }
1089
                        
1090
                        currentConcept = nextConcept;
1✔
1091
                        nextConcept = getNextConcept(currentConcept);
1✔
1092
                        
1093
                        return currentConcept;
1✔
1094
                }
1095
                
1096
                /**
1097
                 * @see java.util.Iterator#remove()
1098
                 */
1099
                @Override
1100
                public void remove() {
1101
                        throw new UnsupportedOperationException();
×
1102
                }
1103
                
1104
        }
1105

1106
        /**
1107
         * @see org.openmrs.api.db.ConceptDAO#getConceptsByMapping(String, String, boolean)
1108
         */
1109
        @Override
1110
        @Deprecated
1111
        public List<Concept> getConceptsByMapping(String code, String sourceName, boolean includeRetired) {
1112
                Session session = sessionFactory.getCurrentSession();
×
1113
                CriteriaBuilder cb = session.getCriteriaBuilder();
×
1114
                CriteriaQuery<Concept> cq = cb.createQuery(Concept.class);
×
1115
                Root<ConceptMap> root = cq.from(ConceptMap.class);
×
1116

1117
                List<Predicate> predicates = createSearchConceptMapCriteria(cb, root, code, sourceName, includeRetired);
×
1118

1119
                cq.where(predicates.toArray(new Predicate[]{}));
×
1120

1121
                cq.select(root.get("concept"));
×
1122

1123
                Join<ConceptMap, Concept> conceptJoin = root.join("concept");
×
1124
                if (includeRetired) {
×
1125
                        cq.orderBy(cb.asc(conceptJoin.get("retired")));
×
1126
                }
1127

1128
                return session.createQuery(cq).getResultList()
×
1129
                        .stream().distinct().collect(toList());
×
1130
        }
1131

1132
        /**
1133
         * @see org.openmrs.api.db.ConceptDAO#getConceptIdsByMapping(String, String, boolean)
1134
         */
1135
        @Override
1136
        public List<Integer> getConceptIdsByMapping(String code, String sourceName, boolean includeRetired) {
1137
                Session session = sessionFactory.getCurrentSession();
1✔
1138
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
1139
                CriteriaQuery<Integer> cq = cb.createQuery(Integer.class);
1✔
1140
                Root<ConceptMap> root = cq.from(ConceptMap.class);
1✔
1141

1142
                List<Predicate> predicates = createSearchConceptMapCriteria(cb, root, code, sourceName, includeRetired);
1✔
1143

1144
                cq.where(predicates.toArray(new Predicate[]{}));
1✔
1145

1146
                cq.select(root.get("concept").get("conceptId"));
1✔
1147

1148
                Join<ConceptMap, Concept> conceptJoin = root.join("concept");
1✔
1149
                if (includeRetired) {
1✔
1150
                        cq.orderBy(cb.asc(conceptJoin.get("retired")));
1✔
1151
                }
1152

1153
                return session.createQuery(cq).getResultList()
1✔
1154
                        .stream().distinct().collect(toList());
1✔
1155
        }
1156
        
1157
        /**
1158
         * @see org.openmrs.api.db.ConceptDAO#getConceptByUuid(java.lang.String)
1159
         */
1160
        @Override
1161
        public Concept getConceptByUuid(String uuid) {
1162
                return HibernateUtil.getUniqueEntityByUUID(sessionFactory, Concept.class, uuid);
1✔
1163
        }
1164

1165
        /**
1166
         * @see org.openmrs.api.db.ConceptDAO#getConcepts(ConceptSearchCriteria)
1167
         */
1168
        @Override
1169
        public List<Concept> getConcepts(ConceptSearchCriteria criteria) {
1170
                if (criteria == null) {
1✔
NEW
1171
                        return Collections.emptyList();
×
1172
                }
1173
                Session session = sessionFactory.getCurrentSession();
1✔
1174
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
1175
                CriteriaQuery<Concept> cq = cb.createQuery(Concept.class);
1✔
1176
                Root<Concept> root = cq.from(Concept.class);
1✔
1177

1178
                List<Predicate> orPredicates = new ArrayList<>();
1✔
1179

1180
                if (criteria.getUuids() != null && !criteria.getUuids().isEmpty()) {
1✔
1181
                        orPredicates.add(root.get("uuid").in(criteria.getUuids()));
1✔
1182
                }
1183

1184
                if (criteria.getConceptIds() != null && !criteria.getConceptIds().isEmpty()) {
1✔
1185
                        orPredicates.add(root.get("conceptId").in(criteria.getConceptIds()));
1✔
1186
                }
1187

1188
                if (criteria.getMappings() != null && !criteria.getMappings().isEmpty()) {
1✔
1189
                        boolean caseSensitive = Context.getAdministrationService().isDatabaseStringComparisonCaseSensitive();
1✔
1190
                        for (String mapping : criteria.getMappings()) {
1✔
1191
                                buildMappingExistsPredicate(cq, root, cb, mapping, caseSensitive).ifPresent(orPredicates::add);
1✔
1192
                        }
1✔
1193
                }
1194

1195
                if (criteria.getNames() != null && !criteria.getNames().isEmpty()) {
1✔
1196
                        boolean caseSensitive = Context.getAdministrationService().isDatabaseStringComparisonCaseSensitive();
1✔
1197
                        Locale locale = Context.getLocale();
1✔
1198
                        Locale language = new Locale(locale.getLanguage() + "%");
1✔
1199
                        for (String name : criteria.getNames()) {
1✔
1200
                                orPredicates.add(buildNameExistsPredicate(cq, root, cb, name, caseSensitive, locale, language));
1✔
1201
                        }
1✔
1202
                }
1203

1204
                if (orPredicates.isEmpty()) {
1✔
1205
                        return new ArrayList<>();
1✔
1206
                }
1207

1208
                Predicate combined = cb.or(orPredicates.toArray(new Predicate[0]));
1✔
1209
                if (!criteria.getIncludeRetired()) {
1✔
1210
                        combined = cb.and(combined, cb.isFalse(root.get("retired")));
1✔
1211
                }
1212
                cq.where(combined);
1✔
1213

1214
                return session.createQuery(cq).getResultList().stream().distinct().collect(toList());
1✔
1215
        }
1216

1217
        // mapping is assumed to be in the form "source:code"
1218
        private Optional<Predicate> buildMappingExistsPredicate(CriteriaQuery<Concept> cq, Root<Concept> root,
1219
                CriteriaBuilder cb, String mapping, boolean caseSensitive) {
1220
                int idx = mapping.indexOf(":");
1✔
1221
                if (idx < 0 || idx >= mapping.length() - 1) {
1✔
NEW
1222
                        return Optional.empty();
×
1223
                }
1224
                String sourceName = mapping.substring(0, idx).trim();
1✔
1225
                String code = mapping.substring(idx + 1).trim();
1✔
1226
                if (sourceName.isEmpty() || code.isEmpty()) {
1✔
NEW
1227
                        return Optional.empty();
×
1228
                }
1229

1230
                Subquery<ConceptMap> sub = cq.subquery(ConceptMap.class);
1✔
1231
                Root<ConceptMap> mapRoot = sub.from(ConceptMap.class);
1✔
1232
                Join<ConceptMap, ConceptReferenceTerm> termJoin = mapRoot.join(CONCEPT_REFERENCE_TERM);
1✔
1233
                Join<ConceptReferenceTerm, ConceptSource> sourceJoin = termJoin.join(CONCEPT_SOURCE);
1✔
1234

1235
                List<Predicate> predicates = new ArrayList<>();
1✔
1236
                predicates.add(cb.equal(mapRoot.get("concept"), root));
1✔
1237
                if (caseSensitive) {
1✔
1238
                        predicates.add(cb.equal(cb.lower(termJoin.get("code")), code.toLowerCase()));
1✔
1239
                        predicates.add(cb.or(cb.equal(cb.lower(sourceJoin.get("name")), sourceName.toLowerCase()),
1✔
1240
                            cb.equal(cb.lower(sourceJoin.get(HL7_CODE)), sourceName.toLowerCase())));
1✔
1241
                } else {
NEW
1242
                        predicates.add(cb.equal(termJoin.get("code"), code));
×
NEW
1243
                        predicates.add(
×
NEW
1244
                            cb.or(cb.equal(sourceJoin.get("name"), sourceName), cb.equal(sourceJoin.get(HL7_CODE), sourceName)));
×
1245
                }
1246
                sub.select(mapRoot).where(predicates.toArray(new Predicate[0]));
1✔
1247
                return Optional.of(cb.exists(sub));
1✔
1248
        }
1249

1250
        private Predicate buildNameExistsPredicate(CriteriaQuery<Concept> cq, Root<Concept> root, CriteriaBuilder cb,
1251
                String name, boolean caseSensitive, Locale locale, Locale language) {
1252
                Subquery<ConceptName> sub = cq.subquery(ConceptName.class);
1✔
1253
                Root<ConceptName> nameRoot = sub.from(ConceptName.class);
1✔
1254

1255
                List<Predicate> predicates = new ArrayList<>();
1✔
1256
                predicates.add(cb.equal(nameRoot.get("concept"), root));
1✔
1257
                predicates.add(cb.or(cb.equal(nameRoot.get("locale"), locale),
1✔
1258
                    cb.like(nameRoot.get("locale").as(String.class), language.toString())));
1✔
1259
                if (caseSensitive) {
1✔
1260
                        predicates.add(cb.like(cb.lower(nameRoot.get("name")), name.toLowerCase()));
1✔
1261
                } else {
NEW
1262
                        predicates.add(cb.equal(nameRoot.get("name"), name));
×
1263
                }
1264
                predicates.add(cb.isFalse(nameRoot.get("voided")));
1✔
1265
                sub.select(nameRoot).where(predicates.toArray(new Predicate[0]));
1✔
1266
                return cb.exists(sub);
1✔
1267
        }
1268

1269
        /**
1270
         * @see org.openmrs.api.db.ConceptDAO#getConceptClassByUuid(java.lang.String)
1271
         */
1272
        @Override
1273
        public ConceptClass getConceptClassByUuid(String uuid) {
1274
                return HibernateUtil.getUniqueEntityByUUID(sessionFactory, ConceptClass.class, uuid);
1✔
1275
        }
1276

1277
        @Override
1278
        public ConceptAnswer getConceptAnswerByUuid(String uuid) {
1279
                return HibernateUtil.getUniqueEntityByUUID(sessionFactory, ConceptAnswer.class, uuid);
1✔
1280
        }
1281

1282
        @Override
1283
        public ConceptName getConceptNameByUuid(String uuid) {
1284
                return HibernateUtil.getUniqueEntityByUUID(sessionFactory, ConceptName.class, uuid);
1✔
1285
        }
1286

1287
        @Override
1288
        public ConceptSet getConceptSetByUuid(String uuid) {
1289
                return HibernateUtil.getUniqueEntityByUUID(sessionFactory, ConceptSet.class, uuid);
1✔
1290
        }
1291

1292
        @Override
1293
        public ConceptSource getConceptSourceByUuid(String uuid) {
1294
                return HibernateUtil.getUniqueEntityByUUID(sessionFactory, ConceptSource.class, uuid);
1✔
1295
        }
1296

1297
        /**
1298
         * @see org.openmrs.api.db.ConceptDAO#getConceptDatatypeByUuid(java.lang.String)
1299
         */
1300
        @Override
1301
        public ConceptDatatype getConceptDatatypeByUuid(String uuid) {
1302
                return HibernateUtil.getUniqueEntityByUUID(sessionFactory, ConceptDatatype.class, uuid);
1✔
1303
        }
1304

1305
        /**
1306
         * @see org.openmrs.api.db.ConceptDAO#getConceptNumericByUuid(java.lang.String)
1307
         */
1308
        @Override
1309
        public ConceptNumeric getConceptNumericByUuid(String uuid) {
1310
                return HibernateUtil.getUniqueEntityByUUID(sessionFactory, ConceptNumeric.class, uuid);
1✔
1311
        }
1312

1313
        /**
1314
         * @see org.openmrs.api.db.ConceptDAO#getConceptProposalByUuid(java.lang.String)
1315
         */
1316
        @Override
1317
        public ConceptProposal getConceptProposalByUuid(String uuid) {
1318
                return HibernateUtil.getUniqueEntityByUUID(sessionFactory, ConceptProposal.class, uuid);
1✔
1319
        }
1320
        
1321
        /**
1322
         * @see org.openmrs.api.db.ConceptDAO#getDrugByUuid(java.lang.String)
1323
         */
1324
        @Override
1325
        public Drug getDrugByUuid(String uuid) {
1326
                return HibernateUtil.getUniqueEntityByUUID(sessionFactory, Drug.class, uuid);
1✔
1327
        }
1328

1329
        @Override
1330
        public DrugIngredient getDrugIngredientByUuid(String uuid) {
1331
                return HibernateUtil.getUniqueEntityByUUID(sessionFactory, DrugIngredient.class, uuid);
1✔
1332
        }
1333
        
1334
        /**
1335
         * @see org.openmrs.api.db.ConceptDAO#getConceptUuids()
1336
         */
1337
        @Override
1338
        @SuppressWarnings("unchecked")
1339
        public Map<Integer, String> getConceptUuids() {
1340
                Map<Integer, String> ret = new HashMap<>();
×
1341
                Query q = sessionFactory.getCurrentSession().createQuery("select conceptId, uuid from Concept");
×
1342
                List<Object[]> list = q.getResultList();
×
1343
                for (Object[] o : list) {
×
1344
                        ret.put((Integer) o[0], (String) o[1]);
×
1345
                }
×
1346
                return ret;
×
1347
        }
1348

1349
        /**
1350
         * @see org.openmrs.api.db.ConceptDAO#getConceptDescriptionByUuid(java.lang.String)
1351
         */
1352
        @Override
1353
        public ConceptDescription getConceptDescriptionByUuid(String uuid) {
1354
                return HibernateUtil.getUniqueEntityByUUID(sessionFactory, ConceptDescription.class, uuid);
1✔
1355
        }
1356

1357
        /**
1358
         * @see org.openmrs.api.db.ConceptDAO#getConceptNameTagByUuid(java.lang.String)
1359
         */
1360
        @Override
1361
        public ConceptNameTag getConceptNameTagByUuid(String uuid) {
1362
                return HibernateUtil.getUniqueEntityByUUID(sessionFactory, ConceptNameTag.class, uuid);
1✔
1363
        }
1364

1365
        /**
1366
         * @see org.openmrs.api.db.ConceptDAO#getConceptMapsBySource(ConceptSource)
1367
         */
1368
        @Override
1369
        public List<ConceptMap> getConceptMapsBySource(ConceptSource conceptSource) throws DAOException {
1370
                Session session = sessionFactory.getCurrentSession();
1✔
1371
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
1372
                CriteriaQuery<ConceptMap> cq = cb.createQuery(ConceptMap.class);
1✔
1373

1374
                Root<ConceptMap> root = cq.from(ConceptMap.class);
1✔
1375
                Join<ConceptMap, ConceptReferenceTerm> conceptReferenceTermJoin = root.join(CONCEPT_REFERENCE_TERM);
1✔
1376

1377
                cq.where(cb.equal(conceptReferenceTermJoin.get(CONCEPT_SOURCE), conceptSource));
1✔
1378

1379
                return session.createQuery(cq).getResultList();
1✔
1380
        }
1381

1382
        /**
1383
         * @see org.openmrs.api.db.ConceptDAO#getConceptSourceByName(java.lang.String)
1384
         */
1385
        @Override
1386
        public ConceptSource getConceptSourceByName(String conceptSourceName) throws DAOException {
1387
                Session session = sessionFactory.getCurrentSession();
1✔
1388
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
1389
                CriteriaQuery<ConceptSource> cq = cb.createQuery(ConceptSource.class);
1✔
1390
                Root<ConceptSource> root = cq.from(ConceptSource.class);
1✔
1391

1392
                cq.where(cb.equal(root.get("name"), conceptSourceName));
1✔
1393

1394
                return session.createQuery(cq).uniqueResult();
1✔
1395
        }
1396

1397
        /**
1398
         * @see org.openmrs.api.db.ConceptDAO#getConceptSourceByUniqueId(java.lang.String)
1399
         */
1400
        @Override
1401
        public ConceptSource getConceptSourceByUniqueId(String uniqueId) {
1402
                if (StringUtils.isBlank(uniqueId)) {
1✔
1403
                        return null;
1✔
1404
                }
1405

1406
                Session session = sessionFactory.getCurrentSession();
1✔
1407
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
1408
                CriteriaQuery<ConceptSource> cq = cb.createQuery(ConceptSource.class);
1✔
1409
                Root<ConceptSource> root = cq.from(ConceptSource.class);
1✔
1410

1411
                cq.where(cb.equal(root.get("uniqueId"), uniqueId));
1✔
1412

1413
                return session.createQuery(cq).uniqueResult();
1✔
1414
        }
1415

1416
        /**
1417
         * @see org.openmrs.api.db.ConceptDAO#getConceptSourceByHL7Code(java.lang.String)
1418
         */
1419
        @Override
1420
        public ConceptSource getConceptSourceByHL7Code(String hl7Code) {
1421
                if (StringUtils.isBlank(hl7Code)) {
1✔
1422
                        return null;
1✔
1423
                }
1424

1425
                Session session = sessionFactory.getCurrentSession();
1✔
1426
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
1427
                CriteriaQuery<ConceptSource> cq = cb.createQuery(ConceptSource.class);
1✔
1428
                Root<ConceptSource> root = cq.from(ConceptSource.class);
1✔
1429

1430
                cq.where(cb.equal(root.get(HL7_CODE), hl7Code));
1✔
1431

1432
                return session.createQuery(cq).uniqueResult();
1✔
1433
        }
1434

1435
        /**
1436
         * @see org.openmrs.api.db.ConceptDAO#getSavedConceptDatatype(org.openmrs.Concept)
1437
         */
1438
        @Override
1439
        public ConceptDatatype getSavedConceptDatatype(Concept concept) {
1440
                Query sql = sessionFactory.getCurrentSession().createSQLQuery(
1✔
1441
                                "select datatype.* from concept_datatype datatype, concept concept where " +
1442
                                        "datatype.concept_datatype_id = concept.datatype_id and concept.concept_id=:conceptId")
1443
                        .addEntity(ConceptDatatype.class);
1✔
1444
                sql.setParameter("conceptId", concept.getConceptId());
1✔
1445

1446
                return JpaUtils.getSingleResultOrNull(sql);
1✔
1447
        }
1448
        
1449
        /**
1450
         * @see org.openmrs.api.db.ConceptDAO#getSavedConceptName(org.openmrs.ConceptName)
1451
         */
1452
        @Override
1453
        public ConceptName getSavedConceptName(ConceptName conceptName) {
1454
                sessionFactory.getCurrentSession().refresh(conceptName);
1✔
1455
                return conceptName;
1✔
1456
        }
1457

1458
        /**
1459
         * @see org.openmrs.api.db.ConceptDAO#getConceptStopWords(java.util.Locale)
1460
         */
1461
        @Override
1462
        public List<String> getConceptStopWords(Locale locale) throws DAOException {
1463

1464
                locale = (locale == null ? Context.getLocale() : locale);
1✔
1465

1466
                Session session = sessionFactory.getCurrentSession();
1✔
1467
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
1468
                CriteriaQuery<String> cq = cb.createQuery(String.class);
1✔
1469
                Root<ConceptStopWord> root = cq.from(ConceptStopWord.class);
1✔
1470

1471
                cq.select(root.get("value"));
1✔
1472
                cq.where(cb.equal(root.get("locale"), locale));
1✔
1473

1474
                return session.createQuery(cq).getResultList();
1✔
1475
        }
1476

1477
        /**
1478
         * @see org.openmrs.api.db.ConceptDAO#saveConceptStopWord(org.openmrs.ConceptStopWord)
1479
         */
1480
        @Override
1481
        public ConceptStopWord saveConceptStopWord(ConceptStopWord conceptStopWord) throws DAOException {
1482
                if (conceptStopWord != null) {
1✔
1483
                        Session session = sessionFactory.getCurrentSession();
1✔
1484
                        CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
1485
                        CriteriaQuery<ConceptStopWord> cq = cb.createQuery(ConceptStopWord.class);
1✔
1486
                        Root<ConceptStopWord> root = cq.from(ConceptStopWord.class);
1✔
1487

1488
                        cq.where(cb.and(
1✔
1489
                                cb.equal(root.get("value"), conceptStopWord.getValue()),
1✔
1490
                                cb.equal(root.get("locale"), conceptStopWord.getLocale())));
1✔
1491

1492
                        List<ConceptStopWord> stopWordList = session.createQuery(cq).getResultList();
1✔
1493

1494
                        if (!stopWordList.isEmpty()) {
1✔
1495
                                throw new DAOException("Duplicate ConceptStopWord Entry");
1✔
1496
                        }
1497
                        session.saveOrUpdate(conceptStopWord);
1✔
1498
                }
1499
                return conceptStopWord;
1✔
1500
        }
1501
        
1502
        /**
1503
         * @see org.openmrs.api.db.ConceptDAO#deleteConceptStopWord(java.lang.Integer)
1504
         */
1505
        @Override
1506
        public void deleteConceptStopWord(Integer conceptStopWordId) throws DAOException {
1507
                if (conceptStopWordId == null) {
1✔
1508
                        throw new DAOException("conceptStopWordId is null");
×
1509
                }
1510

1511
                Session session = sessionFactory.getCurrentSession();
1✔
1512
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
1513
                CriteriaQuery<ConceptStopWord> cq = cb.createQuery(ConceptStopWord.class);
1✔
1514
                Root<ConceptStopWord> root = cq.from(ConceptStopWord.class);
1✔
1515
                
1516
                cq.where(cb.equal(root.get("conceptStopWordId"), conceptStopWordId));
1✔
1517

1518
                ConceptStopWord csw = session.createQuery(cq).uniqueResult();
1✔
1519
                if (csw == null) {
1✔
1520
                        throw new DAOException("Concept Stop Word not found or already deleted");
×
1521
                }
1522
                session.delete(csw);
1✔
1523
        }
1✔
1524

1525
        /**
1526
         * @see org.openmrs.api.db.ConceptDAO#getAllConceptStopWords()
1527
         */
1528
        @Override
1529
        public List<ConceptStopWord> getAllConceptStopWords() {
1530
                Session session = sessionFactory.getCurrentSession();
1✔
1531
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
1532
                CriteriaQuery<ConceptStopWord> cq = cb.createQuery(ConceptStopWord.class);
1✔
1533
                cq.from(ConceptStopWord.class);
1✔
1534

1535
                return session.createQuery(cq).getResultList();
1✔
1536
        }
1537
        
1538
        /**
1539
         * @see ConceptService#getCountOfDrugs(String, Concept, boolean, boolean, boolean)
1540
         */
1541
        @Override
1542
        public Long getCountOfDrugs(String drugName, Concept concept, boolean searchKeywords, boolean searchDrugConceptNames,
1543
                boolean includeRetired) throws DAOException {
1544
                SearchQuery<Drug> drugsQuery = newDrugQuery(drugName, searchKeywords, searchDrugConceptNames, Context.getLocale(),
1✔
1545
                    false, concept, includeRetired);
1546
                
1547
                if (drugsQuery == null) {
1✔
1548
                        return 0L;
×
1549
                }
1550
                
1551
                return drugsQuery.fetchTotalHitCount();
1✔
1552
        }
1553
        
1554
        /**
1555
         * <strong>Should</strong> return a drug if either the drug name or concept name matches the phase not both
1556
         * <strong>Should</strong> return distinct drugs
1557
         * <strong>Should</strong> return a drug, if phrase match concept_name No need to match both concept_name and
1558
         *         drug_name
1559
         * <strong>Should</strong> return drug when phrase match drug_name even searchDrugConceptNames is false
1560
         * <strong>Should</strong> return a drug if phrase match drug_name No need to match both concept_name and
1561
         *         drug_name
1562
         */
1563
        @Override
1564
        public List<Drug> getDrugs(String drugName, Concept concept, boolean searchKeywords, boolean searchDrugConceptNames,
1565
                boolean includeRetired, Integer start, Integer length) throws DAOException {
1566
                SearchQuery<Drug> drugsQuery = newDrugQuery(drugName, searchKeywords, searchDrugConceptNames, Context.getLocale(),
1✔
1567
                    false, concept, includeRetired);
1568
                
1569
                if (drugsQuery == null) {
1✔
1570
                        return Collections.emptyList();
×
1571
                }
1572
                
1573
                return drugsQuery.fetchHits(start, length);
1✔
1574
        }
1575
        
1576
        private SearchQuery<Drug> newDrugQuery(String drugName, boolean searchKeywords, boolean searchDrugConceptNames,
1577
                                                                                   Locale locale, boolean exactLocale, Concept concept, boolean includeRetired) {
1578
                if (StringUtils.isBlank(drugName) && concept == null) {
1✔
1579
                        return null;
×
1580
                }
1581
                final Collection<Locale> locales = Collections.singletonList(locale == null ? Context.getLocale() : locale);
1✔
1582

1583
                final List<Object> conceptIds;
1584
                if (searchDrugConceptNames) {
1✔
1585
                        SearchSession searchSession = searchSessionFactory.getSearchSession();
1✔
1586
                        SearchScope<ConceptName> scope = searchSession.scope(ConceptName.class);
1✔
1587
                        
1588
                        SearchPredicate conceptNamePredicate = newConceptNamePredicate(scope.predicate(), drugName, searchKeywords, locales, exactLocale,
1✔
1589
                                includeRetired, null, null, null, null, null);
1590

1591
                        conceptIds = SearchQueryUnique.findUniqueKeys(searchSession, scope, conceptNamePredicate, "concept.conceptId");
1✔
1592
                } else {
1✔
1593
                        conceptIds = Collections.emptyList();
1✔
1594
                }
1595
                
1596
                return searchSessionFactory.getSearchSession().search(Drug.class).where(f -> f.bool().with(b -> {
1✔
1597
                        b.minimumShouldMatchNumber(1);
1✔
1598
                        List<String> tokenizedName = tokenizeName(drugName, locales);
1✔
1599
                        BooleanPredicateClausesStep<?> nameQuery = newNameQuery(f, tokenizedName, drugName, searchKeywords);
1✔
1600
                        b.should(f.match().field("drugReferenceMaps.conceptReferenceTerm.code").matching(drugName).boost(10f));
1✔
1601
                        b.should(nameQuery.boost(0.5f));
1✔
1602
                        if (concept != null) {
1✔
1603
                                b.should(f.match().field("concept.conceptId").matching(concept.getId()).boost(0.1f));
1✔
1604
                        }
1605
                        if (!conceptIds.isEmpty()) {
1✔
1606
                                float boost = 0.1f;
1✔
1607
                                int boostItems = 10; // boost first items in order
1✔
1608
                                int i = 0;
1✔
1609
                                for (Object conceptId : conceptIds) {
1✔
1610
                                        b.should(f.match().field("concept.conceptId").matching(conceptId).boost(boost));
1✔
1611
                                        boost = boost * 0.9f;
1✔
1612
                                        i++;
1✔
1613
                                        if (boostItems == i) {
1✔
1614
                                                break;
×
1615
                                        }
1616
                                }
1✔
1617
                                if (conceptIds.size() > boostItems) {
1✔
1618
                                        b.should(f.terms().field("concept.conceptId").matchingAny(
×
1619
                                                conceptIds.subList(boostItems, conceptIds.size())).boost(boost));
×
1620
                                }
1621
                        }
1622
                        if (!includeRetired) {
1✔
1623
                                b.filter(f.match().field("retired").matching(Boolean.FALSE));
1✔
1624
                        }
1625
                })).toQuery();
1✔
1626
        }
1627

1628
        /**
1629
         * @see ConceptDAO#getConcepts(String, List, boolean, List, List, List, List, Concept, Integer,
1630
         *      Integer)
1631
         */
1632
        @Override
1633
        public List<ConceptSearchResult> getConcepts(final String phrase, final List<Locale> locales,
1634
                final boolean includeRetired, final List<ConceptClass> requireClasses, final List<ConceptClass> excludeClasses,
1635
                final List<ConceptDatatype> requireDatatypes, final List<ConceptDatatype> excludeDatatypes,
1636
                final Concept answersToConcept, final Integer start, final Integer size) throws DAOException {
1637
                
1638
                return SearchQueryUnique.search(searchSessionFactory, SearchQueryUnique.newQuery(ConceptName.class, f -> 
1✔
1639
                        newConceptNamePredicate(f, phrase, true, locales, false, includeRetired,
1✔
1640
                        requireClasses, excludeClasses, requireDatatypes, excludeDatatypes, answersToConcept), "concept.conceptId", 
1641
                        n -> new ConceptSearchResult(phrase, n.getConcept(), n)), start, size);
1✔
1642
        }
1643
        
1644
        @Override
1645
        public Integer getCountOfConcepts(final String phrase, List<Locale> locales, boolean includeRetired,
1646
                List<ConceptClass> requireClasses, List<ConceptClass> excludeClasses, List<ConceptDatatype> requireDatatypes,
1647
                List<ConceptDatatype> excludeDatatypes, Concept answersToConcept) throws DAOException {
1648
                
1649
                
1650
                return Math.toIntExact(SearchQueryUnique.searchCount(searchSessionFactory, 
1✔
1651
                        SearchQueryUnique.newQuery(ConceptName.class, f -> newConceptNamePredicate(f, phrase, 
1✔
1652
                                true, locales, false, includeRetired, requireClasses, excludeClasses, 
1653
                                requireDatatypes, excludeDatatypes, answersToConcept), "concept.conceptId")));
1654
        }
1655
        
1656
        private SearchPredicate newConceptNamePredicate(SearchPredicateFactory f, final String phrase, boolean searchKeywords,
1657
                                                                                                           Collection<Locale> locales, boolean searchExactLocale, boolean includeRetired, List<ConceptClass> requireClasses,
1658
                                                                                                           List<ConceptClass> excludeClasses, List<ConceptDatatype> requireDatatypes,
1659
                                                                                                           List<ConceptDatatype> excludeDatatypes, Concept answersToConcept) {
1660
                return f.bool().with(b -> {
1✔
1661
                        if (!StringUtils.isBlank(phrase)) {
1✔
1662
                                final Collection<Locale> searchLocales;
1663

1664
                                if (locales == null) {
1✔
1665
                                        searchLocales = Collections.singletonList(Context.getLocale());
1✔
1666
                                } else {
1667
                                        searchLocales = new HashSet<>(locales);
1✔
1668
                                }
1669

1670
                                b.must(newConceptNameQuery(f, phrase, searchKeywords, searchLocales, searchExactLocale));
1✔
1671
                        }
1672

1673
                        if (!CollectionUtils.isEmpty(requireClasses)) {
1✔
1674
                                b.filter(f.terms().field("concept.conceptClass")
1✔
1675
                                        .matchingAny(requireClasses));
1✔
1676
                        }
1677
                        if (!CollectionUtils.isEmpty(excludeClasses)) {
1✔
1678
                                b.filter(f.not(f.terms().field("concept.conceptClass")
1✔
1679
                                        .matchingAny(excludeClasses)));
1✔
1680
                        }
1681
                        if (!CollectionUtils.isEmpty(requireDatatypes)) {
1✔
1682
                                b.filter(f.terms().field("concept.datatype")
×
1683
                                        .matchingAny(requireDatatypes));
×
1684
                        }
1685
                        if (!CollectionUtils.isEmpty(excludeDatatypes)) {
1✔
1686
                                b.filter(f.not(f.terms().field("concept.datatype")
×
1687
                                        .matchingAny(excludeDatatypes)));
×
1688
                        }
1689

1690
                        if (answersToConcept != null) {
1✔
1691
                                Collection<ConceptAnswer> answers = answersToConcept.getAnswers(false);
1✔
1692

1693
                                if (answers != null && !answers.isEmpty()) {
1✔
1694
                                        List<Integer> ids = new ArrayList<>();
×
1695
                                        for (ConceptAnswer conceptAnswer : answersToConcept.getAnswers(false)) {
×
1696
                                                ids.add(conceptAnswer.getAnswerConcept().getId());
×
1697
                                        }
×
1698
                                        b.filter(f.terms().field("concept.conceptId").matchingAny(ids));
×
1699
                                }
1700
                        }
1701

1702
                        if (!includeRetired) {
1✔
1703
                                b.filter(f.match().field("concept.retired").matching(Boolean.FALSE));
1✔
1704
                        }
1705
                }).toPredicate();
1✔
1706
        }
1707

1708
        /**
1709
         * @see org.openmrs.api.db.ConceptDAO#getConceptMapTypes(boolean, boolean)
1710
         */
1711
        @Override
1712
        public List<ConceptMapType> getConceptMapTypes(boolean includeRetired, boolean includeHidden) throws DAOException {
1713
                Session session = sessionFactory.getCurrentSession();
1✔
1714
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
1715
                CriteriaQuery<ConceptMapType> cq = cb.createQuery(ConceptMapType.class);
1✔
1716
                Root<ConceptMapType> root = cq.from(ConceptMapType.class);
1✔
1717

1718
                List<Predicate> predicates = new ArrayList<>();
1✔
1719
                if (!includeRetired) {
1✔
1720
                        predicates.add(cb.isFalse(root.get("retired")));
1✔
1721
                }
1722
                if (!includeHidden) {
1✔
1723
                        predicates.add(cb.isFalse(root.get("isHidden")));
1✔
1724
                }
1725

1726
                cq.where(predicates.toArray(new Predicate[]{}));
1✔
1727

1728
                List<ConceptMapType> conceptMapTypes = session.createQuery(cq).getResultList();
1✔
1729
                conceptMapTypes.sort(new ConceptMapTypeComparator());
1✔
1730

1731
                return conceptMapTypes;
1✔
1732
        }
1733
        
1734
        /**
1735
         * @see org.openmrs.api.db.ConceptDAO#getConceptMapType(java.lang.Integer)
1736
         */
1737
        @Override
1738
        public ConceptMapType getConceptMapType(Integer conceptMapTypeId) throws DAOException {
1739
                return sessionFactory.getCurrentSession().get(ConceptMapType.class, conceptMapTypeId);
1✔
1740
        }
1741

1742
        /**
1743
         * @see org.openmrs.api.db.ConceptDAO#getConceptMapTypeByUuid(java.lang.String)
1744
         */
1745
        @Override
1746
        public ConceptMapType getConceptMapTypeByUuid(String uuid) throws DAOException {
1747
                return HibernateUtil.getUniqueEntityByUUID(sessionFactory, ConceptMapType.class, uuid);
1✔
1748
        }
1749

1750
        /**
1751
         * @see org.openmrs.api.db.ConceptDAO#getConceptMapTypeByName(java.lang.String)
1752
         */
1753
        @Override
1754
        public ConceptMapType getConceptMapTypeByName(String name) throws DAOException {
1755
                Session session = sessionFactory.getCurrentSession();
1✔
1756
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
1757
                CriteriaQuery<ConceptMapType> cq = cb.createQuery(ConceptMapType.class);
1✔
1758
                Root<ConceptMapType> root = cq.from(ConceptMapType.class);
1✔
1759

1760
                cq.where(cb.like(cb.lower(root.get("name")), MatchMode.EXACT.toLowerCasePattern(name)));
1✔
1761

1762
                return session.createQuery(cq).uniqueResult();
1✔
1763
        }
1764
        
1765
        /**
1766
         * @see org.openmrs.api.db.ConceptDAO#saveConceptMapType(org.openmrs.ConceptMapType)
1767
         */
1768
        @Override
1769
        public ConceptMapType saveConceptMapType(ConceptMapType conceptMapType) throws DAOException {
1770
                sessionFactory.getCurrentSession().saveOrUpdate(conceptMapType);
1✔
1771
                return conceptMapType;
1✔
1772
        }
1773
        
1774
        /**
1775
         * @see org.openmrs.api.db.ConceptDAO#deleteConceptMapType(org.openmrs.ConceptMapType)
1776
         */
1777
        @Override
1778
        public void deleteConceptMapType(ConceptMapType conceptMapType) throws DAOException {
1779
                sessionFactory.getCurrentSession().delete(conceptMapType);
1✔
1780
        }
1✔
1781

1782
        /**
1783
         * @see org.openmrs.api.db.ConceptDAO#getConceptReferenceTerms(boolean)
1784
         */
1785
        @Override
1786
        public List<ConceptReferenceTerm> getConceptReferenceTerms(boolean includeRetired) throws DAOException {
1787
                Session session = sessionFactory.getCurrentSession();
1✔
1788
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
1789
                CriteriaQuery<ConceptReferenceTerm> cq = cb.createQuery(ConceptReferenceTerm.class);
1✔
1790
                Root<ConceptReferenceTerm> root = cq.from(ConceptReferenceTerm.class);
1✔
1791

1792
                if (!includeRetired) {
1✔
1793
                        cq.where(cb.isFalse(root.get("retired")));
1✔
1794
                }
1795
                return session.createQuery(cq).getResultList();
1✔
1796
        }
1797
        
1798
        /**
1799
         * @see org.openmrs.api.db.ConceptDAO#getConceptReferenceTerm(java.lang.Integer)
1800
         */
1801
        @Override
1802
        public ConceptReferenceTerm getConceptReferenceTerm(Integer conceptReferenceTermId) throws DAOException {
1803
                return sessionFactory.getCurrentSession().get(ConceptReferenceTerm.class,
1✔
1804
                    conceptReferenceTermId);
1805
        }
1806

1807
        /**
1808
         * @see org.openmrs.api.db.ConceptDAO#getConceptReferenceTermByUuid(java.lang.String)
1809
         */
1810
        @Override
1811
        public ConceptReferenceTerm getConceptReferenceTermByUuid(String uuid) throws DAOException {
1812
                return HibernateUtil.getUniqueEntityByUUID(sessionFactory, ConceptReferenceTerm.class, uuid);
1✔
1813
        }
1814
        
1815
        /**
1816
         * @see org.openmrs.api.db.ConceptDAO#getConceptReferenceTermsBySource(ConceptSource)
1817
         */
1818
        @Override
1819
        public List<ConceptReferenceTerm> getConceptReferenceTermsBySource(ConceptSource conceptSource) throws DAOException {
1820
                Session session = sessionFactory.getCurrentSession();
×
1821
                CriteriaBuilder cb = session.getCriteriaBuilder();
×
1822
                CriteriaQuery<ConceptReferenceTerm> cq = cb.createQuery(ConceptReferenceTerm.class);
×
1823
                Root<ConceptReferenceTerm> root = cq.from(ConceptReferenceTerm.class);
×
1824

NEW
1825
                cq.where(cb.equal(root.get(CONCEPT_SOURCE), conceptSource));
×
1826

1827
                return session.createQuery(cq).getResultList();
×
1828
        }
1829

1830
        /**
1831
         * @see org.openmrs.api.db.ConceptDAO#getConceptReferenceTermByName(java.lang.String,
1832
         *      org.openmrs.ConceptSource)
1833
         */
1834
        @Override
1835
        public ConceptReferenceTerm getConceptReferenceTermByName(String name, ConceptSource conceptSource) throws DAOException {
1836
                Session session = sessionFactory.getCurrentSession();
1✔
1837
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
1838
                CriteriaQuery<ConceptReferenceTerm> cq = cb.createQuery(ConceptReferenceTerm.class);
1✔
1839
                Root<ConceptReferenceTerm> root = cq.from(ConceptReferenceTerm.class);
1✔
1840

1841
                Predicate namePredicate = cb.like(cb.lower(root.get("name")), MatchMode.EXACT.toLowerCasePattern(name));
1✔
1842
                Predicate sourcePredicate = cb.equal(root.get(CONCEPT_SOURCE), conceptSource);
1✔
1843

1844
                cq.where(cb.and(namePredicate, sourcePredicate));
1✔
1845

1846
                List<ConceptReferenceTerm> terms = session.createQuery(cq).getResultList();
1✔
1847
                if (terms.isEmpty()) {
1✔
1848
                        return null;
×
1849
                } else if (terms.size() > 1) {
1✔
1850
                        throw new APIException("ConceptReferenceTerm.foundMultipleTermsWithNameInSource",
×
1851
                                new Object[]{name, conceptSource.getName()});
×
1852
                }
1853
                return terms.get(0);
1✔
1854
        }
1855
        
1856
        /**
1857
         * @see org.openmrs.api.db.ConceptDAO#getConceptReferenceTermByCode(java.lang.String,
1858
         *      org.openmrs.ConceptSource)
1859
         */
1860
        @Override
1861
        public ConceptReferenceTerm getConceptReferenceTermByCode(String code, ConceptSource conceptSource) throws DAOException {
1862
                List<ConceptReferenceTerm> conceptReferenceTerms = getConceptReferenceTermByCode(code, conceptSource, true);
1✔
1863
                
1864
                if (conceptReferenceTerms.isEmpty()) {
1✔
1865
                        return null;
1✔
1866
                } else if (conceptReferenceTerms.size() > 1) {
1✔
1867
                        List<ConceptReferenceTerm> unretiredConceptReferenceTerms = conceptReferenceTerms.stream()
1✔
1868
                                .filter(term -> !term.getRetired())
1✔
1869
                                        .collect(toList());
1✔
1870
                        if (unretiredConceptReferenceTerms.size() == 1) {
1✔
1871
                                return unretiredConceptReferenceTerms.get(0);
1✔
1872
                        }
1873
                        
1874
                        // either more than one unretired concept term or more than one retired concept term
1875
                        throw new APIException("ConceptReferenceTerm.foundMultipleTermsWithCodeInSource",
×
1876
                                new Object[] { code, conceptSource.getName() });
×
1877
                }
1878
                
1879
                return conceptReferenceTerms.get(0);
1✔
1880
        }
1881

1882
        /**
1883
         * @see org.openmrs.api.db.ConceptDAO#getConceptReferenceTermByCode(java.lang.String,
1884
         *      org.openmrs.ConceptSource, boolean)
1885
         */
1886
        @Override
1887
        public List<ConceptReferenceTerm> getConceptReferenceTermByCode(String code, ConceptSource conceptSource,
1888
                boolean includeRetired) throws DAOException {
1889
                Session session = sessionFactory.getCurrentSession();
1✔
1890
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
1891
                CriteriaQuery<ConceptReferenceTerm> cq = cb.createQuery(ConceptReferenceTerm.class);
1✔
1892
                Root<ConceptReferenceTerm> root = cq.from(ConceptReferenceTerm.class);
1✔
1893

1894
                List<Predicate> predicates = new ArrayList<>();
1✔
1895
                predicates.add(cb.equal(root.get("code"), code));
1✔
1896
                predicates.add(cb.equal(root.get(CONCEPT_SOURCE), conceptSource));
1✔
1897

1898
                if (!includeRetired) {
1✔
1899
                        predicates.add(cb.isFalse(root.get("retired")));
1✔
1900
                }
1901
                cq.where(predicates.toArray(new Predicate[]{}));
1✔
1902

1903
                return session.createQuery(cq).getResultList();
1✔
1904
        }
1905
        
1906
        /**
1907
         * @see org.openmrs.api.db.ConceptDAO#saveConceptReferenceTerm(org.openmrs.ConceptReferenceTerm)
1908
         */
1909
        @Override
1910
        public ConceptReferenceTerm saveConceptReferenceTerm(ConceptReferenceTerm conceptReferenceTerm) throws DAOException {
1911
                sessionFactory.getCurrentSession().saveOrUpdate(conceptReferenceTerm);
1✔
1912
                return conceptReferenceTerm;
1✔
1913
        }
1914
        
1915
        /**
1916
         * @see org.openmrs.api.db.ConceptDAO#deleteConceptReferenceTerm(org.openmrs.ConceptReferenceTerm)
1917
         */
1918
        @Override
1919
        public void deleteConceptReferenceTerm(ConceptReferenceTerm conceptReferenceTerm) throws DAOException {
1920
                sessionFactory.getCurrentSession().delete(conceptReferenceTerm);
1✔
1921
        }
1✔
1922

1923
        @Override
1924
        public Long getCountOfConceptReferenceTerms(String query, ConceptSource conceptSource, boolean includeRetired)
1925
                throws DAOException {
1926
                Session session = sessionFactory.getCurrentSession();
1✔
1927
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
1928
                CriteriaQuery<Long> cq = cb.createQuery(Long.class);
1✔
1929
                Root<ConceptReferenceTerm> root = cq.from(ConceptReferenceTerm.class);
1✔
1930

1931
                List<Predicate> predicates = createConceptReferenceTermPredicates(cb, root, query, conceptSource, includeRetired);
1✔
1932

1933
                cq.where(predicates.toArray(new Predicate[]{})).select(cb.count(root));
1✔
1934

1935
                return session.createQuery(cq).getSingleResult();
1✔
1936
        }
1937

1938

1939
        /**
1940
         * @see org.openmrs.api.db.ConceptDAO#getConceptReferenceTerms(String, ConceptSource, Integer,
1941
         *      Integer, boolean)
1942
         */
1943
        @Override
1944
        public List<ConceptReferenceTerm> getConceptReferenceTerms(String query, ConceptSource conceptSource, Integer start,
1945
                                                                                                                           Integer length, boolean includeRetired) throws APIException {
1946
                Session session = sessionFactory.getCurrentSession();
1✔
1947
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
1948
                CriteriaQuery<ConceptReferenceTerm> cq = cb.createQuery(ConceptReferenceTerm.class);
1✔
1949
                Root<ConceptReferenceTerm> root = cq.from(ConceptReferenceTerm.class);
1✔
1950

1951
                List<Predicate> predicates = createConceptReferenceTermPredicates(cb, root, query, conceptSource, includeRetired);
1✔
1952
                cq.where(predicates.toArray(new Predicate[]{}));
1✔
1953

1954
                TypedQuery<ConceptReferenceTerm> typedQuery = session.createQuery(cq);
1✔
1955

1956
                if (start != null) {
1✔
1957
                        typedQuery.setFirstResult(start);
1✔
1958
                }
1959
                if (length != null && length > 0) {
1✔
1960
                        typedQuery.setMaxResults(length);
1✔
1961
                }
1962

1963
                return typedQuery.getResultList();
1✔
1964
        }
1965

1966
        private List<Predicate> createConceptReferenceTermPredicates(CriteriaBuilder cb, Root<ConceptReferenceTerm> root,
1967
                                                                                                                                 String query, ConceptSource conceptSource, boolean includeRetired) {
1968
                List<Predicate> predicates = new ArrayList<>();
1✔
1969

1970
                if (conceptSource != null) {
1✔
1971
                        predicates.add(cb.equal(root.get(CONCEPT_SOURCE), conceptSource));
1✔
1972
                }
1973
                if (!includeRetired) {
1✔
1974
                        predicates.add(cb.isFalse(root.get("retired")));
1✔
1975
                }
1976
                if (query != null) {
1✔
1977
                        Predicate namePredicate = cb.like(cb.lower(root.get("name")), MatchMode.ANYWHERE.toLowerCasePattern(query));
1✔
1978
                        Predicate codePredicate = cb.like(cb.lower(root.get("code")), MatchMode.ANYWHERE.toLowerCasePattern(query));
1✔
1979

1980
                        predicates.add(cb.or(namePredicate, codePredicate));
1✔
1981
                }
1982

1983
                return predicates;
1✔
1984
        }
1985

1986
        /**
1987
         * @see org.openmrs.api.db.ConceptDAO#getReferenceTermMappingsTo(ConceptReferenceTerm)
1988
         */
1989
        @Override
1990
        public List<ConceptReferenceTermMap> getReferenceTermMappingsTo(ConceptReferenceTerm term) throws DAOException {
1991
                Session session = sessionFactory.getCurrentSession();
1✔
1992
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
1993
                CriteriaQuery<ConceptReferenceTermMap> cq = cb.createQuery(ConceptReferenceTermMap.class);
1✔
1994
                Root<ConceptReferenceTermMap> root = cq.from(ConceptReferenceTermMap.class);
1✔
1995

1996
                cq.where(cb.equal(root.get("termB"), term));
1✔
1997

1998
                return session.createQuery(cq).getResultList();
1✔
1999
        }
2000

2001
        /**
2002
         * @see org.openmrs.api.db.ConceptDAO#isConceptReferenceTermInUse(org.openmrs.ConceptReferenceTerm)
2003
         */
2004
        @Override
2005
        public boolean isConceptReferenceTermInUse(ConceptReferenceTerm term) throws DAOException {
2006
                Session session = sessionFactory.getCurrentSession();
1✔
2007
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
2008

2009
                // Check in ConceptMap table
2010
                CriteriaQuery<Long> conceptMapQuery = cb.createQuery(Long.class);
1✔
2011
                Root<ConceptMap> conceptMapRoot = conceptMapQuery.from(ConceptMap.class);
1✔
2012
                conceptMapQuery.select(cb.count(conceptMapRoot));
1✔
2013
                conceptMapQuery.where(cb.equal(conceptMapRoot.get(CONCEPT_REFERENCE_TERM), term));
1✔
2014

2015
                Long conceptMapCount = session.createQuery(conceptMapQuery).uniqueResult();
1✔
2016
                if (conceptMapCount > 0) {
1✔
2017
                        return true;
1✔
2018
                }
2019

2020
                // Check in ConceptReferenceTermMap table
2021
                CriteriaQuery<Long> conceptReferenceTermMapQuery = cb.createQuery(Long.class);
1✔
2022
                Root<ConceptReferenceTermMap> conceptReferenceTermMapRoot =
1✔
2023
                        conceptReferenceTermMapQuery.from(ConceptReferenceTermMap.class);
1✔
2024
                conceptReferenceTermMapQuery.select(cb.count(conceptReferenceTermMapRoot));
1✔
2025
                conceptReferenceTermMapQuery.where(cb.equal(conceptReferenceTermMapRoot.get("termB"), term));
1✔
2026

2027
                Long conceptReferenceTermMapCount = session.createQuery(conceptReferenceTermMapQuery).uniqueResult();
1✔
2028
                return conceptReferenceTermMapCount > 0;
1✔
2029
        }
2030

2031
        /**
2032
         * @see org.openmrs.api.db.ConceptDAO#isConceptMapTypeInUse(org.openmrs.ConceptMapType)
2033
         */
2034
        @Override
2035
        public boolean isConceptMapTypeInUse(ConceptMapType mapType) throws DAOException {
2036
                Session session = sessionFactory.getCurrentSession();
1✔
2037
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
2038

2039
                // Check in ConceptMap table
2040
                CriteriaQuery<Long> conceptQuery = cb.createQuery(Long.class);
1✔
2041
                Root<ConceptMap> conceptRoot = conceptQuery.from(ConceptMap.class);
1✔
2042
                conceptQuery.select(cb.count(conceptRoot));
1✔
2043
                conceptQuery.where(cb.equal(conceptRoot.get("conceptMapType"), mapType));
1✔
2044

2045
                Long conceptCount = session.createQuery(conceptQuery).uniqueResult();
1✔
2046
                if (conceptCount > 0) {
1✔
2047
                        return true;
1✔
2048
                }
2049

2050
                // Check in ConceptReferenceTermMap table
2051
                CriteriaQuery<Long> conceptReferenceTermMapQuery = cb.createQuery(Long.class);
1✔
2052
                Root<ConceptReferenceTermMap> conceptReferenceTermMapRoot = conceptReferenceTermMapQuery.from(ConceptReferenceTermMap.class);
1✔
2053
                conceptReferenceTermMapQuery.select(cb.count(conceptReferenceTermMapRoot));
1✔
2054
                conceptReferenceTermMapQuery.where(cb.equal(conceptReferenceTermMapRoot.get("conceptMapType"), mapType));
1✔
2055

2056
                Long conceptReferenceTermMapCount = session.createQuery(conceptReferenceTermMapQuery).uniqueResult();
1✔
2057
                return conceptReferenceTermMapCount > 0;
1✔
2058
        }
2059
        
2060
        /**
2061
         * @see org.openmrs.api.db.ConceptDAO#getConceptsByName(java.lang.String, java.util.Locale,
2062
         *      java.lang.Boolean)
2063
         */
2064
        @Override
2065
        public List<Concept> getConceptsByName(final String name, final Locale locale, final Boolean exactLocale) {
2066
                
2067
                List<Locale> locales = new ArrayList<>();
1✔
2068
                if (locale == null) {
1✔
2069
                        locales.add(Context.getLocale());
×
2070
                } else {
2071
                        locales.add(locale);
1✔
2072
                }
2073
                
2074
                boolean searchExactLocale = (exactLocale == null) ? false : exactLocale;
1✔
2075
                
2076
                return SearchQueryUnique.search(searchSessionFactory, SearchQueryUnique.newQuery(ConceptName.class, f -> 
1✔
2077
                        newConceptNamePredicate(f, name, true, locales, searchExactLocale, false,
1✔
2078
                        null, null, null, null, null), 
2079
                        "concept.conceptId", ConceptName::getConcept));
2080
        }
2081
        
2082
        /**
2083
         * @see org.openmrs.api.db.ConceptDAO#getConceptByName(java.lang.String)
2084
         */
2085
        @Override
2086
        public Concept getConceptByName(final String name) {
2087
                Session session = sessionFactory.getCurrentSession();
1✔
2088
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
2089
                CriteriaQuery<ConceptName> cq = cb.createQuery(ConceptName.class);
1✔
2090
                Root<ConceptName> root = cq.from(ConceptName.class);
1✔
2091
                Join<ConceptName, Concept> conceptJoin = root.join("concept");
1✔
2092

2093
                Locale locale = Context.getLocale();
1✔
2094
                Locale language = new Locale(locale.getLanguage() + "%");
1✔
2095
                List<Predicate> predicates = new ArrayList<>();
1✔
2096

2097
                predicates.add(cb.or(cb.equal(root.get("locale"), locale), cb.like(root.get("locale").as(String.class), language.toString())));
1✔
2098
                if (Context.getAdministrationService().isDatabaseStringComparisonCaseSensitive()) {
1✔
2099
                        predicates.add(cb.like(cb.lower(root.get("name")), name.toLowerCase()));
1✔
2100
                } else {
2101
                        predicates.add(cb.equal(root.get("name"), name));
×
2102
                }
2103
                predicates.add(cb.isFalse(root.get("voided")));
1✔
2104
                predicates.add(cb.isFalse(conceptJoin.get("retired")));
1✔
2105

2106
                cq.where(predicates.toArray(new Predicate[0]));
1✔
2107

2108
                List<ConceptName> list = session.createQuery(cq).getResultList();
1✔
2109
                LinkedHashSet<Concept> concepts = transformNamesToConcepts(list);
1✔
2110

2111
                if (concepts.size() == 1) {
1✔
2112
                        return concepts.iterator().next();
1✔
UNCOV
2113
                } else if (list.isEmpty()) {
×
UNCOV
2114
                        log.warn("No concept found for '" + name + "'");
×
2115
                } else {
2116
                        log.warn("Multiple concepts found for '" + name + "'");
×
2117

2118
                        for (Concept concept : concepts) {
×
2119
                                for (ConceptName conceptName : concept.getNames(locale)) {
×
2120
                                        if (conceptName.getName().equalsIgnoreCase(name)) {
×
2121
                                                return concept;
×
2122
                                        }
2123
                                }
×
2124
                                for (ConceptName indexTerm : concept.getIndexTermsForLocale(locale)) {
×
2125
                                        if (indexTerm.getName().equalsIgnoreCase(name)) {
×
2126
                                                return concept;
×
2127
                                        }
2128
                                }
×
2129
                        }
×
2130
                }
2131

UNCOV
2132
                return null;
×
2133
        }
2134
        
2135
        /**
2136
         * @see org.openmrs.api.db.ConceptDAO#getDefaultConceptMapType()
2137
         */
2138
        @Override
2139
        public ConceptMapType getDefaultConceptMapType() throws DAOException {
2140
                FlushMode previousFlushMode = sessionFactory.getCurrentSession().getHibernateFlushMode();
1✔
2141
                sessionFactory.getCurrentSession().setHibernateFlushMode(FlushMode.MANUAL);
1✔
2142
                try {
2143
                        //Defaults to same-as if the gp is not set.
2144
                        String defaultConceptMapType = Context.getAdministrationService().getGlobalProperty(
1✔
2145
                            OpenmrsConstants.GP_DEFAULT_CONCEPT_MAP_TYPE);
2146
                        if (defaultConceptMapType == null) {
1✔
2147
                                throw new DAOException("The default concept map type is not set. You need to set the '"
×
2148
                                        + OpenmrsConstants.GP_DEFAULT_CONCEPT_MAP_TYPE + "' global property.");
2149
                        }
2150
                        
2151
                        ConceptMapType conceptMapType = getConceptMapTypeByName(defaultConceptMapType);
1✔
2152
                        if (conceptMapType == null) {
1✔
2153
                                throw new DAOException("The default concept map type (name: " + defaultConceptMapType
×
2154
                                        + ") does not exist! You need to set the '" + OpenmrsConstants.GP_DEFAULT_CONCEPT_MAP_TYPE
2155
                                        + "' global property.");
2156
                        }
2157
                        return conceptMapType;
1✔
2158
                }
2159
                finally {
2160
                        sessionFactory.getCurrentSession().setHibernateFlushMode(previousFlushMode);
1✔
2161
                }
2162
        }
2163

2164
        /**
2165
         * @see org.openmrs.api.db.ConceptDAO#isConceptNameDuplicate(org.openmrs.ConceptName)
2166
         */
2167
        @Override
2168
        public boolean isConceptNameDuplicate(ConceptName name) {
2169
                if (name.getVoided()) {
1✔
2170
                        return false;
×
2171
                }
2172
                if (name.getConcept() != null) {
1✔
2173
                        if (name.getConcept().getRetired()) {
1✔
2174
                                return false;
×
2175
                        }
2176

2177
                        //If it is not a default name of a concept, it cannot be a duplicate.
2178
                        //Note that a concept may not have a default name for the given locale, if just a short name or
2179
                        //a search term is set.
2180
                        if (!name.equals(name.getConcept().getName(name.getLocale()))) {
1✔
2181
                                return false;
1✔
2182
                        }
2183
                }
2184

2185
                Session session = sessionFactory.getCurrentSession();
1✔
2186
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
2187
                CriteriaQuery<ConceptName> cq = cb.createQuery(ConceptName.class);
1✔
2188
                Root<ConceptName> root = cq.from(ConceptName.class);
1✔
2189

2190
                List<Predicate> predicates = new ArrayList<>();
1✔
2191

2192
                predicates.add(cb.isFalse(root.get("voided")));
1✔
2193
                predicates.add(cb.or(cb.equal(root.get("locale"), name.getLocale()),
1✔
2194
                        cb.equal(root.get("locale"), new Locale(name.getLocale().getLanguage()))));
1✔
2195

2196
                if (Context.getAdministrationService().isDatabaseStringComparisonCaseSensitive()) {
1✔
2197
                        predicates.add(cb.equal(cb.lower(root.get("name")), name.getName().toLowerCase()));
1✔
2198
                } else {
2199
                        predicates.add(cb.equal(root.get("name"), name.getName()));
×
2200
                }
2201

2202
                cq.where(predicates.toArray(new Predicate[0]));
1✔
2203

2204
                List<ConceptName> candidateNames = session.createQuery(cq).getResultList();
1✔
2205

2206
                for (ConceptName candidateName : candidateNames) {
1✔
2207
                        if (candidateName.getConcept().getRetired()) {
1✔
2208
                                continue;
1✔
2209
                        }
2210
                        if (candidateName.getConcept().equals(name.getConcept())) {
1✔
2211
                                continue;
1✔
2212
                        }
2213
                        // If it is a default name for a concept
2214
                        if (candidateName.getConcept().getName(candidateName.getLocale()).equals(candidateName)) {
1✔
2215
                                return true;
1✔
2216
                        }
2217
                }
1✔
2218

2219
                return false;
1✔
2220
        }
2221
        
2222
        /**
2223
         * @see ConceptDAO#getDrugs(String, java.util.Locale, boolean, boolean)
2224
         */
2225
        @Override
2226
        public List<Drug> getDrugs(String searchPhrase, Locale locale, boolean exactLocale, boolean includeRetired) {
2227
                SearchQuery<Drug> drugQuery = newDrugQuery(searchPhrase, true, true, locale, exactLocale, null, includeRetired);
1✔
2228
                
2229
                return drugQuery.fetchAllHits();
1✔
2230
        }
2231

2232
        /**
2233
         * @see org.openmrs.api.db.ConceptDAO#getDrugsByMapping(String, ConceptSource, Collection, boolean)
2234
         */
2235
        @Override
2236
        public List<Drug> getDrugsByMapping(String code, ConceptSource conceptSource,
2237
                                                                                Collection<ConceptMapType> withAnyOfTheseTypes, boolean includeRetired) throws DAOException {
2238

2239
                Session session = sessionFactory.getCurrentSession();
1✔
2240
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
2241
                CriteriaQuery<Drug> cq = cb.createQuery(Drug.class);
1✔
2242
                Root<Drug> drugRoot = cq.from(Drug.class);
1✔
2243

2244
                Join<Drug, DrugReferenceMap> drugReferenceMapJoin = drugRoot.join("drugReferenceMaps");
1✔
2245
                Join<DrugReferenceMap, ConceptReferenceTerm> termJoin = drugReferenceMapJoin.join(CONCEPT_REFERENCE_TERM);
1✔
2246
                List<Predicate> basePredicates = createSearchDrugByMappingPredicates(cb, drugRoot, drugReferenceMapJoin, termJoin,
1✔
2247
                    code, conceptSource, includeRetired);
2248

2249
                if (!withAnyOfTheseTypes.isEmpty()) {
1✔
2250
                        // Create a predicate to check if the ConceptMapType is in the provided collection
2251
                        Predicate mapTypePredicate = drugReferenceMapJoin.get("conceptMapType").in(withAnyOfTheseTypes);
1✔
2252
                        basePredicates.add(mapTypePredicate);
1✔
2253
                }
2254

2255
                cq.where(basePredicates.toArray(new Predicate[]{}));
1✔
2256

2257
                return session.createQuery(cq).getResultList().stream().distinct().collect(toList());
1✔
2258
        }
2259

2260
        /**
2261
         * @see org.openmrs.api.db.ConceptDAO#getDrugs
2262
         */
2263
        @Override
2264
        public Drug getDrugByMapping(String code, ConceptSource conceptSource,
2265
                                                                 Collection<ConceptMapType> withAnyOfTheseTypesOrOrderOfPreference) throws DAOException {
2266
                Session session = sessionFactory.getCurrentSession();
1✔
2267
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
2268
                CriteriaQuery<Drug> cq = cb.createQuery(Drug.class);
1✔
2269
                Root<Drug> drugRoot = cq.from(Drug.class);
1✔
2270

2271
                Join<Drug, DrugReferenceMap> drugReferenceMapJoin = drugRoot.join("drugReferenceMaps");
1✔
2272
                Join<DrugReferenceMap, ConceptReferenceTerm> termJoin = drugReferenceMapJoin.join("conceptReferenceTerm");
1✔
2273

2274
                List<Predicate> basePredicates = createSearchDrugByMappingPredicates(cb, drugRoot, drugReferenceMapJoin, termJoin, code, conceptSource, true);
1✔
2275

2276
                if (!withAnyOfTheseTypesOrOrderOfPreference.isEmpty()) {
1✔
2277
                        for (ConceptMapType conceptMapType : withAnyOfTheseTypesOrOrderOfPreference) {
1✔
2278
                                List<Predicate> predicates = new ArrayList<>(basePredicates);
1✔
2279
                                predicates.add(cb.equal(drugReferenceMapJoin.get("conceptMapType"), conceptMapType));
1✔
2280
                                cq.where(predicates.toArray(new Predicate[]{}));
1✔
2281

2282
                                TypedQuery<Drug> query = session.createQuery(cq);
1✔
2283
                                List<Drug> drugs = query.getResultList();
1✔
2284
                                if (drugs.size() > 1) {
1✔
2285
                                        throw new DAOException("There are multiple matches for the highest-priority ConceptMapType");
1✔
2286
                                } else if (drugs.size() == 1) {
1✔
2287
                                        return drugs.get(0);
1✔
2288
                                }
2289
                        }
1✔
2290
                } else {
2291
                        cq.where(basePredicates.toArray(new Predicate[]{}));
1✔
2292

2293
                        TypedQuery<Drug> query = session.createQuery(cq);
1✔
2294
                        List<Drug> drugs = query.getResultList();
1✔
2295
                        if (drugs.size() > 1) {
1✔
2296
                                throw new DAOException("There are multiple matches for the highest-priority ConceptMapType");
×
2297
                        } else if (drugs.size() == 1) {
1✔
2298
                                return drugs.get(0);
1✔
2299
                        }
2300
                }
2301
                return null;
1✔
2302
        }
2303

2304

2305
        /**
2306
         * @see ConceptDAO#getAllConceptAttributeTypes()
2307
         */
2308
        @Override
2309
        public List<ConceptAttributeType> getAllConceptAttributeTypes() {
2310
                Session session = sessionFactory.getCurrentSession();
1✔
2311
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
2312
                CriteriaQuery<ConceptAttributeType> cq = cb.createQuery(ConceptAttributeType.class);
1✔
2313
                cq.from(ConceptAttributeType.class);
1✔
2314

2315
                return session.createQuery(cq).getResultList();
1✔
2316
        }
2317

2318
        /**
2319
         * @see ConceptDAO#saveConceptAttributeType(ConceptAttributeType)
2320
         */
2321
        @Override
2322
        public ConceptAttributeType saveConceptAttributeType(ConceptAttributeType conceptAttributeType) {
2323
                sessionFactory.getCurrentSession().saveOrUpdate(conceptAttributeType);
1✔
2324
                return conceptAttributeType;
1✔
2325
        }
2326

2327
        /**
2328
         * @see ConceptDAO#getConceptAttributeType(Integer)
2329
         */
2330
        @Override
2331
        public ConceptAttributeType getConceptAttributeType(Integer id) {
2332
                return sessionFactory.getCurrentSession().get(ConceptAttributeType.class, id);
1✔
2333
        }
2334

2335
        /**
2336
         * @see ConceptDAO#getConceptAttributeTypeByUuid(String)
2337
         */
2338
        @Override
2339
        public ConceptAttributeType getConceptAttributeTypeByUuid(String uuid) {
2340
                return HibernateUtil.getUniqueEntityByUUID(sessionFactory, ConceptAttributeType.class, uuid);
1✔
2341
        }
2342

2343
        /**
2344
         * @see org.openmrs.api.db.ConceptDAO#deleteConceptAttributeType(org.openmrs.ConceptAttributeType)
2345
         */
2346
        @Override
2347
        public void deleteConceptAttributeType(ConceptAttributeType conceptAttributeType) {
2348
                sessionFactory.getCurrentSession().delete(conceptAttributeType);
1✔
2349
        }
1✔
2350

2351
        /**
2352
         * @see org.openmrs.api.db.ConceptDAO#getConceptAttributeTypes(String)
2353
         */
2354
        @Override
2355
        public List<ConceptAttributeType> getConceptAttributeTypes(String name) {
2356
                Session session = sessionFactory.getCurrentSession();
1✔
2357
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
2358
                CriteriaQuery<ConceptAttributeType> cq = cb.createQuery(ConceptAttributeType.class);
1✔
2359
                Root<ConceptAttributeType> root = cq.from(ConceptAttributeType.class);
1✔
2360

2361
                //match name anywhere and case insensitive
2362
                if (name != null) {
1✔
2363
                        cq.where(cb.like(cb.lower(root.get("name")), MatchMode.ANYWHERE.toLowerCasePattern(name)));
1✔
2364
                }
2365

2366
                return session.createQuery(cq).getResultList();
1✔
2367
        }
2368

2369
        /**
2370
         * @see org.openmrs.api.db.ConceptDAO#getConceptAttributeTypeByName(String)
2371
         */
2372
        @Override
2373
        public ConceptAttributeType getConceptAttributeTypeByName(String exactName) {
2374
                Session session = sessionFactory.getCurrentSession();
1✔
2375
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
2376
                CriteriaQuery<ConceptAttributeType> cq = cb.createQuery(ConceptAttributeType.class);
1✔
2377
                Root<ConceptAttributeType> root = cq.from(ConceptAttributeType.class);
1✔
2378

2379
                cq.where(cb.equal(root.get("name"), exactName));
1✔
2380

2381
                return session.createQuery(cq).uniqueResult();
1✔
2382
        }
2383

2384
        /**
2385
         * @see ConceptDAO#getConceptAttributeByUuid(String)
2386
         */
2387
        @Override
2388
        public ConceptAttribute getConceptAttributeByUuid(String uuid) {
2389
                return HibernateUtil.getUniqueEntityByUUID(sessionFactory, ConceptAttribute.class, uuid);
1✔
2390
        }
2391

2392
        /**
2393
         * @see ConceptDAO#getConceptAttributeCount(ConceptAttributeType)
2394
         */
2395
        @Override
2396
        public long getConceptAttributeCount(ConceptAttributeType conceptAttributeType) {
2397
                Session session = sessionFactory.getCurrentSession();
1✔
2398
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
2399
                CriteriaQuery<Long> cq = cb.createQuery(Long.class);
1✔
2400
                Root<ConceptAttribute> root = cq.from(ConceptAttribute.class);
1✔
2401

2402
                cq.select(cb.count(root)).where(cb.equal(root.get("attributeType"), conceptAttributeType));
1✔
2403

2404
                return session.createQuery(cq).getSingleResult();
1✔
2405
        }
2406

2407
        @Override
2408
        public List<Concept> getConceptsByClass(ConceptClass conceptClass) {
2409
                Session session = sessionFactory.getCurrentSession();
1✔
2410
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
2411
                CriteriaQuery<Concept> cq = cb.createQuery(Concept.class);
1✔
2412
                Root<Concept> root = cq.from(Concept.class);
1✔
2413

2414
                cq.where(cb.equal(root.get("conceptClass"), conceptClass));
1✔
2415

2416
                return session.createQuery(cq).getResultList();
1✔
2417
        }
2418

2419
        private List<Predicate> createSearchDrugByMappingPredicates(CriteriaBuilder cb, Root<Drug> drugRoot, Join<Drug, DrugReferenceMap> drugReferenceMapJoin,
2420
                                                                                                                                Join<DrugReferenceMap, ConceptReferenceTerm> termJoin,
2421
                                                                                                                                String code, ConceptSource conceptSource, boolean includeRetired) {
2422
                List<Predicate> predicates = new ArrayList<>();
1✔
2423
                
2424
                if (code != null) {
1✔
2425
                        predicates.add(cb.equal(termJoin.get("code"), code));
1✔
2426
                }
2427
                if (conceptSource != null) {
1✔
2428
                        predicates.add(cb.equal(termJoin.get(CONCEPT_SOURCE), conceptSource));
1✔
2429
                }
2430
                if (!includeRetired) {
1✔
2431
                        predicates.add(cb.isFalse(drugRoot.get("retired")));
1✔
2432
                }
2433

2434
                return predicates;
1✔
2435
        }
2436

2437
        private List<Predicate> createSearchConceptMapCriteria(CriteriaBuilder cb, Root<ConceptMap> root, String code, String sourceName, boolean includeRetired) {
2438
                List<Predicate> predicates = new ArrayList<>();
1✔
2439

2440
                Join<ConceptMap, ConceptReferenceTerm> termJoin = root.join(CONCEPT_REFERENCE_TERM);
1✔
2441

2442
                // Match the source code to the passed code
2443
                if (Context.getAdministrationService().isDatabaseStringComparisonCaseSensitive()) {
1✔
2444
                        predicates.add(cb.equal(cb.lower(termJoin.get("code")), code.toLowerCase()));
1✔
2445
                } else {
2446
                        predicates.add(cb.equal(termJoin.get("code"), code));
×
2447
                }
2448

2449
                // Join to concept reference source and match to the hl7Code or source name
2450
                Join<ConceptReferenceTerm, ConceptSource> sourceJoin = termJoin.join(CONCEPT_SOURCE);
1✔
2451

2452
                Predicate namePredicate = Context.getAdministrationService().isDatabaseStringComparisonCaseSensitive()
1✔
2453
                        ? cb.equal(cb.lower(sourceJoin.get("name")), sourceName.toLowerCase())
1✔
2454
                        : cb.equal(sourceJoin.get("name"), sourceName);
1✔
2455
                Predicate hl7CodePredicate = Context.getAdministrationService().isDatabaseStringComparisonCaseSensitive()
1✔
2456
                        ? cb.equal(cb.lower(sourceJoin.get(HL7_CODE)), sourceName.toLowerCase())
1✔
2457
                        : cb.equal(sourceJoin.get(HL7_CODE), sourceName);
1✔
2458

2459
                predicates.add(cb.or(namePredicate, hl7CodePredicate));
1✔
2460

2461
                // Join to concept and filter retired ones if necessary
2462
                Join<ConceptMap, Concept> conceptJoin = root.join("concept");
1✔
2463
                if (!includeRetired) {
1✔
2464
                        predicates.add(cb.isFalse(conceptJoin.get("retired")));
1✔
2465
                }
2466
                return predicates;
1✔
2467
        }
2468

2469
        /**
2470
         * @see org.openmrs.api.db.ConceptDAO#saveConceptReferenceRange(ConceptReferenceRange)
2471
         */
2472
        @Override
2473
        public ConceptReferenceRange saveConceptReferenceRange(ConceptReferenceRange conceptReferenceRange) {
2474
                sessionFactory.getCurrentSession().saveOrUpdate(conceptReferenceRange);
1✔
2475
                return conceptReferenceRange;
1✔
2476
        }
2477

2478
        /**
2479
         * @see org.openmrs.api.db.ConceptDAO#getConceptReferenceRangesByConceptId(Integer)
2480
         */
2481
        @Override
2482
        public List<ConceptReferenceRange> getConceptReferenceRangesByConceptId(Integer conceptId) {
2483
                Session session = sessionFactory.getCurrentSession();
1✔
2484
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
2485
                CriteriaQuery<ConceptReferenceRange> cq = cb.createQuery(ConceptReferenceRange.class);
1✔
2486
                Root<ConceptReferenceRange> root = cq.from(ConceptReferenceRange.class);
1✔
2487

2488
                cq.where(cb.equal(root.get("conceptNumeric"), conceptId));
1✔
2489

2490
                return session.createQuery(cq).getResultList();
1✔
2491
        }
2492

2493
        /**
2494
         * @see ConceptDAO#getConceptReferenceRangeByUuid(String)
2495
         */
2496
        @Override
2497
        public ConceptReferenceRange getConceptReferenceRangeByUuid(String uuid) {
2498
                Session session = sessionFactory.getCurrentSession();
1✔
2499
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
2500
                CriteriaQuery<ConceptReferenceRange> cq = cb.createQuery(ConceptReferenceRange.class);
1✔
2501
                Root<ConceptReferenceRange> root = cq.from(ConceptReferenceRange.class);
1✔
2502

2503
                cq.where(cb.equal(root.get("uuid"), uuid));
1✔
2504

2505
                return session.createQuery(cq).uniqueResult();
1✔
2506
        }
2507
        
2508
        /**
2509
         * @see org.openmrs.api.db.ConceptDAO#purgeConceptReferenceRange(org.openmrs.ConceptReferenceRange)
2510
         */
2511
        @Override
2512
        public void purgeConceptReferenceRange(ConceptReferenceRange conceptReferenceRange) {
2513
                sessionFactory.getCurrentSession().delete(conceptReferenceRange);
1✔
2514
        }
1✔
2515
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc