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

openmrs / openmrs-core / 14752386992

30 Apr 2025 10:25AM UTC coverage: 64.96% (-0.1%) from 65.095%
14752386992

push

github

web-flow
TRUNK-6316 Upgrade Hibernate Search to 6.2.4 (#5005)

501 of 591 new or added lines in 24 files covered. (84.77%)

21 existing lines in 6 files now uncovered.

23344 of 35936 relevant lines covered (64.96%)

0.65 hits per line

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

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

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

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

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

81
/**
82
 * The Hibernate class for Concepts, Drugs, and related classes. <br>
83
 * <br>
84
 * Use the {@link ConceptService} to access these methods
85
 * 
86
 * @see ConceptService
87
 */
88
public class HibernateConceptDAO implements ConceptDAO {
1✔
89
        
90
        private static final Logger log = LoggerFactory.getLogger(HibernateConceptDAO.class);
1✔
91
        
92
        private SessionFactory sessionFactory;
93
        
94
        private SearchSessionFactory searchSessionFactory;
95
        
96
        /**
97
         * Sets the session factory
98
         * 
99
         * @param sessionFactory
100
         */
101
        public void setSessionFactory(SessionFactory sessionFactory) {
102
                this.sessionFactory = sessionFactory;
1✔
103
        }
1✔
104

105
        /**
106
         * Sets the search session factory
107
         * 
108
         * @param searchSessionFactory
109
         */
110
        public void setSearchSessionFactory(SearchSessionFactory searchSessionFactory) {
111
                this.searchSessionFactory = searchSessionFactory;
1✔
112
        }
1✔
113

114
        /**
115
         * @see org.openmrs.api.db.ConceptDAO#getConceptComplex(java.lang.Integer)
116
         */
117
        @Override
118
        public ConceptComplex getConceptComplex(Integer conceptId) {
119
                ConceptComplex cc;
120
                Session session = sessionFactory.getCurrentSession();
1✔
121
                Object obj = session.get(ConceptComplex.class, conceptId);
1✔
122
                // If Concept has already been read & cached, we may get back a Concept instead of
123
                // ConceptComplex.  If this happens, we need to clear the object from the cache
124
                // and re-fetch it as a ConceptComplex
125
                if (obj != null && !obj.getClass().equals(ConceptComplex.class)) {
1✔
126
                        // remove from cache
127
                        session.detach(obj);
×
128

129
                        // session.get() did not work here, we need to perform a query to get a ConceptComplex
130
                        CriteriaBuilder cb = session.getCriteriaBuilder();
×
131
                        CriteriaQuery<ConceptComplex> cq = cb.createQuery(ConceptComplex.class);
×
132
                        Root<ConceptComplex> root = cq.from(ConceptComplex.class);
×
133

134
                        cq.where(cb.equal(root.get("conceptId"), conceptId));
×
135

136
                        obj = session.createQuery(cq).uniqueResult();
×
137
                }
138
                cc = (ConceptComplex) obj;
1✔
139

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

370
                List<Predicate> predicates = new ArrayList<>();
1✔
371

372
                if (!includeRetired) {
1✔
373
                        predicates.add(cb.isFalse(drugRoot.get("retired")));
1✔
374
                }
375

376
                if (concept != null) {
1✔
377
                        predicates.add(cb.equal(drugRoot.get("concept"), concept));
1✔
378
                }
379

380
                if (drugName != null) {
1✔
381
                        if (Context.getAdministrationService().isDatabaseStringComparisonCaseSensitive()) {
1✔
382
                                predicates.add(cb.equal(cb.lower(drugRoot.get("name")), MatchMode.EXACT.toLowerCasePattern(drugName)));
1✔
383
                        } else {
384
                                predicates.add(cb.equal(drugRoot.get("name"), MatchMode.EXACT.toCaseSensitivePattern(drugName)));
×
385
                        }
386
                }
387

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

390
                return session.createQuery(cq).getResultList();
1✔
391
        }
392

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

405
                Predicate rhs = cb.equal(drugRoot.get("concept"), ingredient);
1✔
406
                Predicate lhs = cb.equal(ingredientJoin.get("ingredient"), ingredient);
1✔
407

408
                cq.where(cb.or(lhs, rhs));
1✔
409

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

445
                if (name != null) {
1✔
446
                        cq.where(cb.equal(root.get("name"), name));
1✔
447
                }
448

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

462
                // Minor bug - was assigning includeRetired instead of evaluating
463
                if (!includeRetired) {
1✔
464
                        cq.where(cb.isFalse(root.get("retired")));
1✔
465
                }
466

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

510
                if (!includeRetired) {
1✔
511
                        cq.where(cb.isFalse(root.get("retired")));
1✔
512
                }
513

514
                return session.createQuery(cq).getResultList();
1✔
515
        }
516

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

527
                if (name != null) {
1✔
528
                        cq.where(cb.like(root.get("name"), MatchMode.START.toCaseSensitivePattern(name)));
1✔
529
                }
530

531
                return session.createQuery(cq).getResultList();
1✔
532
        }
533

534
        /**
535
         * @see org.openmrs.api.db.ConceptDAO#getConceptDatatypeByName(String)
536
         */
537
        @Override
538
        public ConceptDatatype getConceptDatatypeByName(String name) throws DAOException {
539
                Session session = sessionFactory.getCurrentSession();
1✔
540
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
541
                CriteriaQuery<ConceptDatatype> cq = cb.createQuery(ConceptDatatype.class);
1✔
542
                Root<ConceptDatatype> root = cq.from(ConceptDatatype.class);
1✔
543

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

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

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

709
        /**
710
         * @see org.openmrs.api.db.ConceptDAO#getPrevConcept(org.openmrs.Concept)
711
         */
712
        @Override
713
        public Concept getPrevConcept(Concept c) {
714
                Session session = sessionFactory.getCurrentSession();
1✔
715
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
716
                CriteriaQuery<Concept> cq = cb.createQuery(Concept.class);
1✔
717
                Root<Concept> root = cq.from(Concept.class);
1✔
718

719
                Integer i = c.getConceptId();
1✔
720

721
                cq.where(cb.lessThan(root.get("conceptId"), i));
1✔
722
                cq.orderBy(cb.desc(root.get("conceptId")));
1✔
723

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

726
                if (concepts.isEmpty()) {
1✔
727
                        return null;
1✔
728
                }
729

730
                return concepts.get(0);
1✔
731
        }
732

733
        /**
734
         * @see org.openmrs.api.db.ConceptDAO#getNextConcept(org.openmrs.Concept)
735
         */
736
        @Override
737
        public Concept getNextConcept(Concept c) {
738
                Session session = sessionFactory.getCurrentSession();
1✔
739
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
740
                CriteriaQuery<Concept> cq = cb.createQuery(Concept.class);
1✔
741
                Root<Concept> root = cq.from(Concept.class);
1✔
742

743
                Integer i = c.getConceptId();
1✔
744

745
                cq.where(cb.greaterThan(root.get("conceptId"), i));
1✔
746
                cq.orderBy(cb.asc(root.get("conceptId")));
1✔
747

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

750
                if (concepts.isEmpty()) {
1✔
751
                        return null;
1✔
752
                }
753

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

793
        /**
794
         * @see org.openmrs.api.db.ConceptDAO#getAllConceptProposals(boolean)
795
         */
796
        @Override
797
        public List<ConceptProposal> getAllConceptProposals(boolean includeCompleted) throws DAOException {
798
                Session session = sessionFactory.getCurrentSession();
1✔
799
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
800
                CriteriaQuery<ConceptProposal> cq = cb.createQuery(ConceptProposal.class);
1✔
801
                Root<ConceptProposal> root = cq.from(ConceptProposal.class);
1✔
802

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

828
                Predicate stateCondition = cb.equal(root.get("state"), OpenmrsConstants.CONCEPT_PROPOSAL_UNMAPPED);
1✔
829
                Predicate textCondition = cb.equal(root.get("originalText"), text);
1✔
830

831
                cq.where(cb.and(stateCondition, textCondition));
1✔
832

833
                return session.createQuery(cq).getResultList();
1✔
834
        }
835

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

846
                Predicate stateNotEqual = cb.notEqual(root.get("state"), OpenmrsConstants.CONCEPT_PROPOSAL_UNMAPPED);
1✔
847
                Predicate originalTextEqual = cb.equal(root.get("originalText"), text);
1✔
848
                Predicate mappedConceptNotNull = cb.isNotNull(root.get("mappedConcept"));
1✔
849

850
                cq.select(root.get("mappedConcept")).distinct(true);
1✔
851
                cq.where(stateNotEqual, originalTextEqual, mappedConceptNotNull);
1✔
852

853
                return session.createQuery(cq).getResultList();
1✔
854
        }
855

856
        /**
857
         * @see org.openmrs.api.db.ConceptDAO#getConceptSetsByConcept(org.openmrs.Concept)
858
         */
859
        @Override
860
        public List<ConceptSet> getConceptSetsByConcept(Concept concept) {
861
                Session session = sessionFactory.getCurrentSession();
1✔
862
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
863
                CriteriaQuery<ConceptSet> cq = cb.createQuery(ConceptSet.class);
1✔
864
                Root<ConceptSet> root = cq.from(ConceptSet.class);
1✔
865

866
                cq.where(cb.equal(root.get("conceptSet"), concept));
1✔
867
                cq.orderBy(cb.asc(root.get("sortWeight")));
1✔
868

869
                return session.createQuery(cq).getResultList();
1✔
870
        }
871

872
        /**
873
         * @see org.openmrs.api.db.ConceptDAO#getSetsContainingConcept(org.openmrs.Concept)
874
         */
875
        @Override
876
        public List<ConceptSet> getSetsContainingConcept(Concept concept) {
877
                Session session = sessionFactory.getCurrentSession();
1✔
878
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
879
                CriteriaQuery<ConceptSet> cq = cb.createQuery(ConceptSet.class);
1✔
880
                Root<ConceptSet> root = cq.from(ConceptSet.class);
1✔
881

882
                cq.where(cb.equal(root.get("concept"), concept));
1✔
883

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

939
        /**
940
         * @see org.openmrs.api.db.ConceptDAO#getConceptNameTagByName(java.lang.String)
941
         */
942
        @Override
943
        public ConceptNameTag getConceptNameTagByName(String name) {
944
                Session session = sessionFactory.getCurrentSession();
1✔
945
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
946
                CriteriaQuery<ConceptNameTag> cq = cb.createQuery(ConceptNameTag.class);
1✔
947
                Root<ConceptNameTag> root = cq.from(ConceptNameTag.class);
1✔
948

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

951
                List<ConceptNameTag> conceptNameTags = session.createQuery(cq).getResultList();
1✔
952
                if (conceptNameTags.isEmpty()) {
1✔
953
                        return null;
1✔
954
                }
955

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

986
                if (!includeRetired) {
1✔
987
                        cq.where(cb.isFalse(root.get("retired")));
1✔
988
                }
989

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

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

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

1109
                cq.where(predicates.toArray(new Predicate[]{}));
×
1110

1111
                cq.select(root.get("concept"));
×
1112

1113
                Join<ConceptMap, Concept> conceptJoin = root.join("concept");
×
1114
                if (includeRetired) {
×
1115
                        cq.orderBy(cb.asc(conceptJoin.get("retired")));
×
1116
                }
1117

1118
                return session.createQuery(cq).getResultList()
×
1119
                        .stream().distinct().collect(toList());
×
1120
        }
1121

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

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

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

1136
                cq.select(root.get("concept").get("conceptId"));
1✔
1137

1138
                Join<ConceptMap, Concept> conceptJoin = root.join("concept");
1✔
1139
                if (includeRetired) {
1✔
1140
                        cq.orderBy(cb.asc(conceptJoin.get("retired")));
1✔
1141
                }
1142

1143
                return session.createQuery(cq).getResultList()
1✔
1144
                        .stream().distinct().collect(toList());
1✔
1145
        }
1146
        
1147
        /**
1148
         * @see org.openmrs.api.db.ConceptDAO#getConceptByUuid(java.lang.String)
1149
         */
1150
        @Override
1151
        public Concept getConceptByUuid(String uuid) {
1152
                return HibernateUtil.getUniqueEntityByUUID(sessionFactory, Concept.class, uuid);
1✔
1153
        }
1154

1155
        /**
1156
         * @see org.openmrs.api.db.ConceptDAO#getConceptClassByUuid(java.lang.String)
1157
         */
1158
        @Override
1159
        public ConceptClass getConceptClassByUuid(String uuid) {
1160
                return HibernateUtil.getUniqueEntityByUUID(sessionFactory, ConceptClass.class, uuid);
1✔
1161
        }
1162

1163
        @Override
1164
        public ConceptAnswer getConceptAnswerByUuid(String uuid) {
1165
                return HibernateUtil.getUniqueEntityByUUID(sessionFactory, ConceptAnswer.class, uuid);
1✔
1166
        }
1167

1168
        @Override
1169
        public ConceptName getConceptNameByUuid(String uuid) {
1170
                return HibernateUtil.getUniqueEntityByUUID(sessionFactory, ConceptName.class, uuid);
1✔
1171
        }
1172

1173
        @Override
1174
        public ConceptSet getConceptSetByUuid(String uuid) {
1175
                return HibernateUtil.getUniqueEntityByUUID(sessionFactory, ConceptSet.class, uuid);
1✔
1176
        }
1177

1178
        @Override
1179
        public ConceptSource getConceptSourceByUuid(String uuid) {
1180
                return HibernateUtil.getUniqueEntityByUUID(sessionFactory, ConceptSource.class, uuid);
1✔
1181
        }
1182

1183
        /**
1184
         * @see org.openmrs.api.db.ConceptDAO#getConceptDatatypeByUuid(java.lang.String)
1185
         */
1186
        @Override
1187
        public ConceptDatatype getConceptDatatypeByUuid(String uuid) {
1188
                return HibernateUtil.getUniqueEntityByUUID(sessionFactory, ConceptDatatype.class, uuid);
1✔
1189
        }
1190

1191
        /**
1192
         * @see org.openmrs.api.db.ConceptDAO#getConceptNumericByUuid(java.lang.String)
1193
         */
1194
        @Override
1195
        public ConceptNumeric getConceptNumericByUuid(String uuid) {
1196
                return HibernateUtil.getUniqueEntityByUUID(sessionFactory, ConceptNumeric.class, uuid);
1✔
1197
        }
1198

1199
        /**
1200
         * @see org.openmrs.api.db.ConceptDAO#getConceptProposalByUuid(java.lang.String)
1201
         */
1202
        @Override
1203
        public ConceptProposal getConceptProposalByUuid(String uuid) {
1204
                return HibernateUtil.getUniqueEntityByUUID(sessionFactory, ConceptProposal.class, uuid);
1✔
1205
        }
1206
        
1207
        /**
1208
         * @see org.openmrs.api.db.ConceptDAO#getDrugByUuid(java.lang.String)
1209
         */
1210
        @Override
1211
        public Drug getDrugByUuid(String uuid) {
1212
                return HibernateUtil.getUniqueEntityByUUID(sessionFactory, Drug.class, uuid);
1✔
1213
        }
1214

1215
        @Override
1216
        public DrugIngredient getDrugIngredientByUuid(String uuid) {
1217
                return HibernateUtil.getUniqueEntityByUUID(sessionFactory, DrugIngredient.class, uuid);
1✔
1218
        }
1219
        
1220
        /**
1221
         * @see org.openmrs.api.db.ConceptDAO#getConceptUuids()
1222
         */
1223
        @Override
1224
        @SuppressWarnings("unchecked")
1225
        public Map<Integer, String> getConceptUuids() {
1226
                Map<Integer, String> ret = new HashMap<>();
×
1227
                Query q = sessionFactory.getCurrentSession().createQuery("select conceptId, uuid from Concept");
×
1228
                List<Object[]> list = q.getResultList();
×
1229
                for (Object[] o : list) {
×
1230
                        ret.put((Integer) o[0], (String) o[1]);
×
1231
                }
×
1232
                return ret;
×
1233
        }
1234

1235
        /**
1236
         * @see org.openmrs.api.db.ConceptDAO#getConceptDescriptionByUuid(java.lang.String)
1237
         */
1238
        @Override
1239
        public ConceptDescription getConceptDescriptionByUuid(String uuid) {
1240
                return HibernateUtil.getUniqueEntityByUUID(sessionFactory, ConceptDescription.class, uuid);
1✔
1241
        }
1242

1243
        /**
1244
         * @see org.openmrs.api.db.ConceptDAO#getConceptNameTagByUuid(java.lang.String)
1245
         */
1246
        @Override
1247
        public ConceptNameTag getConceptNameTagByUuid(String uuid) {
1248
                return HibernateUtil.getUniqueEntityByUUID(sessionFactory, ConceptNameTag.class, uuid);
1✔
1249
        }
1250

1251
        /**
1252
         * @see org.openmrs.api.db.ConceptDAO#getConceptMapsBySource(ConceptSource)
1253
         */
1254
        @Override
1255
        public List<ConceptMap> getConceptMapsBySource(ConceptSource conceptSource) throws DAOException {
1256
                Session session = sessionFactory.getCurrentSession();
1✔
1257
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
1258
                CriteriaQuery<ConceptMap> cq = cb.createQuery(ConceptMap.class);
1✔
1259

1260
                Root<ConceptMap> root = cq.from(ConceptMap.class);
1✔
1261
                Join<ConceptMap, ConceptReferenceTerm> conceptReferenceTermJoin = root.join("conceptReferenceTerm");
1✔
1262

1263
                cq.where(cb.equal(conceptReferenceTermJoin.get("conceptSource"), conceptSource));
1✔
1264

1265
                return session.createQuery(cq).getResultList();
1✔
1266
        }
1267

1268
        /**
1269
         * @see org.openmrs.api.db.ConceptDAO#getConceptSourceByName(java.lang.String)
1270
         */
1271
        @Override
1272
        public ConceptSource getConceptSourceByName(String conceptSourceName) throws DAOException {
1273
                Session session = sessionFactory.getCurrentSession();
1✔
1274
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
1275
                CriteriaQuery<ConceptSource> cq = cb.createQuery(ConceptSource.class);
1✔
1276
                Root<ConceptSource> root = cq.from(ConceptSource.class);
1✔
1277

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

1280
                return session.createQuery(cq).uniqueResult();
1✔
1281
        }
1282

1283
        /**
1284
         * @see org.openmrs.api.db.ConceptDAO#getConceptSourceByUniqueId(java.lang.String)
1285
         */
1286
        @Override
1287
        public ConceptSource getConceptSourceByUniqueId(String uniqueId) {
1288
                if (StringUtils.isBlank(uniqueId)) {
1✔
1289
                        return null;
1✔
1290
                }
1291

1292
                Session session = sessionFactory.getCurrentSession();
1✔
1293
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
1294
                CriteriaQuery<ConceptSource> cq = cb.createQuery(ConceptSource.class);
1✔
1295
                Root<ConceptSource> root = cq.from(ConceptSource.class);
1✔
1296

1297
                cq.where(cb.equal(root.get("uniqueId"), uniqueId));
1✔
1298

1299
                return session.createQuery(cq).uniqueResult();
1✔
1300
        }
1301

1302
        /**
1303
         * @see org.openmrs.api.db.ConceptDAO#getConceptSourceByHL7Code(java.lang.String)
1304
         */
1305
        @Override
1306
        public ConceptSource getConceptSourceByHL7Code(String hl7Code) {
1307
                if (StringUtils.isBlank(hl7Code)) {
1✔
1308
                        return null;
1✔
1309
                }
1310

1311
                Session session = sessionFactory.getCurrentSession();
1✔
1312
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
1313
                CriteriaQuery<ConceptSource> cq = cb.createQuery(ConceptSource.class);
1✔
1314
                Root<ConceptSource> root = cq.from(ConceptSource.class);
1✔
1315

1316
                cq.where(cb.equal(root.get("hl7Code"), hl7Code));
1✔
1317

1318
                return session.createQuery(cq).uniqueResult();
1✔
1319
        }
1320

1321
        /**
1322
         * @see org.openmrs.api.db.ConceptDAO#getSavedConceptDatatype(org.openmrs.Concept)
1323
         */
1324
        @Override
1325
        public ConceptDatatype getSavedConceptDatatype(Concept concept) {
1326
                Query sql = sessionFactory.getCurrentSession().createSQLQuery(
1✔
1327
                                "select datatype.* from concept_datatype datatype, concept concept where " +
1328
                                        "datatype.concept_datatype_id = concept.datatype_id and concept.concept_id=:conceptId")
1329
                        .addEntity(ConceptDatatype.class);
1✔
1330
                sql.setParameter("conceptId", concept.getConceptId());
1✔
1331

1332
                return JpaUtils.getSingleResultOrNull(sql);
1✔
1333
        }
1334
        
1335
        /**
1336
         * @see org.openmrs.api.db.ConceptDAO#getSavedConceptName(org.openmrs.ConceptName)
1337
         */
1338
        @Override
1339
        public ConceptName getSavedConceptName(ConceptName conceptName) {
1340
                sessionFactory.getCurrentSession().refresh(conceptName);
1✔
1341
                return conceptName;
1✔
1342
        }
1343

1344
        /**
1345
         * @see org.openmrs.api.db.ConceptDAO#getConceptStopWords(java.util.Locale)
1346
         */
1347
        @Override
1348
        public List<String> getConceptStopWords(Locale locale) throws DAOException {
1349

1350
                locale = (locale == null ? Context.getLocale() : locale);
1✔
1351

1352
                Session session = sessionFactory.getCurrentSession();
1✔
1353
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
1354
                CriteriaQuery<String> cq = cb.createQuery(String.class);
1✔
1355
                Root<ConceptStopWord> root = cq.from(ConceptStopWord.class);
1✔
1356

1357
                cq.select(root.get("value"));
1✔
1358
                cq.where(cb.equal(root.get("locale"), locale));
1✔
1359

1360
                return session.createQuery(cq).getResultList();
1✔
1361
        }
1362

1363
        /**
1364
         * @see org.openmrs.api.db.ConceptDAO#saveConceptStopWord(org.openmrs.ConceptStopWord)
1365
         */
1366
        @Override
1367
        public ConceptStopWord saveConceptStopWord(ConceptStopWord conceptStopWord) throws DAOException {
1368
                if (conceptStopWord != null) {
1✔
1369
                        Session session = sessionFactory.getCurrentSession();
1✔
1370
                        CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
1371
                        CriteriaQuery<ConceptStopWord> cq = cb.createQuery(ConceptStopWord.class);
1✔
1372
                        Root<ConceptStopWord> root = cq.from(ConceptStopWord.class);
1✔
1373

1374
                        cq.where(cb.and(
1✔
1375
                                cb.equal(root.get("value"), conceptStopWord.getValue()),
1✔
1376
                                cb.equal(root.get("locale"), conceptStopWord.getLocale())));
1✔
1377

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

1380
                        if (!stopWordList.isEmpty()) {
1✔
1381
                                throw new DAOException("Duplicate ConceptStopWord Entry");
1✔
1382
                        }
1383
                        session.saveOrUpdate(conceptStopWord);
1✔
1384
                }
1385
                return conceptStopWord;
1✔
1386
        }
1387
        
1388
        /**
1389
         * @see org.openmrs.api.db.ConceptDAO#deleteConceptStopWord(java.lang.Integer)
1390
         */
1391
        @Override
1392
        public void deleteConceptStopWord(Integer conceptStopWordId) throws DAOException {
1393
                if (conceptStopWordId == null) {
1✔
1394
                        throw new DAOException("conceptStopWordId is null");
×
1395
                }
1396

1397
                Session session = sessionFactory.getCurrentSession();
1✔
1398
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
1399
                CriteriaQuery<ConceptStopWord> cq = cb.createQuery(ConceptStopWord.class);
1✔
1400
                Root<ConceptStopWord> root = cq.from(ConceptStopWord.class);
1✔
1401
                
1402
                cq.where(cb.equal(root.get("conceptStopWordId"), conceptStopWordId));
1✔
1403

1404
                ConceptStopWord csw = session.createQuery(cq).uniqueResult();
1✔
1405
                if (csw == null) {
1✔
1406
                        throw new DAOException("Concept Stop Word not found or already deleted");
×
1407
                }
1408
                session.delete(csw);
1✔
1409
        }
1✔
1410

1411
        /**
1412
         * @see org.openmrs.api.db.ConceptDAO#getAllConceptStopWords()
1413
         */
1414
        @Override
1415
        public List<ConceptStopWord> getAllConceptStopWords() {
1416
                Session session = sessionFactory.getCurrentSession();
1✔
1417
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
1418
                CriteriaQuery<ConceptStopWord> cq = cb.createQuery(ConceptStopWord.class);
1✔
1419
                cq.from(ConceptStopWord.class);
1✔
1420

1421
                return session.createQuery(cq).getResultList();
1✔
1422
        }
1423
        
1424
        /**
1425
         * @see ConceptService#getCountOfDrugs(String, Concept, boolean, boolean, boolean)
1426
         */
1427
        @Override
1428
        public Long getCountOfDrugs(String drugName, Concept concept, boolean searchKeywords, boolean searchDrugConceptNames,
1429
                boolean includeRetired) throws DAOException {
1430
                SearchQuery<Drug> drugsQuery = newDrugQuery(drugName, searchKeywords, searchDrugConceptNames, Context.getLocale(),
1✔
1431
                    false, concept, includeRetired);
1432
                
1433
                if (drugsQuery == null) {
1✔
1434
                        return 0L;
×
1435
                }
1436
                
1437
                return drugsQuery.fetchTotalHitCount();
1✔
1438
        }
1439
        
1440
        /**
1441
         * <strong>Should</strong> return a drug if either the drug name or concept name matches the phase not both
1442
         * <strong>Should</strong> return distinct drugs
1443
         * <strong>Should</strong> return a drug, if phrase match concept_name No need to match both concept_name and
1444
         *         drug_name
1445
         * <strong>Should</strong> return drug when phrase match drug_name even searchDrugConceptNames is false
1446
         * <strong>Should</strong> return a drug if phrase match drug_name No need to match both concept_name and
1447
         *         drug_name
1448
         */
1449
        @Override
1450
        public List<Drug> getDrugs(String drugName, Concept concept, boolean searchKeywords, boolean searchDrugConceptNames,
1451
                boolean includeRetired, Integer start, Integer length) throws DAOException {
1452
                SearchQuery<Drug> drugsQuery = newDrugQuery(drugName, searchKeywords, searchDrugConceptNames, Context.getLocale(),
1✔
1453
                    false, concept, includeRetired);
1454
                
1455
                if (drugsQuery == null) {
1✔
1456
                        return Collections.emptyList();
×
1457
                }
1458
                
1459
                return drugsQuery.fetchHits(start, length);
1✔
1460
        }
1461
        
1462
        private SearchQuery<Drug> newDrugQuery(String drugName, boolean searchKeywords, boolean searchDrugConceptNames,
1463
                                                                                   Locale locale, boolean exactLocale, Concept concept, boolean includeRetired) {
1464
                if (StringUtils.isBlank(drugName) && concept == null) {
1✔
1465
                        return null;
×
1466
                }
1467
                final Collection<Locale> locales = Collections.singletonList(locale == null ? Context.getLocale() : locale);
1✔
1468

1469
                final List<Object> conceptIds;
1470
                if (searchDrugConceptNames) {
1✔
1471
                        SearchSession searchSession = searchSessionFactory.getSearchSession();
1✔
1472
                        SearchScope<ConceptName> scope = searchSession.scope(ConceptName.class);
1✔
1473
                        
1474
                        SearchPredicate conceptNamePredicate = newConceptNamePredicate(scope.predicate(), drugName, searchKeywords, locales, exactLocale,
1✔
1475
                                includeRetired, null, null, null, null, null);
1476

1477
                        conceptIds = SearchQueryUnique.findUniqueKeys(searchSession, scope, conceptNamePredicate, "concept.conceptId");
1✔
1478
                } else {
1✔
1479
                        conceptIds = Collections.emptyList();
1✔
1480
                }
1481
                
1482
                return searchSessionFactory.getSearchSession().search(Drug.class).where(f -> f.bool().with(b -> {
1✔
1483
                        b.minimumShouldMatchNumber(1);
1✔
1484
                        List<String> tokenizedName = tokenizeName(drugName, locales);
1✔
1485
                        BooleanPredicateClausesStep<?> nameQuery = newNameQuery(f, tokenizedName, drugName, searchKeywords);
1✔
1486
                        b.should(f.match().field("drugReferenceMaps.conceptReferenceTerm.code").matching(drugName).boost(10f));
1✔
1487
                        b.should(nameQuery.boost(0.5f));
1✔
1488
                        if (concept != null) {
1✔
1489
                                b.should(f.match().field("concept.conceptId").matching(concept.getId()).boost(0.1f));
1✔
1490
                        }
1491
                        if (!conceptIds.isEmpty()) {
1✔
1492
                                float boost = 0.1f;
1✔
1493
                                int boostItems = 10; // boost first items in order
1✔
1494
                                int i = 0;
1✔
1495
                                for (Object conceptId : conceptIds) {
1✔
1496
                                        b.should(f.match().field("concept.conceptId").matching(conceptId).boost(boost));
1✔
1497
                                        boost = boost * 0.9f;
1✔
1498
                                        i++;
1✔
1499
                                        if (boostItems == i) {
1✔
NEW
1500
                                                break;
×
1501
                                        }
1502
                                }
1✔
1503
                                if (conceptIds.size() > boostItems) {
1✔
NEW
1504
                                        b.should(f.terms().field("concept.conceptId").matchingAny(
×
NEW
1505
                                                conceptIds.subList(boostItems, conceptIds.size())).boost(boost));
×
1506
                                }
1507
                        }
1508
                        if (!includeRetired) {
1✔
1509
                                b.filter(f.match().field("retired").matching(Boolean.FALSE));
1✔
1510
                        }
1511
                })).toQuery();
1✔
1512
        }
1513

1514
        /**
1515
         * @see ConceptDAO#getConcepts(String, List, boolean, List, List, List, List, Concept, Integer,
1516
         *      Integer)
1517
         */
1518
        @Override
1519
        public List<ConceptSearchResult> getConcepts(final String phrase, final List<Locale> locales,
1520
                final boolean includeRetired, final List<ConceptClass> requireClasses, final List<ConceptClass> excludeClasses,
1521
                final List<ConceptDatatype> requireDatatypes, final List<ConceptDatatype> excludeDatatypes,
1522
                final Concept answersToConcept, final Integer start, final Integer size) throws DAOException {
1523
                
1524
                return SearchQueryUnique.search(searchSessionFactory, SearchQueryUnique.newQuery(ConceptName.class, f -> 
1✔
1525
                        newConceptNamePredicate(f, phrase, true, locales, false, includeRetired,
1✔
1526
                        requireClasses, excludeClasses, requireDatatypes, excludeDatatypes, answersToConcept), "concept.conceptId", 
1527
                        n -> new ConceptSearchResult(phrase, n.getConcept(), n)), start, size);
1✔
1528
        }
1529
        
1530
        @Override
1531
        public Integer getCountOfConcepts(final String phrase, List<Locale> locales, boolean includeRetired,
1532
                List<ConceptClass> requireClasses, List<ConceptClass> excludeClasses, List<ConceptDatatype> requireDatatypes,
1533
                List<ConceptDatatype> excludeDatatypes, Concept answersToConcept) throws DAOException {
1534
                
1535
                
1536
                return Math.toIntExact(SearchQueryUnique.searchCount(searchSessionFactory, 
1✔
1537
                        SearchQueryUnique.newQuery(ConceptName.class, f -> newConceptNamePredicate(f, phrase, 
1✔
1538
                                true, locales, false, includeRetired, requireClasses, excludeClasses, 
1539
                                requireDatatypes, excludeDatatypes, answersToConcept), "concept.conceptId")));
1540
        }
1541
        
1542
        private SearchPredicate newConceptNamePredicate(SearchPredicateFactory f, final String phrase, boolean searchKeywords,
1543
                                                                                                           Collection<Locale> locales, boolean searchExactLocale, boolean includeRetired, List<ConceptClass> requireClasses,
1544
                                                                                                           List<ConceptClass> excludeClasses, List<ConceptDatatype> requireDatatypes,
1545
                                                                                                           List<ConceptDatatype> excludeDatatypes, Concept answersToConcept) {
1546
                return f.bool().with(b -> {
1✔
1547
                        if (!StringUtils.isBlank(phrase)) {
1✔
1548
                                final Collection<Locale> searchLocales;
1549

1550
                                if (locales == null) {
1✔
1551
                                        searchLocales = Collections.singletonList(Context.getLocale());
1✔
1552
                                } else {
1553
                                        searchLocales = new HashSet<>(locales);
1✔
1554
                                }
1555

1556
                                b.must(newConceptNameQuery(f, phrase, searchKeywords, searchLocales, searchExactLocale));
1✔
1557
                        }
1558

1559
                        if (!CollectionUtils.isEmpty(requireClasses)) {
1✔
1560
                                b.filter(f.terms().field("concept.conceptClass")
1✔
1561
                                        .matchingAny(requireClasses));
1✔
1562
                        }
1563
                        if (!CollectionUtils.isEmpty(excludeClasses)) {
1✔
1564
                                b.filter(f.not(f.terms().field("concept.conceptClass")
1✔
1565
                                        .matchingAny(excludeClasses)));
1✔
1566
                        }
1567
                        if (!CollectionUtils.isEmpty(requireDatatypes)) {
1✔
NEW
1568
                                b.filter(f.terms().field("concept.datatype")
×
NEW
1569
                                        .matchingAny(requireDatatypes));
×
1570
                        }
1571
                        if (!CollectionUtils.isEmpty(excludeDatatypes)) {
1✔
NEW
1572
                                b.filter(f.not(f.terms().field("concept.datatype")
×
NEW
1573
                                        .matchingAny(excludeDatatypes)));
×
1574
                        }
1575

1576
                        if (answersToConcept != null) {
1✔
1577
                                Collection<ConceptAnswer> answers = answersToConcept.getAnswers(false);
1✔
1578

1579
                                if (answers != null && !answers.isEmpty()) {
1✔
NEW
1580
                                        List<Integer> ids = new ArrayList<>();
×
NEW
1581
                                        for (ConceptAnswer conceptAnswer : answersToConcept.getAnswers(false)) {
×
NEW
1582
                                                ids.add(conceptAnswer.getAnswerConcept().getId());
×
NEW
1583
                                        }
×
NEW
1584
                                        b.filter(f.terms().field("concept.conceptId").matchingAny(ids));
×
1585
                                }
1586
                        }
1587

1588
                        if (!includeRetired) {
1✔
1589
                                b.filter(f.match().field("concept.retired").matching(Boolean.FALSE));
1✔
1590
                        }
1591
                }).toPredicate();
1✔
1592
        }
1593

1594
        /**
1595
         * @see org.openmrs.api.db.ConceptDAO#getConceptMapTypes(boolean, boolean)
1596
         */
1597
        @Override
1598
        public List<ConceptMapType> getConceptMapTypes(boolean includeRetired, boolean includeHidden) throws DAOException {
1599
                Session session = sessionFactory.getCurrentSession();
1✔
1600
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
1601
                CriteriaQuery<ConceptMapType> cq = cb.createQuery(ConceptMapType.class);
1✔
1602
                Root<ConceptMapType> root = cq.from(ConceptMapType.class);
1✔
1603

1604
                List<Predicate> predicates = new ArrayList<>();
1✔
1605
                if (!includeRetired) {
1✔
1606
                        predicates.add(cb.isFalse(root.get("retired")));
1✔
1607
                }
1608
                if (!includeHidden) {
1✔
1609
                        predicates.add(cb.isFalse(root.get("isHidden")));
1✔
1610
                }
1611

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

1614
                List<ConceptMapType> conceptMapTypes = session.createQuery(cq).getResultList();
1✔
1615
                conceptMapTypes.sort(new ConceptMapTypeComparator());
1✔
1616

1617
                return conceptMapTypes;
1✔
1618
        }
1619
        
1620
        /**
1621
         * @see org.openmrs.api.db.ConceptDAO#getConceptMapType(java.lang.Integer)
1622
         */
1623
        @Override
1624
        public ConceptMapType getConceptMapType(Integer conceptMapTypeId) throws DAOException {
1625
                return sessionFactory.getCurrentSession().get(ConceptMapType.class, conceptMapTypeId);
1✔
1626
        }
1627

1628
        /**
1629
         * @see org.openmrs.api.db.ConceptDAO#getConceptMapTypeByUuid(java.lang.String)
1630
         */
1631
        @Override
1632
        public ConceptMapType getConceptMapTypeByUuid(String uuid) throws DAOException {
1633
                return HibernateUtil.getUniqueEntityByUUID(sessionFactory, ConceptMapType.class, uuid);
1✔
1634
        }
1635

1636
        /**
1637
         * @see org.openmrs.api.db.ConceptDAO#getConceptMapTypeByName(java.lang.String)
1638
         */
1639
        @Override
1640
        public ConceptMapType getConceptMapTypeByName(String name) throws DAOException {
1641
                Session session = sessionFactory.getCurrentSession();
1✔
1642
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
1643
                CriteriaQuery<ConceptMapType> cq = cb.createQuery(ConceptMapType.class);
1✔
1644
                Root<ConceptMapType> root = cq.from(ConceptMapType.class);
1✔
1645

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

1648
                return session.createQuery(cq).uniqueResult();
1✔
1649
        }
1650
        
1651
        /**
1652
         * @see org.openmrs.api.db.ConceptDAO#saveConceptMapType(org.openmrs.ConceptMapType)
1653
         */
1654
        @Override
1655
        public ConceptMapType saveConceptMapType(ConceptMapType conceptMapType) throws DAOException {
1656
                sessionFactory.getCurrentSession().saveOrUpdate(conceptMapType);
1✔
1657
                return conceptMapType;
1✔
1658
        }
1659
        
1660
        /**
1661
         * @see org.openmrs.api.db.ConceptDAO#deleteConceptMapType(org.openmrs.ConceptMapType)
1662
         */
1663
        @Override
1664
        public void deleteConceptMapType(ConceptMapType conceptMapType) throws DAOException {
1665
                sessionFactory.getCurrentSession().delete(conceptMapType);
1✔
1666
        }
1✔
1667

1668
        /**
1669
         * @see org.openmrs.api.db.ConceptDAO#getConceptReferenceTerms(boolean)
1670
         */
1671
        @Override
1672
        public List<ConceptReferenceTerm> getConceptReferenceTerms(boolean includeRetired) throws DAOException {
1673
                Session session = sessionFactory.getCurrentSession();
1✔
1674
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
1675
                CriteriaQuery<ConceptReferenceTerm> cq = cb.createQuery(ConceptReferenceTerm.class);
1✔
1676
                Root<ConceptReferenceTerm> root = cq.from(ConceptReferenceTerm.class);
1✔
1677

1678
                if (!includeRetired) {
1✔
1679
                        cq.where(cb.isFalse(root.get("retired")));
1✔
1680
                }
1681
                return session.createQuery(cq).getResultList();
1✔
1682
        }
1683
        
1684
        /**
1685
         * @see org.openmrs.api.db.ConceptDAO#getConceptReferenceTerm(java.lang.Integer)
1686
         */
1687
        @Override
1688
        public ConceptReferenceTerm getConceptReferenceTerm(Integer conceptReferenceTermId) throws DAOException {
1689
                return sessionFactory.getCurrentSession().get(ConceptReferenceTerm.class,
1✔
1690
                    conceptReferenceTermId);
1691
        }
1692

1693
        /**
1694
         * @see org.openmrs.api.db.ConceptDAO#getConceptReferenceTermByUuid(java.lang.String)
1695
         */
1696
        @Override
1697
        public ConceptReferenceTerm getConceptReferenceTermByUuid(String uuid) throws DAOException {
1698
                return HibernateUtil.getUniqueEntityByUUID(sessionFactory, ConceptReferenceTerm.class, uuid);
1✔
1699
        }
1700
        
1701
        /**
1702
         * @see org.openmrs.api.db.ConceptDAO#getConceptReferenceTermsBySource(ConceptSource)
1703
         */
1704
        @Override
1705
        public List<ConceptReferenceTerm> getConceptReferenceTermsBySource(ConceptSource conceptSource) throws DAOException {
1706
                Session session = sessionFactory.getCurrentSession();
×
1707
                CriteriaBuilder cb = session.getCriteriaBuilder();
×
1708
                CriteriaQuery<ConceptReferenceTerm> cq = cb.createQuery(ConceptReferenceTerm.class);
×
1709
                Root<ConceptReferenceTerm> root = cq.from(ConceptReferenceTerm.class);
×
1710

1711
                cq.where(cb.equal(root.get("conceptSource"), conceptSource));
×
1712

1713
                return session.createQuery(cq).getResultList();
×
1714
        }
1715

1716
        /**
1717
         * @see org.openmrs.api.db.ConceptDAO#getConceptReferenceTermByName(java.lang.String,
1718
         *      org.openmrs.ConceptSource)
1719
         */
1720
        @Override
1721
        public ConceptReferenceTerm getConceptReferenceTermByName(String name, ConceptSource conceptSource) throws DAOException {
1722
                Session session = sessionFactory.getCurrentSession();
1✔
1723
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
1724
                CriteriaQuery<ConceptReferenceTerm> cq = cb.createQuery(ConceptReferenceTerm.class);
1✔
1725
                Root<ConceptReferenceTerm> root = cq.from(ConceptReferenceTerm.class);
1✔
1726

1727
                Predicate namePredicate = cb.like(cb.lower(root.get("name")), MatchMode.EXACT.toLowerCasePattern(name));
1✔
1728
                Predicate sourcePredicate = cb.equal(root.get("conceptSource"), conceptSource);
1✔
1729

1730
                cq.where(cb.and(namePredicate, sourcePredicate));
1✔
1731

1732
                List<ConceptReferenceTerm> terms = session.createQuery(cq).getResultList();
1✔
1733
                if (terms.isEmpty()) {
1✔
1734
                        return null;
×
1735
                } else if (terms.size() > 1) {
1✔
1736
                        throw new APIException("ConceptReferenceTerm.foundMultipleTermsWithNameInSource",
×
1737
                                new Object[]{name, conceptSource.getName()});
×
1738
                }
1739
                return terms.get(0);
1✔
1740
        }
1741
        
1742
        /**
1743
         * @see org.openmrs.api.db.ConceptDAO#getConceptReferenceTermByCode(java.lang.String,
1744
         *      org.openmrs.ConceptSource)
1745
         */
1746
        @Override
1747
        public ConceptReferenceTerm getConceptReferenceTermByCode(String code, ConceptSource conceptSource) throws DAOException {
1748
                List<ConceptReferenceTerm> conceptReferenceTerms = getConceptReferenceTermByCode(code, conceptSource, true);
1✔
1749
                
1750
                if (conceptReferenceTerms.isEmpty()) {
1✔
1751
                        return null;
1✔
1752
                } else if (conceptReferenceTerms.size() > 1) {
1✔
1753
                        List<ConceptReferenceTerm> unretiredConceptReferenceTerms = conceptReferenceTerms.stream()
1✔
1754
                                .filter(term -> !term.getRetired())
1✔
1755
                                        .collect(toList());
1✔
1756
                        if (unretiredConceptReferenceTerms.size() == 1) {
1✔
1757
                                return unretiredConceptReferenceTerms.get(0);
1✔
1758
                        }
1759
                        
1760
                        // either more than one unretired concept term or more than one retired concept term
1761
                        throw new APIException("ConceptReferenceTerm.foundMultipleTermsWithCodeInSource",
×
1762
                                new Object[] { code, conceptSource.getName() });
×
1763
                }
1764
                
1765
                return conceptReferenceTerms.get(0);
1✔
1766
        }
1767

1768
        /**
1769
         * @see org.openmrs.api.db.ConceptDAO#getConceptReferenceTermByCode(java.lang.String,
1770
         *      org.openmrs.ConceptSource, boolean)
1771
         */
1772
        @Override
1773
        public List<ConceptReferenceTerm> getConceptReferenceTermByCode(String code, ConceptSource conceptSource,
1774
                boolean includeRetired) throws DAOException {
1775
                Session session = sessionFactory.getCurrentSession();
1✔
1776
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
1777
                CriteriaQuery<ConceptReferenceTerm> cq = cb.createQuery(ConceptReferenceTerm.class);
1✔
1778
                Root<ConceptReferenceTerm> root = cq.from(ConceptReferenceTerm.class);
1✔
1779

1780
                List<Predicate> predicates = new ArrayList<>();
1✔
1781
                predicates.add(cb.equal(root.get("code"), code));
1✔
1782
                predicates.add(cb.equal(root.get("conceptSource"), conceptSource));
1✔
1783
                
1784
                if (!includeRetired) {
1✔
1785
                        predicates.add(cb.isFalse(root.get("retired")));
1✔
1786
                }
1787
                cq.where(predicates.toArray(new Predicate[]{}));
1✔
1788

1789
                return session.createQuery(cq).getResultList();
1✔
1790
        }
1791
        
1792
        /**
1793
         * @see org.openmrs.api.db.ConceptDAO#saveConceptReferenceTerm(org.openmrs.ConceptReferenceTerm)
1794
         */
1795
        @Override
1796
        public ConceptReferenceTerm saveConceptReferenceTerm(ConceptReferenceTerm conceptReferenceTerm) throws DAOException {
1797
                sessionFactory.getCurrentSession().saveOrUpdate(conceptReferenceTerm);
1✔
1798
                return conceptReferenceTerm;
1✔
1799
        }
1800
        
1801
        /**
1802
         * @see org.openmrs.api.db.ConceptDAO#deleteConceptReferenceTerm(org.openmrs.ConceptReferenceTerm)
1803
         */
1804
        @Override
1805
        public void deleteConceptReferenceTerm(ConceptReferenceTerm conceptReferenceTerm) throws DAOException {
1806
                sessionFactory.getCurrentSession().delete(conceptReferenceTerm);
1✔
1807
        }
1✔
1808

1809
        @Override
1810
        public Long getCountOfConceptReferenceTerms(String query, ConceptSource conceptSource, boolean includeRetired)
1811
                throws DAOException {
1812
                Session session = sessionFactory.getCurrentSession();
1✔
1813
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
1814
                CriteriaQuery<Long> cq = cb.createQuery(Long.class);
1✔
1815
                Root<ConceptReferenceTerm> root = cq.from(ConceptReferenceTerm.class);
1✔
1816

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

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

1821
                return session.createQuery(cq).getSingleResult();
1✔
1822
        }
1823

1824

1825
        /**
1826
         * @see org.openmrs.api.db.ConceptDAO#getConceptReferenceTerms(String, ConceptSource, Integer,
1827
         *      Integer, boolean)
1828
         */
1829
        @Override
1830
        public List<ConceptReferenceTerm> getConceptReferenceTerms(String query, ConceptSource conceptSource, Integer start,
1831
                                                                                                                           Integer length, boolean includeRetired) throws APIException {
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
                List<Predicate> predicates = createConceptReferenceTermPredicates(cb, root, query, conceptSource, includeRetired);
1✔
1838
                cq.where(predicates.toArray(new Predicate[]{}));
1✔
1839

1840
                TypedQuery<ConceptReferenceTerm> typedQuery = session.createQuery(cq);
1✔
1841

1842
                if (start != null) {
1✔
1843
                        typedQuery.setFirstResult(start);
1✔
1844
                }
1845
                if (length != null && length > 0) {
1✔
1846
                        typedQuery.setMaxResults(length);
1✔
1847
                }
1848

1849
                return typedQuery.getResultList();
1✔
1850
        }
1851

1852
        private List<Predicate> createConceptReferenceTermPredicates(CriteriaBuilder cb, Root<ConceptReferenceTerm> root,
1853
                                                                                                                                 String query, ConceptSource conceptSource, boolean includeRetired) {
1854
                List<Predicate> predicates = new ArrayList<>();
1✔
1855

1856
                if (conceptSource != null) {
1✔
1857
                        predicates.add(cb.equal(root.get("conceptSource"), conceptSource));
1✔
1858
                }
1859
                if (!includeRetired) {
1✔
1860
                        predicates.add(cb.isFalse(root.get("retired")));
1✔
1861
                }
1862
                if (query != null) {
1✔
1863
                        Predicate namePredicate = cb.like(cb.lower(root.get("name")), MatchMode.ANYWHERE.toLowerCasePattern(query));
1✔
1864
                        Predicate codePredicate = cb.like(cb.lower(root.get("code")), MatchMode.ANYWHERE.toLowerCasePattern(query));
1✔
1865

1866
                        predicates.add(cb.or(namePredicate, codePredicate));
1✔
1867
                }
1868

1869
                return predicates;
1✔
1870
        }
1871

1872
        /**
1873
         * @see org.openmrs.api.db.ConceptDAO#getReferenceTermMappingsTo(ConceptReferenceTerm)
1874
         */
1875
        @Override
1876
        public List<ConceptReferenceTermMap> getReferenceTermMappingsTo(ConceptReferenceTerm term) throws DAOException {
1877
                Session session = sessionFactory.getCurrentSession();
1✔
1878
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
1879
                CriteriaQuery<ConceptReferenceTermMap> cq = cb.createQuery(ConceptReferenceTermMap.class);
1✔
1880
                Root<ConceptReferenceTermMap> root = cq.from(ConceptReferenceTermMap.class);
1✔
1881

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

1884
                return session.createQuery(cq).getResultList();
1✔
1885
        }
1886

1887
        /**
1888
         * @see org.openmrs.api.db.ConceptDAO#isConceptReferenceTermInUse(org.openmrs.ConceptReferenceTerm)
1889
         */
1890
        @Override
1891
        public boolean isConceptReferenceTermInUse(ConceptReferenceTerm term) throws DAOException {
1892
                Session session = sessionFactory.getCurrentSession();
1✔
1893
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
1894

1895
                // Check in ConceptMap table
1896
                CriteriaQuery<Long> conceptMapQuery = cb.createQuery(Long.class);
1✔
1897
                Root<ConceptMap> conceptMapRoot = conceptMapQuery.from(ConceptMap.class);
1✔
1898
                conceptMapQuery.select(cb.count(conceptMapRoot));
1✔
1899
                conceptMapQuery.where(cb.equal(conceptMapRoot.get("conceptReferenceTerm"), term));
1✔
1900

1901
                Long conceptMapCount = session.createQuery(conceptMapQuery).uniqueResult();
1✔
1902
                if (conceptMapCount > 0) {
1✔
1903
                        return true;
1✔
1904
                }
1905

1906
                // Check in ConceptReferenceTermMap table
1907
                CriteriaQuery<Long> conceptReferenceTermMapQuery = cb.createQuery(Long.class);
1✔
1908
                Root<ConceptReferenceTermMap> conceptReferenceTermMapRoot =
1✔
1909
                        conceptReferenceTermMapQuery.from(ConceptReferenceTermMap.class);
1✔
1910
                conceptReferenceTermMapQuery.select(cb.count(conceptReferenceTermMapRoot));
1✔
1911
                conceptReferenceTermMapQuery.where(cb.equal(conceptReferenceTermMapRoot.get("termB"), term));
1✔
1912

1913
                Long conceptReferenceTermMapCount = session.createQuery(conceptReferenceTermMapQuery).uniqueResult();
1✔
1914
                return conceptReferenceTermMapCount > 0;
1✔
1915
        }
1916

1917
        /**
1918
         * @see org.openmrs.api.db.ConceptDAO#isConceptMapTypeInUse(org.openmrs.ConceptMapType)
1919
         */
1920
        @Override
1921
        public boolean isConceptMapTypeInUse(ConceptMapType mapType) throws DAOException {
1922
                Session session = sessionFactory.getCurrentSession();
1✔
1923
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
1924

1925
                // Check in ConceptMap table
1926
                CriteriaQuery<Long> conceptQuery = cb.createQuery(Long.class);
1✔
1927
                Root<ConceptMap> conceptRoot = conceptQuery.from(ConceptMap.class);
1✔
1928
                conceptQuery.select(cb.count(conceptRoot));
1✔
1929
                conceptQuery.where(cb.equal(conceptRoot.get("conceptMapType"), mapType));
1✔
1930

1931
                Long conceptCount = session.createQuery(conceptQuery).uniqueResult();
1✔
1932
                if (conceptCount > 0) {
1✔
1933
                        return true;
1✔
1934
                }
1935

1936
                // Check in ConceptReferenceTermMap table
1937
                CriteriaQuery<Long> conceptReferenceTermMapQuery = cb.createQuery(Long.class);
1✔
1938
                Root<ConceptReferenceTermMap> conceptReferenceTermMapRoot = conceptReferenceTermMapQuery.from(ConceptReferenceTermMap.class);
1✔
1939
                conceptReferenceTermMapQuery.select(cb.count(conceptReferenceTermMapRoot));
1✔
1940
                conceptReferenceTermMapQuery.where(cb.equal(conceptReferenceTermMapRoot.get("conceptMapType"), mapType));
1✔
1941

1942
                Long conceptReferenceTermMapCount = session.createQuery(conceptReferenceTermMapQuery).uniqueResult();
1✔
1943
                return conceptReferenceTermMapCount > 0;
1✔
1944
        }
1945
        
1946
        /**
1947
         * @see org.openmrs.api.db.ConceptDAO#getConceptsByName(java.lang.String, java.util.Locale,
1948
         *      java.lang.Boolean)
1949
         */
1950
        @Override
1951
        public List<Concept> getConceptsByName(final String name, final Locale locale, final Boolean exactLocale) {
1952
                
1953
                List<Locale> locales = new ArrayList<>();
1✔
1954
                if (locale == null) {
1✔
1955
                        locales.add(Context.getLocale());
×
1956
                } else {
1957
                        locales.add(locale);
1✔
1958
                }
1959
                
1960
                boolean searchExactLocale = (exactLocale == null) ? false : exactLocale;
1✔
1961
                
1962
                return SearchQueryUnique.search(searchSessionFactory, SearchQueryUnique.newQuery(ConceptName.class, f -> 
1✔
1963
                        newConceptNamePredicate(f, name, true, locales, searchExactLocale, false,
1✔
1964
                        null, null, null, null, null), 
1965
                        "concept.conceptId", ConceptName::getConcept));
1966
        }
1967
        
1968
        /**
1969
         * @see org.openmrs.api.db.ConceptDAO#getConceptByName(java.lang.String)
1970
         */
1971
        @Override
1972
        public Concept getConceptByName(final String name) {
1973
                Session session = sessionFactory.getCurrentSession();
1✔
1974
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
1975
                CriteriaQuery<ConceptName> cq = cb.createQuery(ConceptName.class);
1✔
1976
                Root<ConceptName> root = cq.from(ConceptName.class);
1✔
1977
                Join<ConceptName, Concept> conceptJoin = root.join("concept");
1✔
1978

1979
                Locale locale = Context.getLocale();
1✔
1980
                Locale language = new Locale(locale.getLanguage() + "%");
1✔
1981
                List<Predicate> predicates = new ArrayList<>();
1✔
1982

1983
                predicates.add(cb.or(cb.equal(root.get("locale"), locale), cb.like(root.get("locale").as(String.class), language.toString())));
1✔
1984
                if (Context.getAdministrationService().isDatabaseStringComparisonCaseSensitive()) {
1✔
1985
                        predicates.add(cb.like(cb.lower(root.get("name")), name.toLowerCase()));
1✔
1986
                } else {
1987
                        predicates.add(cb.equal(root.get("name"), name));
×
1988
                }
1989
                predicates.add(cb.isFalse(root.get("voided")));
1✔
1990
                predicates.add(cb.isFalse(conceptJoin.get("retired")));
1✔
1991

1992
                cq.where(predicates.toArray(new Predicate[0]));
1✔
1993

1994
                List<ConceptName> list = session.createQuery(cq).getResultList();
1✔
1995
                LinkedHashSet<Concept> concepts = transformNamesToConcepts(list);
1✔
1996

1997
                if (concepts.size() == 1) {
1✔
1998
                        return concepts.iterator().next();
1✔
1999
                } else if (list.isEmpty()) {
1✔
2000
                        log.warn("No concept found for '" + name + "'");
1✔
2001
                } else {
2002
                        log.warn("Multiple concepts found for '" + name + "'");
×
2003

2004
                        for (Concept concept : concepts) {
×
2005
                                for (ConceptName conceptName : concept.getNames(locale)) {
×
2006
                                        if (conceptName.getName().equalsIgnoreCase(name)) {
×
2007
                                                return concept;
×
2008
                                        }
2009
                                }
×
2010
                                for (ConceptName indexTerm : concept.getIndexTermsForLocale(locale)) {
×
2011
                                        if (indexTerm.getName().equalsIgnoreCase(name)) {
×
2012
                                                return concept;
×
2013
                                        }
2014
                                }
×
2015
                        }
×
2016
                }
2017

2018
                return null;
1✔
2019
        }
2020
        
2021
        /**
2022
         * @see org.openmrs.api.db.ConceptDAO#getDefaultConceptMapType()
2023
         */
2024
        @Override
2025
        public ConceptMapType getDefaultConceptMapType() throws DAOException {
2026
                FlushMode previousFlushMode = sessionFactory.getCurrentSession().getHibernateFlushMode();
1✔
2027
                sessionFactory.getCurrentSession().setHibernateFlushMode(FlushMode.MANUAL);
1✔
2028
                try {
2029
                        //Defaults to same-as if the gp is not set.
2030
                        String defaultConceptMapType = Context.getAdministrationService().getGlobalProperty(
1✔
2031
                            OpenmrsConstants.GP_DEFAULT_CONCEPT_MAP_TYPE);
2032
                        if (defaultConceptMapType == null) {
1✔
2033
                                throw new DAOException("The default concept map type is not set. You need to set the '"
×
2034
                                        + OpenmrsConstants.GP_DEFAULT_CONCEPT_MAP_TYPE + "' global property.");
2035
                        }
2036
                        
2037
                        ConceptMapType conceptMapType = getConceptMapTypeByName(defaultConceptMapType);
1✔
2038
                        if (conceptMapType == null) {
1✔
2039
                                throw new DAOException("The default concept map type (name: " + defaultConceptMapType
×
2040
                                        + ") does not exist! You need to set the '" + OpenmrsConstants.GP_DEFAULT_CONCEPT_MAP_TYPE
2041
                                        + "' global property.");
2042
                        }
2043
                        return conceptMapType;
1✔
2044
                }
2045
                finally {
2046
                        sessionFactory.getCurrentSession().setHibernateFlushMode(previousFlushMode);
1✔
2047
                }
2048
        }
2049

2050
        /**
2051
         * @see org.openmrs.api.db.ConceptDAO#isConceptNameDuplicate(org.openmrs.ConceptName)
2052
         */
2053
        @Override
2054
        public boolean isConceptNameDuplicate(ConceptName name) {
2055
                if (name.getVoided()) {
1✔
2056
                        return false;
×
2057
                }
2058
                if (name.getConcept() != null) {
1✔
2059
                        if (name.getConcept().getRetired()) {
1✔
2060
                                return false;
×
2061
                        }
2062

2063
                        //If it is not a default name of a concept, it cannot be a duplicate.
2064
                        //Note that a concept may not have a default name for the given locale, if just a short name or
2065
                        //a search term is set.
2066
                        if (!name.equals(name.getConcept().getName(name.getLocale()))) {
1✔
2067
                                return false;
1✔
2068
                        }
2069
                }
2070

2071
                Session session = sessionFactory.getCurrentSession();
1✔
2072
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
2073
                CriteriaQuery<ConceptName> cq = cb.createQuery(ConceptName.class);
1✔
2074
                Root<ConceptName> root = cq.from(ConceptName.class);
1✔
2075

2076
                List<Predicate> predicates = new ArrayList<>();
1✔
2077

2078
                predicates.add(cb.isFalse(root.get("voided")));
1✔
2079
                predicates.add(cb.or(cb.equal(root.get("locale"), name.getLocale()),
1✔
2080
                        cb.equal(root.get("locale"), new Locale(name.getLocale().getLanguage()))));
1✔
2081

2082
                if (Context.getAdministrationService().isDatabaseStringComparisonCaseSensitive()) {
1✔
2083
                        predicates.add(cb.equal(cb.lower(root.get("name")), name.getName().toLowerCase()));
1✔
2084
                } else {
2085
                        predicates.add(cb.equal(root.get("name"), name.getName()));
×
2086
                }
2087

2088
                cq.where(predicates.toArray(new Predicate[0]));
1✔
2089

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

2092
                for (ConceptName candidateName : candidateNames) {
1✔
2093
                        if (candidateName.getConcept().getRetired()) {
1✔
2094
                                continue;
1✔
2095
                        }
2096
                        if (candidateName.getConcept().equals(name.getConcept())) {
1✔
2097
                                continue;
1✔
2098
                        }
2099
                        // If it is a default name for a concept
2100
                        if (candidateName.getConcept().getName(candidateName.getLocale()).equals(candidateName)) {
1✔
2101
                                return true;
1✔
2102
                        }
2103
                }
1✔
2104

2105
                return false;
1✔
2106
        }
2107
        
2108
        /**
2109
         * @see ConceptDAO#getDrugs(String, java.util.Locale, boolean, boolean)
2110
         */
2111
        @Override
2112
        public List<Drug> getDrugs(String searchPhrase, Locale locale, boolean exactLocale, boolean includeRetired) {
2113
                SearchQuery<Drug> drugQuery = newDrugQuery(searchPhrase, true, true, locale, exactLocale, null, includeRetired);
1✔
2114
                
2115
                return drugQuery.fetchAllHits();
1✔
2116
        }
2117

2118
        /**
2119
         * @see org.openmrs.api.db.ConceptDAO#getDrugsByMapping(String, ConceptSource, Collection, boolean)
2120
         */
2121
        @Override
2122
        public List<Drug> getDrugsByMapping(String code, ConceptSource conceptSource,
2123
                                                                                Collection<ConceptMapType> withAnyOfTheseTypes, boolean includeRetired) throws DAOException {
2124

2125
                Session session = sessionFactory.getCurrentSession();
1✔
2126
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
2127
                CriteriaQuery<Drug> cq = cb.createQuery(Drug.class);
1✔
2128
                Root<Drug> drugRoot = cq.from(Drug.class);
1✔
2129

2130
                Join<Drug, DrugReferenceMap> drugReferenceMapJoin = drugRoot.join("drugReferenceMaps");
1✔
2131
                Join<DrugReferenceMap, ConceptReferenceTerm> termJoin = drugReferenceMapJoin.join("conceptReferenceTerm");
1✔
2132
                List<Predicate> basePredicates = createSearchDrugByMappingPredicates(cb, drugRoot, drugReferenceMapJoin, termJoin, code, conceptSource, includeRetired);
1✔
2133

2134
                if (!withAnyOfTheseTypes.isEmpty()) {
1✔
2135
                        // Create a predicate to check if the ConceptMapType is in the provided collection
2136
                        Predicate mapTypePredicate = drugReferenceMapJoin.get("conceptMapType").in(withAnyOfTheseTypes);
1✔
2137
                        basePredicates.add(mapTypePredicate);
1✔
2138
                }
2139

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

2142
                return session.createQuery(cq).getResultList().stream().distinct().collect(toList());
1✔
2143
        }
2144

2145
        /**
2146
         * @see org.openmrs.api.db.ConceptDAO#getDrugs
2147
         */
2148
        @Override
2149
        public Drug getDrugByMapping(String code, ConceptSource conceptSource,
2150
                                                                 Collection<ConceptMapType> withAnyOfTheseTypesOrOrderOfPreference) throws DAOException {
2151
                Session session = sessionFactory.getCurrentSession();
1✔
2152
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
2153
                CriteriaQuery<Drug> cq = cb.createQuery(Drug.class);
1✔
2154
                Root<Drug> drugRoot = cq.from(Drug.class);
1✔
2155

2156
                Join<Drug, DrugReferenceMap> drugReferenceMapJoin = drugRoot.join("drugReferenceMaps");
1✔
2157
                Join<DrugReferenceMap, ConceptReferenceTerm> termJoin = drugReferenceMapJoin.join("conceptReferenceTerm");
1✔
2158

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

2161
                if (!withAnyOfTheseTypesOrOrderOfPreference.isEmpty()) {
1✔
2162
                        for (ConceptMapType conceptMapType : withAnyOfTheseTypesOrOrderOfPreference) {
1✔
2163
                                
2164
                                List<Predicate> predicates = new ArrayList<>(basePredicates);
1✔
2165
                                predicates.add(cb.equal(drugReferenceMapJoin.get("conceptMapType"), conceptMapType));
1✔
2166
                                cq.where(predicates.toArray(new Predicate[]{}));
1✔
2167

2168
                                TypedQuery<Drug> query = session.createQuery(cq);
1✔
2169
                                List<Drug> drugs = query.getResultList();
1✔
2170
                                if (drugs.size() > 1) {
1✔
2171
                                        throw new DAOException("There are multiple matches for the highest-priority ConceptMapType");
1✔
2172
                                } else if (drugs.size() == 1) {
1✔
2173
                                        return drugs.get(0);
1✔
2174
                                }
2175
                        }
1✔
2176
                } else {
2177
                        cq.where(basePredicates.toArray(new Predicate[]{}));
1✔
2178

2179
                        TypedQuery<Drug> query = session.createQuery(cq);
1✔
2180
                        List<Drug> drugs = query.getResultList();
1✔
2181
                        if (drugs.size() > 1) {
1✔
2182
                                throw new DAOException("There are multiple matches for the highest-priority ConceptMapType");
×
2183
                        } else if (drugs.size() == 1) {
1✔
2184
                                return drugs.get(0);
1✔
2185
                        }
2186
                }
2187
                return null;
1✔
2188
        }
2189

2190

2191
        /**
2192
         * @see ConceptDAO#getAllConceptAttributeTypes()
2193
         */
2194
        @Override
2195
        public List<ConceptAttributeType> getAllConceptAttributeTypes() {
2196
                Session session = sessionFactory.getCurrentSession();
1✔
2197
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
2198
                CriteriaQuery<ConceptAttributeType> cq = cb.createQuery(ConceptAttributeType.class);
1✔
2199
                cq.from(ConceptAttributeType.class);
1✔
2200

2201
                return session.createQuery(cq).getResultList();
1✔
2202
        }
2203

2204
        /**
2205
         * @see ConceptDAO#saveConceptAttributeType(ConceptAttributeType)
2206
         */
2207
        @Override
2208
        public ConceptAttributeType saveConceptAttributeType(ConceptAttributeType conceptAttributeType) {
2209
                sessionFactory.getCurrentSession().saveOrUpdate(conceptAttributeType);
1✔
2210
                return conceptAttributeType;
1✔
2211
        }
2212

2213
        /**
2214
         * @see ConceptDAO#getConceptAttributeType(Integer)
2215
         */
2216
        @Override
2217
        public ConceptAttributeType getConceptAttributeType(Integer id) {
2218
                return sessionFactory.getCurrentSession().get(ConceptAttributeType.class, id);
1✔
2219
        }
2220

2221
        /**
2222
         * @see ConceptDAO#getConceptAttributeTypeByUuid(String)
2223
         */
2224
        @Override
2225
        public ConceptAttributeType getConceptAttributeTypeByUuid(String uuid) {
2226
                return HibernateUtil.getUniqueEntityByUUID(sessionFactory, ConceptAttributeType.class, uuid);
1✔
2227
        }
2228

2229
        /**
2230
         * @see org.openmrs.api.db.ConceptDAO#deleteConceptAttributeType(org.openmrs.ConceptAttributeType)
2231
         */
2232
        @Override
2233
        public void deleteConceptAttributeType(ConceptAttributeType conceptAttributeType) {
2234
                sessionFactory.getCurrentSession().delete(conceptAttributeType);
1✔
2235
        }
1✔
2236

2237
        /**
2238
         * @see org.openmrs.api.db.ConceptDAO#getConceptAttributeTypes(String)
2239
         */
2240
        @Override
2241
        public List<ConceptAttributeType> getConceptAttributeTypes(String name) {
2242
                Session session = sessionFactory.getCurrentSession();
1✔
2243
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
2244
                CriteriaQuery<ConceptAttributeType> cq = cb.createQuery(ConceptAttributeType.class);
1✔
2245
                Root<ConceptAttributeType> root = cq.from(ConceptAttributeType.class);
1✔
2246

2247
                //match name anywhere and case insensitive
2248
                if (name != null) {
1✔
2249
                        cq.where(cb.like(cb.lower(root.get("name")), MatchMode.ANYWHERE.toLowerCasePattern(name)));
1✔
2250
                }
2251

2252
                return session.createQuery(cq).getResultList();
1✔
2253
        }
2254

2255
        /**
2256
         * @see org.openmrs.api.db.ConceptDAO#getConceptAttributeTypeByName(String)
2257
         */
2258
        @Override
2259
        public ConceptAttributeType getConceptAttributeTypeByName(String exactName) {
2260
                Session session = sessionFactory.getCurrentSession();
1✔
2261
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
2262
                CriteriaQuery<ConceptAttributeType> cq = cb.createQuery(ConceptAttributeType.class);
1✔
2263
                Root<ConceptAttributeType> root = cq.from(ConceptAttributeType.class);
1✔
2264

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

2267
                return session.createQuery(cq).uniqueResult();
1✔
2268
        }
2269

2270
        /**
2271
         * @see ConceptDAO#getConceptAttributeByUuid(String)
2272
         */
2273
        @Override
2274
        public ConceptAttribute getConceptAttributeByUuid(String uuid) {
2275
                return HibernateUtil.getUniqueEntityByUUID(sessionFactory, ConceptAttribute.class, uuid);
1✔
2276
        }
2277

2278
        /**
2279
         * @see ConceptDAO#getConceptAttributeCount(ConceptAttributeType)
2280
         */
2281
        @Override
2282
        public long getConceptAttributeCount(ConceptAttributeType conceptAttributeType) {
2283
                Session session = sessionFactory.getCurrentSession();
1✔
2284
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
2285
                CriteriaQuery<Long> cq = cb.createQuery(Long.class);
1✔
2286
                Root<ConceptAttribute> root = cq.from(ConceptAttribute.class);
1✔
2287

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

2290
                return session.createQuery(cq).getSingleResult();
1✔
2291
        }
2292

2293
        @Override
2294
        public List<Concept> getConceptsByClass(ConceptClass conceptClass) {
2295
                Session session = sessionFactory.getCurrentSession();
1✔
2296
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
2297
                CriteriaQuery<Concept> cq = cb.createQuery(Concept.class);
1✔
2298
                Root<Concept> root = cq.from(Concept.class);
1✔
2299

2300
                cq.where(cb.equal(root.get("conceptClass"), conceptClass));
1✔
2301

2302
                return session.createQuery(cq).getResultList();
1✔
2303
        }
2304

2305
        private List<Predicate> createSearchDrugByMappingPredicates(CriteriaBuilder cb, Root<Drug> drugRoot, Join<Drug, DrugReferenceMap> drugReferenceMapJoin,
2306
                                                                                                                                Join<DrugReferenceMap, ConceptReferenceTerm> termJoin,
2307
                                                                                                                                String code, ConceptSource conceptSource, boolean includeRetired) {
2308
                List<Predicate> predicates = new ArrayList<>();
1✔
2309
                
2310
                if (code != null) {
1✔
2311
                        predicates.add(cb.equal(termJoin.get("code"), code));
1✔
2312
                }
2313
                if (conceptSource != null) {
1✔
2314
                        predicates.add(cb.equal(termJoin.get("conceptSource"), conceptSource));
1✔
2315
                }
2316
                if (!includeRetired) {
1✔
2317
                        predicates.add(cb.isFalse(drugRoot.get("retired")));
1✔
2318
                }
2319

2320
                return predicates;
1✔
2321
        }
2322

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

2326
                Join<ConceptMap, ConceptReferenceTerm> termJoin = root.join("conceptReferenceTerm");
1✔
2327

2328
                // Match the source code to the passed code
2329
                if (Context.getAdministrationService().isDatabaseStringComparisonCaseSensitive()) {
1✔
2330
                        predicates.add(cb.equal(cb.lower(termJoin.get("code")), code.toLowerCase()));
1✔
2331
                } else {
2332
                        predicates.add(cb.equal(termJoin.get("code"), code));
×
2333
                }
2334

2335
                // Join to concept reference source and match to the hl7Code or source name
2336
                Join<ConceptReferenceTerm, ConceptSource> sourceJoin = termJoin.join("conceptSource");
1✔
2337
                
2338
                Predicate namePredicate = Context.getAdministrationService().isDatabaseStringComparisonCaseSensitive() ?
1✔
2339
                                cb.equal(cb.lower(sourceJoin.get("name")), sourceName.toLowerCase()) :
1✔
2340
                                        cb.equal(sourceJoin.get("name"), sourceName);
1✔
2341
                Predicate hl7CodePredicate = Context.getAdministrationService().isDatabaseStringComparisonCaseSensitive() ?
1✔
2342
                                cb.equal(cb.lower(sourceJoin.get("hl7Code")), sourceName.toLowerCase()) :
1✔
2343
                                        cb.equal(sourceJoin.get("hl7Code"), sourceName);
1✔
2344
                
2345
                predicates.add(cb.or(namePredicate, hl7CodePredicate));
1✔
2346

2347
                // Join to concept and filter retired ones if necessary
2348
                Join<ConceptMap, Concept> conceptJoin = root.join("concept");
1✔
2349
                if (!includeRetired) {
1✔
2350
                        predicates.add(cb.isFalse(conceptJoin.get("retired")));
1✔
2351
                }
2352
                return predicates;
1✔
2353
        }
2354

2355
        /**
2356
         * @see org.openmrs.api.db.ConceptDAO#saveConceptReferenceRange(ConceptReferenceRange)
2357
         */
2358
        @Override
2359
        public ConceptReferenceRange saveConceptReferenceRange(ConceptReferenceRange conceptReferenceRange) {
2360
                sessionFactory.getCurrentSession().saveOrUpdate(conceptReferenceRange);
1✔
2361
                return conceptReferenceRange;
1✔
2362
        }
2363

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

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

2376
                return session.createQuery(cq).getResultList();
1✔
2377
        }
2378

2379
        /**
2380
         * @see ConceptDAO#getConceptReferenceRangeByUuid(String)
2381
         */
2382
        @Override
2383
        public ConceptReferenceRange getConceptReferenceRangeByUuid(String uuid) {
2384
                Session session = sessionFactory.getCurrentSession();
1✔
2385
                CriteriaBuilder cb = session.getCriteriaBuilder();
1✔
2386
                CriteriaQuery<ConceptReferenceRange> cq = cb.createQuery(ConceptReferenceRange.class);
1✔
2387
                Root<ConceptReferenceRange> root = cq.from(ConceptReferenceRange.class);
1✔
2388

2389
                cq.where(cb.equal(root.get("uuid"), uuid));
1✔
2390

2391
                return session.createQuery(cq).uniqueResult();
1✔
2392
        }
2393
        
2394
        /**
2395
         * @see org.openmrs.api.db.ConceptDAO#purgeConceptReferenceRange(org.openmrs.ConceptReferenceRange)
2396
         */
2397
        @Override
2398
        public void purgeConceptReferenceRange(ConceptReferenceRange conceptReferenceRange) {
2399
                sessionFactory.getCurrentSession().delete(conceptReferenceRange);
1✔
2400
        }
1✔
2401
}
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