Search in sources :

Example 61 with Function

use of org.hl7.fhir.r5.model.ExpressionNode.Function in project pathling by aehrc.

the class ResolveFunction method invoke.

@Nonnull
@Override
public FhirPath invoke(@Nonnull final NamedFunctionInput input) {
    checkUserInput(input.getInput() instanceof ReferencePath, "Input to " + NAME + " function must be a Reference: " + input.getInput().getExpression());
    checkNoArguments(NAME, input);
    final ReferencePath inputPath = (ReferencePath) input.getInput();
    final Database database = input.getContext().getDatabase();
    // Get the allowed types for the input reference. This gives us the set of possible resource
    // types that this reference could resolve to.
    Set<ResourceType> referenceTypes = inputPath.getResourceTypes();
    // If the type is Resource, all resource types need to be looked at.
    if (referenceTypes.contains(ResourceType.RESOURCE)) {
        referenceTypes = FhirServer.supportedResourceTypes();
    }
    check(referenceTypes.size() > 0);
    final boolean isPolymorphic = referenceTypes.size() > 1;
    final String expression = expressionFromInput(input, NAME);
    if (isPolymorphic) {
        return resolvePolymorphicReference(input, database, referenceTypes, expression);
    } else {
        final FhirContext fhirContext = input.getContext().getFhirContext();
        return resolveMonomorphicReference(input, database, fhirContext, referenceTypes, expression);
    }
}
Also used : FhirContext(ca.uhn.fhir.context.FhirContext) Database(au.csiro.pathling.io.Database) ReferencePath(au.csiro.pathling.fhirpath.element.ReferencePath) ResourceType(org.hl7.fhir.r4.model.Enumerations.ResourceType) Nonnull(javax.annotation.Nonnull)

Example 62 with Function

use of org.hl7.fhir.r5.model.ExpressionNode.Function in project pathling by aehrc.

the class AggregateFunction method buildAggregateResult.

@Nonnull
private <T extends FhirPath> T buildAggregateResult(@Nonnull final Dataset<Row> dataset, @Nonnull final ParserContext parserContext, @Nonnull final Collection<FhirPath> inputs, @Nonnull final Column valueColumn, @Nonnull final String expression, @Nonnull final ResultPathFactory<T> resultPathFactory) {
    checkArgument(!inputs.isEmpty(), "Collection of inputs cannot be empty");
    // Use an ID column from any of the inputs.
    final Column idColumn = inputs.stream().findFirst().get().getIdColumn();
    // Get the grouping columns from the parser context.
    final List<Column> groupByList = parserContext.getGroupingColumns();
    // Drop the requested grouping columns that are not present in the provided dataset.
    // This handles the situation where `%resource` is used in `where()`.
    // The columns requested for aggregation may include $this element ID, which is not present in
    // datasets originating from `%resource` and thus should not be actually used for evaluation of
    // the aggregation.
    final Set<String> existingColumns = Stream.of(dataset.columns()).collect(Collectors.toSet());
    final Column[] groupBy = groupByList.stream().filter(c -> existingColumns.contains(c.toString())).toArray(Column[]::new);
    // The selection will be the first function applied to each column except the grouping columns,
    // plus the value column.
    final Predicate<Column> groupingFilter = column -> !groupByList.contains(column);
    final List<Column> selection = Stream.of(dataset.columns()).map(functions::col).filter(groupingFilter).map(column -> first(column, true).alias(column.toString())).collect(Collectors.toList());
    selection.add(valueColumn.alias("value"));
    final Column firstSelection = checkPresent(selection.stream().limit(1).findFirst());
    final Column[] remainingSelection = selection.stream().skip(1).toArray(Column[]::new);
    // Get any this columns that may be present in the inputs.
    // TODO: This is very error prone as a collection can be passed here instead of an array.
    // How can we make it more stringent?
    @SuppressWarnings("ConfusingArgumentToVarargsMethod") final Optional<Column> thisColumn = NonLiteralPath.findThisColumn(inputs.toArray(new FhirPath[0]));
    final Dataset<Row> finalDataset = dataset.groupBy(groupBy).agg(firstSelection, remainingSelection);
    final Column finalValueColumn = col("value");
    // Clear out the node ID columns in the parser context - as they are no longer valid for joining.
    parserContext.getNodeIdColumns().clear();
    // empty eid column as the result is singular
    return resultPathFactory.create(expression, finalDataset, idColumn, Optional.empty(), finalValueColumn, true, thisColumn);
}
Also used : java.util(java.util) Dataset(org.apache.spark.sql.Dataset) NonLiteralPath(au.csiro.pathling.fhirpath.NonLiteralPath) FHIRDefinedType(org.hl7.fhir.r4.model.Enumerations.FHIRDefinedType) Predicate(java.util.function.Predicate) Column(org.apache.spark.sql.Column) Preconditions.checkArgument(au.csiro.pathling.utilities.Preconditions.checkArgument) org.apache.spark.sql.functions.first(org.apache.spark.sql.functions.first) Row(org.apache.spark.sql.Row) Collectors(java.util.stream.Collectors) Preconditions.checkPresent(au.csiro.pathling.utilities.Preconditions.checkPresent) ElementPath(au.csiro.pathling.fhirpath.element.ElementPath) ParserContext(au.csiro.pathling.fhirpath.parser.ParserContext) Stream(java.util.stream.Stream) FhirPath(au.csiro.pathling.fhirpath.FhirPath) org.apache.spark.sql.functions.col(org.apache.spark.sql.functions.col) org.apache.spark.sql.functions(org.apache.spark.sql.functions) Nonnull(javax.annotation.Nonnull) FhirPath(au.csiro.pathling.fhirpath.FhirPath) Column(org.apache.spark.sql.Column) Row(org.apache.spark.sql.Row) Nonnull(javax.annotation.Nonnull)

Example 63 with Function

use of org.hl7.fhir.r5.model.ExpressionNode.Function in project quality-measure-and-cohort-service by Alvearie.

the class CqlEvaluatorIntegrationTest method testUOMEquivalence_demonstrateConversionOnOneSide.

@Test
public void testUOMEquivalence_demonstrateConversionOnOneSide() throws Exception {
    Patient patient = getPatient("123", Enumerations.AdministrativeGender.FEMALE, "1983-12-02");
    CqlEvaluator evaluator = setupTestFor(patient, "cql.uomequivalence");
    String expression = "AreEquivalent";
    CqlEvaluationResult actual = evaluator.evaluate(new CqlVersionedIdentifier("TestUOMCompare", "1.0.0"), null, newPatientContext("123"), Collections.singleton(expression));
    Map<String, Object> expected = new HashMap<>();
    // you can use the *convert* function to change the
    // units of a quantity to a known value
    expected.put(expression, true);
    Assert.assertEquals(expected, actual.getExpressionResults());
}
Also used : HashMap(java.util.HashMap) Patient(org.hl7.fhir.r4.model.Patient) CqlEvaluationResult(com.ibm.cohort.cql.evaluation.CqlEvaluationResult) CqlEvaluator(com.ibm.cohort.cql.evaluation.CqlEvaluator) CqlVersionedIdentifier(com.ibm.cohort.cql.library.CqlVersionedIdentifier) Test(org.junit.Test)

Example 64 with Function

use of org.hl7.fhir.r5.model.ExpressionNode.Function in project quality-measure-and-cohort-service by Alvearie.

the class CqlEvaluatorIntegrationTest method testConditionDateRangeCriteriaMatched.

@Test
public void testConditionDateRangeCriteriaMatched() throws Exception {
    Patient patient = getPatient("123", Enumerations.AdministrativeGender.FEMALE, null);
    DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
    Date date = sdf.parse("2000-01-01");
    Condition condition = new Condition();
    condition.setId("condition");
    condition.setSubject(new Reference("Patient/123"));
    condition.setRecordedDate(date);
    // Wiremock does not support request matching withQueryParam() function does not support
    // the same parameter multiple times, so we do some regex work and try to make it
    // somewhat order independent while still readable.
    // @see https://github.com/tomakehurst/wiremock/issues/398
    MappingBuilder builder = get(urlMatching("/Condition\\?(recorded-date=[lg]e.*&){2}subject=Patient%2F123&_format=json"));
    mockFhirResourceRetrieval(builder, condition);
    FhirServerConfig fhirConfig = getFhirServerConfig();
    CqlEvaluator evaluator = setupTestFor(patient, fhirConfig, "cql.condition", ClasspathCqlLibraryProvider.FHIR_HELPERS_CLASSPATH);
    Map<String, Parameter> parameters = new HashMap<>();
    parameters.put("MeasurementPeriod", new IntervalParameter(new DatetimeParameter("1999-01-01T00:00:00-05:00"), true, new DatetimeParameter("2000-01-01T00:00:00-05:00"), false));
    String expression = "ConditionInInterval";
    CqlEvaluationResult actual = evaluator.evaluate(new CqlVersionedIdentifier("TestDateQuery", "1.0.0"), parameters, newPatientContext("123"), Collections.singleton(expression));
    Assert.assertEquals(1, actual.getExpressionResults().size());
    List<Object> value = (List) actual.getExpressionResults().get(expression);
    Assert.assertEquals(1, value.size());
    assertFhirEquals(condition, (IBaseResource) value.get(0));
}
Also used : Condition(org.hl7.fhir.r4.model.Condition) HashMap(java.util.HashMap) Reference(org.hl7.fhir.r4.model.Reference) Patient(org.hl7.fhir.r4.model.Patient) CqlEvaluationResult(com.ibm.cohort.cql.evaluation.CqlEvaluationResult) Date(java.util.Date) MappingBuilder(com.github.tomakehurst.wiremock.client.MappingBuilder) SimpleDateFormat(java.text.SimpleDateFormat) DateFormat(java.text.DateFormat) DatetimeParameter(com.ibm.cohort.cql.evaluation.parameters.DatetimeParameter) IntervalParameter(com.ibm.cohort.cql.evaluation.parameters.IntervalParameter) IntegerParameter(com.ibm.cohort.cql.evaluation.parameters.IntegerParameter) Parameter(com.ibm.cohort.cql.evaluation.parameters.Parameter) DatetimeParameter(com.ibm.cohort.cql.evaluation.parameters.DatetimeParameter) FhirServerConfig(com.ibm.cohort.fhir.client.config.FhirServerConfig) List(java.util.List) SimpleDateFormat(java.text.SimpleDateFormat) IntervalParameter(com.ibm.cohort.cql.evaluation.parameters.IntervalParameter) CqlEvaluator(com.ibm.cohort.cql.evaluation.CqlEvaluator) CqlVersionedIdentifier(com.ibm.cohort.cql.library.CqlVersionedIdentifier) Test(org.junit.Test)

Example 65 with Function

use of org.hl7.fhir.r5.model.ExpressionNode.Function in project quality-measure-and-cohort-service by Alvearie.

the class AnyColumnVisitor method visitFunctionRef.

@Override
public Object visitFunctionRef(FunctionRef elm, AnyColumnContext context) {
    if (AnyColumnFunctions.FUNCTION_NAMES.contains(elm.getName())) {
        if (elm.getOperand().size() == 2) {
            QName dataType = ((As) elm.getOperand().get(0)).getOperand().getResultTypeName();
            // TODO - validate that the first operand is a model object. We really should be doing that at the
            // method declaration level instead of Choice<Any>, but that will require the model
            // to have a base class that everything extends from.
            String columnMatchLogic = null;
            if (elm.getOperand().get(1) instanceof Literal) {
                columnMatchLogic = ((Literal) elm.getOperand().get(1)).getValue();
            } else {
                throw new IllegalArgumentException(String.format("Second argument to %s function at %s must be a literal", elm.getName(), elm.getLocator()));
            }
            StringMatcher matcher = null;
            if (elm.getName().equals(AnyColumnFunctions.FUNC_ANY_COLUMN)) {
                matcher = new PrefixStringMatcher(columnMatchLogic);
            } else if (elm.getName().equals(AnyColumnFunctions.FUNC_ANY_COLUMN_REGEX)) {
                matcher = new RegexStringMatcher(columnMatchLogic);
            } else {
                throw new IllegalArgumentException(String.format("Found declared, but unsupported AnyColumn function %s at %s", elm.getName(), elm.getLocator()));
            }
            context.reportAnyColumn(dataType, matcher);
        } else {
            throw new IllegalArgumentException(String.format("%s function at %s should have exactly two arguments", elm.getName(), elm.getLocator()));
        }
    }
    return super.visitFunctionRef(elm, context);
}
Also used : RegexStringMatcher(com.ibm.cohort.cql.util.RegexStringMatcher) QName(javax.xml.namespace.QName) Literal(org.hl7.elm.r1.Literal) StringMatcher(com.ibm.cohort.cql.util.StringMatcher) RegexStringMatcher(com.ibm.cohort.cql.util.RegexStringMatcher) PrefixStringMatcher(com.ibm.cohort.cql.util.PrefixStringMatcher) PrefixStringMatcher(com.ibm.cohort.cql.util.PrefixStringMatcher)

Aggregations

Test (org.junit.jupiter.api.Test)17 List (java.util.List)8 FhirPath (au.csiro.pathling.fhirpath.FhirPath)7 Reference (org.hl7.fhir.r4.model.Reference)7 SpringBootTest (org.springframework.boot.test.context.SpringBootTest)7 ParserContext (au.csiro.pathling.fhirpath.parser.ParserContext)6 MethodOutcome (ca.uhn.fhir.rest.api.MethodOutcome)6 URI (java.net.URI)6 Row (org.apache.spark.sql.Row)6 Session (org.eclipse.jetty.websocket.api.Session)6 ClientUpgradeRequest (org.eclipse.jetty.websocket.client.ClientUpgradeRequest)6 WebSocketClient (org.eclipse.jetty.websocket.client.WebSocketClient)6 IIdType (org.hl7.fhir.instance.model.api.IIdType)6 Complex (org.hl7.fhir.r4.utils.formats.Turtle.Complex)6 FhirReference (org.openmrs.module.fhir2.model.FhirReference)6 FhirTask (org.openmrs.module.fhir2.model.FhirTask)6 DatasetBuilder (au.csiro.pathling.test.builders.DatasetBuilder)5 ElementPathBuilder (au.csiro.pathling.test.builders.ElementPathBuilder)5 ParserContextBuilder (au.csiro.pathling.test.builders.ParserContextBuilder)5 ArrayList (java.util.ArrayList)5