@simplysm/orm-common 14.0.48 → 14.0.50

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 (58) hide show
  1. package/README.md +39 -172
  2. package/dist/db-context.d.ts +6 -6
  3. package/dist/db-context.d.ts.map +1 -1
  4. package/dist/db-context.js.map +1 -1
  5. package/dist/ddl/initialize.js.map +1 -1
  6. package/dist/ddl/table-ddl.d.ts +3 -3
  7. package/dist/ddl/table-ddl.d.ts.map +1 -1
  8. package/dist/ddl/table-ddl.js.map +1 -1
  9. package/dist/exec/queryable.d.ts +10 -10
  10. package/dist/exec/queryable.d.ts.map +1 -1
  11. package/dist/exec/queryable.js.map +1 -1
  12. package/dist/models/system-migration.d.ts +1 -1
  13. package/dist/schema/factory/relation-builder.d.ts +17 -17
  14. package/dist/schema/factory/relation-builder.d.ts.map +1 -1
  15. package/dist/schema/factory/relation-builder.js.map +1 -1
  16. package/dist/schema/table-builder.d.ts +12 -12
  17. package/dist/schema/table-builder.d.ts.map +1 -1
  18. package/dist/schema/table-builder.js +1 -1
  19. package/dist/schema/table-builder.js.map +1 -1
  20. package/dist/types/db-context-def.d.ts +4 -4
  21. package/dist/types/db-context-def.d.ts.map +1 -1
  22. package/dist/utils/result-parser.js.map +1 -1
  23. package/docs/core/db-context.md +208 -0
  24. package/docs/core/db-transaction-error.md +64 -0
  25. package/docs/expression/expr-unit.md +62 -0
  26. package/docs/expression/expr.md +198 -0
  27. package/docs/models/migration.md +37 -0
  28. package/docs/query-builder/create-query-builder.md +80 -0
  29. package/docs/queryable-executable/executable.md +54 -0
  30. package/docs/queryable-executable/parse-search-query.md +75 -0
  31. package/docs/queryable-executable/queryable.md +238 -0
  32. package/docs/schema-builders/column-builder.md +63 -0
  33. package/docs/schema-builders/foreign-key-builder.md +137 -0
  34. package/docs/schema-builders/index-builder.md +54 -0
  35. package/docs/schema-builders/procedure.md +67 -0
  36. package/docs/schema-builders/table.md +94 -0
  37. package/docs/schema-builders/view.md +71 -0
  38. package/docs/types/data-type.md +146 -0
  39. package/docs/types/dialect.md +151 -0
  40. package/docs/types/expr.md +175 -0
  41. package/docs/types/parse-query-result.md +58 -0
  42. package/docs/types/query-def.md +224 -0
  43. package/package.json +2 -2
  44. package/src/db-context.ts +8 -8
  45. package/src/ddl/initialize.ts +4 -4
  46. package/src/ddl/table-ddl.ts +3 -3
  47. package/src/exec/queryable.ts +21 -21
  48. package/src/schema/factory/relation-builder.ts +45 -38
  49. package/src/schema/table-builder.ts +13 -12
  50. package/src/types/db-context-def.ts +4 -4
  51. package/src/utils/result-parser.ts +57 -57
  52. package/docs/core.md +0 -188
  53. package/docs/expression.md +0 -190
  54. package/docs/models.md +0 -17
  55. package/docs/query-builder.md +0 -97
  56. package/docs/queryable-executable.md +0 -311
  57. package/docs/schema-builders.md +0 -364
  58. package/docs/types.md +0 -537
@@ -0,0 +1,224 @@
1
+ # QueryDef
2
+
3
+ SQL AST 정의 타입 모음. `Queryable`이 내부적으로 생성하며, `QueryBuilderBase.build(def)`에 전달되어 SQL 문자열로 변환된다.
4
+
5
+ ## `QueryDef`
6
+
7
+ 모든 쿼리 정의의 유니온 타입.
8
+
9
+ ```typescript
10
+ export type QueryDef =
11
+ | SelectQueryDef
12
+ | InsertQueryDef
13
+ | InsertIfNotExistsQueryDef
14
+ | InsertIntoQueryDef
15
+ | UpdateQueryDef
16
+ | DeleteQueryDef
17
+ | UpsertQueryDef
18
+ | SwitchFkQueryDef
19
+ | CreateTableQueryDef
20
+ | DropTableQueryDef
21
+ | RenameTableQueryDef
22
+ | TruncateQueryDef
23
+ | AddColumnQueryDef
24
+ | DropColumnQueryDef
25
+ | ModifyColumnQueryDef
26
+ | RenameColumnQueryDef
27
+ | AddPrimaryKeyQueryDef
28
+ | DropPrimaryKeyQueryDef
29
+ | AddForeignKeyQueryDef
30
+ | DropForeignKeyQueryDef
31
+ | AddIndexQueryDef
32
+ | DropIndexQueryDef
33
+ | CreateViewQueryDef
34
+ | DropViewQueryDef
35
+ | CreateProcQueryDef
36
+ | DropProcQueryDef
37
+ | ExecProcQueryDef
38
+ | ClearSchemaQueryDef
39
+ | SchemaExistsQueryDef;
40
+ ```
41
+
42
+ ## `QueryDefObjectName`
43
+
44
+ DB 객체 이름 (테이블, 뷰, 프로시저 등).
45
+
46
+ ```typescript
47
+ export interface QueryDefObjectName {
48
+ database?: string;
49
+ schema?: string;
50
+ name: string;
51
+ }
52
+ ```
53
+
54
+ DBMS별 네임스페이스 처리:
55
+ - MySQL: `database.name` (schema 무시)
56
+ - MSSQL: `database.schema.name` (schema 기본값 dbo)
57
+ - PostgreSQL: `schema.name` (database는 연결용)
58
+
59
+ ## DML 쿼리 정의
60
+
61
+ ### `SelectQueryDef`
62
+
63
+ ```typescript
64
+ export interface SelectQueryDef {
65
+ type: "select";
66
+ from?: QueryDefObjectName | SelectQueryDef | SelectQueryDef[] | string;
67
+ as: string;
68
+ select?: Record<string, Expr>;
69
+ distinct?: boolean;
70
+ top?: number;
71
+ lock?: boolean;
72
+ where?: WhereExpr[];
73
+ joins?: SelectQueryDefJoin[];
74
+ orderBy?: [Expr, ("ASC" | "DESC")?][];
75
+ limit?: [number, number];
76
+ groupBy?: Expr[];
77
+ having?: WhereExpr[];
78
+ with?: { name: string; base: SelectQueryDef; recursive: SelectQueryDef };
79
+ }
80
+ ```
81
+
82
+ ### `SelectQueryDefJoin`
83
+
84
+ ```typescript
85
+ export interface SelectQueryDefJoin extends SelectQueryDef {
86
+ isSingle?: boolean;
87
+ }
88
+ ```
89
+
90
+ ### `InsertQueryDef`
91
+
92
+ ```typescript
93
+ export interface InsertQueryDef {
94
+ type: "insert";
95
+ table: QueryDefObjectName;
96
+ records: Record<string, ColumnPrimitive>[];
97
+ overrideIdentity?: boolean;
98
+ output?: CudOutputDef;
99
+ }
100
+ ```
101
+
102
+ ### `InsertIfNotExistsQueryDef`
103
+
104
+ ```typescript
105
+ export interface InsertIfNotExistsQueryDef {
106
+ type: "insertIfNotExists";
107
+ table: QueryDefObjectName;
108
+ record: Record<string, ColumnPrimitive>;
109
+ existsSelectQuery: SelectQueryDef;
110
+ overrideIdentity?: boolean;
111
+ output?: CudOutputDef;
112
+ }
113
+ ```
114
+
115
+ ### `InsertIntoQueryDef`
116
+
117
+ ```typescript
118
+ export interface InsertIntoQueryDef {
119
+ type: "insertInto";
120
+ table: QueryDefObjectName;
121
+ recordsSelectQuery: SelectQueryDef;
122
+ overrideIdentity?: boolean;
123
+ output?: CudOutputDef;
124
+ }
125
+ ```
126
+
127
+ ### `UpdateQueryDef`
128
+
129
+ ```typescript
130
+ export interface UpdateQueryDef {
131
+ type: "update";
132
+ table: QueryDefObjectName;
133
+ as: string;
134
+ record: Record<string, Expr>;
135
+ top?: number;
136
+ where?: WhereExpr[];
137
+ joins?: SelectQueryDefJoin[];
138
+ limit?: [number, number];
139
+ output?: CudOutputDef;
140
+ }
141
+ ```
142
+
143
+ ### `DeleteQueryDef`
144
+
145
+ ```typescript
146
+ export interface DeleteQueryDef {
147
+ type: "delete";
148
+ table: QueryDefObjectName;
149
+ as: string;
150
+ top?: number;
151
+ where?: WhereExpr[];
152
+ joins?: SelectQueryDefJoin[];
153
+ limit?: [number, number];
154
+ output?: CudOutputDef;
155
+ }
156
+ ```
157
+
158
+ ### `UpsertQueryDef`
159
+
160
+ ```typescript
161
+ export interface UpsertQueryDef {
162
+ type: "upsert";
163
+ table: QueryDefObjectName;
164
+ existsSelectQuery: SelectQueryDef;
165
+ insertRecord: Record<string, Expr>;
166
+ updateRecord: Record<string, Expr>;
167
+ overrideIdentity?: boolean;
168
+ output?: CudOutputDef;
169
+ }
170
+ ```
171
+
172
+ ## `CudOutputDef`
173
+
174
+ INSERT/UPDATE/DELETE 후 반환값 정의 (OUTPUT 절).
175
+
176
+ ```typescript
177
+ export interface CudOutputDef {
178
+ columns: string[];
179
+ pkColNames: string[];
180
+ aiColName?: string;
181
+ }
182
+ ```
183
+
184
+ | 필드 | 타입 | 설명 |
185
+ |------|------|------|
186
+ | `columns` | `string[]` | 반환할 컬럼 이름 배열 |
187
+ | `pkColNames` | `string[]` | PK 컬럼 이름 배열 |
188
+ | `aiColName` | `string \| undefined` | AUTO_INCREMENT 컬럼 이름 |
189
+
190
+ ## DDL 쿼리 정의
191
+
192
+ | 인터페이스 | `type` 값 | 설명 |
193
+ |------------|-----------|------|
194
+ | `CreateTableQueryDef` | `"createTable"` | CREATE TABLE |
195
+ | `DropTableQueryDef` | `"dropTable"` | DROP TABLE |
196
+ | `RenameTableQueryDef` | `"renameTable"` | RENAME TABLE |
197
+ | `TruncateQueryDef` | `"truncate"` | TRUNCATE TABLE |
198
+ | `AddColumnQueryDef` | `"addColumn"` | ADD COLUMN |
199
+ | `DropColumnQueryDef` | `"dropColumn"` | DROP COLUMN |
200
+ | `ModifyColumnQueryDef` | `"modifyColumn"` | MODIFY/ALTER COLUMN |
201
+ | `RenameColumnQueryDef` | `"renameColumn"` | RENAME COLUMN |
202
+ | `AddPrimaryKeyQueryDef` | `"addPrimaryKey"` | ADD PRIMARY KEY |
203
+ | `DropPrimaryKeyQueryDef` | `"dropPrimaryKey"` | DROP PRIMARY KEY |
204
+ | `AddForeignKeyQueryDef` | `"addForeignKey"` | ADD FOREIGN KEY |
205
+ | `DropForeignKeyQueryDef` | `"dropForeignKey"` | DROP FOREIGN KEY |
206
+ | `AddIndexQueryDef` | `"addIndex"` | ADD INDEX |
207
+ | `DropIndexQueryDef` | `"dropIndex"` | DROP INDEX |
208
+ | `CreateViewQueryDef` | `"createView"` | CREATE VIEW |
209
+ | `DropViewQueryDef` | `"dropView"` | DROP VIEW |
210
+ | `CreateProcQueryDef` | `"createProc"` | CREATE PROCEDURE |
211
+ | `DropProcQueryDef` | `"dropProc"` | DROP PROCEDURE |
212
+ | `ExecProcQueryDef` | `"execProc"` | EXEC PROCEDURE |
213
+ | `ClearSchemaQueryDef` | `"clearSchema"` | 스키마 내 모든 객체 제거 |
214
+ | `SchemaExistsQueryDef` | `"schemaExists"` | 스키마 존재 여부 확인 |
215
+ | `SwitchFkQueryDef` | `"switchFk"` | FK 제약조건 활성화/비활성화 |
216
+
217
+ ## `DDL_TYPES` / `DdlType`
218
+
219
+ DDL 타입 문자열 목록 및 유니온 타입. `DbContext.executeDefs()` 내부에서 트랜잭션 중 DDL 실행 차단에 사용된다.
220
+
221
+ ```typescript
222
+ export const DDL_TYPES: readonly string[];
223
+ export type DdlType = typeof DDL_TYPES[number];
224
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simplysm/orm-common",
3
- "version": "14.0.48",
3
+ "version": "14.0.50",
4
4
  "description": "심플리즘 패키지 - ORM (common)",
5
5
  "author": "심플리즘",
6
6
  "license": "Apache-2.0",
@@ -22,6 +22,6 @@
22
22
  "@types/node": "^20.19.39"
23
23
  },
24
24
  "dependencies": {
25
- "@simplysm/core-common": "14.0.48"
25
+ "@simplysm/core-common": "14.0.50"
26
26
  }
27
27
  }
package/src/db-context.ts CHANGED
@@ -100,7 +100,7 @@ export abstract class DbContext implements DbContextBase {
100
100
  }
101
101
 
102
102
  getQueryDefObjectName(
103
- tableOrView: TableBuilder<any, any> | ViewBuilder<any, any, any>,
103
+ tableOrView: TableBuilder<any, any, any> | ViewBuilder<any, any, any>,
104
104
  ): QueryDefObjectName {
105
105
  return getQueryDefObjectNameImpl(this, tableOrView);
106
106
  }
@@ -111,9 +111,9 @@ export abstract class DbContext implements DbContextBase {
111
111
 
112
112
  // ── 등록 메서드 ──
113
113
 
114
- protected queryable<T extends TableBuilder<any, any> | ViewBuilder<any, any, any>>(
114
+ protected queryable<T extends TableBuilder<any, any, any> | ViewBuilder<any, any, any>>(
115
115
  builder: T,
116
- ): () => Queryable<T["$inferSelect"], T extends TableBuilder<any, any> ? T : never> {
116
+ ): () => Queryable<T["$inferSelect"], T extends TableBuilder<any, any, any> ? T : never> {
117
117
  const fn = createQueryable(this, builder);
118
118
  Object.defineProperty(fn, SD_BUILDER, { value: builder });
119
119
  return fn;
@@ -245,7 +245,7 @@ export abstract class DbContext implements DbContextBase {
245
245
 
246
246
  // ── DDL 실행 메서드 ──
247
247
 
248
- async createTable(table: TableBuilder<any, any>): Promise<void> {
248
+ async createTable(table: TableBuilder<any, any, any>): Promise<void> {
249
249
  await this.executeDefs([tableDdl.getCreateTableQueryDef(this, table)]);
250
250
  }
251
251
 
@@ -342,12 +342,12 @@ export abstract class DbContext implements DbContextBase {
342
342
 
343
343
  // ── DDL QueryDef 생성기 ──
344
344
 
345
- getCreateTableQueryDef(table: TableBuilder<any, any>): QueryDef {
345
+ getCreateTableQueryDef(table: TableBuilder<any, any, any>): QueryDef {
346
346
  return tableDdl.getCreateTableQueryDef(this, table);
347
347
  }
348
348
 
349
349
  getCreateViewQueryDef(view: ViewBuilder<any, any, any>): QueryDef {
350
- return tableDdl.getCreateViewQueryDef(this as any, view);
350
+ return tableDdl.getCreateViewQueryDef(this, view);
351
351
  }
352
352
 
353
353
  getCreateProcQueryDef(procedure: ProcedureBuilder<any, any>): QueryDef {
@@ -355,9 +355,9 @@ export abstract class DbContext implements DbContextBase {
355
355
  }
356
356
 
357
357
  getCreateObjectQueryDef(
358
- builder: TableBuilder<any, any> | ViewBuilder<any, any, any> | ProcedureBuilder<any, any>,
358
+ builder: TableBuilder<any, any, any> | ViewBuilder<any, any, any> | ProcedureBuilder<any, any>,
359
359
  ): QueryDef {
360
- return tableDdl.getCreateObjectQueryDef(this as any, builder);
360
+ return tableDdl.getCreateObjectQueryDef(this, builder);
361
361
  }
362
362
 
363
363
  getDropTableQueryDef(table: QueryDefObjectName): QueryDef {
@@ -131,7 +131,7 @@ export async function initialize(
131
131
  */
132
132
  async function createAllObjects(
133
133
  db: DbContextBase,
134
- builders: (TableBuilder<any, any> | ViewBuilder<any, any, any> | ProcedureBuilder<any, any>)[],
134
+ builders: (TableBuilder<any, any, any> | ViewBuilder<any, any, any> | ProcedureBuilder<any, any>)[],
135
135
  targetDatabase: string,
136
136
  ): Promise<void> {
137
137
  // targetDatabase에 해당하는 builder만 필터링
@@ -188,16 +188,16 @@ async function createAllObjects(
188
188
  */
189
189
  function collectBuilders(
190
190
  dbContext: object,
191
- ): (TableBuilder<any, any> | ViewBuilder<any, any, any> | ProcedureBuilder<any, any>)[] {
191
+ ): (TableBuilder<any, any, any> | ViewBuilder<any, any, any> | ProcedureBuilder<any, any>)[] {
192
192
  const builders: (
193
- | TableBuilder<any, any>
193
+ | TableBuilder<any, any, any>
194
194
  | ViewBuilder<any, any, any>
195
195
  | ProcedureBuilder<any, any>
196
196
  )[] = [];
197
197
 
198
198
  for (const value of Object.values(dbContext)) {
199
199
  if (typeof value === "function" && SD_BUILDER in value) {
200
- builders.push(value[SD_BUILDER as keyof typeof value] as TableBuilder<any, any>);
200
+ builders.push(value[SD_BUILDER as keyof typeof value] as TableBuilder<any, any, any>);
201
201
  }
202
202
  }
203
203
 
@@ -23,7 +23,7 @@ import { obj } from "@simplysm/core-common";
23
23
  */
24
24
  export function getCreateObjectQueryDef(
25
25
  db: DbContextBase,
26
- builder: TableBuilder<any, any> | ViewBuilder<any, any, any> | ProcedureBuilder<any, any>,
26
+ builder: TableBuilder<any, any, any> | ViewBuilder<any, any, any> | ProcedureBuilder<any, any>,
27
27
  ): QueryDef {
28
28
  if (builder instanceof TableBuilder) {
29
29
  return getCreateTableQueryDef(db, builder);
@@ -44,7 +44,7 @@ export function getCreateObjectQueryDef(
44
44
  * @returns CREATE TABLE QueryDef
45
45
  * @throws {Error} 테이블에 column이 없을 때
46
46
  */
47
- export function getCreateTableQueryDef(db: DbContextBase, table: TableBuilder<any, any>): QueryDef {
47
+ export function getCreateTableQueryDef(db: DbContextBase, table: TableBuilder<any, any, any>): QueryDef {
48
48
  const columns = table.meta.columns as ColumnBuilderRecord | undefined;
49
49
  if (columns == null) {
50
50
  throw new Error(`테이블 '${table.meta.name}'에 column이 없습니다.`);
@@ -179,7 +179,7 @@ export function getDropProcQueryDef(procedure: QueryDefObjectName): DropProcQuer
179
179
  */
180
180
  export function getQueryDefObjectName(
181
181
  db: DbContextBase,
182
- tableOrView: TableBuilder<any, any> | ViewBuilder<any, any, any>,
182
+ tableOrView: TableBuilder<any, any, any> | ViewBuilder<any, any, any>,
183
183
  ): QueryDefObjectName {
184
184
  return obj.clearUndefined({
185
185
  database: tableOrView.meta.database ?? db.database,
@@ -49,7 +49,7 @@ class JoinQueryable {
49
49
  * @param table - 조인할 table
50
50
  * @returns 조인된 Queryable
51
51
  */
52
- from<T extends TableBuilder<any, any>>(table: T): Queryable<T["$inferSelect"], T> {
52
+ from<T extends TableBuilder<any, any, any>>(table: T): Queryable<T["$inferSelect"], T> {
53
53
  return queryable(this._db, table, this._joinAlias)();
54
54
  }
55
55
 
@@ -113,7 +113,7 @@ class RecursiveQueryable<TBaseData extends DataRecord> {
113
113
  * @param table - 재귀할 대상 table
114
114
  * @returns self 속성이 추가된 Queryable (자기 참조용)
115
115
  */
116
- from<T extends TableBuilder<any, any>>(
116
+ from<T extends TableBuilder<any, any, any>>(
117
117
  table: T,
118
118
  ): Queryable<T["$inferSelect"] & { self?: TBaseData[] }, T> {
119
119
  const selfAlias = `${this._cteName}.self`;
@@ -128,7 +128,7 @@ class RecursiveQueryable<TBaseData extends DataRecord> {
128
128
  columns: transformColumnsAlias(this._baseQr.meta.columns, selfAlias, ""),
129
129
  isCustomColumns: false,
130
130
  }),
131
- ) as any;
131
+ );
132
132
  }
133
133
 
134
134
  /**
@@ -227,7 +227,7 @@ class RecursiveQueryable<TBaseData extends DataRecord> {
227
227
  */
228
228
  export class Queryable<
229
229
  TData extends DataRecord,
230
- TFrom extends TableBuilder<any, any> | never, // CUD 연산은 TableBuilder만 지원
230
+ TFrom extends TableBuilder<any, any, any> | never, // CUD 연산은 TableBuilder만 지원
231
231
  > {
232
232
  constructor(readonly meta: QueryableMeta<TData>) {}
233
233
 
@@ -675,7 +675,7 @@ export class Queryable<
675
675
  columns: {
676
676
  ...this.meta.columns,
677
677
  [as]: [joinColumns],
678
- } as QueryableRecord<any>,
678
+ },
679
679
  isCustomColumns: true,
680
680
  joins: [...(this.meta.joins ?? []), { queryable: resultQr, isSingle: false }],
681
681
  }) as any;
@@ -731,7 +731,7 @@ export class Queryable<
731
731
  columns: {
732
732
  ...this.meta.columns,
733
733
  [as]: joinColumns,
734
- } as QueryableRecord<any>,
734
+ },
735
735
  isCustomColumns: true,
736
736
  joins: [...(this.meta.joins ?? []), { queryable: resultQr, isSingle: true }],
737
737
  }) as any;
@@ -1396,15 +1396,15 @@ export class Queryable<
1396
1396
  * .insertInto(ArchivedUser);
1397
1397
  * ```
1398
1398
  */
1399
- async insertInto<TTable extends TableBuilder<DataToColumnBuilderRecord<TData>, any>>(
1399
+ async insertInto<TTable extends TableBuilder<any, DataToColumnBuilderRecord<TData>, any>>(
1400
1400
  targetTable: TTable,
1401
1401
  ): Promise<void>;
1402
1402
  async insertInto<
1403
- TTable extends TableBuilder<DataToColumnBuilderRecord<TData>, any>,
1403
+ TTable extends TableBuilder<any, DataToColumnBuilderRecord<TData>, any>,
1404
1404
  TOut extends keyof TTable["$inferColumns"] & string,
1405
1405
  >(targetTable: TTable, outputColumns: TOut[]): Promise<Pick<TData, TOut>[]>;
1406
1406
  async insertInto<
1407
- TTable extends TableBuilder<DataToColumnBuilderRecord<TData>, any>,
1407
+ TTable extends TableBuilder<any, DataToColumnBuilderRecord<TData>, any>,
1408
1408
  TOut extends keyof TTable["$inferColumns"] & string,
1409
1409
  >(targetTable: TTable, outputColumns?: TOut[]): Promise<Pick<TData, TOut>[] | void> {
1410
1410
  const results = await this.meta.db.executeDefs<Pick<TData, TOut>>(
@@ -1421,7 +1421,7 @@ export class Queryable<
1421
1421
  records: TFrom["$inferInsert"][],
1422
1422
  outputColumns?: (keyof TFrom["$inferColumns"] & string)[],
1423
1423
  ): InsertQueryDef {
1424
- const from = this.meta.from as TableBuilder<any, any> | ViewBuilder<any, any, any>;
1424
+ const from = this.meta.from as TableBuilder<any, any, any> | ViewBuilder<any, any, any>;
1425
1425
  const outputDef = this._getCudOutputDef();
1426
1426
 
1427
1427
  // AI column에 명시적 값이 있으면 overrideIdentity 설정
@@ -1448,7 +1448,7 @@ export class Queryable<
1448
1448
  record: TFrom["$inferInsert"],
1449
1449
  outputColumns?: (keyof TFrom["$inferColumns"] & string)[],
1450
1450
  ): InsertIfNotExistsQueryDef {
1451
- const from = this.meta.from as TableBuilder<any, any> | ViewBuilder<any, any, any>;
1451
+ const from = this.meta.from as TableBuilder<any, any, any> | ViewBuilder<any, any, any>;
1452
1452
  const outputDef = this._getCudOutputDef();
1453
1453
 
1454
1454
  const { select: _, ...existsSelectQuery } = this.getSelectQueryDef();
@@ -1468,7 +1468,7 @@ export class Queryable<
1468
1468
  });
1469
1469
  }
1470
1470
 
1471
- getInsertIntoQueryDef<TTable extends TableBuilder<DataToColumnBuilderRecord<TData>, any>>(
1471
+ getInsertIntoQueryDef<TTable extends TableBuilder<any, DataToColumnBuilderRecord<TData>, any>>(
1472
1472
  targetTable: TTable,
1473
1473
  outputColumns?: (keyof TTable["$inferColumns"] & string)[],
1474
1474
  ): InsertIntoQueryDef {
@@ -1577,7 +1577,7 @@ export class Queryable<
1577
1577
  recordFwd: (cols: QueryableRecord<TData>) => QueryableWriteRecord<TFrom["$inferUpdate"]>,
1578
1578
  outputColumns?: (keyof TFrom["$inferColumns"] & string)[],
1579
1579
  ): UpdateQueryDef {
1580
- const from = this.meta.from as TableBuilder<any, any> | ViewBuilder<any, any, any>;
1580
+ const from = this.meta.from as TableBuilder<any, any, any> | ViewBuilder<any, any, any>;
1581
1581
  const outputDef = this._getCudOutputDef();
1582
1582
 
1583
1583
  return obj.clearUndefined({
@@ -1600,7 +1600,7 @@ export class Queryable<
1600
1600
  }
1601
1601
 
1602
1602
  getDeleteQueryDef(outputColumns?: (keyof TFrom["$inferColumns"] & string)[]): DeleteQueryDef {
1603
- const from = this.meta.from as TableBuilder<any, any> | ViewBuilder<any, any, any>;
1603
+ const from = this.meta.from as TableBuilder<any, any, any> | ViewBuilder<any, any, any>;
1604
1604
  const outputDef = this._getCudOutputDef();
1605
1605
 
1606
1606
  return obj.clearUndefined({
@@ -1709,7 +1709,7 @@ export class Queryable<
1709
1709
  insertRecordFn: (updateRecord: U) => QueryableWriteRecord<TFrom["$inferInsert"]>,
1710
1710
  outputColumns?: (keyof TFrom["$inferColumns"] & string)[],
1711
1711
  ): UpsertQueryDef {
1712
- const from = this.meta.from as TableBuilder<any, any> | ViewBuilder<any, any, any>;
1712
+ const from = this.meta.from as TableBuilder<any, any, any> | ViewBuilder<any, any, any>;
1713
1713
  const outputDef = this._getCudOutputDef();
1714
1714
 
1715
1715
  const { select: _sel, ...existsSelectQuery } = this.getSelectQueryDef();
@@ -1806,7 +1806,7 @@ export class Queryable<
1806
1806
  */
1807
1807
  export function getMatchedPrimaryKeys(
1808
1808
  fkCols: string[],
1809
- targetTable: TableBuilder<any, any>,
1809
+ targetTable: TableBuilder<any, any, any>,
1810
1810
  ): string[] {
1811
1811
  const pk = targetTable.meta.primaryKey;
1812
1812
  if (pk == null || fkCols.length !== pk.length) {
@@ -1866,7 +1866,7 @@ function transformColumnsAlias<TRecord extends DataRecord>(
1866
1866
  interface QueryableMeta<TData extends DataRecord> {
1867
1867
  db: DbContextBase;
1868
1868
  from?:
1869
- | TableBuilder<any, any>
1869
+ | TableBuilder<any, any, any>
1870
1870
  | ViewBuilder<any, any, any>
1871
1871
  | Queryable<any, any>
1872
1872
  | Queryable<TData, any>[]
@@ -1919,8 +1919,8 @@ export type QueryableWriteRecord<TData> = {
1919
1919
  * ExprUnit<T>를 T로 언래핑, 중첩 객체/배열을 재귀적으로 언래핑
1920
1920
  */
1921
1921
  export type UnwrapQueryableRecord<R> = {
1922
- [K in keyof R as K extends symbol ? never : K]: R[K] extends ExprUnit<infer T>
1923
- ? T
1922
+ [K in keyof R as K extends symbol ? never : K]: NonNullable<R[K]> extends ExprUnit<infer T>
1923
+ ? T | Extract<R[K], undefined>
1924
1924
  : NonNullable<R[K]> extends (infer U)[]
1925
1925
  ? U extends Record<string, any>
1926
1926
  ? UnwrapQueryableRecord<U>[] | Extract<R[K], undefined>
@@ -2019,11 +2019,11 @@ function createPathProxy<TObject>(path: string[] = []): PathProxy<TObject> {
2019
2019
  * }
2020
2020
  * ```
2021
2021
  */
2022
- export function queryable<TBuilder extends TableBuilder<any, any> | ViewBuilder<any, any, any>>(
2022
+ export function queryable<TBuilder extends TableBuilder<any, any, any> | ViewBuilder<any, any, any>>(
2023
2023
  db: DbContextBase,
2024
2024
  tableOrView: TBuilder,
2025
2025
  as?: string,
2026
- ): () => Queryable<TBuilder["$inferSelect"], TBuilder extends TableBuilder<any, any> ? TBuilder : never> {
2026
+ ): () => Queryable<TBuilder["$inferSelect"], TBuilder extends TableBuilder<any, any, any> ? TBuilder : never> {
2027
2027
  return () => {
2028
2028
  // as가 미지정이면 db.getNextAlias() 사용 (카운터 증가)
2029
2029
  // as가 지정되면 그대로 사용 (카운터 증가 없음)