@simplysm/sd-claude 14.0.88 → 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.
Files changed (135) hide show
  1. package/claude/references/sd-simplysm14/README.md +16 -17
  2. package/claude/references/sd-simplysm14/apis/angular/README.md +39 -43
  3. package/claude/references/sd-simplysm14/apis/angular/controls.md +174 -80
  4. package/claude/references/sd-simplysm14/apis/angular/crud.md +41 -50
  5. package/claude/references/sd-simplysm14/apis/angular/directives.md +60 -26
  6. package/claude/references/sd-simplysm14/apis/angular/features.md +109 -37
  7. package/claude/references/sd-simplysm14/apis/angular/infra.md +61 -44
  8. package/claude/references/sd-simplysm14/apis/angular/layout.md +39 -31
  9. package/claude/references/sd-simplysm14/apis/angular/overlay.md +73 -85
  10. package/claude/references/sd-simplysm14/apis/angular/routing-appstructure.md +54 -39
  11. package/claude/references/sd-simplysm14/apis/angular/selection-managers.md +55 -30
  12. package/claude/references/sd-simplysm14/apis/angular/shared-data.md +71 -67
  13. package/claude/references/sd-simplysm14/apis/angular/sheet.md +82 -72
  14. package/claude/references/sd-simplysm14/apis/capacitor-plugin-auto-update/README.md +35 -36
  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 +38 -30
  17. package/claude/references/sd-simplysm14/apis/capacitor-plugin-usb-storage/README.md +45 -50
  18. package/claude/references/sd-simplysm14/apis/core-browser/README.md +42 -55
  19. package/claude/references/sd-simplysm14/apis/core-browser/dom-element.md +62 -0
  20. package/claude/references/sd-simplysm14/apis/core-browser/indexed-db.md +39 -38
  21. package/claude/references/sd-simplysm14/apis/core-common/README.md +95 -103
  22. package/claude/references/sd-simplysm14/apis/core-common/array-ext.md +59 -54
  23. package/claude/references/sd-simplysm14/apis/core-common/async-runtime.md +86 -0
  24. package/claude/references/sd-simplysm14/apis/core-common/datetime.md +57 -66
  25. package/claude/references/sd-simplysm14/apis/core-common/errors.md +86 -0
  26. package/claude/references/sd-simplysm14/apis/core-common/obj.md +60 -42
  27. package/claude/references/sd-simplysm14/apis/core-common/serialization.md +55 -0
  28. package/claude/references/sd-simplysm14/apis/core-node/README.md +10 -8
  29. package/claude/references/sd-simplysm14/apis/core-node/consola.md +29 -32
  30. package/claude/references/sd-simplysm14/apis/core-node/cpx.md +34 -22
  31. package/claude/references/sd-simplysm14/apis/core-node/fs-watcher.md +29 -25
  32. package/claude/references/sd-simplysm14/apis/core-node/fsx.md +40 -53
  33. package/claude/references/sd-simplysm14/apis/core-node/pathx.md +22 -29
  34. package/claude/references/sd-simplysm14/apis/core-node/worker.md +31 -31
  35. package/claude/references/sd-simplysm14/apis/excel/README.md +26 -26
  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/lint/README.md +27 -21
  43. package/claude/references/sd-simplysm14/apis/lint/rules.md +89 -49
  44. package/claude/references/sd-simplysm14/apis/orm-common/README.md +6 -62
  45. package/claude/references/sd-simplysm14/apis/orm-common/db-context.md +149 -67
  46. package/claude/references/sd-simplysm14/apis/orm-common/expr.md +111 -99
  47. package/claude/references/sd-simplysm14/apis/orm-common/queryable.md +115 -72
  48. package/claude/references/sd-simplysm14/apis/orm-common/schema.md +134 -92
  49. package/claude/references/sd-simplysm14/apis/orm-common/types.md +67 -52
  50. package/claude/references/sd-simplysm14/apis/orm-node/README.md +63 -26
  51. package/claude/references/sd-simplysm14/apis/orm-node/db-conn.md +51 -40
  52. package/claude/references/sd-simplysm14/apis/sd-cli/README.md +10 -12
  53. package/claude/references/sd-simplysm14/apis/sd-cli/SdTsCompiler.md +92 -45
  54. package/claude/references/sd-simplysm14/apis/sd-cli/sd-config-types.md +226 -108
  55. package/claude/references/sd-simplysm14/apis/service-client/README.md +90 -88
  56. package/claude/references/sd-simplysm14/apis/service-client/orm.md +37 -29
  57. package/claude/references/sd-simplysm14/apis/service-client/transport.md +45 -20
  58. package/claude/references/sd-simplysm14/apis/service-common/README.md +89 -40
  59. package/claude/references/sd-simplysm14/apis/service-common/app-structure.md +126 -34
  60. package/claude/references/sd-simplysm14/apis/service-common/protocol.md +109 -54
  61. package/claude/references/sd-simplysm14/apis/service-server/README.md +70 -66
  62. package/claude/references/sd-simplysm14/apis/service-server/service-authoring.md +47 -47
  63. package/claude/references/sd-simplysm14/apis/service-server/transport-internals.md +71 -34
  64. package/claude/references/sd-simplysm14/apis/service-server/v1-legacy.md +31 -32
  65. package/claude/references/sd-simplysm14/apis/storage/README.md +34 -28
  66. package/claude/references/sd-simplysm14/manuals/client-app-structure.md +142 -140
  67. package/claude/references/sd-simplysm14/manuals/client-orm.md +1 -1
  68. package/claude/references/sd-simplysm14/manuals/client-service.md +19 -7
  69. package/claude/references/sd-simplysm14/manuals/client-shared-data.md +2 -2
  70. package/claude/references/sd-simplysm14/manuals/client-system-log.md +11 -3
  71. package/claude/references/sd-simplysm14/manuals/data-log.md +0 -1
  72. package/claude/references/sd-simplysm14/manuals/orm.md +16 -0
  73. package/claude/rules/sd-design-rules.md +10 -0
  74. package/claude/skills/sd-docs/SKILL.md +58 -46
  75. package/claude/skills/sd-docs/references/{doc-rules.md → subagent-prompt.md} +103 -103
  76. package/claude/skills/sd-impl/SKILL.md +1 -1
  77. package/claude/skills/sd-spec/SKILL.md +858 -858
  78. package/claude/skills/sd-spec/references/example-spec.md +26 -36
  79. package/package.json +1 -1
  80. package/claude/references/sd-simplysm14/apis/core-common/json-transfer.md +0 -47
  81. package/claude/references/sd-simplysm14/apis/orm-common/query-builder.md +0 -29
  82. package/claude/skills/sd-demo/evals/fixtures/inventory-list/.specs/inventory/spec.md +0 -99
  83. package/claude/skills/sd-demo/evals/fixtures/inventory-list/packages/demo-client/package.json +0 -12
  84. package/claude/skills/sd-demo/evals/fixtures/inventory-list/packages/demo-client/src/index.ts +0 -3
  85. package/claude/skills/sd-demo/evals/fixtures/inventory-list/packages/demo-client/src/screens/inbound/inbound.list.ts +0 -150
  86. package/claude/skills/sd-demo/evals/fixtures/inventory-list/packages/demo-client/src/screens/inventory/inventory-master.list.ts +0 -143
  87. package/claude/skills/sd-demo/evals/fixtures/inventory-list/packages/demo-client/src/screens/outbound/outbound.list.ts +0 -150
  88. package/claude/skills/sd-demo/evals/fixtures/inventory-list/pnpm-workspace.yaml +0 -2
  89. package/claude/skills/sd-demo/evals/fixtures/inventory-list/sd.config.ts +0 -12
  90. package/claude/skills/sd-demo/evals/golden.jsonl +0 -1
  91. package/claude/skills/sd-dev/evals/fixtures/minimal-ts-pkg/package.json +0 -8
  92. package/claude/skills/sd-dev/evals/fixtures/minimal-ts-pkg/src/.gitkeep +0 -0
  93. package/claude/skills/sd-dev/evals/fixtures/minimal-ts-pkg/tests/.gitkeep +0 -0
  94. package/claude/skills/sd-dev/evals/fixtures/minimal-ts-pkg/tsconfig.json +0 -10
  95. package/claude/skills/sd-dev/evals/golden.jsonl +0 -1
  96. package/claude/skills/sd-docs/evals/fixtures/new-write/.claude/references/sd-simplysm14/README.md +0 -7
  97. package/claude/skills/sd-docs/evals/fixtures/new-write/packages/bar/package.json +0 -5
  98. package/claude/skills/sd-docs/evals/fixtures/new-write/packages/bar/src/index.ts +0 -3
  99. package/claude/skills/sd-docs/evals/fixtures/new-write/packages/baz/package.json +0 -6
  100. package/claude/skills/sd-docs/evals/fixtures/new-write/packages/baz/src/index.ts +0 -1
  101. package/claude/skills/sd-docs/evals/fixtures/new-write/packages/foo/package.json +0 -5
  102. package/claude/skills/sd-docs/evals/fixtures/new-write/packages/foo/src/index.ts +0 -8
  103. package/claude/skills/sd-docs/evals/fixtures/update-mixed/.claude/references/sd-simplysm14/README.md +0 -7
  104. package/claude/skills/sd-docs/evals/fixtures/update-mixed/.claude/references/sd-simplysm14/apis/foo/README.md +0 -3
  105. package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/bar/package.json +0 -5
  106. package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/bar/src/index.ts +0 -3
  107. package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/baz/package.json +0 -6
  108. package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/baz/src/index.ts +0 -1
  109. package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/foo/package.json +0 -5
  110. package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/foo/src/index.ts +0 -8
  111. package/claude/skills/sd-docs/evals/golden.jsonl +0 -2
  112. package/claude/skills/sd-impl/evals/fixtures/case-a-new-screen/.specs/260513120000_warehouse/spec.md +0 -101
  113. package/claude/skills/sd-impl/evals/fixtures/case-b-update-with-demo/.specs/260513120000_warehouse/spec.md +0 -101
  114. package/claude/skills/sd-impl/evals/fixtures/case-b-update-with-demo/packages/app/src/screens/box-register/box-register.view.ts +0 -46
  115. package/claude/skills/sd-impl/evals/fixtures/case-c-new-cross/.specs/260513120000_warehouse/spec.md +0 -89
  116. package/claude/skills/sd-impl/evals/fixtures/case-d-spec-modify/.specs/260513120000_warehouse/spec.md +0 -101
  117. package/claude/skills/sd-impl/evals/golden.jsonl +0 -4
  118. package/claude/skills/sd-manual/evals/fixtures/new-manual/src/notification.ts +0 -25
  119. package/claude/skills/sd-manual/evals/fixtures/update-manual/.claude/references/sd-simplysm14/manuals/notification.md +0 -14
  120. package/claude/skills/sd-manual/evals/fixtures/update-manual/src/notification.ts +0 -37
  121. package/claude/skills/sd-manual/evals/golden.jsonl +0 -2
  122. package/claude/skills/sd-review/evals/fixtures/code-review/src/foo.ts +0 -7
  123. package/claude/skills/sd-review/evals/fixtures/doc-review/docs/foo.md +0 -4
  124. package/claude/skills/sd-review/evals/golden.jsonl +0 -2
  125. package/claude/skills/sd-skill/evals/fixtures/existing-skill/.claude/skills/todo-format/SKILL.md +0 -14
  126. package/claude/skills/sd-skill/evals/fixtures/new-skill/.gitkeep +0 -0
  127. package/claude/skills/sd-skill/evals/golden.jsonl +0 -2
  128. package/claude/skills/sd-spec/evals/fixtures/case-a-split//355/232/214/354/235/230/353/241/235.md +0 -20
  129. package/claude/skills/sd-spec/evals/fixtures/case-b-detail/.specs/260513120000_warehouse/spec.md +0 -95
  130. package/claude/skills/sd-spec/evals/golden.jsonl +0 -2
  131. package/claude/skills/sd-unpack/evals/fixtures/eml-with-text-attachment/meeting.eml +0 -21
  132. package/claude/skills/sd-unpack/evals/fixtures/simple-eml/meeting.eml +0 -10
  133. package/claude/skills/sd-unpack/evals/golden.jsonl +0 -2
  134. package/claude/skills/sd-use/evals/fixtures/empty/.gitkeep +0 -0
  135. package/claude/skills/sd-use/evals/golden.jsonl +0 -6
@@ -1,80 +1,162 @@
1
- # @simplysm/orm-common — DbContext / 연결·DDL·마이그레이션
1
+ # @simplysm/orm-common — DbContext / 연결·트랜잭션·DDL·마이그레이션
2
2
 
3
- 테이블/뷰/프로시저 빌더를 class 프로퍼티로 등록하고, 연결·트랜잭션·DDL·초기화·마이그레이션을 제공하는 추상 클래스. 서브클래스로 확장해 사용. 실제 DB I/O 생성자에 주입한 `DbContextExecutor` 담당.
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
- - `new DbContext(executor: DbContextExecutor, opt: { database: string; schema? })` — 생성자(서브클래스가 호출). `executor` 는 DB I/O 구현, `opt.database`/`opt.schema` 는 기본 네임스페이스.
8
- - `status: DbContextStatus` — 현재 상태(`"ready"`|`"connect"`|`"transact"`). 연결/트랜잭션 가드에 사용.
9
- - `database` / `schema` — 주입한 기본 database/schema.
10
- - 등록 메서드(protected, 서브클래스 프로퍼티 초기화에서 호출):
11
- - `queryable(builder): () => Queryable` Table/View 빌더를 Queryable 팩토리로 등록. 호출할 때마다 새 alias 부여.
12
- - `executable(builder): () => Executable` — Procedure 빌더를 Executable 팩토리로 등록.
13
- - `migrations: Migration[]` 마이그레이션 정의(서브클래스에서 오버라이드). 기본 빈 배열.
7
+ ## DbContext (abstract class)
8
+
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 {
17
50
  user = this.queryable(User);
18
51
  post = this.queryable(Post);
19
52
  getUserById = this.executable(GetUserById);
20
- migrations = [{ name: "001", up: async (db) => { await db.createTable(User); } }];
53
+ override migrations = [{ name: "001", up: async (db) => { await db.createTable(User); } }];
21
54
  }
55
+
22
56
  const db = new MainDb(executor, { database: "mydb" });
23
- await db.connect(async () => { await db.user().execute(); });
57
+ const users = await db.connect(async () => {
58
+ return db.user().where((u) => [expr.eq(u.isActive, true)]).execute();
59
+ });
24
60
  ```
25
61
 
26
- ## 연결 / 트랜잭션
27
-
28
- - `connect<T>(fn, isolationLevel?): Promise<T>` 연결 + 트랜잭션 1개를 감싸 `fn` 실행. 성공 commit, 예외 rollback throw, 종료 시 항상 close. `ready` 아니면 throw. 최초 호출 시 관계 정합성 검증. `isolationLevel` 격리 수준(선택).
29
- - `connectWithoutTransaction<T>(callback): Promise<T>` 트랜잭션 없이 연결만 잡고 `callback` 실행, 종료 close. 내부에서 별도 `transaction()` 직접 호출할 때 사용.
30
- - `transaction<T>(fn, isolationLevel?): Promise<T>` — 이미 연결된 상태에서 트랜잭션만 시작/commit/rollback. `transact` 상태면 throw. (DDL 은 transact 상태에서 실행 불가 — `executeDefs` 가 throw)
31
-
32
- ## DbContextBase 내부 인터페이스 메서드
33
-
34
- executor·Queryable 이 의존하는 저수준 메서드(직접 호출은 드묾):
35
- - `getNextAlias(): string` — 다음 테이블 alias(`T1`, `T2`...) 발급.
36
- - `resetAliasCounter(): void` alias 카운터 초기화(연결 시작 호출).
37
- - `executeDefs<T>(defs: QueryDef[], resultMetas?): Promise<T[][]>` QueryDef 배열을 executor 로 실행. transact 상태에서 DDL 포함 시 throw.
38
- - `getQueryDefObjectName(tableOrView): QueryDefObjectName` 빌더 DB 객체 이름(database/schema/name) 해석.
39
- - `switchFk(table, enabled): Promise<void>`FK 제약 활성/비활성(트랜잭션 가능).
40
-
41
- ## DDL 실행 메서드 (await 즉시 실행)
42
-
43
- 각각 해당 DDL 을 `executeDefs` 즉시 실행. `table`/`view`/`procedure` 인자는 `QueryDefObjectName` 또는 빌더.
44
- - `createTable(table)` / `dropTable(table)` / `renameTable(table, newName)` — 테이블 생성/삭제/이름변경.
45
- - `createView(view)` / `dropView(view)` 생성/삭제.
46
- - `createProc(procedure)` / `dropProc(procedure)` — 프로시저 생성/삭제.
47
- - `addColumn(table, columnName, column)` column 추가(`column` `ColumnBuilder`).
48
- - `dropColumn(table, column)` — column 삭제.
49
- - `modifyColumn(table, columnName, column)` — column 타입/속성 변경.
50
- - `renameColumn(table, column, newName)` — column 이름 변경.
51
- - `addPrimaryKey(table, columns)` / `dropPrimaryKey(table)` — PK 추가/삭제.
52
- - `addForeignKey(table, relationName, relationDef)` FK 추가(`relationDef` `ForeignKeyBuilder`).
53
- - `dropForeignKey(table, relationName)` — FK 삭제.
54
- - `addIndex(table, indexBuilder)` / `dropIndex(table, columns)` — index 추가/삭제.
55
- - `clearSchema(params: { database; schema? })` 스키마 모든 객체 삭제.
56
- - `schemaExists(database, schema?): Promise<boolean>`스키마 존재 확인.
57
- - `truncate(table)` 테이블 비우기.
58
-
59
- ## DDL QueryDef 생성기 (실행 없이 def 만 반환)
60
-
61
- DDL 들의 `get*QueryDef(...)` 버전. 즉시 실행하지 않고 `QueryDef` 반환해 배치·검사용으로 모을 사용. 예: `getCreateTableQueryDef(table)`, `getDropTableQueryDef(table)`, `getAddColumnQueryDef(table, columnName, column)`, `getAddForeignKeyQueryDef(...)`, `getTruncateQueryDef(table)`, `getSwitchFkQueryDef(table, enabled)` 등. `getCreateObjectQueryDef(builder)` Table/View/Procedure 무엇이든 받아 알맞은 CREATE def 반환.
62
-
63
- ## 초기화 / 마이그레이션
64
-
65
- - `initialize(options?: { dbs?: string[]; force?: boolean }): Promise<boolean>` — 스키마 동기화/마이그레이션 실행.
66
- - `dbs?: string[]` — 대상 database 한정(미지정 시 전체).
67
- - `force?: boolean` — true 기존 스키마를 강제 재생성. 운영 데이터 손실 위험이 있어 개발/초기 셋업에서만.
68
- - 반환 boolean — 초기화 수행 여부.
69
- - `interface Migration` — 마이그레이션 1건.
70
- - `name: string` — 고유 이름(타임스탬프 권장, 적용 여부 추적 ).
71
- - `up: (db) => Promise<void>` — 적용 함수. `db` DDL 메서드를 갖춘 컨텍스트.
72
-
73
- ## 관련 타입
74
-
75
- - `type DbContextStatus = "ready" | "connect" | "transact"`.
76
- - `interface DbContextBase` — Queryable/Executable/ViewBuilder 가 의존하는 핵심 인터페이스(위 저수준 메서드 + database/schema/status).
77
- - `interface DbContextDdlMethods` — DDL 실행+생성기 메서드 시그니처 모음(Migration.up 의 db 타입).
78
- - `interface DbContextExecutor` — 주입할 실행기 인터페이스. `connect()`/`close()`/`beginTransaction(isolationLevel?)`/`commitTransaction()`/`rollbackTransaction()`/`executeDefs(defs, resultMetas?)`.
79
- - `const SD_BUILDER: symbol` 등록된 팩토리 함수에 원본 빌더를 매달아두는 심볼 키(내부 메타 조회용).
80
- - `_Migration` — 시스템 마이그레이션 테이블 빌더(`_migration`, PK `code: varchar(255)`). initialize 가 적용 이력 저장에 사용.
62
+ 주의:
63
+
64
+ - 트랜잭션("transact") 상태에서 DDL(`createTable` 등)을 `executeDefs` 보내면 "TRANSACTION 상태에서는 DDL을 실행할 없습니다" throw. DDL `connectWithoutTransaction` 안에서 실행.
65
+ - 롤백 자체가 실패해도 원래 에러를 우선 throw 하고, 롤백 실패 원인은 `err.cause` 부착(단, `NO_ACTIVE_TRANSACTION` 무시).
66
+
67
+ ## DDL 실행 메서드
68
+
69
+ `connectWithoutTransaction` 안에서 호출하며, 즉시 executor 로 실행한다. 모두 `Promise<void>`(예외: `schemaExists` → `Promise<boolean>`).
70
+
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 이 아니라 트랜잭션 안에서도 호출 가능.
82
+
83
+ `createX`/`dropX`/... 에는 동일 시그니처의 `getXQueryDef(...): QueryDef` 생성기 버전이 쌍으로 존재(실행하지 않고 QueryDef AST 만 반환). 추가로 `getCreateObjectQueryDef(builder)` Table/View/Procedure 중 무엇이든 받아 알맞은 create QueryDef 를 반환한다. 마이그레이션에서 여러 DDL 을 모아 한 번에 보내거나 DDL 을 검사·로깅할 때 사용.
84
+
85
+ ## initialize
86
+
87
+ ```typescript
88
+ initialize(options?: { dbs?: string[]; force?: boolean }): Promise<boolean>
89
+ ```
90
+
91
+ - `dbs?: string[]` 초기화 대상 데이터베이스명 목록. 미지정 컨텍스트의 기본 database.
92
+ - `force?: boolean`true 기존 스키마를 비우고(`clearSchema`) 전체 재생성. false/미지정이면 미적용 마이그레이션만 증분 실행하고, 변경이 있었는지를 boolean 으로 반환.
93
+ - 반환값 — 실제로 스키마를 만들거나 마이그레이션을 적용했으면 true. 트랜잭션 안에서 돌지 않으므로 `connectWithoutTransaction` 으로 호출.
94
+
95
+ ## DbContextBase / DbContextStatus / DbContextDdlMethods
96
+
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 을 호출할 수 있다.
100
+
101
+ ## DbContextExecutor / ResultMeta
102
+
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
111
+
112
+ ```typescript
113
+ interface Migration {
114
+ name: string;
115
+ up: (db: DbContextBase & DbContextDdlMethods) => Promise<void>;
116
+ }
117
+ ```
118
+
119
+ - `name: string` — 마이그레이션 고유 이름(타임스탬프 권장, 예 `20260105_001_create_user`). 적용 여부 추적 키이므로 한 번 배포 후 변경 금지.
120
+ - `up(db)` — 적용 시 실행할 함수. `db` 로 DDL 메서드를 호출. 미적용 항목만 `name` 순서대로 1회씩 실행된다.
121
+
122
+ ## IsolationLevel
123
+
124
+ `connect`/`transaction`/`beginTransaction` 의 격리 수준.
125
+
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` — 잠금 대기 타임아웃.
154
+
155
+ ```typescript
156
+ try {
157
+ await executor.rollbackTransaction();
158
+ } catch (err) {
159
+ if (err instanceof DbTransactionError && err.code === DbErrorCode.NO_ACTIVE_TRANSACTION) return;
160
+ throw err;
161
+ }
162
+ ```
@@ -1,113 +1,125 @@
1
1
  # @simplysm/orm-common — expr (SQL 표현식 빌더)
2
2
 
3
- dialect 독립 SQL 표현식을 JSON AST(`Expr`)로 만드는 `expr` 객체. `where`/`having`/`search` 콜백에선 비교·논리 함수(`WhereExprUnit` 반환), `select`/`orderBy`/`groupBy` 콜백에선 값·함수·집계(`ExprUnit<T>` 반환)를 쓴다. `ExprInput<T>` = `ExprUnit<T> | T`(리터럴 직접 전달 가능). `ExprUnit.n` 게터는 nullable 을 non-null 타입으로 좁힌다.
3
+ `expr` 객체로 dialect 독립 SQL 표현식을 JSON AST(`Expr`)로 조립한다. dialect별 QueryBuilder 가 MySQL/MSSQL/PostgreSQL 로 변환. where/having 콜백은 `WhereExprUnit[]`, select/orderBy/groupBy 콜백은 `ExprUnit<T>`, update/upsert/where 비교값은 `ExprInput<T>`(= `ExprUnit<T> | T`) 다룬다.
4
+
5
+ **리터럴 래핑 규칙(orm.md)**: where 비교·update/upsert/insert 값은 `ExprInput` 자리라 **리터럴을 그대로** 넘긴다 — `expr.val` 로 감싸지 말 것. `expr.val` 은 `select` 콜백에서 상수 column 을 만들 때처럼 `ExprUnit` 이 요구되는 자리에서만.
6
+
7
+ ```typescript
8
+ // 좋음 // 나쁨 (불필요한 래핑)
9
+ .where((u) => [expr.eq(u.status, "active")]) // expr.eq(u.status, expr.val("string","active"))
10
+ .update((u) => ({ name: "새이름" })) // ({ name: expr.val("string","새이름") })
11
+ ```
12
+
13
+ 연산 함수 인자는 대부분 `ExprInput<T>` — column 프록시(`ExprUnit`)·중첩 식·리터럴을 섞어 넘길 수 있다. `undefined` 컬럼 타입은 `.n` getter 로 non-null 단언 가능.
14
+
15
+ ## ExprUnit / WhereExprUnit / ExprInput
16
+
17
+ - `ExprUnit<TPrimitive>` — 타입 안전 값 표현식 래퍼. `.dataType`(ColumnPrimitiveStr), `.expr`(AST), `.$infer`(타입 추론 마커). `.n` getter — 동일 식을 `NonNullable<T>` 로 좁힌 새 ExprUnit(`p.state!.sumQty` 처럼 nullable join 컬럼을 non-null 로 다룰 때 `.n` 대신 `!` 도 가능).
18
+ - `WhereExprUnit` — WHERE/HAVING 절 boolean 표현식 래퍼(`.expr: WhereExpr`). 비교·논리 함수가 반환.
19
+ - `ExprInput<T>` — `ExprUnit<T> | T`. 연산 인자·쓰기 값이 받는 타입(리터럴 직접 허용).
4
20
 
5
21
  ## 값 생성
6
22
 
7
- - `expr.val(dataType, value): ExprUnit` — 리터럴 래핑. `dataType` 은 `"string"|"number"|"boolean"|"DateTime"|"DateOnly"|"Time"|"Uuid"|"Bytes"`, `value` 값(undefined=NULL 허용). UPDATE/UPSERT 쓰기값에 주로 사용.
8
- - `expr.col(dataType, ...path): ExprUnit` — column 참조 직접 생성(보통은 프록시 사용, 내부용).
9
- - `expr.raw(dataType)\`SQL ${expr}\`: ExprUnit` Raw SQL 이스케이프 해치. 태그드 템플릿, 보간값은 자동 파라미터화. ORM 미지원 DB 함수가 필요할 때만.
10
- - `expr.toExpr(value): Expr` — `ExprInput` → `Expr` AST 변환(내부 헬퍼).
11
-
12
- ## WHERE — 비교 (WhereExprUnit 반환)
13
-
14
- - `expr.eq(source, target)` — 동등(=). **NULL 안전**(MySQL `<=>`, MSSQL/PG `IS NULL OR =`).
15
- - `expr.gt(source, target)` 초과(>).
16
- - `expr.lt(source, target)` — 미만(<).
17
- - `expr.gte(source, target)` — 이상(>=).
18
- - `expr.lte(source, target)` — 이하(<=).
19
- - `expr.between(source, from?, to?)` — 범위(BETWEEN). `from`/`to` undefined 면 해당 방향 무제한(한쪽만 주면 `>=`/`<=`).
20
- - `expr.null(source)` — IS NULL 검사.
21
- - `expr.like(source, pattern)` — LIKE 패턴(`%`=0+, `_`=1자, 특수문자 `\` 이스케이프).
22
- - `expr.regexp(source, pattern)` — 정규식 매칭(구문은 DBMS 의존).
23
- - `expr.in(source, values)` — IN 값 목록.
24
- - `expr.inQuery(source, query)` IN (서브쿼리). `query` 는 단일 column SELECT Queryable(아니면 throw).
25
- - `expr.exists(query)` — EXISTS 서브쿼리(행 1개 이상이면 true). SELECT 절은 패킷 절약 위해 제거됨.
26
-
27
- ## WHERE논리
28
-
29
- - `expr.not(arg: WhereExprUnit)` — 부정(NOT).
30
- - `expr.and(conditions: WhereExprUnit[])` AND 결합. 빈 배열 throw.
31
- - `expr.or(conditions: WhereExprUnit[])` — OR 결합. 빈 배열 throw.
32
-
33
- ## SELECT 문자열 (ExprUnit 반환)
34
-
35
- - `expr.concat(...args)` — CONCAT(NULL 문자열 취급).
36
- - `expr.left(source, length)` / `expr.right(source, length)` — 좌/우 N자 추출.
37
- - `expr.trim(source)` — 양쪽 공백 제거.
38
- - `expr.padStart(source, length, fillString)` — 좌측 패딩(LPAD), 목표 길이까지 `fillString` 반복.
39
- - `expr.replace(source, from, to)` — 치환.
40
- - `expr.upper(source)` / `expr.lower(source)` 대/소문자 변환.
41
- - `expr.length(source)` — 문자 수(CHAR_LENGTH).
42
- - `expr.byteLength(source)`바이트 길이(UTF-8 CJK 3바이트).
43
- - `expr.substring(source, start, length?)` — 부분 문자열(1-base 인덱스, length 생략 시 끝까지).
44
- - `expr.indexOf(source, search)` — 위치(1-base, 없으면 0).
45
-
46
- ## SELECT — 숫자
47
-
48
- - `expr.abs(source)` — 절대값.
49
- - `expr.round(source, digits: number)` — 반올림(소수 `digits` 자리).
50
- - `expr.ceil(source)` / `expr.floor(source)` — 올림/내림.
51
-
52
- ## SELECT — 날짜
53
-
54
- - `expr.year/month/day(source)` — 연/월/일 추출(`DateTime|DateOnly`).
55
- - `expr.hour/minute/second(source)`시/분/초 추출(`DateTime|Time`).
56
- - `expr.isoWeek(source)` — ISO 주 번호(월요일 시작, 1~53). `DateOnly`.
57
- - `expr.isoWeekStartDate(source)` — 해당 월요일 날짜. `DateOnly`.
58
- - `expr.isoYearMonth(source)` — 해당 1일. `DateOnly`.
59
- - `expr.dateDiff(unit: DateUnit, from, to)` — 날짜 (`to - from`). `unit` = `"year"|"month"|"day"|"hour"|"minute"|"second"`.
60
- - `expr.dateAdd(unit, source, value)` — 날짜 가감(`value` 음수 허용). 반환 타입은 source 와 동일.
61
- - `expr.formatDate(source, format: string)` — 포맷 문자열로 변환(규칙 DBMS 의존).
62
-
63
- ## SELECT — 조건
64
-
65
- - `expr.coalesce(...args)` non-null 반환(COALESCE). 마지막 인자가 non-nullable 이면 결과도 non-nullable.
66
- - `expr.nullIf(source, value)` — `source===value` 면 NULL, 아니면 source.
67
- - `expr.is(condition: WhereExprUnit): ExprUnit<boolean>` WHERE 조건을 boolean 값으로 SELECT.
68
- - `expr.switch<T>()` CASE WHEN 빌더. `.case(condition, then).case(...).default(value)` 체이닝으로 분기 구성. 타입은 then/default 의 ExprUnit 또는 non-null 리터럴에서 추론(전부 null 이면 throw).
69
- - `expr.if(condition, then, else_)` 삼항(IF/IIF). then/else 중 최소 하나 non-null(전부 null throw).
70
-
71
- ## SELECT — 집계
72
-
73
- 집계는 모든 NULL/행 없음일 때만 NULL(NULL 행은 무시).
74
- - `expr.count(arg?, distinct?: boolean)` — COUNT. `arg` 생략 전체 행, `distinct:true` 중복 제거.
75
- - `expr.sum(arg)` — 합계(nullable number).
76
- - `expr.avg(arg)` — 평균(nullable number).
77
- - `expr.max(arg)` / `expr.min(arg)` — 최대/최소(nullable, 입력 타입 유지).
78
-
79
- ## SELECT — 기타
80
-
81
- - `expr.greatest(...args)` / `expr.least(...args)` — 인자 중 최대/최소값(GREATEST/LEAST). 인자 중 ExprUnit 없으면 throw.
82
- - `expr.rowNum(): ExprUnit<number>` 단순 순번(1-base).
83
- - `expr.random(): ExprUnit<number>` 0~1 난수(무작위 정렬 ).
84
- - `expr.cast(source, targetType: DataType): ExprUnit` — 타입 변환(CAST). `targetType` 예: `{ type: "varchar", length: 20 }`.
85
- - `expr.subquery(dataType, queryable): ExprUnit` — 스칼라 서브쿼리(정확히 11열). `queryable` `getSelectQueryDef()` 가진 객체.
86
-
87
- ## SELECTWindow 함수
88
-
89
- `spec: WinSpecInput` = `{ partitionBy?: ExprInput[]; orderBy?: [ExprInput, ("ASC"|"DESC")?][] }`.
90
- - `expr.rowNumber(spec)` — ROW_NUMBER()(파티션 내 1-base 순번).
91
- - `expr.rank(spec)` — RANK()(동순위 후 건너뜀: 1,1,3).
92
- - `expr.denseRank(spec)` — DENSE_RANK()(동순위 후 연속: 1,1,2).
93
- - `expr.ntile(n: number, spec)` — NTILE(n)(파티션을 n 그룹으로, 1~n).
94
- - `expr.lag(column, spec, options?)` / `expr.lead(column, spec, options?)` — 이전/다음 행 값. `options` = `{ offset?: number; default?: ExprInput }`(offset 기본 1, default 는 경계값).
95
- - `expr.firstValue(column, spec)` / `expr.lastValue(column, spec)` — 프레임 첫/마지막 값.
96
- - `expr.sumOver/avgOver(column, spec)` — window 합/평균(누적합·이동평균).
97
- - `expr.countOver(spec, column?)` — window 카운트(column 생략 시 전체).
98
- - `expr.minOver/maxOver(column, spec)` — window 최소/최대.
23
+ - `val(dataType, value)` — 리터럴을 ExprUnit 으로 래핑. `dataType`="string"|"number"|"boolean"|"DateTime"|"DateOnly"|"Time"|"Uuid"|"Bytes". `value` undefined 허용(결과 타입에 undefined 포함). `select` 상수 컬럼 등 ExprUnit 강제 자리에서만.
24
+ - `col(dataType, ...path)` — column 참조 생성(내부용). 보통 콜백 프록시로 충분.
25
+ - `raw(dataType)\`SQL\`` — 이스케이프 해치. 태그드 템플릿, 보간값은 자동 파라미터화. ORM 미지원 DB 함수 직접 사용 시. 보간값은 `ExprInput`. union 의 NULL 자리채움(`` expr.raw("number")`NULL` ``)에도 사용(orm-union.md).
26
+ - `toExpr(value)` — `ExprInput` → `Expr` AST 변환(내부 헬퍼).
27
+
28
+ ## WHERE — 비교 (반환 `WhereExprUnit`)
29
+
30
+ - `eq(source, target)` — 동등(NULL 안전: MySQL `<=>`, `IS NULL OR =`).
31
+ - `gt(source, target)` / `lt(source, target)` / `gte(source, target)` / `lte(source, target)` — `>` / `<` / `>=` / `<=`.
32
+ - `between(source, from?, to?)` — 범위. `from`/`to` 중 하나가 undefined 면 그 방향 제한 없음(한쪽만 주면 `>=`/`<=` 로 동작).
33
+ - `null(source)` — IS NULL.
34
+ - `like(source, pattern)` — LIKE. `%`=0+ 문자, `_`=1 문자, 특수문자 `\` 이스케이프.
35
+ - `regexp(source, pattern)` — 정규식 매칭(구문은 DBMS 의존).
36
+ - `in(source, values)` — IN(값 목록).
37
+ - `inQuery(source, query)` — IN (SELECT ...). `query` 단일 column SELECT Queryable — 아니면 throw.
38
+ - `exists(query)` — EXISTS (서브쿼리 존재). SELECT 절은 제거되어 패킷 절약. (orm.md: SELECT 절 내부 `exists` 는 행당 N회 실행되므로 금지 — `joinSingle` 로 부착)
39
+
40
+ ## WHERE논리 (반환 `WhereExprUnit`)
41
+
42
+ - `not(arg)` — NOT.
43
+ - `and(conditions)`AND 결합. 빈 배열이면 throw. `where` 에 배열 넘기면 자동 AND 라 보통 불필요.
44
+ - `or(conditions)` — OR 결합. 빈 배열이면 throw.
45
+
46
+ ## SELECT문자열 (반환 `ExprUnit`)
47
+
48
+ - `concat(...args)` — CONCAT(NULL→빈문자열).
49
+ - `left(source, length)` / `right(source, length)` — 왼쪽/오른쪽 N자.
50
+ - `trim(source)` — 양쪽 공백 제거.
51
+ - `padStart(source, length, fillString)` — LPAD(목표 길이까지 왼쪽 채움).
52
+ - `replace(source, from, to)` — 문자열 치환.
53
+ - `upper(source)` / `lower(source)` 대/소문자 변환.
54
+ - `length(source)` — 문자 수. `byteLength(source)` 바이트 수(UTF-8 CJK 3바이트).
55
+ - `substring(source, start, length?)` — 부분 문자열(1-기반 인덱스, length 생략 시 끝까지).
56
+ - `indexOf(source, search)` 위치(1-기반, 없으면 0).
57
+
58
+ ## SELECT숫자 (반환 `ExprUnit`)
59
+
60
+ - `abs(source)` — 절대값. `round(source, digits)` — 반올림(소수 자릿수). `ceil(source)` — 올림. `floor(source)` — 내림.
61
+
62
+ ## SELECT — 날짜 (반환 `ExprUnit`)
63
+
64
+ - `year(source)` / `month(source)` / `day(source)` 연/월/일(source: DateTime|DateOnly).
65
+ - `hour(source)` / `minute(source)` / `second(source)` 시/분/초(source: DateTime|Time).
66
+ - `isoWeek(source)` — ISO 주 번호(1~53). `isoWeekStartDate(source)` 그 주 월요일. `isoYearMonth(source)` — 해당 월 1일.
67
+ - `dateDiff(unit, from, to)` — 날짜 차(to - from). `unit`="year"|"month"|"day"|"hour"|"minute"|"second".
68
+ - `dateAdd(unit, source, value)` — 날짜 가감(value 음수 허용). 결과 타입은 source 와 동일.
69
+ - `formatDate(source, format)` — 포맷 문자열로 변환(`"%Y-%m-%d"` 등, 규칙 DBMS 의존).
70
+
71
+ ## SELECT조건 (반환 `ExprUnit`)
72
+
73
+ - `coalesce(...args)` — non-null. 마지막 인수가 non-nullable 이면 결과도 non-nullable. join 도출 컬럼 기본값(`coalesce(p.state!.sum, 0)`)에 자주.
74
+ - `nullIf(source, value)` — source===value 이면 NULL(빈 문자열→NULL 변환 등).
75
+ - `is(condition)` — `WhereExprUnit` → boolean column 으로 변환(SELECT 절에서 조건 결과를 컬럼화).
76
+ - `switch<T>()` — CASE WHEN 빌더. `.case(condition, then).case(...).default(value)` 체이닝으로 `ExprUnit<T>` 마무리.
77
+ - `if(condition, then, else_)` — 삼항(IF/IIF). then/else 중 최소 하나 non-null 아니면 throw(타입 추론용).
78
+
79
+ ## SELECT — 집계 (반환 `ExprUnit`)
80
+
81
+ NULL 행은 무시, 전부 NULL/무행이면 NULL.
82
+
83
+ - `count(arg?, distinct?)` 수. `arg` 미지정=전체, `distinct: true`=중복 제거.
84
+ - `sum(arg)` / `avg(arg)` 합/평균(number, 결과 nullable).
85
+ - `max(arg)` / `min(arg)` 최대/최소(결과 nullable).
86
+
87
+ ## SELECT — 기타 (반환 `ExprUnit`)
88
+
89
+ - `greatest(...args)` / `least(...args)` 여러 값 중 최대/최소( 비교). 인자 중 ExprUnit 하나는 있어야 타입 추론(없으면 throw).
90
+ - `rowNum()` — 전체 순번(1-기반, 단순 버전). `random()` 0~1 난수(무작위 정렬에).
91
+ - `cast(source, targetType)` — 타입 변환. `targetType`=`DataType`(`{ type:"varchar", length:20 }` 등).
92
+ - `subquery(dataType, queryable)` — 스칼라 서브쿼리(1행 1열). `queryable`=`getSelectQueryDef()` 보유 객체. (orm.md: SELECT 절 내부 subquery 는 행당 N회 실행 → `joinSingle` 권장)
93
+
94
+ ## SELECT — Window 함수 (반환 `ExprUnit`)
95
+
96
+ 모두 `spec: { partitionBy?: ExprInput[]; orderBy?: [ExprInput, ("ASC"|"DESC")?][] }`(OVER 절) 인자를 받음.
97
+
98
+ - `rowNumber(spec)`파티션 순번(1-기반).
99
+ - `rank(spec)`순위(동순위 후 건너뜀: 1,1,3). `denseRank(spec)` 순위(동순위 후 연속: 1,1,2).
100
+ - `ntile(n, spec)` — 파티션을 n 그룹으로 분할(그룹 번호 1~n).
101
+ - `lag(column, spec, options?)` / `lead(column, spec, options?)` 이전/다음값. `options.offset?`(기본 1), `options.default?`(없을 기본값).
102
+ - `firstValue(column, spec)` / `lastValue(column, spec)` — 프레임 내 첫/마지막 값.
103
+ - `sumOver(column, spec)` / `avgOver(column, spec)` / `minOver(column, spec)` / `maxOver(column, spec)` window 합/평균/최소/최대(누적합·이동평균 등).
104
+ - `countOver(spec, column?)` — window 행 수. `column` 미지정=전체.
99
105
 
100
106
  ```typescript
101
107
  db.order().select((o) => ({
102
108
  ...o,
103
- rowNum: expr.rowNumber({ partitionBy: [o.userId], orderBy: [[o.createdAt, "DESC"]] }),
104
109
  runningTotal: expr.sumOver(o.amount, { partitionBy: [o.userId], orderBy: [[o.createdAt, "ASC"]] }),
105
110
  }));
106
111
  ```
107
112
 
108
- ## 관련 타입 / 클래스
113
+ ## SwitchExprBuilder
114
+
115
+ `expr.switch<T>()` 반환 객체.
109
116
 
110
- - `class ExprUnit<T>` 표현식 래퍼. `dataType`/`expr`(AST)/`$infer`(타입). `.n` 게터로 non-null 좁히기.
111
- - `class WhereExprUnit` — WHERE 표현식 래퍼(`expr` AST 만).
112
- - `type ExprInput<T> = ExprUnit<T> | T`.
113
- - `interface SwitchExprBuilder<T>` — `expr.switch()` 빌더 인터페이스(`case`/`default`).
117
+ - `case(condition: WhereExprUnit, then: ExprInput<T>)`분기 추가(체이닝).
118
+ - `default(value: ExprInput<T>)` — ELSE + 마무리, `ExprUnit<T>` 반환. case/default 중 최소 하나 non-null 아니면 throw.
119
+
120
+ ```typescript
121
+ grade: expr.switch<string>()
122
+ .case(expr.gte(u.score, 90), "A")
123
+ .case(expr.gte(u.score, 80), "B")
124
+ .default("F"),
125
+ ```