Skip to content

Commit

Permalink
Merge pull request #152 from medizininformatik-initiative/update-mapp…
Browse files Browse the repository at this point in the history
…ing-tree

Update Mapping Tree
  • Loading branch information
bastianschaffer authored Sep 4, 2024
2 parents 2022a45 + f147096 commit 7ff7575
Show file tree
Hide file tree
Showing 24 changed files with 741 additions and 552 deletions.
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
<hapi-fhir.version>7.2.1</hapi-fhir.version>
<testcontainers.version>1.20.0</testcontainers.version>
<slf4j.version>2.0.13</slf4j.version>
<ontology.version>2.2.0</ontology.version>
<ontology.version>3.0.0-test.1</ontology.version>
</properties>

<dependencies>
Expand Down Expand Up @@ -177,7 +177,7 @@
<goal>download-single</goal>
</goals>
<configuration>
<url>https://github.com/medizininformatik-initiative/fhir-ontology-generator/raw/v${ontology.version}/example/mii_core_data_set/ontology/mapping.zip</url>
<url>https://github.com/medizininformatik-initiative/fhir-ontology-generator/raw/v${ontology.version}/example/fdpg-ontology/mapping.zip</url>
<toDir>${project.build.directory}</toDir>
</configuration>
</execution>
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/de/numcodex/sq2cql/model/MappingContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@
public class MappingContext {

private final Map<ContextualTermCode, Mapping> mappings;
private final TermCodeNode conceptTree;
private final MappingTreeBase conceptTree;
private final Map<String, CodeSystemDefinition> codeSystemDefinitions;

private MappingContext(Map<ContextualTermCode, Mapping> mappings, TermCodeNode conceptTree,
private MappingContext(Map<ContextualTermCode, Mapping> mappings, MappingTreeBase conceptTree,
Map<String, CodeSystemDefinition> codeSystemDefinitions) {
this.mappings = mappings;
this.conceptTree = conceptTree;
Expand All @@ -48,7 +48,7 @@ public static MappingContext of() {
* @param codeSystemAliases a map of code system URLs to their aliases
* @return the mapping context
*/
public static MappingContext of(Map<ContextualTermCode, Mapping> mappings, TermCodeNode conceptTree,
public static MappingContext of(Map<ContextualTermCode, Mapping> mappings, MappingTreeBase conceptTree,
Map<String, String> codeSystemAliases) {
return new MappingContext(Map.copyOf(mappings), conceptTree, codeSystemAliases.entrySet().stream()
.collect(Collectors.toConcurrentMap(Map.Entry::getKey,
Expand Down
17 changes: 17 additions & 0 deletions src/main/java/de/numcodex/sq2cql/model/MappingTreeBase.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package de.numcodex.sq2cql.model;


import de.numcodex.sq2cql.model.structured_query.ContextualTermCode;

import java.util.List;
import java.util.stream.Stream;

public record MappingTreeBase(List<MappingTreeModuleRoot> moduleRoots) {

public Stream<ContextualTermCode> expand(ContextualTermCode termCode) {
var key = termCode.termCode().code();

return moduleRoots.stream().flatMap(moduleRoot ->
moduleRoot.isModuleMatching(termCode) ? moduleRoot.expand(key) : Stream.empty());
}
}
16 changes: 16 additions & 0 deletions src/main/java/de/numcodex/sq2cql/model/MappingTreeModuleEntry.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package de.numcodex.sq2cql.model;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;

import java.util.List;

@JsonIgnoreProperties(ignoreUnknown = true)
public record MappingTreeModuleEntry(String key, List<String> children) {
@JsonCreator
static MappingTreeModuleEntry fromJson(@JsonProperty("key") String key,
@JsonProperty("children") List<String> children) {
return new MappingTreeModuleEntry(key, children);
}
}
40 changes: 40 additions & 0 deletions src/main/java/de/numcodex/sq2cql/model/MappingTreeModuleRoot.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package de.numcodex.sq2cql.model;


import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import de.numcodex.sq2cql.model.common.TermCode;
import de.numcodex.sq2cql.model.structured_query.ContextualTermCode;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static java.util.function.Function.identity;

@JsonIgnoreProperties(ignoreUnknown = true)
public record MappingTreeModuleRoot(TermCode context, String system, Map<String, MappingTreeModuleEntry> entries) {
@JsonCreator
static MappingTreeModuleRoot fromJson(@JsonProperty("context") TermCode context,
@JsonProperty("system") String system,
@JsonProperty("entries") List<MappingTreeModuleEntry> entries) {
return new MappingTreeModuleRoot(
context,
system,
entries.stream().collect(Collectors.toMap(MappingTreeModuleEntry::key, identity())));
}

public Stream<ContextualTermCode> expand(String key) {
var newTermCode = new ContextualTermCode(context, new TermCode(system, key, ""));

return Stream.concat(Stream.of(newTermCode), entries.get(key).children().stream().flatMap(this::expand));
}

boolean isModuleMatching(ContextualTermCode contextualTermCode) {
return context.equals(contextualTermCode.context()) &&
system.equals(contextualTermCode.termCode().system()) &&
entries.containsKey(contextualTermCode.termCode().code());
}
}
61 changes: 0 additions & 61 deletions src/main/java/de/numcodex/sq2cql/model/TermCodeNode.java

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ static Container<RetrieveExpression> retrieveExpr(MappingContext mappingContext,
}

private static String referenceName(TermCode termCode) {
return "%s".formatted(termCode.display() + termCode.code() + "Ref");
return termCode.code() + "Ref";
}

public abstract T appendAttributeFilter(AttributeFilter attributeFilter);
Expand Down
52 changes: 14 additions & 38 deletions src/test/java/de/numcodex/sq2cql/AcceptanceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import de.numcodex.sq2cql.model.structured_query.StructuredQuery;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r4.model.*;
import org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.Library;
import org.hl7.fhir.r4.model.Measure;
import org.hl7.fhir.r4.model.MeasureReport;
import org.hl7.fhir.r4.model.Parameters;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
Expand All @@ -32,9 +36,8 @@
import java.nio.file.Paths;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.zip.ZipFile;
import java.util.stream.Stream;

import static de.numcodex.sq2cql.Util.createTranslator;
import static java.lang.String.format;
Expand Down Expand Up @@ -78,41 +81,14 @@ private static Bundle createBundle(Library library, Measure measure) {
}

public static List<StructuredQuery> getTestQueriesReturningOnePatient() throws URISyntaxException, IOException {
var exclusions = Set.of("new_testdata/1-age.json",
// Blaze can't parse the unit [arb'U]/mL https://github.com/samply/blaze/issues/1234
"new_testdata/ObservationLab-38dfe76b-ae35-8290-6d80-ab08c963d148",
"new_testdata/ObservationLab-16408169-a38d-8afc-fdd2-ed7af97ccc57",
"new_testdata/ObservationLab-0fa07a3f-2e29-5065-6fa2-31e959acdd98",
"new_testdata/ObservationLab-43eb280e-7901-7990-64e3-22cfa51de78b",
"new_testdata/ObservationLab-09c67417-306a-a871-feef-71cbc915d113",
"new_testdata/ObservationLab-26184c80-edf6-b1e0-ee8f-0e0999755cb9",
"new_testdata/ObservationLab-9d44c93e-7799-a8e2-b368-c5539c30ceaa",
"new_testdata/ObservationLab-755a3ac1-32ae-2a20-1ac9-02ee25777cf0",
"new_testdata/ObservationLab-8ec9ea98-6581-f934-9bcf-b1c4f87e3560",
"new_testdata/ObservationLab-315e8080-7425-f4e9-3891-aef5ebe0572c",
"new_testdata/ObservationLab-44c8fd00-1a0f-f218-9eb8-83257add8fed",
"new_testdata/ObservationLab-7a2be049-40d2-d16f-3db6-12f46df2fc82",
"new_testdata/ObservationLab-78c5a976-1786-72e8-006b-8fd6af157ed9",
"new_testdata/ObservationLab-254bf7ae-1d0a-b994-f20b-575d4e28e674",
"new_testdata/ObservationLab-4bf41e10-1c62-2f82-d081-3d923aca43f2",
// Blaze can't parse the unit /[HPF]
"new_testdata/ObservationLab-bf7b68ae-1f89-41b6-e6a1-a40bf031f4b9",
"new_testdata/ObservationLab-b080e003-5e7f-503c-4b13-47f601d6d903",
"new_testdata/ObservationLab-3dd0c866-0649-def5-0fb2-de1ea0b976c2",
"new_testdata/ObservationLab-98b33c6e-0a14-b90a-7795-e98680ee526e",
// Blaze can't parse the unit /100{WBCs}
"new_testdata/ObservationLab-d2d07223-0b20-ee0f-8505-0a17d2e1ed4d"
);
try (var zipFile = new ZipFile(resourcePath("returningOnePatient.zip").toString())) {
return zipFile.stream()
.filter(entry -> !exclusions.contains(entry.toString()))
.map(entry -> {
try {
return new ObjectMapper().readValue(zipFile.getInputStream(entry), StructuredQuery.class);
} catch (IOException e) {
throw new RuntimeException(e);
}
}).toList();
try (Stream<Path> paths = Files.list(resourcePath("returningOnePatient"))) {
return paths.map(path -> {
try {
return new ObjectMapper().readValue(Files.readString(path), StructuredQuery.class);
} catch (IOException e) {
throw new RuntimeException(e);
}
}).toList();
}
}

Expand Down
14 changes: 7 additions & 7 deletions src/test/java/de/numcodex/sq2cql/EvaluationIT.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@
import ca.uhn.fhir.rest.param.DateParam;
import ca.uhn.fhir.rest.param.StringParam;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.numcodex.sq2cql.model.Mapping;
import de.numcodex.sq2cql.model.MappingContext;
import de.numcodex.sq2cql.model.TermCodeNode;
import de.numcodex.sq2cql.model.*;
import de.numcodex.sq2cql.model.common.TermCode;
import de.numcodex.sq2cql.model.structured_query.ContextualConcept;
import de.numcodex.sq2cql.model.structured_query.ContextualTermCode;
Expand All @@ -31,6 +29,7 @@
import java.util.Map;
import java.util.UUID;

import static de.numcodex.sq2cql.Util.createTreeWithoutChildren;
import static de.numcodex.sq2cql.model.common.Comparator.LESS_THAN;
import static java.lang.String.format;
import static java.nio.charset.StandardCharsets.UTF_8;
Expand All @@ -42,8 +41,9 @@
public class EvaluationIT {

static final TermCode CONTEXT = TermCode.of("context", "context", "context");
static final ContextualTermCode ROOT = ContextualTermCode.of(CONTEXT, TermCode.of("", "", ""));
static final ContextualTermCode BLOOD_PRESSURE = ContextualTermCode.of(CONTEXT, TermCode.of("http://loinc.org", "85354-9",
static final String BLOOD_PRESSURE_CODE = "85354-9";
static final String BLOOD_PRESSURE_SYSTEM = "http://loinc.org";
static final ContextualTermCode BLOOD_PRESSURE = ContextualTermCode.of(CONTEXT, TermCode.of(BLOOD_PRESSURE_SYSTEM, BLOOD_PRESSURE_CODE,
"Blood pressure panel with all children optional"));
static final TermCode DIASTOLIC_BLOOD_PRESSURE = TermCode.of("http://loinc.org", "8462-4",
"Diastolic blood pressure");
Expand Down Expand Up @@ -99,7 +99,7 @@ public void evaluateBloodPressure() throws Exception {
var valueFhirPath = format("component.where(code.coding.exists(system = '%s' and code = '%s')).value.first()",
DIASTOLIC_BLOOD_PRESSURE.system(), DIASTOLIC_BLOOD_PRESSURE.code());
var mappings = Map.of(BLOOD_PRESSURE, Mapping.of(BLOOD_PRESSURE, "Observation", valueFhirPath));
var conceptTree = TermCodeNode.of(ROOT, TermCodeNode.of(BLOOD_PRESSURE));
var conceptTree = createTreeWithoutChildren(BLOOD_PRESSURE);
var mappingContext = MappingContext.of(mappings, conceptTree, CODE_SYSTEM_ALIASES);
var translator = Translator.of(mappingContext);
var criterion = NumericCriterion.of(ContextualConcept.of(BLOOD_PRESSURE), LESS_THAN, BigDecimal.valueOf(80), "mm[Hg]");
Expand Down Expand Up @@ -157,7 +157,7 @@ public void evaluateBloodPressureAttribute() throws Exception {
}
""");
var mappings = Map.of(BLOOD_PRESSURE, mapping);
var conceptTree = TermCodeNode.of(ROOT, TermCodeNode.of(BLOOD_PRESSURE));
var conceptTree = createTreeWithoutChildren(BLOOD_PRESSURE);
var mappingContext = MappingContext.of(mappings, conceptTree, CODE_SYSTEM_ALIASES);
var translator = Translator.of(mappingContext);
var structuredQuery = readStructuredQuery("""
Expand Down
Loading

0 comments on commit 7ff7575

Please sign in to comment.