@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.
- package/README.md +2 -1
- package/dist/create-db-context.d.ts.map +1 -1
- package/dist/ddl/column-ddl.d.ts.map +1 -1
- package/dist/ddl/initialize.d.ts.map +1 -1
- package/dist/ddl/relation-ddl.d.ts.map +1 -1
- package/dist/ddl/schema-ddl.d.ts.map +1 -1
- package/dist/ddl/table-ddl.d.ts.map +1 -1
- package/dist/define-db-context.d.ts.map +1 -1
- package/dist/errors/db-transaction-error.d.ts.map +1 -1
- package/dist/exec/executable.d.ts.map +1 -1
- package/dist/exec/queryable.d.ts +21 -10
- package/dist/exec/queryable.d.ts.map +1 -1
- package/dist/exec/queryable.js +3 -1
- package/dist/exec/queryable.js.map +1 -1
- package/dist/exec/search-parser.d.ts.map +1 -1
- package/dist/expr/expr-unit.d.ts.map +1 -1
- package/dist/expr/expr.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/models/system-migration.d.ts.map +1 -1
- package/dist/query-builder/base/expr-renderer-base.d.ts.map +1 -1
- package/dist/query-builder/base/query-builder-base.d.ts.map +1 -1
- package/dist/query-builder/mssql/mssql-expr-renderer.d.ts.map +1 -1
- package/dist/query-builder/mssql/mssql-query-builder.d.ts.map +1 -1
- package/dist/query-builder/mysql/mysql-expr-renderer.d.ts.map +1 -1
- package/dist/query-builder/mysql/mysql-query-builder.d.ts.map +1 -1
- package/dist/query-builder/postgresql/postgresql-expr-renderer.d.ts.map +1 -1
- package/dist/query-builder/postgresql/postgresql-query-builder.d.ts.map +1 -1
- package/dist/query-builder/query-builder.d.ts.map +1 -1
- package/dist/schema/factory/column-builder.d.ts.map +1 -1
- package/dist/schema/factory/index-builder.d.ts.map +1 -1
- package/dist/schema/factory/relation-builder.d.ts.map +1 -1
- package/dist/schema/procedure-builder.d.ts.map +1 -1
- package/dist/schema/table-builder.d.ts.map +1 -1
- package/dist/schema/view-builder.d.ts.map +1 -1
- package/dist/types/column.d.ts.map +1 -1
- package/dist/types/db-context-def.d.ts.map +1 -1
- package/dist/types/db.d.ts.map +1 -1
- package/dist/types/expr.d.ts.map +1 -1
- package/dist/types/query-def.d.ts.map +1 -1
- package/dist/utils/result-parser.d.ts.map +1 -1
- package/dist/utils/result-parser.js +3 -2
- package/dist/utils/result-parser.js.map +1 -1
- package/docs/queries.md +18 -9
- package/package.json +2 -2
- package/src/exec/queryable.ts +59 -35
- package/src/utils/result-parser.ts +10 -2
package/src/exec/queryable.ts
CHANGED
|
@@ -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
|
|
251
|
-
fn: (columns: QueryableRecord<TData>) =>
|
|
252
|
-
): Queryable<R
|
|
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
|
|
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(
|
|
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>) =>
|
|
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>) =>
|
|
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>) =>
|
|
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>) =>
|
|
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>) =>
|
|
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>) =>
|
|
1626
|
+
insertFwd: (cols: QueryableRecord<TData>) => QueryableWriteRecord<TFrom["$inferInsert"]>,
|
|
1621
1627
|
outputColumns?: K[],
|
|
1622
1628
|
): Promise<Pick<TFrom["$inferColumns"], K>[]>;
|
|
1623
|
-
async upsert<U extends
|
|
1629
|
+
async upsert<U extends QueryableWriteRecord<TFrom["$inferUpdate"]>>(
|
|
1624
1630
|
updateFwd: (cols: QueryableRecord<TData>) => U,
|
|
1625
|
-
insertFwd: (updateRecord: U) =>
|
|
1631
|
+
insertFwd: (updateRecord: U) => QueryableWriteRecord<TFrom["$inferInsert"]>,
|
|
1626
1632
|
): Promise<void>;
|
|
1627
1633
|
async upsert<
|
|
1628
|
-
U extends
|
|
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) =>
|
|
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
|
|
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>) =>
|
|
1642
|
-
insertFwdOrOutputColumns?:
|
|
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) =>
|
|
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
|
|
1672
|
+
getUpsertQueryDef<U extends QueryableWriteRecord<TFrom["$inferUpdate"]>>(
|
|
1665
1673
|
updateRecordFwd: (cols: QueryableRecord<TData>) => U,
|
|
1666
|
-
insertRecordFwd: (updateRecord: U) =>
|
|
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
|
-
:
|
|
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
|
-
:
|
|
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
|
-
//
|
|
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
|
-
:
|
|
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
|
-
:
|
|
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
|
|
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
|
|
232
|
+
await yieldToEventLoop();
|
|
225
233
|
}
|
|
226
234
|
nestedRecords.push(flatToNested(rawResults[i], meta.columns));
|
|
227
235
|
}
|