@simplysm/orm-node 13.0.69 → 13.0.70
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 +20 -476
- package/dist/connections/mssql-db-conn.d.ts +5 -5
- package/dist/connections/mssql-db-conn.js +12 -12
- package/dist/connections/mssql-db-conn.js.map +1 -1
- package/dist/connections/mysql-db-conn.d.ts +3 -3
- package/dist/connections/mysql-db-conn.js +9 -9
- package/dist/connections/mysql-db-conn.js.map +1 -1
- package/dist/connections/postgresql-db-conn.d.ts +3 -3
- package/dist/connections/postgresql-db-conn.js +6 -6
- package/dist/connections/postgresql-db-conn.js.map +1 -1
- package/dist/create-db-conn.d.ts +5 -5
- package/dist/create-db-conn.js +1 -1
- package/dist/create-orm.d.ts +18 -18
- package/dist/node-db-context-executor.d.ts +30 -30
- package/dist/node-db-context-executor.js +28 -28
- package/dist/pooled-db-conn.d.ts +27 -27
- package/dist/pooled-db-conn.js +29 -29
- package/dist/pooled-db-conn.js.map +1 -1
- package/dist/types/db-conn.d.ts +47 -47
- package/dist/types/db-conn.d.ts.map +1 -1
- package/dist/types/db-conn.js +2 -2
- package/package.json +5 -5
- package/src/connections/mssql-db-conn.ts +18 -18
- package/src/connections/mysql-db-conn.ts +25 -25
- package/src/connections/postgresql-db-conn.ts +14 -14
- package/src/create-db-conn.ts +17 -17
- package/src/create-orm.ts +20 -20
- package/src/node-db-context-executor.ts +34 -34
- package/src/pooled-db-conn.ts +42 -42
- package/src/types/db-conn.ts +48 -48
|
@@ -25,9 +25,9 @@ import {
|
|
|
25
25
|
const logger = consola.withTag("mysql-db-conn");
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
|
-
* MySQL
|
|
28
|
+
* MySQL database connection class
|
|
29
29
|
*
|
|
30
|
-
*
|
|
30
|
+
* Manages MySQL connections using the mysql2/promise library.
|
|
31
31
|
*/
|
|
32
32
|
export class MysqlDbConn extends EventEmitter<{ close: void }> implements DbConn {
|
|
33
33
|
private static readonly _ROOT_USER = "root";
|
|
@@ -56,12 +56,12 @@ export class MysqlDbConn extends EventEmitter<{ close: void }> implements DbConn
|
|
|
56
56
|
port: this.config.port,
|
|
57
57
|
user: this.config.username,
|
|
58
58
|
password: this.config.password,
|
|
59
|
-
//
|
|
60
|
-
//
|
|
59
|
+
// Root user connects without binding to specific database
|
|
60
|
+
// to allow access to all databases (for admin operations)
|
|
61
61
|
database: this.config.username === MysqlDbConn._ROOT_USER ? undefined : this.config.database,
|
|
62
62
|
multipleStatements: true,
|
|
63
63
|
charset: "utf8mb4",
|
|
64
|
-
infileStreamFactory: (filePath: string) => fs.createReadStream(filePath), // LOAD DATA LOCAL INFILE
|
|
64
|
+
infileStreamFactory: (filePath: string) => fs.createReadStream(filePath), // Support for LOAD DATA LOCAL INFILE
|
|
65
65
|
} as Parameters<typeof this._mysql2.createConnection>[0]);
|
|
66
66
|
|
|
67
67
|
conn.on("end", () => {
|
|
@@ -70,7 +70,7 @@ export class MysqlDbConn extends EventEmitter<{ close: void }> implements DbConn
|
|
|
70
70
|
});
|
|
71
71
|
|
|
72
72
|
conn.on("error", (error) => {
|
|
73
|
-
logger.error("DB
|
|
73
|
+
logger.error("DB connection error", error.message);
|
|
74
74
|
});
|
|
75
75
|
|
|
76
76
|
this._conn = conn;
|
|
@@ -100,13 +100,13 @@ export class MysqlDbConn extends EventEmitter<{ close: void }> implements DbConn
|
|
|
100
100
|
"READ_UNCOMMITTED"
|
|
101
101
|
).replace(/_/g, " ");
|
|
102
102
|
|
|
103
|
-
//
|
|
103
|
+
// Set isolation level first (applies to next transaction)
|
|
104
104
|
await conn.query({
|
|
105
105
|
sql: `SET SESSION TRANSACTION ISOLATION LEVEL ${level}`,
|
|
106
106
|
timeout: this._timeout,
|
|
107
107
|
});
|
|
108
108
|
|
|
109
|
-
//
|
|
109
|
+
// Then start transaction
|
|
110
110
|
await conn.beginTransaction();
|
|
111
111
|
|
|
112
112
|
this.isInTransaction = true;
|
|
@@ -139,7 +139,7 @@ export class MysqlDbConn extends EventEmitter<{ close: void }> implements DbConn
|
|
|
139
139
|
): Promise<Record<string, unknown>[][]> {
|
|
140
140
|
const conn = this._assertConnected();
|
|
141
141
|
|
|
142
|
-
logger.debug("
|
|
142
|
+
logger.debug("Query execution", { queryLength: query.length, params });
|
|
143
143
|
|
|
144
144
|
try {
|
|
145
145
|
const [queryResults] = await conn.query({
|
|
@@ -150,9 +150,9 @@ export class MysqlDbConn extends EventEmitter<{ close: void }> implements DbConn
|
|
|
150
150
|
|
|
151
151
|
this._startTimeout();
|
|
152
152
|
|
|
153
|
-
// MySQL
|
|
154
|
-
//
|
|
155
|
-
// ResultSetHeader
|
|
153
|
+
// MySQL returns ResultSetHeader for INSERT/UPDATE/DELETE statements
|
|
154
|
+
// Filter ResultSetHeader objects to extract only SELECT results
|
|
155
|
+
// ResultSetHeader has fields like affectedRows, fieldCount, etc.
|
|
156
156
|
const result: Record<string, unknown>[] = [];
|
|
157
157
|
if (queryResults instanceof Array) {
|
|
158
158
|
for (const queryResult of queryResults.filter(
|
|
@@ -174,7 +174,7 @@ export class MysqlDbConn extends EventEmitter<{ close: void }> implements DbConn
|
|
|
174
174
|
const error = err as Error & { sql?: string };
|
|
175
175
|
throw new SdError(
|
|
176
176
|
error,
|
|
177
|
-
"
|
|
177
|
+
"Error executing query" +
|
|
178
178
|
(error.sql != null ? "\n-- query\n" + error.sql.trim() + "\n--" : ""),
|
|
179
179
|
);
|
|
180
180
|
}
|
|
@@ -191,12 +191,12 @@ export class MysqlDbConn extends EventEmitter<{ close: void }> implements DbConn
|
|
|
191
191
|
|
|
192
192
|
const colNames = Object.keys(columnMetas);
|
|
193
193
|
|
|
194
|
-
//
|
|
194
|
+
// Create temporary CSV file
|
|
195
195
|
const tmpDir = os.tmpdir();
|
|
196
196
|
const tmpFile = path.join(tmpDir, `mysql_bulk_${randomUUID()}.csv`);
|
|
197
197
|
|
|
198
198
|
try {
|
|
199
|
-
// CSV
|
|
199
|
+
// Generate CSV data
|
|
200
200
|
const csvLines: string[] = [];
|
|
201
201
|
for (const record of records) {
|
|
202
202
|
const row = colNames.map((colName) =>
|
|
@@ -206,10 +206,10 @@ export class MysqlDbConn extends EventEmitter<{ close: void }> implements DbConn
|
|
|
206
206
|
}
|
|
207
207
|
const csvContent = csvLines.join("\n");
|
|
208
208
|
|
|
209
|
-
//
|
|
209
|
+
// Write file
|
|
210
210
|
await fs.promises.writeFile(tmpFile, csvContent, "utf8");
|
|
211
211
|
|
|
212
|
-
// UUID/binary
|
|
212
|
+
// UUID/binary columns are read as temporary variables and converted with UNHEX() in SET clause
|
|
213
213
|
const binaryColNames = colNames.filter((c) => {
|
|
214
214
|
const dt = columnMetas[c].dataType.type;
|
|
215
215
|
return dt === "uuid" || dt === "binary";
|
|
@@ -220,7 +220,7 @@ export class MysqlDbConn extends EventEmitter<{ close: void }> implements DbConn
|
|
|
220
220
|
});
|
|
221
221
|
const setClauses = binaryColNames.map((c) => `\`${c}\` = UNHEX(@_${c})`);
|
|
222
222
|
|
|
223
|
-
// LOAD DATA LOCAL INFILE
|
|
223
|
+
// Execute LOAD DATA LOCAL INFILE
|
|
224
224
|
let query = `LOAD DATA LOCAL INFILE ? INTO TABLE ${tableName} FIELDS TERMINATED BY '\\t' LINES TERMINATED BY '\\n' (${normalCols.join(", ")})`;
|
|
225
225
|
if (setClauses.length > 0) {
|
|
226
226
|
query += ` SET ${setClauses.join(", ")}`;
|
|
@@ -228,11 +228,11 @@ export class MysqlDbConn extends EventEmitter<{ close: void }> implements DbConn
|
|
|
228
228
|
|
|
229
229
|
await conn.query({ sql: query, timeout: this._timeout, values: [tmpFile] });
|
|
230
230
|
} finally {
|
|
231
|
-
//
|
|
231
|
+
// Delete temporary file
|
|
232
232
|
try {
|
|
233
233
|
await fs.promises.unlink(tmpFile);
|
|
234
234
|
} catch {
|
|
235
|
-
//
|
|
235
|
+
// Ignore deletion failure
|
|
236
236
|
}
|
|
237
237
|
}
|
|
238
238
|
}
|
|
@@ -242,11 +242,11 @@ export class MysqlDbConn extends EventEmitter<{ close: void }> implements DbConn
|
|
|
242
242
|
// ─────────────────────────────────────────────
|
|
243
243
|
|
|
244
244
|
/**
|
|
245
|
-
* MySQL LOAD DATA INFILE
|
|
245
|
+
* Escape value for MySQL LOAD DATA INFILE
|
|
246
246
|
*/
|
|
247
247
|
private _escapeForCsv(value: unknown, dataType: DataType): string {
|
|
248
248
|
if (value == null) {
|
|
249
|
-
return "\\N"; // MySQL NULL
|
|
249
|
+
return "\\N"; // MySQL NULL representation
|
|
250
250
|
}
|
|
251
251
|
|
|
252
252
|
switch (dataType.type) {
|
|
@@ -264,7 +264,7 @@ export class MysqlDbConn extends EventEmitter<{ close: void }> implements DbConn
|
|
|
264
264
|
case "char":
|
|
265
265
|
case "text": {
|
|
266
266
|
const str = value as string;
|
|
267
|
-
//
|
|
267
|
+
// Escape tab, newline, backslash
|
|
268
268
|
return str
|
|
269
269
|
.replace(/\\/g, "\\\\")
|
|
270
270
|
.replace(/\0/g, "\\0")
|
|
@@ -283,13 +283,13 @@ export class MysqlDbConn extends EventEmitter<{ close: void }> implements DbConn
|
|
|
283
283
|
return (value as Time).toFormatString("HH:mm:ss");
|
|
284
284
|
|
|
285
285
|
case "uuid":
|
|
286
|
-
return (value as Uuid).toString().replace(/-/g, ""); // BINARY(16)
|
|
286
|
+
return (value as Uuid).toString().replace(/-/g, ""); // Hex for BINARY(16) storage
|
|
287
287
|
|
|
288
288
|
case "binary":
|
|
289
289
|
return bytesToHex(value as Uint8Array);
|
|
290
290
|
|
|
291
291
|
default:
|
|
292
|
-
throw new SdError(
|
|
292
|
+
throw new SdError(`Unsupported DataType: ${JSON.stringify(dataType)}`);
|
|
293
293
|
}
|
|
294
294
|
}
|
|
295
295
|
|
|
@@ -23,9 +23,9 @@ import type { Client } from "pg";
|
|
|
23
23
|
const logger = consola.withTag("postgresql-db-conn");
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
|
-
* PostgreSQL
|
|
26
|
+
* PostgreSQL database connection class
|
|
27
27
|
*
|
|
28
|
-
*
|
|
28
|
+
* Manages PostgreSQL connections using the pg library.
|
|
29
29
|
*/
|
|
30
30
|
export class PostgresqlDbConn extends EventEmitter<{ close: void }> implements DbConn {
|
|
31
31
|
private readonly _timeout = DB_CONN_DEFAULT_TIMEOUT;
|
|
@@ -65,7 +65,7 @@ export class PostgresqlDbConn extends EventEmitter<{ close: void }> implements D
|
|
|
65
65
|
});
|
|
66
66
|
|
|
67
67
|
client.on("error", (error) => {
|
|
68
|
-
logger.error("DB
|
|
68
|
+
logger.error("DB connection error", error.message);
|
|
69
69
|
});
|
|
70
70
|
|
|
71
71
|
await client.connect();
|
|
@@ -130,19 +130,19 @@ export class PostgresqlDbConn extends EventEmitter<{ close: void }> implements D
|
|
|
130
130
|
): Promise<Record<string, unknown>[][]> {
|
|
131
131
|
this._assertConnected();
|
|
132
132
|
|
|
133
|
-
logger.debug("
|
|
133
|
+
logger.debug("Query execution", { queryLength: query.length, params });
|
|
134
134
|
|
|
135
135
|
try {
|
|
136
136
|
const result = await this._client!.query(query, params);
|
|
137
137
|
|
|
138
138
|
this._startTimeout();
|
|
139
139
|
|
|
140
|
-
// PostgreSQL
|
|
140
|
+
// PostgreSQL returns a single result set
|
|
141
141
|
return [result.rows];
|
|
142
142
|
} catch (err) {
|
|
143
143
|
this._startTimeout();
|
|
144
144
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
145
|
-
throw new SdError(error, "
|
|
145
|
+
throw new SdError(error, "Error executing query\n-- query\n" + query.trim() + "\n--");
|
|
146
146
|
}
|
|
147
147
|
}
|
|
148
148
|
|
|
@@ -158,11 +158,11 @@ export class PostgresqlDbConn extends EventEmitter<{ close: void }> implements D
|
|
|
158
158
|
const colNames = Object.keys(columnMetas);
|
|
159
159
|
const wrappedCols = colNames.map((c) => `"${c}"`).join(", ");
|
|
160
160
|
|
|
161
|
-
// COPY FROM STDIN
|
|
161
|
+
// Create COPY FROM STDIN stream
|
|
162
162
|
const copyQuery = `COPY ${tableName} (${wrappedCols}) FROM STDIN WITH (FORMAT csv, NULL '\\N')`;
|
|
163
163
|
const stream = this._client!.query(this._pgCopyStreams.from(copyQuery));
|
|
164
164
|
|
|
165
|
-
// CSV
|
|
165
|
+
// Generate CSV data
|
|
166
166
|
const csvLines: string[] = [];
|
|
167
167
|
for (const record of records) {
|
|
168
168
|
const row = colNames.map((colName) =>
|
|
@@ -172,7 +172,7 @@ export class PostgresqlDbConn extends EventEmitter<{ close: void }> implements D
|
|
|
172
172
|
}
|
|
173
173
|
const csvContent = csvLines.join("\n") + "\n";
|
|
174
174
|
|
|
175
|
-
//
|
|
175
|
+
// Send data via stream
|
|
176
176
|
await new Promise<void>((resolve, reject) => {
|
|
177
177
|
const readable = Readable.from([csvContent]);
|
|
178
178
|
|
|
@@ -189,11 +189,11 @@ export class PostgresqlDbConn extends EventEmitter<{ close: void }> implements D
|
|
|
189
189
|
// ─────────────────────────────────────────────
|
|
190
190
|
|
|
191
191
|
/**
|
|
192
|
-
* PostgreSQL COPY CSV
|
|
192
|
+
* Escape value for PostgreSQL COPY CSV
|
|
193
193
|
*/
|
|
194
194
|
private _escapeForCsv(value: unknown, dataType: DataType): string {
|
|
195
195
|
if (value == null) {
|
|
196
|
-
return "\\N"; // NULL
|
|
196
|
+
return "\\N"; // NULL representation
|
|
197
197
|
}
|
|
198
198
|
|
|
199
199
|
switch (dataType.type) {
|
|
@@ -211,7 +211,7 @@ export class PostgresqlDbConn extends EventEmitter<{ close: void }> implements D
|
|
|
211
211
|
case "char":
|
|
212
212
|
case "text": {
|
|
213
213
|
const str = value as string;
|
|
214
|
-
// CSV
|
|
214
|
+
// CSV format: wrap with double quotes, escape internal double quotes with double quotes
|
|
215
215
|
if (
|
|
216
216
|
str.includes('"') ||
|
|
217
217
|
str.includes(",") ||
|
|
@@ -237,10 +237,10 @@ export class PostgresqlDbConn extends EventEmitter<{ close: void }> implements D
|
|
|
237
237
|
return (value as Uuid).toString();
|
|
238
238
|
|
|
239
239
|
case "binary":
|
|
240
|
-
return '"\\x' + bytesToHex(value as Uint8Array) + '"'; // PostgreSQL bytea hex
|
|
240
|
+
return '"\\x' + bytesToHex(value as Uint8Array) + '"'; // PostgreSQL bytea hex format (wrapped in CSV double quotes)
|
|
241
241
|
|
|
242
242
|
default:
|
|
243
|
-
throw new SdError(
|
|
243
|
+
throw new SdError(`Unsupported DataType: ${JSON.stringify(dataType)}`);
|
|
244
244
|
}
|
|
245
245
|
}
|
|
246
246
|
|
package/src/create-db-conn.ts
CHANGED
|
@@ -7,19 +7,19 @@ import { MssqlDbConn } from "./connections/mssql-db-conn";
|
|
|
7
7
|
import { PostgresqlDbConn } from "./connections/postgresql-db-conn";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
* DB
|
|
10
|
+
* DB connection factory
|
|
11
11
|
*
|
|
12
|
-
*
|
|
13
|
-
* MSSQL, MySQL, PostgreSQL
|
|
12
|
+
* Creates database connection instances and manages pooling.
|
|
13
|
+
* Supports MSSQL, MySQL, and PostgreSQL.
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
//
|
|
16
|
+
// Cache connection pools by configuration
|
|
17
17
|
const poolMap = new Map<string, Pool<DbConn>>();
|
|
18
18
|
|
|
19
|
-
//
|
|
19
|
+
// Cache last error when pool creation fails (by configKey)
|
|
20
20
|
const poolLastErrorMap = new Map<string, Error>();
|
|
21
21
|
|
|
22
|
-
//
|
|
22
|
+
// Lazy-loaded module cache
|
|
23
23
|
const modules: {
|
|
24
24
|
tedious?: typeof import("tedious");
|
|
25
25
|
mysql?: typeof import("mysql2/promise");
|
|
@@ -28,19 +28,19 @@ const modules: {
|
|
|
28
28
|
} = {};
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
|
-
* DB
|
|
31
|
+
* Create DB connection
|
|
32
32
|
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
33
|
+
* Acquires and returns a connection from the connection pool.
|
|
34
|
+
* Creates a new pool if one does not exist.
|
|
35
35
|
*
|
|
36
|
-
* @param config -
|
|
37
|
-
* @returns
|
|
36
|
+
* @param config - Database connection configuration
|
|
37
|
+
* @returns Pooled DB connection object
|
|
38
38
|
*/
|
|
39
39
|
export function createDbConn(config: DbConnConfig): Promise<DbConn> {
|
|
40
|
-
// 1.
|
|
40
|
+
// 1. Get pool (create if not exists)
|
|
41
41
|
const { pool, getLastCreateError } = getOrCreatePool(config);
|
|
42
42
|
|
|
43
|
-
// 2.
|
|
43
|
+
// 2. Return wrapper object
|
|
44
44
|
return Promise.resolve(new PooledDbConn(pool, config, getLastCreateError));
|
|
45
45
|
}
|
|
46
46
|
|
|
@@ -48,7 +48,7 @@ function getOrCreatePool(config: DbConnConfig): {
|
|
|
48
48
|
pool: Pool<DbConn>;
|
|
49
49
|
getLastCreateError: () => Error | undefined;
|
|
50
50
|
} {
|
|
51
|
-
//
|
|
51
|
+
// Convert object to string key (sort nested objects to ensure consistent keys for identical configurations)
|
|
52
52
|
const configKey = JSON.stringify(config, (_, value: unknown) =>
|
|
53
53
|
value != null && typeof value === "object" && !Array.isArray(value)
|
|
54
54
|
? Object.fromEntries(Object.entries(value).sort(([a], [b]) => a.localeCompare(b)))
|
|
@@ -64,10 +64,10 @@ function getOrCreatePool(config: DbConnConfig): {
|
|
|
64
64
|
return conn;
|
|
65
65
|
},
|
|
66
66
|
destroy: async (conn) => {
|
|
67
|
-
await conn.close(); //
|
|
67
|
+
await conn.close(); // Close actual connection when removed from pool
|
|
68
68
|
},
|
|
69
69
|
validate: (conn) => {
|
|
70
|
-
//
|
|
70
|
+
// Check connection status on acquisition (Pool will dispose and recreate if disconnected)
|
|
71
71
|
return Promise.resolve(conn.isConnected);
|
|
72
72
|
},
|
|
73
73
|
},
|
|
@@ -76,7 +76,7 @@ function getOrCreatePool(config: DbConnConfig): {
|
|
|
76
76
|
max: config.pool?.max ?? 10,
|
|
77
77
|
acquireTimeoutMillis: config.pool?.acquireTimeoutMillis ?? 30000,
|
|
78
78
|
idleTimeoutMillis: config.pool?.idleTimeoutMillis ?? 30000,
|
|
79
|
-
testOnBorrow: true, // [
|
|
79
|
+
testOnBorrow: true, // [IMPORTANT] Whether to run validate when borrowing
|
|
80
80
|
},
|
|
81
81
|
);
|
|
82
82
|
|
package/src/create-orm.ts
CHANGED
|
@@ -8,26 +8,26 @@ import type { DbConnConfig } from "./types/db-conn";
|
|
|
8
8
|
import { NodeDbContextExecutor } from "./node-db-context-executor";
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
*
|
|
11
|
+
* ORM options
|
|
12
12
|
*
|
|
13
|
-
*
|
|
13
|
+
* DbContext options that take precedence over DbConnConfig
|
|
14
14
|
*/
|
|
15
15
|
export interface OrmOptions {
|
|
16
16
|
/**
|
|
17
|
-
*
|
|
17
|
+
* Database name (used instead of DbConnConfig's database)
|
|
18
18
|
*/
|
|
19
19
|
database?: string;
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
|
-
*
|
|
22
|
+
* Schema name (MSSQL: dbo, PostgreSQL: public)
|
|
23
23
|
*/
|
|
24
24
|
schema?: string;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
|
-
*
|
|
28
|
+
* ORM instance type
|
|
29
29
|
*
|
|
30
|
-
*
|
|
30
|
+
* Type of the object returned from createOrm
|
|
31
31
|
*/
|
|
32
32
|
export interface Orm<TDef extends DbContextDef<any, any, any>> {
|
|
33
33
|
readonly dbContextDef: TDef;
|
|
@@ -35,11 +35,11 @@ export interface Orm<TDef extends DbContextDef<any, any, any>> {
|
|
|
35
35
|
readonly options?: OrmOptions;
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
|
-
*
|
|
38
|
+
* Execute callback within a transaction
|
|
39
39
|
*
|
|
40
|
-
* @param callback -
|
|
41
|
-
* @param isolationLevel -
|
|
42
|
-
* @returns
|
|
40
|
+
* @param callback - Callback to execute after DB connection
|
|
41
|
+
* @param isolationLevel - Transaction isolation level
|
|
42
|
+
* @returns Callback result
|
|
43
43
|
*/
|
|
44
44
|
connect<R>(
|
|
45
45
|
callback: (conn: DbContextInstance<TDef>) => Promise<R>,
|
|
@@ -47,19 +47,19 @@ export interface Orm<TDef extends DbContextDef<any, any, any>> {
|
|
|
47
47
|
): Promise<R>;
|
|
48
48
|
|
|
49
49
|
/**
|
|
50
|
-
*
|
|
50
|
+
* Execute callback without a transaction
|
|
51
51
|
*
|
|
52
|
-
* @param callback -
|
|
53
|
-
* @returns
|
|
52
|
+
* @param callback - Callback to execute after DB connection
|
|
53
|
+
* @returns Callback result
|
|
54
54
|
*/
|
|
55
55
|
connectWithoutTransaction<R>(callback: (conn: DbContextInstance<TDef>) => Promise<R>): Promise<R>;
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
/**
|
|
59
|
-
* Node.js ORM
|
|
59
|
+
* Node.js ORM factory function
|
|
60
60
|
*
|
|
61
|
-
*
|
|
62
|
-
* DbContext
|
|
61
|
+
* Creates an instance that manages DbContext and DB connections.
|
|
62
|
+
* Receives DbContext definition and connection configuration to manage transactions.
|
|
63
63
|
*
|
|
64
64
|
* @example
|
|
65
65
|
* ```typescript
|
|
@@ -76,13 +76,13 @@ export interface Orm<TDef extends DbContextDef<any, any, any>> {
|
|
|
76
76
|
* database: "mydb",
|
|
77
77
|
* });
|
|
78
78
|
*
|
|
79
|
-
* //
|
|
79
|
+
* // Execute within a transaction
|
|
80
80
|
* await orm.connect(async (db) => {
|
|
81
81
|
* const users = await db.user().result();
|
|
82
82
|
* return users;
|
|
83
83
|
* });
|
|
84
84
|
*
|
|
85
|
-
* //
|
|
85
|
+
* // Execute without a transaction
|
|
86
86
|
* await orm.connectWithoutTransaction(async (db) => {
|
|
87
87
|
* const users = await db.user().result();
|
|
88
88
|
* return users;
|
|
@@ -95,13 +95,13 @@ export function createOrm<TDef extends DbContextDef<any, any, any>>(
|
|
|
95
95
|
options?: OrmOptions,
|
|
96
96
|
): Orm<TDef> {
|
|
97
97
|
function _createDbContext(): DbContextInstance<TDef> {
|
|
98
|
-
// database
|
|
98
|
+
// database from options first, then from config
|
|
99
99
|
const database = options?.database ?? ("database" in config ? config.database : undefined);
|
|
100
100
|
if (database == null || database === "") {
|
|
101
101
|
throw new Error("database is required");
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
-
// schema
|
|
104
|
+
// schema from options first, then from config
|
|
105
105
|
const schema = options?.schema ?? ("schema" in config ? config.schema : undefined);
|
|
106
106
|
|
|
107
107
|
return createDbContext(dbContextDef, new NodeDbContextExecutor(config), {
|
|
@@ -14,9 +14,9 @@ import { DB_CONN_ERRORS, getDialectFromConfig } from "./types/db-conn";
|
|
|
14
14
|
import { createDbConn } from "./create-db-conn";
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
|
-
* Node.js
|
|
17
|
+
* DbContextExecutor for Node.js environment
|
|
18
18
|
*
|
|
19
|
-
* DbContext
|
|
19
|
+
* Executor used by DbContext that handles actual DB connections.
|
|
20
20
|
*/
|
|
21
21
|
export class NodeDbContextExecutor implements DbContextExecutor {
|
|
22
22
|
private _conn?: DbConn;
|
|
@@ -27,9 +27,9 @@ export class NodeDbContextExecutor implements DbContextExecutor {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
|
-
* DB
|
|
30
|
+
* Establish DB connection
|
|
31
31
|
*
|
|
32
|
-
*
|
|
32
|
+
* Acquires connection from connection pool and activates the connection state.
|
|
33
33
|
*/
|
|
34
34
|
async connect(): Promise<void> {
|
|
35
35
|
this._conn = await createDbConn(this._config);
|
|
@@ -37,11 +37,11 @@ export class NodeDbContextExecutor implements DbContextExecutor {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
/**
|
|
40
|
-
* DB
|
|
40
|
+
* Close DB connection
|
|
41
41
|
*
|
|
42
|
-
*
|
|
42
|
+
* Returns connection to the connection pool.
|
|
43
43
|
*
|
|
44
|
-
* @throws {Error}
|
|
44
|
+
* @throws {Error} When not connected
|
|
45
45
|
*/
|
|
46
46
|
async close(): Promise<void> {
|
|
47
47
|
const conn = this._requireConn();
|
|
@@ -50,10 +50,10 @@ export class NodeDbContextExecutor implements DbContextExecutor {
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
/**
|
|
53
|
-
*
|
|
53
|
+
* Begin transaction
|
|
54
54
|
*
|
|
55
|
-
* @param isolationLevel -
|
|
56
|
-
* @throws {Error}
|
|
55
|
+
* @param isolationLevel - Transaction isolation level
|
|
56
|
+
* @throws {Error} When not connected
|
|
57
57
|
*/
|
|
58
58
|
async beginTransaction(isolationLevel?: IsolationLevel): Promise<void> {
|
|
59
59
|
const conn = this._requireConn();
|
|
@@ -61,9 +61,9 @@ export class NodeDbContextExecutor implements DbContextExecutor {
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
/**
|
|
64
|
-
*
|
|
64
|
+
* Commit transaction
|
|
65
65
|
*
|
|
66
|
-
* @throws {Error}
|
|
66
|
+
* @throws {Error} When not connected
|
|
67
67
|
*/
|
|
68
68
|
async commitTransaction(): Promise<void> {
|
|
69
69
|
const conn = this._requireConn();
|
|
@@ -71,9 +71,9 @@ export class NodeDbContextExecutor implements DbContextExecutor {
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
/**
|
|
74
|
-
*
|
|
74
|
+
* Rollback transaction
|
|
75
75
|
*
|
|
76
|
-
* @throws {Error}
|
|
76
|
+
* @throws {Error} When not connected
|
|
77
77
|
*/
|
|
78
78
|
async rollbackTransaction(): Promise<void> {
|
|
79
79
|
const conn = this._requireConn();
|
|
@@ -81,12 +81,12 @@ export class NodeDbContextExecutor implements DbContextExecutor {
|
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
/**
|
|
84
|
-
*
|
|
84
|
+
* Execute parameterized query
|
|
85
85
|
*
|
|
86
|
-
* @param query - SQL
|
|
87
|
-
* @param params -
|
|
88
|
-
* @returns
|
|
89
|
-
* @throws {Error}
|
|
86
|
+
* @param query - SQL query string
|
|
87
|
+
* @param params - Query parameter array
|
|
88
|
+
* @returns Query result array
|
|
89
|
+
* @throws {Error} When not connected
|
|
90
90
|
*/
|
|
91
91
|
async executeParametrized(
|
|
92
92
|
query: string,
|
|
@@ -97,12 +97,12 @@ export class NodeDbContextExecutor implements DbContextExecutor {
|
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
/**
|
|
100
|
-
*
|
|
100
|
+
* Bulk insert data (using native bulk API)
|
|
101
101
|
*
|
|
102
|
-
* @param tableName -
|
|
103
|
-
* @param columnMetas -
|
|
104
|
-
* @param records -
|
|
105
|
-
* @throws {Error}
|
|
102
|
+
* @param tableName - Target table name
|
|
103
|
+
* @param columnMetas - Column metadata
|
|
104
|
+
* @param records - Record array to insert
|
|
105
|
+
* @throws {Error} When not connected
|
|
106
106
|
*/
|
|
107
107
|
async bulkInsert(
|
|
108
108
|
tableName: string,
|
|
@@ -114,14 +114,14 @@ export class NodeDbContextExecutor implements DbContextExecutor {
|
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
/**
|
|
117
|
-
* QueryDef
|
|
117
|
+
* Execute QueryDef array
|
|
118
118
|
*
|
|
119
|
-
* QueryDef
|
|
119
|
+
* Converts QueryDef to SQL and executes, parses results using ResultMeta.
|
|
120
120
|
*
|
|
121
|
-
* @param defs -
|
|
122
|
-
* @param resultMetas -
|
|
123
|
-
* @returns
|
|
124
|
-
* @throws {Error}
|
|
121
|
+
* @param defs - QueryDef array to execute
|
|
122
|
+
* @param resultMetas - Result parsing metadata array (used for type conversion)
|
|
123
|
+
* @returns Array of execution results for each QueryDef
|
|
124
|
+
* @throws {Error} When not connected
|
|
125
125
|
*/
|
|
126
126
|
async executeDefs<T = DataRecord>(
|
|
127
127
|
defs: QueryDef[],
|
|
@@ -131,15 +131,15 @@ export class NodeDbContextExecutor implements DbContextExecutor {
|
|
|
131
131
|
|
|
132
132
|
const builder = createQueryBuilder(this._dialect);
|
|
133
133
|
|
|
134
|
-
//
|
|
135
|
-
//
|
|
134
|
+
// When configured not to fetch data, send one request with a single query
|
|
135
|
+
// Since results are not needed, return empty arrays matching defs.length to maintain interface contract
|
|
136
136
|
if (resultMetas != null && resultMetas.every((item) => item == null)) {
|
|
137
137
|
const combinedSql = defs.map((def) => builder.build(def).sql).join("\n");
|
|
138
138
|
await conn.execute([combinedSql]);
|
|
139
139
|
return defs.map(() => []) as T[][];
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
-
//
|
|
142
|
+
// Execute each def individually
|
|
143
143
|
const results: T[][] = [];
|
|
144
144
|
for (let i = 0; i < defs.length; i++) {
|
|
145
145
|
const def = defs[i];
|
|
@@ -148,7 +148,7 @@ export class NodeDbContextExecutor implements DbContextExecutor {
|
|
|
148
148
|
|
|
149
149
|
const rawResults = await conn.execute([buildResult.sql]);
|
|
150
150
|
|
|
151
|
-
//
|
|
151
|
+
// Use result set at specified index if resultSetIndex is specified
|
|
152
152
|
const targetResultSet =
|
|
153
153
|
buildResult.resultSetIndex != null ? rawResults[buildResult.resultSetIndex] : rawResults[0];
|
|
154
154
|
|