@simplysm/orm-common 14.1.2 → 14.1.7
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/db-context.d.ts +11 -10
- package/dist/db-context.d.ts.map +1 -1
- package/dist/db-context.js +14 -11
- package/dist/db-context.js.map +1 -1
- package/dist/ddl/initialize.js.map +1 -1
- package/dist/ddl/relation-ddl.d.ts +1 -1
- package/dist/ddl/relation-ddl.d.ts.map +1 -1
- package/dist/ddl/relation-ddl.js.map +1 -1
- package/dist/ddl/table-ddl.d.ts +3 -3
- package/dist/ddl/table-ddl.d.ts.map +1 -1
- package/dist/ddl/table-ddl.js.map +1 -1
- package/dist/errors/db-transaction-error.d.ts +4 -5
- package/dist/errors/db-transaction-error.d.ts.map +1 -1
- package/dist/errors/db-transaction-error.js +5 -6
- package/dist/errors/db-transaction-error.js.map +1 -1
- package/dist/exec/executable.d.ts +4 -13
- package/dist/exec/executable.d.ts.map +1 -1
- package/dist/exec/executable.js.map +1 -1
- package/dist/exec/queryable.d.ts +11 -9
- package/dist/exec/queryable.d.ts.map +1 -1
- package/dist/exec/queryable.js +9 -5
- package/dist/exec/queryable.js.map +1 -1
- package/dist/expr/expr.d.ts +7 -4
- package/dist/expr/expr.d.ts.map +1 -1
- package/dist/expr/expr.js +5 -2
- package/dist/expr/expr.js.map +1 -1
- package/dist/models/system-migration.d.ts +1 -1
- package/dist/models/system-migration.d.ts.map +1 -1
- package/dist/query-builder/base/expr-renderer-base.d.ts +2 -1
- package/dist/query-builder/base/expr-renderer-base.d.ts.map +1 -1
- package/dist/query-builder/base/expr-renderer-base.js.map +1 -1
- package/dist/query-builder/mssql/mssql-expr-renderer.d.ts +2 -2
- package/dist/query-builder/mssql/mssql-expr-renderer.d.ts.map +1 -1
- package/dist/query-builder/mssql/mssql-expr-renderer.js.map +1 -1
- package/dist/query-builder/mysql/mysql-expr-renderer.d.ts +2 -2
- package/dist/query-builder/mysql/mysql-expr-renderer.d.ts.map +1 -1
- package/dist/query-builder/mysql/mysql-expr-renderer.js.map +1 -1
- package/dist/query-builder/postgresql/postgresql-expr-renderer.d.ts +2 -2
- package/dist/query-builder/postgresql/postgresql-expr-renderer.d.ts.map +1 -1
- package/dist/query-builder/postgresql/postgresql-expr-renderer.js.map +1 -1
- package/dist/query-builder/postgresql/postgresql-query-builder.d.ts.map +1 -1
- package/dist/query-builder/postgresql/postgresql-query-builder.js.map +1 -1
- package/dist/schema/factory/column-builder.d.ts +1 -1
- package/dist/schema/factory/column-builder.d.ts.map +1 -1
- package/dist/schema/factory/relation-builder.d.ts +55 -49
- package/dist/schema/factory/relation-builder.d.ts.map +1 -1
- package/dist/schema/factory/relation-builder.js +12 -15
- package/dist/schema/factory/relation-builder.js.map +1 -1
- package/dist/schema/table-builder.d.ts +35 -18
- package/dist/schema/table-builder.d.ts.map +1 -1
- package/dist/schema/table-builder.js +32 -15
- package/dist/schema/table-builder.js.map +1 -1
- package/dist/schema/view-builder.d.ts +28 -24
- package/dist/schema/view-builder.d.ts.map +1 -1
- package/dist/schema/view-builder.js +18 -14
- package/dist/schema/view-builder.js.map +1 -1
- package/dist/types/column.d.ts +6 -17
- package/dist/types/column.d.ts.map +1 -1
- package/dist/types/column.js +3 -19
- package/dist/types/column.js.map +1 -1
- package/dist/types/db-context-def.d.ts +7 -7
- package/dist/types/db-context-def.d.ts.map +1 -1
- package/dist/types/query-def.d.ts +1 -1
- package/dist/types/query-def.d.ts.map +1 -1
- package/dist/utils/result-parser.d.ts.map +1 -1
- package/dist/utils/result-parser.js +3 -7
- package/dist/utils/result-parser.js.map +1 -1
- package/package.json +3 -3
- package/src/db-context.ts +23 -20
- package/src/ddl/initialize.ts +4 -4
- package/src/ddl/relation-ddl.ts +1 -1
- package/src/ddl/table-ddl.ts +3 -3
- package/src/errors/db-transaction-error.ts +6 -4
- package/src/exec/executable.ts +5 -4
- package/src/exec/queryable.ts +31 -24
- package/src/expr/expr.ts +10 -4
- package/src/query-builder/base/expr-renderer-base.ts +2 -1
- package/src/query-builder/mssql/mssql-expr-renderer.ts +5 -5
- package/src/query-builder/mysql/mysql-expr-renderer.ts +2 -2
- package/src/query-builder/postgresql/postgresql-expr-renderer.ts +5 -5
- package/src/query-builder/postgresql/postgresql-query-builder.ts +4 -3
- package/src/schema/factory/column-builder.ts +3 -3
- package/src/schema/factory/relation-builder.ts +350 -346
- package/src/schema/table-builder.ts +209 -193
- package/src/schema/view-builder.ts +148 -143
- package/src/types/column.ts +7 -26
- package/src/types/db-context-def.ts +7 -7
- package/src/types/query-def.ts +1 -1
- package/src/utils/result-parser.ts +11 -19
|
@@ -1,143 +1,148 @@
|
|
|
1
|
-
import type { DbContextBase } from "../types/db-context-def";
|
|
2
|
-
import type { Queryable } from "../exec/queryable";
|
|
3
|
-
import type { DataRecord } from "../types/db";
|
|
4
|
-
import {
|
|
5
|
-
createRelationFactory,
|
|
6
|
-
type InferDeepRelations,
|
|
7
|
-
type
|
|
8
|
-
} from "./factory/relation-builder";
|
|
9
|
-
|
|
10
|
-
// ============================================
|
|
11
|
-
// ViewBuilder
|
|
12
|
-
// ============================================
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Database View 정의 builder
|
|
16
|
-
*
|
|
17
|
-
* Fluent API로 View query
|
|
18
|
-
* DbContext의 queryable()과 함께 사용하여 타입 안전한 query 구성
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* @
|
|
25
|
-
* @
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
*
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
*
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
*
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
*
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
1
|
+
import type { DbContextBase } from "../types/db-context-def";
|
|
2
|
+
import type { Queryable } from "../exec/queryable";
|
|
3
|
+
import type { DataRecord } from "../types/db";
|
|
4
|
+
import {
|
|
5
|
+
createRelationFactory,
|
|
6
|
+
type InferDeepRelations,
|
|
7
|
+
type ViewRelationFactory,
|
|
8
|
+
} from "./factory/relation-builder";
|
|
9
|
+
|
|
10
|
+
// ============================================
|
|
11
|
+
// ViewBuilder
|
|
12
|
+
// ============================================
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Database View 정의 builder
|
|
16
|
+
*
|
|
17
|
+
* Fluent API로 View query를 정의
|
|
18
|
+
* DbContext의 queryable()과 함께 사용하여 타입 안전한 query 구성
|
|
19
|
+
*
|
|
20
|
+
* 관계는 `.relations((r) => ({ ... }))` 메서드 체이닝으로 정의한다(RelationKey만 사용 가능).
|
|
21
|
+
* 관계를 잡는 4번째 제네릭 `TRelations` 는 **무제약**이라 TS6 순환을 회피한다.
|
|
22
|
+
*
|
|
23
|
+
* @template TDbContext - DbContext 타입
|
|
24
|
+
* @template TName - View 이름
|
|
25
|
+
* @template TData - View 데이터 레코드 타입
|
|
26
|
+
* @template TRelations - 관계 정의 레코드 타입 (무제약, 기본값 `{}`)
|
|
27
|
+
*
|
|
28
|
+
* @see {@link View} factory 함수
|
|
29
|
+
* @see {@link queryable} Queryable 생성
|
|
30
|
+
*/
|
|
31
|
+
export class ViewBuilder<
|
|
32
|
+
TDbContext extends DbContextBase,
|
|
33
|
+
TName extends string,
|
|
34
|
+
TData extends DataRecord,
|
|
35
|
+
TRelations = {},
|
|
36
|
+
> {
|
|
37
|
+
/**
|
|
38
|
+
* 전체 타입 추론 (column + 관계).
|
|
39
|
+
*
|
|
40
|
+
* 관계는 `TRelations` 를 구조적으로 lazy walk 하여 다단계로 해소된다.
|
|
41
|
+
*/
|
|
42
|
+
readonly $inferSelect!: TData & InferDeepRelations<TRelations>;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @param meta - View 메타데이터
|
|
46
|
+
* @param meta.name - View 이름
|
|
47
|
+
* @param meta.description - View 설명 (comment)
|
|
48
|
+
* @param meta.database - Database 이름
|
|
49
|
+
* @param meta.schema - Schema 이름 (MSSQL/PostgreSQL)
|
|
50
|
+
* @param meta.viewFn - View query 정의 함수
|
|
51
|
+
* @param meta.relations - 관계 정의 (런타임: `.relations(fn)` 호출 시 부착됨)
|
|
52
|
+
*/
|
|
53
|
+
constructor(
|
|
54
|
+
readonly meta: {
|
|
55
|
+
name: TName;
|
|
56
|
+
description?: string;
|
|
57
|
+
database?: string;
|
|
58
|
+
schema?: string;
|
|
59
|
+
viewFn?: (db: TDbContext) => Queryable<TData, any>;
|
|
60
|
+
relations?: TRelations;
|
|
61
|
+
},
|
|
62
|
+
) {}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* View 설명 설정
|
|
66
|
+
*
|
|
67
|
+
* @param desc - View 설명 (DDL Comment로 사용됨)
|
|
68
|
+
* @returns 새 ViewBuilder 인스턴스
|
|
69
|
+
*/
|
|
70
|
+
description(desc: string): ViewBuilder<TDbContext, TName, TData, TRelations> {
|
|
71
|
+
return new ViewBuilder({ ...this.meta, description: desc });
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Database 이름 설정
|
|
76
|
+
*
|
|
77
|
+
* @param db - Database 이름
|
|
78
|
+
* @returns 새 ViewBuilder 인스턴스
|
|
79
|
+
*/
|
|
80
|
+
database(db: string): ViewBuilder<TDbContext, TName, TData, TRelations> {
|
|
81
|
+
return new ViewBuilder({ ...this.meta, database: db });
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Schema 이름 설정
|
|
86
|
+
*
|
|
87
|
+
* MSSQL, PostgreSQL에서 사용
|
|
88
|
+
*
|
|
89
|
+
* @param schema - Schema 이름 (MSSQL: dbo, PostgreSQL: public)
|
|
90
|
+
* @returns 새 ViewBuilder 인스턴스
|
|
91
|
+
*/
|
|
92
|
+
schema(schema: string): ViewBuilder<TDbContext, TName, TData, TRelations> {
|
|
93
|
+
return new ViewBuilder({ ...this.meta, schema });
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* View query 정의
|
|
98
|
+
*
|
|
99
|
+
* SELECT query를 통해 View의 데이터 소스를 정의
|
|
100
|
+
*
|
|
101
|
+
* @template TViewData - View 데이터 타입
|
|
102
|
+
* @template TDb - DbContext 타입
|
|
103
|
+
* @param viewFn - DbContext를 받아 Queryable을 반환하는 함수
|
|
104
|
+
* @returns 새 ViewBuilder 인스턴스
|
|
105
|
+
*/
|
|
106
|
+
query<TViewData extends DataRecord, TDb extends DbContextBase>(
|
|
107
|
+
viewFn: (db: TDb) => Queryable<TViewData, any>,
|
|
108
|
+
): ViewBuilder<TDb, TName, TViewData, TRelations> {
|
|
109
|
+
return new ViewBuilder({ ...this.meta, viewFn });
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* 관계 정의 (RelationKey / RelationKeyTarget 만 사용 가능)
|
|
114
|
+
*
|
|
115
|
+
* 관계 타입 `T` 는 **무제약**으로 추론되며, 내부적으로 런타임 결과를
|
|
116
|
+
* `meta.relations` 에 저장한다(`as any`). TS6 순환 회피.
|
|
117
|
+
*
|
|
118
|
+
* @template T - 관계 정의 레코드 타입 (무제약)
|
|
119
|
+
* @param fn - 관계 factory를 받아 관계 정의를 반환하는 함수
|
|
120
|
+
* @returns 관계가 부착된 새 ViewBuilder 인스턴스
|
|
121
|
+
*/
|
|
122
|
+
relations<T>(
|
|
123
|
+
fn: (r: ViewRelationFactory<keyof TData & string>) => T,
|
|
124
|
+
): ViewBuilder<TDbContext, TName, TData, T> {
|
|
125
|
+
return new ViewBuilder<TDbContext, TName, TData, T>({
|
|
126
|
+
...this.meta,
|
|
127
|
+
relations: fn(createRelationFactory<keyof TData & string>()),
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// ============================================
|
|
133
|
+
// View 함수
|
|
134
|
+
// ============================================
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* View builder factory 함수
|
|
138
|
+
*
|
|
139
|
+
* Fluent API로 View schema를 정의하기 위한 ViewBuilder를 생성
|
|
140
|
+
*
|
|
141
|
+
* @param name - View 이름
|
|
142
|
+
* @returns ViewBuilder 인스턴스
|
|
143
|
+
*
|
|
144
|
+
* @see {@link ViewBuilder} builder 클래스
|
|
145
|
+
*/
|
|
146
|
+
export function View<TName extends string>(name: TName) {
|
|
147
|
+
return new ViewBuilder<DbContextBase, TName, DataRecord, {}>({ name });
|
|
148
|
+
}
|
package/src/types/column.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { primitive, type PrimitiveType, type PrimitiveTypeMap, type PrimitiveTypeStr } from "@simplysm/core-common";
|
|
2
2
|
|
|
3
3
|
// ============================================
|
|
4
4
|
// DataType (SQL 타입 정의)
|
|
@@ -45,31 +45,20 @@ export type DataType =
|
|
|
45
45
|
|
|
46
46
|
/**
|
|
47
47
|
* Column 원시 타입 매핑
|
|
48
|
-
*
|
|
49
|
-
* TypeScript 타입 이름 (문자열) → 실제 TypeScript 타입 매핑
|
|
50
48
|
*/
|
|
51
|
-
export type ColumnPrimitiveMap =
|
|
52
|
-
string: string;
|
|
53
|
-
number: number;
|
|
54
|
-
boolean: boolean;
|
|
55
|
-
DateTime: DateTime;
|
|
56
|
-
DateOnly: DateOnly;
|
|
57
|
-
Time: Time;
|
|
58
|
-
Uuid: Uuid;
|
|
59
|
-
Bytes: Bytes;
|
|
60
|
-
};
|
|
49
|
+
export type ColumnPrimitiveMap = PrimitiveTypeMap;
|
|
61
50
|
|
|
62
51
|
/**
|
|
63
52
|
* Column 원시 타입 이름 (문자열)
|
|
64
53
|
*/
|
|
65
|
-
export type ColumnPrimitiveStr =
|
|
54
|
+
export type ColumnPrimitiveStr = PrimitiveTypeStr;
|
|
66
55
|
|
|
67
56
|
/**
|
|
68
57
|
* Column에 저장 가능한 모든 원시 타입
|
|
69
58
|
*
|
|
70
59
|
* undefined는 NULL을 나타냄
|
|
71
60
|
*/
|
|
72
|
-
export type ColumnPrimitive =
|
|
61
|
+
export type ColumnPrimitive = PrimitiveType;
|
|
73
62
|
|
|
74
63
|
// ============================================
|
|
75
64
|
// DataType ↔ ColumnPrimitive Mapping
|
|
@@ -108,18 +97,10 @@ export type InferColumnPrimitiveFromDataType<TDataType extends DataType> =
|
|
|
108
97
|
*
|
|
109
98
|
* @param value - Column 값
|
|
110
99
|
* @returns ColumnPrimitiveStr 타입 이름
|
|
111
|
-
* @throws 값 타입이 알 수 없을 때
|
|
100
|
+
* @throws 값 타입이 알 수 없을 때 ArgumentError
|
|
112
101
|
*/
|
|
113
|
-
export function inferColumnPrimitiveStr(value: ColumnPrimitive): ColumnPrimitiveStr {
|
|
114
|
-
|
|
115
|
-
if (typeof value === "number") return "number";
|
|
116
|
-
if (typeof value === "boolean") return "boolean";
|
|
117
|
-
if (value instanceof DateTime) return "DateTime";
|
|
118
|
-
if (value instanceof DateOnly) return "DateOnly";
|
|
119
|
-
if (value instanceof Time) return "Time";
|
|
120
|
-
if (value instanceof Uuid) return "Uuid";
|
|
121
|
-
if (value instanceof Uint8Array) return "Bytes";
|
|
122
|
-
throw new Error("NULL 값으로는 타입을 추론할 수 없습니다.");
|
|
102
|
+
export function inferColumnPrimitiveStr(value: Exclude<ColumnPrimitive, undefined>): ColumnPrimitiveStr {
|
|
103
|
+
return primitive.typeStr(value);
|
|
123
104
|
}
|
|
124
105
|
|
|
125
106
|
// ============================================
|
|
@@ -14,7 +14,7 @@ import type { QueryDef, QueryDefObjectName } from "./query-def";
|
|
|
14
14
|
* DbContext class가 이 인터페이스를 구현한다.
|
|
15
15
|
*/
|
|
16
16
|
export interface DbContextBase {
|
|
17
|
-
status: DbContextStatus;
|
|
17
|
+
readonly status: DbContextStatus;
|
|
18
18
|
readonly database: string | undefined;
|
|
19
19
|
readonly schema: string | undefined;
|
|
20
20
|
getNextAlias(): string;
|
|
@@ -24,7 +24,7 @@ export interface DbContextBase {
|
|
|
24
24
|
resultMetas?: (ResultMeta | undefined)[],
|
|
25
25
|
): Promise<T[][]>;
|
|
26
26
|
getQueryDefObjectName(
|
|
27
|
-
tableOrView: TableBuilder<any, any
|
|
27
|
+
tableOrView: TableBuilder<any, any> | ViewBuilder<any, any, any>,
|
|
28
28
|
): QueryDefObjectName;
|
|
29
29
|
switchFk(table: QueryDefObjectName, enabled: boolean): Promise<void>;
|
|
30
30
|
}
|
|
@@ -32,7 +32,7 @@ export interface DbContextBase {
|
|
|
32
32
|
export type DbContextStatus = "ready" | "connect" | "transact";
|
|
33
33
|
|
|
34
34
|
export interface DbContextDdlMethods {
|
|
35
|
-
createTable(table: TableBuilder<any, any
|
|
35
|
+
createTable(table: TableBuilder<any, any>): Promise<void>;
|
|
36
36
|
dropTable(table: QueryDefObjectName): Promise<void>;
|
|
37
37
|
renameTable(table: QueryDefObjectName, newName: string): Promise<void>;
|
|
38
38
|
createView(view: ViewBuilder<any, any, any>): Promise<void>;
|
|
@@ -56,7 +56,7 @@ export interface DbContextDdlMethods {
|
|
|
56
56
|
addForeignKey(
|
|
57
57
|
table: QueryDefObjectName,
|
|
58
58
|
relationName: string,
|
|
59
|
-
relationDef: ForeignKeyBuilder<any
|
|
59
|
+
relationDef: ForeignKeyBuilder<any>,
|
|
60
60
|
): Promise<void>;
|
|
61
61
|
addIndex(table: QueryDefObjectName, indexBuilder: IndexBuilder<string[]>): Promise<void>;
|
|
62
62
|
dropForeignKey(table: QueryDefObjectName, relationName: string): Promise<void>;
|
|
@@ -66,11 +66,11 @@ export interface DbContextDdlMethods {
|
|
|
66
66
|
truncate(table: QueryDefObjectName): Promise<void>;
|
|
67
67
|
switchFk(table: QueryDefObjectName, enabled: boolean): Promise<void>;
|
|
68
68
|
// QueryDef 생성기
|
|
69
|
-
getCreateTableQueryDef(table: TableBuilder<any, any
|
|
69
|
+
getCreateTableQueryDef(table: TableBuilder<any, any>): QueryDef;
|
|
70
70
|
getCreateViewQueryDef(view: ViewBuilder<any, any, any>): QueryDef;
|
|
71
71
|
getCreateProcQueryDef(procedure: ProcedureBuilder<any, any>): QueryDef;
|
|
72
72
|
getCreateObjectQueryDef(
|
|
73
|
-
builder: TableBuilder<any, any
|
|
73
|
+
builder: TableBuilder<any, any> | ViewBuilder<any, any, any> | ProcedureBuilder<any, any>,
|
|
74
74
|
): QueryDef;
|
|
75
75
|
getDropTableQueryDef(table: QueryDefObjectName): QueryDef;
|
|
76
76
|
getRenameTableQueryDef(table: QueryDefObjectName, newName: string): QueryDef;
|
|
@@ -93,7 +93,7 @@ export interface DbContextDdlMethods {
|
|
|
93
93
|
getAddForeignKeyQueryDef(
|
|
94
94
|
table: QueryDefObjectName,
|
|
95
95
|
relationName: string,
|
|
96
|
-
relationDef: ForeignKeyBuilder<any
|
|
96
|
+
relationDef: ForeignKeyBuilder<any>,
|
|
97
97
|
): QueryDef;
|
|
98
98
|
getAddIndexQueryDef(table: QueryDefObjectName, indexBuilder: IndexBuilder<string[]>): QueryDef;
|
|
99
99
|
getDropForeignKeyQueryDef(table: QueryDefObjectName, relationName: string): QueryDef;
|
package/src/types/query-def.ts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import { bytes, obj, DateOnly, DateTime, Time, Uuid } from "@simplysm/core-common";
|
|
1
|
+
import { bytes, obj, wait, DateOnly, DateTime, Time, Uuid } from "@simplysm/core-common";
|
|
2
2
|
import type { ColumnPrimitiveStr } from "../types/column";
|
|
3
3
|
import type { ResultMeta } from "../types/db";
|
|
4
4
|
|
|
5
|
-
declare function setImmediate(callback: () => void): void;
|
|
6
|
-
|
|
7
5
|
// ============================================
|
|
8
6
|
// 타입 파서
|
|
9
7
|
// ============================================
|
|
@@ -164,12 +162,6 @@ function isEmptyJoinObject(record: Record<string, unknown>): boolean {
|
|
|
164
162
|
/** 양보 간격: N개 레코드마다 이벤트 루프에 양보 */
|
|
165
163
|
const YIELD_INTERVAL = 100;
|
|
166
164
|
|
|
167
|
-
/** 이벤트 루프 양보: Node.js는 setImmediate, 브라우저는 setTimeout 폴백 */
|
|
168
|
-
const yieldToEventLoop: () => Promise<void> =
|
|
169
|
-
typeof setImmediate !== "undefined"
|
|
170
|
-
? () => new Promise<void>((resolve) => setImmediate(resolve))
|
|
171
|
-
: () => new Promise<void>((resolve) => setTimeout(resolve, 0));
|
|
172
|
-
|
|
173
165
|
/**
|
|
174
166
|
* ResultMeta를 통해 DB 쿼리 결과를 TypeScript 객체로 변환
|
|
175
167
|
*
|
|
@@ -197,27 +189,27 @@ export async function parseQueryResult<TRecord>(
|
|
|
197
189
|
|
|
198
190
|
// JOIN 없음: 단순 타입 파싱만 수행
|
|
199
191
|
if (joinKeys.length === 0) {
|
|
200
|
-
return parseSimpleRecords
|
|
192
|
+
return parseSimpleRecords(rawResults, meta.columns) as Promise<TRecord[] | undefined>;
|
|
201
193
|
}
|
|
202
194
|
|
|
203
195
|
// JOIN 있음: 그룹핑 + 중첩
|
|
204
|
-
return parseJoinedRecords
|
|
196
|
+
return parseJoinedRecords(rawResults, meta) as Promise<TRecord[] | undefined>;
|
|
205
197
|
}
|
|
206
198
|
|
|
207
199
|
/**
|
|
208
200
|
* JOIN이 없는 단순 레코드 파싱
|
|
209
201
|
*/
|
|
210
|
-
async function parseSimpleRecords
|
|
202
|
+
async function parseSimpleRecords(
|
|
211
203
|
rawResults: Record<string, unknown>[],
|
|
212
204
|
columns: Record<string, ColumnPrimitiveStr>,
|
|
213
|
-
): Promise<
|
|
205
|
+
): Promise<Record<string, unknown>[] | undefined> {
|
|
214
206
|
const columnInfos = buildColumnInfos(columns);
|
|
215
207
|
const results: Record<string, unknown>[] = [];
|
|
216
208
|
|
|
217
209
|
for (let i = 0; i < rawResults.length; i++) {
|
|
218
210
|
// 이벤트 루프에 양보
|
|
219
211
|
if (i > 0 && i % YIELD_INTERVAL === 0) {
|
|
220
|
-
await
|
|
212
|
+
await wait.immediate();
|
|
221
213
|
}
|
|
222
214
|
|
|
223
215
|
const parsed = flatToNested(rawResults[i], columnInfos);
|
|
@@ -229,7 +221,7 @@ async function parseSimpleRecords<TRecord>(
|
|
|
229
221
|
}
|
|
230
222
|
|
|
231
223
|
// 빈 배열은 undefined 반환
|
|
232
|
-
return results.length > 0 ?
|
|
224
|
+
return results.length > 0 ? results : undefined;
|
|
233
225
|
}
|
|
234
226
|
|
|
235
227
|
/**
|
|
@@ -247,16 +239,16 @@ function sortJoinKeysByDepth(joinKeys: string[]): string[] {
|
|
|
247
239
|
/**
|
|
248
240
|
* JOIN이 있는 레코드 파싱 (재귀 그룹핑)
|
|
249
241
|
*/
|
|
250
|
-
async function parseJoinedRecords
|
|
242
|
+
async function parseJoinedRecords(
|
|
251
243
|
rawResults: Record<string, unknown>[],
|
|
252
244
|
meta: ResultMeta,
|
|
253
|
-
): Promise<
|
|
245
|
+
): Promise<Record<string, unknown>[] | undefined> {
|
|
254
246
|
// 1. 모든 레코드를 중첩 구조로 변환
|
|
255
247
|
const columnInfos = buildColumnInfos(meta.columns);
|
|
256
248
|
const nestedRecords: Record<string, unknown>[] = [];
|
|
257
249
|
for (let i = 0; i < rawResults.length; i++) {
|
|
258
250
|
if (i > 0 && i % YIELD_INTERVAL === 0) {
|
|
259
|
-
await
|
|
251
|
+
await wait.immediate();
|
|
260
252
|
}
|
|
261
253
|
nestedRecords.push(flatToNested(rawResults[i], columnInfos));
|
|
262
254
|
}
|
|
@@ -270,7 +262,7 @@ async function parseJoinedRecords<TRecord>(
|
|
|
270
262
|
// 4. 빈 결과 필터링
|
|
271
263
|
const filteredResults = results.filter((r) => !isEmptyObject(r));
|
|
272
264
|
|
|
273
|
-
return filteredResults.length > 0 ?
|
|
265
|
+
return filteredResults.length > 0 ? filteredResults : undefined;
|
|
274
266
|
}
|
|
275
267
|
|
|
276
268
|
/**
|