@simplysm/orm-common 14.0.50 → 14.0.52
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/dist/exec/queryable.d.ts +1 -1
- package/dist/exec/queryable.d.ts.map +1 -1
- package/dist/exec/queryable.js +8 -2
- package/dist/exec/queryable.js.map +1 -1
- package/package.json +3 -4
- package/src/exec/queryable.ts +10 -3
- package/README.md +0 -136
- package/docs/core/db-context.md +0 -208
- package/docs/core/db-transaction-error.md +0 -64
- package/docs/expression/expr-unit.md +0 -62
- package/docs/expression/expr.md +0 -198
- package/docs/models/migration.md +0 -37
- package/docs/query-builder/create-query-builder.md +0 -80
- package/docs/queryable-executable/executable.md +0 -54
- package/docs/queryable-executable/parse-search-query.md +0 -75
- package/docs/queryable-executable/queryable.md +0 -238
- package/docs/schema-builders/column-builder.md +0 -63
- package/docs/schema-builders/foreign-key-builder.md +0 -137
- package/docs/schema-builders/index-builder.md +0 -54
- package/docs/schema-builders/procedure.md +0 -67
- package/docs/schema-builders/table.md +0 -94
- package/docs/schema-builders/view.md +0 -71
- package/docs/types/data-type.md +0 -146
- package/docs/types/dialect.md +0 -151
- package/docs/types/expr.md +0 -175
- package/docs/types/parse-query-result.md +0 -58
- package/docs/types/query-def.md +0 -224
package/docs/core/db-context.md
DELETED
|
@@ -1,208 +0,0 @@
|
|
|
1
|
-
# DbContext
|
|
2
|
-
|
|
3
|
-
DB 연결/트랜잭션/DDL/초기화를 제공하는 추상 클래스. `queryable()`/`executable()`로 테이블/프로시저를 class 프로퍼티로 등록하며, 각 프로퍼티가 독립 직렬화되어 40+ 테이블에서도 TS7056이 발생하지 않는다.
|
|
4
|
-
|
|
5
|
-
```typescript
|
|
6
|
-
export abstract class DbContext implements DbContextBase {
|
|
7
|
-
status: DbContextStatus;
|
|
8
|
-
_migration: () => Queryable<...>;
|
|
9
|
-
migrations: Migration[];
|
|
10
|
-
|
|
11
|
-
constructor(
|
|
12
|
-
executor: DbContextExecutor,
|
|
13
|
-
opt: { database: string; schema?: string },
|
|
14
|
-
);
|
|
15
|
-
}
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
## Members
|
|
19
|
-
|
|
20
|
-
### 상태 / 메타데이터
|
|
21
|
-
|
|
22
|
-
| Member | Kind | Type | Description |
|
|
23
|
-
|--------|------|------|-------------|
|
|
24
|
-
| `status` | property | `DbContextStatus` | 현재 연결 상태 (`"ready"` \| `"connect"` \| `"transact"`) |
|
|
25
|
-
| `database` | getter | `string \| undefined` | Database 이름 |
|
|
26
|
-
| `schema` | getter | `string \| undefined` | Schema 이름 |
|
|
27
|
-
| `migrations` | property | `Migration[]` | 마이그레이션 정의 배열. 서브클래스에서 오버라이드 |
|
|
28
|
-
| `_migration` | property | `() => Queryable<...>` | 시스템 마이그레이션 테이블 쿼리어블 |
|
|
29
|
-
|
|
30
|
-
### 등록 메서드
|
|
31
|
-
|
|
32
|
-
| Member | Kind | Type | Description |
|
|
33
|
-
|--------|------|------|-------------|
|
|
34
|
-
| `queryable(builder)` | method (protected) | `() => Queryable<T>` | 테이블/뷰 쿼리어블 등록. 반환값을 class 프로퍼티에 할당 |
|
|
35
|
-
| `executable(builder)` | method (protected) | `() => Executable<TParams, TReturns>` | 프로시저 실행 래퍼 등록 |
|
|
36
|
-
|
|
37
|
-
### 연결 관리
|
|
38
|
-
|
|
39
|
-
| Member | Kind | Type | Description |
|
|
40
|
-
|--------|------|------|-------------|
|
|
41
|
-
| `connect(fn, isolationLevel?)` | method | `Promise<TResult>` | 연결 → 트랜잭션 시작 → fn → 커밋 → 종료 |
|
|
42
|
-
| `connectWithoutTransaction(fn)` | method | `Promise<TResult>` | 연결 → fn → 종료. 트랜잭션 없는 DDL/읽기 작업에 사용 |
|
|
43
|
-
| `transaction(fn, isolationLevel?)` | method | `Promise<TResult>` | 이미 연결된 상태에서 부분 트랜잭션 시작 |
|
|
44
|
-
|
|
45
|
-
### DDL 실행 메서드
|
|
46
|
-
|
|
47
|
-
| Member | Kind | Type | Description |
|
|
48
|
-
|--------|------|------|-------------|
|
|
49
|
-
| `createTable(table)` | method | `Promise<void>` | CREATE TABLE |
|
|
50
|
-
| `dropTable(table)` | method | `Promise<void>` | DROP TABLE |
|
|
51
|
-
| `renameTable(table, newName)` | method | `Promise<void>` | RENAME TABLE |
|
|
52
|
-
| `createView(view)` | method | `Promise<void>` | CREATE VIEW |
|
|
53
|
-
| `dropView(view)` | method | `Promise<void>` | DROP VIEW |
|
|
54
|
-
| `createProc(procedure)` | method | `Promise<void>` | CREATE PROCEDURE |
|
|
55
|
-
| `dropProc(procedure)` | method | `Promise<void>` | DROP PROCEDURE |
|
|
56
|
-
| `addColumn(table, columnName, column)` | method | `Promise<void>` | ADD COLUMN |
|
|
57
|
-
| `dropColumn(table, column)` | method | `Promise<void>` | DROP COLUMN |
|
|
58
|
-
| `modifyColumn(table, columnName, column)` | method | `Promise<void>` | MODIFY/ALTER COLUMN |
|
|
59
|
-
| `renameColumn(table, column, newName)` | method | `Promise<void>` | RENAME COLUMN |
|
|
60
|
-
| `addPrimaryKey(table, columns)` | method | `Promise<void>` | ADD PRIMARY KEY |
|
|
61
|
-
| `dropPrimaryKey(table)` | method | `Promise<void>` | DROP PRIMARY KEY |
|
|
62
|
-
| `addForeignKey(table, relationName, relationDef)` | method | `Promise<void>` | ADD FOREIGN KEY |
|
|
63
|
-
| `addIndex(table, indexBuilder)` | method | `Promise<void>` | ADD INDEX |
|
|
64
|
-
| `dropForeignKey(table, relationName)` | method | `Promise<void>` | DROP FOREIGN KEY |
|
|
65
|
-
| `dropIndex(table, columns)` | method | `Promise<void>` | DROP INDEX |
|
|
66
|
-
| `clearSchema(params)` | method | `Promise<void>` | 스키마 내 모든 객체 제거 |
|
|
67
|
-
| `schemaExists(database, schema?)` | method | `Promise<boolean>` | 스키마 존재 여부 확인 |
|
|
68
|
-
| `truncate(table)` | method | `Promise<void>` | TRUNCATE TABLE |
|
|
69
|
-
| `switchFk(table, enabled)` | method | `Promise<void>` | FK 제약조건 활성화/비활성화 |
|
|
70
|
-
|
|
71
|
-
### DDL QueryDef 생성기
|
|
72
|
-
|
|
73
|
-
직접 실행하지 않고 `QueryDef`만 반환한다. `executeDefs()`로 수동 실행할 때 사용.
|
|
74
|
-
|
|
75
|
-
| Member | Kind | Type | Description |
|
|
76
|
-
|--------|------|------|-------------|
|
|
77
|
-
| `getCreateTableQueryDef(table)` | method | `QueryDef` | CREATE TABLE QueryDef |
|
|
78
|
-
| `getCreateViewQueryDef(view)` | method | `QueryDef` | CREATE VIEW QueryDef |
|
|
79
|
-
| `getCreateProcQueryDef(procedure)` | method | `QueryDef` | CREATE PROCEDURE QueryDef |
|
|
80
|
-
| `getCreateObjectQueryDef(builder)` | method | `QueryDef` | Table/View/Procedure 구분 없이 CREATE QueryDef |
|
|
81
|
-
| `getDropTableQueryDef(table)` | method | `QueryDef` | DROP TABLE QueryDef |
|
|
82
|
-
| `getRenameTableQueryDef(table, newName)` | method | `QueryDef` | RENAME TABLE QueryDef |
|
|
83
|
-
| `getDropViewQueryDef(view)` | method | `QueryDef` | DROP VIEW QueryDef |
|
|
84
|
-
| `getDropProcQueryDef(procedure)` | method | `QueryDef` | DROP PROCEDURE QueryDef |
|
|
85
|
-
| `getAddColumnQueryDef(table, columnName, column)` | method | `QueryDef` | ADD COLUMN QueryDef |
|
|
86
|
-
| `getDropColumnQueryDef(table, column)` | method | `QueryDef` | DROP COLUMN QueryDef |
|
|
87
|
-
| `getModifyColumnQueryDef(table, columnName, column)` | method | `QueryDef` | MODIFY COLUMN QueryDef |
|
|
88
|
-
| `getRenameColumnQueryDef(table, column, newName)` | method | `QueryDef` | RENAME COLUMN QueryDef |
|
|
89
|
-
| `getAddPrimaryKeyQueryDef(table, columns)` | method | `QueryDef` | ADD PK QueryDef |
|
|
90
|
-
| `getDropPrimaryKeyQueryDef(table)` | method | `QueryDef` | DROP PK QueryDef |
|
|
91
|
-
| `getAddForeignKeyQueryDef(table, relationName, relationDef)` | method | `QueryDef` | ADD FK QueryDef |
|
|
92
|
-
| `getAddIndexQueryDef(table, indexBuilder)` | method | `QueryDef` | ADD INDEX QueryDef |
|
|
93
|
-
| `getDropForeignKeyQueryDef(table, relationName)` | method | `QueryDef` | DROP FK QueryDef |
|
|
94
|
-
| `getDropIndexQueryDef(table, columns)` | method | `QueryDef` | DROP INDEX QueryDef |
|
|
95
|
-
| `getClearSchemaQueryDef(params)` | method | `QueryDef` | Clear Schema QueryDef |
|
|
96
|
-
| `getSchemaExistsQueryDef(database, schema?)` | method | `QueryDef` | Schema Exists QueryDef |
|
|
97
|
-
| `getTruncateQueryDef(table)` | method | `QueryDef` | TRUNCATE QueryDef |
|
|
98
|
-
| `getSwitchFkQueryDef(table, enabled)` | method | `QueryDef` | Switch FK QueryDef |
|
|
99
|
-
|
|
100
|
-
### 기타
|
|
101
|
-
|
|
102
|
-
| Member | Kind | Type | Description |
|
|
103
|
-
|--------|------|------|-------------|
|
|
104
|
-
| `getNextAlias()` | method | `string` | 다음 테이블 별칭 생성 (`T1`, `T2`, ...) |
|
|
105
|
-
| `resetAliasCounter()` | method | `void` | 별칭 카운터 초기화 |
|
|
106
|
-
| `executeDefs<T>(defs, resultMetas?)` | method | `Promise<T[][]>` | QueryDef 배열 직접 실행 |
|
|
107
|
-
| `getQueryDefObjectName(tableOrView)` | method | `QueryDefObjectName` | 테이블/뷰의 QueryDef 객체명 반환 |
|
|
108
|
-
| `initialize(options?)` | method | `Promise<boolean>` | Code First 초기화 + 마이그레이션 실행 |
|
|
109
|
-
|
|
110
|
-
## Related Types
|
|
111
|
-
|
|
112
|
-
### `DbContextBase`
|
|
113
|
-
|
|
114
|
-
Queryable, Executable, ViewBuilder 내부에서 사용하는 DbContext 인터페이스.
|
|
115
|
-
|
|
116
|
-
```typescript
|
|
117
|
-
export interface DbContextBase {
|
|
118
|
-
status: DbContextStatus;
|
|
119
|
-
readonly database: string | undefined;
|
|
120
|
-
readonly schema: string | undefined;
|
|
121
|
-
getNextAlias(): string;
|
|
122
|
-
resetAliasCounter(): void;
|
|
123
|
-
executeDefs<T = DataRecord>(
|
|
124
|
-
defs: QueryDef[],
|
|
125
|
-
resultMetas?: (ResultMeta | undefined)[],
|
|
126
|
-
): Promise<T[][]>;
|
|
127
|
-
getQueryDefObjectName(
|
|
128
|
-
tableOrView: TableBuilder<any, any> | ViewBuilder<any, any, any>,
|
|
129
|
-
): QueryDefObjectName;
|
|
130
|
-
switchFk(table: QueryDefObjectName, enabled: boolean): Promise<void>;
|
|
131
|
-
}
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
### `DbContextStatus`
|
|
135
|
-
|
|
136
|
-
```typescript
|
|
137
|
-
export type DbContextStatus = "ready" | "connect" | "transact";
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
| 값 | 설명 |
|
|
141
|
-
|----|------|
|
|
142
|
-
| `"ready"` | 연결 없음. `connect()`/`connectWithoutTransaction()` 호출 가능 |
|
|
143
|
-
| `"connect"` | 연결됨. 트랜잭션 없는 상태 |
|
|
144
|
-
| `"transact"` | 트랜잭션 진행 중 |
|
|
145
|
-
|
|
146
|
-
### `DbContextDdlMethods`
|
|
147
|
-
|
|
148
|
-
`DbContext`가 구현하는 DDL 메서드 전체 인터페이스. DDL 실행 메서드(`createTable`, `dropTable`, ...) 및 QueryDef 생성 메서드(`getCreateTableQueryDef`, ...) 모두 포함.
|
|
149
|
-
|
|
150
|
-
```typescript
|
|
151
|
-
export interface DbContextDdlMethods {
|
|
152
|
-
createTable(table: TableBuilder<any, any>): Promise<void>;
|
|
153
|
-
dropTable(table: QueryDefObjectName): Promise<void>;
|
|
154
|
-
// ... (DbContext의 DDL 메서드 시그니처와 동일)
|
|
155
|
-
}
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
### `SD_BUILDER`
|
|
159
|
-
|
|
160
|
-
`DbContext.queryable()`/`executable()`로 등록된 프로퍼티에 부착된 빌더 참조용 Symbol.
|
|
161
|
-
|
|
162
|
-
```typescript
|
|
163
|
-
export const SD_BUILDER: unique symbol;
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
## 연결/트랜잭션 패턴
|
|
167
|
-
|
|
168
|
-
| 메서드 | 용도 |
|
|
169
|
-
|--------|------|
|
|
170
|
-
| `connect(fn)` | 연결 → 트랜잭션 시작 → fn → 커밋 → 종료. 일반 DML 작업에 사용 |
|
|
171
|
-
| `connectWithoutTransaction(fn)` | 연결 → fn → 종료. 트랜잭션 없는 DDL/읽기 전용 작업에 사용 |
|
|
172
|
-
| `transaction(fn)` | 이미 연결된 상태에서 부분 트랜잭션 시작. `connectWithoutTransaction` 내부에서 사용 |
|
|
173
|
-
|
|
174
|
-
- `connect()`/`connectWithoutTransaction()`은 status가 `"ready"`가 아니면 에러를 던진다 (재진입 방지).
|
|
175
|
-
- 트랜잭션 중 DDL 실행은 런타임 에러를 발생시킨다.
|
|
176
|
-
- 롤백 실패 시 원래 에러의 `cause`에 롤백 에러를 첨부하여 전파한다.
|
|
177
|
-
|
|
178
|
-
## Usage
|
|
179
|
-
|
|
180
|
-
```typescript
|
|
181
|
-
class MainDb extends DbContext {
|
|
182
|
-
user = this.queryable(User);
|
|
183
|
-
post = this.queryable(Post);
|
|
184
|
-
activeUsers = this.queryable(ActiveUsers);
|
|
185
|
-
getUserById = this.executable(GetUserById);
|
|
186
|
-
|
|
187
|
-
migrations = [{ name: "001", up: async (db) => { await db.createTable(User); } }];
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
const db = new MainDb(executor, { database: "mydb", schema: "dbo" });
|
|
191
|
-
|
|
192
|
-
// 일반 DML (트랜잭션 포함)
|
|
193
|
-
await db.connect(async () => {
|
|
194
|
-
const users = await db.user().execute();
|
|
195
|
-
await db.user().insert([{ name: "Alice", createdAt: DateTime.now() }]);
|
|
196
|
-
});
|
|
197
|
-
|
|
198
|
-
// DDL (트랜잭션 없음)
|
|
199
|
-
await db.connectWithoutTransaction(async () => {
|
|
200
|
-
await db.createTable(User);
|
|
201
|
-
await db.addColumn({ name: "User" }, "phone", phoneColumn);
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
// Code First 초기화 + 마이그레이션
|
|
205
|
-
await db.connectWithoutTransaction(async () => {
|
|
206
|
-
await db.initialize();
|
|
207
|
-
});
|
|
208
|
-
```
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
# DbTransactionError
|
|
2
|
-
|
|
3
|
-
DBMS별 네이티브 트랜잭션 에러를 표준화된 에러 코드로 래핑하는 에러 클래스. DBMS 독립적인 에러 처리를 지원한다.
|
|
4
|
-
|
|
5
|
-
```typescript
|
|
6
|
-
export class DbTransactionError extends Error {
|
|
7
|
-
override readonly name = "DbTransactionError";
|
|
8
|
-
|
|
9
|
-
constructor(
|
|
10
|
-
public readonly code: DbErrorCode,
|
|
11
|
-
message: string,
|
|
12
|
-
public readonly originalError?: unknown,
|
|
13
|
-
);
|
|
14
|
-
}
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
## Members
|
|
18
|
-
|
|
19
|
-
| Member | Kind | Type | Description |
|
|
20
|
-
|--------|------|------|-------------|
|
|
21
|
-
| `name` | property | `"DbTransactionError"` | 에러 이름 |
|
|
22
|
-
| `code` | property | `DbErrorCode` | 표준화된 에러 코드 |
|
|
23
|
-
| `originalError` | property | `unknown \| undefined` | 원본 DBMS 에러 (디버깅용) |
|
|
24
|
-
|
|
25
|
-
## Related Types
|
|
26
|
-
|
|
27
|
-
### `DbErrorCode`
|
|
28
|
-
|
|
29
|
-
트랜잭션 관련 에러 코드. DBMS별 네이티브 에러 코드를 추상화한다.
|
|
30
|
-
|
|
31
|
-
```typescript
|
|
32
|
-
export enum DbErrorCode {
|
|
33
|
-
NO_ACTIVE_TRANSACTION = "NO_ACTIVE_TRANSACTION",
|
|
34
|
-
TRANSACTION_ALREADY_STARTED = "TRANSACTION_ALREADY_STARTED",
|
|
35
|
-
DEADLOCK = "DEADLOCK",
|
|
36
|
-
LOCK_TIMEOUT = "LOCK_TIMEOUT",
|
|
37
|
-
}
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
| 값 | 설명 |
|
|
41
|
-
|----|------|
|
|
42
|
-
| `NO_ACTIVE_TRANSACTION` | 활성 트랜잭션 없음 (ROLLBACK 시 트랜잭션 없음) |
|
|
43
|
-
| `TRANSACTION_ALREADY_STARTED` | 트랜잭션 이미 시작됨 |
|
|
44
|
-
| `DEADLOCK` | 데드락 발생 |
|
|
45
|
-
| `LOCK_TIMEOUT` | 잠금 타임아웃 |
|
|
46
|
-
|
|
47
|
-
## Usage
|
|
48
|
-
|
|
49
|
-
```typescript
|
|
50
|
-
try {
|
|
51
|
-
await executor.rollbackTransaction();
|
|
52
|
-
} catch (err) {
|
|
53
|
-
if (err instanceof DbTransactionError) {
|
|
54
|
-
if (err.code === DbErrorCode.NO_ACTIVE_TRANSACTION) {
|
|
55
|
-
// 이미 롤백된 경우 무시
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
if (err.code === DbErrorCode.DEADLOCK) {
|
|
59
|
-
// 데드락 재시도 로직
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
throw err;
|
|
63
|
-
}
|
|
64
|
-
```
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
# ExprUnit
|
|
2
|
-
|
|
3
|
-
타입 안전 표현식 래퍼. TypeScript 제네릭으로 표현식의 반환 타입을 추적한다. `expr.*` 함수들이 반환하며, `Queryable` 콜백에서 column 참조에 사용된다.
|
|
4
|
-
|
|
5
|
-
```typescript
|
|
6
|
-
export class ExprUnit<TPrimitive extends ColumnPrimitive> {
|
|
7
|
-
readonly $infer!: TPrimitive;
|
|
8
|
-
|
|
9
|
-
get n(): ExprUnit<NonNullable<TPrimitive>>;
|
|
10
|
-
|
|
11
|
-
constructor(
|
|
12
|
-
readonly dataType: ColumnPrimitiveStr,
|
|
13
|
-
readonly expr: Expr,
|
|
14
|
-
);
|
|
15
|
-
}
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
## Members
|
|
19
|
-
|
|
20
|
-
| Member | Kind | Type | Description |
|
|
21
|
-
|--------|------|------|-------------|
|
|
22
|
-
| `$infer` | property | `TPrimitive` | 타입 추론용 마커 (런타임 미사용) |
|
|
23
|
-
| `n` | getter | `ExprUnit<NonNullable<TPrimitive>>` | nullable 타입을 non-nullable로 좁힘 |
|
|
24
|
-
| `dataType` | property | `ColumnPrimitiveStr` | 표현식 반환 타입 이름 |
|
|
25
|
-
| `expr` | property | `Expr` | 표현식 AST |
|
|
26
|
-
|
|
27
|
-
## Related Types
|
|
28
|
-
|
|
29
|
-
### `WhereExprUnit`
|
|
30
|
-
|
|
31
|
-
WHERE 절용 표현식 래퍼. `expr.eq()`, `expr.gt()`, `expr.like()` 등 비교/논리 연산자가 반환한다.
|
|
32
|
-
|
|
33
|
-
```typescript
|
|
34
|
-
export class WhereExprUnit {
|
|
35
|
-
constructor(readonly expr: WhereExpr);
|
|
36
|
-
}
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
### `ExprInput<TPrimitive>`
|
|
40
|
-
|
|
41
|
-
`ExprUnit` 또는 리터럴 값을 모두 받는 입력 타입. `expr.*` 함수의 파라미터에 사용된다.
|
|
42
|
-
|
|
43
|
-
```typescript
|
|
44
|
-
export type ExprInput<TPrimitive extends ColumnPrimitive> = ExprUnit<TPrimitive> | TPrimitive;
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
## Usage
|
|
48
|
-
|
|
49
|
-
```typescript
|
|
50
|
-
// ExprUnit은 주로 Queryable 콜백의 column 프록시에서 만남
|
|
51
|
-
db.user().where((u) => [
|
|
52
|
-
// u.isActive 가 ExprUnit<boolean>
|
|
53
|
-
expr.eq(u.isActive, true),
|
|
54
|
-
]);
|
|
55
|
-
|
|
56
|
-
// ExprInput 덕분에 리터럴 값도 직접 전달 가능
|
|
57
|
-
expr.eq(u.age, 18) // ExprInput<number> → 18 (리터럴)
|
|
58
|
-
expr.eq(u.age, u.minAge) // ExprInput<number> → ExprUnit<number>
|
|
59
|
-
|
|
60
|
-
// .n 으로 nullable 제거 후 연산
|
|
61
|
-
const nonNullName: ExprUnit<string> = u.name.n;
|
|
62
|
-
```
|
package/docs/expression/expr.md
DELETED
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
# expr
|
|
2
|
-
|
|
3
|
-
Dialect 독립적 SQL 표현식 빌더 네임스페이스. SQL 문자열 대신 JSON AST(`Expr`)를 생성하며, `QueryBuilder`가 각 DBMS(MySQL, MSSQL, PostgreSQL)로 변환한다.
|
|
4
|
-
|
|
5
|
-
```typescript
|
|
6
|
-
export const expr: { ... };
|
|
7
|
-
```
|
|
8
|
-
|
|
9
|
-
## 값 생성
|
|
10
|
-
|
|
11
|
-
| 함수 | 시그니처 | 설명 |
|
|
12
|
-
|------|----------|------|
|
|
13
|
-
| `val(dataType, value)` | `(TStr, T) => ExprUnit<T>` | 리터럴 값을 ExprUnit으로 래핑 |
|
|
14
|
-
| `col(dataType, ...path)` | `(ColumnPrimitiveStr, ...string[]) => ExprUnit<...>` | Column 참조 생성 (내부 사용) |
|
|
15
|
-
| `raw(dataType)` | `(TStr) => (strings, ...values) => ExprUnit<...>` | Raw SQL 태그드 템플릿. 보간 값은 자동 파라미터화 |
|
|
16
|
-
| `toExpr(value)` | `(ExprInput<T>) => Expr` | ExprInput을 Expr AST로 변환 (내부/커스텀 빌더용) |
|
|
17
|
-
|
|
18
|
-
## WHERE 조건 — 비교
|
|
19
|
-
|
|
20
|
-
| 함수 | 설명 |
|
|
21
|
-
|------|------|
|
|
22
|
-
| `eq(source, target)` | `=` (NULL 안전 비교. MySQL: `<=>`, MSSQL/PG: `IS NULL OR =`) |
|
|
23
|
-
| `gt(source, target)` | `>` 초과 |
|
|
24
|
-
| `lt(source, target)` | `<` 미만 |
|
|
25
|
-
| `gte(source, target)` | `>=` 이상 |
|
|
26
|
-
| `lte(source, target)` | `<=` 이하 |
|
|
27
|
-
| `between(source, from?, to?)` | `BETWEEN`. `from`/`to` undefined 시 해당 방향 제한 없음 |
|
|
28
|
-
|
|
29
|
-
## WHERE 조건 — NULL 검사
|
|
30
|
-
|
|
31
|
-
| 함수 | 설명 |
|
|
32
|
-
|------|------|
|
|
33
|
-
| `null(source)` | `IS NULL` |
|
|
34
|
-
|
|
35
|
-
## WHERE 조건 — 문자열 검색
|
|
36
|
-
|
|
37
|
-
| 함수 | 설명 |
|
|
38
|
-
|------|------|
|
|
39
|
-
| `like(source, pattern)` | `LIKE` 패턴 매칭 (`%` `_` 와일드카드) |
|
|
40
|
-
| `regexp(source, pattern)` | 정규식 매칭 (DBMS별 구문 차이 있음) |
|
|
41
|
-
|
|
42
|
-
## WHERE 조건 — IN
|
|
43
|
-
|
|
44
|
-
| 함수 | 설명 |
|
|
45
|
-
|------|------|
|
|
46
|
-
| `in(source, values)` | `IN (...)` 값 목록 비교 |
|
|
47
|
-
| `inQuery(source, query)` | `IN (SELECT ...)` 서브쿼리 비교. 쿼리는 단일 column SELECT 필요 |
|
|
48
|
-
| `exists(query)` | `EXISTS (SELECT ...)` |
|
|
49
|
-
|
|
50
|
-
## WHERE 조건 — 논리 연산자
|
|
51
|
-
|
|
52
|
-
| 함수 | 설명 |
|
|
53
|
-
|------|------|
|
|
54
|
-
| `not(condition)` | `NOT` |
|
|
55
|
-
| `and(conditions)` | `AND` 결합. 빈 배열 허용 안 함 |
|
|
56
|
-
| `or(conditions)` | `OR` 결합. 빈 배열 허용 안 함 |
|
|
57
|
-
|
|
58
|
-
## SELECT — 문자열
|
|
59
|
-
|
|
60
|
-
| 함수 | 설명 |
|
|
61
|
-
|------|------|
|
|
62
|
-
| `concat(...args)` | `CONCAT(...)` — NULL은 빈 문자열 처리 |
|
|
63
|
-
| `left(source, length)` | `LEFT(source, n)` |
|
|
64
|
-
| `right(source, length)` | `RIGHT(source, n)` |
|
|
65
|
-
| `trim(source)` | `TRIM(source)` |
|
|
66
|
-
| `padStart(source, length, fillString)` | `LPAD(source, n, fill)` |
|
|
67
|
-
| `replace(source, from, to)` | `REPLACE(source, from, to)` |
|
|
68
|
-
| `upper(source)` | `UPPER(source)` |
|
|
69
|
-
| `lower(source)` | `LOWER(source)` |
|
|
70
|
-
| `length(source)` | `CHAR_LENGTH(source)` — 문자 수 |
|
|
71
|
-
| `byteLength(source)` | `OCTET_LENGTH(source)` — 바이트 수 |
|
|
72
|
-
| `substring(source, start, length?)` | `SUBSTRING(source, start, len)` — 1부터 시작 |
|
|
73
|
-
| `indexOf(source, search)` | `LOCATE/CHARINDEX` — 1부터 시작, 없으면 0 |
|
|
74
|
-
|
|
75
|
-
## SELECT — 숫자
|
|
76
|
-
|
|
77
|
-
| 함수 | 설명 |
|
|
78
|
-
|------|------|
|
|
79
|
-
| `abs(source)` | `ABS(source)` |
|
|
80
|
-
| `round(source, digits)` | `ROUND(source, n)` |
|
|
81
|
-
| `ceil(source)` | `CEILING(source)` |
|
|
82
|
-
| `floor(source)` | `FLOOR(source)` |
|
|
83
|
-
| `add(source, target)` | `source + target` |
|
|
84
|
-
| `sub(source, target)` | `source - target` |
|
|
85
|
-
| `mul(source, target)` | `source * target` |
|
|
86
|
-
| `div(source, target)` | `source / target` |
|
|
87
|
-
| `mod(source, target)` | `source % target` |
|
|
88
|
-
|
|
89
|
-
## SELECT — 날짜
|
|
90
|
-
|
|
91
|
-
| 함수 | 설명 |
|
|
92
|
-
|------|------|
|
|
93
|
-
| `year(source)` | `YEAR(source)` |
|
|
94
|
-
| `month(source)` | `MONTH(source)` (1~12) |
|
|
95
|
-
| `day(source)` | `DAY(source)` (1~31) |
|
|
96
|
-
| `hour(source)` | `HOUR(source)` (0~23) |
|
|
97
|
-
| `minute(source)` | `MINUTE(source)` (0~59) |
|
|
98
|
-
| `second(source)` | `SECOND(source)` (0~59) |
|
|
99
|
-
| `dateDiff(unit, from, to)` | `DATEDIFF(unit, from, to)` — 두 날짜 차이 |
|
|
100
|
-
| `dateAdd(unit, source, amount)` | `DATEADD(unit, n, source)` — 날짜 더하기 |
|
|
101
|
-
|
|
102
|
-
## SELECT — 집계 함수
|
|
103
|
-
|
|
104
|
-
| 함수 | 설명 |
|
|
105
|
-
|------|------|
|
|
106
|
-
| `count(source?)` | `COUNT(source)` 또는 `COUNT(*)` |
|
|
107
|
-
| `sum(source)` | `SUM(source)` |
|
|
108
|
-
| `avg(source)` | `AVG(source)` |
|
|
109
|
-
| `max(source)` | `MAX(source)` |
|
|
110
|
-
| `min(source)` | `MIN(source)` |
|
|
111
|
-
|
|
112
|
-
## SELECT — 윈도우 함수
|
|
113
|
-
|
|
114
|
-
| 함수 | 설명 |
|
|
115
|
-
|------|------|
|
|
116
|
-
| `rowNumber(winSpec)` | `ROW_NUMBER() OVER (PARTITION BY ... ORDER BY ...)` |
|
|
117
|
-
| `rank(winSpec)` | `RANK() OVER (...)` |
|
|
118
|
-
| `denseRank(winSpec)` | `DENSE_RANK() OVER (...)` |
|
|
119
|
-
| `lag(source, offset?, def?, winSpec?)` | `LAG(source, offset, default) OVER (...)` |
|
|
120
|
-
| `lead(source, offset?, def?, winSpec?)` | `LEAD(source, offset, default) OVER (...)` |
|
|
121
|
-
| `sumOver(source, winSpec)` | `SUM(source) OVER (...)` |
|
|
122
|
-
| `countOver(source, winSpec)` | `COUNT(source) OVER (...)` |
|
|
123
|
-
| `avgOver(source, winSpec)` | `AVG(source) OVER (...)` |
|
|
124
|
-
| `maxOver(source, winSpec)` | `MAX(source) OVER (...)` |
|
|
125
|
-
| `minOver(source, winSpec)` | `MIN(source) OVER (...)` |
|
|
126
|
-
| `firstValue(source, winSpec)` | `FIRST_VALUE(source) OVER (...)` |
|
|
127
|
-
| `lastValue(source, winSpec)` | `LAST_VALUE(source) OVER (...)` |
|
|
128
|
-
| `ntile(n, winSpec)` | `NTILE(n) OVER (...)` |
|
|
129
|
-
|
|
130
|
-
## SELECT — 서브쿼리
|
|
131
|
-
|
|
132
|
-
| 함수 | 설명 |
|
|
133
|
-
|------|------|
|
|
134
|
-
| `subquery(dataType, query, fn?)` | 서브쿼리를 SELECT 표현식으로 사용. 단일 값 반환 |
|
|
135
|
-
|
|
136
|
-
## SELECT — 조건부 표현식
|
|
137
|
-
|
|
138
|
-
| 함수 | 설명 |
|
|
139
|
-
|------|------|
|
|
140
|
-
| `if(condition, then, else_)` | `IF(cond, then, else)` |
|
|
141
|
-
| `switch()` | `CASE WHEN` 체이닝. `.case(cond, then).default(val)` |
|
|
142
|
-
| `coalesce(...args)` | `COALESCE(...)` — 첫 번째 non-NULL 값 반환 |
|
|
143
|
-
| `nullIf(source, target)` | `NULLIF(source, target)` — 같으면 NULL |
|
|
144
|
-
|
|
145
|
-
## SELECT — 타입 변환
|
|
146
|
-
|
|
147
|
-
| 함수 | 설명 |
|
|
148
|
-
|------|------|
|
|
149
|
-
| `cast(source, dataType)` | `CAST(source AS type)` |
|
|
150
|
-
| `toDateOnly(source)` | DateTime → DateOnly 변환 |
|
|
151
|
-
| `toDateTime(source)` | DateOnly → DateTime 변환 |
|
|
152
|
-
|
|
153
|
-
## Related Types
|
|
154
|
-
|
|
155
|
-
### `SwitchExprBuilder<TPrimitive>`
|
|
156
|
-
|
|
157
|
-
`expr.switch()`의 체이닝 빌더 인터페이스.
|
|
158
|
-
|
|
159
|
-
```typescript
|
|
160
|
-
export interface SwitchExprBuilder<TPrimitive extends ColumnPrimitive> {
|
|
161
|
-
case(condition: WhereExprUnit, then: ExprInput<TPrimitive>): SwitchExprBuilder<TPrimitive>;
|
|
162
|
-
default(value: ExprInput<TPrimitive>): ExprUnit<TPrimitive>;
|
|
163
|
-
}
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
## Usage
|
|
167
|
-
|
|
168
|
-
```typescript
|
|
169
|
-
import { expr } from "@simplysm/orm-common";
|
|
170
|
-
|
|
171
|
-
// 비교/논리
|
|
172
|
-
expr.eq(u.status, "active")
|
|
173
|
-
expr.between(u.age, 18, 65)
|
|
174
|
-
expr.and([expr.eq(u.isActive, true), expr.gt(u.age, 18)])
|
|
175
|
-
|
|
176
|
-
// 집계/윈도우
|
|
177
|
-
expr.sum(o.amount)
|
|
178
|
-
expr.rowNumber({ partitionBy: [u.companyId], orderBy: [[u.createdAt, "DESC"]] })
|
|
179
|
-
|
|
180
|
-
// 문자열
|
|
181
|
-
expr.concat(u.firstName, " ", u.lastName)
|
|
182
|
-
expr.padStart(expr.cast(o.id, { type: "varchar", length: 10 }), 8, "0")
|
|
183
|
-
|
|
184
|
-
// 날짜
|
|
185
|
-
expr.dateDiff("year", u.birthDate, expr.val("DateOnly", DateOnly.today()))
|
|
186
|
-
|
|
187
|
-
// CASE WHEN
|
|
188
|
-
const label = expr.switch<string>()
|
|
189
|
-
.case(expr.eq(u.status, "active"), "활성")
|
|
190
|
-
.case(expr.eq(u.status, "inactive"), "비활성")
|
|
191
|
-
.default("알 수 없음");
|
|
192
|
-
|
|
193
|
-
// 서브쿼리
|
|
194
|
-
expr.subquery("number", db.post().where((p) => [expr.eq(p.authorId, u.id)]))
|
|
195
|
-
|
|
196
|
-
// Raw SQL (이스케이프 해치)
|
|
197
|
-
expr.raw("string")`JSON_EXTRACT(${u.metadata}, '$.email')`
|
|
198
|
-
```
|
package/docs/models/migration.md
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
# _Migration
|
|
2
|
-
|
|
3
|
-
시스템 마이그레이션 테이블 정의. `DbContext`가 내부적으로 사용하며, `initialize()`가 실행된 마이그레이션 이름을 이 테이블에 기록한다.
|
|
4
|
-
|
|
5
|
-
```typescript
|
|
6
|
-
export const _Migration: TableBuilder<
|
|
7
|
-
{ code: ColumnBuilder<string, { type: "string"; dataType: { type: "varchar"; length: 255 } }> },
|
|
8
|
-
never
|
|
9
|
-
>;
|
|
10
|
-
```
|
|
11
|
-
|
|
12
|
-
내부 정의:
|
|
13
|
-
```typescript
|
|
14
|
-
export const _Migration = Table("_migration")
|
|
15
|
-
.columns((c) => ({
|
|
16
|
-
code: c.varchar(255),
|
|
17
|
-
}))
|
|
18
|
-
.description("시스템 마이그레이션 테이블")
|
|
19
|
-
.primaryKey("code");
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
## 컬럼
|
|
23
|
-
|
|
24
|
-
| 컬럼 | 타입 | 설명 |
|
|
25
|
-
|------|------|------|
|
|
26
|
-
| `code` | `varchar(255)` (PK) | 실행된 마이그레이션 이름 |
|
|
27
|
-
|
|
28
|
-
## Usage
|
|
29
|
-
|
|
30
|
-
`DbContext`에서 `this._migration`으로 접근 가능하나, 일반적으로 직접 조작하지 않고 `initialize()`를 통해 자동 관리한다.
|
|
31
|
-
|
|
32
|
-
```typescript
|
|
33
|
-
// initialize()가 내부적으로 사용
|
|
34
|
-
await db.connectWithoutTransaction(async () => {
|
|
35
|
-
await db.initialize(); // _migration 테이블 생성 + 미실행 마이그레이션 순차 실행
|
|
36
|
-
});
|
|
37
|
-
```
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
# createQueryBuilder
|
|
2
|
-
|
|
3
|
-
주어진 Dialect에 맞는 QueryBuilder 인스턴스를 생성한다. `Queryable.execute()` 내부에서 자동 호출되며, 직접 호출은 테스트 목적에만 사용한다.
|
|
4
|
-
|
|
5
|
-
```typescript
|
|
6
|
-
export function createQueryBuilder(dialect: Dialect): QueryBuilderBase;
|
|
7
|
-
```
|
|
8
|
-
|
|
9
|
-
## Parameters
|
|
10
|
-
|
|
11
|
-
| Param | Type | Description |
|
|
12
|
-
|-------|------|-------------|
|
|
13
|
-
| `dialect` | `Dialect` | `"mysql"` \| `"mssql"` \| `"postgresql"` |
|
|
14
|
-
|
|
15
|
-
## Returns
|
|
16
|
-
|
|
17
|
-
`QueryBuilderBase` — 해당 dialect의 QueryBuilder 구현체
|
|
18
|
-
|
|
19
|
-
## Related Types
|
|
20
|
-
|
|
21
|
-
### `QueryBuilderBase`
|
|
22
|
-
|
|
23
|
-
QueryDef → SQL 문자열 변환 추상 기본 클래스. 모든 dialect에서 100% 동일한 dispatch 로직만 구현하고, dialect별 차이는 abstract 메서드로 위임한다.
|
|
24
|
-
|
|
25
|
-
```typescript
|
|
26
|
-
export abstract class QueryBuilderBase {
|
|
27
|
-
protected abstract expr: ExprRendererBase;
|
|
28
|
-
|
|
29
|
-
build(def: QueryDef): QueryBuildResult;
|
|
30
|
-
|
|
31
|
-
// DML
|
|
32
|
-
protected select(def: SelectQueryDef): QueryBuildResult;
|
|
33
|
-
protected insert(def: InsertQueryDef): QueryBuildResult;
|
|
34
|
-
protected update(def: UpdateQueryDef): QueryBuildResult;
|
|
35
|
-
protected delete(def: DeleteQueryDef): QueryBuildResult;
|
|
36
|
-
protected upsert(def: UpsertQueryDef): QueryBuildResult;
|
|
37
|
-
// ... 기타 DDL 메서드들
|
|
38
|
-
}
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
### `ExprRendererBase`
|
|
42
|
-
|
|
43
|
-
Expr AST → SQL 표현식 문자열 변환 추상 기본 클래스.
|
|
44
|
-
|
|
45
|
-
```typescript
|
|
46
|
-
export abstract class ExprRendererBase {
|
|
47
|
-
render(expr: Expr): string;
|
|
48
|
-
renderWhere(expr: WhereExpr): string;
|
|
49
|
-
// ... dialect별 abstract 메서드들
|
|
50
|
-
}
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
### Dialect별 구현체
|
|
54
|
-
|
|
55
|
-
| 클래스 | 설명 |
|
|
56
|
-
|--------|------|
|
|
57
|
-
| `MysqlQueryBuilder` | MySQL 8.0.14+ 구현체 |
|
|
58
|
-
| `MysqlExprRenderer` | MySQL 표현식 렌더러 |
|
|
59
|
-
| `MssqlQueryBuilder` | MSSQL 2012+ 구현체 |
|
|
60
|
-
| `MssqlExprRenderer` | MSSQL 표현식 렌더러 |
|
|
61
|
-
| `PostgresqlQueryBuilder` | PostgreSQL 9.0+ 구현체 |
|
|
62
|
-
| `PostgresqlExprRenderer` | PostgreSQL 표현식 렌더러 |
|
|
63
|
-
|
|
64
|
-
## Usage
|
|
65
|
-
|
|
66
|
-
```typescript
|
|
67
|
-
// 일반적으로 직접 호출하지 않음 — Queryable.execute()가 내부적으로 처리
|
|
68
|
-
|
|
69
|
-
// 테스트에서 SQL 생성 검증 시 직접 사용
|
|
70
|
-
const builder = createQueryBuilder("mysql"); // | "mssql" | "postgresql"
|
|
71
|
-
const { sql } = builder.build(queryDef);
|
|
72
|
-
expect(sql).toBe("SELECT ...");
|
|
73
|
-
|
|
74
|
-
// dialect별 테스트
|
|
75
|
-
const dialects: Dialect[] = ["mysql", "mssql", "postgresql"];
|
|
76
|
-
it.each(dialects)("[%s] SQL 검증", (dialect) => {
|
|
77
|
-
const { sql } = createQueryBuilder(dialect).build(queryDef);
|
|
78
|
-
expect(sql).toBe(expected[dialect]);
|
|
79
|
-
});
|
|
80
|
-
```
|