@simplysm/orm-common 13.0.28 → 13.0.29
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/dist/create-db-context.d.ts.map +1 -1
- package/dist/create-db-context.js +7 -2
- package/dist/create-db-context.js.map +1 -1
- package/dist/ddl/column-ddl.d.ts.map +1 -1
- package/dist/ddl/column-ddl.js.map +1 -1
- package/dist/ddl/initialize.d.ts.map +1 -1
- package/dist/ddl/initialize.js.map +1 -1
- package/dist/ddl/relation-ddl.d.ts.map +1 -1
- package/dist/ddl/relation-ddl.js.map +1 -1
- package/dist/ddl/schema-ddl.d.ts.map +1 -1
- package/dist/ddl/schema-ddl.js.map +1 -1
- package/dist/ddl/table-ddl.d.ts.map +1 -1
- package/dist/ddl/table-ddl.js.map +1 -1
- package/dist/define-db-context.d.ts.map +1 -1
- package/dist/define-db-context.js.map +1 -1
- package/dist/exec/executable.d.ts.map +1 -1
- package/dist/exec/executable.js.map +1 -1
- package/dist/exec/queryable.d.ts.map +1 -1
- package/dist/exec/queryable.js +19 -6
- package/dist/exec/queryable.js.map +1 -1
- package/dist/exec/search-parser.js.map +1 -1
- package/dist/expr/expr.d.ts.map +1 -1
- package/dist/expr/expr.js.map +1 -1
- package/dist/query-builder/base/query-builder-base.d.ts.map +1 -1
- package/dist/query-builder/base/query-builder-base.js +3 -1
- package/dist/query-builder/base/query-builder-base.js.map +1 -1
- package/dist/query-builder/mssql/mssql-expr-renderer.d.ts.map +1 -1
- package/dist/query-builder/mssql/mssql-expr-renderer.js +3 -1
- package/dist/query-builder/mssql/mssql-expr-renderer.js.map +1 -1
- package/dist/query-builder/mssql/mssql-query-builder.d.ts.map +1 -1
- package/dist/query-builder/mssql/mssql-query-builder.js +9 -3
- package/dist/query-builder/mssql/mssql-query-builder.js.map +1 -1
- package/dist/query-builder/mysql/mysql-expr-renderer.d.ts.map +1 -1
- package/dist/query-builder/mysql/mysql-expr-renderer.js +3 -1
- package/dist/query-builder/mysql/mysql-expr-renderer.js.map +1 -1
- package/dist/query-builder/mysql/mysql-query-builder.d.ts.map +1 -1
- package/dist/query-builder/mysql/mysql-query-builder.js +12 -4
- package/dist/query-builder/mysql/mysql-query-builder.js.map +1 -1
- package/dist/query-builder/postgresql/postgresql-expr-renderer.d.ts.map +1 -1
- package/dist/query-builder/postgresql/postgresql-expr-renderer.js +3 -1
- package/dist/query-builder/postgresql/postgresql-expr-renderer.js.map +1 -1
- package/dist/query-builder/postgresql/postgresql-query-builder.d.ts.map +1 -1
- package/dist/query-builder/postgresql/postgresql-query-builder.js +21 -7
- package/dist/query-builder/postgresql/postgresql-query-builder.js.map +1 -1
- package/dist/schema/factory/column-builder.d.ts.map +1 -1
- package/dist/schema/factory/column-builder.js.map +1 -1
- package/dist/schema/factory/relation-builder.d.ts.map +1 -1
- package/dist/schema/factory/relation-builder.js.map +1 -1
- package/dist/schema/procedure-builder.d.ts.map +1 -1
- package/dist/schema/procedure-builder.js.map +1 -1
- package/dist/schema/table-builder.d.ts.map +1 -1
- package/dist/schema/table-builder.js +3 -1
- package/dist/schema/table-builder.js.map +1 -1
- package/dist/schema/view-builder.d.ts.map +1 -1
- package/dist/schema/view-builder.js +3 -1
- package/dist/schema/view-builder.js.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/utils/result-parser.js +3 -1
- package/dist/utils/result-parser.js.map +1 -1
- package/package.json +2 -2
- package/src/create-db-context.ts +53 -15
- package/src/ddl/column-ddl.ts +4 -1
- package/src/ddl/initialize.ts +13 -3
- package/src/ddl/relation-ddl.ts +4 -1
- package/src/ddl/schema-ddl.ts +8 -2
- package/src/ddl/table-ddl.ts +12 -3
- package/src/define-db-context.ts +3 -1
- package/src/exec/executable.ts +4 -1
- package/src/exec/queryable.ts +91 -26
- package/src/exec/search-parser.ts +5 -1
- package/src/expr/expr.ts +56 -15
- package/src/query-builder/base/query-builder-base.ts +3 -1
- package/src/query-builder/mssql/mssql-expr-renderer.ts +6 -2
- package/src/query-builder/mssql/mssql-query-builder.ts +15 -5
- package/src/query-builder/mysql/mysql-expr-renderer.ts +6 -2
- package/src/query-builder/mysql/mysql-query-builder.ts +19 -6
- package/src/query-builder/postgresql/postgresql-expr-renderer.ts +6 -2
- package/src/query-builder/postgresql/postgresql-query-builder.ts +35 -13
- package/src/schema/factory/column-builder.ts +16 -5
- package/src/schema/factory/relation-builder.ts +14 -4
- package/src/schema/procedure-builder.ts +4 -1
- package/src/schema/table-builder.ts +14 -3
- package/src/schema/view-builder.ts +5 -1
- package/src/types/db-context-def.ts +37 -8
- package/src/types/db.ts +9 -2
- package/src/utils/result-parser.ts +10 -3
package/src/expr/expr.ts
CHANGED
|
@@ -88,7 +88,9 @@ export const expr = {
|
|
|
88
88
|
val<TStr extends ColumnPrimitiveStr, T extends ColumnPrimitiveMap[TStr] | undefined>(
|
|
89
89
|
dataType: TStr,
|
|
90
90
|
value: T,
|
|
91
|
-
): ExprUnit<
|
|
91
|
+
): ExprUnit<
|
|
92
|
+
T extends undefined ? ColumnPrimitiveMap[TStr] | undefined : ColumnPrimitiveMap[TStr]
|
|
93
|
+
> {
|
|
92
94
|
return new ExprUnit(dataType, { type: "value", value });
|
|
93
95
|
},
|
|
94
96
|
|
|
@@ -287,7 +289,11 @@ export const expr = {
|
|
|
287
289
|
* // WHERE age >= 18
|
|
288
290
|
* ```
|
|
289
291
|
*/
|
|
290
|
-
between<T extends ColumnPrimitive>(
|
|
292
|
+
between<T extends ColumnPrimitive>(
|
|
293
|
+
source: ExprUnit<T>,
|
|
294
|
+
from?: ExprInput<T>,
|
|
295
|
+
to?: ExprInput<T>,
|
|
296
|
+
): WhereExprUnit {
|
|
291
297
|
return new WhereExprUnit({
|
|
292
298
|
type: "between",
|
|
293
299
|
source: toExpr(source),
|
|
@@ -343,7 +349,10 @@ export const expr = {
|
|
|
343
349
|
* db.user().where((u) => [expr.like(u.email, "%@gmail.com")])
|
|
344
350
|
* ```
|
|
345
351
|
*/
|
|
346
|
-
like(
|
|
352
|
+
like(
|
|
353
|
+
source: ExprUnit<string | undefined>,
|
|
354
|
+
pattern: ExprInput<string | undefined>,
|
|
355
|
+
): WhereExprUnit {
|
|
347
356
|
return new WhereExprUnit({
|
|
348
357
|
type: "like",
|
|
349
358
|
source: toExpr(source),
|
|
@@ -366,7 +375,10 @@ export const expr = {
|
|
|
366
375
|
* // MySQL: WHERE email REGEXP '^[a-z]+@'
|
|
367
376
|
* ```
|
|
368
377
|
*/
|
|
369
|
-
regexp(
|
|
378
|
+
regexp(
|
|
379
|
+
source: ExprUnit<string | undefined>,
|
|
380
|
+
pattern: ExprInput<string | undefined>,
|
|
381
|
+
): WhereExprUnit {
|
|
370
382
|
return new WhereExprUnit({
|
|
371
383
|
type: "regexp",
|
|
372
384
|
source: toExpr(source),
|
|
@@ -1022,7 +1034,9 @@ export const expr = {
|
|
|
1022
1034
|
* // SELECT HOUR(createdAt) AS logHour
|
|
1023
1035
|
* ```
|
|
1024
1036
|
*/
|
|
1025
|
-
hour<T extends DateTime | Time | undefined>(
|
|
1037
|
+
hour<T extends DateTime | Time | undefined>(
|
|
1038
|
+
source: ExprUnit<T>,
|
|
1039
|
+
): ExprUnit<T extends undefined ? undefined : number> {
|
|
1026
1040
|
return new ExprUnit("number", {
|
|
1027
1041
|
type: "hour",
|
|
1028
1042
|
arg: toExpr(source),
|
|
@@ -1091,7 +1105,9 @@ export const expr = {
|
|
|
1091
1105
|
* // SELECT WEEK(orderDate, 3) AS weekNum (MySQL)
|
|
1092
1106
|
* ```
|
|
1093
1107
|
*/
|
|
1094
|
-
isoWeek<T extends DateOnly | undefined>(
|
|
1108
|
+
isoWeek<T extends DateOnly | undefined>(
|
|
1109
|
+
source: ExprUnit<T>,
|
|
1110
|
+
): ExprUnit<T extends undefined ? undefined : number> {
|
|
1095
1111
|
return new ExprUnit("number", {
|
|
1096
1112
|
type: "isoWeek",
|
|
1097
1113
|
arg: toExpr(source),
|
|
@@ -1271,7 +1287,10 @@ export const expr = {
|
|
|
1271
1287
|
* // SELECT NULLIF(bio, '') AS bio
|
|
1272
1288
|
* ```
|
|
1273
1289
|
*/
|
|
1274
|
-
nullIf<T extends ColumnPrimitive>(
|
|
1290
|
+
nullIf<T extends ColumnPrimitive>(
|
|
1291
|
+
source: ExprUnit<T>,
|
|
1292
|
+
value: ExprInput<T>,
|
|
1293
|
+
): ExprUnit<T | undefined> {
|
|
1275
1294
|
return new ExprUnit(source.dataType, {
|
|
1276
1295
|
type: "nullIf",
|
|
1277
1296
|
source: toExpr(source),
|
|
@@ -1341,7 +1360,11 @@ export const expr = {
|
|
|
1341
1360
|
* // SELECT IF(age >= 18, 'adult', 'minor') AS type
|
|
1342
1361
|
* ```
|
|
1343
1362
|
*/
|
|
1344
|
-
if<T extends ColumnPrimitive>(
|
|
1363
|
+
if<T extends ColumnPrimitive>(
|
|
1364
|
+
condition: WhereExprUnit,
|
|
1365
|
+
then: ExprInput<T>,
|
|
1366
|
+
else_: ExprInput<T>,
|
|
1367
|
+
): ExprUnit<T> {
|
|
1345
1368
|
const allValues = [then, else_];
|
|
1346
1369
|
// 1. ExprUnit에서 dataType 찾기
|
|
1347
1370
|
const exprUnit = allValues.find((v): v is ExprUnit<T> => v instanceof ExprUnit);
|
|
@@ -1832,7 +1855,10 @@ export const expr = {
|
|
|
1832
1855
|
* }))
|
|
1833
1856
|
* ```
|
|
1834
1857
|
*/
|
|
1835
|
-
firstValue<T extends ColumnPrimitive>(
|
|
1858
|
+
firstValue<T extends ColumnPrimitive>(
|
|
1859
|
+
column: ExprUnit<T>,
|
|
1860
|
+
spec: WinSpecInput,
|
|
1861
|
+
): ExprUnit<T | undefined> {
|
|
1836
1862
|
return new ExprUnit(column.dataType, {
|
|
1837
1863
|
type: "window",
|
|
1838
1864
|
fn: { type: "firstValue", column: toExpr(column) },
|
|
@@ -1858,7 +1884,10 @@ export const expr = {
|
|
|
1858
1884
|
* }))
|
|
1859
1885
|
* ```
|
|
1860
1886
|
*/
|
|
1861
|
-
lastValue<T extends ColumnPrimitive>(
|
|
1887
|
+
lastValue<T extends ColumnPrimitive>(
|
|
1888
|
+
column: ExprUnit<T>,
|
|
1889
|
+
spec: WinSpecInput,
|
|
1890
|
+
): ExprUnit<T | undefined> {
|
|
1862
1891
|
return new ExprUnit(column.dataType, {
|
|
1863
1892
|
type: "window",
|
|
1864
1893
|
fn: { type: "lastValue", column: toExpr(column) },
|
|
@@ -1962,7 +1991,10 @@ export const expr = {
|
|
|
1962
1991
|
* }))
|
|
1963
1992
|
* ```
|
|
1964
1993
|
*/
|
|
1965
|
-
minOver<T extends ColumnPrimitive>(
|
|
1994
|
+
minOver<T extends ColumnPrimitive>(
|
|
1995
|
+
column: ExprUnit<T>,
|
|
1996
|
+
spec: WinSpecInput,
|
|
1997
|
+
): ExprUnit<T | undefined> {
|
|
1966
1998
|
return new ExprUnit(column.dataType, {
|
|
1967
1999
|
type: "window",
|
|
1968
2000
|
fn: { type: "min", column: toExpr(column) },
|
|
@@ -1987,7 +2019,10 @@ export const expr = {
|
|
|
1987
2019
|
* }))
|
|
1988
2020
|
* ```
|
|
1989
2021
|
*/
|
|
1990
|
-
maxOver<T extends ColumnPrimitive>(
|
|
2022
|
+
maxOver<T extends ColumnPrimitive>(
|
|
2023
|
+
column: ExprUnit<T>,
|
|
2024
|
+
spec: WinSpecInput,
|
|
2025
|
+
): ExprUnit<T | undefined> {
|
|
1991
2026
|
return new ExprUnit(column.dataType, {
|
|
1992
2027
|
type: "window",
|
|
1993
2028
|
fn: { type: "max", column: toExpr(column) },
|
|
@@ -2022,8 +2057,12 @@ function ifNull<TPrimitive extends ColumnPrimitive>(
|
|
|
2022
2057
|
ExprInput<NonNullable<TPrimitive>>,
|
|
2023
2058
|
]
|
|
2024
2059
|
): ExprUnit<NonNullable<TPrimitive>>;
|
|
2025
|
-
function ifNull<TPrimitive extends ColumnPrimitive>(
|
|
2026
|
-
|
|
2060
|
+
function ifNull<TPrimitive extends ColumnPrimitive>(
|
|
2061
|
+
...args: ExprInput<TPrimitive>[]
|
|
2062
|
+
): ExprUnit<TPrimitive>;
|
|
2063
|
+
function ifNull<TPrimitive extends ColumnPrimitive>(
|
|
2064
|
+
...args: ExprInput<TPrimitive>[]
|
|
2065
|
+
): ExprUnit<TPrimitive> {
|
|
2027
2066
|
return new ExprUnit(findDataType(args), {
|
|
2028
2067
|
type: "ifNull",
|
|
2029
2068
|
args: args.map((a) => toExpr(a)),
|
|
@@ -2077,7 +2116,9 @@ export function toExpr(value: ExprInput<ColumnPrimitive>): Expr {
|
|
|
2077
2116
|
return { type: "value", value };
|
|
2078
2117
|
}
|
|
2079
2118
|
|
|
2080
|
-
function findDataType<TPrimitive extends ColumnPrimitive>(
|
|
2119
|
+
function findDataType<TPrimitive extends ColumnPrimitive>(
|
|
2120
|
+
args: ExprInput<TPrimitive>[],
|
|
2121
|
+
): ColumnPrimitiveStr {
|
|
2081
2122
|
const exprUnit = args.find((a): a is ExprUnit<TPrimitive> => a instanceof ExprUnit);
|
|
2082
2123
|
if (!exprUnit) {
|
|
2083
2124
|
throw new Error("args중 적어도 하나는 ExprUnit이어야 합니다.");
|
|
@@ -78,7 +78,9 @@ export abstract class QueryBuilderBase {
|
|
|
78
78
|
/** ORDER BY 절 렌더링 */
|
|
79
79
|
protected renderOrderBy(orderBy: [Expr, ("ASC" | "DESC")?][] | undefined): string {
|
|
80
80
|
if (orderBy == null || orderBy.length === 0) return "";
|
|
81
|
-
const parts = orderBy.map(
|
|
81
|
+
const parts = orderBy.map(
|
|
82
|
+
([e, dir]) => `${this.expr.render(e)}${dir != null ? ` ${dir}` : ""}`,
|
|
83
|
+
);
|
|
82
84
|
return ` ORDER BY ${parts.join(", ")}`;
|
|
83
85
|
}
|
|
84
86
|
|
|
@@ -457,7 +457,9 @@ export class MssqlExprRenderer extends ExprRendererBase {
|
|
|
457
457
|
}
|
|
458
458
|
|
|
459
459
|
protected switch(expr: ExprSwitch): string {
|
|
460
|
-
const cases = expr.cases
|
|
460
|
+
const cases = expr.cases
|
|
461
|
+
.map((c) => `WHEN ${this.render(c.when)} THEN ${this.render(c.then)}`)
|
|
462
|
+
.join(" ");
|
|
461
463
|
return `CASE ${cases} ELSE ${this.render(expr.else)} END`;
|
|
462
464
|
}
|
|
463
465
|
|
|
@@ -585,7 +587,9 @@ export class MssqlExprRenderer extends ExprRendererBase {
|
|
|
585
587
|
parts.push(`PARTITION BY ${spec.partitionBy.map((p) => this.render(p)).join(", ")}`);
|
|
586
588
|
}
|
|
587
589
|
if (spec.orderBy != null && spec.orderBy.length > 0) {
|
|
588
|
-
const orderParts = spec.orderBy.map(
|
|
590
|
+
const orderParts = spec.orderBy.map(
|
|
591
|
+
([expr, dir]) => `${this.render(expr)}${dir != null ? ` ${dir}` : ""}`,
|
|
592
|
+
);
|
|
589
593
|
parts.push(`ORDER BY ${orderParts.join(", ")}`);
|
|
590
594
|
}
|
|
591
595
|
return parts.join(" ");
|
|
@@ -75,7 +75,10 @@ export class MssqlQueryBuilder extends QueryBuilderBase {
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
// 일반 JOIN
|
|
78
|
-
const where =
|
|
78
|
+
const where =
|
|
79
|
+
join.where != null && join.where.length > 0
|
|
80
|
+
? ` ON ${this.expr.renderWhere(join.where)}`
|
|
81
|
+
: " ON 1=1";
|
|
79
82
|
return ` LEFT OUTER JOIN ${from} AS ${alias}${where}`;
|
|
80
83
|
}
|
|
81
84
|
|
|
@@ -321,7 +324,8 @@ export class MssqlQueryBuilder extends QueryBuilderBase {
|
|
|
321
324
|
|
|
322
325
|
let sql = `MERGE ${table} AS ${alias}\n`;
|
|
323
326
|
sql += `USING (SELECT 1 AS [_]) AS [_src] ON `;
|
|
324
|
-
sql +=
|
|
327
|
+
sql +=
|
|
328
|
+
existsWhere != null && existsWhere.length > 0 ? this.expr.renderWhere(existsWhere) : "1=0";
|
|
325
329
|
|
|
326
330
|
if (updateSetParts.length > 0) {
|
|
327
331
|
sql += `\nWHEN MATCHED THEN UPDATE SET ${updateSetParts.join(", ")}`;
|
|
@@ -422,7 +426,9 @@ export class MssqlQueryBuilder extends QueryBuilderBase {
|
|
|
422
426
|
}
|
|
423
427
|
|
|
424
428
|
protected dropColumn(def: DropColumnQueryDef): QueryBuildResult {
|
|
425
|
-
return {
|
|
429
|
+
return {
|
|
430
|
+
sql: `ALTER TABLE ${this.tableName(def.table)} DROP COLUMN ${this.expr.wrap(def.column)}`,
|
|
431
|
+
};
|
|
426
432
|
}
|
|
427
433
|
|
|
428
434
|
protected modifyColumn(def: ModifyColumnQueryDef): QueryBuildResult {
|
|
@@ -458,7 +464,9 @@ export class MssqlQueryBuilder extends QueryBuilderBase {
|
|
|
458
464
|
const table = this.tableName(def.table);
|
|
459
465
|
const cols = def.columns.map((c) => this.expr.wrap(c)).join(", ");
|
|
460
466
|
const pkName = `PK_${def.table.name}`;
|
|
461
|
-
return {
|
|
467
|
+
return {
|
|
468
|
+
sql: `ALTER TABLE ${table} ADD CONSTRAINT ${this.expr.wrap(pkName)} PRIMARY KEY (${cols})`,
|
|
469
|
+
};
|
|
462
470
|
}
|
|
463
471
|
|
|
464
472
|
protected dropPk(def: DropPkQueryDef): QueryBuildResult {
|
|
@@ -484,7 +492,9 @@ export class MssqlQueryBuilder extends QueryBuilderBase {
|
|
|
484
492
|
}
|
|
485
493
|
|
|
486
494
|
protected dropFk(def: DropFkQueryDef): QueryBuildResult {
|
|
487
|
-
return {
|
|
495
|
+
return {
|
|
496
|
+
sql: `ALTER TABLE ${this.tableName(def.table)} DROP CONSTRAINT ${this.expr.wrap(def.foreignKey)}`,
|
|
497
|
+
};
|
|
488
498
|
}
|
|
489
499
|
|
|
490
500
|
protected addIdx(def: AddIdxQueryDef): QueryBuildResult {
|
|
@@ -467,7 +467,9 @@ export class MysqlExprRenderer extends ExprRendererBase {
|
|
|
467
467
|
}
|
|
468
468
|
|
|
469
469
|
protected switch(expr: ExprSwitch): string {
|
|
470
|
-
const cases = expr.cases
|
|
470
|
+
const cases = expr.cases
|
|
471
|
+
.map((c) => `WHEN ${this.render(c.when)} THEN ${this.render(c.then)}`)
|
|
472
|
+
.join(" ");
|
|
471
473
|
return `CASE ${cases} ELSE ${this.render(expr.else)} END`;
|
|
472
474
|
}
|
|
473
475
|
|
|
@@ -591,7 +593,9 @@ export class MysqlExprRenderer extends ExprRendererBase {
|
|
|
591
593
|
parts.push(`PARTITION BY ${spec.partitionBy.map((p) => this.render(p)).join(", ")}`);
|
|
592
594
|
}
|
|
593
595
|
if (spec.orderBy != null && spec.orderBy.length > 0) {
|
|
594
|
-
const orderParts = spec.orderBy.map(
|
|
596
|
+
const orderParts = spec.orderBy.map(
|
|
597
|
+
([expr, dir]) => `${this.render(expr)}${dir != null ? ` ${dir}` : ""}`,
|
|
598
|
+
);
|
|
595
599
|
parts.push(`ORDER BY ${orderParts.join(", ")}`);
|
|
596
600
|
}
|
|
597
601
|
return parts.join(" ");
|
|
@@ -75,7 +75,10 @@ export class MysqlQueryBuilder extends QueryBuilderBase {
|
|
|
75
75
|
protected renderJoin(join: SelectQueryDefJoin): string {
|
|
76
76
|
const alias = this.expr.wrap(join.as);
|
|
77
77
|
const from = this.renderFrom(join.from);
|
|
78
|
-
const where =
|
|
78
|
+
const where =
|
|
79
|
+
join.where != null && join.where.length > 0
|
|
80
|
+
? ` ON ${this.expr.renderWhere(join.where)}`
|
|
81
|
+
: " ON TRUE";
|
|
79
82
|
|
|
80
83
|
// LATERAL JOIN 필요 여부 감지
|
|
81
84
|
if (this.needsLateral(join)) {
|
|
@@ -287,7 +290,9 @@ export class MysqlQueryBuilder extends QueryBuilderBase {
|
|
|
287
290
|
// recordsSelectQuery에서 PK 컬럼만 추출한 SELECT 생성
|
|
288
291
|
const pkSelectDef: SelectQueryDef = {
|
|
289
292
|
...def.recordsSelectQuery,
|
|
290
|
-
select: Object.fromEntries(
|
|
293
|
+
select: Object.fromEntries(
|
|
294
|
+
def.output.pkColNames.map((pk) => [pk, def.recordsSelectQuery.select![pk]]),
|
|
295
|
+
),
|
|
291
296
|
};
|
|
292
297
|
const pkSelectSql = this.select(pkSelectDef).sql;
|
|
293
298
|
|
|
@@ -569,7 +574,9 @@ export class MysqlQueryBuilder extends QueryBuilderBase {
|
|
|
569
574
|
}
|
|
570
575
|
|
|
571
576
|
protected dropColumn(def: DropColumnQueryDef): QueryBuildResult {
|
|
572
|
-
return {
|
|
577
|
+
return {
|
|
578
|
+
sql: `ALTER TABLE ${this.tableName(def.table)} DROP COLUMN ${this.expr.wrap(def.column)}`,
|
|
579
|
+
};
|
|
573
580
|
}
|
|
574
581
|
|
|
575
582
|
protected modifyColumn(def: ModifyColumnQueryDef): QueryBuildResult {
|
|
@@ -632,7 +639,9 @@ export class MysqlQueryBuilder extends QueryBuilderBase {
|
|
|
632
639
|
}
|
|
633
640
|
|
|
634
641
|
protected dropFk(def: DropFkQueryDef): QueryBuildResult {
|
|
635
|
-
return {
|
|
642
|
+
return {
|
|
643
|
+
sql: `ALTER TABLE ${this.tableName(def.table)} DROP FOREIGN KEY ${this.expr.wrap(def.foreignKey)}`,
|
|
644
|
+
};
|
|
636
645
|
}
|
|
637
646
|
|
|
638
647
|
protected addIdx(def: AddIdxQueryDef): QueryBuildResult {
|
|
@@ -731,12 +740,16 @@ SET FOREIGN_KEY_CHECKS = 1`,
|
|
|
731
740
|
protected schemaExists(def: SchemaExistsQueryDef): QueryBuildResult {
|
|
732
741
|
// MySQL: database와 schema는 동의어
|
|
733
742
|
const dbName = this.expr.escapeString(def.database);
|
|
734
|
-
return {
|
|
743
|
+
return {
|
|
744
|
+
sql: `SELECT SCHEMA_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME = '${dbName}'`,
|
|
745
|
+
};
|
|
735
746
|
}
|
|
736
747
|
|
|
737
748
|
/** MySQL은 전역 설정만 지원 (테이블 파라미터 무시됨) */
|
|
738
749
|
protected switchFk(def: SwitchFkQueryDef): QueryBuildResult {
|
|
739
|
-
return def.switch === "on"
|
|
750
|
+
return def.switch === "on"
|
|
751
|
+
? { sql: "SET FOREIGN_KEY_CHECKS = 1" }
|
|
752
|
+
: { sql: "SET FOREIGN_KEY_CHECKS = 0" };
|
|
740
753
|
}
|
|
741
754
|
|
|
742
755
|
//#endregion
|
|
@@ -465,7 +465,9 @@ export class PostgresqlExprRenderer extends ExprRendererBase {
|
|
|
465
465
|
}
|
|
466
466
|
|
|
467
467
|
protected switch(expr: ExprSwitch): string {
|
|
468
|
-
const cases = expr.cases
|
|
468
|
+
const cases = expr.cases
|
|
469
|
+
.map((c) => `WHEN ${this.render(c.when)} THEN ${this.render(c.then)}`)
|
|
470
|
+
.join(" ");
|
|
469
471
|
return `CASE ${cases} ELSE ${this.render(expr.else)} END`;
|
|
470
472
|
}
|
|
471
473
|
|
|
@@ -589,7 +591,9 @@ export class PostgresqlExprRenderer extends ExprRendererBase {
|
|
|
589
591
|
parts.push(`PARTITION BY ${spec.partitionBy.map((p) => this.render(p)).join(", ")}`);
|
|
590
592
|
}
|
|
591
593
|
if (spec.orderBy != null && spec.orderBy.length > 0) {
|
|
592
|
-
const orderParts = spec.orderBy.map(
|
|
594
|
+
const orderParts = spec.orderBy.map(
|
|
595
|
+
([expr, dir]) => `${this.render(expr)}${dir != null ? ` ${dir}` : ""}`,
|
|
596
|
+
);
|
|
593
597
|
parts.push(`ORDER BY ${orderParts.join(", ")}`);
|
|
594
598
|
}
|
|
595
599
|
return parts.join(" ");
|
|
@@ -71,7 +71,10 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
71
71
|
protected renderJoin(join: SelectQueryDefJoin): string {
|
|
72
72
|
const from = this.renderFrom(join.from);
|
|
73
73
|
const alias = this.expr.wrap(join.as);
|
|
74
|
-
const where =
|
|
74
|
+
const where =
|
|
75
|
+
join.where != null && join.where.length > 0
|
|
76
|
+
? ` ON ${this.expr.renderWhere(join.where)}`
|
|
77
|
+
: " ON TRUE";
|
|
75
78
|
|
|
76
79
|
// LATERAL JOIN 필요 여부 감지
|
|
77
80
|
if (this.needsLateral(join)) {
|
|
@@ -236,7 +239,9 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
236
239
|
const alias = this.expr.wrap(def.as);
|
|
237
240
|
|
|
238
241
|
// SET
|
|
239
|
-
const setParts = Object.entries(def.record).map(
|
|
242
|
+
const setParts = Object.entries(def.record).map(
|
|
243
|
+
([col, e]) => `${this.expr.wrap(col)} = ${this.expr.render(e)}`,
|
|
244
|
+
);
|
|
240
245
|
|
|
241
246
|
let sql = `UPDATE ${table} AS ${alias} SET ${setParts.join(", ")}`;
|
|
242
247
|
|
|
@@ -253,8 +258,10 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
253
258
|
.filter((j) => j.where != null && j.where.length > 0)
|
|
254
259
|
.map((j) => this.expr.renderWhere(j.where!));
|
|
255
260
|
if (joinConditions.length > 0) {
|
|
256
|
-
const whereCondition =
|
|
257
|
-
|
|
261
|
+
const whereCondition =
|
|
262
|
+
def.where != null && def.where.length > 0 ? this.expr.renderWhere(def.where) : null;
|
|
263
|
+
const allConditions =
|
|
264
|
+
whereCondition != null ? [whereCondition, ...joinConditions] : joinConditions;
|
|
258
265
|
sql += ` WHERE ${allConditions.join(" AND ")}`;
|
|
259
266
|
} else {
|
|
260
267
|
sql += this.renderWhere(def.where);
|
|
@@ -295,8 +302,10 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
295
302
|
.filter((j) => j.where != null && j.where.length > 0)
|
|
296
303
|
.map((j) => this.expr.renderWhere(j.where!));
|
|
297
304
|
if (joinConditions.length > 0) {
|
|
298
|
-
const whereCondition =
|
|
299
|
-
|
|
305
|
+
const whereCondition =
|
|
306
|
+
def.where != null && def.where.length > 0 ? this.expr.renderWhere(def.where) : null;
|
|
307
|
+
const allConditions =
|
|
308
|
+
whereCondition != null ? [whereCondition, ...joinConditions] : joinConditions;
|
|
300
309
|
sql += ` WHERE ${allConditions.join(" AND ")}`;
|
|
301
310
|
} else {
|
|
302
311
|
sql += this.renderWhere(def.where);
|
|
@@ -340,7 +349,8 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
340
349
|
: "TRUE";
|
|
341
350
|
|
|
342
351
|
// OUTPUT 컬럼
|
|
343
|
-
const outputCols =
|
|
352
|
+
const outputCols =
|
|
353
|
+
def.output != null ? def.output.columns.map((c) => this.expr.wrap(c)).join(", ") : "*";
|
|
344
354
|
|
|
345
355
|
// CTE 방식 UPSERT
|
|
346
356
|
let sql = `WITH matched AS (\n`;
|
|
@@ -405,7 +415,9 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
405
415
|
}
|
|
406
416
|
|
|
407
417
|
protected renameTable(def: RenameTableQueryDef): QueryBuildResult {
|
|
408
|
-
return {
|
|
418
|
+
return {
|
|
419
|
+
sql: `ALTER TABLE ${this.tableName(def.table)} RENAME TO ${this.expr.wrap(def.newName)}`,
|
|
420
|
+
};
|
|
409
421
|
}
|
|
410
422
|
|
|
411
423
|
protected truncate(def: TruncateQueryDef): QueryBuildResult {
|
|
@@ -442,7 +454,9 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
442
454
|
}
|
|
443
455
|
|
|
444
456
|
protected dropColumn(def: DropColumnQueryDef): QueryBuildResult {
|
|
445
|
-
return {
|
|
457
|
+
return {
|
|
458
|
+
sql: `ALTER TABLE ${this.tableName(def.table)} DROP COLUMN ${this.expr.wrap(def.column)}`,
|
|
459
|
+
};
|
|
446
460
|
}
|
|
447
461
|
|
|
448
462
|
protected modifyColumn(def: ModifyColumnQueryDef): QueryBuildResult {
|
|
@@ -453,7 +467,9 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
453
467
|
const parts: string[] = [];
|
|
454
468
|
|
|
455
469
|
// TYPE 변경
|
|
456
|
-
parts.push(
|
|
470
|
+
parts.push(
|
|
471
|
+
`ALTER COLUMN ${this.expr.wrap(col.name)} TYPE ${this.expr.renderDataType(col.dataType)}`,
|
|
472
|
+
);
|
|
457
473
|
|
|
458
474
|
// NULL 변경
|
|
459
475
|
if (col.nullable === false) {
|
|
@@ -464,7 +480,9 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
464
480
|
|
|
465
481
|
// DEFAULT 변경
|
|
466
482
|
if (col.default !== undefined) {
|
|
467
|
-
parts.push(
|
|
483
|
+
parts.push(
|
|
484
|
+
`ALTER COLUMN ${this.expr.wrap(col.name)} SET DEFAULT ${this.expr.escapeValue(col.default)}`,
|
|
485
|
+
);
|
|
468
486
|
}
|
|
469
487
|
|
|
470
488
|
return { sql: `ALTER TABLE ${table} ${parts.join(", ")}` };
|
|
@@ -485,7 +503,9 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
485
503
|
const table = this.tableName(def.table);
|
|
486
504
|
const cols = def.columns.map((c) => this.expr.wrap(c)).join(", ");
|
|
487
505
|
const pkName = `PK_${def.table.name}`;
|
|
488
|
-
return {
|
|
506
|
+
return {
|
|
507
|
+
sql: `ALTER TABLE ${table} ADD CONSTRAINT ${this.expr.wrap(pkName)} PRIMARY KEY (${cols})`,
|
|
508
|
+
};
|
|
489
509
|
}
|
|
490
510
|
|
|
491
511
|
protected dropPk(def: DropPkQueryDef): QueryBuildResult {
|
|
@@ -511,7 +531,9 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
511
531
|
}
|
|
512
532
|
|
|
513
533
|
protected dropFk(def: DropFkQueryDef): QueryBuildResult {
|
|
514
|
-
return {
|
|
534
|
+
return {
|
|
535
|
+
sql: `ALTER TABLE ${this.tableName(def.table)} DROP CONSTRAINT ${this.expr.wrap(def.foreignKey)}`,
|
|
536
|
+
};
|
|
515
537
|
}
|
|
516
538
|
|
|
517
539
|
protected addIdx(def: AddIdxQueryDef): QueryBuildResult {
|
|
@@ -83,7 +83,9 @@ export class ColumnBuilder<TValue extends ColumnPrimitive, TMeta extends ColumnM
|
|
|
83
83
|
* createdAt: c.datetime().default("CURRENT_TIMESTAMP")
|
|
84
84
|
* ```
|
|
85
85
|
*/
|
|
86
|
-
default(
|
|
86
|
+
default(
|
|
87
|
+
value: TValue,
|
|
88
|
+
): ColumnBuilder<TValue, Omit<TMeta, "default"> & { default: typeof value }> {
|
|
87
89
|
return new ColumnBuilder({ ...this.meta, default: value });
|
|
88
90
|
}
|
|
89
91
|
|
|
@@ -196,7 +198,10 @@ export function createColumnFactory() {
|
|
|
196
198
|
decimal(
|
|
197
199
|
precision: number,
|
|
198
200
|
scale?: number,
|
|
199
|
-
): ColumnBuilder<
|
|
201
|
+
): ColumnBuilder<
|
|
202
|
+
number,
|
|
203
|
+
{ type: "number"; dataType: { type: "decimal"; precision: number; scale?: number } }
|
|
204
|
+
> {
|
|
200
205
|
return new ColumnBuilder({ type: "number", dataType: { type: "decimal", precision, scale } });
|
|
201
206
|
},
|
|
202
207
|
|
|
@@ -211,7 +216,9 @@ export function createColumnFactory() {
|
|
|
211
216
|
* name: c.varchar(100) // VARCHAR(100)
|
|
212
217
|
* ```
|
|
213
218
|
*/
|
|
214
|
-
varchar(
|
|
219
|
+
varchar(
|
|
220
|
+
length: number,
|
|
221
|
+
): ColumnBuilder<string, { type: "string"; dataType: { type: "varchar"; length: number } }> {
|
|
215
222
|
return new ColumnBuilder({ type: "string", dataType: { type: "varchar", length } });
|
|
216
223
|
},
|
|
217
224
|
|
|
@@ -226,7 +233,9 @@ export function createColumnFactory() {
|
|
|
226
233
|
* countryCode: c.char(2) // CHAR(2)
|
|
227
234
|
* ```
|
|
228
235
|
*/
|
|
229
|
-
char(
|
|
236
|
+
char(
|
|
237
|
+
length: number,
|
|
238
|
+
): ColumnBuilder<string, { type: "string"; dataType: { type: "char"; length: number } }> {
|
|
230
239
|
return new ColumnBuilder({ type: "string", dataType: { type: "char" as const, length } });
|
|
231
240
|
},
|
|
232
241
|
|
|
@@ -397,7 +406,9 @@ export type InferInsertColumns<TBuilders extends ColumnBuilderRecord> = Pick<
|
|
|
397
406
|
*
|
|
398
407
|
* @template T - 컬럼 빌더 레코드 타입
|
|
399
408
|
*/
|
|
400
|
-
export type InferUpdateColumns<TBuilders extends ColumnBuilderRecord> = Partial<
|
|
409
|
+
export type InferUpdateColumns<TBuilders extends ColumnBuilderRecord> = Partial<
|
|
410
|
+
InferColumns<TBuilders>
|
|
411
|
+
>;
|
|
401
412
|
|
|
402
413
|
/**
|
|
403
414
|
* 데이터 레코드에서 컬럼 빌더 레코드로 변환
|
|
@@ -32,7 +32,10 @@ import type { ViewBuilder } from "../view-builder";
|
|
|
32
32
|
* @see {@link ForeignKeyTargetBuilder} 역참조 빌더
|
|
33
33
|
* @see {@link RelationKeyBuilder} DB FK 없는 관계
|
|
34
34
|
*/
|
|
35
|
-
export class ForeignKeyBuilder<
|
|
35
|
+
export class ForeignKeyBuilder<
|
|
36
|
+
TOwner extends TableBuilder<any, any>,
|
|
37
|
+
TTargetFn extends () => TableBuilder<any, any>,
|
|
38
|
+
> {
|
|
36
39
|
/**
|
|
37
40
|
* @param meta - FK 메타데이터
|
|
38
41
|
* @param meta.ownerFn - 소유 테이블 팩토리
|
|
@@ -88,7 +91,10 @@ export class ForeignKeyBuilder<TOwner extends TableBuilder<any, any>, TTargetFn
|
|
|
88
91
|
*
|
|
89
92
|
* @see {@link ForeignKeyBuilder} FK 빌더
|
|
90
93
|
*/
|
|
91
|
-
export class ForeignKeyTargetBuilder<
|
|
94
|
+
export class ForeignKeyTargetBuilder<
|
|
95
|
+
TTargetTableFn extends () => TableBuilder<any, any>,
|
|
96
|
+
TIsSingle extends boolean,
|
|
97
|
+
> {
|
|
92
98
|
/**
|
|
93
99
|
* @param meta - FK 역참조 메타데이터
|
|
94
100
|
* @param meta.targetTableFn - 참조하는 테이블 팩토리
|
|
@@ -294,7 +300,9 @@ type RelationRkFactory<
|
|
|
294
300
|
targetFn: TTargetFn,
|
|
295
301
|
): RelationKeyBuilder<TOwner, TTargetFn>;
|
|
296
302
|
/** 1:N 논리적 역참조 정의 */
|
|
297
|
-
relationKeyTarget<
|
|
303
|
+
relationKeyTarget<
|
|
304
|
+
TTargetTableFn extends () => TableBuilder<any, any> | ViewBuilder<any, any, any>,
|
|
305
|
+
>(
|
|
298
306
|
targetTableFn: TTargetTableFn,
|
|
299
307
|
relationName: string,
|
|
300
308
|
): RelationKeyTargetBuilder<TTargetTableFn, false>;
|
|
@@ -439,5 +447,7 @@ export type ExtractRelationTargetResult<TRelation> = TRelation extends
|
|
|
439
447
|
* ```
|
|
440
448
|
*/
|
|
441
449
|
export type InferDeepRelations<TRelations extends RelationBuilderRecord> = {
|
|
442
|
-
[K in keyof TRelations]?:
|
|
450
|
+
[K in keyof TRelations]?:
|
|
451
|
+
| ExtractRelationTarget<TRelations[K]>
|
|
452
|
+
| ExtractRelationTargetResult<TRelations[K]>;
|
|
443
453
|
};
|
|
@@ -40,7 +40,10 @@ import { type ColumnBuilderRecord, createColumnFactory } from "./factory/column-
|
|
|
40
40
|
* @see {@link Procedure} 팩토리 함수
|
|
41
41
|
* @see {@link executable} Executable 생성
|
|
42
42
|
*/
|
|
43
|
-
export class ProcedureBuilder<
|
|
43
|
+
export class ProcedureBuilder<
|
|
44
|
+
TParams extends ColumnBuilderRecord,
|
|
45
|
+
TReturns extends ColumnBuilderRecord,
|
|
46
|
+
> {
|
|
44
47
|
/** 파라미터 정의 (타입 추론용) */
|
|
45
48
|
readonly $params!: TParams;
|
|
46
49
|
/** 반환 타입 정의 (타입 추론용) */
|
|
@@ -6,7 +6,11 @@ import {
|
|
|
6
6
|
type InferUpdateColumns,
|
|
7
7
|
} from "./factory/column-builder";
|
|
8
8
|
import { createIndexFactory, type IndexBuilder } from "./factory/index-builder";
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
createRelationFactory,
|
|
11
|
+
type InferDeepRelations,
|
|
12
|
+
type RelationBuilderRecord,
|
|
13
|
+
} from "./factory/relation-builder";
|
|
10
14
|
|
|
11
15
|
// ============================================
|
|
12
16
|
// TableBuilder
|
|
@@ -44,7 +48,10 @@ import { createRelationFactory, type InferDeepRelations, type RelationBuilderRec
|
|
|
44
48
|
* @see {@link Table} 팩토리 함수
|
|
45
49
|
* @see {@link queryable} Queryable 생성
|
|
46
50
|
*/
|
|
47
|
-
export class TableBuilder<
|
|
51
|
+
export class TableBuilder<
|
|
52
|
+
TColumns extends ColumnBuilderRecord,
|
|
53
|
+
TRelations extends RelationBuilderRecord,
|
|
54
|
+
> {
|
|
48
55
|
/** 컬럼 정의 (타입 추론용) */
|
|
49
56
|
readonly $columns!: TColumns;
|
|
50
57
|
/** 관계 정의 (타입 추론용) */
|
|
@@ -206,7 +213,11 @@ export class TableBuilder<TColumns extends ColumnBuilderRecord, TRelations exten
|
|
|
206
213
|
* ]);
|
|
207
214
|
* ```
|
|
208
215
|
*/
|
|
209
|
-
indexes(
|
|
216
|
+
indexes(
|
|
217
|
+
fn: (
|
|
218
|
+
i: ReturnType<typeof createIndexFactory<keyof TColumns & string>>,
|
|
219
|
+
) => IndexBuilder<string[]>[],
|
|
220
|
+
) {
|
|
210
221
|
return new TableBuilder({
|
|
211
222
|
...this.meta,
|
|
212
223
|
indexes: fn(createIndexFactory<keyof TColumns & string>()),
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import type { DbContextBase } from "../types/db-context-def";
|
|
2
2
|
import type { Queryable } from "../exec/queryable";
|
|
3
3
|
import type { DataRecord } from "../types/db";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
createRelationFactory,
|
|
6
|
+
type InferDeepRelations,
|
|
7
|
+
type RelationBuilderRecord,
|
|
8
|
+
} from "./factory/relation-builder";
|
|
5
9
|
|
|
6
10
|
// ============================================
|
|
7
11
|
// ViewBuilder
|