4545import javax .persistence .criteria .Selection ;
4646import javax .persistence .criteria .Subquery ;
4747
48- import de . symeda . sormas . api . environment . environmentsample . EnvironmentSampleMaterial ;
48+ import org . apache . commons . lang3 . StringUtils ;
4949import org .apache .commons .lang3 .tuple .Pair ;
5050import org .jetbrains .annotations .NotNull ;
5151
5252import de .symeda .sormas .api .dashboard .SampleDashboardCriteria ;
5353import de .symeda .sormas .api .dashboard .sample .MapSampleDto ;
5454import de .symeda .sormas .api .dashboard .sample .SampleShipmentStatus ;
5555import de .symeda .sormas .api .environment .environmentsample .EnvironmentSampleCriteria ;
56+ import de .symeda .sormas .api .environment .environmentsample .EnvironmentSampleMaterial ;
5657import de .symeda .sormas .api .sample .PathogenTestResultType ;
5758import de .symeda .sormas .api .sample .SampleAssociationType ;
5859import de .symeda .sormas .api .sample .SampleCriteria ;
@@ -150,15 +151,17 @@ public Map<SpecimenCondition, Long> getSampleCountsBySpecimenCondition(SampleDas
150151
151152 public Map <SpecimenCondition , Long > getEnvironmentalSampleCountsBySpecimenCondition (SampleDashboardCriteria dashboardCriteria ) {
152153 return getEnvironmentalSampleCountsBySpecimenCondition (
153- EnvironmentSample .SPECIMEN_CONDITION ,
154- SpecimenCondition .class ,
155- dashboardCriteria ,
156- null );
154+ EnvironmentSample .SPECIMEN_CONDITION ,
155+ SpecimenCondition .class ,
156+ dashboardCriteria ,
157+ null );
157158 }
158159
159- private Map <SpecimenCondition , Long > getEnvironmentalSampleCountsBySpecimenCondition (String property , Class <SpecimenCondition > propertyType ,
160- SampleDashboardCriteria dashboardCriteria ,
161- BiFunction <CriteriaBuilder , Root <EnvironmentSample >, Predicate > additionalFilters ) {
160+ private Map <SpecimenCondition , Long > getEnvironmentalSampleCountsBySpecimenCondition (
161+ String property ,
162+ Class <SpecimenCondition > propertyType ,
163+ SampleDashboardCriteria dashboardCriteria ,
164+ BiFunction <CriteriaBuilder , Root <EnvironmentSample >, Predicate > additionalFilters ) {
162165 final CriteriaBuilder cb = em .getCriteriaBuilder ();
163166 final CriteriaQuery <Tuple > cq = cb .createTupleQuery ();
164167 final Root <EnvironmentSample > sample = cq .from (EnvironmentSample .class );
@@ -173,9 +176,9 @@ private Map<SpecimenCondition, Long> getEnvironmentalSampleCountsBySpecimenCondi
173176 cq .groupBy (groupingProperty );
174177
175178 return QueryHelper .getResultList (em , cq , null , null , Function .identity ())
176- .stream ()
177- .filter (t -> t .get (0 ) != null )
178- .collect (Collectors .toMap (t -> propertyType .cast (t .get (0 )), t -> (Long ) t .get (1 )));
179+ .stream ()
180+ .filter (t -> t .get (0 ) != null )
181+ .collect (Collectors .toMap (t -> propertyType .cast (t .get (0 )), t -> (Long ) t .get (1 )));
179182 }
180183
181184 private <T extends Enum <?>> Map <T , Long > getSampleCountsByEnumProperty (
@@ -219,8 +222,8 @@ public Map<SampleShipmentStatus, Long> getSampleCountsByShipmentStatus(SampleDas
219222 cq .groupBy (shipped , received );
220223
221224 return QueryHelper .getResultList (em , cq , null , null , Function .identity ())
222- .stream ()
223- .collect (Collectors .toMap (t -> getSampleShipmentStatusByFlags ((Boolean ) t .get (0 ), (Boolean ) t .get (1 )), t -> (Long ) t .get (2 ), Long ::sum ));
225+ .stream ()
226+ .collect (Collectors .toMap (t -> getSampleShipmentStatusByFlags ((Boolean ) t .get (0 ), (Boolean ) t .get (1 )), t -> (Long ) t .get (2 ), Long ::sum ));
224227 }
225228
226229 public Map <SampleShipmentStatus , Long > getEnvironmentalSampleCountsByShipmentStatus (SampleDashboardCriteria dashboardCriteria ) {
@@ -238,8 +241,8 @@ public Map<SampleShipmentStatus, Long> getEnvironmentalSampleCountsByShipmentSta
238241 cq .groupBy (shipped , received );
239242
240243 return QueryHelper .getResultList (em , cq , null , null , Function .identity ())
241- .stream ()
242- .collect (Collectors .toMap (t -> getSampleShipmentStatusByFlags ((Boolean ) t .get (0 ), (Boolean ) t .get (1 )), t -> (Long ) t .get (2 ), Long ::sum ));
244+ .stream ()
245+ .collect (Collectors .toMap (t -> getSampleShipmentStatusByFlags ((Boolean ) t .get (0 ), (Boolean ) t .get (1 )), t -> (Long ) t .get (2 ), Long ::sum ));
243246 }
244247
245248 private SampleShipmentStatus getSampleShipmentStatusByFlags (Boolean shipped , Boolean received ) {
@@ -255,7 +258,10 @@ public Map<PathogenTestResultType, Long> getTestResultCountsByResultType(SampleD
255258
256259 cq .multiselect (pathogenTestResult , cb .count (pathogenTestJoin ));
257260
258- final Predicate criteriaFilter = createSampleFilter (new SampleQueryContext (cb , cq , sample ), dashboardCriteria );
261+ Predicate criteriaFilter = createSampleFilter (new SampleQueryContext (cb , cq , sample ), dashboardCriteria );
262+ if (dashboardCriteria .getPathogenTestResult () != null ) {
263+ criteriaFilter = CriteriaBuilderHelper .and (cb , criteriaFilter , cb .equal (pathogenTestResult , dashboardCriteria .getPathogenTestResult ()));
264+ }
259265 cq .where (criteriaFilter );
260266
261267 cq .groupBy (pathogenTestResult );
@@ -286,9 +292,9 @@ public Map<PathogenTestResultType, Long> getEnvironmentalTestResultCountsByResul
286292 cq .groupBy (pathogenTestResult );
287293
288294 return QueryHelper .getResultList (em , cq , null , null , Function .identity ())
289- .stream ()
290- .filter (t -> t .get (0 ) != null )
291- .collect (Collectors .toMap (t -> (PathogenTestResultType ) t .get (0 ), t -> (Long ) t .get (1 )));
295+ .stream ()
296+ .filter (t -> t .get (0 ) != null )
297+ .collect (Collectors .toMap (t -> (PathogenTestResultType ) t .get (0 ), t -> (Long ) t .get (1 )));
292298 }
293299
294300 /**
@@ -304,13 +310,14 @@ public Map<EnvironmentSampleMaterial, Long> getEnvironmentalSampleCounts(SampleD
304310 final Root <EnvironmentSample > sample = cq .from (EnvironmentSample .class );
305311 final Path <Object > groupingProperty = sample .get (EnvironmentSample .SAMPLE_MATERIAL );
306312 cq .multiselect (groupingProperty , cb .count (sample ));
307- final Predicate criteriaFilter = createEnvironmentSampleFilter (new EnvironmentSampleQueryContext (cb , cq , sample , new EnvironmentSampleJoins (sample )), dashboardCriteria );
313+ final Predicate criteriaFilter =
314+ createEnvironmentSampleFilter (new EnvironmentSampleQueryContext (cb , cq , sample , new EnvironmentSampleJoins (sample )), dashboardCriteria );
308315 cq .where (criteriaFilter );
309316 cq .groupBy (groupingProperty );
310317 return QueryHelper .getResultList (em , cq , null , null , Function .identity ())
311- .stream ()
312- .filter (t -> t .get (0 ) != null )
313- .collect (Collectors .toMap (t -> (EnvironmentSampleMaterial ) t .get (0 ), t -> (Long ) t .get (1 )));
318+ .stream ()
319+ .filter (t -> t .get (0 ) != null )
320+ .collect (Collectors .toMap (t -> (EnvironmentSampleMaterial ) t .get (0 ), t -> (Long ) t .get (1 )));
314321 }
315322
316323 private static <J extends ISampleJoins > List <Selection <?>> getCoordinatesSelection (
@@ -510,6 +517,32 @@ private <T extends AbstractDomainObject> Predicate createSampleFilter(SampleQuer
510517 filter = CriteriaBuilderHelper .and (cb , filter , cb .equal (sampleRoot .get (Sample .SAMPLE_MATERIAL ), criteria .getSampleMaterial ()));
511518 }
512519
520+ // Test result is denormalized on the sample (final lab result) → direct equality, no join.
521+ if (criteria .getPathogenTestResult () != null ) {
522+ filter = CriteriaBuilderHelper .and (cb , filter , cb .equal (sampleRoot .get (Sample .PATHOGEN_TEST_RESULT ), criteria .getPathogenTestResult ()));
523+ }
524+
525+ if (StringUtils .isNotBlank (criteria .getSerogroup ())) {
526+ Subquery <Long > serogroupSubquery = cq .subquery (Long .class );
527+ Root <PathogenTest > pathogenTestRoot = serogroupSubquery .from (PathogenTest .class );
528+ serogroupSubquery .select (pathogenTestRoot .get (PathogenTest .ID ));
529+ serogroupSubquery .where (
530+ cb .equal (pathogenTestRoot .get (PathogenTest .SAMPLE ), sampleRoot ),
531+ CriteriaBuilderHelper .unaccentedIlike (cb , pathogenTestRoot .get (PathogenTest .SEROTYPE_TEXT ), criteria .getSerogroup ().trim ()),
532+ cb .isFalse (pathogenTestRoot .get (PathogenTest .DELETED )));
533+ filter = CriteriaBuilderHelper .and (cb , filter , cb .exists (serogroupSubquery ));
534+ }
535+ if (criteria .getDiseaseVariant () != null ) {
536+ Subquery <Long > variantSubquery = cq .subquery (Long .class );
537+ Root <PathogenTest > pathogenTestRoot = variantSubquery .from (PathogenTest .class );
538+ variantSubquery .select (pathogenTestRoot .get (PathogenTest .ID ));
539+ variantSubquery .where (
540+ cb .equal (pathogenTestRoot .get (PathogenTest .SAMPLE ), sampleRoot ),
541+ cb .equal (pathogenTestRoot .get (PathogenTest .TESTED_DISEASE_VARIANT_VALUE ), criteria .getDiseaseVariant ().getValue ()),
542+ cb .isFalse (pathogenTestRoot .get (PathogenTest .DELETED )));
543+ filter = CriteriaBuilderHelper .and (cb , filter , cb .exists (variantSubquery ));
544+ }
545+
513546 if (Boolean .TRUE .equals (criteria .getWithNoDisease ())) {
514547 filter = CriteriaBuilderHelper .and (cb , filter , cb .isNotNull (joins .getEventParticipant ()), cb .isNull (joins .getEvent ().get (Event .DISEASE )));
515548 } else if (Boolean .FALSE .equals (criteria .getWithNoDisease ())) {
@@ -573,7 +606,8 @@ private Predicate createEnvironmentSampleFilter(EnvironmentSampleQueryContext qu
573606 }
574607
575608 if (criteria .getEnvironmentSampleMaterial () != null ) {
576- filter = CriteriaBuilderHelper .and (cb , filter , cb .equal (sampleRoot .get (EnvironmentSample .SAMPLE_MATERIAL ), criteria .getEnvironmentSampleMaterial ()));
609+ filter = CriteriaBuilderHelper
610+ .and (cb , filter , cb .equal (sampleRoot .get (EnvironmentSample .SAMPLE_MATERIAL ), criteria .getEnvironmentSampleMaterial ()));
577611 }
578612
579613 return CriteriaBuilderHelper .and (
0 commit comments