Skip to content

Commit

Permalink
FHIRPath: Better handle codes that are represented as enumeration in …
Browse files Browse the repository at this point in the history
…FHIR protos.

PiperOrigin-RevId: 368690656
  • Loading branch information
aaronnash authored and Cameron Tew committed May 11, 2021
1 parent 8161839 commit 2c18c16
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 10 deletions.
4 changes: 4 additions & 0 deletions cc/google/fhir/fhir_path/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ cc_library(
":fhir_path_types",
":utils",
"//cc/google/fhir:annotations",
"//cc/google/fhir:codes",
"//cc/google/fhir:fhir_types",
"//cc/google/fhir:primitive_handler",
"//cc/google/fhir:proto_util",
"//cc/google/fhir:util",
Expand Down Expand Up @@ -150,6 +152,7 @@ cc_library(
visibility = [":__pkg__"],
deps = [
"//cc/google/fhir:annotations",
"//cc/google/fhir:fhir_types",
"//cc/google/fhir/status:statusor",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/status:statusor",
Expand Down Expand Up @@ -278,6 +281,7 @@ cc_test(
"//cc/google/fhir:util",
"//proto/google/fhir/proto/r4/core:datatypes_cc_proto",
"//proto/google/fhir/proto/r4/core/resources:bundle_and_contained_resource_cc_proto",
"//proto/google/fhir/proto/stu3:codes_cc_proto",
"//proto/google/fhir/proto/stu3:datatypes_cc_proto",
"//proto/google/fhir/proto/stu3:resources_cc_proto",
"@com_google_absl//absl/status:statusor",
Expand Down
13 changes: 11 additions & 2 deletions cc/google/fhir/fhir_path/fhir_path.cc
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,13 @@
#include "absl/time/time.h"
#include "absl/types/optional.h"
#include "google/fhir/annotations.h"
#include "google/fhir/codes.h"
#include "google/fhir/fhir_path/FhirPathBaseVisitor.h"
#include "google/fhir/fhir_path/FhirPathLexer.h"
#include "google/fhir/fhir_path/FhirPathParser.h"
#include "google/fhir/fhir_path/fhir_path_types.h"
#include "google/fhir/fhir_path/utils.h"
#include "google/fhir/fhir_types.h"
#include "google/fhir/proto_util.h"
#include "google/fhir/status/status.h"
#include "google/fhir/status/statusor.h"
Expand Down Expand Up @@ -151,6 +153,10 @@ absl::StatusOr<std::string> MessageToString(const WorkspaceMessage& message) {
return InvalidArgumentError("Expression is not a string.");
}

if (HasValueset(message.Message()->GetDescriptor())) {
return GetCodeAsString(*message.Message());
}

std::string value;
return GetPrimitiveStringValue(*message.Message(), &value);
}
Expand Down Expand Up @@ -2237,12 +2243,15 @@ absl::StatusOr<ExpressionNode*> static CreateConvertsToFunction(
return InvalidArgumentError("convertsTo*() requires zero arguments.");
}

// .convertsTo*() is equivalent to .single().select(to*().exists()).
// .convertsTo*() is equivalent to .single().select($this.to*().exists()).
std::vector<std::shared_ptr<ExpressionNode>> empty_params = {};
return new SelectFunction(
std::make_shared<SingleFunction>(child_expression, empty_params),
{std::make_shared<ExistsFunction>(
std::make_shared<T>(child_expression, empty_params), empty_params)});
std::make_shared<T>(
std::make_shared<ThisReference>(child_expression->ReturnType()),
empty_params),
empty_params)});
}

// Implements the FHIRPath .ofType() function.
Expand Down
16 changes: 16 additions & 0 deletions cc/google/fhir/fhir_path/fhir_path_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -845,6 +845,10 @@ TYPED_TEST(FhirPathTest, TestFunctionConvertsToString) {
TestFixture::Evaluate(ValidEncounter<typename TypeParam::Encounter>(),
"convertsToString()"),
EvalsToFalse());
EXPECT_THAT(
TestFixture::Evaluate(ValidEncounter<typename TypeParam::Encounter>(),
"status.convertsToString()"),
EvalsToTrue());
EXPECT_THAT(TestFixture::Evaluate("(1 | 2).convertsToString()"),
HasStatusCode(StatusCode::kFailedPrecondition));
}
Expand Down Expand Up @@ -1762,6 +1766,12 @@ TYPED_TEST(FhirPathTest, TestStringAddition) {
EXPECT_THAT(TestFixture::Evaluate("('foo' + {})"), EvalsToEmpty());
}

TYPED_TEST(FhirPathTest, TestStringAdditionWithCodeEnum) {
auto encounter = ValidEncounter<typename TypeParam::Encounter>();
EXPECT_THAT(TestFixture::Evaluate(encounter, "status + 'foo'"),
EvalsToStringThatMatches(StrEq("triagedfoo")));
}

TYPED_TEST(FhirPathTest, TestStringConcatenation) {
EXPECT_THAT(TestFixture::Evaluate("('foo' & 'bar')"),
EvalsToStringThatMatches(StrEq("foobar")));
Expand All @@ -1773,6 +1783,12 @@ TYPED_TEST(FhirPathTest, TestStringConcatenation) {
EvalsToStringThatMatches(StrEq("")));
}

TYPED_TEST(FhirPathTest, TestStringConcatenationWithCodeEnum) {
auto encounter = ValidEncounter<typename TypeParam::Encounter>();
EXPECT_THAT(TestFixture::Evaluate(encounter, "status & 'foo'"),
EvalsToStringThatMatches(StrEq("triagedfoo")));
}

TYPED_TEST(FhirPathTest, TestEmptyComparisons) {
EXPECT_THAT(TestFixture::Evaluate("{} = 42"), EvalsToEmpty());
EXPECT_THAT(TestFixture::Evaluate("42 = {}"), EvalsToEmpty());
Expand Down
20 changes: 15 additions & 5 deletions cc/google/fhir/fhir_path/fhir_path_types.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h"
#include "google/fhir/annotations.h"
#include "google/fhir/fhir_types.h"

namespace google::fhir::fhir_path::internal {

Expand Down Expand Up @@ -71,12 +72,21 @@ absl::StatusOr<FhirPathSystemType> GetSystemType(

auto type =
type_map->find(GetStructureDefinitionUrl(fhir_primitive.GetDescriptor()));
if (type == type_map->end()) {
return absl::NotFoundError(
absl::StrCat(fhir_primitive.GetTypeName(),
" does not map to a FHIRPath primitive type."));
if (type != type_map->end()) {
return type->second;
}
return type->second;

// Codes don't necessarily have the correct structure definition set (i.e.
// https://hl7.org/fhir/StructureDefinition/code.) Instead, we must use
// `IsTypeOrProfileOfCode` which checks for additional annotations that
// indicate the message is a Code.
if (IsTypeOrProfileOfCode(fhir_primitive)) {
return FhirPathSystemType::kString;
}

return absl::NotFoundError(
absl::StrCat(fhir_primitive.GetTypeName(),
" does not map to a FHIRPath primitive type."));
}

bool IsSystemInteger(const Message& message) {
Expand Down
11 changes: 8 additions & 3 deletions cc/google/fhir/fhir_path/fhir_path_types_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "google/fhir/util.h"
#include "proto/google/fhir/proto/r4/core/datatypes.pb.h"
#include "proto/google/fhir/proto/r4/core/resources/bundle_and_contained_resource.pb.h"
#include "proto/google/fhir/proto/stu3/codes.pb.h"
#include "proto/google/fhir/proto/stu3/datatypes.pb.h"
#include "proto/google/fhir/proto/stu3/resources.pb.h"

Expand Down Expand Up @@ -89,11 +90,15 @@ struct FhirTypes {
using Quantities = FhirPrimitiveTypes<FHIR_DATATYPE(BundleType, quantity)>;
};

struct Stu3Types : public FhirTypes<stu3::proto::Bundle> {};
struct Stu3Types : public FhirTypes<stu3::proto::Bundle> {
using Strings =
FhirStringTypes<stu3::proto::Bundle, stu3::proto::BundleTypeCode>;
};

struct R4Types : public FhirTypes<r4::core::Bundle> {
using Strings = FhirStringTypes<r4::core::Bundle, r4::core::Uuid,
r4::core::Canonical, r4::core::Url>;
using Strings =
FhirStringTypes<r4::core::Bundle, r4::core::Uuid, r4::core::Canonical,
r4::core::Url, r4::core::Bundle::TypeCode>;
};

template <typename T>
Expand Down

0 comments on commit 2c18c16

Please sign in to comment.