Search in sources :

Example 1 with NamedFunction

use of au.csiro.pathling.fhirpath.function.NamedFunction in project pathling by aehrc.

the class SubsumesFunctionTest method throwsErrorIfArgumentTypeIsUnsupported.

@Test
void throwsErrorIfArgumentTypeIsUnsupported() {
    final ParserContext parserContext = new ParserContextBuilder(spark, fhirContext).terminologyClientFactory(mock(TerminologyServiceFactory.class)).build();
    final ElementPath input = new ElementPathBuilder(spark).fhirType(FHIRDefinedType.CODEABLECONCEPT).build();
    final StringLiteralPath argument = StringLiteralPath.fromString("'str'", input);
    final NamedFunctionInput functionInput = new NamedFunctionInput(parserContext, input, Collections.singletonList(argument));
    final NamedFunction subsumesFunction = NamedFunction.getInstance("subsumes");
    final InvalidUserInputError error = assertThrows(InvalidUserInputError.class, () -> subsumesFunction.invoke(functionInput));
    assertEquals("subsumes function accepts argument of type Coding or CodeableConcept", error.getMessage());
}
Also used : InvalidUserInputError(au.csiro.pathling.errors.InvalidUserInputError) ElementPath(au.csiro.pathling.fhirpath.element.ElementPath) StringLiteralPath(au.csiro.pathling.fhirpath.literal.StringLiteralPath) NamedFunctionInput(au.csiro.pathling.fhirpath.function.NamedFunctionInput) ParserContextBuilder(au.csiro.pathling.test.builders.ParserContextBuilder) NamedFunction(au.csiro.pathling.fhirpath.function.NamedFunction) ParserContext(au.csiro.pathling.fhirpath.parser.ParserContext) ElementPathBuilder(au.csiro.pathling.test.builders.ElementPathBuilder) Test(org.junit.jupiter.api.Test) SpringBootTest(org.springframework.boot.test.context.SpringBootTest)

Example 2 with NamedFunction

use of au.csiro.pathling.fhirpath.function.NamedFunction in project pathling by aehrc.

the class SubsumesFunctionTest method throwsErrorIfInputTypeIsUnsupported.

// 
// Test for various validation errors
// 
@Test
void throwsErrorIfInputTypeIsUnsupported() {
    final ParserContext parserContext = new ParserContextBuilder(spark, fhirContext).terminologyClientFactory(mock(TerminologyServiceFactory.class)).build();
    final ElementPath argument = new ElementPathBuilder(spark).fhirType(FHIRDefinedType.CODEABLECONCEPT).build();
    final ElementPath input = new ElementPathBuilder(spark).fhirType(FHIRDefinedType.STRING).build();
    final NamedFunctionInput functionInput = new NamedFunctionInput(parserContext, input, Collections.singletonList(argument));
    final NamedFunction subsumesFunction = NamedFunction.getInstance("subsumedBy");
    final InvalidUserInputError error = assertThrows(InvalidUserInputError.class, () -> subsumesFunction.invoke(functionInput));
    assertEquals("subsumedBy function accepts input of type Coding or CodeableConcept", error.getMessage());
}
Also used : InvalidUserInputError(au.csiro.pathling.errors.InvalidUserInputError) ElementPath(au.csiro.pathling.fhirpath.element.ElementPath) NamedFunctionInput(au.csiro.pathling.fhirpath.function.NamedFunctionInput) ParserContextBuilder(au.csiro.pathling.test.builders.ParserContextBuilder) NamedFunction(au.csiro.pathling.fhirpath.function.NamedFunction) ParserContext(au.csiro.pathling.fhirpath.parser.ParserContext) ElementPathBuilder(au.csiro.pathling.test.builders.ElementPathBuilder) Test(org.junit.jupiter.api.Test) SpringBootTest(org.springframework.boot.test.context.SpringBootTest)

Example 3 with NamedFunction

use of au.csiro.pathling.fhirpath.function.NamedFunction in project pathling by aehrc.

the class SubsumesFunctionTest method throwsErrorIfMoreThanOneArgument.

@Test
void throwsErrorIfMoreThanOneArgument() {
    final ParserContext parserContext = new ParserContextBuilder(spark, fhirContext).terminologyClientFactory(mock(TerminologyServiceFactory.class)).build();
    final ElementPath input = new ElementPathBuilder(spark).fhirType(FHIRDefinedType.CODEABLECONCEPT).build();
    final CodingLiteralPath argument1 = CodingLiteralPath.fromString(CODING_MEDIUM.getSystem() + "|" + CODING_MEDIUM.getCode(), input);
    final CodingLiteralPath argument2 = CodingLiteralPath.fromString(CODING_MEDIUM.getSystem() + "|" + CODING_MEDIUM.getCode(), input);
    final NamedFunctionInput functionInput = new NamedFunctionInput(parserContext, input, Arrays.asList(argument1, argument2));
    final NamedFunction subsumesFunction = NamedFunction.getInstance("subsumes");
    final InvalidUserInputError error = assertThrows(InvalidUserInputError.class, () -> subsumesFunction.invoke(functionInput));
    assertEquals("subsumes function accepts one argument of type Coding or CodeableConcept", error.getMessage());
}
Also used : InvalidUserInputError(au.csiro.pathling.errors.InvalidUserInputError) ElementPath(au.csiro.pathling.fhirpath.element.ElementPath) CodingLiteralPath(au.csiro.pathling.fhirpath.literal.CodingLiteralPath) NamedFunctionInput(au.csiro.pathling.fhirpath.function.NamedFunctionInput) ParserContextBuilder(au.csiro.pathling.test.builders.ParserContextBuilder) NamedFunction(au.csiro.pathling.fhirpath.function.NamedFunction) ParserContext(au.csiro.pathling.fhirpath.parser.ParserContext) ElementPathBuilder(au.csiro.pathling.test.builders.ElementPathBuilder) Test(org.junit.jupiter.api.Test) SpringBootTest(org.springframework.boot.test.context.SpringBootTest)

Example 4 with NamedFunction

use of au.csiro.pathling.fhirpath.function.NamedFunction in project pathling by aehrc.

the class InvocationVisitor method visitFunctionInvocation.

/**
 * This method gets called when a function call is on the right-hand side of an invocation
 * expression.
 *
 * @param ctx The {@link FunctionInvocationContext}
 * @return A {@link FhirPath} expression
 */
@Override
@Nonnull
public FhirPath visitFunctionInvocation(@Nullable final FunctionInvocationContext ctx) {
    @Nullable final String functionIdentifier = checkNotNull(ctx).function().identifier().getText();
    checkNotNull(functionIdentifier);
    final NamedFunction function = NamedFunction.getInstance(functionIdentifier);
    // If there is no invoker, we use either the input context or the this context, depending on
    // whether we are in the context of function arguments.
    final FhirPath input = invoker == null ? context.getThisContext().orElse(context.getInputContext()) : invoker;
    // A literal cannot be used as a function input.
    checkUserInput(input instanceof NonLiteralPath, "Literal expression cannot be used as input to a function invocation: " + input.getExpression());
    final NonLiteralPath nonLiteral = (NonLiteralPath) input;
    @Nullable final ParamListContext paramList = ctx.function().paramList();
    final List<FhirPath> arguments = new ArrayList<>();
    if (paramList != null) {
        // The `$this` path will be the same as the input, but with a different expression, and it
        // will be singular as it represents a single item.
        // NOTE: This works because for $this the context for aggregation grouping on elements
        // includes `id` and `this` columns.
        // Create and alias the $this column.
        final NonLiteralPath thisPath = nonLiteral.toThisPath();
        // If the this context has an element ID, we need to add this to the grouping columns so that
        // aggregations that occur within the arguments are in the context of an element. Otherwise,
        // we add the resource ID column to the groupings.
        final List<Column> argumentGroupings = new ArrayList<>(context.getGroupingColumns());
        thisPath.getEidColumn().ifPresentOrElse(argumentGroupings::add, () -> argumentGroupings.add(thisPath.getIdColumn()));
        // Create a new ParserContext, which includes information about how to evaluate the `$this`
        // expression.
        final ParserContext argumentContext = new ParserContext(context.getInputContext(), context.getFhirContext(), context.getSparkSession(), context.getDatabase(), context.getTerminologyServiceFactory(), argumentGroupings, context.getNodeIdColumns());
        argumentContext.setThisContext(thisPath);
        // Parse each of the expressions passed as arguments to the function.
        arguments.addAll(paramList.expression().stream().map(expression -> new Visitor(argumentContext).visit(expression)).collect(Collectors.toList()));
    }
    final NamedFunctionInput functionInput = new NamedFunctionInput(context, nonLiteral, arguments);
    return function.invoke(functionInput);
}
Also used : FhirPath(au.csiro.pathling.fhirpath.FhirPath) FhirPathBaseVisitor(au.csiro.pathling.fhirpath.parser.generated.FhirPathBaseVisitor) ArrayList(java.util.ArrayList) NamedFunction(au.csiro.pathling.fhirpath.function.NamedFunction) NamedFunctionInput(au.csiro.pathling.fhirpath.function.NamedFunctionInput) Column(org.apache.spark.sql.Column) ParamListContext(au.csiro.pathling.fhirpath.parser.generated.FhirPathParser.ParamListContext) NonLiteralPath(au.csiro.pathling.fhirpath.NonLiteralPath) Nullable(javax.annotation.Nullable) Nonnull(javax.annotation.Nonnull)

Aggregations

NamedFunction (au.csiro.pathling.fhirpath.function.NamedFunction)4 NamedFunctionInput (au.csiro.pathling.fhirpath.function.NamedFunctionInput)4 InvalidUserInputError (au.csiro.pathling.errors.InvalidUserInputError)3 ElementPath (au.csiro.pathling.fhirpath.element.ElementPath)3 ParserContext (au.csiro.pathling.fhirpath.parser.ParserContext)3 ElementPathBuilder (au.csiro.pathling.test.builders.ElementPathBuilder)3 ParserContextBuilder (au.csiro.pathling.test.builders.ParserContextBuilder)3 Test (org.junit.jupiter.api.Test)3 SpringBootTest (org.springframework.boot.test.context.SpringBootTest)3 FhirPath (au.csiro.pathling.fhirpath.FhirPath)1 NonLiteralPath (au.csiro.pathling.fhirpath.NonLiteralPath)1 CodingLiteralPath (au.csiro.pathling.fhirpath.literal.CodingLiteralPath)1 StringLiteralPath (au.csiro.pathling.fhirpath.literal.StringLiteralPath)1 FhirPathBaseVisitor (au.csiro.pathling.fhirpath.parser.generated.FhirPathBaseVisitor)1 ParamListContext (au.csiro.pathling.fhirpath.parser.generated.FhirPathParser.ParamListContext)1 ArrayList (java.util.ArrayList)1 Nonnull (javax.annotation.Nonnull)1 Nullable (javax.annotation.Nullable)1 Column (org.apache.spark.sql.Column)1