@simplysm/orm-common 13.0.100 → 14.0.4
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 +90 -147
- package/dist/create-db-context.d.ts +10 -10
- package/dist/create-db-context.js +312 -276
- package/dist/create-db-context.js.map +1 -6
- package/dist/ddl/column-ddl.d.ts +4 -4
- package/dist/ddl/column-ddl.js +41 -35
- package/dist/ddl/column-ddl.js.map +1 -6
- package/dist/ddl/initialize.d.ts +17 -17
- package/dist/ddl/initialize.js +200 -142
- package/dist/ddl/initialize.js.map +1 -6
- package/dist/ddl/relation-ddl.d.ts +6 -6
- package/dist/ddl/relation-ddl.js +55 -48
- package/dist/ddl/relation-ddl.js.map +1 -6
- package/dist/ddl/schema-ddl.d.ts +4 -4
- package/dist/ddl/schema-ddl.js +21 -15
- package/dist/ddl/schema-ddl.js.map +1 -6
- package/dist/ddl/table-ddl.d.ts +20 -20
- package/dist/ddl/table-ddl.js +139 -93
- package/dist/ddl/table-ddl.js.map +1 -6
- package/dist/define-db-context.js +10 -13
- package/dist/define-db-context.js.map +1 -6
- package/dist/errors/db-transaction-error.d.ts +15 -15
- package/dist/errors/db-transaction-error.d.ts.map +1 -1
- package/dist/errors/db-transaction-error.js +53 -19
- package/dist/errors/db-transaction-error.js.map +1 -6
- package/dist/exec/executable.d.ts +23 -23
- package/dist/exec/executable.js +94 -40
- package/dist/exec/executable.js.map +1 -6
- package/dist/exec/queryable.d.ts +97 -97
- package/dist/exec/queryable.js +1310 -1204
- package/dist/exec/queryable.js.map +1 -6
- package/dist/exec/search-parser.d.ts +31 -31
- package/dist/exec/search-parser.d.ts.map +1 -1
- package/dist/exec/search-parser.js +158 -59
- package/dist/exec/search-parser.js.map +1 -6
- package/dist/expr/expr-unit.d.ts +4 -4
- package/dist/expr/expr-unit.js +24 -18
- package/dist/expr/expr-unit.js.map +1 -6
- package/dist/expr/expr.d.ts +108 -108
- package/dist/expr/expr.js +1872 -1844
- package/dist/expr/expr.js.map +1 -6
- package/dist/index.js +23 -1
- package/dist/index.js.map +1 -6
- package/dist/models/system-migration.js +7 -7
- package/dist/models/system-migration.js.map +1 -6
- package/dist/query-builder/base/expr-renderer-base.d.ts +10 -10
- package/dist/query-builder/base/expr-renderer-base.js +27 -21
- package/dist/query-builder/base/expr-renderer-base.js.map +1 -6
- package/dist/query-builder/base/query-builder-base.d.ts +21 -21
- package/dist/query-builder/base/query-builder-base.d.ts.map +1 -1
- package/dist/query-builder/base/query-builder-base.js +90 -80
- package/dist/query-builder/base/query-builder-base.js.map +1 -6
- package/dist/query-builder/mssql/mssql-expr-renderer.d.ts +5 -5
- package/dist/query-builder/mssql/mssql-expr-renderer.d.ts.map +1 -1
- package/dist/query-builder/mssql/mssql-expr-renderer.js +447 -420
- package/dist/query-builder/mssql/mssql-expr-renderer.js.map +1 -6
- package/dist/query-builder/mssql/mssql-query-builder.d.ts +2 -2
- package/dist/query-builder/mssql/mssql-query-builder.d.ts.map +1 -1
- package/dist/query-builder/mssql/mssql-query-builder.js +483 -443
- package/dist/query-builder/mssql/mssql-query-builder.js.map +1 -6
- package/dist/query-builder/mysql/mysql-expr-renderer.d.ts +5 -5
- package/dist/query-builder/mysql/mysql-expr-renderer.d.ts.map +1 -1
- package/dist/query-builder/mysql/mysql-expr-renderer.js +451 -419
- package/dist/query-builder/mysql/mysql-expr-renderer.js.map +1 -6
- package/dist/query-builder/mysql/mysql-query-builder.d.ts +10 -10
- package/dist/query-builder/mysql/mysql-query-builder.d.ts.map +1 -1
- package/dist/query-builder/mysql/mysql-query-builder.js +570 -479
- package/dist/query-builder/mysql/mysql-query-builder.js.map +1 -6
- package/dist/query-builder/postgresql/postgresql-expr-renderer.d.ts +5 -5
- package/dist/query-builder/postgresql/postgresql-expr-renderer.d.ts.map +1 -1
- package/dist/query-builder/postgresql/postgresql-expr-renderer.js +449 -422
- package/dist/query-builder/postgresql/postgresql-expr-renderer.js.map +1 -6
- package/dist/query-builder/postgresql/postgresql-query-builder.d.ts +8 -8
- package/dist/query-builder/postgresql/postgresql-query-builder.d.ts.map +1 -1
- package/dist/query-builder/postgresql/postgresql-query-builder.js +511 -460
- package/dist/query-builder/postgresql/postgresql-query-builder.js.map +1 -6
- package/dist/query-builder/query-builder.d.ts +1 -1
- package/dist/query-builder/query-builder.js +13 -13
- package/dist/query-builder/query-builder.js.map +1 -6
- package/dist/schema/factory/column-builder.d.ts +84 -84
- package/dist/schema/factory/column-builder.js +248 -185
- package/dist/schema/factory/column-builder.js.map +1 -6
- package/dist/schema/factory/index-builder.d.ts +38 -38
- package/dist/schema/factory/index-builder.js +144 -85
- package/dist/schema/factory/index-builder.js.map +1 -6
- package/dist/schema/factory/relation-builder.d.ts +99 -99
- package/dist/schema/factory/relation-builder.d.ts.map +1 -1
- package/dist/schema/factory/relation-builder.js +274 -136
- package/dist/schema/factory/relation-builder.js.map +1 -6
- package/dist/schema/procedure-builder.d.ts +51 -51
- package/dist/schema/procedure-builder.d.ts.map +1 -1
- package/dist/schema/procedure-builder.js +205 -131
- package/dist/schema/procedure-builder.js.map +1 -6
- package/dist/schema/table-builder.d.ts +55 -55
- package/dist/schema/table-builder.d.ts.map +1 -1
- package/dist/schema/table-builder.js +274 -205
- package/dist/schema/table-builder.js.map +1 -6
- package/dist/schema/view-builder.d.ts +44 -44
- package/dist/schema/view-builder.d.ts.map +1 -1
- package/dist/schema/view-builder.js +189 -116
- package/dist/schema/view-builder.js.map +1 -6
- package/dist/types/column.d.ts +21 -21
- package/dist/types/column.js +60 -30
- package/dist/types/column.js.map +1 -6
- package/dist/types/db-context-def.d.ts +9 -9
- package/dist/types/db-context-def.js +2 -1
- package/dist/types/db-context-def.js.map +1 -6
- package/dist/types/db.d.ts +47 -47
- package/dist/types/db.js +15 -5
- package/dist/types/db.js.map +1 -6
- package/dist/types/expr.d.ts +81 -81
- package/dist/types/expr.d.ts.map +1 -1
- package/dist/types/expr.js +3 -1
- package/dist/types/expr.js.map +1 -6
- package/dist/types/query-def.d.ts +46 -46
- package/dist/types/query-def.d.ts.map +1 -1
- package/dist/types/query-def.js +31 -24
- package/dist/types/query-def.js.map +1 -6
- package/dist/utils/result-parser.d.ts +11 -11
- package/dist/utils/result-parser.js +362 -221
- package/dist/utils/result-parser.js.map +1 -6
- package/docs/core.md +117 -145
- package/docs/expression.md +186 -203
- package/docs/query-builder.md +75 -42
- package/docs/queryable.md +189 -151
- package/docs/schema-builders.md +172 -283
- package/docs/types.md +229 -173
- package/package.json +7 -5
- package/src/create-db-context.ts +31 -31
- package/src/ddl/column-ddl.ts +4 -4
- package/src/ddl/initialize.ts +38 -38
- package/src/ddl/relation-ddl.ts +6 -6
- package/src/ddl/schema-ddl.ts +4 -4
- package/src/ddl/table-ddl.ts +24 -24
- package/src/errors/db-transaction-error.ts +13 -13
- package/src/exec/executable.ts +25 -25
- package/src/exec/queryable.ts +152 -152
- package/src/exec/search-parser.ts +50 -50
- package/src/expr/expr-unit.ts +4 -4
- package/src/expr/expr.ts +118 -118
- package/src/index.ts +8 -8
- package/src/models/system-migration.ts +1 -1
- package/src/query-builder/base/expr-renderer-base.ts +21 -21
- package/src/query-builder/base/query-builder-base.ts +33 -33
- package/src/query-builder/mssql/mssql-expr-renderer.ts +28 -28
- package/src/query-builder/mssql/mssql-query-builder.ts +37 -37
- package/src/query-builder/mysql/mysql-expr-renderer.ts +29 -29
- package/src/query-builder/mysql/mysql-query-builder.ts +70 -70
- package/src/query-builder/postgresql/postgresql-expr-renderer.ts +22 -22
- package/src/query-builder/postgresql/postgresql-query-builder.ts +54 -54
- package/src/query-builder/query-builder.ts +1 -1
- package/src/schema/factory/column-builder.ts +86 -86
- package/src/schema/factory/index-builder.ts +38 -38
- package/src/schema/factory/relation-builder.ts +102 -102
- package/src/schema/procedure-builder.ts +52 -52
- package/src/schema/table-builder.ts +56 -56
- package/src/schema/view-builder.ts +47 -47
- package/src/types/column.ts +24 -24
- package/src/types/db-context-def.ts +15 -15
- package/src/types/db.ts +50 -50
- package/src/types/expr.ts +103 -103
- package/src/types/query-def.ts +50 -50
- package/src/utils/result-parser.ts +88 -88
- package/docs/utilities.md +0 -27
- package/tests/db-context/create-db-context.spec.ts +0 -193
- package/tests/db-context/define-db-context.spec.ts +0 -17
- package/tests/ddl/basic.expected.ts +0 -341
- package/tests/ddl/basic.spec.ts +0 -557
- package/tests/ddl/column-builder.expected.ts +0 -310
- package/tests/ddl/column-builder.spec.ts +0 -525
- package/tests/ddl/index-builder.expected.ts +0 -38
- package/tests/ddl/index-builder.spec.ts +0 -148
- package/tests/ddl/procedure-builder.expected.ts +0 -52
- package/tests/ddl/procedure-builder.spec.ts +0 -128
- package/tests/ddl/relation-builder.expected.ts +0 -36
- package/tests/ddl/relation-builder.spec.ts +0 -171
- package/tests/ddl/table-builder.expected.ts +0 -113
- package/tests/ddl/table-builder.spec.ts +0 -399
- package/tests/ddl/view-builder.expected.ts +0 -38
- package/tests/ddl/view-builder.spec.ts +0 -116
- package/tests/dml/delete.expected.ts +0 -96
- package/tests/dml/delete.spec.ts +0 -127
- package/tests/dml/insert.expected.ts +0 -192
- package/tests/dml/insert.spec.ts +0 -210
- package/tests/dml/update.expected.ts +0 -176
- package/tests/dml/update.spec.ts +0 -222
- package/tests/dml/upsert.expected.ts +0 -215
- package/tests/dml/upsert.spec.ts +0 -190
- package/tests/errors/queryable-errors.spec.ts +0 -126
- package/tests/escape.spec.ts +0 -59
- package/tests/examples/pivot.expected.ts +0 -211
- package/tests/examples/pivot.spec.ts +0 -200
- package/tests/examples/sampling.expected.ts +0 -69
- package/tests/examples/sampling.spec.ts +0 -42
- package/tests/examples/unpivot.expected.ts +0 -120
- package/tests/examples/unpivot.spec.ts +0 -161
- package/tests/exec/search-parser.spec.ts +0 -267
- package/tests/executable/basic.expected.ts +0 -18
- package/tests/executable/basic.spec.ts +0 -54
- package/tests/expr/comparison.expected.ts +0 -282
- package/tests/expr/comparison.spec.ts +0 -334
- package/tests/expr/conditional.expected.ts +0 -134
- package/tests/expr/conditional.spec.ts +0 -249
- package/tests/expr/date.expected.ts +0 -332
- package/tests/expr/date.spec.ts +0 -459
- package/tests/expr/math.expected.ts +0 -62
- package/tests/expr/math.spec.ts +0 -59
- package/tests/expr/string.expected.ts +0 -218
- package/tests/expr/string.spec.ts +0 -300
- package/tests/expr/utility.expected.ts +0 -147
- package/tests/expr/utility.spec.ts +0 -155
- package/tests/select/basic.expected.ts +0 -322
- package/tests/select/basic.spec.ts +0 -433
- package/tests/select/filter.expected.ts +0 -357
- package/tests/select/filter.spec.ts +0 -954
- package/tests/select/group.expected.ts +0 -169
- package/tests/select/group.spec.ts +0 -159
- package/tests/select/join.expected.ts +0 -582
- package/tests/select/join.spec.ts +0 -692
- package/tests/select/order.expected.ts +0 -150
- package/tests/select/order.spec.ts +0 -140
- package/tests/select/recursive-cte.expected.ts +0 -244
- package/tests/select/recursive-cte.spec.ts +0 -514
- package/tests/select/result-meta.spec.ts +0 -270
- package/tests/select/subquery.expected.ts +0 -363
- package/tests/select/subquery.spec.ts +0 -441
- package/tests/select/view.expected.ts +0 -155
- package/tests/select/view.spec.ts +0 -235
- package/tests/select/window.expected.ts +0 -345
- package/tests/select/window.spec.ts +0 -433
- package/tests/setup/MockExecutor.ts +0 -18
- package/tests/setup/TestDbContext.ts +0 -59
- package/tests/setup/models/Company.ts +0 -13
- package/tests/setup/models/Employee.ts +0 -10
- package/tests/setup/models/MonthlySales.ts +0 -11
- package/tests/setup/models/Post.ts +0 -16
- package/tests/setup/models/Sales.ts +0 -10
- package/tests/setup/models/User.ts +0 -19
- package/tests/setup/procedure/GetAllUsers.ts +0 -9
- package/tests/setup/procedure/GetUserById.ts +0 -12
- package/tests/setup/test-utils.ts +0 -72
- package/tests/setup/views/ActiveUsers.ts +0 -8
- package/tests/setup/views/UserSummary.ts +0 -11
- package/tests/types/nullable-queryable-record.spec.ts +0 -97
- package/tests/utils/result-parser-perf.spec.ts +0 -143
- package/tests/utils/result-parser.spec.ts +0 -667
|
@@ -38,25 +38,25 @@ import { PostgresqlExprRenderer } from "./postgresql-expr-renderer";
|
|
|
38
38
|
/**
|
|
39
39
|
* PostgreSQL QueryBuilder
|
|
40
40
|
*
|
|
41
|
-
* PostgreSQL
|
|
42
|
-
* - OUTPUT:
|
|
43
|
-
* - TRUNCATE: RESTART IDENTITY
|
|
44
|
-
* - UPSERT: CTE
|
|
45
|
-
* - AUTO_INCREMENT: GENERATED BY DEFAULT AS IDENTITY (
|
|
46
|
-
* -
|
|
41
|
+
* PostgreSQL 고유 사항:
|
|
42
|
+
* - OUTPUT: RETURNING 절 사용 (네이티브 지원)
|
|
43
|
+
* - TRUNCATE: RESTART IDENTITY 옵션 필요
|
|
44
|
+
* - UPSERT: CTE 방식 (INSERT ... ON CONFLICT는 단일 유니크 제약조건만 지원)
|
|
45
|
+
* - AUTO_INCREMENT: GENERATED BY DEFAULT AS IDENTITY (명시적 값 할당 가능)
|
|
46
|
+
* - FK 추가 시 별도 인덱스 생성 필요 (MySQL과 다름)
|
|
47
47
|
*/
|
|
48
48
|
export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
49
49
|
protected expr = new PostgresqlExprRenderer((def) => this.select(def).sql);
|
|
50
50
|
|
|
51
51
|
//#region ========== Utilities ==========
|
|
52
52
|
|
|
53
|
-
/**
|
|
53
|
+
/** 테이블명 렌더링 (PostgreSQL: database는 연결에서 처리, schema.table만 사용) */
|
|
54
54
|
protected tableName(obj: QueryDefObjectName): string {
|
|
55
55
|
const schema = obj.schema ?? "public";
|
|
56
56
|
return `${this.expr.wrap(schema)}.${this.expr.wrap(obj.name)}`;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
/**
|
|
59
|
+
/** LIMIT...OFFSET 절 렌더링 */
|
|
60
60
|
protected renderLimit(limit: [number, number] | undefined, top: number | undefined): string {
|
|
61
61
|
if (limit != null) {
|
|
62
62
|
const [offset, count] = limit;
|
|
@@ -71,15 +71,15 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
71
71
|
protected renderJoin(join: SelectQueryDefJoin): string {
|
|
72
72
|
const alias = this.expr.wrap(join.as);
|
|
73
73
|
|
|
74
|
-
//
|
|
74
|
+
// LATERAL JOIN이 필요한지 감지
|
|
75
75
|
if (this.needsLateral(join)) {
|
|
76
|
-
//
|
|
77
|
-
//
|
|
76
|
+
// from이 배열(UNION ALL)이면 renderFrom(join.from) 사용,
|
|
77
|
+
// 그 외(orderBy, top, select 등)이면 renderFrom(join)으로 서브쿼리 생성
|
|
78
78
|
const from = Array.isArray(join.from) ? this.renderFrom(join.from) : this.renderFrom(join);
|
|
79
79
|
return ` LEFT OUTER JOIN LATERAL ${from} AS ${alias} ON TRUE`;
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
//
|
|
82
|
+
// 일반 JOIN
|
|
83
83
|
const from = this.renderFrom(join.from);
|
|
84
84
|
const where =
|
|
85
85
|
join.where != null && join.where.length > 0
|
|
@@ -140,7 +140,7 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
140
140
|
// LIMIT
|
|
141
141
|
sql += this.renderLimit(def.limit, def.top);
|
|
142
142
|
|
|
143
|
-
// LOCK (FOR UPDATE
|
|
143
|
+
// LOCK (끝에 FOR UPDATE 추가)
|
|
144
144
|
if (def.lock) {
|
|
145
145
|
sql += " FOR UPDATE";
|
|
146
146
|
}
|
|
@@ -156,7 +156,7 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
156
156
|
const table = this.tableName(def.table);
|
|
157
157
|
|
|
158
158
|
if (def.records.length === 0) {
|
|
159
|
-
throw new Error("INSERT
|
|
159
|
+
throw new Error("INSERT에는 최소 1개의 레코드가 필요합니다.");
|
|
160
160
|
}
|
|
161
161
|
|
|
162
162
|
const columns = Object.keys(def.records[0]);
|
|
@@ -169,14 +169,14 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
169
169
|
|
|
170
170
|
let sql = `INSERT INTO ${table} (${colList})`;
|
|
171
171
|
|
|
172
|
-
// GENERATED BY DEFAULT AS IDENTITY
|
|
173
|
-
// overrideIdentity
|
|
174
|
-
// PostgreSQL
|
|
175
|
-
// (
|
|
172
|
+
// GENERATED BY DEFAULT AS IDENTITY이므로 명시적 값 삽입에 추가 구문 불필요
|
|
173
|
+
// overrideIdentity 파라미터는 MSSQL (SET IDENTITY_INSERT) 호환성을 위해 유지하지만
|
|
174
|
+
// PostgreSQL의 GENERATED BY DEFAULT는 자동으로 명시적 값을 허용
|
|
175
|
+
// (참고: GENERATED ALWAYS를 사용했다면 OVERRIDING SYSTEM VALUE가 필요)
|
|
176
176
|
|
|
177
177
|
sql += ` VALUES ${valuesList.join(", ")}`;
|
|
178
178
|
|
|
179
|
-
// RETURNING (PostgreSQL
|
|
179
|
+
// RETURNING (PostgreSQL 네이티브 지원)
|
|
180
180
|
if (def.output != null) {
|
|
181
181
|
const outputCols = def.output.columns.map((c) => this.expr.wrap(c)).join(", ");
|
|
182
182
|
sql += ` RETURNING ${outputCols}`;
|
|
@@ -192,7 +192,7 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
192
192
|
const colList = columns.map((c) => this.expr.wrap(c)).join(", ");
|
|
193
193
|
const values = columns.map((c) => this.expr.escapeValue(def.record[c])).join(", ");
|
|
194
194
|
|
|
195
|
-
//
|
|
195
|
+
// existsSelectQuery를 SELECT 1 AS _로 렌더링
|
|
196
196
|
const existsQuerySql = this.select({
|
|
197
197
|
...def.existsSelectQuery,
|
|
198
198
|
select: { _: { type: "value", value: 1 } },
|
|
@@ -200,7 +200,7 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
200
200
|
|
|
201
201
|
let sql = `INSERT INTO ${table} (${colList}) SELECT ${values} WHERE NOT EXISTS (${existsQuerySql})`;
|
|
202
202
|
|
|
203
|
-
// RETURNING
|
|
203
|
+
// RETURNING 절
|
|
204
204
|
if (def.output != null) {
|
|
205
205
|
const outputCols = def.output.columns.map((c) => this.expr.wrap(c)).join(", ");
|
|
206
206
|
sql += ` RETURNING ${outputCols}`;
|
|
@@ -213,7 +213,7 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
213
213
|
const table = this.tableName(def.table);
|
|
214
214
|
const selectSql = this.select(def.recordsSelectQuery).sql;
|
|
215
215
|
|
|
216
|
-
//
|
|
216
|
+
// INSERT INTO SELECT에서 column 추출
|
|
217
217
|
const selectDef = def.recordsSelectQuery;
|
|
218
218
|
const colList =
|
|
219
219
|
selectDef.select != null
|
|
@@ -224,7 +224,7 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
224
224
|
|
|
225
225
|
let sql = `INSERT INTO ${table} (${colList}) ${selectSql}`;
|
|
226
226
|
|
|
227
|
-
// RETURNING
|
|
227
|
+
// RETURNING 절
|
|
228
228
|
if (def.output != null) {
|
|
229
229
|
const outputCols = def.output.columns.map((c) => this.expr.wrap(c)).join(", ");
|
|
230
230
|
sql += ` RETURNING ${outputCols}`;
|
|
@@ -248,7 +248,7 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
248
248
|
|
|
249
249
|
let sql = `UPDATE ${table} AS ${alias} SET ${setParts.join(", ")}`;
|
|
250
250
|
|
|
251
|
-
// PostgreSQL:
|
|
251
|
+
// PostgreSQL: JOIN은 FROM 절로 처리
|
|
252
252
|
if (def.joins != null && def.joins.length > 0) {
|
|
253
253
|
const joinTables = def.joins.map((j) => {
|
|
254
254
|
const from = this.renderFrom(j.from);
|
|
@@ -256,7 +256,7 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
256
256
|
});
|
|
257
257
|
sql += ` FROM ${joinTables.join(", ")}`;
|
|
258
258
|
|
|
259
|
-
//
|
|
259
|
+
// JOIN ON 조건을 WHERE에 추가
|
|
260
260
|
const joinConditions = def.joins
|
|
261
261
|
.filter((j) => j.where != null && j.where.length > 0)
|
|
262
262
|
.map((j) => this.expr.renderWhere(j.where!));
|
|
@@ -273,7 +273,7 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
273
273
|
sql += this.renderWhere(def.where);
|
|
274
274
|
}
|
|
275
275
|
|
|
276
|
-
// RETURNING
|
|
276
|
+
// RETURNING 절
|
|
277
277
|
if (def.output != null) {
|
|
278
278
|
const outputCols = def.output.columns.map((c) => `${alias}.${this.expr.wrap(c)}`).join(", ");
|
|
279
279
|
sql += ` RETURNING ${outputCols}`;
|
|
@@ -292,7 +292,7 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
292
292
|
|
|
293
293
|
let sql = `DELETE FROM ${table} AS ${alias}`;
|
|
294
294
|
|
|
295
|
-
// PostgreSQL:
|
|
295
|
+
// PostgreSQL: JOIN은 USING 절로 처리
|
|
296
296
|
if (def.joins != null && def.joins.length > 0) {
|
|
297
297
|
const joinTables = def.joins.map((j) => {
|
|
298
298
|
const from = this.renderFrom(j.from);
|
|
@@ -300,7 +300,7 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
300
300
|
});
|
|
301
301
|
sql += ` USING ${joinTables.join(", ")}`;
|
|
302
302
|
|
|
303
|
-
//
|
|
303
|
+
// JOIN ON 조건을 WHERE에 추가
|
|
304
304
|
const joinConditions = def.joins
|
|
305
305
|
.filter((j) => j.where != null && j.where.length > 0)
|
|
306
306
|
.map((j) => this.expr.renderWhere(j.where!));
|
|
@@ -317,7 +317,7 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
317
317
|
sql += this.renderWhere(def.where);
|
|
318
318
|
}
|
|
319
319
|
|
|
320
|
-
// RETURNING (PostgreSQL:
|
|
320
|
+
// RETURNING (PostgreSQL: DELETE에서도 지원)
|
|
321
321
|
if (def.output != null) {
|
|
322
322
|
const outputCols = def.output.columns.map((c) => this.expr.wrap(c)).join(", ");
|
|
323
323
|
sql += ` RETURNING ${outputCols}`;
|
|
@@ -331,31 +331,31 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
331
331
|
//#region ========== DML - UPSERT ==========
|
|
332
332
|
|
|
333
333
|
protected upsert(def: UpsertQueryDef): QueryBuildResult {
|
|
334
|
-
// PostgreSQL: CTE
|
|
334
|
+
// PostgreSQL: CTE 방식 (ON CONFLICT는 단일 유니크 제약조건만 지원하므로 범용성을 위해 CTE 사용)
|
|
335
335
|
const table = this.tableName(def.table);
|
|
336
336
|
const alias = this.expr.wrap(def.existsSelectQuery.as);
|
|
337
337
|
|
|
338
|
-
// UPDATE SET
|
|
338
|
+
// UPDATE SET 부분
|
|
339
339
|
const updateSetParts = Object.entries(def.updateRecord).map(
|
|
340
340
|
([col, e]) => `${this.expr.wrap(col)} = ${this.expr.render(e)}`,
|
|
341
341
|
);
|
|
342
342
|
|
|
343
|
-
// INSERT
|
|
343
|
+
// INSERT 부분
|
|
344
344
|
const insertColumns = Object.keys(def.insertRecord);
|
|
345
345
|
const insertColList = insertColumns.map((c) => this.expr.wrap(c)).join(", ");
|
|
346
346
|
const insertValues = insertColumns.map((c) => this.expr.render(def.insertRecord[c])).join(", ");
|
|
347
347
|
|
|
348
|
-
// WHERE
|
|
348
|
+
// WHERE 조건
|
|
349
349
|
const whereCondition =
|
|
350
350
|
def.existsSelectQuery.where != null && def.existsSelectQuery.where.length > 0
|
|
351
351
|
? this.expr.renderWhere(def.existsSelectQuery.where)
|
|
352
352
|
: "TRUE";
|
|
353
353
|
|
|
354
|
-
// OUTPUT column
|
|
354
|
+
// OUTPUT column 정의
|
|
355
355
|
const outputCols =
|
|
356
356
|
def.output != null ? def.output.columns.map((c) => this.expr.wrap(c)).join(", ") : "*";
|
|
357
357
|
|
|
358
|
-
// CTE
|
|
358
|
+
// CTE 기반 UPSERT
|
|
359
359
|
let sql = `WITH matched AS (\n`;
|
|
360
360
|
sql += ` SELECT ${alias}.* FROM ${table} AS ${alias} WHERE ${whereCondition}\n`;
|
|
361
361
|
sql += `),\n`;
|
|
@@ -385,7 +385,7 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
385
385
|
const colDefs = def.columns.map((col) => {
|
|
386
386
|
let colSql = `${this.expr.wrap(col.name)} ${this.expr.renderDataType(col.dataType)}`;
|
|
387
387
|
|
|
388
|
-
// nullable: true → NULL,
|
|
388
|
+
// nullable: true → NULL, 아니면 → NOT NULL
|
|
389
389
|
if (col.nullable === true) {
|
|
390
390
|
colSql += " NULL";
|
|
391
391
|
} else {
|
|
@@ -403,7 +403,7 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
403
403
|
return colSql;
|
|
404
404
|
});
|
|
405
405
|
|
|
406
|
-
//
|
|
406
|
+
// CONSTRAINT 이름이 포함된 Primary Key
|
|
407
407
|
if (def.primaryKey != null && def.primaryKey.length > 0) {
|
|
408
408
|
const pkCols = def.primaryKey.map((c) => this.expr.wrap(c)).join(", ");
|
|
409
409
|
const pkName = this.expr.wrap(`PK_${def.table.name}`);
|
|
@@ -424,7 +424,7 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
424
424
|
}
|
|
425
425
|
|
|
426
426
|
protected truncate(def: TruncateQueryDef): QueryBuildResult {
|
|
427
|
-
// PostgreSQL:
|
|
427
|
+
// PostgreSQL: RESTART IDENTITY로 시퀀스 초기화
|
|
428
428
|
return { sql: `TRUNCATE TABLE ${this.tableName(def.table)} RESTART IDENTITY` };
|
|
429
429
|
}
|
|
430
430
|
|
|
@@ -466,22 +466,22 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
466
466
|
const table = this.tableName(def.table);
|
|
467
467
|
const col = def.column;
|
|
468
468
|
|
|
469
|
-
// PostgreSQL: ALTER COLUMN
|
|
469
|
+
// PostgreSQL: ALTER COLUMN은 여러 ALTER 문이 필요
|
|
470
470
|
const parts: string[] = [];
|
|
471
471
|
|
|
472
|
-
//
|
|
472
|
+
// TYPE 변경
|
|
473
473
|
parts.push(
|
|
474
474
|
`ALTER COLUMN ${this.expr.wrap(col.name)} TYPE ${this.expr.renderDataType(col.dataType)}`,
|
|
475
475
|
);
|
|
476
476
|
|
|
477
|
-
//
|
|
477
|
+
// NULL 제약조건 변경
|
|
478
478
|
if (col.nullable === false) {
|
|
479
479
|
parts.push(`ALTER COLUMN ${this.expr.wrap(col.name)} SET NOT NULL`);
|
|
480
480
|
} else {
|
|
481
481
|
parts.push(`ALTER COLUMN ${this.expr.wrap(col.name)} DROP NOT NULL`);
|
|
482
482
|
}
|
|
483
483
|
|
|
484
|
-
//
|
|
484
|
+
// DEFAULT 변경
|
|
485
485
|
if (col.default !== undefined) {
|
|
486
486
|
parts.push(
|
|
487
487
|
`ALTER COLUMN ${this.expr.wrap(col.name)} SET DEFAULT ${this.expr.escapeValue(col.default)}`,
|
|
@@ -526,7 +526,7 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
526
526
|
|
|
527
527
|
let sql = `ALTER TABLE ${table} ADD CONSTRAINT ${this.expr.wrap(fk.name)} FOREIGN KEY (${fkCols}) REFERENCES ${targetTable} (${targetCols})`;
|
|
528
528
|
|
|
529
|
-
// PostgreSQL:
|
|
529
|
+
// PostgreSQL: FK에 대한 별도 인덱스 생성 필요
|
|
530
530
|
const idxName = `IDX_${def.table.name}_${fk.name.replace(/^FK_/, "")}`;
|
|
531
531
|
sql += `;\nCREATE INDEX ${this.expr.wrap(idxName)} ON ${table} (${fkCols});`;
|
|
532
532
|
|
|
@@ -548,7 +548,7 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
548
548
|
}
|
|
549
549
|
|
|
550
550
|
protected dropIndex(def: DropIndexQueryDef): QueryBuildResult {
|
|
551
|
-
// PostgreSQL:
|
|
551
|
+
// PostgreSQL: 인덱스는 스키마 수준에서 고유하므로 테이블명은 불필요하지만 스키마 지정 필요
|
|
552
552
|
const schema = def.table.schema ?? "public";
|
|
553
553
|
return { sql: `DROP INDEX ${this.expr.wrap(schema)}.${this.expr.wrap(def.index)}` };
|
|
554
554
|
}
|
|
@@ -570,7 +570,7 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
570
570
|
protected createProc(def: CreateProcQueryDef): QueryBuildResult {
|
|
571
571
|
const proc = this.tableName(def.procedure);
|
|
572
572
|
|
|
573
|
-
//
|
|
573
|
+
// 파라미터 처리
|
|
574
574
|
const paramList =
|
|
575
575
|
def.params
|
|
576
576
|
?.map((p) => {
|
|
@@ -582,7 +582,7 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
582
582
|
})
|
|
583
583
|
.join(", ") ?? "";
|
|
584
584
|
|
|
585
|
-
//
|
|
585
|
+
// 반환 타입 처리
|
|
586
586
|
let returnClause = "VOID";
|
|
587
587
|
if (def.returns && def.returns.length > 0) {
|
|
588
588
|
const returnFields = def.returns
|
|
@@ -625,9 +625,9 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
625
625
|
|
|
626
626
|
protected clearSchema(def: ClearSchemaQueryDef): QueryBuildResult {
|
|
627
627
|
const schemaName = def.schema ?? "public";
|
|
628
|
-
// SQL
|
|
628
|
+
// SQL 인젝션 방지: schema 이름 유효성 검사
|
|
629
629
|
if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(schemaName)) {
|
|
630
|
-
throw new Error(
|
|
630
|
+
throw new Error(`잘못된 schema 이름: ${schemaName}`);
|
|
631
631
|
}
|
|
632
632
|
const schema = this.expr.escapeString(schemaName);
|
|
633
633
|
return {
|
|
@@ -636,7 +636,7 @@ DO $$
|
|
|
636
636
|
DECLARE
|
|
637
637
|
r RECORD;
|
|
638
638
|
BEGIN
|
|
639
|
-
--
|
|
639
|
+
-- FK 제약조건 삭제
|
|
640
640
|
FOR r IN (SELECT conname, conrelid::regclass AS tablename
|
|
641
641
|
FROM pg_constraint
|
|
642
642
|
WHERE contype = 'f' AND connamespace = '${schema}'::regnamespace)
|
|
@@ -644,19 +644,19 @@ BEGIN
|
|
|
644
644
|
EXECUTE 'ALTER TABLE ' || r.tablename || ' DROP CONSTRAINT ' || quote_ident(r.conname);
|
|
645
645
|
END LOOP;
|
|
646
646
|
|
|
647
|
-
--
|
|
647
|
+
-- 테이블 삭제
|
|
648
648
|
FOR r IN (SELECT tablename FROM pg_tables WHERE schemaname = '${schema}')
|
|
649
649
|
LOOP
|
|
650
650
|
EXECUTE 'DROP TABLE IF EXISTS ' || quote_ident(r.tablename) || ' CASCADE';
|
|
651
651
|
END LOOP;
|
|
652
652
|
|
|
653
|
-
--
|
|
653
|
+
-- 뷰 삭제
|
|
654
654
|
FOR r IN (SELECT viewname FROM pg_views WHERE schemaname = '${schema}')
|
|
655
655
|
LOOP
|
|
656
656
|
EXECUTE 'DROP VIEW IF EXISTS ' || quote_ident(r.viewname) || ' CASCADE';
|
|
657
657
|
END LOOP;
|
|
658
658
|
|
|
659
|
-
--
|
|
659
|
+
-- 함수 삭제
|
|
660
660
|
FOR r IN (SELECT proname, pg_get_function_identity_arguments(oid) AS args
|
|
661
661
|
FROM pg_proc WHERE pronamespace = '${schema}'::regnamespace)
|
|
662
662
|
LOOP
|
|
@@ -675,10 +675,10 @@ END $$`,
|
|
|
675
675
|
protected switchFk(def: SwitchFkQueryDef): QueryBuildResult {
|
|
676
676
|
const table = this.tableName(def.table);
|
|
677
677
|
if (def.enabled) {
|
|
678
|
-
// PostgreSQL:
|
|
678
|
+
// PostgreSQL: 테이블의 모든 FK 트리거 활성화
|
|
679
679
|
return { sql: `ALTER TABLE ${table} ENABLE TRIGGER ALL` };
|
|
680
680
|
}
|
|
681
|
-
// PostgreSQL:
|
|
681
|
+
// PostgreSQL: 테이블의 모든 FK 트리거 비활성화
|
|
682
682
|
return { sql: `ALTER TABLE ${table} DISABLE TRIGGER ALL` };
|
|
683
683
|
}
|
|
684
684
|
|
|
@@ -5,7 +5,7 @@ import { MysqlQueryBuilder } from "./mysql/mysql-query-builder";
|
|
|
5
5
|
import { PostgresqlQueryBuilder } from "./postgresql/postgresql-query-builder";
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
8
|
+
* 주어진 Dialect에 맞는 QueryBuilder 인스턴스 생성
|
|
9
9
|
*/
|
|
10
10
|
export function createQueryBuilder(dialect: Dialect): QueryBuilderBase {
|
|
11
11
|
switch (dialect) {
|