@simplysm/orm-common 14.1.2 → 14.1.6
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/db-context.d.ts +11 -10
- package/dist/db-context.d.ts.map +1 -1
- package/dist/db-context.js +14 -11
- package/dist/db-context.js.map +1 -1
- package/dist/ddl/initialize.js.map +1 -1
- package/dist/ddl/relation-ddl.d.ts +1 -1
- package/dist/ddl/relation-ddl.d.ts.map +1 -1
- package/dist/ddl/relation-ddl.js.map +1 -1
- package/dist/ddl/table-ddl.d.ts +3 -3
- package/dist/ddl/table-ddl.d.ts.map +1 -1
- package/dist/ddl/table-ddl.js.map +1 -1
- package/dist/errors/db-transaction-error.d.ts +4 -5
- package/dist/errors/db-transaction-error.d.ts.map +1 -1
- package/dist/errors/db-transaction-error.js +5 -6
- package/dist/errors/db-transaction-error.js.map +1 -1
- package/dist/exec/executable.d.ts +4 -13
- package/dist/exec/executable.d.ts.map +1 -1
- package/dist/exec/executable.js.map +1 -1
- package/dist/exec/queryable.d.ts +11 -9
- package/dist/exec/queryable.d.ts.map +1 -1
- package/dist/exec/queryable.js +9 -5
- package/dist/exec/queryable.js.map +1 -1
- package/dist/expr/expr.d.ts +7 -4
- package/dist/expr/expr.d.ts.map +1 -1
- package/dist/expr/expr.js +5 -2
- package/dist/expr/expr.js.map +1 -1
- package/dist/models/system-migration.d.ts +1 -1
- package/dist/models/system-migration.d.ts.map +1 -1
- package/dist/query-builder/base/expr-renderer-base.d.ts +2 -1
- package/dist/query-builder/base/expr-renderer-base.d.ts.map +1 -1
- package/dist/query-builder/base/expr-renderer-base.js.map +1 -1
- package/dist/query-builder/mssql/mssql-expr-renderer.d.ts +2 -2
- package/dist/query-builder/mssql/mssql-expr-renderer.d.ts.map +1 -1
- package/dist/query-builder/mssql/mssql-expr-renderer.js.map +1 -1
- package/dist/query-builder/mysql/mysql-expr-renderer.d.ts +2 -2
- package/dist/query-builder/mysql/mysql-expr-renderer.d.ts.map +1 -1
- package/dist/query-builder/mysql/mysql-expr-renderer.js.map +1 -1
- package/dist/query-builder/postgresql/postgresql-expr-renderer.d.ts +2 -2
- package/dist/query-builder/postgresql/postgresql-expr-renderer.d.ts.map +1 -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.map +1 -1
- package/dist/schema/factory/column-builder.d.ts +1 -1
- package/dist/schema/factory/column-builder.d.ts.map +1 -1
- package/dist/schema/factory/relation-builder.d.ts +55 -49
- package/dist/schema/factory/relation-builder.d.ts.map +1 -1
- package/dist/schema/factory/relation-builder.js +12 -15
- package/dist/schema/factory/relation-builder.js.map +1 -1
- package/dist/schema/table-builder.d.ts +35 -18
- package/dist/schema/table-builder.d.ts.map +1 -1
- package/dist/schema/table-builder.js +32 -15
- package/dist/schema/table-builder.js.map +1 -1
- package/dist/schema/view-builder.d.ts +28 -24
- package/dist/schema/view-builder.d.ts.map +1 -1
- package/dist/schema/view-builder.js +18 -14
- package/dist/schema/view-builder.js.map +1 -1
- package/dist/types/column.d.ts +6 -17
- package/dist/types/column.d.ts.map +1 -1
- package/dist/types/column.js +3 -19
- package/dist/types/column.js.map +1 -1
- package/dist/types/db-context-def.d.ts +7 -7
- package/dist/types/db-context-def.d.ts.map +1 -1
- package/dist/types/query-def.d.ts +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 -7
- package/dist/utils/result-parser.js.map +1 -1
- package/package.json +3 -3
- package/src/db-context.ts +23 -20
- package/src/ddl/initialize.ts +4 -4
- package/src/ddl/relation-ddl.ts +1 -1
- package/src/ddl/table-ddl.ts +3 -3
- package/src/errors/db-transaction-error.ts +6 -4
- package/src/exec/executable.ts +5 -4
- package/src/exec/queryable.ts +31 -24
- package/src/expr/expr.ts +10 -4
- package/src/query-builder/base/expr-renderer-base.ts +2 -1
- package/src/query-builder/mssql/mssql-expr-renderer.ts +5 -5
- package/src/query-builder/mysql/mysql-expr-renderer.ts +2 -2
- package/src/query-builder/postgresql/postgresql-expr-renderer.ts +5 -5
- package/src/query-builder/postgresql/postgresql-query-builder.ts +4 -3
- package/src/schema/factory/column-builder.ts +3 -3
- package/src/schema/factory/relation-builder.ts +350 -346
- package/src/schema/table-builder.ts +209 -193
- package/src/schema/view-builder.ts +148 -143
- package/src/types/column.ts +7 -26
- package/src/types/db-context-def.ts +7 -7
- package/src/types/query-def.ts +1 -1
- 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
|
-
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
134
|
+
this._status = "connect";
|
|
132
135
|
|
|
133
136
|
try {
|
|
134
137
|
await this._executor.beginTransaction(isolationLevel);
|
|
135
|
-
this.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
400
|
+
relationDef: ForeignKeyBuilder<any>,
|
|
398
401
|
): QueryDef {
|
|
399
402
|
return relationDdl.getAddForeignKeyQueryDef(this, table, relationName, relationDef);
|
|
400
403
|
}
|
package/src/ddl/initialize.ts
CHANGED
|
@@ -131,7 +131,7 @@ export async function initialize(
|
|
|
131
131
|
*/
|
|
132
132
|
async function createAllObjects(
|
|
133
133
|
db: DbContextBase,
|
|
134
|
-
builders: (TableBuilder<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
|
|
191
|
+
): (TableBuilder<any, any> | ViewBuilder<any, any, any> | ProcedureBuilder<any, any>)[] {
|
|
192
192
|
const builders: (
|
|
193
|
-
| TableBuilder<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
|
|
200
|
+
builders.push(value[SD_BUILDER as keyof typeof value] as TableBuilder<any, any>);
|
|
201
201
|
}
|
|
202
202
|
}
|
|
203
203
|
|
package/src/ddl/relation-ddl.ts
CHANGED
|
@@ -33,7 +33,7 @@ export function getAddForeignKeyQueryDef(
|
|
|
33
33
|
db: DbContextBase,
|
|
34
34
|
table: QueryDefObjectName,
|
|
35
35
|
relationName: string,
|
|
36
|
-
relationDef: ForeignKeyBuilder<any
|
|
36
|
+
relationDef: ForeignKeyBuilder<any>,
|
|
37
37
|
): QueryDef {
|
|
38
38
|
const targetTable = relationDef.meta.targetFn();
|
|
39
39
|
const fkColumns = relationDef.meta.columns;
|
package/src/ddl/table-ddl.ts
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
36
|
+
/** 원본 DBMS 에러 (cause 체인으로 보존) */
|
|
37
|
+
cause?: Error,
|
|
36
38
|
) {
|
|
37
|
-
super(message);
|
|
39
|
+
super(cause as Error, message);
|
|
38
40
|
}
|
|
39
41
|
}
|
package/src/exec/executable.ts
CHANGED
|
@@ -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<
|
|
59
|
-
return this._db.executeDefs<
|
|
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
|
|
package/src/exec/queryable.ts
CHANGED
|
@@ -49,7 +49,7 @@ class JoinQueryable {
|
|
|
49
49
|
* @param table - 조인할 table
|
|
50
50
|
* @returns 조인된 Queryable
|
|
51
51
|
*/
|
|
52
|
-
from<T extends TableBuilder<any, any
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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.
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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
|
|
1576
|
-
?
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
:
|
|
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
|
|
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
|
|
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:
|
|
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
|
-
*
|
|
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 (
|
|
573
|
+
* @returns Position (0-based, -1 if not found; undefined if source is NULL)
|
|
574
574
|
*/
|
|
575
|
-
indexOf
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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?:
|
|
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
|
|
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
|
|
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
|
-
:
|
|
286
|
-
?
|
|
287
|
-
:
|
|
285
|
+
: "default" extends keyof M
|
|
286
|
+
? never
|
|
287
|
+
: K
|
|
288
288
|
: never;
|
|
289
289
|
}[keyof TBuilders];
|
|
290
290
|
|