The decorator's save() flow now preserves the live row's id PK across
updates and captures each prior version as a fresh row with a new id.
This unblocks fewo-webapp#459: the consumer's composite-FK schema needs
stable child references to the live row (UNIQUE(entity_id, valid_until)
with ON UPDATE CASCADE on every child FK), which the previous
close-then-insert flow couldn't provide.
New flow on update (when a live row exists for entity_id):
1. Clone the live row in memory (cloneDto via oatpp reflection),
assign a fresh id and set valid_until=now, save → INSERT historical.
2. Set the new dto's id=live.id (preserve PK), valid_from=now,
valid_until=SENTINEL, save → inner UPDATEs the live row in place by
PK.
Inner adapter contract changes from "upsert keyed by (entity_id,
valid_from)" to "upsert keyed by id (per-row PK)". TemporalFieldTraits
gains an id() accessor; OATPP_AUTHKIT_REGISTER_TEMPORAL grows from 4 to
5 args (Dto + IdMember + EntityIdMember + FromMember + UntilMember).
Tests: test_repository_decorators asserts livePk stability across saves
and fresh historicalPk per version; remaining decorator tests updated to
the 5-arg macro form. README's TemporalRepository.hpp row rewritten to
describe the new write semantics.
Bumped CMake version 0.7.0 → 0.8.0 (semantic break — save() no longer
reallocates the live PK; consumers depending on the old contract need
audit).
Closes#13
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Each decorator now bundles its schema prereqs alongside its code via
DecoratorPrereq (additive CREATE-IF-NOT-EXISTS) and ReshapeStep
(non-idempotent reshape gated on a detectSql probe).
applyDecoratorMigrations<Decorators...>(table, probe, exec, recorder)
walks the listed decorators at startup, runs every PREREQ, runs every
reshape step whose probe returns false. Database-agnostic — consumer
wires probe/exec to their DbClient. SCHEMA_MIGRATIONS_TABLE_SQL is
provided for observability; the detect-probe is the source of truth.
TemporalRepository ships add_valid_from / add_valid_until /
drop_unique_entity_id / composite_unique (UNIQUE(entity_id, valid_until)
so close-then-insert can run in a deferred-FK transaction).
AuditLogRepository ships the audit_log CREATE TABLE.
ScopeGuardRepository ships nothing — exposes empty PREREQ + zero-length
RESHAPE_STEPS so it can be listed in applyDecoratorMigrations alongside
the schema-touching decorators without SFINAE.
Closes#12
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>