@simplysm/sd-claude 14.0.89 → 14.0.91

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.
Files changed (79) hide show
  1. package/claude/references/sd-simplysm14/README.md +16 -17
  2. package/claude/references/sd-simplysm14/apis/angular/README.md +52 -30
  3. package/claude/references/sd-simplysm14/apis/angular/controls.md +200 -38
  4. package/claude/references/sd-simplysm14/apis/angular/crud.md +41 -53
  5. package/claude/references/sd-simplysm14/apis/angular/directives.md +66 -22
  6. package/claude/references/sd-simplysm14/apis/angular/features.md +127 -40
  7. package/claude/references/sd-simplysm14/apis/angular/infra.md +60 -43
  8. package/claude/references/sd-simplysm14/apis/angular/layout.md +56 -20
  9. package/claude/references/sd-simplysm14/apis/angular/overlay.md +74 -74
  10. package/claude/references/sd-simplysm14/apis/angular/routing-appstructure.md +50 -40
  11. package/claude/references/sd-simplysm14/apis/angular/selection-managers.md +55 -15
  12. package/claude/references/sd-simplysm14/apis/angular/shared-data.md +59 -42
  13. package/claude/references/sd-simplysm14/apis/angular/sheet.md +77 -62
  14. package/claude/references/sd-simplysm14/apis/capacitor-plugin-auto-update/README.md +8 -7
  15. package/claude/references/sd-simplysm14/apis/capacitor-plugin-file-system/README.md +71 -43
  16. package/claude/references/sd-simplysm14/apis/capacitor-plugin-intent/README.md +22 -14
  17. package/claude/references/sd-simplysm14/apis/capacitor-plugin-usb-storage/README.md +19 -19
  18. package/claude/references/sd-simplysm14/apis/core-browser/README.md +17 -17
  19. package/claude/references/sd-simplysm14/apis/core-browser/dom-element.md +28 -28
  20. package/claude/references/sd-simplysm14/apis/core-browser/indexed-db.md +37 -37
  21. package/claude/references/sd-simplysm14/apis/core-common/README.md +87 -219
  22. package/claude/references/sd-simplysm14/apis/core-common/array-ext.md +54 -98
  23. package/claude/references/sd-simplysm14/apis/core-common/async-runtime.md +57 -99
  24. package/claude/references/sd-simplysm14/apis/core-common/datetime.md +60 -103
  25. package/claude/references/sd-simplysm14/apis/core-common/errors.md +42 -47
  26. package/claude/references/sd-simplysm14/apis/core-common/obj.md +42 -88
  27. package/claude/references/sd-simplysm14/apis/core-common/serialization.md +55 -0
  28. package/claude/references/sd-simplysm14/apis/core-node/README.md +6 -7
  29. package/claude/references/sd-simplysm14/apis/core-node/consola.md +17 -12
  30. package/claude/references/sd-simplysm14/apis/core-node/cpx.md +14 -13
  31. package/claude/references/sd-simplysm14/apis/core-node/fs-watcher.md +9 -8
  32. package/claude/references/sd-simplysm14/apis/core-node/fsx.md +14 -13
  33. package/claude/references/sd-simplysm14/apis/core-node/pathx.md +4 -8
  34. package/claude/references/sd-simplysm14/apis/core-node/worker.md +14 -12
  35. package/claude/references/sd-simplysm14/apis/excel/README.md +22 -22
  36. package/claude/references/sd-simplysm14/apis/excel/cell.md +37 -29
  37. package/claude/references/sd-simplysm14/apis/excel/conditional-format.md +29 -15
  38. package/claude/references/sd-simplysm14/apis/excel/style.md +33 -27
  39. package/claude/references/sd-simplysm14/apis/excel/utils.md +29 -19
  40. package/claude/references/sd-simplysm14/apis/excel/workbook-worksheet.md +78 -55
  41. package/claude/references/sd-simplysm14/apis/excel/wrapper.md +42 -45
  42. package/claude/references/sd-simplysm14/apis/orm-common/README.md +6 -8
  43. package/claude/references/sd-simplysm14/apis/orm-common/db-context.md +118 -67
  44. package/claude/references/sd-simplysm14/apis/orm-common/expr.md +83 -86
  45. package/claude/references/sd-simplysm14/apis/orm-common/queryable.md +102 -93
  46. package/claude/references/sd-simplysm14/apis/orm-common/schema.md +138 -81
  47. package/claude/references/sd-simplysm14/apis/orm-common/types.md +49 -44
  48. package/claude/references/sd-simplysm14/apis/orm-node/README.md +42 -42
  49. package/claude/references/sd-simplysm14/apis/orm-node/db-conn.md +44 -33
  50. package/claude/references/sd-simplysm14/apis/sd-cli/README.md +11 -10
  51. package/claude/references/sd-simplysm14/apis/service-client/README.md +56 -52
  52. package/claude/references/sd-simplysm14/apis/service-client/orm.md +33 -28
  53. package/claude/references/sd-simplysm14/apis/service-client/transport.md +23 -21
  54. package/claude/references/sd-simplysm14/apis/service-common/README.md +83 -48
  55. package/claude/references/sd-simplysm14/apis/service-common/app-structure.md +126 -34
  56. package/claude/references/sd-simplysm14/apis/service-common/protocol.md +109 -54
  57. package/claude/references/sd-simplysm14/apis/service-server/README.md +69 -81
  58. package/claude/references/sd-simplysm14/apis/service-server/service-authoring.md +46 -43
  59. package/claude/references/sd-simplysm14/apis/service-server/transport-internals.md +63 -37
  60. package/claude/references/sd-simplysm14/apis/service-server/v1-legacy.md +40 -30
  61. package/claude/references/sd-simplysm14/apis/storage/README.md +17 -17
  62. package/claude/references/sd-simplysm14/manuals/client-app-structure.md +135 -140
  63. package/claude/references/sd-simplysm14/manuals/client-orm.md +1 -1
  64. package/claude/references/sd-simplysm14/manuals/client-service.md +19 -7
  65. package/claude/references/sd-simplysm14/manuals/client-shared-data.md +2 -2
  66. package/claude/references/sd-simplysm14/manuals/client-system-log.md +16 -4
  67. package/claude/references/sd-simplysm14/manuals/data-log.md +0 -1
  68. package/claude/references/sd-simplysm14/manuals/orm.md +16 -0
  69. package/claude/rules/sd-design-rules.md +10 -0
  70. package/claude/skills/sd-demo/SKILL.md +0 -6
  71. package/claude/skills/sd-docs/SKILL.md +60 -0
  72. package/claude/{workflows/sd-docs.rules.md → skills/sd-docs/references/subagent-prompt.md} +118 -103
  73. package/claude/skills/sd-impl/SKILL.md +7 -4
  74. package/claude/skills/sd-spec/SKILL.md +842 -15
  75. package/claude/skills/sd-spec/references/example-spec.md +26 -36
  76. package/package.json +1 -1
  77. package/claude/references/sd-simplysm14/apis/core-common/json-transfer.md +0 -53
  78. package/claude/skills/sd-spec/references/spec-authoring.md +0 -519
  79. package/claude/workflows/sd-docs.js +0 -84
@@ -1,6 +1,6 @@
1
1
  # @simplysm/excel — ExcelWorkbook / ExcelWorksheet
2
2
 
3
- .xlsx 파일을 열거나 새로 만들고, 시트를 추가·조회하고, 시트 단위로 데이터 테이블/매트릭스/이미지/뷰를 다루고, 바이트/Blob 로 내보낼 함께 읽는 묶음. 워크북은 내부 ZIP 리소스를 lazy-load 하므로 사용 후 반드시 `close()` 해야 한다.
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
- - 생성자 `arg` — 기존 .xlsx 데이터(`Blob` 또는 `Uint8Array`). 생략하면 빈 워크북(ContentTypes/rels/workbook 골격)을 새로 만든다. 기존 파일 편집이면 전달, 파일 생성이면 생략.
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·workbook rels 함께 갱신. `name` = 추가할 시트 이름.
17
- - `getWorksheet(nameOrIndex: string | number): Promise<ExcelWorksheet>` — 이름(string) 또는 0 기반 인덱스(number)로 시트 조회. 같은 시트는 캐시돼 동일 인스턴스 반환. 없으면 throw.
18
- - `setDefaultStyle(opts: ExcelStyleOptions): Promise<void>` — 워크북 전역 default 셀 스타일. fontId/fillId/borderId 를 명시하지 않은 모든 셀에 적용. 자세히: [style.md](./style.md).
19
- - `toBytes(): Promise<Bytes>` — 워크북을 ZIP 직렬화해 바이트로 반환.
20
- - `toBlob(): Promise<Blob>` — `toBytes()` 결과를 xlsx MIME 의 `Blob` 으로 래핑. 브라우저 다운로드용.
21
- - `close(): Promise<void>` — ZIP 리더·내부 캐시 해제. 호출 워크북 사용 불가. 이미 닫혔으면 no-op(안전). 미호출 리소스 누수.
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
- `close()` 외 모든 메서드는 닫힌 워크북에서 호출 시 throw.
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 table = await ws.getDataTable({ checkEndColIndex: 0 });
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.getWorksheet` / `wb.addWorksheet` 얻는다. 행/열/셀 접근, 복사, 데이터 변환, 뷰, 조건부 서식, 이미지를 제공.
52
+ `wb.addWorksheet` / `wb.getWorksheet` 로만 얻는다(직접 생성 함). 0 기반 행/열 인덱스를 쓴다.
41
53
 
42
- ### 이름
54
+ 이름:
43
55
 
44
- - `getName(): Promise<string>` — 시트 이름 반환(못 찾으면 throw).
56
+ - `getName(): Promise<string>` — 시트 이름 반환.
45
57
  - `setName(newName: string): Promise<void>` — 시트 이름 변경.
46
58
 
47
- ### 셀/행/열 접근 (모두 0 기반)
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
- - `row(r): ExcelRow` — `r` 행 객체(캐시). 행 단위 순회·셀 접근. 자세히: [cell.md](./cell.md).
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
- - `copyCellStyle(srcAddr, targetAddr): Promise<void>` — 셀 스타일 ID 만 복사(값 미복사). `srcAddr`/`targetAddr` = `ExcelAddressPoint`.
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
- - `getDataTable(opt?): Promise<Record<string, ExcelValueType>[]>` — 헤더 행을 키로, 이후 행을 레코드로 변환.
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
- - `setTabColor(color): Promise<void>` — 시트 탭 색. `color` = ARGB 8자리(예: `"00FF0000"`).
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
- - `addConditionalFormat(opts): Promise<void>` — 셀/범위에 native CF 규칙 추가. 자세히: [conditional-format.md](./conditional-format.md).
82
- - `addImage(opts): Promise<void>` — 이미지 삽입.
97
+ 이미지:
98
+
99
+ - `addImage(opts): Promise<void>` — 시트에 이미지 삽입.
83
100
  - `opts.bytes: Bytes` — 이미지 바이너리.
84
- - `opts.ext: string` — 확장자(png/jpg 등). MIME 결정 불가 시 throw.
85
- - `opts.from: { r, c, rOff?, cOff? }` — 시작 앵커(0 기반 행/열, `rOff`/`cOff` 는 EMU 오프셋).
86
- - `opts.to?: { r, c, rOff?, cOff? }` — 끝 앵커. 생략 시 `from` 기준 1행·1 크기로 배치.
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.addWorksheet("매출");
93
- await ws.setRecords([{ 품목: "사과", 수량: 10 }]);
94
- await ws.setZoom(85);
95
- await ws.freezeAt({ r: 0 });
96
- await ws.addImage({ bytes, ext: "png", from: { r: 0, c: 3 } });
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 스키마 1개로 레코드 배열 ↔ Excel 파일을 타입 안전하게 매핑할읽는다. 스키마 각 필드의 `.describe()` Excel 헤더(표시명)가 되고, 필드 타입으로 읽기 변환·검증을 수행한다. 저수준 조작 없이 "정형 데이터의 import/export" 용도일 때 사용.
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
- - `schema: z.ZodObject` — 레코드 구조. 각 필드의 `.describe("표시명")` 이 Excel 헤더명. 미지정 시 필드 키를 헤더로 사용.
24
- - `read.file: Bytes | Blob`읽을 .xlsx 데이터.
25
- - `read.wsNameOrIndex: string | number` — 대상 시트(기본 0번). 이름 또는 0 기반 인덱스.
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
- name: z.string().describe("이름"),
62
- age: z.number().optional().describe("나이"),
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
- // 읽기 ("이름"/"나이" 헤더를 0번 시트에서 매칭)
67
- const rows = await wrapper.read(bytes);
63
+ // 읽기
64
+ const records = await wrapper.read(bytes, "입력", { excludes: ["note"] });
68
65
 
69
- // 쓰기 (호출자가 close 책임)
70
- const wb = await wrapper.write("회원", [{ name: "홍길동", age: 30 }]);
66
+ // 쓰기 (워크북 close 는 호출자 책임)
67
+ const wb = await wrapper.write("결과", records);
71
68
  try {
72
- const out = await wb.toBytes();
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()` 표시명이 실제 Excel 헤더와 일치해야 `read` 컬럼을 인식. 일치 헤더가 전혀 없으면 데이터 0건으로 throw.
81
- - 표시명 미지정 필드는 필드 그대로 헤더로 쓰이므로, 한글 헤더가 필요하면 반드시 `.describe()` 지정.
82
- - `read` 검증은 전부-성공 전제: 행이라도 `safeParse` 실패 전체 throw.
83
- - `write` 반환 워크북 미`close` 리소스 누수.
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 독립 ORM 코어. 테이블/뷰/프로시저를 fluent builder 로 정의하고, `DbContext` 클래스에 등록한 뒤, 체이닝 `Queryable` 타입 안전한 SELECT/CUD 쿼리를 JSON AST(`QueryDef`/`Expr`)조립한다. 실제 SQL 변환은 패키지의 dialect QueryBuilder(MySQL/MSSQL/PostgreSQL)가, DB 연결·실행은 `DbContextExecutor` 구현체(`@simplysm/orm-node` 등)가 담당한다.
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
- - **스키마 정의 (Table/View/Procedure/Column/Index/Relation 빌더)** — DB 객체를 fluent 빌더로 선언하고 column·PK·index·FK 관계를 잡을 때. 자세히: [schema.md](./schema.md)
8
- - **DbContext (연결·트랜잭션·DDL·마이그레이션·초기화·트랜잭션 에러)** 빌더들을 컨텍스트에 등록하고 `connect`/`transaction` 으로 실행, DDL·migration·`initialize` 돌리거나 `DbTransactionError` 처리할 때. 자세히: [db-context.md](./db-context.md)
9
- - **Queryable (SELECT/JOIN/CUD 체이닝 · 프로시저 실행 · 검색 파서)** — `db.user()` 로 받은 쿼리 빌더에 where/orderBy/join/include/group/recursive/union 걸고 execute/single/count/insert/update/delete/upsert 하거나, `Executable`프로시저를 실행하고 `search()` 텍스트 검색을 쓸 때. 자세히: [queryable.md](./queryable.md)
10
- - **expr (SQL 표현식 빌더)** — where/select/orderBy 콜백 안에서 비교·문자열·숫자·날짜·집계·조건·window·서브쿼리 표현식을 만들 때. 자세히: [expr.md](./expr.md)
11
- - **타입·실행 엔진 내부 (QueryDef/Expr/Column 타입 · dialect QueryBuilder · 결과 파서)**executor·QueryBuilder 를 직접 구현하거나 AST·결과 메타를 다루고, QueryDef SQL렌더링하거나 raw 결과를 환원할 때. 자세히: [types.md](./types.md)
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·마이그레이션을 실행하는 묶음. executor(`DbContextExecutor`) 구현체와 `{ database, schema? }` 옵션을 생성자로 주입한다. 트랜잭션 롤백 에러는 `DbTransactionError` 로 표준화된다.
3
+ `DbContext` 추상 클래스를 상속해 테이블·뷰·프로시저를 클래스 프로퍼티로 등록하고, 연결·트랜잭션·DDL·마이그레이션을 실행하는 묶음. `DbContextExecutor` 구현체와 `{ database, schema? }` 옵션을 생성자로 주입한다. 각 프로퍼티가 독립 직렬화되어 40+ 테이블에서도 TS7056 이 발생하지 않는다. 트랜잭션 롤백 에러는 `DbTransactionError` 로 표준화된다.
4
4
 
5
- ## DbContext (정의·등록)
5
+ > 앱(Angular) 환경에서는 화면이 `DbContext` 를 직접 생성하지 않고 `AppOrmProvider.connectAsync(cb)` 로 감싼다(client-orm.md). `db` 인자가 곧 아래 `DbContext` 인스턴스이므로, 콜백 안의 쿼리 작성법은 동일하다.
6
6
 
7
- `abstract class DbContext implements DbContextBase`. 서브클래스에서 `this.queryable(...)`/`this.executable(...)` 로 멤버를 만들고 `migrations` 를 오버라이드한다.
7
+ ## DbContext (abstract class)
8
8
 
9
- - `constructor(executor: DbContextExecutor, opt: { database: string; schema?: string })` — executor 와 대상 DB 옵션 주입.
10
- - `protected queryable(builder): () => Queryable` — Table/View 빌더를 Queryable 팩토리로 등록. 호출 시마다 새 alias 부여(View 는 viewFn 실행). 반환 함수에 `SD_BUILDER` 심볼로 원본 빌더를 부착.
11
- - `protected executable(builder): () => Executable` Procedure 빌더를 Executable 팩토리로 등록. 마찬가지로 `SD_BUILDER` 부착.
12
- - `migrations: Migration[]` — 마이그레이션 정의 배열. 서브클래스에서 오버라이드. `initialize()` 가 미적용분만 순서대로 실행.
13
- - `_migration` 내부 시스템 마이그레이션 테이블(`_Migration`) Queryable. 적용 이력 저장용.
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
- ## 상태·내부 (DbContextBase / DbContextStatus)
62
+ 주의:
26
63
 
27
- `interface DbContextBase` Queryable/Executable/View 의존하는 핵심 면. DbContext 구현. executor·어댑터 작성 참조.
64
+ - 트랜잭션("transact") 상태에서 DDL(`createTable` 등)을 `executeDefs` 보내면 "TRANSACTION 상태에서는 DDL을 실행할 없습니다" throw. DDL `connectWithoutTransaction` 안에서 실행.
65
+ - 롤백 자체가 실패해도 원래 에러를 우선 throw 하고, 롤백 실패 원인은 `err.cause` 로 부착(단, `NO_ACTIVE_TRANSACTION` 은 무시).
28
66
 
29
- - `status: DbContextStatus` — `"ready"`(미연결) / `"connect"`(연결됨, 트랜잭션 밖) / `"transact"`(트랜잭션 중). `transact` 상태에서 DDL 실행 시 throw.
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
- `type DbContextStatus = "ready" | "connect" | "transact"`. `interface DbContextDdlMethods` 아래 DDL 메서드들의 시그니처 모음(`Migration.up` 의 인자 타입).
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
- - `connect<T>(fn, isolationLevel?): Promise<T>` 연결+트랜잭션으로 `fn` 실행. 최초 1회 관계 검증(`validateRelations`) alias 리셋, beginTransaction fn commit, 예외 rollback rethrow, 끝에 항상 close. `ready` 상태 아니면 throw. 일반적인 "한 작업=한 트랜잭션" 경로.
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
- 롤백 중 발생한 에러가 `DbTransactionError` 이고 코드가 `NO_ACTIVE_TRANSACTION` 이면 무시(원 에러 보존), 그 외엔 원 에러의 `cause` 로 부착.
85
+ ## initialize
47
86
 
48
87
  ```typescript
49
- await db.connect(async () => {
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
- ## DDL 실행 메서드
91
+ - `dbs?: string[]` — 초기화 대상 데이터베이스명 목록. 미지정 시 컨텍스트의 기본 database.
92
+ - `force?: boolean` — true 면 기존 스키마를 비우고(`clearSchema`) 전체 재생성. false/미지정이면 미적용 마이그레이션만 증분 실행하고, 변경이 있었는지를 boolean 으로 반환.
93
+ - 반환값 — 실제로 스키마를 만들거나 마이그레이션을 적용했으면 true. 트랜잭션 안에서 돌지 않으므로 `connectWithoutTransaction` 으로 호출.
56
94
 
57
- 메서드는 해당 QueryDef 1개를 `executeDefs` 로 실행한다(`transact` 중 호출 시 throw). 대상 `table`/`view`/`procedure` 인자는 빌더 또는 `QueryDefObjectName`.
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
- `get...QueryDef(...)` 형태의 생성기(`getCreateTableQueryDef` 메서드 1:1 대응 + `getCreateObjectQueryDef`) 실행 없이 `QueryDef` 반환 여러 DDL 모아 번에 실행하거나 SQL 을 미리 확인할 때.
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
- ## 초기화 / Migration
101
+ ## DbContextExecutor / ResultMeta
74
102
 
75
- - `initialize(options?: { dbs?: string[]; force?: boolean }): Promise<boolean>` 스키마·마이그레이션 적용. `dbs`=대상 DB 한정, `force`=강제 재생성. 적용 여부 반환.
76
- - `interface Migration` — `{ name: string; up: (db: DbContextBase & DbContextDdlMethods) => Promise<void> }`. `name` 은 고유(타임스탬프 권장), `up` 안에서 DDL 호출. `initialize` 가 미적용 `name` 만 순서대로 실행.
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
- override migrations: Migration[] = [
80
- { name: "20260105_001_create_user", up: async (db) => { await db.createTable(User); } },
81
- { name: "20260105_002_add_email", up: async (db) => { await db.addColumn(User, "email", c.varchar(200).nullable()); } },
82
- ];
113
+ interface Migration {
114
+ name: string;
115
+ up: (db: DbContextBase & DbContextDdlMethods) => Promise<void>;
116
+ }
83
117
  ```
84
118
 
85
- ## 트랜잭션 에러 (DbTransactionError / DbErrorCode)
119
+ - `name: string` — 마이그레이션 고유 이름(타임스탬프 권장, 예 `20260105_001_create_user`). 적용 여부 추적 키이므로 한 번 배포 후 변경 금지.
120
+ - `up(db)` — 적용 시 실행할 함수. `db` 로 DDL 메서드를 호출. 미적용 항목만 `name` 순서대로 1회씩 실행된다.
121
+
122
+ ## IsolationLevel
86
123
 
87
- DBMS 네이티브 트랜잭션 에러를 표준 코드로 래핑. `connect`/`transaction` 의 롤백 경로에서 던져진다(주로 executor 구현이 생성).
124
+ `connect`/`transaction`/`beginTransaction` 의 격리 수준.
88
125
 
89
- - `class DbTransactionError extends Error`
90
- - `code: DbErrorCode` — 표준 에러 코드(생성자 1번째 인자).
91
- - `message: string` — 메시지(생성자 2번째 인자).
92
- - `originalError?: unknown` — 원본 DBMS 에러(생성자 3번째, 디버깅용).
93
- - `name` — 항상 `"DbTransactionError"`.
94
- - `enum DbErrorCode` (문자열 값)
95
- - `NO_ACTIVE_TRANSACTION` — 활성 트랜잭션 없는데 ROLLBACK 시도. 롤백 중 이 코드면 컨텍스트가 무시하고 원 에러를 보존.
96
- - `TRANSACTION_ALREADY_STARTED` 이미 트랜잭션 시작됨.
97
- - `DEADLOCK` — 데드락.
98
- - `LOCK_TIMEOUT` — 잠금 타임아웃.
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 db.rollbackTransaction();
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 자동화) 사용.