@simplysm/sd-claude 14.0.91 → 14.0.93
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 +7 -6
- package/claude/references/sd-simplysm14/apis/angular/README.md +59 -39
- package/claude/references/sd-simplysm14/apis/angular/controls.md +119 -186
- package/claude/references/sd-simplysm14/apis/angular/crud.md +70 -31
- package/claude/references/sd-simplysm14/apis/angular/directives.md +55 -57
- package/claude/references/sd-simplysm14/apis/angular/features.md +86 -105
- package/claude/references/sd-simplysm14/apis/angular/infra.md +48 -57
- package/claude/references/sd-simplysm14/apis/angular/layout.md +37 -47
- package/claude/references/sd-simplysm14/apis/angular/overlay.md +82 -74
- package/claude/references/sd-simplysm14/apis/angular/routing-appstructure.md +61 -50
- package/claude/references/sd-simplysm14/apis/angular/shared-data.md +74 -57
- package/claude/references/sd-simplysm14/apis/angular/sheet.md +63 -72
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-auto-update/README.md +23 -18
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-file-system/README.md +21 -19
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-intent/README.md +23 -18
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-usb-storage/README.md +72 -32
- package/claude/references/sd-simplysm14/apis/core-browser/README.md +18 -18
- package/claude/references/sd-simplysm14/apis/core-browser/dom-element.md +29 -29
- package/claude/references/sd-simplysm14/apis/core-browser/indexed-db.md +41 -41
- package/claude/references/sd-simplysm14/apis/core-common/README.md +97 -90
- package/claude/references/sd-simplysm14/apis/core-common/async-runtime.md +75 -51
- package/claude/references/sd-simplysm14/apis/core-common/collection-ext.md +81 -0
- package/claude/references/sd-simplysm14/apis/core-common/errors.md +27 -29
- package/claude/references/sd-simplysm14/apis/core-common/obj.md +44 -45
- package/claude/references/sd-simplysm14/apis/core-common/serialization.md +34 -33
- package/claude/references/sd-simplysm14/apis/core-common/value-types.md +86 -0
- package/claude/references/sd-simplysm14/apis/core-node/README.md +6 -6
- package/claude/references/sd-simplysm14/apis/core-node/consola.md +3 -0
- package/claude/references/sd-simplysm14/apis/core-node/cpx.md +2 -2
- package/claude/references/sd-simplysm14/apis/core-node/fs-watcher.md +1 -1
- package/claude/references/sd-simplysm14/apis/core-node/fsx.md +2 -2
- package/claude/references/sd-simplysm14/apis/core-node/worker.md +6 -3
- package/claude/references/sd-simplysm14/apis/excel/README.md +10 -10
- package/claude/references/sd-simplysm14/apis/excel/conditional-format.md +4 -2
- package/claude/references/sd-simplysm14/apis/excel/utils.md +1 -1
- package/claude/references/sd-simplysm14/apis/excel/workbook-worksheet.md +6 -6
- package/claude/references/sd-simplysm14/apis/lint/README.md +6 -32
- package/claude/references/sd-simplysm14/apis/lint/recommended.md +60 -0
- package/claude/references/sd-simplysm14/apis/lint/rules.md +17 -17
- package/claude/references/sd-simplysm14/apis/orm-common/README.md +15 -6
- package/claude/references/sd-simplysm14/apis/orm-common/db-context.md +68 -102
- package/claude/references/sd-simplysm14/apis/orm-common/expr.md +75 -89
- package/claude/references/sd-simplysm14/apis/orm-common/queryable.md +87 -99
- package/claude/references/sd-simplysm14/apis/orm-common/schema.md +110 -147
- package/claude/references/sd-simplysm14/apis/orm-common/types.md +48 -51
- package/claude/references/sd-simplysm14/apis/orm-node/README.md +8 -13
- package/claude/references/sd-simplysm14/apis/orm-node/db-conn.md +5 -5
- package/claude/references/sd-simplysm14/apis/sd-cli/README.md +9 -6
- package/claude/references/sd-simplysm14/apis/sd-cli/SdTsCompiler.md +9 -8
- package/claude/references/sd-simplysm14/apis/sd-cli/sd-config-types.md +23 -19
- package/claude/references/sd-simplysm14/apis/service-client/README.md +20 -12
- package/claude/references/sd-simplysm14/apis/service-client/orm.md +6 -6
- package/claude/references/sd-simplysm14/apis/service-client/transport.md +1 -1
- package/claude/references/sd-simplysm14/apis/service-common/README.md +35 -32
- package/claude/references/sd-simplysm14/apis/service-common/app-structure.md +23 -22
- package/claude/references/sd-simplysm14/apis/service-common/protocol.md +23 -23
- package/claude/references/sd-simplysm14/apis/service-server/README.md +51 -43
- package/claude/references/sd-simplysm14/apis/service-server/service-authoring.md +6 -6
- package/claude/references/sd-simplysm14/apis/service-server/transport-internals.md +31 -21
- package/claude/references/sd-simplysm14/apis/service-server/v1-legacy.md +8 -8
- package/claude/references/sd-simplysm14/apis/storage/README.md +55 -49
- package/claude/references/sd-simplysm14/manuals/client-component.md +843 -740
- package/claude/references/sd-simplysm14/manuals/client-crud.md +8 -0
- package/claude/references/sd-simplysm14/manuals/client-demo.md +6 -16
- package/claude/references/sd-simplysm14/manuals/client-shared-data.md +26 -0
- package/claude/references/sd-simplysm14/manuals/logging.md +1 -1
- package/claude/references/sd-simplysm14/manuals/orm.md +15 -1
- package/claude/rules/sd-design-rules.md +7 -0
- package/claude/sd-system-prompt.md +5 -8
- package/claude/skills/sd-debug/SKILL.md +43 -0
- package/claude/skills/sd-debug/workflow.js +390 -0
- package/claude/skills/sd-demo/SKILL.md +18 -20
- package/claude/skills/sd-dev/SKILL.md +127 -24
- package/claude/skills/sd-docs/SKILL.md +5 -3
- package/claude/skills/sd-docs/references/subagent-prompt.md +2 -3
- package/claude/skills/sd-impl/SKILL.md +18 -18
- package/claude/skills/sd-manual/SKILL.md +1 -0
- package/claude/skills/sd-review/SKILL.md +24 -18
- package/claude/skills/sd-review/workflow.js +324 -0
- package/claude/skills/sd-spec/SKILL.md +96 -679
- package/claude/skills/sd-spec/references/example-spec.md +28 -50
- package/claude/skills/sd-spec/references/format-analyze.md +232 -0
- package/claude/skills/sd-spec/references/format-design.md +248 -0
- package/claude/skills/sd-spec/workflow-analyze.js +615 -0
- package/claude/skills/sd-spec/workflow-design.js +667 -0
- package/claude/skills/sd-unpack/scripts/handlers/office_com.py +5 -1
- package/package.json +1 -1
- package/scripts/postinstall.mjs +157 -18
- package/claude/references/sd-simplysm14/apis/angular/selection-managers.md +0 -68
- package/claude/references/sd-simplysm14/apis/core-common/array-ext.md +0 -77
- package/claude/references/sd-simplysm14/apis/core-common/datetime.md +0 -86
- package/claude/skills/sd-skill/SKILL.md +0 -245
- package/claude/skills/sd-skill/scripts/run_eval.py +0 -380
|
@@ -1,113 +1,85 @@
|
|
|
1
1
|
# @simplysm/orm-common — DbContext / 연결·트랜잭션·DDL·마이그레이션
|
|
2
2
|
|
|
3
|
-
`DbContext` 추상 클래스를 상속해 테이블·뷰·프로시저를 클래스 프로퍼티로 등록하고, 연결·트랜잭션·DDL·마이그레이션을 실행하는 묶음. `DbContextExecutor` 구현체와 `{ database, schema? }` 옵션을
|
|
4
|
-
|
|
5
|
-
> 앱(Angular) 환경에서는 화면이 `DbContext` 를 직접 생성하지 않고 `AppOrmProvider.connectAsync(cb)` 로 감싼다(client-orm.md). `db` 인자가 곧 아래 `DbContext` 인스턴스이므로, 콜백 안의 쿼리 작성법은 동일하다.
|
|
3
|
+
`DbContext` 추상 클래스를 상속해 테이블·뷰·프로시저를 클래스 프로퍼티로 등록하고, 연결·트랜잭션·DDL·마이그레이션을 실행하는 묶음. 생성자에 `DbContextExecutor` 구현체와 `{ database, schema? }` 옵션을 주입한다. 각 프로퍼티가 독립적으로 직렬화되므로 40+ 테이블에서도 TS7056 이 발생하지 않는다. 롤백 중 발생하는 트랜잭션 에러는 `DbTransactionError` 로 표준화된다.
|
|
6
4
|
|
|
7
5
|
## DbContext (abstract class)
|
|
8
6
|
|
|
9
7
|
```typescript
|
|
10
8
|
abstract class DbContext implements DbContextBase {
|
|
11
9
|
constructor(executor: DbContextExecutor, opt: { database: string; schema?: string });
|
|
12
|
-
|
|
13
|
-
status: DbContextStatus; // "ready" | "connect" | "transact"
|
|
10
|
+
status: DbContextStatus; // "ready" | "connect" | "transact"
|
|
14
11
|
get database(): string | undefined;
|
|
15
12
|
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 ...
|
|
13
|
+
migrations: Migration[]; // 서브클래스에서 오버라이드
|
|
28
14
|
}
|
|
29
15
|
```
|
|
30
16
|
|
|
31
|
-
|
|
17
|
+
서브클래스에서 `protected queryable(builder)` / `protected executable(builder)` 로 멤버를 등록한다.
|
|
32
18
|
|
|
33
|
-
-
|
|
34
|
-
-
|
|
35
|
-
-
|
|
36
|
-
- `status
|
|
37
|
-
- `
|
|
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` 참조.
|
|
19
|
+
- `executor`: `DbContextExecutor` — 실제 connect/close/begin/commit/rollback/executeDefs 를 수행하는 어댑터. 서버는 node 구현, 클라이언트는 service-client 구현을 넣는다.
|
|
20
|
+
- `opt.database`: string — 대상 데이터베이스 이름. `database` getter 로 노출.
|
|
21
|
+
- `opt.schema`: string — MSSQL/PostgreSQL 스키마(선택). 미지정 시 dialect 기본값.
|
|
22
|
+
- `status`: `"ready" | "connect" | "transact"` — 현재 연결 단계. "ready"=미연결, "connect"=연결됨(트랜잭션 밖), "transact"=트랜잭션 중. `transact` 상태에서 DDL 실행 시 throw.
|
|
23
|
+
- `migrations`: `Migration[]` — 서브클래스에서 오버라이드하는 마이그레이션 정의 배열. `initialize()` 가 이미 적용된 것을 제외하고 순서대로 실행.
|
|
45
24
|
|
|
46
|
-
|
|
25
|
+
### 멤버 등록 (protected)
|
|
26
|
+
|
|
27
|
+
- `queryable(builder)` — `TableBuilder`/`ViewBuilder` 를 받아 `() => Queryable<...>` 팩토리를 반환. 호출할 때마다 새 alias 가 부여된 Queryable 생성. CUD 는 `TableBuilder` 기반에서만 가능.
|
|
28
|
+
- `executable(builder)` — `ProcedureBuilder` 를 받아 `() => Executable<...>` 팩토리를 반환.
|
|
47
29
|
|
|
48
30
|
```typescript
|
|
49
|
-
class
|
|
31
|
+
class AppDb extends DbContext {
|
|
50
32
|
user = this.queryable(User);
|
|
51
|
-
|
|
52
|
-
getUserById = this.executable(GetUserById);
|
|
53
|
-
override migrations = [{ name: "
|
|
33
|
+
activeUsers = this.queryable(ActiveUsers); // View
|
|
34
|
+
getUserById = this.executable(GetUserById); // Procedure
|
|
35
|
+
override migrations = [{ name: "001_init", up: async (db) => { await db.createTable(User); } }];
|
|
54
36
|
}
|
|
55
|
-
|
|
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
|
-
});
|
|
37
|
+
const db = new AppDb(executor, { database: "mydb" });
|
|
60
38
|
```
|
|
61
39
|
|
|
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>`).
|
|
40
|
+
### 연결·트랜잭션
|
|
70
41
|
|
|
71
|
-
- `
|
|
72
|
-
- `
|
|
73
|
-
- `
|
|
74
|
-
- `
|
|
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
|
|
42
|
+
- `connect(fn, isolationLevel?)` — 연결 → 트랜잭션 시작 → `fn` 실행 → 성공 시 commit, 예외 시 rollback 후 재throw → 최종 close. `ready` 가 아니면 throw. 최초 호출 시 관계 정의를 1회 검증. 업무 단위의 표준 진입점.
|
|
43
|
+
- `connectWithoutTransaction(callback)` — 트랜잭션 없이 연결만 잡고 `callback` 실행 후 close. DDL·초기화처럼 트랜잭션 밖에서 실행해야 하는 작업용.
|
|
44
|
+
- `transaction(fn, isolationLevel?)` — 이미 `connect` 상태에서 추가 트랜잭션 경계를 잡을 때. `transact` 상태면 throw. 성공 시 commit, 예외 시 rollback.
|
|
45
|
+
- `isolationLevel`: `"READ_UNCOMMITTED" | "READ_COMMITTED" | "REPEATABLE_READ" | "SERIALIZABLE"` — 격리 수준(선택). 미지정 시 DB 기본값(보통 READ_COMMITTED). 더티 리드 허용~완전 직렬화 순으로 엄격해짐.
|
|
86
46
|
|
|
87
47
|
```typescript
|
|
88
|
-
|
|
48
|
+
await db.connect(async () => {
|
|
49
|
+
const users = await db.user().where((u) => [expr.eq(u.isActive, true)]).execute();
|
|
50
|
+
await db.user().where((u) => [expr.eq(u.id, 1)]).update((u) => ({ name: "수정" }));
|
|
51
|
+
}); // 콜백 정상 종료 시 commit, throw 시 rollback
|
|
89
52
|
```
|
|
90
53
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
54
|
+
### DDL 실행 메서드 (트랜잭션 밖에서만)
|
|
55
|
+
|
|
56
|
+
각각 `executeDefs` 로 즉시 실행한다. `transact` 상태에서 호출하면 throw.
|
|
94
57
|
|
|
95
|
-
|
|
58
|
+
- `createTable(table)` / `dropTable(name)` / `renameTable(name, newName)` — 테이블 생성/삭제/이름변경.
|
|
59
|
+
- `truncate(name)` — 테이블 비우기(전 행 삭제, identity 리셋).
|
|
60
|
+
- `createView(view)` / `dropView(name)` — 뷰 생성/삭제.
|
|
61
|
+
- `createProc(procedure)` / `dropProc(name)` — 프로시저 생성/삭제.
|
|
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 추가/삭제. `columns` 는 컬럼명 배열(복합 PK).
|
|
64
|
+
- `addForeignKey(table, relationName, relationDef)` / `dropForeignKey(table, relationName)` — FK 추가/삭제. `relationDef` 는 `ForeignKeyBuilder`.
|
|
65
|
+
- `addIndex(table, indexBuilder)` / `dropIndex(table, columns)` — 인덱스 추가/삭제.
|
|
66
|
+
- `clearSchema({ database, schema? })` — 스키마 내 모든 객체 삭제.
|
|
67
|
+
- `schemaExists(database, schema?)` — 스키마 존재 여부 `boolean` 반환.
|
|
68
|
+
- `switchFk(table, enabled)` — FK 제약 활성/비활성 토글. `enabled` true=활성, false=비활성. DDL 이 아니라 `transact` 상태에서도 호출 가능(대량 적재 시 FK 일시 해제 용도).
|
|
69
|
+
- `getQueryDefObjectName(tableOrView)` — 빌더에서 dialect 네임스페이스가 반영된 `QueryDefObjectName` 산출.
|
|
96
70
|
|
|
97
|
-
|
|
98
|
-
- `DbContextStatus` — `"ready" | "connect" | "transact"`. 위 `status` 와 동일 의미.
|
|
99
|
-
- `DbContextDdlMethods` (interface) — 위 DDL 실행 메서드 + QueryDef 생성기 전체를 모은 인터페이스. `Migration.up(db)` 의 `db` 타입이 `DbContextBase & DbContextDdlMethods` 라 마이그레이션 콜백에서 DDL 을 호출할 수 있다.
|
|
71
|
+
### DDL QueryDef 생성기 (실행 없이 def 만)
|
|
100
72
|
|
|
101
|
-
|
|
73
|
+
위 실행 메서드와 1:1 대응하는 `get*QueryDef(...)` 가 모두 있다(`getCreateTableQueryDef`, `getDropTableQueryDef`, `getAddColumnQueryDef`, `getAddForeignKeyQueryDef`, `getTruncateQueryDef`, `getSwitchFkQueryDef`, `getClearSchemaQueryDef`, `getSchemaExistsQueryDef` 등). 실행하지 않고 `QueryDef` AST 만 얻어 배치 실행·검증·SQL 변환에 쓸 때 사용. 단일 `getCreateObjectQueryDef(builder)` 는 Table/View/Procedure 빌더 종류를 보고 알맞은 CREATE def 를 만든다.
|
|
102
74
|
|
|
103
|
-
|
|
75
|
+
### 마이그레이션 / 초기화
|
|
104
76
|
|
|
105
|
-
- `
|
|
106
|
-
- `
|
|
107
|
-
- `
|
|
108
|
-
- `
|
|
77
|
+
- `initialize(options?)` — `migrations` 중 미적용분을 순서대로 실행하고, 적용 여부를 `_migration` 시스템 테이블에 기록. `boolean` 반환(변경 발생 여부 등).
|
|
78
|
+
- `options.dbs`: string[] — 대상 데이터베이스 목록 한정(선택).
|
|
79
|
+
- `options.force`: boolean — true 면 강제 재초기화. 스키마를 다시 깔아야 할 때만 사용.
|
|
80
|
+
- `executeDefs(defs, resultMetas?)` — `QueryDef[]` 를 executor 로 실행해 `T[][]`(def 별 결과) 반환. `transact` 상태에서 DDL 타입이 섞이면 throw. 빌더가 만든 def 를 저수준으로 직접 실행할 때 사용.
|
|
109
81
|
|
|
110
|
-
## Migration
|
|
82
|
+
## Migration (interface)
|
|
111
83
|
|
|
112
84
|
```typescript
|
|
113
85
|
interface Migration {
|
|
@@ -116,47 +88,41 @@ interface Migration {
|
|
|
116
88
|
}
|
|
117
89
|
```
|
|
118
90
|
|
|
119
|
-
- `name
|
|
120
|
-
- `up(db)
|
|
121
|
-
|
|
122
|
-
## IsolationLevel
|
|
123
|
-
|
|
124
|
-
`connect`/`transaction`/`beginTransaction` 의 격리 수준.
|
|
125
|
-
|
|
126
|
-
- `"READ_UNCOMMITTED"` — 커밋 전 데이터까지 읽음(Dirty Read 허용). 가장 느슨, 정합성 낮음.
|
|
127
|
-
- `"READ_COMMITTED"` — 커밋된 데이터만 읽음. 일반적 기본값.
|
|
128
|
-
- `"REPEATABLE_READ"` — 트랜잭션 내 동일 쿼리가 동일 결과 보장.
|
|
129
|
-
- `"SERIALIZABLE"` — 완전 직렬화. 가장 엄격, 경합 시 잠금/충돌 비용 큼.
|
|
91
|
+
- `name`: string — 고유 마이그레이션 식별자. 타임스탬프 접두 권장(`20260105_001_...`). 이 값으로 적용 여부를 추적하므로 한번 배포되면 변경 금지.
|
|
92
|
+
- `up`: `(db) => Promise<void>` — 스키마 변경 함수. `db` 로 DDL 메서드를 호출. 실행은 `initialize()` 가 미적용분만 골라 호출.
|
|
130
93
|
|
|
131
94
|
## DbTransactionError / DbErrorCode
|
|
132
95
|
|
|
133
|
-
DBMS
|
|
96
|
+
DBMS 네이티브 에러를 dialect 독립 코드로 래핑한다. `connect`/`transaction` 의 롤백 단계에서 "이미 롤백되어 활성 트랜잭션이 없음" 같은 상황을 코드로 식별해 무시 여부를 판단할 때 쓴다.
|
|
134
97
|
|
|
135
98
|
```typescript
|
|
136
99
|
class DbTransactionError extends Error {
|
|
137
|
-
readonly name = "DbTransactionError";
|
|
138
100
|
constructor(code: DbErrorCode, message: string, originalError?: unknown);
|
|
139
101
|
readonly code: DbErrorCode;
|
|
140
102
|
readonly originalError?: unknown;
|
|
141
103
|
}
|
|
104
|
+
enum DbErrorCode { NO_ACTIVE_TRANSACTION, TRANSACTION_ALREADY_STARTED, DEADLOCK, LOCK_TIMEOUT }
|
|
142
105
|
```
|
|
143
106
|
|
|
144
|
-
- `code
|
|
145
|
-
- `
|
|
146
|
-
- `
|
|
147
|
-
|
|
148
|
-
`
|
|
149
|
-
|
|
150
|
-
- `NO_ACTIVE_TRANSACTION` — 롤백 대상 활성 트랜잭션 없음. 이미 롤백/커밋된 경우. `connect` 내부에서 이 코드는 무시된다.
|
|
151
|
-
- `TRANSACTION_ALREADY_STARTED` — 트랜잭션이 이미 시작됨(중복 begin).
|
|
152
|
-
- `DEADLOCK` — 데드락 발생. 재시도 정책 트리거로 사용.
|
|
153
|
-
- `LOCK_TIMEOUT` — 잠금 대기 타임아웃.
|
|
107
|
+
- `code`: `DbErrorCode` — 표준화된 에러 종류. 아래 enum literal 로 분기.
|
|
108
|
+
- `originalError`: unknown — 래핑 전 원본 DBMS 에러(디버깅용). dialect 별 원인 추적 시 참조.
|
|
109
|
+
- `NO_ACTIVE_TRANSACTION` — 롤백/커밋할 활성 트랜잭션이 없음. 이미 롤백된 경우 무시 분기에 사용.
|
|
110
|
+
- `TRANSACTION_ALREADY_STARTED` — 트랜잭션이 이미 시작됨(중첩 시작 시도).
|
|
111
|
+
- `DEADLOCK` — 교착 상태로 트랜잭션이 강제 중단됨. 재시도 정책 분기에 사용.
|
|
112
|
+
- `LOCK_TIMEOUT` — 잠금 대기 시간 초과. 재시도/백오프 분기에 사용.
|
|
154
113
|
|
|
155
114
|
```typescript
|
|
156
115
|
try {
|
|
157
|
-
await
|
|
116
|
+
await db.rollbackTransaction();
|
|
158
117
|
} catch (err) {
|
|
159
118
|
if (err instanceof DbTransactionError && err.code === DbErrorCode.NO_ACTIVE_TRANSACTION) return;
|
|
160
119
|
throw err;
|
|
161
120
|
}
|
|
162
121
|
```
|
|
122
|
+
|
|
123
|
+
## DbContextBase / DbContextStatus / DbContextDdlMethods / SD_BUILDER
|
|
124
|
+
|
|
125
|
+
- `DbContextBase` (interface) — `Queryable`/`Executable`/`ViewBuilder` 가 의존하는 컨텍스트 최소 인터페이스(`status`, `database`, `schema`, `getNextAlias`, `resetAliasCounter`, `executeDefs`, `getQueryDefObjectName`, `switchFk`). `DbContext` 가 구현한다. executor·뷰 정의처럼 컨텍스트 전체가 아니라 일부 능력만 요구하는 시그니처에 쓴다.
|
|
126
|
+
- `DbContextStatus` (type) — `"ready" | "connect" | "transact"`. 위 `status` 와 동일.
|
|
127
|
+
- `DbContextDdlMethods` (interface) — DDL 실행 메서드 + `get*QueryDef` 생성기를 모은 인터페이스. `Migration.up` 의 `db` 파라미터 타입(`DbContextBase & DbContextDdlMethods`)에 쓰여, 마이그레이션 함수에서 DDL 만 노출되게 한다.
|
|
128
|
+
- `SD_BUILDER` (symbol) — `queryable()`/`executable()` 가 반환하는 팩토리 함수에 원본 빌더를 매다는 심볼 키. 등록된 멤버에서 원본 `TableBuilder`/`ViewBuilder`/`ProcedureBuilder` 를 역참조해야 할 때(스키마 수집·DDL 자동화 등) 사용.
|
|
@@ -1,125 +1,111 @@
|
|
|
1
1
|
# @simplysm/orm-common — expr (SQL 표현식 빌더)
|
|
2
2
|
|
|
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`)를 다룬다.
|
|
3
|
+
`expr` 객체로 dialect 독립 SQL 표현식을 JSON AST(`Expr`)로 조립한다. dialect 별 QueryBuilder 가 MySQL/MSSQL/PostgreSQL 로 변환. where/having 콜백은 `WhereExprUnit[]`, select/orderBy/groupBy 콜백은 `ExprUnit<T>`, update/upsert/insert/where 비교값은 `ExprInput<T>`(= `ExprUnit<T> | T`)를 다룬다. 비교·쓰기 값은 리터럴을 그대로 넘긴다 — `expr.val` 로 감싸지 말 것(orm.md). `expr.subquery`/`expr.exists` 를 SELECT 절에 넣지 말고 `joinSingle` 로 집계를 부착한다(orm.md).
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## 래퍼 타입
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
.
|
|
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`. 연산 인자·쓰기 값이 받는 타입(리터럴 직접 허용).
|
|
7
|
+
- `ExprUnit<T>` — 타입 안전 표현식 래퍼. `dataType`(`ColumnPrimitiveStr`)·`expr`(`Expr` AST) 보유. getter `n` 은 동일 표현식을 non-nullable 타입(`NonNullable<T>`)으로 다시 래핑(coalesce 후 null 아님이 보장될 때 타입만 좁힐 용도).
|
|
8
|
+
- `WhereExprUnit` — WHERE 절용 래퍼(`WhereExpr` AST 보유). `where`/`having` 콜백 반환 원소.
|
|
9
|
+
- `ExprInput<T>` = `ExprUnit<T> | T` — 표현식 또는 리터럴 둘 다 받는 입력 타입. 비교 target·쓰기 값 자리.
|
|
10
|
+
- `SwitchExprBuilder<T>` — `expr.switch()` 가 반환하는 CASE 빌더(`case`/`default`).
|
|
20
11
|
|
|
21
12
|
## 값 생성
|
|
22
13
|
|
|
23
|
-
- `val(dataType, value)` — 리터럴을 ExprUnit 으로 래핑. `dataType
|
|
24
|
-
- `col(dataType, ...path)` —
|
|
25
|
-
- `raw(dataType)
|
|
26
|
-
- `toExpr(value)` — `ExprInput`
|
|
14
|
+
- `val(dataType, value)` — 리터럴을 `ExprUnit` 으로 래핑. `dataType`=`"string"|"number"|"boolean"|"DateTime"|"DateOnly"|"Time"|"Uuid"|"Buffer"` 등 원시 타입 문자열. `value`=값(undefined 허용 → NULL). `ExprUnit` 이 요구되는 자리(select 의 리터럴 상수 컬럼 등)에서만 사용.
|
|
15
|
+
- `col(dataType, ...path)` — 컬럼 참조 `ExprUnit` 생성. `path`=별칭·컬럼 경로. 보통 콜백의 컬럼 프록시가 대신하므로 내부용.
|
|
16
|
+
- `raw(dataType)\`...\`` — Raw SQL 이스케이프 해치. 태그드 템플릿. 보간 값은 자동 파라미터화. ORM 미지원 DB 함수·UNION 의 타입 명시 NULL(`` expr.raw("number")`NULL` ``)에 사용.
|
|
17
|
+
- `toExpr(value)` — `ExprInput` 을 `Expr` AST 로 변환(내부 헬퍼).
|
|
27
18
|
|
|
28
|
-
## WHERE — 비교 (
|
|
19
|
+
## WHERE — 비교 (`WhereExprUnit` 반환)
|
|
29
20
|
|
|
30
|
-
- `eq(source, target)` —
|
|
21
|
+
- `eq(source, target)` — `=` 비교(NULL 안전: MySQL `<=>`, 그 외 `IS NULL OR =`). NULL 끼리도 일치 판정해야 할 때.
|
|
31
22
|
- `gt(source, target)` / `lt(source, target)` / `gte(source, target)` / `lte(source, target)` — `>` / `<` / `>=` / `<=`.
|
|
32
|
-
- `between(source, from?, to?)` — 범위. `from
|
|
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` 로 부착)
|
|
23
|
+
- `between(source, from?, to?)` — 범위. `from` undefined 면 하한 없음, `to` undefined 면 상한 없음(한쪽만 주면 단방향 부등호).
|
|
24
|
+
- `null(source)` — `IS NULL`. nullable 컬럼의 결측 판정.
|
|
39
25
|
|
|
40
|
-
## WHERE —
|
|
26
|
+
## WHERE — 문자열/IN/논리
|
|
41
27
|
|
|
42
|
-
- `
|
|
43
|
-
- `
|
|
44
|
-
- `
|
|
28
|
+
- `like(source, pattern)` — `LIKE`(% 다수, _ 단일, `\` 이스케이프). 부분/접두/접미 검색.
|
|
29
|
+
- `regexp(source, pattern)` — 정규식 매칭(구문은 DBMS 의존).
|
|
30
|
+
- `in(source, values)` — `IN (값목록)`. `values`=`ExprInput[]`.
|
|
31
|
+
- `inQuery(source, query)` — `IN (SELECT 단일컬럼)`. 서브쿼리가 단일 컬럼 select 가 아니면 throw.
|
|
32
|
+
- `exists(query)` — `EXISTS (...)`. 서브쿼리 SELECT 절은 패킷 절약 위해 제거됨. WHERE 절 존재 검사용(SELECT 절에는 쓰지 말 것).
|
|
33
|
+
- `not(arg)` — 조건 부정.
|
|
34
|
+
- `and(conditions)` / `or(conditions)` — 조건 배열 AND/OR 결합. 빈 배열이면 `ArgumentError`. (`where` 에 배열을 넘기면 자동 AND 이므로 `and` 는 OR 안에서 묶을 때 등에 사용.)
|
|
45
35
|
|
|
46
|
-
|
|
36
|
+
```typescript
|
|
37
|
+
db.user().where((u) => [
|
|
38
|
+
expr.eq(u.status, "active"),
|
|
39
|
+
expr.between(u.age, 18, undefined),
|
|
40
|
+
expr.or([expr.like(u.name, "김%"), expr.like(u.name, "이%")]),
|
|
41
|
+
])
|
|
42
|
+
```
|
|
47
43
|
|
|
48
|
-
|
|
49
|
-
|
|
44
|
+
## SELECT — 문자열 (`ExprUnit` 반환)
|
|
45
|
+
|
|
46
|
+
- `concat(...args)` — `CONCAT`(NULL 은 빈 문자열 처리).
|
|
47
|
+
- `left(source, length)` / `right(source, length)` — 왼쪽/오른쪽 N자 추출.
|
|
50
48
|
- `trim(source)` — 양쪽 공백 제거.
|
|
51
|
-
- `padStart(source, length, fillString)` — LPAD
|
|
49
|
+
- `padStart(source, length, fillString)` — `LPAD`. `length` 도달까지 `fillString` 으로 왼쪽 패딩(주문번호 zero-pad 등).
|
|
52
50
|
- `replace(source, from, to)` — 문자열 치환.
|
|
53
51
|
- `upper(source)` / `lower(source)` — 대/소문자 변환.
|
|
54
52
|
- `length(source)` — 문자 수. `byteLength(source)` — 바이트 수(UTF-8 CJK 3바이트).
|
|
55
|
-
- `substring(source, start, length?)` — 부분 문자열(1
|
|
56
|
-
- `indexOf(source, search)` — 위치(1
|
|
57
|
-
|
|
58
|
-
## SELECT — 숫자 (반환 `ExprUnit`)
|
|
53
|
+
- `substring(source, start, length?)` — 부분 문자열(1부터 시작, `length` 생략 시 끝까지).
|
|
54
|
+
- `indexOf(source, search)` — 위치 찾기(1부터, 없으면 0).
|
|
59
55
|
|
|
60
|
-
|
|
56
|
+
## SELECT — 숫자 / 날짜
|
|
61
57
|
|
|
62
|
-
|
|
58
|
+
- `abs(source)` / `round(source, digits)` / `ceil(source)` / `floor(source)` — 절대값/반올림(`digits`=소수자릿수)/올림/내림.
|
|
59
|
+
- `year`/`month`/`day`/`hour`/`minute`/`second`(source) — 날짜·시간 구성요소 추출(number).
|
|
60
|
+
- `isoWeek(source)` — ISO 8601 주 번호(월요일 시작, 1~53). `isoWeekStartDate(source)` — 해당 주 월요일(DateOnly). `isoYearMonth(source)` — 해당 월 1일(DateOnly).
|
|
61
|
+
- `dateDiff(unit, from, to)` — 날짜 차이(`to - from`). `unit`=`"year"|"month"|"day"|"hour"|"minute"|"second"`.
|
|
62
|
+
- `dateAdd(unit, source, value)` — 날짜 가감(`value` 음수 허용). 결과 타입은 `source` 와 동일.
|
|
63
|
+
- `formatDate(source, format)` — 날짜 포맷 문자열(포맷 구문 DBMS 의존, 예 `"%Y-%m-%d"`).
|
|
63
64
|
|
|
64
|
-
|
|
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 의존).
|
|
65
|
+
## SELECT — 조건
|
|
70
66
|
|
|
71
|
-
|
|
67
|
+
- `coalesce(...args)` — 첫 non-null 값(`COALESCE`). 마지막 인자가 non-nullable 이면 결과도 non-nullable 로 추론.
|
|
68
|
+
- `nullIf(source, value)` — `source === value` 면 NULL, 아니면 source(빈 문자열 → NULL 변환 등).
|
|
69
|
+
- `is(condition)` — `WhereExprUnit` 을 boolean `ExprUnit` 으로 변환(조건 결과를 컬럼으로). select 절에서 도메인 boolean 컬럼 만들 때.
|
|
70
|
+
- `switch<T>()` — CASE WHEN 빌더(`SwitchExprBuilder`). `case(condition, then)` 체이닝 후 `default(value)` 로 종료. then/default 의 타입에서 결과 타입 추론(모두 리터럴이면 non-null 하나에서 추론, 전부 null 이면 throw).
|
|
71
|
+
- `if(condition, then, else_)` — 삼항(IIF/IF). then/else 중 ExprUnit 또는 non-null 리터럴에서 타입 추론.
|
|
72
72
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
## SELECT — 집계 (반환 `ExprUnit`)
|
|
80
|
-
|
|
81
|
-
NULL 값 행은 무시, 전부 NULL/무행이면 NULL.
|
|
73
|
+
```typescript
|
|
74
|
+
db.user().select((u) => ({
|
|
75
|
+
isActive: expr.is(expr.eq(u.status, "active")),
|
|
76
|
+
grade: expr.switch<string>().case(expr.gte(u.score, 90), "A").case(expr.gte(u.score, 80), "B").default("F"),
|
|
77
|
+
}))
|
|
78
|
+
```
|
|
82
79
|
|
|
83
|
-
|
|
84
|
-
- `sum(arg)` / `avg(arg)` — 합/평균(number, 결과 nullable).
|
|
85
|
-
- `max(arg)` / `min(arg)` — 최대/최소(결과 nullable).
|
|
80
|
+
## SELECT — 집계 / 기타
|
|
86
81
|
|
|
87
|
-
|
|
82
|
+
집계는 NULL 값 행을 무시하고, 모든 값이 NULL 이거나 행이 없을 때만 NULL 반환.
|
|
88
83
|
|
|
89
|
-
- `
|
|
90
|
-
- `
|
|
91
|
-
- `
|
|
92
|
-
- `
|
|
84
|
+
- `count(arg?, distinct?)` — `COUNT`. `arg` 생략 시 전체 행, 지정 시 그 컬럼의 non-null 행. `distinct` true 면 중복 제거 카운트.
|
|
85
|
+
- `sum(arg)` / `avg(arg)` — 합계/평균(number, NULL 가능).
|
|
86
|
+
- `max(arg)` / `min(arg)` — 최대/최소(타입 유지, NULL 가능).
|
|
87
|
+
- `greatest(...args)` / `least(...args)` — 인자들 중 최대/최소값(행 단위, 집계 아님).
|
|
88
|
+
- `rowNum()` — 단순 행 순번(1부터). `random()` — 0~1 난수(무작위 정렬 `orderBy(() => expr.random())`).
|
|
89
|
+
- `cast(source, targetType)` — 타입 변환. `targetType`=`DataType`(예 `{ type: "varchar", length: 20 }`).
|
|
90
|
+
- `subquery(dataType, queryable)` — 스칼라 서브쿼리(단일 행·단일 컬럼). SELECT 절에서 단일 값 반환. (행마다 N회 실행되므로 집계는 `joinSingle` 권장, orm.md.)
|
|
93
91
|
|
|
94
|
-
## SELECT —
|
|
92
|
+
## SELECT — 윈도우 함수
|
|
95
93
|
|
|
96
|
-
모두 `spec: { partitionBy?: ExprInput[]; orderBy?: [ExprInput, ("ASC"|"DESC")?][] }`(
|
|
94
|
+
모두 `spec: { partitionBy?: ExprInput[]; orderBy?: [ExprInput, ("ASC"|"DESC")?][] }` 를 받는다(`partitionBy`=구간 분할 컬럼, `orderBy`=구간 내 정렬).
|
|
97
95
|
|
|
98
|
-
- `rowNumber(spec)` — 파티션 내 순번
|
|
99
|
-
- `rank(spec)` —
|
|
100
|
-
- `ntile(n, spec)` — 파티션을 n 그룹으로
|
|
101
|
-
- `lag(column, spec, options?)` / `lead(column, spec, options?)` — 이전/다음 행 값. `options.offset
|
|
96
|
+
- `rowNumber(spec)` — `ROW_NUMBER()`(파티션 내 1부터 순번).
|
|
97
|
+
- `rank(spec)` — `RANK()`(동순위 후 건너뜀: 1,1,3). `denseRank(spec)` — `DENSE_RANK()`(연속: 1,1,2).
|
|
98
|
+
- `ntile(n, spec)` — `NTILE(n)`(파티션을 `n` 그룹으로 분할, 1~n).
|
|
99
|
+
- `lag(column, spec, options?)` / `lead(column, spec, options?)` — 이전/다음 행 값. `options.offset`(기본 1)·`options.default`(이전/다음 행 없을 때 기본값).
|
|
102
100
|
- `firstValue(column, spec)` / `lastValue(column, spec)` — 프레임 내 첫/마지막 값.
|
|
103
|
-
- `sumOver
|
|
104
|
-
- `countOver(spec, column?)` —
|
|
101
|
+
- `sumOver`/`avgOver`(column, spec) — 윈도우 합계/평균(누적합·이동평균).
|
|
102
|
+
- `countOver(spec, column?)` — 윈도우 카운트(`column` 생략 시 전체 행).
|
|
103
|
+
- `minOver`/`maxOver`(column, spec) — 윈도우 최소/최대.
|
|
105
104
|
|
|
106
105
|
```typescript
|
|
107
106
|
db.order().select((o) => ({
|
|
108
107
|
...o,
|
|
108
|
+
rowNum: expr.rowNumber({ partitionBy: [o.userId], orderBy: [[o.createdAt, "DESC"]] }),
|
|
109
109
|
runningTotal: expr.sumOver(o.amount, { partitionBy: [o.userId], orderBy: [[o.createdAt, "ASC"]] }),
|
|
110
|
-
}))
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
## SwitchExprBuilder
|
|
114
|
-
|
|
115
|
-
`expr.switch<T>()` 반환 객체.
|
|
116
|
-
|
|
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"),
|
|
110
|
+
}))
|
|
125
111
|
```
|