Skip to content

Commit f6a15c9

Browse files
authored
When a Code without system is passed in to in, check only the code value and throw if the resolved value set contains codes from multiple code systems (#1026)
For `Code`s without system passed in to `in`, check only the code value and throw if the resolved value set contains codes from multiple code systems
1 parent d340296 commit f6a15c9

3 files changed

Lines changed: 45 additions & 3 deletions

File tree

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,12 +97,22 @@ public boolean in(Code code, ValueSetInfo valueSet) {
9797

9898
List<Code> codes = this.expand(valueSet);
9999

100+
if (code.getSystem() == null) {
101+
// If the system is not provided and the resolved value set contains codes from multiple code systems, a
102+
// run-time error is thrown because the operation is ambiguous
103+
var distinctSystems = codes.stream().map(Code::getSystem).distinct().count();
104+
if (distinctSystems > 1) {
105+
throw new IllegalArgumentException(
106+
"The 'in' operation is ambiguous because the the code system is not provided and the resolved value set contains codes from multiple code systems");
107+
}
108+
}
109+
100110
// This range includes all codes that have an equivalent code value,
101111
// So we only need to check the code system.
102112
Range range = this.getSearchRange(code, codes);
103113
for (int i = range.start; i < range.end; i++) {
104114
var c = codes.get(i);
105-
if (c.getSystem().equals(code.getSystem())) {
115+
if (code.getSystem() == null || c.getSystem().equals(code.getSystem())) {
106116
return true;
107117
}
108118
}

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

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.opencds.cqf.fhir.cql.engine.terminology;
22

33
import static org.junit.jupiter.api.Assertions.assertFalse;
4+
import static org.junit.jupiter.api.Assertions.assertThrows;
45
import static org.junit.jupiter.api.Assertions.assertTrue;
56
import static org.mockito.ArgumentMatchers.any;
67
import static org.mockito.ArgumentMatchers.isNull;
@@ -24,6 +25,7 @@ class RepositoryTerminologyProviderTest {
2425
private static final String VALID_VALUE_SET_URL = "http://example.com/ValueSet/ValidValueSet";
2526
private static final String MISSING_SYSTEM_VALUE_SET_URL = "http://example.com/ValueSet/MissingSystemValueSet";
2627
private static final String MISSING_CODE_VALUE_SET_URL = "http://example.com/ValueSet/MissingCodeValueSet";
28+
private static final String MULTIPLE_SYSTEMS_VALUE_SET_URL = "http://example.com/ValueSet/MultipleSystemsValueSet";
2729

2830
@Test
2931
void validCodesInValueSet() {
@@ -37,6 +39,15 @@ void validCodesInValueSet() {
3739
assertFalse(terminologyProvider.in(codeDoesNotExistInValueSet, vsInfo));
3840
}
3941

42+
@Test
43+
void failOnCodeWithoutSystemAndMultiSystemValueSet() {
44+
var terminologyProvider = terminologyProviderWith("MultipleSystemsValueSet");
45+
var vsInfo = new ValueSetInfo().withId(MULTIPLE_SYSTEMS_VALUE_SET_URL);
46+
47+
var code = new Code().withCode("123");
48+
assertThrows(IllegalArgumentException.class, () -> terminologyProvider.in(code, vsInfo));
49+
}
50+
4051
@Test
4152
void missingCodeValueSetMatches() {
4253
var terminologyProvider = terminologyProviderWith("MissingCodeValueSet");
@@ -49,7 +60,7 @@ void missingCodeValueSetMatches() {
4960
assertFalse(terminologyProvider.in(codeMissingCode, vsInfo));
5061

5162
var codeMissingSystem = new Code().withCode("123");
52-
assertFalse(terminologyProvider.in(codeMissingSystem, vsInfo));
63+
assertTrue(terminologyProvider.in(codeMissingSystem, vsInfo));
5364
}
5465

5566
@Test
@@ -64,7 +75,7 @@ void missingSystemValueSetMatches() {
6475
assertFalse(terminologyProvider.in(codeMissingCode, vsInfo));
6576

6677
var codeMissingSystem = new Code().withCode("123");
67-
assertFalse(terminologyProvider.in(codeMissingSystem, vsInfo));
78+
assertTrue(terminologyProvider.in(codeMissingSystem, vsInfo));
6879
}
6980

7081
IRepository mockRepositoryFor(String id) {
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"resourceType": "ValueSet",
3+
"id": "MultipleSystemsValueSet",
4+
"url": "http://example.com/ValueSet/MultipleSystemsValueSet",
5+
"expansion": {
6+
"contains": [
7+
{
8+
"system": "http://example.com/CodeSystem/Codes1",
9+
"code": "123"
10+
},
11+
{
12+
"system": "http://example.com/CodeSystem/Codes2",
13+
"code": "456"
14+
},
15+
{
16+
"system": "http://example.com/CodeSystem/Codes3",
17+
"code": "789"
18+
}
19+
]
20+
}
21+
}

0 commit comments

Comments
 (0)