Codegen entity meta-model — C++ repository

Table of Contents

This page is a segment of the Codegen org-entity meta-model hub, covering the ores.cpp.repository facet: the persistence layer between the plain C++ Domain struct and the database — the entity, mapper, and repository classes, plus list/count/save/delete/get CRUD.

Physical model mapping

Facet Description
ores.cpp.repository Repository layer: entity, mapper, CRUD.

Flags

** Flags
,:PROPERTIES:
,:subcomponent: api
,:END:
Property Required Meaning
:subcomponent: no Sub-directory under the component the domain struct lives in (api is the default assumption; set when it diverges, e.g. a core-only helper type). Affects the #include paths the repository/service facets generate for this entity's domain header.

Repository naming

Naming-convention strings the templates need but cannot always derive mechanically from the entity's singular/plural forms (compound words, irregular plurals):

Property Meaning
:entity_singular_short: Short form used in generated variable names, e.g. currency.
:entity_plural_short: Plural short form, e.g. currencies (not just entity_plural with an "s" — irregular plurals need this spelled out).
:entity_singular_words: Human-readable singular, for doc-comments.
:entity_plural_words: Human-readable plural, for doc-comments.
** Repository
,:PROPERTIES:
,:entity_singular_short: currency
,:entity_plural_short:   currencies
,:entity_singular_words: currency
,:entity_plural_words:   currencies
,:END:

Entity includes

Same shape as C++ Domain's Domain includes, but for the repository entity header (the sqlgen-mapped struct) instead of the domain struct.

Generates, in book_entity.hpp:

#include "ores.database/repository/db_types.hpp"
#include "sqlgen/PrimaryKey.hpp"
#include <optional>
#include <ostream>
#include <string>

namespace ores::refdata::repository {

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

struct book_entity {
    constexpr static const char* schema = "public";
    constexpr static const char* tablename = "ores_refdata_books_tbl";

    sqlgen::PrimaryKey<std::string> id;
    // ... fields from Keys and columns ...
};

}

Conventions

Property Meaning
:iterator_var: Loop variable name used in generated range-based for loops over this entity's rows (defaults are usually fine; override for readability on an unusually-named entity).

Table display

An org table mapping column names to their display headers, consumed by more than one downstream facet (Qt list columns, CSV/XML export column headers) wherever a human-readable label is needed for a raw column name:

** Table display

| Column | Header |
|--------+--------|
| name   | Name   |
| party_id | Party |

Paste blocks

The ores.cpp.repository facet defines the following paste block kinds, one per sub-heading below — see Paste blocks for the general mechanism they assume.

Additional class-member declarations

Class-member declarations inserted just before the closing brace of the generated <entity>_repository class, expecting a declaration block.

Example of an inclusion of this paste block in a template:

    void remove(context ctx, const std::string& id);
    // <<paste:DCA78C69-E508-48D9-9972-A9B8094D91FB>>
};

To use this paste block on an entity, declare it under ** Paste blocks > *** Additional class-member declarations, one **** sub-heading per custom method. See the following example:

** Paste blocks
*** Additional class-member declarations
**** read_system_party
,:PROPERTIES:
,:ID: 9B7C5D2E-1A4F-4E7B-9D8A-6F3C2E1B5A4D
,:END:

Prose describing what this method does and why it cannot be templated.

#+begin_src cpp :name declaration :implements DCA78C69-E508-48D9-9972-A9B8094D91FB
std::vector<domain::party>
read_system_party(context ctx, const std::string& tenant_id);
#+end_src

Additional out-of-class implementations

Out-of-class method definitions inserted into the generated <entity>_repository.cpp, just before the closing namespace brace — the .cpp counterpart of the declaration above, expecting a body block. Multiple implementing blocks concatenate with a blank line between them.

Additional .cpp includes

Additional #include directives the implementations above need, inserted near the top of the generated <entity>_repository.cpp's include block, expecting a body block. Multiple methods may each declare their own includes block; the C++ compiler de-duplicates #include directives at preprocessing time regardless, so no need to worry about collisions between them.

See also

Emacs 29.3 (Org mode 9.6.15)