Codegen entity meta-model — keys and columns
Table of Contents
This page is a segment of the Codegen org-entity meta-model hub. It is the one segment that does not map to a single facet — a column declaration is relevant to both SQL (to generate the table's DDL) and C++ Domain/C++ Repository (to generate the domain struct field and the sqlgen-mapped entity field), so it was abstracted into a segment of its own rather than duplicated in each. Author a column once here; it becomes a SQL column, a domain struct field, and a repository entity field, all three kept in sync by construction.
This page splits its fields across two diagrams, per Applied MASD § "The entity model file as a unified literate document":
- Structural fields — always part of the entity's shape — drawn as
a UML class diagram under Flags below: the identity properties
(
:schema:,:product:,:component:) and the Primary key, Natural key, and Column property sets. - Non-structural — two authored, optional VMM features — drawn as a
UVL feature diagram under Multi-tenancy below:
:has_tenant_id:and:has_workspace_id:.
Physical model mapping
This segment projects into three facets in physical space:
| Facet | Description |
|---|---|
| ores.sql.schema | Bi-temporal schema: table create/drop, insert triggers, notify triggers. |
| ores.cpp.domain | Domain types: class, JSON I/O, table I/O. |
| ores.cpp.repository | Repository layer: entity, mapper, CRUD. |
Flags
Cross-cutting properties consulted by both the SQL and C++ pipelines, set once at the top of the file:
| Property | Required | Meaning |
|---|---|---|
:schema: |
yes | Postgres schema (almost always public). |
:product: |
yes | Top-level C++ namespace (ores). |
:component: |
yes | Component name (refdata, trading, …) — drives both the C++ namespace and the <product>_<component>_... SQL naming convention. |
:has_tenant_id: |
no | See Multi-tenancy below. |
:has_workspace_id: |
no | See Multi-tenancy below. |
Structural view — the identity properties above, plus the Primary key, Natural key, and Column property sets documented further down this page:
(Source: entity_meta_model_keys_and_columns.puml, rendered with
plantuml.)
* Flags
,:PROPERTIES:
,:schema: public
,:product: ores
,:component: refdata
,:has_tenant_id: true
,:END:
Multi-tenancy: has_tenant_id=/=has_workspace_id
Setting :has_tenant_id: true tells the generator to emit a
tenant_id uuid not null column on the table and a matching field on
the domain struct, isolating the entity's rows by tenant; omit it
only for genuinely global entities (currencies, countries).
:has_workspace_id: does the same for workspace-scoped isolation.
Non-structural view — neither property is itself a field of the
entity: authoring :has_tenant_id: true produces no field named
has_tenant_id anywhere in the generated code. Rather, the generator
reads it to decide whether to branch into the template logic that
emits the tenant_id column and field. That the resulting column
exists is a structural fact about the entity once the decision is
made; the decision itself is a genuine, authored VMM feature, no
different in kind from SQL's :has_parent_id::
Primary key
The entity's surrogate key. In SQL this becomes part of the
composite primary key (paired with tenant_id and the temporal
range — see SQL); in C++ it becomes an sqlgen::PrimaryKey<T>-wrapped
field on the repository entity (not on the domain struct — the
domain struct exposes it as a plain field, the wrapping is a
repository-layer concern).
| Property | Required | Meaning |
|---|---|---|
:column: |
yes | SQL column name. |
:type: |
yes | SQL type (uuid, text, etc.). |
:cpp_type: |
yes | C++ type (boost::uuids::uuid, std::string, …). |
Example of book's primary key:
* Primary key
,:PROPERTIES:
,:column: id
,:type: uuid
,:cpp_type: boost::uuids::uuid
,:END:
UUID uniquely identifying this book.
Generates, in the repository entity (book_entity.hpp):
struct book_entity { constexpr static const char* schema = "public"; constexpr static const char* tablename = "ores_refdata_books_tbl"; sqlgen::PrimaryKey<std::string> id; // ... };
(book's primary key is actually text, not uuid — see C++ Qt's
:has_uuid_primary_key: knob, which governs how the Qt layer
treats whichever type is declared here; the SQL/repository/domain
layers just use whatever :type:=/:cpp_type:= says, uuid or not.)
Natural keys
A container for natural-key sub-headings — the human-meaningful
column(s) that uniquely identify a record within a tenant (as
opposed to the surrogate Primary key above, which exists purely
for foreign-key stability). Each ** sub-heading is one natural key,
using the same property shape as a column (see below), and may carry
a generator babel block for synthetic test data.
Columns
A container for the entity's remaining column sub-headings. Each
** sub-heading is one column, its heading title the column name.
| Property | Required | Meaning |
|---|---|---|
:type: |
yes | SQL type. |
:cpp_type: |
yes | C++ type. |
:nullable: |
no | true for nullable columns; default false. |
Each column's body is split into a description (first paragraph —
becomes the field's doc-comment) and an optional detail (second
paragraph onward — extra context for a human reader, not emitted
into generated code). A column may also carry a generator babel
block: a C++ expression producing a synthetic value for that field,
used by the C++ Generator facet.
Example of book's name column:
** name ,:PROPERTIES: ,:type: text ,:cpp_type: std::string ,:nullable: false ,:END: Human-readable identifier for this book. Unique per tenant; used as the natural key in the Qt list window. #+begin_src cpp :name generator ,std::string(faker::word::adjective()) + "_" + std::string(faker::word::noun()) #+end_src
Generates, in the domain struct (book.hpp):
namespace ores::refdata::domain { struct book { // ... std::string name; // ... }; }
And, in the SQL table DDL (refdata_books_create.sql):
create table if not exists "ores_refdata_books_tbl" ( "id" uuid not null, "tenant_id" uuid not null, "version" integer not null, "party_id" uuid not null, "name" text not null, "description" text null, -- ... );
See also
- Codegen org-entity meta-model — the hub.
- SQL — how these columns become the table's DDL, temporal constraints, and triggers.
- Variability — the structural/non-structural distinction referenced above.
- C++ Domain — how they become the plain domain struct.
- C++ Repository — how they become the sqlgen-mapped entity and mapper.