@simplysm/orm-common 13.0.68 → 13.0.70

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 (204) hide show
  1. package/README.md +54 -1447
  2. package/dist/create-db-context.d.ts +10 -10
  3. package/dist/create-db-context.js +9 -9
  4. package/dist/create-db-context.js.map +1 -1
  5. package/dist/ddl/column-ddl.d.ts +4 -4
  6. package/dist/ddl/initialize.d.ts +17 -17
  7. package/dist/ddl/initialize.js +2 -2
  8. package/dist/ddl/initialize.js.map +1 -1
  9. package/dist/ddl/relation-ddl.d.ts +6 -6
  10. package/dist/ddl/schema-ddl.d.ts +4 -4
  11. package/dist/ddl/table-ddl.d.ts +24 -24
  12. package/dist/ddl/table-ddl.js +4 -4
  13. package/dist/ddl/table-ddl.js.map +1 -1
  14. package/dist/errors/db-transaction-error.d.ts +15 -15
  15. package/dist/errors/db-transaction-error.d.ts.map +1 -1
  16. package/dist/exec/executable.d.ts +23 -23
  17. package/dist/exec/executable.js +3 -3
  18. package/dist/exec/executable.js.map +1 -1
  19. package/dist/exec/queryable.d.ts +160 -160
  20. package/dist/exec/queryable.js +119 -119
  21. package/dist/exec/queryable.js.map +1 -1
  22. package/dist/exec/search-parser.d.ts +37 -37
  23. package/dist/exec/search-parser.d.ts.map +1 -1
  24. package/dist/expr/expr-unit.d.ts +4 -4
  25. package/dist/expr/expr.d.ts +257 -257
  26. package/dist/expr/expr.js +265 -265
  27. package/dist/expr/expr.js.map +1 -1
  28. package/dist/query-builder/base/expr-renderer-base.d.ts +9 -9
  29. package/dist/query-builder/base/expr-renderer-base.js +2 -2
  30. package/dist/query-builder/base/expr-renderer-base.js.map +1 -1
  31. package/dist/query-builder/base/query-builder-base.d.ts +26 -26
  32. package/dist/query-builder/base/query-builder-base.d.ts.map +1 -1
  33. package/dist/query-builder/base/query-builder-base.js +22 -22
  34. package/dist/query-builder/base/query-builder-base.js.map +1 -1
  35. package/dist/query-builder/mssql/mssql-expr-renderer.d.ts +4 -4
  36. package/dist/query-builder/mssql/mssql-expr-renderer.d.ts.map +1 -1
  37. package/dist/query-builder/mssql/mssql-expr-renderer.js +18 -18
  38. package/dist/query-builder/mssql/mssql-expr-renderer.js.map +1 -1
  39. package/dist/query-builder/mssql/mssql-query-builder.d.ts +2 -2
  40. package/dist/query-builder/mssql/mssql-query-builder.d.ts.map +1 -1
  41. package/dist/query-builder/mssql/mssql-query-builder.js +11 -11
  42. package/dist/query-builder/mssql/mssql-query-builder.js.map +1 -1
  43. package/dist/query-builder/mysql/mysql-expr-renderer.d.ts +4 -4
  44. package/dist/query-builder/mysql/mysql-expr-renderer.d.ts.map +1 -1
  45. package/dist/query-builder/mysql/mysql-expr-renderer.js +17 -17
  46. package/dist/query-builder/mysql/mysql-expr-renderer.js.map +1 -1
  47. package/dist/query-builder/mysql/mysql-query-builder.d.ts +8 -8
  48. package/dist/query-builder/mysql/mysql-query-builder.d.ts.map +1 -1
  49. package/dist/query-builder/mysql/mysql-query-builder.js +5 -5
  50. package/dist/query-builder/mysql/mysql-query-builder.js.map +1 -1
  51. package/dist/query-builder/postgresql/postgresql-expr-renderer.d.ts +4 -4
  52. package/dist/query-builder/postgresql/postgresql-expr-renderer.d.ts.map +1 -1
  53. package/dist/query-builder/postgresql/postgresql-expr-renderer.js +17 -17
  54. package/dist/query-builder/postgresql/postgresql-expr-renderer.js.map +1 -1
  55. package/dist/query-builder/postgresql/postgresql-query-builder.d.ts +5 -5
  56. package/dist/query-builder/postgresql/postgresql-query-builder.d.ts.map +1 -1
  57. package/dist/query-builder/postgresql/postgresql-query-builder.js +8 -8
  58. package/dist/query-builder/postgresql/postgresql-query-builder.js.map +1 -1
  59. package/dist/query-builder/query-builder.d.ts +1 -1
  60. package/dist/schema/factory/column-builder.d.ts +79 -79
  61. package/dist/schema/factory/column-builder.js +42 -42
  62. package/dist/schema/factory/index-builder.d.ts +39 -39
  63. package/dist/schema/factory/index-builder.js +26 -26
  64. package/dist/schema/factory/relation-builder.d.ts +99 -99
  65. package/dist/schema/factory/relation-builder.d.ts.map +1 -1
  66. package/dist/schema/factory/relation-builder.js +38 -38
  67. package/dist/schema/procedure-builder.d.ts +49 -49
  68. package/dist/schema/procedure-builder.d.ts.map +1 -1
  69. package/dist/schema/procedure-builder.js +33 -33
  70. package/dist/schema/table-builder.d.ts +59 -59
  71. package/dist/schema/table-builder.d.ts.map +1 -1
  72. package/dist/schema/table-builder.js +43 -43
  73. package/dist/schema/view-builder.d.ts +49 -49
  74. package/dist/schema/view-builder.d.ts.map +1 -1
  75. package/dist/schema/view-builder.js +32 -32
  76. package/dist/types/column.d.ts +22 -22
  77. package/dist/types/column.js +1 -1
  78. package/dist/types/column.js.map +1 -1
  79. package/dist/types/db.d.ts +40 -40
  80. package/dist/types/expr.d.ts +59 -59
  81. package/dist/types/expr.d.ts.map +1 -1
  82. package/dist/types/query-def.d.ts +44 -44
  83. package/dist/types/query-def.d.ts.map +1 -1
  84. package/dist/utils/result-parser.d.ts +11 -11
  85. package/dist/utils/result-parser.js +3 -3
  86. package/dist/utils/result-parser.js.map +1 -1
  87. package/package.json +5 -5
  88. package/src/create-db-context.ts +20 -20
  89. package/src/ddl/column-ddl.ts +4 -4
  90. package/src/ddl/initialize.ts +259 -259
  91. package/src/ddl/relation-ddl.ts +89 -89
  92. package/src/ddl/schema-ddl.ts +4 -4
  93. package/src/ddl/table-ddl.ts +189 -189
  94. package/src/errors/db-transaction-error.ts +13 -13
  95. package/src/exec/executable.ts +25 -25
  96. package/src/exec/queryable.ts +2033 -2033
  97. package/src/exec/search-parser.ts +57 -57
  98. package/src/expr/expr-unit.ts +4 -4
  99. package/src/expr/expr.ts +2140 -2140
  100. package/src/query-builder/base/expr-renderer-base.ts +237 -237
  101. package/src/query-builder/base/query-builder-base.ts +213 -213
  102. package/src/query-builder/mssql/mssql-expr-renderer.ts +607 -607
  103. package/src/query-builder/mssql/mssql-query-builder.ts +650 -650
  104. package/src/query-builder/mysql/mysql-expr-renderer.ts +613 -613
  105. package/src/query-builder/mysql/mysql-query-builder.ts +759 -759
  106. package/src/query-builder/postgresql/postgresql-expr-renderer.ts +611 -611
  107. package/src/query-builder/postgresql/postgresql-query-builder.ts +686 -686
  108. package/src/query-builder/query-builder.ts +19 -19
  109. package/src/schema/factory/column-builder.ts +423 -423
  110. package/src/schema/factory/index-builder.ts +164 -164
  111. package/src/schema/factory/relation-builder.ts +453 -453
  112. package/src/schema/procedure-builder.ts +232 -232
  113. package/src/schema/table-builder.ts +319 -319
  114. package/src/schema/view-builder.ts +221 -221
  115. package/src/types/column.ts +188 -188
  116. package/src/types/db.ts +208 -208
  117. package/src/types/expr.ts +697 -697
  118. package/src/types/query-def.ts +513 -513
  119. package/src/utils/result-parser.ts +458 -458
  120. package/tests/db-context/create-db-context.spec.ts +224 -0
  121. package/tests/db-context/define-db-context.spec.ts +68 -0
  122. package/tests/ddl/basic.expected.ts +341 -0
  123. package/tests/ddl/basic.spec.ts +714 -0
  124. package/tests/ddl/column-builder.expected.ts +310 -0
  125. package/tests/ddl/column-builder.spec.ts +637 -0
  126. package/tests/ddl/index-builder.expected.ts +38 -0
  127. package/tests/ddl/index-builder.spec.ts +202 -0
  128. package/tests/ddl/procedure-builder.expected.ts +52 -0
  129. package/tests/ddl/procedure-builder.spec.ts +234 -0
  130. package/tests/ddl/relation-builder.expected.ts +36 -0
  131. package/tests/ddl/relation-builder.spec.ts +372 -0
  132. package/tests/ddl/table-builder.expected.ts +113 -0
  133. package/tests/ddl/table-builder.spec.ts +433 -0
  134. package/tests/ddl/view-builder.expected.ts +38 -0
  135. package/tests/ddl/view-builder.spec.ts +176 -0
  136. package/tests/dml/delete.expected.ts +96 -0
  137. package/tests/dml/delete.spec.ts +160 -0
  138. package/tests/dml/insert.expected.ts +192 -0
  139. package/tests/dml/insert.spec.ts +288 -0
  140. package/tests/dml/update.expected.ts +176 -0
  141. package/tests/dml/update.spec.ts +318 -0
  142. package/tests/dml/upsert.expected.ts +215 -0
  143. package/tests/dml/upsert.spec.ts +242 -0
  144. package/tests/errors/queryable-errors.spec.ts +177 -0
  145. package/tests/escape.spec.ts +100 -0
  146. package/tests/examples/pivot.expected.ts +211 -0
  147. package/tests/examples/pivot.spec.ts +533 -0
  148. package/tests/examples/sampling.expected.ts +69 -0
  149. package/tests/examples/sampling.spec.ts +104 -0
  150. package/tests/examples/unpivot.expected.ts +120 -0
  151. package/tests/examples/unpivot.spec.ts +226 -0
  152. package/tests/exec/search-parser.spec.ts +283 -0
  153. package/tests/executable/basic.expected.ts +18 -0
  154. package/tests/executable/basic.spec.ts +54 -0
  155. package/tests/expr/comparison.expected.ts +282 -0
  156. package/tests/expr/comparison.spec.ts +400 -0
  157. package/tests/expr/conditional.expected.ts +134 -0
  158. package/tests/expr/conditional.spec.ts +276 -0
  159. package/tests/expr/date.expected.ts +332 -0
  160. package/tests/expr/date.spec.ts +526 -0
  161. package/tests/expr/math.expected.ts +62 -0
  162. package/tests/expr/math.spec.ts +106 -0
  163. package/tests/expr/string.expected.ts +218 -0
  164. package/tests/expr/string.spec.ts +356 -0
  165. package/tests/expr/utility.expected.ts +147 -0
  166. package/tests/expr/utility.spec.ts +182 -0
  167. package/tests/select/basic.expected.ts +322 -0
  168. package/tests/select/basic.spec.ts +502 -0
  169. package/tests/select/filter.expected.ts +357 -0
  170. package/tests/select/filter.spec.ts +1068 -0
  171. package/tests/select/group.expected.ts +169 -0
  172. package/tests/select/group.spec.ts +244 -0
  173. package/tests/select/join.expected.ts +582 -0
  174. package/tests/select/join.spec.ts +805 -0
  175. package/tests/select/order.expected.ts +150 -0
  176. package/tests/select/order.spec.ts +189 -0
  177. package/tests/select/recursive-cte.expected.ts +244 -0
  178. package/tests/select/recursive-cte.spec.ts +514 -0
  179. package/tests/select/result-meta.spec.ts +270 -0
  180. package/tests/select/subquery.expected.ts +363 -0
  181. package/tests/select/subquery.spec.ts +537 -0
  182. package/tests/select/view.expected.ts +155 -0
  183. package/tests/select/view.spec.ts +235 -0
  184. package/tests/select/window.expected.ts +345 -0
  185. package/tests/select/window.spec.ts +618 -0
  186. package/tests/setup/MockExecutor.ts +18 -0
  187. package/tests/setup/TestDbContext.ts +59 -0
  188. package/tests/setup/models/Company.ts +13 -0
  189. package/tests/setup/models/Employee.ts +10 -0
  190. package/tests/setup/models/MonthlySales.ts +11 -0
  191. package/tests/setup/models/Post.ts +16 -0
  192. package/tests/setup/models/Sales.ts +10 -0
  193. package/tests/setup/models/User.ts +19 -0
  194. package/tests/setup/procedure/GetAllUsers.ts +9 -0
  195. package/tests/setup/procedure/GetUserById.ts +12 -0
  196. package/tests/setup/test-utils.ts +72 -0
  197. package/tests/setup/views/ActiveUsers.ts +8 -0
  198. package/tests/setup/views/UserSummary.ts +11 -0
  199. package/tests/types/nullable-queryable-record.spec.ts +145 -0
  200. package/tests/utils/result-parser-perf.spec.ts +210 -0
  201. package/tests/utils/result-parser.spec.ts +701 -0
  202. package/docs/expressions.md +0 -172
  203. package/docs/queries.md +0 -444
  204. package/docs/schema.md +0 -245
@@ -1,453 +1,453 @@
1
- import { type InferColumns } from "./column-builder";
2
- import type { TableBuilder } from "../table-builder";
3
- import type { ViewBuilder } from "../view-builder";
4
-
5
- // ============================================
6
- // ForeignKeyBuilder
7
- // ============================================
8
-
9
- /**
10
- * Foreign Key 관계 빌더 (N:1)
11
- *
12
- * 현재 테이블에서 참조 테이블로의 FK 관계 정의
13
- * DB에 실제 FK 제약조건 생성
14
- *
15
- * @template TOwner - 소유 테이블 빌더 타입
16
- * @template TTargetFn - 참조 테이블 빌더 팩토리 타입
17
- *
18
- * @example
19
- * ```typescript
20
- * const Post = Table("Post")
21
- * .columns((c) => ({
22
- * id: c.bigint().autoIncrement(),
23
- * authorId: c.bigint(), // FK 컬럼
24
- * }))
25
- * .primaryKey("id")
26
- * .relations((r) => ({
27
- * // N:1 관계 - Post → User
28
- * author: r.foreignKey(["authorId"], () => User),
29
- * }));
30
- * ```
31
- *
32
- * @see {@link ForeignKeyTargetBuilder} 역참조 빌더
33
- * @see {@link RelationKeyBuilder} DB FK 없는 관계
34
- */
35
- export class ForeignKeyBuilder<
36
- TOwner extends TableBuilder<any, any>,
37
- TTargetFn extends () => TableBuilder<any, any>,
38
- > {
39
- /**
40
- * @param meta - FK 메타데이터
41
- * @param meta.ownerFn - 소유 테이블 팩토리
42
- * @param meta.columns - FK 컬럼명 배열
43
- * @param meta.targetFn - 참조 테이블 팩토리
44
- * @param meta.description - 관계 설명
45
- */
46
- constructor(
47
- readonly meta: {
48
- ownerFn: () => TOwner;
49
- columns: string[];
50
- targetFn: TTargetFn;
51
- description?: string;
52
- },
53
- ) {}
54
-
55
- /**
56
- * 관계 설명 설정
57
- *
58
- * @param desc - 관계 설명
59
- * @returns 새 ForeignKeyBuilder 인스턴스
60
- */
61
- description(desc: string): ForeignKeyBuilder<TOwner, TTargetFn> {
62
- return new ForeignKeyBuilder({ ...this.meta, description: desc });
63
- }
64
- }
65
-
66
- /**
67
- * Foreign Key 역참조 빌더 (1:N)
68
- *
69
- * 다른 테이블에서 현재 테이블을 참조하는 FK의 역참조 정의
70
- * include() 시 배열로 로드 (single() 호출 시 단일 객체)
71
- *
72
- * @template TTargetTableFn - 참조하는 테이블 빌더 팩토리 타입
73
- * @template TIsSingle - 단일 객체 여부
74
- *
75
- * @example
76
- * ```typescript
77
- * const User = Table("User")
78
- * .columns((c) => ({
79
- * id: c.bigint().autoIncrement(),
80
- * name: c.varchar(100),
81
- * }))
82
- * .primaryKey("id")
83
- * .relations((r) => ({
84
- * // 1:N 관계 - User ← Post.author
85
- * posts: r.foreignKeyTarget(() => Post, "author"),
86
- *
87
- * // 1:1 관계 (단일 객체)
88
- * profile: r.foreignKeyTarget(() => Profile, "user").single(),
89
- * }));
90
- * ```
91
- *
92
- * @see {@link ForeignKeyBuilder} FK 빌더
93
- */
94
- export class ForeignKeyTargetBuilder<
95
- TTargetTableFn extends () => TableBuilder<any, any>,
96
- TIsSingle extends boolean,
97
- > {
98
- /**
99
- * @param meta - FK 역참조 메타데이터
100
- * @param meta.targetTableFn - 참조하는 테이블 팩토리
101
- * @param meta.relationName - 참조하는 테이블의 FK 관계명
102
- * @param meta.description - 관계 설명
103
- * @param meta.isSingle - 단일 객체 여부
104
- */
105
- constructor(
106
- readonly meta: {
107
- targetTableFn: TTargetTableFn;
108
- relationName: string;
109
- description?: string;
110
- isSingle?: TIsSingle;
111
- },
112
- ) {}
113
-
114
- /**
115
- * 관계 설명 설정
116
- *
117
- * @param desc - 관계 설명
118
- * @returns 새 ForeignKeyTargetBuilder 인스턴스
119
- */
120
- description(desc: string): ForeignKeyTargetBuilder<TTargetTableFn, TIsSingle> {
121
- return new ForeignKeyTargetBuilder({ ...this.meta, description: desc });
122
- }
123
-
124
- /**
125
- * 단일 객체 관계로 설정 (1:1)
126
- *
127
- * 기본은 배열 (1:N), single() 호출 시 단일 객체
128
- *
129
- * @returns 새 ForeignKeyTargetBuilder 인스턴스 (isSingle=true)
130
- *
131
- * @example
132
- * ```typescript
133
- * profile: r.foreignKeyTarget(() => Profile, "user").single()
134
- * ```
135
- */
136
- single(): ForeignKeyTargetBuilder<TTargetTableFn, true> {
137
- return new ForeignKeyTargetBuilder({ ...this.meta, isSingle: true });
138
- }
139
- }
140
-
141
- // ============================================
142
- // RelationKeyBuilder (FK와 동일하지만 DB에 FK 등록 안 함)
143
- // ============================================
144
-
145
- /**
146
- * 논리적 관계 빌더 (N:1) - DB FK 미생성
147
- *
148
- * ForeignKeyBuilder와 동일하지만 DB에 FK 제약조건을 생성하지 않음
149
- * (View)에서도 사용 가능
150
- *
151
- * @template TOwner - 소유 테이블/뷰 빌더 타입
152
- * @template TTargetFn - 참조 테이블/뷰 빌더 팩토리 타입
153
- *
154
- * @example
155
- * ```typescript
156
- * // 뷰에서 테이블로 관계 정의
157
- * const UserSummary = View("UserSummary")
158
- * .query((db: MyDb) => db.user().select(...))
159
- * .relations((r) => ({
160
- * // 테이블 (FK 미생성)
161
- * company: r.relationKey(["companyId"], () => Company),
162
- * }));
163
- *
164
- * // 테이블에서 FK 없이 관계 정의
165
- * const Report = Table("Report")
166
- * .columns((c) => ({ userId: c.bigint() }))
167
- * .relations((r) => ({
168
- * user: r.relationKey(["userId"], () => User),
169
- * }));
170
- * ```
171
- *
172
- * @see {@link ForeignKeyBuilder} DB FK 생성 버전
173
- */
174
- export class RelationKeyBuilder<
175
- TOwner extends TableBuilder<any, any> | ViewBuilder<any, any, any>,
176
- TTargetFn extends () => TableBuilder<any, any> | ViewBuilder<any, any, any>,
177
- > {
178
- /**
179
- * @param meta - 관계 메타데이터
180
- * @param meta.ownerFn - 소유 테이블/뷰 팩토리
181
- * @param meta.columns - 관계 컬럼명 배열
182
- * @param meta.targetFn - 참조 테이블/뷰 팩토리
183
- * @param meta.description - 관계 설명
184
- */
185
- constructor(
186
- readonly meta: {
187
- ownerFn: () => TOwner;
188
- columns: string[];
189
- targetFn: TTargetFn;
190
- description?: string;
191
- },
192
- ) {}
193
-
194
- /**
195
- * 관계 설명 설정
196
- *
197
- * @param desc - 관계 설명
198
- * @returns 새 RelationKeyBuilder 인스턴스
199
- */
200
- description(desc: string): RelationKeyBuilder<TOwner, TTargetFn> {
201
- return new RelationKeyBuilder({ ...this.meta, description: desc });
202
- }
203
- }
204
-
205
- /**
206
- * 논리적 관계 역참조 빌더 (1:N) - DB FK 미생성
207
- *
208
- * ForeignKeyTargetBuilder와 동일하지만 DB에 FK 제약조건을 생성하지 않음
209
- * (View)에서도 사용 가능
210
- *
211
- * @template TTargetTableFn - 참조하는 테이블/뷰 빌더 팩토리 타입
212
- * @template TIsSingle - 단일 객체 여부
213
- *
214
- * @example
215
- * ```typescript
216
- * const Company = Table("Company")
217
- * .columns((c) => ({ id: c.bigint() }))
218
- * .relations((r) => ({
219
- * // 역참조 (FK 미생성)
220
- * employees: r.relationKeyTarget(() => UserSummary, "company"),
221
- * }));
222
- * ```
223
- *
224
- * @see {@link ForeignKeyTargetBuilder} DB FK 생성 버전
225
- */
226
- export class RelationKeyTargetBuilder<
227
- TTargetTableFn extends () => TableBuilder<any, any> | ViewBuilder<any, any, any>,
228
- TIsSingle extends boolean,
229
- > {
230
- /**
231
- * @param meta - 관계 역참조 메타데이터
232
- * @param meta.targetTableFn - 참조하는 테이블/뷰 팩토리
233
- * @param meta.relationName - 참조하는 테이블/뷰의 관계명
234
- * @param meta.description - 관계 설명
235
- * @param meta.isSingle - 단일 객체 여부
236
- */
237
- constructor(
238
- readonly meta: {
239
- targetTableFn: TTargetTableFn;
240
- relationName: string;
241
- description?: string;
242
- isSingle?: TIsSingle;
243
- },
244
- ) {}
245
-
246
- /**
247
- * 관계 설명 설정
248
- *
249
- * @param desc - 관계 설명
250
- * @returns 새 RelationKeyTargetBuilder 인스턴스
251
- */
252
- description(desc: string): RelationKeyTargetBuilder<TTargetTableFn, TIsSingle> {
253
- return new RelationKeyTargetBuilder({ ...this.meta, description: desc });
254
- }
255
-
256
- /**
257
- * 단일 객체 관계로 설정 (1:1)
258
- *
259
- * 기본은 배열 (1:N), single() 호출 시 단일 객체
260
- *
261
- * @returns 새 RelationKeyTargetBuilder 인스턴스 (isSingle=true)
262
- */
263
- single(): RelationKeyTargetBuilder<TTargetTableFn, true> {
264
- return new RelationKeyTargetBuilder({ ...this.meta, isSingle: true });
265
- }
266
- }
267
-
268
- /**
269
- * FK 관계 팩토리 타입 (테이블 전용)
270
- *
271
- * @template TOwner - 소유 테이블 빌더 타입
272
- * @template TColumnKey - 컬럼 타입
273
- */
274
- type RelationFkFactory<TOwner extends TableBuilder<any, any>, TColumnKey extends string> = {
275
- /** N:1 FK 관계 정의 (DB FK 생성) */
276
- foreignKey<TTargetFn extends () => TableBuilder<any, any>>(
277
- columns: TColumnKey[],
278
- targetFn: TTargetFn,
279
- ): ForeignKeyBuilder<TOwner, TTargetFn>;
280
- /** 1:N FK 역참조 정의 */
281
- foreignKeyTarget<TTargetTableFn extends () => TableBuilder<any, any>>(
282
- targetTableFn: TTargetTableFn,
283
- relationName: string,
284
- ): ForeignKeyTargetBuilder<TTargetTableFn, false>;
285
- };
286
-
287
- /**
288
- * 논리적 관계 팩토리 타입 (테이블/뷰 공용)
289
- *
290
- * @template TOwner - 소유 테이블/뷰 빌더 타입
291
- * @template TColumnKey - 컬럼 타입
292
- */
293
- type RelationRkFactory<
294
- TOwner extends TableBuilder<any, any> | ViewBuilder<any, any, any>,
295
- TColumnKey extends string,
296
- > = {
297
- /** N:1 논리적 관계 정의 (DB FK 미생성) */
298
- relationKey<TTargetFn extends () => TableBuilder<any, any> | ViewBuilder<any, any, any>>(
299
- columns: TColumnKey[],
300
- targetFn: TTargetFn,
301
- ): RelationKeyBuilder<TOwner, TTargetFn>;
302
- /** 1:N 논리적 역참조 정의 */
303
- relationKeyTarget<
304
- TTargetTableFn extends () => TableBuilder<any, any> | ViewBuilder<any, any, any>,
305
- >(
306
- targetTableFn: TTargetTableFn,
307
- relationName: string,
308
- ): RelationKeyTargetBuilder<TTargetTableFn, false>;
309
- };
310
-
311
- /**
312
- * 관계 빌더 팩토리 생성
313
- *
314
- * TableBuilder.relations() 및 ViewBuilder.relations()에서 사용
315
- * 테이블은 FK + RelationKey 모두 사용 가능, 뷰는 RelationKey만 사용 가능
316
- *
317
- * @template TOwner - 소유 테이블/뷰 빌더 타입
318
- * @template TColumnKey - 컬럼 타입
319
- * @param ownerFn - 소유 테이블/뷰 팩토리 함수
320
- * @returns 관계 빌더 팩토리
321
- *
322
- * @example
323
- * ```typescript
324
- * // 테이블 - FK, RelationKey 모두 사용 가능
325
- * const Post = Table("Post")
326
- * .columns((c) => ({
327
- * id: c.bigint(),
328
- * authorId: c.bigint(),
329
- * }))
330
- * .relations((r) => ({
331
- * author: r.foreignKey(["authorId"], () => User), // FK 생성
332
- * }));
333
- *
334
- * // - RelationKey만 사용 가능
335
- * const UserSummary = View("UserSummary")
336
- * .query(...)
337
- * .relations((r) => ({
338
- * posts: r.relationKeyTarget(() => Post, "author"), // FK 미생성
339
- * }));
340
- * ```
341
- */
342
- export function createRelationFactory<
343
- TOwner extends TableBuilder<any, any> | ViewBuilder<any, any, any>,
344
- TColumnKey extends string,
345
- >(
346
- ownerFn: () => TOwner,
347
- ): TOwner extends TableBuilder<any, any>
348
- ? RelationFkFactory<TOwner, TColumnKey> & RelationRkFactory<TOwner, TColumnKey>
349
- : RelationRkFactory<TOwner, TColumnKey> {
350
- return {
351
- foreignKey(columns, targetFn) {
352
- return new ForeignKeyBuilder({
353
- ownerFn: ownerFn as () => TableBuilder<any, any>,
354
- columns,
355
- targetFn,
356
- });
357
- },
358
- foreignKeyTarget(targetTableFn, relationName) {
359
- return new ForeignKeyTargetBuilder({ targetTableFn, relationName });
360
- },
361
- relationKey(columns, targetFn) {
362
- return new RelationKeyBuilder({
363
- ownerFn: ownerFn,
364
- columns,
365
- targetFn,
366
- });
367
- },
368
- relationKeyTarget(targetTableFn, relationName) {
369
- return new RelationKeyTargetBuilder({ targetTableFn, relationName });
370
- },
371
- } as TOwner extends TableBuilder<any, any>
372
- ? RelationFkFactory<TOwner, TColumnKey> & RelationRkFactory<TOwner, TColumnKey>
373
- : RelationRkFactory<TOwner, TColumnKey>;
374
- }
375
-
376
- // ============================================
377
- // 빌더 레코드
378
- // ============================================
379
-
380
- /**
381
- * 관계 빌더 레코드 타입
382
- *
383
- * TableBuilder.relations() 및 ViewBuilder.relations()의 반환 타입
384
- */
385
- export type RelationBuilderRecord = Record<
386
- string,
387
- | ForeignKeyBuilder<any, any>
388
- | ForeignKeyTargetBuilder<any, any>
389
- | RelationKeyBuilder<any, any>
390
- | RelationKeyTargetBuilder<any, any>
391
- >;
392
-
393
- // ============================================
394
- // Infer - 관계 타입 추론
395
- // ============================================
396
-
397
- /**
398
- * FK/RelationKey에서 참조 대상 타입 추출 (단일 객체)
399
- *
400
- * N:1 관계의 참조 대상 타입
401
- *
402
- * @template T - FK 또는 RelationKey 빌더 타입
403
- */
404
- export type ExtractRelationTarget<TRelation> = TRelation extends
405
- | ForeignKeyBuilder<any, infer TTargetFn>
406
- | RelationKeyBuilder<any, infer TTargetFn>
407
- ? ReturnType<TTargetFn> extends TableBuilder<infer TCols, infer TRels>
408
- ? InferColumns<TCols> & InferDeepRelations<TRels>
409
- : ReturnType<TTargetFn> extends ViewBuilder<any, infer TData, infer TRels>
410
- ? TData & InferDeepRelations<TRels>
411
- : never
412
- : never;
413
-
414
- /**
415
- * FKTarget/RelationKeyTarget에서 참조 대상 타입 추출 (배열 또는 단일 객체)
416
- *
417
- * 1:N 관계의 참조 대상 타입 (single() 호출 시 단일 객체)
418
- * TTargetTableFn: () => Post 형태로 lazy evaluation하여 순환참조 방지
419
- *
420
- * @template T - FKTarget 또는 RelationKeyTarget 빌더 타입
421
- */
422
- export type ExtractRelationTargetResult<TRelation> = TRelation extends
423
- | ForeignKeyTargetBuilder<infer TTargetTableFn, infer TIsSingle>
424
- | RelationKeyTargetBuilder<infer TTargetTableFn, infer TIsSingle>
425
- ? ReturnType<TTargetTableFn> extends TableBuilder<infer TCols, infer TRels>
426
- ? TIsSingle extends true
427
- ? InferColumns<TCols> & InferDeepRelations<TRels>
428
- : (InferColumns<TCols> & InferDeepRelations<TRels>)[]
429
- : ReturnType<TTargetTableFn> extends ViewBuilder<any, infer TData, infer TRels>
430
- ? TIsSingle extends true
431
- ? TData & InferDeepRelations<TRels>
432
- : (TData & InferDeepRelations<TRels>)[]
433
- : never
434
- : never;
435
-
436
- /**
437
- * 관계 정의에서 깊은 관계 타입 추론
438
- *
439
- * 모든 관계를 optional로 만들어 include() 없이 접근 시 undefined 처리
440
- *
441
- * @template TRelations - 관계 빌더 레코드 타입
442
- *
443
- * @example
444
- * ```typescript
445
- * type UserRelations = InferDeepRelations<typeof User.$relations>;
446
- * // { posts?: Post[]; profile?: Profile; }
447
- * ```
448
- */
449
- export type InferDeepRelations<TRelations extends RelationBuilderRecord> = {
450
- [K in keyof TRelations]?:
451
- | ExtractRelationTarget<TRelations[K]>
452
- | ExtractRelationTargetResult<TRelations[K]>;
453
- };
1
+ import { type InferColumns } from "./column-builder";
2
+ import type { TableBuilder } from "../table-builder";
3
+ import type { ViewBuilder } from "../view-builder";
4
+
5
+ // ============================================
6
+ // ForeignKeyBuilder
7
+ // ============================================
8
+
9
+ /**
10
+ * Foreign Key relationship builder (N:1)
11
+ *
12
+ * 현재 Table에서 참조 Table로의 FK relationship definition
13
+ * DB에 실제 FK constraint Generate
14
+ *
15
+ * @template TOwner - 소유 Table builder type
16
+ * @template TTargetFn - 참조 Table builder factory type
17
+ *
18
+ * @example
19
+ * ```typescript
20
+ * const Post = Table("Post")
21
+ * .columns((c) => ({
22
+ * id: c.bigint().autoIncrement(),
23
+ * authorId: c.bigint(), // FK column
24
+ * }))
25
+ * .primaryKey("id")
26
+ * .relations((r) => ({
27
+ * // N:1 relationship - Post → User
28
+ * author: r.foreignKey(["authorId"], () => User),
29
+ * }));
30
+ * ```
31
+ *
32
+ * @see {@link ForeignKeyTargetBuilder} 역참조 builder
33
+ * @see {@link RelationKeyBuilder} DB FK 없는 relationship
34
+ */
35
+ export class ForeignKeyBuilder<
36
+ TOwner extends TableBuilder<any, any>,
37
+ TTargetFn extends () => TableBuilder<any, any>,
38
+ > {
39
+ /**
40
+ * @param meta - FK Metadata
41
+ * @param meta.ownerFn - 소유 Table factory
42
+ * @param meta.columns - FK column명 array
43
+ * @param meta.targetFn - 참조 Table factory
44
+ * @param meta.description - relationship description
45
+ */
46
+ constructor(
47
+ readonly meta: {
48
+ ownerFn: () => TOwner;
49
+ columns: string[];
50
+ targetFn: TTargetFn;
51
+ description?: string;
52
+ },
53
+ ) {}
54
+
55
+ /**
56
+ * relationship set description
57
+ *
58
+ * @param desc - relationship description
59
+ * @returns 새 ForeignKeyBuilder instance
60
+ */
61
+ description(desc: string): ForeignKeyBuilder<TOwner, TTargetFn> {
62
+ return new ForeignKeyBuilder({ ...this.meta, description: desc });
63
+ }
64
+ }
65
+
66
+ /**
67
+ * Foreign Key 역참조 builder (1:N)
68
+ *
69
+ * 다른 Table에서 현재 Table을 참조하는 FK의 역참조 definition
70
+ * include() 시 배열로 로드 (single() 호출 시 단일 object)
71
+ *
72
+ * @template TTargetTableFn - 참조하는 Table builder factory type
73
+ * @template TIsSingle - 단일 object 여부
74
+ *
75
+ * @example
76
+ * ```typescript
77
+ * const User = Table("User")
78
+ * .columns((c) => ({
79
+ * id: c.bigint().autoIncrement(),
80
+ * name: c.varchar(100),
81
+ * }))
82
+ * .primaryKey("id")
83
+ * .relations((r) => ({
84
+ * // 1:N relationship - User ← Post.author
85
+ * posts: r.foreignKeyTarget(() => Post, "author"),
86
+ *
87
+ * // 1:1 relationship (단일 object)
88
+ * profile: r.foreignKeyTarget(() => Profile, "user").single(),
89
+ * }));
90
+ * ```
91
+ *
92
+ * @see {@link ForeignKeyBuilder} FK builder
93
+ */
94
+ export class ForeignKeyTargetBuilder<
95
+ TTargetTableFn extends () => TableBuilder<any, any>,
96
+ TIsSingle extends boolean,
97
+ > {
98
+ /**
99
+ * @param meta - FK 역참조 Metadata
100
+ * @param meta.targetTableFn - 참조하는 Table factory
101
+ * @param meta.relationName - 참조하는 Table의 FK 관계명
102
+ * @param meta.description - relationship description
103
+ * @param meta.isSingle - 단일 object 여부
104
+ */
105
+ constructor(
106
+ readonly meta: {
107
+ targetTableFn: TTargetTableFn;
108
+ relationName: string;
109
+ description?: string;
110
+ isSingle?: TIsSingle;
111
+ },
112
+ ) {}
113
+
114
+ /**
115
+ * relationship set description
116
+ *
117
+ * @param desc - relationship description
118
+ * @returns 새 ForeignKeyTargetBuilder instance
119
+ */
120
+ description(desc: string): ForeignKeyTargetBuilder<TTargetTableFn, TIsSingle> {
121
+ return new ForeignKeyTargetBuilder({ ...this.meta, description: desc });
122
+ }
123
+
124
+ /**
125
+ * 단일 object 관계로 설정 (1:1)
126
+ *
127
+ * Basic은 array (1:N), single() 호출 시 단일 object
128
+ *
129
+ * @returns 새 ForeignKeyTargetBuilder instance (isSingle=true)
130
+ *
131
+ * @example
132
+ * ```typescript
133
+ * profile: r.foreignKeyTarget(() => Profile, "user").single()
134
+ * ```
135
+ */
136
+ single(): ForeignKeyTargetBuilder<TTargetTableFn, true> {
137
+ return new ForeignKeyTargetBuilder({ ...this.meta, isSingle: true });
138
+ }
139
+ }
140
+
141
+ // ============================================
142
+ // RelationKeyBuilder (FK와 동일하지만 DB에 FK 등록 안 함)
143
+ // ============================================
144
+
145
+ /**
146
+ * 논리적 relationship builder (N:1) - DB FK 미생성
147
+ *
148
+ * ForeignKeyBuilder와 동일하지만 DB에 FK 제약조건을 생성하지 않음
149
+ * View(View)에서도 사용 가능
150
+ *
151
+ * @template TOwner - 소유 Table/View builder type
152
+ * @template TTargetFn - 참조 Table/View builder factory type
153
+ *
154
+ * @example
155
+ * ```typescript
156
+ * // View에서 Table로 relationship definition
157
+ * const UserSummary = View("UserSummary")
158
+ * .query((db: MyDb) => db.user().select(...))
159
+ * .relations((r) => ({
160
+ * // ViewTable (FK 미생성)
161
+ * company: r.relationKey(["companyId"], () => Company),
162
+ * }));
163
+ *
164
+ * // Table에서 FK 없이 relationship definition
165
+ * const Report = Table("Report")
166
+ * .columns((c) => ({ userId: c.bigint() }))
167
+ * .relations((r) => ({
168
+ * user: r.relationKey(["userId"], () => User),
169
+ * }));
170
+ * ```
171
+ *
172
+ * @see {@link ForeignKeyBuilder} DB FK Generate 버전
173
+ */
174
+ export class RelationKeyBuilder<
175
+ TOwner extends TableBuilder<any, any> | ViewBuilder<any, any, any>,
176
+ TTargetFn extends () => TableBuilder<any, any> | ViewBuilder<any, any, any>,
177
+ > {
178
+ /**
179
+ * @param meta - relationship Metadata
180
+ * @param meta.ownerFn - 소유 Table/View factory
181
+ * @param meta.columns - relationship column명 array
182
+ * @param meta.targetFn - 참조 Table/View factory
183
+ * @param meta.description - relationship description
184
+ */
185
+ constructor(
186
+ readonly meta: {
187
+ ownerFn: () => TOwner;
188
+ columns: string[];
189
+ targetFn: TTargetFn;
190
+ description?: string;
191
+ },
192
+ ) {}
193
+
194
+ /**
195
+ * relationship set description
196
+ *
197
+ * @param desc - relationship description
198
+ * @returns 새 RelationKeyBuilder instance
199
+ */
200
+ description(desc: string): RelationKeyBuilder<TOwner, TTargetFn> {
201
+ return new RelationKeyBuilder({ ...this.meta, description: desc });
202
+ }
203
+ }
204
+
205
+ /**
206
+ * 논리적 relationship 역참조 builder (1:N) - DB FK 미생성
207
+ *
208
+ * ForeignKeyTargetBuilder와 동일하지만 DB에 FK 제약조건을 생성하지 않음
209
+ * View(View)에서도 사용 가능
210
+ *
211
+ * @template TTargetTableFn - 참조하는 Table/View builder factory type
212
+ * @template TIsSingle - 단일 object 여부
213
+ *
214
+ * @example
215
+ * ```typescript
216
+ * const Company = Table("Company")
217
+ * .columns((c) => ({ id: c.bigint() }))
218
+ * .relations((r) => ({
219
+ * // 역참조 (FK 미생성)
220
+ * employees: r.relationKeyTarget(() => UserSummary, "company"),
221
+ * }));
222
+ * ```
223
+ *
224
+ * @see {@link ForeignKeyTargetBuilder} DB FK Generate 버전
225
+ */
226
+ export class RelationKeyTargetBuilder<
227
+ TTargetTableFn extends () => TableBuilder<any, any> | ViewBuilder<any, any, any>,
228
+ TIsSingle extends boolean,
229
+ > {
230
+ /**
231
+ * @param meta - relationship 역참조 Metadata
232
+ * @param meta.targetTableFn - 참조하는 Table/View factory
233
+ * @param meta.relationName - 참조하는 Table/View의 관계명
234
+ * @param meta.description - relationship description
235
+ * @param meta.isSingle - 단일 object 여부
236
+ */
237
+ constructor(
238
+ readonly meta: {
239
+ targetTableFn: TTargetTableFn;
240
+ relationName: string;
241
+ description?: string;
242
+ isSingle?: TIsSingle;
243
+ },
244
+ ) {}
245
+
246
+ /**
247
+ * relationship set description
248
+ *
249
+ * @param desc - relationship description
250
+ * @returns 새 RelationKeyTargetBuilder instance
251
+ */
252
+ description(desc: string): RelationKeyTargetBuilder<TTargetTableFn, TIsSingle> {
253
+ return new RelationKeyTargetBuilder({ ...this.meta, description: desc });
254
+ }
255
+
256
+ /**
257
+ * 단일 object 관계로 설정 (1:1)
258
+ *
259
+ * Basic은 array (1:N), single() 호출 시 단일 object
260
+ *
261
+ * @returns 새 RelationKeyTargetBuilder instance (isSingle=true)
262
+ */
263
+ single(): RelationKeyTargetBuilder<TTargetTableFn, true> {
264
+ return new RelationKeyTargetBuilder({ ...this.meta, isSingle: true });
265
+ }
266
+ }
267
+
268
+ /**
269
+ * FK relationship factory type (table 전용)
270
+ *
271
+ * @template TOwner - 소유 Table builder type
272
+ * @template TColumnKey - Column key type
273
+ */
274
+ type RelationFkFactory<TOwner extends TableBuilder<any, any>, TColumnKey extends string> = {
275
+ /** N:1 FK relationship definition (DB FK Create) */
276
+ foreignKey<TTargetFn extends () => TableBuilder<any, any>>(
277
+ columns: TColumnKey[],
278
+ targetFn: TTargetFn,
279
+ ): ForeignKeyBuilder<TOwner, TTargetFn>;
280
+ /** 1:N FK 역참조 definition */
281
+ foreignKeyTarget<TTargetTableFn extends () => TableBuilder<any, any>>(
282
+ targetTableFn: TTargetTableFn,
283
+ relationName: string,
284
+ ): ForeignKeyTargetBuilder<TTargetTableFn, false>;
285
+ };
286
+
287
+ /**
288
+ * 논리적 relationship factory type (table/View 공용)
289
+ *
290
+ * @template TOwner - 소유 Table/View builder type
291
+ * @template TColumnKey - Column key type
292
+ */
293
+ type RelationRkFactory<
294
+ TOwner extends TableBuilder<any, any> | ViewBuilder<any, any, any>,
295
+ TColumnKey extends string,
296
+ > = {
297
+ /** N:1 논리적 relationship definition (DB FK 미생성) */
298
+ relationKey<TTargetFn extends () => TableBuilder<any, any> | ViewBuilder<any, any, any>>(
299
+ columns: TColumnKey[],
300
+ targetFn: TTargetFn,
301
+ ): RelationKeyBuilder<TOwner, TTargetFn>;
302
+ /** 1:N 논리적 역참조 definition */
303
+ relationKeyTarget<
304
+ TTargetTableFn extends () => TableBuilder<any, any> | ViewBuilder<any, any, any>,
305
+ >(
306
+ targetTableFn: TTargetTableFn,
307
+ relationName: string,
308
+ ): RelationKeyTargetBuilder<TTargetTableFn, false>;
309
+ };
310
+
311
+ /**
312
+ * relationship builder factory Generate
313
+ *
314
+ * TableBuilder.relations() 및 ViewBuilder.relations()used in
315
+ * Table은 FK + RelationKey 모두 사용 가능, View는 RelationKey만 사용 가능
316
+ *
317
+ * @template TOwner - 소유 Table/View builder type
318
+ * @template TColumnKey - Column key type
319
+ * @param ownerFn - 소유 Table/View factory function
320
+ * @returns relationship builder factory
321
+ *
322
+ * @example
323
+ * ```typescript
324
+ * // Table - FK, RelationKey 모두 사용 가능
325
+ * const Post = Table("Post")
326
+ * .columns((c) => ({
327
+ * id: c.bigint(),
328
+ * authorId: c.bigint(),
329
+ * }))
330
+ * .relations((r) => ({
331
+ * author: r.foreignKey(["authorId"], () => User), // FK Generate
332
+ * }));
333
+ *
334
+ * // View - RelationKey만 사용 가능
335
+ * const UserSummary = View("UserSummary")
336
+ * .query(...)
337
+ * .relations((r) => ({
338
+ * posts: r.relationKeyTarget(() => Post, "author"), // FK 미생성
339
+ * }));
340
+ * ```
341
+ */
342
+ export function createRelationFactory<
343
+ TOwner extends TableBuilder<any, any> | ViewBuilder<any, any, any>,
344
+ TColumnKey extends string,
345
+ >(
346
+ ownerFn: () => TOwner,
347
+ ): TOwner extends TableBuilder<any, any>
348
+ ? RelationFkFactory<TOwner, TColumnKey> & RelationRkFactory<TOwner, TColumnKey>
349
+ : RelationRkFactory<TOwner, TColumnKey> {
350
+ return {
351
+ foreignKey(columns, targetFn) {
352
+ return new ForeignKeyBuilder({
353
+ ownerFn: ownerFn as () => TableBuilder<any, any>,
354
+ columns,
355
+ targetFn,
356
+ });
357
+ },
358
+ foreignKeyTarget(targetTableFn, relationName) {
359
+ return new ForeignKeyTargetBuilder({ targetTableFn, relationName });
360
+ },
361
+ relationKey(columns, targetFn) {
362
+ return new RelationKeyBuilder({
363
+ ownerFn: ownerFn,
364
+ columns,
365
+ targetFn,
366
+ });
367
+ },
368
+ relationKeyTarget(targetTableFn, relationName) {
369
+ return new RelationKeyTargetBuilder({ targetTableFn, relationName });
370
+ },
371
+ } as TOwner extends TableBuilder<any, any>
372
+ ? RelationFkFactory<TOwner, TColumnKey> & RelationRkFactory<TOwner, TColumnKey>
373
+ : RelationRkFactory<TOwner, TColumnKey>;
374
+ }
375
+
376
+ // ============================================
377
+ // builder 레코드
378
+ // ============================================
379
+
380
+ /**
381
+ * relationship builder record type
382
+ *
383
+ * TableBuilder.relations() 및 ViewBuilder.relations()의 return type
384
+ */
385
+ export type RelationBuilderRecord = Record<
386
+ string,
387
+ | ForeignKeyBuilder<any, any>
388
+ | ForeignKeyTargetBuilder<any, any>
389
+ | RelationKeyBuilder<any, any>
390
+ | RelationKeyTargetBuilder<any, any>
391
+ >;
392
+
393
+ // ============================================
394
+ // Infer - relationship Type inference
395
+ // ============================================
396
+
397
+ /**
398
+ * FK/RelationKey에서 참조 대상 type 추출 (단일 object)
399
+ *
400
+ * N:1 관계의 참조 대상 type
401
+ *
402
+ * @template T - FK 또는 RelationKey builder type
403
+ */
404
+ export type ExtractRelationTarget<TRelation> = TRelation extends
405
+ | ForeignKeyBuilder<any, infer TTargetFn>
406
+ | RelationKeyBuilder<any, infer TTargetFn>
407
+ ? ReturnType<TTargetFn> extends TableBuilder<infer TCols, infer TRels>
408
+ ? InferColumns<TCols> & InferDeepRelations<TRels>
409
+ : ReturnType<TTargetFn> extends ViewBuilder<any, infer TData, infer TRels>
410
+ ? TData & InferDeepRelations<TRels>
411
+ : never
412
+ : never;
413
+
414
+ /**
415
+ * FKTarget/RelationKeyTarget에서 참조 대상 type 추출 (array 또는 단일 object)
416
+ *
417
+ * 1:N 관계의 참조 대상 type (single() 호출 시 단일 object)
418
+ * TTargetTableFn: () => Post 형태로 lazy evaluation하여 순환참조 방지
419
+ *
420
+ * @template T - FKTarget 또는 RelationKeyTarget builder type
421
+ */
422
+ export type ExtractRelationTargetResult<TRelation> = TRelation extends
423
+ | ForeignKeyTargetBuilder<infer TTargetTableFn, infer TIsSingle>
424
+ | RelationKeyTargetBuilder<infer TTargetTableFn, infer TIsSingle>
425
+ ? ReturnType<TTargetTableFn> extends TableBuilder<infer TCols, infer TRels>
426
+ ? TIsSingle extends true
427
+ ? InferColumns<TCols> & InferDeepRelations<TRels>
428
+ : (InferColumns<TCols> & InferDeepRelations<TRels>)[]
429
+ : ReturnType<TTargetTableFn> extends ViewBuilder<any, infer TData, infer TRels>
430
+ ? TIsSingle extends true
431
+ ? TData & InferDeepRelations<TRels>
432
+ : (TData & InferDeepRelations<TRels>)[]
433
+ : never
434
+ : never;
435
+
436
+ /**
437
+ * relationship 정의에서 깊은 relationship Type inference
438
+ *
439
+ * 모든 관계를 optional로 만들어 include() 없이 access 시 undefined processing
440
+ *
441
+ * @template TRelations - relationship builder record type
442
+ *
443
+ * @example
444
+ * ```typescript
445
+ * type UserRelations = InferDeepRelations<typeof User.$relations>;
446
+ * // { posts?: Post[]; profile?: Profile; }
447
+ * ```
448
+ */
449
+ export type InferDeepRelations<TRelations extends RelationBuilderRecord> = {
450
+ [K in keyof TRelations]?:
451
+ | ExtractRelationTarget<TRelations[K]>
452
+ | ExtractRelationTargetResult<TRelations[K]>;
453
+ };