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

openmrs / openmrs-core / 26783997561

01 Jun 2026 09:45PM UTC coverage: 63.427% (+0.05%) from 63.376%
26783997561

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%)

7 existing lines in 4 files now uncovered.

23681 of 37336 relevant lines covered (63.43%)

0.63 hits per line

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

88.28
/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.JoinType;
20
import javax.persistence.criteria.Predicate;
21
import javax.persistence.criteria.Root;
22
import java.util.ArrayList;
23
import java.util.Arrays;
24
import java.util.Collection;
25
import java.util.Collections;
26
import java.util.HashMap;
27
import java.util.HashSet;
28
import java.util.Iterator;
29
import java.util.LinkedHashSet;
30
import java.util.List;
31
import java.util.Locale;
32
import java.util.Map;
33
import java.util.Optional;
34
import java.util.Set;
35

36
import javax.persistence.criteria.Subquery;
37

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

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

98
        private static final String CONCEPT_REFERENCE_TERM = "conceptReferenceTerm";
99

100
        private static final String CONCEPT_SOURCE = "conceptSource";
101

102
        private static final String HL7_CODE = "hl7Code";
103

104
        private SessionFactory sessionFactory;
105

106
        private SearchSessionFactory searchSessionFactory;
107

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

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

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

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

146
                        cq.where(cb.equal(root.get("conceptId"), conceptId));
×
147

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

152
                return cc;
1✔
153
        }
154
        
155
        /**
156
         * @see org.openmrs.api.db.ConceptDAO#saveConcept(org.openmrs.Concept)
157
         */
158
        @Override
159
        public Concept saveConcept(Concept concept) throws DAOException {
160
                if ((concept.getConceptId() != null) && (concept.getConceptId() > 0)) {
1✔
161
                        // this method checks the concept_numeric, concept_derived, etc tables
162
                        // to see if a row exists there or not.  This is needed because hibernate
163
                        // doesn't like to insert into concept_numeric but update concept in the
164
                        // same go.  It assumes that its either in both tables or no tables
165
                        insertRowIntoSubclassIfNecessary(concept);
1✔
166
                }
167
                
168
                sessionFactory.getCurrentSession().saveOrUpdate(concept);
1✔
169
                return concept;
1✔
170
        }
171
        
172
        /**
173
         * Convenience method that will check this concept for subtype values (ConceptNumeric,
174
         * ConceptDerived, etc) and insert a line into that subtable if needed. This prevents a
175
         * hibernate ConstraintViolationException
176
         * 
177
         * @param concept the concept that will be inserted
178
         */
179
        private void insertRowIntoSubclassIfNecessary(Concept concept) {
180
                
181
                // check the concept_numeric table
182
                if (concept instanceof ConceptNumeric) {
1✔
183
                        
184
                        String select = "SELECT 1 from concept_numeric WHERE concept_id = :conceptId";
1✔
185
                        Query query = sessionFactory.getCurrentSession().createSQLQuery(select);
1✔
186
                        query.setParameter("conceptId", concept.getConceptId());
1✔
187
                        
188
                        // Converting to concept numeric:  A single concept row exists, but concept numeric has not been populated yet.
189
                        if (JpaUtils.getSingleResultOrNull(query) == null) {
1✔
190
                                // we have to evict the current concept out of the session because
191
                                // the user probably had to change the class of this object to get it
192
                                // to now be a numeric
193
                                // (must be done before the "insert into...")
194
                                sessionFactory.getCurrentSession().clear();
1✔
195
                                
196
                                //Just in case this was changed from concept_complex to numeric
197
                                //We need to add a delete line for each concept sub class that is not concept_numeric
198
                                deleteSubclassConcept("concept_complex", concept.getConceptId());
1✔
199
                                
200
                                String insert = "INSERT INTO concept_numeric (concept_id, allow_decimal) VALUES (:conceptId, false)";
1✔
201
                                query = sessionFactory.getCurrentSession().createSQLQuery(insert);
1✔
202
                                query.setParameter("conceptId", concept.getConceptId());
1✔
203
                                query.executeUpdate();
1✔
204
                                
205
                        } else {
1✔
206
                                // Converting from concept numeric:  The concept and concept numeric rows both exist, so we need to delete concept_numeric.
207
                                
208
                                // concept is changed from numeric to something else
209
                                // hence row should be deleted from the concept_numeric
210
                                if (!concept.isNumeric()) {
1✔
211
                                        deleteSubclassConcept("concept_numeric", concept.getConceptId());
1✔
212
                                }
213
                        }
214
                }
1✔
215
                // check the concept complex table
216
                else if (concept instanceof ConceptComplex) {
1✔
217
                        
218
                        String select = "SELECT 1 FROM concept_complex WHERE concept_id = :conceptId";
1✔
219
                        Query query = sessionFactory.getCurrentSession().createSQLQuery(select);
1✔
220
                        query.setParameter("conceptId", concept.getConceptId());
1✔
221
                        
222
                        // Converting to concept complex:  A single concept row exists, but concept complex has not been populated yet.
223
                        if (JpaUtils.getSingleResultOrNull(query) == null) {
1✔
224
                                // we have to evict the current concept out of the session because
225
                                // the user probably had to change the class of this object to get it
226
                                // to now be a ConceptComplex
227
                                // (must be done before the "insert into...")
228
                                sessionFactory.getCurrentSession().clear();
1✔
229
                                
230
                                //Just in case this was changed from concept_numeric to complex
231
                                //We need to add a delete line for each concept sub class that is not concept_complex
232
                                deleteSubclassConcept("concept_numeric", concept.getConceptId());
1✔
233
                                
234
                                // Add an empty row into the concept_complex table
235
                                String insert = "INSERT INTO concept_complex (concept_id) VALUES (:conceptId)";
1✔
236
                                query = sessionFactory.getCurrentSession().createSQLQuery(insert);
1✔
237
                                query.setParameter("conceptId", concept.getConceptId());
1✔
238
                                query.executeUpdate();
1✔
239
                                
240
                        } else {
1✔
241
                                // Converting from concept complex:  The concept and concept complex rows both exist, so we need to delete the concept_complex row.
242
                                // no stub insert is needed because either a concept row doesn't exist OR a concept_complex row does exist
243
                                
244
                                // concept is changed from complex to something else
245
                                // hence row should be deleted from the concept_complex
246
                                if (!concept.isComplex()) {
×
247
                                        deleteSubclassConcept("concept_complex", concept.getConceptId());
×
248
                                }
249
                        }
250
                }
251
        }
1✔
252
        
253
        /**
254
         * Deletes a concept from a sub class table
255
         * 
256
         * @param tableName the sub class table name
257
         * @param conceptId the concept id
258
         */
259
        private void deleteSubclassConcept(String tableName, Integer conceptId) {
260
                String delete = "DELETE FROM " + tableName + " WHERE concept_id = :conceptId";
1✔
261
                Query query = sessionFactory.getCurrentSession().createSQLQuery(delete);
1✔
262
                query.setParameter("conceptId", conceptId);
1✔
263
                query.executeUpdate();
1✔
264
        }
1✔
265
        
266
        /**
267
         * @see org.openmrs.api.db.ConceptDAO#purgeConcept(org.openmrs.Concept)
268
         */
269
        @Override
270
        public void purgeConcept(Concept concept) throws DAOException {
271
                sessionFactory.getCurrentSession().delete(concept);
1✔
272
        }
1✔
273
        
274
        /**
275
         * @see org.openmrs.api.db.ConceptDAO#getConcept(java.lang.Integer)
276
         */
277
        @Override
278
        public Concept getConcept(Integer conceptId) throws DAOException {
279
                return sessionFactory.getCurrentSession().get(Concept.class, conceptId);
1✔
280
        }
281
        
282
        /**
283
         * @see org.openmrs.api.db.ConceptDAO#getConceptName(java.lang.Integer)
284
         */
285
        @Override
286
        public ConceptName getConceptName(Integer conceptNameId) throws DAOException {
287
                return sessionFactory.getCurrentSession().get(ConceptName.class, conceptNameId);
1✔
288
        }
289
        
290
        /**
291
         * @see org.openmrs.api.db.ConceptDAO#getConceptAnswer(java.lang.Integer)
292
         */
293
        @Override
294
        public ConceptAnswer getConceptAnswer(Integer conceptAnswerId) throws DAOException {
295
                return sessionFactory.getCurrentSession().get(ConceptAnswer.class, conceptAnswerId);
1✔
296
        }
297
        
298
        /**
299
         * @see org.openmrs.api.db.ConceptDAO#getAllConcepts(java.lang.String, boolean, boolean)
300
         */
301
        @Override
302
        public List<Concept> getAllConcepts(String sortBy, boolean asc, boolean includeRetired) throws DAOException {
303

304
                boolean isNameField = false;
1✔
305

306
                try {
307
                        Concept.class.getDeclaredField(sortBy);
1✔
308
                }
309
                catch (NoSuchFieldException e) {
1✔
310
                        try {
311
                                ConceptName.class.getDeclaredField(sortBy);
1✔
312
                                isNameField = true;
1✔
313
                        }
314
                        catch (NoSuchFieldException e2) {
×
315
                                sortBy = "conceptId";
×
316
                        }
1✔
317
                }
1✔
318

319
                Session session = sessionFactory.getCurrentSession();
1✔
320
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
321
                CriteriaQuery<Concept> cq = cb.createQuery(Concept.class);
1✔
322
                Root<Concept> root = cq.from(Concept.class);
1✔
323

324
                List<Predicate> predicates = new ArrayList<>();
1✔
325

326
                // When sorting by a ConceptName field, join to names filtered on FULLY_SPECIFIED
327
                // to avoid duplicates (each concept should have exactly one fully specified name)
328
                Join<Concept, ConceptName> namesJoin = null;
1✔
329
                if (isNameField) {
1✔
330
                        namesJoin = root.join("names", JoinType.LEFT);
1✔
331
                        predicates.add(cb.equal(namesJoin.get("conceptNameType"), ConceptNameType.FULLY_SPECIFIED));
1✔
332
                }
333

334
                if (!includeRetired) {
1✔
335
                        predicates.add(cb.isFalse(root.get("retired")));
1✔
336
                }
337

338
                cq.select(root).where(predicates.toArray(new Predicate[0]));
1✔
339

340
                if (isNameField) {
1✔
341
                        cq.orderBy(asc ? cb.asc(namesJoin.get(sortBy)) : cb.desc(namesJoin.get(sortBy)));
1✔
342
                } else {
343
                        cq.orderBy(asc ? cb.asc(root.get(sortBy)) : cb.desc(root.get(sortBy)));
1✔
344
                }
345

346
                return session.createQuery(cq).getResultList();
1✔
347
        }
348
        
349
        /**
350
         * @see org.openmrs.api.db.ConceptDAO#saveDrug(org.openmrs.Drug)
351
         */
352
        @Override
353
        public Drug saveDrug(Drug drug) throws DAOException {
354
                sessionFactory.getCurrentSession().saveOrUpdate(drug);
1✔
355
                return drug;
1✔
356
        }
357
        
358
        /**
359
         * @see org.openmrs.api.db.ConceptDAO#getDrug(java.lang.Integer)
360
         */
361
        @Override
362
        public Drug getDrug(Integer drugId) throws DAOException {
363
                return sessionFactory.getCurrentSession().get(Drug.class, drugId);
1✔
364
        }
365
        
366
        /**
367
         * @see org.openmrs.api.db.ConceptDAO#getDrugs(java.lang.String, org.openmrs.Concept, boolean)
368
         */
369
        @Override
370
        public List<Drug> getDrugs(String drugName, Concept concept, boolean includeRetired) throws DAOException {
371
                Session session = sessionFactory.getCurrentSession();
1✔
372
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
373
                CriteriaQuery<Drug> cq = cb.createQuery(Drug.class);
1✔
374
                Root<Drug> drugRoot = cq.from(Drug.class);
1✔
375

376
                List<Predicate> predicates = new ArrayList<>();
1✔
377

378
                if (!includeRetired) {
1✔
379
                        predicates.add(cb.isFalse(drugRoot.get("retired")));
1✔
380
                }
381

382
                if (concept != null) {
1✔
383
                        predicates.add(cb.equal(drugRoot.get("concept"), concept));
1✔
384
                }
385

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

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

396
                return session.createQuery(cq).getResultList();
1✔
397
        }
398

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

411
                Predicate rhs = cb.equal(drugRoot.get("concept"), ingredient);
1✔
412
                Predicate lhs = cb.equal(ingredientJoin.get("ingredient"), ingredient);
1✔
413

414
                cq.where(cb.or(lhs, rhs));
1✔
415

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

451
                if (name != null) {
1✔
452
                        cq.where(cb.equal(root.get("name"), name));
1✔
453
                }
454

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

468
                // Minor bug - was assigning includeRetired instead of evaluating
469
                if (!includeRetired) {
1✔
470
                        cq.where(cb.isFalse(root.get("retired")));
1✔
471
                }
472

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

516
                if (!includeRetired) {
1✔
517
                        cq.where(cb.isFalse(root.get("retired")));
1✔
518
                }
519

520
                return session.createQuery(cq).getResultList();
1✔
521
        }
522

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

533
                if (name != null) {
1✔
534
                        cq.where(cb.like(root.get("name"), MatchMode.START.toCaseSensitivePattern(name)));
1✔
535
                }
536

537
                return session.createQuery(cq).getResultList();
1✔
538
        }
539

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

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

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

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

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

725
                Integer i = c.getConceptId();
1✔
726

727
                cq.where(cb.lessThan(root.get("conceptId"), i));
1✔
728
                cq.orderBy(cb.desc(root.get("conceptId")));
1✔
729

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

732
                if (concepts.isEmpty()) {
1✔
733
                        return null;
1✔
734
                }
735

736
                return concepts.get(0);
1✔
737
        }
738

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

749
                Integer i = c.getConceptId();
1✔
750

751
                cq.where(cb.greaterThan(root.get("conceptId"), i));
1✔
752
                cq.orderBy(cb.asc(root.get("conceptId")));
1✔
753

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

756
                if (concepts.isEmpty()) {
1✔
757
                        return null;
1✔
758
                }
759

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

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

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

834
                Predicate stateCondition = cb.equal(root.get("state"), OpenmrsConstants.CONCEPT_PROPOSAL_UNMAPPED);
1✔
835
                Predicate textCondition = cb.equal(root.get("originalText"), text);
1✔
836

837
                cq.where(cb.and(stateCondition, textCondition));
1✔
838

839
                return session.createQuery(cq).getResultList();
1✔
840
        }
841

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

852
                Predicate stateNotEqual = cb.notEqual(root.get("state"), OpenmrsConstants.CONCEPT_PROPOSAL_UNMAPPED);
1✔
853
                Predicate originalTextEqual = cb.equal(root.get("originalText"), text);
1✔
854
                Predicate mappedConceptNotNull = cb.isNotNull(root.get("mappedConcept"));
1✔
855

856
                cq.select(root.get("mappedConcept")).distinct(true);
1✔
857
                cq.where(stateNotEqual, originalTextEqual, mappedConceptNotNull);
1✔
858

859
                return session.createQuery(cq).getResultList();
1✔
860
        }
861

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

872
                cq.where(cb.equal(root.get("conceptSet"), concept));
1✔
873
                cq.orderBy(cb.asc(root.get("sortWeight")));
1✔
874

875
                return session.createQuery(cq).getResultList();
1✔
876
        }
877

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

888
                cq.where(cb.equal(root.get("concept"), concept));
1✔
889

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

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

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

957
                List<ConceptNameTag> conceptNameTags = session.createQuery(cq).getResultList();
1✔
958
                if (conceptNameTags.isEmpty()) {
1✔
959
                        return null;
1✔
960
                }
961

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

992
                if (!includeRetired) {
1✔
993
                        cq.where(cb.isFalse(root.get("retired")));
1✔
994
                }
995

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

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

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

1115
                cq.where(predicates.toArray(new Predicate[]{}));
×
1116

1117
                cq.select(root.get("concept"));
×
1118

1119
                Join<ConceptMap, Concept> conceptJoin = root.join("concept");
×
1120
                if (includeRetired) {
×
1121
                        cq.orderBy(cb.asc(conceptJoin.get("retired")));
×
1122
                }
1123

1124
                return session.createQuery(cq).getResultList()
×
1125
                        .stream().distinct().collect(toList());
×
1126
        }
1127

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

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

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

1142
                cq.select(root.get("concept").get("conceptId"));
1✔
1143

1144
                Join<ConceptMap, Concept> conceptJoin = root.join("concept");
1✔
1145
                if (includeRetired) {
1✔
1146
                        cq.orderBy(cb.asc(conceptJoin.get("retired")));
1✔
1147
                }
1148

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

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

1174
                List<Predicate> orPredicates = new ArrayList<>();
1✔
1175

1176
                if (criteria.getUuids() != null && !criteria.getUuids().isEmpty()) {
1✔
1177
                        orPredicates.add(root.get("uuid").in(criteria.getUuids()));
1✔
1178
                }
1179

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

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

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

1200
                if (orPredicates.isEmpty()) {
1✔
1201
                        return new ArrayList<>();
1✔
1202
                }
1203

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

1210
                return session.createQuery(cq).getResultList().stream().distinct().collect(toList());
1✔
1211
        }
1212

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

1226
                Subquery<ConceptMap> sub = cq.subquery(ConceptMap.class);
1✔
1227
                Root<ConceptMap> mapRoot = sub.from(ConceptMap.class);
1✔
1228
                Join<ConceptMap, ConceptReferenceTerm> termJoin = mapRoot.join(CONCEPT_REFERENCE_TERM);
1✔
1229
                Join<ConceptReferenceTerm, ConceptSource> sourceJoin = termJoin.join(CONCEPT_SOURCE);
1✔
1230

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

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

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

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

1273
        @Override
1274
        public ConceptAnswer getConceptAnswerByUuid(String uuid) {
1275
                return HibernateUtil.getUniqueEntityByUUID(sessionFactory, ConceptAnswer.class, uuid);
1✔
1276
        }
1277

1278
        @Override
1279
        public ConceptName getConceptNameByUuid(String uuid) {
1280
                return HibernateUtil.getUniqueEntityByUUID(sessionFactory, ConceptName.class, uuid);
1✔
1281
        }
1282

1283
        @Override
1284
        public ConceptSet getConceptSetByUuid(String uuid) {
1285
                return HibernateUtil.getUniqueEntityByUUID(sessionFactory, ConceptSet.class, uuid);
1✔
1286
        }
1287

1288
        @Override
1289
        public ConceptSource getConceptSourceByUuid(String uuid) {
1290
                return HibernateUtil.getUniqueEntityByUUID(sessionFactory, ConceptSource.class, uuid);
1✔
1291
        }
1292

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

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

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

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

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

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

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

1370
                Root<ConceptMap> root = cq.from(ConceptMap.class);
1✔
1371
                Join<ConceptMap, ConceptReferenceTerm> conceptReferenceTermJoin = root.join(CONCEPT_REFERENCE_TERM);
1✔
1372

1373
                cq.where(cb.equal(conceptReferenceTermJoin.get(CONCEPT_SOURCE), conceptSource));
1✔
1374

1375
                return session.createQuery(cq).getResultList();
1✔
1376
        }
1377

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

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

1390
                return session.createQuery(cq).uniqueResult();
1✔
1391
        }
1392

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

1402
                Session session = sessionFactory.getCurrentSession();
1✔
1403
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
1404
                CriteriaQuery<ConceptSource> cq = cb.createQuery(ConceptSource.class);
1✔
1405
                Root<ConceptSource> root = cq.from(ConceptSource.class);
1✔
1406

1407
                cq.where(cb.equal(root.get("uniqueId"), uniqueId));
1✔
1408

1409
                return session.createQuery(cq).uniqueResult();
1✔
1410
        }
1411

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

1421
                Session session = sessionFactory.getCurrentSession();
1✔
1422
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
1423
                CriteriaQuery<ConceptSource> cq = cb.createQuery(ConceptSource.class);
1✔
1424
                Root<ConceptSource> root = cq.from(ConceptSource.class);
1✔
1425

1426
                cq.where(cb.equal(root.get(HL7_CODE), hl7Code));
1✔
1427

1428
                return session.createQuery(cq).uniqueResult();
1✔
1429
        }
1430

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

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

1454
        /**
1455
         * @see org.openmrs.api.db.ConceptDAO#getConceptStopWords(java.util.Locale)
1456
         */
1457
        @Override
1458
        public List<String> getConceptStopWords(Locale locale) throws DAOException {
1459

1460
                locale = (locale == null ? Context.getLocale() : locale);
1✔
1461

1462
                Session session = sessionFactory.getCurrentSession();
1✔
1463
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
1464
                CriteriaQuery<String> cq = cb.createQuery(String.class);
1✔
1465
                Root<ConceptStopWord> root = cq.from(ConceptStopWord.class);
1✔
1466

1467
                cq.select(root.get("value"));
1✔
1468
                cq.where(cb.equal(root.get("locale"), locale));
1✔
1469

1470
                return session.createQuery(cq).getResultList();
1✔
1471
        }
1472

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

1484
                        cq.where(cb.and(
1✔
1485
                                cb.equal(root.get("value"), conceptStopWord.getValue()),
1✔
1486
                                cb.equal(root.get("locale"), conceptStopWord.getLocale())));
1✔
1487

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

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

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

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

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

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

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

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

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

1660
                                if (locales == null) {
1✔
1661
                                        searchLocales = Collections.singletonList(Context.getLocale());
1✔
1662
                                } else {
1663
                                        searchLocales = new HashSet<>(locales);
1✔
1664
                                }
1665

1666
                                b.must(newConceptNameQuery(f, phrase, searchKeywords, searchLocales, searchExactLocale));
1✔
1667
                        }
1668

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

1686
                        if (answersToConcept != null) {
1✔
1687
                                Collection<ConceptAnswer> answers = answersToConcept.getAnswers(false);
1✔
1688

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

1698
                        if (!includeRetired) {
1✔
1699
                                b.filter(f.match().field("concept.retired").matching(Boolean.FALSE));
1✔
1700
                        }
1701
                }).toPredicate();
1✔
1702
        }
1703

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

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

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

1724
                List<ConceptMapType> conceptMapTypes = session.createQuery(cq).getResultList();
1✔
1725
                conceptMapTypes.sort(new ConceptMapTypeComparator());
1✔
1726

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

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

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

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

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

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

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

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

NEW
1821
                cq.where(cb.equal(root.get(CONCEPT_SOURCE), conceptSource));
×
1822

1823
                return session.createQuery(cq).getResultList();
×
1824
        }
1825

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

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

1840
                cq.where(cb.and(namePredicate, sourcePredicate));
1✔
1841

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

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

1890
                List<Predicate> predicates = new ArrayList<>();
1✔
1891
                predicates.add(cb.equal(root.get("code"), code));
1✔
1892
                predicates.add(cb.equal(root.get(CONCEPT_SOURCE), conceptSource));
1✔
1893

1894
                if (!includeRetired) {
1✔
1895
                        predicates.add(cb.isFalse(root.get("retired")));
1✔
1896
                }
1897
                cq.where(predicates.toArray(new Predicate[]{}));
1✔
1898

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

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

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

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

1931
                return session.createQuery(cq).getSingleResult();
1✔
1932
        }
1933

1934

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

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

1950
                TypedQuery<ConceptReferenceTerm> typedQuery = session.createQuery(cq);
1✔
1951

1952
                if (start != null) {
1✔
1953
                        typedQuery.setFirstResult(start);
1✔
1954
                }
1955
                if (length != null && length > 0) {
1✔
1956
                        typedQuery.setMaxResults(length);
1✔
1957
                }
1958

1959
                return typedQuery.getResultList();
1✔
1960
        }
1961

1962
        private List<Predicate> createConceptReferenceTermPredicates(CriteriaBuilder cb, Root<ConceptReferenceTerm> root,
1963
                                                                                                                                 String query, ConceptSource conceptSource, boolean includeRetired) {
1964
                List<Predicate> predicates = new ArrayList<>();
1✔
1965

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

1976
                        predicates.add(cb.or(namePredicate, codePredicate));
1✔
1977
                }
1978

1979
                return predicates;
1✔
1980
        }
1981

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

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

1994
                return session.createQuery(cq).getResultList();
1✔
1995
        }
1996

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

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

2011
                Long conceptMapCount = session.createQuery(conceptMapQuery).uniqueResult();
1✔
2012
                if (conceptMapCount > 0) {
1✔
2013
                        return true;
1✔
2014
                }
2015

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

2023
                Long conceptReferenceTermMapCount = session.createQuery(conceptReferenceTermMapQuery).uniqueResult();
1✔
2024
                return conceptReferenceTermMapCount > 0;
1✔
2025
        }
2026

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

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

2041
                Long conceptCount = session.createQuery(conceptQuery).uniqueResult();
1✔
2042
                if (conceptCount > 0) {
1✔
2043
                        return true;
1✔
2044
                }
2045

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

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

2089
                Locale locale = Context.getLocale();
1✔
2090
                Locale language = new Locale(locale.getLanguage() + "%");
1✔
2091
                List<Predicate> predicates = new ArrayList<>();
1✔
2092

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

2102
                cq.where(predicates.toArray(new Predicate[0]));
1✔
2103

2104
                List<ConceptName> list = session.createQuery(cq).getResultList();
1✔
2105
                LinkedHashSet<Concept> concepts = transformNamesToConcepts(list);
1✔
2106

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

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

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

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

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

2181
                Session session = sessionFactory.getCurrentSession();
1✔
2182
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
2183
                CriteriaQuery<ConceptName> cq = cb.createQuery(ConceptName.class);
1✔
2184
                Root<ConceptName> root = cq.from(ConceptName.class);
1✔
2185

2186
                List<Predicate> predicates = new ArrayList<>();
1✔
2187

2188
                predicates.add(cb.isFalse(root.get("voided")));
1✔
2189
                predicates.add(cb.or(cb.equal(root.get("locale"), name.getLocale()),
1✔
2190
                        cb.equal(root.get("locale"), new Locale(name.getLocale().getLanguage()))));
1✔
2191

2192
                if (Context.getAdministrationService().isDatabaseStringComparisonCaseSensitive()) {
1✔
2193
                        predicates.add(cb.equal(cb.lower(root.get("name")), name.getName().toLowerCase()));
1✔
2194
                } else {
2195
                        predicates.add(cb.equal(root.get("name"), name.getName()));
×
2196
                }
2197

2198
                cq.where(predicates.toArray(new Predicate[0]));
1✔
2199

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

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

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

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

2235
                Session session = sessionFactory.getCurrentSession();
1✔
2236
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
2237
                CriteriaQuery<Drug> cq = cb.createQuery(Drug.class);
1✔
2238
                Root<Drug> drugRoot = cq.from(Drug.class);
1✔
2239

2240
                Join<Drug, DrugReferenceMap> drugReferenceMapJoin = drugRoot.join("drugReferenceMaps");
1✔
2241
                Join<DrugReferenceMap, ConceptReferenceTerm> termJoin = drugReferenceMapJoin.join(CONCEPT_REFERENCE_TERM);
1✔
2242
                List<Predicate> basePredicates = createSearchDrugByMappingPredicates(cb, drugRoot, drugReferenceMapJoin, termJoin,
1✔
2243
                    code, conceptSource, includeRetired);
2244

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

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

2253
                return session.createQuery(cq).getResultList().stream().distinct().collect(toList());
1✔
2254
        }
2255

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

2267
                Join<Drug, DrugReferenceMap> drugReferenceMapJoin = drugRoot.join("drugReferenceMaps");
1✔
2268
                Join<DrugReferenceMap, ConceptReferenceTerm> termJoin = drugReferenceMapJoin.join("conceptReferenceTerm");
1✔
2269

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

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

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

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

2300

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

2311
                return session.createQuery(cq).getResultList();
1✔
2312
        }
2313

2314
        /**
2315
         * @see ConceptDAO#saveConceptAttributeType(ConceptAttributeType)
2316
         */
2317
        @Override
2318
        public ConceptAttributeType saveConceptAttributeType(ConceptAttributeType conceptAttributeType) {
2319
                sessionFactory.getCurrentSession().saveOrUpdate(conceptAttributeType);
1✔
2320
                return conceptAttributeType;
1✔
2321
        }
2322

2323
        /**
2324
         * @see ConceptDAO#getConceptAttributeType(Integer)
2325
         */
2326
        @Override
2327
        public ConceptAttributeType getConceptAttributeType(Integer id) {
2328
                return sessionFactory.getCurrentSession().get(ConceptAttributeType.class, id);
1✔
2329
        }
2330

2331
        /**
2332
         * @see ConceptDAO#getConceptAttributeTypeByUuid(String)
2333
         */
2334
        @Override
2335
        public ConceptAttributeType getConceptAttributeTypeByUuid(String uuid) {
2336
                return HibernateUtil.getUniqueEntityByUUID(sessionFactory, ConceptAttributeType.class, uuid);
1✔
2337
        }
2338

2339
        /**
2340
         * @see org.openmrs.api.db.ConceptDAO#deleteConceptAttributeType(org.openmrs.ConceptAttributeType)
2341
         */
2342
        @Override
2343
        public void deleteConceptAttributeType(ConceptAttributeType conceptAttributeType) {
2344
                sessionFactory.getCurrentSession().delete(conceptAttributeType);
1✔
2345
        }
1✔
2346

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

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

2362
                return session.createQuery(cq).getResultList();
1✔
2363
        }
2364

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

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

2377
                return session.createQuery(cq).uniqueResult();
1✔
2378
        }
2379

2380
        /**
2381
         * @see ConceptDAO#getConceptAttributeByUuid(String)
2382
         */
2383
        @Override
2384
        public ConceptAttribute getConceptAttributeByUuid(String uuid) {
2385
                return HibernateUtil.getUniqueEntityByUUID(sessionFactory, ConceptAttribute.class, uuid);
1✔
2386
        }
2387

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

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

2400
                return session.createQuery(cq).getSingleResult();
1✔
2401
        }
2402

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

2410
                cq.where(cb.equal(root.get("conceptClass"), conceptClass));
1✔
2411

2412
                return session.createQuery(cq).getResultList();
1✔
2413
        }
2414

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

2430
                return predicates;
1✔
2431
        }
2432

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

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

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

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

2448
                Predicate namePredicate = Context.getAdministrationService().isDatabaseStringComparisonCaseSensitive()
1✔
2449
                        ? cb.equal(cb.lower(sourceJoin.get("name")), sourceName.toLowerCase())
1✔
2450
                        : cb.equal(sourceJoin.get("name"), sourceName);
1✔
2451
                Predicate hl7CodePredicate = Context.getAdministrationService().isDatabaseStringComparisonCaseSensitive()
1✔
2452
                        ? cb.equal(cb.lower(sourceJoin.get(HL7_CODE)), sourceName.toLowerCase())
1✔
2453
                        : cb.equal(sourceJoin.get(HL7_CODE), sourceName);
1✔
2454

2455
                predicates.add(cb.or(namePredicate, hl7CodePredicate));
1✔
2456

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

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

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

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

2486
                return session.createQuery(cq).getResultList();
1✔
2487
        }
2488

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

2499
                cq.where(cb.equal(root.get("uuid"), uuid));
1✔
2500

2501
                return session.createQuery(cq).uniqueResult();
1✔
2502
        }
2503
        
2504
        /**
2505
         * @see org.openmrs.api.db.ConceptDAO#purgeConceptReferenceRange(org.openmrs.ConceptReferenceRange)
2506
         */
2507
        @Override
2508
        public void purgeConceptReferenceRange(ConceptReferenceRange conceptReferenceRange) {
2509
                sessionFactory.getCurrentSession().delete(conceptReferenceRange);
1✔
2510
        }
1✔
2511
}
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