ores.cpp.presentation.history_field_mapper_impl

Table of Contents

Implements render_{entity}_fields(): one field_value push per field, dispatched on a set of render_is_* flags computed directly from each column's raw cpp_type string — deliberately not the is_uuid=/=is_nullable_string=/=is_already_optional=/=is_plain_string flags the repository/SQL facets use, since those encode a nullable-to- optional promotion for the storage layer that the domain class template (cpp_domain_type_class.hpp.mustache) does not apply: it emits \{\{\{cpp_type\}\}\} verbatim, so a column with :nullable: true but an explicit :cpp_type: std::string override gets a plain std::string field, not std::optional<std::string>. The mapper must match that same ground truth, or it doesn't compile against the actual generated struct. presentation profile.

Scope: both flat and C1202-nested (has_identity_group=/ =has_audit_group) entities, matching the mapper/repository/service facets' existing branching convention (v.identity.x=/=v.audit.x vs flat v.x). Primary key supports string and uuid only; natural keys support string, uuid, date, timestamp, and int. Natural keys are not identity-group-aware (mirroring the mapper facet's same carve-out — an entity with natural keys inside the identity group would need this extended). Enum columns render via rfl::enum_to_string (render_is_enum, derived from the raw is_enum flag rather than the nullable-narrowed is_enum column flag, matching every other render_is_* flag's ground-truth-over-derived-flag rule above) – added for the ores.synthetic.market_data_generation_config scope=/=binding_mode columns (Synthetic data scope and binding story, compass show 9DEED9D1-680C-4B87-A7DF-2B9AA9ED7277). Nullable enum columns are not yet covered.

See the Template variable reference for the complete list of available variables and their semantics.

Template

The full template source. Edit here and re-tangle with compass build --direct tangle_codegen_templates to regenerate library/templates/cpp_history_field_mapper.cpp.mustache.

{{! GENERATED FILE — tangled from projects/ores.codegen/library/templates/cpp_presentation.org. Edit the org source. }}
{{{cpp_license}}}
{{#domain_entity}}
#include "ores.{{component_core}}/presentation/{{entity_singular}}_history_field_mapper.hpp"

{{#has_render_uuid_columns}}
#include <boost/uuid/uuid_io.hpp>
{{/has_render_uuid_columns}}
#include "ores.platform/time/datetime.hpp"
{{#has_date_natural_keys}}
#include <format>
{{/has_date_natural_keys}}
{{#has_enum_columns}}
#include <rfl/enums.hpp>
{{/has_enum_columns}}

namespace ores::{{component}}::presentation {

std::vector<ores::diff::domain::field_value>
render_{{entity_singular}}_fields(const domain::{{entity_singular}}& v) {
    using ores::diff::domain::field_value;
    std::vector<field_value> fields;

{{#has_identity_group}}
{{#primary_key.is_uuid}}
    fields.push_back(
        {.name = "{{primary_key.render_label}}", .value = boost::uuids::to_string(v.identity.{{primary_key.column}})});
{{/primary_key.is_uuid}}
{{^primary_key.is_uuid}}
    fields.push_back({.name = "{{primary_key.render_label}}", .value = v.identity.{{primary_key.column}}});
{{/primary_key.is_uuid}}
{{/has_identity_group}}
{{^has_identity_group}}
{{#primary_key.is_uuid}}
    fields.push_back(
        {.name = "{{primary_key.render_label}}", .value = boost::uuids::to_string(v.{{primary_key.column}})});
{{/primary_key.is_uuid}}
{{^primary_key.is_uuid}}
    fields.push_back({.name = "{{primary_key.render_label}}", .value = v.{{primary_key.column}}});
{{/primary_key.is_uuid}}
{{/has_identity_group}}
{{#natural_keys}}
{{#is_uuid}}
    fields.push_back({.name = "{{render_label}}", .value = boost::uuids::to_string(v.{{column}})});
{{/is_uuid}}
{{^is_uuid}}
{{#is_date}}
    fields.push_back({.name = "{{render_label}}", .value = std::format("{:%Y-%m-%d}", v.{{column}})});
{{/is_date}}
{{^is_date}}
{{#is_timestamp}}
    fields.push_back(
        {.name = "{{render_label}}", .value = ores::platform::time::datetime::to_iso8601_utc(v.{{column}})});
{{/is_timestamp}}
{{^is_timestamp}}
{{#is_int}}
    fields.push_back({.name = "{{render_label}}", .value = std::to_string(v.{{column}})});
{{/is_int}}
{{^is_int}}
    fields.push_back({.name = "{{render_label}}", .value = v.{{column}}});
{{/is_int}}
{{/is_timestamp}}
{{/is_date}}
{{/is_uuid}}
{{/natural_keys}}
{{#columns}}
{{#is_identity_group_column}}
{{#render_is_uuid}}
    fields.push_back({.name = "{{render_label}}", .value = boost::uuids::to_string(v.identity.{{name}})});
{{/render_is_uuid}}
{{#render_is_optional_uuid}}
    fields.push_back({.name = "{{render_label}}",
                      .value = v.identity.{{name}} ? boost::uuids::to_string(*v.identity.{{name}}) : std::string{}});
{{/render_is_optional_uuid}}
{{#render_is_timestamp}}
    fields.push_back(
        {.name = "{{render_label}}", .value = ores::platform::time::datetime::to_iso8601_utc(v.identity.{{name}})});
{{/render_is_timestamp}}
{{#render_is_optional_timestamp}}
    fields.push_back({.name = "{{render_label}}",
                      .value = v.identity.{{name}} ? ores::platform::time::datetime::to_iso8601_utc(*v.identity.{{name}}) : std::string{}});
{{/render_is_optional_timestamp}}
{{#render_is_optional_string}}
    fields.push_back({.name = "{{render_label}}", .value = v.identity.{{name}}.value_or(std::string{})});
{{/render_is_optional_string}}
{{#render_is_optional_bool}}
    fields.push_back({.name = "{{render_label}}", .value = v.identity.{{name}} ? (*v.identity.{{name}} ? "true" : "false") : std::string{}});
{{/render_is_optional_bool}}
{{#render_is_optional_int}}
    fields.push_back({.name = "{{render_label}}",
                      .value = v.identity.{{name}} ? std::to_string(*v.identity.{{name}}) : std::string{}});
{{/render_is_optional_int}}
{{#render_is_optional_double}}
    fields.push_back({.name = "{{render_label}}",
                      .value = v.identity.{{name}} ? std::to_string(*v.identity.{{name}}) : std::string{}});
{{/render_is_optional_double}}
{{#render_is_string}}
    fields.push_back({.name = "{{render_label}}", .value = v.identity.{{name}}});
{{/render_is_string}}
{{#render_is_bool}}
    fields.push_back({.name = "{{render_label}}", .value = v.identity.{{name}} ? "true" : "false"});
{{/render_is_bool}}
{{#render_is_int}}
    fields.push_back({.name = "{{render_label}}", .value = std::to_string(v.identity.{{name}})});
{{/render_is_int}}
{{#render_is_double}}
    fields.push_back({.name = "{{render_label}}", .value = std::to_string(v.identity.{{name}})});
{{/render_is_double}}
{{#render_is_enum}}
    fields.push_back({.name = "{{render_label}}", .value = rfl::enum_to_string(v.identity.{{name}})});
{{/render_is_enum}}
{{/is_identity_group_column}}
{{^is_identity_group_column}}
{{#render_is_uuid}}
    fields.push_back({.name = "{{render_label}}", .value = boost::uuids::to_string(v.{{name}})});
{{/render_is_uuid}}
{{#render_is_optional_uuid}}
    fields.push_back({.name = "{{render_label}}",
                      .value = v.{{name}} ? boost::uuids::to_string(*v.{{name}}) : std::string{}});
{{/render_is_optional_uuid}}
{{#render_is_timestamp}}
    fields.push_back(
        {.name = "{{render_label}}", .value = ores::platform::time::datetime::to_iso8601_utc(v.{{name}})});
{{/render_is_timestamp}}
{{#render_is_optional_timestamp}}
    fields.push_back({.name = "{{render_label}}",
                      .value = v.{{name}} ? ores::platform::time::datetime::to_iso8601_utc(*v.{{name}}) : std::string{}});
{{/render_is_optional_timestamp}}
{{#render_is_optional_string}}
    fields.push_back({.name = "{{render_label}}", .value = v.{{name}}.value_or(std::string{})});
{{/render_is_optional_string}}
{{#render_is_optional_bool}}
    fields.push_back({.name = "{{render_label}}", .value = v.{{name}} ? (*v.{{name}} ? "true" : "false") : std::string{}});
{{/render_is_optional_bool}}
{{#render_is_optional_int}}
    fields.push_back({.name = "{{render_label}}",
                      .value = v.{{name}} ? std::to_string(*v.{{name}}) : std::string{}});
{{/render_is_optional_int}}
{{#render_is_optional_double}}
    fields.push_back({.name = "{{render_label}}",
                      .value = v.{{name}} ? std::to_string(*v.{{name}}) : std::string{}});
{{/render_is_optional_double}}
{{#render_is_string}}
    fields.push_back({.name = "{{render_label}}", .value = v.{{name}}});
{{/render_is_string}}
{{#render_is_bool}}
    fields.push_back({.name = "{{render_label}}", .value = v.{{name}} ? "true" : "false"});
{{/render_is_bool}}
{{#render_is_int}}
    fields.push_back({.name = "{{render_label}}", .value = std::to_string(v.{{name}})});
{{/render_is_int}}
{{#render_is_double}}
    fields.push_back({.name = "{{render_label}}", .value = std::to_string(v.{{name}})});
{{/render_is_double}}
{{#render_is_enum}}
    fields.push_back({.name = "{{render_label}}", .value = rfl::enum_to_string(v.{{name}})});
{{/render_is_enum}}
{{/is_identity_group_column}}
{{/columns}}
{{#has_audit_group}}
{{#has_audit_columns}}
    fields.push_back({.name = "Modified By", .value = v.audit.modified_by});
    fields.push_back({.name = "Performed By", .value = v.audit.performed_by});
    fields.push_back({.name = "Change Reason Code", .value = v.audit.change_reason_code});
    fields.push_back({.name = "Change Commentary", .value = v.audit.change_commentary});
{{/has_audit_columns}}
    fields.push_back(
        {.name = "Recorded At", .value = ores::platform::time::datetime::to_iso8601_utc(v.audit.recorded_at)});
{{/has_audit_group}}
{{^has_audit_group}}
{{#has_audit_columns}}
    fields.push_back({.name = "Modified By", .value = v.modified_by});
    fields.push_back({.name = "Performed By", .value = v.performed_by});
    fields.push_back({.name = "Change Reason Code", .value = v.change_reason_code});
    fields.push_back({.name = "Change Commentary", .value = v.change_commentary});
{{/has_audit_columns}}
    fields.push_back(
        {.name = "Recorded At", .value = ores::platform::time::datetime::to_iso8601_utc(v.recorded_at)});
{{/has_audit_group}}

    return fields;
}

}
{{/domain_entity}}

See also

Emacs 29.3 (Org mode 9.6.15)