@simplysm/orm-node 13.0.96 → 13.0.98

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 (2) hide show
  1. package/README.md +163 -203
  2. package/package.json +5 -5
package/README.md CHANGED
@@ -1,182 +1,104 @@
1
1
  # @simplysm/orm-node
2
2
 
3
- Node.js용 ORM 모듈. MySQL, PostgreSQL, MSSQL(Azure 포함) 데이터베이스를 지원한다.
3
+ ORM module (node) -- database connections and ORM integration for MySQL, PostgreSQL, and MSSQL on Node.js.
4
4
 
5
- ## 설치
5
+ ## Installation
6
6
 
7
7
  ```bash
8
8
  npm install @simplysm/orm-node
9
9
  ```
10
10
 
11
- 사용하는 DB에 따라 드라이버를 추가로 설치한다 (모두 optional peerDependency):
11
+ ## API Overview
12
12
 
13
- ```bash
14
- npm install mysql2 # MySQL
15
- npm install pg pg-copy-streams # PostgreSQL
16
- npm install tedious # MSSQL / Azure SQL
17
- ```
18
-
19
- **의존성:** `@simplysm/core-common`, `@simplysm/orm-common`, `consola`
20
-
21
- ## 아키텍처 개요
22
-
23
- ```
24
- createOrm() -- 최상위 팩토리 (ORM 인스턴스)
25
- └─ NodeDbContextExecutor -- DbContextExecutor 구현체
26
- └─ createDbConn() -- DB 연결 생성
27
- └─ MysqlDbConn / PostgresqlDbConn / MssqlDbConn -- 실제 연결
28
- ```
29
-
30
- - `createOrm` -- `@simplysm/orm-common`의 `DbContext`와 DB 연결을 결합하는 고수준 API
31
- - `NodeDbContextExecutor` -- `QueryDef` -> SQL 변환 및 실행을 담당하는 어댑터
32
- - `createDbConn` -- DB 연결 인스턴스를 생성하는 팩토리
33
- - `MysqlDbConn` / `PostgresqlDbConn` / `MssqlDbConn` -- 각 DBMS별 실제 연결 구현
34
-
35
- ## 주요 사용법
36
-
37
- ### ORM 인스턴스 생성 및 트랜잭션
38
-
39
- ```typescript
40
- import { createOrm } from "@simplysm/orm-node";
41
- import { defineDbContext, Table } from "@simplysm/orm-common";
42
-
43
- // 1. 테이블 및 DbContext 정의 (orm-common)
44
- const User = Table("user")
45
- .columns((c) => ({ id: c.int().autoIncrement(), name: c.varchar(100) }))
46
- .primaryKey("id");
47
-
48
- const Order = Table("order")
49
- .columns((c) => ({ id: c.int().autoIncrement(), userId: c.int(), amount: c.decimal(10, 2) }))
50
- .primaryKey("id");
13
+ ### Types
51
14
 
52
- const MyDb = defineDbContext({
53
- tables: { user: User, order: Order },
54
- });
15
+ | API | Type | Description |
16
+ |-----|------|-------------|
17
+ | `DB_CONN_CONNECT_TIMEOUT` | const | Connection establishment timeout (10 seconds) |
18
+ | `DB_CONN_DEFAULT_TIMEOUT` | const | Query default timeout (10 minutes) |
19
+ | `DB_CONN_ERRORS` | const | Error message constants (`NOT_CONNECTED`, `ALREADY_CONNECTED`) |
20
+ | `DbConn` | interface | Low-level DB connection interface |
21
+ | `DbConnConfig` | type | Union of all DB connection configs |
22
+ | `MysqlDbConnConfig` | interface | MySQL connection configuration |
23
+ | `MssqlDbConnConfig` | interface | MSSQL/Azure SQL connection configuration |
24
+ | `PostgresqlDbConnConfig` | interface | PostgreSQL connection configuration |
25
+ | `getDialectFromConfig` | function | Extract `Dialect` from a `DbConnConfig` |
55
26
 
56
- // 2. ORM 인스턴스 생성
57
- // database는 필수 -- config 또는 options 중 하나에 반드시 지정해야 한다.
58
- const orm = createOrm(MyDb, {
59
- dialect: "mysql",
60
- host: "localhost",
61
- port: 3306,
62
- username: "root",
63
- password: "password",
64
- database: "mydb",
65
- });
27
+ ### Connections
66
28
 
67
- // 3-a. 자동 트랜잭션 (commit/rollback 자동 처리)
68
- const result = await orm.connect(async (db) => {
69
- const users = await db.user().execute();
70
- await db.user().insert([{ name: "Alice" }]);
71
- return users;
72
- });
29
+ | API | Type | Description |
30
+ |-----|------|-------------|
31
+ | `createDbConn` | function | Factory function to create a DB connection from config |
32
+ | `MysqlDbConn` | class | MySQL connection implementation (mysql2) |
33
+ | `PostgresqlDbConn` | class | PostgreSQL connection implementation (pg) |
34
+ | `MssqlDbConn` | class | MSSQL connection implementation (tedious) |
73
35
 
74
- // 3-b. 트랜잭션 없이 실행
75
- const users = await orm.connectWithoutTransaction(async (db) => {
76
- return await db.user().execute();
77
- });
36
+ ### Core
78
37
 
79
- // 3-c. 격리 수준 지정
80
- await orm.connect(async (db) => {
81
- /* ... */
82
- }, "SERIALIZABLE");
83
- ```
38
+ | API | Type | Description |
39
+ |-----|------|-------------|
40
+ | `OrmOptions` | interface | ORM options (database name, schema override) |
41
+ | `Orm` | interface | ORM instance with `connect` and `connectWithoutTransaction` |
42
+ | `createOrm` | function | Create an ORM instance from a DbContext definition and config |
43
+ | `NodeDbContextExecutor` | class | DbContextExecutor for Node.js environment |
84
44
 
85
- ### OrmOptions로 database/schema 오버라이드
45
+ ## `DbConnConfig`
86
46
 
87
47
  ```typescript
88
- const orm = createOrm(MyDb, config, {
89
- database: "other_db", // config.database 대신 사용
90
- schema: "custom_schema", // config.schema 대신 사용
91
- });
48
+ type DbConnConfig = MysqlDbConnConfig | MssqlDbConnConfig | PostgresqlDbConnConfig;
92
49
  ```
93
50
 
94
- ### 저수준 DB 연결
51
+ ## `MysqlDbConnConfig`
95
52
 
96
53
  ```typescript
97
- import { createDbConn } from "@simplysm/orm-node";
98
-
99
- // createDbConn은 연결 객체만 생성한다. connect()를 호출해야 실제 연결이 수립된다.
100
- const conn = await createDbConn(config);
101
- await conn.connect();
102
-
103
- await conn.beginTransaction();
104
- try {
105
- const rows = await conn.execute(["SELECT * FROM users"]);
106
- await conn.executeParametrized("INSERT INTO users (name) VALUES (?)", ["Alice"]);
107
- await conn.commitTransaction();
108
- } catch {
109
- await conn.rollbackTransaction();
54
+ interface MysqlDbConnConfig {
55
+ dialect: "mysql";
56
+ host: string;
57
+ port?: number;
58
+ username: string;
59
+ password: string;
60
+ database?: string;
61
+ defaultIsolationLevel?: IsolationLevel;
110
62
  }
111
-
112
- await conn.close();
113
63
  ```
114
64
 
115
- ### 벌크 인서트
116
-
117
- 각 DBMS의 네이티브 벌크 API를 사용하여 최적 성능을 제공한다.
118
-
119
- ```typescript
120
- await conn.bulkInsert("users", columnMetas, records);
121
- ```
122
-
123
- | DBMS | 방식 |
124
- |------|------|
125
- | MySQL | `LOAD DATA LOCAL INFILE` (임시 CSV 파일) |
126
- | PostgreSQL | `COPY FROM STDIN` (스트림 기반 CSV) |
127
- | MSSQL | tedious `BulkLoad` API (네이티브) |
128
-
129
- ## API 레퍼런스
130
-
131
- ### `createOrm(dbContextDef, config, options?): Orm`
132
-
133
- ORM 인스턴스 팩토리. `defineDbContext`로 정의한 DbContext 정의와 연결 설정을 결합한다.
65
+ ## `MssqlDbConnConfig`
134
66
 
135
67
  ```typescript
136
- function createOrm<TDef extends DbContextDef<any, any, any>>(
137
- dbContextDef: TDef,
138
- config: DbConnConfig,
139
- options?: OrmOptions,
140
- ): Orm<TDef>;
68
+ interface MssqlDbConnConfig {
69
+ dialect: "mssql" | "mssql-azure";
70
+ host: string;
71
+ port?: number;
72
+ username: string;
73
+ password: string;
74
+ database?: string;
75
+ schema?: string;
76
+ defaultIsolationLevel?: IsolationLevel;
77
+ }
141
78
  ```
142
79
 
143
- `database`는 `options.database` -> `config.database` 순서로 결정되며, 둘 다 없으면 에러가 발생한다. `schema`도 같은 우선순위로 결정된다.
144
-
145
- **`Orm<TDef>` 인터페이스:**
146
-
147
- | 속성/메서드 | 타입 | 설명 |
148
- |---|---|---|
149
- | `dbContextDef` | `TDef` (readonly) | DbContext 정의 |
150
- | `config` | `DbConnConfig` (readonly) | 연결 설정 |
151
- | `options` | `OrmOptions` (readonly, optional) | 옵션 |
152
- | `connect(callback, isolationLevel?)` | `Promise<R>` | 트랜잭션 내에서 콜백 실행 |
153
- | `connectWithoutTransaction(callback)` | `Promise<R>` | 트랜잭션 없이 콜백 실행 |
154
-
155
- **`OrmOptions` 인터페이스:**
156
-
157
- | 필드 | 타입 | 설명 |
158
- |---|---|---|
159
- | `database?` | `string` | config.database 대신 사용할 DB 이름 |
160
- | `schema?` | `string` | config.schema 대신 사용할 스키마 이름 |
161
-
162
- ### `createDbConn(config): Promise<DbConn>`
163
-
164
- DB 연결 인스턴스를 생성하여 반환한다. 반환된 객체에 `connect()`를 호출해야 실제 연결이 수립된다. 드라이버 모듈은 호출 시 lazy import된다.
80
+ ## `PostgresqlDbConnConfig`
165
81
 
166
82
  ```typescript
167
- function createDbConn(config: DbConnConfig): Promise<DbConn>;
83
+ interface PostgresqlDbConnConfig {
84
+ dialect: "postgresql";
85
+ host: string;
86
+ port?: number;
87
+ username: string;
88
+ password: string;
89
+ database?: string;
90
+ schema?: string;
91
+ defaultIsolationLevel?: IsolationLevel;
92
+ }
168
93
  ```
169
94
 
170
- ### `DbConn` 인터페이스
171
-
172
- 모든 DB 연결 구현체의 공통 인터페이스. `EventEmitter<{ close: void }>`를 상속한다.
95
+ ## `DbConn`
173
96
 
174
97
  ```typescript
175
98
  interface DbConn extends EventEmitter<{ close: void }> {
176
99
  config: DbConnConfig;
177
100
  isConnected: boolean;
178
101
  isInTransaction: boolean;
179
-
180
102
  connect(): Promise<void>;
181
103
  close(): Promise<void>;
182
104
  beginTransaction(isolationLevel?: IsolationLevel): Promise<void>;
@@ -192,98 +114,136 @@ interface DbConn extends EventEmitter<{ close: void }> {
192
114
  }
193
115
  ```
194
116
 
195
- ### `DbConnConfig` 타입
117
+ ## `getDialectFromConfig`
118
+
119
+ ```typescript
120
+ function getDialectFromConfig(config: DbConnConfig): Dialect;
121
+ ```
122
+
123
+ Returns the `Dialect` for a given config. Maps `"mssql-azure"` to `"mssql"`.
196
124
 
197
- `dialect` 필드로 분기되는 유니온 타입이다.
125
+ ## `createDbConn`
198
126
 
199
127
  ```typescript
200
- type DbConnConfig = MysqlDbConnConfig | MssqlDbConnConfig | PostgresqlDbConnConfig;
128
+ async function createDbConn(config: DbConnConfig): Promise<DbConn>;
201
129
  ```
202
130
 
203
- **공통 필드:**
131
+ Factory function that creates a DB connection. Driver modules (mysql2, pg, tedious) are lazy-loaded. Returns an unconnected instance -- call `connect()` separately.
204
132
 
205
- | 필드 | 타입 | 설명 |
206
- |---|---|---|
207
- | `dialect` | `"mysql"` \| `"mssql"` \| `"mssql-azure"` \| `"postgresql"` | DBMS 종류 |
208
- | `host` | `string` | 호스트 |
209
- | `port?` | `number` | 포트 |
210
- | `username` | `string` | 사용자명 |
211
- | `password` | `string` | 비밀번호 |
212
- | `database?` | `string` | 데이터베이스명 |
213
- | `defaultIsolationLevel?` | `IsolationLevel` | 기본 격리 수준 |
133
+ ## `OrmOptions`
214
134
 
215
- **MSSQL/PostgreSQL 전용:**
135
+ ```typescript
136
+ interface OrmOptions {
137
+ database?: string;
138
+ schema?: string;
139
+ }
140
+ ```
141
+
142
+ ## `Orm`
143
+
144
+ ```typescript
145
+ interface Orm<TDef extends DbContextDef<any, any, any>> {
146
+ readonly dbContextDef: TDef;
147
+ readonly config: DbConnConfig;
148
+ readonly options?: OrmOptions;
149
+ connect<R>(
150
+ callback: (conn: DbContextInstance<TDef>) => Promise<R>,
151
+ isolationLevel?: IsolationLevel,
152
+ ): Promise<R>;
153
+ connectWithoutTransaction<R>(
154
+ callback: (conn: DbContextInstance<TDef>) => Promise<R>,
155
+ ): Promise<R>;
156
+ }
157
+ ```
216
158
 
217
- | 필드 | 타입 | 설명 |
218
- |---|---|---|
219
- | `schema?` | `string` | 스키마 (MSSQL 기본: `dbo`, PostgreSQL 기본: `public`) |
159
+ ## `createOrm`
220
160
 
221
- **MSSQL 특수 dialect:**
222
- - `"mssql-azure"`: Azure SQL용. `encrypt: true`가 자동 적용됨.
161
+ ```typescript
162
+ function createOrm<TDef extends DbContextDef<any, any, any>>(
163
+ dbContextDef: TDef,
164
+ config: DbConnConfig,
165
+ options?: OrmOptions,
166
+ ): Orm<TDef>;
167
+ ```
223
168
 
224
- ### `NodeDbContextExecutor`
169
+ Node.js ORM factory. Creates an instance that manages DbContext and DB connections with automatic transaction handling.
225
170
 
226
- `@simplysm/orm-common`의 `DbContextExecutor` 인터페이스 구현체. `DbContext`가 내부적으로 사용한다.
171
+ ## `NodeDbContextExecutor`
227
172
 
228
173
  ```typescript
229
174
  class NodeDbContextExecutor implements DbContextExecutor {
230
175
  constructor(config: DbConnConfig);
231
-
232
- connect(): Promise<void>;
233
- close(): Promise<void>;
234
- beginTransaction(isolationLevel?: IsolationLevel): Promise<void>;
235
- commitTransaction(): Promise<void>;
236
- rollbackTransaction(): Promise<void>;
237
- executeParametrized(query: string, params?: unknown[]): Promise<Record<string, unknown>[][]>;
238
- bulkInsert(tableName: string, columnMetas: Record<string, ColumnMeta>, records: DataRecord[]): Promise<void>;
239
- executeDefs<T = DataRecord>(defs: QueryDef[], resultMetas?: (ResultMeta | undefined)[]): Promise<T[][]>;
176
+ async connect(): Promise<void>;
177
+ async close(): Promise<void>;
178
+ async beginTransaction(isolationLevel?: IsolationLevel): Promise<void>;
179
+ async commitTransaction(): Promise<void>;
180
+ async rollbackTransaction(): Promise<void>;
181
+ async executeParametrized(query: string, params?: unknown[]): Promise<Record<string, unknown>[][]>;
182
+ async bulkInsert(
183
+ tableName: string,
184
+ columnMetas: Record<string, ColumnMeta>,
185
+ records: DataRecord[],
186
+ ): Promise<void>;
187
+ async executeDefs<T = DataRecord>(
188
+ defs: QueryDef[],
189
+ resultMetas?: (ResultMeta | undefined)[],
190
+ ): Promise<T[][]>;
240
191
  }
241
192
  ```
242
193
 
243
- **`executeDefs` 동작:**
244
- - `QueryDef`를 dialect에 맞는 SQL로 변환 (`createQueryBuilder`)
245
- - `resultMetas`가 모두 `undefined`이면 -> 결과 없는 쿼리로 판단하여 단일 배치 실행
246
- - `ResultMeta`가 있으면 -> `parseQueryResult`로 타입 변환 적용
194
+ DbContextExecutor for Node.js. Handles actual DB connections and query execution including QueryDef-to-SQL conversion.
247
195
 
248
- ### DB 연결 구현 클래스
196
+ ## Usage Examples
249
197
 
250
- | 클래스 | 드라이버 | dialect |
251
- |---|---|---|
252
- | `MysqlDbConn` | `mysql2/promise` | `"mysql"` |
253
- | `PostgresqlDbConn` | `pg` + `pg-copy-streams` | `"postgresql"` |
254
- | `MssqlDbConn` | `tedious` | `"mssql"`, `"mssql-azure"` |
198
+ ### Create ORM and run queries in a transaction
255
199
 
256
- 모두 `EventEmitter<{ close: void }>`를 상속하고 `DbConn`을 구현한다. 드라이버 모듈은 `createDbConn` 호출 시 lazy import된다.
257
-
258
- **DBMS별 참고 사항:**
259
- - MySQL: `username`이 `"root"`인 경우 특정 database에 바인딩하지 않고 연결한다 (관리 작업용).
260
- - MySQL: `charset`은 `utf8mb4`로 고정, `multipleStatements`가 활성화되어 있다.
261
- - PostgreSQL: 기본 포트 `5432`가 자동 적용된다.
262
- - MSSQL: `trustServerCertificate: true`로 설정된다.
200
+ ```typescript
201
+ import { createOrm } from "@simplysm/orm-node";
202
+ import { defineDbContext, queryable } from "@simplysm/orm-common";
263
203
 
264
- ### `getDialectFromConfig(config): Dialect`
204
+ const MyDb = defineDbContext({
205
+ user: (db) => queryable(db, User),
206
+ });
265
207
 
266
- config에서 `Dialect`를 추출한다. `"mssql-azure"` -> `"mssql"`로 변환된다.
208
+ const orm = createOrm(MyDb, {
209
+ dialect: "mysql",
210
+ host: "localhost",
211
+ port: 3306,
212
+ username: "root",
213
+ password: "password",
214
+ database: "mydb",
215
+ });
267
216
 
268
- ```typescript
269
- function getDialectFromConfig(config: DbConnConfig): Dialect;
217
+ const users = await orm.connect(async (db) => {
218
+ return await db.user().execute();
219
+ });
270
220
  ```
271
221
 
272
- ### 상수
222
+ ### Use low-level DB connection
273
223
 
274
- | 상수 | 값 | 설명 |
275
- |---|---|---|
276
- | `DB_CONN_CONNECT_TIMEOUT` | 10초 (10,000ms) | 연결 타임아웃 |
277
- | `DB_CONN_DEFAULT_TIMEOUT` | 10분 (600,000ms) | 쿼리 기본 타임아웃 |
278
- | `DB_CONN_ERRORS.NOT_CONNECTED` | `"'Connection' is not connected."` | 미연결 에러 메시지 |
279
- | `DB_CONN_ERRORS.ALREADY_CONNECTED` | `"'Connection' is already connected."` | 중복 연결 에러 메시지 |
224
+ ```typescript
225
+ import { createDbConn } from "@simplysm/orm-node";
280
226
 
281
- 연결 유휴 자동 종료: 마지막 쿼리 실행 후 `DB_CONN_DEFAULT_TIMEOUT * 2` (20분) 동안 활동이 없으면 연결이 자동으로 닫힌다.
227
+ const conn = await createDbConn({
228
+ dialect: "postgresql",
229
+ host: "localhost",
230
+ username: "admin",
231
+ password: "secret",
232
+ database: "testdb",
233
+ });
282
234
 
283
- ### IsolationLevel 타입
235
+ await conn.connect();
236
+ try {
237
+ const results = await conn.execute(["SELECT * FROM users"]);
238
+ } finally {
239
+ await conn.close();
240
+ }
241
+ ```
284
242
 
285
- `@simplysm/orm-common`에서 제공하는 트랜잭션 격리 수준이다. `isolationLevel`을 지정하지 않으면 `config.defaultIsolationLevel`이 사용되고, 이것도 없으면 `READ_UNCOMMITTED`가 기본값이다.
243
+ ### Run without transaction
286
244
 
287
245
  ```typescript
288
- type IsolationLevel = "READ_UNCOMMITTED" | "READ_COMMITTED" | "REPEATABLE_READ" | "SERIALIZABLE";
246
+ const result = await orm.connectWithoutTransaction(async (db) => {
247
+ return await db.user().execute();
248
+ });
289
249
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simplysm/orm-node",
3
- "version": "13.0.96",
3
+ "version": "13.0.98",
4
4
  "description": "Simplysm package - ORM module (node)",
5
5
  "author": "simplysm",
6
6
  "license": "Apache-2.0",
@@ -20,13 +20,13 @@
20
20
  "sideEffects": false,
21
21
  "dependencies": {
22
22
  "consola": "^3.4.2",
23
- "@simplysm/core-common": "13.0.96",
24
- "@simplysm/orm-common": "13.0.96"
23
+ "@simplysm/core-common": "13.0.98",
24
+ "@simplysm/orm-common": "13.0.98"
25
25
  },
26
26
  "devDependencies": {
27
- "@types/pg": "^8.18.0",
27
+ "@types/pg": "^8.20.0",
28
28
  "@types/pg-copy-streams": "^1.2.5",
29
- "mysql2": "^3.19.1",
29
+ "mysql2": "^3.20.0",
30
30
  "pg": "^8.20.0",
31
31
  "pg-copy-streams": "^7.0.0",
32
32
  "tedious": "^19.2.1"