Entity-table writes go through the repositories
Table of Contents
1. Summary
Application code writes an entity table only through the generated repository for that entity. The repository states the optimistic concurrency claim, stamps the audit columns, and applies the tenant and the party the row must carry; a hand-written write states all of that itself and drifts from the repository the moment either changes. Two classes are excepted: the sanctioned tenant purge and test fixtures. A check states the rule to a machine, and a ratchet baseline names the writers that predate it.
2. Detail
2.1. The rule
A table named ores_<component>_<entity>_tbl is an entity table. Only the
generated repository for that entity writes it. Neither a SQL function nor a
hand-written C++ file runs insert, update or delete against one.
The repository is where the shape of a write lives:
- The claim. Who last read the row, which the store checks before it writes.
- The audit.
modified_by,performed_by, the change reason and the comment. - The tenant and the party. Row-level security holds the written row to both.
2.2. The exceptions
The sanctioned purge. ores_iam_purge_tenant_fn deletes across the
component tables when a tenant is removed. It is the one function allowed to
write entity tables directly, and ores_iam_purge_test_tenants_fn is its test
counterpart.
Test fixtures. The SQL test tree, projects/ores.sql/test/, and every
tests directory, write the rows a repository would, so that a test can set
up the state it needs. They are not application code.
2.3. The check
projects/ores.codegen/scripts/check_entity_table_writes.py reads every SQL
function under projects/ores.sql/create/ and every hand-written C++ file
under projects/ores.*/. It fails on a writer of an entity table that is not
a repository, the purge or a fixture. It runs in
.github/workflows/codegen-drift.yml and locally:
python3 projects/ores.codegen/scripts/check_entity_table_writes.py
2.4. The ratchet baseline
projects/ores.codegen/scripts/entity_table_writes_baseline.json names the
writers that predate the rule, each with a reason. The check fails on a writer
that is not in it, and on an entry that no longer writes, so the list can only
shrink. Remove an entry when its writer is fixed. Run --write-baseline only
to accept a new writer, and state its reason.
3. See also
- No service reads or writes another component's tables — the sibling rule for whose table a component may reach.
- Data storage — the relational database and what reaches it.
- PostgreSQL Row-Level Security — the policies a written row is held to.
- ores.sql — the component that owns the DDL and the purge.