Skip to content

content: Concrete value classes for each field #1424

Description

@grigasp

ContentDescriptor.fields is a flat Record<Field["id"], Field> keyed by PropertyField.computeId, which derives identity from the declaring class + property name + relationship path only. There is no content-source / target component in the key. When several content sources (one per selected class) surface a property declared on a shared ancestor, those occurrences collapse into a single fields entry. Any per-source decision — most importantly a propertyOverrides entry scoped to one class — then leaks onto every other source that shares the field.

Worked example (the requirement)

Two selected classes, Stuff.Door and Stuff.Window, both derive from Stuff.Thing, which declares Height. Today the descriptor contains exactly one field:

id:               "Stuff.Thing.Height"
sourceClassName:  "Stuff.Thing"   // declaring class
propertyName:     "Height"
pathFromTarget:   []

Desired behavior when a content modifier overrides Height specifically for Window (e.g. relabel/hide):

  • Door keeps an unmodified Height field.
  • Window gets a separate Height field carrying the override.

i.e. the descriptor must be able to represent two fields for the same declared property when — and only when — a per-source decision makes them diverge. While they remain identical (no scoped override), they stay merged as one field.

Worked example 2 (the harder requirement: related, polymorphic endpoint)

A fields provider loads related properties over bis.Element → bis.ExternalSourceAspect, surfacing Identifier (declared on the base ExternalSourceAspect). In the data, elements actually carry aspects of two concrete subclasses, ExternalSourceAspectX and ExternalSourceAspectY. Today that is a single field:

id:               "BisCore.ExternalSourceAspect.Identifier(<path>)"
sourceClassName:  "BisCore.ExternalSourceAspect"   // declaring class
propertyName:     "Identifier"
pathFromTarget:   [ Element→ExternalSourceAspect ]

Desired behavior when a modifier overrides Identifier specifically for ExternalSourceAspectX:

  • The ExternalSourceAspectY occurrence keeps an unmodified Identifier.
  • The ExternalSourceAspectX occurrence gets a separate Identifier field carrying the override.

The divergence axis here is not the selected primary class (Door/Window) — it is the concrete class of the related instance that supplies the value (ExternalSourceAspectX vs ExternalSourceAspectY). The provenance model must therefore key on the value-supplier class, which unifies both worked examples: for a direct property the value-supplier is the primary instance; for a related property it is the instance at the path's terminal end.

This is a prerequisite for implementing a descriptor transformer that can handle legacy content modifiers - propertyOverrides transformer cannot be made correct until the descriptor model can carry per-value-supplier provenance and split a shared field.

Metadata

Metadata

Assignees

Type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions