This commit is contained in:
Grahame Grieve 2024-02-10 23:11:56 +11:00
parent b548b98496
commit 85a8807e7b
2 changed files with 221 additions and 5 deletions

View File

@ -82,6 +82,8 @@ public class ValueSetRenderer extends TerminologyRenderer {
private static final int MAX_DESIGNATIONS_IN_LINE = 5;
private static final int MAX_BATCH_VALIDATION_SIZE = 1000;
private List<ConceptMapRenderInstructions> renderingMaps = new ArrayList<ConceptMapRenderInstructions>();
public boolean render(XhtmlNode x, Resource dr) throws FHIRFormatError, DefinitionException, IOException {
@ -1431,12 +1433,23 @@ public class ValueSetRenderer extends TerminologyRenderer {
}
}
if (!context.isNoSlowLookup() && !serverList.isEmpty()) {
getContext().getWorker().validateCodeBatch(getContext().getTerminologyServiceOptions(), serverList, null);
for (CodingValidationRequest vr : serverList) {
ConceptDefinitionComponent v = vr.getResult().asConceptDefinition();
if (v != null) {
results.put(vr.getCoding().getCode(), v);
try {
// todo: split this into 10k batches
int i = 0;
while (serverList.size() > i) {
int len = Integer.min(serverList.size(), MAX_BATCH_VALIDATION_SIZE);
List<CodingValidationRequest> list = serverList.subList(i, i+len);
i += len;
getContext().getWorker().validateCodeBatch(getContext().getTerminologyServiceOptions(), list, null);
for (CodingValidationRequest vr : list) {
ConceptDefinitionComponent v = vr.getResult().asConceptDefinition();
if (v != null) {
results.put(vr.getCoding().getCode(), v);
}
}
}
} catch (Exception e1) {
return null;
}
}
return results;

View File

@ -1,7 +1,11 @@
package org.hl7.fhir.r5.terminologies;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.hl7.fhir.r5.model.CanonicalType;
import org.hl7.fhir.r5.model.CodeSystem;
@ -10,6 +14,8 @@ import org.hl7.fhir.r5.model.ConceptMap;
import org.hl7.fhir.r5.model.ConceptMap.ConceptMapGroupComponent;
import org.hl7.fhir.r5.model.ConceptMap.SourceElementComponent;
import org.hl7.fhir.r5.model.ConceptMap.TargetElementComponent;
import org.hl7.fhir.r5.model.Enumerations.ConceptMapRelationship;
import org.hl7.fhir.r5.terminologies.ConceptMapUtilities.ConceptMapElementSorter;
import org.hl7.fhir.r5.model.Identifier;
import org.hl7.fhir.r5.model.Meta;
import org.hl7.fhir.r5.model.UriType;
@ -17,6 +23,40 @@ import org.hl7.fhir.r5.model.ValueSet;
public class ConceptMapUtilities {
public static class TranslatedCode {
private String code;
private ConceptMapRelationship relationship;
public TranslatedCode(String code, ConceptMapRelationship relationship) {
super();
this.code = code;
this.relationship = relationship;
}
public String getCode() {
return code;
}
public ConceptMapRelationship getRelationship() {
return relationship;
}
}
public static class ConceptMapElementSorter implements Comparator<SourceElementComponent> {
@Override
public int compare(SourceElementComponent o1, SourceElementComponent o2) {
return o1.getCode().compareTo(o2.getCode());
}
}
public static class ConceptMapTargetElementSorter implements Comparator<TargetElementComponent> {
@Override
public int compare(TargetElementComponent o1, TargetElementComponent o2) {
return o1.getCode().compareTo(o2.getCode());
}
}
public static boolean hasOID(ConceptMap cm) {
return getOID(cm) != null;
}
@ -85,4 +125,167 @@ public class ConceptMapUtilities {
return cm;
}
public static ConceptMap invert(ConceptMap src, String id, String url, String name, boolean collate) {
ConceptMap dst = src.copy();
dst.setId(id);
dst.setUrl(url);
dst.setName(name);
dst.getGroup().clear();
dst.setSourceScope(src.getTargetScope());
dst.setTargetScope(src.getSourceScope());
for (ConceptMapGroupComponent gs : src.getGroup()) {
ConceptMapGroupComponent gd = dst.addGroup();
gd.setTargetElement(gs.getSourceElement());
gd.setSourceElement(gs.getTargetElement());
Map<String, SourceElementComponent> dstMap = new HashMap<>();
for (SourceElementComponent es : gs.getElement()) {
for (TargetElementComponent ts : es.getTarget()) {
SourceElementComponent ed = collate ? dstMap.get(ts.getCode()) : null;
if (ed == null) {
ed = gd.addElement();
ed.setCodeElement(ts.getCodeElement());
if (collate) {
dstMap.put(ed.getCode(), ed);
}
}
TargetElementComponent td = ed.addTarget();
td.setCode(es.getCode());
td.setComment(ts.getComment());
td.setRelationship(invertRelationship(ts.getRelationship()));
}
}
}
return dst;
}
private static ConceptMapRelationship invertRelationship(ConceptMapRelationship relationship) {
if (relationship == null) {
return null;
}
switch (relationship) {
case EQUIVALENT:
return ConceptMapRelationship.EQUIVALENT;
case NOTRELATEDTO:
return ConceptMapRelationship.NOTRELATEDTO;
case NULL:
return ConceptMapRelationship.NULL;
case RELATEDTO:
return ConceptMapRelationship.RELATEDTO;
case SOURCEISBROADERTHANTARGET:
return ConceptMapRelationship.SOURCEISNARROWERTHANTARGET;
case SOURCEISNARROWERTHANTARGET:
return ConceptMapRelationship.SOURCEISBROADERTHANTARGET;
default:
return null;
}
}
public static ConceptMap collapse(String id, String url, boolean cumulative, ConceptMap src, ConceptMap... sequence) {
ConceptMap res = src.copy();
res.setId(id);
res.setUrl(url);
for (ConceptMap cm : sequence) {
if (res.hasTargetScope() && src.hasTargetScope()) {
if (!cm.getSourceScope().equals(cm.getTargetScope())) {
throw new Error("Mismatch between seqeuntial concept maps: ");
} else {
res.setTargetScope(cm.getTargetScope());
}
} else {
res.setTargetScope(null);
}
}
for (ConceptMapGroupComponent gd : res.getGroup()) {
for (ConceptMap cm : sequence) {
for (ConceptMapGroupComponent gt : cm.getGroup()) {
if (gt.getSource().equals(gd.getTarget())) {
gd.setTarget(gt.getTarget());
List<SourceElementComponent> processed = new ArrayList<ConceptMap.SourceElementComponent>();
for (SourceElementComponent ed : gd.getElement()) {
List<TargetElementComponent> list = new ArrayList<>();
list.addAll(ed.getTarget());
ed.getTarget().clear();
for (TargetElementComponent ts : list) {
for (SourceElementComponent et : gt.getElement()) {
if (et.getCode().equals(ed.getCode())) {
processed.add(et);
for (TargetElementComponent tt : et.getTarget()) {
ed.addTarget().setCode(tt.getCode()).setRelationship(combineRelationships(ts.getRelationship(), tt.getRelationship()));
}
}
}
}
if (ed.getTarget().isEmpty()) {
if (cumulative) {
ed.getTarget().addAll(list);
} else {
ed.setNoMap(true);
}
}
}
if (cumulative) {
for (SourceElementComponent et : gt.getElement()) {
if (!processed.contains(et)) {
gd.addElement(et.copy());
}
}
}
}
Collections.sort(gt.getElement(), new ConceptMapElementSorter());
for (SourceElementComponent e: gt.getElement()) {
Collections.sort(e.getTarget(), new ConceptMapTargetElementSorter());
}
}
}
}
return res;
}
public static ConceptMapRelationship combineRelationships(ConceptMapRelationship rel1, ConceptMapRelationship rel2) {
switch (rel1) {
case EQUIVALENT:
return rel2;
case NOTRELATEDTO:
return ConceptMapRelationship.NOTRELATEDTO;
case NULL:
return null;
case RELATEDTO:
return rel2;
case SOURCEISBROADERTHANTARGET:
switch (rel2) {
case EQUIVALENT:
return ConceptMapRelationship.SOURCEISBROADERTHANTARGET;
case NOTRELATEDTO:
return ConceptMapRelationship.NOTRELATEDTO;
case NULL:
return null;
case RELATEDTO:
return ConceptMapRelationship.RELATEDTO;
case SOURCEISBROADERTHANTARGET:
return ConceptMapRelationship.SOURCEISBROADERTHANTARGET;
case SOURCEISNARROWERTHANTARGET:
return ConceptMapRelationship.RELATEDTO;
}
case SOURCEISNARROWERTHANTARGET:
switch (rel2) {
case EQUIVALENT:
return ConceptMapRelationship.SOURCEISNARROWERTHANTARGET;
case NOTRELATEDTO:
return ConceptMapRelationship.NOTRELATEDTO;
case NULL:
return null;
case RELATEDTO:
return ConceptMapRelationship.RELATEDTO;
case SOURCEISBROADERTHANTARGET:
return ConceptMapRelationship.RELATEDTO;
case SOURCEISNARROWERTHANTARGET:
return ConceptMapRelationship.SOURCEISNARROWERTHANTARGET;
}
}
return null;
}
}