Commit cc4b4fd
fix: ADR-0039 — resolving accessors are the default (own*() breaks extends) — all 5 ports (#138)
* fix(metadata): ADR-0039 — resolving accessors are the default (TS reference)
extends is a super-REFERENCE, not a flatten: inherited attrs/children/isArray
live on the parent, reachable only through the resolving accessors. Reading a
field/node's effective property or member set through an own-only accessor
silently dropped everything inherited via extends — corrupting codegen, runtime,
effective serialization, and schema. Flip own→resolving everywhere except the
sanctioned emit-declared-here cases (codegen subclass-emit ownFields, own-mode
canonical serializer, overlay/super-resolution walks) and the deliberately
own-only @dbColumnType (physical, never inherited).
New: MetaData.resolvedIsArray() — the resolving accessor for the native isArray
flag (isArray is a boolean property, not an attr, so it has no attrs()-based
resolution path). All codegen/runtime/effective-serializer reads of a node's
array-ness now route through it.
Fixed helpers + sites:
- meta-field.ts getters (objectRef/column/default/defaultValue/maxLength/
precision/scale/unique/isRequired) → attr() resolving.
- meta-identity.ts + meta-relationship.ts getters → resolving.
- naming.resolveColumnName, serializer-json effective isArray, object-serializer,
validation-passes (field.object @objectref + field.map + flattened-array),
migrate-ts expected-schema (@storage/@unique/@objectRef/@default/@autoSet/
@maxLength/@precision/@scale/@localTime/isArray; @dbColumnType kept own) +
referential-actions.isRequired, runtime-ts object-manager PK lookup,
type-coercer jsonb (@storage resolve, @dbColumnType own), extract-object
(@required/@values/@enumAlias/@normalize/isArray), codegen-ts inferred-types/
zod-validators/payload/projection/output-parser/fr010/template-data/
docs-data-builder/column-mapper, codegen-ts-react form-file.
Conformance fixture (fails on pre-fix code): abstract field.string(isArray+
@maxlength) / field.decimal(@precision/@scale) / field.object(@objectref+@storage
+isArray) each extended by a concrete field, plus a BaseEntity(uuid PK+timestamp)
extended by a concrete entity. The effective serializer + validation own-reads
both broke pre-fix (ERR_OBJECT_FIELD_WITHOUT_OBJECT_REF + effective isArray
mismatch). Plus a codegen gate asserting the Drizzle schema honors every
inherited value.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GF9xLEQZaPus5Y6opk398n
* fix(csharp): ADR-0039 — resolving accessors are the default (C# port)
extends is a super-REFERENCE, not a flatten: inherited attrs/children/isArray
live on the parent, reachable only through the resolving accessors. Reading a
field/node's effective property or member set through an own-only accessor
silently dropped everything inherited via extends — corrupting codegen (EF
entities/DbContext/routes/payload/extract), effective serialization, and loader
validation. Flip own→resolving everywhere except the sanctioned emit-declared-here
cases (codegen subclass-emit OwnFields/OwnChildren, the own-mode canonical
serializer, overlay/super-resolution walks, projection OwnSources) and the
deliberately own-only @dbColumnType (physical, never inherited). Mirrors the TS
reference (d62aab5).
New: MetaData.ResolvedIsArray() — the resolving accessor for the native isArray
flag (isArray is a bool property, not an attr, so it has no Attrs()-based
resolution path); walks own→super, own true wins, cycle-guarded, cached. All
codegen/effective-serializer reads of a node's array-ness route through it.
Fixed helpers + sites:
- MetaField getters (ObjectRef/ValueType/Storage/DbColumn/Default/DefaultValue/
MaxLength/Precision/Scale/Unique + the @required half of IsRequired) → resolving
Attr(); DbColumnType + EnumValues KEPT own (commented).
- MetaSource + MetaRelationship getters → resolving (reconciled with the already-
resolving MetaIdentity).
- SerializerJson effective-mode isArray → ResolvedIsArray (own mode keeps IsArray);
ValidationPasses field.object @objectref + flattened-array isArray + field.map
@valueType/@objectref → resolving.
- Codegen: CSharpNaming (IsRequired/IsLocalTime/RequiresSystemNet), EntityGenerator/
DbContextGenerator/RoutesGenerator isArray, PayloadCodegen (@objectref + isArray),
ExtractObject (@required/@values/@enumAlias/@normalize/@default/@coerceDefault/
@xmlText/isArray), TemplateData, Fr010FieldMapping (dropped the dead OwnAttr
("isArray") clause; @required/@values/@default/@coerceDefault/@normalize/@xmlText
→ resolving).
Gate: the shared cross-port fixture
fixtures/conformance/extends-abstract-field-inheritance now passes in C#
(effective serializer + loader), and a new C# codegen honor-inheritance test
asserts the generated Contact entity honors inherited isArray/@maxLength/
@precision/@objectRef/@storage + the BaseEntity UUID PK. No golden changed.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GF9xLEQZaPus5Y6opk398n
* fix(metadata): ADR-0039 — resolving accessors are the default (Python port)
extends is a super-REFERENCE, not a flatten: inherited attrs/children/isArray
live on the parent, reachable only through the resolving accessors. Reading an
effective property or member set through an own-only accessor silently dropped
everything inherited via extends. Python's naming is INVERTED vs TS/Java —
attr(name) is OWN-ONLY, attrs().get(name) resolves — so this port both fixes the
own reads and makes the resolving form the obvious/default-named call.
Naming (the durable hardening): a full attr()->own_attr() rename was too invasive
(148 call sites, many legitimately own-only in the loader-validation of authored
declarations, plus the own-mode serializer/merge which already use own_meta_attrs/
own_children — NOT attr()). Instead:
- added MetaData.get_meta_attr(name) — the RESOLVING attr read (own + inherited
via the super chain); the default read to prefer for any effective property.
- added MetaData.resolved_is_array() — isArray is a native boolean property (not
an attr), so it resolves the native flag through the super chain OR the loaded
@isarray attr. Mirrors the TS resolvedIsArray().
- re-documented attr() LOUDLY as OWN-ONLY, calling out the TS/Java inversion and
naming the only sanctioned own uses (own-mode serialize, overlay/merge + super
walks, validating the own declaration, @dbColumnType).
Fixed effective-property reads (own -> resolving):
- meta_field.object_ref: attr()->get_meta_attr (unifies with codegen attrs().get
@objectref — both now resolve).
- codegen fr010_field_mapping: is_array->resolved_is_array; coerceDefault/default/
normalize (_attr_string) -> get_meta_attr.
- codegen type_map.field_is_array + template_codegen/template_data (isArray/
required/maxLength) -> resolving.
- codegen fr019_shared_enum.is_provided (@provided) -> get_meta_attr.
- runtime object_manager: identity @fields (PK lookup), @localTime, @column,
field-is-array -> resolving; @dbColumnType kept own-only (commented — the one
deliberately never-inherited attribute).
- loader validation_passes: field.object @objectRef/@storage/isArray + field.map
@valueType/@objectref + effective-children iteration -> resolving (a concrete
field.object inheriting @objectref from an abstract parent no longer falsely
trips ERR_OBJECT_FIELD_WITHOUT_OBJECT_REF). The own-declaration validators
(@values / @default / @dbColumnType membership) stay own-only, commented.
- serializer_json: EFFECTIVE mode now resolves isArray through the super chain;
own mode still emits the authored flag (round-trips the extends tree).
KEPT own-only (each commented): the sanctioned emit-declared-here case
(EntityModelGenerator.own_fields, pinned by test_entity_model.py — a Contact
subclass extends the generated BaseEntity and does NOT re-emit inherited id/
createdAt); the own-mode canonical serializer; overlay/merge + TPH discriminator
super-resolution walks; the loader's validate-the-own-declaration passes; and the
physical @dbColumnType.
The shared cross-port fixture fixtures/conformance/extends-abstract-field-
inheritance (unchanged) now passes — the effective serializer previously dropped
the inherited isArray:true on tags/addresses. New Python codegen gate
(test_extends_abstract_field_inheritance.py) asserts a concrete field extending an
abstract array/decimal/object field, and an entity inheriting fields via
BaseEntity, generate correctly (list[str] / list[Address] / Decimal / subclass-
emit). Existing goldens unchanged for non-abstract-extends inputs (full non-
integration suite green except 2 pre-existing, unrelated staleness-nudge failures).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GF9xLEQZaPus5Y6opk398n
* fix(jvm): ADR-0039 — resolving accessors are the default (Java + Kotlin port)
extends is a super-REFERENCE, not a flatten: inherited attrs/children/isArray
live on the parent, reachable only through the resolving accessors. Reading a
field/node's effective property or member set through an own-only accessor
silently dropped everything inherited via extends — corrupting codegen (an
entity inheriting its source.rdb emitted NOTHING), effective serialization,
and loader validation. Mirrors the TS reference.
The isArray resolver
- MetaField.isArrayType() now FULLY resolves: it walks the extends super chain
for the native isArray flag (resolvedNativeIsArray) as well as the @isarray
attr, so a concrete field extending an abstract array field is array-typed.
isArray() stays the own-only raw flag; all codegen array reads route through
isArrayType().
Metadata core
- MetaObject.getSources() no-arg now RESOLVES (getSources(true)), matching
getMetaFields()/getIdentities()/getRelationships(). The declaration-layer
one-primary-source validation keeps own-only via explicit getSources(false).
- ValidationPhase: field.object @objectRef/@storage and field.map
@valueType/@objectref reads flipped own→resolving (fixed the shared fixture's
false ERR_OBJECT_FIELD_WITHOUT_OBJECT_REF for a field.object extending an
abstract AddressBag). @dbColumnType stays own-only (commented).
- CanonicalJsonSerializer: effective mode now inlines inherited array-ness
(getNativeIsArray resolves via isArrayType in effective mode; own mode keeps
the raw flag so the authored form round-trips).
Java codegen (codegen-spring)
- SpringTypeMapper / SpringPayloadGenerator / OutputFormatSpecEmitter: raw
field.isArray() → resolving isArrayType(); OutputFormatSpecEmitter
@enumDoc/@example/@Instruction flipped own→resolving (consistent with the
already-resolving @values/@required).
Kotlin codegen (codegen-kotlin)
- New resolving source lookup KotlinGenUtil.firstRdbSource/hasRdbSource
(getSources(true)); routed ALL 8 generators' own-only
entity.children.filterIsInstance<RdbSource>() reads through it — an entity
inheriting its source.rdb via extends now emits its table/controller/etc.
- KotlinTypeMapper: intAttr (@precision/@scale) and stringAttr default
(@valueType) flipped own→resolving (consistent with stringMaxLength).
- KotlinExtractSchemaEmitter / KotlinOutputFormatSpecEmitter: raw .isArray →
isArrayType(); @enumDoc/@example/@Instruction → resolving.
- KotlinEntityGenerator.validator(): raw field.children →
getChildren(MetaValidator, true).
Kept own-only (each commented): @dbColumnType (never inherited by policy);
one-primary-source validation (declaration-layer); @isAbstract/@discriminator/
@provided/@kind/template-ref reads; origin.* reads (origin never inherits).
Tests
- New KotlinAbstractFieldExtendsInheritanceTest gates the two ADR-0039 shapes:
a concrete entity inheriting its source.rdb via extends emits an Exposed
table, and concrete fields extending an abstract array field / abstract
decimal field inherit isArray / @precision+@scale. Verified it FAILS on
pre-fix code.
- Shared fixtures/conformance/extends-abstract-field-inheritance now passes in
the Java conformance runner (loader + effective serializer). Fixture unchanged.
All green: Java metadata+codegen-spring 158, Java conformance 394, Kotlin
codegen 266, Kotlin integration (Testcontainers) 92, Java integration
(Testcontainers) 86. No existing goldens/snapshots changed.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GF9xLEQZaPus5Y6opk398n
---------
Co-authored-by: Doug Mealing <noreply@anthropic.com>1 parent 999269c commit cc4b4fd
74 files changed
Lines changed: 1390 additions & 294 deletions
File tree
- fixtures/conformance/extends-abstract-field-inheritance
- input
- server
- csharp
- MetaObjects.Codegen.Tests
- MetaObjects.Codegen
- Generators
- Runtime
- TemplateCodegen
- MetaObjects
- Loader
- Meta
- java
- codegen-kotlin/src
- main/kotlin/com/metaobjects/generator/kotlin
- apidocs
- test/kotlin/com/metaobjects/generator/kotlin
- codegen-spring/src/main/java/com/metaobjects/generator/spring
- metadata/src/main/java/com/metaobjects
- field
- io/json
- loader
- object
- python
- src/metaobjects
- codegen
- generators
- template_codegen
- loader
- meta
- core/field
- runtime
- tests/codegen
- typescript/packages
- codegen-ts-react/src/templates
- codegen-ts
- src
- generators
- template-codegen
- templates
- test
- fixtures
- metadata/src
- core
- field
- identity
- relationship
- loader
- migrate-ts/src
- runtime-ts/src
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 142 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
Lines changed: 116 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
Lines changed: 103 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
0 commit comments