@simplysm/orm-common 14.0.1 → 14.0.5
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 +163 -0
- package/dist/exec/queryable.js +18 -18
- package/dist/exec/queryable.js.map +1 -1
- package/dist/expr/expr.d.ts +102 -102
- package/dist/expr/expr.js +105 -105
- package/dist/expr/expr.js.map +1 -1
- package/dist/query-builder/mssql/mssql-expr-renderer.d.ts +1 -1
- package/dist/query-builder/mssql/mssql-expr-renderer.d.ts.map +1 -1
- package/dist/query-builder/mssql/mssql-expr-renderer.js +17 -17
- package/dist/query-builder/mssql/mssql-expr-renderer.js.map +1 -1
- 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 +26 -26
- package/dist/query-builder/mssql/mssql-query-builder.js.map +1 -1
- package/dist/query-builder/mysql/mysql-expr-renderer.d.ts +1 -1
- package/dist/query-builder/mysql/mysql-expr-renderer.d.ts.map +1 -1
- package/dist/query-builder/mysql/mysql-expr-renderer.js +14 -14
- package/dist/query-builder/mysql/mysql-expr-renderer.js.map +1 -1
- 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 +67 -67
- package/dist/query-builder/mysql/mysql-query-builder.js.map +1 -1
- package/dist/query-builder/postgresql/postgresql-expr-renderer.d.ts +1 -1
- package/dist/query-builder/postgresql/postgresql-expr-renderer.d.ts.map +1 -1
- package/dist/query-builder/postgresql/postgresql-expr-renderer.js +13 -13
- package/dist/query-builder/postgresql/postgresql-expr-renderer.js.map +1 -1
- 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 +47 -47
- package/dist/query-builder/postgresql/postgresql-query-builder.js.map +1 -1
- package/dist/schema/factory/relation-builder.d.ts +8 -8
- package/dist/schema/factory/relation-builder.js +9 -9
- package/dist/schema/factory/relation-builder.js.map +1 -1
- package/dist/schema/view-builder.js +2 -2
- package/dist/schema/view-builder.js.map +1 -1
- package/dist/types/column.d.ts +21 -21
- package/dist/types/column.js +5 -5
- package/dist/utils/result-parser.d.ts +11 -11
- package/dist/utils/result-parser.js +48 -48
- package/dist/utils/result-parser.js.map +1 -1
- package/docs/core.md +157 -0
- package/docs/expression.md +220 -0
- package/docs/query-builder.md +150 -0
- package/docs/queryable.md +261 -0
- package/docs/schema-builders.md +294 -0
- package/docs/types.md +520 -0
- package/package.json +7 -3
- package/src/exec/queryable.ts +18 -18
- package/src/expr/expr.ts +105 -105
- package/src/query-builder/mssql/mssql-expr-renderer.ts +17 -17
- package/src/query-builder/mssql/mssql-query-builder.ts +26 -26
- package/src/query-builder/mysql/mysql-expr-renderer.ts +14 -14
- package/src/query-builder/mysql/mysql-query-builder.ts +67 -67
- package/src/query-builder/postgresql/postgresql-expr-renderer.ts +13 -13
- package/src/query-builder/postgresql/postgresql-query-builder.ts +47 -47
- package/src/schema/factory/relation-builder.ts +9 -9
- package/src/schema/view-builder.ts +2 -2
- package/src/types/column.ts +23 -23
- package/src/utils/result-parser.ts +49 -49
|
@@ -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
|
}
|
|
@@ -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
|
|
@@ -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
|
|
|
@@ -139,7 +139,7 @@ export class ForeignKeyTargetBuilder<
|
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
// ============================================
|
|
142
|
-
// RelationKeyBuilder (
|
|
142
|
+
// RelationKeyBuilder (FK와 동일하지만 DB에 FK를 등록하지 않음)
|
|
143
143
|
// ============================================
|
|
144
144
|
|
|
145
145
|
/**
|
|
@@ -153,15 +153,15 @@ export class ForeignKeyTargetBuilder<
|
|
|
153
153
|
*
|
|
154
154
|
* @example
|
|
155
155
|
* ```typescript
|
|
156
|
-
* //
|
|
156
|
+
* // View에서 Table로의 관계 정의
|
|
157
157
|
* const UserSummary = View("UserSummary")
|
|
158
158
|
* .query((db: MyDb) => db.user().select(...))
|
|
159
159
|
* .relations((r) => ({
|
|
160
|
-
* // View → Table (
|
|
160
|
+
* // View → Table (FK 미생성)
|
|
161
161
|
* company: r.relationKey(["companyId"], () => Company),
|
|
162
162
|
* }));
|
|
163
163
|
*
|
|
164
|
-
* //
|
|
164
|
+
* // FK 없는 Table 관계 정의
|
|
165
165
|
* const Report = Table("Report")
|
|
166
166
|
* .columns((c) => ({ userId: c.bigint() }))
|
|
167
167
|
* .relations((r) => ({
|
|
@@ -216,7 +216,7 @@ export class RelationKeyBuilder<
|
|
|
216
216
|
* const Company = Table("Company")
|
|
217
217
|
* .columns((c) => ({ id: c.bigint() }))
|
|
218
218
|
* .relations((r) => ({
|
|
219
|
-
* //
|
|
219
|
+
* // 역참조 (FK 미생성)
|
|
220
220
|
* employees: r.relationKeyTarget(() => UserSummary, "company"),
|
|
221
221
|
* }));
|
|
222
222
|
* ```
|
|
@@ -321,21 +321,21 @@ type RelationRkFactory<
|
|
|
321
321
|
*
|
|
322
322
|
* @example
|
|
323
323
|
* ```typescript
|
|
324
|
-
* // Table -
|
|
324
|
+
* // Table - FK와 RelationKey 모두 사용 가능
|
|
325
325
|
* const Post = Table("Post")
|
|
326
326
|
* .columns((c) => ({
|
|
327
327
|
* id: c.bigint(),
|
|
328
328
|
* authorId: c.bigint(),
|
|
329
329
|
* }))
|
|
330
330
|
* .relations((r) => ({
|
|
331
|
-
* author: r.foreignKey(["authorId"], () => User), // FK
|
|
331
|
+
* author: r.foreignKey(["authorId"], () => User), // FK 생성
|
|
332
332
|
* }));
|
|
333
333
|
*
|
|
334
|
-
* // View -
|
|
334
|
+
* // View - RelationKey만 사용 가능
|
|
335
335
|
* const UserSummary = View("UserSummary")
|
|
336
336
|
* .query(...)
|
|
337
337
|
* .relations((r) => ({
|
|
338
|
-
* posts: r.relationKeyTarget(() => Post, "author"), //
|
|
338
|
+
* posts: r.relationKeyTarget(() => Post, "author"), // FK 미생성
|
|
339
339
|
* }));
|
|
340
340
|
* ```
|
|
341
341
|
*/
|
|
@@ -169,8 +169,8 @@ export class ViewBuilder<
|
|
|
169
169
|
relations<T extends RelationBuilderRecord>(
|
|
170
170
|
fn: (r: ReturnType<typeof createRelationFactory<this, keyof TData & string>>) => T,
|
|
171
171
|
): ViewBuilder<TDbContext, TData & InferDeepRelations<T>, TRelations> {
|
|
172
|
-
//
|
|
173
|
-
//
|
|
172
|
+
// TypeScript 제네릭 타입 추론 한계로 인해 캐스팅이 불가피
|
|
173
|
+
// TRelations 타입 파라미터와 새로 생성된 관계 타입 T 간의 타입 불일치 해결
|
|
174
174
|
return new ViewBuilder({
|
|
175
175
|
...this.meta,
|
|
176
176
|
relations: fn(createRelationFactory<this, keyof TData & string>(() => this)),
|
package/src/types/column.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { DateOnly, DateTime, Time, Uuid, type Bytes } from "@simplysm/core-common";
|
|
2
2
|
|
|
3
3
|
// ============================================
|
|
4
|
-
// DataType (SQL
|
|
4
|
+
// DataType (SQL 타입 정의)
|
|
5
5
|
// ============================================
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
* SQL
|
|
8
|
+
* SQL 데이터 타입 정의
|
|
9
9
|
*
|
|
10
|
-
* DBMS
|
|
10
|
+
* DBMS 매핑:
|
|
11
11
|
* - `int`: INT (4 bytes)
|
|
12
12
|
* - `bigint`: BIGINT (8 bytes)
|
|
13
13
|
* - `float`: FLOAT/REAL (4 bytes)
|
|
@@ -47,13 +47,13 @@ export type DataType =
|
|
|
47
47
|
| { type: "uuid" };
|
|
48
48
|
|
|
49
49
|
// ============================================
|
|
50
|
-
// ColumnPrimitive (TypeScript
|
|
50
|
+
// ColumnPrimitive (TypeScript 타입)
|
|
51
51
|
// ============================================
|
|
52
52
|
|
|
53
53
|
/**
|
|
54
|
-
* Column
|
|
54
|
+
* Column 원시 타입 매핑
|
|
55
55
|
*
|
|
56
|
-
* TypeScript
|
|
56
|
+
* TypeScript 타입 이름 (문자열) → 실제 TypeScript 타입 매핑
|
|
57
57
|
*
|
|
58
58
|
* @example
|
|
59
59
|
* ```typescript
|
|
@@ -73,7 +73,7 @@ export type ColumnPrimitiveMap = {
|
|
|
73
73
|
};
|
|
74
74
|
|
|
75
75
|
/**
|
|
76
|
-
* Column
|
|
76
|
+
* Column 원시 타입 이름 (문자열)
|
|
77
77
|
*
|
|
78
78
|
* @example
|
|
79
79
|
* ```typescript
|
|
@@ -84,9 +84,9 @@ export type ColumnPrimitiveMap = {
|
|
|
84
84
|
export type ColumnPrimitiveStr = keyof ColumnPrimitiveMap;
|
|
85
85
|
|
|
86
86
|
/**
|
|
87
|
-
*
|
|
87
|
+
* Column에 저장 가능한 모든 원시 타입
|
|
88
88
|
*
|
|
89
|
-
* undefined
|
|
89
|
+
* undefined는 NULL을 나타냄
|
|
90
90
|
*/
|
|
91
91
|
export type ColumnPrimitive = ColumnPrimitiveMap[ColumnPrimitiveStr] | undefined;
|
|
92
92
|
|
|
@@ -95,7 +95,7 @@ export type ColumnPrimitive = ColumnPrimitiveMap[ColumnPrimitiveStr] | undefined
|
|
|
95
95
|
// ============================================
|
|
96
96
|
|
|
97
97
|
/**
|
|
98
|
-
* SQL DataType → TypeScript
|
|
98
|
+
* SQL DataType → TypeScript 타입 이름 매핑
|
|
99
99
|
*
|
|
100
100
|
* @example
|
|
101
101
|
* ```typescript
|
|
@@ -121,7 +121,7 @@ export const dataTypeStrToColumnPrimitiveStr = {
|
|
|
121
121
|
};
|
|
122
122
|
|
|
123
123
|
/**
|
|
124
|
-
* TypeScript
|
|
124
|
+
* DataType으로부터 TypeScript 타입 추론
|
|
125
125
|
*
|
|
126
126
|
* @template T - DataType
|
|
127
127
|
*
|
|
@@ -135,11 +135,11 @@ export type InferColumnPrimitiveFromDataType<TDataType extends DataType> =
|
|
|
135
135
|
ColumnPrimitiveMap[(typeof dataTypeStrToColumnPrimitiveStr)[TDataType["type"]]];
|
|
136
136
|
|
|
137
137
|
/**
|
|
138
|
-
*
|
|
138
|
+
* 런타임 값에서 ColumnPrimitiveStr 추론
|
|
139
139
|
*
|
|
140
|
-
* @param value - Column
|
|
141
|
-
* @returns ColumnPrimitiveStr
|
|
142
|
-
* @throws
|
|
140
|
+
* @param value - Column 값
|
|
141
|
+
* @returns ColumnPrimitiveStr 타입 이름
|
|
142
|
+
* @throws 값 타입이 알 수 없을 때 Error
|
|
143
143
|
*
|
|
144
144
|
* @example
|
|
145
145
|
* ```typescript
|
|
@@ -165,16 +165,16 @@ export function inferColumnPrimitiveStr(value: ColumnPrimitive): ColumnPrimitive
|
|
|
165
165
|
// ============================================
|
|
166
166
|
|
|
167
167
|
/**
|
|
168
|
-
* Column
|
|
168
|
+
* Column 메타데이터
|
|
169
169
|
*
|
|
170
|
-
*
|
|
170
|
+
* ColumnBuilder에서 생성되어 TableBuilder에 전달됨
|
|
171
171
|
*
|
|
172
|
-
* @property type - TypeScript
|
|
173
|
-
* @property dataType - SQL
|
|
174
|
-
* @property autoIncrement -
|
|
175
|
-
* @property nullable -
|
|
176
|
-
* @property default -
|
|
177
|
-
* @property description - Column
|
|
172
|
+
* @property type - TypeScript 타입 이름 (ColumnPrimitiveStr)
|
|
173
|
+
* @property dataType - SQL 데이터 타입
|
|
174
|
+
* @property autoIncrement - 자동 증가 여부
|
|
175
|
+
* @property nullable - NULL 허용 여부
|
|
176
|
+
* @property default - 기본값
|
|
177
|
+
* @property description - Column 설명 (DDL 코멘트)
|
|
178
178
|
*
|
|
179
179
|
* @see {@link ColumnBuilder} Column builder
|
|
180
180
|
*/
|