Repository: aehrc/pathling (language: python)

Issue:
Reference extension cannot be resolved
FHIRPath objects representing extensions of type Reference do not currently retain enough information to be successfully resolved. The following search query causes a 500:

https://go.pathling.app/search?subjectResource=List&filters%5B0%5D%5Blabel%5D=&filters%5B0%5D%5Bexpression%5D=subject.resolve%28%29.ofType%28Patient%29.id.exists%28%29&filters%5B1%5D%5Blabel%5D=&filters%5B1%5D%5Bexpression%5D=extension.valueReference.resolve%28%29.ofType%28EpisodeOfCare%29.id.exists%28%29


Discussion / hints:

Fix patch:
diff --git a/fhir-server/src/main/java/au/csiro/pathling/fhirpath/UntypedResourcePath.java b/fhir-server/src/main/java/au/csiro/pathling/fhirpath/UntypedResourcePath.java
index 1c113efe0d..af4d29b9e8 100644
--- a/fhir-server/src/main/java/au/csiro/pathling/fhirpath/UntypedResourcePath.java
+++ b/fhir-server/src/main/java/au/csiro/pathling/fhirpath/UntypedResourcePath.java
@@ -17,75 +17,47 @@
 
 package au.csiro.pathling.fhirpath;
 
-import static au.csiro.pathling.QueryHelpers.createColumn;
 import static au.csiro.pathling.QueryHelpers.createColumns;
-import static au.csiro.pathling.QueryHelpers.getUnionableColumns;
-import static au.csiro.pathling.utilities.Preconditions.checkArgument;
 
-import au.csiro.pathling.QueryHelpers.DatasetWithColumn;
 import au.csiro.pathling.QueryHelpers.DatasetWithColumnMap;
 import au.csiro.pathling.errors.InvalidUserInputError;
 import au.csiro.pathling.fhirpath.element.ElementDefinition;
 import au.csiro.pathling.fhirpath.element.ReferencePath;
-import java.util.Arrays;
-import java.util.List;
 import java.util.Optional;
 import javax.annotation.Nonnull;
-import lombok.Getter;
 import org.apache.spark.sql.Column;
 import org.apache.spark.sql.Dataset;
 import org.apache.spark.sql.Row;
-import org.jetbrains.annotations.NotNull;
+import org.hl7.fhir.r4.model.Enumerations.FHIRDefinedType;
 
 /**
  * Represents a path that is a collection of resources of more than one type.
  *
  * @author John Grimes
  */
-public class UntypedResourcePath extends NonLiteralPath implements Referrer {
+public class UntypedResourcePath extends ReferencePath {
 
-  /**
-   * A column within the dataset containing the resource type.
-   */
-  @Nonnull
-  @Getter
-  private final Column typeColumn;
-
-  private UntypedResourcePath(@Nonnull final String expression, @Nonnull final Dataset<Row> dataset,
+  public UntypedResourcePath(@Nonnull final String expression, @Nonnull final Dataset<Row> dataset,
       @Nonnull final Column idColumn, @Nonnull final Optional<Column> eidColumn,
       @Nonnull final Column valueColumn, final boolean singular,
-      @Nonnull final Optional<Column> thisColumn, @Nonnull final Column typeColumn) {
-    super(expression, dataset, idColumn, eidColumn, valueColumn, singular, Optional.empty(),
-        thisColumn);
-
-    checkArgument(Arrays.asList(dataset.columns()).contains(typeColumn.toString()),
-        "Type column not present in dataset");
-    this.typeColumn = typeColumn;
+      @Nonnull final Optional<ResourcePath> currentResource,
+      @Nonnull final Optional<Column> thisColumn, @Nonnull final FHIRDefinedType fhirType) {
+    super(expression, dataset, idColumn, eidColumn, valueColumn, singular, currentResource,
+        thisColumn, fhirType);
   }
 
   /**
    * @param referencePath a {@link ReferencePath} to base the new UntypedResourcePath on
    * @param expression the FHIRPath representation of this path
-   * @param dataset a {@link Dataset} that can be used to evaluate this path against data
-   * @param idColumn a column within the dataset containing the identity of the subject resource
-   * @param eidColumn a column within the dataset containing the element identities of the nodes
-   * @param typeColumn a column within the dataset containing the resource type
    * @return a shiny new UntypedResourcePath
    */
   @Nonnull
   public static UntypedResourcePath build(@Nonnull final ReferencePath referencePath,
-      @Nonnull final String expression, @Nonnull final Dataset<Row> dataset,
-      @Nonnull final Column idColumn, @Nonnull final Optional<Column> eidColumn,
-      @Nonnull final Column typeColumn) {
-
-    final Column valueColumn = referencePath.getValueColumn();
-    final DatasetWithColumn datasetWithType = createColumn(dataset, typeColumn);
-    final Dataset<Row> finalDataset = datasetWithType.getDataset();
-    final Column finalTypeColumn = datasetWithType.getColumn();
-
-    return new UntypedResourcePath(expression, finalDataset, idColumn, eidColumn, valueColumn,
-        referencePath.isSingular(), referencePath.getThisColumn(), finalTypeColumn
-    );
+      @Nonnull final String expression) {
+    return new UntypedResourcePath(expression, referencePath.getDataset(),
+        referencePath.getIdColumn(), referencePath.getEidColumn(), referencePath.getValueColumn(),
+        referencePath.isSingular(), referencePath.getCurrentResource(),
+        referencePath.getThisColumn(), referencePath.getFhirType());
   }
 
   @Nonnull
@@ -121,8 +93,8 @@ public UntypedResourcePath copy(@Nonnull final String expression,
         eidCol, valueColumn)).orElseGet(() -> createColumns(dataset, valueColumn));
 
     return new UntypedResourcePath(expression, datasetWithColumns.getDataset(), idColumn,
-        eidColumn.map(datasetWithColumns::getColumn),
-        datasetWithColumns.getColumn(valueColumn), singular, thisColumn, typeColumn);
+        eidColumn.map(datasetWithColumns::getColumn), datasetWithColumns.getColumn(valueColumn),
+        singular, currentResource, thisColumn, getFhirType());
   }
 
   @Override
@@ -141,12 +113,4 @@ public NonLiteralPath combineWith(@Nonnull final FhirPath target,
             .getExpression());
   }
 
-  @Nonnull
-  @Override
-  public Dataset<Row> getUnionableDataset(@NotNull final FhirPath target) {
-    final List<Column> selection = getUnionableColumns(this, target);
-    selection.add(getTypeColumn());
-    return getDataset().select(selection.toArray(new Column[]{}));
-  }
-
 }
diff --git a/fhir-server/src/main/java/au/csiro/pathling/fhirpath/element/ElementDefinition.java b/fhir-server/src/main/java/au/csiro/pathling/fhirpath/element/ElementDefinition.java
index c2672e4926..2e998c838e 100644
--- a/fhir-server/src/main/java/au/csiro/pathling/fhirpath/element/ElementDefinition.java
+++ b/fhir-server/src/main/java/au/csiro/pathling/fhirpath/element/ElementDefinition.java
@@ -20,6 +20,7 @@
 import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
 import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition;
 import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
+import ca.uhn.fhir.context.RuntimeChildAny;
 import ca.uhn.fhir.context.RuntimeChildResourceDefinition;
 import com.google.common.collect.ImmutableMap;
 import java.util.Collections;
@@ -91,7 +92,9 @@ protected ElementDefinition(@Nonnull final BaseRuntimeChildDefinition childDefin
   @Nonnull
   public static ElementDefinition build(@Nonnull final BaseRuntimeChildDefinition childDefinition,
       @Nonnull final String elementName) {
-    if (childDefinition instanceof RuntimeChildResourceDefinition) {
+    if (elementName.equals("valueReference") && childDefinition instanceof RuntimeChildAny) {
+      return new ReferenceExtensionDefinition(childDefinition, elementName);
+    } else if (childDefinition instanceof RuntimeChildResourceDefinition) {
       return new ReferenceDefinition((RuntimeChildResourceDefinition) childDefinition, elementName);
     } else {
       return new ElementDefinition(childDefinition, elementName);
diff --git a/fhir-server/src/main/java/au/csiro/pathling/fhirpath/element/ReferenceExtensionDefinition.java b/fhir-server/src/main/java/au/csiro/pathling/fhirpath/element/ReferenceExtensionDefinition.java
new file mode 100644
index 0000000000..c214616c25
--- /dev/null
+++ b/fhir-server/src/main/java/au/csiro/pathling/fhirpath/element/ReferenceExtensionDefinition.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2022 Commonwealth Scientific and Industrial Research
+ * Organisation (CSIRO) ABN 41 687 119 230.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package au.csiro.pathling.fhirpath.element;
+
+import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
+import java.util.Set;
+import javax.annotation.Nonnull;
+import org.hl7.fhir.r4.model.Enumerations.ResourceType;
+
+/**
+ * Encapsulates the FHIR definitions for a Reference-typed extension.
+ *
+ * @author John Grimes
+ */
+public class ReferenceExtensionDefinition extends ElementDefinition {
+
+  protected ReferenceExtensionDefinition(@Nonnull final BaseRuntimeChildDefinition childDefinition,
+      @Nonnull final String elementName) {
+    super(childDefinition, elementName);
+  }
+
+  @Override
+  @Nonnull
+  public Set<ResourceType> getReferenceTypes() {
+    // We always treat a reference extension as a reference to any resource, as we don't have enough 
+    // information to constrain it further.
+    return Set.of(ResourceType.RESOURCE);
+  }
+
+}
diff --git a/fhir-server/src/main/java/au/csiro/pathling/fhirpath/function/OfTypeFunction.java b/fhir-server/src/main/java/au/csiro/pathling/fhirpath/function/OfTypeFunction.java
index 79e9091949..bf73c30e67 100644
--- a/fhir-server/src/main/java/au/csiro/pathling/fhirpath/function/OfTypeFunction.java
+++ b/fhir-server/src/main/java/au/csiro/pathling/fhirpath/function/OfTypeFunction.java
@@ -17,18 +17,12 @@
 
 package au.csiro.pathling.fhirpath.function;
 
-import static au.csiro.pathling.QueryHelpers.join;
 import static au.csiro.pathling.utilities.Preconditions.checkUserInput;
 
-import au.csiro.pathling.QueryHelpers.JoinType;
 import au.csiro.pathling.fhirpath.FhirPath;
 import au.csiro.pathling.fhirpath.ResourcePath;
 import au.csiro.pathling.fhirpath.UntypedResourcePath;
-import java.util.Optional;
 import javax.annotation.Nonnull;
-import org.apache.spark.sql.Column;
-import org.apache.spark.sql.Dataset;
-import org.apache.spark.sql.Row;
 
 /**
  * A function filters items in the input collection to only those that are of the given type.
@@ -58,19 +52,9 @@ public FhirPath invoke(@Nonnull final NamedFunctionInput input) {
         "Argument to ofType function must be a resource type: " + argumentPath.getExpression());
     final ResourcePath resourcePath = (ResourcePath) argumentPath;
 
-    // Do a left outer join to the resource dataset using the reference in the untyped dataset - the
-    // result will be null in the rows that are not of the resource type nominated.
-    final Column joinCondition = inputPath.getResourceEquality(resourcePath);
-    final Dataset<Row> dataset = join(inputPath.getDataset(), resourcePath.getDataset(),
-        joinCondition, JoinType.LEFT_OUTER);
-
-    // Return a new resource path with the joined dataset, and the argument's value column.
-    final Optional<Column> thisColumn = inputPath.getThisColumn();
-    final ResourcePath result = resourcePath.copy(expression, dataset, inputPath.getIdColumn(),
-        inputPath.getEidColumn(), resourcePath.getValueColumn(), inputPath.isSingular(),
-        thisColumn);
-    result.setCurrentResource(resourcePath);
-    return result;
+    return ResolveFunction.resolveMonomorphicReference(inputPath, input.getContext().getDatabase(),
+        input.getContext().getFhirContext(), resourcePath.getResourceType(), expression,
+        input.getContext());
   }
 
 }
diff --git a/fhir-server/src/main/java/au/csiro/pathling/fhirpath/function/ResolveFunction.java b/fhir-server/src/main/java/au/csiro/pathling/fhirpath/function/ResolveFunction.java
index 869d3dd1eb..f5d4ca0f5c 100644
--- a/fhir-server/src/main/java/au/csiro/pathling/fhirpath/function/ResolveFunction.java
+++ b/fhir-server/src/main/java/au/csiro/pathling/fhirpath/function/ResolveFunction.java
@@ -18,14 +18,10 @@
 package au.csiro.pathling.fhirpath.function;
 
 import static au.csiro.pathling.QueryHelpers.join;
-import static au.csiro.pathling.QueryHelpers.union;
 import static au.csiro.pathling.fhirpath.function.NamedFunction.checkNoArguments;
 import static au.csiro.pathling.fhirpath.function.NamedFunction.expressionFromInput;
 import static au.csiro.pathling.utilities.Preconditions.check;
-import static au.csiro.pathling.utilities.Preconditions.checkNotNull;
 import static au.csiro.pathling.utilities.Preconditions.checkUserInput;
-import static au.csiro.pathling.utilities.Strings.randomAlias;
-import static org.apache.spark.sql.functions.lit;
 
 import au.csiro.pathling.QueryHelpers.JoinType;
 import au.csiro.pathling.fhir.FhirServer;
@@ -33,10 +29,9 @@
 import au.csiro.pathling.fhirpath.ResourcePath;
 import au.csiro.pathling.fhirpath.UntypedResourcePath;
 import au.csiro.pathling.fhirpath.element.ReferencePath;
+import au.csiro.pathling.fhirpath.parser.ParserContext;
 import au.csiro.pathling.io.Database;
 import ca.uhn.fhir.context.FhirContext;
-import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Optional;
 import java.util.Set;
 import javax.annotation.Nonnull;
@@ -82,72 +77,23 @@ public FhirPath invoke(@Nonnull final NamedFunctionInput input) {
     final String expression = expressionFromInput(input, NAME);
 
     if (isPolymorphic) {
-      return resolvePolymorphicReference(input, database, referenceTypes, expression);
+      final ReferencePath referencePath = (ReferencePath) input.getInput();
+      return UntypedResourcePath.build(referencePath, expression);
     } else {
       final FhirContext fhirContext = input.getContext().getFhirContext();
-      return resolveMonomorphicReference(input, database, fhirContext, referenceTypes,
-          expression);
+      final ResourceType resourceType = (ResourceType) referenceTypes.toArray()[0];
+      return resolveMonomorphicReference(inputPath, database, fhirContext, resourceType, expression,
+          input.getContext());
     }
   }
 
   @Nonnull
-  private static FhirPath resolvePolymorphicReference(@Nonnull final NamedFunctionInput input,
-      @Nonnull final Database database,
-      @Nonnull final Iterable<ResourceType> referenceTypes, final String expression) {
-    final ReferencePath referencePath = (ReferencePath) input.getInput();
-
-    // If this is a polymorphic reference, create a dataset for each reference type, and union
-    // them together to produce the target dataset. The dataset will not contain the resources
-    // themselves, only a type and identifier for later resolution.
-    final Collection<Dataset<Row>> typeDatasets = new ArrayList<>();
-    for (final ResourceType referenceType : referenceTypes) {
-      if (FhirServer.supportedResourceTypes().contains(referenceType)) {
-        // We can't include the full content of the resource, as you can't union two datasets with
-        // different schema. The content of the resource is added later, when ofType is invoked.
-        final Dataset<Row> typeDatasetWithColumns = database.read(referenceType);
-        final Column idColumn = typeDatasetWithColumns.col("id");
-        Dataset<Row> typeDataset = typeDatasetWithColumns
-            .withColumn("type", lit(referenceType.toCode()));
-        typeDataset = typeDataset.select(idColumn, typeDataset.col("type"));
-
-        typeDatasets.add(typeDataset);
-      }
-    }
-    checkUserInput(!typeDatasets.isEmpty(),
-        "No types within reference are available, cannot resolve: " + referencePath
-            .getExpression());
-    final String idColumnName = randomAlias();
-    final String targetColumnName = randomAlias();
-    Dataset<Row> targetDataset = union(typeDatasets);
-    Column targetId = targetDataset.col(targetDataset.columns()[0]);
-    Column targetType = targetDataset.col(targetDataset.columns()[1]);
-    targetDataset = targetDataset
-        .withColumn(idColumnName, targetId)
-        .withColumn(targetColumnName, targetType);
-    targetId = targetDataset.col(idColumnName);
-    targetType = targetDataset.col(targetColumnName);
-    targetDataset = targetDataset.select(targetId, targetType);
-
-    checkNotNull(targetId);
-    final Column joinCondition = referencePath.getResourceEquality(targetId, targetType);
-    final Dataset<Row> dataset = join(referencePath.getDataset(), targetDataset, joinCondition,
-        JoinType.LEFT_OUTER);
-
-    final Column inputId = referencePath.getIdColumn();
-    final Optional<Column> inputEid = referencePath.getEidColumn();
-    return UntypedResourcePath
-        .build(referencePath, expression, dataset, inputId, inputEid, targetType);
-  }
-
-  @Nonnull
-  private FhirPath resolveMonomorphicReference(@Nonnull final NamedFunctionInput input,
+  public static FhirPath resolveMonomorphicReference(@Nonnull final ReferencePath referencePath,
       @Nonnull final Database database, @Nonnull final FhirContext fhirContext,
-      @Nonnull final Collection<ResourceType> referenceTypes, final String expression) {
-    final ReferencePath referencePath = (ReferencePath) input.getInput();
-
+      @Nonnull final ResourceType resourceType, @Nonnull final String expression,
+      @Nonnull final ParserContext context) {
     // If this is a monomorphic reference, we just need to retrieve the appropriate table and
     // create a dataset with the full resources.
-    final ResourceType resourceType = (ResourceType) referenceTypes.toArray()[0];
     final ResourcePath resourcePath = ResourcePath
         .build(fhirContext, database, resourceType, expression, referencePath.isSingular());
 
@@ -161,7 +107,7 @@ private FhirPath resolveMonomorphicReference(@Nonnull final NamedFunctionInput i
 
     // We need to add the resource ID column to the parser context so that it can be used within
     // joins in certain situations, e.g. extract.
-    input.getContext().getNodeIdColumns()
+    context.getNodeIdColumns()
         .putIfAbsent(expression, resourcePath.getElementColumn("id"));
 
     final ResourcePath result = resourcePath.copy(expression, dataset, inputId, inputEid,


Test patch:
diff --git a/fhir-server/src/test/java/au/csiro/pathling/aggregate/AggregateExecutorTest.java b/fhir-server/src/test/java/au/csiro/pathling/aggregate/AggregateExecutorTest.java
index f4a2c52fa7..413926f507 100644
--- a/fhir-server/src/test/java/au/csiro/pathling/aggregate/AggregateExecutorTest.java
+++ b/fhir-server/src/test/java/au/csiro/pathling/aggregate/AggregateExecutorTest.java
@@ -127,8 +127,4 @@ void mockResource(final ResourceType... resourceTypes) {
     TestHelpers.mockResource(database, spark, resourceTypes);
   }
 
-  void mockEmptyResource(final ResourceType... resourceType) {
-    TestHelpers.mockEmptyResource(database, spark, fhirEncoders, resourceType);
-  }
-
 }
diff --git a/fhir-server/src/test/java/au/csiro/pathling/aggregate/AggregateQueryTest.java b/fhir-server/src/test/java/au/csiro/pathling/aggregate/AggregateQueryTest.java
index f13a361b3f..805676d035 100644
--- a/fhir-server/src/test/java/au/csiro/pathling/aggregate/AggregateQueryTest.java
+++ b/fhir-server/src/test/java/au/csiro/pathling/aggregate/AggregateQueryTest.java
@@ -172,7 +172,6 @@ void queryWithResolve() {
   void queryWithPolymorphicResolve() {
     subjectResource = ResourceType.DIAGNOSTICREPORT;
     mockResource(subjectResource, ResourceType.PATIENT);
-    mockEmptyResource(ResourceType.GROUP, ResourceType.DEVICE, ResourceType.LOCATION);
 
     final AggregateRequest request = new AggregateRequestBuilder(subjectResource)
         .withAggregation("count()")
diff --git a/fhir-server/src/test/java/au/csiro/pathling/extract/ExtractQueryTest.java b/fhir-server/src/test/java/au/csiro/pathling/extract/ExtractQueryTest.java
index 17e4708311..2d3c18893b 100644
--- a/fhir-server/src/test/java/au/csiro/pathling/extract/ExtractQueryTest.java
+++ b/fhir-server/src/test/java/au/csiro/pathling/extract/ExtractQueryTest.java
@@ -18,7 +18,6 @@
 package au.csiro.pathling.extract;
 
 import static au.csiro.pathling.test.assertions.Assertions.assertThat;
-import static au.csiro.pathling.test.helpers.TestHelpers.mockEmptyResource;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.mockito.Mockito.mock;
@@ -26,9 +25,9 @@
 import au.csiro.pathling.config.Configuration;
 import au.csiro.pathling.encoders.FhirEncoders;
 import au.csiro.pathling.errors.InvalidUserInputError;
-import au.csiro.pathling.terminology.TerminologyServiceFactory;
 import au.csiro.pathling.io.Database;
 import au.csiro.pathling.io.ResultWriter;
+import au.csiro.pathling.terminology.TerminologyServiceFactory;
 import au.csiro.pathling.test.SharedMocks;
 import au.csiro.pathling.test.TimingExtension;
 import au.csiro.pathling.test.helpers.TestHelpers;
@@ -147,8 +146,6 @@ void multipleReverseResolves() {
   void multiplePolymorphicResolves() {
     subjectResource = ResourceType.DIAGNOSTICREPORT;
     mockResource(ResourceType.DIAGNOSTICREPORT, ResourceType.PATIENT);
-    mockEmptyResource(database, spark, fhirEncoders, ResourceType.GROUP, ResourceType.DEVICE,
-        ResourceType.LOCATION);
 
     final ExtractRequest request = new ExtractRequestBuilder(subjectResource)
         .withColumn("id")
diff --git a/fhir-server/src/test/java/au/csiro/pathling/fhirpath/CanBeCombinedWithTest.java b/fhir-server/src/test/java/au/csiro/pathling/fhirpath/CanBeCombinedWithTest.java
index aa2054e8cb..1bf7f3f494 100644
--- a/fhir-server/src/test/java/au/csiro/pathling/fhirpath/CanBeCombinedWithTest.java
+++ b/fhir-server/src/test/java/au/csiro/pathling/fhirpath/CanBeCombinedWithTest.java
@@ -20,6 +20,7 @@
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
 import au.csiro.pathling.fhirpath.element.ElementPath;
+import au.csiro.pathling.fhirpath.element.ReferencePath;
 import au.csiro.pathling.fhirpath.literal.BooleanLiteralPath;
 import au.csiro.pathling.fhirpath.literal.CodingLiteralPath;
 import au.csiro.pathling.fhirpath.literal.DateLiteralPath;
@@ -31,7 +32,6 @@
 import au.csiro.pathling.fhirpath.literal.TimeLiteralPath;
 import au.csiro.pathling.test.builders.ElementPathBuilder;
 import au.csiro.pathling.test.builders.ResourcePathBuilder;
-import au.csiro.pathling.test.builders.UntypedResourcePathBuilder;
 import java.text.ParseException;
 import java.util.Arrays;
 import java.util.Collection;
@@ -69,7 +69,7 @@ class CanBeCombinedWithTest {
   final ElementPath dateTimePath;
   final ElementPath decimalPath;
   final ElementPath integerPath;
-  final ElementPath referencePath;
+  final ReferencePath referencePath;
   final ElementPath stringPath;
   final ElementPath timePath;
 
@@ -89,8 +89,6 @@ class CanBeCombinedWithTest {
   CanBeCombinedWithTest(@Nonnull final SparkSession spark) throws ParseException {
     resourcePath = new ResourcePathBuilder(spark)
         .build();
-    untypedResourcePath = new UntypedResourcePathBuilder(spark)
-        .build();
 
     booleanPath = new ElementPathBuilder(spark)
         .fhirType(FHIRDefinedType.BOOLEAN)
@@ -110,9 +108,10 @@ class CanBeCombinedWithTest {
     integerPath = new ElementPathBuilder(spark)
         .fhirType(FHIRDefinedType.INTEGER)
         .build();
-    referencePath = new ElementPathBuilder(spark)
+    referencePath = (ReferencePath) new ElementPathBuilder(spark)
         .fhirType(FHIRDefinedType.REFERENCE)
         .build();
+    untypedResourcePath = UntypedResourcePath.build(referencePath, referencePath.getExpression());
     stringPath = new ElementPathBuilder(spark)
         .fhirType(FHIRDefinedType.STRING)
         .build();
diff --git a/fhir-server/src/test/java/au/csiro/pathling/fhirpath/function/OfTypeFunctionTest.java b/fhir-server/src/test/java/au/csiro/pathling/fhirpath/function/OfTypeFunctionTest.java
index 577e955658..293cd37475 100644
--- a/fhir-server/src/test/java/au/csiro/pathling/fhirpath/function/OfTypeFunctionTest.java
+++ b/fhir-server/src/test/java/au/csiro/pathling/fhirpath/function/OfTypeFunctionTest.java
@@ -23,6 +23,7 @@
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
@@ -78,28 +79,20 @@ void resolvesPolymorphicReference() {
     final Dataset<Row> inputDataset = new DatasetBuilder(spark)
         .withIdColumn()
         .withEidColumn()
-        .withTypeColumn()
         .withStructTypeColumns(referenceStructType())
-        .withRow("encounter-1", makeEid(1), "Patient",
-            RowFactory.create(null, "Patient/patient-1", null))
-        .withRow("encounter-1", makeEid(0), "Patient",
-            RowFactory.create(null, "Patient/patient-2", null))
-        .withRow("encounter-2", makeEid(0), "Patient",
-            RowFactory.create(null, "Patient/patient-3", null))
-        .withRow("encounter-2", makeEid(1), "Group",
-            RowFactory.create(null, "Group/group-1", null))
-        .withRow("encounter-3", makeEid(0), "Patient",
-            RowFactory.create(null, "Patient/patient-2", null))
-        .withRow("encounter-4", makeEid(0), "Patient",
-            RowFactory.create(null, "Patient/patient-2", null))
-        .withRow("encounter-5", makeEid(0), "Group",
-            RowFactory.create(null, "Group/group-1", null))
-        .withRow("encounter-6", null, null, null)
+        .withRow("encounter-1", makeEid(1), RowFactory.create(null, "Patient/patient-1", null))
+        .withRow("encounter-1", makeEid(0), RowFactory.create(null, "Patient/patient-2", null))
+        .withRow("encounter-2", makeEid(0), RowFactory.create(null, "Patient/patient-3", null))
+        .withRow("encounter-2", makeEid(1), RowFactory.create(null, "Group/group-1", null))
+        .withRow("encounter-3", makeEid(0), RowFactory.create(null, "Patient/patient-2", null))
+        .withRow("encounter-4", makeEid(0), RowFactory.create(null, "Patient/patient-2", null))
+        .withRow("encounter-5", makeEid(0), RowFactory.create(null, "Group/group-1", null))
+        .withRow("encounter-6", null, null)
         .buildWithStructValue();
     final UntypedResourcePath inputPath = new UntypedResourcePathBuilder(spark)
         .expression("subject.resolve()")
         .dataset(inputDataset)
-        .idEidTypeAndValueColumns()
+        .idEidAndValueColumns()
         .singular(false)
         .build();
 
@@ -111,7 +104,7 @@ void resolvesPolymorphicReference() {
         .withRow("patient-2", "female", false)
         .withRow("patient-3", "male", true)
         .build();
-    when(database.read(ResourceType.PATIENT))
+    when(database.read(eq(ResourceType.PATIENT)))
         .thenReturn(argumentDataset);
     final ResourcePath argumentPath = new ResourcePathBuilder(spark)
         .database(database)
@@ -121,6 +114,7 @@ void resolvesPolymorphicReference() {
 
     final ParserContext parserContext = new ParserContextBuilder(spark, fhirContext)
         .idColumn(inputPath.getIdColumn())
+        .database(database)
         .build();
     final NamedFunctionInput ofTypeInput = new NamedFunctionInput(parserContext, inputPath,
         Collections.singletonList(argumentPath));
diff --git a/fhir-server/src/test/java/au/csiro/pathling/fhirpath/function/ResolveFunctionTest.java b/fhir-server/src/test/java/au/csiro/pathling/fhirpath/function/ResolveFunctionTest.java
index a71498da1a..eb3d68911e 100644
--- a/fhir-server/src/test/java/au/csiro/pathling/fhirpath/function/ResolveFunctionTest.java
+++ b/fhir-server/src/test/java/au/csiro/pathling/fhirpath/function/ResolveFunctionTest.java
@@ -189,22 +189,21 @@ void polymorphicResolve() {
     final FhirPath result = invokeResolve(resolveInput);
 
     assertTrue(result instanceof UntypedResourcePath);
-    assertThat((UntypedResourcePath) result)
+    assertThat(result)
         .hasExpression("Encounter.subject.resolve()")
         .isSingular();
 
     final Dataset<Row> expectedDataset = new DatasetBuilder(spark)
         .withIdColumn()
-        .withTypeColumn()
         .withStructTypeColumns(referenceStructType())
-        .withRow("encounter-1", "Patient", RowFactory.create(null, "Patient/patient-1", null))
-        .withRow("encounter-2", "Patient", RowFactory.create(null, "Patient/patient-3", null))
-        .withRow("encounter-3", "Patient", RowFactory.create(null, "Patient/patient-2", null))
-        .withRow("encounter-4", "Patient", RowFactory.create(null, "Patient/patient-2", null))
-        .withRow("encounter-5", "Group", RowFactory.create(null, "Group/group-1", null))
+        .withRow("encounter-1", RowFactory.create(null, "Patient/patient-1", null))
+        .withRow("encounter-2", RowFactory.create(null, "Patient/patient-3", null))
+        .withRow("encounter-3", RowFactory.create(null, "Patient/patient-2", null))
+        .withRow("encounter-4", RowFactory.create(null, "Patient/patient-2", null))
+        .withRow("encounter-5", RowFactory.create(null, "Group/group-1", null))
         .buildWithStructValue();
-    assertThat((UntypedResourcePath) result)
-        .selectUntypedResourceResult()
+    assertThat(result)
+        .selectResult()
         .hasRows(expectedDataset);
   }
 
@@ -254,21 +253,19 @@ void polymorphicResolveAnyType() {
     final FhirPath result = invokeResolve(resolveInput);
 
     assertTrue(result instanceof UntypedResourcePath);
-    assertThat((UntypedResourcePath) result)
+    assertThat(result)
         .hasExpression("Condition.evidence.detail.resolve()")
         .isNotSingular();
 
     final Dataset<Row> expectedDataset = new DatasetBuilder(spark)
         .withIdColumn()
-        .withTypeColumn()
         .withStructTypeColumns(referenceStructType())
-        .withRow("condition-1", "Observation",
-            RowFactory.create(null, "Observation/observation-1", null))
-        .withRow("condition-2", "ClinicalImpression",
+        .withRow("condition-1", RowFactory.create(null, "Observation/observation-1", null))
+        .withRow("condition-2",
             RowFactory.create(null, "ClinicalImpression/clinicalimpression-1", null))
         .buildWithStructValue();
-    assertThat((UntypedResourcePath) result)
-        .selectUntypedResourceResult()
+    assertThat(result)
+        .selectResult()
         .hasRows(expectedDataset);
   }
 
diff --git a/fhir-server/src/test/java/au/csiro/pathling/fhirpath/function/terminology/DesignationFunctionTest.java b/fhir-server/src/test/java/au/csiro/pathling/fhirpath/function/terminology/DesignationFunctionTest.java
index 26fef77a76..81ee7c7544 100644
--- a/fhir-server/src/test/java/au/csiro/pathling/fhirpath/function/terminology/DesignationFunctionTest.java
+++ b/fhir-server/src/test/java/au/csiro/pathling/fhirpath/function/terminology/DesignationFunctionTest.java
@@ -37,7 +37,6 @@
 import au.csiro.pathling.fhirpath.literal.CodingLiteral;
 import au.csiro.pathling.fhirpath.literal.CodingLiteralPath;
 import au.csiro.pathling.fhirpath.literal.IntegerLiteralPath;
-import au.csiro.pathling.fhirpath.literal.LiteralPath;
 import au.csiro.pathling.fhirpath.literal.StringLiteralPath;
 import au.csiro.pathling.fhirpath.parser.ParserContext;
 import au.csiro.pathling.terminology.TerminologyService2;
@@ -63,7 +62,6 @@
 import org.apache.spark.sql.types.DataTypes;
 import org.hl7.fhir.r4.model.Coding;
 import org.hl7.fhir.r4.model.Enumerations.FHIRDefinedType;
-import org.hl7.fhir.r4.model.Type;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Tag;
 import org.junit.jupiter.api.Test;
@@ -220,7 +218,7 @@ public void designationWithDefaultLanguage() {
     checkDesignationsOfCoding(Optional.of(CODING_D), Optional.empty(),
         expectedResult);
   }
-  
+
   @Test
   public void designationWithDefaultLanguageAndUse() {
 
@@ -240,7 +238,7 @@ public void designationWithDefaultLanguageAndUse() {
     checkDesignationsOfCoding(Optional.empty(), Optional.empty(),
         expectedResult);
   }
-  
+
   @Test
   void throwsErrorIfInputTypeIsUnsupported() {
     final FhirPath mockContext = new ElementPathBuilder(spark).build();
diff --git a/fhir-server/src/test/java/au/csiro/pathling/fhirpath/operator/QuantityOperatorsPrecisionTest.java b/fhir-server/src/test/java/au/csiro/pathling/fhirpath/operator/QuantityOperatorsPrecisionTest.java
index 6e5028c9f9..9283385399 100644
--- a/fhir-server/src/test/java/au/csiro/pathling/fhirpath/operator/QuantityOperatorsPrecisionTest.java
+++ b/fhir-server/src/test/java/au/csiro/pathling/fhirpath/operator/QuantityOperatorsPrecisionTest.java
@@ -42,7 +42,6 @@
 import org.fhir.ucum.Prefix;
 import org.fhir.ucum.UcumService;
 import org.hl7.fhir.r4.model.Enumerations.FHIRDefinedType;
-import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Tag;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -86,7 +85,7 @@ public class QuantityOperatorsPrecisionTest {
       "Zmol",
       "Emol", "Pmol", "Tmol");
 
-  
+
   @Nonnull
   private static String unitToRowId(@Nonnull final String unit) {
     return "unit-" + unit;
diff --git a/fhir-server/src/test/java/au/csiro/pathling/fhirpath/parser/DateTimeArithmeticParserTest.java b/fhir-server/src/test/java/au/csiro/pathling/fhirpath/parser/DateTimeArithmeticParserTest.java
index dea6ffaded..d80817a44e 100644
--- a/fhir-server/src/test/java/au/csiro/pathling/fhirpath/parser/DateTimeArithmeticParserTest.java
+++ b/fhir-server/src/test/java/au/csiro/pathling/fhirpath/parser/DateTimeArithmeticParserTest.java
@@ -17,8 +17,6 @@
 
 package au.csiro.pathling.fhirpath.parser;
 
-import static au.csiro.pathling.test.helpers.TestHelpers.mockEmptyResource;
-
 import au.csiro.pathling.fhirpath.ResourcePath;
 import au.csiro.pathling.fhirpath.element.BooleanPath;
 import au.csiro.pathling.test.builders.ParserContextBuilder;
@@ -41,8 +39,6 @@ void lengthOfEncounter() {
         .build();
     parser = new Parser(parserContext);
 
-    mockEmptyResource(database, spark, fhirEncoders, ResourceType.GROUP);
-
     assertThatResultOf("(period.start + 20 minutes) > period.end")
         .isElementPath(BooleanPath.class)
         .selectResult()
@@ -62,8 +58,6 @@ void ageAtTimeOfEncounter() {
         .build();
     parser = new Parser(parserContext);
 
-    mockEmptyResource(database, spark, fhirEncoders, ResourceType.GROUP);
-
     assertThatResultOf("period.start > (subject.resolve().ofType(Patient).birthDate + 60 years)")
         .isElementPath(BooleanPath.class)
         .selectResult()
diff --git a/fhir-server/src/test/java/au/csiro/pathling/fhirpath/parser/ParserTest.java b/fhir-server/src/test/java/au/csiro/pathling/fhirpath/parser/ParserTest.java
index c2cce7499d..cb283a6c80 100644
--- a/fhir-server/src/test/java/au/csiro/pathling/fhirpath/parser/ParserTest.java
+++ b/fhir-server/src/test/java/au/csiro/pathling/fhirpath/parser/ParserTest.java
@@ -34,7 +34,6 @@
 import static au.csiro.pathling.test.helpers.TerminologyHelpers.HL7_USE_DISPLAY;
 import static au.csiro.pathling.test.helpers.TerminologyHelpers.mockCoding;
 import static au.csiro.pathling.test.helpers.TerminologyServiceHelpers.setupSubsumes;
-import static au.csiro.pathling.test.helpers.TestHelpers.mockEmptyResource;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
 import au.csiro.pathling.errors.InvalidUserInputError;
@@ -459,7 +458,6 @@ void testIfFunctionWithComplexTypeResult() {
 
   @Test
   void testIfFunctionWithUntypedResourceResult() {
-    mockEmptyResource(database, spark, fhirEncoders, ResourceType.RELATEDPERSON);
     assertThatResultOf(
         "iif(gender = 'male', link.where(type = 'replaced-by').other.resolve(), "
             + "link.where(type = 'replaces').other.resolve()).ofType(Patient).gender")
@@ -518,7 +516,7 @@ void testPropertyFunctionWithCodingType() {
 
   @Test
   void testDesignationFunctionWithLanguage() {
-    
+
     setupMockPropertiesFor_195662009_444814009();
     assertThatResultOf(ResourceType.CONDITION,
         "code.coding.designation(http://snomed.info/sct|900000000000003001, 'en')")
@@ -614,8 +612,6 @@ void testCombineOperatorWithTwoLiterals() {
 
   @Test
   void testCombineOperatorWithTwoUntypedResourcePaths() {
-    mockEmptyResource(database, spark, fhirEncoders, ResourceType.GROUP,
-        ResourceType.DEVICE, ResourceType.LOCATION);
     assertThatResultOf(
         "(reverseResolve(Condition.subject).subject.resolve() combine "
             + "reverseResolve(DiagnosticReport.subject).subject.resolve()).ofType(Patient)")
@@ -692,7 +688,6 @@ void testNestedExtensions() {
 
   @Test
   void testExtensionsCurrentResource() {
-    mockEmptyResource(database, spark, fhirEncoders, ResourceType.GROUP);
     assertThatResultOf(ResourceType.CONDITION,
         "subject.resolve().ofType(Patient).extension.url")
         .isElementPath(StringPath.class)
@@ -756,9 +751,6 @@ void testReverseResolveFollowingMonomorphicResolve() {
   @Test
   void testReverseResolveFollowingPolymorphicResolve() {
     setSubjectResource(ResourceType.ENCOUNTER);
-
-    mockEmptyResource(database, spark, fhirEncoders, ResourceType.GROUP);
-
     assertThatResultOf(
         "subject.resolve().ofType(Patient).reverseResolve(Encounter.subject).id "
             + "contains '2aff9edd-def2-487a-b435-a162e11a303c'")
@@ -787,7 +779,6 @@ void testIifWithNullLiteral() {
   @Test
   void testUntilFunction() {
     setSubjectResource(ResourceType.ENCOUNTER);
-    mockEmptyResource(database, spark, fhirEncoders, ResourceType.GROUP);
     assertThatResultOf(
         "subject.resolve().ofType(Patient).birthDate.until(%resource.period.start, 'years')")
         .isElementPath(IntegerPath.class)
@@ -854,4 +845,26 @@ void testTraversalToUnsupportedReferenceChild() {
     assertEquals("No such child: " + expression, error.getMessage());
   }
 
+  @Test
+  void testResolutionOfExtensionReference() {
+    mockResource(ResourceType.PATIENT, ResourceType.ENCOUNTER, ResourceType.GOAL);
+    assertThatResultOf(
+        "reverseResolve(Encounter.subject).extension.where(url = 'urn:test:associated-goal')"
+            + ".valueReference.resolve().ofType(Goal).description.text")
+        .isElementPath(StringPath.class)
+        .selectResult()
+        .hasRows(spark, "responses/ParserTest/testResolutionOfExtensionReference.csv");
+  }
+
+  @Test
+  void testResolutionOfExtensionReferenceWithWrongType() {
+    mockResource(ResourceType.PATIENT, ResourceType.ENCOUNTER, ResourceType.GOAL);
+    assertThatResultOf(
+        "reverseResolve(Encounter.subject).extension.where(url = 'urn:test:associated-goal')"
+            + ".valueReference.resolve().ofType(Condition).id")
+        .isElementPath(StringPath.class)
+        .selectResult()
+        .hasRows(spark, "responses/ParserTest/testResolutionOfExtensionReferenceWithWrongType.csv");
+  }
+
 }
diff --git a/fhir-server/src/test/java/au/csiro/pathling/test/assertions/Assertions.java b/fhir-server/src/test/java/au/csiro/pathling/test/assertions/Assertions.java
index d519b98d5d..102946b2a2 100644
--- a/fhir-server/src/test/java/au/csiro/pathling/test/assertions/Assertions.java
+++ b/fhir-server/src/test/java/au/csiro/pathling/test/assertions/Assertions.java
@@ -18,11 +18,9 @@
 package au.csiro.pathling.test.assertions;
 
 import static au.csiro.pathling.test.TestResources.getResourceAsUrl;
-import static org.junit.jupiter.api.Assertions.fail;
 
 import au.csiro.pathling.fhirpath.FhirPath;
 import au.csiro.pathling.fhirpath.ResourcePath;
-import au.csiro.pathling.fhirpath.UntypedResourcePath;
 import au.csiro.pathling.fhirpath.element.ElementPath;
 import java.net.URL;
 import java.net.URLDecoder;
@@ -53,12 +51,6 @@ public static ElementPathAssertion assertThat(@Nonnull final ElementPath fhirPat
     return new ElementPathAssertion(fhirPath);
   }
 
-  @Nonnull
-  public static UntypedResourcePathAssertion assertThat(
-      @Nonnull final UntypedResourcePath fhirPath) {
-    return new UntypedResourcePathAssertion(fhirPath);
-  }
-
   @Nonnull
   public static DatasetAssert assertThat(@Nonnull final Dataset<Row> rowDataset) {
     return new DatasetAssert(rowDataset);
diff --git a/fhir-server/src/test/java/au/csiro/pathling/test/assertions/UntypedResourcePathAssertion.java b/fhir-server/src/test/java/au/csiro/pathling/test/assertions/UntypedResourcePathAssertion.java
deleted file mode 100644
index d66e2aab81..0000000000
--- a/fhir-server/src/test/java/au/csiro/pathling/test/assertions/UntypedResourcePathAssertion.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2022 Commonwealth Scientific and Industrial Research
- * Organisation (CSIRO) ABN 41 687 119 230.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package au.csiro.pathling.test.assertions;
-
-import au.csiro.pathling.fhirpath.UntypedResourcePath;
-import java.util.Arrays;
-import javax.annotation.Nonnull;
-import org.apache.spark.sql.Column;
-
-/**
- * @author John Grimes
- */
-@SuppressWarnings("UnusedReturnValue")
-public class UntypedResourcePathAssertion extends
-    BaseFhirPathAssertion<UntypedResourcePathAssertion> {
-
-  @Nonnull
-  private final UntypedResourcePath fhirPath;
-
-  UntypedResourcePathAssertion(@Nonnull final UntypedResourcePath fhirPath) {
-    super(fhirPath);
-    this.fhirPath = fhirPath;
-  }
-
-  @Nonnull
-  public DatasetAssert selectUntypedResourceResult() {
-    final Column[] selection = Arrays
-        .asList(fhirPath.getIdColumn(), fhirPath.getTypeColumn(), fhirPath.getValueColumn())
-        .toArray(new Column[0]);
-    return new DatasetAssert(fhirPath.getOrderedDataset()
-        .select(selection)
-        .orderBy(selection));
-  }
-
-}
diff --git a/fhir-server/src/test/java/au/csiro/pathling/test/benchmark/SearchDevBenchmark.java b/fhir-server/src/test/java/au/csiro/pathling/test/benchmark/SearchDevBenchmark.java
new file mode 100644
index 0000000000..92cb7a3eb2
--- /dev/null
+++ b/fhir-server/src/test/java/au/csiro/pathling/test/benchmark/SearchDevBenchmark.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2022 Commonwealth Scientific and Industrial Research
+ * Organisation (CSIRO) ABN 41 687 119 230.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package au.csiro.pathling.test.benchmark;
+
+import au.csiro.pathling.config.Configuration;
+import au.csiro.pathling.encoders.FhirEncoders;
+import au.csiro.pathling.io.Database;
+import au.csiro.pathling.jmh.AbstractJmhSpringBootState;
+import au.csiro.pathling.search.SearchExecutor;
+import au.csiro.pathling.terminology.TerminologyServiceFactory;
+import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.parser.IParser;
+import ca.uhn.fhir.rest.api.server.IBundleProvider;
+import ca.uhn.fhir.rest.param.StringAndListParam;
+import ca.uhn.fhir.rest.param.StringParam;
+import java.util.List;
+import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+import javax.annotation.Nonnull;
+import org.apache.spark.sql.SparkSession;
+import org.hl7.fhir.instance.model.api.IBaseResource;
+import org.hl7.fhir.r4.model.Enumerations.ResourceType;
+import org.junit.jupiter.api.Tag;
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Fork;
+import org.openjdk.jmh.annotations.Measurement;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.OutputTimeUnit;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.Warmup;
+import org.openjdk.jmh.infra.Blackhole;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+import org.springframework.stereotype.Component;
+import org.springframework.test.context.ActiveProfiles;
+
+@BenchmarkMode(Mode.AverageTime)
+@OutputTimeUnit(TimeUnit.MILLISECONDS)
+@Tag("UnitTest")
+@Fork(0)
+@Warmup(iterations = 1)
+@Measurement(iterations = 5)
+public class SearchDevBenchmark {
+
+  public static final int PAGE_SIZE = 10;
+
+  @Component
+  @State(Scope.Benchmark)
+  @ActiveProfiles("unit-test")
+  public static class SearchState extends AbstractJmhSpringBootState {
+
+    @Autowired
+    SparkSession spark;
+
+    @Autowired
+    TerminologyServiceFactory terminologyServiceFactory;
+
+    @Autowired
+    Configuration configuration;
+
+    @Autowired
+    FhirContext fhirContext;
+
+    @Autowired
+    IParser jsonParser;
+
+    @Autowired
+    FhirEncoders fhirEncoders;
+
+    @Autowired
+    Database database;
+
+    @Bean
+    @ConditionalOnMissingBean
+    public static Database database(@Nonnull final Configuration configuration,
+        @Nonnull final SparkSession spark, @Nonnull final FhirEncoders fhirEncoders,
+        @Nonnull final ThreadPoolTaskExecutor executor) {
+      return new Database(configuration, spark, fhirEncoders, executor);
+    }
+
+    public List<IBaseResource> execute(@Nonnull final Optional<StringAndListParam> filters) {
+      final IBundleProvider executor = new SearchExecutor(configuration, fhirContext, spark,
+          database, Optional.of(terminologyServiceFactory), fhirEncoders, ResourceType.ENCOUNTER,
+          filters);
+      executor.size();
+      return executor.getResources(0, PAGE_SIZE);
+    }
+  }
+
+  @Benchmark
+  public void referenceExtension_Benchmark(final Blackhole bh, final SearchState executor) {
+    final StringAndListParam filters = new StringAndListParam()
+        .addAnd(new StringParam(
+            "extension.where(url = 'urn:test:associated-goal').valueReference"
+                + ".resolve().ofType(Goal).exists()"));
+    bh.consume(executor.execute(Optional.of(filters)));
+  }
+
+}
diff --git a/fhir-server/src/test/java/au/csiro/pathling/test/builders/DatasetBuilder.java b/fhir-server/src/test/java/au/csiro/pathling/test/builders/DatasetBuilder.java
index c13004638d..42def182e3 100644
--- a/fhir-server/src/test/java/au/csiro/pathling/test/builders/DatasetBuilder.java
+++ b/fhir-server/src/test/java/au/csiro/pathling/test/builders/DatasetBuilder.java
@@ -106,11 +106,6 @@ public DatasetBuilder withIdColumn(@Nonnull final String alias) {
     return withColumn(alias, DataTypes.StringType);
   }
 
-  @Nonnull
-  public DatasetBuilder withTypeColumn() {
-    return withColumn(DataTypes.StringType);
-  }
-
   @Nonnull
   public DatasetBuilder withFidColumn() {
     return withColumn("_fid", DataTypes.IntegerType);
@@ -260,9 +255,9 @@ public static List<Integer> makeEid(final Integer... levels) {
     return Arrays.asList(levels);
   }
 
-  @Nonnull 
-  public static  DatasetBuilder of(@Nonnull final SparkSession spark) {
+  @Nonnull
+  public static DatasetBuilder of(@Nonnull final SparkSession spark) {
     return new DatasetBuilder(spark);
   }
-  
+
 }
diff --git a/fhir-server/src/test/java/au/csiro/pathling/test/builders/UntypedResourcePathBuilder.java b/fhir-server/src/test/java/au/csiro/pathling/test/builders/UntypedResourcePathBuilder.java
index 5bf0964fde..288383fc8b 100644
--- a/fhir-server/src/test/java/au/csiro/pathling/test/builders/UntypedResourcePathBuilder.java
+++ b/fhir-server/src/test/java/au/csiro/pathling/test/builders/UntypedResourcePathBuilder.java
@@ -32,6 +32,7 @@
 import org.apache.spark.sql.SparkSession;
 import org.apache.spark.sql.functions;
 import org.apache.spark.sql.types.DataTypes;
+import org.hl7.fhir.r4.model.Enumerations.FHIRDefinedType;
 
 /**
  * @author John Grimes
@@ -58,37 +59,30 @@ public class UntypedResourcePathBuilder {
   @Nullable
   private Column thisColumn;
 
-  @Nonnull
-  private Column typeColumn;
-
   public UntypedResourcePathBuilder(@Nonnull final SparkSession spark) {
     expression = "";
     eidColumn = Optional.empty();
     dataset = new DatasetBuilder(spark)
         .withIdColumn()
         .withColumn(DataTypes.StringType)
-        .withColumn(DataTypes.StringType)
         .build();
     idColumn = col(dataset.columns()[0]);
     valueColumn = col(dataset.columns()[1]);
-    typeColumn = col(dataset.columns()[2]);
     singular = false;
   }
 
   @Nonnull
-  public UntypedResourcePathBuilder idTypeAndValueColumns() {
+  public UntypedResourcePathBuilder idAndValueColumns() {
     idColumn = functions.col(dataset.columns()[0]);
-    typeColumn = functions.col(dataset.columns()[1]);
-    valueColumn = functions.col(dataset.columns()[2]);
+    valueColumn = functions.col(dataset.columns()[1]);
     return this;
   }
 
   @Nonnull
-  public UntypedResourcePathBuilder idEidTypeAndValueColumns() {
+  public UntypedResourcePathBuilder idEidAndValueColumns() {
     idColumn = functions.col(dataset.columns()[0]);
     eidColumn = Optional.of(functions.col(dataset.columns()[1]));
-    typeColumn = functions.col(dataset.columns()[2]);
-    valueColumn = functions.col(dataset.columns()[3]);
+    valueColumn = functions.col(dataset.columns()[2]);
     return this;
   }
 
@@ -122,21 +116,18 @@ public UntypedResourcePathBuilder thisColumn(@Nonnull final Column thisColumn) {
     return this;
   }
 
-  @Nonnull
-  public UntypedResourcePathBuilder typeColumn(@Nonnull final Column typeColumn) {
-    this.typeColumn = typeColumn;
-    return this;
-  }
-
   @Nonnull
   public UntypedResourcePath build() {
     final ReferencePath referencePath = mock(ReferencePath.class);
+    when(referencePath.getIdColumn()).thenReturn(idColumn);
+    when(referencePath.getEidColumn()).thenReturn(eidColumn);
     when(referencePath.getValueColumn()).thenReturn(valueColumn);
+    when(referencePath.getDataset()).thenReturn(dataset);
     when(referencePath.isSingular()).thenReturn(singular);
+    when(referencePath.getCurrentResource()).thenReturn(Optional.empty());
     when(referencePath.getThisColumn()).thenReturn(Optional.ofNullable(thisColumn));
-    return UntypedResourcePath
-        .build(referencePath, expression, dataset, idColumn, eidColumn,
-            typeColumn);
+    when(referencePath.getFhirType()).thenReturn(FHIRDefinedType.REFERENCE);
+    return UntypedResourcePath.build(referencePath, expression);
   }
 
 }
diff --git a/fhir-server/src/test/java/au/csiro/pathling/test/helpers/TestHelpers.java b/fhir-server/src/test/java/au/csiro/pathling/test/helpers/TestHelpers.java
index 4c6a5b8e39..adf5e6f898 100644
--- a/fhir-server/src/test/java/au/csiro/pathling/test/helpers/TestHelpers.java
+++ b/fhir-server/src/test/java/au/csiro/pathling/test/helpers/TestHelpers.java
@@ -63,7 +63,7 @@ public static void mockCachedResource(@Nonnull final Database database,
       when(database.read(resourceType)).thenReturn(dataset);
     }
   }
-  
+
   public static void mockResource(@Nonnull final Database database,
       @Nonnull final SparkSession spark, final int numPartitions,
       @Nonnull final ResourceType... resourceTypes) {
@@ -81,16 +81,6 @@ public static void mockResource(@Nonnull final Database database,
     when(database.read(resourceType)).thenReturn(dataset);
   }
 
-  public static void mockEmptyResource(@Nonnull final Database database,
-      @Nonnull final SparkSession spark, @Nonnull final FhirEncoders fhirEncoders,
-      @Nonnull final ResourceType... resourceTypes) {
-    for (final ResourceType resourceType : resourceTypes) {
-      final Dataset<Row> dataset = QueryHelpers.createEmptyDataset(spark, fhirEncoders,
-          resourceType);
-      when(database.read(resourceType)).thenReturn(dataset);
-    }
-  }
-
   public static void mockAllEmptyResources(@Nonnull final Database database,
       @Nonnull final SparkSession spark, @Nonnull final FhirEncoders fhirEncoders) {
     final Set<ResourceType> resourceTypes = FhirServer.supportedResourceTypes();
diff --git a/fhir-server/src/test/resources/responses/ParserTest/testResolutionOfExtensionReference.csv b/fhir-server/src/test/resources/responses/ParserTest/testResolutionOfExtensionReference.csv
new file mode 100644
index 0000000000..9bd1b08b0c
--- /dev/null
+++ b/fhir-server/src/test/resources/responses/ParserTest/testResolutionOfExtensionReference.csv
@@ -0,0 +1,217 @@
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+2b36c1e2-bbe1-45ae-8124-4adad2677702,
+2b36c1e2-bbe1-45ae-8124-4adad2677702,
+2b36c1e2-bbe1-45ae-8124-4adad2677702,
+2b36c1e2-bbe1-45ae-8124-4adad2677702,
+2b36c1e2-bbe1-45ae-8124-4adad2677702,
+2b36c1e2-bbe1-45ae-8124-4adad2677702,
+2b36c1e2-bbe1-45ae-8124-4adad2677702,
+2b36c1e2-bbe1-45ae-8124-4adad2677702,
+2b36c1e2-bbe1-45ae-8124-4adad2677702,
+2b36c1e2-bbe1-45ae-8124-4adad2677702,
+2b36c1e2-bbe1-45ae-8124-4adad2677702,
+2b36c1e2-bbe1-45ae-8124-4adad2677702,
+7001ad9c-34d2-4eb5-8165-5fdc2147f469,
+7001ad9c-34d2-4eb5-8165-5fdc2147f469,
+7001ad9c-34d2-4eb5-8165-5fdc2147f469,
+7001ad9c-34d2-4eb5-8165-5fdc2147f469,
+7001ad9c-34d2-4eb5-8165-5fdc2147f469,
+7001ad9c-34d2-4eb5-8165-5fdc2147f469,
+7001ad9c-34d2-4eb5-8165-5fdc2147f469,
+7001ad9c-34d2-4eb5-8165-5fdc2147f469,
+7001ad9c-34d2-4eb5-8165-5fdc2147f469,
+7001ad9c-34d2-4eb5-8165-5fdc2147f469,
+7001ad9c-34d2-4eb5-8165-5fdc2147f469,
+7001ad9c-34d2-4eb5-8165-5fdc2147f469,
+7001ad9c-34d2-4eb5-8165-5fdc2147f469,
+7001ad9c-34d2-4eb5-8165-5fdc2147f469,
+7001ad9c-34d2-4eb5-8165-5fdc2147f469,
+7001ad9c-34d2-4eb5-8165-5fdc2147f469,
+7001ad9c-34d2-4eb5-8165-5fdc2147f469,
+8ee183e2-b3c0-4151-be94-b945d6aa8c6d,
+8ee183e2-b3c0-4151-be94-b945d6aa8c6d,
+8ee183e2-b3c0-4151-be94-b945d6aa8c6d,
+8ee183e2-b3c0-4151-be94-b945d6aa8c6d,
+8ee183e2-b3c0-4151-be94-b945d6aa8c6d,
+8ee183e2-b3c0-4151-be94-b945d6aa8c6d,
+8ee183e2-b3c0-4151-be94-b945d6aa8c6d,
+8ee183e2-b3c0-4151-be94-b945d6aa8c6d,Hemoglobin A1c total in Blood < 7.0
+8ee183e2-b3c0-4151-be94-b945d6aa8c6d,
+8ee183e2-b3c0-4151-be94-b945d6aa8c6d,
+8ee183e2-b3c0-4151-be94-b945d6aa8c6d,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+beff242e-580b-47c0-9844-c1a68c36c5bf,
+beff242e-580b-47c0-9844-c1a68c36c5bf,
+beff242e-580b-47c0-9844-c1a68c36c5bf,
+beff242e-580b-47c0-9844-c1a68c36c5bf,
+beff242e-580b-47c0-9844-c1a68c36c5bf,
+beff242e-580b-47c0-9844-c1a68c36c5bf,
+beff242e-580b-47c0-9844-c1a68c36c5bf,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
diff --git a/fhir-server/src/test/resources/responses/ParserTest/testResolutionOfExtensionReferenceWithWrongType.csv b/fhir-server/src/test/resources/responses/ParserTest/testResolutionOfExtensionReferenceWithWrongType.csv
new file mode 100644
index 0000000000..799e0d7cfd
--- /dev/null
+++ b/fhir-server/src/test/resources/responses/ParserTest/testResolutionOfExtensionReferenceWithWrongType.csv
@@ -0,0 +1,217 @@
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+121503c8-9564-4b48-9086-a22df717948e,
+2b36c1e2-bbe1-45ae-8124-4adad2677702,
+2b36c1e2-bbe1-45ae-8124-4adad2677702,
+2b36c1e2-bbe1-45ae-8124-4adad2677702,
+2b36c1e2-bbe1-45ae-8124-4adad2677702,
+2b36c1e2-bbe1-45ae-8124-4adad2677702,
+2b36c1e2-bbe1-45ae-8124-4adad2677702,
+2b36c1e2-bbe1-45ae-8124-4adad2677702,
+2b36c1e2-bbe1-45ae-8124-4adad2677702,
+2b36c1e2-bbe1-45ae-8124-4adad2677702,
+2b36c1e2-bbe1-45ae-8124-4adad2677702,
+2b36c1e2-bbe1-45ae-8124-4adad2677702,
+2b36c1e2-bbe1-45ae-8124-4adad2677702,
+7001ad9c-34d2-4eb5-8165-5fdc2147f469,
+7001ad9c-34d2-4eb5-8165-5fdc2147f469,
+7001ad9c-34d2-4eb5-8165-5fdc2147f469,
+7001ad9c-34d2-4eb5-8165-5fdc2147f469,
+7001ad9c-34d2-4eb5-8165-5fdc2147f469,
+7001ad9c-34d2-4eb5-8165-5fdc2147f469,
+7001ad9c-34d2-4eb5-8165-5fdc2147f469,
+7001ad9c-34d2-4eb5-8165-5fdc2147f469,
+7001ad9c-34d2-4eb5-8165-5fdc2147f469,
+7001ad9c-34d2-4eb5-8165-5fdc2147f469,
+7001ad9c-34d2-4eb5-8165-5fdc2147f469,
+7001ad9c-34d2-4eb5-8165-5fdc2147f469,
+7001ad9c-34d2-4eb5-8165-5fdc2147f469,
+7001ad9c-34d2-4eb5-8165-5fdc2147f469,
+7001ad9c-34d2-4eb5-8165-5fdc2147f469,
+7001ad9c-34d2-4eb5-8165-5fdc2147f469,
+7001ad9c-34d2-4eb5-8165-5fdc2147f469,
+8ee183e2-b3c0-4151-be94-b945d6aa8c6d,
+8ee183e2-b3c0-4151-be94-b945d6aa8c6d,
+8ee183e2-b3c0-4151-be94-b945d6aa8c6d,
+8ee183e2-b3c0-4151-be94-b945d6aa8c6d,
+8ee183e2-b3c0-4151-be94-b945d6aa8c6d,
+8ee183e2-b3c0-4151-be94-b945d6aa8c6d,
+8ee183e2-b3c0-4151-be94-b945d6aa8c6d,
+8ee183e2-b3c0-4151-be94-b945d6aa8c6d,
+8ee183e2-b3c0-4151-be94-b945d6aa8c6d,
+8ee183e2-b3c0-4151-be94-b945d6aa8c6d,
+8ee183e2-b3c0-4151-be94-b945d6aa8c6d,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+9360820c-8602-4335-8b50-c88d627a0c20,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+a7eb2ce7-1075-426c-addd-957b861b0e55,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+bbd33563-70d9-4f6d-a79a-dd1fc55f5ad9,
+beff242e-580b-47c0-9844-c1a68c36c5bf,
+beff242e-580b-47c0-9844-c1a68c36c5bf,
+beff242e-580b-47c0-9844-c1a68c36c5bf,
+beff242e-580b-47c0-9844-c1a68c36c5bf,
+beff242e-580b-47c0-9844-c1a68c36c5bf,
+beff242e-580b-47c0-9844-c1a68c36c5bf,
+beff242e-580b-47c0-9844-c1a68c36c5bf,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
+e62e52ae-2d75-4070-a0ae-3cc78d35ed08,
diff --git a/fhir-server/src/test/resources/test-data/fhir/Encounter.ndjson b/fhir-server/src/test/resources/test-data/fhir/Encounter.ndjson
index 2b1878ab53..80e4a5d9fc 100644
--- a/fhir-server/src/test/resources/test-data/fhir/Encounter.ndjson
+++ b/fhir-server/src/test/resources/test-data/fhir/Encounter.ndjson
@@ -1,4 +1,4 @@
-{"resourceType":"Encounter","id":"2aff9edd-def2-487a-b435-a162e11a303c","status":"finished","class":{"system":"http://terminology.hl7.org/CodeSystem/v3-ActCode","code":"AMB"},"type":[{"coding":[{"system":"http://snomed.info/sct","code":"185349003","display":"Encounter for check up (procedure)"}],"text":"Encounter for check up (procedure)"}],"subject":{"reference":"Patient/8ee183e2-b3c0-4151-be94-b945d6aa8c6d"},"participant":[{"individual":{"reference":"Practitioner/0000016c-ffcb-bcdf-0000-0000000000aa"}}],"period":{"start":"1982-03-07T09:24:41+00:00","end":"2016-02-07T09:24:41+00:00"},"serviceProvider":{"reference":"Organization/a0b6ec0c-e587-3b2a-bf9f-248849f29ee5"}}
+{"resourceType":"Encounter","id":"2aff9edd-def2-487a-b435-a162e11a303c","status":"finished","class":{"system":"http://terminology.hl7.org/CodeSystem/v3-ActCode","code":"AMB"},"type":[{"coding":[{"system":"http://snomed.info/sct","code":"185349003","display":"Encounter for check up (procedure)"}],"text":"Encounter for check up (procedure)"}],"subject":{"reference":"Patient/8ee183e2-b3c0-4151-be94-b945d6aa8c6d"},"participant":[{"individual":{"reference":"Practitioner/0000016c-ffcb-bcdf-0000-0000000000aa"}}],"period":{"start":"1982-03-07T09:24:41+00:00","end":"2016-02-07T09:24:41+00:00"},"serviceProvider":{"reference":"Organization/a0b6ec0c-e587-3b2a-bf9f-248849f29ee5"},"extension":[{"url":"urn:test:associated-goal","valueReference":{"reference":"Goal/c879c300-7fdf-4b53-aa6a-a2b4a266b30c"}}]}
 {"resourceType":"Encounter","id":"b00df815-7528-4967-bfe2-311130d91c21","status":"finished","class":{"system":"http://terminology.hl7.org/CodeSystem/v3-ActCode","code":"AMB"},"type":[{"coding":[{"system":"http://snomed.info/sct","code":"185345009","display":"Encounter for symptom"}],"text":"Encounter for symptom"}],"subject":{"reference":"Patient/beff242e-580b-47c0-9844-c1a68c36c5bf"},"participant":[{"individual":{"reference":"Practitioner/0000016c-ffcb-bcdf-0000-00000000010e"}}],"period":{"start":"2010-06-19T18:35:39+00:00","end":"2010-06-19T18:50:39+00:00"},"reasonCode":[{"coding":[{"system":"http://snomed.info/sct","code":"444814009","display":"Viral sinusitis (disorder)"}]}],"serviceProvider":{"reference":"Organization/d692e283-0833-3201-8e55-4f868a9c0736"}}
 {"resourceType":"Encounter","id":"836b2e59-fb97-4014-ab0c-d5a5dc750969","status":"finished","class":{"system":"http://terminology.hl7.org/CodeSystem/v3-ActCode","code":"AMB"},"type":[{"coding":[{"system":"http://snomed.info/sct","code":"185347001","display":"Encounter for problem"}],"text":"Encounter for problem"}],"subject":{"reference":"Patient/e62e52ae-2d75-4070-a0ae-3cc78d35ed08"},"participant":[{"individual":{"reference":"Practitioner/0000016c-ffcb-bcdf-0000-000000000258"}}],"period":{"start":"1960-03-25T09:11:55+00:00","end":"1960-03-25T09:26:55+00:00"},"serviceProvider":{"reference":"Organization/d7b11827-25f2-350b-bcd8-939fc59851b0"}}
 {"resourceType":"Encounter","id":"39efc9b8-a75f-43a3-98a2-5bdc1c8207d2","status":"finished","class":{"system":"http://terminology.hl7.org/CodeSystem/v3-ActCode","code":"AMB"},"type":[{"coding":[{"system":"http://snomed.info/sct","code":"410620009","display":"Well child visit (procedure)"}],"text":"Well child visit (procedure)"}],"subject":{"reference":"Patient/2b36c1e2-bbe1-45ae-8124-4adad2677702"},"participant":[{"individual":{"reference":"Practitioner/0000016c-ffcb-bcdf-0000-00000000be96"}}],"period":{"start":"2010-01-09T19:04:32+00:00","end":"2010-01-09T19:19:32+00:00"},"serviceProvider":{"reference":"Organization/4afe828b-d23e-3b89-afa4-f2fa00720415"}}
diff --git a/fhir-server/src/test/resources/test-data/fhir/Goal.ndjson b/fhir-server/src/test/resources/test-data/fhir/Goal.ndjson
index 695ace48c6..6f621966dd 100644
--- a/fhir-server/src/test/resources/test-data/fhir/Goal.ndjson
+++ b/fhir-server/src/test/resources/test-data/fhir/Goal.ndjson
@@ -1,4 +1,4 @@
-{"resourceType":"Goal","id":"01210ad4-56e9-4e8d-ab50-d014b07f725a","lifecycleStatus":"accepted","achievementStatus":{"coding":[{"system":"http://terminology.hl7.org/CodeSystem/goal-achievement","code":"in-progress"}]},"description":{"text":"Hemoglobin A1c total in Blood < 7.0"},"subject":{"reference":"Patient/8ee183e2-b3c0-4151-be94-b945d6aa8c6d"}}
+{"resourceType":"Goal","id":"c879c300-7fdf-4b53-aa6a-a2b4a266b30c","lifecycleStatus":"accepted","achievementStatus":{"coding":[{"system":"http://terminology.hl7.org/CodeSystem/goal-achievement","code":"in-progress"}]},"description":{"text":"Hemoglobin A1c total in Blood < 7.0"},"subject":{"reference":"Patient/8ee183e2-b3c0-4151-be94-b945d6aa8c6d"}}
 {"resourceType":"Goal","id":"77508ad8-9b28-4295-9c23-e523f404e642","lifecycleStatus":"accepted","achievementStatus":{"coding":[{"system":"http://terminology.hl7.org/CodeSystem/goal-achievement","code":"in-progress"}]},"description":{"text":"Hemoglobin A1c total in Blood < 7.0"},"subject":{"reference":"Patient/e62e52ae-2d75-4070-a0ae-3cc78d35ed08"}}
 {"resourceType":"Goal","id":"ecf0117e-8516-4a6a-9a71-25b3e046edfe","lifecycleStatus":"accepted","achievementStatus":{"coding":[{"system":"http://terminology.hl7.org/CodeSystem/goal-achievement","code":"in-progress"}]},"description":{"text":"Glucose [Mass/volume] in Blood < 108"},"subject":{"reference":"Patient/8ee183e2-b3c0-4151-be94-b945d6aa8c6d"}}
 {"resourceType":"Goal","id":"298032f7-f544-4468-bf4a-8c13cc8564a8","lifecycleStatus":"accepted","achievementStatus":{"coding":[{"system":"http://terminology.hl7.org/CodeSystem/goal-achievement","code":"in-progress"}]},"description":{"text":"Glucose [Mass/volume] in Blood < 108"},"subject":{"reference":"Patient/e62e52ae-2d75-4070-a0ae-3cc78d35ed08"}}