diff --git a/src/main/java/de/numcodex/sq2cql/model/structured_query/ReferenceModifier.java b/src/main/java/de/numcodex/sq2cql/model/structured_query/ReferenceModifier.java index 4a1abb3..9b9d727 100644 --- a/src/main/java/de/numcodex/sq2cql/model/structured_query/ReferenceModifier.java +++ b/src/main/java/de/numcodex/sq2cql/model/structured_query/ReferenceModifier.java @@ -29,7 +29,7 @@ public Container updateQuery(MappingContext mappingContext, Con var referenceExpr = InvocationExpression.of(query.sourceAlias(), path); var alias = StandardIdentifierExpression.of(targetType.substring(0, 1)); var ref = AdditionExpressionTerm.of(StringLiteralExpression.of(targetType + "/"), InvocationExpression.of(alias, "id")); - var comparatorExpr = ComparatorExpression.equal(referenceExpr, ref); + var comparatorExpr = MembershipExpression.contains(referenceExpr, ref); return query.appendQueryInclusionClause(WithClause.of(AliasedQuerySource.of(referencesExprName, alias), comparatorExpr)); })); } diff --git a/src/test/java/de/numcodex/sq2cql/AcceptanceTest.java b/src/test/java/de/numcodex/sq2cql/AcceptanceTest.java index fe1a38e..98e143d 100644 --- a/src/test/java/de/numcodex/sq2cql/AcceptanceTest.java +++ b/src/test/java/de/numcodex/sq2cql/AcceptanceTest.java @@ -13,6 +13,7 @@ import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.TestInstance.Lifecycle; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.ValueSource; import org.slf4j.Logger; @@ -49,7 +50,7 @@ public class AcceptanceTest { private static final Logger logger = LoggerFactory.getLogger(AcceptanceTest.class); private final GenericContainer blaze = new GenericContainer<>( - DockerImageName.parse("samply/blaze:0.27")) + DockerImageName.parse("samply/blaze:0.28")) .withImagePullPolicy(PullPolicy.alwaysPull()) .withEnv("LOG_LEVEL", "debug") .withExposedPorts(8080) @@ -158,7 +159,8 @@ public void consent() throws Exception { } @ParameterizedTest - @ValueSource(strings = {"large-query-worst-case-with-time-constraints.json", "test-large-query-more-crit-time-rest-1.json"}) + @ValueSource(strings = {"large-query-worst-case-with-time-constraints.json", + "test-large-query-more-crit-time-rest-1.json"}) public void largeQuery(String filename) throws Exception { var structuredQuery = new ObjectMapper().readValue(slurp(filename), StructuredQuery.class); var cql = translator.toCql(structuredQuery).print(); @@ -168,6 +170,23 @@ public void largeQuery(String filename) throws Exception { assertEquals(0, report.getGroupFirstRep().getPopulationFirstRep().getCount()); } + @ParameterizedTest + @CsvSource({ + "SpecimenSQ.json, 0", + "SpecimenSQExclusion.json, 159", + "SpecimenSQTwoInclusion.json, 0", + "SpecimenSQTwoReferenceCriteria.json, 0", + "SpecimenSQAndBodySite.json, 0" + }) + public void specimenQuery(String filename, int count) throws Exception { + var structuredQuery = new ObjectMapper().readValue(slurp(filename), StructuredQuery.class); + var cql = translator.toCql(structuredQuery).print(); + var measureUri = createMeasureAndLibrary(cql); + var report = evaluateMeasure(measureUri); + + assertEquals(count, report.getGroupFirstRep().getPopulationFirstRep().getCount()); + } + private String createMeasureAndLibrary(String cql) throws Exception { var libraryUri = "urn:uuid" + UUID.randomUUID(); var library = appendCql(parseResource(Library.class, slurp("Library.json")).setUrl(libraryUri), cql); diff --git a/src/test/java/de/numcodex/sq2cql/EvaluationIT.java b/src/test/java/de/numcodex/sq2cql/EvaluationIT.java index 46eede3..a607782 100644 --- a/src/test/java/de/numcodex/sq2cql/EvaluationIT.java +++ b/src/test/java/de/numcodex/sq2cql/EvaluationIT.java @@ -50,7 +50,7 @@ public class EvaluationIT { static final Map CODE_SYSTEM_ALIASES = Map.of("http://loinc.org", "loinc"); @Container - private final GenericContainer blaze = new GenericContainer<>(DockerImageName.parse("samply/blaze:0.27")) + private final GenericContainer blaze = new GenericContainer<>(DockerImageName.parse("samply/blaze:0.28")) .withImagePullPolicy(PullPolicy.alwaysPull()) .withExposedPorts(8080) .waitingFor(Wait.forHttp("/health").forStatusCode(200)) diff --git a/src/test/java/de/numcodex/sq2cql/SpecimenTest.java b/src/test/java/de/numcodex/sq2cql/SpecimenTest.java index f5456fe..11eaab2 100644 --- a/src/test/java/de/numcodex/sq2cql/SpecimenTest.java +++ b/src/test/java/de/numcodex/sq2cql/SpecimenTest.java @@ -52,25 +52,25 @@ public void translate() throws Exception { define Criterion: exists (from [Specimen: Code '119364003' from snomed] S with "Diagnose E13.9" C - such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference = 'Condition/' + C.id) or + such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference contains 'Condition/' + C.id) or exists (from [Specimen: Code '258590006' from snomed] S with "Diagnose E13.9" C - such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference = 'Condition/' + C.id) or + such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference contains 'Condition/' + C.id) or exists (from [Specimen: Code '866034009' from snomed] S with "Diagnose E13.9" C - such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference = 'Condition/' + C.id) or + such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference contains 'Condition/' + C.id) or exists (from [Specimen: Code '2421000181104' from snomed] S with "Diagnose E13.9" C - such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference = 'Condition/' + C.id) or + such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference contains 'Condition/' + C.id) or exists (from [Specimen: Code '866035005' from snomed] S with "Diagnose E13.9" C - such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference = 'Condition/' + C.id) or + such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference contains 'Condition/' + C.id) or exists (from [Specimen: Code '442427000' from snomed] S with "Diagnose E13.9" C - such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference = 'Condition/' + C.id) or + such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference contains 'Condition/' + C.id) or exists (from [Specimen: Code '737089009' from snomed] S with "Diagnose E13.9" C - such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference = 'Condition/' + C.id) + such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference contains 'Condition/' + C.id) define InInitialPopulation: Criterion @@ -108,25 +108,25 @@ public void translateExclusion() throws Exception { define "Criterion 2": exists (from [Specimen: Code '119364003' from snomed] S with "Diagnose E13.9" C - such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference = 'Condition/' + C.id) or + such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference contains 'Condition/' + C.id) or exists (from [Specimen: Code '258590006' from snomed] S with "Diagnose E13.9" C - such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference = 'Condition/' + C.id) or + such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference contains 'Condition/' + C.id) or exists (from [Specimen: Code '866034009' from snomed] S with "Diagnose E13.9" C - such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference = 'Condition/' + C.id) or + such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference contains 'Condition/' + C.id) or exists (from [Specimen: Code '2421000181104' from snomed] S with "Diagnose E13.9" C - such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference = 'Condition/' + C.id) or + such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference contains 'Condition/' + C.id) or exists (from [Specimen: Code '866035005' from snomed] S with "Diagnose E13.9" C - such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference = 'Condition/' + C.id) or + such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference contains 'Condition/' + C.id) or exists (from [Specimen: Code '442427000' from snomed] S with "Diagnose E13.9" C - such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference = 'Condition/' + C.id) or + such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference contains 'Condition/' + C.id) or exists (from [Specimen: Code '737089009' from snomed] S with "Diagnose E13.9" C - such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference = 'Condition/' + C.id) + such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference contains 'Condition/' + C.id) define Exclusion: "Criterion 2" @@ -165,25 +165,25 @@ public void translateTwoInclusion() throws Exception { define "Criterion 2": exists (from [Specimen: Code '119364003' from snomed] S with "Diagnose E13.9" C - such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference = 'Condition/' + C.id) or + such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference contains 'Condition/' + C.id) or exists (from [Specimen: Code '258590006' from snomed] S with "Diagnose E13.9" C - such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference = 'Condition/' + C.id) or + such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference contains 'Condition/' + C.id) or exists (from [Specimen: Code '866034009' from snomed] S with "Diagnose E13.9" C - such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference = 'Condition/' + C.id) or + such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference contains 'Condition/' + C.id) or exists (from [Specimen: Code '2421000181104' from snomed] S with "Diagnose E13.9" C - such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference = 'Condition/' + C.id) or + such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference contains 'Condition/' + C.id) or exists (from [Specimen: Code '866035005' from snomed] S with "Diagnose E13.9" C - such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference = 'Condition/' + C.id) or + such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference contains 'Condition/' + C.id) or exists (from [Specimen: Code '442427000' from snomed] S with "Diagnose E13.9" C - such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference = 'Condition/' + C.id) or + such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference contains 'Condition/' + C.id) or exists (from [Specimen: Code '737089009' from snomed] S with "Diagnose E13.9" C - such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference = 'Condition/' + C.id) + such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference contains 'Condition/' + C.id) define InInitialPopulation: "Criterion 1" and @@ -218,25 +218,25 @@ public void translateTwoReferenceCriteria() throws Exception { define Criterion: exists (from [Specimen: Code '119364003' from snomed] S with "Diagnose E13.9 and Diagnose E13.1" C - such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference = 'Condition/' + C.id) or + such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference contains 'Condition/' + C.id) or exists (from [Specimen: Code '258590006' from snomed] S with "Diagnose E13.9 and Diagnose E13.1" C - such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference = 'Condition/' + C.id) or + such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference contains 'Condition/' + C.id) or exists (from [Specimen: Code '866034009' from snomed] S with "Diagnose E13.9 and Diagnose E13.1" C - such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference = 'Condition/' + C.id) or + such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference contains 'Condition/' + C.id) or exists (from [Specimen: Code '2421000181104' from snomed] S with "Diagnose E13.9 and Diagnose E13.1" C - such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference = 'Condition/' + C.id) or + such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference contains 'Condition/' + C.id) or exists (from [Specimen: Code '866035005' from snomed] S with "Diagnose E13.9 and Diagnose E13.1" C - such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference = 'Condition/' + C.id) or + such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference contains 'Condition/' + C.id) or exists (from [Specimen: Code '442427000' from snomed] S with "Diagnose E13.9 and Diagnose E13.1" C - such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference = 'Condition/' + C.id) or + such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference contains 'Condition/' + C.id) or exists (from [Specimen: Code '737089009' from snomed] S with "Diagnose E13.9 and Diagnose E13.1" C - such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference = 'Condition/' + C.id) + such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference contains 'Condition/' + C.id) define InInitialPopulation: Criterion @@ -269,31 +269,31 @@ public void translateAndBodySite() throws Exception { define Criterion: exists (from [Specimen: Code '119364003' from snomed] S with "Diagnose E13.9" C - such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference = 'Condition/' + C.id + such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference contains 'Condition/' + C.id where S.collection.bodySite.coding contains Code 'C44.6' from icd_o_3) or exists (from [Specimen: Code '258590006' from snomed] S with "Diagnose E13.9" C - such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference = 'Condition/' + C.id + such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference contains 'Condition/' + C.id where S.collection.bodySite.coding contains Code 'C44.6' from icd_o_3) or exists (from [Specimen: Code '866034009' from snomed] S with "Diagnose E13.9" C - such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference = 'Condition/' + C.id + such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference contains 'Condition/' + C.id where S.collection.bodySite.coding contains Code 'C44.6' from icd_o_3) or exists (from [Specimen: Code '2421000181104' from snomed] S with "Diagnose E13.9" C - such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference = 'Condition/' + C.id + such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference contains 'Condition/' + C.id where S.collection.bodySite.coding contains Code 'C44.6' from icd_o_3) or exists (from [Specimen: Code '866035005' from snomed] S with "Diagnose E13.9" C - such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference = 'Condition/' + C.id + such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference contains 'Condition/' + C.id where S.collection.bodySite.coding contains Code 'C44.6' from icd_o_3) or exists (from [Specimen: Code '442427000' from snomed] S with "Diagnose E13.9" C - such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference = 'Condition/' + C.id + such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference contains 'Condition/' + C.id where S.collection.bodySite.coding contains Code 'C44.6' from icd_o_3) or exists (from [Specimen: Code '737089009' from snomed] S with "Diagnose E13.9" C - such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference = 'Condition/' + C.id + such that S.extension.where(url='https://www.medizininformatik-initiative.de/fhir/ext/modul-biobank/StructureDefinition/Diagnose').first().value.as(Reference).reference contains 'Condition/' + C.id where S.collection.bodySite.coding contains Code 'C44.6' from icd_o_3) define InInitialPopulation: