@simplysm/orm-node 13.0.0-beta.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.
Files changed (172) hide show
  1. package/.cache/typecheck-node.tsbuildinfo +1 -0
  2. package/README.md +418 -0
  3. package/dist/connections/mssql-db-conn.js +386 -0
  4. package/dist/connections/mssql-db-conn.js.map +7 -0
  5. package/dist/connections/mysql-db-conn.js +227 -0
  6. package/dist/connections/mysql-db-conn.js.map +7 -0
  7. package/dist/connections/postgresql-db-conn.js +191 -0
  8. package/dist/connections/postgresql-db-conn.js.map +7 -0
  9. package/dist/core-common/src/common.types.d.ts +74 -0
  10. package/dist/core-common/src/common.types.d.ts.map +1 -0
  11. package/dist/core-common/src/env.d.ts +6 -0
  12. package/dist/core-common/src/env.d.ts.map +1 -0
  13. package/dist/core-common/src/errors/argument-error.d.ts +25 -0
  14. package/dist/core-common/src/errors/argument-error.d.ts.map +1 -0
  15. package/dist/core-common/src/errors/not-implemented-error.d.ts +29 -0
  16. package/dist/core-common/src/errors/not-implemented-error.d.ts.map +1 -0
  17. package/dist/core-common/src/errors/sd-error.d.ts +27 -0
  18. package/dist/core-common/src/errors/sd-error.d.ts.map +1 -0
  19. package/dist/core-common/src/errors/timeout-error.d.ts +31 -0
  20. package/dist/core-common/src/errors/timeout-error.d.ts.map +1 -0
  21. package/dist/core-common/src/extensions/arr-ext.d.ts +15 -0
  22. package/dist/core-common/src/extensions/arr-ext.d.ts.map +1 -0
  23. package/dist/core-common/src/extensions/arr-ext.helpers.d.ts +19 -0
  24. package/dist/core-common/src/extensions/arr-ext.helpers.d.ts.map +1 -0
  25. package/dist/core-common/src/extensions/arr-ext.types.d.ts +215 -0
  26. package/dist/core-common/src/extensions/arr-ext.types.d.ts.map +1 -0
  27. package/dist/core-common/src/extensions/map-ext.d.ts +57 -0
  28. package/dist/core-common/src/extensions/map-ext.d.ts.map +1 -0
  29. package/dist/core-common/src/extensions/set-ext.d.ts +36 -0
  30. package/dist/core-common/src/extensions/set-ext.d.ts.map +1 -0
  31. package/dist/core-common/src/features/debounce-queue.d.ts +53 -0
  32. package/dist/core-common/src/features/debounce-queue.d.ts.map +1 -0
  33. package/dist/core-common/src/features/event-emitter.d.ts +66 -0
  34. package/dist/core-common/src/features/event-emitter.d.ts.map +1 -0
  35. package/dist/core-common/src/features/serial-queue.d.ts +47 -0
  36. package/dist/core-common/src/features/serial-queue.d.ts.map +1 -0
  37. package/dist/core-common/src/index.d.ts +32 -0
  38. package/dist/core-common/src/index.d.ts.map +1 -0
  39. package/dist/core-common/src/types/date-only.d.ts +152 -0
  40. package/dist/core-common/src/types/date-only.d.ts.map +1 -0
  41. package/dist/core-common/src/types/date-time.d.ts +96 -0
  42. package/dist/core-common/src/types/date-time.d.ts.map +1 -0
  43. package/dist/core-common/src/types/lazy-gc-map.d.ts +80 -0
  44. package/dist/core-common/src/types/lazy-gc-map.d.ts.map +1 -0
  45. package/dist/core-common/src/types/time.d.ts +68 -0
  46. package/dist/core-common/src/types/time.d.ts.map +1 -0
  47. package/dist/core-common/src/types/uuid.d.ts +35 -0
  48. package/dist/core-common/src/types/uuid.d.ts.map +1 -0
  49. package/dist/core-common/src/utils/bytes.d.ts +51 -0
  50. package/dist/core-common/src/utils/bytes.d.ts.map +1 -0
  51. package/dist/core-common/src/utils/date-format.d.ts +90 -0
  52. package/dist/core-common/src/utils/date-format.d.ts.map +1 -0
  53. package/dist/core-common/src/utils/json.d.ts +34 -0
  54. package/dist/core-common/src/utils/json.d.ts.map +1 -0
  55. package/dist/core-common/src/utils/num.d.ts +60 -0
  56. package/dist/core-common/src/utils/num.d.ts.map +1 -0
  57. package/dist/core-common/src/utils/obj.d.ts +258 -0
  58. package/dist/core-common/src/utils/obj.d.ts.map +1 -0
  59. package/dist/core-common/src/utils/path.d.ts +23 -0
  60. package/dist/core-common/src/utils/path.d.ts.map +1 -0
  61. package/dist/core-common/src/utils/primitive.d.ts +18 -0
  62. package/dist/core-common/src/utils/primitive.d.ts.map +1 -0
  63. package/dist/core-common/src/utils/str.d.ts +103 -0
  64. package/dist/core-common/src/utils/str.d.ts.map +1 -0
  65. package/dist/core-common/src/utils/template-strings.d.ts +84 -0
  66. package/dist/core-common/src/utils/template-strings.d.ts.map +1 -0
  67. package/dist/core-common/src/utils/transferable.d.ts +47 -0
  68. package/dist/core-common/src/utils/transferable.d.ts.map +1 -0
  69. package/dist/core-common/src/utils/wait.d.ts +19 -0
  70. package/dist/core-common/src/utils/wait.d.ts.map +1 -0
  71. package/dist/core-common/src/utils/xml.d.ts +36 -0
  72. package/dist/core-common/src/utils/xml.d.ts.map +1 -0
  73. package/dist/core-common/src/zip/sd-zip.d.ts +80 -0
  74. package/dist/core-common/src/zip/sd-zip.d.ts.map +1 -0
  75. package/dist/db-conn-factory.js +88 -0
  76. package/dist/db-conn-factory.js.map +7 -0
  77. package/dist/index.js +9 -0
  78. package/dist/index.js.map +7 -0
  79. package/dist/node-db-context-executor.js +129 -0
  80. package/dist/node-db-context-executor.js.map +7 -0
  81. package/dist/orm-common/src/db-context.d.ts +669 -0
  82. package/dist/orm-common/src/db-context.d.ts.map +1 -0
  83. package/dist/orm-common/src/errors/db-transaction-error.d.ts +51 -0
  84. package/dist/orm-common/src/errors/db-transaction-error.d.ts.map +1 -0
  85. package/dist/orm-common/src/exec/executable.d.ts +79 -0
  86. package/dist/orm-common/src/exec/executable.d.ts.map +1 -0
  87. package/dist/orm-common/src/exec/queryable.d.ts +708 -0
  88. package/dist/orm-common/src/exec/queryable.d.ts.map +1 -0
  89. package/dist/orm-common/src/exec/search-parser.d.ts +72 -0
  90. package/dist/orm-common/src/exec/search-parser.d.ts.map +1 -0
  91. package/dist/orm-common/src/expr/expr-unit.d.ts +25 -0
  92. package/dist/orm-common/src/expr/expr-unit.d.ts.map +1 -0
  93. package/dist/orm-common/src/expr/expr.d.ts +1369 -0
  94. package/dist/orm-common/src/expr/expr.d.ts.map +1 -0
  95. package/dist/orm-common/src/index.d.ts +32 -0
  96. package/dist/orm-common/src/index.d.ts.map +1 -0
  97. package/dist/orm-common/src/models/system-migration.d.ts +10 -0
  98. package/dist/orm-common/src/models/system-migration.d.ts.map +1 -0
  99. package/dist/orm-common/src/query-builder/base/expr-renderer-base.d.ts +95 -0
  100. package/dist/orm-common/src/query-builder/base/expr-renderer-base.d.ts.map +1 -0
  101. package/dist/orm-common/src/query-builder/base/query-builder-base.d.ts +66 -0
  102. package/dist/orm-common/src/query-builder/base/query-builder-base.d.ts.map +1 -0
  103. package/dist/orm-common/src/query-builder/mssql/mssql-expr-renderer.d.ts +84 -0
  104. package/dist/orm-common/src/query-builder/mssql/mssql-expr-renderer.d.ts.map +1 -0
  105. package/dist/orm-common/src/query-builder/mssql/mssql-query-builder.d.ts +45 -0
  106. package/dist/orm-common/src/query-builder/mssql/mssql-query-builder.d.ts.map +1 -0
  107. package/dist/orm-common/src/query-builder/mysql/mysql-expr-renderer.d.ts +84 -0
  108. package/dist/orm-common/src/query-builder/mysql/mysql-expr-renderer.d.ts.map +1 -0
  109. package/dist/orm-common/src/query-builder/mysql/mysql-query-builder.d.ts +54 -0
  110. package/dist/orm-common/src/query-builder/mysql/mysql-query-builder.d.ts.map +1 -0
  111. package/dist/orm-common/src/query-builder/postgresql/postgresql-expr-renderer.d.ts +84 -0
  112. package/dist/orm-common/src/query-builder/postgresql/postgresql-expr-renderer.d.ts.map +1 -0
  113. package/dist/orm-common/src/query-builder/postgresql/postgresql-query-builder.d.ts +52 -0
  114. package/dist/orm-common/src/query-builder/postgresql/postgresql-query-builder.d.ts.map +1 -0
  115. package/dist/orm-common/src/query-builder/query-builder.d.ts +7 -0
  116. package/dist/orm-common/src/query-builder/query-builder.d.ts.map +1 -0
  117. package/dist/orm-common/src/schema/factory/column-builder.d.ts +394 -0
  118. package/dist/orm-common/src/schema/factory/column-builder.d.ts.map +1 -0
  119. package/dist/orm-common/src/schema/factory/index-builder.d.ts +151 -0
  120. package/dist/orm-common/src/schema/factory/index-builder.d.ts.map +1 -0
  121. package/dist/orm-common/src/schema/factory/relation-builder.d.ts +337 -0
  122. package/dist/orm-common/src/schema/factory/relation-builder.d.ts.map +1 -0
  123. package/dist/orm-common/src/schema/procedure-builder.d.ts +202 -0
  124. package/dist/orm-common/src/schema/procedure-builder.d.ts.map +1 -0
  125. package/dist/orm-common/src/schema/table-builder.d.ts +259 -0
  126. package/dist/orm-common/src/schema/table-builder.d.ts.map +1 -0
  127. package/dist/orm-common/src/schema/view-builder.d.ts +183 -0
  128. package/dist/orm-common/src/schema/view-builder.d.ts.map +1 -0
  129. package/dist/orm-common/src/types/column.d.ts +172 -0
  130. package/dist/orm-common/src/types/column.d.ts.map +1 -0
  131. package/dist/orm-common/src/types/db.d.ts +175 -0
  132. package/dist/orm-common/src/types/db.d.ts.map +1 -0
  133. package/dist/orm-common/src/types/expr.d.ts +474 -0
  134. package/dist/orm-common/src/types/expr.d.ts.map +1 -0
  135. package/dist/orm-common/src/types/query-def.d.ts +351 -0
  136. package/dist/orm-common/src/types/query-def.d.ts.map +1 -0
  137. package/dist/orm-common/src/utils/result-parser.d.ts +38 -0
  138. package/dist/orm-common/src/utils/result-parser.d.ts.map +1 -0
  139. package/dist/orm-node/src/connections/mssql-db-conn.d.ts +44 -0
  140. package/dist/orm-node/src/connections/mssql-db-conn.d.ts.map +1 -0
  141. package/dist/orm-node/src/connections/mysql-db-conn.d.ts +38 -0
  142. package/dist/orm-node/src/connections/mysql-db-conn.d.ts.map +1 -0
  143. package/dist/orm-node/src/connections/postgresql-db-conn.d.ts +39 -0
  144. package/dist/orm-node/src/connections/postgresql-db-conn.d.ts.map +1 -0
  145. package/dist/orm-node/src/db-conn-factory.d.ts +25 -0
  146. package/dist/orm-node/src/db-conn-factory.d.ts.map +1 -0
  147. package/dist/orm-node/src/index.d.ts +9 -0
  148. package/dist/orm-node/src/index.d.ts.map +1 -0
  149. package/dist/orm-node/src/node-db-context-executor.d.ts +77 -0
  150. package/dist/orm-node/src/node-db-context-executor.d.ts.map +1 -0
  151. package/dist/orm-node/src/pooled-db-conn.d.ts +79 -0
  152. package/dist/orm-node/src/pooled-db-conn.d.ts.map +1 -0
  153. package/dist/orm-node/src/sd-orm.d.ts +78 -0
  154. package/dist/orm-node/src/sd-orm.d.ts.map +1 -0
  155. package/dist/orm-node/src/types/db-conn.d.ts +159 -0
  156. package/dist/orm-node/src/types/db-conn.d.ts.map +1 -0
  157. package/dist/pooled-db-conn.js +134 -0
  158. package/dist/pooled-db-conn.js.map +7 -0
  159. package/dist/sd-orm.js +44 -0
  160. package/dist/sd-orm.js.map +7 -0
  161. package/dist/types/db-conn.js +17 -0
  162. package/dist/types/db-conn.js.map +7 -0
  163. package/package.json +50 -0
  164. package/src/connections/mssql-db-conn.ts +483 -0
  165. package/src/connections/mysql-db-conn.ts +299 -0
  166. package/src/connections/postgresql-db-conn.ts +254 -0
  167. package/src/db-conn-factory.ts +114 -0
  168. package/src/index.ts +13 -0
  169. package/src/node-db-context-executor.ts +162 -0
  170. package/src/pooled-db-conn.ts +175 -0
  171. package/src/sd-orm.ts +102 -0
  172. package/src/types/db-conn.ts +196 -0
@@ -0,0 +1,162 @@
1
+ import { SdError } from "@simplysm/core-common";
2
+ import type {
3
+ DbContextExecutor,
4
+ IsolationLevel,
5
+ QueryDef,
6
+ ResultMeta,
7
+ Dialect,
8
+ ColumnMeta,
9
+ DataRecord,
10
+ } from "@simplysm/orm-common";
11
+ import { createQueryBuilder, parseQueryResult } from "@simplysm/orm-common";
12
+ import type { DbConn, DbConnConfig } from "./types/db-conn";
13
+ import { DB_CONN_ERRORS, getDialectFromConfig } from "./types/db-conn";
14
+ import { DbConnFactory } from "./db-conn-factory";
15
+
16
+ /**
17
+ * Node.js 환경용 DbContextExecutor
18
+ *
19
+ * DbContext에서 사용하는 실행기로, 실제 DB 연결을 담당한다.
20
+ */
21
+ export class NodeDbContextExecutor implements DbContextExecutor {
22
+ private _conn?: DbConn;
23
+ private readonly _dialect: Dialect;
24
+
25
+ constructor(private readonly _config: DbConnConfig) {
26
+ this._dialect = getDialectFromConfig(_config);
27
+ }
28
+
29
+ /**
30
+ * DB 연결 수립
31
+ *
32
+ * 커넥션 풀에서 연결을 획득하고 연결 상태를 활성화한다.
33
+ */
34
+ async connect(): Promise<void> {
35
+ this._conn = await DbConnFactory.create(this._config);
36
+ await this._conn.connect();
37
+ }
38
+
39
+ /**
40
+ * DB 연결 종료
41
+ *
42
+ * 커넥션 풀에 연결을 반환한다.
43
+ *
44
+ * @throws {Error} 연결되지 않은 상태일 때
45
+ */
46
+ async close(): Promise<void> {
47
+ const conn = this._requireConn();
48
+ await conn.close();
49
+ this._conn = undefined;
50
+ }
51
+
52
+ /**
53
+ * 트랜잭션 시작
54
+ *
55
+ * @param isolationLevel - 트랜잭션 격리 수준
56
+ * @throws {Error} 연결되지 않은 상태일 때
57
+ */
58
+ async beginTransaction(isolationLevel?: IsolationLevel): Promise<void> {
59
+ const conn = this._requireConn();
60
+ await conn.beginTransaction(isolationLevel);
61
+ }
62
+
63
+ /**
64
+ * 트랜잭션 커밋
65
+ *
66
+ * @throws {Error} 연결되지 않은 상태일 때
67
+ */
68
+ async commitTransaction(): Promise<void> {
69
+ const conn = this._requireConn();
70
+ await conn.commitTransaction();
71
+ }
72
+
73
+ /**
74
+ * 트랜잭션 롤백
75
+ *
76
+ * @throws {Error} 연결되지 않은 상태일 때
77
+ */
78
+ async rollbackTransaction(): Promise<void> {
79
+ const conn = this._requireConn();
80
+ await conn.rollbackTransaction();
81
+ }
82
+
83
+ /**
84
+ * 파라미터화된 쿼리 실행
85
+ *
86
+ * @param query - SQL 쿼리 문자열
87
+ * @param params - 쿼리 파라미터 배열
88
+ * @returns 쿼리 결과 배열
89
+ * @throws {Error} 연결되지 않은 상태일 때
90
+ */
91
+ async executeParametrized(query: string, params?: unknown[]): Promise<unknown[][]> {
92
+ const conn = this._requireConn();
93
+ return conn.executeParametrized(query, params);
94
+ }
95
+
96
+ /**
97
+ * 대량 데이터 삽입 (네이티브 벌크 API 사용)
98
+ *
99
+ * @param tableName - 대상 테이블명
100
+ * @param columnMetas - 컬럼 메타데이터
101
+ * @param records - 삽입할 레코드 배열
102
+ * @throws {Error} 연결되지 않은 상태일 때
103
+ */
104
+ async bulkInsert(tableName: string, columnMetas: Record<string, ColumnMeta>, records: DataRecord[]): Promise<void> {
105
+ const conn = this._requireConn();
106
+ await conn.bulkInsert(tableName, columnMetas, records);
107
+ }
108
+
109
+ /**
110
+ * QueryDef 배열 실행
111
+ *
112
+ * QueryDef를 SQL로 변환하여 실행하고, ResultMeta를 사용하여 결과를 파싱한다.
113
+ *
114
+ * @param defs - 실행할 QueryDef 배열
115
+ * @param resultMetas - 결과 파싱용 메타데이터 배열 (타입 변환에 사용)
116
+ * @returns 각 QueryDef의 실행 결과 배열
117
+ * @throws {Error} 연결되지 않은 상태일 때
118
+ */
119
+ async executeDefs<T = DataRecord>(defs: QueryDef[], resultMetas?: (ResultMeta | undefined)[]): Promise<T[][]> {
120
+ const conn = this._requireConn();
121
+
122
+ const builder = createQueryBuilder(this._dialect);
123
+
124
+ // 가져올 데이터가 없는 것으로 옵션 설정을 했을 때, 하나의 쿼리로 한번의 요청 보냄
125
+ // 결과가 필요 없으므로 defs.length개의 빈 배열을 반환하여 인터페이스 계약 유지
126
+ if (resultMetas != null && resultMetas.every((item) => item == null)) {
127
+ const combinedSql = defs.map((def) => builder.build(def).sql).join("\n");
128
+ await conn.execute([combinedSql]);
129
+ return defs.map(() => []) as T[][];
130
+ }
131
+
132
+ // 각 def를 개별 실행
133
+ const results: T[][] = [];
134
+ for (let i = 0; i < defs.length; i++) {
135
+ const def = defs[i];
136
+ const meta = resultMetas?.[i];
137
+ const buildResult = builder.build(def);
138
+
139
+ const rawResults = await conn.execute([buildResult.sql]);
140
+
141
+ // resultSetIndex가 지정된 경우 해당 인덱스의 결과셋 사용
142
+ const targetResultSet =
143
+ buildResult.resultSetIndex != null ? rawResults[buildResult.resultSetIndex] : rawResults[0];
144
+
145
+ if (meta != null) {
146
+ const parsed = await parseQueryResult<T>(targetResultSet as Record<string, unknown>[], meta);
147
+ results.push(parsed ?? []);
148
+ } else {
149
+ results.push(targetResultSet as T[]);
150
+ }
151
+ }
152
+
153
+ return results;
154
+ }
155
+
156
+ private _requireConn(): DbConn {
157
+ if (this._conn == null) {
158
+ throw new SdError(DB_CONN_ERRORS.NOT_CONNECTED);
159
+ }
160
+ return this._conn;
161
+ }
162
+ }
@@ -0,0 +1,175 @@
1
+ import { createConsola } from "consola";
2
+ import { SdError, EventEmitter } from "@simplysm/core-common";
3
+ import type { Pool } from "generic-pool";
4
+ import type { ColumnMeta, IsolationLevel } from "@simplysm/orm-common";
5
+ import { DB_CONN_ERRORS, type DbConn, type DbConnConfig } from "./types/db-conn";
6
+
7
+ const logger = createConsola().withTag("pooled-db-conn");
8
+
9
+ /**
10
+ * 커넥션 풀에서 관리되는 DB 연결 래퍼
11
+ *
12
+ * generic-pool 라이브러리를 사용하여 커넥션 풀링을 지원한다.
13
+ * 실제 물리 연결은 풀에서 획득하고 반환한다.
14
+ */
15
+ export class PooledDbConn extends EventEmitter<{ close: void }> implements DbConn {
16
+ // 풀에서 빌려온 실제 물리 커넥션
17
+ private _rawConn?: DbConn;
18
+
19
+ constructor(
20
+ private readonly _pool: Pool<DbConn>,
21
+ private readonly _initialConfig: DbConnConfig,
22
+ ) {
23
+ super();
24
+ }
25
+
26
+ // [Property] config
27
+ get config(): DbConnConfig {
28
+ return this._rawConn?.config ?? this._initialConfig;
29
+ }
30
+
31
+ // [Property] isConnected
32
+ get isConnected(): boolean {
33
+ return this._rawConn?.isConnected ?? false;
34
+ }
35
+
36
+ // [Property] isOnTransaction
37
+ get isOnTransaction(): boolean {
38
+ return this._rawConn?.isOnTransaction ?? false;
39
+ }
40
+
41
+ /**
42
+ * 풀에서 DB 연결을 획득한다.
43
+ *
44
+ * @throws {SdError} 이미 연결된 상태일 때
45
+ */
46
+ async connect(): Promise<void> {
47
+ if (this._rawConn != null) {
48
+ throw new SdError(DB_CONN_ERRORS.ALREADY_CONNECTED);
49
+ }
50
+
51
+ // 1. 풀에서 커넥션 획득
52
+ this._rawConn = await this._pool.acquire();
53
+
54
+ // 2. 물리 연결이 (타임아웃 등으로) 끊어질 경우를 대비해 리스너 등록
55
+ // 만약 사용 중에 끊기면 PooledDbConn도 close 이벤트를 발생시켜야 함
56
+ this._rawConn.on("close", this._onRawConnClose);
57
+ }
58
+
59
+ /**
60
+ * 풀에 DB 연결을 반환한다. (실제 연결을 종료하지 않음)
61
+ */
62
+ async close(): Promise<void> {
63
+ if (this._rawConn != null) {
64
+ // 1. 트랜잭션 진행 중이면 롤백하여 깨끗한 상태로 풀에 반환
65
+ if (this._rawConn.isOnTransaction) {
66
+ try {
67
+ await this._rawConn.rollbackTransaction();
68
+ } catch (err) {
69
+ // 롤백 실패 시 로그만 남기고 계속 진행 (연결이 이미 끊긴 경우 등)
70
+ logger.warn("풀 반환 시 롤백 실패", err instanceof Error ? err.message : String(err));
71
+ }
72
+ }
73
+
74
+ // 2. 리스너 해제 (Pool에 돌아가서 다른 래퍼에 의해 재사용될 때 영향 주지 않도록)
75
+ this._rawConn.off("close", this._onRawConnClose);
76
+
77
+ // 3. 풀에 커넥션 반환 (실제로 끊지 않음)
78
+ await this._pool.release(this._rawConn);
79
+ this._rawConn = undefined;
80
+
81
+ // 4. 소비자에게 논리적으로 연결이 닫혔음을 알림
82
+ this.emit("close");
83
+ }
84
+ }
85
+
86
+ // 물리 연결이 끊겼을 때 처리 핸들러
87
+ private readonly _onRawConnClose = () => {
88
+ // 물리 연결이 끊겼으므로 참조 제거 (Pool에서는 validate 시점에 걸러낼 것임)
89
+ this._rawConn = undefined;
90
+ // 소비자에게 알림
91
+ this.emit("close");
92
+ };
93
+
94
+ // --- 아래는 위임(Delegation) 메소드 ---
95
+
96
+ /**
97
+ * 트랜잭션 시작
98
+ *
99
+ * @param isolationLevel - 트랜잭션 격리 수준
100
+ * @throws {SdError} 연결이 획득되지 않은 상태일 때
101
+ */
102
+ async beginTransaction(isolationLevel?: IsolationLevel): Promise<void> {
103
+ const conn = this._requireRawConn();
104
+ await conn.beginTransaction(isolationLevel);
105
+ }
106
+
107
+ /**
108
+ * 트랜잭션 커밋
109
+ *
110
+ * @throws {SdError} 연결이 획득되지 않은 상태일 때
111
+ */
112
+ async commitTransaction(): Promise<void> {
113
+ const conn = this._requireRawConn();
114
+ await conn.commitTransaction();
115
+ }
116
+
117
+ /**
118
+ * 트랜잭션 롤백
119
+ *
120
+ * @throws {SdError} 연결이 획득되지 않은 상태일 때
121
+ */
122
+ async rollbackTransaction(): Promise<void> {
123
+ const conn = this._requireRawConn();
124
+ await conn.rollbackTransaction();
125
+ }
126
+
127
+ /**
128
+ * SQL 쿼리 실행
129
+ *
130
+ * @param queries - 실행할 SQL 쿼리 배열
131
+ * @returns 각 쿼리의 결과 배열
132
+ * @throws {SdError} 연결이 획득되지 않은 상태일 때
133
+ */
134
+ async execute(queries: string[]): Promise<unknown[][]> {
135
+ const conn = this._requireRawConn();
136
+ return conn.execute(queries);
137
+ }
138
+
139
+ /**
140
+ * 파라미터화된 SQL 쿼리 실행
141
+ *
142
+ * @param query - SQL 쿼리 문자열
143
+ * @param params - 쿼리 파라미터 배열
144
+ * @returns 쿼리 결과 배열
145
+ * @throws {SdError} 연결이 획득되지 않은 상태일 때
146
+ */
147
+ async executeParametrized(query: string, params?: unknown[]): Promise<unknown[][]> {
148
+ const conn = this._requireRawConn();
149
+ return conn.executeParametrized(query, params);
150
+ }
151
+
152
+ /**
153
+ * 대량 데이터 삽입 (네이티브 벌크 API 사용)
154
+ *
155
+ * @param tableName - 대상 테이블명
156
+ * @param columnMetas - 컬럼 메타데이터
157
+ * @param records - 삽입할 레코드 배열
158
+ * @throws {SdError} 연결이 획득되지 않은 상태일 때
159
+ */
160
+ async bulkInsert(
161
+ tableName: string,
162
+ columnMetas: Record<string, ColumnMeta>,
163
+ records: Record<string, unknown>[],
164
+ ): Promise<void> {
165
+ const conn = this._requireRawConn();
166
+ await conn.bulkInsert(tableName, columnMetas, records);
167
+ }
168
+
169
+ private _requireRawConn(): DbConn {
170
+ if (this._rawConn == null) {
171
+ throw new SdError(`${DB_CONN_ERRORS.NOT_CONNECTED} (Pool Connection is not acquired)`);
172
+ }
173
+ return this._rawConn;
174
+ }
175
+ }
package/src/sd-orm.ts ADDED
@@ -0,0 +1,102 @@
1
+ import type { DbContext, IsolationLevel } from "@simplysm/orm-common";
2
+ import type { Type } from "@simplysm/core-common";
3
+ import type { DbConnConfig } from "./types/db-conn";
4
+ import { NodeDbContextExecutor } from "./node-db-context-executor";
5
+
6
+ /**
7
+ * SdOrm 옵션
8
+ *
9
+ * DbConnConfig보다 우선 적용되는 DbContext 옵션
10
+ */
11
+ export interface SdOrmOptions {
12
+ /**
13
+ * 데이터베이스 이름 (DbConnConfig의 database 대신 사용)
14
+ */
15
+ database?: string;
16
+
17
+ /**
18
+ * 스키마 이름 (MSSQL: dbo, PostgreSQL: public)
19
+ */
20
+ schema?: string;
21
+ }
22
+
23
+ /**
24
+ * Node.js ORM 클래스
25
+ *
26
+ * DbContext와 DB 연결을 관리하는 최상위 클래스입니다.
27
+ * DbContext 타입과 연결 설정을 받아 트랜잭션을 관리합니다.
28
+ *
29
+ * @example
30
+ * ```typescript
31
+ * class MyDb extends DbContext {
32
+ * readonly user = queryable(this, User);
33
+ * }
34
+ *
35
+ * const orm = new SdOrm(MyDb, {
36
+ * dialect: "mysql",
37
+ * host: "localhost",
38
+ * port: 3306,
39
+ * username: "root",
40
+ * password: "password",
41
+ * database: "mydb",
42
+ * });
43
+ *
44
+ * // 트랜잭션 내에서 실행
45
+ * await orm.connect(async (db) => {
46
+ * const users = await db.user().result();
47
+ * return users;
48
+ * });
49
+ *
50
+ * // 트랜잭션 없이 실행
51
+ * await orm.connectWithoutTransaction(async (db) => {
52
+ * const users = await db.user().result();
53
+ * return users;
54
+ * });
55
+ * ```
56
+ */
57
+ export class SdOrm<T extends DbContext> {
58
+ constructor(
59
+ readonly dbContextType: Type<T>,
60
+ readonly config: DbConnConfig,
61
+ readonly options?: SdOrmOptions,
62
+ ) {}
63
+
64
+ /**
65
+ * 트랜잭션 내에서 콜백 실행
66
+ *
67
+ * @param callback - DB 연결 후 실행할 콜백
68
+ * @param isolationLevel - 트랜잭션 격리 수준
69
+ * @returns 콜백 결과
70
+ */
71
+ async connect<R>(callback: (conn: T) => Promise<R>, isolationLevel?: IsolationLevel): Promise<R> {
72
+ const db = this._createDbContext();
73
+ return db.connect(async () => callback(db), isolationLevel);
74
+ }
75
+
76
+ /**
77
+ * 트랜잭션 없이 콜백 실행
78
+ *
79
+ * @param callback - DB 연결 후 실행할 콜백
80
+ * @returns 콜백 결과
81
+ */
82
+ async connectWithoutTransaction<R>(callback: (conn: T) => Promise<R>): Promise<R> {
83
+ const db = this._createDbContext();
84
+ return db.connectWithoutTransaction(async () => callback(db));
85
+ }
86
+
87
+ /**
88
+ * DbContext 인스턴스 생성
89
+ */
90
+ private _createDbContext(): T {
91
+ // database는 options에서 우선, 없으면 config에서
92
+ const database = this.options?.database ?? ("database" in this.config ? this.config.database : undefined);
93
+
94
+ // schema는 options에서 우선, 없으면 config에서
95
+ const schema = this.options?.schema ?? ("schema" in this.config ? this.config.schema : undefined);
96
+
97
+ return new this.dbContextType(new NodeDbContextExecutor(this.config), {
98
+ database,
99
+ schema,
100
+ });
101
+ }
102
+ }
@@ -0,0 +1,196 @@
1
+ import type { EventEmitter } from "@simplysm/core-common";
2
+ import type { ColumnMeta, Dialect, IsolationLevel } from "@simplysm/orm-common";
3
+
4
+ // ============================================
5
+ // 공통 상수
6
+ // ============================================
7
+
8
+ /**
9
+ * DB 연결 기본 타임아웃 (10분)
10
+ */
11
+ export const DB_CONN_DEFAULT_TIMEOUT = 10 * 60 * 1000;
12
+
13
+ /**
14
+ * DB 연결 에러 메시지
15
+ */
16
+ export const DB_CONN_ERRORS = {
17
+ NOT_CONNECTED: "'Connection'이 연결되어있지 않습니다.",
18
+ ALREADY_CONNECTED: "이미 'Connection'이 연결되어있습니다.",
19
+ } as const;
20
+
21
+ // ============================================
22
+ // IDbConn Interface
23
+ // ============================================
24
+
25
+ /**
26
+ * 저수준 DB 연결 인터페이스
27
+ *
28
+ * 각 DBMS별 구현체가 이 인터페이스를 구현합니다.
29
+ * - {@link MysqlDbConn} - MySQL 연결
30
+ * - {@link MssqlDbConn} - MSSQL 연결
31
+ * - {@link PostgresqlDbConn} - PostgreSQL 연결
32
+ *
33
+ * @remarks
34
+ * SdEventEmitter를 상속하여 'close' 이벤트를 발생시킵니다.
35
+ */
36
+ export interface DbConn extends EventEmitter<{ close: void }> {
37
+ /**
38
+ * 연결 설정
39
+ */
40
+ config: DbConnConfig;
41
+
42
+ /**
43
+ * 연결 여부
44
+ */
45
+ isConnected: boolean;
46
+
47
+ /**
48
+ * 트랜잭션 진행 여부
49
+ */
50
+ isOnTransaction: boolean;
51
+
52
+ /**
53
+ * DB 연결 수립
54
+ */
55
+ connect(): Promise<void>;
56
+
57
+ /**
58
+ * DB 연결 종료
59
+ */
60
+ close(): Promise<void>;
61
+
62
+ /**
63
+ * 트랜잭션 시작
64
+ *
65
+ * @param isolationLevel - 격리 수준 (선택)
66
+ */
67
+ beginTransaction(isolationLevel?: IsolationLevel): Promise<void>;
68
+
69
+ /**
70
+ * 트랜잭션 커밋
71
+ */
72
+ commitTransaction(): Promise<void>;
73
+
74
+ /**
75
+ * 트랜잭션 롤백
76
+ */
77
+ rollbackTransaction(): Promise<void>;
78
+
79
+ /**
80
+ * SQL 쿼리 배열 실행
81
+ *
82
+ * @param queries - 실행할 SQL 문자열 배열
83
+ * @returns 각 쿼리별 결과 배열의 배열
84
+ */
85
+ execute(queries: string[]): Promise<unknown[][]>;
86
+
87
+ /**
88
+ * 파라미터화된 쿼리 실행
89
+ *
90
+ * @param query - SQL 쿼리 문자열
91
+ * @param params - 바인딩 파라미터 (선택)
92
+ * @returns 결과 배열의 배열
93
+ */
94
+ executeParametrized(query: string, params?: unknown[]): Promise<unknown[][]>;
95
+
96
+ /**
97
+ * 대량 INSERT (네이티브 벌크 API 사용)
98
+ *
99
+ * - MSSQL: tedious BulkLoad
100
+ * - MySQL: LOAD DATA LOCAL INFILE (임시 파일)
101
+ * - PostgreSQL: COPY FROM STDIN
102
+ *
103
+ * @param tableName - 테이블명 (database.table 또는 database.schema.table)
104
+ * @param columnMetas - 컬럼명 → ColumnMeta 매핑
105
+ * @param records - 삽입할 레코드 배열
106
+ */
107
+ bulkInsert(
108
+ tableName: string,
109
+ columnMetas: Record<string, ColumnMeta>,
110
+ records: Record<string, unknown>[],
111
+ ): Promise<void>;
112
+ }
113
+
114
+ // ============================================
115
+ // DbConnConfig Types
116
+ // ============================================
117
+
118
+ /**
119
+ * 커넥션 풀 설정
120
+ *
121
+ * @remarks
122
+ * 각 값의 기본값:
123
+ * - min: 1 (최소 연결 수)
124
+ * - max: 10 (최대 연결 수)
125
+ * - acquireTimeoutMillis: 30000 (연결 획득 타임아웃)
126
+ * - idleTimeoutMillis: 30000 (유휴 연결 타임아웃)
127
+ */
128
+ export interface DbPoolConfig {
129
+ /** 최소 연결 수 (기본: 1) */
130
+ min?: number;
131
+ /** 최대 연결 수 (기본: 10) */
132
+ max?: number;
133
+ /** 연결 획득 타임아웃 (밀리초, 기본: 30000) */
134
+ acquireTimeoutMillis?: number;
135
+ /** 유휴 연결 타임아웃 (밀리초, 기본: 30000) */
136
+ idleTimeoutMillis?: number;
137
+ }
138
+
139
+ /**
140
+ * DB 연결 설정 타입 (dialect별 분기)
141
+ */
142
+ export type DbConnConfig = MysqlDbConnConfig | MssqlDbConnConfig | PostgresqlDbConnConfig;
143
+
144
+ /**
145
+ * MySQL 연결 설정
146
+ */
147
+ export interface MysqlDbConnConfig {
148
+ dialect: "mysql";
149
+ host: string;
150
+ port?: number;
151
+ username: string;
152
+ password: string;
153
+ database?: string;
154
+ defaultIsolationLevel?: IsolationLevel;
155
+ pool?: DbPoolConfig;
156
+ }
157
+
158
+ /**
159
+ * MSSQL 연결 설정
160
+ */
161
+ export interface MssqlDbConnConfig {
162
+ dialect: "mssql" | "mssql-azure";
163
+ host: string;
164
+ port?: number;
165
+ username: string;
166
+ password: string;
167
+ database?: string;
168
+ schema?: string;
169
+ defaultIsolationLevel?: IsolationLevel;
170
+ pool?: DbPoolConfig;
171
+ }
172
+
173
+ /**
174
+ * PostgreSQL 연결 설정
175
+ */
176
+ export interface PostgresqlDbConnConfig {
177
+ dialect: "postgresql";
178
+ host: string;
179
+ port?: number;
180
+ username: string;
181
+ password: string;
182
+ database?: string;
183
+ schema?: string;
184
+ defaultIsolationLevel?: IsolationLevel;
185
+ pool?: DbPoolConfig;
186
+ }
187
+
188
+ /**
189
+ * DbConnConfig에서 Dialect 추출
190
+ */
191
+ export function getDialectFromConfig(config: DbConnConfig): Dialect {
192
+ if (config.dialect === "mssql-azure") {
193
+ return "mssql";
194
+ }
195
+ return config.dialect;
196
+ }