@simplysm/sd-claude 14.0.82 → 14.0.83

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 (87) hide show
  1. package/claude/references/sd-requirement-source-handling.md +20 -20
  2. package/claude/references/sd-simplysm14/README.md +13 -13
  3. package/claude/references/sd-simplysm14/manuals/client-component.md +92 -92
  4. package/claude/references/sd-simplysm14/manuals/client-crud.md +11 -11
  5. package/claude/references/sd-simplysm14/manuals/client-demo.md +28 -28
  6. package/claude/references/sd-simplysm14/manuals/client-rules.md +1 -1
  7. package/claude/references/sd-simplysm14/manuals/client-setup.md +21 -21
  8. package/claude/references/sd-simplysm14/manuals/client-tab.md +3 -3
  9. package/claude/references/sd-simplysm14/manuals/logging.md +15 -15
  10. package/claude/references/sd-simplysm14/manuals/orm-union.md +6 -6
  11. package/claude/references/sd-simplysm14/manuals/orm.md +19 -19
  12. package/claude/references/sd-simplysm14/manuals/test.md +33 -33
  13. package/claude/rules/sd-base-rules.md +44 -43
  14. package/claude/rules/sd-design-rules.md +18 -18
  15. package/claude/skills/sd-commit/SKILL.md +10 -10
  16. package/claude/skills/sd-config/SKILL.md +2 -2
  17. package/claude/skills/sd-demo/SKILL.md +45 -45
  18. package/claude/skills/sd-dev/SKILL.md +15 -15
  19. package/claude/skills/sd-docs/SKILL.md +7 -7
  20. package/claude/skills/sd-docs/references/subagent-prompt.md +33 -33
  21. package/claude/skills/sd-impl/SKILL.md +60 -60
  22. package/claude/skills/sd-review/SKILL.md +9 -9
  23. package/claude/skills/sd-skill/SKILL.md +74 -74
  24. package/claude/skills/sd-skill/evals/fixtures/existing-skill/.claude/skills/todo-format/SKILL.md +1 -1
  25. package/claude/skills/sd-spec/SKILL.md +355 -319
  26. package/claude/skills/sd-spec/references/example-spec.md +104 -104
  27. package/claude/skills/sd-unpack/SKILL.md +34 -34
  28. package/claude/skills/sd-use/SKILL.md +4 -4
  29. package/package.json +1 -1
  30. package/claude/references/sd-simplysm14/apis/angular/README.md +0 -37
  31. package/claude/references/sd-simplysm14/apis/angular/app-structure.md +0 -92
  32. package/claude/references/sd-simplysm14/apis/angular/buttons.md +0 -88
  33. package/claude/references/sd-simplysm14/apis/angular/crud.md +0 -100
  34. package/claude/references/sd-simplysm14/apis/angular/forms.md +0 -200
  35. package/claude/references/sd-simplysm14/apis/angular/infrastructure.md +0 -231
  36. package/claude/references/sd-simplysm14/apis/angular/kanban.md +0 -80
  37. package/claude/references/sd-simplysm14/apis/angular/layout.md +0 -92
  38. package/claude/references/sd-simplysm14/apis/angular/modal.md +0 -115
  39. package/claude/references/sd-simplysm14/apis/angular/routing.md +0 -107
  40. package/claude/references/sd-simplysm14/apis/angular/select-dropdown.md +0 -35
  41. package/claude/references/sd-simplysm14/apis/angular/selection-managers.md +0 -82
  42. package/claude/references/sd-simplysm14/apis/angular/shared-data.md +0 -134
  43. package/claude/references/sd-simplysm14/apis/angular/sheet.md +0 -127
  44. package/claude/references/sd-simplysm14/apis/angular/toast.md +0 -97
  45. package/claude/references/sd-simplysm14/apis/angular/visual.md +0 -167
  46. package/claude/references/sd-simplysm14/apis/capacitor-plugin-auto-update/README.md +0 -79
  47. package/claude/references/sd-simplysm14/apis/capacitor-plugin-file-system/README.md +0 -83
  48. package/claude/references/sd-simplysm14/apis/capacitor-plugin-intent/README.md +0 -91
  49. package/claude/references/sd-simplysm14/apis/capacitor-plugin-usb-storage/README.md +0 -49
  50. package/claude/references/sd-simplysm14/apis/core-browser/README.md +0 -143
  51. package/claude/references/sd-simplysm14/apis/core-common/README.md +0 -58
  52. package/claude/references/sd-simplysm14/apis/core-common/extensions.md +0 -88
  53. package/claude/references/sd-simplysm14/apis/core-common/features.md +0 -51
  54. package/claude/references/sd-simplysm14/apis/core-common/types.md +0 -88
  55. package/claude/references/sd-simplysm14/apis/core-common/utils.md +0 -189
  56. package/claude/references/sd-simplysm14/apis/core-node/README.md +0 -12
  57. package/claude/references/sd-simplysm14/apis/core-node/consola.md +0 -59
  58. package/claude/references/sd-simplysm14/apis/core-node/cpx.md +0 -44
  59. package/claude/references/sd-simplysm14/apis/core-node/fs-watcher.md +0 -42
  60. package/claude/references/sd-simplysm14/apis/core-node/fsx.md +0 -53
  61. package/claude/references/sd-simplysm14/apis/core-node/pathx.md +0 -24
  62. package/claude/references/sd-simplysm14/apis/core-node/worker.md +0 -65
  63. package/claude/references/sd-simplysm14/apis/excel/README.md +0 -193
  64. package/claude/references/sd-simplysm14/apis/lint/README.md +0 -94
  65. package/claude/references/sd-simplysm14/apis/orm-common/README.md +0 -58
  66. package/claude/references/sd-simplysm14/apis/orm-common/db-context.md +0 -77
  67. package/claude/references/sd-simplysm14/apis/orm-common/executable.md +0 -20
  68. package/claude/references/sd-simplysm14/apis/orm-common/expr.md +0 -92
  69. package/claude/references/sd-simplysm14/apis/orm-common/queryable.md +0 -98
  70. package/claude/references/sd-simplysm14/apis/orm-common/schema-builders.md +0 -128
  71. package/claude/references/sd-simplysm14/apis/orm-node/README.md +0 -69
  72. package/claude/references/sd-simplysm14/apis/sd-claude/README.md +0 -32
  73. package/claude/references/sd-simplysm14/apis/sd-cli/README.md +0 -80
  74. package/claude/references/sd-simplysm14/apis/sd-cli/sd-config.md +0 -155
  75. package/claude/references/sd-simplysm14/apis/service-client/README.md +0 -131
  76. package/claude/references/sd-simplysm14/apis/service-common/README.md +0 -29
  77. package/claude/references/sd-simplysm14/apis/service-common/app-structure.md +0 -63
  78. package/claude/references/sd-simplysm14/apis/service-common/messages.md +0 -56
  79. package/claude/references/sd-simplysm14/apis/service-common/protocol.md +0 -64
  80. package/claude/references/sd-simplysm14/apis/service-common/service-types.md +0 -43
  81. package/claude/references/sd-simplysm14/apis/service-server/README.md +0 -13
  82. package/claude/references/sd-simplysm14/apis/service-server/auth.md +0 -39
  83. package/claude/references/sd-simplysm14/apis/service-server/builtin-services.md +0 -71
  84. package/claude/references/sd-simplysm14/apis/service-server/define-service.md +0 -55
  85. package/claude/references/sd-simplysm14/apis/service-server/internals.md +0 -82
  86. package/claude/references/sd-simplysm14/apis/service-server/server.md +0 -57
  87. package/claude/references/sd-simplysm14/apis/storage/README.md +0 -71
@@ -1,58 +0,0 @@
1
- # @simplysm/orm-common
2
-
3
- Dialect 독립 ORM 코어. `DbContext` 상속으로 테이블/뷰/프로시저를 등록하고, fluent builder + Expr AST 로 쿼리를 구성하면, 각 DBMS(MySQL/MSSQL/PostgreSQL) QueryBuilder 가 SQL 로 렌더한다. 실제 connect/execute 는 외부 executor 가 구현 (서버=`@simplysm/orm-node`, 클라이언트=`@simplysm/service-client` 의 OrmServiceClient).
4
-
5
- ## 사용 트리거 인덱스
6
-
7
- - **`DbContext` (abstract class)** — DB 1개에 매핑되는 서브클래스를 만들 때. `protected queryable(Builder)` / `executable(Builder)` 로 테이블·뷰·프로시저를 인스턴스 프로퍼티로 등록, `connect()`/`transaction()` 로 실행 경계 잡고, DDL/`initialize()` 로 스키마 만들 때. 자세히: [db-context.md](./db-context.md)
8
- - **Schema Builders** — `Table(name)`, `View(name)`, `Procedure(name)` 로 스키마 객체 정의할 때. Column / Index / Relation factory 포함. 자세히: [schema-builders.md](./schema-builders.md)
9
- - **`Queryable` / `queryable()`** — `DbContext` 에 등록된 테이블/뷰에서 SELECT/INSERT/UPDATE/DELETE/UPSERT 빌더 체이닝, JOIN/include/recursive CTE/UNION/search 할 때. 자세히: [queryable.md](./queryable.md)
10
- - **`Executable` / `executable()`** — 등록된 프로시저 호출 결과 받을 때. 자세히: [executable.md](./executable.md)
11
- - **`expr` namespace + `ExprUnit`/`WhereExprUnit`** — `where`/`select`/`groupBy`/`having`/`update` 콜백 안에서 비교·논리·문자열·날짜·집계·윈도우·CASE·subquery 등 SQL 표현식 만들 때. dialect 독립 AST. 자세히: [expr.md](./expr.md)
12
- - **`parseSearchQuery(text)`** — `Queryable.search()` 내부에서 쓰는 OR/`+`AND/`-`NOT/`"…"`/`*` 구문 파서. 직접 LIKE 패턴이 필요할 때만 외부 사용. (`ParsedSearchQuery` = `{ or, must, not }`)
13
- - **`createQueryBuilder(dialect)`** — `Dialect` 문자열로 dialect 별 QueryBuilder 인스턴스 받을 때 (executor 진입점).
14
- - **`QueryBuilderBase` / `ExprRendererBase`** — 커스텀 dialect 구현을 위해 상속 베이스 필요할 때.
15
- - **`MysqlQueryBuilder` / `MssqlQueryBuilder` / `PostgresqlQueryBuilder`** (와 대응 `*ExprRenderer`) — 특정 dialect 인스턴스를 직접 new 하거나 `instanceof` 분기할 때. 일반은 `createQueryBuilder` 사용.
16
- - **`QueryDef` (union) + `QueryDefObjectName` (`./types/query-def`)** — executor 가 받는 query AST 의 union 타입 / 모든 DDL/DML 이 공통으로 쓰는 `{database?, schema?, name}` 형태의 DB 객체 식별자.
17
- - **`SelectQueryDef`, `InsertQueryDef`, `InsertIfNotExistsQueryDef`, `InsertIntoQueryDef`, `UpdateQueryDef`, `DeleteQueryDef`, `UpsertQueryDef`, `SelectQueryDefJoin`, `CudOutputDef`** — DML AST 노드를 직접 만들거나 검사할 때 (executor·테스트).
18
- - **DDL QueryDef (`Create*` / `Drop*` / `Rename*` / `Add*` / `Modify*` / `Truncate*` / `Clear*` / `Schema*` / `ExecProc*` 등)** — 스키마 변경/프로시저 호출 AST 를 직접 다룰 때 (`getXxxQueryDef()` 반환 타입과 일치).
19
- - **`DDL_TYPES` (배열) / `DdlType` (union)** — query 가 DDL 인지 런타임/타입 레벨에서 검사할 때. 트랜잭션 내 DDL 차단 가드에서 사용.
20
- - **`Expr` (union) / `WhereExpr` (union)** — SELECT·ORDER BY·SET 콜백이 모두 받는 일반 표현식 AST 와, WHERE·HAVING 전용 boolean 표현식 AST. ExprRenderer 가 dispatch 하는 대상.
21
- - **개별 Expr 노드 (`ExprColumn`, `ExprValue`, `ExprRaw`, `ExprEq`, `ExprLike`, `ExprConcat`, `ExprDateDiff`, `ExprSwitch`, `ExprCount`, `ExprWindow`, `ExprSubquery` …)** — Expr renderer 구현, AST 검사, 디버깅 시 개별 노드 타입 필요할 때. 응용 코드는 `expr.*` 헬퍼만 사용.
22
- - **`WinFn` (union) / `WinSpec` / `WinFn*` 개별 노드** — Window 함수 AST 분기 (`rowNumber`, `rank`, `lag`, `sumOver` 등) 를 직접 처리할 때.
23
- - **`DateUnit`** — `dateDiff`/`dateAdd` 의 단위 union (`"year" | "month" | "day" | "hour" | "minute" | "second"`). 동적으로 단위 선택할 때.
24
- - **`DataType` (`./types/column`)** — SQL 타입 union (`{type:"int"}` / `{type:"varchar",length}` / `{type:"decimal",precision,scale?}` ...). DDL/cast 의 타입 인자.
25
- - **`ColumnPrimitive` / `ColumnPrimitiveStr` / `ColumnPrimitiveMap`** — Column 값으로 허용되는 TS 타입 union (`string|number|boolean|DateTime|DateOnly|Time|Uuid|Bytes|undefined`), 그 키 이름 union, 키→타입 매핑. ExprUnit/ResultMeta 가 사용.
26
- - **`ColumnMeta`** — `ColumnBuilder.meta` 의 형태 (`{type, dataType, autoIncrement?, nullable?, default?, description?}`). 외부에서 column 정의를 읽어 DDL 만들 때.
27
- - **`dataTypeStrToColumnPrimitiveStr`** — `DataType.type` → `ColumnPrimitiveStr` 상수 매핑. cast 결과 dataType 추론에 사용.
28
- - **`InferColumnPrimitiveFromDataType<T>`** — `DataType` 타입에서 TS 값 타입 추론 (제네릭 타입 유틸).
29
- - **`inferColumnPrimitiveStr(value)`** — 런타임 값에서 `ColumnPrimitiveStr` 추론. NULL/unknown 이면 throw.
30
- - **`Dialect`** — `"mysql" | "mssql" | "postgresql"` union. dialect 분기/`createQueryBuilder` 인자.
31
- - **`dialects`** — `Dialect[]` 상수 배열. 테스트의 `it.each(dialects)` 또는 모든 dialect 순회용.
32
- - **`DataRecord`** — query 결과 row 의 재귀 타입 (`{ [key]: ColumnPrimitive | DataRecord | DataRecord[] }`). Queryable/Executable 의 결과 제약.
33
- - **`DbContextExecutor`** — 외부에서 DbContext 에 주입할 executor 인터페이스 (`connect`/`close`/`beginTransaction`/`commitTransaction`/`rollbackTransaction`/`executeDefs`). 신규 dialect/원격 executor 구현 시.
34
- - **`ResultMeta`** — `executeDefs` 가 받는 `{columns: Record<string,ColumnPrimitiveStr>, joins: Record<string,{isSingle}>}`. raw row → 타입 변환·JOIN 그룹핑에 필요.
35
- - **`IsolationLevel`** — `"READ_UNCOMMITTED" | "READ_COMMITTED" | "REPEATABLE_READ" | "SERIALIZABLE"`. `connect`/`transaction` 인자.
36
- - **`Migration`** — `{name, up(db)}`. DbContext 서브클래스의 `migrations` 프로퍼티 타입. `initialize()` 가 적용.
37
- - **`QueryBuildResult`** — `QueryBuilder.build()` 반환 (`{sql, resultSetIndex?, resultSetStride?}`). executor 가 `pickResultSets` 로 좁힐 때 필요.
38
- - **`DbContextBase` (`./types/db-context-def`)** — DbContext 의 코어 인터페이스 (`status`/`database`/`schema`/`executeDefs`/`getNextAlias` 등). Queryable·Executable·ViewBuilder 가 의존하므로 mock/대체 구현 시 사용.
39
- - **`DbContextStatus`** — `"ready" | "connect" | "transact"`. status 분기 시.
40
- - **`DbContextDdlMethods`** — `createTable`/`addColumn`/`addForeignKey` 등 DDL 메서드 집합 인터페이스. `Migration.up` 의 db 인자 타입.
41
- - **`DbTransactionError`** — executor 가 트랜잭션 에러를 표준화해 throw 하는 클래스. 호출측은 `instanceof DbTransactionError` 로 분기.
42
- - **`DbErrorCode`** — `NO_ACTIVE_TRANSACTION` / `TRANSACTION_ALREADY_STARTED` / `DEADLOCK` / `LOCK_TIMEOUT` enum. `err.code === DbErrorCode.DEADLOCK` 같은 분기에 사용.
43
- - **`parseQueryResult(rows, meta)` (`./utils/result-parser`)** — flat row 배열 + `ResultMeta` → 타입 변환 + JOIN 그룹핑된 중첩 객체 배열. async. 빈 결과면 undefined. executor 가 SELECT/OUTPUT 결과를 사용자 객체로 가공할 때.
44
- - **`pickResultSets(rawResults, buildResult)` (`./utils/pick-result-sets`)** — `QueryBuildResult` 의 `resultSetIndex`/`resultSetStride` 따라 여러 결과 셋 중 필요한 셋만 추출/concat. MySQL 배치 INSERT 의 OUTPUT SELECT 만 모을 때.
45
- - **`_Migration`** — `_migration(code PK varchar(255))` 시스템 테이블의 TableBuilder. DbContext 가 자동 등록, 사용자 직접 import 불필요.
46
- - **`SD_BUILDER`** — `queryable()`/`executable()` 팩토리 함수에 builder 를 부착하는 심볼. `initialize()` 가 DbContext 의 프로퍼티에서 builder 를 회수할 때 사용. 사용자 코드 직접 사용 X.
47
-
48
- ## QueryBuilder (인라인)
49
-
50
- ```ts
51
- import { createQueryBuilder } from "@simplysm/orm-common";
52
- const qb = createQueryBuilder("mysql"); // | "mssql" | "postgresql"
53
- const { sql, resultSetIndex, resultSetStride } = qb.build(queryDef);
54
- ```
55
-
56
- `QueryBuilderBase.build(def)` 가 `def.type` 으로 동적 dispatch 하여 dialect 별 메서드 호출. 결과는 `QueryBuildResult { sql; resultSetIndex?; resultSetStride? }` — 여러 result set 이 돌아오는 dialect 별 패턴(MySQL OUTPUT INSERT 등)을 위해 추출 인덱스/스트라이드 동봉. executor 는 받은 raw set 배열을 `pickResultSets(raw, buildResult)` 로 좁힌다.
57
-
58
- `createQueryBuilder(dialect)` 외에 dialect 클래스(`MysqlQueryBuilder`/`MssqlQueryBuilder`/`PostgresqlQueryBuilder` 와 대응 `*ExprRenderer`)도 export. 일반적으로 `createQueryBuilder` 만 쓰면 충분, 커스텀 확장 시 `QueryBuilderBase`/`ExprRendererBase` 상속.
@@ -1,77 +0,0 @@
1
- # @simplysm/orm-common — DbContext
2
-
3
- DB 1개에 대응하는 추상 클래스. 서브클래싱하여 테이블/뷰/프로시저를 인스턴스 프로퍼티로 등록하고, connect/transaction/DDL/initialize 진입점을 제공한다. 실제 SQL 실행은 생성자에 주입된 `DbContextExecutor` 가 담당.
4
-
5
- ## 생성·등록
6
-
7
- ```ts
8
- class MainDb extends DbContext {
9
- user = this.queryable(User); // → () => Queryable<User.$inferSelect, typeof User>
10
- vUser = this.queryable(UserSummary); // View 도 동일
11
- getUserById = this.executable(GetUserById); // → () => Executable<TParams, TReturns>
12
-
13
- migrations = [
14
- { name: "001-init", up: async (db) => { await db.createTable(User); } },
15
- ];
16
- }
17
-
18
- const db = new MainDb(executor, { database: "mydb", schema: "dbo" });
19
- ```
20
-
21
- - `protected queryable(builder)`: `TableBuilder | ViewBuilder` 를 받아 호출시마다 새 alias 가 할당된 `Queryable` 을 만드는 팩토리 함수를 반환. 반환 함수에는 `SD_BUILDER` 심볼로 원본 builder 가 부착됨 (initialize 가 회수).
22
- - `protected executable(builder)`: `ProcedureBuilder` → `Executable` 팩토리. 동일하게 `SD_BUILDER` 부착.
23
- - `_migration` 프로퍼티: 시스템 마이그레이션 테이블(`_migration(code PK varchar(255))`) 이 자동 등록됨.
24
-
25
- ## 연결 / 트랜잭션
26
-
27
- ```ts
28
- await db.connect(async () => { ... }); // connect + tx (auto commit/rollback)
29
- await db.connect(async () => { ... }, "REPEATABLE_READ"); // isolation level
30
- await db.connectWithoutTransaction(async () => { ... }); // connect only
31
- await db.transaction(async () => { ... }); // 이미 connect 인 상태에서 tx 만
32
- ```
33
-
34
- - `status: "ready" | "connect" | "transact"`. 잘못된 진입(중복 connect, 중복 tx)은 throw.
35
- - `connect()` 진입시 1회 `validateRelationsImpl` 호출 (relation 무결성 검사 — 잘못된 FK 정의는 여기서 throw).
36
- - 본문 throw 시 자동 rollback → `_executor.close()` 후 status `ready` 복귀. rollback 중 `DbTransactionError(NO_ACTIVE_TRANSACTION)` 는 무시.
37
- - `transaction()` 단독은 `status==="connect"` 일 때만. 이미 transact 면 throw.
38
- - `executeDefs(defs, resultMetas?)`: `_executor.executeDefs` 위임. `status==="transact"` 중 DDL 포함 시 throw.
39
-
40
- ## DDL 실행
41
-
42
- `createTable`, `dropTable`, `renameTable`, `createView`, `dropView`, `createProc`, `dropProc`, `addColumn`, `dropColumn`, `modifyColumn`, `renameColumn`, `addPrimaryKey`, `dropPrimaryKey`, `addForeignKey`, `addIndex`, `dropForeignKey`, `dropIndex`, `clearSchema({database, schema?})`, `schemaExists(database, schema?): Promise<boolean>`, `truncate(table)`, `switchFk(table, enabled)`.
43
-
44
- 각각 `executeDefs([...QueryDef])` 로 1건씩 실행. 트랜잭션 내에서는 `switchFk` 외 모두 차단(`executeDefs` 에서 검사).
45
-
46
- 대응 `getXxxQueryDef(...)` 형태의 *생성기* 메서드도 동일 시그니처로 제공 (실행 없이 `QueryDef` 만 반환). `initialize()` 가 배치 DDL 을 모을 때 사용.
47
-
48
- `getCreateObjectQueryDef(builder)` — Table/View/Procedure 중 무엇이든 받아 알맞은 create DDL 반환.
49
-
50
- ## initialize
51
-
52
- ```ts
53
- await db.initialize(); // 미적용 migration 만 실행
54
- await db.initialize({ dbs: ["a", "b"] }); // 다중 DB
55
- await db.initialize({ force: true }); // 스키마 clear + 전체 재생성 + 모든 migration 을 "적용됨" 등록
56
- ```
57
-
58
- 반환값: 실행된 migration 이 있으면 `true`, 아니면 `false`.
59
-
60
- 동작:
61
- - `force=true`: `clearSchema` → DbContext 의 모든 등록 객체(`queryable`/`executable` 프로퍼티에서 `SD_BUILDER` 로 회수) create → `_Migration` 에 모든 migration name 등록 → `false`.
62
- - `force=false`:
63
- - `_Migration` 테이블 없음 = 신규 DB → 전체 create + 모든 migration 등록 → `false`.
64
- - 있음 → 미적용 migration 만 순차 실행 → 실행분 있으면 `true`.
65
-
66
- 서브클래스가 `migrations: Migration[]` 를 오버라이드해 `{ name, up(db) }` 목록 제공.
67
-
68
- ## 헬퍼
69
-
70
- - `database`/`schema` getter — 생성자 옵션 노출.
71
- - `getNextAlias(): string` — `T1`, `T2`, ... alias 카운터. `connect`/`connectWithoutTransaction` 진입시 reset.
72
- - `resetAliasCounter()`.
73
- - `getQueryDefObjectName(tableOrView)` — Table/View 메타에서 `{database, schema, name}` 산출 (없으면 DbContext 옵션 fallback).
74
-
75
- ## 인터페이스
76
-
77
- 외부에서 DbContext 를 의존성으로 다룰 때는 `DbContextBase`(코어) + `DbContextDdlMethods`(DDL) 인터페이스 사용 (`./types/db-context-def`). `DbContext` 가 둘 다 구현.
@@ -1,20 +0,0 @@
1
- # @simplysm/orm-common — Executable
2
-
3
- 저장 프로시저 호출 래퍼. `DbContext.executable(builder)` 가 만든 팩토리 호출(`db.getUserById()`)마다 새 인스턴스 반환.
4
-
5
- ```ts
6
- class Executable<TParams extends ColumnBuilderRecord, TReturns extends ColumnBuilderRecord> {
7
- getExecProcQueryDef(params?: InferColumnExprs<TParams>): ExecProcQueryDef
8
- async execute(params: InferColumnExprs<TParams>): Promise<InferColumnExprs<TReturns>[][]>
9
- }
10
- ```
11
-
12
- - `params` 의 각 값은 `ExprInput<T>` (= `ExprUnit<T> | T`). 리터럴이면 `expr.val(meta.type, value)` 로 자동 래핑.
13
- - 프로시저에 `params` 가 정의되지 않은 builder 에 인자를 넘기면 throw.
14
- - 반환은 결과 셋의 배열 (프로시저가 여러 SELECT 를 반환할 수 있음).
15
-
16
- ```ts
17
- const [users] = await db.getUserById().execute({ userId: 1 });
18
- ```
19
-
20
- `executable(db, builder)` — 팩토리. `DbContext.executable` 의 내부 구현이며, `SD_BUILDER` 심볼로 builder 를 부착해야 `initialize()` 가 회수할 수 있다 (직접 쓰지 말고 `DbContext.executable` 사용 권장).
@@ -1,92 +0,0 @@
1
- # @simplysm/orm-common — expr
2
-
3
- Dialect 독립 SQL 표현식 빌더. SQL 문자열 대신 JSON AST(`Expr`/`WhereExpr`) 를 만들어 `Queryable` 메타에 누적되고, QueryBuilder 가 DBMS 별로 렌더.
4
-
5
- ## 래퍼
6
-
7
- - `ExprUnit<T extends ColumnPrimitive>` — `{ dataType: ColumnPrimitiveStr, expr: Expr }`. `.n` 게터로 `NonNullable<T>` 로 cast.
8
- - `WhereExprUnit` — boolean 컨텍스트 (`where`/`having`/논리 연산자) 전용.
9
- - `ExprInput<T> = ExprUnit<T> | T` — 리터럴도 받는 입력 타입.
10
- - `expr.toExpr(value)` / `toExpr(value)` 헬퍼 — `ExprUnit` 이면 풀고, 아니면 `{type:"value", value}` 로 감쌈.
11
-
12
- ## 카테고리별 API
13
-
14
- ### 값 / 컬럼 / Raw
15
- - `expr.val(dataType, value)` — 리터럴 → `ExprUnit`. `dataType ∈ "string"|"number"|"boolean"|"DateTime"|"DateOnly"|"Time"|"Uuid"|"Bytes"`.
16
- - `expr.col(dataType, ...path)` — 컬럼 참조(주로 내부).
17
- - `expr.raw(dataType)\`SQL ${interp}\`` — 태그드 템플릿. 보간값은 파라미터화. dialect 의존 함수 사용 시 escape hatch.
18
-
19
- ### 비교 / NULL (→ `WhereExprUnit`)
20
- - `eq`, `gt`, `lt`, `gte`, `lte`(source, target)
21
- - `between(source, from?, to?)`
22
- - `null(source)` — IS NULL
23
- - `like(source, pattern)`, `regexp(source, pattern)`
24
- - `in(source, values[])`, `inQuery(source, queryable)` — `queryable` 은 1-컬럼 select 여야 함. `exists(queryable)`.
25
-
26
- ### 논리
27
- - `not(WhereExprUnit)`, `and(WhereExprUnit[])`, `or(WhereExprUnit[])` — 빈 배열은 throw.
28
-
29
- ### 문자열 (→ `ExprUnit<string ...>`)
30
- - `concat(...args)`, `left(s, n)`, `right(s, n)`, `trim(s)`
31
- - `padStart(s, length, fillString)`, `replace(s, from, to)`
32
- - `upper(s)`, `lower(s)`
33
- - `length(s)` → number, `byteLength(s)` → number
34
- - `substring(s, start, length?)`, `indexOf(s, search)` → number
35
-
36
- ### 숫자
37
- - `abs`, `round(s, digits)`, `ceil`, `floor`.
38
-
39
- ### 날짜 (`DateUnit = "year"|"month"|"day"|"hour"|"minute"|"second"`)
40
- - `year/month/day/hour/minute/second(source)`
41
- - `isoWeek(d)`, `isoWeekStartDate(d)`, `isoYearMonth(d)`
42
- - `dateDiff(unit, from, to)` → number
43
- - `dateAdd(unit, source, value)`
44
- - `formatDate(source, format: string)` — format 문자열은 dialect 변환.
45
-
46
- ### NULL 처리 / 조건
47
- - `coalesce(...args)` — 첫 non-null. 마지막 인자가 NonNullable 이면 반환 타입도 NonNullable.
48
- - `nullIf(source, value)`
49
- - `is(WhereExprUnit)` → `ExprUnit<boolean>` (boolean 변환)
50
- - `if(condition, then, else_)` → `ExprUnit<T>` — 결과 dataType 은 ExprUnit/non-null 리터럴에서 추론.
51
- - `switch<T>()` → `SwitchExprBuilder<T>` — `.case(cond, then).case(...).default(value)` 체이닝.
52
-
53
- ### 집계 (GROUP BY 컨텍스트)
54
- - `count(arg?, distinct?)` → number
55
- - `sum(arg)`, `avg(arg)` → `number | undefined`
56
- - `max(arg)`, `min(arg)` → `T | undefined`
57
- - `greatest(...args)`, `least(...args)` — 행 내 최대/최소.
58
-
59
- ### 기타 스칼라
60
- - `rowNum()` → number — MSSQL `ROW_NUMBER() OVER(...)` 가 아니라 dialect 별 row 식별 함수 (간단 시퀀스).
61
- - `random()` → number, 0~1.
62
- - `cast(source, targetType: DataType)` — 결과 dataType 은 `dataTypeStrToColumnPrimitiveStr` 매핑.
63
- - `subquery(dataType, queryable)` — 1-컬럼 select 의 스칼라 서브쿼리.
64
-
65
- ### 윈도우 함수 (`WinSpecInput = { partitionBy?: ExprInput[], orderBy?: [ExprInput, "ASC"|"DESC"?][] }`)
66
- - 순위: `rowNumber(spec)`, `rank(spec)`, `denseRank(spec)`, `ntile(n, spec)`
67
- - 시퀀스 비교: `lag(column, spec, { offset?, default? })`, `lead(column, spec, { offset?, default? })`
68
- - 첫/끝: `firstValue(column, spec)`, `lastValue(column, spec)`
69
- - 집계 윈도우: `sumOver(column, spec)`, `avgOver(column, spec)`, `countOver(spec, column?)`, `minOver(column, spec)`, `maxOver(column, spec)`
70
-
71
- ## 예시
72
-
73
- ```ts
74
- db.user()
75
- .where(u => [
76
- expr.eq(u.status, "active"),
77
- expr.between(u.age, 18, 65),
78
- expr.or([expr.like(u.name, "%kim%"), expr.like(u.email, "%kim%")]),
79
- ])
80
- .select(u => ({
81
- name: expr.concat(u.firstName, " ", u.lastName),
82
- rank: expr.rowNumber({ partitionBy: [u.deptId], orderBy: [[u.score, "DESC"]] }),
83
- label: expr.switch<string>()
84
- .case(expr.gte(u.score, 90), "A")
85
- .case(expr.gte(u.score, 80), "B")
86
- .default("C"),
87
- }))
88
- ```
89
-
90
- ## Expr AST 타입
91
-
92
- 세부 노드 타입은 `./types/expr` 의 union (`ExprColumn`/`ExprValue`/`ExprRaw`/...`ExprWindow`/`ExprSubquery`). 일반 사용자는 직접 다룰 필요 없음 — ExprRenderer 구현이나 디버깅·검증 시만.
@@ -1,98 +0,0 @@
1
- # @simplysm/orm-common — Queryable
2
-
3
- 체이닝 SELECT/INSERT/UPDATE/DELETE/UPSERT 빌더. `DbContext.queryable(builder)` 가 만든 팩토리 호출(`db.user()`)마다 새 alias 가 할당된 새 `Queryable` 이 반환된다. 모든 체이닝 메서드는 새 인스턴스를 반환(immutable).
4
-
5
- ```ts
6
- class Queryable<TData extends DataRecord, TFrom extends TableBuilder | never>
7
- ```
8
- - `TData` — 결과 row 타입 (관계 include 포함).
9
- - `TFrom` — CUD(INSERT/UPDATE/DELETE/UPSERT) 시 필요한 원본 TableBuilder. `select`/`join`/`union`/`wrap`/`groupBy`/`recursive`/`distinct` 한 후엔 `never` 가 되어 CUD 불가.
10
-
11
- ## 옵션 체이닝
12
-
13
- - `.select(fn: cols => mapped)` — SELECT 컬럼/표현식 재구성. 원시 리터럴은 자동 `ExprUnit` 으로 래핑. → `Queryable<UnwrapQueryableRecord<R>, never>`.
14
- - `.distinct()` — DISTINCT.
15
- - `.lock()` — FOR UPDATE.
16
- - `.top(n)` — TOP N (ORDER BY 무관).
17
- - `.limit(skip, take)` — `orderBy` 필수, 없으면 throw.
18
- - `.orderBy(fn | "key.path", "ASC" | "DESC"?)` — 누적. 문자열 overload 는 `obj.getChainValue` 로 컬럼 검색 (동적 정렬용).
19
- - `.where(predicate: cols => WhereExprUnit[])` — 누적, AND 결합.
20
- - `.search(cols => ExprUnit<string|undefined>[], text)` — `parseSearchQuery` 의 OR/AND(`+`)/NOT(`-`)/`"…"`/`*` 구문을 컬럼들에 LIKE 로 적용 (소문자 비교).
21
- - `.groupBy(cols => ExprUnit[])` — `TFrom` → never.
22
- - `.having(predicate)` — GROUP BY 후 필터, 누적 AND.
23
-
24
- ## JOIN / INCLUDE
25
-
26
- ```ts
27
- .join(as, (qr, cols) => Queryable) // 1:N — { ..., [as]?: R[] }
28
- .joinSingle(as, (qr, cols) => Queryable) // N:1 또는 1:1 — { ..., [as]?: R }
29
- .include(item => item.user.company) // PathProxy 기반 자동 JOIN (TableBuilder 기반만)
30
- ```
31
-
32
- - 콜백의 `qr: JoinQueryable` 은 `.from(table)` / `.select(customCols)` / `.union(...queries)` 제공.
33
- - `.include` 는 `TableBuilder.relations` 정의를 따라 FK/RelationKey(=joinSingle) 또는 FKT/RelationKeyTarget(=join, `single:true` 면 joinSingle) 으로 풀림. 동일 경로 중복 호출은 무시. 다단계(`a.b.c`)는 부모 객체 안으로 nested 됨.
34
- - PathProxy 는 ColumnPrimitive 필드 접근을 컴파일 에러로 막아 관계 키만 허용.
35
-
36
- ## Subquery / UNION / Recursive CTE
37
-
38
- - `.wrap()` — 현재 Queryable 을 서브쿼리로 감싼 새 Queryable. `distinct()`/`groupBy()` 후 `count()` 직전에 필요.
39
- - `Queryable.union(q1, q2, ...)` (static) — UNION (중복 제거). 2개 미만 throw. 첫 query 의 컬럼 구조 사용.
40
- - `.recursive(fn: (cte: RecursiveQueryable<TData>) => Queryable<TData>)` — WITH RECURSIVE 생성. 콜백 안에서 `cte.from(table)` 한 결과에 `self` 프로퍼티(현재 CTE 자기 참조)가 부여됨. `.union(...)` 도 가능.
41
-
42
- ## 실행 (SELECT)
43
-
44
- - `await qr.execute(): Promise<TData[]>`
45
- - `await qr.single(): Promise<TData | undefined>` — 2개 이상이면 throw.
46
- - `await qr.first(): Promise<TData | undefined>` — 내부 `top(1)`.
47
- - `await qr.count(fn?): Promise<number>` — `distinct`/`groupBy` 후 직접 호출시 throw → `wrap()` 필요.
48
- - `await qr.exists(): Promise<boolean>` — `top(1)` 으로 행 존재 확인.
49
-
50
- ## CUD (TFrom = TableBuilder 필요)
51
-
52
- ```ts
53
- await q.insert(records);
54
- const [{ id }] = await q.insert([{...}], ["id"]); // OUTPUT
55
-
56
- await q.insertIfNotExists(record); // WHERE 조건과 결합
57
- await q.insertIfNotExists(record, ["id"]); // 단건 반환
58
-
59
- await q2.insertInto(TargetTable); // INSERT INTO ... SELECT
60
- await q2.insertInto(TargetTable, ["id"]);
61
-
62
- await q.update(cols => ({ name: expr.val("string", "x") }));
63
- await q.update(cols => ({...}), ["id"]);
64
-
65
- await q.delete();
66
- await q.delete(["id", "name"]);
67
-
68
- await q.upsert(updateFn); // UPDATE 또는 INSERT (existsSelectQuery=현재 where)
69
- await q.upsert(updateFn, ["id"]);
70
- await q.upsert(updateFn, insertFn);
71
- await q.upsert(updateFn, insertFn, ["id"]);
72
- ```
73
-
74
- - `insert(records)` 는 records 0건이면 noop. MSSQL 1000행 제한을 위해 청크 분할(`CHUNK_SIZE=1000`) — 각 청크는 별도 `executeDefs` 호출, OUTPUT 도 누적.
75
- - `insert` 의 records 에 autoIncrement 컬럼 값이 명시되면 자동으로 `overrideIdentity` 켜짐.
76
- - CUD 는 `TFrom` 이 `TableBuilder` 일 때만 — 아니면 `_getCudOutputDef` 에서 throw. ViewBuilder/Queryable 합성/Union 후엔 사용 불가.
77
- - `await q.switchFk(enabled)` — TableBuilder/ViewBuilder 기반에서 FK on/off (트랜잭션 내 사용 가능).
78
-
79
- ## QueryDef 생성기 (실행 없이 def 만)
80
-
81
- `getSelectQueryDef()`, `getInsertQueryDef(records, output?)`, `getInsertIfNotExistsQueryDef(record, output?)`, `getInsertIntoQueryDef(target, output?)`, `getUpdateQueryDef(recordFwd, output?)`, `getDeleteQueryDef(output?)`, `getUpsertQueryDef(updateFn, insertFn, output?)`, `getResultMeta(outputColumns?)`.
82
-
83
- ## 타입
84
-
85
- `QueryableRecord<TData>` — `TData` 의 원시 필드를 `ExprUnit<T>`, 중첩 객체/배열은 재귀로 감싼 형태. `where`/`select` 콜백 인자 타입.
86
-
87
- `QueryableWriteRecord<TData>` — `ExprInput<T>` (= `ExprUnit<T> | T`) 으로, `update`/`upsert` 의 record 값 입력 타입.
88
-
89
- `UnwrapQueryableRecord<R>` — `.select` 결과를 다시 DataRecord 로 역추론.
90
-
91
- `PathProxy<T>` — `.include` 인자 타입. 비-ColumnPrimitive 필드만 노출.
92
-
93
- ## 보조 함수
94
-
95
- ```ts
96
- queryable(db, tableOrView, as?) // Queryable factory 생성. DbContext.queryable 의 내부 구현
97
- getMatchedPrimaryKeys(fkCols, targetTable) // include 가 FK 컬럼과 대상 PK 매칭
98
- ```
@@ -1,128 +0,0 @@
1
- # @simplysm/orm-common — Schema Builders
2
-
3
- 테이블/뷰/프로시저를 fluent 로 정의하는 immutable 빌더. `DbContext` 의 `queryable()`/`executable()` 에 전달하여 등록한다. 모든 메서드는 `new Xxx({...this.meta, ...})` 형태로 새 인스턴스 반환.
4
-
5
- ## Table / TableBuilder
6
-
7
- ```ts
8
- import { Table } from "@simplysm/orm-common";
9
-
10
- const User = Table("User") // Table<TName>(name)
11
- .database("mydb")
12
- .schema("dbo") // MSSQL/PostgreSQL only
13
- .description("사용자")
14
- .columns((c) => ({
15
- id: c.bigint().autoIncrement(),
16
- name: c.varchar(100),
17
- email: c.varchar(200).nullable(),
18
- status: c.varchar(20).default("active"),
19
- }))
20
- .primaryKey("id") // 복합: .primaryKey("a","b")
21
- .indexes((i) => [i.index("email").unique()])
22
- .relations((r) => ({
23
- posts: r.foreignKeyTarget(() => Post, "author"),
24
- }));
25
- ```
26
-
27
- 타입 추론 프로퍼티 (`readonly $xxx!` — 런타임 값 X, 타입 추출용):
28
- - `$inferSelect` — 컬럼 + (deep) 관계 (관계는 optional)
29
- - `$inferColumns` — 컬럼만
30
- - `$inferInsert` — `autoIncrement`/`nullable`/`default` 컬럼은 optional
31
- - `$inferUpdate` — 모든 필드 optional
32
- - `$columns`, `$relations` — 정의 자체
33
-
34
- `meta`: `{ name; description?; database?; schema?; columns?; primaryKey?; relations?; indexes? }`.
35
-
36
- ## View / ViewBuilder
37
-
38
- ```ts
39
- import { View } from "@simplysm/orm-common";
40
-
41
- const ActiveUsers = View("ActiveUsers")
42
- .database("mydb")
43
- .query((db: MainDb) =>
44
- db.user().where(u => [expr.eq(u.status, "active")])
45
- .select(u => ({ id: u.id, name: u.name })))
46
- .relations(r => ({ posts: r.relationKeyTarget(() => Post, "author") }));
47
- ```
48
-
49
- - `.query<TData>(viewFn: (db) => Queryable<TData>)` 의 viewFn 은 `queryable()` 호출시(=`createView` DDL 만들 때, `db.queryable(ViewBuilder)` 팩토리에서) 실행된다.
50
- - View 의 관계는 `relationKey`/`relationKeyTarget` 만 사용 (DB FK 미생성).
51
- - `$inferSelect: TData`.
52
-
53
- ## Procedure / ProcedureBuilder
54
-
55
- ```ts
56
- import { Procedure } from "@simplysm/orm-common";
57
-
58
- const GetUserById = Procedure("GetUserById")
59
- .database("mydb")
60
- .params(c => ({ userId: c.bigint() }))
61
- .returns(c => ({ id: c.bigint(), name: c.varchar(100) }))
62
- .body("SELECT id, name FROM User WHERE id = userId");
63
- // MSSQL 본문은 @userId 사용. PostgreSQL 은 RETURN QUERY 필요.
64
- ```
65
-
66
- `$params`, `$returns` 타입 추론. `meta`: `{ name; description?; database?; schema?; params?; returns?; query? }`.
67
-
68
- ## Column Factory (`columns((c) => ...)` 안에서 사용)
69
-
70
- `createColumnFactory()` 반환 객체의 메서드 — 모두 `ColumnBuilder<TValue, TMeta>` 반환:
71
-
72
- | 메서드 | TS 타입 | SQL 매핑 |
73
- |---|---|---|
74
- | `int()` | number | INT |
75
- | `bigint()` | number | BIGINT |
76
- | `float()` | number | FLOAT/REAL |
77
- | `double()` | number | DOUBLE |
78
- | `decimal(precision, scale?)` | number | DECIMAL(p,s) |
79
- | `varchar(length)` | string | VARCHAR(n) |
80
- | `char(length)` | string | CHAR(n) |
81
- | `text()` | string | TEXT/LONGTEXT |
82
- | `binary()` | Bytes | LONGBLOB/VARBINARY(MAX)/BYTEA |
83
- | `boolean()` | boolean | TINYINT(1)/BIT/BOOLEAN |
84
- | `datetime()` | DateTime | DATETIME |
85
- | `date()` | DateOnly | DATE |
86
- | `time()` | Time | TIME |
87
- | `uuid()` | Uuid | BINARY(16)/UNIQUEIDENTIFIER/UUID |
88
-
89
- `ColumnBuilder` 체이닝:
90
- - `.autoIncrement()` — INSERT 시 자동 증가, `$inferInsert` 에서 optional.
91
- - `.nullable()` — TS 타입에 `| undefined` 추가.
92
- - `.default(value)` — 기본값. `$inferInsert` 에서 optional.
93
- - `.description(text)` — DDL Comment.
94
-
95
- 타입 유틸: `ColumnBuilderRecord`, `InferColumns<T>`, `InferColumnExprs<T>` (Executable params), `RequiredInsertKeys<T>`, `OptionalInsertKeys<T>`, `InferInsertColumns<T>`, `InferUpdateColumns<T>`, `DataToColumnBuilderRecord<TData>`.
96
-
97
- ## Index Factory (`indexes((i) => ...)` 안에서)
98
-
99
- ```ts
100
- i.index("email").unique()
101
- i.index("name", "createdAt").orderBy("ASC", "DESC")
102
- i.index("createdAt").name("IX_Foo")
103
- i.index("a").description("...")
104
- ```
105
-
106
- `IndexBuilder<TKeys>` 의 `meta`: `{ columns; name?; unique?; orderBy?; description? }`.
107
-
108
- ## Relation Factory (`relations((r) => ...)` 안에서)
109
-
110
- Table 은 4개 모두, View 는 `relationKey`/`relationKeyTarget` 만 노출.
111
-
112
- ```ts
113
- // N:1
114
- r.foreignKey(["authorId"], () => User, { description?: string }) // DB FK 생성
115
- r.relationKey(["companyId"], () => Company, { description?: string }) // 논리 관계 (FK X) — View 가능
116
-
117
- // 1:N (기본) 또는 1:1 (single: true)
118
- r.foreignKeyTarget(() => Post, "author")
119
- r.foreignKeyTarget(() => Profile, "user", { single: true })
120
- r.relationKeyTarget(() => UserSummary, "company", { single?, description? })
121
- ```
122
-
123
- - `foreignKey` 의 두 번째 인자는 *대상 테이블 factory* `() => TableBuilder` (순환 참조 회피).
124
- - `foreignKeyTarget` 의 두 번째 인자 `relationName` 은 대상 테이블에 정의된 자기방향 FK 의 키 이름.
125
- - 메서드 체이닝(`.description()`/`.single()`)은 TS 순환 참조 (TS7022) 회피용으로 *제거됨* — 옵션은 마지막 `opts` 객체로만 전달.
126
- - 빌더 클래스: `ForeignKeyBuilder`, `ForeignKeyTargetBuilder`, `RelationKeyBuilder`, `RelationKeyTargetBuilder`.
127
-
128
- 타입 유틸: `RelationBuilderRecord`, `ExtractRelationTarget<T>`, `ExtractRelationTargetResult<T>`, `InferDeepRelations<TRelations>` — 모두 관계를 optional 로 추론, 같은 테이블 재방문 시 더 깊이 들어가지 않음 (순환 끊김).
@@ -1,69 +0,0 @@
1
- # @simplysm/orm-node
2
-
3
- Node.js 환경에서 `@simplysm/orm-common` 의 `DbContext` 를 실제 DB(MSSQL/MySQL/PostgreSQL)에 붙여 실행하기 위한 어댑터. 드라이버 모듈(`tedious`/`mysql2`/`pg`/`pg-copy-streams`)은 dialect 선택 시점에 지연 import.
4
-
5
- ## 사용 트리거 인덱스
6
-
7
- - **`createOrm`** — `DbContext` 서브클래스 + `DbConnConfig` 로 ORM 인스턴스 생성. 일반 ORM 사용의 진입점.
8
- - **`Orm<T>`** — `createOrm` 반환 타입. 함수 시그니처·DI 토큰에서 참조하거나 `connect` / `connectWithoutTransaction` 호출 시.
9
- - **`OrmOptions`** — `createOrm` 3번째 인자. `DbConnConfig` 의 `database` / `schema` 를 런타임에 덮어쓸 때.
10
- - **`createDbConn`** — `DbConnConfig` 만으로 저수준 `DbConn` 인스턴스 직접 생성. `DbContext` 없이 raw SQL/bulk insert 가 필요할 때.
11
- - **`NodeDbContextExecutor`** — `DbContext` 의 executor 직접 주입이 필요할 때. 일반적으로는 `createOrm` 이 내부적으로 사용.
12
- - **`MysqlDbConn`** — MySQL 용 `DbConn` 구현 클래스. 직접 `new` 하지 말고 `createDbConn` 사용. 타입 참조용 import.
13
- - **`MssqlDbConn`** — MSSQL/Azure SQL 용 `DbConn` 구현 클래스. 직접 `new` 하지 말고 `createDbConn` 사용. 타입 참조용 import.
14
- - **`PostgresqlDbConn`** — PostgreSQL 용 `DbConn` 구현 클래스. 직접 `new` 하지 말고 `createDbConn` 사용. 타입 참조용 import.
15
- - **`DbConn`** — 저수준 연결 인터페이스. 모든 dialect 공통 메서드(`connect`/`close`/트랜잭션/`execute`/`executeParametrized`/`bulkInsert`) 와 `close` 이벤트.
16
- - **`DbConnConfig`** — dialect 분기 union 타입. `createOrm`/`createDbConn` 입력.
17
- - **`MysqlDbConnConfig`** — `dialect: "mysql"` 한정 설정 타입.
18
- - **`MssqlDbConnConfig`** — `dialect: "mssql" | "mssql-azure"` 설정 타입. `schema?` 포함.
19
- - **`PostgresqlDbConnConfig`** — `dialect: "postgresql"` 설정 타입. `schema?` 포함.
20
- - **`getDialectFromConfig`** — `DbConnConfig` → `Dialect` 변환(`mssql-azure` → `mssql`). 쿼리 빌더 선택 시.
21
- - **`DB_CONN_CONNECT_TIMEOUT`** — DB 연결 수립 타임아웃 상수 (10초).
22
- - **`DB_CONN_DEFAULT_TIMEOUT`** — 쿼리/유휴 기본 타임아웃 상수 (10분).
23
- - **`DB_CONN_ERRORS`** — `NOT_CONNECTED` / `ALREADY_CONNECTED` 에러 메시지 리터럴.
24
-
25
- ## createOrm
26
-
27
- ```ts
28
- function createOrm<T extends DbContext>(
29
- DbClass: new (executor: DbContextExecutor, opt: { database: string; schema?: string }) => T,
30
- config: DbConnConfig,
31
- options?: OrmOptions, // { database?: string; schema?: string } — config 보다 우선
32
- ): Orm<T>;
33
-
34
- interface Orm<T> {
35
- connect<R>(cb: (db: T) => Promise<R>, isolationLevel?: IsolationLevel): Promise<R>; // 트랜잭션
36
- connectWithoutTransaction<R>(cb: (db: T) => Promise<R>): Promise<R>; // 트랜잭션 없음
37
- }
38
- ```
39
-
40
- `database` 가 `options` 와 `config` 양쪽 모두 없으면 throw. 매 `connect*` 호출마다 새 `DbContext` 인스턴스를 만들어 콜백 종료 시 연결을 닫는다.
41
-
42
- ```ts
43
- const orm = createOrm(MyDb, { dialect: "mysql", host, port, username, password, database });
44
- await orm.connect(async (db) => db.user().execute());
45
- ```
46
-
47
- ## createDbConn
48
-
49
- ```ts
50
- function createDbConn(config: DbConnConfig): Promise<DbConn>;
51
- ```
52
-
53
- dialect 에 따라 드라이버 모듈을 lazy import 한 뒤 해당 `DbConn` 구현 반환. **반환된 객체는 미연결 상태** — 호출자가 `conn.connect()` → 사용 → `conn.close()` 까지 책임. `DbConn` 은 `EventEmitter<{ close: void }>` 이며 다음 메서드 제공: `connect`, `close`, `beginTransaction(isolationLevel?)`, `commitTransaction`, `rollbackTransaction`, `execute(queries: string[])`, `executeParametrized(query, params?)`, `bulkInsert(tableName, columnMetas, records)`. `bulkInsert` 는 dialect별 네이티브 경로 사용(MSSQL: tedious BulkLoad / MySQL: `LOAD DATA LOCAL INFILE` 임시파일 / PostgreSQL: `COPY FROM STDIN`).
54
-
55
- ## DbConnConfig
56
-
57
- dialect 분기 union. 공통 필드: `host`, `port?`, `username`, `password`, `database?`, `defaultIsolationLevel?`.
58
-
59
- - `MysqlDbConnConfig` — `dialect: "mysql"`.
60
- - `MssqlDbConnConfig` — `dialect: "mssql" | "mssql-azure"`, `schema?`. `mssql-azure` 는 `encrypt: true` 로 연결.
61
- - `PostgresqlDbConnConfig` — `dialect: "postgresql"`, `schema?`.
62
-
63
- ## NodeDbContextExecutor
64
-
65
- ```ts
66
- new NodeDbContextExecutor(config: DbConnConfig)
67
- ```
68
-
69
- `DbContextExecutor` 구현. `connect` 시 내부에서 `createDbConn` + `conn.connect()` 수행. `executeDefs(defs, resultMetas?)` 는 `@simplysm/orm-common` 의 `createQueryBuilder` + `parseQueryResult` 를 사용해 `QueryDef[]` → SQL → 파싱 결과. `resultMetas` 가 전부 `null` 인 경우 단일 결합 SQL 1회로 묶어 실행하고 `defs.length` 개의 빈 배열 반환(결과 불필요 케이스 최적화). 미연결 상태에서 메서드 호출 시 `DB_CONN_ERRORS.NOT_CONNECTED` SdError throw.
@@ -1,32 +0,0 @@
1
- # @simplysm/sd-claude
2
-
3
- Claude Code 셋업 자산(`.claude/` 의 sd-* 스킬·룰·훅) 배포 및 `sd-claude` CLI 제공 패키지. 코드 API 없음 — 외부 import 가능한 라이브러리 심볼 미노출.
4
-
5
- ## 사용 트리거 인덱스
6
-
7
- - 현재 로그인된 Claude 계정을 프로필로 저장 → [auth save](#cli-sd-claude)
8
- - 저장된 다른 Claude 계정으로 전환 → [auth switch](#cli-sd-claude)
9
- - 소비 프로젝트 설치 시 `.claude/` 자산 자동 배치 → [postinstall](#패키지-훅)
10
- - 워크스페이스 `.claude/` 변경분을 패키지 `claude/` 로 동기화(배포 직전) → [prepack / sync](#패키지-훅)
11
-
12
- ## CLI `sd-claude`
13
-
14
- `bin: sd-claude` → `scripts/cli.mjs`. 사용법: `sd-claude <subcommand> <action>`.
15
-
16
- - `auth save`: 현재 `claude auth status` 의 `orgName` 을 프로필 키로, `~/.claude/.credentials.json` 의 `claudeAiOauth.refreshToken` 과 `~/.claude/statusline-cache.json` 의 사용량 스냅샷을 `~/.claude/profiles.json` 에 저장하고 `current` 를 해당 프로필로 설정. orgName 또는 refreshToken 미획득 시 stderr 출력 후 exit 1.
17
- - `auth switch`: `profiles.json` 의 계정 목록을 번호 + 현재 마커(`*`) + 사용량(현재 계정은 live, 그 외는 저장 시점) 으로 출력. 번호 입력으로 대상 선택 → 현재 계정의 최신 refreshToken·사용량을 백업 저장 → `CLAUDE_CODE_OAUTH_REFRESH_TOKEN`/`CLAUDE_CODE_OAUTH_SCOPES` 환경변수로 `claude auth login` 을 spawn → 갱신된 refreshToken 저장 + `current` 업데이트. TTY 아니면 exit 1.
18
- - 그 외 인자: 사용법 출력 후 exit 1.
19
-
20
- 저장 위치 식별자 풀이:
21
- - `~/.claude/profiles.json`: `{ current: string, accounts: { [orgName]: { refreshToken, usage } } }` 구조. 패키지가 관리.
22
- - `~/.claude/.credentials.json`: Claude Code 본체가 관리. `claudeAiOauth.refreshToken` 만 읽음.
23
- - `~/.claude/statusline-cache.json`: Claude Code 본체가 관리. `rate_limits.five_hour` / `seven_day` 의 `used_percentage` + `resets_at` 만 읽음.
24
-
25
- ## 패키지 훅
26
-
27
- - `postinstall` (`scripts/postinstall.mjs`): 소비 프로젝트의 `node_modules` 설치 시 자동 실행. `INIT_CWD` 또는 `node_modules` 경로 역추적으로 프로젝트 루트 결정 → `<projectRoot>/.claude/` 의 기존 sd-* 항목(root 1단계 + 하위 디렉토리 1단계의 `^sd[-_]` 매칭) 정리 후 패키지 `claude/` 의 동일 항목 + `settings.json` + `simplysm.json` 을 복사. 소비 프로젝트가 `name: "simplysm"` 이고 메이저 버전이 같으면 skip(모노레포 자기 자신 보호). 실패해도 throw 하지 않음(install 차단 방지).
28
- - `prepack` (`scripts/sync.mjs`): `pnpm pub`/`npm pack` 직전 실행. 워크스페이스 루트(`../../`)의 `.claude/` 에서 sd-* 항목(+ `settings.json`/`simplysm.json`) 을 패키지 `claude/` 로 증분 복사. 동일 파일은 mtime+size 비교로 skip, 변경분은 unlink 후 copy + src mtime 보존, src 에 없는 dest 항목은 prune. 제외: `evals/` 하위, 파일명 `SKILL.eval.md`, `eval_*` 접두 파일. (Windows EPERM 회피 위해 일괄 rmSync 미사용.)
29
-
30
- 식별자 풀이:
31
- - sd-* 항목 스캔 범위: 디렉토리 root + 1단계 하위. 정규식 `^sd[-_]`. 즉 `.claude/skills/sd-foo/`, `.claude/rules/sd-bar.md`, `.claude/sd-baz/` 등 매칭.
32
- - watch 훅 연동: 모노레포에서는 `sd.config.ts` 의 `scripts` 타겟이 `.claude/sd-*` 변경 감지 시 본 `sync.mjs` 를 호출(패키지 외부 설정).