@g1cloud/entity-modeler-next 5.0.0-beta.9 → 5.0.0
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/README.md +19 -5
- package/dist/adapter/diagramAdapter.d.ts +6 -0
- package/dist/adapter/healBackfill.d.ts +38 -0
- package/dist/agent/resolver.d.ts +195 -7
- package/dist/agent/symbolicOp.d.ts +53 -4
- package/dist/command/op.d.ts +35 -1
- package/dist/command/opSync.d.ts +11 -1
- package/dist/command/stack.d.ts +11 -1
- package/dist/core/associationNav.d.ts +14 -0
- package/dist/core/columnResolve.d.ts +36 -0
- package/dist/core/embedSlots.d.ts +18 -0
- package/dist/core/entityPackage.d.ts +24 -0
- package/dist/core/fkDerived.d.ts +22 -2
- package/dist/core/indexCleanup.d.ts +16 -0
- package/dist/core/indexColumnRef.d.ts +27 -0
- package/dist/core/javaTypes.d.ts +5 -0
- package/dist/core/opSubject.d.ts +54 -0
- package/dist/core/projectActionLog.d.ts +7 -10
- package/dist/core/projectSeqDiff.d.ts +41 -0
- package/dist/core/propagation.d.ts +33 -2
- package/dist/core/quickFix.d.ts +9 -4
- package/dist/core/resolve.d.ts +0 -3
- package/dist/core/scaffoldJava.d.ts +30 -1
- package/dist/core/text.d.ts +2 -1
- package/dist/core/validation.d.ts +1 -13
- package/dist/editor/association.d.ts +18 -0
- package/dist/editor/attribute.d.ts +25 -0
- package/dist/editor/clipboardImport.d.ts +23 -0
- package/dist/editor/commandPlans.d.ts +111 -0
- package/dist/editor/controller.d.ts +61 -20
- package/dist/editor/entity.d.ts +19 -0
- package/dist/editor/group.d.ts +22 -0
- package/dist/editor/hostSync.d.ts +30 -0
- package/dist/editor/note.d.ts +11 -0
- package/dist/editor/selection.d.ts +22 -0
- package/dist/entity-modeler-next.css +1 -1
- package/dist/entity-modeler.js +16701 -13753
- package/dist/entity-modeler.umd.cjs +28 -24
- package/dist/i18n/ko.d.ts +64 -2
- package/dist/index.d.ts +26 -23
- package/dist/view/ColumnLangSelect.vue.d.ts +16 -0
- package/dist/view/DiagramCanvas.vue.d.ts +9 -0
- package/dist/view/DiagramExplorer.vue.d.ts +7 -2
- package/dist/view/HistoryPanel.vue.d.ts +3 -0
- package/dist/view/MultiLangTextField.vue.d.ts +7 -0
- package/dist/view/columnResolution.d.ts +91 -0
- package/dist/view/diffOverlay.d.ts +14 -0
- package/dist/view/embedSlotCollapse.d.ts +36 -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/dist/view/useAttributeEditing.d.ts +82 -0
- package/dist/view/useTreeCollapse.d.ts +16 -0
- package/package.json +9 -6
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Entity, IndexColumn, ModelId } from './types';
|
|
2
|
+
/** 한 인덱스의 정리 결과 — `columns` 는 정리 **후** 전량(패치가 통째 교체이므로). */
|
|
3
|
+
export type IndexColumnCleanup = {
|
|
4
|
+
indexRef: ModelId;
|
|
5
|
+
columns: IndexColumn[];
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* `entity` 에서 `removedAttributeIds` 가 사라질 때 정리해야 할 인덱스 목록.
|
|
9
|
+
*
|
|
10
|
+
* 고아가 되는 ref = 사라지는 속성의 **속성 modelId + 그 dbAttr modelId 전부**(두 표기 모두 유입 가능).
|
|
11
|
+
* 변화가 없는 인덱스는 결과에 넣지 않는다(빈 패치 방출 = INV-5 멱등 위배).
|
|
12
|
+
*
|
|
13
|
+
* ⚠️한 조작에서 여러 속성이 사라지면 **한 번에** 넘길 것 — 속성마다 따로 호출하면 각 산출이 원본 기준이라
|
|
14
|
+
* 나중 패치가 앞의 정리를 되돌린다.
|
|
15
|
+
*/
|
|
16
|
+
export declare function planIndexColumnCleanup(entity: Entity, removedAttributeIds: readonly ModelId[]): IndexColumnCleanup[];
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Attribute, DbColumn, ModelId } from './types';
|
|
2
|
+
/** 한 엔티티의 인덱스 columnRef 해소기. 두 표기(속성 modelId / dbAttr modelId)를 모두 받는다. */
|
|
3
|
+
export type IndexRefResolver = {
|
|
4
|
+
/** 이 ref 가 속한 속성(표시용). 다중 컬럼 속성 ref 도 여기선 해소된다. */
|
|
5
|
+
attributeOf(ref: ModelId): Attribute | undefined;
|
|
6
|
+
/**
|
|
7
|
+
* 이 ref 가 **특정하는 물리 컬럼**. undefined 면 컬럼이 특정되지 않은 것이다(다중 컬럼 속성 ref /
|
|
8
|
+
* 상속 · dangling). ⚠️`attributeOf` 가 있는데 이것이 없다 = *대상은 있으나 어느 컬럼인지 미지정*.
|
|
9
|
+
*/
|
|
10
|
+
columnOf(ref: ModelId): DbColumn | undefined;
|
|
11
|
+
/**
|
|
12
|
+
* 비교용 정규 키 — **컬럼이 특정되면** 그 dbAttr modelId, 아니면 원문 그대로.
|
|
13
|
+
* 원문이 그대로 나오는 경우는 셋이다: 이미 dbAttr 표기 / 다중 컬럼 속성 ref(모호) / 상속·dangling.
|
|
14
|
+
*/
|
|
15
|
+
canon(ref: ModelId): ModelId;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* 엔티티 속성 목록으로 해소기를 만든다. 인덱스는 **엔티티 로컬**이므로 그 엔티티 속성만 넘긴다
|
|
19
|
+
* (전역 맵을 쓰면 실 데이터의 modelId 중복[N-2 레거시 유입]에서 남의 엔티티 컬럼으로 해소된다 —
|
|
20
|
+
* `ddl.ts`의 `ownCols`가 같은 이유로 테이블 로컬이다).
|
|
21
|
+
*/
|
|
22
|
+
export declare function indexRefResolver(attributes: readonly Attribute[]): IndexRefResolver;
|
|
23
|
+
/**
|
|
24
|
+
* 미해소 ref 의 진단 라벨 — 산출물(DDL 생략 주석·코드젠 fillIn)이 **고칠 자리를 지목**하도록 한다.
|
|
25
|
+
* ref 원문(UUID)만 내면 사용자가 어느 컬럼인지 찾을 수 없다.
|
|
26
|
+
*/
|
|
27
|
+
export declare function describeIndexRef(r: IndexRefResolver, ref: ModelId): string;
|
package/dist/core/javaTypes.d.ts
CHANGED
|
@@ -17,6 +17,11 @@ export declare const DEFAULT_JAVA_TYPE = "String";
|
|
|
17
17
|
export declare const JAVA_TYPES: readonly JavaTypeDef[];
|
|
18
18
|
/** 저장값 → 표시 라벨. 미등록 값(임베더블 타입명·커스텀명·미지 값)은 그대로 반환(폴백). */
|
|
19
19
|
export declare function javaTypeLabel(value: string): string;
|
|
20
|
+
/**
|
|
21
|
+
* 물리 DB 타입 → 자바 타입 저장값. 매핑 없는 타입(미지 타입·구조 타입·JDBC 추상 타입)은 undefined —
|
|
22
|
+
* 호출자가 타입을 비워 "모른다"를 보존한다. 위 `JAVA_TYPE_BY_DATA_TYPE` 주석의 결정 근거 참조.
|
|
23
|
+
*/
|
|
24
|
+
export declare function javaTypeFromDataType(dataType: string | undefined): string | undefined;
|
|
20
25
|
/**
|
|
21
26
|
* ① 스칼라 자바 타입 셀렉트 후보(단일 출처). JAVA_TYPES에서 비후보(⑤·레거시 표시용)를 빼고
|
|
22
27
|
* ④ CustomType은 "사용자정의" 안내 라벨로 노출. ②embeddable·③customtype은 애초에 JAVA_TYPES에 없음.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { ModelId } from './types';
|
|
2
|
+
import { OpShape } from '../command/op';
|
|
3
|
+
/** 감사 대상 종류 — 논리 모델의 편집 단위. 레이아웃 축은 대상이 아니다. */
|
|
4
|
+
export type OpSubjectKind = 'entity' | 'attribute' | 'operation' | 'index' | 'association' | 'associationEnd' | 'group';
|
|
5
|
+
/** 무엇이 바뀐 대상인가. `entityRef`는 자식(속성/연산/인덱스)의 부모(이름 조회·복원 스코프). */
|
|
6
|
+
export interface OpSubject {
|
|
7
|
+
kind: OpSubjectKind;
|
|
8
|
+
ref: ModelId;
|
|
9
|
+
entityRef?: ModelId;
|
|
10
|
+
end?: 'end1' | 'end2';
|
|
11
|
+
}
|
|
12
|
+
/** op이 한 대상에 가하는 접촉 — 존재 변화(add/remove) 또는 내용 변경(existence 없음). */
|
|
13
|
+
export interface OpSubjectTouch {
|
|
14
|
+
subject: OpSubject;
|
|
15
|
+
/** 대상의 생성/삭제. 내용 변경(update)·기타는 undefined. */
|
|
16
|
+
existence?: 'add' | 'remove';
|
|
17
|
+
/** `entity.add` value에 인라인돼 태어난 자식(자기 op 없음) — 소비자가 top-level만 볼 때 거른다. */
|
|
18
|
+
inline?: true;
|
|
19
|
+
}
|
|
20
|
+
/** 인벤토리 한 행 — 이 kind를 감사 축이 어떻게 다루는가. */
|
|
21
|
+
export interface OpAuditHandling {
|
|
22
|
+
/** 이 op이 지목하는 대상 종류. `null`=감사 범위 밖(레이아웃 축). */
|
|
23
|
+
subject: OpSubjectKind | null;
|
|
24
|
+
/** 대상의 존재 변화 여부. */
|
|
25
|
+
existence: 'add' | 'remove' | null;
|
|
26
|
+
/** `projectFieldAudit`가 필드 변경(born/patch/tombstone)으로 투영하는가. */
|
|
27
|
+
fieldAudit: boolean;
|
|
28
|
+
/** 범위 밖이거나 예외적인 행의 근거. */
|
|
29
|
+
note?: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* **전 op 어휘 인벤토리.** lib이 방출하는 kind는 전부 여기 있어야 한다 —
|
|
33
|
+
* `opSubject.coverage.test.ts`가 소스의 `kind:` 리터럴과 대조해 누락을 실패로 만든다.
|
|
34
|
+
* (새 어휘를 추가하면 그 테스트가 깨진다 = "조용히 무시"가 "명시적 결정"으로 바뀌는 지점.)
|
|
35
|
+
*/
|
|
36
|
+
export declare const OP_AUDIT_INVENTORY: Record<string, OpAuditHandling>;
|
|
37
|
+
/**
|
|
38
|
+
* op이 건드리는 감사 대상 목록. 인벤토리에 없는(=이 lib이 모르는) kind는 빈 배열 — 발굴은
|
|
39
|
+
* `describeContainer`의 접두 폴백이 계속 덮는다.
|
|
40
|
+
*
|
|
41
|
+
* `entity.add`는 자신 + value에 인라인된 자식(속성/연산/인덱스)을 함께 낸다(`inline: true`).
|
|
42
|
+
* 인라인 자식을 볼지 여부는 소비자가 정한다 — 필드 감사가 이미 필드로 잡는 축이면 거른다.
|
|
43
|
+
*/
|
|
44
|
+
export declare function describeOpSubjects(op: OpShape): OpSubjectTouch[];
|
|
45
|
+
/** 발굴용 top-level 소속 대상. */
|
|
46
|
+
export interface OpContainer {
|
|
47
|
+
kind: 'entity' | 'association' | 'group';
|
|
48
|
+
ref: ModelId;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* op이 속한 top-level 대상(엔티티/연관/그룹). **접두 매칭**이라 같은 계열의 미지 어휘도 덮는다
|
|
52
|
+
* (모듈 헤더 ★ 참조 — 발굴 누락은 그 seq를 이력에서 통째로 지운다).
|
|
53
|
+
*/
|
|
54
|
+
export declare function describeContainer(op: OpShape): OpContainer | null;
|
|
@@ -1,14 +1,11 @@
|
|
|
1
|
-
import { ModelId } from './types';
|
|
2
1
|
import { FieldAuditRecord } from './projectFieldAudit';
|
|
3
|
-
import {
|
|
4
|
-
export type ActionSubjectKind =
|
|
5
|
-
/**
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
end?: 'end1' | 'end2';
|
|
11
|
-
}
|
|
2
|
+
import { OpSubject, OpSubjectKind } from './opSubject';
|
|
3
|
+
export type ActionSubjectKind = OpSubjectKind;
|
|
4
|
+
/**
|
|
5
|
+
* 무엇이 바뀐 대상인가. entityRef는 자식(속성/연산/인덱스) subject의 부모(이름 조회·복원 스코프).
|
|
6
|
+
* 정의는 `opSubject`(어휘 해석 단일 출처)가 갖고 여기선 공개 이름만 유지한다.
|
|
7
|
+
*/
|
|
8
|
+
export type ActionSubject = OpSubject;
|
|
12
9
|
/** 한 대상의 한 필드 변경(old→new / tombstone). */
|
|
13
10
|
export interface ActionFieldChange {
|
|
14
11
|
field: string;
|
|
@@ -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>;
|
|
@@ -40,13 +40,44 @@ export declare function computeForeignAttributes(logical: LogicalModel, associat
|
|
|
40
40
|
* 멱등(INV-5): 이미 맞춰진 상태에서 다시 호출하면 빈 계획을 돌려준다.
|
|
41
41
|
*/
|
|
42
42
|
export declare function reconcileForeignAttributes(logical: LogicalModel, childEntityId: ModelId, idFactory?: IdFactory): ReconcilePlan;
|
|
43
|
+
/**
|
|
44
|
+
* 같은 자식에 두 번째 계획이 도착했을 때(비등깊이 다중 경로 — A→D 직행 + A→B→D 경유) 병합한다.
|
|
45
|
+
* next는 "원본 + base 적용" 상태 기준의 diff이므로, base의 add를 겨냥한 후속 update/remove를
|
|
46
|
+
* add 쪽으로 fold하면 병합 결과는 다시 *원본* 기준 diff가 된다(반환 계약 보존).
|
|
47
|
+
* add의 modelId는 work에 이미 적용된 것을 그대로 유지해야 한다 — 후손 계획의
|
|
48
|
+
* sourceAttributeRef가 이 id를 참조하므로 재계산(새 id 발급)은 정합을 깨뜨린다.
|
|
49
|
+
*/
|
|
50
|
+
/**
|
|
51
|
+
* 두 reconcile 계획을 하나로 접는다 — 늦게 온 patch 가 이긴다(같은 속성이면 필드 단위 덮어쓰기).
|
|
52
|
+
* ★다중 경로 전파(CC-2)뿐 아니라 **여러 루트의 cascade 가 같은 후손에 겹칠 때**도 쓴다
|
|
53
|
+
* (`childReconcileWithCascade` — 다이아몬드에서 같은 자식이 두 번 계획되면 op 배치에 같은 경로의
|
|
54
|
+
* `$set` 이 두 번 실려 호스트가 배치를 거부한다).
|
|
55
|
+
*/
|
|
56
|
+
export declare function mergePlans(base: ReconcilePlan, next: ReconcilePlan): ReconcilePlan;
|
|
43
57
|
/**
|
|
44
58
|
* changedEntityId의 식별자 변경이 영향을 주는 모든 후손 자식의 reconcile 계획.
|
|
45
|
-
* A→B→C 연쇄와 사이클(A→B→A)을 visited 가드로 안전 종료(INV-6).
|
|
46
59
|
* 클론에 단계별로 적용하며 다음 단계 입력을 갱신하므로, 반환 계획은 *원본* logical 기준이다.
|
|
47
60
|
* self-association은 비식별이라 자식 식별자를 바꾸지 않아 더 전파되지 않는다(자연 종료).
|
|
61
|
+
*
|
|
62
|
+
* 비등깊이 다중 경로(A→D + A→B→D)에서는 D의 desired가 두 단계에 걸쳐 도착한다 —
|
|
63
|
+
* 늦게 온 계획은 mergePlans로 병합하고, 계획을 받은 자식은 재큐해 후손을 재연쇄한다.
|
|
64
|
+
* 종료(INV-6): reconcile이 멱등 diff라 비순환 그래프는 자연 수렴(재처리 횟수 ≤ 최장 경로 깊이).
|
|
65
|
+
* 식별 사이클(A⇄B)은 desired가 무한 성장하므로 엔터티당 처리 횟수를 entities.length로 캡해 절단한다
|
|
66
|
+
* (비순환에선 최장 경로 ≤ 엔터티 수라 캡이 정확성을 해치지 않는다).
|
|
48
67
|
*/
|
|
49
68
|
export declare function planPropagation(logical: LogicalModel, changedEntityId: ModelId, idFactory?: IdFactory): Map<ModelId, ReconcilePlan>;
|
|
69
|
+
/**
|
|
70
|
+
* "자식의 FK 집합이 직접 바뀌는" 트리거(관계 삭제·identifying 토글·부모 엔터티 삭제)의
|
|
71
|
+
* seed reconcile + 후손 cascade 통합 계획. futureLogical은 트리거 변경이 이미 반영된 상태여야 한다.
|
|
72
|
+
* 반환은 seed(자식)부터 후손 순서의 목록 — 빈 계획은 제외.
|
|
73
|
+
*
|
|
74
|
+
* editor controller(→Command)와 agent resolver(→OpShape)가 이 산식을 공유한다 — 계약 4(cascade =
|
|
75
|
+
* 클라 명시 분해)의 계산 주체를 한 곳에 두어 쓰기 경로별 분해 드리프트를 구조적으로 차단한다.
|
|
76
|
+
*/
|
|
77
|
+
export declare function planChildReconcileWithCascade(futureLogical: LogicalModel, childId: ModelId, idFactory?: IdFactory): Array<{
|
|
78
|
+
entityId: ModelId;
|
|
79
|
+
plan: ReconcilePlan;
|
|
80
|
+
}>;
|
|
50
81
|
/**
|
|
51
82
|
* 주어진 속성이 "연관관계가 관리하는 FK 컬럼"이면 그 소유 연관관계를 돌려준다(아니면 undefined).
|
|
52
83
|
*
|
|
@@ -54,7 +85,7 @@ export declare function planPropagation(logical: LogicalModel, changedEntityId:
|
|
|
54
85
|
* 관계가 소유한다 — 컬럼을 직접 지우는 게 아니라 관계를 삭제/변경해 제거해야 한다. 이 판별로
|
|
55
86
|
* FK 속성의 직접 삭제를 차단(어포던스+가드)하고 사용자를 관계 삭제 경로로 유도한다.
|
|
56
87
|
*
|
|
57
|
-
* FK 컬럼 불변식(RELATION* + 물리 컬럼
|
|
88
|
+
* FK 컬럼 불변식(`isFkDerivedColumn` = RELATION* + 물리 컬럼 보유)으로 먼저 게이트해, 관계의
|
|
58
89
|
* 부모측 end가 가리키는 PK(비-RELATION) 오탐을 배제한다. 그다음 두 신호로 소유 관계를 찾는다:
|
|
59
90
|
*
|
|
60
91
|
* 1순위 `derivedFrom.associationRef` — 전파가 심은 권위 신호. v2 네이티브 doc에 보존되고 어댑터
|
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;
|
package/dist/core/resolve.d.ts
CHANGED
|
@@ -49,9 +49,6 @@ export interface ResolvedDiagram {
|
|
|
49
49
|
notes: ResolvedNote[];
|
|
50
50
|
/** 노트 → 대상 엔티티 연결선 (대상이 존재하는 것만; dangling은 prune) */
|
|
51
51
|
noteConnections: ResolvedNoteConnection[];
|
|
52
|
-
/** 레이아웃에만 있던(논리에 없는) 정리 대상 항목 */
|
|
53
|
-
prunedEntityRefs: ModelId[];
|
|
54
|
-
prunedAssociationRefs: ModelId[];
|
|
55
52
|
}
|
|
56
53
|
export interface AutoLayoutOptions {
|
|
57
54
|
startX: number;
|
|
@@ -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/text.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { DisplayMode, LogicalModel } from './types';
|
|
2
|
+
import { ColumnResolveContext } from './columnResolve';
|
|
2
3
|
/**
|
|
3
4
|
* 표시 모드별 라벨(평문) — Diagram Explorer 트리/캡션 공용.
|
|
4
5
|
* EntityNode의 labelSegs와 동일 의미 규칙: '논리'는 업무 논리명이며 없으면 '(논리명)'
|
|
@@ -8,4 +9,4 @@ import { DisplayMode, LogicalModel } from './types';
|
|
|
8
9
|
* (`em.node.logicalMissing`)을 주입하고, 미주입 시 ko 기본값으로 폴백(codegen/테스트 무회귀).
|
|
9
10
|
*/
|
|
10
11
|
export declare function displayLabel(mode: DisplayMode, code: string, logical: string | undefined, physical: string | undefined, logicalFallback?: string): string;
|
|
11
|
-
export declare function entityModelToText(logical: LogicalModel): string;
|
|
12
|
+
export declare function entityModelToText(logical: LogicalModel, ctx?: ColumnResolveContext): string;
|
|
@@ -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는 저장 시점에만 표시).
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Ref } from 'vue';
|
|
2
|
+
import { Command, EditorState } from '../command/types';
|
|
3
|
+
import { EditorController } from './controller';
|
|
4
|
+
import { ModelId } from '../core/types';
|
|
5
|
+
/** 이 축이 팩토리 클로저에서 쓰는 것 전부. 늘어나면 여기 선언이 먼저 늘어난다(= 의존 인벤토리). */
|
|
6
|
+
export interface AssociationContext {
|
|
7
|
+
/** 편집 대상 reactive 상태(속성만 교체되므로 참조 안정). */
|
|
8
|
+
state: EditorState;
|
|
9
|
+
/** 조회 모드 판정 — add류가 `null`을 돌려주려면 run()의 no-op 백스톱보다 앞에서 봐야 한다. */
|
|
10
|
+
editable: Ref<boolean>;
|
|
11
|
+
/** 모델 변경의 단일 실행점(조회 모드 no-op + 안내). */
|
|
12
|
+
run: (c: Command) => void;
|
|
13
|
+
/** 잠금 게이트(엔티티) — 관계 *생성*은 관계가 아직 없어 양 끝을 각각 본다. */
|
|
14
|
+
gateEntityLocked: (id: ModelId) => boolean;
|
|
15
|
+
/** 잠금 게이트(관계) — 양끝 중 하나라도 잠기면 차단(그 의미론의 단일 출처). */
|
|
16
|
+
gateAssocLocked: (assocId: ModelId) => boolean;
|
|
17
|
+
}
|
|
18
|
+
export declare function createAssociationApi(ctx: AssociationContext): Pick<EditorController, 'addAssociation' | 'addEmbedAssociation' | 'setEmbedCardinality' | 'removeAssociation' | 'setAssociationIdentifying' | 'updateAssociationEnd'>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Ref } from 'vue';
|
|
2
|
+
import { Command, EditorState } from '../command/types';
|
|
3
|
+
import { Translator } from '../i18n';
|
|
4
|
+
import { EditorController, Selection } from './controller';
|
|
5
|
+
import { EmbeddableCatalog, ModelId } from '../core/types';
|
|
6
|
+
/** 이 축이 팩토리 클로저에서 쓰는 것 전부. 늘어나면 여기 선언이 먼저 늘어난다(= 의존 인벤토리). */
|
|
7
|
+
export interface AttributeContext {
|
|
8
|
+
/** 편집 대상 reactive 상태(속성만 교체되므로 참조 안정). */
|
|
9
|
+
state: EditorState;
|
|
10
|
+
/** 조회 모드 판정 — add류가 `null`을 돌려주려면 run()의 no-op 백스톱보다 앞에서 봐야 한다. */
|
|
11
|
+
editable: Ref<boolean>;
|
|
12
|
+
/** 모델 변경의 단일 실행점(조회 모드 no-op + 안내). */
|
|
13
|
+
run: (c: Command) => void;
|
|
14
|
+
/** 잠금 게이트 — 차단 시 true + 안내 emit. 속성 편집은 소속 엔티티 잠금을 따른다. */
|
|
15
|
+
gateEntityLocked: (entityId: ModelId) => boolean;
|
|
16
|
+
/** 호스트 주입 임베더블 카탈로그(`addPredefinedEmbed`의 슬롯 골격 소스). */
|
|
17
|
+
embeddableCatalog: Ref<EmbeddableCatalog>;
|
|
18
|
+
/** UI 크롬 번역기 — FK 직접 삭제 차단 안내 문구용. */
|
|
19
|
+
t: Translator;
|
|
20
|
+
/** 차단 안내(텍스트별 단기 dedup) — 무음 차단을 막는 백스톱. */
|
|
21
|
+
emitGateNotice: (text: string) => void;
|
|
22
|
+
/** 삭제된 행을 선택이 가리키지 않도록 해제하는 쓰기(`removeAttributes`). */
|
|
23
|
+
selection: Ref<Selection>;
|
|
24
|
+
}
|
|
25
|
+
export declare function createAttributeApi(ctx: AttributeContext): Pick<EditorController, 'addPredefinedEmbed' | 'addAttribute' | 'addDivider' | 'updateAttribute' | 'setAttributeGroupCode' | 'setEmbedColumns' | 'removeAttribute' | 'removeAttributes' | 'setAttributeSwatch' | 'setAttributeSwatches' | 'reorderAttributes'>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ComputedRef, Ref } from 'vue';
|
|
2
|
+
import { Command, EditorState } from '../command/types';
|
|
3
|
+
import { ClipboardContent, EditorController, Selection } from './controller';
|
|
4
|
+
import { ModelId } from '../core/types';
|
|
5
|
+
/** 이 축이 팩토리 클로저에서 쓰는 것 전부 — 늘어나면 여기 선언이 먼저 늘어난다(의존 표면 = 이 타입). */
|
|
6
|
+
export interface ClipboardImportContext {
|
|
7
|
+
/** 편집 대상 reactive 상태(속성 교체만 일어나므로 참조 안정). */
|
|
8
|
+
state: EditorState;
|
|
9
|
+
clipboard: Ref<ClipboardContent | null>;
|
|
10
|
+
/** paste·importEntities가 붙여넣은 대상으로 선택을 옮긴다(쓰기). */
|
|
11
|
+
selection: Ref<Selection>;
|
|
12
|
+
inspectedEntityId: ComputedRef<ModelId | null>;
|
|
13
|
+
/** 조회 모드 판정 — run()의 백스톱과 별개로 selection 부수효과를 막기 위해 진입에서 직접 본다. */
|
|
14
|
+
editable: Ref<boolean>;
|
|
15
|
+
/** 모델 변경의 단일 실행점(조회 모드 no-op + 안내). */
|
|
16
|
+
run: (c: Command) => void;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* 클립보드·임포트 인텐트 3종을 조립한다. 컨트롤러는 반환된 메서드를 `EditorController`에 **명시 위임**한다
|
|
20
|
+
* (스프레드가 아니라 한 줄씩) — 스프레드는 이 모듈에 export가 늘면 컨트롤러 런타임 표면이 **무심사로**
|
|
21
|
+
* 증식하는 배럴과 같은 실패 모드다(TI-4 `export *` 금지와 같은 논거: 최소 저항 경로가 곧 올바른 행동).
|
|
22
|
+
*/
|
|
23
|
+
export declare function createClipboardImportApi(ctx: ClipboardImportContext): Pick<EditorController, 'copy' | 'paste' | 'importEntities'>;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { Command, EditorState } from '../command/types';
|
|
2
|
+
import { ReconcilePlan } from '../core/propagation';
|
|
3
|
+
import { Attribute, DbColumn, Entity, LogicalModel, ModelId, Point } from '../core/types';
|
|
4
|
+
/**
|
|
5
|
+
* 한 조작이 지우는 속성의 누산기 — 인덱스 컬럼 정리를 **조작당 한 번**만 방출하기 위한 것.
|
|
6
|
+
*
|
|
7
|
+
* ★왜 누산해야 하나: 정리 패치(`index.update`)는 `columns` 배열을 **통째로 교체**하고, 계획은
|
|
8
|
+
* 구성 시점에 고정된다(결정적 redo). 그래서 같은 엔티티의 속성을 두 경로가 각각 지우면서 각자
|
|
9
|
+
* 정리를 내면 **뒤 패치가 앞 정리를 되돌린다** — 자기참조 관계가 정확히 그 형상이다(관계 삭제 시
|
|
10
|
+
* 부모 inverse nav 제거와 자식 FK reconcile 제거가 *같은 엔티티*에 떨어진다). 사이트마다 이 배열을
|
|
11
|
+
* 넘기고 마지막에 `indexCleanupCommands`를 한 번 부르면 그 충돌이 구조적으로 불가능해진다
|
|
12
|
+
* (resolver 가 `OrderAllocator`·`removedAttrDedup`을 스레딩하는 것과 같은 관용구).
|
|
13
|
+
*/
|
|
14
|
+
export type RemovedAttributes = {
|
|
15
|
+
entityId: ModelId;
|
|
16
|
+
attributeId: ModelId;
|
|
17
|
+
}[];
|
|
18
|
+
/**
|
|
19
|
+
* 속성 제거 명령 — **`cmd.removeAttribute`를 직접 부르지 않고 항상 이것을 쓴다.** 제거 사실을
|
|
20
|
+
* `removed`에 기록해 인덱스 정리가 빠지지 않게 한다(그 누락이 이 트랙이 고치는 결함이다).
|
|
21
|
+
*/
|
|
22
|
+
export declare function removeAttributeCommands(entityId: ModelId, attributeIds: readonly ModelId[], removed: RemovedAttributes): Command[];
|
|
23
|
+
/**
|
|
24
|
+
* 누산된 제거가 남길 인덱스 dangling 정리 명령 — 조작의 서브명령 **맨 끝**에 한 번 붙인다.
|
|
25
|
+
* `logical`은 제거 **전** 상태여야 한다(사라지는 속성의 dbAttr modelId를 알아야 하므로).
|
|
26
|
+
*/
|
|
27
|
+
export declare function indexCleanupCommands(logical: LogicalModel, removed: RemovedAttributes): Command[];
|
|
28
|
+
/**
|
|
29
|
+
* 식별자 전파 reconcile 계획을 자식 엔터티 대상 서브명령 배열로 변환.
|
|
30
|
+
* 1차 변경(관계 생성/삭제 등)과 함께 composite로 묶으면 전파 FK 동기화가 하나의 undo/redo
|
|
31
|
+
* 원자 단위가 된다 — 부분 undo로 고아 FK가 남지 않는다.
|
|
32
|
+
* 순서(remove→update→add)는 각기 다른 속성을 대상으로 해 상호 간섭이 없다.
|
|
33
|
+
*
|
|
34
|
+
* ★**owner 앵커 와이어링(CC-3)** — 계획이 관계의 FK를 새로 만들면 `end2.attributeRef`를 그 FK로 맞춘다.
|
|
35
|
+
* 종전에는 속성 CRUD만 방출해 앵커가 죽은 id를 계속 가리켰고, 코드젠 `relByAttr`(scaffoldJava:454)이
|
|
36
|
+
* 해소에 실패해 **관계가 산출에서 사라졌다**. 두 형상을 함께 덮는다:
|
|
37
|
+
* - **교체**: 부모 PK가 바뀌어 구 FK remove + 신 FK add가 같이 나는데 앵커가 구 FK를 가리킴
|
|
38
|
+
* → 모델은 완전한데 산출만 소실되는 최악 형상.
|
|
39
|
+
* - **재획득**: 부모가 PK를 얻어 FK가 add되는데 앵커가 미설정/죽은 상태 → cascade add 경로엔
|
|
40
|
+
* 앵커 배선이 없었다(생성 경로 `addAssociation:1947`·임베더블 전환 `:749`에만 있었다).
|
|
41
|
+
* 살아남는 속성을 가리키는 앵커는 건드리지 않는다(멱등 + 사용자/기존 상태 존중).
|
|
42
|
+
*
|
|
43
|
+
* ⚠️ **예방 전용 — 기존 dangling은 복구하지 않는다.** 이 함수는 전파 계획이 있을 때만 호출되므로,
|
|
44
|
+
* 이미 앵커가 죽은 문서는 그 자식에 계획이 발동하는 편집(부모 식별자 변경 등)이 있어야 정정된다.
|
|
45
|
+
* 엔티티명 변경 같은 비-식별자 편집은 계획이 비어 도달하지 않는다(실측: 실 데이터 유일 사례
|
|
46
|
+
* `Cart` self-assoc은 부모 rename으로 정정되지 않음). 기존 분의 복구는 로드-타임 파생 + 통합 스윕
|
|
47
|
+
* (`planHealBackfillOps`가 이미 `end1.attributeRef`를 diff하므로 end2 대칭 확장) 소관 — 별 결정.
|
|
48
|
+
*
|
|
49
|
+
* ⚠️ 순수 제거(부모가 PK를 잃음·임베더블 전환)로 **가리킬 FK가 아예 없는 경우는 해제하지 않는다** —
|
|
50
|
+
* 그 상태는 전파 산출이 0이라 방출할 관계도 없어 무해하고, `CHK-JPA-19`도 같은 근거로 면제한다(관계가
|
|
51
|
+
* 아니라 부모 PK 부재가 고칠 자리 = `CHK-JPA-1`). 호스트 검출기 규칙 5(`owner-fk-attr`)에는 남으므로
|
|
52
|
+
* 축적 위반 정리(B축) 소관.
|
|
53
|
+
* ※ 종전 이 자리에 적힌 "undefined가 wire에서 탈락해(CC-8) clear를 표현할 수 없다"는 **해소됐다** —
|
|
54
|
+
* `toWirePatch`(op.ts)가 update patch의 undefined를 null로 정규화하므로 `{attributeRef: undefined}`도
|
|
55
|
+
* 서버에 clear로 도달한다. 즉 위 판단은 이제 **전송 제약이 아니라 도메인 판단**으로만 서 있다(해제해도
|
|
56
|
+
* 무해하지만 얻는 것이 없다). 해제로 전환하려면 CC-3 복구 트랙에서 함께 결정할 것.
|
|
57
|
+
*/
|
|
58
|
+
export declare function reconcilePlanToCommands(logical: LogicalModel, childId: ModelId, plan: ReconcilePlan, removed: RemovedAttributes): Command[];
|
|
59
|
+
/** logical을 얕게 복제하되 한 엔터티의 attributes만 transform 결과로 교체(읽기 전용 전파 계획 입력용). */
|
|
60
|
+
export declare function withEntityAttributes(logical: LogicalModel, entityId: ModelId, transform: (attrs: Attribute[]) => Attribute[]): LogicalModel;
|
|
61
|
+
/**
|
|
62
|
+
* 부모(parentId) 식별자 변경이 자식·후손으로 번지는 연쇄 reconcile 서브명령.
|
|
63
|
+
* futureLogical은 변경이 이미 반영된 상태여야 한다(construction 시점 계획 고정 → 결정적 redo).
|
|
64
|
+
* 영향 없는 변경(비식별 속성 등)이면 빈 배열을 돌려준다(planPropagation이 빈 계획만 산출).
|
|
65
|
+
*
|
|
66
|
+
* **임베드 슬롯 보충도 여기서 함께 방출**한다 — 편집된 엔티티가 임베더블이면 사용처(owner)의
|
|
67
|
+
* `EMBED_OWN` 표시 속성 슬롯을 선언 컬럼 수까지 채운다(FK 전파의 임베드 짝, `core/embedSlots`).
|
|
68
|
+
* 이 seam을 고른 이유: 속성 추가·수정·삭제·임베더블 전환의 모든 진입점이 이미 여기를 지나므로
|
|
69
|
+
* 트리거를 한 곳에만 두면 되고, 서브명령이 같은 composite에 실려 **undo가 원자적**이다.
|
|
70
|
+
*/
|
|
71
|
+
export declare function cascadeCommands(futureLogical: LogicalModel, parentId: ModelId, removed: RemovedAttributes): Command[];
|
|
72
|
+
/**
|
|
73
|
+
* "자식의 FK 집합이 직접 바뀌는" 트리거(관계 삭제·identifying 토글)용 연쇄 서브명령.
|
|
74
|
+
* 1) seed 자식을 직접 reconcile(FK 증감/플립), 2) 그 변화를 적용한 상태로 후손 cascade.
|
|
75
|
+
* (부모 식별자 자체가 바뀌는 트리거는 부모 자신 reconcile이 불필요해 cascadeCommands를 직접 쓴다.)
|
|
76
|
+
* futureLogical은 트리거 변경이 이미 반영된 상태여야 한다(construction 시점 계획 고정).
|
|
77
|
+
*/
|
|
78
|
+
export declare function childReconcileWithCascade(futureLogical: LogicalModel, childIds: readonly ModelId[], removed: RemovedAttributes): Command[];
|
|
79
|
+
export declare function flattenEmbeddableColumns(embeddable: Entity): DbColumn[];
|
|
80
|
+
/**
|
|
81
|
+
* 임베더블 → 일반 엔터티 역전환의 부수 명령(stereotype update 명령에 합성).
|
|
82
|
+
* 임베더블이 1급 엔터티가 되면 자체 테이블·PK를 가지므로:
|
|
83
|
+
* 1) PK 자동 부여 — 식별자가 하나도 없으면 기본 PK(id/Long/BIGINT, addEntity 기본형과 동일)를 신설.
|
|
84
|
+
* 2) 이 임베더블(id)을 임베드하던 EMBED 관계를 일반 관계로 전환 — owner가 보유한 EMBED_OWN 표시속성
|
|
85
|
+
* (embedded.embeddableRef === id)을 제거하고, 관계 ends를 owner=end1(부모)/X=end2(자식)로 정규화한다.
|
|
86
|
+
* composition·embed attributeRef·legacyEmbedRaw를 버려야 저장 분기(assocToEmbed·legacyEmbedRaw)가
|
|
87
|
+
* 더는 EMBED로 환원하지 않는다. owner를 부모로 유지해 X(end2 자식)가 owner PK를 FK로 받는다(전파).
|
|
88
|
+
* plan은 construction 시점 고정(결정적 redo) — childReconcileWithCascade와 동일 산식을 인라인한다.
|
|
89
|
+
*/
|
|
90
|
+
export declare function leavingEmbeddableCommands(logical: LogicalModel, id: ModelId): Command[];
|
|
91
|
+
export declare function enteringEmbeddableCommands(logical: LogicalModel, id: ModelId): Command[];
|
|
92
|
+
/**
|
|
93
|
+
* 그룹 이동 명령 집합 — 그룹 박스 + 멤버 절대좌표 + 내부 관계 waypoint를 같은 delta로.
|
|
94
|
+
* 드래그(`./group` dragGroup)·키보드(`./selection` nudgeNodes) 양쪽에서 재사용; 호출부가
|
|
95
|
+
* composite로 감싸 한 명령으로 실행한다.
|
|
96
|
+
*
|
|
97
|
+
* ★**이 파일에서 유일하게 `LogicalModel`이 아니라 `EditorState`를 받는다**(위 헤더 계약의 예외).
|
|
98
|
+
* 그룹 이동은 본질적으로 레이아웃 연산이라 `groupLayouts`·`associationLayouts`·`notes`를 읽어야
|
|
99
|
+
* 하고, 그러면서 멤버십 판정(`logical.groups`)·내부 관계 판정(`logical.associations`)도 필요해
|
|
100
|
+
* 양 뎁스를 함께 본다. 순수성(같은 입력 → 같은 `Command[]`)은 그대로다.
|
|
101
|
+
* ★**여기로 내려온 경위**(VE-6 결정 ②): 팩토리 클로저 안에 있으면서 `./selection`에 주입되고
|
|
102
|
+
* `dragGroup`(컨트롤러)도 쓰던 함수다. S8이 그룹 축을 분리하면서 **소비자 둘 다 외부 모듈**이
|
|
103
|
+
* 되어, 팩토리가 자기는 쓰지 않는 헬퍼를 들고 두 모듈에 배관만 하는 형태가 됐다 ⇒ 중립 위치인
|
|
104
|
+
* 여기로 내리고 양쪽이 직접 import 한다(`SelectionContext`의 주입 항목이 하나 줄었다).
|
|
105
|
+
* `selection.ts` 헤더가 *"세 번째 소비자가 생길 때"*로 적어 둔 트리거의 실제 발동 사유는
|
|
106
|
+
* 개수가 아니라 **팩토리가 소비자에서 빠진 것**이었다.
|
|
107
|
+
*/
|
|
108
|
+
export declare function groupMoveCommands(state: EditorState, groupId: ModelId, location: Point, members: {
|
|
109
|
+
id: ModelId;
|
|
110
|
+
location: Point;
|
|
111
|
+
}[]): Command[];
|