Skip to content

Commit

Permalink
Makes C++ not rely on the json_name annotation on Reference.uri. Th…
Browse files Browse the repository at this point in the history
…is is step 1 of resolving #45.

PiperOrigin-RevId: 582013548
  • Loading branch information
nickgeorge authored and Copybara-Service committed Nov 14, 2023
1 parent a07197f commit c7bd464
Show file tree
Hide file tree
Showing 12 changed files with 251 additions and 38 deletions.
16 changes: 11 additions & 5 deletions cc/google/fhir/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,15 @@ cc_library(
deps = [
":annotations",
":core_resource_registry",
":type_macros",
":proto_util",
":util",
"//cc/google/fhir/status",
"//cc/google/fhir/status:statusor",
"@com_google_absl//absl/memory",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/types:optional",
"@com_google_protobuf//:protobuf",
"@com_googlesource_code_re2//:re2",
],
Expand Down Expand Up @@ -327,6 +330,7 @@ cc_library(
":extensions",
":fhir_types",
":json_format_results",
":json_util",
":primitive_handler",
":primitive_wrapper",
":proto_util",
Expand All @@ -340,6 +344,7 @@ cc_library(
"//cc/google/fhir/status",
"//cc/google/fhir/status:statusor",
"//proto/google/fhir/proto:annotations_cc_proto",
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/memory",
"@com_google_absl//absl/status",
Expand Down Expand Up @@ -480,10 +485,12 @@ cc_library(
hdrs = ["json_util.h"],
strip_include_prefix = "//cc/",
deps = [
":annotations",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings",
"@com_google_protobuf//:protobuf",
],
)

Expand Down Expand Up @@ -521,10 +528,9 @@ cc_test(
deps = [
":json_util",
"//cc/google/fhir/status",
"//cc/google/fhir/status:statusor",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings",
"//proto/google/fhir/proto/r4/core:datatypes_cc_proto",
"//proto/google/fhir/proto/r4/core/resources:observation_cc_proto",
"//proto/google/fhir/proto/r4/core/resources:patient_cc_proto",
"@com_google_googletest//:gtest_main",
],
)
Expand Down
7 changes: 3 additions & 4 deletions cc/google/fhir/fhir_path/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -82,19 +82,17 @@ cc_library(
":fhir_path",
"//cc/google/fhir:annotations",
"//cc/google/fhir:error_reporter",
"//cc/google/fhir:json_util",
"//cc/google/fhir:primitive_handler",
"//cc/google/fhir:proto_util",
"//cc/google/fhir:util",
"//cc/google/fhir/status",
"//cc/google/fhir/status:statusor",
"//proto/google/fhir/proto:annotations_cc_proto",
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/memory",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/synchronization",
"@com_google_absl//absl/types:optional",
"@com_google_protobuf//:protobuf",
],
)
Expand Down Expand Up @@ -181,9 +179,10 @@ cc_library(
strip_include_prefix = "//cc/",
visibility = [":__pkg__"],
deps = [
"//cc/google/fhir:annotations",
"//cc/google/fhir:json_util",
"//cc/google/fhir:references",
"//cc/google/fhir:util",
"//cc/google/fhir/status",
"@com_google_absl//absl/status",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:str_format",
Expand Down
10 changes: 6 additions & 4 deletions cc/google/fhir/fhir_path/fhir_path_validation.cc
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "google/fhir/annotations.h"
#include "google/fhir/error_reporter.h"
#include "google/fhir/fhir_path/fhir_path.h"
#include "google/fhir/json_util.h"
#include "google/fhir/primitive_handler.h"
#include "google/fhir/proto_util.h"
#include "google/fhir/status/status.h"
Expand Down Expand Up @@ -320,10 +321,11 @@ absl::Status ValidateConstraint(const internal::WorkspaceMessage& message,
}

std::string PathTerm(const Message& message, const FieldDescriptor* field) {
return IsContainedResource(message) ||
IsChoiceTypeContainer(message.GetDescriptor())
? absl::StrCat("ofType(", field->message_type()->name(), ")")
: field->json_name();
if (IsContainedResource(message) ||
IsChoiceTypeContainer(message.GetDescriptor())) {
return absl::StrCat("ofType(", field->message_type()->name(), ")");
}
return FhirJsonName(field);
}

namespace {
Expand Down
20 changes: 11 additions & 9 deletions cc/google/fhir/fhir_path/utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,12 @@
#include "google/fhir/fhir_path/utils.h"

#include "google/protobuf/any.pb.h"
#include "google/protobuf/descriptor.h"
#include "absl/status/status.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include "google/fhir/annotations.h"
#include "google/fhir/json_util.h"
#include "google/fhir/references.h"
#include "google/fhir/util.h"

Expand All @@ -27,8 +30,8 @@ namespace fhir_path {
namespace internal {

using ::absl::NotFoundError;
using ::google::protobuf::FieldDescriptor;
using ::google::protobuf::Descriptor;
using ::google::protobuf::FieldDescriptor;
using ::google::protobuf::Message;
using ::google::protobuf::Reflection;

Expand Down Expand Up @@ -68,15 +71,14 @@ absl::Status OneofMessageFromContainer(const Message& container_message,

namespace {

// Returns true if `message` is a Reference and field_descriptor is a field
// within `message` that resolves to 'reference' in FHIR.
// Note: the json_name corresponds to fields in FHIR.
bool IsReference(const Message& message,
const google::protobuf::FieldDescriptor& field_descriptor) {
// Returns true if `message` is a Reference and field_descriptor is the `uri`
// field.
bool IsReferenceUri(const Message& message,
const google::protobuf::FieldDescriptor& field_descriptor) {
return message.GetDescriptor()->options().GetExtension(
::google::fhir::proto::fhir_structure_definition_url) ==
"http://hl7.org/fhir/StructureDefinition/Reference" &&
field_descriptor.json_name() == "reference";
field_descriptor.name() == "uri";
}

} // namespace
Expand All @@ -95,7 +97,7 @@ absl::Status RetrieveField(
// If asked to retrieve a reference, retrieve a String value with a standard
// representation (i.e. ResourceType/id) regardless of how the reference is
// stored in the source message.
if (IsReference(root, field)) {
if (IsReferenceUri(root, field)) {
Message* string_message = message_factory(field.message_type());
if (string_message == nullptr) {
return absl::InternalError(
Expand Down Expand Up @@ -162,7 +164,7 @@ bool HasFieldWithJsonName(const Descriptor* descriptor,
const FieldDescriptor* FindFieldByJsonName(const Descriptor* descriptor,
absl::string_view json_name) {
for (int i = 0; i < descriptor->field_count(); ++i) {
if (json_name == descriptor->field(i)->json_name()) {
if (json_name == FhirJsonName(descriptor->field(i))) {
return descriptor->field(i);
}
}
Expand Down
16 changes: 11 additions & 5 deletions cc/google/fhir/json_parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,23 @@
#include <ctype.h>

#include <cctype>
#include <cstdint>
#include <iosfwd>
#include <memory>
#include <string>
#include <unordered_map>
#include <utility>

#include "google/protobuf/any.pb.h"
#include "absl/base/attributes.h"
#include "absl/base/const_init.h"
#include "absl/container/flat_hash_map.h"
#include "absl/memory/memory.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include "absl/strings/string_view.h"
#include "absl/synchronization/mutex.h"
#include "google/fhir/annotations.h"
#include "google/fhir/core_resource_registry.h"
Expand All @@ -39,6 +43,7 @@
#include "google/fhir/json/json_sax_handler.h"
#include "google/fhir/json_format.h"
#include "google/fhir/json_format_results.h"
#include "google/fhir/json_util.h"
#include "google/fhir/primitive_wrapper.h"
#include "google/fhir/r4/profiles.h"
#include "google/fhir/references.h"
Expand Down Expand Up @@ -75,6 +80,7 @@ MakeFieldMap(const Descriptor* descriptor) {
std::unordered_map<std::string, const FieldDescriptor*>>();
for (int i = 0; i < descriptor->field_count(); i++) {
const FieldDescriptor* field = descriptor->field(i);
const std::string& json_name = FhirJsonName(field);
if (IsChoiceType(field)) {
std::unique_ptr<
const std::unordered_map<std::string, const FieldDescriptor*>>
Expand All @@ -85,23 +91,23 @@ MakeFieldMap(const Descriptor* descriptor) {
// Convert primitive extension field name to field on choice type,
// e.g., value + _boolean -> _valueBoolean for Extension.value.
child_field_name[1] = std::toupper(child_field_name[1]);
(*field_map)[absl::StrCat("_", field->json_name(),
(*field_map)[absl::StrCat("_", json_name,
child_field_name.substr(1))] = field;
} else {
// For non-primitive, just append them together as camelcase, e.g.,
// value + boolean = valueBoolean
child_field_name[0] = std::toupper(child_field_name[0]);
(*field_map)[absl::StrCat(field->json_name(), child_field_name)] =
field;
(*field_map)[absl::StrCat(json_name, child_field_name)] = field;
}
}
} else {
(*field_map)[field->json_name()] = field;
(*field_map)[json_name] = field;

if (field->type() == FieldDescriptor::TYPE_MESSAGE &&
IsPrimitive(field->message_type())) {
// Fhir JSON represents extensions to primitive fields as separate
// standalone JSON objects, keyed by the "_" + field name.
(*field_map)["_" + field->json_name()] = field;
(*field_map)["_" + json_name] = field;
}
}
}
Expand Down
15 changes: 8 additions & 7 deletions cc/google/fhir/json_printer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include "google/fhir/extensions.h"
#include "google/fhir/fhir_types.h"
#include "google/fhir/json_format.h"
#include "google/fhir/json_util.h"
#include "google/fhir/primitive_handler.h"
#include "google/fhir/proto_util.h"
#include "google/fhir/r4/codeable_concepts.h"
Expand Down Expand Up @@ -269,7 +270,7 @@ class Printer {
// to query all possible choice types in a single query.
if (IsChoiceType(field) && json_format_ == kFormatPure) {
FHIR_RETURN_IF_ERROR(PrintChoiceTypeField(
reflection->GetMessage(proto, field), field->json_name()));
reflection->GetMessage(proto, field), FhirJsonName(field)));
} else {
FHIR_RETURN_IF_ERROR(PrintField(proto, field, print_as_string));
}
Expand Down Expand Up @@ -347,7 +348,7 @@ class Printer {
} else {
int field_size = reflection->FieldSize(containing_proto, field);

PrintFieldPreamble(field->json_name());
PrintFieldPreamble(FhirJsonName(field));
output_ += "[";
Indent();
AddNewline();
Expand All @@ -370,9 +371,9 @@ class Printer {
if (IsPrimitive(field->message_type())) {
FHIR_RETURN_IF_ERROR(
PrintPrimitiveField(reflection->GetMessage(containing_proto, field),
field->json_name()));
FhirJsonName(field)));
} else {
PrintFieldPreamble(field->json_name());
PrintFieldPreamble(FhirJsonName(field));
FHIR_RETURN_IF_ERROR(
PrintNonPrimitive(reflection->GetMessage(containing_proto, field)));
}
Expand Down Expand Up @@ -432,7 +433,7 @@ class Printer {
}
const google::protobuf::FieldDescriptor* value_field =
choice_reflection->GetOneofFieldDescriptor(choice_container, oneof);
std::string oneof_field_name = value_field->json_name();
std::string oneof_field_name = FhirJsonName(value_field);
oneof_field_name[0] = toupper(oneof_field_name[0]);

if (IsPrimitive(value_field->message_type())) {
Expand Down Expand Up @@ -474,7 +475,7 @@ class Printer {
}

if (non_null_values_found) {
PrintFieldPreamble(field->json_name());
PrintFieldPreamble(FhirJsonName(field));
output_ += "[";
Indent();
for (const JsonPrimitive& json_primitive : json_primitives) {
Expand All @@ -493,7 +494,7 @@ class Printer {
output_ += ",";
AddNewline();
}
PrintFieldPreamble(absl::StrCat("_", field->json_name()));
PrintFieldPreamble(absl::StrCat("_", FhirJsonName(field)));
output_ += "[";
Indent();
for (const JsonPrimitive& json_primitive : json_primitives) {
Expand Down
13 changes: 13 additions & 0 deletions cc/google/fhir/json_util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@

#include <string>

#include "google/protobuf/descriptor.h"
#include "absl/container/flat_hash_map.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h"
#include "google/fhir/annotations.h"

namespace google::fhir {

Expand Down Expand Up @@ -60,4 +62,15 @@ absl::StatusOr<std::string> ToJsonStringValue(absl::string_view raw_value) {
return result;
}

const std::string& FhirJsonName(const google::protobuf::FieldDescriptor* field) {
// When translating References between proto and JSON, the unstructured
// FHIR JSON Reference.reference field maps to the absolute URI field
// in the proto Reference.
static const std::string* kReferenceFieldName = new std::string("reference");
if (field->name() == "uri" && IsReference(field->containing_type())) {
return *kReferenceFieldName;
}
return field->json_name();
}

} // namespace google::fhir
4 changes: 4 additions & 0 deletions cc/google/fhir/json_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#include <string>

#include "google/protobuf/descriptor.h"
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h"

Expand All @@ -44,6 +45,9 @@ namespace google::fhir {
// http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf
absl::StatusOr<std::string> ToJsonStringValue(absl::string_view raw_value);

// Given a proto field, returns the name of the field in FHIR JSON.
const std::string& FhirJsonName(const google::protobuf::FieldDescriptor* field);

} // namespace google::fhir

#endif // GOOGLE_FHIR_JSON_UTIL_H_
Loading

0 comments on commit c7bd464

Please sign in to comment.