@simplysm/orm-common 13.0.93 → 13.0.96
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/docs/ddl.md +105 -0
- package/docs/query.md +176 -1
- package/docs/schema.md +87 -0
- package/package.json +2 -2
package/docs/ddl.md
CHANGED
|
@@ -19,6 +19,15 @@ await db.connectWithoutTransaction(async () => {
|
|
|
19
19
|
});
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
+
### initialize API
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
db.initialize(options?: {
|
|
26
|
+
dbs?: string[]; // 초기화할 DB 목록 (생략 시 전체)
|
|
27
|
+
force?: boolean; // true이면 기존 스키마 삭제 후 재생성
|
|
28
|
+
}): Promise<void>
|
|
29
|
+
```
|
|
30
|
+
|
|
22
31
|
## 테이블 DDL
|
|
23
32
|
|
|
24
33
|
```typescript
|
|
@@ -95,6 +104,49 @@ await db.switchFk({ name: "user" }, false); // FK 비활성화
|
|
|
95
104
|
await db.switchFk({ name: "user" }, true); // FK 활성화
|
|
96
105
|
```
|
|
97
106
|
|
|
107
|
+
## DDL 메서드 API
|
|
108
|
+
|
|
109
|
+
### 테이블/뷰/프로시저
|
|
110
|
+
|
|
111
|
+
| 메서드 | 시그니처 | 설명 |
|
|
112
|
+
|--------|---------|------|
|
|
113
|
+
| `createTable` | `(table: TableBuilder) => Promise<void>` | 테이블 생성 |
|
|
114
|
+
| `dropTable` | `(table: QueryDefObjectName) => Promise<void>` | 테이블 삭제 |
|
|
115
|
+
| `renameTable` | `(table: QueryDefObjectName, newName: string) => Promise<void>` | 테이블 이름 변경 |
|
|
116
|
+
| `createView` | `(view: ViewBuilder) => Promise<void>` | 뷰 생성 |
|
|
117
|
+
| `dropView` | `(view: QueryDefObjectName) => Promise<void>` | 뷰 삭제 |
|
|
118
|
+
| `createProc` | `(proc: ProcedureBuilder) => Promise<void>` | 프로시저 생성 |
|
|
119
|
+
| `dropProc` | `(proc: QueryDefObjectName) => Promise<void>` | 프로시저 삭제 |
|
|
120
|
+
|
|
121
|
+
### 컬럼
|
|
122
|
+
|
|
123
|
+
| 메서드 | 시그니처 | 설명 |
|
|
124
|
+
|--------|---------|------|
|
|
125
|
+
| `addColumn` | `(table, columnName, column: ColumnBuilder) => Promise<void>` | 컬럼 추가 |
|
|
126
|
+
| `dropColumn` | `(table, column: string) => Promise<void>` | 컬럼 삭제 |
|
|
127
|
+
| `modifyColumn` | `(table, columnName, column: ColumnBuilder) => Promise<void>` | 컬럼 수정 |
|
|
128
|
+
| `renameColumn` | `(table, column, newName) => Promise<void>` | 컬럼 이름 변경 |
|
|
129
|
+
|
|
130
|
+
### 키/인덱스
|
|
131
|
+
|
|
132
|
+
| 메서드 | 시그니처 | 설명 |
|
|
133
|
+
|--------|---------|------|
|
|
134
|
+
| `addPrimaryKey` | `(table, columns: string[]) => Promise<void>` | PK 추가 |
|
|
135
|
+
| `dropPrimaryKey` | `(table) => Promise<void>` | PK 삭제 |
|
|
136
|
+
| `addForeignKey` | `(table, relationName, relationDef) => Promise<void>` | FK 추가 |
|
|
137
|
+
| `dropForeignKey` | `(table, relationName) => Promise<void>` | FK 삭제 |
|
|
138
|
+
| `addIndex` | `(table, indexBuilder) => Promise<void>` | 인덱스 추가 |
|
|
139
|
+
| `dropIndex` | `(table, columns: string[]) => Promise<void>` | 인덱스 삭제 |
|
|
140
|
+
|
|
141
|
+
### 스키마
|
|
142
|
+
|
|
143
|
+
| 메서드 | 시그니처 | 설명 |
|
|
144
|
+
|--------|---------|------|
|
|
145
|
+
| `schemaExists` | `(database, schema?) => Promise<boolean>` | 스키마 존재 여부 |
|
|
146
|
+
| `clearSchema` | `(params: { database, schema? }) => Promise<void>` | 스키마 내 모든 테이블 삭제 |
|
|
147
|
+
| `truncate` | `(table) => Promise<void>` | 테이블 TRUNCATE |
|
|
148
|
+
| `switchFk` | `(table, enabled: boolean) => Promise<void>` | FK 제약조건 on/off |
|
|
149
|
+
|
|
98
150
|
## 연결 & 트랜잭션
|
|
99
151
|
|
|
100
152
|
```typescript
|
|
@@ -121,6 +173,14 @@ await db.connectWithoutTransaction(async () => {
|
|
|
121
173
|
});
|
|
122
174
|
```
|
|
123
175
|
|
|
176
|
+
### 연결 API
|
|
177
|
+
|
|
178
|
+
| 메서드 | 시그니처 | 설명 |
|
|
179
|
+
|--------|---------|------|
|
|
180
|
+
| `connect` | `(fn, isolationLevel?) => Promise<T>` | 자동 트랜잭션 (connect -> begin -> fn -> commit/rollback -> close) |
|
|
181
|
+
| `connectWithoutTransaction` | `(fn) => Promise<T>` | 트랜잭션 없이 연결 (DDL용) |
|
|
182
|
+
| `transaction` | `(fn, isolationLevel?) => Promise<T>` | 수동 트랜잭션 (connectWithoutTransaction 내에서) |
|
|
183
|
+
|
|
124
184
|
격리 수준: `"READ_UNCOMMITTED"`, `"READ_COMMITTED"`, `"REPEATABLE_READ"`, `"SERIALIZABLE"`
|
|
125
185
|
|
|
126
186
|
## DbContextExecutor 인터페이스
|
|
@@ -163,6 +223,15 @@ const MyDb = defineDbContext({
|
|
|
163
223
|
});
|
|
164
224
|
```
|
|
165
225
|
|
|
226
|
+
### Migration 인터페이스
|
|
227
|
+
|
|
228
|
+
```typescript
|
|
229
|
+
interface Migration {
|
|
230
|
+
name: string;
|
|
231
|
+
up: (db: DbContextBase & DbContextDdlMethods) => Promise<void>;
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
166
235
|
실행된 마이그레이션은 `_migration` 테이블에 기록된다.
|
|
167
236
|
|
|
168
237
|
```typescript
|
|
@@ -184,6 +253,17 @@ import { DbTransactionError, DbErrorCode } from "@simplysm/orm-common";
|
|
|
184
253
|
// - LOCK_TIMEOUT: 잠금 타임아웃
|
|
185
254
|
```
|
|
186
255
|
|
|
256
|
+
### DbTransactionError API
|
|
257
|
+
|
|
258
|
+
```typescript
|
|
259
|
+
class DbTransactionError extends Error {
|
|
260
|
+
readonly name: "DbTransactionError";
|
|
261
|
+
readonly code: DbErrorCode;
|
|
262
|
+
readonly originalError?: unknown;
|
|
263
|
+
constructor(code: DbErrorCode, message: string, originalError?: unknown);
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
187
267
|
## QueryDef 생성기
|
|
188
268
|
|
|
189
269
|
DDL 메서드 외에도 `get*QueryDef()` 메서드로 QueryDef만 생성할 수 있다 (직접 실행하지 않음).
|
|
@@ -193,3 +273,28 @@ const def = db.getCreateTableQueryDef(User);
|
|
|
193
273
|
const def2 = db.getAddColumnQueryDef({ name: "user" }, "phone", c.varchar(20));
|
|
194
274
|
// ... 등. 모든 DDL 메서드에 대응하는 get*QueryDef() 메서드가 있다.
|
|
195
275
|
```
|
|
276
|
+
|
|
277
|
+
| 생성기 | 대응 DDL 메서드 |
|
|
278
|
+
|--------|---------------|
|
|
279
|
+
| `getCreateTableQueryDef` | `createTable` |
|
|
280
|
+
| `getCreateViewQueryDef` | `createView` |
|
|
281
|
+
| `getCreateProcQueryDef` | `createProc` |
|
|
282
|
+
| `getCreateObjectQueryDef` | Table/View/Procedure 자동 판별 |
|
|
283
|
+
| `getDropTableQueryDef` | `dropTable` |
|
|
284
|
+
| `getRenameTableQueryDef` | `renameTable` |
|
|
285
|
+
| `getDropViewQueryDef` | `dropView` |
|
|
286
|
+
| `getDropProcQueryDef` | `dropProc` |
|
|
287
|
+
| `getAddColumnQueryDef` | `addColumn` |
|
|
288
|
+
| `getDropColumnQueryDef` | `dropColumn` |
|
|
289
|
+
| `getModifyColumnQueryDef` | `modifyColumn` |
|
|
290
|
+
| `getRenameColumnQueryDef` | `renameColumn` |
|
|
291
|
+
| `getAddPrimaryKeyQueryDef` | `addPrimaryKey` |
|
|
292
|
+
| `getDropPrimaryKeyQueryDef` | `dropPrimaryKey` |
|
|
293
|
+
| `getAddForeignKeyQueryDef` | `addForeignKey` |
|
|
294
|
+
| `getAddIndexQueryDef` | `addIndex` |
|
|
295
|
+
| `getDropForeignKeyQueryDef` | `dropForeignKey` |
|
|
296
|
+
| `getDropIndexQueryDef` | `dropIndex` |
|
|
297
|
+
| `getClearSchemaQueryDef` | `clearSchema` |
|
|
298
|
+
| `getSchemaExistsQueryDef` | `schemaExists` |
|
|
299
|
+
| `getTruncateQueryDef` | `truncate` |
|
|
300
|
+
| `getSwitchFkQueryDef` | `switchFk` |
|
package/docs/query.md
CHANGED
|
@@ -29,6 +29,61 @@ const hasAdmin = await db.user()
|
|
|
29
29
|
.exists();
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
+
### Queryable API
|
|
33
|
+
|
|
34
|
+
#### 실행 메서드
|
|
35
|
+
|
|
36
|
+
| 메서드 | 시그니처 | 설명 |
|
|
37
|
+
|--------|---------|------|
|
|
38
|
+
| `execute` | `() => Promise<TData[]>` | SELECT 실행, 결과 배열 반환 |
|
|
39
|
+
| `single` | `() => Promise<TData \| undefined>` | 단건 반환 (2건 이상이면 throw) |
|
|
40
|
+
| `first` | `() => Promise<TData \| undefined>` | 첫 번째 결과 반환 |
|
|
41
|
+
| `count` | `(fn?) => Promise<number>` | 행 수 반환. distinct/groupBy 이후에는 wrap() 필요 |
|
|
42
|
+
| `exists` | `() => Promise<boolean>` | 데이터 존재 여부 |
|
|
43
|
+
|
|
44
|
+
#### 조건 메서드 (체이닝)
|
|
45
|
+
|
|
46
|
+
| 메서드 | 시그니처 | 설명 |
|
|
47
|
+
|--------|---------|------|
|
|
48
|
+
| `where` | `(fn: (cols) => WhereExprUnit[]) => Queryable` | WHERE 조건 (여러 번 호출 시 AND 결합) |
|
|
49
|
+
| `search` | `(fn: (cols) => ExprUnit[], text: string) => Queryable` | 텍스트 검색 |
|
|
50
|
+
| `orderBy` | `(fn: (cols) => ExprUnit, dir?) => Queryable` | 정렬 (기본 ASC, 여러 번 호출 가능) |
|
|
51
|
+
| `top` | `(count: number) => Queryable` | 상위 N건 (ORDER BY 없이 사용 가능) |
|
|
52
|
+
| `limit` | `(skip: number, take: number) => Queryable` | 페이징 (ORDER BY 필수) |
|
|
53
|
+
| `select` | `(fn: (cols) => Record) => Queryable` | 컬럼 선택/변환 |
|
|
54
|
+
| `distinct` | `() => Queryable` | 중복 제거 |
|
|
55
|
+
| `lock` | `() => Queryable` | FOR UPDATE 잠금 |
|
|
56
|
+
| `groupBy` | `(fn: (cols) => ExprUnit[]) => Queryable` | 그룹화 |
|
|
57
|
+
| `having` | `(fn: (cols) => WhereExprUnit[]) => Queryable` | 그룹 필터링 |
|
|
58
|
+
|
|
59
|
+
#### JOIN 메서드
|
|
60
|
+
|
|
61
|
+
| 메서드 | 시그니처 | 설명 |
|
|
62
|
+
|--------|---------|------|
|
|
63
|
+
| `join` | `(as, fn: (qr, cols) => Queryable) => Queryable` | LEFT JOIN (1:N, 배열) |
|
|
64
|
+
| `joinSingle` | `(as, fn: (qr, cols) => Queryable) => Queryable` | LEFT JOIN (N:1, 단일 객체) |
|
|
65
|
+
| `include` | `(fn: (item) => PathProxy) => Queryable` | 관계 기반 자동 JOIN |
|
|
66
|
+
|
|
67
|
+
#### 서브쿼리/유틸리티
|
|
68
|
+
|
|
69
|
+
| 메서드 | 시그니처 | 설명 |
|
|
70
|
+
|--------|---------|------|
|
|
71
|
+
| `wrap` | `() => Queryable` | 서브쿼리로 래핑 |
|
|
72
|
+
| `Queryable.union` | `(...queries) => Queryable` | UNION (최소 2개) |
|
|
73
|
+
| `recursive` | `(fn: (cte) => Queryable) => Queryable` | 재귀 CTE |
|
|
74
|
+
|
|
75
|
+
#### CUD 메서드
|
|
76
|
+
|
|
77
|
+
| 메서드 | 시그니처 | 설명 |
|
|
78
|
+
|--------|---------|------|
|
|
79
|
+
| `insert` | `(records, outputColumns?) => Promise` | INSERT (1000건 단위 자동 분할) |
|
|
80
|
+
| `insertIfNotExists` | `(record, outputColumns?) => Promise` | 조건부 INSERT |
|
|
81
|
+
| `insertInto` | `(targetTable, outputColumns?) => Promise` | INSERT INTO ... SELECT |
|
|
82
|
+
| `update` | `(fn: (cols) => Record, outputColumns?) => Promise` | UPDATE |
|
|
83
|
+
| `delete` | `(outputColumns?) => Promise` | DELETE |
|
|
84
|
+
| `upsert` | `(updateFn, insertFn?, outputColumns?) => Promise` | UPSERT (UPDATE or INSERT) |
|
|
85
|
+
| `switchFk` | `(enabled: boolean) => Promise<void>` | FK 제약조건 on/off |
|
|
86
|
+
|
|
32
87
|
### 필터링 (WHERE)
|
|
33
88
|
|
|
34
89
|
```typescript
|
|
@@ -60,7 +115,7 @@ db.user()
|
|
|
60
115
|
.search((c) => [c.name, c.email], "John +admin -withdrawn")
|
|
61
116
|
```
|
|
62
117
|
|
|
63
|
-
검색 문법: `term`(OR), `+term`(AND 필수), `-term`(NOT 제외), `"exact"`(정확히), `wild*`(접두사). 내부적으로 `parseSearchQuery()`를 사용하여 SQL LIKE 패턴으로 변환한다.
|
|
118
|
+
검색 문법: `term`(OR), `+term`(AND 필수), `-term`(NOT 제외), `"exact"`(정확히 + 필수), `wild*`(접두사). 내부적으로 `parseSearchQuery()`를 사용하여 SQL LIKE 패턴으로 변환한다.
|
|
64
119
|
|
|
65
120
|
### 정렬 (ORDER BY)
|
|
66
121
|
|
|
@@ -252,6 +307,12 @@ await db.user()
|
|
|
252
307
|
.where((c) => [expr.eq(c.id, 1)])
|
|
253
308
|
.update((c) => ({ name: expr.val("string", "Alice2") }));
|
|
254
309
|
|
|
310
|
+
// 기존 값 참조
|
|
311
|
+
await db.product()
|
|
312
|
+
.update((p) => ({
|
|
313
|
+
price: expr.mul(p.price, expr.val("number", 1.1)),
|
|
314
|
+
}));
|
|
315
|
+
|
|
255
316
|
// OUTPUT으로 변경된 데이터 반환
|
|
256
317
|
const updated = await db.user()
|
|
257
318
|
.where((c) => [expr.eq(c.id, 1)])
|
|
@@ -320,15 +381,25 @@ await db.connect(async () => {
|
|
|
320
381
|
});
|
|
321
382
|
```
|
|
322
383
|
|
|
384
|
+
### Executable API
|
|
385
|
+
|
|
386
|
+
| 메서드 | 시그니처 | 설명 |
|
|
387
|
+
|--------|---------|------|
|
|
388
|
+
| `execute` | `(params) => Promise<TReturns[][]>` | 프로시저 실행 |
|
|
389
|
+
| `getExecProcQueryDef` | `(params?) => QueryDef` | QueryDef만 생성 (실행 안 함) |
|
|
390
|
+
|
|
323
391
|
---
|
|
324
392
|
|
|
325
393
|
## expr -- 표현식 빌더
|
|
326
394
|
|
|
395
|
+
방언 독립적인 SQL 표현식을 생성한다. JSON AST(Expr)를 생성하며, QueryBuilder가 각 DBMS(MySQL, MSSQL, PostgreSQL)에 맞게 변환한다.
|
|
396
|
+
|
|
327
397
|
### 값/조건
|
|
328
398
|
|
|
329
399
|
| 함수 | 설명 |
|
|
330
400
|
|------|------|
|
|
331
401
|
| `expr.val(type, value)` | 리터럴 값 |
|
|
402
|
+
| `expr.col(type, alias, key)` | 컬럼 참조 |
|
|
332
403
|
| `expr.raw(type)\`sql\`` | Raw SQL (태그 템플릿) |
|
|
333
404
|
| `expr.eq(a, b)` | `=` (NULL 안전) |
|
|
334
405
|
| `expr.gt(a, b)` | `>` |
|
|
@@ -449,6 +520,29 @@ expr.maxOver(c.amount, { partitionBy: [c.dept] })
|
|
|
449
520
|
|
|
450
521
|
---
|
|
451
522
|
|
|
523
|
+
## ExprUnit / WhereExprUnit
|
|
524
|
+
|
|
525
|
+
Queryable 콜백에서 컬럼 참조 시 자동으로 `ExprUnit`으로 래핑된다.
|
|
526
|
+
|
|
527
|
+
```typescript
|
|
528
|
+
// ExprUnit<TPrimitive> -- 타입 안전한 표현식 래퍼
|
|
529
|
+
class ExprUnit<TPrimitive extends ColumnPrimitive> {
|
|
530
|
+
readonly dataType: ColumnPrimitiveStr;
|
|
531
|
+
readonly expr: Expr;
|
|
532
|
+
get n(): ExprUnit<NonNullable<TPrimitive>>; // nullable 제거
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
// WhereExprUnit -- WHERE 절용 표현식 래퍼
|
|
536
|
+
class WhereExprUnit {
|
|
537
|
+
readonly expr: WhereExpr;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
// ExprInput -- ExprUnit 또는 리터럴 값을 받는 입력 타입
|
|
541
|
+
type ExprInput<TPrimitive> = ExprUnit<TPrimitive> | TPrimitive;
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
---
|
|
545
|
+
|
|
452
546
|
## 검색 파서
|
|
453
547
|
|
|
454
548
|
사용자 검색 문법을 SQL LIKE 패턴으로 변환.
|
|
@@ -464,6 +558,87 @@ parseSearchQuery('apple +fruit -rotten "green apple" wild*');
|
|
|
464
558
|
// }
|
|
465
559
|
```
|
|
466
560
|
|
|
561
|
+
### parseSearchQuery API
|
|
562
|
+
|
|
563
|
+
```
|
|
564
|
+
parseSearchQuery(searchText: string): ParsedSearchQuery
|
|
565
|
+
|
|
566
|
+
interface ParsedSearchQuery {
|
|
567
|
+
or: string[]; // OR 조건 (LIKE 패턴)
|
|
568
|
+
must: string[]; // AND 필수 조건 (LIKE 패턴)
|
|
569
|
+
not: string[]; // NOT 제외 조건 (LIKE 패턴)
|
|
570
|
+
}
|
|
571
|
+
```
|
|
572
|
+
|
|
467
573
|
문법: `term`(OR), `+term`(AND 필수), `-term`(NOT 제외), `"exact"`(정확히 + 필수), `wild*`(접두사)
|
|
468
574
|
|
|
469
575
|
이스케이프: `\\` (리터럴 `\`), `\*` (리터럴 `*`), `\%` (리터럴 `%`), `\"` (리터럴 `"`), `\+` (리터럴 `+`), `\-` (리터럴 `-`)
|
|
576
|
+
|
|
577
|
+
---
|
|
578
|
+
|
|
579
|
+
## QueryBuilder
|
|
580
|
+
|
|
581
|
+
QueryDef(JSON AST)를 DBMS별 SQL 문자열로 변환한다.
|
|
582
|
+
|
|
583
|
+
```typescript
|
|
584
|
+
import { createQueryBuilder } from "@simplysm/orm-common";
|
|
585
|
+
import type { Dialect } from "@simplysm/orm-common";
|
|
586
|
+
|
|
587
|
+
const builder = createQueryBuilder("mysql"); // "mysql" | "mssql" | "postgresql"
|
|
588
|
+
const result = builder.build(queryDef);
|
|
589
|
+
// result.sql -> SQL 문자열
|
|
590
|
+
```
|
|
591
|
+
|
|
592
|
+
### createQueryBuilder API
|
|
593
|
+
|
|
594
|
+
```
|
|
595
|
+
createQueryBuilder(dialect: Dialect): QueryBuilderBase
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
| 방언 | 구현 클래스 |
|
|
599
|
+
|------|-----------|
|
|
600
|
+
| `"mysql"` | `MysqlQueryBuilder` |
|
|
601
|
+
| `"mssql"` | `MssqlQueryBuilder` |
|
|
602
|
+
| `"postgresql"` | `PostgresqlQueryBuilder` |
|
|
603
|
+
|
|
604
|
+
---
|
|
605
|
+
|
|
606
|
+
## parseQueryResult
|
|
607
|
+
|
|
608
|
+
DB 쿼리 결과를 ResultMeta 기반으로 TypeScript 객체로 변환한다. 타입 파싱과 JOIN 결과 중첩을 처리한다.
|
|
609
|
+
|
|
610
|
+
```typescript
|
|
611
|
+
import { parseQueryResult } from "@simplysm/orm-common";
|
|
612
|
+
|
|
613
|
+
// 단순 타입 파싱
|
|
614
|
+
const raw = [{ id: "1", createdAt: "2026-01-07T10:00:00.000Z" }];
|
|
615
|
+
const meta = { columns: { id: "number", createdAt: "DateTime" }, joins: {} };
|
|
616
|
+
const result = await parseQueryResult(raw, meta);
|
|
617
|
+
// [{ id: 1, createdAt: DateTime(...) }]
|
|
618
|
+
|
|
619
|
+
// JOIN 결과 중첩
|
|
620
|
+
const raw2 = [
|
|
621
|
+
{ id: 1, name: "User1", "posts.id": 10, "posts.title": "Post1" },
|
|
622
|
+
{ id: 1, name: "User1", "posts.id": 11, "posts.title": "Post2" },
|
|
623
|
+
];
|
|
624
|
+
const meta2 = {
|
|
625
|
+
columns: { id: "number", name: "string", "posts.id": "number", "posts.title": "string" },
|
|
626
|
+
joins: { posts: { isSingle: false } },
|
|
627
|
+
};
|
|
628
|
+
const result2 = await parseQueryResult(raw2, meta2);
|
|
629
|
+
// [{ id: 1, name: "User1", posts: [{ id: 10, title: "Post1" }, { id: 11, title: "Post2" }] }]
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
### parseQueryResult API
|
|
633
|
+
|
|
634
|
+
```
|
|
635
|
+
parseQueryResult<TRecord>(
|
|
636
|
+
rawResults: Record<string, unknown>[],
|
|
637
|
+
meta: ResultMeta,
|
|
638
|
+
): Promise<TRecord[] | undefined>
|
|
639
|
+
|
|
640
|
+
interface ResultMeta {
|
|
641
|
+
columns: Record<string, ColumnPrimitiveStr>;
|
|
642
|
+
joins: Record<string, { isSingle: boolean }>;
|
|
643
|
+
}
|
|
644
|
+
```
|
package/docs/schema.md
CHANGED
|
@@ -37,6 +37,22 @@ const User = Table("user")
|
|
|
37
37
|
}));
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
+
### Table API
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
Table(name: string): TableBuilder
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
| 메서드 | 시그니처 | 설명 |
|
|
47
|
+
|--------|---------|------|
|
|
48
|
+
| `description` | `(desc: string) => TableBuilder` | 테이블 설명 (DDL 코멘트) |
|
|
49
|
+
| `database` | `(db: string) => TableBuilder` | 데이터베이스 이름 |
|
|
50
|
+
| `schema` | `(schema: string) => TableBuilder` | 스키마 이름 (MSSQL: dbo, PostgreSQL: public) |
|
|
51
|
+
| `columns` | `(fn: (c) => Record) => TableBuilder` | 컬럼 정의 |
|
|
52
|
+
| `primaryKey` | `(...columns: string[]) => TableBuilder` | PK 설정 (복합 PK 지원) |
|
|
53
|
+
| `indexes` | `(fn: (i) => IndexBuilder[]) => TableBuilder` | 인덱스 정의 |
|
|
54
|
+
| `relations` | `(fn: (r) => Record) => TableBuilder` | 관계 정의 |
|
|
55
|
+
|
|
40
56
|
### 컬럼 타입
|
|
41
57
|
|
|
42
58
|
| 메서드 | SQL 타입 | TypeScript 타입 |
|
|
@@ -115,6 +131,22 @@ View에서도 사용 가능. DB에 FK 제약조건을 생성하지 않는다.
|
|
|
115
131
|
}))
|
|
116
132
|
```
|
|
117
133
|
|
|
134
|
+
### 관계 빌더 API
|
|
135
|
+
|
|
136
|
+
| 빌더 | 용도 | DB FK 생성 |
|
|
137
|
+
|------|------|----------|
|
|
138
|
+
| `ForeignKeyBuilder` | N:1 관계 (FK 컬럼 소유) | O |
|
|
139
|
+
| `ForeignKeyTargetBuilder` | 1:N / 1:1 역참조 | O (대상 테이블) |
|
|
140
|
+
| `RelationKeyBuilder` | N:1 논리적 관계 | X |
|
|
141
|
+
| `RelationKeyTargetBuilder` | 1:N / 1:1 논리적 역참조 | X |
|
|
142
|
+
|
|
143
|
+
공통 메서드:
|
|
144
|
+
|
|
145
|
+
| 메서드 | 설명 |
|
|
146
|
+
|--------|------|
|
|
147
|
+
| `.description(desc)` | 관계 설명 |
|
|
148
|
+
| `.single()` | 1:1 관계 (ForeignKeyTargetBuilder, RelationKeyTargetBuilder만 해당) |
|
|
149
|
+
|
|
118
150
|
---
|
|
119
151
|
|
|
120
152
|
## View
|
|
@@ -139,6 +171,20 @@ const UserSummary = View("user_summary")
|
|
|
139
171
|
}));
|
|
140
172
|
```
|
|
141
173
|
|
|
174
|
+
### View API
|
|
175
|
+
|
|
176
|
+
```
|
|
177
|
+
View(name: string): ViewBuilder
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
| 메서드 | 시그니처 | 설명 |
|
|
181
|
+
|--------|---------|------|
|
|
182
|
+
| `description` | `(desc: string) => ViewBuilder` | 뷰 설명 |
|
|
183
|
+
| `database` | `(db: string) => ViewBuilder` | 데이터베이스 이름 |
|
|
184
|
+
| `schema` | `(schema: string) => ViewBuilder` | 스키마 이름 |
|
|
185
|
+
| `query` | `(viewFn: (db) => Queryable) => ViewBuilder` | 뷰 쿼리 정의 |
|
|
186
|
+
| `relations` | `(fn: (r) => Record) => ViewBuilder` | 관계 정의 (relationKey만 가능) |
|
|
187
|
+
|
|
142
188
|
**DbContext 등록:**
|
|
143
189
|
|
|
144
190
|
```typescript
|
|
@@ -173,6 +219,21 @@ const GetUserOrders = Procedure("get_user_orders")
|
|
|
173
219
|
`);
|
|
174
220
|
```
|
|
175
221
|
|
|
222
|
+
### Procedure API
|
|
223
|
+
|
|
224
|
+
```
|
|
225
|
+
Procedure(name: string): ProcedureBuilder
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
| 메서드 | 시그니처 | 설명 |
|
|
229
|
+
|--------|---------|------|
|
|
230
|
+
| `description` | `(desc: string) => ProcedureBuilder` | 프로시저 설명 |
|
|
231
|
+
| `database` | `(db: string) => ProcedureBuilder` | 데이터베이스 이름 |
|
|
232
|
+
| `schema` | `(schema: string) => ProcedureBuilder` | 스키마 이름 |
|
|
233
|
+
| `params` | `(fn: (c) => Record) => ProcedureBuilder` | 파라미터 정의 |
|
|
234
|
+
| `returns` | `(fn: (c) => Record) => ProcedureBuilder` | 반환 타입 정의 |
|
|
235
|
+
| `body` | `(sql: string) => ProcedureBuilder` | 프로시저 본문 SQL |
|
|
236
|
+
|
|
176
237
|
**DbContext 등록:**
|
|
177
238
|
|
|
178
239
|
```typescript
|
|
@@ -197,6 +258,16 @@ MSSQL은 파라미터에 `@` 접두사 필요: `@userId`, `@fromDate`
|
|
|
197
258
|
])
|
|
198
259
|
```
|
|
199
260
|
|
|
261
|
+
### IndexBuilder API
|
|
262
|
+
|
|
263
|
+
| 메서드 | 시그니처 | 설명 |
|
|
264
|
+
|--------|---------|------|
|
|
265
|
+
| `index` | `(...columns: string[]) => IndexBuilder` | 인덱스 생성 (단일/복합) |
|
|
266
|
+
| `unique` | `() => IndexBuilder` | 유니크 인덱스 설정 |
|
|
267
|
+
| `orderBy` | `(...dirs: ("ASC"\|"DESC")[]) => IndexBuilder` | 컬럼별 정렬 방향 |
|
|
268
|
+
| `name` | `(name: string) => IndexBuilder` | 커스텀 인덱스 이름 |
|
|
269
|
+
| `description` | `(desc: string) => IndexBuilder` | 인덱스 설명 |
|
|
270
|
+
|
|
200
271
|
---
|
|
201
272
|
|
|
202
273
|
## defineDbContext / createDbContext
|
|
@@ -235,4 +306,20 @@ const db = createDbContext(MyDb, executor, {
|
|
|
235
306
|
});
|
|
236
307
|
```
|
|
237
308
|
|
|
309
|
+
```
|
|
310
|
+
createDbContext(
|
|
311
|
+
def: DbContextDef,
|
|
312
|
+
executor: DbContextExecutor,
|
|
313
|
+
opt: { database: string; schema?: string },
|
|
314
|
+
): DbContextInstance
|
|
315
|
+
```
|
|
316
|
+
|
|
238
317
|
`executor`는 `DbContextExecutor` 인터페이스를 구현해야 한다 (`@simplysm/orm-node`의 `NodeDbContextExecutor` 등).
|
|
318
|
+
|
|
319
|
+
생성된 인스턴스는 다음을 포함한다:
|
|
320
|
+
- 등록된 테이블/뷰에 대한 `Queryable` 접근자 (예: `db.user()`, `db.order()`)
|
|
321
|
+
- 등록된 프로시저에 대한 `Executable` 접근자 (예: `db.getUserOrders()`)
|
|
322
|
+
- 연결/트랜잭션 관리 메서드
|
|
323
|
+
- DDL 실행 메서드
|
|
324
|
+
- `initialize()` 메서드
|
|
325
|
+
- `_migration()` 시스템 테이블 접근자
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@simplysm/orm-common",
|
|
3
|
-
"version": "13.0.
|
|
3
|
+
"version": "13.0.96",
|
|
4
4
|
"description": "Simplysm Package - ORM Module (common)",
|
|
5
5
|
"author": "simplysm",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -20,6 +20,6 @@
|
|
|
20
20
|
],
|
|
21
21
|
"sideEffects": false,
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@simplysm/core-common": "13.0.
|
|
23
|
+
"@simplysm/core-common": "13.0.96"
|
|
24
24
|
}
|
|
25
25
|
}
|