@heyhru/business-dms-datasource 0.8.3 → 0.8.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/dist/index.js +7 -241
- package/dist/index.mjs +7 -204
- package/package.json +6 -6
package/dist/index.js
CHANGED
|
@@ -1,253 +1,19 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
|
|
20
|
-
// src/index.ts
|
|
21
|
-
var index_exports = {};
|
|
22
|
-
__export(index_exports, {
|
|
23
|
-
datasourceCreate: () => datasourceCreate,
|
|
24
|
-
datasourceDelete: () => datasourceDelete,
|
|
25
|
-
datasourceGet: () => datasourceGet,
|
|
26
|
-
datasourceList: () => datasourceList,
|
|
27
|
-
datasourceUpdate: () => datasourceUpdate,
|
|
28
|
-
getDataSourceName: () => getDataSourceName,
|
|
29
|
-
getDataSourceType: () => getDataSourceType,
|
|
30
|
-
getDataSourceWithPassword: () => getDataSourceWithPassword,
|
|
31
|
-
getPool: () => getPool,
|
|
32
|
-
getPoolForDatabase: () => getPoolForDatabase,
|
|
33
|
-
getPoolStats: () => getPoolStats
|
|
34
|
-
});
|
|
35
|
-
module.exports = __toCommonJS(index_exports);
|
|
36
|
-
|
|
37
|
-
// src/datasources.service.ts
|
|
38
|
-
var import_server_util_crypto = require("@heyhru/server-util-crypto");
|
|
39
|
-
var import_server_plugin_mysql = require("@heyhru/server-plugin-mysql");
|
|
40
|
-
var import_server_plugin_pg2 = require("@heyhru/server-plugin-pg");
|
|
41
|
-
var import_common_util_logger = require("@heyhru/common-util-logger");
|
|
42
|
-
|
|
43
|
-
// src/datasources.model.ts
|
|
44
|
-
var import_server_plugin_pg = require("@heyhru/server-plugin-pg");
|
|
45
|
-
|
|
46
|
-
// src/datasources.sql.ts
|
|
47
|
-
var LIST = `
|
|
1
|
+
"use strict";var c=Object.defineProperty;var B=Object.getOwnPropertyDescriptor;var H=Object.getOwnPropertyNames;var Y=Object.prototype.hasOwnProperty;var k=(t,o)=>{for(var e in o)c(t,e,{get:o[e],enumerable:!0})},$=(t,o,e,s)=>{if(o&&typeof o=="object"||typeof o=="function")for(let r of H(o))!Y.call(t,r)&&r!==e&&c(t,r,{get:()=>o[r],enumerable:!(s=B(o,r))||s.enumerable});return t};var G=t=>$(c({},"__esModule",{value:!0}),t);var z={};k(z,{datasourceCreate:()=>A,datasourceDelete:()=>M,datasourceGet:()=>C,datasourceList:()=>O,datasourceUpdate:()=>v,getDataSourceName:()=>N,getDataSourceType:()=>W,getDataSourceWithPassword:()=>d,getPool:()=>l,getPoolForDatabase:()=>q,getPoolStats:()=>F});module.exports=G(z);var p=require("@heyhru/server-util-crypto"),h=require("@heyhru/server-plugin-mysql"),P=require("@heyhru/server-plugin-pg"),T=require("@heyhru/common-util-logger");var n=require("@heyhru/server-plugin-pg");var m=`
|
|
48
2
|
SELECT id, name, type, host, port, database, username, ssl, pool_min, pool_max, created_by, created_at
|
|
49
3
|
FROM data_sources
|
|
50
|
-
ORDER BY created_at DESC
|
|
51
|
-
var LIST_TEST_ONLY = `
|
|
4
|
+
ORDER BY created_at DESC`,g=`
|
|
52
5
|
SELECT id, name, type, host, port, database, username, ssl, pool_min, pool_max, created_by, created_at
|
|
53
6
|
FROM data_sources
|
|
54
7
|
WHERE name LIKE '%-test%'
|
|
55
|
-
ORDER BY created_at DESC
|
|
56
|
-
var FIND_BY_ID = `
|
|
8
|
+
ORDER BY created_at DESC`,y=`
|
|
57
9
|
SELECT id, name, type, host, port, database, username, ssl, pool_min, pool_max, created_by, created_at
|
|
58
10
|
FROM data_sources
|
|
59
|
-
WHERE id =
|
|
60
|
-
var FIND_WITH_PASSWORD = `
|
|
11
|
+
WHERE id = ?`,_=`
|
|
61
12
|
SELECT *
|
|
62
13
|
FROM data_sources
|
|
63
|
-
WHERE id =
|
|
64
|
-
var CREATE = `
|
|
14
|
+
WHERE id = ?`,f=`
|
|
65
15
|
INSERT INTO data_sources (name, type, host, port, database, username, password_encrypted, ssl, pool_min, pool_max, created_by)
|
|
66
16
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
67
|
-
RETURNING id, name, type, host, port, database, username, ssl, pool_min, pool_max, created_by, created_at
|
|
68
|
-
var UPDATE_FIELDS = ["name", "type", "host", "port", "database", "username", "ssl", "pool_min", "pool_max"];
|
|
69
|
-
var DELETE = `
|
|
17
|
+
RETURNING id, name, type, host, port, database, username, ssl, pool_min, pool_max, created_by, created_at`,b=["name","type","host","port","database","username","ssl","pool_min","pool_max"],D=`
|
|
70
18
|
DELETE FROM data_sources
|
|
71
|
-
WHERE id = ?`;
|
|
72
|
-
|
|
73
|
-
// src/datasources.model.ts
|
|
74
|
-
function listDataSources(testOnly = false) {
|
|
75
|
-
return (0, import_server_plugin_pg.getPgDb)().query(testOnly ? LIST_TEST_ONLY : LIST);
|
|
76
|
-
}
|
|
77
|
-
function getDataSourceById(id) {
|
|
78
|
-
return (0, import_server_plugin_pg.getPgDb)().queryOne(FIND_BY_ID, [id]);
|
|
79
|
-
}
|
|
80
|
-
function getDataSourceRow(id) {
|
|
81
|
-
return (0, import_server_plugin_pg.getPgDb)().queryOne(FIND_WITH_PASSWORD, [id]);
|
|
82
|
-
}
|
|
83
|
-
function insertDataSource(data, encryptedPassword, createdBy) {
|
|
84
|
-
return (0, import_server_plugin_pg.getPgDb)().queryOne(CREATE, [
|
|
85
|
-
data.name,
|
|
86
|
-
data.type,
|
|
87
|
-
data.host,
|
|
88
|
-
data.port,
|
|
89
|
-
data.database,
|
|
90
|
-
data.username,
|
|
91
|
-
encryptedPassword,
|
|
92
|
-
data.ssl,
|
|
93
|
-
data.pool_min,
|
|
94
|
-
data.pool_max,
|
|
95
|
-
createdBy
|
|
96
|
-
]);
|
|
97
|
-
}
|
|
98
|
-
async function updateDataSource(id, data, encryptedPassword) {
|
|
99
|
-
const fields = [];
|
|
100
|
-
const values = [];
|
|
101
|
-
for (const key of UPDATE_FIELDS) {
|
|
102
|
-
if (data[key] !== void 0) {
|
|
103
|
-
fields.push(`${key} = ?`);
|
|
104
|
-
values.push(data[key]);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
if (encryptedPassword) {
|
|
108
|
-
fields.push("password_encrypted = ?");
|
|
109
|
-
values.push(encryptedPassword);
|
|
110
|
-
}
|
|
111
|
-
if (!fields.length) return getDataSourceById(id);
|
|
112
|
-
values.push(id);
|
|
113
|
-
return (0, import_server_plugin_pg.getPgDb)().queryOne(
|
|
114
|
-
`UPDATE data_sources SET ${fields.join(", ")} WHERE id = ? RETURNING id, name, type, host, port, database, username, ssl, pool_min, pool_max, created_by, created_at`,
|
|
115
|
-
values
|
|
116
|
-
);
|
|
117
|
-
}
|
|
118
|
-
function removeDataSource(id) {
|
|
119
|
-
return (0, import_server_plugin_pg.getPgDb)().run(DELETE, [id]);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// src/datasources.service.ts
|
|
123
|
-
var logger = (0, import_common_util_logger.createLogger)({ name: "@heyhru/business-dms-datasource" });
|
|
124
|
-
var pools = /* @__PURE__ */ new Map();
|
|
125
|
-
function getPoolStats() {
|
|
126
|
-
return Array.from(pools.entries()).map(([key, pool]) => {
|
|
127
|
-
const colonIdx = key.indexOf(":");
|
|
128
|
-
const dataSourceId = colonIdx >= 0 ? key.slice(0, colonIdx) : key;
|
|
129
|
-
const database = colonIdx >= 0 ? key.slice(colonIdx + 1) : null;
|
|
130
|
-
const s = pool.stats();
|
|
131
|
-
return { dataSourceId, database, active: s?.active ?? null, waiting: s?.waiting ?? null };
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
function poolKey(id, database) {
|
|
135
|
-
return database ? `${id}:${database}` : id;
|
|
136
|
-
}
|
|
137
|
-
function getPool(ds) {
|
|
138
|
-
const key = poolKey(ds.id, ds.database);
|
|
139
|
-
if (pools.has(key)) return pools.get(key);
|
|
140
|
-
const pool = ds.type === "mysql" ? (0, import_server_plugin_mysql.createPool)({
|
|
141
|
-
host: ds.host,
|
|
142
|
-
port: ds.port,
|
|
143
|
-
database: ds.database,
|
|
144
|
-
username: ds.username,
|
|
145
|
-
password: ds.password,
|
|
146
|
-
poolMax: ds.pool_max
|
|
147
|
-
}) : (0, import_server_plugin_pg2.createPool)({
|
|
148
|
-
host: ds.host,
|
|
149
|
-
port: ds.port,
|
|
150
|
-
database: ds.database,
|
|
151
|
-
username: ds.username,
|
|
152
|
-
password: ds.password,
|
|
153
|
-
poolMin: ds.pool_min,
|
|
154
|
-
poolMax: ds.pool_max,
|
|
155
|
-
ssl: ds.ssl
|
|
156
|
-
});
|
|
157
|
-
pools.set(key, pool);
|
|
158
|
-
logger.info("Connection pool created (ds=%s, db=%s, type=%s)", ds.id, ds.database, ds.type);
|
|
159
|
-
return pool;
|
|
160
|
-
}
|
|
161
|
-
async function getDataSourceWithPassword(id, encryptionKey) {
|
|
162
|
-
const row = await getDataSourceRow(id);
|
|
163
|
-
if (!row) return null;
|
|
164
|
-
return {
|
|
165
|
-
id: row.id,
|
|
166
|
-
type: row.type,
|
|
167
|
-
host: row.host,
|
|
168
|
-
port: row.port,
|
|
169
|
-
database: row.database ?? null,
|
|
170
|
-
username: row.username,
|
|
171
|
-
password: (0, import_server_util_crypto.decrypt)(row.password_encrypted, encryptionKey),
|
|
172
|
-
ssl: row.ssl,
|
|
173
|
-
pool_min: row.pool_min,
|
|
174
|
-
pool_max: row.pool_max
|
|
175
|
-
};
|
|
176
|
-
}
|
|
177
|
-
async function getPoolForDatabase(dataSourceId, database, encryptionKey) {
|
|
178
|
-
const ds = await getDataSourceWithPassword(dataSourceId, encryptionKey);
|
|
179
|
-
if (!ds) return null;
|
|
180
|
-
return getPool({ ...ds, database });
|
|
181
|
-
}
|
|
182
|
-
async function destroyPool(id) {
|
|
183
|
-
const prefix = `${id}:`;
|
|
184
|
-
for (const [key, pool] of pools) {
|
|
185
|
-
if (key === id || key.startsWith(prefix)) {
|
|
186
|
-
await pool.end();
|
|
187
|
-
pools.delete(key);
|
|
188
|
-
logger.info("Connection pool destroyed (key=%s)", key);
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
var RESTRICTED_DS_ROLES = /* @__PURE__ */ new Set(["developer", "viewer"]);
|
|
193
|
-
async function datasourceList(req, reply) {
|
|
194
|
-
const role = req.user.role;
|
|
195
|
-
const testOnly = RESTRICTED_DS_ROLES.has(role);
|
|
196
|
-
return reply.send(await listDataSources(testOnly));
|
|
197
|
-
}
|
|
198
|
-
async function getDataSourceName(id) {
|
|
199
|
-
const row = await getDataSourceById(id);
|
|
200
|
-
return row ? row.name : null;
|
|
201
|
-
}
|
|
202
|
-
async function getDataSourceType(id) {
|
|
203
|
-
const row = await getDataSourceById(id);
|
|
204
|
-
return row ? row.type : null;
|
|
205
|
-
}
|
|
206
|
-
async function datasourceGet(req, reply) {
|
|
207
|
-
const { id } = req.body ?? {};
|
|
208
|
-
const ds = await getDataSourceById(id);
|
|
209
|
-
if (!ds) return reply.code(404).send({ error: "Not found" });
|
|
210
|
-
return reply.send(ds);
|
|
211
|
-
}
|
|
212
|
-
function datasourceCreate(encryptionKey) {
|
|
213
|
-
return async (req, reply) => {
|
|
214
|
-
const body = req.body ?? {};
|
|
215
|
-
const ds = await insertDataSource(
|
|
216
|
-
{ ...body, ssl: body.ssl ?? false, pool_min: body.pool_min ?? 1, pool_max: body.pool_max ?? 10 },
|
|
217
|
-
(0, import_server_util_crypto.encrypt)(body.password, encryptionKey),
|
|
218
|
-
req.user.id
|
|
219
|
-
);
|
|
220
|
-
return reply.code(201).send(ds);
|
|
221
|
-
};
|
|
222
|
-
}
|
|
223
|
-
function datasourceUpdate(encryptionKey) {
|
|
224
|
-
return async (req, reply) => {
|
|
225
|
-
const { id, password, ...rest } = req.body ?? {};
|
|
226
|
-
const existing = await getDataSourceById(id);
|
|
227
|
-
if (!existing) return reply.code(404).send({ error: "Not found" });
|
|
228
|
-
const encryptedPassword = password ? (0, import_server_util_crypto.encrypt)(password, encryptionKey) : void 0;
|
|
229
|
-
await destroyPool(id);
|
|
230
|
-
const ds = await updateDataSource(id, rest, encryptedPassword);
|
|
231
|
-
return reply.send(ds);
|
|
232
|
-
};
|
|
233
|
-
}
|
|
234
|
-
async function datasourceDelete(req, reply) {
|
|
235
|
-
const { id } = req.body ?? {};
|
|
236
|
-
await destroyPool(id);
|
|
237
|
-
await removeDataSource(id);
|
|
238
|
-
return reply.code(204).send();
|
|
239
|
-
}
|
|
240
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
241
|
-
0 && (module.exports = {
|
|
242
|
-
datasourceCreate,
|
|
243
|
-
datasourceDelete,
|
|
244
|
-
datasourceGet,
|
|
245
|
-
datasourceList,
|
|
246
|
-
datasourceUpdate,
|
|
247
|
-
getDataSourceName,
|
|
248
|
-
getDataSourceType,
|
|
249
|
-
getDataSourceWithPassword,
|
|
250
|
-
getPool,
|
|
251
|
-
getPoolForDatabase,
|
|
252
|
-
getPoolStats
|
|
253
|
-
});
|
|
19
|
+
WHERE id = ?`;function x(t=!1){return(0,n.getPgDb)().query(t?g:m)}function i(t){return(0,n.getPgDb)().queryOne(y,[t])}function S(t){return(0,n.getPgDb)().queryOne(_,[t])}function E(t,o,e){return(0,n.getPgDb)().queryOne(f,[t.name,t.type,t.host,t.port,t.database,t.username,o,t.ssl,t.pool_min,t.pool_max,e])}async function w(t,o,e){let s=[],r=[];for(let a of b)o[a]!==void 0&&(s.push(`${a} = ?`),r.push(o[a]));return e&&(s.push("password_encrypted = ?"),r.push(e)),s.length?(r.push(t),(0,n.getPgDb)().queryOne(`UPDATE data_sources SET ${s.join(", ")} WHERE id = ? RETURNING id, name, type, host, port, database, username, ssl, pool_min, pool_max, created_by, created_at`,r)):i(t)}function R(t){return(0,n.getPgDb)().run(D,[t])}var I=(0,T.createLogger)({name:"@heyhru/business-dms-datasource"}),u=new Map;function F(){return Array.from(u.entries()).map(([t,o])=>{let e=t.indexOf(":"),s=e>=0?t.slice(0,e):t,r=e>=0?t.slice(e+1):null,a=o.stats();return{dataSourceId:s,database:r,active:a?.active??null,waiting:a?.waiting??null}})}function K(t,o){return o?`${t}:${o}`:t}function l(t){let o=K(t.id,t.database);if(u.has(o))return u.get(o);let e=t.type==="mysql"?(0,h.createPool)({host:t.host,port:t.port,database:t.database,username:t.username,password:t.password,poolMax:t.pool_max}):(0,P.createPool)({host:t.host,port:t.port,database:t.database,username:t.username,password:t.password,poolMin:t.pool_min,poolMax:t.pool_max,ssl:t.ssl});return u.set(o,e),I.info("Connection pool created (ds=%s, db=%s, type=%s)",t.id,t.database,t.type),e}async function d(t,o){let e=await S(t);return e?{id:e.id,type:e.type,host:e.host,port:e.port,database:e.database??null,username:e.username,password:(0,p.decrypt)(e.password_encrypted,o),ssl:e.ssl,pool_min:e.pool_min,pool_max:e.pool_max}:null}async function q(t,o,e){let s=await d(t,e);return s?l({...s,database:o}):null}async function L(t){let o=`${t}:`;for(let[e,s]of u)(e===t||e.startsWith(o))&&(await s.end(),u.delete(e),I.info("Connection pool destroyed (key=%s)",e))}var V=new Set(["developer","viewer"]);async function O(t,o){let e=t.user.role,s=V.has(e);return o.send(await x(s))}async function N(t){let o=await i(t);return o?o.name:null}async function W(t){let o=await i(t);return o?o.type:null}async function C(t,o){let{id:e}=t.body??{},s=await i(e);return s?o.send(s):o.code(404).send({error:"Not found"})}function A(t){return async(o,e)=>{let s=o.body??{},r=await E({...s,ssl:s.ssl??!1,pool_min:s.pool_min??1,pool_max:s.pool_max??10},(0,p.encrypt)(s.password,t),o.user.id);return e.code(201).send(r)}}function v(t){return async(o,e)=>{let{id:s,password:r,...a}=o.body??{};if(!await i(s))return e.code(404).send({error:"Not found"});let Q=r?(0,p.encrypt)(r,t):void 0;await L(s);let U=await w(s,a,Q);return e.send(U)}}async function M(t,o){let{id:e}=t.body??{};return await L(e),await R(e),o.code(204).send()}0&&(module.exports={datasourceCreate,datasourceDelete,datasourceGet,datasourceList,datasourceUpdate,getDataSourceName,getDataSourceType,getDataSourceWithPassword,getPool,getPoolForDatabase,getPoolStats});
|
package/dist/index.mjs
CHANGED
|
@@ -1,216 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
import { encrypt, decrypt } from "@heyhru/server-util-crypto";
|
|
3
|
-
import { createPool as createMysqlPool } from "@heyhru/server-plugin-mysql";
|
|
4
|
-
import { createPool as createPgPool } from "@heyhru/server-plugin-pg";
|
|
5
|
-
import { createLogger } from "@heyhru/common-util-logger";
|
|
6
|
-
|
|
7
|
-
// src/datasources.model.ts
|
|
8
|
-
import { getPgDb } from "@heyhru/server-plugin-pg";
|
|
9
|
-
|
|
10
|
-
// src/datasources.sql.ts
|
|
11
|
-
var LIST = `
|
|
1
|
+
import{encrypt as S,decrypt as F}from"@heyhru/server-util-crypto";import{createPool as q}from"@heyhru/server-plugin-mysql";import{createPool as L}from"@heyhru/server-plugin-pg";import{createLogger as O}from"@heyhru/common-util-logger";import{getPgDb as n}from"@heyhru/server-plugin-pg";var p=`
|
|
12
2
|
SELECT id, name, type, host, port, database, username, ssl, pool_min, pool_max, created_by, created_at
|
|
13
3
|
FROM data_sources
|
|
14
|
-
ORDER BY created_at DESC
|
|
15
|
-
var LIST_TEST_ONLY = `
|
|
4
|
+
ORDER BY created_at DESC`,c=`
|
|
16
5
|
SELECT id, name, type, host, port, database, username, ssl, pool_min, pool_max, created_by, created_at
|
|
17
6
|
FROM data_sources
|
|
18
7
|
WHERE name LIKE '%-test%'
|
|
19
|
-
ORDER BY created_at DESC
|
|
20
|
-
var FIND_BY_ID = `
|
|
8
|
+
ORDER BY created_at DESC`,l=`
|
|
21
9
|
SELECT id, name, type, host, port, database, username, ssl, pool_min, pool_max, created_by, created_at
|
|
22
10
|
FROM data_sources
|
|
23
|
-
WHERE id =
|
|
24
|
-
var FIND_WITH_PASSWORD = `
|
|
11
|
+
WHERE id = ?`,d=`
|
|
25
12
|
SELECT *
|
|
26
13
|
FROM data_sources
|
|
27
|
-
WHERE id =
|
|
28
|
-
var CREATE = `
|
|
14
|
+
WHERE id = ?`,m=`
|
|
29
15
|
INSERT INTO data_sources (name, type, host, port, database, username, password_encrypted, ssl, pool_min, pool_max, created_by)
|
|
30
16
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
31
|
-
RETURNING id, name, type, host, port, database, username, ssl, pool_min, pool_max, created_by, created_at
|
|
32
|
-
var UPDATE_FIELDS = ["name", "type", "host", "port", "database", "username", "ssl", "pool_min", "pool_max"];
|
|
33
|
-
var DELETE = `
|
|
17
|
+
RETURNING id, name, type, host, port, database, username, ssl, pool_min, pool_max, created_by, created_at`,g=["name","type","host","port","database","username","ssl","pool_min","pool_max"],y=`
|
|
34
18
|
DELETE FROM data_sources
|
|
35
|
-
WHERE id = ?`;
|
|
36
|
-
|
|
37
|
-
// src/datasources.model.ts
|
|
38
|
-
function listDataSources(testOnly = false) {
|
|
39
|
-
return getPgDb().query(testOnly ? LIST_TEST_ONLY : LIST);
|
|
40
|
-
}
|
|
41
|
-
function getDataSourceById(id) {
|
|
42
|
-
return getPgDb().queryOne(FIND_BY_ID, [id]);
|
|
43
|
-
}
|
|
44
|
-
function getDataSourceRow(id) {
|
|
45
|
-
return getPgDb().queryOne(FIND_WITH_PASSWORD, [id]);
|
|
46
|
-
}
|
|
47
|
-
function insertDataSource(data, encryptedPassword, createdBy) {
|
|
48
|
-
return getPgDb().queryOne(CREATE, [
|
|
49
|
-
data.name,
|
|
50
|
-
data.type,
|
|
51
|
-
data.host,
|
|
52
|
-
data.port,
|
|
53
|
-
data.database,
|
|
54
|
-
data.username,
|
|
55
|
-
encryptedPassword,
|
|
56
|
-
data.ssl,
|
|
57
|
-
data.pool_min,
|
|
58
|
-
data.pool_max,
|
|
59
|
-
createdBy
|
|
60
|
-
]);
|
|
61
|
-
}
|
|
62
|
-
async function updateDataSource(id, data, encryptedPassword) {
|
|
63
|
-
const fields = [];
|
|
64
|
-
const values = [];
|
|
65
|
-
for (const key of UPDATE_FIELDS) {
|
|
66
|
-
if (data[key] !== void 0) {
|
|
67
|
-
fields.push(`${key} = ?`);
|
|
68
|
-
values.push(data[key]);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
if (encryptedPassword) {
|
|
72
|
-
fields.push("password_encrypted = ?");
|
|
73
|
-
values.push(encryptedPassword);
|
|
74
|
-
}
|
|
75
|
-
if (!fields.length) return getDataSourceById(id);
|
|
76
|
-
values.push(id);
|
|
77
|
-
return getPgDb().queryOne(
|
|
78
|
-
`UPDATE data_sources SET ${fields.join(", ")} WHERE id = ? RETURNING id, name, type, host, port, database, username, ssl, pool_min, pool_max, created_by, created_at`,
|
|
79
|
-
values
|
|
80
|
-
);
|
|
81
|
-
}
|
|
82
|
-
function removeDataSource(id) {
|
|
83
|
-
return getPgDb().run(DELETE, [id]);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// src/datasources.service.ts
|
|
87
|
-
var logger = createLogger({ name: "@heyhru/business-dms-datasource" });
|
|
88
|
-
var pools = /* @__PURE__ */ new Map();
|
|
89
|
-
function getPoolStats() {
|
|
90
|
-
return Array.from(pools.entries()).map(([key, pool]) => {
|
|
91
|
-
const colonIdx = key.indexOf(":");
|
|
92
|
-
const dataSourceId = colonIdx >= 0 ? key.slice(0, colonIdx) : key;
|
|
93
|
-
const database = colonIdx >= 0 ? key.slice(colonIdx + 1) : null;
|
|
94
|
-
const s = pool.stats();
|
|
95
|
-
return { dataSourceId, database, active: s?.active ?? null, waiting: s?.waiting ?? null };
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
function poolKey(id, database) {
|
|
99
|
-
return database ? `${id}:${database}` : id;
|
|
100
|
-
}
|
|
101
|
-
function getPool(ds) {
|
|
102
|
-
const key = poolKey(ds.id, ds.database);
|
|
103
|
-
if (pools.has(key)) return pools.get(key);
|
|
104
|
-
const pool = ds.type === "mysql" ? createMysqlPool({
|
|
105
|
-
host: ds.host,
|
|
106
|
-
port: ds.port,
|
|
107
|
-
database: ds.database,
|
|
108
|
-
username: ds.username,
|
|
109
|
-
password: ds.password,
|
|
110
|
-
poolMax: ds.pool_max
|
|
111
|
-
}) : createPgPool({
|
|
112
|
-
host: ds.host,
|
|
113
|
-
port: ds.port,
|
|
114
|
-
database: ds.database,
|
|
115
|
-
username: ds.username,
|
|
116
|
-
password: ds.password,
|
|
117
|
-
poolMin: ds.pool_min,
|
|
118
|
-
poolMax: ds.pool_max,
|
|
119
|
-
ssl: ds.ssl
|
|
120
|
-
});
|
|
121
|
-
pools.set(key, pool);
|
|
122
|
-
logger.info("Connection pool created (ds=%s, db=%s, type=%s)", ds.id, ds.database, ds.type);
|
|
123
|
-
return pool;
|
|
124
|
-
}
|
|
125
|
-
async function getDataSourceWithPassword(id, encryptionKey) {
|
|
126
|
-
const row = await getDataSourceRow(id);
|
|
127
|
-
if (!row) return null;
|
|
128
|
-
return {
|
|
129
|
-
id: row.id,
|
|
130
|
-
type: row.type,
|
|
131
|
-
host: row.host,
|
|
132
|
-
port: row.port,
|
|
133
|
-
database: row.database ?? null,
|
|
134
|
-
username: row.username,
|
|
135
|
-
password: decrypt(row.password_encrypted, encryptionKey),
|
|
136
|
-
ssl: row.ssl,
|
|
137
|
-
pool_min: row.pool_min,
|
|
138
|
-
pool_max: row.pool_max
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
async function getPoolForDatabase(dataSourceId, database, encryptionKey) {
|
|
142
|
-
const ds = await getDataSourceWithPassword(dataSourceId, encryptionKey);
|
|
143
|
-
if (!ds) return null;
|
|
144
|
-
return getPool({ ...ds, database });
|
|
145
|
-
}
|
|
146
|
-
async function destroyPool(id) {
|
|
147
|
-
const prefix = `${id}:`;
|
|
148
|
-
for (const [key, pool] of pools) {
|
|
149
|
-
if (key === id || key.startsWith(prefix)) {
|
|
150
|
-
await pool.end();
|
|
151
|
-
pools.delete(key);
|
|
152
|
-
logger.info("Connection pool destroyed (key=%s)", key);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
var RESTRICTED_DS_ROLES = /* @__PURE__ */ new Set(["developer", "viewer"]);
|
|
157
|
-
async function datasourceList(req, reply) {
|
|
158
|
-
const role = req.user.role;
|
|
159
|
-
const testOnly = RESTRICTED_DS_ROLES.has(role);
|
|
160
|
-
return reply.send(await listDataSources(testOnly));
|
|
161
|
-
}
|
|
162
|
-
async function getDataSourceName(id) {
|
|
163
|
-
const row = await getDataSourceById(id);
|
|
164
|
-
return row ? row.name : null;
|
|
165
|
-
}
|
|
166
|
-
async function getDataSourceType(id) {
|
|
167
|
-
const row = await getDataSourceById(id);
|
|
168
|
-
return row ? row.type : null;
|
|
169
|
-
}
|
|
170
|
-
async function datasourceGet(req, reply) {
|
|
171
|
-
const { id } = req.body ?? {};
|
|
172
|
-
const ds = await getDataSourceById(id);
|
|
173
|
-
if (!ds) return reply.code(404).send({ error: "Not found" });
|
|
174
|
-
return reply.send(ds);
|
|
175
|
-
}
|
|
176
|
-
function datasourceCreate(encryptionKey) {
|
|
177
|
-
return async (req, reply) => {
|
|
178
|
-
const body = req.body ?? {};
|
|
179
|
-
const ds = await insertDataSource(
|
|
180
|
-
{ ...body, ssl: body.ssl ?? false, pool_min: body.pool_min ?? 1, pool_max: body.pool_max ?? 10 },
|
|
181
|
-
encrypt(body.password, encryptionKey),
|
|
182
|
-
req.user.id
|
|
183
|
-
);
|
|
184
|
-
return reply.code(201).send(ds);
|
|
185
|
-
};
|
|
186
|
-
}
|
|
187
|
-
function datasourceUpdate(encryptionKey) {
|
|
188
|
-
return async (req, reply) => {
|
|
189
|
-
const { id, password, ...rest } = req.body ?? {};
|
|
190
|
-
const existing = await getDataSourceById(id);
|
|
191
|
-
if (!existing) return reply.code(404).send({ error: "Not found" });
|
|
192
|
-
const encryptedPassword = password ? encrypt(password, encryptionKey) : void 0;
|
|
193
|
-
await destroyPool(id);
|
|
194
|
-
const ds = await updateDataSource(id, rest, encryptedPassword);
|
|
195
|
-
return reply.send(ds);
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
async function datasourceDelete(req, reply) {
|
|
199
|
-
const { id } = req.body ?? {};
|
|
200
|
-
await destroyPool(id);
|
|
201
|
-
await removeDataSource(id);
|
|
202
|
-
return reply.code(204).send();
|
|
203
|
-
}
|
|
204
|
-
export {
|
|
205
|
-
datasourceCreate,
|
|
206
|
-
datasourceDelete,
|
|
207
|
-
datasourceGet,
|
|
208
|
-
datasourceList,
|
|
209
|
-
datasourceUpdate,
|
|
210
|
-
getDataSourceName,
|
|
211
|
-
getDataSourceType,
|
|
212
|
-
getDataSourceWithPassword,
|
|
213
|
-
getPool,
|
|
214
|
-
getPoolForDatabase,
|
|
215
|
-
getPoolStats
|
|
216
|
-
};
|
|
19
|
+
WHERE id = ?`;function _(t=!1){return n().query(t?c:p)}function i(t){return n().queryOne(l,[t])}function f(t){return n().queryOne(d,[t])}function b(t,o,e){return n().queryOne(m,[t.name,t.type,t.host,t.port,t.database,t.username,o,t.ssl,t.pool_min,t.pool_max,e])}async function D(t,o,e){let s=[],r=[];for(let a of g)o[a]!==void 0&&(s.push(`${a} = ?`),r.push(o[a]));return e&&(s.push("password_encrypted = ?"),r.push(e)),s.length?(r.push(t),n().queryOne(`UPDATE data_sources SET ${s.join(", ")} WHERE id = ? RETURNING id, name, type, host, port, database, username, ssl, pool_min, pool_max, created_by, created_at`,r)):i(t)}function x(t){return n().run(y,[t])}var E=O({name:"@heyhru/business-dms-datasource"}),u=new Map;function N(){return Array.from(u.entries()).map(([t,o])=>{let e=t.indexOf(":"),s=e>=0?t.slice(0,e):t,r=e>=0?t.slice(e+1):null,a=o.stats();return{dataSourceId:s,database:r,active:a?.active??null,waiting:a?.waiting??null}})}function W(t,o){return o?`${t}:${o}`:t}function w(t){let o=W(t.id,t.database);if(u.has(o))return u.get(o);let e=t.type==="mysql"?q({host:t.host,port:t.port,database:t.database,username:t.username,password:t.password,poolMax:t.pool_max}):L({host:t.host,port:t.port,database:t.database,username:t.username,password:t.password,poolMin:t.pool_min,poolMax:t.pool_max,ssl:t.ssl});return u.set(o,e),E.info("Connection pool created (ds=%s, db=%s, type=%s)",t.id,t.database,t.type),e}async function R(t,o){let e=await f(t);return e?{id:e.id,type:e.type,host:e.host,port:e.port,database:e.database??null,username:e.username,password:F(e.password_encrypted,o),ssl:e.ssl,pool_min:e.pool_min,pool_max:e.pool_max}:null}async function C(t,o,e){let s=await R(t,e);return s?w({...s,database:o}):null}async function h(t){let o=`${t}:`;for(let[e,s]of u)(e===t||e.startsWith(o))&&(await s.end(),u.delete(e),E.info("Connection pool destroyed (key=%s)",e))}var A=new Set(["developer","viewer"]);async function v(t,o){let e=t.user.role,s=A.has(e);return o.send(await _(s))}async function M(t){let o=await i(t);return o?o.name:null}async function Q(t){let o=await i(t);return o?o.type:null}async function U(t,o){let{id:e}=t.body??{},s=await i(e);return s?o.send(s):o.code(404).send({error:"Not found"})}function B(t){return async(o,e)=>{let s=o.body??{},r=await b({...s,ssl:s.ssl??!1,pool_min:s.pool_min??1,pool_max:s.pool_max??10},S(s.password,t),o.user.id);return e.code(201).send(r)}}function H(t){return async(o,e)=>{let{id:s,password:r,...a}=o.body??{};if(!await i(s))return e.code(404).send({error:"Not found"});let P=r?S(r,t):void 0;await h(s);let T=await D(s,a,P);return e.send(T)}}async function Y(t,o){let{id:e}=t.body??{};return await h(e),await x(e),o.code(204).send()}export{B as datasourceCreate,Y as datasourceDelete,U as datasourceGet,v as datasourceList,H as datasourceUpdate,M as getDataSourceName,Q as getDataSourceType,R as getDataSourceWithPassword,w as getPool,C as getPoolForDatabase,N as getPoolStats};
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "0.8.
|
|
6
|
+
"version": "0.8.4",
|
|
7
7
|
"description": "DMS data source domain logic: service, model, sql, pool management",
|
|
8
8
|
"main": "./dist/index.js",
|
|
9
9
|
"module": "./dist/index.mjs",
|
|
@@ -26,10 +26,10 @@
|
|
|
26
26
|
"clean": "rm -rf dist"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@heyhru/common-util-logger": "0.6.
|
|
30
|
-
"@heyhru/server-plugin-mysql": "0.8.
|
|
31
|
-
"@heyhru/server-plugin-pg": "0.8.
|
|
32
|
-
"@heyhru/server-util-crypto": "0.6.
|
|
29
|
+
"@heyhru/common-util-logger": "0.6.1",
|
|
30
|
+
"@heyhru/server-plugin-mysql": "0.8.1",
|
|
31
|
+
"@heyhru/server-plugin-pg": "0.8.1",
|
|
32
|
+
"@heyhru/server-util-crypto": "0.6.1",
|
|
33
33
|
"fastify": "^5.8.4"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
@@ -37,5 +37,5 @@
|
|
|
37
37
|
"typescript": "^6.0.2",
|
|
38
38
|
"vitest": "^4.1.4"
|
|
39
39
|
},
|
|
40
|
-
"gitHead": "
|
|
40
|
+
"gitHead": "f9b600df3b574040ab7fb62fc438073652256505"
|
|
41
41
|
}
|