@simplysm/orm-node 13.0.100 → 14.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +195 -168
- package/dist/connections/mssql-db-conn.d.ts +5 -5
- package/dist/connections/mssql-db-conn.js +356 -369
- package/dist/connections/mssql-db-conn.js.map +1 -6
- package/dist/connections/mysql-db-conn.d.ts +3 -3
- package/dist/connections/mysql-db-conn.js +227 -215
- package/dist/connections/mysql-db-conn.js.map +1 -6
- package/dist/connections/postgresql-db-conn.d.ts +3 -3
- package/dist/connections/postgresql-db-conn.js +185 -183
- package/dist/connections/postgresql-db-conn.js.map +1 -6
- package/dist/create-db-conn.d.ts +3 -3
- package/dist/create-db-conn.js +43 -27
- package/dist/create-db-conn.js.map +1 -6
- package/dist/create-orm.d.ts +18 -18
- package/dist/create-orm.js +62 -31
- package/dist/create-orm.js.map +1 -6
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -6
- package/dist/node-db-context-executor.d.ts +28 -28
- package/dist/node-db-context-executor.js +125 -117
- package/dist/node-db-context-executor.js.map +1 -6
- package/dist/types/db-conn.d.ts +37 -37
- package/dist/types/db-conn.js +26 -17
- package/dist/types/db-conn.js.map +1 -6
- package/package.json +9 -9
- package/src/connections/mssql-db-conn.ts +22 -22
- package/src/connections/mysql-db-conn.ts +27 -27
- package/src/connections/postgresql-db-conn.ts +16 -16
- package/src/create-db-conn.ts +7 -7
- package/src/create-orm.ts +21 -21
- package/src/index.ts +3 -3
- package/src/node-db-context-executor.ts +32 -32
- package/src/types/db-conn.ts +40 -40
|
@@ -1,392 +1,379 @@
|
|
|
1
1
|
import consola from "consola";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
DateTime,
|
|
5
|
-
json,
|
|
6
|
-
str,
|
|
7
|
-
wait,
|
|
8
|
-
SdError,
|
|
9
|
-
EventEmitter,
|
|
10
|
-
Time,
|
|
11
|
-
Uuid
|
|
12
|
-
} from "@simplysm/core-common";
|
|
13
|
-
import {
|
|
14
|
-
DB_CONN_CONNECT_TIMEOUT,
|
|
15
|
-
DB_CONN_DEFAULT_TIMEOUT,
|
|
16
|
-
DB_CONN_ERRORS
|
|
17
|
-
} from "../types/db-conn.js";
|
|
2
|
+
import { DateOnly, DateTime, json, str, wait, SdError, EventEmitter, Time, Uuid, } from "@simplysm/core-common";
|
|
3
|
+
import { DB_CONN_CONNECT_TIMEOUT, DB_CONN_DEFAULT_TIMEOUT, DB_CONN_ERRORS, } from "../types/db-conn.js";
|
|
18
4
|
const logger = consola.withTag("mssql-db-conn");
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
5
|
+
/**
|
|
6
|
+
* MSSQL 데이터베이스 연결 클래스
|
|
7
|
+
*
|
|
8
|
+
* tedious 라이브러리를 사용하여 MSSQL/Azure SQL 연결을 관리한다.
|
|
9
|
+
*/
|
|
10
|
+
export class MssqlDbConn extends EventEmitter {
|
|
11
|
+
_tedious;
|
|
12
|
+
config;
|
|
13
|
+
_timeout = DB_CONN_DEFAULT_TIMEOUT;
|
|
14
|
+
_conn;
|
|
15
|
+
_connTimeout;
|
|
16
|
+
_requests = [];
|
|
17
|
+
isConnected = false;
|
|
18
|
+
isInTransaction = false;
|
|
19
|
+
constructor(_tedious, config) {
|
|
20
|
+
super();
|
|
21
|
+
this._tedious = _tedious;
|
|
22
|
+
this.config = config;
|
|
34
23
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
type: "default",
|
|
39
|
-
options: {
|
|
40
|
-
userName: this.config.username,
|
|
41
|
-
password: this.config.password
|
|
24
|
+
async connect() {
|
|
25
|
+
if (this.isConnected) {
|
|
26
|
+
throw new SdError(DB_CONN_ERRORS.ALREADY_CONNECTED);
|
|
42
27
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
28
|
+
const conn = new this._tedious.Connection({
|
|
29
|
+
server: this.config.host,
|
|
30
|
+
authentication: {
|
|
31
|
+
type: "default",
|
|
32
|
+
options: {
|
|
33
|
+
userName: this.config.username,
|
|
34
|
+
password: this.config.password,
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
options: {
|
|
38
|
+
database: this.config.database,
|
|
39
|
+
port: this.config.port,
|
|
40
|
+
rowCollectionOnDone: true,
|
|
41
|
+
useUTC: false,
|
|
42
|
+
encrypt: this.config.dialect === "mssql-azure",
|
|
43
|
+
requestTimeout: this._timeout,
|
|
44
|
+
trustServerCertificate: true,
|
|
45
|
+
connectTimeout: DB_CONN_CONNECT_TIMEOUT,
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
conn.on("infoMessage", (info) => {
|
|
49
|
+
logger.debug("정보", info.message);
|
|
50
|
+
});
|
|
51
|
+
conn.on("errorMessage", (error) => {
|
|
52
|
+
logger.error("오류 메시지", error.message);
|
|
53
|
+
});
|
|
54
|
+
conn.on("error", (error) => {
|
|
55
|
+
logger.error("오류", error.message);
|
|
56
|
+
});
|
|
57
|
+
conn.on("end", () => {
|
|
58
|
+
this.emit("close");
|
|
59
|
+
this._resetState();
|
|
60
|
+
});
|
|
61
|
+
await new Promise((resolve, reject) => {
|
|
62
|
+
conn.connect((err) => {
|
|
63
|
+
if (err != null) {
|
|
64
|
+
reject(new SdError(err));
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
this._startTimeout();
|
|
68
|
+
this.isConnected = true;
|
|
69
|
+
this.isInTransaction = false;
|
|
70
|
+
resolve();
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
this._conn = conn;
|
|
86
74
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
await new Promise((resolve) => {
|
|
91
|
-
conn.on("end", () => {
|
|
92
|
-
wait.until(() => this._conn == null, 3e4, 100).then(() => resolve()).catch(() => resolve());
|
|
93
|
-
});
|
|
94
|
-
conn.close();
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
async beginTransaction(isolationLevel) {
|
|
98
|
-
this._assertConnected();
|
|
99
|
-
this._startTimeout();
|
|
100
|
-
const conn = this._conn;
|
|
101
|
-
await new Promise((resolve, reject) => {
|
|
102
|
-
conn.beginTransaction(
|
|
103
|
-
(err) => {
|
|
104
|
-
if (err != null) {
|
|
105
|
-
reject(new SdError(err));
|
|
75
|
+
async close() {
|
|
76
|
+
this._stopTimeout();
|
|
77
|
+
if (this._conn == null || !this.isConnected) {
|
|
106
78
|
return;
|
|
107
|
-
}
|
|
108
|
-
this.isInTransaction = true;
|
|
109
|
-
resolve();
|
|
110
|
-
},
|
|
111
|
-
"",
|
|
112
|
-
this._tedious.ISOLATION_LEVEL[isolationLevel ?? this.config.defaultIsolationLevel ?? "READ_UNCOMMITTED"]
|
|
113
|
-
);
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
async commitTransaction() {
|
|
117
|
-
this._assertConnected();
|
|
118
|
-
this._startTimeout();
|
|
119
|
-
const conn = this._conn;
|
|
120
|
-
await new Promise((resolve, reject) => {
|
|
121
|
-
conn.commitTransaction((err) => {
|
|
122
|
-
if (err != null) {
|
|
123
|
-
reject(new SdError(err));
|
|
124
|
-
return;
|
|
125
|
-
}
|
|
126
|
-
this.isInTransaction = false;
|
|
127
|
-
resolve();
|
|
128
|
-
});
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
async rollbackTransaction() {
|
|
132
|
-
this._assertConnected();
|
|
133
|
-
this._startTimeout();
|
|
134
|
-
const conn = this._conn;
|
|
135
|
-
await new Promise((resolve, reject) => {
|
|
136
|
-
conn.rollbackTransaction((err) => {
|
|
137
|
-
if (err != null) {
|
|
138
|
-
reject(new SdError(err));
|
|
139
|
-
return;
|
|
140
79
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
80
|
+
const conn = this._conn;
|
|
81
|
+
// 진행 중인 요청 취소
|
|
82
|
+
conn.cancel();
|
|
83
|
+
await wait.until(() => this._requests.length < 1, 30000, 100);
|
|
84
|
+
// 연결 종료 대기
|
|
85
|
+
await new Promise((resolve) => {
|
|
86
|
+
conn.on("end", () => {
|
|
87
|
+
wait.until(() => this._conn == null, 30000, 100)
|
|
88
|
+
.then(() => resolve())
|
|
89
|
+
.catch(() => resolve());
|
|
90
|
+
});
|
|
91
|
+
conn.close();
|
|
92
|
+
});
|
|
151
93
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
async executeParametrized(query, params) {
|
|
155
|
-
this._assertConnected();
|
|
156
|
-
this._startTimeout();
|
|
157
|
-
const conn = this._conn;
|
|
158
|
-
const results = [];
|
|
159
|
-
logger.debug("Query execution", { queryLength: query.length, params });
|
|
160
|
-
await new Promise((resolve, reject) => {
|
|
161
|
-
let rejected = false;
|
|
162
|
-
const queryRequest = new this._tedious.Request(query, (err) => {
|
|
163
|
-
if (err != null) {
|
|
164
|
-
rejected = true;
|
|
165
|
-
this._requests = this._requests.filter((r) => r !== queryRequest);
|
|
166
|
-
const errCode = "code" in err ? err.code : void 0;
|
|
167
|
-
if (errCode === "ECANCEL") {
|
|
168
|
-
reject(new SdError(err, "Query was cancelled."));
|
|
169
|
-
} else {
|
|
170
|
-
const lineNumber = "lineNumber" in err && typeof err.lineNumber === "number" ? err.lineNumber : void 0;
|
|
171
|
-
if (lineNumber != null && lineNumber > 0) {
|
|
172
|
-
const splitQuery = query.split("\n");
|
|
173
|
-
splitQuery[lineNumber - 1] = "==> " + splitQuery[lineNumber - 1];
|
|
174
|
-
reject(
|
|
175
|
-
new SdError(err, `Error executing query
|
|
176
|
-
-- query
|
|
177
|
-
${splitQuery.join("\n")}
|
|
178
|
-
--`)
|
|
179
|
-
);
|
|
180
|
-
} else {
|
|
181
|
-
reject(new SdError(err, `Error executing query
|
|
182
|
-
-- query
|
|
183
|
-
${query}
|
|
184
|
-
--`));
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
});
|
|
189
|
-
queryRequest.on("done", (_rowCount, _more, rst) => {
|
|
94
|
+
async beginTransaction(isolationLevel) {
|
|
95
|
+
this._assertConnected();
|
|
190
96
|
this._startTimeout();
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
97
|
+
const conn = this._conn;
|
|
98
|
+
await new Promise((resolve, reject) => {
|
|
99
|
+
conn.beginTransaction((err) => {
|
|
100
|
+
if (err != null) {
|
|
101
|
+
reject(new SdError(err));
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
this.isInTransaction = true;
|
|
105
|
+
resolve();
|
|
106
|
+
}, "", this._tedious.ISOLATION_LEVEL[isolationLevel ?? this.config.defaultIsolationLevel ?? "READ_UNCOMMITTED"]);
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
async commitTransaction() {
|
|
110
|
+
this._assertConnected();
|
|
196
111
|
this._startTimeout();
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
112
|
+
const conn = this._conn;
|
|
113
|
+
await new Promise((resolve, reject) => {
|
|
114
|
+
conn.commitTransaction((err) => {
|
|
115
|
+
if (err != null) {
|
|
116
|
+
reject(new SdError(err));
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
this.isInTransaction = false;
|
|
120
|
+
resolve();
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
async rollbackTransaction() {
|
|
125
|
+
this._assertConnected();
|
|
202
126
|
this._startTimeout();
|
|
203
|
-
|
|
204
|
-
|
|
127
|
+
const conn = this._conn;
|
|
128
|
+
await new Promise((resolve, reject) => {
|
|
129
|
+
conn.rollbackTransaction((err) => {
|
|
130
|
+
if (err != null) {
|
|
131
|
+
reject(new SdError(err));
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
this.isInTransaction = false;
|
|
135
|
+
resolve();
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
async execute(queries) {
|
|
140
|
+
const results = [];
|
|
141
|
+
for (const query of queries.filter((item) => !str.isNullOrEmpty(item))) {
|
|
142
|
+
const resultItems = await this.executeParametrized(query);
|
|
143
|
+
results.push(...resultItems);
|
|
205
144
|
}
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
${query}
|
|
211
|
-
--`));
|
|
212
|
-
}).on("requestCompleted", () => {
|
|
145
|
+
return results;
|
|
146
|
+
}
|
|
147
|
+
async executeParametrized(query, params) {
|
|
148
|
+
this._assertConnected();
|
|
213
149
|
this._startTimeout();
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
150
|
+
const conn = this._conn;
|
|
151
|
+
const results = [];
|
|
152
|
+
logger.debug("쿼리 실행", { queryLength: query.length, params });
|
|
153
|
+
await new Promise((resolve, reject) => {
|
|
154
|
+
let rejected = false;
|
|
155
|
+
const queryRequest = new this._tedious.Request(query, (err) => {
|
|
156
|
+
if (err != null) {
|
|
157
|
+
rejected = true;
|
|
158
|
+
this._requests = this._requests.filter((r) => r !== queryRequest);
|
|
159
|
+
const errCode = "code" in err ? err.code : undefined;
|
|
160
|
+
if (errCode === "ECANCEL") {
|
|
161
|
+
reject(new SdError(err, "쿼리가 취소되었습니다."));
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
const lineNumber = "lineNumber" in err && typeof err.lineNumber === "number" ? err.lineNumber : undefined;
|
|
165
|
+
if (lineNumber != null && lineNumber > 0) {
|
|
166
|
+
const splitQuery = query.split("\n");
|
|
167
|
+
splitQuery[lineNumber - 1] = "==> " + splitQuery[lineNumber - 1];
|
|
168
|
+
reject(new SdError(err, `쿼리 실행 오류\n-- query\n${splitQuery.join("\n")}\n--`));
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
reject(new SdError(err, `쿼리 실행 오류\n-- query\n${query}\n--`));
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
queryRequest
|
|
177
|
+
.on("done", (_rowCount, _more, rst) => {
|
|
178
|
+
this._startTimeout();
|
|
179
|
+
if (rejected) {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
results.push(this._parseRowsToRecords(rst));
|
|
183
|
+
})
|
|
184
|
+
.on("doneInProc", (_rowCount, _more, rst) => {
|
|
185
|
+
this._startTimeout();
|
|
186
|
+
if (rejected) {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
results.push(this._parseRowsToRecords(rst));
|
|
190
|
+
})
|
|
191
|
+
.on("error", (err) => {
|
|
192
|
+
this._startTimeout();
|
|
193
|
+
if (rejected) {
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
rejected = true;
|
|
197
|
+
this._requests = this._requests.filter((r) => r !== queryRequest);
|
|
198
|
+
reject(new SdError(err, `쿼리 실행 오류\n-- query\n${query}\n--`));
|
|
199
|
+
})
|
|
200
|
+
.on("requestCompleted", () => {
|
|
201
|
+
this._startTimeout();
|
|
202
|
+
if (rejected) {
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
this._requests = this._requests.filter((r) => r !== queryRequest);
|
|
206
|
+
resolve();
|
|
207
|
+
});
|
|
208
|
+
this._requests.push(queryRequest);
|
|
209
|
+
if (params != null) {
|
|
210
|
+
for (let i = 0; i < params.length; i++) {
|
|
211
|
+
const paramValue = params[i];
|
|
212
|
+
const paramName = `p${i}`;
|
|
213
|
+
const type = this._guessTediousType(paramValue);
|
|
214
|
+
queryRequest.addParameter(paramName, type, paramValue);
|
|
215
|
+
}
|
|
216
|
+
conn.execSql(queryRequest);
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
conn.execSqlBatch(queryRequest);
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
return results;
|
|
223
|
+
}
|
|
224
|
+
async bulkInsert(tableName, columnMetas, records) {
|
|
225
|
+
if (records.length === 0)
|
|
226
|
+
return;
|
|
227
|
+
this._assertConnected();
|
|
228
|
+
this._startTimeout();
|
|
229
|
+
const tediousColumnDefs = Object.entries(columnMetas).map(([name, meta]) => this._convertColumnMetaToTediousBulkColumnDef(name, meta));
|
|
230
|
+
await new Promise((resolve, reject) => {
|
|
231
|
+
const bulkLoad = this._conn.newBulkLoad(tableName, (err) => {
|
|
232
|
+
if (err != null) {
|
|
233
|
+
reject(new SdError(err, `Bulk Insert 오류\n${json.stringify(tediousColumnDefs)}\n-- data\n${json.stringify(records).substring(0, 10000)}...\n--`));
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
resolve();
|
|
237
|
+
});
|
|
238
|
+
const colNames = Object.keys(columnMetas);
|
|
239
|
+
for (const tediousColumnDef of tediousColumnDefs) {
|
|
240
|
+
bulkLoad.addColumn(tediousColumnDef.name, tediousColumnDef.type, tediousColumnDef.options);
|
|
241
|
+
}
|
|
242
|
+
// 레코드를 행 배열로 변환 (컬럼 순서 유지, 값 변환 포함)
|
|
243
|
+
const rows = records.map((record) => colNames.map((colName) => {
|
|
244
|
+
const val = record[colName];
|
|
245
|
+
if (val instanceof Uuid)
|
|
246
|
+
return val.toString();
|
|
247
|
+
// eslint-disable-next-line no-restricted-globals -- tedious library requires Buffer
|
|
248
|
+
if (val instanceof Uint8Array)
|
|
249
|
+
return Buffer.from(val);
|
|
250
|
+
if (val instanceof DateTime)
|
|
251
|
+
return val.date;
|
|
252
|
+
if (val instanceof DateOnly)
|
|
253
|
+
return val.date;
|
|
254
|
+
if (val instanceof Time)
|
|
255
|
+
return val.toFormatString("HH:mm:ss");
|
|
256
|
+
return val;
|
|
257
|
+
}));
|
|
258
|
+
this._conn.execBulkLoad(bulkLoad, rows);
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
// ─────────────────────────────────────────────
|
|
262
|
+
// 내부 헬퍼
|
|
263
|
+
// ─────────────────────────────────────────────
|
|
264
|
+
_assertConnected() {
|
|
265
|
+
if (this._conn == null || !this.isConnected) {
|
|
266
|
+
throw new SdError(DB_CONN_ERRORS.NOT_CONNECTED);
|
|
227
267
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
err,
|
|
248
|
-
`Bulk Insert error
|
|
249
|
-
${json.stringify(tediousColumnDefs)}
|
|
250
|
-
-- data
|
|
251
|
-
${json.stringify(records).substring(0, 1e4)}...
|
|
252
|
-
--`
|
|
253
|
-
)
|
|
254
|
-
);
|
|
255
|
-
return;
|
|
268
|
+
}
|
|
269
|
+
_parseRowsToRecords(rows) {
|
|
270
|
+
return (rows ?? []).map((item) => {
|
|
271
|
+
const resultItem = {};
|
|
272
|
+
for (const col of item) {
|
|
273
|
+
resultItem[col.metadata.colName] = col.value;
|
|
274
|
+
}
|
|
275
|
+
return resultItem;
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
_resetState() {
|
|
279
|
+
this.isConnected = false;
|
|
280
|
+
this.isInTransaction = false;
|
|
281
|
+
this._conn = undefined;
|
|
282
|
+
this._requests = [];
|
|
283
|
+
}
|
|
284
|
+
_stopTimeout() {
|
|
285
|
+
if (this._connTimeout != null) {
|
|
286
|
+
clearTimeout(this._connTimeout);
|
|
256
287
|
}
|
|
257
|
-
resolve();
|
|
258
|
-
});
|
|
259
|
-
const colNames = Object.keys(columnMetas);
|
|
260
|
-
for (const tediousColumnDef of tediousColumnDefs) {
|
|
261
|
-
bulkLoad.addColumn(tediousColumnDef.name, tediousColumnDef.type, tediousColumnDef.options);
|
|
262
|
-
}
|
|
263
|
-
const rows = records.map(
|
|
264
|
-
(record) => colNames.map((colName) => {
|
|
265
|
-
const val = record[colName];
|
|
266
|
-
if (val instanceof Uuid) return val.toString();
|
|
267
|
-
if (val instanceof Uint8Array) return Buffer.from(val);
|
|
268
|
-
if (val instanceof DateTime) return val.date;
|
|
269
|
-
if (val instanceof DateOnly) return val.date;
|
|
270
|
-
if (val instanceof Time) return val.toFormatString("HH:mm:ss");
|
|
271
|
-
return val;
|
|
272
|
-
})
|
|
273
|
-
);
|
|
274
|
-
this._conn.execBulkLoad(bulkLoad, rows);
|
|
275
|
-
});
|
|
276
|
-
}
|
|
277
|
-
// ─────────────────────────────────────────────
|
|
278
|
-
// Private helpers
|
|
279
|
-
// ─────────────────────────────────────────────
|
|
280
|
-
_assertConnected() {
|
|
281
|
-
if (this._conn == null || !this.isConnected) {
|
|
282
|
-
throw new SdError(DB_CONN_ERRORS.NOT_CONNECTED);
|
|
283
288
|
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
return resultItem;
|
|
292
|
-
});
|
|
293
|
-
}
|
|
294
|
-
_resetState() {
|
|
295
|
-
this.isConnected = false;
|
|
296
|
-
this.isInTransaction = false;
|
|
297
|
-
this._conn = void 0;
|
|
298
|
-
this._requests = [];
|
|
299
|
-
}
|
|
300
|
-
_stopTimeout() {
|
|
301
|
-
if (this._connTimeout != null) {
|
|
302
|
-
clearTimeout(this._connTimeout);
|
|
289
|
+
_startTimeout() {
|
|
290
|
+
this._stopTimeout();
|
|
291
|
+
this._connTimeout = setTimeout(() => {
|
|
292
|
+
this.close().catch((err) => {
|
|
293
|
+
logger.error("연결 종료 오류", err instanceof Error ? err.message : String(err));
|
|
294
|
+
});
|
|
295
|
+
}, this._timeout * 2);
|
|
303
296
|
}
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
this._stopTimeout();
|
|
307
|
-
this._connTimeout = setTimeout(() => {
|
|
308
|
-
this.close().catch((err) => {
|
|
309
|
-
logger.error("close error", err instanceof Error ? err.message : String(err));
|
|
310
|
-
});
|
|
311
|
-
}, this._timeout * 2);
|
|
312
|
-
}
|
|
313
|
-
_convertColumnMetaToTediousBulkColumnDef(name, meta) {
|
|
314
|
-
const tediousDataType = this._convertDataTypeToTediousBulkColumnType(meta.dataType);
|
|
315
|
-
return {
|
|
316
|
-
name,
|
|
317
|
-
type: tediousDataType.type,
|
|
318
|
-
options: {
|
|
319
|
-
length: tediousDataType.length,
|
|
320
|
-
nullable: meta.nullable ?? false,
|
|
321
|
-
precision: tediousDataType.precision,
|
|
322
|
-
scale: tediousDataType.scale
|
|
323
|
-
}
|
|
324
|
-
};
|
|
325
|
-
}
|
|
326
|
-
_convertDataTypeToTediousBulkColumnType(dataType) {
|
|
327
|
-
switch (dataType.type) {
|
|
328
|
-
case "int":
|
|
329
|
-
return { type: this._tedious.TYPES.Int };
|
|
330
|
-
case "bigint":
|
|
331
|
-
return { type: this._tedious.TYPES.BigInt };
|
|
332
|
-
case "float":
|
|
333
|
-
return { type: this._tedious.TYPES.Real };
|
|
334
|
-
case "double":
|
|
335
|
-
return { type: this._tedious.TYPES.Float };
|
|
336
|
-
case "decimal":
|
|
297
|
+
_convertColumnMetaToTediousBulkColumnDef(name, meta) {
|
|
298
|
+
const tediousDataType = this._convertDataTypeToTediousBulkColumnType(meta.dataType);
|
|
337
299
|
return {
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
300
|
+
name,
|
|
301
|
+
type: tediousDataType.type,
|
|
302
|
+
options: {
|
|
303
|
+
length: tediousDataType.length,
|
|
304
|
+
nullable: meta.nullable ?? false,
|
|
305
|
+
precision: tediousDataType.precision,
|
|
306
|
+
scale: tediousDataType.scale,
|
|
307
|
+
},
|
|
341
308
|
};
|
|
342
|
-
case "varchar":
|
|
343
|
-
return { type: this._tedious.TYPES.NVarChar, length: dataType.length };
|
|
344
|
-
case "char":
|
|
345
|
-
return { type: this._tedious.TYPES.NChar, length: dataType.length };
|
|
346
|
-
case "text":
|
|
347
|
-
return { type: this._tedious.TYPES.NText };
|
|
348
|
-
case "binary":
|
|
349
|
-
return { type: this._tedious.TYPES.VarBinary, length: Infinity };
|
|
350
|
-
case "boolean":
|
|
351
|
-
return { type: this._tedious.TYPES.Bit };
|
|
352
|
-
case "datetime":
|
|
353
|
-
return { type: this._tedious.TYPES.DateTime2 };
|
|
354
|
-
case "date":
|
|
355
|
-
return { type: this._tedious.TYPES.Date };
|
|
356
|
-
case "time":
|
|
357
|
-
return { type: this._tedious.TYPES.Time };
|
|
358
|
-
case "uuid":
|
|
359
|
-
return { type: this._tedious.TYPES.UniqueIdentifier };
|
|
360
|
-
default:
|
|
361
|
-
throw new SdError(`Unsupported DataType: ${JSON.stringify(dataType)}`);
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
/**
|
|
365
|
-
* Infer the type of a value and return Tedious data type
|
|
366
|
-
*
|
|
367
|
-
* @param value - Value whose type is to be inferred (error if null/undefined is passed)
|
|
368
|
-
* @throws Error if null/undefined is passed
|
|
369
|
-
*/
|
|
370
|
-
_guessTediousType(value) {
|
|
371
|
-
if (value == null) {
|
|
372
|
-
throw new SdError("_guessTediousType: null/undefined values are not supported.");
|
|
373
309
|
}
|
|
374
|
-
|
|
375
|
-
|
|
310
|
+
_convertDataTypeToTediousBulkColumnType(dataType) {
|
|
311
|
+
switch (dataType.type) {
|
|
312
|
+
case "int":
|
|
313
|
+
return { type: this._tedious.TYPES.Int };
|
|
314
|
+
case "bigint":
|
|
315
|
+
return { type: this._tedious.TYPES.BigInt };
|
|
316
|
+
case "float":
|
|
317
|
+
return { type: this._tedious.TYPES.Real };
|
|
318
|
+
case "double":
|
|
319
|
+
return { type: this._tedious.TYPES.Float };
|
|
320
|
+
case "decimal":
|
|
321
|
+
return {
|
|
322
|
+
type: this._tedious.TYPES.Decimal,
|
|
323
|
+
precision: dataType.precision,
|
|
324
|
+
scale: dataType.scale,
|
|
325
|
+
};
|
|
326
|
+
case "varchar":
|
|
327
|
+
return { type: this._tedious.TYPES.NVarChar, length: dataType.length };
|
|
328
|
+
case "char":
|
|
329
|
+
return { type: this._tedious.TYPES.NChar, length: dataType.length };
|
|
330
|
+
case "text":
|
|
331
|
+
return { type: this._tedious.TYPES.NText };
|
|
332
|
+
case "binary":
|
|
333
|
+
return { type: this._tedious.TYPES.VarBinary, length: Infinity };
|
|
334
|
+
case "boolean":
|
|
335
|
+
return { type: this._tedious.TYPES.Bit };
|
|
336
|
+
case "datetime":
|
|
337
|
+
return { type: this._tedious.TYPES.DateTime2 };
|
|
338
|
+
case "date":
|
|
339
|
+
return { type: this._tedious.TYPES.Date };
|
|
340
|
+
case "time":
|
|
341
|
+
return { type: this._tedious.TYPES.Time };
|
|
342
|
+
case "uuid":
|
|
343
|
+
return { type: this._tedious.TYPES.UniqueIdentifier };
|
|
344
|
+
default:
|
|
345
|
+
throw new SdError(`지원하지 않는 DataType: ${JSON.stringify(dataType)}`);
|
|
346
|
+
}
|
|
376
347
|
}
|
|
377
|
-
|
|
378
|
-
|
|
348
|
+
/**
|
|
349
|
+
* 값의 타입을 추론하여 Tedious 데이터 타입을 반환한다
|
|
350
|
+
*
|
|
351
|
+
* @param value - 타입을 추론할 값 (null/undefined 전달 시 오류 발생)
|
|
352
|
+
* @throws null/undefined 전달 시 오류
|
|
353
|
+
*/
|
|
354
|
+
_guessTediousType(value) {
|
|
355
|
+
if (value == null) {
|
|
356
|
+
throw new SdError("_guessTediousType: null/undefined 값은 지원하지 않습니다.");
|
|
357
|
+
}
|
|
358
|
+
if (typeof value === "string") {
|
|
359
|
+
return this._tedious.TYPES.NVarChar;
|
|
360
|
+
}
|
|
361
|
+
if (typeof value === "number") {
|
|
362
|
+
return Number.isInteger(value) ? this._tedious.TYPES.BigInt : this._tedious.TYPES.Decimal;
|
|
363
|
+
}
|
|
364
|
+
if (typeof value === "boolean")
|
|
365
|
+
return this._tedious.TYPES.Bit;
|
|
366
|
+
if (value instanceof DateTime)
|
|
367
|
+
return this._tedious.TYPES.DateTime2;
|
|
368
|
+
if (value instanceof DateOnly)
|
|
369
|
+
return this._tedious.TYPES.Date;
|
|
370
|
+
if (value instanceof Time)
|
|
371
|
+
return this._tedious.TYPES.Time;
|
|
372
|
+
if (value instanceof Uuid)
|
|
373
|
+
return this._tedious.TYPES.UniqueIdentifier;
|
|
374
|
+
if (value instanceof Uint8Array)
|
|
375
|
+
return this._tedious.TYPES.VarBinary;
|
|
376
|
+
throw new SdError(`알 수 없는 값 타입: ${typeof value}`);
|
|
379
377
|
}
|
|
380
|
-
if (typeof value === "boolean") return this._tedious.TYPES.Bit;
|
|
381
|
-
if (value instanceof DateTime) return this._tedious.TYPES.DateTime2;
|
|
382
|
-
if (value instanceof DateOnly) return this._tedious.TYPES.Date;
|
|
383
|
-
if (value instanceof Time) return this._tedious.TYPES.Time;
|
|
384
|
-
if (value instanceof Uuid) return this._tedious.TYPES.UniqueIdentifier;
|
|
385
|
-
if (value instanceof Uint8Array) return this._tedious.TYPES.VarBinary;
|
|
386
|
-
throw new SdError(`Unknown value type: ${typeof value}`);
|
|
387
|
-
}
|
|
388
378
|
}
|
|
389
|
-
|
|
390
|
-
MssqlDbConn
|
|
391
|
-
};
|
|
392
|
-
//# sourceMappingURL=mssql-db-conn.js.map
|
|
379
|
+
//# sourceMappingURL=mssql-db-conn.js.map
|