Skip to content

Commit 08cf4dc

Browse files
Fix Search helpers to use Multimap (#969)
* Change searches to use Multimap instead of deprecated Map * Add test of library with multiple versions * Fix minor sonar issues. --------- Co-authored-by: Luke deGruchy <luke.degruchy@smiledigitalhealth.com>
1 parent 6eb220f commit 08cf4dc

19 files changed

Lines changed: 246 additions & 99 deletions

File tree

cqf-fhir-cql/src/main/java/org/opencds/cqf/fhir/cql/engine/terminology/RepositoryTerminologyProvider.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
* search, but found that the performance was reduced by ~33%. Please run the benchmarks to verify
3535
* that changes to this class do not result in significant performance degradation.
3636
*/
37+
@SuppressWarnings("UnstableApiUsage")
3738
public class RepositoryTerminologyProvider implements TerminologyProvider {
3839

3940
private static final Logger logger = LoggerFactory.getLogger(RepositoryTerminologyProvider.class);

cqf-fhir-cql/src/test/java/org/opencds/cqf/fhir/cql/engine/terminology/RepositoryTerminologyProviderTest.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,15 @@
99

1010
import ca.uhn.fhir.context.FhirContext;
1111
import ca.uhn.fhir.repository.IRepository;
12-
import java.util.Map;
12+
import com.google.common.collect.Multimap;
1313
import org.hl7.fhir.r4.model.Bundle;
1414
import org.hl7.fhir.r4.model.ValueSet;
1515
import org.junit.jupiter.api.Test;
1616
import org.opencds.cqf.cql.engine.runtime.Code;
1717
import org.opencds.cqf.cql.engine.terminology.TerminologyProvider;
1818
import org.opencds.cqf.cql.engine.terminology.ValueSetInfo;
1919

20+
@SuppressWarnings("UnstableApiUsage")
2021
class RepositoryTerminologyProviderTest {
2122

2223
private static final String SYSTEM_FOR_CODES = "http://example.com/CodeSystem/Codes";
@@ -77,7 +78,7 @@ IRepository mockRepositoryWithValueSet(ValueSet valueSet) {
7778
when(mockRepository.fhirContext()).thenReturn(FhirContext.forR4Cached());
7879
Bundle bundle = new Bundle();
7980
bundle.addEntry().setFullUrl(valueSet.getUrl()).setResource(valueSet);
80-
when(mockRepository.search(any(), any(), any(Map.class), isNull())).thenReturn(bundle);
81+
when(mockRepository.search(any(), any(), any(Multimap.class), isNull())).thenReturn(bundle);
8182
return mockRepository;
8283
}
8384

cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/common/ResourceResolver.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import static org.opencds.cqf.fhir.utility.Resources.castOrThrow;
55

66
import ca.uhn.fhir.repository.IRepository;
7+
import ca.uhn.fhir.util.bundle.BundleEntryParts;
78
import java.util.function.Function;
89
import org.hl7.fhir.exceptions.FHIRException;
910
import org.hl7.fhir.instance.model.api.IBaseBundle;
@@ -15,6 +16,7 @@
1516
import org.opencds.cqf.fhir.utility.monad.Either3;
1617
import org.opencds.cqf.fhir.utility.search.Searches;
1718

19+
@SuppressWarnings("UnstableApiUsage")
1820
public class ResourceResolver {
1921
final String invalidResourceType = "The resource passed in was not a valid instance of %s.class";
2022
final String resourceType;
@@ -50,7 +52,7 @@ public ResourceResolver(String resourceType, IRepository repository) {
5052

5153
protected <C extends IPrimitiveType<String>> IBaseResource resolveByUrl(C url) {
5254
var result = this.repository.search(bundleClazz, clazz, Searches.byCanonical(url.getValue()));
53-
var iterator = new BundleMappingIterable<>(repository, result, p -> p.getResource()).iterator();
55+
var iterator = new BundleMappingIterable<>(repository, result, BundleEntryParts::getResource).iterator();
5456
return iterator.hasNext() ? iterator.next() : null;
5557
}
5658

cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/graphdefinition/apply/ApplyProcessor.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import ca.uhn.fhir.rest.param.ReferenceParam;
1010
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
1111
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
12+
import com.google.common.collect.Multimap;
1213
import java.util.Collections;
1314
import java.util.Date;
1415
import java.util.HashMap;
@@ -143,7 +144,7 @@ protected SectionComponent transformTargetToSection(
143144
return sectionComponent;
144145
}
145146

146-
protected Map<String, List<IQueryParameterType>> getSearchParams(
147+
protected Multimap<String, List<IQueryParameterType>> getSearchParams(
147148
ApplyRequest request, String type, String profile) {
148149
var searchParams = Searches.byProfile(profile);
149150
searchParams.put(

cqf-fhir-cr/src/test/java/org/opencds/cqf/fhir/cr/common/InputParametersTest.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
import com.google.common.collect.Multimap;
1414
import java.util.Arrays;
1515
import java.util.List;
16-
import java.util.Map;
1716
import org.hl7.fhir.instance.model.api.IBaseExtension;
1817
import org.hl7.fhir.r4.model.Bundle;
1918
import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent;
@@ -570,7 +569,7 @@ void testResolveInputParametersWithDataRequirements() {
570569
var obsBundle = new Bundle().addEntry(new BundleEntryComponent().setResource(obs));
571570
doReturn(fhirContextR4).when(repository).fhirContext();
572571
doReturn(patient).when(repository).read(org.hl7.fhir.r4.model.Patient.class, patient.getIdElement());
573-
doReturn(valueSetBundle).when(repository).search(eq(Bundle.class), eq(ValueSet.class), any(Map.class));
572+
doReturn(valueSetBundle).when(repository).search(eq(Bundle.class), eq(ValueSet.class), any(Multimap.class));
574573
doReturn(obsBundle)
575574
.when(repository)
576575
.search(eq(Bundle.class), eq(Observation.class), any(Multimap.class), any());

cqf-fhir-cr/src/test/java/org/opencds/cqf/fhir/cr/library/LibraryProcessorTests.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import java.nio.file.Path;
1313
import java.util.List;
1414
import org.hl7.fhir.r4.model.Library;
15+
import org.hl7.fhir.r4.model.StringType;
1516
import org.junit.jupiter.api.Test;
1617
import org.junit.jupiter.api.extension.ExtendWith;
1718
import org.mockito.Mock;
@@ -201,4 +202,31 @@ void testPrefetchData() {
201202
.thenEvaluate()
202203
.hasResults(6);
203204
}
205+
206+
@Test
207+
void testEvaluateMultipleLibraryVersions() {
208+
var libraryUrl = "http://fhir.org/guides/cdc/opioid-cds/Library/HelloWorld";
209+
var version1 = "1.0.0";
210+
var version2 = "2.0.0";
211+
var repository =
212+
new IgRepository(fhirContextR4, Path.of(getResourcePath(this.getClass()) + "/" + CLASS_PATH + "/r4"));
213+
var evaluationSettings = EvaluationSettings.getDefault();
214+
given().repository(repository)
215+
.evaluationSettings(evaluationSettings)
216+
.when()
217+
.libraryUrl(String.format("%s|%s", libraryUrl, version1))
218+
.subjectId("Patient1")
219+
.thenEvaluate()
220+
.hasResults(8)
221+
.resultHasValue(3, new StringType("Hello World!"));
222+
223+
given().repository(repository)
224+
.evaluationSettings(evaluationSettings)
225+
.when()
226+
.libraryUrl(String.format("%s|%s", libraryUrl, version2))
227+
.subjectId("Patient1")
228+
.thenEvaluate()
229+
.hasResults(8)
230+
.resultHasValue(3, new StringType("Hello World! I am a new version!"));
231+
}
204232
}

cqf-fhir-cr/src/test/java/org/opencds/cqf/fhir/cr/library/TestLibrary.java

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.opencds.cqf.fhir.cr.library;
22

33
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
45
import static org.junit.jupiter.api.Assertions.assertTrue;
56
import static org.opencds.cqf.fhir.test.Resources.getResourcePath;
67
import static org.opencds.cqf.fhir.utility.BundleHelper.addEntry;
@@ -28,6 +29,7 @@
2829
import org.hl7.fhir.instance.model.api.IBaseParameters;
2930
import org.hl7.fhir.instance.model.api.IBaseResource;
3031
import org.hl7.fhir.instance.model.api.IIdType;
32+
import org.hl7.fhir.instance.model.api.IPrimitiveType;
3133
import org.opencds.cqf.cql.engine.model.ModelResolver;
3234
import org.opencds.cqf.fhir.cql.EvaluationSettings;
3335
import org.opencds.cqf.fhir.cql.engine.retrieve.RetrieveSettings.SEARCH_FILTER_MODE;
@@ -38,6 +40,7 @@
3840
import org.opencds.cqf.fhir.cr.helpers.DataRequirementsLibrary;
3941
import org.opencds.cqf.fhir.cr.helpers.GeneratedPackage;
4042
import org.opencds.cqf.fhir.utility.Ids;
43+
import org.opencds.cqf.fhir.utility.adapter.IAdapterFactory;
4144
import org.opencds.cqf.fhir.utility.model.FhirModelResolverCache;
4245
import org.opencds.cqf.fhir.utility.monad.Eithers;
4346
import org.opencds.cqf.fhir.utility.repository.InMemoryFhirRepository;
@@ -288,7 +291,8 @@ public static class Evaluation {
288291
final IBaseParameters result;
289292
final IParser jsonParser;
290293
final ModelResolver modelResolver;
291-
final List<IBaseResource> parameter;
294+
final List<IBase> parameter;
295+
final IAdapterFactory adapterFactory;
292296

293297
@SuppressWarnings("unchecked")
294298
public Evaluation(IRepository repository, IBaseParameters result) {
@@ -297,7 +301,8 @@ public Evaluation(IRepository repository, IBaseParameters result) {
297301
jsonParser = this.repository.fhirContext().newJsonParser().setPrettyPrint(true);
298302
modelResolver = FhirModelResolverCache.resolverForVersion(
299303
this.repository.fhirContext().getVersion().getVersion());
300-
parameter = ((List<IBaseResource>) modelResolver.resolvePath(result, "parameter"));
304+
adapterFactory = IAdapterFactory.forFhirContext(this.repository.fhirContext());
305+
parameter = ((List<IBase>) modelResolver.resolvePath(result, "parameter"));
301306
}
302307

303308
public Evaluation hasResults(Integer count) {
@@ -310,9 +315,16 @@ public Evaluation hasOperationOutcome() {
310315
return this;
311316
}
312317

318+
@SuppressWarnings("unchecked")
313319
public Evaluation resultHasValue(Integer index, IBase value) {
314-
var actual = parameter.get(index);
315-
assertEquals(value, actual);
320+
var actual = adapterFactory
321+
.createParametersParameter(parameter.get(index))
322+
.getValue();
323+
if (value instanceof IPrimitiveType<?> primitiveValue) {
324+
assertEquals(primitiveValue.getValueAsString(), ((IPrimitiveType<String>) actual).getValueAsString());
325+
} else {
326+
assertInstanceOf(value.getClass(), actual);
327+
}
316328
return this;
317329
}
318330
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
library HelloWorld version '2.0.0'
2+
3+
using FHIR version '4.0.1'
4+
5+
include FHIRHelpers version '4.0.1'
6+
7+
8+
context Patient
9+
10+
define "Info":
11+
'info'
12+
13+
define "Warning":
14+
'warning'
15+
16+
define "Critical":
17+
'critical'
18+
19+
define "Main Action Condition Expression Is True":
20+
true
21+
22+
define "Get Title":
23+
'Hello World! I am a new version!'
24+
25+
define "Get Description":
26+
'The CDS Service is alive and communicating successfully!'
27+
28+
define "Get Indicator":
29+
'info'

cqf-fhir-cr/src/test/resources/org/opencds/cqf/fhir/cr/shared/r4/input/resources/Library-BadLibrary.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
],
1212
"url": "http://fhir.org/guides/cdc/opioid-cds/Library/BadLibrary",
1313
"version": "1.0.0",
14-
"name": "HelloWorld",
14+
"name": "NotACorrectLibraryName",
1515
"relatedArtifact": [
1616
{
1717
"type": "depends-on",
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
{
2+
"resourceType": "Library",
3+
"id": "HelloWorld2",
4+
"extension": [
5+
{
6+
"url": "http://hl7.org/fhir/us/cqfmeasures/StructureDefinition/cqfm-softwaresystem",
7+
"valueReference": {
8+
"reference": "Device/cqf-tooling"
9+
}
10+
}
11+
],
12+
"url": "http://fhir.org/guides/cdc/opioid-cds/Library/HelloWorld",
13+
"version": "2.0.0",
14+
"name": "HelloWorld",
15+
"relatedArtifact": [
16+
{
17+
"type": "depends-on",
18+
"display": "FHIR model information",
19+
"resource": "http://fhir.org/guides/cqf/common/Library/FHIR-ModelInfo|4.0.1"
20+
}
21+
],
22+
"parameter": [
23+
{
24+
"name": "Patient",
25+
"use": "out",
26+
"min": 0,
27+
"max": "1",
28+
"type": "Patient"
29+
},
30+
{
31+
"name": "Info",
32+
"use": "out",
33+
"min": 0,
34+
"max": "1",
35+
"type": "string"
36+
},
37+
{
38+
"name": "Warning",
39+
"use": "out",
40+
"min": 0,
41+
"max": "1",
42+
"type": "string"
43+
},
44+
{
45+
"name": "Critical",
46+
"use": "out",
47+
"min": 0,
48+
"max": "1",
49+
"type": "string"
50+
},
51+
{
52+
"name": "Main Action Condition Expression Is True",
53+
"use": "out",
54+
"min": 0,
55+
"max": "1",
56+
"type": "boolean"
57+
},
58+
{
59+
"name": "Get Title",
60+
"use": "out",
61+
"min": 0,
62+
"max": "1",
63+
"type": "string"
64+
},
65+
{
66+
"name": "Get Description",
67+
"use": "out",
68+
"min": 0,
69+
"max": "1",
70+
"type": "string"
71+
},
72+
{
73+
"name": "Get Indicator",
74+
"use": "out",
75+
"min": 0,
76+
"max": "1",
77+
"type": "string"
78+
}
79+
],
80+
"dataRequirement": [
81+
{
82+
"type": "Patient",
83+
"profile": [
84+
"http://hl7.org/fhir/StructureDefinition/Patient"
85+
]
86+
}
87+
],
88+
"content": [
89+
{
90+
"contentType": "text/cql",
91+
"url": "../cql/HelloWorld2.cql"
92+
}
93+
]
94+
}

0 commit comments

Comments
 (0)