Search in sources :

Example 1 with CodeInfo

use of au.csiro.redmatch.terminology.CodeInfo in project redmatch by aehrc.

the class RedmatchGrammarValidator method handleExtensionValue.

private CodeInfo handleExtensionValue(String path) {
    CodeInfo res = new CodeInfo(path);
    res.setMin(0);
    res.setMax("1");
    res.setType("");
    return res;
}
Also used : CodeInfo(au.csiro.redmatch.terminology.CodeInfo)

Example 2 with CodeInfo

use of au.csiro.redmatch.terminology.CodeInfo in project redmatch by aehrc.

the class FhirExporter method createResource.

/**
 * Creates a resource and populates its attributes.
 *
 * @param resource The internal resource representation.
 * @param vertex A vertex with patient data.
 * @param recordId The id of this record. Used to create the FHIR ids.
 */
private void createResource(Resource resource, JsonObject vertex, String recordId) {
    final String resourceId = resource.getResourceId();
    final String fhirId = resourceId + (recordId != null ? ("-" + recordId) : "");
    DomainResource fhirResource = fhirResourceMap.get(fhirId);
    if (fhirResource == null) {
        String resourceType = resource.getResourceType();
        CodeInfo codeInfo;
        try {
            VersionedFhirPackage fhirPackage = doc.getFhirPackage() != null ? doc.getFhirPackage() : defaultFhirPackage;
            codeInfo = terminologyService.lookup(fhirPackage, resourceType);
            if (codeInfo.isProfile() && codeInfo.getBaseResource() != null) {
                String baseResource = codeInfo.getBaseResource();
                String[] parts = baseResource.split("[/]");
                resourceType = parts[parts.length - 1];
            }
        } catch (IOException e) {
            throw new TransformationException("Unable to lookup information about resource " + resourceType, e);
        }
        // This can be a profile name, so we need to get the base FHIR resource
        Object instance;
        try {
            instance = Class.forName(HapiReflectionHelper.FHIR_TYPES_BASE_PACKAGE + "." + resourceType).getConstructor().newInstance();
        } catch (ClassNotFoundException | IllegalAccessException | InstantiationException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) {
            throw new TransformationException("Unable to create resource " + resource.getResourceType(), e);
        }
        fhirResource = (DomainResource) instance;
        fhirResource.setId(fhirId);
        if (codeInfo.getProfileUrl() != null) {
            fhirResource.getMeta().addProfile(codeInfo.getProfileUrl());
        }
        fhirResourceMap.put(fhirId, fhirResource);
    }
    VersionedFhirPackage fhirPackage = doc.getFhirPackage() != null ? doc.getFhirPackage() : defaultFhirPackage;
    for (AttributeValue attVal : resource.getResourceAttributeValues()) {
        setValue(fhirResource, attVal.getAttributes(), attVal.getValue(), vertex, recordId, fhirPackage, resource.getResourceType());
    }
}
Also used : CodeInfo(au.csiro.redmatch.terminology.CodeInfo) IOException(java.io.IOException) VersionedFhirPackage(au.csiro.redmatch.model.VersionedFhirPackage) InvocationTargetException(java.lang.reflect.InvocationTargetException) JsonObject(com.google.gson.JsonObject)

Example 3 with CodeInfo

use of au.csiro.redmatch.terminology.CodeInfo in project redmatch by aehrc.

the class FhirExporter method getValue.

/**
 * Resolves a value.
 *
 * @param value The value specified in the transformation rules.
 * @param fhirType The type of the FHIR attribute where this value will be set.
 * @param vertex A vertex with patient data.
 * @param recordId The id of this record. Used to create the references to FHIR ids.
 * @param enumFactory If the type is an enumeration, this is the factory to create an instance.
 * @param fhirPackage The target FHIR package.
 * @return The value or null if the value cannot be determined. This can also be a list.
 */
private Base getValue(Value value, Class<?> fhirType, JsonObject vertex, String recordId, Class<?> enumFactory, VersionedFhirPackage fhirPackage) throws IOException {
    // If this is a field-based value then make sure that there is a value and if not return null
    if (value instanceof FieldBasedValue) {
        FieldBasedValue fbv = (FieldBasedValue) value;
        // Account for field ids of the form xx___y
        String fieldId = fbv.getFieldId();
        String shortFieldId = null;
        String regex = "(?<fieldId>.*)___\\d+$";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(fieldId);
        if (matcher.find()) {
            shortFieldId = matcher.group("fieldId");
            log.debug("Transformed fieldId into '" + fieldId + "'");
        }
        boolean hasValue = false;
        JsonElement jsonElement = vertex.get(fieldId);
        if (jsonElement != null) {
            String rawValue = jsonElement.getAsString();
            if (!rawValue.isEmpty()) {
                hasValue = true;
            }
        }
        if (!hasValue && shortFieldId != null) {
            jsonElement = vertex.get(shortFieldId);
            if (jsonElement != null) {
                String rawValue = jsonElement.getAsString();
                if (!rawValue.isEmpty()) {
                    hasValue = true;
                }
            }
        }
        if (!hasValue) {
            return null;
        }
    }
    if (value instanceof BooleanValue) {
        return new BooleanType(((BooleanValue) value).getValue());
    } else if (value instanceof CodeLiteralValue) {
        String code = ((CodeLiteralValue) value).getCode();
        return getCode(code, enumFactory);
    } else if (value instanceof ConceptLiteralValue) {
        ConceptLiteralValue clv = (ConceptLiteralValue) value;
        String system = clv.getSystem();
        String code = clv.getCode();
        String display = clv.getDisplay() != null ? clv.getDisplay() : "";
        return getConcept(system, code, display, fhirType);
    } else if (value instanceof DoubleValue) {
        return new DecimalType(((DoubleValue) value).getValue());
    } else if (value instanceof IntegerValue) {
        return new IntegerType(((IntegerValue) value).getValue());
    } else if (value instanceof ReferenceValue) {
        ReferenceValue rv = (ReferenceValue) value;
        Reference ref = new Reference();
        String resourceType = rv.getResourceType();
        String resourceId = rv.getResourceId();
        boolean unique = uniqueIds.contains(resourceType + "<" + resourceId + ">");
        CodeInfo codeInfo = terminologyService.lookup(fhirPackage, resourceType);
        if (codeInfo.isProfile()) {
            resourceType = StringUtils.getLastPath(codeInfo.getBaseResource());
        }
        if (unique) {
            // This is a reference to a unique resource - no need to append row id
            if (fhirResourceMap.containsKey(resourceId)) {
                ref.setReference("/" + resourceType + "/" + resourceId);
            } else {
                log.debug("Did not find resource " + resourceType + "/" + resourceId);
            }
        } else {
            if (fhirResourceMap.containsKey(resourceId + "-" + recordId)) {
                ref.setReference("/" + resourceType + "/" + resourceId + "-" + recordId);
            } else {
                log.debug("Did not find resource " + resourceType + "/" + resourceId + "-" + recordId);
            }
        }
        return ref;
    } else if (value instanceof StringValue) {
        if (fhirType.equals(StringType.class)) {
            return new StringType(((StringValue) value).getStringValue());
        } else if (fhirType.equals(MarkdownType.class)) {
            return new MarkdownType(((StringValue) value).getStringValue());
        } else if (fhirType.equals(IdType.class)) {
            return new IdType(((StringValue) value).getStringValue());
        } else if (fhirType.equals(UriType.class)) {
            return new UriType(((StringValue) value).getStringValue());
        } else if (fhirType.equals(OidType.class)) {
            return new OidType(((StringValue) value).getStringValue());
        } else if (fhirType.equals(UuidType.class)) {
            return new UuidType(((StringValue) value).getStringValue());
        } else if (fhirType.equals(CanonicalType.class)) {
            return new CanonicalType(((StringValue) value).getStringValue());
        } else if (fhirType.equals(UrlType.class)) {
            return new UrlType(((StringValue) value).getStringValue());
        } else {
            throw new TransformationException("Got StringValue for FHIR type " + fhirType.getName() + ". This should not happen!");
        }
    } else if (value instanceof CodeSelectedValue) {
        CodeSelectedValue csv = (CodeSelectedValue) value;
        String fieldId = csv.getFieldId();
        Mapping m = getSelectedMapping(fieldId, vertex);
        if (m == null) {
            throw new TransformationException("Mapping for field " + fieldId + " is required but was not found.");
        }
        return getTarget(m).getCodeElement();
    } else if (value instanceof ConceptSelectedValue) {
        ConceptSelectedValue csv = (ConceptSelectedValue) value;
        String fieldId = csv.getFieldId();
        Mapping m = getSelectedMapping(fieldId, vertex);
        if (m == null) {
            throw new TransformationException("Mapping for field " + fieldId + " is required but was not found.");
        }
        if (fhirType.isAssignableFrom(Coding.class)) {
            return getTarget(m);
        } else if (fhirType.isAssignableFrom(CodeableConcept.class)) {
            return new CodeableConcept().addCoding(getTarget(m));
        } else {
            throw new TransformationException("FHIR type of field " + fieldId + " (" + fhirType + ") is incompatible with CONCEPT_SELECTED.");
        }
    } else if (value instanceof ConceptValue) {
        // Ontoserver REDCap plugin format: 74400008|Appendicitis|http://snomed.info/sct
        ConceptValue cv = (ConceptValue) value;
        String fieldId = cv.getFieldId();
        Mapping m = getMapping(fieldId);
        if (m != null) {
            if (fhirType.isAssignableFrom(Coding.class)) {
                return getTarget(m);
            } else if (fhirType.isAssignableFrom(CodeableConcept.class)) {
                return new CodeableConcept().addCoding(getTarget(m));
            } else {
                throw new TransformationException("FHIR type of field " + fieldId + " (" + fhirType + ") is incompatible with CONCEPT.");
            }
        } else {
            au.csiro.redmatch.model.Field field = doc.getSchema().getField(fieldId);
            Coding c = field.getCoding(vertex);
            if (c != null) {
                if (fhirType.isAssignableFrom(Coding.class)) {
                    return c;
                } else if (fhirType.isAssignableFrom(CodeableConcept.class)) {
                    return new CodeableConcept().addCoding(c);
                } else {
                    throw new TransformationException("FHIR type of field " + fieldId + " (" + fhirType + ") is incompatible with CONCEPT.");
                }
            }
        }
        throw new TransformationException("Could not get concept for field " + fieldId + ".");
    } else if (value instanceof FieldValue) {
        FieldValue fv = (FieldValue) value;
        String fieldId = fv.getFieldId();
        FieldValue.DatePrecision pr = fv.getDatePrecision();
        au.csiro.redmatch.model.Field field = doc.getSchema().getField(fieldId);
        return field.getValue(vertex, fhirType, pr);
    } else {
        throw new TransformationException("Unable to get VALUE for " + value);
    }
}
Also used : CodeInfo(au.csiro.redmatch.terminology.CodeInfo) Matcher(java.util.regex.Matcher) Field(java.lang.reflect.Field) org.hl7.fhir.r4.model(org.hl7.fhir.r4.model) Pattern(java.util.regex.Pattern) JsonElement(com.google.gson.JsonElement)

Example 4 with CodeInfo

use of au.csiro.redmatch.terminology.CodeInfo in project redmatch by aehrc.

the class RedmatchGrammarValidator method handleExtensionUrl.

private CodeInfo handleExtensionUrl(String path) {
    CodeInfo res = new CodeInfo(path);
    res.setMin(1);
    res.setMax("1");
    res.setType("uri");
    return res;
}
Also used : CodeInfo(au.csiro.redmatch.terminology.CodeInfo)

Example 5 with CodeInfo

use of au.csiro.redmatch.terminology.CodeInfo in project redmatch by aehrc.

the class RedmatchCompiler method visitAttributeInternal.

private List<Attribute> visitAttributeInternal(String resourceType, AttributeContext ctx, Variables var) throws IOException {
    final List<Attribute> res = new ArrayList<>();
    String path = resourceType;
    for (AttributePathContext apCtx : ctx.attributePath()) {
        Attribute att = visitAttributePathInternal(apCtx, var);
        res.add(att);
        // Validate attribute
        path = path + "." + att.getName();
        log.debug("Validating path " + path);
        ValidationResult vr = validator.validateAttributePath(path);
        if (!vr.getResult()) {
            for (String msg : vr.getMessages()) {
                this.diagnostics.add(getDiagnosticFromContext(ctx, msg, DiagnosticSeverity.Error, CODE_INVALID_FHIR_ATTRIBUTE_PATH.toString()));
            }
            break;
        } else {
            // TODO: check what happens with extension[0].valueReference = REF(ResearchStudy<rstud>)
            // Add test case for FHIR exporter with an extension
            CodeInfo info = validator.getPathInfo(path);
            lastInfo = info;
            String max = info.getMax();
            if ("*".equals(max)) {
                att.setList(true);
            } else {
                int maxInt = Integer.parseInt(max);
                if (maxInt == 0) {
                    this.diagnostics.add(getDiagnosticFromContext(ctx, "Unable to set attribute " + path + " with max cardinality of 0.", DiagnosticSeverity.Error, CODE_FHIR_ATTRIBUTE_NOT_ALLOWED.toString()));
                    break;
                } else if (att.hasAttributeIndex() && att.getAttributeIndex() >= maxInt) {
                    // e.g. myAttr[1] would be illegal if maxInt = 1
                    this.diagnostics.add(getDiagnosticFromContext(ctx, "Attribute " + att + " is setting an invalid index (max = " + maxInt + ").", DiagnosticSeverity.Error, CODE_INVALID_FHIR_ATTRIBUTE_INDEX.toString()));
                    break;
                }
            }
        }
    }
    return res;
}
Also used : CodeInfo(au.csiro.redmatch.terminology.CodeInfo) AttributePathContext(au.csiro.redmatch.grammar.RedmatchGrammar.AttributePathContext) ValidationResult(au.csiro.redmatch.validation.ValidationResult)

Aggregations

CodeInfo (au.csiro.redmatch.terminology.CodeInfo)6 Attribute (au.csiro.redmatch.compiler.Attribute)1 AttributePathContext (au.csiro.redmatch.grammar.RedmatchGrammar.AttributePathContext)1 VersionedFhirPackage (au.csiro.redmatch.model.VersionedFhirPackage)1 ValidationResult (au.csiro.redmatch.validation.ValidationResult)1 JsonElement (com.google.gson.JsonElement)1 JsonObject (com.google.gson.JsonObject)1 IOException (java.io.IOException)1 Field (java.lang.reflect.Field)1 InvocationTargetException (java.lang.reflect.InvocationTargetException)1 Matcher (java.util.regex.Matcher)1 Pattern (java.util.regex.Pattern)1 org.hl7.fhir.r4.model (org.hl7.fhir.r4.model)1