@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.
Files changed (89) hide show
  1. package/dist/db-context.d.ts +11 -10
  2. package/dist/db-context.d.ts.map +1 -1
  3. package/dist/db-context.js +14 -11
  4. package/dist/db-context.js.map +1 -1
  5. package/dist/ddl/initialize.js.map +1 -1
  6. package/dist/ddl/relation-ddl.d.ts +1 -1
  7. package/dist/ddl/relation-ddl.d.ts.map +1 -1
  8. package/dist/ddl/relation-ddl.js.map +1 -1
  9. package/dist/ddl/table-ddl.d.ts +3 -3
  10. package/dist/ddl/table-ddl.d.ts.map +1 -1
  11. package/dist/ddl/table-ddl.js.map +1 -1
  12. package/dist/errors/db-transaction-error.d.ts +4 -5
  13. package/dist/errors/db-transaction-error.d.ts.map +1 -1
  14. package/dist/errors/db-transaction-error.js +5 -6
  15. package/dist/errors/db-transaction-error.js.map +1 -1
  16. package/dist/exec/executable.d.ts +4 -13
  17. package/dist/exec/executable.d.ts.map +1 -1
  18. package/dist/exec/executable.js.map +1 -1
  19. package/dist/exec/queryable.d.ts +11 -9
  20. package/dist/exec/queryable.d.ts.map +1 -1
  21. package/dist/exec/queryable.js +9 -5
  22. package/dist/exec/queryable.js.map +1 -1
  23. package/dist/expr/expr.d.ts +7 -4
  24. package/dist/expr/expr.d.ts.map +1 -1
  25. package/dist/expr/expr.js +5 -2
  26. package/dist/expr/expr.js.map +1 -1
  27. package/dist/models/system-migration.d.ts +1 -1
  28. package/dist/models/system-migration.d.ts.map +1 -1
  29. package/dist/query-builder/base/expr-renderer-base.d.ts +2 -1
  30. package/dist/query-builder/base/expr-renderer-base.d.ts.map +1 -1
  31. package/dist/query-builder/base/expr-renderer-base.js.map +1 -1
  32. package/dist/query-builder/mssql/mssql-expr-renderer.d.ts +2 -2
  33. package/dist/query-builder/mssql/mssql-expr-renderer.d.ts.map +1 -1
  34. package/dist/query-builder/mssql/mssql-expr-renderer.js.map +1 -1
  35. package/dist/query-builder/mysql/mysql-expr-renderer.d.ts +2 -2
  36. package/dist/query-builder/mysql/mysql-expr-renderer.d.ts.map +1 -1
  37. package/dist/query-builder/mysql/mysql-expr-renderer.js.map +1 -1
  38. package/dist/query-builder/postgresql/postgresql-expr-renderer.d.ts +2 -2
  39. package/dist/query-builder/postgresql/postgresql-expr-renderer.d.ts.map +1 -1
  40. package/dist/query-builder/postgresql/postgresql-expr-renderer.js.map +1 -1
  41. package/dist/query-builder/postgresql/postgresql-query-builder.d.ts.map +1 -1
  42. package/dist/query-builder/postgresql/postgresql-query-builder.js.map +1 -1
  43. package/dist/schema/factory/column-builder.d.ts +1 -1
  44. package/dist/schema/factory/column-builder.d.ts.map +1 -1
  45. package/dist/schema/factory/relation-builder.d.ts +55 -49
  46. package/dist/schema/factory/relation-builder.d.ts.map +1 -1
  47. package/dist/schema/factory/relation-builder.js +12 -15
  48. package/dist/schema/factory/relation-builder.js.map +1 -1
  49. package/dist/schema/table-builder.d.ts +35 -18
  50. package/dist/schema/table-builder.d.ts.map +1 -1
  51. package/dist/schema/table-builder.js +32 -15
  52. package/dist/schema/table-builder.js.map +1 -1
  53. package/dist/schema/view-builder.d.ts +28 -24
  54. package/dist/schema/view-builder.d.ts.map +1 -1
  55. package/dist/schema/view-builder.js +18 -14
  56. package/dist/schema/view-builder.js.map +1 -1
  57. package/dist/types/column.d.ts +6 -17
  58. package/dist/types/column.d.ts.map +1 -1
  59. package/dist/types/column.js +3 -19
  60. package/dist/types/column.js.map +1 -1
  61. package/dist/types/db-context-def.d.ts +7 -7
  62. package/dist/types/db-context-def.d.ts.map +1 -1
  63. package/dist/types/query-def.d.ts +1 -1
  64. package/dist/types/query-def.d.ts.map +1 -1
  65. package/dist/utils/result-parser.d.ts.map +1 -1
  66. package/dist/utils/result-parser.js +3 -7
  67. package/dist/utils/result-parser.js.map +1 -1
  68. package/package.json +3 -3
  69. package/src/db-context.ts +23 -20
  70. package/src/ddl/initialize.ts +4 -4
  71. package/src/ddl/relation-ddl.ts +1 -1
  72. package/src/ddl/table-ddl.ts +3 -3
  73. package/src/errors/db-transaction-error.ts +6 -4
  74. package/src/exec/executable.ts +5 -4
  75. package/src/exec/queryable.ts +31 -24
  76. package/src/expr/expr.ts +10 -4
  77. package/src/query-builder/base/expr-renderer-base.ts +2 -1
  78. package/src/query-builder/mssql/mssql-expr-renderer.ts +5 -5
  79. package/src/query-builder/mysql/mysql-expr-renderer.ts +2 -2
  80. package/src/query-builder/postgresql/postgresql-expr-renderer.ts +5 -5
  81. package/src/query-builder/postgresql/postgresql-query-builder.ts +4 -3
  82. package/src/schema/factory/column-builder.ts +3 -3
  83. package/src/schema/factory/relation-builder.ts +350 -346
  84. package/src/schema/table-builder.ts +209 -193
  85. package/src/schema/view-builder.ts +148 -143
  86. package/src/types/column.ts +7 -26
  87. package/src/types/db-context-def.ts +7 -7
  88. package/src/types/query-def.ts +1 -1
  89. package/src/utils/result-parser.ts +11 -19
package/src/db-context.ts CHANGED
@@ -42,7 +42,10 @@ export const SD_BUILDER = Symbol("sdBuilder");
42
42
  */
43
43
  export abstract class DbContext implements DbContextBase {
44
44
  // ── 상태 ──
45
- status: DbContextStatus = "ready";
45
+ private _status: DbContextStatus = "ready";
46
+ get status(): DbContextStatus {
47
+ return this._status;
48
+ }
46
49
  private _aliasCounter = 0;
47
50
  private _relationsValidated = false;
48
51
 
@@ -83,7 +86,7 @@ export abstract class DbContext implements DbContextBase {
83
86
  }
84
87
 
85
88
  getQueryDefObjectName(
86
- tableOrView: TableBuilder<any, any, any> | ViewBuilder<any, any, any>,
89
+ tableOrView: TableBuilder<any, any> | ViewBuilder<any, any, any>,
87
90
  ): QueryDefObjectName {
88
91
  return getQueryDefObjectNameImpl(this, tableOrView);
89
92
  }
@@ -94,9 +97,9 @@ export abstract class DbContext implements DbContextBase {
94
97
 
95
98
  // ── 등록 메서드 ──
96
99
 
97
- protected queryable<T extends TableBuilder<any, any, any> | ViewBuilder<any, any, any>>(
100
+ protected queryable<T extends TableBuilder<any, any> | ViewBuilder<any, any, any>>(
98
101
  builder: T,
99
- ): () => Queryable<T["$inferSelect"], T extends TableBuilder<any, any, any> ? T : never> {
102
+ ): () => Queryable<T["$inferSelect"], T extends TableBuilder<any, any> ? T : never> {
100
103
  const fn = createQueryable(this, builder);
101
104
  Object.defineProperty(fn, SD_BUILDER, { value: builder });
102
105
  return fn;
@@ -128,18 +131,18 @@ export abstract class DbContext implements DbContextBase {
128
131
  this.resetAliasCounter();
129
132
 
130
133
  await this._executor.connect();
131
- this.status = "connect";
134
+ this._status = "connect";
132
135
 
133
136
  try {
134
137
  await this._executor.beginTransaction(isolationLevel);
135
- this.status = "transact";
138
+ this._status = "transact";
136
139
 
137
140
  let result: TResult;
138
141
  try {
139
142
  result = await fn();
140
143
 
141
144
  await this._executor.commitTransaction();
142
- this.status = "connect";
145
+ this._status = "connect";
143
146
  } catch (err) {
144
147
  try {
145
148
  await this._executor.rollbackTransaction();
@@ -151,7 +154,7 @@ export abstract class DbContext implements DbContextBase {
151
154
  (err as Error).cause = err1;
152
155
  }
153
156
  }
154
- this.status = "connect";
157
+ this._status = "connect";
155
158
  throw err;
156
159
  }
157
160
 
@@ -160,7 +163,7 @@ export abstract class DbContext implements DbContextBase {
160
163
  try {
161
164
  await this._executor.close();
162
165
  } finally {
163
- this.status = "ready";
166
+ this._status = "ready";
164
167
  }
165
168
  }
166
169
  }
@@ -178,7 +181,7 @@ export abstract class DbContext implements DbContextBase {
178
181
  this.resetAliasCounter();
179
182
 
180
183
  await this._executor.connect();
181
- this.status = "connect";
184
+ this._status = "connect";
182
185
 
183
186
  try {
184
187
  return await callback();
@@ -186,7 +189,7 @@ export abstract class DbContext implements DbContextBase {
186
189
  try {
187
190
  await this._executor.close();
188
191
  } finally {
189
- this.status = "ready";
192
+ this._status = "ready";
190
193
  }
191
194
  }
192
195
  }
@@ -200,14 +203,14 @@ export abstract class DbContext implements DbContextBase {
200
203
  }
201
204
 
202
205
  await this._executor.beginTransaction(isolationLevel);
203
- this.status = "transact";
206
+ this._status = "transact";
204
207
 
205
208
  let result: TResult;
206
209
  try {
207
210
  result = await fn();
208
211
 
209
212
  await this._executor.commitTransaction();
210
- this.status = "connect";
213
+ this._status = "connect";
211
214
  } catch (err) {
212
215
  try {
213
216
  await this._executor.rollbackTransaction();
@@ -219,7 +222,7 @@ export abstract class DbContext implements DbContextBase {
219
222
  (err as Error).cause = err1;
220
223
  }
221
224
  }
222
- this.status = "connect";
225
+ this._status = "connect";
223
226
  throw err;
224
227
  }
225
228
 
@@ -228,7 +231,7 @@ export abstract class DbContext implements DbContextBase {
228
231
 
229
232
  // ── DDL 실행 메서드 ──
230
233
 
231
- async createTable(table: TableBuilder<any, any, any>): Promise<void> {
234
+ async createTable(table: TableBuilder<any, any>): Promise<void> {
232
235
  await this.executeDefs([tableDdl.getCreateTableQueryDef(this, table)]);
233
236
  }
234
237
 
@@ -241,7 +244,7 @@ export abstract class DbContext implements DbContextBase {
241
244
  }
242
245
 
243
246
  async createView(view: ViewBuilder<any, any, any>): Promise<void> {
244
- await this.executeDefs([tableDdl.getCreateViewQueryDef(this as any, view)]);
247
+ await this.executeDefs([tableDdl.getCreateViewQueryDef(this, view)]);
245
248
  }
246
249
 
247
250
  async dropView(view: QueryDefObjectName): Promise<void> {
@@ -291,7 +294,7 @@ export abstract class DbContext implements DbContextBase {
291
294
  async addForeignKey(
292
295
  table: QueryDefObjectName,
293
296
  relationName: string,
294
- relationDef: ForeignKeyBuilder<any, any>,
297
+ relationDef: ForeignKeyBuilder<any>,
295
298
  ): Promise<void> {
296
299
  await this.executeDefs([
297
300
  relationDdl.getAddForeignKeyQueryDef(this, table, relationName, relationDef),
@@ -325,7 +328,7 @@ export abstract class DbContext implements DbContextBase {
325
328
 
326
329
  // ── DDL QueryDef 생성기 ──
327
330
 
328
- getCreateTableQueryDef(table: TableBuilder<any, any, any>): QueryDef {
331
+ getCreateTableQueryDef(table: TableBuilder<any, any>): QueryDef {
329
332
  return tableDdl.getCreateTableQueryDef(this, table);
330
333
  }
331
334
 
@@ -338,7 +341,7 @@ export abstract class DbContext implements DbContextBase {
338
341
  }
339
342
 
340
343
  getCreateObjectQueryDef(
341
- builder: TableBuilder<any, any, any> | ViewBuilder<any, any, any> | ProcedureBuilder<any, any>,
344
+ builder: TableBuilder<any, any> | ViewBuilder<any, any, any> | ProcedureBuilder<any, any>,
342
345
  ): QueryDef {
343
346
  return tableDdl.getCreateObjectQueryDef(this, builder);
344
347
  }
@@ -394,7 +397,7 @@ export abstract class DbContext implements DbContextBase {
394
397
  getAddForeignKeyQueryDef(
395
398
  table: QueryDefObjectName,
396
399
  relationName: string,
397
- relationDef: ForeignKeyBuilder<any, any>,
400
+ relationDef: ForeignKeyBuilder<any>,
398
401
  ): QueryDef {
399
402
  return relationDdl.getAddForeignKeyQueryDef(this, table, relationName, relationDef);
400
403
  }
@@ -131,7 +131,7 @@ export async function initialize(
131
131
  */
132
132
  async function createAllObjects(
133
133
  db: DbContextBase,
134
- builders: (TableBuilder<any, any, any> | ViewBuilder<any, any, any> | ProcedureBuilder<any, any>)[],
134
+ builders: (TableBuilder<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, any> | ViewBuilder<any, any, any> | ProcedureBuilder<any, any>)[] {
191
+ ): (TableBuilder<any, any> | ViewBuilder<any, any, any> | ProcedureBuilder<any, any>)[] {
192
192
  const builders: (
193
- | TableBuilder<any, any, any>
193
+ | TableBuilder<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, any>);
200
+ builders.push(value[SD_BUILDER as keyof typeof value] as TableBuilder<any, any>);
201
201
  }
202
202
  }
203
203
 
@@ -33,7 +33,7 @@ export function getAddForeignKeyQueryDef(
33
33
  db: DbContextBase,
34
34
  table: QueryDefObjectName,
35
35
  relationName: string,
36
- relationDef: ForeignKeyBuilder<any, any>,
36
+ relationDef: ForeignKeyBuilder<any>,
37
37
  ): QueryDef {
38
38
  const targetTable = relationDef.meta.targetFn();
39
39
  const fkColumns = relationDef.meta.columns;
@@ -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, any> | ViewBuilder<any, any, any> | ProcedureBuilder<any, any>,
26
+ builder: TableBuilder<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, any>): QueryDef {
47
+ export function getCreateTableQueryDef(db: DbContextBase, table: TableBuilder<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, any> | ViewBuilder<any, any, any>,
182
+ tableOrView: TableBuilder<any, any> | ViewBuilder<any, any, any>,
183
183
  ): QueryDefObjectName {
184
184
  return obj.clearUndefined({
185
185
  database: tableOrView.meta.database ?? db.database,
@@ -1,3 +1,5 @@
1
+ import { SdError } from "@simplysm/core-common";
2
+
1
3
  /**
2
4
  * 트랜잭션 관련 에러 코드
3
5
  *
@@ -23,7 +25,7 @@ export enum DbErrorCode {
23
25
  * DBMS별 네이티브 에러를 표준화된 에러 코드로 래핑하여
24
26
  * DBMS 독립적인 에러 처리를 지원한다
25
27
  */
26
- export class DbTransactionError extends Error {
28
+ export class DbTransactionError extends SdError {
27
29
  override readonly name = "DbTransactionError";
28
30
 
29
31
  constructor(
@@ -31,9 +33,9 @@ export class DbTransactionError extends Error {
31
33
  public readonly code: DbErrorCode,
32
34
  /** 에러 메시지 */
33
35
  message: string,
34
- /** 원본 DBMS 에러 (디버깅용) */
35
- public readonly originalError?: unknown,
36
+ /** 원본 DBMS 에러 (cause 체인으로 보존) */
37
+ cause?: Error,
36
38
  ) {
37
- super(message);
39
+ super(cause as Error, message);
38
40
  }
39
41
  }
@@ -1,6 +1,7 @@
1
- import type { ColumnBuilderRecord, InferColumnExprs } from "../schema/factory/column-builder";
1
+ import type { ColumnBuilderRecord, InferColumnExprs, InferColumns } from "../schema/factory/column-builder";
2
2
  import type { ProcedureBuilder } from "../schema/procedure-builder";
3
3
  import type { DbContextBase } from "../types/db-context-def";
4
+ import type { ExecProcQueryDef } from "../types/query-def";
4
5
  import { ExprUnit } from "../expr/expr-unit";
5
6
  import { expr } from "../expr/expr";
6
7
 
@@ -25,7 +26,7 @@ export class Executable<TParams extends ColumnBuilderRecord, TReturns extends Co
25
26
  /**
26
27
  * 프로시저 실행 QueryDef 생성
27
28
  */
28
- getExecProcQueryDef(params?: InferColumnExprs<TParams>) {
29
+ getExecProcQueryDef(params?: InferColumnExprs<TParams>): ExecProcQueryDef {
29
30
  const meta = this._builder.meta;
30
31
  if (params && !meta.params) {
31
32
  throw new Error(`Procedure '${meta.name}'에 파라미터가 없습니다.`);
@@ -55,8 +56,8 @@ export class Executable<TParams extends ColumnBuilderRecord, TReturns extends Co
55
56
  /**
56
57
  * 프로시저 실행
57
58
  */
58
- async execute(params: InferColumnExprs<TParams>): Promise<InferColumnExprs<TReturns>[][]> {
59
- return this._db.executeDefs<InferColumnExprs<TReturns>>([this.getExecProcQueryDef(params)]);
59
+ async execute(params: InferColumnExprs<TParams>): Promise<InferColumns<TReturns>[][]> {
60
+ return this._db.executeDefs<InferColumns<TReturns>>([this.getExecProcQueryDef(params)]);
60
61
  }
61
62
  }
62
63
 
@@ -49,7 +49,7 @@ class JoinQueryable {
49
49
  * @param table - 조인할 table
50
50
  * @returns 조인된 Queryable
51
51
  */
52
- from<T extends TableBuilder<any, any, any>>(table: T): Queryable<T["$inferSelect"], T> {
52
+ from<T extends TableBuilder<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, any>>(
116
+ from<T extends TableBuilder<any, any>>(
117
117
  table: T,
118
118
  ): Queryable<T["$inferSelect"] & { self?: TBaseData[] }, T> {
119
119
  const selfAlias = `${this._cteName}.self`;
@@ -210,7 +210,7 @@ class RecursiveQueryable<TBaseData extends DataRecord> {
210
210
  */
211
211
  export class Queryable<
212
212
  TData extends DataRecord,
213
- TFrom extends TableBuilder<any, any, any> | never, // CUD 연산은 TableBuilder만 지원
213
+ TFrom extends TableBuilder<any, any> | never, // CUD 연산은 TableBuilder만 지원
214
214
  > {
215
215
  constructor(readonly meta: QueryableMeta<TData>) {}
216
216
 
@@ -1060,15 +1060,15 @@ export class Queryable<
1060
1060
  * @param outputColumns - Column name array to receive (optional)
1061
1061
  * @returns When outputColumns specified, returns array of inserted records
1062
1062
  */
1063
- async insertInto<TTable extends TableBuilder<any, DataToColumnBuilderRecord<TData>, any>>(
1063
+ async insertInto<TTable extends TableBuilder<any, DataToColumnBuilderRecord<TData>>>(
1064
1064
  targetTable: TTable,
1065
1065
  ): Promise<void>;
1066
1066
  async insertInto<
1067
- TTable extends TableBuilder<any, DataToColumnBuilderRecord<TData>, any>,
1067
+ TTable extends TableBuilder<any, DataToColumnBuilderRecord<TData>>,
1068
1068
  TOut extends keyof TTable["$inferColumns"] & string,
1069
1069
  >(targetTable: TTable, outputColumns: TOut[]): Promise<Pick<TData, TOut>[]>;
1070
1070
  async insertInto<
1071
- TTable extends TableBuilder<any, DataToColumnBuilderRecord<TData>, any>,
1071
+ TTable extends TableBuilder<any, DataToColumnBuilderRecord<TData>>,
1072
1072
  TOut extends keyof TTable["$inferColumns"] & string,
1073
1073
  >(targetTable: TTable, outputColumns?: TOut[]): Promise<Pick<TData, TOut>[] | void> {
1074
1074
  const results = await this.meta.db.executeDefs<Pick<TData, TOut>>(
@@ -1085,7 +1085,7 @@ export class Queryable<
1085
1085
  records: TFrom["$inferInsert"][],
1086
1086
  outputColumns?: (keyof TFrom["$inferColumns"] & string)[],
1087
1087
  ): InsertQueryDef {
1088
- const from = this.meta.from as TableBuilder<any, any, any> | ViewBuilder<any, any, any>;
1088
+ const from = this._getCudFrom();
1089
1089
  const outputDef = this._getCudOutputDef();
1090
1090
 
1091
1091
  // AI column에 명시적 값이 있으면 overrideIdentity 설정
@@ -1113,7 +1113,7 @@ export class Queryable<
1113
1113
  record: TFrom["$inferInsert"],
1114
1114
  outputColumns?: (keyof TFrom["$inferColumns"] & string)[],
1115
1115
  ): InsertIfNotExistsQueryDef {
1116
- const from = this.meta.from as TableBuilder<any, any, any> | ViewBuilder<any, any, any>;
1116
+ const from = this._getCudFrom();
1117
1117
  const outputDef = this._getCudOutputDef();
1118
1118
 
1119
1119
  const { select: _, ...existsSelectQuery } = this.getSelectQueryDef();
@@ -1133,7 +1133,7 @@ export class Queryable<
1133
1133
  });
1134
1134
  }
1135
1135
 
1136
- getInsertIntoQueryDef<TTable extends TableBuilder<any, DataToColumnBuilderRecord<TData>, any>>(
1136
+ getInsertIntoQueryDef<TTable extends TableBuilder<any, DataToColumnBuilderRecord<TData>>>(
1137
1137
  targetTable: TTable,
1138
1138
  outputColumns?: (keyof TTable["$inferColumns"] & string)[],
1139
1139
  ): InsertIntoQueryDef {
@@ -1212,7 +1212,7 @@ export class Queryable<
1212
1212
  recordFwd: (cols: QueryableRecord<TData>) => QueryableWriteRecord<TFrom["$inferUpdate"]>,
1213
1213
  outputColumns?: (keyof TFrom["$inferColumns"] & string)[],
1214
1214
  ): UpdateQueryDef {
1215
- const from = this.meta.from as TableBuilder<any, any, any> | ViewBuilder<any, any, any>;
1215
+ const from = this._getCudFrom();
1216
1216
  const outputDef = this._getCudOutputDef();
1217
1217
 
1218
1218
  return obj.clearUndefined({
@@ -1235,7 +1235,7 @@ export class Queryable<
1235
1235
  }
1236
1236
 
1237
1237
  getDeleteQueryDef(outputColumns?: (keyof TFrom["$inferColumns"] & string)[]): DeleteQueryDef {
1238
- const from = this.meta.from as TableBuilder<any, any, any> | ViewBuilder<any, any, any>;
1238
+ const from = this._getCudFrom();
1239
1239
  const outputDef = this._getCudOutputDef();
1240
1240
 
1241
1241
  return obj.clearUndefined({
@@ -1325,7 +1325,7 @@ export class Queryable<
1325
1325
  insertRecordFn: (updateRecord: U) => QueryableWriteRecord<TFrom["$inferInsert"]>,
1326
1326
  outputColumns?: (keyof TFrom["$inferColumns"] & string)[],
1327
1327
  ): UpsertQueryDef {
1328
- const from = this.meta.from as TableBuilder<any, any, any> | ViewBuilder<any, any, any>;
1328
+ const from = this._getCudFrom();
1329
1329
  const outputDef = this._getCudOutputDef();
1330
1330
 
1331
1331
  const { select: _sel, ...existsSelectQuery } = this.getSelectQueryDef();
@@ -1380,6 +1380,11 @@ export class Queryable<
1380
1380
 
1381
1381
  //#region ========== CUD Common ==========
1382
1382
 
1383
+ /** CUD QueryDef 생성용 from(Table/View) 캐스팅 통일 */
1384
+ private _getCudFrom(): TableBuilder<any, any> | ViewBuilder<any, any, any> {
1385
+ return this.meta.from as TableBuilder<any, any> | ViewBuilder<any, any, any>;
1386
+ }
1387
+
1383
1388
  private _getCudOutputDef(): {
1384
1389
  pkColNames: string[];
1385
1390
  aiColName?: string;
@@ -1422,7 +1427,7 @@ export class Queryable<
1422
1427
  */
1423
1428
  export function getMatchedPrimaryKeys(
1424
1429
  fkCols: string[],
1425
- targetTable: TableBuilder<any, any, any>,
1430
+ targetTable: TableBuilder<any, any>,
1426
1431
  ): string[] {
1427
1432
  const pk = targetTable.meta.primaryKey;
1428
1433
  if (pk == null || fkCols.length !== pk.length) {
@@ -1470,7 +1475,7 @@ function transformColumnsAlias<TRecord extends DataRecord>(
1470
1475
  } else if (value == null) {
1471
1476
  result[key] = value;
1472
1477
  } else {
1473
- result[key] = new ExprUnit(inferColumnPrimitiveStr(value as ColumnPrimitive), {
1478
+ result[key] = new ExprUnit(inferColumnPrimitiveStr(value as Exclude<ColumnPrimitive, undefined>), {
1474
1479
  type: "value",
1475
1480
  value: value as ColumnPrimitive,
1476
1481
  });
@@ -1500,7 +1505,7 @@ function wrapColumnsPrimitives<T>(columns: T): T {
1500
1505
  } else if (value == null) {
1501
1506
  result[key] = value;
1502
1507
  } else {
1503
- result[key] = new ExprUnit(inferColumnPrimitiveStr(value as ColumnPrimitive), {
1508
+ result[key] = new ExprUnit(inferColumnPrimitiveStr(value as Exclude<ColumnPrimitive, undefined>), {
1504
1509
  type: "value",
1505
1510
  value: value as ColumnPrimitive,
1506
1511
  });
@@ -1572,13 +1577,15 @@ export type QueryableWriteRecord<TData> = {
1572
1577
  export type UnwrapQueryableRecord<R> = {
1573
1578
  [K in keyof R as K extends symbol ? never : K]: NonNullable<R[K]> extends ExprUnit<infer T>
1574
1579
  ? T | Extract<R[K], undefined>
1575
- : NonNullable<R[K]> extends (infer U)[]
1576
- ? U extends Record<string, any>
1577
- ? UnwrapQueryableRecord<U>[] | Extract<R[K], undefined>
1578
- : never
1579
- : NonNullable<R[K]> extends Record<string, any>
1580
- ? UnwrapQueryableRecord<NonNullable<R[K]>> | Extract<R[K], undefined>
1581
- : never;
1580
+ : NonNullable<R[K]> extends ColumnPrimitive
1581
+ ? R[K]
1582
+ : NonNullable<R[K]> extends (infer U)[]
1583
+ ? U extends Record<string, any>
1584
+ ? UnwrapQueryableRecord<U>[] | Extract<R[K], undefined>
1585
+ : never
1586
+ : NonNullable<R[K]> extends Record<string, any>
1587
+ ? UnwrapQueryableRecord<NonNullable<R[K]>> | Extract<R[K], undefined>
1588
+ : never;
1582
1589
  };
1583
1590
 
1584
1591
  //#region ========== PathProxy - Type-safe path builder for include ==========
@@ -1646,11 +1653,11 @@ function createPathProxy<TObject>(path: string[] = []): PathProxy<TObject> {
1646
1653
  * @param as - Alias 지정 (선택, 미지정 시 자동 생성)
1647
1654
  * @returns Queryable을 반환하는 factory 함수
1648
1655
  */
1649
- export function queryable<TBuilder extends TableBuilder<any, any, any> | ViewBuilder<any, any, any>>(
1656
+ export function queryable<TBuilder extends TableBuilder<any, any> | ViewBuilder<any, any, any>>(
1650
1657
  db: DbContextBase,
1651
1658
  tableOrView: TBuilder,
1652
1659
  as?: string,
1653
- ): () => Queryable<TBuilder["$inferSelect"], TBuilder extends TableBuilder<any, any, any> ? TBuilder : never> {
1660
+ ): () => Queryable<TBuilder["$inferSelect"], TBuilder extends TableBuilder<any, any> ? TBuilder : never> {
1654
1661
  return () => {
1655
1662
  // as가 미지정이면 db.getNextAlias() 사용 (카운터 증가)
1656
1663
  // as가 지정되면 그대로 사용 (카운터 증가 없음)
package/src/expr/expr.ts CHANGED
@@ -68,7 +68,7 @@ export const expr = {
68
68
  * @returns Column 참조 ExprUnit 인스턴스
69
69
  */
70
70
  col<TStr extends ColumnPrimitiveStr>(
71
- dataType: ColumnPrimitiveStr,
71
+ dataType: TStr,
72
72
  ...path: string[]
73
73
  ): ExprUnit<ColumnPrimitiveMap[TStr] | undefined> {
74
74
  return new ExprUnit(dataType, { type: "column", path });
@@ -566,13 +566,16 @@ export const expr = {
566
566
  /**
567
567
  * 문자열 내 위치 찾기 (LOCATE/CHARINDEX)
568
568
  *
569
- * 1부터 시작하는 인덱스 반환, 찾지 못하면 0 반환
569
+ * 0부터 시작하는 인덱스 반환, 찾지 못하면 -1 반환. source가 NULL이면 undefined.
570
570
  *
571
571
  * @param source - String to search in
572
572
  * @param search - String to find
573
- * @returns Position (starting from 1, 0 if not found)
573
+ * @returns Position (0-based, -1 if not found; undefined if source is NULL)
574
574
  */
575
- indexOf(source: ExprUnit<string | undefined>, search: ExprInput<string>): ExprUnit<number> {
575
+ indexOf<T extends string | undefined>(
576
+ source: ExprUnit<T>,
577
+ search: ExprInput<string>,
578
+ ): ExprUnit<T extends undefined ? number | undefined : number> {
576
579
  return new ExprUnit("number", {
577
580
  type: "indexOf",
578
581
  source: toExpr(source),
@@ -897,6 +900,9 @@ export const expr = {
897
900
  *
898
901
  * 메서드 체이닝으로 조건 분기 구성
899
902
  *
903
+ * 타입 인자 생략 시 case/default 값 타입이 강제되지 않음.
904
+ * 분기 값 타입의 동질성을 컴파일 시점에 강제하려면 `expr.switch<T>()` 로 T 를 명시.
905
+ *
900
906
  * @returns SwitchExprBuilder instance
901
907
  */
902
908
  switch<T extends ColumnPrimitive>(): SwitchExprBuilder<T> {
@@ -1,3 +1,4 @@
1
+ import type { ColumnPrimitive } from "../../types/column";
1
2
  import type {
2
3
  Expr,
3
4
  WhereExpr,
@@ -96,7 +97,7 @@ export abstract class ExprRendererBase {
96
97
  /**
97
98
  * 값 이스케이프 (타입에 맞는 SQL 리터럴로 변환)
98
99
  */
99
- abstract escapeValue(value: unknown): string;
100
+ abstract escapeValue(value: ColumnPrimitive): string;
100
101
 
101
102
  //#endregion
102
103
 
@@ -65,7 +65,7 @@ import type {
65
65
  ExprSubquery,
66
66
  DateUnit,
67
67
  } from "../../types/expr";
68
- import type { DataType } from "../../types/column";
68
+ import type { ColumnPrimitive, DataType } from "../../types/column";
69
69
  import { ExprRendererBase } from "../base/expr-renderer-base";
70
70
 
71
71
  /**
@@ -85,7 +85,7 @@ export class MssqlExprRenderer extends ExprRendererBase {
85
85
  }
86
86
 
87
87
  /** 값 이스케이프 */
88
- escapeValue(value: unknown): string {
88
+ escapeValue(value: ColumnPrimitive): string {
89
89
  if (value == null) {
90
90
  return "NULL";
91
91
  }
@@ -325,9 +325,9 @@ export class MssqlExprRenderer extends ExprRendererBase {
325
325
  return `SUBSTRING(${this.render(expr.source)}, ${this.render(expr.start)}, LEN(${this.render(expr.source)}))`;
326
326
  }
327
327
 
328
- protected indexOf(expr: ExprIndexOf): string {
329
- return `(CHARINDEX(${this.render(expr.search)}, ${this.render(expr.source)}) - 1)`;
330
- }
328
+ protected indexOf(expr: ExprIndexOf): string {
329
+ return `(CHARINDEX(${this.render(expr.search)}, ${this.render(expr.source)}) - 1)`;
330
+ }
331
331
 
332
332
  //#endregion
333
333
 
@@ -65,7 +65,7 @@ import type {
65
65
  ExprSubquery,
66
66
  DateUnit,
67
67
  } from "../../types/expr";
68
- import type { DataType } from "../../types/column";
68
+ import type { ColumnPrimitive, DataType } from "../../types/column";
69
69
  import { ExprRendererBase } from "../base/expr-renderer-base";
70
70
 
71
71
  /**
@@ -91,7 +91,7 @@ export class MysqlExprRenderer extends ExprRendererBase {
91
91
  }
92
92
 
93
93
  /** 값 이스케이프 */
94
- escapeValue(value: unknown): string {
94
+ escapeValue(value: ColumnPrimitive): string {
95
95
  if (value == null) {
96
96
  return "NULL";
97
97
  }
@@ -65,7 +65,7 @@ import type {
65
65
  ExprSubquery,
66
66
  DateUnit,
67
67
  } from "../../types/expr";
68
- import type { DataType } from "../../types/column";
68
+ import type { ColumnPrimitive, DataType } from "../../types/column";
69
69
  import { ExprRendererBase } from "../base/expr-renderer-base";
70
70
 
71
71
  /**
@@ -85,7 +85,7 @@ export class PostgresqlExprRenderer extends ExprRendererBase {
85
85
  }
86
86
 
87
87
  /** 값 이스케이프 */
88
- escapeValue(value: unknown): string {
88
+ escapeValue(value: ColumnPrimitive): string {
89
89
  if (value == null) {
90
90
  return "NULL";
91
91
  }
@@ -320,9 +320,9 @@ export class PostgresqlExprRenderer extends ExprRendererBase {
320
320
  return `SUBSTRING(${this.render(expr.source)} FROM ${this.render(expr.start)})`;
321
321
  }
322
322
 
323
- protected indexOf(expr: ExprIndexOf): string {
324
- return `(POSITION(${this.render(expr.search)} IN ${this.render(expr.source)}) - 1)`;
325
- }
323
+ protected indexOf(expr: ExprIndexOf): string {
324
+ return `(POSITION(${this.render(expr.search)} IN ${this.render(expr.source)}) - 1)`;
325
+ }
326
326
 
327
327
  //#endregion
328
328
 
@@ -31,6 +31,7 @@ import type {
31
31
  UpdateQueryDef,
32
32
  UpsertQueryDef,
33
33
  } from "../../types/query-def";
34
+ import type { WhereExpr } from "../../types/expr";
34
35
  import type { QueryBuildResult } from "../../types/db";
35
36
  import { QueryBuilderBase } from "../base/query-builder-base";
36
37
  import { PostgresqlExprRenderer } from "./postgresql-expr-renderer";
@@ -685,7 +686,7 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
685
686
  * ctid 기반 CTE로 변환한다.
686
687
  */
687
688
  private _buildLimitCte(
688
- def: { table: QueryDefObjectName; as: string; top?: number; limit?: [number, number]; where?: unknown[]; joins?: SelectQueryDefJoin[] },
689
+ def: { table: QueryDefObjectName; as: string; top?: number; limit?: [number, number]; where?: WhereExpr[]; joins?: SelectQueryDefJoin[] },
689
690
  table: string,
690
691
  alias: string,
691
692
  ): string {
@@ -703,7 +704,7 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
703
704
  .map((j) => this.expr.renderWhere(j.where!));
704
705
  const whereCondition =
705
706
  def.where != null && def.where.length > 0
706
- ? this.expr.renderWhere(def.where as any)
707
+ ? this.expr.renderWhere(def.where)
707
708
  : null;
708
709
  const allConditions = [
709
710
  ...(whereCondition != null ? [whereCondition] : []),
@@ -713,7 +714,7 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
713
714
  sql += ` WHERE ${allConditions.join(" AND ")}`;
714
715
  }
715
716
  } else if (def.where != null && def.where.length > 0) {
716
- sql += ` WHERE ${this.expr.renderWhere(def.where as any)}`;
717
+ sql += ` WHERE ${this.expr.renderWhere(def.where)}`;
717
718
  }
718
719
 
719
720
  if (def.limit != null) {
@@ -282,9 +282,9 @@ export type RequiredInsertKeys<TBuilders extends ColumnBuilderRecord> = {
282
282
  ? never
283
283
  : M["nullable"] extends true
284
284
  ? never
285
- : M["default"] extends undefined
286
- ? K
287
- : never
285
+ : "default" extends keyof M
286
+ ? never
287
+ : K
288
288
  : never;
289
289
  }[keyof TBuilders];
290
290