
Paul RastoinandGitHub
5544b5dcfe
Fix and refactor all metadata relation (#17978)
# Introduction
The initial motivation was that in the workspace migration create action
some universal foreign key aggregators weren't correctly deleted before
returned due to constant missconfiguration
<img width="2300" height="972" alt="image"
src="https://github.com/user-attachments/assets/9401eb02-2bb2-4e69-9c5f-9a354ff61079"
/>
It also meant that under the hood some optimistic behavior wasn't
correctly rendered for some aggregators
## Solution
Refactored the `ALL_METADATA_RELATIONS` as follows:
This way we can infer the FK and transpile it to a universalFK, also the
aggregators are one to one instead of one versus all available
Making the only manual configuration to be defined the `foreignKey` and
`inverseOneToManyProperty`
```
┌──────────────────────────────────────┐ ┌─────────────────────────────────────────────┐
│ ALL_MANY_TO_ONE_METADATA_FOREIGN_KEY│ │ ALL_ONE_TO_MANY_METADATA_RELATIONS │
│──────────────────────────────────────│ │─────────────────────────────────────────────│
│ Derived from: Entity types │ │ Derived from: Entity types │
│ │ │ │
│ Provides: │ │ Provides: │
│ • foreignKey │ │ • metadataName │
│ │ │ • flatEntityForeignKeyAggregator │
│ Standalone low-level primitive │ │ • universalFlatEntityForeignKeyAggregator │
└──────────────┬───────────────────────┘ └──────────────┬──────────────────────────────┘
│ │
│ foreignKey type + │ inverseOneToManyProperty
│ universalForeignKey derivation │ keys (type constraint)
│ │
▼ ▼
┌───────────────────────────────────────────────────────────────┐
│ ALL_MANY_TO_ONE_METADATA_RELATIONS │
│───────────────────────────────────────────────────────────────│
│ Derived from: │
│ • Entity types (metadataName, isNullable) │
│ • ALL_MANY_TO_ONE_METADATA_FOREIGN_KEY (FK → universalFK) │
│ • ALL_ONE_TO_MANY_METADATA_RELATIONS (inverse keys) │
│ │
│ Provides: │
│ • metadataName │
│ • foreignKey (replicated from FK constant) │
│ • inverseOneToManyProperty │
│ • isNullable │
│ • universalForeignKey │
└──────────────────────────┬────────────────────────────────────┘
│
┌──────────────────┼──────────────────┐
│ │ │
▼ ▼ ▼
┌───────────────────┐ ┌────────────────┐ ┌──────────────────────┐
│ Type consumers │ │ Atomic utils │ │ Optimistic utils │
│───────────────────│ │────────────────│ │──────────────────────│
│ • JoinColumn │ │ • resolve-* │ │ • add/delete flat │
│ • RelatedNames │ │ • get-* │ │ entity maps │
│ • UniversalFlat │ │ │ │ • add/delete │
│ EntityFrom │ │ │ │ universal flat │
│ │ │ │ │ entity maps │
└───────────────────┘ └────────────────┘ │ │
│ (bridge via │
│ inverseOneToMany │
│ Property → │
│ ONE_TO_MANY for │
│ aggregator lookup) │
└──────────────────────┘
```
### Previously
```
┌─────────────────────────────────────────────────────────────────────┐
│ ALL_METADATA_RELATIONS │
│─────────────────────────────────────────────────────────────────────│
│ Derived from: Entity types │
│ │
│ Structure: { [metadataName]: { manyToOne: {...}, oneToMany: {...},│
│ serializedRelations?: {...} } } │
│ │
│ manyToOne provides: │
│ • metadataName │
│ • foreignKey │
│ • flatEntityForeignKeyAggregator (nullable, often wrong/null) │
│ • isNullable │
│ │
│ oneToMany provides: │
│ • metadataName │
│ │
│ Monolithic single source of truth │
└──────────────────────────┬──────────────────────────────────────────┘
│
│ manyToOne entries transformed via
│ ToUniversalMetadataManyToOneRelationConfiguration
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ ALL_UNIVERSAL_METADATA_RELATIONS │
│─────────────────────────────────────────────────────────────────────│
│ Derived from: ALL_METADATA_RELATIONS (type-level transform) │
│ │
│ Structure: { [metadataName]: { manyToOne: {...}, oneToMany: {...} │
│ } } │
│ │
│ manyToOne provides: │
│ • metadataName │
│ • foreignKey │
│ • universalForeignKey (derived: FK → replace Id → UniversalId) │
│ • universalFlatEntityForeignKeyAggregator (derived from │
│ flatEntityForeignKeyAggregator → replace Ids → UniversalIds) │
│ • isNullable │
│ │
│ oneToMany: passthrough from ALL_METADATA_RELATIONS │
│ │
│ Duplicated monolith with universal key transforms │
└──────────────────────────┬──────────────────────────────────────────┘
│
┌──────────────────┼──────────────────────┐
│ │ │
▼ ▼ ▼
┌───────────────┐ ┌────────────────────┐ ┌──────────────────────┐
│ Type consumers│ │ Atomic utils │ │ Optimistic utils │
│───────────────│ │────────────────────│ │──────────────────────│
│ • JoinColumn │ │ • resolve-entity- │ │ • add/delete flat │
│ • RelatedNames│ │ relation-univ-id │ │ entity maps │
│ • Universal │ │ (ALL_METADATA_ │ │ (ALL_METADATA_ │
│ FlatEntity │ │ RELATIONS │ │ RELATIONS │
│ From │ │ .manyToOne) │ │ .manyToOne) │
│ │ │ │ │ │
│ Mixed usage │ │ • resolve-univ- │ │ • add/delete univ │
│ of both │ │ relation-ids │ │ flat entity maps │
│ constants │ │ (ALL_UNIVERSAL_ │ │ (ALL_UNIVERSAL_ │
│ │ │ METADATA_REL │ │ METADATA_REL │
│ │ │ .manyToOne) │ │ .manyToOne) │
│ │ │ │ │ │
│ │ │ • resolve-univ- │ │ universalFlatEntity │
│ │ │ update-rel-ids │ │ ForeignKeyAggregator │
│ │ │ (ALL_UNIVERSAL_ │ │ read directly from │
│ │ │ METADATA_REL │ │ the constant │
│ │ │ .manyToOne) │ │ │
│ │ │ │ │ │
│ │ │ • regex hack: │ │ │
│ │ │ foreignKey │ │ │
│ │ │ .replace(/Id$/, │ │ │
│ │ │ 'UniversalId') │ │ │
└───────────────┘ └────────────────────┘ └──────────────────────┘
```
2026-02-17 11:13:54 +01:00
..
2026-02-17 11:13:54 +01:00
2025-05-15 16:26:38 +02:00
2026-01-13 08:18:07 +00:00
2023-12-10 18:10:54 +01:00
2025-08-08 01:27:05 +02:00
2025-08-08 01:27:05 +02:00
2025-06-23 18:24:42 +02:00
2025-12-15 17:44:23 +01:00
2025-11-10 22:11:52 +01:00
2025-12-16 14:44:27 +01:00
2023-12-18 15:45:30 +01:00
2025-08-08 01:27:05 +02:00
2025-11-19 19:16:46 +01:00
2026-02-13 09:23:14 +00:00
2024-02-07 18:52:48 +01:00
2025-12-15 17:44:23 +01:00
2026-01-19 12:46:34 +01:00
2024-08-27 17:06:39 +02:00
2025-05-22 17:58:59 +02:00
2025-08-07 22:19:43 +02:00
2025-08-08 01:27:05 +02:00
2025-09-11 15:25:36 +00:00
2025-03-28 08:45:24 +01:00
2025-09-21 16:55:34 +02:00
2026-01-23 13:43:53 +01:00
2025-05-15 16:26:38 +02:00
2024-06-12 21:17:31 +02:00
2025-08-28 14:47:48 +02:00
2025-08-08 01:27:05 +02:00
2026-01-20 16:19:47 +00:00
2025-08-19 18:10:35 +02:00