ores.cpp.repository.entity_header

Table of Contents

The repository entity: a struct mirroring the table shape, with the column list the query builder binds. repository profile.

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

1. Template

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

{{! GENERATED FILE — tangled from projects/ores.codegen/library/templates/cpp_repository.org. Edit the org source. }}
{{{cpp_license}}}
{{#domain_entity}}
#ifndef ORES_{{component_core_upper}}_REPOSITORY_{{entity_singular_upper}}_ENTITY_HPP
#define ORES_{{component_core_upper}}_REPOSITORY_{{entity_singular_upper}}_ENTITY_HPP

#include <string>
#include <optional>
#include <ostream>
#include <chrono>
#include "ores.database/repository/db_types.hpp"
#include "ores.database/query_builder/columns.hpp"
{{#has_uuid_columns}}
#include <boost/uuid/uuid.hpp>
{{/has_uuid_columns}}
{{#has_tenant_id}}
#include "ores.utility/uuid/tenant_id.hpp"
{{/has_tenant_id}}
{{#has_decimal_columns}}
#include "ores.utility/decimal/decimal.hpp"
{{/has_decimal_columns}}
{{#cpp.includes.entity}}
#include {{{.}}}
{{/cpp.includes.entity}}

namespace ores::{{component}}::repository {

using db_timestamp = ores::database::repository::db_timestamp;

/**
 * @brief Represents a {{entity_title_lower}} in the database.
 *
 * Each member holds the type its column has, so the layer binds and reads it
 * in the binary format and the mapper copies it to the domain member. A column
 * whose type the layer has no codec for keeps its text, and the mapper converts
 * it.
 */
struct {{entity_singular}}_entity {
    constexpr static const char* schema = "public";
    constexpr static const char* tablename = "{{sql.tablename}}";

{{#primary_key.columns}}
{{#is_uuid}}
    boost::uuids::uuid {{column}};
{{/is_uuid}}
{{#is_timestamp}}
    db_timestamp {{column}};
{{/is_timestamp}}
{{#is_int}}
    int {{column}}{};
{{/is_int}}
{{#is_text}}
    std::string {{column}};
{{/is_text}}
{{/primary_key.columns}}
{{#has_tenant_id}}
{{#nullable_tenant_id}}
    std::optional<utility::uuid::tenant_id> tenant_id;
{{/nullable_tenant_id}}
{{^nullable_tenant_id}}
    utility::uuid::tenant_id tenant_id = utility::uuid::tenant_id::system();
{{/nullable_tenant_id}}
{{/has_tenant_id}}
{{#has_audit_columns}}
    int version = 0;
{{/has_audit_columns}}
{{#natural_keys}}
{{#is_optional_uuid}}
    std::optional<boost::uuids::uuid> {{column}};
{{/is_optional_uuid}}
{{#is_uuid}}
{{^is_optional_uuid}}
    boost::uuids::uuid {{column}}{{#default_value}} = {{{default_value}}}{{/default_value}};
{{/is_optional_uuid}}
{{/is_uuid}}
{{#is_optional_timestamp}}
    std::optional<db_timestamp> {{column}};
{{/is_optional_timestamp}}
{{#is_date}}
    std::chrono::year_month_day {{column}};
{{/is_date}}
{{#is_timestamp}}
{{^is_optional_timestamp}}
    db_timestamp {{column}};
{{/is_optional_timestamp}}
{{/is_timestamp}}
{{^is_uuid}}{{^is_optional_uuid}}{{^is_date}}{{^is_timestamp}}{{^is_optional_timestamp}}
    {{{cpp_type}}} {{column}}{{#default_value}} = {{{default_value}}}{{/default_value}}{{^default_value}}{{{cpp_value_init}}}{{/default_value}};
{{/is_optional_timestamp}}{{/is_timestamp}}{{/is_date}}{{/is_optional_uuid}}{{/is_uuid}}
{{/natural_keys}}
{{#columns}}
{{#is_optional_uuid}}
    std::optional<boost::uuids::uuid> {{name}};
{{/is_optional_uuid}}
{{#is_uuid}}
    boost::uuids::uuid {{name}};
{{/is_uuid}}
{{#is_optional_timestamp}}
    std::optional<db_timestamp> {{name}};
{{/is_optional_timestamp}}
{{#is_required_timestamp}}
    db_timestamp {{name}};
{{/is_required_timestamp}}
{{#is_optional_date}}
    std::optional<std::chrono::year_month_day> {{name}};
{{/is_optional_date}}
{{#is_required_date}}
    std::chrono::year_month_day {{name}};
{{/is_required_date}}
{{#is_optional_decimal}}
    std::optional<ores::utility::decimal::decimal> {{name}};
{{/is_optional_decimal}}
{{#is_required_decimal}}
    ores::utility::decimal::decimal {{name}};
{{/is_required_decimal}}
{{#is_required_inet}}
    std::string {{name}};
{{/is_required_inet}}
{{#is_base64}}
    std::string {{name}};
{{/is_base64}}
{{#is_nullable_string}}
    std::optional<std::string> {{name}};
{{/is_nullable_string}}
{{#is_nullable_numeric}}
    std::optional<{{{cpp_type}}}> {{name}};
{{/is_nullable_numeric}}
{{#is_already_optional}}
    {{{cpp_type}}} {{name}};
{{/is_already_optional}}
{{#is_enum}}
    std::string {{name}};
{{/is_enum}}
{{#is_value_type}}
    std::string {{name}};
{{/is_value_type}}
{{#render_is_enum}}
{{^is_enum}}
    std::optional<std::string> {{name}};
{{/is_enum}}
{{/render_is_enum}}
{{#is_simple}}
    {{{cpp_type}}} {{name}}{{#default_value}} = {{{default_value}}}{{/default_value}}{{^default_value}}{{{cpp_value_init}}}{{/default_value}};
{{/is_simple}}
{{/columns}}
{{#has_audit_columns}}
    std::string modified_by;
    std::string performed_by;
    std::string change_reason_code;
    std::string change_commentary;
{{/has_audit_columns}}
{{^current_state}}
    db_timestamp valid_from = db_timestamp::max();
    db_timestamp valid_to = db_timestamp::max();
{{/current_state}}

    /**
     * @brief The columns of the table, named as the members, with the key.
     */
    static constexpr auto columns() {
        using e = {{entity_singular}}_entity;
        namespace query_builder = ores::database::query_builder;
        return query_builder::columns<e>()
{{#primary_key.columns}}
            | query_builder::key("{{column}}", &e::{{column}})
{{/primary_key.columns}}
{{#has_tenant_id}}
            | query_builder::bind("tenant_id", &e::tenant_id)
{{/has_tenant_id}}
{{#has_audit_columns}}
            | query_builder::bind("version", &e::version)
{{/has_audit_columns}}
{{#natural_keys}}
{{#is_text_stored}}
            | query_builder::bind_text("{{column}}", &e::{{column}})
{{/is_text_stored}}
{{^is_text_stored}}
            | query_builder::bind("{{column}}", &e::{{column}})
{{/is_text_stored}}
{{/natural_keys}}
{{#columns}}
{{^sql_only}}
{{#is_text_stored}}
            | query_builder::bind_text("{{name}}", &e::{{name}})
{{/is_text_stored}}
{{^is_text_stored}}
            | query_builder::bind("{{name}}", &e::{{name}})
{{/is_text_stored}}
{{/sql_only}}
{{/columns}}
{{#has_audit_columns}}
            | query_builder::bind("modified_by", &e::modified_by)
            | query_builder::bind("performed_by", &e::performed_by)
            | query_builder::bind("change_reason_code", &e::change_reason_code)
            | query_builder::bind("change_commentary", &e::change_commentary)
{{/has_audit_columns}}
{{^current_state}}
            | query_builder::bind("valid_from", &e::valid_from)
            | query_builder::bind("valid_to", &e::valid_to)
{{/current_state}}
            ;
    }
};

std::ostream& operator<<(std::ostream& s, const {{entity_singular}}_entity& v);

}

#endif
{{/domain_entity}}
{{#junction}}
#ifndef ORES_{{component_core_upper}}_REPOSITORY_{{name_singular_upper}}_ENTITY_HPP
#define ORES_{{component_core_upper}}_REPOSITORY_{{name_singular_upper}}_ENTITY_HPP

#include <string>
#include <optional>
#include <ostream>
#include <chrono>
#include "ores.database/repository/db_types.hpp"
#include "ores.database/query_builder/columns.hpp"
{{#has_uuid_left_or_right}}
#include <boost/uuid/uuid.hpp>
{{/has_uuid_left_or_right}}
{{#has_tenant_id}}
#include "ores.utility/uuid/tenant_id.hpp"
{{/has_tenant_id}}
{{#has_decimal_columns}}
#include "ores.utility/decimal/decimal.hpp"
{{/has_decimal_columns}}
{{#cpp.includes.entity}}
#include {{{.}}}
{{/cpp.includes.entity}}

namespace ores::{{component}}::repository {

using db_timestamp = ores::database::repository::db_timestamp;

/**
 * @brief Represents a {{name_title_lower}} in the database.
 *
 * Junction table with composite primary key ({{left.column}}, {{right.column}}, valid_from).
 */
struct {{name_singular}}_entity {
    constexpr static const char* schema = "public";
    constexpr static const char* tablename = "{{sql.tablename}}";

{{#left.is_uuid}}
    boost::uuids::uuid {{left.column}};
{{/left.is_uuid}}
{{#left.is_date}}
    std::chrono::year_month_day {{left.column}};
{{/left.is_date}}
{{^left.is_uuid}}{{^left.is_date}}
    std::string {{left.column}};
{{/left.is_date}}{{/left.is_uuid}}
{{#has_tenant_id}}
    std::string tenant_id;
{{/has_tenant_id}}
{{#right.is_uuid}}
    boost::uuids::uuid {{right.column}};
{{/right.is_uuid}}
{{#right.is_date}}
    std::chrono::year_month_day {{right.column}};
{{/right.is_date}}
{{^right.is_uuid}}{{^right.is_date}}
    std::string {{right.column}};
{{/right.is_date}}{{/right.is_uuid}}
    int version = 0;
{{#columns}}
{{#is_uuid}}
    boost::uuids::uuid {{name}};
{{/is_uuid}}
{{#is_optional_uuid}}
    std::optional<boost::uuids::uuid> {{name}};
{{/is_optional_uuid}}
{{#is_optional_timestamp}}
    std::optional<db_timestamp> {{name}};
{{/is_optional_timestamp}}
{{#is_required_timestamp}}
    db_timestamp {{name}};
{{/is_required_timestamp}}
{{#is_date}}
    std::chrono::year_month_day {{name}};
{{/is_date}}
{{#is_base64}}
    std::string {{name}};
{{/is_base64}}
{{^is_uuid}}{{^is_optional_uuid}}{{^is_optional_timestamp}}{{^is_required_timestamp}}{{^is_date}}{{^is_base64}}
    {{{cpp_type}}} {{name}}{{#default_value}} = {{{default_value}}}{{/default_value}}{{^default_value}}{{{cpp_value_init}}}{{/default_value}};
{{/is_base64}}{{/is_date}}{{/is_required_timestamp}}{{/is_optional_timestamp}}{{/is_optional_uuid}}{{/is_uuid}}
{{/columns}}
    std::string modified_by;
    std::string performed_by;
    std::string change_reason_code;
    std::string change_commentary;
    db_timestamp valid_from = db_timestamp::max();
    db_timestamp valid_to = db_timestamp::max();
{{#history}}
    std::optional<std::string> closed_by;
{{/history}}

    /**
     * @brief The columns of the table, named as the members, with the key.
     */
    static constexpr auto columns() {
        using e = {{name_singular}}_entity;
        namespace query_builder = ores::database::query_builder;
        return query_builder::columns<e>()
            | query_builder::key("{{left.column}}", &e::{{left.column}})
{{#has_tenant_id}}
            | query_builder::bind_text("tenant_id", &e::tenant_id)
{{/has_tenant_id}}
            | query_builder::bind("{{right.column}}", &e::{{right.column}})
            | query_builder::bind("version", &e::version)
{{#columns}}
{{^sql_only}}
{{#is_text_stored}}
            | query_builder::bind_text("{{name}}", &e::{{name}})
{{/is_text_stored}}
{{^is_text_stored}}
            | query_builder::bind("{{name}}", &e::{{name}})
{{/is_text_stored}}
{{/sql_only}}
{{/columns}}
            | query_builder::bind("modified_by", &e::modified_by)
            | query_builder::bind("performed_by", &e::performed_by)
            | query_builder::bind("change_reason_code", &e::change_reason_code)
            | query_builder::bind("change_commentary", &e::change_commentary)
            | query_builder::bind("valid_from", &e::valid_from)
            | query_builder::bind("valid_to", &e::valid_to)
{{#history}}
            | query_builder::bind("closed_by", &e::closed_by)
{{/history}}
            ;
    }
};

std::ostream& operator<<(std::ostream& s, const {{name_singular}}_entity& v);

}

#endif
{{/junction}}

2. Design notes

2.1. Org entity includes feed the header (2026-09-06)

The {{#cpp.includes.entity}} arm emits the org-declared "Entity includes" block after the template's standard include set. The org_loader filters out the standard tokens, so only includes the template cannot derive – e.g. the header of a domain-enum column type such as ores.trading.api/domain/product_type.hpp for trade_type's product_type column – reach the emitted header. Org blocks that merely repeat the standard set leave regeneration byte-identical.

The filter (org_loader's _ENTITY_HEADER_STANDARD_INCLUDES) also drops the tokens org blocks add that no emitted member can require, and applies to junction entity headers as well as domain ones:

  • boost/uuid/uuid.hpp is never needed in an org block: the template emits it under has_uuid_columns, which counts every uuid-typed member the header declares, including a junction's PK and FK sides;
  • <cstdint> is a stale transcription of headers no entity member needs; the canonical entity headers compile without it and the drift registry pins them byte-for-byte.

Without these drops, the whole-estate drift check flags the four registered-component headers whose orgs declare them (compute app_version_platform, iam account_party, reporting report_definition and report_instance). A real future need for one of these headers in the entity header belongs in this template's fixed include set, not in an org block.

2.2. Domain entity and junction

Both the {{#domain_entity}} and {{#junction}} sections use the db_timestamp type (ores::database::repository::db_timestamp, from db_types.hpp) for valid_from and valid_to, and both use the component_core_upper-based include guard.

3. See also

Emacs 29.3 (Org mode 9.6.15)