@simplysm/orm-common 13.0.38 → 13.0.39

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 (46) hide show
  1. package/README.md +2 -1
  2. package/dist/create-db-context.d.ts.map +1 -1
  3. package/dist/ddl/column-ddl.d.ts.map +1 -1
  4. package/dist/ddl/initialize.d.ts.map +1 -1
  5. package/dist/ddl/relation-ddl.d.ts.map +1 -1
  6. package/dist/ddl/schema-ddl.d.ts.map +1 -1
  7. package/dist/ddl/table-ddl.d.ts.map +1 -1
  8. package/dist/define-db-context.d.ts.map +1 -1
  9. package/dist/errors/db-transaction-error.d.ts.map +1 -1
  10. package/dist/exec/executable.d.ts.map +1 -1
  11. package/dist/exec/queryable.d.ts +21 -10
  12. package/dist/exec/queryable.d.ts.map +1 -1
  13. package/dist/exec/queryable.js +3 -1
  14. package/dist/exec/queryable.js.map +1 -1
  15. package/dist/exec/search-parser.d.ts.map +1 -1
  16. package/dist/expr/expr-unit.d.ts.map +1 -1
  17. package/dist/expr/expr.d.ts.map +1 -1
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/models/system-migration.d.ts.map +1 -1
  20. package/dist/query-builder/base/expr-renderer-base.d.ts.map +1 -1
  21. package/dist/query-builder/base/query-builder-base.d.ts.map +1 -1
  22. package/dist/query-builder/mssql/mssql-expr-renderer.d.ts.map +1 -1
  23. package/dist/query-builder/mssql/mssql-query-builder.d.ts.map +1 -1
  24. package/dist/query-builder/mysql/mysql-expr-renderer.d.ts.map +1 -1
  25. package/dist/query-builder/mysql/mysql-query-builder.d.ts.map +1 -1
  26. package/dist/query-builder/postgresql/postgresql-expr-renderer.d.ts.map +1 -1
  27. package/dist/query-builder/postgresql/postgresql-query-builder.d.ts.map +1 -1
  28. package/dist/query-builder/query-builder.d.ts.map +1 -1
  29. package/dist/schema/factory/column-builder.d.ts.map +1 -1
  30. package/dist/schema/factory/index-builder.d.ts.map +1 -1
  31. package/dist/schema/factory/relation-builder.d.ts.map +1 -1
  32. package/dist/schema/procedure-builder.d.ts.map +1 -1
  33. package/dist/schema/table-builder.d.ts.map +1 -1
  34. package/dist/schema/view-builder.d.ts.map +1 -1
  35. package/dist/types/column.d.ts.map +1 -1
  36. package/dist/types/db-context-def.d.ts.map +1 -1
  37. package/dist/types/db.d.ts.map +1 -1
  38. package/dist/types/expr.d.ts.map +1 -1
  39. package/dist/types/query-def.d.ts.map +1 -1
  40. package/dist/utils/result-parser.d.ts.map +1 -1
  41. package/dist/utils/result-parser.js +3 -2
  42. package/dist/utils/result-parser.js.map +1 -1
  43. package/docs/queries.md +18 -9
  44. package/package.json +2 -2
  45. package/src/exec/queryable.ts +59 -35
  46. package/src/utils/result-parser.ts +10 -2
@@ -19,7 +19,7 @@ import {
19
19
  type DataToColumnBuilderRecord,
20
20
  } from "../schema/factory/column-builder";
21
21
  import type { ColumnPrimitive, ColumnPrimitiveStr } from "../types/column";
22
- import type { WhereExprUnit } from "../expr/expr-unit";
22
+ import type { WhereExprUnit, ExprInput } from "../expr/expr-unit";
23
23
  import { ExprUnit } from "../expr/expr-unit";
24
24
  import type { Expr } from "../types/expr";
25
25
  import { ArgumentError, objClearUndefined } from "@simplysm/core-common";
@@ -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
- );
131
+ ) as any;
132
132
  }
133
133
 
134
134
  /**
@@ -247,16 +247,16 @@ export class Queryable<
247
247
  * }))
248
248
  * ```
249
249
  */
250
- select<R extends DataRecord>(
251
- fn: (columns: QueryableRecord<TData>) => QueryableRecord<R>,
252
- ): Queryable<R, never> {
250
+ select<R extends Record<string, any>>(
251
+ fn: (columns: QueryableRecord<TData>) => R,
252
+ ): Queryable<UnwrapQueryableRecord<R>, never> {
253
253
  if (Array.isArray(this.meta.from)) {
254
254
  const newFroms = this.meta.from.map((from) => from.select(fn));
255
255
  return new Queryable({
256
256
  ...this.meta,
257
257
  from: newFroms,
258
- columns: transformColumnsAlias<R>(newFroms[0].meta.columns, this.meta.as, ""),
259
- });
258
+ columns: transformColumnsAlias(newFroms[0].meta.columns, this.meta.as, ""),
259
+ }) as any;
260
260
  }
261
261
 
262
262
  const newColumns = fn(this.meta.columns);
@@ -1175,7 +1175,10 @@ export class Queryable<
1175
1175
  return from;
1176
1176
  }
1177
1177
 
1178
- private _buildSelectDef(columns: QueryableRecord<any>, prefix: string): Record<string, Expr> {
1178
+ private _buildSelectDef(
1179
+ columns: QueryableRecord<any> | QueryableWriteRecord<any>,
1180
+ prefix: string,
1181
+ ): Record<string, Expr> {
1179
1182
  const result: Record<string, Expr> = {};
1180
1183
 
1181
1184
  for (const [key, val] of Object.entries(columns)) {
@@ -1187,8 +1190,11 @@ export class Queryable<
1187
1190
  if (val.length > 0) {
1188
1191
  Object.assign(result, this._buildSelectDef(val[0], fullKey));
1189
1192
  }
1190
- } else if (typeof val === "object") {
1193
+ } else if (typeof val === "object" && val != null) {
1191
1194
  Object.assign(result, this._buildSelectDef(val, fullKey));
1195
+ } else {
1196
+ // Plain value (string, number, boolean, etc.) — convert to Expr
1197
+ result[fullKey] = expr.toExpr(val);
1192
1198
  }
1193
1199
  }
1194
1200
 
@@ -1476,14 +1482,14 @@ export class Queryable<
1476
1482
  * ```
1477
1483
  */
1478
1484
  async update(
1479
- recordFwd: (cols: QueryableRecord<TData>) => QueryableRecord<TFrom["$inferUpdate"]>,
1485
+ recordFwd: (cols: QueryableRecord<TData>) => QueryableWriteRecord<TFrom["$inferUpdate"]>,
1480
1486
  ): Promise<void>;
1481
1487
  async update<K extends keyof TFrom["$columns"] & string>(
1482
- recordFwd: (cols: QueryableRecord<TData>) => QueryableRecord<TFrom["$inferUpdate"]>,
1488
+ recordFwd: (cols: QueryableRecord<TData>) => QueryableWriteRecord<TFrom["$inferUpdate"]>,
1483
1489
  outputColumns: K[],
1484
1490
  ): Promise<Pick<TFrom["$columns"], K>[]>;
1485
1491
  async update<K extends keyof TFrom["$columns"] & string>(
1486
- recordFwd: (cols: QueryableRecord<TData>) => QueryableRecord<TFrom["$inferUpdate"]>,
1492
+ recordFwd: (cols: QueryableRecord<TData>) => QueryableWriteRecord<TFrom["$inferUpdate"]>,
1487
1493
  outputColumns?: K[],
1488
1494
  ): Promise<Pick<TFrom["$columns"], K>[] | void> {
1489
1495
  const results = await this.meta.db.executeDefs<Pick<TFrom["$columns"], K>>(
@@ -1533,7 +1539,7 @@ export class Queryable<
1533
1539
  }
1534
1540
 
1535
1541
  getUpdateQueryDef(
1536
- recordFwd: (cols: QueryableRecord<TData>) => QueryableRecord<TFrom["$inferUpdate"]>,
1542
+ recordFwd: (cols: QueryableRecord<TData>) => QueryableWriteRecord<TFrom["$inferUpdate"]>,
1537
1543
  outputColumns?: (keyof TFrom["$inferColumns"] & string)[],
1538
1544
  ): UpdateQueryDef {
1539
1545
  const from = this.meta.from as TableBuilder<any, any> | ViewBuilder<any, any, any>;
@@ -1614,39 +1620,41 @@ export class Queryable<
1614
1620
  * ```
1615
1621
  */
1616
1622
  async upsert(
1617
- updateFwd: (cols: QueryableRecord<TData>) => QueryableRecord<TFrom["$inferUpdate"]>,
1623
+ updateFwd: (cols: QueryableRecord<TData>) => QueryableWriteRecord<TFrom["$inferUpdate"]>,
1618
1624
  ): Promise<void>;
1619
1625
  async upsert<K extends keyof TFrom["$inferColumns"] & string>(
1620
- insertFwd: (cols: QueryableRecord<TData>) => QueryableRecord<TFrom["$inferInsert"]>,
1626
+ insertFwd: (cols: QueryableRecord<TData>) => QueryableWriteRecord<TFrom["$inferInsert"]>,
1621
1627
  outputColumns?: K[],
1622
1628
  ): Promise<Pick<TFrom["$inferColumns"], K>[]>;
1623
- async upsert<U extends QueryableRecord<TFrom["$inferUpdate"]>>(
1629
+ async upsert<U extends QueryableWriteRecord<TFrom["$inferUpdate"]>>(
1624
1630
  updateFwd: (cols: QueryableRecord<TData>) => U,
1625
- insertFwd: (updateRecord: U) => QueryableRecord<TFrom["$inferInsert"]>,
1631
+ insertFwd: (updateRecord: U) => QueryableWriteRecord<TFrom["$inferInsert"]>,
1626
1632
  ): Promise<void>;
1627
1633
  async upsert<
1628
- U extends QueryableRecord<TFrom["$inferUpdate"]>,
1634
+ U extends QueryableWriteRecord<TFrom["$inferUpdate"]>,
1629
1635
  K extends keyof TFrom["$inferColumns"] & string,
1630
1636
  >(
1631
1637
  updateFwd: (cols: QueryableRecord<TData>) => U,
1632
- insertFwd: (updateRecord: U) => QueryableRecord<TFrom["$inferInsert"]>,
1638
+ insertFwd: (updateRecord: U) => QueryableWriteRecord<TFrom["$inferInsert"]>,
1633
1639
  outputColumns?: K[],
1634
1640
  ): Promise<Pick<TFrom["$inferColumns"], K>[]>;
1635
1641
  async upsert<
1636
- U extends QueryableRecord<TFrom["$inferUpdate"]>,
1642
+ U extends QueryableWriteRecord<TFrom["$inferUpdate"]>,
1637
1643
  K extends keyof TFrom["$inferColumns"] & string,
1638
1644
  >(
1639
1645
  updateFwdOrInsertFwd:
1640
1646
  | ((cols: QueryableRecord<TData>) => U)
1641
- | ((cols: QueryableRecord<TData>) => QueryableRecord<TFrom["$inferInsert"]>),
1642
- insertFwdOrOutputColumns?: ((updateRecord: U) => QueryableRecord<TFrom["$inferInsert"]>) | K[],
1647
+ | ((cols: QueryableRecord<TData>) => QueryableWriteRecord<TFrom["$inferInsert"]>),
1648
+ insertFwdOrOutputColumns?:
1649
+ | ((updateRecord: U) => QueryableWriteRecord<TFrom["$inferInsert"]>)
1650
+ | K[],
1643
1651
  outputColumns?: K[],
1644
1652
  ): Promise<Pick<TFrom["$inferColumns"], K>[] | void> {
1645
1653
  const updateRecordFwd = updateFwdOrInsertFwd as (cols: QueryableRecord<TData>) => U;
1646
1654
 
1647
1655
  const insertRecordFwd = (
1648
1656
  insertFwdOrOutputColumns instanceof Function ? insertFwdOrOutputColumns : updateFwdOrInsertFwd
1649
- ) as (updateRecord: U) => QueryableRecord<TFrom["$inferInsert"]>;
1657
+ ) as (updateRecord: U) => QueryableWriteRecord<TFrom["$inferInsert"]>;
1650
1658
 
1651
1659
  const realOutputColumns =
1652
1660
  insertFwdOrOutputColumns instanceof Function ? outputColumns : insertFwdOrOutputColumns;
@@ -1661,9 +1669,9 @@ export class Queryable<
1661
1669
  }
1662
1670
  }
1663
1671
 
1664
- getUpsertQueryDef<U extends QueryableRecord<TFrom["$inferUpdate"]>>(
1672
+ getUpsertQueryDef<U extends QueryableWriteRecord<TFrom["$inferUpdate"]>>(
1665
1673
  updateRecordFwd: (cols: QueryableRecord<TData>) => U,
1666
- insertRecordFwd: (updateRecord: U) => QueryableRecord<TFrom["$inferInsert"]>,
1674
+ insertRecordFwd: (updateRecord: U) => QueryableWriteRecord<TFrom["$inferInsert"]>,
1667
1675
  outputColumns?: (keyof TFrom["$inferColumns"] & string)[],
1668
1676
  ): UpsertQueryDef {
1669
1677
  const from = this.meta.from as TableBuilder<any, any> | ViewBuilder<any, any, any>;
@@ -1849,11 +1857,9 @@ interface QueryableMetaJoin {
1849
1857
  }
1850
1858
 
1851
1859
  export type QueryableRecord<TData extends DataRecord> = {
1852
- // 1. Primitive 처리
1853
1860
  [K in keyof TData]: TData[K] extends ColumnPrimitive
1854
1861
  ? ExprUnit<TData[K]>
1855
- : // 2. 배열 처리 (옵셔널 포함)
1856
- TData[K] extends (infer U)[]
1862
+ : TData[K] extends (infer U)[]
1857
1863
  ? U extends DataRecord
1858
1864
  ? QueryableRecord<U>[]
1859
1865
  : never
@@ -1861,20 +1867,22 @@ export type QueryableRecord<TData extends DataRecord> = {
1861
1867
  ? U extends DataRecord
1862
1868
  ? NullableQueryableRecord<U>[] | undefined
1863
1869
  : never
1864
- : // 3. 단일 객체 처리 (옵셔널 포함)
1865
- TData[K] extends DataRecord
1870
+ : TData[K] extends DataRecord
1866
1871
  ? QueryableRecord<TData[K]>
1867
1872
  : TData[K] extends DataRecord | undefined
1868
1873
  ? NullableQueryableRecord<Exclude<TData[K], undefined>> | undefined
1869
1874
  : never;
1870
1875
  };
1871
1876
 
1877
+ export type QueryableWriteRecord<TData> = {
1878
+ [K in keyof TData]: TData[K] extends ColumnPrimitive ? ExprInput<TData[K]> : never;
1879
+ };
1880
+
1872
1881
  export type NullableQueryableRecord<TData extends DataRecord> = {
1873
- // 1. Primitive — always | undefined (LEFT JOIN NULL propagation)
1882
+ // Primitive — always | undefined (LEFT JOIN NULL propagation)
1874
1883
  [K in keyof TData]: TData[K] extends ColumnPrimitive
1875
1884
  ? ExprUnit<TData[K] | undefined>
1876
- : // 2. Array (optional included)
1877
- TData[K] extends (infer U)[]
1885
+ : TData[K] extends (infer U)[]
1878
1886
  ? U extends DataRecord
1879
1887
  ? NullableQueryableRecord<U>[]
1880
1888
  : never
@@ -1882,14 +1890,30 @@ export type NullableQueryableRecord<TData extends DataRecord> = {
1882
1890
  ? U extends DataRecord
1883
1891
  ? NullableQueryableRecord<U>[] | undefined
1884
1892
  : never
1885
- : // 3. Single object (optional included)
1886
- TData[K] extends DataRecord
1893
+ : TData[K] extends DataRecord
1887
1894
  ? NullableQueryableRecord<TData[K]>
1888
1895
  : TData[K] extends DataRecord | undefined
1889
1896
  ? NullableQueryableRecord<Exclude<TData[K], undefined>> | undefined
1890
1897
  : never;
1891
1898
  };
1892
1899
 
1900
+ /**
1901
+ * QueryableRecord에서 DataRecord로 역변환
1902
+ *
1903
+ * ExprUnit<T>를 T로, 중첩 객체/배열을 재귀적으로 풀어냄
1904
+ */
1905
+ export type UnwrapQueryableRecord<R> = {
1906
+ [K in keyof R]: R[K] extends ExprUnit<infer T>
1907
+ ? T
1908
+ : NonNullable<R[K]> extends (infer U)[]
1909
+ ? U extends Record<string, any>
1910
+ ? UnwrapQueryableRecord<U>[] | Extract<R[K], undefined>
1911
+ : never
1912
+ : NonNullable<R[K]> extends Record<string, any>
1913
+ ? UnwrapQueryableRecord<NonNullable<R[K]>> | Extract<R[K], undefined>
1914
+ : never;
1915
+ };
1916
+
1893
1917
  //#region ========== PathProxy - include용 타입 안전 경로 빌더 ==========
1894
1918
 
1895
1919
  /**
@@ -2,6 +2,8 @@ import { bytesFromHex, DateOnly, DateTime, objEqual, Time, Uuid } from "@simplys
2
2
  import type { ColumnPrimitiveStr } from "../types/column";
3
3
  import type { ResultMeta } from "../types/db";
4
4
 
5
+ declare function setImmediate(callback: () => void): void;
6
+
5
7
  // ============================================
6
8
  // Type Parsers
7
9
  // ============================================
@@ -116,6 +118,12 @@ function isEmptyObject(obj: Record<string, unknown>): boolean {
116
118
  /** yield 간격: N개 처리마다 이벤트 루프 양보 */
117
119
  const YIELD_INTERVAL = 100;
118
120
 
121
+ /** 이벤트 루프 양보: Node.js에서는 setImmediate, 브라우저에서는 setTimeout 폴백 */
122
+ const yieldToEventLoop: () => Promise<void> =
123
+ typeof setImmediate !== "undefined"
124
+ ? () => new Promise<void>((resolve) => setImmediate(resolve))
125
+ : () => new Promise<void>((resolve) => setTimeout(resolve, 0));
126
+
119
127
  /**
120
128
  * DB 쿼리 결과를 ResultMeta를 통해 TypeScript 객체로 변환
121
129
  *
@@ -183,7 +191,7 @@ async function parseSimpleRecords<TRecord>(
183
191
  for (let i = 0; i < rawResults.length; i++) {
184
192
  // yield 처리
185
193
  if (i > 0 && i % YIELD_INTERVAL === 0) {
186
- await new Promise<void>((resolve) => setTimeout(resolve, 0));
194
+ await yieldToEventLoop();
187
195
  }
188
196
 
189
197
  const parsed = flatToNested(rawResults[i], columns);
@@ -221,7 +229,7 @@ async function parseJoinedRecords<TRecord>(
221
229
  const nestedRecords: Record<string, unknown>[] = [];
222
230
  for (let i = 0; i < rawResults.length; i++) {
223
231
  if (i > 0 && i % YIELD_INTERVAL === 0) {
224
- await new Promise<void>((resolve) => setTimeout(resolve, 0));
232
+ await yieldToEventLoop();
225
233
  }
226
234
  nestedRecords.push(flatToNested(rawResults[i], meta.columns));
227
235
  }