@simplysm/orm-node 13.0.0-beta.51 → 13.0.1
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 +28 -23
- package/dist/create-db-conn.d.ts +12 -0
- package/dist/create-db-conn.d.ts.map +1 -0
- package/dist/create-db-conn.js +75 -0
- package/dist/create-db-conn.js.map +6 -0
- package/dist/{sd-orm.d.ts → create-orm.d.ts} +37 -37
- package/dist/create-orm.d.ts.map +1 -0
- package/dist/create-orm.js +32 -0
- package/dist/create-orm.js.map +6 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/node-db-context-executor.js +2 -2
- package/dist/node-db-context-executor.js.map +1 -1
- package/package.json +3 -3
- package/src/create-db-conn.ts +111 -0
- package/src/create-orm.ts +118 -0
- package/src/index.ts +2 -2
- package/src/node-db-context-executor.ts +2 -2
- package/dist/db-conn-factory.d.ts +0 -25
- package/dist/db-conn-factory.d.ts.map +0 -1
- package/dist/db-conn-factory.js +0 -88
- package/dist/db-conn-factory.js.map +0 -6
- package/dist/sd-orm.d.ts.map +0 -1
- package/dist/sd-orm.js +0 -44
- package/dist/sd-orm.js.map +0 -6
- package/src/db-conn-factory.ts +0 -114
- package/src/sd-orm.ts +0 -102
package/README.md
CHANGED
|
@@ -28,28 +28,33 @@ npm install pg pg-copy-streams
|
|
|
28
28
|
## Architecture
|
|
29
29
|
|
|
30
30
|
```
|
|
31
|
-
|
|
31
|
+
createOrm() (top-level entry point)
|
|
32
32
|
└── NodeDbContextExecutor (executor between DbContext and actual DB)
|
|
33
|
-
└──
|
|
33
|
+
└── createDbConn() (connection creation and pool management)
|
|
34
34
|
└── PooledDbConn (connection pool wrapper)
|
|
35
35
|
└── MysqlDbConn / MssqlDbConn / PostgresqlDbConn (DBMS-specific low-level connections)
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
-
- `
|
|
38
|
+
- `createOrm()` is the top-level factory function that takes a `DbContext` type and connection settings to manage transactions.
|
|
39
39
|
- `NodeDbContextExecutor` is the executor used by `DbContext`, converting `QueryDef` to SQL and executing it.
|
|
40
|
-
- `
|
|
40
|
+
- `createDbConn()` is a factory function that acquires connections from the connection pool.
|
|
41
41
|
- `PooledDbConn` is a connection pool wrapper based on `generic-pool`, returning connections to the pool instead of closing them after use.
|
|
42
42
|
- Each DBMS-specific connection class (`MysqlDbConn`, `MssqlDbConn`, `PostgresqlDbConn`) directly uses low-level DB drivers.
|
|
43
43
|
|
|
44
44
|
## Core Modules
|
|
45
45
|
|
|
46
|
+
### Functions
|
|
47
|
+
|
|
48
|
+
| Function | Description |
|
|
49
|
+
|----------|-------------|
|
|
50
|
+
| `createOrm()` | ORM factory function. Takes `DbContext` type and connection settings to manage transaction-based connections. |
|
|
51
|
+
| `createDbConn()` | Connection factory function. Caches connection pools by configuration and returns `PooledDbConn`. |
|
|
52
|
+
|
|
46
53
|
### Classes
|
|
47
54
|
|
|
48
55
|
| Class | Description |
|
|
49
56
|
|--------|------|
|
|
50
|
-
| `SdOrm` | ORM top-level class. Takes `DbContext` type and connection settings to manage transaction-based connections. |
|
|
51
57
|
| `NodeDbContextExecutor` | `DbContextExecutor` implementation. Converts `QueryDef` to SQL, executes it, and parses results. |
|
|
52
|
-
| `DbConnFactory` | Connection factory. Caches connection pools by configuration and returns `PooledDbConn`. |
|
|
53
58
|
| `PooledDbConn` | Connection pool wrapper. Acquires/returns physical connections from `generic-pool`, implements `DbConn` interface. |
|
|
54
59
|
| `MysqlDbConn` | MySQL connection class. Uses `mysql2/promise` driver. |
|
|
55
60
|
| `MssqlDbConn` | MSSQL/Azure SQL connection class. Uses `tedious` driver. |
|
|
@@ -65,7 +70,7 @@ SdOrm (top-level entry point)
|
|
|
65
70
|
| `MssqlDbConnConfig` | MSSQL connection config. `dialect: "mssql" \| "mssql-azure"`. |
|
|
66
71
|
| `PostgresqlDbConnConfig` | PostgreSQL connection config. `dialect: "postgresql"`. |
|
|
67
72
|
| `DbPoolConfig` | Connection pool config (`min`, `max`, `acquireTimeoutMillis`, `idleTimeoutMillis`). |
|
|
68
|
-
| `
|
|
73
|
+
| `OrmOptions` | `createOrm()` options. `database`, `schema` settings that override `DbConnConfig`. |
|
|
69
74
|
|
|
70
75
|
### Constants and Utility Functions
|
|
71
76
|
|
|
@@ -77,12 +82,12 @@ SdOrm (top-level entry point)
|
|
|
77
82
|
|
|
78
83
|
## Usage
|
|
79
84
|
|
|
80
|
-
### Basic Usage with
|
|
85
|
+
### Basic Usage with createOrm
|
|
81
86
|
|
|
82
|
-
`
|
|
87
|
+
`createOrm()` is the top-level factory function used with `DbContext`. It automatically handles transaction management.
|
|
83
88
|
|
|
84
89
|
```typescript
|
|
85
|
-
import {
|
|
90
|
+
import { createOrm } from "@simplysm/orm-node";
|
|
86
91
|
import { DbContext, queryable, Table } from "@simplysm/orm-common";
|
|
87
92
|
|
|
88
93
|
// 1. Define table
|
|
@@ -100,8 +105,8 @@ class MyDb extends DbContext {
|
|
|
100
105
|
readonly user = queryable(this, User);
|
|
101
106
|
}
|
|
102
107
|
|
|
103
|
-
// 3. Create
|
|
104
|
-
const orm =
|
|
108
|
+
// 3. Create ORM instance
|
|
109
|
+
const orm = createOrm(MyDb, {
|
|
105
110
|
dialect: "mysql",
|
|
106
111
|
host: "localhost",
|
|
107
112
|
port: 3306,
|
|
@@ -148,12 +153,12 @@ Supported isolation levels (`IsolationLevel`):
|
|
|
148
153
|
- `"REPEATABLE_READ"`
|
|
149
154
|
- `"SERIALIZABLE"`
|
|
150
155
|
|
|
151
|
-
### Overriding database/schema via
|
|
156
|
+
### Overriding database/schema via OrmOptions
|
|
152
157
|
|
|
153
|
-
Using `
|
|
158
|
+
Using `OrmOptions`, you can use different values instead of the `database`/`schema` set in `DbConnConfig`.
|
|
154
159
|
|
|
155
160
|
```typescript
|
|
156
|
-
const orm =
|
|
161
|
+
const orm = createOrm(MyDb, {
|
|
157
162
|
dialect: "postgresql",
|
|
158
163
|
host: "localhost",
|
|
159
164
|
port: 5432,
|
|
@@ -172,7 +177,7 @@ const orm = new SdOrm(MyDb, {
|
|
|
172
177
|
Configure connection pool via the `pool` field in `DbConnConfig`. The pool is based on the `generic-pool` library, and pools are automatically cached for identical configurations.
|
|
173
178
|
|
|
174
179
|
```typescript
|
|
175
|
-
const orm =
|
|
180
|
+
const orm = createOrm(MyDb, {
|
|
176
181
|
dialect: "mssql",
|
|
177
182
|
host: "localhost",
|
|
178
183
|
port: 1433,
|
|
@@ -188,15 +193,15 @@ const orm = new SdOrm(MyDb, {
|
|
|
188
193
|
});
|
|
189
194
|
```
|
|
190
195
|
|
|
191
|
-
### Low-Level Connection with
|
|
196
|
+
### Low-Level Connection with createDbConn
|
|
192
197
|
|
|
193
|
-
You can connect directly to the DB and execute SQL without `
|
|
198
|
+
You can connect directly to the DB and execute SQL without `createOrm`/`DbContext`. `createDbConn()` returns `PooledDbConn` from the connection pool.
|
|
194
199
|
|
|
195
200
|
```typescript
|
|
196
|
-
import {
|
|
201
|
+
import { createDbConn } from "@simplysm/orm-node";
|
|
197
202
|
|
|
198
203
|
// Create connection (acquire from pool)
|
|
199
|
-
const conn = await
|
|
204
|
+
const conn = await createDbConn({
|
|
200
205
|
dialect: "mysql",
|
|
201
206
|
host: "localhost",
|
|
202
207
|
port: 3306,
|
|
@@ -233,7 +238,7 @@ try {
|
|
|
233
238
|
Each connection class supports parameter binding via the `executeParametrized()` method.
|
|
234
239
|
|
|
235
240
|
```typescript
|
|
236
|
-
const conn = await
|
|
241
|
+
const conn = await createDbConn({
|
|
237
242
|
dialect: "postgresql",
|
|
238
243
|
host: "localhost",
|
|
239
244
|
port: 5432,
|
|
@@ -266,7 +271,7 @@ Supports bulk data insertion using native bulk APIs for each DBMS.
|
|
|
266
271
|
```typescript
|
|
267
272
|
import type { ColumnMeta } from "@simplysm/orm-common";
|
|
268
273
|
|
|
269
|
-
const conn = await
|
|
274
|
+
const conn = await createDbConn({
|
|
270
275
|
dialect: "mysql",
|
|
271
276
|
host: "localhost",
|
|
272
277
|
port: 3306,
|
|
@@ -398,7 +403,7 @@ The common interface implemented by all DBMS-specific connection classes (`Mysql
|
|
|
398
403
|
|
|
399
404
|
### Driver Lazy Loading
|
|
400
405
|
|
|
401
|
-
DBMS-specific drivers (`mysql2`, `tedious`, `pg`) are lazy-loaded within `
|
|
406
|
+
DBMS-specific drivers (`mysql2`, `tedious`, `pg`) are lazy-loaded within `createDbConn()`. Therefore, import errors won't occur even if unused drivers are not installed.
|
|
402
407
|
|
|
403
408
|
### PooledDbConn close Behavior
|
|
404
409
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { DbConn, DbConnConfig } from "./types/db-conn";
|
|
2
|
+
/**
|
|
3
|
+
* DB 연결 생성
|
|
4
|
+
*
|
|
5
|
+
* 커넥션 풀에서 연결을 획득하여 반환한다.
|
|
6
|
+
* 풀이 없는 경우 새로 생성한다.
|
|
7
|
+
*
|
|
8
|
+
* @param config - 데이터베이스 연결 설정
|
|
9
|
+
* @returns 풀링된 DB 연결 객체
|
|
10
|
+
*/
|
|
11
|
+
export declare function createDbConn(config: DbConnConfig): Promise<DbConn>;
|
|
12
|
+
//# sourceMappingURL=create-db-conn.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-db-conn.d.ts","sourceRoot":"","sources":["../src/create-db-conn.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAwB5D;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAMlE"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { createPool } from "generic-pool";
|
|
2
|
+
import { PooledDbConn } from "./pooled-db-conn.js";
|
|
3
|
+
import { MysqlDbConn } from "./connections/mysql-db-conn.js";
|
|
4
|
+
import { MssqlDbConn } from "./connections/mssql-db-conn.js";
|
|
5
|
+
import { PostgresqlDbConn } from "./connections/postgresql-db-conn.js";
|
|
6
|
+
const poolMap = /* @__PURE__ */ new Map();
|
|
7
|
+
const modules = {};
|
|
8
|
+
function createDbConn(config) {
|
|
9
|
+
const pool = getOrCreatePool(config);
|
|
10
|
+
return Promise.resolve(new PooledDbConn(pool, config));
|
|
11
|
+
}
|
|
12
|
+
function getOrCreatePool(config) {
|
|
13
|
+
const configKey = JSON.stringify(
|
|
14
|
+
config,
|
|
15
|
+
(_, value) => value != null && typeof value === "object" && !Array.isArray(value) ? Object.fromEntries(Object.entries(value).sort(([a], [b]) => a.localeCompare(b))) : value
|
|
16
|
+
);
|
|
17
|
+
if (!poolMap.has(configKey)) {
|
|
18
|
+
const pool = createPool(
|
|
19
|
+
{
|
|
20
|
+
create: async () => {
|
|
21
|
+
const conn = await createRawConnection(config);
|
|
22
|
+
await conn.connect();
|
|
23
|
+
return conn;
|
|
24
|
+
},
|
|
25
|
+
destroy: async (conn) => {
|
|
26
|
+
await conn.close();
|
|
27
|
+
},
|
|
28
|
+
validate: (conn) => {
|
|
29
|
+
return Promise.resolve(conn.isConnected);
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
min: config.pool?.min ?? 1,
|
|
34
|
+
max: config.pool?.max ?? 10,
|
|
35
|
+
acquireTimeoutMillis: config.pool?.acquireTimeoutMillis ?? 3e4,
|
|
36
|
+
idleTimeoutMillis: config.pool?.idleTimeoutMillis ?? 3e4,
|
|
37
|
+
testOnBorrow: true
|
|
38
|
+
// [중요] 빌려줄 때 validate 실행 여부
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
poolMap.set(configKey, pool);
|
|
42
|
+
}
|
|
43
|
+
return poolMap.get(configKey);
|
|
44
|
+
}
|
|
45
|
+
async function createRawConnection(config) {
|
|
46
|
+
if (config.dialect === "mysql") {
|
|
47
|
+
const mysql = await ensureModule("mysql");
|
|
48
|
+
return new MysqlDbConn(mysql, config);
|
|
49
|
+
} else if (config.dialect === "postgresql") {
|
|
50
|
+
const pg = await ensureModule("pg");
|
|
51
|
+
const pgCopyStreams = await ensureModule("pgCopyStreams");
|
|
52
|
+
return new PostgresqlDbConn(pg, pgCopyStreams.from, config);
|
|
53
|
+
} else {
|
|
54
|
+
const tedious = await ensureModule("tedious");
|
|
55
|
+
return new MssqlDbConn(tedious, config);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
async function ensureModule(name) {
|
|
59
|
+
if (modules[name] == null) {
|
|
60
|
+
if (name === "mysql") {
|
|
61
|
+
modules.mysql = await import("mysql2/promise");
|
|
62
|
+
} else if (name === "pg") {
|
|
63
|
+
modules.pg = await import("pg");
|
|
64
|
+
} else if (name === "pgCopyStreams") {
|
|
65
|
+
modules.pgCopyStreams = await import("pg-copy-streams");
|
|
66
|
+
} else {
|
|
67
|
+
modules.tedious = await import("tedious");
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return modules[name];
|
|
71
|
+
}
|
|
72
|
+
export {
|
|
73
|
+
createDbConn
|
|
74
|
+
};
|
|
75
|
+
//# sourceMappingURL=create-db-conn.js.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/create-db-conn.ts"],
|
|
4
|
+
"mappings": "AACA,SAAS,kBAAkB;AAE3B,SAAS,oBAAoB;AAC7B,SAAS,mBAAmB;AAC5B,SAAS,mBAAmB;AAC5B,SAAS,wBAAwB;AAUjC,MAAM,UAAU,oBAAI,IAA0B;AAG9C,MAAM,UAKF,CAAC;AAWE,SAAS,aAAa,QAAuC;AAElE,QAAM,OAAO,gBAAgB,MAAM;AAGnC,SAAO,QAAQ,QAAQ,IAAI,aAAa,MAAM,MAAM,CAAC;AACvD;AAEA,SAAS,gBAAgB,QAAoC;AAE3D,QAAM,YAAY,KAAK;AAAA,IAAU;AAAA,IAAQ,CAAC,GAAG,UAC3C,SAAS,QAAQ,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK,IAC9D,OAAO,YAAY,OAAO,QAAQ,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC,IAC/E;AAAA,EACN;AAEA,MAAI,CAAC,QAAQ,IAAI,SAAS,GAAG;AAC3B,UAAM,OAAO;AAAA,MACX;AAAA,QACE,QAAQ,YAAY;AAClB,gBAAM,OAAO,MAAM,oBAAoB,MAAM;AAC7C,gBAAM,KAAK,QAAQ;AACnB,iBAAO;AAAA,QACT;AAAA,QACA,SAAS,OAAO,SAAS;AACvB,gBAAM,KAAK,MAAM;AAAA,QACnB;AAAA,QACA,UAAU,CAAC,SAAS;AAElB,iBAAO,QAAQ,QAAQ,KAAK,WAAW;AAAA,QACzC;AAAA,MACF;AAAA,MACA;AAAA,QACE,KAAK,OAAO,MAAM,OAAO;AAAA,QACzB,KAAK,OAAO,MAAM,OAAO;AAAA,QACzB,sBAAsB,OAAO,MAAM,wBAAwB;AAAA,QAC3D,mBAAmB,OAAO,MAAM,qBAAqB;AAAA,QACrD,cAAc;AAAA;AAAA,MAChB;AAAA,IACF;AAEA,YAAQ,IAAI,WAAW,IAAI;AAAA,EAC7B;AAEA,SAAO,QAAQ,IAAI,SAAS;AAC9B;AAEA,eAAe,oBAAoB,QAAuC;AACxE,MAAI,OAAO,YAAY,SAAS;AAC9B,UAAM,QAAQ,MAAM,aAAa,OAAO;AACxC,WAAO,IAAI,YAAY,OAAO,MAAM;AAAA,EACtC,WAAW,OAAO,YAAY,cAAc;AAC1C,UAAM,KAAK,MAAM,aAAa,IAAI;AAClC,UAAM,gBAAgB,MAAM,aAAa,eAAe;AACxD,WAAO,IAAI,iBAAiB,IAAI,cAAc,MAAM,MAAM;AAAA,EAC5D,OAAO;AAEL,UAAM,UAAU,MAAM,aAAa,SAAS;AAC5C,WAAO,IAAI,YAAY,SAAS,MAAM;AAAA,EACxC;AACF;AAEA,eAAe,aAA6C,MAAoD;AAC9G,MAAI,QAAQ,IAAI,KAAK,MAAM;AACzB,QAAI,SAAS,SAAS;AACpB,cAAQ,QAAQ,MAAM,OAAO,gBAAgB;AAAA,IAC/C,WAAW,SAAS,MAAM;AACxB,cAAQ,KAAK,MAAM,OAAO,IAAI;AAAA,IAChC,WAAW,SAAS,iBAAiB;AACnC,cAAQ,gBAAgB,MAAM,OAAO,iBAAiB;AAAA,IACxD,OAAO;AACL,cAAQ,UAAU,MAAM,OAAO,SAAS;AAAA,IAC1C;AAAA,EACF;AACA,SAAO,QAAQ,IAAI;AACrB;",
|
|
5
|
+
"names": []
|
|
6
|
+
}
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import type { Type } from "@simplysm/core-common";
|
|
1
|
+
import { type DbContextDef, type DbContextInstance, type IsolationLevel } from "@simplysm/orm-common";
|
|
3
2
|
import type { DbConnConfig } from "./types/db-conn";
|
|
4
3
|
/**
|
|
5
|
-
*
|
|
4
|
+
* Orm 옵션
|
|
6
5
|
*
|
|
7
6
|
* DbConnConfig보다 우선 적용되는 DbContext 옵션
|
|
8
7
|
*/
|
|
9
|
-
export interface
|
|
8
|
+
export interface OrmOptions {
|
|
10
9
|
/**
|
|
11
10
|
* 데이터베이스 이름 (DbConnConfig의 database 대신 사용)
|
|
12
11
|
*/
|
|
@@ -17,18 +16,43 @@ export interface SdOrmOptions {
|
|
|
17
16
|
schema?: string;
|
|
18
17
|
}
|
|
19
18
|
/**
|
|
20
|
-
*
|
|
19
|
+
* Orm 인스턴스 타입
|
|
21
20
|
*
|
|
22
|
-
*
|
|
23
|
-
|
|
21
|
+
* createOrm에서 반환되는 객체의 타입
|
|
22
|
+
*/
|
|
23
|
+
export interface Orm<TDef extends DbContextDef<any, any, any>> {
|
|
24
|
+
readonly dbContextDef: TDef;
|
|
25
|
+
readonly config: DbConnConfig;
|
|
26
|
+
readonly options?: OrmOptions;
|
|
27
|
+
/**
|
|
28
|
+
* 트랜잭션 내에서 콜백 실행
|
|
29
|
+
*
|
|
30
|
+
* @param callback - DB 연결 후 실행할 콜백
|
|
31
|
+
* @param isolationLevel - 트랜잭션 격리 수준
|
|
32
|
+
* @returns 콜백 결과
|
|
33
|
+
*/
|
|
34
|
+
connect<R>(callback: (conn: DbContextInstance<TDef>) => Promise<R>, isolationLevel?: IsolationLevel): Promise<R>;
|
|
35
|
+
/**
|
|
36
|
+
* 트랜잭션 없이 콜백 실행
|
|
37
|
+
*
|
|
38
|
+
* @param callback - DB 연결 후 실행할 콜백
|
|
39
|
+
* @returns 콜백 결과
|
|
40
|
+
*/
|
|
41
|
+
connectWithoutTransaction<R>(callback: (conn: DbContextInstance<TDef>) => Promise<R>): Promise<R>;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Node.js ORM 팩토리 함수
|
|
45
|
+
*
|
|
46
|
+
* DbContext와 DB 연결을 관리하는 인스턴스를 생성합니다.
|
|
47
|
+
* DbContext 정의와 연결 설정을 받아 트랜잭션을 관리합니다.
|
|
24
48
|
*
|
|
25
49
|
* @example
|
|
26
50
|
* ```typescript
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* }
|
|
51
|
+
* const MyDb = defineDbContext({
|
|
52
|
+
* user: (db) => queryable(db, User),
|
|
53
|
+
* });
|
|
30
54
|
*
|
|
31
|
-
* const orm =
|
|
55
|
+
* const orm = createOrm(MyDb, {
|
|
32
56
|
* dialect: "mysql",
|
|
33
57
|
* host: "localhost",
|
|
34
58
|
* port: 3306,
|
|
@@ -50,29 +74,5 @@ export interface SdOrmOptions {
|
|
|
50
74
|
* });
|
|
51
75
|
* ```
|
|
52
76
|
*/
|
|
53
|
-
export declare
|
|
54
|
-
|
|
55
|
-
readonly config: DbConnConfig;
|
|
56
|
-
readonly options?: SdOrmOptions | undefined;
|
|
57
|
-
constructor(dbContextType: Type<T>, config: DbConnConfig, options?: SdOrmOptions | undefined);
|
|
58
|
-
/**
|
|
59
|
-
* 트랜잭션 내에서 콜백 실행
|
|
60
|
-
*
|
|
61
|
-
* @param callback - DB 연결 후 실행할 콜백
|
|
62
|
-
* @param isolationLevel - 트랜잭션 격리 수준
|
|
63
|
-
* @returns 콜백 결과
|
|
64
|
-
*/
|
|
65
|
-
connect<R>(callback: (conn: T) => Promise<R>, isolationLevel?: IsolationLevel): Promise<R>;
|
|
66
|
-
/**
|
|
67
|
-
* 트랜잭션 없이 콜백 실행
|
|
68
|
-
*
|
|
69
|
-
* @param callback - DB 연결 후 실행할 콜백
|
|
70
|
-
* @returns 콜백 결과
|
|
71
|
-
*/
|
|
72
|
-
connectWithoutTransaction<R>(callback: (conn: T) => Promise<R>): Promise<R>;
|
|
73
|
-
/**
|
|
74
|
-
* DbContext 인스턴스 생성
|
|
75
|
-
*/
|
|
76
|
-
private _createDbContext;
|
|
77
|
-
}
|
|
78
|
-
//# sourceMappingURL=sd-orm.d.ts.map
|
|
77
|
+
export declare function createOrm<TDef extends DbContextDef<any, any, any>>(dbContextDef: TDef, config: DbConnConfig, options?: OrmOptions): Orm<TDef>;
|
|
78
|
+
//# sourceMappingURL=create-orm.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-orm.d.ts","sourceRoot":"","sources":["../src/create-orm.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,YAAY,EAAE,KAAK,iBAAiB,EAAE,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACvH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAGpD;;;;GAIG;AACH,MAAM,WAAW,UAAU;IACzB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,MAAM,WAAW,GAAG,CAAC,IAAI,SAAS,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IAC3D,QAAQ,CAAC,YAAY,EAAE,IAAI,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,OAAO,CAAC,EAAE,UAAU,CAAC;IAE9B;;;;;;OAMG;IACH,OAAO,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,iBAAiB,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,EAAE,cAAc,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAEjH;;;;;OAKG;IACH,yBAAyB,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,iBAAiB,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CACnG;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAgB,SAAS,CAAC,IAAI,SAAS,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,EAChE,YAAY,EAAE,IAAI,EAClB,MAAM,EAAE,YAAY,EACpB,OAAO,CAAC,EAAE,UAAU,GACnB,GAAG,CAAC,IAAI,CAAC,CA8BX"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { createDbContext } from "@simplysm/orm-common";
|
|
2
|
+
import { NodeDbContextExecutor } from "./node-db-context-executor.js";
|
|
3
|
+
function createOrm(dbContextDef, config, options) {
|
|
4
|
+
function _createDbContext() {
|
|
5
|
+
const database = options?.database ?? ("database" in config ? config.database : void 0);
|
|
6
|
+
if (database == null || database === "") {
|
|
7
|
+
throw new Error("database is required");
|
|
8
|
+
}
|
|
9
|
+
const schema = options?.schema ?? ("schema" in config ? config.schema : void 0);
|
|
10
|
+
return createDbContext(dbContextDef, new NodeDbContextExecutor(config), {
|
|
11
|
+
database,
|
|
12
|
+
schema
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
return {
|
|
16
|
+
dbContextDef,
|
|
17
|
+
config,
|
|
18
|
+
options,
|
|
19
|
+
async connect(callback, isolationLevel) {
|
|
20
|
+
const db = _createDbContext();
|
|
21
|
+
return db.connect(async () => callback(db), isolationLevel);
|
|
22
|
+
},
|
|
23
|
+
async connectWithoutTransaction(callback) {
|
|
24
|
+
const db = _createDbContext();
|
|
25
|
+
return db.connectWithoutTransaction(async () => callback(db));
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export {
|
|
30
|
+
createOrm
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=create-orm.js.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/create-orm.ts"],
|
|
4
|
+
"mappings": "AAAA,SAAS,uBAAuF;AAEhG,SAAS,6BAA6B;AAiF/B,SAAS,UACd,cACA,QACA,SACW;AACX,WAAS,mBAA4C;AAEnD,UAAM,WAAW,SAAS,aAAa,cAAc,SAAS,OAAO,WAAW;AAChF,QAAI,YAAY,QAAQ,aAAa,IAAI;AACvC,YAAM,IAAI,MAAM,sBAAsB;AAAA,IACxC;AAGA,UAAM,SAAS,SAAS,WAAW,YAAY,SAAS,OAAO,SAAS;AAExE,WAAO,gBAAgB,cAAc,IAAI,sBAAsB,MAAM,GAAG;AAAA,MACtE;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,MAAM,QAAQ,UAAU,gBAAiB;AACvC,YAAM,KAAK,iBAAiB;AAC5B,aAAO,GAAG,QAAQ,YAAY,SAAS,EAAE,GAAG,cAAc;AAAA,IAC5D;AAAA,IACA,MAAM,0BAA0B,UAAU;AACxC,YAAM,KAAK,iBAAiB;AAC5B,aAAO,GAAG,0BAA0B,YAAY,SAAS,EAAE,CAAC;AAAA,IAC9D;AAAA,EACF;AACF;",
|
|
5
|
+
"names": []
|
|
6
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,8 +2,8 @@ export * from "./types/db-conn";
|
|
|
2
2
|
export * from "./connections/mssql-db-conn";
|
|
3
3
|
export * from "./connections/mysql-db-conn";
|
|
4
4
|
export * from "./connections/postgresql-db-conn";
|
|
5
|
-
export * from "./db-conn
|
|
5
|
+
export * from "./create-db-conn";
|
|
6
6
|
export * from "./node-db-context-executor";
|
|
7
7
|
export * from "./pooled-db-conn";
|
|
8
|
-
export * from "./
|
|
8
|
+
export * from "./create-orm";
|
|
9
9
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,iBAAiB,CAAC;AAGhC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,kCAAkC,CAAC;AAGjD,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,iBAAiB,CAAC;AAGhC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,kCAAkC,CAAC;AAGjD,cAAc,kBAAkB,CAAC;AACjC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -2,8 +2,8 @@ export * from "./types/db-conn.js";
|
|
|
2
2
|
export * from "./connections/mssql-db-conn.js";
|
|
3
3
|
export * from "./connections/mysql-db-conn.js";
|
|
4
4
|
export * from "./connections/postgresql-db-conn.js";
|
|
5
|
-
export * from "./db-conn
|
|
5
|
+
export * from "./create-db-conn.js";
|
|
6
6
|
export * from "./node-db-context-executor.js";
|
|
7
7
|
export * from "./pooled-db-conn.js";
|
|
8
|
-
export * from "./
|
|
8
|
+
export * from "./create-orm.js";
|
|
9
9
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { SdError } from "@simplysm/core-common";
|
|
2
2
|
import { createQueryBuilder, parseQueryResult } from "@simplysm/orm-common";
|
|
3
3
|
import { DB_CONN_ERRORS, getDialectFromConfig } from "./types/db-conn.js";
|
|
4
|
-
import {
|
|
4
|
+
import { createDbConn } from "./create-db-conn.js";
|
|
5
5
|
class NodeDbContextExecutor {
|
|
6
6
|
constructor(_config) {
|
|
7
7
|
this._config = _config;
|
|
@@ -15,7 +15,7 @@ class NodeDbContextExecutor {
|
|
|
15
15
|
* 커넥션 풀에서 연결을 획득하고 연결 상태를 활성화한다.
|
|
16
16
|
*/
|
|
17
17
|
async connect() {
|
|
18
|
-
this._conn = await
|
|
18
|
+
this._conn = await createDbConn(this._config);
|
|
19
19
|
await this._conn.connect();
|
|
20
20
|
}
|
|
21
21
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/node-db-context-executor.ts"],
|
|
4
|
-
"mappings": "AAAA,SAAS,eAAe;AAUxB,SAAS,oBAAoB,wBAAwB;AAErD,SAAS,gBAAgB,4BAA4B;AACrD,SAAS,
|
|
4
|
+
"mappings": "AAAA,SAAS,eAAe;AAUxB,SAAS,oBAAoB,wBAAwB;AAErD,SAAS,gBAAgB,4BAA4B;AACrD,SAAS,oBAAoB;AAOtB,MAAM,sBAAmD;AAAA,EAI9D,YAA6B,SAAuB;AAAvB;AAC3B,SAAK,WAAW,qBAAqB,OAAO;AAAA,EAC9C;AAAA,EALQ;AAAA,EACS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWjB,MAAM,UAAyB;AAC7B,SAAK,QAAQ,MAAM,aAAa,KAAK,OAAO;AAC5C,UAAM,KAAK,MAAM,QAAQ;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,QAAuB;AAC3B,UAAM,OAAO,KAAK,aAAa;AAC/B,UAAM,KAAK,MAAM;AACjB,SAAK,QAAQ;AAAA,EACf;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,iBAAiB,gBAAgD;AACrE,UAAM,OAAO,KAAK,aAAa;AAC/B,UAAM,KAAK,iBAAiB,cAAc;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,oBAAmC;AACvC,UAAM,OAAO,KAAK,aAAa;AAC/B,UAAM,KAAK,kBAAkB;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,sBAAqC;AACzC,UAAM,OAAO,KAAK,aAAa;AAC/B,UAAM,KAAK,oBAAoB;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,oBAAoB,OAAe,QAA0C;AACjF,UAAM,OAAO,KAAK,aAAa;AAC/B,WAAO,KAAK,oBAAoB,OAAO,MAAM;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,WAAW,WAAmB,aAAyC,SAAsC;AACjH,UAAM,OAAO,KAAK,aAAa;AAC/B,UAAM,KAAK,WAAW,WAAW,aAAa,OAAO;AAAA,EACvD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,YAA4B,MAAkB,aAA0D;AAC5G,UAAM,OAAO,KAAK,aAAa;AAE/B,UAAM,UAAU,mBAAmB,KAAK,QAAQ;AAIhD,QAAI,eAAe,QAAQ,YAAY,MAAM,CAAC,SAAS,QAAQ,IAAI,GAAG;AACpE,YAAM,cAAc,KAAK,IAAI,CAAC,QAAQ,QAAQ,MAAM,GAAG,EAAE,GAAG,EAAE,KAAK,IAAI;AACvE,YAAM,KAAK,QAAQ,CAAC,WAAW,CAAC;AAChC,aAAO,KAAK,IAAI,MAAM,CAAC,CAAC;AAAA,IAC1B;AAGA,UAAM,UAAiB,CAAC;AACxB,aAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,YAAM,MAAM,KAAK,CAAC;AAClB,YAAM,OAAO,cAAc,CAAC;AAC5B,YAAM,cAAc,QAAQ,MAAM,GAAG;AAErC,YAAM,aAAa,MAAM,KAAK,QAAQ,CAAC,YAAY,GAAG,CAAC;AAGvD,YAAM,kBACJ,YAAY,kBAAkB,OAAO,WAAW,YAAY,cAAc,IAAI,WAAW,CAAC;AAE5F,UAAI,QAAQ,MAAM;AAChB,cAAM,SAAS,MAAM,iBAAoB,iBAA8C,IAAI;AAC3F,gBAAQ,KAAK,UAAU,CAAC,CAAC;AAAA,MAC3B,OAAO;AACL,gBAAQ,KAAK,eAAsB;AAAA,MACrC;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEQ,eAAuB;AAC7B,QAAI,KAAK,SAAS,MAAM;AACtB,YAAM,IAAI,QAAQ,eAAe,aAAa;AAAA,IAChD;AACA,WAAO,KAAK;AAAA,EACd;AACF;",
|
|
5
5
|
"names": []
|
|
6
6
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@simplysm/orm-node",
|
|
3
3
|
"sideEffects": false,
|
|
4
|
-
"version": "13.0.
|
|
4
|
+
"version": "13.0.1",
|
|
5
5
|
"description": "심플리즘 패키지 - ORM 모듈 (node)",
|
|
6
6
|
"author": "김석래",
|
|
7
7
|
"repository": {
|
|
@@ -20,8 +20,8 @@
|
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"consola": "^3.4.2",
|
|
22
22
|
"generic-pool": "^3.9.0",
|
|
23
|
-
"@simplysm/core-common": "13.0.
|
|
24
|
-
"@simplysm/orm-common": "13.0.
|
|
23
|
+
"@simplysm/core-common": "13.0.1",
|
|
24
|
+
"@simplysm/orm-common": "13.0.1"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@types/pg": "^8.16.0",
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import type { Pool } from "generic-pool";
|
|
2
|
+
import { createPool } from "generic-pool";
|
|
3
|
+
import type { DbConn, DbConnConfig } from "./types/db-conn";
|
|
4
|
+
import { PooledDbConn } from "./pooled-db-conn";
|
|
5
|
+
import { MysqlDbConn } from "./connections/mysql-db-conn";
|
|
6
|
+
import { MssqlDbConn } from "./connections/mssql-db-conn";
|
|
7
|
+
import { PostgresqlDbConn } from "./connections/postgresql-db-conn";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* DB 연결 팩토리
|
|
11
|
+
*
|
|
12
|
+
* 데이터베이스 연결 인스턴스를 생성하고 풀링을 관리한다.
|
|
13
|
+
* MSSQL, MySQL, PostgreSQL을 지원한다.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
// 설정별 커넥션 풀 캐싱
|
|
17
|
+
const poolMap = new Map<string, Pool<DbConn>>();
|
|
18
|
+
|
|
19
|
+
// 지연 로딩 모듈 캐시
|
|
20
|
+
const modules: {
|
|
21
|
+
tedious?: typeof import("tedious");
|
|
22
|
+
mysql?: typeof import("mysql2/promise");
|
|
23
|
+
pg?: typeof import("pg");
|
|
24
|
+
pgCopyStreams?: typeof import("pg-copy-streams");
|
|
25
|
+
} = {};
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* DB 연결 생성
|
|
29
|
+
*
|
|
30
|
+
* 커넥션 풀에서 연결을 획득하여 반환한다.
|
|
31
|
+
* 풀이 없는 경우 새로 생성한다.
|
|
32
|
+
*
|
|
33
|
+
* @param config - 데이터베이스 연결 설정
|
|
34
|
+
* @returns 풀링된 DB 연결 객체
|
|
35
|
+
*/
|
|
36
|
+
export function createDbConn(config: DbConnConfig): Promise<DbConn> {
|
|
37
|
+
// 1. 풀 가져오기 (없으면 생성)
|
|
38
|
+
const pool = getOrCreatePool(config);
|
|
39
|
+
|
|
40
|
+
// 2. 래퍼 객체 반환
|
|
41
|
+
return Promise.resolve(new PooledDbConn(pool, config));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function getOrCreatePool(config: DbConnConfig): Pool<DbConn> {
|
|
45
|
+
// 객체를 키로 쓰기 위해 문자열 변환 (중첩 객체도 정렬하여 동일 설정의 일관된 키 보장)
|
|
46
|
+
const configKey = JSON.stringify(config, (_, value: unknown) =>
|
|
47
|
+
value != null && typeof value === "object" && !Array.isArray(value)
|
|
48
|
+
? Object.fromEntries(Object.entries(value).sort(([a], [b]) => a.localeCompare(b)))
|
|
49
|
+
: value,
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
if (!poolMap.has(configKey)) {
|
|
53
|
+
const pool = createPool<DbConn>(
|
|
54
|
+
{
|
|
55
|
+
create: async () => {
|
|
56
|
+
const conn = await createRawConnection(config);
|
|
57
|
+
await conn.connect();
|
|
58
|
+
return conn;
|
|
59
|
+
},
|
|
60
|
+
destroy: async (conn) => {
|
|
61
|
+
await conn.close(); // 풀에서 제거될 때 실제 연결 종료
|
|
62
|
+
},
|
|
63
|
+
validate: (conn) => {
|
|
64
|
+
// 획득 시 연결 상태 확인 (끊겨있으면 Pool이 폐기하고 새로 만듦)
|
|
65
|
+
return Promise.resolve(conn.isConnected);
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
min: config.pool?.min ?? 1,
|
|
70
|
+
max: config.pool?.max ?? 10,
|
|
71
|
+
acquireTimeoutMillis: config.pool?.acquireTimeoutMillis ?? 30000,
|
|
72
|
+
idleTimeoutMillis: config.pool?.idleTimeoutMillis ?? 30000,
|
|
73
|
+
testOnBorrow: true, // [중요] 빌려줄 때 validate 실행 여부
|
|
74
|
+
},
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
poolMap.set(configKey, pool);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return poolMap.get(configKey)!;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async function createRawConnection(config: DbConnConfig): Promise<DbConn> {
|
|
84
|
+
if (config.dialect === "mysql") {
|
|
85
|
+
const mysql = await ensureModule("mysql");
|
|
86
|
+
return new MysqlDbConn(mysql, config);
|
|
87
|
+
} else if (config.dialect === "postgresql") {
|
|
88
|
+
const pg = await ensureModule("pg");
|
|
89
|
+
const pgCopyStreams = await ensureModule("pgCopyStreams");
|
|
90
|
+
return new PostgresqlDbConn(pg, pgCopyStreams.from, config);
|
|
91
|
+
} else {
|
|
92
|
+
// mssql, mssql-azure
|
|
93
|
+
const tedious = await ensureModule("tedious");
|
|
94
|
+
return new MssqlDbConn(tedious, config);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async function ensureModule<K extends keyof typeof modules>(name: K): Promise<NonNullable<(typeof modules)[K]>> {
|
|
99
|
+
if (modules[name] == null) {
|
|
100
|
+
if (name === "mysql") {
|
|
101
|
+
modules.mysql = await import("mysql2/promise");
|
|
102
|
+
} else if (name === "pg") {
|
|
103
|
+
modules.pg = await import("pg");
|
|
104
|
+
} else if (name === "pgCopyStreams") {
|
|
105
|
+
modules.pgCopyStreams = await import("pg-copy-streams");
|
|
106
|
+
} else {
|
|
107
|
+
modules.tedious = await import("tedious");
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return modules[name]!;
|
|
111
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { createDbContext, type DbContextDef, type DbContextInstance, type IsolationLevel } from "@simplysm/orm-common";
|
|
2
|
+
import type { DbConnConfig } from "./types/db-conn";
|
|
3
|
+
import { NodeDbContextExecutor } from "./node-db-context-executor";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Orm 옵션
|
|
7
|
+
*
|
|
8
|
+
* DbConnConfig보다 우선 적용되는 DbContext 옵션
|
|
9
|
+
*/
|
|
10
|
+
export interface OrmOptions {
|
|
11
|
+
/**
|
|
12
|
+
* 데이터베이스 이름 (DbConnConfig의 database 대신 사용)
|
|
13
|
+
*/
|
|
14
|
+
database?: string;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* 스키마 이름 (MSSQL: dbo, PostgreSQL: public)
|
|
18
|
+
*/
|
|
19
|
+
schema?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Orm 인스턴스 타입
|
|
24
|
+
*
|
|
25
|
+
* createOrm에서 반환되는 객체의 타입
|
|
26
|
+
*/
|
|
27
|
+
export interface Orm<TDef extends DbContextDef<any, any, any>> {
|
|
28
|
+
readonly dbContextDef: TDef;
|
|
29
|
+
readonly config: DbConnConfig;
|
|
30
|
+
readonly options?: OrmOptions;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* 트랜잭션 내에서 콜백 실행
|
|
34
|
+
*
|
|
35
|
+
* @param callback - DB 연결 후 실행할 콜백
|
|
36
|
+
* @param isolationLevel - 트랜잭션 격리 수준
|
|
37
|
+
* @returns 콜백 결과
|
|
38
|
+
*/
|
|
39
|
+
connect<R>(callback: (conn: DbContextInstance<TDef>) => Promise<R>, isolationLevel?: IsolationLevel): Promise<R>;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* 트랜잭션 없이 콜백 실행
|
|
43
|
+
*
|
|
44
|
+
* @param callback - DB 연결 후 실행할 콜백
|
|
45
|
+
* @returns 콜백 결과
|
|
46
|
+
*/
|
|
47
|
+
connectWithoutTransaction<R>(callback: (conn: DbContextInstance<TDef>) => Promise<R>): Promise<R>;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Node.js ORM 팩토리 함수
|
|
52
|
+
*
|
|
53
|
+
* DbContext와 DB 연결을 관리하는 인스턴스를 생성합니다.
|
|
54
|
+
* DbContext 정의와 연결 설정을 받아 트랜잭션을 관리합니다.
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```typescript
|
|
58
|
+
* const MyDb = defineDbContext({
|
|
59
|
+
* user: (db) => queryable(db, User),
|
|
60
|
+
* });
|
|
61
|
+
*
|
|
62
|
+
* const orm = createOrm(MyDb, {
|
|
63
|
+
* dialect: "mysql",
|
|
64
|
+
* host: "localhost",
|
|
65
|
+
* port: 3306,
|
|
66
|
+
* username: "root",
|
|
67
|
+
* password: "password",
|
|
68
|
+
* database: "mydb",
|
|
69
|
+
* });
|
|
70
|
+
*
|
|
71
|
+
* // 트랜잭션 내에서 실행
|
|
72
|
+
* await orm.connect(async (db) => {
|
|
73
|
+
* const users = await db.user().result();
|
|
74
|
+
* return users;
|
|
75
|
+
* });
|
|
76
|
+
*
|
|
77
|
+
* // 트랜잭션 없이 실행
|
|
78
|
+
* await orm.connectWithoutTransaction(async (db) => {
|
|
79
|
+
* const users = await db.user().result();
|
|
80
|
+
* return users;
|
|
81
|
+
* });
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
export function createOrm<TDef extends DbContextDef<any, any, any>>(
|
|
85
|
+
dbContextDef: TDef,
|
|
86
|
+
config: DbConnConfig,
|
|
87
|
+
options?: OrmOptions,
|
|
88
|
+
): Orm<TDef> {
|
|
89
|
+
function _createDbContext(): DbContextInstance<TDef> {
|
|
90
|
+
// database는 options에서 우선, 없으면 config에서
|
|
91
|
+
const database = options?.database ?? ("database" in config ? config.database : undefined);
|
|
92
|
+
if (database == null || database === "") {
|
|
93
|
+
throw new Error("database is required");
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// schema는 options에서 우선, 없으면 config에서
|
|
97
|
+
const schema = options?.schema ?? ("schema" in config ? config.schema : undefined);
|
|
98
|
+
|
|
99
|
+
return createDbContext(dbContextDef, new NodeDbContextExecutor(config), {
|
|
100
|
+
database,
|
|
101
|
+
schema,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
dbContextDef,
|
|
107
|
+
config,
|
|
108
|
+
options,
|
|
109
|
+
async connect(callback, isolationLevel?) {
|
|
110
|
+
const db = _createDbContext();
|
|
111
|
+
return db.connect(async () => callback(db), isolationLevel);
|
|
112
|
+
},
|
|
113
|
+
async connectWithoutTransaction(callback) {
|
|
114
|
+
const db = _createDbContext();
|
|
115
|
+
return db.connectWithoutTransaction(async () => callback(db));
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -7,7 +7,7 @@ export * from "./connections/mysql-db-conn";
|
|
|
7
7
|
export * from "./connections/postgresql-db-conn";
|
|
8
8
|
|
|
9
9
|
// Core
|
|
10
|
-
export * from "./db-conn
|
|
10
|
+
export * from "./create-db-conn";
|
|
11
11
|
export * from "./node-db-context-executor";
|
|
12
12
|
export * from "./pooled-db-conn";
|
|
13
|
-
export * from "./
|
|
13
|
+
export * from "./create-orm";
|
|
@@ -11,7 +11,7 @@ import type {
|
|
|
11
11
|
import { createQueryBuilder, parseQueryResult } from "@simplysm/orm-common";
|
|
12
12
|
import type { DbConn, DbConnConfig } from "./types/db-conn";
|
|
13
13
|
import { DB_CONN_ERRORS, getDialectFromConfig } from "./types/db-conn";
|
|
14
|
-
import {
|
|
14
|
+
import { createDbConn } from "./create-db-conn";
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* Node.js 환경용 DbContextExecutor
|
|
@@ -32,7 +32,7 @@ export class NodeDbContextExecutor implements DbContextExecutor {
|
|
|
32
32
|
* 커넥션 풀에서 연결을 획득하고 연결 상태를 활성화한다.
|
|
33
33
|
*/
|
|
34
34
|
async connect(): Promise<void> {
|
|
35
|
-
this._conn = await
|
|
35
|
+
this._conn = await createDbConn(this._config);
|
|
36
36
|
await this._conn.connect();
|
|
37
37
|
}
|
|
38
38
|
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import type { DbConn, DbConnConfig } from "./types/db-conn";
|
|
2
|
-
/**
|
|
3
|
-
* DB 연결 팩토리
|
|
4
|
-
*
|
|
5
|
-
* 데이터베이스 연결 인스턴스를 생성하고 풀링을 관리한다.
|
|
6
|
-
* MSSQL, MySQL, PostgreSQL을 지원한다.
|
|
7
|
-
*/
|
|
8
|
-
export declare class DbConnFactory {
|
|
9
|
-
private static readonly _poolMap;
|
|
10
|
-
/**
|
|
11
|
-
* DB 연결 생성
|
|
12
|
-
*
|
|
13
|
-
* 커넥션 풀에서 연결을 획득하여 반환한다.
|
|
14
|
-
* 풀이 없는 경우 새로 생성한다.
|
|
15
|
-
*
|
|
16
|
-
* @param config - 데이터베이스 연결 설정
|
|
17
|
-
* @returns 풀링된 DB 연결 객체
|
|
18
|
-
*/
|
|
19
|
-
static create(config: DbConnConfig): Promise<DbConn>;
|
|
20
|
-
private static _getOrCreatePool;
|
|
21
|
-
private static _createRawConnection;
|
|
22
|
-
private static readonly _modules;
|
|
23
|
-
private static _ensureModule;
|
|
24
|
-
}
|
|
25
|
-
//# sourceMappingURL=db-conn-factory.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"db-conn-factory.d.ts","sourceRoot":"","sources":["../src/db-conn-factory.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAM5D;;;;;GAKG;AACH,qBAAa,aAAa;IAExB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAmC;IAEnE;;;;;;;;OAQG;IACH,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IAQpD,OAAO,CAAC,MAAM,CAAC,gBAAgB;mBAuCV,oBAAoB;IAgBzC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAKzB;mBAEc,aAAa;CAgBnC"}
|
package/dist/db-conn-factory.js
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import { createPool } from "generic-pool";
|
|
2
|
-
import { PooledDbConn } from "./pooled-db-conn.js";
|
|
3
|
-
import { MysqlDbConn } from "./connections/mysql-db-conn.js";
|
|
4
|
-
import { MssqlDbConn } from "./connections/mssql-db-conn.js";
|
|
5
|
-
import { PostgresqlDbConn } from "./connections/postgresql-db-conn.js";
|
|
6
|
-
class DbConnFactory {
|
|
7
|
-
// 설정별 커넥션 풀 캐싱
|
|
8
|
-
static _poolMap = /* @__PURE__ */ new Map();
|
|
9
|
-
/**
|
|
10
|
-
* DB 연결 생성
|
|
11
|
-
*
|
|
12
|
-
* 커넥션 풀에서 연결을 획득하여 반환한다.
|
|
13
|
-
* 풀이 없는 경우 새로 생성한다.
|
|
14
|
-
*
|
|
15
|
-
* @param config - 데이터베이스 연결 설정
|
|
16
|
-
* @returns 풀링된 DB 연결 객체
|
|
17
|
-
*/
|
|
18
|
-
static create(config) {
|
|
19
|
-
const pool = this._getOrCreatePool(config);
|
|
20
|
-
return Promise.resolve(new PooledDbConn(pool, config));
|
|
21
|
-
}
|
|
22
|
-
static _getOrCreatePool(config) {
|
|
23
|
-
const configKey = JSON.stringify(
|
|
24
|
-
config,
|
|
25
|
-
(_, value) => value != null && typeof value === "object" && !Array.isArray(value) ? Object.fromEntries(Object.entries(value).sort(([a], [b]) => a.localeCompare(b))) : value
|
|
26
|
-
);
|
|
27
|
-
if (!this._poolMap.has(configKey)) {
|
|
28
|
-
const pool = createPool(
|
|
29
|
-
{
|
|
30
|
-
create: async () => {
|
|
31
|
-
const conn = await this._createRawConnection(config);
|
|
32
|
-
await conn.connect();
|
|
33
|
-
return conn;
|
|
34
|
-
},
|
|
35
|
-
destroy: async (conn) => {
|
|
36
|
-
await conn.close();
|
|
37
|
-
},
|
|
38
|
-
validate: (conn) => {
|
|
39
|
-
return Promise.resolve(conn.isConnected);
|
|
40
|
-
}
|
|
41
|
-
},
|
|
42
|
-
{
|
|
43
|
-
min: config.pool?.min ?? 1,
|
|
44
|
-
max: config.pool?.max ?? 10,
|
|
45
|
-
acquireTimeoutMillis: config.pool?.acquireTimeoutMillis ?? 3e4,
|
|
46
|
-
idleTimeoutMillis: config.pool?.idleTimeoutMillis ?? 3e4,
|
|
47
|
-
testOnBorrow: true
|
|
48
|
-
// [중요] 빌려줄 때 validate 실행 여부
|
|
49
|
-
}
|
|
50
|
-
);
|
|
51
|
-
this._poolMap.set(configKey, pool);
|
|
52
|
-
}
|
|
53
|
-
return this._poolMap.get(configKey);
|
|
54
|
-
}
|
|
55
|
-
static async _createRawConnection(config) {
|
|
56
|
-
if (config.dialect === "mysql") {
|
|
57
|
-
const mysql = await this._ensureModule("mysql");
|
|
58
|
-
return new MysqlDbConn(mysql, config);
|
|
59
|
-
} else if (config.dialect === "postgresql") {
|
|
60
|
-
const pg = await this._ensureModule("pg");
|
|
61
|
-
const pgCopyStreams = await this._ensureModule("pgCopyStreams");
|
|
62
|
-
return new PostgresqlDbConn(pg, pgCopyStreams.from, config);
|
|
63
|
-
} else {
|
|
64
|
-
const tedious = await this._ensureModule("tedious");
|
|
65
|
-
return new MssqlDbConn(tedious, config);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
// 지연 로딩 모듈 캐시
|
|
69
|
-
static _modules = {};
|
|
70
|
-
static async _ensureModule(name) {
|
|
71
|
-
if (this._modules[name] == null) {
|
|
72
|
-
if (name === "mysql") {
|
|
73
|
-
this._modules.mysql = await import("mysql2/promise");
|
|
74
|
-
} else if (name === "pg") {
|
|
75
|
-
this._modules.pg = await import("pg");
|
|
76
|
-
} else if (name === "pgCopyStreams") {
|
|
77
|
-
this._modules.pgCopyStreams = await import("pg-copy-streams");
|
|
78
|
-
} else {
|
|
79
|
-
this._modules.tedious = await import("tedious");
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
return this._modules[name];
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
export {
|
|
86
|
-
DbConnFactory
|
|
87
|
-
};
|
|
88
|
-
//# sourceMappingURL=db-conn-factory.js.map
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/db-conn-factory.ts"],
|
|
4
|
-
"mappings": "AACA,SAAS,kBAAkB;AAE3B,SAAS,oBAAoB;AAC7B,SAAS,mBAAmB;AAC5B,SAAS,mBAAmB;AAC5B,SAAS,wBAAwB;AAQ1B,MAAM,cAAc;AAAA;AAAA,EAEzB,OAAwB,WAAW,oBAAI,IAA0B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWjE,OAAO,OAAO,QAAuC;AAEnD,UAAM,OAAO,KAAK,iBAAiB,MAAM;AAGzC,WAAO,QAAQ,QAAQ,IAAI,aAAa,MAAM,MAAM,CAAC;AAAA,EACvD;AAAA,EAEA,OAAe,iBAAiB,QAAoC;AAElE,UAAM,YAAY,KAAK;AAAA,MAAU;AAAA,MAAQ,CAAC,GAAG,UAC3C,SAAS,QAAQ,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK,IAC9D,OAAO,YAAY,OAAO,QAAQ,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC,IAC/E;AAAA,IACN;AAEA,QAAI,CAAC,KAAK,SAAS,IAAI,SAAS,GAAG;AACjC,YAAM,OAAO;AAAA,QACX;AAAA,UACE,QAAQ,YAAY;AAClB,kBAAM,OAAO,MAAM,KAAK,qBAAqB,MAAM;AACnD,kBAAM,KAAK,QAAQ;AACnB,mBAAO;AAAA,UACT;AAAA,UACA,SAAS,OAAO,SAAS;AACvB,kBAAM,KAAK,MAAM;AAAA,UACnB;AAAA,UACA,UAAU,CAAC,SAAS;AAElB,mBAAO,QAAQ,QAAQ,KAAK,WAAW;AAAA,UACzC;AAAA,QACF;AAAA,QACA;AAAA,UACE,KAAK,OAAO,MAAM,OAAO;AAAA,UACzB,KAAK,OAAO,MAAM,OAAO;AAAA,UACzB,sBAAsB,OAAO,MAAM,wBAAwB;AAAA,UAC3D,mBAAmB,OAAO,MAAM,qBAAqB;AAAA,UACrD,cAAc;AAAA;AAAA,QAChB;AAAA,MACF;AAEA,WAAK,SAAS,IAAI,WAAW,IAAI;AAAA,IACnC;AAEA,WAAO,KAAK,SAAS,IAAI,SAAS;AAAA,EACpC;AAAA,EAEA,aAAqB,qBAAqB,QAAuC;AAC/E,QAAI,OAAO,YAAY,SAAS;AAC9B,YAAM,QAAQ,MAAM,KAAK,cAAc,OAAO;AAC9C,aAAO,IAAI,YAAY,OAAO,MAAM;AAAA,IACtC,WAAW,OAAO,YAAY,cAAc;AAC1C,YAAM,KAAK,MAAM,KAAK,cAAc,IAAI;AACxC,YAAM,gBAAgB,MAAM,KAAK,cAAc,eAAe;AAC9D,aAAO,IAAI,iBAAiB,IAAI,cAAc,MAAM,MAAM;AAAA,IAC5D,OAAO;AAEL,YAAM,UAAU,MAAM,KAAK,cAAc,SAAS;AAClD,aAAO,IAAI,YAAY,SAAS,MAAM;AAAA,IACxC;AAAA,EACF;AAAA;AAAA,EAGA,OAAwB,WAKpB,CAAC;AAAA,EAEL,aAAqB,cACnB,MACiD;AACjD,QAAI,KAAK,SAAS,IAAI,KAAK,MAAM;AAC/B,UAAI,SAAS,SAAS;AACpB,aAAK,SAAS,QAAQ,MAAM,OAAO,gBAAgB;AAAA,MACrD,WAAW,SAAS,MAAM;AACxB,aAAK,SAAS,KAAK,MAAM,OAAO,IAAI;AAAA,MACtC,WAAW,SAAS,iBAAiB;AACnC,aAAK,SAAS,gBAAgB,MAAM,OAAO,iBAAiB;AAAA,MAC9D,OAAO;AACL,aAAK,SAAS,UAAU,MAAM,OAAO,SAAS;AAAA,MAChD;AAAA,IACF;AACA,WAAO,KAAK,SAAS,IAAI;AAAA,EAC3B;AACF;",
|
|
5
|
-
"names": []
|
|
6
|
-
}
|
package/dist/sd-orm.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sd-orm.d.ts","sourceRoot":"","sources":["../src/sd-orm.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAGpD;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,qBAAa,KAAK,CAAC,CAAC,SAAS,SAAS;IAElC,QAAQ,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,YAAY;IAC7B,QAAQ,CAAC,OAAO,CAAC,EAAE,YAAY;gBAFtB,aAAa,EAAE,IAAI,CAAC,CAAC,CAAC,EACtB,MAAM,EAAE,YAAY,EACpB,OAAO,CAAC,EAAE,YAAY,YAAA;IAGjC;;;;;;OAMG;IACG,OAAO,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,EAAE,cAAc,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,CAAC,CAAC;IAKhG;;;;;OAKG;IACG,yBAAyB,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAKjF;;OAEG;IACH,OAAO,CAAC,gBAAgB;CAYzB"}
|
package/dist/sd-orm.js
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { NodeDbContextExecutor } from "./node-db-context-executor.js";
|
|
2
|
-
class SdOrm {
|
|
3
|
-
constructor(dbContextType, config, options) {
|
|
4
|
-
this.dbContextType = dbContextType;
|
|
5
|
-
this.config = config;
|
|
6
|
-
this.options = options;
|
|
7
|
-
}
|
|
8
|
-
/**
|
|
9
|
-
* 트랜잭션 내에서 콜백 실행
|
|
10
|
-
*
|
|
11
|
-
* @param callback - DB 연결 후 실행할 콜백
|
|
12
|
-
* @param isolationLevel - 트랜잭션 격리 수준
|
|
13
|
-
* @returns 콜백 결과
|
|
14
|
-
*/
|
|
15
|
-
async connect(callback, isolationLevel) {
|
|
16
|
-
const db = this._createDbContext();
|
|
17
|
-
return db.connect(async () => callback(db), isolationLevel);
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* 트랜잭션 없이 콜백 실행
|
|
21
|
-
*
|
|
22
|
-
* @param callback - DB 연결 후 실행할 콜백
|
|
23
|
-
* @returns 콜백 결과
|
|
24
|
-
*/
|
|
25
|
-
async connectWithoutTransaction(callback) {
|
|
26
|
-
const db = this._createDbContext();
|
|
27
|
-
return db.connectWithoutTransaction(async () => callback(db));
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* DbContext 인스턴스 생성
|
|
31
|
-
*/
|
|
32
|
-
_createDbContext() {
|
|
33
|
-
const database = this.options?.database ?? ("database" in this.config ? this.config.database : void 0);
|
|
34
|
-
const schema = this.options?.schema ?? ("schema" in this.config ? this.config.schema : void 0);
|
|
35
|
-
return new this.dbContextType(new NodeDbContextExecutor(this.config), {
|
|
36
|
-
database,
|
|
37
|
-
schema
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
export {
|
|
42
|
-
SdOrm
|
|
43
|
-
};
|
|
44
|
-
//# sourceMappingURL=sd-orm.js.map
|
package/dist/sd-orm.js.map
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/sd-orm.ts"],
|
|
4
|
-
"mappings": "AAGA,SAAS,6BAA6B;AAqD/B,MAAM,MAA2B;AAAA,EACtC,YACW,eACA,QACA,SACT;AAHS;AACA;AACA;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASH,MAAM,QAAW,UAAmC,gBAA6C;AAC/F,UAAM,KAAK,KAAK,iBAAiB;AACjC,WAAO,GAAG,QAAQ,YAAY,SAAS,EAAE,GAAG,cAAc;AAAA,EAC5D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,0BAA6B,UAA+C;AAChF,UAAM,KAAK,KAAK,iBAAiB;AACjC,WAAO,GAAG,0BAA0B,YAAY,SAAS,EAAE,CAAC;AAAA,EAC9D;AAAA;AAAA;AAAA;AAAA,EAKQ,mBAAsB;AAE5B,UAAM,WAAW,KAAK,SAAS,aAAa,cAAc,KAAK,SAAS,KAAK,OAAO,WAAW;AAG/F,UAAM,SAAS,KAAK,SAAS,WAAW,YAAY,KAAK,SAAS,KAAK,OAAO,SAAS;AAEvF,WAAO,IAAI,KAAK,cAAc,IAAI,sBAAsB,KAAK,MAAM,GAAG;AAAA,MACpE;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AACF;",
|
|
5
|
-
"names": []
|
|
6
|
-
}
|
package/src/db-conn-factory.ts
DELETED
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
import type { Pool } from "generic-pool";
|
|
2
|
-
import { createPool } from "generic-pool";
|
|
3
|
-
import type { DbConn, DbConnConfig } from "./types/db-conn";
|
|
4
|
-
import { PooledDbConn } from "./pooled-db-conn";
|
|
5
|
-
import { MysqlDbConn } from "./connections/mysql-db-conn";
|
|
6
|
-
import { MssqlDbConn } from "./connections/mssql-db-conn";
|
|
7
|
-
import { PostgresqlDbConn } from "./connections/postgresql-db-conn";
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* DB 연결 팩토리
|
|
11
|
-
*
|
|
12
|
-
* 데이터베이스 연결 인스턴스를 생성하고 풀링을 관리한다.
|
|
13
|
-
* MSSQL, MySQL, PostgreSQL을 지원한다.
|
|
14
|
-
*/
|
|
15
|
-
export class DbConnFactory {
|
|
16
|
-
// 설정별 커넥션 풀 캐싱
|
|
17
|
-
private static readonly _poolMap = new Map<string, Pool<DbConn>>();
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* DB 연결 생성
|
|
21
|
-
*
|
|
22
|
-
* 커넥션 풀에서 연결을 획득하여 반환한다.
|
|
23
|
-
* 풀이 없는 경우 새로 생성한다.
|
|
24
|
-
*
|
|
25
|
-
* @param config - 데이터베이스 연결 설정
|
|
26
|
-
* @returns 풀링된 DB 연결 객체
|
|
27
|
-
*/
|
|
28
|
-
static create(config: DbConnConfig): Promise<DbConn> {
|
|
29
|
-
// 1. 풀 가져오기 (없으면 생성)
|
|
30
|
-
const pool = this._getOrCreatePool(config);
|
|
31
|
-
|
|
32
|
-
// 2. 래퍼 객체 반환
|
|
33
|
-
return Promise.resolve(new PooledDbConn(pool, config));
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
private static _getOrCreatePool(config: DbConnConfig): Pool<DbConn> {
|
|
37
|
-
// 객체를 키로 쓰기 위해 문자열 변환 (중첩 객체도 정렬하여 동일 설정의 일관된 키 보장)
|
|
38
|
-
const configKey = JSON.stringify(config, (_, value: unknown) =>
|
|
39
|
-
value != null && typeof value === "object" && !Array.isArray(value)
|
|
40
|
-
? Object.fromEntries(Object.entries(value).sort(([a], [b]) => a.localeCompare(b)))
|
|
41
|
-
: value,
|
|
42
|
-
);
|
|
43
|
-
|
|
44
|
-
if (!this._poolMap.has(configKey)) {
|
|
45
|
-
const pool = createPool<DbConn>(
|
|
46
|
-
{
|
|
47
|
-
create: async () => {
|
|
48
|
-
const conn = await this._createRawConnection(config);
|
|
49
|
-
await conn.connect();
|
|
50
|
-
return conn;
|
|
51
|
-
},
|
|
52
|
-
destroy: async (conn) => {
|
|
53
|
-
await conn.close(); // 풀에서 제거될 때 실제 연결 종료
|
|
54
|
-
},
|
|
55
|
-
validate: (conn) => {
|
|
56
|
-
// 획득 시 연결 상태 확인 (끊겨있으면 Pool이 폐기하고 새로 만듦)
|
|
57
|
-
return Promise.resolve(conn.isConnected);
|
|
58
|
-
},
|
|
59
|
-
},
|
|
60
|
-
{
|
|
61
|
-
min: config.pool?.min ?? 1,
|
|
62
|
-
max: config.pool?.max ?? 10,
|
|
63
|
-
acquireTimeoutMillis: config.pool?.acquireTimeoutMillis ?? 30000,
|
|
64
|
-
idleTimeoutMillis: config.pool?.idleTimeoutMillis ?? 30000,
|
|
65
|
-
testOnBorrow: true, // [중요] 빌려줄 때 validate 실행 여부
|
|
66
|
-
},
|
|
67
|
-
);
|
|
68
|
-
|
|
69
|
-
this._poolMap.set(configKey, pool);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
return this._poolMap.get(configKey)!;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
private static async _createRawConnection(config: DbConnConfig): Promise<DbConn> {
|
|
76
|
-
if (config.dialect === "mysql") {
|
|
77
|
-
const mysql = await this._ensureModule("mysql");
|
|
78
|
-
return new MysqlDbConn(mysql, config);
|
|
79
|
-
} else if (config.dialect === "postgresql") {
|
|
80
|
-
const pg = await this._ensureModule("pg");
|
|
81
|
-
const pgCopyStreams = await this._ensureModule("pgCopyStreams");
|
|
82
|
-
return new PostgresqlDbConn(pg, pgCopyStreams.from, config);
|
|
83
|
-
} else {
|
|
84
|
-
// mssql, mssql-azure
|
|
85
|
-
const tedious = await this._ensureModule("tedious");
|
|
86
|
-
return new MssqlDbConn(tedious, config);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// 지연 로딩 모듈 캐시
|
|
91
|
-
private static readonly _modules: {
|
|
92
|
-
tedious?: typeof import("tedious");
|
|
93
|
-
mysql?: typeof import("mysql2/promise");
|
|
94
|
-
pg?: typeof import("pg");
|
|
95
|
-
pgCopyStreams?: typeof import("pg-copy-streams");
|
|
96
|
-
} = {};
|
|
97
|
-
|
|
98
|
-
private static async _ensureModule<K extends keyof typeof this._modules>(
|
|
99
|
-
name: K,
|
|
100
|
-
): Promise<NonNullable<(typeof this._modules)[K]>> {
|
|
101
|
-
if (this._modules[name] == null) {
|
|
102
|
-
if (name === "mysql") {
|
|
103
|
-
this._modules.mysql = await import("mysql2/promise");
|
|
104
|
-
} else if (name === "pg") {
|
|
105
|
-
this._modules.pg = await import("pg");
|
|
106
|
-
} else if (name === "pgCopyStreams") {
|
|
107
|
-
this._modules.pgCopyStreams = await import("pg-copy-streams");
|
|
108
|
-
} else {
|
|
109
|
-
this._modules.tedious = await import("tedious");
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
return this._modules[name]!;
|
|
113
|
-
}
|
|
114
|
-
}
|
package/src/sd-orm.ts
DELETED
|
@@ -1,102 +0,0 @@
|
|
|
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
|
-
}
|