@simplysm/sd-claude 14.0.89 → 14.0.90
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/claude/references/sd-simplysm14/README.md +16 -17
- package/claude/references/sd-simplysm14/apis/angular/README.md +52 -30
- package/claude/references/sd-simplysm14/apis/angular/controls.md +200 -38
- package/claude/references/sd-simplysm14/apis/angular/crud.md +41 -53
- package/claude/references/sd-simplysm14/apis/angular/directives.md +66 -22
- package/claude/references/sd-simplysm14/apis/angular/features.md +127 -40
- package/claude/references/sd-simplysm14/apis/angular/infra.md +60 -43
- package/claude/references/sd-simplysm14/apis/angular/layout.md +56 -20
- package/claude/references/sd-simplysm14/apis/angular/overlay.md +74 -74
- package/claude/references/sd-simplysm14/apis/angular/routing-appstructure.md +50 -40
- package/claude/references/sd-simplysm14/apis/angular/selection-managers.md +55 -15
- package/claude/references/sd-simplysm14/apis/angular/shared-data.md +59 -42
- package/claude/references/sd-simplysm14/apis/angular/sheet.md +77 -62
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-auto-update/README.md +8 -7
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-file-system/README.md +71 -43
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-intent/README.md +22 -14
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-usb-storage/README.md +19 -19
- package/claude/references/sd-simplysm14/apis/core-browser/README.md +17 -17
- package/claude/references/sd-simplysm14/apis/core-browser/dom-element.md +28 -28
- package/claude/references/sd-simplysm14/apis/core-browser/indexed-db.md +37 -37
- package/claude/references/sd-simplysm14/apis/core-common/README.md +87 -219
- package/claude/references/sd-simplysm14/apis/core-common/array-ext.md +54 -98
- package/claude/references/sd-simplysm14/apis/core-common/async-runtime.md +57 -99
- package/claude/references/sd-simplysm14/apis/core-common/datetime.md +60 -103
- package/claude/references/sd-simplysm14/apis/core-common/errors.md +42 -47
- package/claude/references/sd-simplysm14/apis/core-common/obj.md +42 -88
- package/claude/references/sd-simplysm14/apis/core-common/serialization.md +55 -0
- package/claude/references/sd-simplysm14/apis/core-node/README.md +6 -7
- package/claude/references/sd-simplysm14/apis/core-node/consola.md +17 -12
- package/claude/references/sd-simplysm14/apis/core-node/cpx.md +14 -13
- package/claude/references/sd-simplysm14/apis/core-node/fs-watcher.md +9 -8
- package/claude/references/sd-simplysm14/apis/core-node/fsx.md +14 -13
- package/claude/references/sd-simplysm14/apis/core-node/pathx.md +4 -8
- package/claude/references/sd-simplysm14/apis/core-node/worker.md +14 -12
- package/claude/references/sd-simplysm14/apis/excel/README.md +22 -22
- package/claude/references/sd-simplysm14/apis/excel/cell.md +37 -29
- package/claude/references/sd-simplysm14/apis/excel/conditional-format.md +29 -15
- package/claude/references/sd-simplysm14/apis/excel/style.md +33 -27
- package/claude/references/sd-simplysm14/apis/excel/utils.md +29 -19
- package/claude/references/sd-simplysm14/apis/excel/workbook-worksheet.md +78 -55
- package/claude/references/sd-simplysm14/apis/excel/wrapper.md +42 -45
- package/claude/references/sd-simplysm14/apis/orm-common/README.md +6 -8
- package/claude/references/sd-simplysm14/apis/orm-common/db-context.md +118 -67
- package/claude/references/sd-simplysm14/apis/orm-common/expr.md +83 -86
- package/claude/references/sd-simplysm14/apis/orm-common/queryable.md +102 -93
- package/claude/references/sd-simplysm14/apis/orm-common/schema.md +138 -81
- package/claude/references/sd-simplysm14/apis/orm-common/types.md +49 -44
- package/claude/references/sd-simplysm14/apis/orm-node/README.md +42 -42
- package/claude/references/sd-simplysm14/apis/orm-node/db-conn.md +44 -33
- package/claude/references/sd-simplysm14/apis/sd-cli/README.md +11 -10
- package/claude/references/sd-simplysm14/apis/service-client/README.md +56 -52
- package/claude/references/sd-simplysm14/apis/service-client/orm.md +33 -28
- package/claude/references/sd-simplysm14/apis/service-client/transport.md +23 -21
- package/claude/references/sd-simplysm14/apis/service-common/README.md +83 -48
- package/claude/references/sd-simplysm14/apis/service-common/app-structure.md +126 -34
- package/claude/references/sd-simplysm14/apis/service-common/protocol.md +109 -54
- package/claude/references/sd-simplysm14/apis/service-server/README.md +69 -81
- package/claude/references/sd-simplysm14/apis/service-server/service-authoring.md +46 -43
- package/claude/references/sd-simplysm14/apis/service-server/transport-internals.md +63 -37
- package/claude/references/sd-simplysm14/apis/service-server/v1-legacy.md +40 -30
- package/claude/references/sd-simplysm14/apis/storage/README.md +17 -17
- package/claude/references/sd-simplysm14/manuals/client-app-structure.md +142 -140
- package/claude/references/sd-simplysm14/manuals/client-orm.md +1 -1
- package/claude/references/sd-simplysm14/manuals/client-service.md +19 -7
- package/claude/references/sd-simplysm14/manuals/client-shared-data.md +2 -2
- package/claude/references/sd-simplysm14/manuals/client-system-log.md +11 -3
- package/claude/references/sd-simplysm14/manuals/data-log.md +0 -1
- package/claude/references/sd-simplysm14/manuals/orm.md +16 -0
- package/claude/rules/sd-design-rules.md +10 -0
- package/claude/skills/sd-demo/SKILL.md +0 -6
- package/claude/skills/sd-docs/SKILL.md +58 -0
- package/claude/{workflows/sd-docs.rules.md → skills/sd-docs/references/subagent-prompt.md} +103 -103
- package/claude/skills/sd-impl/SKILL.md +7 -4
- package/claude/skills/sd-spec/SKILL.md +842 -15
- package/claude/skills/sd-spec/references/example-spec.md +26 -36
- package/package.json +1 -1
- package/claude/references/sd-simplysm14/apis/core-common/json-transfer.md +0 -53
- package/claude/skills/sd-spec/references/spec-authoring.md +0 -519
- package/claude/workflows/sd-docs.js +0 -84
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @simplysm/excel — ExcelWorkbook / ExcelWorksheet
|
|
2
2
|
|
|
3
|
-
.xlsx 파일을 열거나 새로 만들고, 시트를
|
|
3
|
+
.xlsx 파일을 열거나 새로 만들고, 시트를 추가/조회하고, 시트 단위로 데이터 테이블·매트릭스·레코드 쓰기·행 복사/삽입·이미지·뷰를 다룬 뒤 바이트/Blob 로 내보내는 진입 흐름. 워크북은 내부적으로 ZIP 리소스를 잡으므로 사용 후 반드시 `close()` 해야 한다(미해제 시 리소스 누수).
|
|
4
4
|
|
|
5
5
|
## ExcelWorkbook
|
|
6
6
|
|
|
@@ -8,28 +8,40 @@
|
|
|
8
8
|
new ExcelWorkbook(arg?: Blob | Bytes)
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
-
|
|
11
|
+
- `arg?: Blob | Bytes` — 기존 .xlsx 파일 데이터. 생략하면 빈 워크북을 새로 만든다(ContentTypes/rels/workbook 기본 파트 자동 구성). 파일을 읽을 땐 바이트나 Blob 을 그대로 전달.
|
|
12
12
|
|
|
13
13
|
메서드:
|
|
14
14
|
|
|
15
|
-
- `getWorksheetNames(): Promise<string[]>` — 워크북의 모든 시트 이름을 정의 순서로 반환.
|
|
16
|
-
- `addWorksheet(name: string): Promise<ExcelWorksheet>` — 새 시트를 만들어 반환. ContentTypes
|
|
17
|
-
- `getWorksheet(nameOrIndex: string | number): Promise<ExcelWorksheet>` — 이름(string) 또는 0 기반 인덱스(number)로 시트 조회. 같은 시트는
|
|
18
|
-
- `setDefaultStyle(opts: ExcelStyleOptions): Promise<void>` — 워크북 전역
|
|
19
|
-
- `toBytes(): Promise<Bytes>` — 워크북을 ZIP
|
|
20
|
-
- `toBlob(): Promise<Blob>` — `
|
|
21
|
-
- `close(): Promise<void>` — ZIP 리더·내부 캐시 해제.
|
|
22
|
-
- `readonly zipCache: ZipCache` — 내부 ZIP
|
|
15
|
+
- `getWorksheetNames(): Promise<string[]>` — 워크북의 모든 시트 이름을 정의 순서로 반환. 시트 존재 여부·선택지를 미리 알아야 할 때.
|
|
16
|
+
- `addWorksheet(name: string): Promise<ExcelWorksheet>` — 새 시트를 만들어 반환. workbook/ContentTypes/rels 파트를 함께 갱신한다. 새 파일 쓰기 시작점.
|
|
17
|
+
- `getWorksheet(nameOrIndex: string | number): Promise<ExcelWorksheet>` — 이름(string) 또는 0 기반 인덱스(number)로 시트 조회. 없으면 throw. 같은 시트는 캐시되어 동일 인스턴스를 반환한다.
|
|
18
|
+
- `setDefaultStyle(opts: ExcelStyleOptions): Promise<void>` — 워크북 전역 기본 셀 스타일. `styles.xml` 의 0번 자원 슬롯(font/fill/border)을 덮어써, fontId/fillId/borderId 를 따로 지정하지 않은 모든 셀에 적용된다. 옵션 풀이는 [style.md](./style.md) 참조.
|
|
19
|
+
- `toBytes(): Promise<Bytes>` — 워크북을 ZIP 바이트로 직렬화. 파일 저장·서버 전송용.
|
|
20
|
+
- `toBlob(): Promise<Blob>` — 워크북을 `.sheet` MIME 의 Blob 으로 직렬화. 브라우저 다운로드용.
|
|
21
|
+
- `close(): Promise<void>` — ZIP 리더·내부 캐시 해제. 이후 인스턴스 사용 불가. 이미 닫혔으면 no-op(중복 호출 안전). 모든 작업을 `try/finally` 로 감싸 반드시 호출.
|
|
22
|
+
- `readonly zipCache: ZipCache` — 내부 ZIP 캐시 핸들(저수준). 일반 사용에서 직접 만질 일 없음.
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
### 사용 예
|
|
24
|
+
읽기 예:
|
|
27
25
|
|
|
28
26
|
```typescript
|
|
29
|
-
const wb = new ExcelWorkbook(bytes);
|
|
27
|
+
const wb = new ExcelWorkbook(bytes);
|
|
30
28
|
try {
|
|
31
29
|
const ws = await wb.getWorksheet(0);
|
|
32
|
-
const
|
|
30
|
+
const rows = await ws.getDataTable();
|
|
31
|
+
} finally {
|
|
32
|
+
await wb.close();
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
쓰기 예:
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
const wb = new ExcelWorkbook();
|
|
40
|
+
try {
|
|
41
|
+
await wb.setDefaultStyle({ font: { family: "맑은 고딕", size: 10 } });
|
|
42
|
+
const ws = await wb.addWorksheet("결과");
|
|
43
|
+
await ws.setRecords([{ 코드: "A1", 수량: 3 }]);
|
|
44
|
+
return await wb.toBytes();
|
|
33
45
|
} finally {
|
|
34
46
|
await wb.close();
|
|
35
47
|
}
|
|
@@ -37,61 +49,72 @@ try {
|
|
|
37
49
|
|
|
38
50
|
## ExcelWorksheet
|
|
39
51
|
|
|
40
|
-
`wb.
|
|
52
|
+
`wb.addWorksheet` / `wb.getWorksheet` 로만 얻는다(직접 생성 안 함). 0 기반 행/열 인덱스를 쓴다.
|
|
41
53
|
|
|
42
|
-
|
|
54
|
+
이름:
|
|
43
55
|
|
|
44
|
-
- `getName(): Promise<string>` — 시트 이름
|
|
56
|
+
- `getName(): Promise<string>` — 시트 이름 반환.
|
|
45
57
|
- `setName(newName: string): Promise<void>` — 시트 이름 변경.
|
|
46
58
|
|
|
47
|
-
|
|
59
|
+
셀 접근:
|
|
60
|
+
|
|
61
|
+
- `cell(r: number, c: number): ExcelCell` — 0 기반 행 `r`·열 `c` 의 셀 객체 반환(동기, 인스턴스 캐시). 값/스타일 실제 I/O 는 ExcelCell 의 async 메서드에서. 상세 [cell.md](./cell.md).
|
|
62
|
+
- `row(r: number): ExcelRow` — 0 기반 행 객체 반환.
|
|
63
|
+
- `col(c: number): ExcelCol` — 0 기반 열 객체 반환.
|
|
64
|
+
|
|
65
|
+
범위:
|
|
66
|
+
|
|
67
|
+
- `getRange(): Promise<ExcelAddressRangePoint>` — 시트의 데이터 범위(`{s,e}`, 양끝 inclusive) 반환. 전체 셀 순회 루프 경계로 사용.
|
|
68
|
+
- `getCells(): Promise<ExcelCell[][]>` — 데이터 범위 전체 셀을 행 우선 2차원 배열로 반환. 채워지는 인덱스는 range 기준(앞쪽 빈 행/열은 비어 있음).
|
|
48
69
|
|
|
49
|
-
|
|
50
|
-
- `col(c): ExcelCol` — `c` 열 객체(캐시). 열 단위 순회·너비 설정.
|
|
51
|
-
- `cell(r, c): ExcelCell` — 단일 셀 객체(캐시). 값/수식/스타일/병합.
|
|
52
|
-
- `getRange(): Promise<ExcelAddressRangePoint>` — 시트의 데이터 범위(`{s, e}`).
|
|
53
|
-
- `getCells(): Promise<ExcelCell[][]>` — 데이터 범위 전체를 행 우선 2차원 셀 배열로.
|
|
70
|
+
데이터(테이블/매트릭스/레코드):
|
|
54
71
|
|
|
55
|
-
|
|
72
|
+
- `getDataTable(opt?): Promise<Record<string, ExcelValueType>[]>` — 헤더 행을 키로 한 레코드 배열로 읽기.
|
|
73
|
+
- `opt.headerRowIndex?: number` — 헤더로 쓸 행 인덱스. 미지정 시 range 시작 행. 상단에 제목 행이 있으면 실제 헤더 행 인덱스를 지정.
|
|
74
|
+
- `opt.checkEndColIndex?: number` — 데이터 끝 판정 열. 그 열 셀이 비면 이후 행을 더 읽지 않고 종료. 빈 행으로 데이터가 끊기는 양식에서 사용.
|
|
75
|
+
- `opt.usableHeaderNameFn?: (headerName: string) => boolean` — 헤더 채택 필터. `true` 인 헤더만 키로 사용. 일부 열만 읽을 때. 채택된 헤더가 중복이면 throw.
|
|
76
|
+
- `setDataMatrix(matrix: ExcelValueType[][]): Promise<void>` — 2차원 배열을 0,0 부터 행 우선으로 쓰기. 헤더 없이 좌표 그대로 채울 때. `undefined` 원소는 해당 셀 삭제.
|
|
77
|
+
- `setRecords(records: Record<string, ExcelValueType>[]): Promise<void>` — 0행에 헤더(전 레코드 키 합집합, 빈 키 제외)를 자동 생성하고 1행부터 값 기록. 키 순서는 첫 등장 순. 표 형태 출력의 기본 수단.
|
|
56
78
|
|
|
57
|
-
|
|
58
|
-
- `copyRowStyle(srcR, targetR): Promise<void>` — 데이터 범위 폭만큼 한 행의 셀 스타일을 다른 행에 복사.
|
|
59
|
-
- `copyCell(srcAddr, targetAddr): Promise<void>` — 셀 전체(값·수식·스타일) 복사.
|
|
60
|
-
- `copyRow(srcR, targetR): Promise<void>` — 한 행을 다른 행으로 복사(대상 덮어쓰기).
|
|
61
|
-
- `insertCopyRow(srcR, targetR): Promise<void>` — `srcR` 행을 `targetR` 위치에 삽입 복사. `targetR` 이하 기존 행은 한 칸 아래로 밀리고, 삽입 지점을 관통하는 다중행 병합은 1행 확장된다. 행 추가 삽입(기존 보존)이 필요할 때 `copyRow`(덮어쓰기) 대신 사용.
|
|
79
|
+
뷰:
|
|
62
80
|
|
|
63
|
-
|
|
81
|
+
- `setTabColor(color: string): Promise<void>` — 시트 탭 색(ARGB 8자리, 예 `"00FF0000"`). 시트 구분 강조용.
|
|
82
|
+
- `setZoom(percent: number): Promise<void>` — 확대/축소 비율(퍼센트). 워크북 뷰를 함께 초기화한다.
|
|
83
|
+
- `freezeAt(point: { r?: number; c?: number }): Promise<void>` — 틀 고정. `r` = 위쪽 고정할 행 분할 지점, `c` = 왼쪽 고정할 열 분할 지점(0 기반). 헤더 한 줄 고정이면 `{ r: 0 }`(0행까지 위가 고정되고 1행부터 스크롤).
|
|
64
84
|
|
|
65
|
-
|
|
66
|
-
- `opt.headerRowIndex?: number` — 헤더로 쓸 행 인덱스. 미지정 시 데이터 범위 첫 행.
|
|
67
|
-
- `opt.checkEndColIndex?: number` — 데이터 끝 판정 열. 이 열이 비면 그 행에서 중단. 빈 행 뒤 잡음 데이터를 끊을 때 지정.
|
|
68
|
-
- `opt.usableHeaderNameFn?: (headerName: string) => boolean` — `true` 반환한 헤더만 컬럼으로 채택. 일부 컬럼만 읽을 때.
|
|
69
|
-
- 헤더 문자열이 중복되면 throw.
|
|
70
|
-
- `setDataMatrix(matrix: ExcelValueType[][]): Promise<void>` — 0행 0열부터 행 우선으로 2차원 배열을 그대로 기록.
|
|
71
|
-
- `setRecords(records: Record<string, ExcelValueType>[]): Promise<void>` — 0행에 헤더(전 레코드 키의 distinct, 빈 키 제외) 자동 생성 후 1행부터 값 기록.
|
|
85
|
+
조건부 서식:
|
|
72
86
|
|
|
73
|
-
|
|
87
|
+
- `addConditionalFormat(opts: { ref: string; rules: ExcelConditionalRule[] }): Promise<void>` — 셀/범위에 native CF 규칙 추가. 상세 [conditional-format.md](./conditional-format.md).
|
|
74
88
|
|
|
75
|
-
|
|
76
|
-
- `setZoom(percent): Promise<void>` — 확대/축소 비율(퍼센트).
|
|
77
|
-
- `freezeAt(point: { r?: number; c?: number }): Promise<void>` — 틀 고정. `r` = 이 행 위에서 고정, `c` = 이 열 왼쪽에서 고정. 둘 다/하나만 지정 가능.
|
|
89
|
+
복사/삽입:
|
|
78
90
|
|
|
79
|
-
|
|
91
|
+
- `copyCellStyle(srcAddr: ExcelAddressPoint, targetAddr: ExcelAddressPoint): Promise<void>` — 셀 스타일 ID 만 복사(값 제외). 원본에 스타일이 없으면 무변경.
|
|
92
|
+
- `copyRowStyle(srcR: number, targetR: number): Promise<void>` — range 내 모든 열에 대해 행 스타일 복사.
|
|
93
|
+
- `copyCell(srcAddr, targetAddr): Promise<void>` — 셀(값+스타일)을 대상에 복사.
|
|
94
|
+
- `copyRow(srcR: number, targetR: number): Promise<void>` — 행 전체를 대상 행에 복사(대상 기존 내용 덮어쓰기).
|
|
95
|
+
- `insertCopyRow(srcR: number, targetR: number): Promise<void>` — 원본 행을 대상 위치에 "삽입" 복사. 대상 이하 기존 행은 1칸 아래로 밀리고, 삽입 지점을 관통하는 다중행 병합은 1행 확장, 원본의 단일행 병합은 대상 행에 복제된다. 템플릿 행을 반복 펼칠 때 사용(덮어쓰기 방지).
|
|
80
96
|
|
|
81
|
-
|
|
82
|
-
|
|
97
|
+
이미지:
|
|
98
|
+
|
|
99
|
+
- `addImage(opts): Promise<void>` — 시트에 이미지 삽입.
|
|
83
100
|
- `opts.bytes: Bytes` — 이미지 바이너리.
|
|
84
|
-
- `opts.ext: string` — 확장자(png
|
|
85
|
-
- `opts.from: { r
|
|
86
|
-
- `opts.to?: { r
|
|
87
|
-
- 같은 시트의 기존 drawing 이 있으면 재사용하고 없으면 새로 만든다.
|
|
101
|
+
- `opts.ext: string` — 확장자(`"png"`, `"jpg"` 등). MIME 미해석 시 throw.
|
|
102
|
+
- `opts.from: { r: number; c: number; rOff?: number | string; cOff?: number | string }` — 시작 위치(0 기반 행/열, `rOff`/`cOff` 는 셀 내부 EMU 오프셋).
|
|
103
|
+
- `opts.to?: { r; c; rOff?; cOff? }` — 끝 위치. 생략 시 `from` 의 한 칸 우하단(`from.r+1, from.c+1`)에 배치되어 약 1셀 크기로 들어간다. 명시하면 두 셀 앵커 사이로 늘려 배치.
|
|
88
104
|
|
|
89
|
-
|
|
105
|
+
데이터 읽기 예:
|
|
90
106
|
|
|
91
107
|
```typescript
|
|
92
|
-
const ws = await wb.
|
|
93
|
-
await ws.
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
108
|
+
const ws = await wb.getWorksheet("입력");
|
|
109
|
+
const rows = await ws.getDataTable({
|
|
110
|
+
headerRowIndex: 1,
|
|
111
|
+
checkEndColIndex: 0,
|
|
112
|
+
usableHeaderNameFn: (h) => ["코드", "수량"].includes(h),
|
|
113
|
+
});
|
|
97
114
|
```
|
|
115
|
+
|
|
116
|
+
## 주의사항
|
|
117
|
+
|
|
118
|
+
- 모든 셀/시트 I/O 메서드는 `async` — lazy XML 로드 때문. 반복 쓰기는 await 누적이 필요하다.
|
|
119
|
+
- `ExcelWorkbook` 은 반드시 `close()` 해야 한다. 닫힌 워크북의 모든 메서드는 throw.
|
|
120
|
+
- `setRecords` 헤더는 레코드 키에서 자동 생성되므로 열 순서를 고정하려면 모든 레코드의 키 등장 순을 일정하게 유지하거나 `setDataMatrix` 를 사용.
|
|
@@ -1,18 +1,42 @@
|
|
|
1
1
|
# @simplysm/excel — ExcelWrapper
|
|
2
2
|
|
|
3
|
-
Zod
|
|
3
|
+
Zod 스키마로 엑셀 헤더 ↔ 필드 매핑, 셀 값 타입 변환, 행 단위 유효성 검사를 자동화해 "레코드 배열 ↔ 엑셀" 변환을 한 번에 처리할 때 쓰는 고수준 래퍼. 헤더 텍스트는 각 필드의 `.describe()` 로 지정하며, 미지정 필드는 키 이름을 헤더로 쓴다. 표준 입력 양식 업로드/다운로드 같은 정형 변환에 적합.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## 생성자
|
|
6
6
|
|
|
7
7
|
```typescript
|
|
8
8
|
new ExcelWrapper<TSchema extends z.ZodObject<z.ZodRawShape>>(schema: TSchema)
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
- `schema: TSchema` — 레코드 구조를 정의하는 Zod 객체 스키마. 각 필드에 `.describe("헤더이름")` 으로 엑셀 헤더 표시명을 지정한다. optional/nullable/default/boolean 여부가 읽기 기본값·필수 강조·타입 변환 동작을 결정한다.
|
|
12
|
+
|
|
13
|
+
## read
|
|
9
14
|
|
|
15
|
+
```typescript
|
|
10
16
|
read(
|
|
11
17
|
file: Bytes | Blob,
|
|
12
18
|
wsNameOrIndex: string | number = 0,
|
|
13
19
|
options?: { excludes?: (keyof z.infer<TSchema>)[] },
|
|
14
20
|
): Promise<z.infer<TSchema>[]>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
- `file: Bytes | Blob` — 읽을 .xlsx 데이터.
|
|
24
|
+
- `wsNameOrIndex: string | number` — 읽을 시트 이름 또는 0 기반 인덱스. 기본 `0`(첫 시트).
|
|
25
|
+
- `options.excludes?: (keyof Schema)[]` — 매핑에서 제외할 필드 키 배열. 해당 헤더는 읽지 않음.
|
|
26
|
+
|
|
27
|
+
동작: 스키마 표시명 집합에 해당하는 헤더만 골라 데이터 테이블을 읽고, 각 행을 필드 키로 역매핑한 뒤 값 변환 → Zod `safeParse` 검증한다. 빈/누락 값은 스키마 기본값 규칙(아래)으로 채우고, 한 행의 모든 매핑 값이 비면 그 행은 건너뛴다. 데이터가 0건이거나 검증 실패면 시트명을 포함해 throw(부분 반영 없이 전체 중단). 워크북은 내부에서 열고 finally 로 닫는다.
|
|
28
|
+
|
|
29
|
+
값 변환 규칙:
|
|
30
|
+
|
|
31
|
+
- `ZodString` → 문자열(비문자열은 `String()`).
|
|
32
|
+
- `ZodNumber` → `num.parseFloat`.
|
|
33
|
+
- `ZodBoolean` → `"1"`/`"true"`→`true`, `"0"`/`"false"`→`false`, 그 외 `Boolean()`.
|
|
34
|
+
- `DateOnly`/`DateTime`/`Time` 인스턴스 → 그대로 보존.
|
|
35
|
+
- 빈/누락 값(`null`/`""`) → 스키마 기본값: `ZodDefault` 면 그 기본값, optional/nullable 면 `undefined`, 필수 boolean 이면 `false`, 그 외 `undefined`.
|
|
15
36
|
|
|
37
|
+
## write
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
16
40
|
write(
|
|
17
41
|
wsName: string,
|
|
18
42
|
records: Partial<z.infer<TSchema>>[],
|
|
@@ -20,56 +44,29 @@ write(
|
|
|
20
44
|
): Promise<ExcelWorkbook>
|
|
21
45
|
```
|
|
22
46
|
|
|
23
|
-
- `
|
|
24
|
-
- `
|
|
25
|
-
- `
|
|
26
|
-
- `read.options.excludes?: (keyof ...)[]` — 매핑에서 제외할 필드 키 목록.
|
|
27
|
-
- `write.wsName: string` — 생성할 시트 이름.
|
|
28
|
-
- `write.records: Partial<...>[]` — 기록할 부분 레코드 배열. 누락 필드는 빈 셀.
|
|
29
|
-
- `write.options.excludes?: (keyof ...)[]` — 출력에서 제외할 필드 키 목록.
|
|
30
|
-
|
|
31
|
-
## read 동작
|
|
32
|
-
|
|
33
|
-
- 헤더명↔필드 역매핑 후 `ws.getDataTable({ usableHeaderNameFn })` 로 표시명에 일치하는 컬럼만 추출.
|
|
34
|
-
- 각 셀 값을 필드 타입별로 변환 후, 행마다 `schema.safeParse` 로 검증. 실패하면 그 행에서 throw(부분 반영 없음).
|
|
35
|
-
- 모든 필드가 null/`""` 인 행은 skip.
|
|
36
|
-
- 데이터가 한 건도 없으면 기대 헤더 목록을 담은 메시지로 throw.
|
|
37
|
-
- 내부에서 워크북을 열고 `finally` 로 `close()` 하므로 호출자 정리 불필요.
|
|
47
|
+
- `wsName: string` — 만들 시트 이름.
|
|
48
|
+
- `records: Partial<Schema>[]` — 출력할 레코드 배열(부분 객체 허용 — 누락 키는 빈 셀).
|
|
49
|
+
- `options.excludes?: (keyof Schema)[]` — 출력에서 제외할 필드 키 배열.
|
|
38
50
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
- 빈값(null/`""`) → 스키마 기본값: `ZodDefault` 면 그 기본값, optional/nullable 이면 `undefined`, 필수 boolean 이면 `false`, 그 외 `undefined`.
|
|
42
|
-
- `ZodString` → 문자열(아니면 `String()` 캐스팅).
|
|
43
|
-
- `ZodNumber` → number(문자열은 `num.parseFloat`).
|
|
44
|
-
- `ZodBoolean` → `"1"`/`"true"` → `true`, `"0"`/`"false"` → `false`, 그 외 `Boolean()`.
|
|
45
|
-
- `DateOnly`/`DateTime`/`Time` 인스턴스는 그대로 통과.
|
|
46
|
-
|
|
47
|
-
## write 동작
|
|
48
|
-
|
|
49
|
-
- 0행에 헤더(제외 후 필드 순서), 1행부터 레코드 값 기록.
|
|
50
|
-
- 전 셀에 4변 테두리 적용.
|
|
51
|
-
- **필수**(optional/nullable/default 아님)이며 boolean 이 아닌 필드의 헤더 셀은 노란색(`00FFFF00`) 강조.
|
|
52
|
-
- zoom 85%, 0행 틀고정 적용.
|
|
53
|
-
- 반환된 `ExcelWorkbook` 의 리소스 관리는 **호출자 책임** — 사용 후 `close()` 필수. write 중 예외 발생 시 내부에서 close 후 rethrow.
|
|
51
|
+
동작: 새 워크북에 시트 1개를 만들고, 0행에 표시명 헤더, 1행부터 각 레코드 값을 스키마 키 순서대로 쓴다. 전체 표에 4변 테두리, 필수(non-optional·non-nullable·non-default)이며 boolean 이 아닌 필드의 헤더 셀에 노란 배경(`"00FFFF00"`) 강조, zoom 85%, 0행 틀고정을 적용한다. **반환된 워크북의 close 는 호출자 책임** — 사용 후 반드시 `close()`.
|
|
54
52
|
|
|
55
53
|
## 사용 예
|
|
56
54
|
|
|
57
55
|
```typescript
|
|
58
|
-
import { z } from "zod";
|
|
59
|
-
|
|
60
56
|
const schema = z.object({
|
|
61
|
-
|
|
62
|
-
|
|
57
|
+
code: z.string().describe("코드"),
|
|
58
|
+
qty: z.number().describe("수량"),
|
|
59
|
+
note: z.string().optional().describe("비고"),
|
|
63
60
|
});
|
|
64
61
|
const wrapper = new ExcelWrapper(schema);
|
|
65
62
|
|
|
66
|
-
// 읽기
|
|
67
|
-
const
|
|
63
|
+
// 읽기
|
|
64
|
+
const records = await wrapper.read(bytes, "입력", { excludes: ["note"] });
|
|
68
65
|
|
|
69
|
-
// 쓰기 (
|
|
70
|
-
const wb = await wrapper.write("
|
|
66
|
+
// 쓰기 (워크북 close 는 호출자 책임)
|
|
67
|
+
const wb = await wrapper.write("결과", records);
|
|
71
68
|
try {
|
|
72
|
-
const
|
|
69
|
+
const bytes = await wb.toBytes();
|
|
73
70
|
} finally {
|
|
74
71
|
await wb.close();
|
|
75
72
|
}
|
|
@@ -77,7 +74,7 @@ try {
|
|
|
77
74
|
|
|
78
75
|
## 주의사항
|
|
79
76
|
|
|
80
|
-
- `.describe()`
|
|
81
|
-
-
|
|
82
|
-
- `
|
|
83
|
-
- `
|
|
77
|
+
- 헤더 매핑은 `.describe()` 값(미지정 시 키)이 엑셀 헤더 텍스트와 정확히 일치해야 한다. 매핑되는 헤더가 한 행 내 중복이거나 데이터가 0건이면 throw.
|
|
78
|
+
- `read` 는 행 단위 Zod 검증을 거치므로, 한 행이라도 스키마 위반이면 전체가 throw(부분 결과 없음).
|
|
79
|
+
- `write` 의 필수 헤더 노랑 강조는 "필수 입력 칸" 안내 목적 — optional/nullable/default 또는 boolean 필드는 강조되지 않는다.
|
|
80
|
+
- 결측 보존: optional/nullable 필드의 빈 값은 `undefined` 로 유지된다(임의 치환 없음). 필수 boolean 만 `false` 로 채워진다.
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
# @simplysm/orm-common
|
|
2
2
|
|
|
3
|
-
Dialect
|
|
3
|
+
Dialect 독립적 ORM 코어. `DbContext` 를 상속해 테이블/뷰/프로시저를 등록하고, fluent `Queryable` 체이닝 + JSON AST `expr` 로 쿼리를 구성하면 dialect별 QueryBuilder 가 MySQL/MSSQL/PostgreSQL SQL 로 변환한다. 실제 DB 연결·실행은 `DbContextExecutor` 구현체(서버/클라이언트)가 담당하므로 이 패키지 자체는 SQL 문자열·QueryDef AST 까지만 생성한다.
|
|
4
4
|
|
|
5
5
|
## 사용 트리거 인덱스
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
- **Queryable
|
|
10
|
-
- **expr
|
|
11
|
-
-
|
|
12
|
-
|
|
13
|
-
모든 군이 별도 파일로 분할되어 있다. README 인라인 섹션은 두지 않는다.
|
|
7
|
+
- **DbContext / 연결 / 트랜잭션 / DDL / 마이그레이션** — DB 컨텍스트 클래스를 정의하거나, `connect`/`transaction` 으로 쿼리를 감싸거나, 스키마를 생성·변경하거나, `initialize`/`migrations` 로 마이그레이션을 돌릴 때. `DbTransactionError`·`Migration`·`IsolationLevel`·`DbContextExecutor` 포함. 자세히: [db-context.md](./db-context.md)
|
|
8
|
+
- **스키마 정의 (Table / View / Procedure / column / index / relation)** — `Table(...)`/`View(...)`/`Procedure(...)` 빌더로 테이블·뷰·프로시저 스키마와 column·PK·index·FK 관계를 선언하고 타입을 추론할 때. 자세히: [schema.md](./schema.md)
|
|
9
|
+
- **Queryable 체이닝 / CRUD 실행 / 검색** — `db.X()` 로 얻은 `Queryable` 을 `select`/`where`/`join`/`include`/`groupBy`/`orderBy` 로 조립하고 `execute`/`single`/`count`/`insert`/`update`/`delete`/`upsert` 로 실행할 때. `Queryable.union`·`search`·`Executable`·`parseSearchQuery` 포함. 자세히: [queryable.md](./queryable.md)
|
|
10
|
+
- **expr 표현식 빌더** — `where`/`select`/`orderBy`/`having` 콜백 안에서 비교·논리·문자열·숫자·날짜·집계·window·조건·서브쿼리 표현식을 만들 때. `ExprUnit`/`WhereExprUnit`/`ExprInput` 포함. 자세히: [expr.md](./expr.md)
|
|
11
|
+
- **하위 타입 / QueryDef AST / QueryBuilder / 결과 파싱** — Executor·QueryBuilder 를 직접 구현하거나, `QueryDef` AST·`Expr` AST·column 타입을 다루거나, 원시 결과를 `parseQueryResult`/`pickResultSets` 로 변환할 때. 자세히: [types.md](./types.md)
|
|
@@ -1,16 +1,49 @@
|
|
|
1
1
|
# @simplysm/orm-common — DbContext / 연결·트랜잭션·DDL·마이그레이션
|
|
2
2
|
|
|
3
|
-
`DbContext` 추상 클래스를 상속해 테이블·뷰·프로시저를 프로퍼티로 등록하고, 연결·트랜잭션·DDL·마이그레이션을 실행하는 묶음.
|
|
3
|
+
`DbContext` 추상 클래스를 상속해 테이블·뷰·프로시저를 클래스 프로퍼티로 등록하고, 연결·트랜잭션·DDL·마이그레이션을 실행하는 묶음. `DbContextExecutor` 구현체와 `{ database, schema? }` 옵션을 생성자로 주입한다. 각 프로퍼티가 독립 직렬화되어 40+ 테이블에서도 TS7056 이 발생하지 않는다. 트랜잭션 롤백 에러는 `DbTransactionError` 로 표준화된다.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
> 앱(Angular) 환경에서는 화면이 `DbContext` 를 직접 생성하지 않고 `AppOrmProvider.connectAsync(cb)` 로 감싼다(client-orm.md). `db` 인자가 곧 아래 `DbContext` 인스턴스이므로, 콜백 안의 쿼리 작성법은 동일하다.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## DbContext (abstract class)
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
```typescript
|
|
10
|
+
abstract class DbContext implements DbContextBase {
|
|
11
|
+
constructor(executor: DbContextExecutor, opt: { database: string; schema?: string });
|
|
12
|
+
|
|
13
|
+
status: DbContextStatus; // "ready" | "connect" | "transact"
|
|
14
|
+
get database(): string | undefined;
|
|
15
|
+
get schema(): string | undefined;
|
|
16
|
+
migrations: Migration[]; // 서브클래스에서 오버라이드
|
|
17
|
+
|
|
18
|
+
// 등록 (protected — 서브클래스 프로퍼티 초기화에서 사용)
|
|
19
|
+
protected queryable<T>(builder: T): () => Queryable<...>;
|
|
20
|
+
protected executable<T>(builder: T): () => Executable<...>;
|
|
21
|
+
|
|
22
|
+
// 연결
|
|
23
|
+
connect<R>(fn: () => Promise<R>, isolationLevel?: IsolationLevel): Promise<R>;
|
|
24
|
+
connectWithoutTransaction<R>(callback: () => Promise<R>): Promise<R>;
|
|
25
|
+
transaction<R>(fn: () => Promise<R>, isolationLevel?: IsolationLevel): Promise<R>;
|
|
26
|
+
|
|
27
|
+
// DDL 실행 / DDL QueryDef 생성기 / initialize ...
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
식별자 풀이:
|
|
32
|
+
|
|
33
|
+
- constructor `executor: DbContextExecutor` — 실제 DB 연결·쿼리 실행을 위임할 어댑터(서버 측 node executor, 클라이언트 측 service-client executor). 이 패키지는 SQL/QueryDef 까지만 만들고 실행은 전부 executor 가 한다.
|
|
34
|
+
- constructor `opt.database: string` — 기본 데이터베이스명. 빌더가 database 를 지정하지 않으면 이 값이 객체 네임스페이스에 쓰인다.
|
|
35
|
+
- constructor `opt.schema?: string` — 기본 스키마명(MSSQL `dbo`, PostgreSQL `public`). MySQL 은 무시.
|
|
36
|
+
- `status: "ready"|"connect"|"transact"` — 현재 상태. "ready"=미연결, "connect"=연결됨(트랜잭션 없음), "transact"=트랜잭션 중. `connect()` 중복 호출 방지·트랜잭션 중 DDL 차단 판정에 쓰인다.
|
|
37
|
+
- `database` / `schema` (getter) — 주입한 opt 값을 그대로 노출. 빌더의 `getQueryDefObjectName` 기본값으로 쓰임.
|
|
38
|
+
- `migrations: Migration[]` — 마이그레이션 정의 배열. 기본 `[]`, 서브클래스에서 오버라이드해 채운다. `initialize()` 가 미실행 항목만 순서대로 실행.
|
|
39
|
+
- `queryable(builder)` (protected) — `TableBuilder`/`ViewBuilder` 를 받아 호출할 때마다 새 alias 가 붙는 `() => Queryable` 팩토리를 반환. 서브클래스에서 `user = this.queryable(User)` 형태로 멤버를 만든다.
|
|
40
|
+
- `executable(builder)` (protected) — `ProcedureBuilder` 를 받아 `() => Executable` 팩토리를 반환. 서브클래스에서 `getUserById = this.executable(GetUserById)` 형태로 만든다.
|
|
41
|
+
- `connect(fn, isolationLevel?)` — 연결 + 트랜잭션으로 `fn` 을 감싼다. 정상 종료 시 commit, throw 시 rollback 후 재throw, 무조건 close. 첫 호출 시 관계 정합성을 1회 검증(`validateRelations`). 기본 진입점.
|
|
42
|
+
- `connectWithoutTransaction(callback)` — 연결만 하고 트랜잭션은 열지 않음. 트랜잭션 안에서 동작하지 않는 작업(`initialize`/일부 DDL) 전용. 끝나면 close.
|
|
43
|
+
- `transaction(fn, isolationLevel?)` — 이미 `connect` 상태일 때 그 안에서 트랜잭션 블록을 추가로 연다. "transact" 상태에서 재호출하면 throw.
|
|
44
|
+
- `isolationLevel?` — 트랜잭션 격리 수준. 미지정 시 executor/DB 기본값. 값별 의미는 아래 `IsolationLevel` 참조.
|
|
45
|
+
|
|
46
|
+
사용 예 (직접 API):
|
|
14
47
|
|
|
15
48
|
```typescript
|
|
16
49
|
class MainDb extends DbContext {
|
|
@@ -19,93 +52,111 @@ class MainDb extends DbContext {
|
|
|
19
52
|
getUserById = this.executable(GetUserById);
|
|
20
53
|
override migrations = [{ name: "001", up: async (db) => { await db.createTable(User); } }];
|
|
21
54
|
}
|
|
55
|
+
|
|
22
56
|
const db = new MainDb(executor, { database: "mydb" });
|
|
57
|
+
const users = await db.connect(async () => {
|
|
58
|
+
return db.user().where((u) => [expr.eq(u.isActive, true)]).execute();
|
|
59
|
+
});
|
|
23
60
|
```
|
|
24
61
|
|
|
25
|
-
|
|
62
|
+
주의:
|
|
26
63
|
|
|
27
|
-
`
|
|
64
|
+
- 트랜잭션("transact") 상태에서 DDL(`createTable` 등)을 `executeDefs` 로 보내면 "TRANSACTION 상태에서는 DDL을 실행할 수 없습니다" throw. DDL 은 `connectWithoutTransaction` 안에서 실행.
|
|
65
|
+
- 롤백 자체가 실패해도 원래 에러를 우선 throw 하고, 롤백 실패 원인은 `err.cause` 로 부착(단, `NO_ACTIVE_TRANSACTION` 은 무시).
|
|
28
66
|
|
|
29
|
-
|
|
30
|
-
- `readonly database` / `readonly schema` — 주입된 옵션 값(`string | undefined`).
|
|
31
|
-
- `getNextAlias(): string` — 다음 테이블 alias(`T1`, `T2`...) 발급. 카운터 증가.
|
|
32
|
-
- `resetAliasCounter(): void` — alias 카운터 0 으로. connect 시작 시 호출됨.
|
|
33
|
-
- `executeDefs<T>(defs, resultMetas?): Promise<T[][]>` — QueryDef 배열 실행 위임. `transact` 중 DDL 포함 시 throw. 모든 쿼리 실행의 단일 통로.
|
|
34
|
-
- `getQueryDefObjectName(tableOrView): QueryDefObjectName` — 빌더에서 `{database, schema, name}` 추출.
|
|
35
|
-
- `switchFk(table, enabled): Promise<void>` — FK 제약 on/off(트랜잭션 내 허용).
|
|
67
|
+
## DDL 실행 메서드
|
|
36
68
|
|
|
37
|
-
`
|
|
69
|
+
`connectWithoutTransaction` 안에서 호출하며, 즉시 executor 로 실행한다. 모두 `Promise<void>`(예외: `schemaExists` → `Promise<boolean>`).
|
|
38
70
|
|
|
39
|
-
|
|
71
|
+
- `createTable(table: TableBuilder)` / `dropTable(table)` / `renameTable(table, newName)` — 테이블 생성/삭제/이름변경. drop·rename 의 `table` 인자는 `QueryDefObjectName`(`{ database?, schema?, name }`).
|
|
72
|
+
- `createView(view: ViewBuilder)` / `dropView(view)` — 뷰 생성/삭제.
|
|
73
|
+
- `createProc(procedure: ProcedureBuilder)` / `dropProc(procedure)` — 프로시저 생성/삭제.
|
|
74
|
+
- `addColumn(table, columnName, column: ColumnBuilder)` / `dropColumn(table, column)` / `modifyColumn(table, columnName, column)` / `renameColumn(table, column, newName)` — column 추가/삭제/타입·속성변경/이름변경.
|
|
75
|
+
- `addPrimaryKey(table, columns: string[])` / `dropPrimaryKey(table)` — PK 추가/삭제. 복합 PK 는 `columns` 에 여러 이름.
|
|
76
|
+
- `addForeignKey(table, relationName, relationDef: ForeignKeyBuilder)` / `dropForeignKey(table, relationName)` — FK 제약 추가/삭제.
|
|
77
|
+
- `addIndex(table, indexBuilder: IndexBuilder<string[]>)` / `dropIndex(table, columns: string[])` — index 추가/삭제. drop 은 column 이름 배열로 식별.
|
|
78
|
+
- `clearSchema(params: { database; schema? })` — 스키마의 모든 객체 삭제(초기화).
|
|
79
|
+
- `schemaExists(database, schema?): Promise<boolean>` — 스키마 존재 여부.
|
|
80
|
+
- `truncate(table)` — 테이블 데이터 전체 비우기(구조 유지).
|
|
81
|
+
- `switchFk(table, enabled: boolean)` — FK 제약 일시 활성/비활성. `enabled` false=비활성(대량 적재 전), true=재활성. DDL 이 아니라 트랜잭션 안에서도 호출 가능.
|
|
40
82
|
|
|
41
|
-
|
|
42
|
-
- `connectWithoutTransaction<T>(callback): Promise<T>` — 연결만(트랜잭션 없이) `callback` 실행 후 close. DDL·여러 독립 트랜잭션을 그 안에서 직접 열 때.
|
|
43
|
-
- `transaction<T>(fn, isolationLevel?): Promise<T>` — 이미 연결된 상태에서 트랜잭션 1개 실행(begin→fn→commit, 실패 시 rollback). `transact` 중 재호출하면 throw. `connectWithoutTransaction` 안에서 트랜잭션을 나눠 쓸 때.
|
|
44
|
-
- `isolationLevel` — `"READ_UNCOMMITTED"|"READ_COMMITTED"|"REPEATABLE_READ"|"SERIALIZABLE"`. 미지정 시 DB 기본값. 동시성 요구에 따라 선택.
|
|
83
|
+
각 `createX`/`dropX`/... 에는 동일 시그니처의 `getXQueryDef(...): QueryDef` 생성기 버전이 쌍으로 존재(실행하지 않고 QueryDef AST 만 반환). 추가로 `getCreateObjectQueryDef(builder)` 는 Table/View/Procedure 중 무엇이든 받아 알맞은 create QueryDef 를 반환한다. 마이그레이션에서 여러 DDL 을 모아 한 번에 보내거나 DDL 을 검사·로깅할 때 사용.
|
|
45
84
|
|
|
46
|
-
|
|
85
|
+
## initialize
|
|
47
86
|
|
|
48
87
|
```typescript
|
|
49
|
-
|
|
50
|
-
const user = await db.user().where((u) => [expr.eq(u.id, 1)]).lock().single();
|
|
51
|
-
await db.user().where((u) => [expr.eq(u.id, 1)]).update((u) => ({ name: expr.val("string", "X") }));
|
|
52
|
-
}, "REPEATABLE_READ");
|
|
88
|
+
initialize(options?: { dbs?: string[]; force?: boolean }): Promise<boolean>
|
|
53
89
|
```
|
|
54
90
|
|
|
55
|
-
|
|
91
|
+
- `dbs?: string[]` — 초기화 대상 데이터베이스명 목록. 미지정 시 컨텍스트의 기본 database.
|
|
92
|
+
- `force?: boolean` — true 면 기존 스키마를 비우고(`clearSchema`) 전체 재생성. false/미지정이면 미적용 마이그레이션만 증분 실행하고, 변경이 있었는지를 boolean 으로 반환.
|
|
93
|
+
- 반환값 — 실제로 스키마를 만들거나 마이그레이션을 적용했으면 true. 트랜잭션 안에서 돌지 않으므로 `connectWithoutTransaction` 으로 호출.
|
|
56
94
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
- `createTable(table)` / `dropTable(table)` / `renameTable(table, newName)` — 테이블 생성·삭제·이름변경.
|
|
60
|
-
- `createView(view)` / `dropView(view)` — 뷰 생성·삭제.
|
|
61
|
-
- `createProc(procedure)` / `dropProc(procedure)` — 프로시저 생성·삭제.
|
|
62
|
-
- `addColumn(table, columnName, column)` / `dropColumn(table, column)` / `modifyColumn(table, columnName, column)` / `renameColumn(table, column, newName)` — 컬럼 추가·삭제·변경·이름변경. `column` 은 `ColumnBuilder`.
|
|
63
|
-
- `addPrimaryKey(table, columns)` / `dropPrimaryKey(table)` — PK 추가·삭제.
|
|
64
|
-
- `addForeignKey(table, relationName, relationDef)` / `dropForeignKey(table, relationName)` — FK 추가·삭제. `relationDef` 는 `ForeignKeyBuilder`.
|
|
65
|
-
- `addIndex(table, indexBuilder)` / `dropIndex(table, columns)` — 인덱스 추가·삭제.
|
|
66
|
-
- `truncate(table)` — 데이터 전체 삭제(DDL 취급).
|
|
67
|
-
- `clearSchema(params: { database, schema? })` — 스키마 내 모든 객체 삭제. 초기화·테스트 정리에.
|
|
68
|
-
- `schemaExists(database, schema?): Promise<boolean>` — 스키마 존재 여부.
|
|
69
|
-
- `switchFk(table, enabled): Promise<void>` — FK 제약 일시 on/off(트랜잭션 내 허용, DDL 아님).
|
|
95
|
+
## DbContextBase / DbContextStatus / DbContextDdlMethods
|
|
70
96
|
|
|
71
|
-
`
|
|
97
|
+
- `DbContextBase` (interface) — `Queryable`/`Executable`/`ViewBuilder` 가 의존하는 컨텍스트 최소 면(`status`, `database`, `schema`, `getNextAlias()`, `resetAliasCounter()`, `executeDefs()`, `getQueryDefObjectName()`, `switchFk()`). 직접 구현할 일은 드물고, 커스텀 컨텍스트 타입의 상한으로 쓰인다.
|
|
98
|
+
- `DbContextStatus` — `"ready" | "connect" | "transact"`. 위 `status` 와 동일 의미.
|
|
99
|
+
- `DbContextDdlMethods` (interface) — 위 DDL 실행 메서드 + QueryDef 생성기 전체를 모은 인터페이스. `Migration.up(db)` 의 `db` 타입이 `DbContextBase & DbContextDdlMethods` 라 마이그레이션 콜백에서 DDL 을 호출할 수 있다.
|
|
72
100
|
|
|
73
|
-
##
|
|
101
|
+
## DbContextExecutor / ResultMeta
|
|
74
102
|
|
|
75
|
-
|
|
76
|
-
|
|
103
|
+
`DbContextExecutor` (interface) — DbContext 가 연결·실행을 위임할 어댑터. 직접 구현은 서버/클라이언트 어댑터 패키지에서만.
|
|
104
|
+
|
|
105
|
+
- `connect(): Promise<void>` / `close(): Promise<void>` — 물리 연결 수립/종료.
|
|
106
|
+
- `beginTransaction(isolationLevel?)` / `commitTransaction()` / `rollbackTransaction()` — 트랜잭션 제어. rollback 은 활성 트랜잭션이 없으면 `DbTransactionError(NO_ACTIVE_TRANSACTION)` 를 던질 수 있음.
|
|
107
|
+
- `executeDefs<T>(defs: QueryDef[], resultMetas?: (ResultMeta|undefined)[]): Promise<T[][]>` — QueryDef 배열을 실행하고 def별 결과 배열을 반환. `resultMetas` 가 있으면 해당 def 결과를 그 메타로 타입 환원.
|
|
108
|
+
- `ResultMeta` (interface) — `{ columns: Record<string, ColumnPrimitiveStr>; joins: Record<string, { isSingle: boolean }> }`. SELECT 결과를 TS 객체로 환원할 때의 column 타입·JOIN 중첩 구조 메타. `Queryable.getResultMeta()` 가 생성. (자세히는 [types.md](./types.md))
|
|
109
|
+
|
|
110
|
+
## Migration
|
|
77
111
|
|
|
78
112
|
```typescript
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
113
|
+
interface Migration {
|
|
114
|
+
name: string;
|
|
115
|
+
up: (db: DbContextBase & DbContextDdlMethods) => Promise<void>;
|
|
116
|
+
}
|
|
83
117
|
```
|
|
84
118
|
|
|
85
|
-
|
|
119
|
+
- `name: string` — 마이그레이션 고유 이름(타임스탬프 권장, 예 `20260105_001_create_user`). 적용 여부 추적 키이므로 한 번 배포 후 변경 금지.
|
|
120
|
+
- `up(db)` — 적용 시 실행할 함수. `db` 로 DDL 메서드를 호출. 미적용 항목만 `name` 순서대로 1회씩 실행된다.
|
|
121
|
+
|
|
122
|
+
## IsolationLevel
|
|
86
123
|
|
|
87
|
-
|
|
124
|
+
`connect`/`transaction`/`beginTransaction` 의 격리 수준.
|
|
88
125
|
|
|
89
|
-
- `
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
126
|
+
- `"READ_UNCOMMITTED"` — 커밋 전 데이터까지 읽음(Dirty Read 허용). 가장 느슨, 정합성 낮음.
|
|
127
|
+
- `"READ_COMMITTED"` — 커밋된 데이터만 읽음. 일반적 기본값.
|
|
128
|
+
- `"REPEATABLE_READ"` — 트랜잭션 내 동일 쿼리가 동일 결과 보장.
|
|
129
|
+
- `"SERIALIZABLE"` — 완전 직렬화. 가장 엄격, 경합 시 잠금/충돌 비용 큼.
|
|
130
|
+
|
|
131
|
+
## DbTransactionError / DbErrorCode
|
|
132
|
+
|
|
133
|
+
DBMS별 네이티브 트랜잭션 에러를 표준 코드로 래핑한다. 롤백·재시도 분기에서 `instanceof DbTransactionError` + `err.code` 로 판별.
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
class DbTransactionError extends Error {
|
|
137
|
+
readonly name = "DbTransactionError";
|
|
138
|
+
constructor(code: DbErrorCode, message: string, originalError?: unknown);
|
|
139
|
+
readonly code: DbErrorCode;
|
|
140
|
+
readonly originalError?: unknown;
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
- `code: DbErrorCode` — 표준화된 에러 코드(아래). 분기 기준.
|
|
145
|
+
- `message: string` — 사람용 메시지.
|
|
146
|
+
- `originalError?: unknown` — 원본 DBMS 에러(디버깅용 원형 보존).
|
|
147
|
+
|
|
148
|
+
`DbErrorCode` (enum, 값은 동명 문자열):
|
|
149
|
+
|
|
150
|
+
- `NO_ACTIVE_TRANSACTION` — 롤백 대상 활성 트랜잭션 없음. 이미 롤백/커밋된 경우. `connect` 내부에서 이 코드는 무시된다.
|
|
151
|
+
- `TRANSACTION_ALREADY_STARTED` — 트랜잭션이 이미 시작됨(중복 begin).
|
|
152
|
+
- `DEADLOCK` — 데드락 발생. 재시도 정책 트리거로 사용.
|
|
153
|
+
- `LOCK_TIMEOUT` — 잠금 대기 타임아웃.
|
|
99
154
|
|
|
100
155
|
```typescript
|
|
101
156
|
try {
|
|
102
|
-
await
|
|
157
|
+
await executor.rollbackTransaction();
|
|
103
158
|
} catch (err) {
|
|
104
159
|
if (err instanceof DbTransactionError && err.code === DbErrorCode.NO_ACTIVE_TRANSACTION) return;
|
|
105
160
|
throw err;
|
|
106
161
|
}
|
|
107
162
|
```
|
|
108
|
-
|
|
109
|
-
## SD_BUILDER
|
|
110
|
-
|
|
111
|
-
- `const SD_BUILDER: unique symbol` — `queryable()`/`executable()` 가 반환한 팩토리 함수에 원본 빌더(TableBuilder/ViewBuilder/ProcedureBuilder)를 부착하는 심볼 키. 컨텍스트 멤버에서 정의 빌더를 역으로 꺼낼 때(예: 전체 테이블 순회·DDL 자동화) 사용.
|