Search in sources :

Example 16 with NonLiteralPath

use of au.csiro.pathling.fhirpath.NonLiteralPath in project pathling by aehrc.

the class WhereFunctionTest method whereOnResource.

// This test simulates the execution of the where function on the path
// `Patient.reverseResolve(Encounter.subject).where($this.status = 'in-progress')`.
@Test
void whereOnResource() {
    final String statusColumn = randomAlias();
    final Dataset<Row> inputDataset = new DatasetBuilder(spark).withIdColumn().withEidColumn().withIdColumn().withColumn(statusColumn, DataTypes.StringType).withRow("patient-1", makeEid(1), "encounter-1", "in-progress").withRow("patient-1", makeEid(0), "encounter-2", "finished").withRow("patient-2", makeEid(0), "encounter-3", "in-progress").withRow("patient-3", makeEid(1), "encounter-4", "in-progress").withRow("patient-3", makeEid(0), "encounter-5", "finished").withRow("patient-4", makeEid(1), "encounter-6", "finished").withRow("patient-4", makeEid(0), "encounter-7", "finished").withRow("patient-5", makeEid(1), "encounter-8", "in-progress").withRow("patient-5", makeEid(0), "encounter-9", "in-progress").withRow("patient-6", null, null, null).build();
    final ResourcePath inputPath = new ResourcePathBuilder(spark).expression("reverseResolve(Encounter.subject)").dataset(inputDataset).idEidAndValueColumns().buildCustom();
    // Build an expression which represents the argument to the function. We assume that the value
    // column from the input dataset is also present within the argument dataset.
    final NonLiteralPath thisPath = inputPath.toThisPath();
    final Dataset<Row> argumentDataset = thisPath.getDataset().withColumn("value", thisPath.getDataset().col(statusColumn).equalTo("in-progress"));
    assertTrue(thisPath.getThisColumn().isPresent());
    final ElementPath argumentPath = new ElementPathBuilder(spark).fhirType(FHIRDefinedType.BOOLEAN).dataset(argumentDataset).idColumn(inputPath.getIdColumn()).valueColumn(argumentDataset.col("value")).thisColumn(thisPath.getThisColumn().get()).singular(true).build();
    // Prepare the input to the function.
    final ParserContext parserContext = new ParserContextBuilder(spark, fhirContext).build();
    final NamedFunctionInput whereInput = new NamedFunctionInput(parserContext, inputPath, Collections.singletonList(argumentPath));
    // Execute the function.
    final NamedFunction whereFunction = NamedFunction.getInstance("where");
    final FhirPath result = whereFunction.invoke(whereInput);
    // Check the result dataset.
    final Dataset<Row> expectedDataset = new DatasetBuilder(spark).withIdColumn().withEidColumn().withIdColumn().withRow("patient-1", makeEid(0), null).withRow("patient-1", makeEid(1), "patient-1").withRow("patient-2", makeEid(0), "patient-2").withRow("patient-3", makeEid(0), null).withRow("patient-3", makeEid(1), "patient-3").withRow("patient-4", makeEid(0), null).withRow("patient-4", makeEid(1), null).withRow("patient-5", makeEid(0), "patient-5").withRow("patient-5", makeEid(1), "patient-5").withRow("patient-6", null, null).build();
    assertThat(result).selectOrderedResultWithEid().hasRows(expectedDataset);
}
Also used : FhirPath(au.csiro.pathling.fhirpath.FhirPath) ParserContextBuilder(au.csiro.pathling.test.builders.ParserContextBuilder) ResourcePathBuilder(au.csiro.pathling.test.builders.ResourcePathBuilder) ResourcePath(au.csiro.pathling.fhirpath.ResourcePath) ElementPath(au.csiro.pathling.fhirpath.element.ElementPath) Row(org.apache.spark.sql.Row) DatasetBuilder(au.csiro.pathling.test.builders.DatasetBuilder) ParserContext(au.csiro.pathling.fhirpath.parser.ParserContext) NonLiteralPath(au.csiro.pathling.fhirpath.NonLiteralPath) ElementPathBuilder(au.csiro.pathling.test.builders.ElementPathBuilder) Test(org.junit.jupiter.api.Test) SpringBootTest(org.springframework.boot.test.context.SpringBootTest)

Example 17 with NonLiteralPath

use of au.csiro.pathling.fhirpath.NonLiteralPath in project pathling by aehrc.

the class WhereFunctionTest method whereOnElement.

@Test
void whereOnElement() {
    // Build an expression which represents the input to the function.
    final Dataset<Row> dataset = new DatasetBuilder(spark).withIdColumn().withEidColumn().withColumn(DataTypes.StringType).withRow("patient-1", makeEid(1), "en").withRow("patient-1", makeEid(0), "es").withRow("patient-2", makeEid(0), "de").withRow("patient-3", makeEid(2), "en").withRow("patient-3", makeEid(1), "en").withRow("patient-3", makeEid(0), "zh").withRow("patient-4", makeEid(1), "fr").withRow("patient-4", makeEid(0), "fr").withRow("patient-5", null, null).build();
    final ElementPath inputPath = new ElementPathBuilder(spark).fhirType(FHIRDefinedType.STRING).dataset(dataset).idAndEidAndValueColumns().singular(false).build();
    final NonLiteralPath thisPath = inputPath.toThisPath();
    // Build an expression which represents the argument to the function.
    final Dataset<Row> argumentDataset = thisPath.getDataset().withColumn("value", inputPath.getValueColumn().equalTo("en"));
    assertTrue(thisPath.getThisColumn().isPresent());
    final ElementPath argumentExpression = new ElementPathBuilder(spark).fhirType(FHIRDefinedType.BOOLEAN).dataset(argumentDataset).idColumn(inputPath.getIdColumn()).valueColumn(argumentDataset.col("value")).thisColumn(thisPath.getThisColumn().get()).singular(true).build();
    // Prepare the input to the function.
    final ParserContext parserContext = new ParserContextBuilder(spark, fhirContext).build();
    final NamedFunctionInput whereInput = new NamedFunctionInput(parserContext, inputPath, Collections.singletonList(argumentExpression));
    // Execute the function.
    final NamedFunction whereFunction = NamedFunction.getInstance("where");
    final FhirPath result = whereFunction.invoke(whereInput);
    // Check the result dataset.
    final Dataset<Row> expectedDataset = new DatasetBuilder(spark).withIdColumn().withEidColumn().withColumn(DataTypes.StringType).withRow("patient-1", makeEid(0), null).withRow("patient-1", makeEid(1), "en").withRow("patient-2", makeEid(0), null).withRow("patient-3", makeEid(0), null).withRow("patient-3", makeEid(1), "en").withRow("patient-3", makeEid(2), "en").withRow("patient-4", makeEid(0), null).withRow("patient-4", makeEid(1), null).withRow("patient-5", null, null).build();
    assertThat(result).selectOrderedResultWithEid().hasRows(expectedDataset);
}
Also used : ElementPath(au.csiro.pathling.fhirpath.element.ElementPath) FhirPath(au.csiro.pathling.fhirpath.FhirPath) ParserContextBuilder(au.csiro.pathling.test.builders.ParserContextBuilder) Row(org.apache.spark.sql.Row) DatasetBuilder(au.csiro.pathling.test.builders.DatasetBuilder) ParserContext(au.csiro.pathling.fhirpath.parser.ParserContext) NonLiteralPath(au.csiro.pathling.fhirpath.NonLiteralPath) ElementPathBuilder(au.csiro.pathling.test.builders.ElementPathBuilder) Test(org.junit.jupiter.api.Test) SpringBootTest(org.springframework.boot.test.context.SpringBootTest)

Example 18 with NonLiteralPath

use of au.csiro.pathling.fhirpath.NonLiteralPath in project pathling by aehrc.

the class QueryHelpers method join.

/**
 * Joins any number of {@link FhirPath} expressions, using equality between their respective
 * resource ID columns.
 *
 * @param parserContext the current {@link ParserContext}
 * @param fhirPaths a list of {@link FhirPath} expressions
 * @param joinType a {@link JoinType}
 * @return a new {@link Dataset}
 */
@Nonnull
public static Dataset<Row> join(@Nonnull final ParserContext parserContext, @Nonnull final List<FhirPath> fhirPaths, @Nonnull final JoinType joinType) {
    checkArgument(fhirPaths.size() > 1, "fhirPaths must contain more than one FhirPath");
    final FhirPath left = fhirPaths.get(0);
    final List<FhirPath> joinTargets = fhirPaths.subList(1, fhirPaths.size());
    // Only non-literal paths will trigger a join.
    final List<FhirPath> nonLiteralTargets = joinTargets.stream().filter(t -> t instanceof NonLiteralPath).collect(Collectors.toList());
    if (left instanceof NonLiteralPath && nonLiteralTargets.isEmpty()) {
        // to join.
        return left.getDataset();
    } else if (left instanceof LiteralPath && !nonLiteralTargets.isEmpty()) {
        // right without any need to join.
        return nonLiteralTargets.get(0).getDataset();
    }
    Dataset<Row> dataset = left.getDataset();
    final List<Column> groupingColumns = parserContext.getGroupingColumns();
    final Column idColumn = parserContext.getInputContext().getIdColumn();
    final List<Column> leftColumns = checkColumnsAndFallback(left.getDataset(), groupingColumns, idColumn);
    for (final FhirPath right : nonLiteralTargets) {
        final List<Column> resolvedGroupingColumns = checkColumnsAndFallback(right.getDataset(), leftColumns, idColumn);
        dataset = join(dataset, resolvedGroupingColumns, right.getDataset(), resolvedGroupingColumns, joinType);
    }
    return dataset;
}
Also used : Arrays(java.util.Arrays) Getter(lombok.Getter) Dataset(org.apache.spark.sql.Dataset) NonLiteralPath(au.csiro.pathling.fhirpath.NonLiteralPath) ResourceType(org.hl7.fhir.r4.model.Enumerations.ResourceType) ArrayList(java.util.ArrayList) Value(lombok.Value) HashSet(java.util.HashSet) LinkedHashMap(java.util.LinkedHashMap) Strings.randomAlias(au.csiro.pathling.utilities.Strings.randomAlias) FhirEncoders(au.csiro.pathling.encoders.FhirEncoders) IBaseResource(org.hl7.fhir.instance.model.api.IBaseResource) Map(java.util.Map) org.apache.spark.sql.functions.lit(org.apache.spark.sql.functions.lit) Strings(au.csiro.pathling.utilities.Strings) Nonnull(javax.annotation.Nonnull) SparkSession(org.apache.spark.sql.SparkSession) Column(org.apache.spark.sql.Column) Collection(java.util.Collection) Set(java.util.Set) Preconditions.checkArgument(au.csiro.pathling.utilities.Preconditions.checkArgument) Row(org.apache.spark.sql.Row) Collectors(java.util.stream.Collectors) ParserContext(au.csiro.pathling.fhirpath.parser.ParserContext) ExpressionEncoder(org.apache.spark.sql.catalyst.encoders.ExpressionEncoder) List(java.util.List) Stream(java.util.stream.Stream) LiteralPath(au.csiro.pathling.fhirpath.literal.LiteralPath) FhirPath(au.csiro.pathling.fhirpath.FhirPath) org.apache.spark.sql.functions.col(org.apache.spark.sql.functions.col) Optional(java.util.Optional) org.apache.spark.sql.functions(org.apache.spark.sql.functions) Comparator(java.util.Comparator) Collections(java.util.Collections) FhirPath(au.csiro.pathling.fhirpath.FhirPath) NonLiteralPath(au.csiro.pathling.fhirpath.NonLiteralPath) LiteralPath(au.csiro.pathling.fhirpath.literal.LiteralPath) Column(org.apache.spark.sql.Column) Row(org.apache.spark.sql.Row) NonLiteralPath(au.csiro.pathling.fhirpath.NonLiteralPath) Nonnull(javax.annotation.Nonnull)

Example 19 with NonLiteralPath

use of au.csiro.pathling.fhirpath.NonLiteralPath in project pathling by aehrc.

the class WhereFunctionTest method nullValuesAreNull.

@Test
void nullValuesAreNull() {
    // Build an expression which represents the input to the function.
    final Dataset<Row> dataset = new DatasetBuilder(spark).withIdColumn().withEidColumn().withColumn(DataTypes.StringType).withRow("patient-1", makeEid(0), "en").withRow("patient-1", makeEid(1), "es").withRow("patient-2", makeEid(0), "de").withRow("patient-3", makeEid(0), "en").withRow("patient-3", makeEid(1), "en").withRow("patient-3", makeEid(2), "zh").withRow("patient-4", makeEid(0), "ar").build();
    final ElementPath inputPath = new ElementPathBuilder(spark).fhirType(FHIRDefinedType.STRING).dataset(dataset).idAndEidAndValueColumns().singular(false).build();
    // Build an expression which represents the argument to the function.
    final NonLiteralPath thisPath = inputPath.toThisPath();
    final Dataset<Row> argumentDataset = thisPath.getDataset().withColumn("value", functions.when(inputPath.getValueColumn().equalTo("en"), null).otherwise(true));
    assertTrue(thisPath.getThisColumn().isPresent());
    final ElementPath argumentPath = new ElementPathBuilder(spark).fhirType(FHIRDefinedType.BOOLEAN).dataset(argumentDataset).idColumn(inputPath.getIdColumn()).valueColumn(argumentDataset.col("value")).thisColumn(thisPath.getThisColumn().get()).singular(true).build();
    // Prepare the input to the function.
    final ParserContext parserContext = new ParserContextBuilder(spark, fhirContext).build();
    final NamedFunctionInput whereInput = new NamedFunctionInput(parserContext, inputPath, Collections.singletonList(argumentPath));
    // Execute the function.
    final NamedFunction whereFunction = NamedFunction.getInstance("where");
    final FhirPath result = whereFunction.invoke(whereInput);
    // Check the result dataset.
    final Dataset<Row> expectedDataset = new DatasetBuilder(spark).withIdColumn().withEidColumn().withColumn(DataTypes.StringType).withRow("patient-1", makeEid(0), null).withRow("patient-1", makeEid(1), "es").withRow("patient-2", makeEid(0), "de").withRow("patient-3", makeEid(0), null).withRow("patient-3", makeEid(1), null).withRow("patient-3", makeEid(2), "zh").withRow("patient-4", makeEid(0), "ar").build();
    assertThat(result).selectOrderedResultWithEid().hasRows(expectedDataset);
}
Also used : ElementPath(au.csiro.pathling.fhirpath.element.ElementPath) FhirPath(au.csiro.pathling.fhirpath.FhirPath) ParserContextBuilder(au.csiro.pathling.test.builders.ParserContextBuilder) Row(org.apache.spark.sql.Row) DatasetBuilder(au.csiro.pathling.test.builders.DatasetBuilder) ParserContext(au.csiro.pathling.fhirpath.parser.ParserContext) NonLiteralPath(au.csiro.pathling.fhirpath.NonLiteralPath) ElementPathBuilder(au.csiro.pathling.test.builders.ElementPathBuilder) Test(org.junit.jupiter.api.Test) SpringBootTest(org.springframework.boot.test.context.SpringBootTest)

Example 20 with NonLiteralPath

use of au.csiro.pathling.fhirpath.NonLiteralPath in project pathling by aehrc.

the class IifFunctionTest method throwsErrorWithUntypedResourceAndLiteralResults.

@Test
void throwsErrorWithUntypedResourceAndLiteralResults() {
    final NonLiteralPath condition = new ElementPathBuilder(spark).fhirType(FHIRDefinedType.BOOLEAN).expression("valueBoolean").singular(true).build().toThisPath();
    final UntypedResourcePath ifTrue = new UntypedResourcePathBuilder(spark).expression("someUntypedResource").build();
    final StringLiteralPath otherwise = StringLiteralPath.fromString("foo", condition);
    final NamedFunctionInput iifInput = new NamedFunctionInput(parserContext, condition, Arrays.asList(condition, ifTrue, otherwise));
    final NamedFunction notFunction = NamedFunction.getInstance("iif");
    final InvalidUserInputError error = assertThrows(InvalidUserInputError.class, () -> notFunction.invoke(iifInput));
    assertEquals("Paths cannot be merged into a collection together: someUntypedResource, 'foo'", error.getMessage());
}
Also used : InvalidUserInputError(au.csiro.pathling.errors.InvalidUserInputError) StringLiteralPath(au.csiro.pathling.fhirpath.literal.StringLiteralPath) UntypedResourcePathBuilder(au.csiro.pathling.test.builders.UntypedResourcePathBuilder) NonLiteralPath(au.csiro.pathling.fhirpath.NonLiteralPath) UntypedResourcePath(au.csiro.pathling.fhirpath.UntypedResourcePath) ElementPathBuilder(au.csiro.pathling.test.builders.ElementPathBuilder) Test(org.junit.jupiter.api.Test) SpringBootTest(org.springframework.boot.test.context.SpringBootTest)

Aggregations

NonLiteralPath (au.csiro.pathling.fhirpath.NonLiteralPath)28 Nonnull (javax.annotation.Nonnull)16 Row (org.apache.spark.sql.Row)15 FhirPath (au.csiro.pathling.fhirpath.FhirPath)14 Column (org.apache.spark.sql.Column)14 ElementPathBuilder (au.csiro.pathling.test.builders.ElementPathBuilder)12 Test (org.junit.jupiter.api.Test)12 SpringBootTest (org.springframework.boot.test.context.SpringBootTest)12 ElementPath (au.csiro.pathling.fhirpath.element.ElementPath)9 ResourcePath (au.csiro.pathling.fhirpath.ResourcePath)7 InvalidUserInputError (au.csiro.pathling.errors.InvalidUserInputError)6 UntypedResourcePath (au.csiro.pathling.fhirpath.UntypedResourcePath)6 DatasetBuilder (au.csiro.pathling.test.builders.DatasetBuilder)6 ParserContextBuilder (au.csiro.pathling.test.builders.ParserContextBuilder)6 ResourcePathBuilder (au.csiro.pathling.test.builders.ResourcePathBuilder)6 UntypedResourcePathBuilder (au.csiro.pathling.test.builders.UntypedResourcePathBuilder)6 StringLiteralPath (au.csiro.pathling.fhirpath.literal.StringLiteralPath)5 ParserContext (au.csiro.pathling.fhirpath.parser.ParserContext)5 BooleanPath (au.csiro.pathling.fhirpath.element.BooleanPath)4 ResourceDatasetBuilder (au.csiro.pathling.test.builders.ResourceDatasetBuilder)3