Skip to content

Commit 3f0daa8

Browse files
Yaraslau Tamashevichclaude
andcommitted
docs: describe the reference schema structurally, without naming it
The relation-generation notes and one test comment identified the production database, its schema and five of its table/column names. None of that is needed: the generation rules are derived from structural shapes and their counts, which are what the documents actually reason about. Replaces the identifying detail with neutral equivalents - the join-table examples keep their shape (two columns, each a single-column foreign key to a distinct table, composite primary key over exactly those two) under generic names. Also refreshes the status section, which still said the inverse and through relations were never generated, and points at CompositeForeignKey for the composite foreign keys it lists as unrepresentable. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TVec3YeQg2FZnToiPQwcQH
1 parent ecd43d3 commit 3f0daa8

2 files changed

Lines changed: 25 additions & 19 deletions

File tree

docs/ddl2cpp-relation-generation.md

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22

33
## Status
44

5-
`ddl2cpp` currently emits exactly one relation type: `Light::BelongsTo`, on the child side of a
6-
single-column foreign key. The inverse and through relations that `DataMapper` supports —
7-
`HasMany`, `HasManyThrough`, `HasOneThrough` — are never generated, so a generated model is
8-
navigable only from child to parent.
5+
`ddl2cpp` generates `Light::BelongsTo` on the child side of a single-column foreign key, and — as of
6+
the relation-generation work on this branch — the inverse and through relations too: `HasMany`,
7+
`HasManyThrough` and `HasOneThrough`. See `src/tests/CxxModelRelationTests.cpp` for the rule-by-rule
8+
coverage.
99

10-
This page records what a real production schema needs, and what is genuinely not representable.
10+
This page records what a real production schema needs, which shapes are deliberately *not* collapsed,
11+
and what remains genuinely not representable.
1112

1213
> **Depends on the relation selectors from PR #528.** Generating inverse relations for a real schema
1314
> is impossible without them: this reference schema has table pairs joined by up to **55** foreign
@@ -18,15 +19,19 @@ This page records what a real production schema needs, and what is genuinely not
1819
> rather than from `master`, and must not merge ahead of it.
1920
2021
There is also **no `HasOne`** type in the library — only `HasOneThrough`. A one-to-one relation that
21-
is *not* across a join table has no representation, so the plan below records it as
22-
`Kind::HasOne` and the emitter falls back to `HasMany` for it, with a note in the generated header.
23-
Adding a real `HasOne` is out of scope here.
22+
is *not* across a join table has no representation, so the planner records it as `Kind::HasOne` and
23+
the emitter falls back to `HasMany`, with a note in the generated header saying why. Adding a real
24+
`HasOne` is out of scope here.
25+
26+
Composite foreign keys remain ungenerated, but are no longer inexpressible: see
27+
`docs/composite-keys-design.md` for `CompositeForeignKey` / `Connection`. Teaching the generator to
28+
emit them is the natural follow-up.
2429

2530
## Reference schema
2631

27-
The numbers below come from the `konrad_english` database used by the Lastrada application
28-
(MS SQL Server 2022, single schema `lasa`), which is the largest schema this generator is pointed
29-
at in practice.
32+
The numbers below come from a large production schema (MS SQL Server 2022, single schema), the
33+
biggest this generator is pointed at in practice. Table and column names are not reproduced; only
34+
the structural shapes and their counts, which is what the generation rules are derived from.
3035

3136
| Metric | Count |
3237
|--------|-------|
@@ -69,10 +74,13 @@ Of those, **84 also have a composite primary key**, which is the classic many-to
6974
Concrete examples, both two-column tables:
7075

7176
```
72-
XLAB_PROJECT_USER (PROJECT_NR -> XLAB_PROJECT, USER_NR -> XLAB_USER)
73-
MANDANT_KUNDE (KUNDEN_NR -> KUNDE, MANDANT_NR -> MANDANTEN)
77+
project_user (project_id -> project, user_id -> user)
78+
tenant_customer (customer_id -> customer, tenant_id -> tenant)
7479
```
7580

81+
(Shapes reproduced with neutral names: two columns, each a single-column foreign key to a distinct
82+
table, composite primary key over exactly those two.)
83+
7684
Each should yield a `HasManyThrough` on both referenced tables. Because both foreign keys of the
7785
join record point at *different* tables here, the selectors are only needed when a join table
7886
points twice at the same target.

src/tests/CxxModelRelationTests.cpp

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,13 @@
88
// other table.
99
//
1010
// The shapes tested here are taken from the reference schema surveyed in
11-
// `docs/ddl2cpp-relation-generation.md` (the `konrad_english` database behind the Lastrada
12-
// application, 686 tables / 1860 foreign keys), reduced to the smallest fixtures that reproduce
13-
// each structural case found there:
11+
// `docs/ddl2cpp-relation-generation.md` (a large production schema, 686 tables / 1860 foreign keys),
12+
// reduced to the smallest fixtures that reproduce each structural case found there:
1413
//
1514
// - a plain parent/child pair -> HasMany
1615
// - two foreign keys from one child into one parent -> HasMany + selector (that schema has a
1716
// pair joined by 55 foreign keys)
1817
// - a two-column join table -> HasManyThrough on both sides
19-
// (e.g. XLAB_PROJECT_USER, MANDANT_KUNDE)
2018
// - a join table whose far key is uniquely indexed -> HasOneThrough
2119
// - a uniquely indexed child foreign key -> one-to-one
2220
// - a join table carrying payload columns -> NOT a join table (association object)
@@ -219,8 +217,8 @@ TEST_CASE("PlanRelations: a composite unique index does not make a relation one-
219217

220218
TEST_CASE("PlanRelations: a two-column join table yields HasManyThrough on both sides", "[CxxModelPrinter][relations]")
221219
{
222-
// Modelled on XLAB_PROJECT_USER(PROJECT_NR -> XLAB_PROJECT, USER_NR -> XLAB_USER) from the
223-
// reference schema: a composite primary key over exactly the two foreign keys, no payload.
220+
// The join-table shape found repeatedly in the reference schema: a composite primary key over
221+
// exactly the two foreign keys, and no payload columns.
224222
auto const tables = std::vector<Lightweight::SqlSchema::Table> {
225223
{ .schema = "", .name = "project", .columns = { IdColumn() }, .primaryKeys = { "id" } },
226224
{ .schema = "", .name = "user", .columns = { IdColumn() }, .primaryKeys = { "id" } },

0 commit comments

Comments
 (0)