Skip to content

Commit f305599

Browse files
dmealingclaude
andcommitted
docs(naming): CHANGELOG upgrade-impact notes; README per-port table covers every refusal test file
CHANGELOG: spell out, for an already-plural entity name, exactly what changes on upgrade (REST path, generated hook/query/finder/list names, DbSet/collection names — old doubled URLs 404, hand-written code importing the old symbol fails to compile/import after regen), what does NOT change (default physical table/column names, frozen on purpose), that there is no per-entity override for a route or generated name (TS `overrides` renames only the Drizzle variable), and that a same-scope Singular/Plural entity pair is now a generation error rather than a silent collision. README: the per-port table only named the FIRST test file touched for C#/Java/Python, missing the dedicated collision-refusal test files/theories each port ended up with (CSharpNamingTests.cs's own theory, Java's RouteNamingTest additions, Python's separate test_collection_name_collision.py). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01M1mRRB1K2WdYy82kntMQdx
1 parent 7c00cfa commit f305599

2 files changed

Lines changed: 43 additions & 18 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 40 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,23 +19,48 @@ here.**
1919
ending in "s" as already-plural UNLESS the character before that final "s" is one of
2020
s/u/i/a (so `Stats`/`Settings`/`Series`/`News`/`Analytics`/`Photos` stay unchanged, while
2121
`Status`/`Address`/`Bonus`/`Alias`/`Gas`/`Analysis` keep pluralizing exactly as before —
22-
the heuristic's one documented miss is `Lens` → `Lens`, correct plural `Lenses`). The
23-
DEFAULT PHYSICAL table/column name derivation is explicitly **frozen** at the old
24-
suffix-only rule in every port (a new, separately-named/byte-for-byte-preserved function
25-
where the two pluralizers were previously the same function), so an adopter's existing
26-
database never sees `meta migrate` propose a rename for an already-plural entity it
27-
didn't touch. Fixing the doubling surfaced two further, narrower defects it was
28-
incidentally masking: a TypeScript already-plural entity's generated Drizzle collection
29-
variable name could collide with its own singular row variable in the same statement
30-
(`const [x] = await db.insert(x)...`, a TDZ compile error) — the colliding local variable
31-
now gets a `Row` suffix only in that exact case; and a C# already-plural entity's own
32-
`DbSet` property name could collide with its own entity TYPE name inside `OnModelCreating`
33-
(C# resolves a bare same-named reference to the DbSet member before the type, same
22+
the heuristic's one documented miss is `Lens` → `Lens`, correct plural `Lenses`).
23+
24+
**Upgrade impact — read before regenerating.** If any entity name in your model is
25+
already a plural noun (`Stats`, `Settings`, `Series`, and the like):
26+
- **The REST collection path changes.** `/program_purchase_statses` becomes
27+
`/program_purchase_stats`. A client still calling the old doubled URL gets a plain
28+
404, not a redirect — update callers before or alongside the regen.
29+
- **Generated hook, query, finder, and list function/method names change too**
30+
(`useProgramPurchaseStatses` → `useProgramPurchaseStats`, `listProgramPurchaseStatses`
31+
→ `listProgramPurchaseStats`, the C# DbSet property, the Java/Python finder/router
32+
names). Any hand-written code importing or calling the OLD doubled symbol fails to
33+
compile (TS/C#/Kotlin) or import (Python) after you regenerate — grep for the old
34+
spelling across your own code, not just generated output.
35+
- **There is no per-entity override for a route or generated hook/finder/list name.**
36+
TypeScript's `variableNameFromEntity`/`CollectionNameOptions.overrides` renames only
37+
the Drizzle collection VARIABLE — it does not touch the REST path or any hook/query/
38+
finder/list name. If the new spelling is wrong for your API, the fix is to rename the
39+
entity itself; there is no config knob that renames only the generated surface.
40+
- **Default PHYSICAL table and column names do NOT change.** The fallback used when
41+
metadata declares no explicit physical name is explicitly **frozen** at the old
42+
suffix-only rule in every port (a new, separately-named, byte-for-byte-preserved
43+
function where the two pluralizers were previously the same one) — `meta migrate`
44+
proposes no rename for an already-plural entity you didn't touch.
45+
- **Two entities in one generation run whose names now land on the same API-surface
46+
collection name is a GENERATION ERROR, not a silent collision.** `Address` + `Addresses`
47+
(or `Order` + `Orders`) both resolve to `/addresses` / `/orders` once an already-plural
48+
name stops doubling — before this fix they did not collide (`Addresses` doubled to
49+
`addresseses`). Every port now refuses such a model outright, before any generator
50+
runs, naming both entities and the colliding name; rename one entity to proceed. New
51+
cross-port fixture corpus `fixtures/naming-conformance/` carries both the already-plural
52+
cases and the expected-collision cases, run by every port.
53+
54+
Fixing the doubling also surfaced two further, narrower defects it was incidentally
55+
masking: a TypeScript already-plural entity's generated Drizzle collection variable name
56+
could collide with its own singular row variable in the same statement (`const [x] =
57+
await db.insert(x)...`, a TDZ compile error) — the colliding local variable now gets a
58+
`Row` suffix only in that exact case; and a C# already-plural entity's own `DbSet`
59+
property name could collide with its own entity TYPE name inside `OnModelCreating` (C#
60+
resolves a bare same-named reference to the DbSet member before the type, the same
3461
shadowing class as the pre-existing `Address`/`Addresses` cross-entity hazard) — the
3562
TPH-discriminator and int-backed-enum nested-type references are now `global::`-qualified
36-
when (and only when) the owning entity's name is itself already-plural. New cross-port
37-
fixture corpus `fixtures/naming-conformance/` proves all five ports agree on both the
38-
API-surface and frozen-legacy pluralizers for the same input set.
63+
when, and only when, the owning entity's name is itself already-plural.
3964

4065
- **Kotlin: two pre-existing generated-controller compile defects, found extending the
4166
`exposedApi=1` controller-tier compile check.** Both were excluded (not fixed) when that

‎fixtures/naming-conformance/README.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,9 @@ Each port's existing naming unit-test file reads this JSON and asserts both
9393
| Port | Test file |
9494
|---|---|
9595
| TypeScript | `server/typescript/packages/metadata/test/naming.test.ts` (pluralizers); `server/typescript/packages/codegen-ts/test/naming/collection-name-collision.test.ts` (refusal — `assertNoCollectionNameCollisions`, wired into `runGen` in `runner.ts`) |
96-
| C# | `server/csharp/MetaObjects.Codegen.Tests/CSharpNamingTests.cs` (pluralizers); `server/csharp/MetaObjects.Codegen.Tests/DbContextForeignKeyConfigTests.cs` (refusal — the historical Address/Addresses fixture, now an expected-error test) |
97-
| Java / Kotlin | `server/java/codegen-base/src/test/java/com/metaobjects/generator/util/RouteNamingTest.java` (pluralizers; Kotlin inherits — `KotlinNaming.collectionSegment` delegates to the same `RouteNaming.pluralize`) |
98-
| Python | `server/python/tests/codegen/test_route_path_naming.py` (pluralizers) |
96+
| C# | `server/csharp/MetaObjects.Codegen.Tests/CSharpNamingTests.cs` (pluralizers + refusal — `CSharpNaming.AssertNoCollectionNameCollisions`, wired into `CodegenRunner.Run`); `server/csharp/MetaObjects.Codegen.Tests/DbContextForeignKeyConfigTests.cs` (the historical Address/Addresses fixture, now an expected-error test at both the unit and `CodegenRunner.Run` integration level) |
97+
| Java / Kotlin | `server/java/codegen-base/src/test/java/com/metaobjects/generator/util/RouteNamingTest.java` (pluralizers + refusal — `RouteNaming.assertNoCollectionNameCollisions`, wired into `MetaDataGeneratorMojo#executeGenerators`; Kotlin inherits both — it runs through the same Maven goal) |
98+
| Python | `server/python/tests/codegen/test_route_path_naming.py` (pluralizers); `server/python/tests/codegen/test_collection_name_collision.py` (refusal — `assert_no_collection_name_collisions`, wired into `run_gen` in `runner.py`) |
9999

100100
No HTTP server, no database — this corpus is intentionally a pure function
101101
check, unlike `api-contract-conformance` (which is the right place for the

0 commit comments

Comments
 (0)