@g1cloud/entity-modeler-next 5.1.1 → 5.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent/resolver.d.ts +37 -0
- package/dist/core/columnResolve.d.ts +50 -1
- package/dist/core/embedSlots.d.ts +53 -0
- package/dist/entity-modeler.js +5407 -5328
- package/dist/entity-modeler.umd.cjs +18 -18
- package/package.json +1 -1
package/dist/agent/resolver.d.ts
CHANGED
|
@@ -76,6 +76,43 @@ export type ResolveError = {
|
|
|
76
76
|
opIndex: number;
|
|
77
77
|
handle: AssocHandle;
|
|
78
78
|
}
|
|
79
|
+
/**
|
|
80
|
+
* `association.add` 의 end 중 하나가 `JPA_EMBEDDABLE` — 임베더블은 독립 참조 대상이 아니라 owner 테이블로
|
|
81
|
+
* 평탄화되는 값이므로 그 관계는 **EMBED 여야** 한다(owner 의 `EMBED_OWN` 표시속성 + `end.composition` +
|
|
82
|
+
* `end.attributeRef` 셋이 EMBED 판정의 유일한 근거다 — `core/sharedColumn.sharedColumnScopeEntities`·
|
|
83
|
+
* `ddl.ts` 평탄화·코드젠 `@Embedded` 가 전부 그것을 본다).
|
|
84
|
+
*
|
|
85
|
+
* ★resolver 에는 **EMBED 관계 생성 어휘가 없다**(AA-5 S3 미구현). 그래서 통과시키면 *항상* 「스테레오타입은
|
|
86
|
+
* 임베더블인데 관계는 일반」 형상이 만들어지고, 그 형상은 **아무도 신호하지 않는다**: 공유 통화 스코프가
|
|
87
|
+
* 자기 자신으로 좁아져 owner 통화 컬럼을 `SHARED_REF` 로 고를 수 없고(GUI picker 후보 0 = 사용자에겐
|
|
88
|
+
* 「리졸빙 안 됨」으로만 보인다) DDL 은 컬럼을 평탄화하지 않으며 코드젠은 `@Embedded` 를 내지 않는다.
|
|
89
|
+
* 실측(2026-08-25 프로덕션): 이 형상 4건 중 1건이 증상으로 드러나고 3건은 잠복이었다.
|
|
90
|
+
*
|
|
91
|
+
* ⇒ GUI 는 이 조작을 애초에 EMBED 로 분기한다(`DiagramCanvas.vue` 연결 핸들러·`editor/association.ts`).
|
|
92
|
+
* 같은 불변식을 op 경로에서도 지킨다 — 어휘가 생기면(AA-5 S3) 거부 대신 EMBED 방출로 바뀔 자리다.
|
|
93
|
+
*/
|
|
94
|
+
| {
|
|
95
|
+
code: 'embeddable-relation-unsupported';
|
|
96
|
+
opIndex: number;
|
|
97
|
+
handle: AssocHandle;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* `entity.update` patch 의 `stereotype` 이 **`JPA_EMBEDDABLE` 경계를 넘음** — 이 전환은 단일 필드 쓰기가
|
|
101
|
+
* 아니라 **동반 명령을 가진 composite** 다(`editor/entity.ts` becomingEmbeddable/leavingEmbeddable):
|
|
102
|
+
* - 들어갈 때: 자기 PK 해제(임베더블은 `@Id` 불가 = `CHK-JPA-2`) + 보유 FK 제거·자식 cascade reconcile +
|
|
103
|
+
* 이 엔티티를 가리키는 일반 관계를 EMBED 로 복원(`enteringEmbeddableCommands`).
|
|
104
|
+
* - 나올 때: PK 자동 부여 + EMBED 관계를 일반 관계로 정규화(`leavingEmbeddableCommands`).
|
|
105
|
+
* 맨 patch 만 흘리면 PK·FK 잔재(`CHK-JPA-2` error)와 「임베더블인데 일반 연관」 형상이 동시에 남는다.
|
|
106
|
+
* ★`navigable-toggle-unsupported` 와 같은 근거의 구조 거부다 — *동반 작업이 GUI 소유*라 op 경로엔 표현이 없다.
|
|
107
|
+
* 경계를 넘지 않는 전환(예: `JPA_ENTITY`↔`JPA_MULTI_LANGUAGE_ENTITY`)은 그대로 통과한다.
|
|
108
|
+
*/
|
|
109
|
+
| {
|
|
110
|
+
code: 'stereotype-embeddable-transition-unsupported';
|
|
111
|
+
opIndex: number;
|
|
112
|
+
entity: Handle;
|
|
113
|
+
from: string;
|
|
114
|
+
to: string;
|
|
115
|
+
}
|
|
79
116
|
/** `type:'GroupCodeEnum'` 인데 `groupCode` 미동반 — groupCode 바인딩 없는 깨진 파생 타입 방지(B3). */
|
|
80
117
|
| {
|
|
81
118
|
code: 'groupcode-required';
|
|
@@ -1,4 +1,53 @@
|
|
|
1
|
-
import { Attribute, DbColumn, EmbeddableCatalog, Entity, LogicalModel } from './types';
|
|
1
|
+
import { Attribute, DbColumn, EmbeddableCatalog, Entity, LogicalModel, ModelId } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* 임베더블이 **선언하는 슬롯** 하나 — 배열 인덱스가 곧 사용처(owner) 슬롯 위치다.
|
|
4
|
+
*
|
|
5
|
+
* ★이 목록이 「임베더블이 선언한 컬럼」의 **단일 출처**다. 종전엔 같은 개념이 다섯 곳에 흩어져 있었고
|
|
6
|
+
* 그중 코드젠만 다른 정의를 써서(DIVIDER·빈 물리명 제외) 위치 페어링이 밀렸다 — 실측 손채움 157건.
|
|
7
|
+
* 기준을 **전 `dbAttrs`** 로 잡는 이유: 소비처 5 중 4가 이미 그것이고, 특히 **상속 해소가 인덱스
|
|
8
|
+
* 대응**이라 이 축을 바꾸면 표시·DDL·코드젠·검증이 동시에 흔들린다. DIVIDER 는 `dbAttrs` 가 없어
|
|
9
|
+
* 정의상 0 기여이므로 «DIVIDER 를 제외한다» 는 조작이 애초에 불필요하다.
|
|
10
|
+
*
|
|
11
|
+
* 배치: `embedSlots.ts` 가 아니라 여기 두는 이유는 **순환 회피**다(`embedSlots → columnResolve` 의존이
|
|
12
|
+
* 이미 있다) — 그리고 인덱스 대응 시맨틱의 소유자가 이 모듈이다(`inheritedSlotOf`).
|
|
13
|
+
*/
|
|
14
|
+
export interface DeclaredEmbedSlot {
|
|
15
|
+
/** 선언 컬럼(임베더블 소유). */
|
|
16
|
+
col: DbColumn;
|
|
17
|
+
/**
|
|
18
|
+
* 임베더블 루트에서 이 슬롯의 **basic 속성까지의 JPA 프로퍼티 경로** — 코드젠 `@AttributeOverride(name=…)` 의 값.
|
|
19
|
+
*
|
|
20
|
+
* 단일 컬럼 속성이면 속성명 하나(`buyerName`)지만, 그 속성이 **자기도 임베더블**이면 JPA 는 basic 까지의
|
|
21
|
+
* 경로를 요구하므로 dotted 가 된다(`totalBaseSellingAmt.amount`). 실물 `Cancellation.before` 는 40/40 이
|
|
22
|
+
* dotted 다. ★종전엔 속성명만 실어서 **Money 를 품은 임베더블의 사용처가 매핑되지 않았다** — 게다가
|
|
23
|
+
* 한 속성의 두 컬럼이 **같은 이름**을 받아 `@AttributeOverrides` 안에 name 중복이 생겼다(실측 5블록·46라인).
|
|
24
|
+
*
|
|
25
|
+
* **해소 못 하면 빈 문자열**이다(모르는 값 규약 — 발명하지 않는다). 소비처는 빈값을 손채움으로 표면화한다.
|
|
26
|
+
*/
|
|
27
|
+
propertyPath: string;
|
|
28
|
+
/** 선언 기본 물리명. 공유 투영·미물질화면 빈 문자열. */
|
|
29
|
+
defaultPhysical: string;
|
|
30
|
+
/** 선언이 지정한 공유 타깃 — 사용처 바인딩과 **비교**하는 기준. */
|
|
31
|
+
defaultSharedRef?: ModelId;
|
|
32
|
+
/**
|
|
33
|
+
* 이 자리에 **자체 물리 컬럼**이 생기는가 — 공유 투영(`sharedColumnRef`)과 미물질화(빈 이름)는 false.
|
|
34
|
+
* ⚠️**방출 게이트가 아니다** — 코드젠 방출은 「사용처 실효 바인딩이 선언 기본과 다른가」가 정한다.
|
|
35
|
+
* 이 플래그는 규칙의 규모 분해(`CHK-JPA-21` 부족분 중 실제 컬럼 수)와 형상 판정에 쓴다.
|
|
36
|
+
*/
|
|
37
|
+
ownColumn: boolean;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* 선언 슬롯의 **프로퍼티 경로 해소 컨텍스트** — 경로 축에만 쓰인다(`col`·`defaultPhysical`·`ownColumn` 은
|
|
41
|
+
* 컨텍스트 없이도 종전과 동일). 미주입이면 중첩 축만 graceful degrade 하고 나머지는 그대로다.
|
|
42
|
+
*/
|
|
43
|
+
export interface DeclaredSlotContext {
|
|
44
|
+
/** 중첩 임베더블(`EMBED_OWN`) 해소용 — 모델 엔티티 목록. */
|
|
45
|
+
entities?: readonly Entity[];
|
|
46
|
+
/** `EMBED_PREDEF` 서브필드명 해소용(호스트 주입). */
|
|
47
|
+
embeddableCatalog?: EmbeddableCatalog;
|
|
48
|
+
}
|
|
49
|
+
/** 임베더블 선언 슬롯 목록 — 연결·규칙·보충·상속·코드젠의 단일 출처(`DeclaredEmbedSlot`). */
|
|
50
|
+
export declare function declaredEmbedSlots(embeddable: Entity | undefined, ctx?: DeclaredSlotContext): DeclaredEmbedSlot[];
|
|
2
51
|
/** 상속 해소 컨텍스트 — `ValidationContext`·`DdlContext`와 동형(카탈로그는 호스트 주입). */
|
|
3
52
|
export interface ColumnResolveContext {
|
|
4
53
|
/** EMBED_PREDEF 서브컬럼의 선언값 해석용. 미주입 시 그 축만 graceful degrade(빈 값). */
|
|
@@ -57,3 +57,56 @@ export interface EmbedSlotReorder {
|
|
|
57
57
|
* @param nextAttributeOrder 재정렬 후 임베더블 속성 순서(전체 — `reorderedSequence` 산출).
|
|
58
58
|
*/
|
|
59
59
|
export declare function planEmbedSlotReorder(model: LogicalModel, embeddableRef: ModelId, nextAttributeOrder: readonly ModelId[]): EmbedSlotReorder[];
|
|
60
|
+
/** 한 사용처의 **형상 정규화** 계획 — legacy(1 속성 = 1 슬롯) → fresh(1 컬럼 = 1 슬롯). */
|
|
61
|
+
export interface EmbedSlotShapeNormalization {
|
|
62
|
+
/** 표시 속성을 보유한 소유자 엔티티. */
|
|
63
|
+
entityId: ModelId;
|
|
64
|
+
/** `EMBED_OWN` 표시 속성. */
|
|
65
|
+
attributeId: ModelId;
|
|
66
|
+
/** 정규화 후 전체 슬롯 목록 — 기존 슬롯이 **제자리로 이동** + 빈 슬롯 삽입 + 잉여 제거. */
|
|
67
|
+
dbAttrs: DbColumn[];
|
|
68
|
+
/** 자리를 옮긴 기존 슬롯 수(로그·테스트 가독용). */
|
|
69
|
+
moved: number;
|
|
70
|
+
/** 새로 삽입한 빈 슬롯 수(선언 다중 컬럼 속성의 2번째 이후 자리). */
|
|
71
|
+
inserted: number;
|
|
72
|
+
/** 대응할 선언 컬럼이 없어 빠진 슬롯 — **호출자가 무엇이 사라지는지 볼 수 있게** 실어 보낸다. */
|
|
73
|
+
dropped: DbColumn[];
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* 임베드 슬롯 **형상 정규화** — v1 유래 legacy 사용처를 선언 형상(fresh)에 맞춘다.
|
|
77
|
+
* `planEmbedSlotFill`(꼬리 보충)·`planEmbedSlotReorder`(순열)에 이어지는 **세 번째 축**이고,
|
|
78
|
+
* 앞의 둘이 손대지 못하던 «중간이 어긋난» 형상을 다룬다.
|
|
79
|
+
*
|
|
80
|
+
* ## 왜 여기서는 대응을 복원할 수 있는가 — 이 파일 헤더의 한계에 대한 예외
|
|
81
|
+
* 헤더는 *"어느 슬롯이 어느 컬럼이었는지 복원할 근거가 모델에 없다(소스 링크 부재)"* 라고 적었고
|
|
82
|
+
* 그건 **임의 드리프트**에 대해 참이다. legacy 형상은 임의가 아니라 **체계적 산물**이라 다르다:
|
|
83
|
+
* - `migrateLegacyMoney` 가 v1→v2 에서 레거시 1컬럼 `CustomMoneyType` 을 amount(**verbatim 보존**) +
|
|
84
|
+
* currency(빈 슬롯) 2컬럼으로 승격하는데, 그 판정이 `attrType === 'NORMAL'` 이라 **임베더블 선언에만
|
|
85
|
+
* 적용되고 owner 의 `EMBED_OWN` 사용처 슬롯은 따라가지 않는다**.
|
|
86
|
+
* - v1 의 DIVIDER 는 이름이 대시인 가짜 `NORMAL` 속성이었고 사용처 평탄화에 **한 칸**을 차지했는데,
|
|
87
|
+
* 로드 시 `DIVIDER` 로 승격되며 선언 측에서 `dbAttrs: []` 가 됐다(`types.ts`).
|
|
88
|
+
* ⇒ 남는 형상이 정확히 **「1 속성 = 1 슬롯」**이고, 그 슬롯은 선언 속성의 **첫 컬럼**(Money 면 amount)이다.
|
|
89
|
+
* 즉 대응의 근거는 슬롯이 아니라 **형상 규칙**이 들고 있다.
|
|
90
|
+
*
|
|
91
|
+
* ★실측이 이 산식을 확증한다(프로덕션 v2 24문서 · EMBED_OWN 사용처 100):
|
|
92
|
+
* fresh **70** · legacy **27** · other 3 이고, legacy 27 은 **27/27 이 `슬롯 수 == 선언 속성 수`**다
|
|
93
|
+
* (경쟁 가설 «물질화 컬럼 수»는 단독 성립 **0**). legacy 임베더블의 다중 컬럼 선언 속성은
|
|
94
|
+
* **전부 `Money:2`**(175건)이라 «첫 컬럼» 이 모호해질 자리가 없다.
|
|
95
|
+
*
|
|
96
|
+
* ## 왜 삭제가 아니라 정렬인가 (S4 → S5 흡수)
|
|
97
|
+
* DIVIDER 자리 슬롯만 **지우는** 안은 시뮬레이션이 기각했다 — 그 빈 슬롯이 인덱스 상속으로 이름을 얻어
|
|
98
|
+
* 어떤 컬럼의 *유일 방출자*가 되어 있어 실 컬럼 2개를 잃었다. 삭제는 **재인덱싱**이라 현재 상태로
|
|
99
|
+
* 계산한 어떤 기준도 삭제 후를 예측하지 못한다. 정렬은 반대로 **선언 컬럼마다 슬롯이 하나씩** 생기므로
|
|
100
|
+
* 컬럼 집합이 구성상 보존되고, 그 뒤에야 잉여가 «대응 없음»으로 명확히 식별된다.
|
|
101
|
+
*
|
|
102
|
+
* ## 게이트 셋
|
|
103
|
+
* 1. **legacy 형상일 때만** — 슬롯 수가 선언 **속성 수**와 같고 선언 **컬럼 수**와는 다를 때.
|
|
104
|
+
* 둘이 같으면(다중 컬럼·DIVIDER 없는 임베더블) 이미 정렬돼 있어 할 일이 없다.
|
|
105
|
+
* 2. **잉여는 빈 슬롯일 때만 뺀다** — 대응 자리가 없는 슬롯이 물리명·공유참조를 **명시 보유**하면
|
|
106
|
+
* 그건 사람이 넣은 값이라 도구가 버릴 수 없다(실측 22/22 가 빈 슬롯이지만 규칙으로 박아 둔다).
|
|
107
|
+
* 3. **이름 충돌을 만들지 않을 때만** — 삽입 슬롯은 선언 기본명을 상속하므로, 같은 임베더블을 두 번 쓰는
|
|
108
|
+
* 엔티티에서 서로 같은 이름이 될 수 있다. 정규화 **후** 실효 이름 다중집합을 실제로 계산해
|
|
109
|
+
* 중복이 늘면 그 사용처는 보류한다(`CHK-JPA-21` 이 계속 지목하므로 무신호가 아니다).
|
|
110
|
+
* ★기준 계산이 아니라 **산출물 대조**다 — S4 가 기준 계산으로 두 개의 다른 답을 얻은 자리다.
|
|
111
|
+
*/
|
|
112
|
+
export declare function planEmbedSlotShapeNormalization(model: LogicalModel, embeddableRef: ModelId, genId?: () => ModelId): EmbedSlotShapeNormalization[];
|