@g1cloud/entity-modeler-next 5.0.0-beta.3 → 5.0.0-beta.31
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/adapter/diagramAdapter.d.ts +6 -0
- package/dist/adapter/healBackfill.d.ts +38 -0
- package/dist/agent/resolver.d.ts +79 -4
- package/dist/agent/symbolicOp.d.ts +9 -1
- package/dist/command/commands.d.ts +4 -3
- package/dist/core/associationNav.d.ts +20 -0
- package/dist/core/attributeOrder.d.ts +9 -0
- package/dist/core/columnResolve.d.ts +22 -0
- package/dist/core/fkDerived.d.ts +21 -0
- package/dist/core/projectSeqDiff.d.ts +41 -0
- package/dist/core/propagation.d.ts +18 -1
- package/dist/core/quickFix.d.ts +9 -4
- package/dist/core/scaffoldJava.d.ts +30 -1
- package/dist/core/stereotype.d.ts +2 -0
- package/dist/core/types.d.ts +7 -0
- package/dist/core/validation.d.ts +1 -13
- package/dist/editor/controller.d.ts +29 -17
- package/dist/entity-modeler-next.css +1 -1
- package/dist/entity-modeler.js +14161 -12555
- package/dist/entity-modeler.umd.cjs +30 -26
- package/dist/i18n/ko.d.ts +46 -1
- package/dist/index.d.ts +6 -1
- package/dist/view/DiagramCanvas.vue.d.ts +4 -0
- package/dist/view/HistoryPanel.vue.d.ts +3 -0
- package/dist/view/diffOverlay.d.ts +14 -0
- package/dist/view/nodeInternals.d.ts +15 -0
- package/dist/view/opConflictNotice.d.ts +8 -6
- package/dist/view/swatches.d.ts +3 -2
- package/package.json +6 -6
|
@@ -27,6 +27,12 @@ export interface DiagramMeta {
|
|
|
27
27
|
/**
|
|
28
28
|
* 마커 분기 파서 — `schemaVersion`을 보고 v1(legacy flat) vs v2(logical/layout) 경로 선택(B-0).
|
|
29
29
|
* reload(프리즈 후 재적재)도 이 진입점을 경유해 동일 분기를 탄다.
|
|
30
|
+
*
|
|
31
|
+
* 산출 state는 입력 doc과 **참조 비공유**(계약) — 진입 시 deep-clone한다. 로드 자가치유
|
|
32
|
+
* (heal/normalize)와 이후 편집(commands의 in-place 변형)이 모두 사본 위에서 일어나므로,
|
|
33
|
+
* 호출자 소유 객체(호스트 useFetch payload 등 리액티브 소스)를 오염시키지 않는다.
|
|
34
|
+
* reactive proxy에 structuredClone은 throw할 수 있어 JSON deep-clone(controller 클립보드와
|
|
35
|
+
* 동일 패턴). undefined 값 키는 탈락하나 부재와 의미 동치.
|
|
30
36
|
*/
|
|
31
37
|
export declare function fromPersisted(doc: PDiagram | PDiagramV2): {
|
|
32
38
|
state: EditorState;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { ModelId } from '../core/types';
|
|
2
|
+
import { OpShape } from '../command/op';
|
|
3
|
+
import { PDiagram, PDiagramV2 } from './persisted';
|
|
4
|
+
/**
|
|
5
|
+
* 로드 경로가 파생하는 **속성 스칼라 필드** 목록 — 이 플래너가 raw↔healed diff로 정렬하는 축.
|
|
6
|
+
*
|
|
7
|
+
* 전체 필드를 무조건 diff하지 않는 이유: 로드 경로가 의도적으로 바꾸지 않는 필드까지 잡아
|
|
8
|
+
* 오탐(JSON 왕복의 `null`↔부재 등)을 낼 수 있다. **선언된 목록**이 곧 "무엇이 파생값인가"의
|
|
9
|
+
* 레지스트리이며, 새 파생 축 추가 = 여기에 이름 한 줄(라우트·플래너 신설 불요).
|
|
10
|
+
*
|
|
11
|
+
* - `notNull` : FK는 부모 end 다중성 파생(`deriveFkNotNull`, CC-4). 비-FK 속성은 파생 대상이
|
|
12
|
+
* 아니지만 파생기가 FK만 건드리므로 diff도 자연히 FK에서만 발생한다.
|
|
13
|
+
*/
|
|
14
|
+
declare const DERIVED_ATTRIBUTE_FIELDS: readonly ["notNull"];
|
|
15
|
+
export interface HealBackfillPlan {
|
|
16
|
+
/** backfill op 배치 (비면 정렬 대상 없음 — 문서 skip). */
|
|
17
|
+
ops: OpShape[];
|
|
18
|
+
/** raw doc의 컨테이너 rev 스냅샷 — `buildAgentBatch(diagramId, revs, ops)` CAS base. */
|
|
19
|
+
revs: Record<ModelId, number>;
|
|
20
|
+
/** dry-run 리포트용 집계. */
|
|
21
|
+
summary: {
|
|
22
|
+
navAdds: number;
|
|
23
|
+
navRefPatches: number;
|
|
24
|
+
identifyingPatches: number;
|
|
25
|
+
/** 파생 스칼라 필드 정렬 건수(`DERIVED_ATTRIBUTE_FIELDS`) — 필드별 분해. */
|
|
26
|
+
attributeFieldPatches: number;
|
|
27
|
+
attributeFieldsByName: Partial<Record<(typeof DERIVED_ATTRIBUTE_FIELDS)[number], number>>;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* v2 doc 하나에 대한 파생값 backfill 계획을 산출한다.
|
|
32
|
+
*
|
|
33
|
+
* v1 doc은 빈 계획 — 스윕 라우트가 v2 컬렉션 대상이고, v1은 마이그레이션을 거쳐 v2가 된 뒤
|
|
34
|
+
* 대상이 된다. 마이그레이션 산출은 hydration이 이미 현재 규칙으로 파생하므로(nav 실체화·
|
|
35
|
+
* identifying·notNull) 새로 마이그레이션된 문서는 정렬된 상태로 태어난다.
|
|
36
|
+
*/
|
|
37
|
+
export declare function planHealBackfillOps(doc: PDiagram | PDiagramV2): HealBackfillPlan;
|
|
38
|
+
export {};
|
package/dist/agent/resolver.d.ts
CHANGED
|
@@ -43,6 +43,13 @@ export type ResolveError = {
|
|
|
43
43
|
entity: Handle;
|
|
44
44
|
handle: Handle;
|
|
45
45
|
}
|
|
46
|
+
/** 물리 컬럼을 만들면서 dataType 미지정 — 빈 타입 컬럼은 DDL에서 드롭된다(발명 대신 요구). */
|
|
47
|
+
| {
|
|
48
|
+
code: 'datatype-required';
|
|
49
|
+
opIndex: number;
|
|
50
|
+
entity: Handle;
|
|
51
|
+
handle: Handle;
|
|
52
|
+
}
|
|
46
53
|
/** index.add 컬럼 핸들이 엔티티 내 dbAttr와 0개 매칭. */
|
|
47
54
|
| {
|
|
48
55
|
code: 'column-not-found';
|
|
@@ -84,6 +91,28 @@ export type ResolveError = {
|
|
|
84
91
|
handle: Handle;
|
|
85
92
|
matches: ModelId[];
|
|
86
93
|
}
|
|
94
|
+
/** reorder order 목록의 핸들이 엔티티 내 속성/메서드와 0개 매칭(D7 — 부분 재배치 안 함, 전체 거부). */
|
|
95
|
+
| {
|
|
96
|
+
code: 'reorder-handle-not-found';
|
|
97
|
+
opIndex: number;
|
|
98
|
+
entity: Handle;
|
|
99
|
+
handle: Handle;
|
|
100
|
+
}
|
|
101
|
+
/** reorder order 목록의 핸들이 복수 매칭(모호). */
|
|
102
|
+
| {
|
|
103
|
+
code: 'reorder-handle-ambiguous';
|
|
104
|
+
opIndex: number;
|
|
105
|
+
entity: Handle;
|
|
106
|
+
handle: Handle;
|
|
107
|
+
matches: ModelId[];
|
|
108
|
+
}
|
|
109
|
+
/** reorder order 목록에 같은 요소가 두 번(중복 핸들) — 배열 재배치 모호. */
|
|
110
|
+
| {
|
|
111
|
+
code: 'reorder-handle-duplicate';
|
|
112
|
+
opIndex: number;
|
|
113
|
+
entity: Handle;
|
|
114
|
+
handle: Handle;
|
|
115
|
+
}
|
|
87
116
|
/**
|
|
88
117
|
* index.update patch에 `columns` 키 — columnRef(dbAttr modelId)는 사람 핸들로 표현 불가라 패스스루 시
|
|
89
118
|
* 깨진 인덱스가 된다. 컬럼 변경은 index.remove + index.add(컬럼 핸들 해소 구현)로 유도(거부 권고안).
|
|
@@ -129,6 +158,56 @@ export type ResolveError = {
|
|
|
129
158
|
entity: Handle;
|
|
130
159
|
handle: Handle;
|
|
131
160
|
matches: ModelId[];
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* attribute.update patch의 평탄 dbAttr 키를 스칼라 단일 컬럼으로 매핑할 수 없음. 스칼라(NORMAL·단일 dbAttr)면
|
|
164
|
+
* `dbAttrs[0]`로 자동 매핑되지만, 모호/불가한 대상은 거부한다: EMBED_PREDEF/다중 dbAttr(어느 컬럼인지 모호 →
|
|
165
|
+
* `embeddableOverrides`), dbAttrs 0개/transient(머지할 컬럼 없음), `sharedColumnRef` 평탄(opaque modelId),
|
|
166
|
+
* flat + dotted-dbAttrs 혼용($set 충돌). 통과 시 논리 노드 blind-write로 orphan 오염이라 거부.
|
|
167
|
+
*/
|
|
168
|
+
| {
|
|
169
|
+
code: 'attribute-patch-dbattr-flat-key';
|
|
170
|
+
opIndex: number;
|
|
171
|
+
entity: Handle;
|
|
172
|
+
handle: Handle;
|
|
173
|
+
keys: string[];
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* attribute.update patch에 Attribute 논리 노드에 실재하지 않는 미지 키 — 통과 시 orphan blind-write.
|
|
177
|
+
* 오탈자/스키마 밖 키를 조용히 흡수하지 않고 명시 거부(자기증식 오염 원천 차단).
|
|
178
|
+
*/
|
|
179
|
+
| {
|
|
180
|
+
code: 'attribute-patch-unknown-key';
|
|
181
|
+
opIndex: number;
|
|
182
|
+
entity: Handle;
|
|
183
|
+
handle: Handle;
|
|
184
|
+
keys: string[];
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* associationEnd.update patch의 `navigable`(양 end) — end1(from): inverse nav 실체화/철거는
|
|
188
|
+
* RELATION_REF 속성 생성·삭제가 동반되는 GUI 토글 소유(통과 시 "navigable=true ⟺ RELATION_REF 존재"
|
|
189
|
+
* 불변식이 깨져 로드 자가치유가 비결정 실체화를 반복). end2(to): JPA 소유측 참조는 관계 존재와
|
|
190
|
+
* 동치라 고정 true — 참조 없는 FK는 관계가 아니라 일반 컬럼으로 모델링.
|
|
191
|
+
*/
|
|
192
|
+
| {
|
|
193
|
+
code: 'navigable-toggle-unsupported';
|
|
194
|
+
opIndex: number;
|
|
195
|
+
handle: AssocHandle;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* FK 파생 속성(RELATION* + 물리 컬럼) 직접 삭제 — 관계가 소유하는 파생물이라 직접 지우면 관계
|
|
199
|
+
* end.attributeRef가 끊긴다(GUI removeAttribute 가드 동형, Option B). `association`(양 끝 엔티티명)의
|
|
200
|
+
* 관계를 association.remove로 삭제하도록 유도.
|
|
201
|
+
*/
|
|
202
|
+
| {
|
|
203
|
+
code: 'attribute-fk-managed';
|
|
204
|
+
opIndex: number;
|
|
205
|
+
entity: Handle;
|
|
206
|
+
handle: Handle;
|
|
207
|
+
association: {
|
|
208
|
+
from: string;
|
|
209
|
+
to: string;
|
|
210
|
+
};
|
|
132
211
|
};
|
|
133
212
|
export type ResolveResult = {
|
|
134
213
|
ok: true;
|
|
@@ -147,8 +226,4 @@ export interface ResolverOptions {
|
|
|
147
226
|
*/
|
|
148
227
|
embeddableCatalog?: EmbeddableCatalog;
|
|
149
228
|
}
|
|
150
|
-
/**
|
|
151
|
-
* 심볼릭 op 배치를 OpShape 배치로 해소한다.
|
|
152
|
-
* 전부 해소되면 `{ok:true, ops}`, 하나라도 실패하면 `{ok:false, errors}`(모든 실패 누적 — 에이전트가 한 번에 재질의).
|
|
153
|
-
*/
|
|
154
229
|
export declare function resolveSymbolicOps(model: LogicalModel, ops: SymbolicOp[], options?: ResolverOptions): ResolveResult;
|
|
@@ -231,6 +231,10 @@ export type SymbolicOp = {
|
|
|
231
231
|
kind: 'attribute.remove';
|
|
232
232
|
entity: Handle;
|
|
233
233
|
attribute: Handle;
|
|
234
|
+
} | {
|
|
235
|
+
kind: 'attribute.reorder';
|
|
236
|
+
entity: Handle;
|
|
237
|
+
order: Handle[];
|
|
234
238
|
} | {
|
|
235
239
|
kind: 'association.add';
|
|
236
240
|
spec: AssocSpec;
|
|
@@ -272,6 +276,10 @@ export type SymbolicOp = {
|
|
|
272
276
|
kind: 'operation.remove';
|
|
273
277
|
entity: Handle;
|
|
274
278
|
operation: Handle;
|
|
279
|
+
} | {
|
|
280
|
+
kind: 'operation.reorder';
|
|
281
|
+
entity: Handle;
|
|
282
|
+
operations: Handle[];
|
|
275
283
|
} | {
|
|
276
284
|
kind: 'group.add';
|
|
277
285
|
spec: GroupSpec;
|
|
@@ -280,5 +288,5 @@ export type SymbolicOp = {
|
|
|
280
288
|
* v1이 다루는 심볼릭 op 종류의 닫힌 집합(단일 출처). resolver·JSON Schema(`schema.ts`)가 공유한다.
|
|
281
289
|
* 아래 컴파일타임 단언이 이 튜플과 `SymbolicOp['kind']`의 일치를 강제 — 한쪽만 늘리면 타입 에러.
|
|
282
290
|
*/
|
|
283
|
-
export declare const SYMBOLIC_OP_KINDS: readonly ["entity.add", "entity.update", "entity.remove", "attribute.add", "attribute.update", "attribute.remove", "association.add", "association.remove", "association.update", "associationEnd.update", "index.add", "index.update", "index.remove", "operation.add", "operation.update", "operation.remove", "group.add"];
|
|
291
|
+
export declare const SYMBOLIC_OP_KINDS: readonly ["entity.add", "entity.update", "entity.remove", "attribute.add", "attribute.update", "attribute.remove", "association.add", "association.remove", "association.update", "associationEnd.update", "index.add", "index.update", "index.remove", "operation.add", "operation.update", "operation.remove", "attribute.reorder", "operation.reorder", "group.add"];
|
|
284
292
|
export type SymbolicOpKind = (typeof SYMBOLIC_OP_KINDS)[number];
|
|
@@ -60,10 +60,11 @@ export declare function updateAttribute(entityId: ModelId, attributeId: ModelId,
|
|
|
60
60
|
export declare function removeAttribute(entityId: ModelId, attributeId: ModelId): Command;
|
|
61
61
|
/**
|
|
62
62
|
* 속성 재정렬 — 대상(attrIds)을 현재 표시 순서를 유지한 채 toIndex로 이동.
|
|
63
|
-
* 표시 순서
|
|
64
|
-
*
|
|
65
|
-
* toIndex = 대상을 모두 제거한 뒤의 배열(rest) 기준 삽입 위치.
|
|
63
|
+
* 표시 순서 SoT는 `order` 필드다(S1 이후 전 뷰가 order sort). 배열도 splice로 함께 맞춰 두 표현을
|
|
64
|
+
* 일관 유지하고(캔버스 노드가 배열도 참조하는 전환기 안전), order 필드를 0..n-1로 전체 재인덱싱한다
|
|
65
|
+
* (중간 삭제로 생긴 기존 갭도 함께 치유). toIndex = 대상을 모두 제거한 뒤의 배열(rest) 기준 삽입 위치.
|
|
66
66
|
* invert는 변경 전 배열 스냅샷(order 포함 얕은 복사)으로 통째 복원 → 재인덱싱 손실 없이 원자 원복.
|
|
67
|
+
* emit은 order 패치(S3, orderPatchEmission) — 배열 $set 아님.
|
|
67
68
|
*/
|
|
68
69
|
export declare function reorderAttributes(entityId: ModelId, attrIds: ModelId[], toIndex: number): Command;
|
|
69
70
|
export declare function addOperation(entityId: ModelId, operation: Operation): Command;
|
|
@@ -1,6 +1,26 @@
|
|
|
1
1
|
import { Multiplicity } from './types';
|
|
2
2
|
/** end2 multiplicity가 컬렉션(0..* / 1..*)인가 — 코드젠의 @OneToMany vs @OneToOne 분기와 동일 기준. */
|
|
3
3
|
export declare function isCollectionMultiplicity(m: Multiplicity): boolean;
|
|
4
|
+
/**
|
|
5
|
+
* 최소 개수가 0인가(0..1 / 0..*) — 레거시 `Multiplicity.isOptional()` 이식.
|
|
6
|
+
*
|
|
7
|
+
* FK nullability의 파생원이다: 부모 end(end1)가 optional이 아니면(=`1`) 자식은 부모 없이 존재할 수
|
|
8
|
+
* 없으므로 FK는 NOT NULL이다. 레거시 코드젠이 `@ManyToOne(optional=…)`·`@JoinColumn(nullable=…)`을
|
|
9
|
+
* 정확히 이 값으로 방출했다(bluework-im `EntityJavaFile:900,932,1072,1120`).
|
|
10
|
+
*
|
|
11
|
+
* 자식 end(end2)의 `0..*` vs `1..*`는 이 축이 아니다 — "부모가 자식을 최소 1개 가진다"는 자식 테이블의
|
|
12
|
+
* 컬럼 제약으로 표현할 수 없다(레거시도 여기서 nullability를 뽑지 않는다).
|
|
13
|
+
*
|
|
14
|
+
* 판정을 "required 목록의 여집합"으로 쓴다(`!== '1' && !== '1..*'`) — union 밖 값(레거시는 다중성
|
|
15
|
+
* 미설정을 null로 허용)이 흘러들어도 optional=nullable로 안전하게 떨어진다.
|
|
16
|
+
*/
|
|
17
|
+
export declare function isOptionalMultiplicity(m: Multiplicity): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* 다중성 표시 기호(0..1 / 1 / 0..* / 1..*) — 영속용 enum(`*_INSTANCE(S)`)의 단일 표시 SoT.
|
|
20
|
+
* 기호는 언어 무관 UML 표기라 i18n 대상이 아니다. 캔버스 관계선 라벨·인스펙터 select·mermaid
|
|
21
|
+
* 라벨이 모두 이 함수로 위임한다(과거 multSymbol/multHuman으로 중복 정의되던 것 통합).
|
|
22
|
+
*/
|
|
23
|
+
export declare function multiplicityLabel(m: Multiplicity): string;
|
|
4
24
|
/**
|
|
5
25
|
* inverse nav 기본 이름: 자식 엔티티명(camel). 컬렉션이면 복수형.
|
|
6
26
|
* 예: Order→OrderItem 컬렉션 → `orderItems`, 단일 → `orderItem`.
|
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
import { Attribute, Entity } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* 다음 표시 순서 값 = 현재 최대 `order` + 1(비어 있으면 0). 표시 순서가 `order` 필드 단일 SoT이므로
|
|
4
|
+
* add-side는 반드시 이 값을 써야 order가 항상 distinct하다. 배열 `.length`를 쓰면
|
|
5
|
+
* `removeAttribute`/`removeOperation`가 재인덱싱하지 않아(splice만) 남은 order와 length가 충돌할 수
|
|
6
|
+
* 있다(order [0,2] + length 2 → 신규 order 2 = 중복). [[attribute-display-order-array-vs-order-field]]
|
|
7
|
+
*/
|
|
8
|
+
export declare function nextOrder(items: readonly {
|
|
9
|
+
order: number;
|
|
10
|
+
}[]): number;
|
|
2
11
|
/** 물리 FK 컬럼을 가진 FK 여부 — derivedFrom(관계 파생) + dbAttrs(물리 컬럼) 보유. */
|
|
3
12
|
export declare function isPhysicalFk(a: Attribute): boolean;
|
|
4
13
|
/**
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Attribute, DbColumn, EmbeddableCatalog, Entity, LogicalModel } from './types';
|
|
2
|
+
/** 상속 해소 컨텍스트 — `ValidationContext`·`DdlContext`와 동형(카탈로그는 호스트 주입). */
|
|
3
|
+
export interface ColumnResolveContext {
|
|
4
|
+
/** EMBED_PREDEF 서브컬럼의 선언값 해석용. 미주입 시 그 축만 graceful degrade(빈 값). */
|
|
5
|
+
embeddableCatalog?: EmbeddableCatalog;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* 컬럼의 **실효 값** — 자기 값이 비어 있으면 선언원에서 상속. 문자열은 빈값 폴백(`||`), 수치는
|
|
9
|
+
* null/undefined 폴백(`??`)이다(저장 라운드트립이 미설정 수치를 `null`로 바꾸므로 — propagation `nn()` 동형).
|
|
10
|
+
*
|
|
11
|
+
* 축별 폴백(값 단위)이지 슬롯 통째 대체가 아니다: 사용처가 물리명만 override하고 타입은 상속하는 형태
|
|
12
|
+
* (@AttributeOverride의 실제 용법)가 지배적이라, 한 축을 채웠다고 나머지까지 자기 값으로 강제하면
|
|
13
|
+
* 대다수 정상 데이터가 도로 빈 값이 된다. 캔버스 `EntityNode.effectiveAttr`가 쓰던 시맨틱과 동일.
|
|
14
|
+
*/
|
|
15
|
+
export declare function resolveEffectiveColumn(attr: Attribute, col: DbColumn, index: number, entity: Entity | undefined, model: LogicalModel, ctx?: ColumnResolveContext): DbColumn;
|
|
16
|
+
/**
|
|
17
|
+
* 실효 물리명 — override(비어있지 않은 physicalName)가 있으면 그 값, 없으면 상속 기본값.
|
|
18
|
+
* 컬럼 충돌 판정(CHK-NAME-2)은 raw `''`가 아니라 이 값으로 해야 한다: 한 테이블에 같은 임베더블
|
|
19
|
+
* (예: Money)이 여러 번 쓰이고 서브컬럼을 비워두면 전부 같은 기본명을 상속해 실제 컬럼 충돌이 나고,
|
|
20
|
+
* FK도 물리명 미지정 시 부모 PK 컬럼명을 그대로 쓰므로 자식 자기 컬럼과 충돌할 수 있다.
|
|
21
|
+
*/
|
|
22
|
+
export declare function resolveColumnPhysicalName(attr: Attribute, col: DbColumn, index: number, entity: Entity | undefined, model: LogicalModel, ctx?: ColumnResolveContext): string;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Association, Attribute, DbColumn, Entity } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* FK 유래 컬럼 = 물리 컬럼을 보유한 관계 속성(RELATION* + dbAttrs). 형상(dataType/length/scale/
|
|
4
|
+
* physicalName/notNull 등)은 부모 식별자(PK) + 관계 identifying에서 파생된다.
|
|
5
|
+
* derivedFrom이 아니라 이 불변식을 쓰는 이유: derivedFrom은 관계·전파가 심는 링크라 그 자체가 결손일 수
|
|
6
|
+
* 있는 반면, "관계 속성이 물리 컬럼을 갖는다"는 형상은 FK의 정의 자체다.
|
|
7
|
+
* (과거 이 자리엔 "derivedFrom은 영속 데이터엔 0건"이라는 근거가 적혀 있었으나 **실측과 어긋난다** —
|
|
8
|
+
* BNKR_SALES 32문서에서 FK 속성 666건 전량이 derivedFrom을 보유한다. v2는 문서에 그대로 저장되고,
|
|
9
|
+
* v1은 어댑터 `assocFromHydrated`(diagramAdapter.ts:350)가 하이드레이션 시 합성한다. 두 판정은 이
|
|
10
|
+
* 데이터에서 100% 일치하므로 동작 차이는 없다.)
|
|
11
|
+
* RELATION_REF(inverse nav, dbAttrs=0)는 물리 컬럼이 없어 제외.
|
|
12
|
+
*/
|
|
13
|
+
export declare function isFkDerivedColumn(attr: Attribute): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* FK 유래 컬럼 i의 원본(부모 식별자) 컬럼 — 물리명·타입·길이·스케일이 여기서 파생된다. FK 컬럼 자신의
|
|
16
|
+
* dbAttrs가 비어 있을 때(v1→v2 로드/레거시 데이터, 어댑터가 재전파를 하지 않음) placeholder·캔버스
|
|
17
|
+
* 표시에 쓴다(레거시 getForeignDatabaseAttributePlaceholder 동형). 1순위 derivedFrom.sourceAttributeRef
|
|
18
|
+
* (전파가 심은 권위), 2순위 관계 역참조로 부모 식별자 컬럼(derivedFrom 부재하는 레거시 v1 로드 FK 폴백).
|
|
19
|
+
* 못 찾으면 undefined.
|
|
20
|
+
*/
|
|
21
|
+
export declare function resolveFkOriginColumn(attr: Attribute, childEntity: Entity | null | undefined, entities: readonly Entity[], associations: readonly Association[], i?: number): DbColumn | undefined;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { ModelId } from './types';
|
|
2
|
+
import { FieldAuditRecord } from './projectFieldAudit';
|
|
3
|
+
import { ActionFieldChange, ActionSubject } from './projectActionLog';
|
|
4
|
+
/** 한 대상의 구간 net 결과 — verb + net 필드 변경(최초 old→최종 new). */
|
|
5
|
+
export interface SeqDiffEntry {
|
|
6
|
+
subject: ActionSubject;
|
|
7
|
+
/** added=구간 내 생성되어 B에 존재 / removed=A에 존재했고 구간 내 삭제 / modified=양쪽 존재+내용 변경. */
|
|
8
|
+
verb: 'added' | 'modified' | 'removed';
|
|
9
|
+
/** net 필드 변경. added=최종값(요약), removed=빈 배열(tombstone), modified=old→new(수렴分 제외). */
|
|
10
|
+
fields: ActionFieldChange[];
|
|
11
|
+
}
|
|
12
|
+
export interface SeqDiff {
|
|
13
|
+
fromSeq: number;
|
|
14
|
+
/** 실효 상한 — 옵션 미지정 시 스트림 최신 seq(레코드 없으면 fromSeq). */
|
|
15
|
+
toSeq: number;
|
|
16
|
+
/** subject 최초 등장 순(결정적). */
|
|
17
|
+
entries: SeqDiffEntry[];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* op 이력 스트림을 구간 `(fromSeq, toSeq]`의 subject별 net diff로 투영한다.
|
|
21
|
+
*
|
|
22
|
+
* @param records seq 정렬 이력 레코드(전체 스트림 — old 파생 정확성을 위해 구간 밖 레코드도 포함해 전달).
|
|
23
|
+
* @param range fromSeq(비포함)·toSeq(포함, 생략=최신). D1: 투영기는 일반형, UI는 "과거↔현재"부터.
|
|
24
|
+
*/
|
|
25
|
+
export declare function projectSeqDiff(records: readonly FieldAuditRecord[], range: {
|
|
26
|
+
fromSeq: number;
|
|
27
|
+
toSeq?: number;
|
|
28
|
+
}): SeqDiff;
|
|
29
|
+
/** 캔버스 오버레이 마크 — 엔티티 노드 단위(removed 대상은 캔버스에 없어 패널 전용, D3). */
|
|
30
|
+
export interface DiffMark {
|
|
31
|
+
verb: 'added' | 'modified';
|
|
32
|
+
/** 구간 내 추가/변경된 속성 행(하이라이트 대상). 삭제 속성은 행이 없어 제외. */
|
|
33
|
+
changedAttributeIds: Set<ModelId>;
|
|
34
|
+
/** 구간 내 추가/변경된 연산 행. */
|
|
35
|
+
changedOperationIds: Set<ModelId>;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* SeqDiff → 캔버스 마크 맵. 엔티티 subject는 자기 verb로, 자식(속성/연산/인덱스) 변경은 부모 엔티티를
|
|
39
|
+
* modified로 승격(이미 added면 유지)한다. 연관/그룹은 S3 스코프 밖(엔티티 오버레이 전용).
|
|
40
|
+
*/
|
|
41
|
+
export declare function buildDiffMarks(diff: SeqDiff): Map<ModelId, DiffMark>;
|
|
@@ -42,11 +42,28 @@ export declare function computeForeignAttributes(logical: LogicalModel, associat
|
|
|
42
42
|
export declare function reconcileForeignAttributes(logical: LogicalModel, childEntityId: ModelId, idFactory?: IdFactory): ReconcilePlan;
|
|
43
43
|
/**
|
|
44
44
|
* changedEntityId의 식별자 변경이 영향을 주는 모든 후손 자식의 reconcile 계획.
|
|
45
|
-
* A→B→C 연쇄와 사이클(A→B→A)을 visited 가드로 안전 종료(INV-6).
|
|
46
45
|
* 클론에 단계별로 적용하며 다음 단계 입력을 갱신하므로, 반환 계획은 *원본* logical 기준이다.
|
|
47
46
|
* self-association은 비식별이라 자식 식별자를 바꾸지 않아 더 전파되지 않는다(자연 종료).
|
|
47
|
+
*
|
|
48
|
+
* 비등깊이 다중 경로(A→D + A→B→D)에서는 D의 desired가 두 단계에 걸쳐 도착한다 —
|
|
49
|
+
* 늦게 온 계획은 mergePlans로 병합하고, 계획을 받은 자식은 재큐해 후손을 재연쇄한다.
|
|
50
|
+
* 종료(INV-6): reconcile이 멱등 diff라 비순환 그래프는 자연 수렴(재처리 횟수 ≤ 최장 경로 깊이).
|
|
51
|
+
* 식별 사이클(A⇄B)은 desired가 무한 성장하므로 엔터티당 처리 횟수를 entities.length로 캡해 절단한다
|
|
52
|
+
* (비순환에선 최장 경로 ≤ 엔터티 수라 캡이 정확성을 해치지 않는다).
|
|
48
53
|
*/
|
|
49
54
|
export declare function planPropagation(logical: LogicalModel, changedEntityId: ModelId, idFactory?: IdFactory): Map<ModelId, ReconcilePlan>;
|
|
55
|
+
/**
|
|
56
|
+
* "자식의 FK 집합이 직접 바뀌는" 트리거(관계 삭제·identifying 토글·부모 엔터티 삭제)의
|
|
57
|
+
* seed reconcile + 후손 cascade 통합 계획. futureLogical은 트리거 변경이 이미 반영된 상태여야 한다.
|
|
58
|
+
* 반환은 seed(자식)부터 후손 순서의 목록 — 빈 계획은 제외.
|
|
59
|
+
*
|
|
60
|
+
* editor controller(→Command)와 agent resolver(→OpShape)가 이 산식을 공유한다 — 계약 4(cascade =
|
|
61
|
+
* 클라 명시 분해)의 계산 주체를 한 곳에 두어 쓰기 경로별 분해 드리프트를 구조적으로 차단한다.
|
|
62
|
+
*/
|
|
63
|
+
export declare function planChildReconcileWithCascade(futureLogical: LogicalModel, childId: ModelId, idFactory?: IdFactory): Array<{
|
|
64
|
+
entityId: ModelId;
|
|
65
|
+
plan: ReconcilePlan;
|
|
66
|
+
}>;
|
|
50
67
|
/**
|
|
51
68
|
* 주어진 속성이 "연관관계가 관리하는 FK 컬럼"이면 그 소유 연관관계를 돌려준다(아니면 undefined).
|
|
52
69
|
*
|
package/dist/core/quickFix.d.ts
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
|
-
import { JpaCascadeType, LogicalModel, ModelId } from './types';
|
|
1
|
+
import { IndexColumn, JpaCascadeType, LogicalModel, ModelId } from './types';
|
|
2
2
|
import { ValidationIssue } from './validation';
|
|
3
|
-
export
|
|
3
|
+
export type QuickFixPlan = {
|
|
4
4
|
ruleId: string;
|
|
5
|
-
/** 현재는 association end의 cascade 재설정 한 종류(중복 제거). 확장 시 kind 분기 추가. */
|
|
6
5
|
kind: 'setEndCascades';
|
|
7
6
|
assocRef: ModelId;
|
|
8
7
|
which: 'end1' | 'end2';
|
|
9
8
|
cascades: JpaCascadeType[];
|
|
10
|
-
}
|
|
9
|
+
} | {
|
|
10
|
+
ruleId: string;
|
|
11
|
+
kind: 'setIndexColumns';
|
|
12
|
+
entityRef: ModelId;
|
|
13
|
+
indexRef: ModelId;
|
|
14
|
+
columns: IndexColumn[];
|
|
15
|
+
};
|
|
11
16
|
/** 이슈에 적용 가능한 결정적 quick-fix가 있으면 계획을, 없으면 null(순수·부수효과 없음). */
|
|
12
17
|
export declare function resolveQuickFix(issue: ValidationIssue, model: LogicalModel): QuickFixPlan | null;
|
|
@@ -1,6 +1,17 @@
|
|
|
1
|
-
import { LogicalModel, ModelId, SuperClassCatalog, EmbeddableCatalog } from './types';
|
|
1
|
+
import { Entity, LogicalModel, ModelId, SuperClassCatalog, EmbeddableCatalog } from './types';
|
|
2
2
|
import { JavaTypeDef } from './javaTypes';
|
|
3
3
|
export interface ScaffoldOptions {
|
|
4
|
+
/**
|
|
5
|
+
* **산출 불가 대상 자동 제외**(기본 `true`) — 엔티티명 미지정 / `@Id` 없는 JPA 엔티티는 파일을 만들지
|
|
6
|
+
* 않는다. 레거시 배치 선택 계층 패리티(`EntityJavaSrcGen.generateImplModel:105·108`이 각각
|
|
7
|
+
* `isBlank(entityName)`·`JPA_ENTITY && !hasIdField`를 `logger.warn + continue`로 스킵).
|
|
8
|
+
*
|
|
9
|
+
* ★레거시는 이 판정을 **선택 계층**(generateImplModel)에 두고 렌더러(EntityJavaFile)와 분리한다.
|
|
10
|
+
* lib은 두 역할이 `scaffoldEntityJava` 한 함수에 겹쳐 있어 옵션으로 seam을 만든다 — 모듈 산출
|
|
11
|
+
* (호스트 오라클)은 기본값을 쓰고, **렌더러로 직접 쓰는 경우**(단위 테스트·부분 렌더 프리뷰)는
|
|
12
|
+
* `false`로 꺼서 PK 없는 축약 모델도 렌더한다.
|
|
13
|
+
*/
|
|
14
|
+
skipUngeneratable?: boolean;
|
|
4
15
|
/** 저장값→소스 타입 역해소 카탈로그. 미주입 시 lib 내장 `JAVA_TYPES` 폴백(호스트 javaTypeCatalog 미러). */
|
|
5
16
|
javaTypeCatalog?: readonly JavaTypeDef[];
|
|
6
17
|
/** 임베더블 타입 해소용(EMBED_PREDEF 필드 타입·클래스명). 미주입 시 모델 type 폴백 + fillIn. */
|
|
@@ -59,4 +70,22 @@ export interface ScaffoldedEntity {
|
|
|
59
70
|
* 대상 엔티티들을 JPA 자바 소스로 렌더한다. `logical`은 참조 폐포(FK 대상 등) 해소를 위해 전체를 받고,
|
|
60
71
|
* `targetIds`가 실제 산출(파일 생성) 스코프다. 스코프 밖 엔티티는 읽기(폐포)에만 쓰이고 산출되지 않는다.
|
|
61
72
|
*/
|
|
73
|
+
/**
|
|
74
|
+
* 산출 대상 판정 — 레거시 배치 선택 계층(`EntityJavaSrcGen.generateImplModel:105·108`) 패리티.
|
|
75
|
+
*
|
|
76
|
+
* - 엔티티명 미지정: 방출하면 `undefined.java` / `public class undefined {`가 나간다(실측 module-order).
|
|
77
|
+
* - `@Id` 없는 JPA 엔티티: JPA는 식별자가 필수라 방출해도 부트스트랩 불가.
|
|
78
|
+
*
|
|
79
|
+
* 판정은 레거시 `hasIdField`→`countIdAttributes`(자기 속성 중 identifier, attrType 무관)와 동형.
|
|
80
|
+
* 레거시의 `countReferredIdAttributes` 보정분은 v2에선 식별 전파로 자식 attributes에 FK가
|
|
81
|
+
* `identifier=true`로 물질화되므로 여기에 이미 포함된다.
|
|
82
|
+
*
|
|
83
|
+
* ⚠️ 레거시는 abstractClass도 예외 없이 스킵한다(:108에 예외 조항 없음). lib `CHK-JPA-1`은 추상 베이스를
|
|
84
|
+
* 면제하므로 "모델은 정당한데 산출은 제외"되는 divergence가 이론상 가능하다 — 다만 abstract이면서 PK 없는
|
|
85
|
+
* `@Entity`는 `@MappedSuperclass` 없이 JPA 자체가 불가하고, 실 데이터(로컬 BNKR_SALES) PK 없는 JPA 엔티티
|
|
86
|
+
* 17건 중 abstract는 0건이라 레거시 시맨틱을 그대로 따른다.
|
|
87
|
+
*
|
|
88
|
+
* 모델 레벨 신호는 검증이 담당한다 — 엔티티명 빈값=`CHK-NAME-4`, PK 부재=`CHK-JPA-1`.
|
|
89
|
+
*/
|
|
90
|
+
export declare function isGeneratable(entity: Entity): boolean;
|
|
62
91
|
export declare function scaffoldEntityJava(logical: LogicalModel, targetIds: readonly ModelId[], opts?: ScaffoldOptions): ScaffoldedEntity[];
|
package/dist/core/types.d.ts
CHANGED
|
@@ -321,6 +321,13 @@ export interface AssociationEnd {
|
|
|
321
321
|
* 이 ref가 그것을 가리킨다(diagramAdapter.assocFromHydrated). 레이아웃 앵커는 layout.sourceColumnRef로 분리.
|
|
322
322
|
*/
|
|
323
323
|
attributeRef?: ModelId;
|
|
324
|
+
/**
|
|
325
|
+
* inverse nav(RELATION_REF) 미실체화 시 마지막 nav 필드명 기억용. navigable=false면 nav 속성 자체는
|
|
326
|
+
* 삭제되어(불변식 "navigable=true ⟺ nav 속성 존재" 유지·코드젠 무영향) 저장된 이름이 없다 — 이 힌트가
|
|
327
|
+
* 사용자가 편집했던 이름을 보관해, 인스펙터 비활성 필드 표시 및 재활성화 시 기본명 대신 복원에 쓰인다.
|
|
328
|
+
* 실체화되면 속성 name이 SoT이므로 이 힌트는 정리(재-off 시 현재 name을 다시 캡처).
|
|
329
|
+
*/
|
|
330
|
+
navFieldNameHint?: string;
|
|
324
331
|
/**
|
|
325
332
|
* 라운드트립 전용 — 레거시 EMBED 직렬화의 인라인 속성 원형(EMBED_REF/EMBED_OWN).
|
|
326
333
|
* EMBED hydration은 load-only라 저장 시 소유자로 펼친 표시 속성을 버리고 이 원형을 verbatim 환원한다
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { EmbeddableCatalog, LogicalModel, ModelId, SuperClassCatalog } from './types';
|
|
2
2
|
export declare const PHYSICAL_NAME_MAX_LENGTH = 63;
|
|
3
3
|
/**
|
|
4
4
|
* 물리명이 이식성 권장 한도를 초과하면 **초과 길이(문자 수)**, 아니면 null(비차단 — 호출부는 저장을
|
|
@@ -63,18 +63,6 @@ export interface ValidationContext {
|
|
|
63
63
|
*/
|
|
64
64
|
superClassCatalog?: SuperClassCatalog;
|
|
65
65
|
}
|
|
66
|
-
/** 같은 키를 2회 이상 갖는 항목만 중복으로 — 중복 그룹의 모든 멤버를 반환(어느 쪽이든 보고 고치게). */
|
|
67
|
-
/**
|
|
68
|
-
* 임베드 서브컬럼의 **실효 물리명** — 물리명 override(비어있지 않은 physicalName)가 있으면 그 값, 없으면
|
|
69
|
-
* 상속 기본값을 해석한다. EMBED_PREDEF·EMBED_OWN의 빈 슬롯은 "미매핑"이 아니라 카탈로그/임베더블 source의
|
|
70
|
-
* 기본 컬럼명을 상속하므로(JPA @Embedded는 @AttributeOverride 부재 시 임베더블 선언 컬럼명 사용), 컬럼 충돌
|
|
71
|
-
* 판정은 raw '' 가 아닌 이 실효 물리명으로 해야 한다. 특히 한 테이블에 같은 임베더블(예: Money)이 여러 번
|
|
72
|
-
* 쓰이고 서브컬럼을 비워두면 전부 같은 기본명으로 상속돼 실제 컬럼 충돌이 난다.
|
|
73
|
-
* - EMBED_PREDEF: 카탈로그 fields[index].physicalName (ctx 미주입이면 해석 불가 → '' 로 graceful degrade).
|
|
74
|
-
* - EMBED_OWN: 임베더블 엔터티 source 컬럼[index]의 physicalName(선언순 평탄화 = flattenEmbeddableColumns 동형).
|
|
75
|
-
* - NORMAL 등 그 외: raw physicalName 그대로(빈 값은 '' → 충돌 판정 제외).
|
|
76
|
-
*/
|
|
77
|
-
export declare function resolveColumnPhysicalName(attr: Attribute, col: DbColumn, index: number, model: LogicalModel, ctx?: Pick<ValidationContext, 'embeddableCatalog'>): string;
|
|
78
66
|
/**
|
|
79
67
|
* 설계 품질 검증 — 논리 모델(+선택 컨텍스트)을 받아 이슈 목록을 돌려준다.
|
|
80
68
|
* 순수 함수. 호출부가 심각도/차단정책/표시시점을 해석한다(예: 빈 이름 info는 저장 시점에만 표시).
|
|
@@ -11,11 +11,6 @@ import { ValidationIssue } from '../core/validation';
|
|
|
11
11
|
import { UiLocale, Translator } from '../i18n';
|
|
12
12
|
import { AssociationEnd, Attribute, DisplayMode, EmbeddableCatalog, Entity, EntityIndex, Geo, GroupCodeCatalog, LangCode, LogicalGroup, ModelId, Multiplicity, Operation, Point, PredefinedCustomTypeCatalog, SuperClassCatalog } from '../core/types';
|
|
13
13
|
import * as cmd from '../command/commands';
|
|
14
|
-
/**
|
|
15
|
-
* 관계 파생 FK 직접 삭제 시도 시의 안내 — 뷰 tooltip(어포던스)과 차단 시 토스트(피드백)가 공유한다.
|
|
16
|
-
* FK는 관계가 소유·관리하므로 컬럼을 직접 지우는 대신 연관관계선을 삭제해야 한다(Option B).
|
|
17
|
-
*/
|
|
18
|
-
export declare const FK_MANAGED_DELETE_MESSAGE = "\uC678\uB798\uD0A4\uB294 \uC5F0\uAD00\uAD00\uACC4\uC5D0\uC11C \uD30C\uC0DD\uB429\uB2C8\uB2E4. \uC0AD\uC81C\uD558\uB824\uBA74 \uC5F0\uAD00\uAD00\uACC4\uC120\uC744 \uC120\uD0DD\uD574 \uC0AD\uC81C\uD558\uC138\uC694.";
|
|
19
14
|
/** 엔티티 내부 속성을 가리키는 주소 원자 — 선택·컨텍스트·재정렬·연결 등 속성 단위 기능의 공통 참조점. */
|
|
20
15
|
export type AttrRef = {
|
|
21
16
|
entityId: ModelId;
|
|
@@ -219,7 +214,12 @@ export interface EditorController {
|
|
|
219
214
|
undo(): void;
|
|
220
215
|
redo(): void;
|
|
221
216
|
markSaved(): void;
|
|
222
|
-
|
|
217
|
+
/**
|
|
218
|
+
* add류 intent 공통 반환 계약: 성공 시 생성된 ModelId, 실패(조회 모드·충돌 프리즈·잠금·가드 차단) 시
|
|
219
|
+
* null. 거짓 성공 id를 돌려주면 뷰가 존재하지 않는 대상을 select(빈 폼)하므로, 소비처는 null 가드 후
|
|
220
|
+
* 후속 동작(자동 선택 등)을 수행해야 한다.
|
|
221
|
+
*/
|
|
222
|
+
addEntity(name?: string, location?: Point): ModelId | null;
|
|
223
223
|
renameEntity(id: ModelId, name: string): void;
|
|
224
224
|
updateEntity(id: ModelId, patch: Partial<Entity>): void;
|
|
225
225
|
moveEntity(id: ModelId, location: Point): void;
|
|
@@ -237,6 +237,11 @@ export interface EditorController {
|
|
|
237
237
|
setEntityLocked(id: ModelId, locked: boolean): void;
|
|
238
238
|
/** 엔티티 잠금 여부 조회 (레이아웃) */
|
|
239
239
|
isEntityLocked(id: ModelId): boolean;
|
|
240
|
+
/**
|
|
241
|
+
* 연관 잠금 여부 조회 — 양 끝 엔티티 중 한쪽이라도 잠겼으면 true(내부 게이트 isAssocLockedFn와
|
|
242
|
+
* 동일 의미론 단일 출처). 뷰가 관계 편집 어포던스(삭제 메뉴·인스펙터 폼)를 억제할 때 사용.
|
|
243
|
+
*/
|
|
244
|
+
isAssociationLocked(assocId: ModelId): boolean;
|
|
240
245
|
/** 활성 다이어그램 전체 엔티티 접기/펼치기 — 사전 상태 캡처 단일 커맨드(1 undo 스텝) */
|
|
241
246
|
collapseAll(): void;
|
|
242
247
|
expandAll(): void;
|
|
@@ -259,10 +264,10 @@ export interface EditorController {
|
|
|
259
264
|
setGroupLocked(groupId: ModelId, locked: boolean): void;
|
|
260
265
|
/** 그룹 잠금 여부 조회 (레이아웃) */
|
|
261
266
|
isGroupLocked(groupId: ModelId): boolean;
|
|
262
|
-
/** 선택 엔티티들로 새 그룹 생성 (멤버 bbox에 박스 배치) */
|
|
267
|
+
/** 선택 엔티티들로 새 그룹 생성 (멤버 bbox에 박스 배치) — 빈 입력·조회 모드 시 null */
|
|
263
268
|
createGroup(entityIds: ModelId[], name?: string): ModelId | null;
|
|
264
269
|
/** 빈 그룹 박스 생성 (이후 드래그로 엔티티 편입) */
|
|
265
|
-
addEmptyGroup(location: Point, name?: string): ModelId;
|
|
270
|
+
addEmptyGroup(location: Point, name?: string): ModelId | null;
|
|
266
271
|
removeGroup(groupId: ModelId): void;
|
|
267
272
|
/** 엔티티 이동 + 컨테인먼트에 따른 그룹 편입/해제를 한 명령으로 */
|
|
268
273
|
dropEntity(entityId: ModelId, location: Point, targetGroupId: ModelId | null): void;
|
|
@@ -338,16 +343,16 @@ export interface EditorController {
|
|
|
338
343
|
* dbAttr 슬롯은 레거시 `initAttributeDatabaseAttribute` 동형으로 **빈 골격**(physicalName/dataType
|
|
339
344
|
* 미설정)만 시드하고, 표시·저장 시 카탈로그 메타모델로 폴백한다(`SVG:976` 대응). 참조가 아니므로
|
|
340
345
|
* association은 만들지 않는다(entity.attributes 직접 보유 — 레거시 NORMAL 부류). 카탈로그에 없거나
|
|
341
|
-
* 대상 엔티티가 없으면 no-op(
|
|
346
|
+
* 대상 엔티티가 없으면 no-op(null).
|
|
342
347
|
*/
|
|
343
|
-
addPredefinedEmbed(entityId: ModelId, embeddableType: string): ModelId |
|
|
344
|
-
addAttribute(entityId: ModelId, partial?: Partial<Attribute>): ModelId;
|
|
348
|
+
addPredefinedEmbed(entityId: ModelId, embeddableType: string): ModelId | null;
|
|
349
|
+
addAttribute(entityId: ModelId, partial?: Partial<Attribute>): ModelId | null;
|
|
345
350
|
/**
|
|
346
351
|
* 시각 구획 행(DIVIDER) 추가 — 거대 엔티티에서 속성 묶음을 끊는 구분선. DB 컬럼·타입·식별자 없이
|
|
347
352
|
* 말미에 추가되며(이후 grip 드래그로 위치 조정), `name`은 선택적 섹션 라벨. divider 기본값을 단일
|
|
348
353
|
* 출처로 보장하려고 addAttribute에 위임한다.
|
|
349
354
|
*/
|
|
350
|
-
addDivider(entityId: ModelId): ModelId;
|
|
355
|
+
addDivider(entityId: ModelId): ModelId | null;
|
|
351
356
|
updateAttribute(entityId: ModelId, attributeId: ModelId, patch: Partial<Attribute>): void;
|
|
352
357
|
/**
|
|
353
358
|
* ⑤ 파생 타입 결합 — 속성 groupCode를 설정/해제하며 type을 동반 조정한다(레거시 정합).
|
|
@@ -378,21 +383,21 @@ export interface EditorController {
|
|
|
378
383
|
updateIndex(entityId: ModelId, indexId: ModelId, patch: Partial<EntityIndex>): void;
|
|
379
384
|
removeIndex(entityId: ModelId, indexId: ModelId): void;
|
|
380
385
|
/** 메서드(operation) 추가 — 신규는 visibility=PACKAGE, order=말미. 생성된 modelId 반환. */
|
|
381
|
-
addOperation(entityId: ModelId, partial?: Partial<Operation>): ModelId;
|
|
386
|
+
addOperation(entityId: ModelId, partial?: Partial<Operation>): ModelId | null;
|
|
382
387
|
updateOperation(entityId: ModelId, operationId: ModelId, patch: Partial<Operation>): void;
|
|
383
388
|
removeOperation(entityId: ModelId, operationId: ModelId): void;
|
|
384
389
|
/** 메서드 행 재정렬 — toIndex = 대상 제거 후 배열 기준 삽입 위치(단일 명령, undo 원자). */
|
|
385
390
|
reorderOperations(entityId: ModelId, operationIds: ModelId[], toIndex: number): void;
|
|
386
391
|
/** 메서드 강조 색 토큰 지정 (null이면 해제). */
|
|
387
392
|
setOperationSwatch(entityId: ModelId, operationId: ModelId, token: string | null): void;
|
|
388
|
-
addAssociation(sourceEntityId: ModelId, targetEntityId: ModelId, sourceColumnRef?: ModelId, targetColumnRef?: ModelId): ModelId;
|
|
393
|
+
addAssociation(sourceEntityId: ModelId, targetEntityId: ModelId, sourceColumnRef?: ModelId, targetColumnRef?: ModelId): ModelId | null;
|
|
389
394
|
/**
|
|
390
395
|
* 임베드 생성 — 소유자에 EMBED_OWN 표시 속성을 물질화(임베더블 source 컬럼 복사 + `embedded` 마커)하고
|
|
391
396
|
* EMBED association(owner EXACTLY_ONE / embeddable EXACTLY_ONE+composition)을 한 composite로 추가한다.
|
|
392
397
|
* 가드(결정 2 단일): 대상이 JPA_EMBEDDABLE이 아니거나 소유자가 이미 그 임베더블을 임베드했으면 no-op.
|
|
393
|
-
* 반환은 생성된 association id, 가드 차단 시
|
|
398
|
+
* 반환은 생성된 association id, 가드 차단 시 null.
|
|
394
399
|
*/
|
|
395
|
-
addEmbedAssociation(ownerEntityId: ModelId, embeddableEntityId: ModelId): ModelId |
|
|
400
|
+
addEmbedAssociation(ownerEntityId: ModelId, embeddableEntityId: ModelId): ModelId | null;
|
|
396
401
|
/**
|
|
397
402
|
* 임베드 카디널리티 설정 — 임베더블 end multiplicity를 지정 값으로 바꾼다. 컬렉션(`@ElementCollection`)
|
|
398
403
|
* 여부는 이 multiplicity에서 파생되는 값(권위=multiplicity, 결정 3): `*_MORE`(0..N / 1..N)면 컬렉션,
|
|
@@ -415,7 +420,7 @@ export interface EditorController {
|
|
|
415
420
|
addWaypoint(assocId: ModelId, index: number, point: Point): void;
|
|
416
421
|
removeWaypoint(assocId: ModelId, index: number): void;
|
|
417
422
|
clearWaypoints(assocId: ModelId): void;
|
|
418
|
-
addNote(memo?: string, location?: Point): ModelId;
|
|
423
|
+
addNote(memo?: string, location?: Point): ModelId | null;
|
|
419
424
|
removeNote(noteId: ModelId): void;
|
|
420
425
|
moveNote(noteId: ModelId, location: Point): void;
|
|
421
426
|
resizeNote(noteId: ModelId, size: {
|
|
@@ -512,4 +517,11 @@ export declare function createEditorController(initial?: EditorState, options?:
|
|
|
512
517
|
largeEntityThreshold?: number;
|
|
513
518
|
/** CHK-DSN-3 초기 활성 여부 — 기본 false. 런타임은 flagEntitiesWithoutRelations로 사용자가 토글. */
|
|
514
519
|
flagEntitiesWithoutRelations?: boolean;
|
|
520
|
+
/**
|
|
521
|
+
* 검증(validateModel) 재실행 디바운스 창(ms, 기본 250). validateModel은 전체 모델 스캔이라 키 입력마다
|
|
522
|
+
* 동기 재실행하면 대형 다이어그램에서 입력 지연의 주요 축(VE-1) — 기본은 변경 신호(revision) 기반
|
|
523
|
+
* 트레일링 디바운스. `0` 이하 주입 시 현행 동기 computed 그대로(변경 직후 즉시 일관성이 필요한
|
|
524
|
+
* 테스트·소비자용 escape hatch).
|
|
525
|
+
*/
|
|
526
|
+
validationDebounceMs?: number;
|
|
515
527
|
}): EditorController;
|