@berthojoris/mcp-mysql-server 1.0.0
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/LICENSE +21 -0
- package/README.md +1142 -0
- package/bin/mcp-mysql.js +122 -0
- package/dist/auth/authService.d.ts +29 -0
- package/dist/auth/authService.js +114 -0
- package/dist/config/config.d.ts +12 -0
- package/dist/config/config.js +19 -0
- package/dist/config/featureConfig.d.ts +51 -0
- package/dist/config/featureConfig.js +130 -0
- package/dist/db/connection.d.ts +22 -0
- package/dist/db/connection.js +135 -0
- package/dist/index.d.ts +236 -0
- package/dist/index.js +273 -0
- package/dist/mcp-server.d.ts +2 -0
- package/dist/mcp-server.js +748 -0
- package/dist/security/securityLayer.d.ts +52 -0
- package/dist/security/securityLayer.js +213 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.js +283 -0
- package/dist/tools/crudTools.d.ts +59 -0
- package/dist/tools/crudTools.js +443 -0
- package/dist/tools/databaseTools.d.ts +33 -0
- package/dist/tools/databaseTools.js +108 -0
- package/dist/tools/ddlTools.d.ts +69 -0
- package/dist/tools/ddlTools.js +199 -0
- package/dist/tools/queryTools.d.ts +29 -0
- package/dist/tools/queryTools.js +119 -0
- package/dist/tools/storedProcedureTools.d.ts +80 -0
- package/dist/tools/storedProcedureTools.js +411 -0
- package/dist/tools/transactionTools.d.ts +45 -0
- package/dist/tools/transactionTools.js +130 -0
- package/dist/tools/utilityTools.d.ts +30 -0
- package/dist/tools/utilityTools.js +121 -0
- package/dist/validation/schemas.d.ts +423 -0
- package/dist/validation/schemas.js +287 -0
- package/manifest.json +248 -0
- package/package.json +83 -0
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.StoredProcedureTools = void 0;
|
|
7
|
+
const connection_1 = __importDefault(require("../db/connection"));
|
|
8
|
+
const config_1 = require("../config/config");
|
|
9
|
+
const schemas_1 = require("../validation/schemas");
|
|
10
|
+
class StoredProcedureTools {
|
|
11
|
+
constructor(security) {
|
|
12
|
+
this.db = connection_1.default.getInstance();
|
|
13
|
+
this.security = security;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* List all stored procedures in the current database
|
|
17
|
+
*/
|
|
18
|
+
async listStoredProcedures(params) {
|
|
19
|
+
try {
|
|
20
|
+
// Validate input
|
|
21
|
+
if (!(0, schemas_1.validateListStoredProcedures)(params)) {
|
|
22
|
+
return {
|
|
23
|
+
status: 'error',
|
|
24
|
+
error: 'Invalid parameters: ' + JSON.stringify(schemas_1.validateListStoredProcedures.errors)
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
const database = params.database || config_1.dbConfig.database;
|
|
28
|
+
if (!database) {
|
|
29
|
+
return {
|
|
30
|
+
status: 'error',
|
|
31
|
+
error: 'No database specified and no current database selected'
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
const query = `
|
|
35
|
+
SELECT
|
|
36
|
+
ROUTINE_NAME as name,
|
|
37
|
+
ROUTINE_TYPE as type,
|
|
38
|
+
DATA_TYPE as return_type,
|
|
39
|
+
ROUTINE_DEFINITION as definition,
|
|
40
|
+
CREATED,
|
|
41
|
+
LAST_ALTERED,
|
|
42
|
+
ROUTINE_COMMENT as comment,
|
|
43
|
+
DEFINER,
|
|
44
|
+
SQL_MODE,
|
|
45
|
+
SECURITY_TYPE
|
|
46
|
+
FROM INFORMATION_SCHEMA.ROUTINES
|
|
47
|
+
WHERE ROUTINE_SCHEMA = ? AND ROUTINE_TYPE = 'PROCEDURE'
|
|
48
|
+
ORDER BY ROUTINE_NAME
|
|
49
|
+
`;
|
|
50
|
+
const results = await this.db.query(query, [database]);
|
|
51
|
+
return {
|
|
52
|
+
status: 'success',
|
|
53
|
+
data: results
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
return {
|
|
58
|
+
status: 'error',
|
|
59
|
+
error: error.message
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Get detailed information about a specific stored procedure
|
|
65
|
+
*/
|
|
66
|
+
async getStoredProcedureInfo(params) {
|
|
67
|
+
try {
|
|
68
|
+
// Validate input
|
|
69
|
+
if (!(0, schemas_1.validateGetStoredProcedureInfo)(params)) {
|
|
70
|
+
return {
|
|
71
|
+
status: 'error',
|
|
72
|
+
error: 'Invalid parameters: ' + JSON.stringify(schemas_1.validateGetStoredProcedureInfo.errors)
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
const { procedure_name } = params;
|
|
76
|
+
const database = params.database || config_1.dbConfig.database;
|
|
77
|
+
if (!database) {
|
|
78
|
+
return {
|
|
79
|
+
status: 'error',
|
|
80
|
+
error: 'No database specified and no current database selected'
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
// Get procedure information
|
|
84
|
+
const procedureQuery = `
|
|
85
|
+
SELECT
|
|
86
|
+
ROUTINE_NAME as name,
|
|
87
|
+
ROUTINE_TYPE as type,
|
|
88
|
+
DATA_TYPE as return_type,
|
|
89
|
+
ROUTINE_DEFINITION as definition,
|
|
90
|
+
CREATED,
|
|
91
|
+
LAST_ALTERED,
|
|
92
|
+
ROUTINE_COMMENT as comment,
|
|
93
|
+
DEFINER,
|
|
94
|
+
SQL_MODE,
|
|
95
|
+
SECURITY_TYPE,
|
|
96
|
+
IS_DETERMINISTIC,
|
|
97
|
+
SQL_DATA_ACCESS,
|
|
98
|
+
ROUTINE_BODY
|
|
99
|
+
FROM INFORMATION_SCHEMA.ROUTINES
|
|
100
|
+
WHERE ROUTINE_SCHEMA = ? AND ROUTINE_NAME = ? AND ROUTINE_TYPE = 'PROCEDURE'
|
|
101
|
+
`;
|
|
102
|
+
// Get procedure parameters
|
|
103
|
+
const parametersQuery = `
|
|
104
|
+
SELECT
|
|
105
|
+
PARAMETER_NAME as name,
|
|
106
|
+
PARAMETER_MODE as mode,
|
|
107
|
+
DATA_TYPE as data_type,
|
|
108
|
+
CHARACTER_MAXIMUM_LENGTH as max_length,
|
|
109
|
+
ORDINAL_POSITION as position
|
|
110
|
+
FROM INFORMATION_SCHEMA.PARAMETERS
|
|
111
|
+
WHERE SPECIFIC_SCHEMA = ? AND SPECIFIC_NAME = ?
|
|
112
|
+
ORDER BY ORDINAL_POSITION
|
|
113
|
+
`;
|
|
114
|
+
const [procedureInfo, parameters] = await Promise.all([
|
|
115
|
+
this.db.query(procedureQuery, [database, procedure_name]),
|
|
116
|
+
this.db.query(parametersQuery, [database, procedure_name])
|
|
117
|
+
]);
|
|
118
|
+
if (procedureInfo.length === 0) {
|
|
119
|
+
return {
|
|
120
|
+
status: 'error',
|
|
121
|
+
error: `Stored procedure '${procedure_name}' not found in database '${database}'`
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
return {
|
|
125
|
+
status: 'success',
|
|
126
|
+
data: {
|
|
127
|
+
...procedureInfo[0],
|
|
128
|
+
parameters: parameters
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
return {
|
|
134
|
+
status: 'error',
|
|
135
|
+
error: error.message
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Execute a stored procedure with parameters
|
|
141
|
+
*/
|
|
142
|
+
async executeStoredProcedure(params) {
|
|
143
|
+
// Validate input schema
|
|
144
|
+
if (!(0, schemas_1.validateStoredProcedureExecution)(params)) {
|
|
145
|
+
return {
|
|
146
|
+
status: 'error',
|
|
147
|
+
error: 'Invalid parameters: ' + JSON.stringify(schemas_1.validateStoredProcedureExecution.errors)
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
try {
|
|
151
|
+
const { procedure_name, parameters = [] } = params;
|
|
152
|
+
const database = params.database || config_1.dbConfig.database;
|
|
153
|
+
if (!database) {
|
|
154
|
+
return {
|
|
155
|
+
status: 'error',
|
|
156
|
+
error: 'No database specified and no current database selected'
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
// Validate procedure name
|
|
160
|
+
const identifierValidation = this.security.validateIdentifier(procedure_name);
|
|
161
|
+
if (!identifierValidation.valid) {
|
|
162
|
+
return {
|
|
163
|
+
status: 'error',
|
|
164
|
+
error: identifierValidation.error || 'Invalid procedure name'
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
// Get procedure parameter information to handle OUT/INOUT parameters
|
|
168
|
+
const procInfo = await this.getStoredProcedureInfo({ procedure_name, database });
|
|
169
|
+
if (procInfo.status !== 'success' || !procInfo.data) {
|
|
170
|
+
return {
|
|
171
|
+
status: 'error',
|
|
172
|
+
error: `Could not retrieve procedure information: ${procInfo.error || 'Unknown error'}`
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
const procedureParams = procInfo.data.parameters || [];
|
|
176
|
+
// Validate parameter count
|
|
177
|
+
if (parameters.length > procedureParams.length) {
|
|
178
|
+
return {
|
|
179
|
+
status: 'error',
|
|
180
|
+
error: `Too many parameters provided. Expected ${procedureParams.length}, got ${parameters.length}`
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
// Validate parameters
|
|
184
|
+
const paramValidation = this.security.validateParameters(parameters);
|
|
185
|
+
if (!paramValidation.valid) {
|
|
186
|
+
return {
|
|
187
|
+
status: 'error',
|
|
188
|
+
error: `Parameter validation failed: ${paramValidation.error}`
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
// Build parameter list for CALL statement
|
|
192
|
+
const callParams = [];
|
|
193
|
+
const sessionVars = [];
|
|
194
|
+
let paramIndex = 0;
|
|
195
|
+
for (let i = 0; i < procedureParams.length; i++) {
|
|
196
|
+
const procParam = procedureParams[i];
|
|
197
|
+
if (procParam.mode === 'IN') {
|
|
198
|
+
// IN parameters use provided values or NULL if not provided
|
|
199
|
+
if (paramIndex < parameters.length) {
|
|
200
|
+
callParams.push('?');
|
|
201
|
+
paramIndex++;
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
callParams.push('NULL');
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
else if (procParam.mode === 'OUT' || procParam.mode === 'INOUT') {
|
|
208
|
+
// OUT/INOUT parameters use session variables
|
|
209
|
+
const varName = `@${procParam.name}_${Date.now()}_${i}`;
|
|
210
|
+
sessionVars.push(varName);
|
|
211
|
+
if (procParam.mode === 'INOUT' && paramIndex < parameters.length) {
|
|
212
|
+
// For INOUT, set the session variable to the input value first
|
|
213
|
+
await this.db.query(`SET ${varName} = ?`, [paramValidation.sanitizedParams[paramIndex]]);
|
|
214
|
+
paramIndex++;
|
|
215
|
+
}
|
|
216
|
+
callParams.push(varName);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
// Build and execute CALL statement
|
|
220
|
+
const callQuery = `CALL \`${database}\`.\`${procedure_name}\`(${callParams.join(', ')})`;
|
|
221
|
+
const callResults = await this.db.query(callQuery, paramValidation.sanitizedParams.slice(0, paramIndex));
|
|
222
|
+
// Get OUT/INOUT parameter values
|
|
223
|
+
const outputValues = {};
|
|
224
|
+
if (sessionVars.length > 0) {
|
|
225
|
+
const selectQuery = `SELECT ${sessionVars.join(', ')}`;
|
|
226
|
+
const outputResults = await this.db.query(selectQuery);
|
|
227
|
+
if (outputResults && outputResults.length > 0) {
|
|
228
|
+
const outputRow = outputResults[0];
|
|
229
|
+
sessionVars.forEach((varName, index) => {
|
|
230
|
+
const paramName = procedureParams.find((p) => (p.mode === 'OUT' || p.mode === 'INOUT') &&
|
|
231
|
+
varName.includes(p.name))?.name || `param_${index}`;
|
|
232
|
+
outputValues[paramName] = outputRow[varName];
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return {
|
|
237
|
+
status: 'success',
|
|
238
|
+
data: {
|
|
239
|
+
results: callResults,
|
|
240
|
+
outputParameters: Object.keys(outputValues).length > 0 ? outputValues : undefined
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
catch (error) {
|
|
245
|
+
return {
|
|
246
|
+
status: 'error',
|
|
247
|
+
error: error.message
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Create a new stored procedure
|
|
253
|
+
*/
|
|
254
|
+
async createStoredProcedure(params) {
|
|
255
|
+
// Validate input schema
|
|
256
|
+
if (!(0, schemas_1.validateStoredProcedureCreation)(params)) {
|
|
257
|
+
return {
|
|
258
|
+
status: 'error',
|
|
259
|
+
error: 'Invalid parameters: ' + JSON.stringify(schemas_1.validateStoredProcedureCreation.errors)
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
try {
|
|
263
|
+
const { procedure_name, parameters = [], body, comment } = params;
|
|
264
|
+
const database = params.database || config_1.dbConfig.database;
|
|
265
|
+
if (!database) {
|
|
266
|
+
return {
|
|
267
|
+
status: 'error',
|
|
268
|
+
error: 'No database specified and no current database selected'
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
// Validate procedure name
|
|
272
|
+
const identifierValidation = this.security.validateIdentifier(procedure_name);
|
|
273
|
+
if (!identifierValidation.valid) {
|
|
274
|
+
return {
|
|
275
|
+
status: 'error',
|
|
276
|
+
error: identifierValidation.error || 'Invalid procedure name'
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
// Build parameter list
|
|
280
|
+
const parameterList = parameters.map(param => {
|
|
281
|
+
if (!this.security.validateIdentifier(param.name).valid) {
|
|
282
|
+
throw new Error(`Invalid parameter name: ${param.name}`);
|
|
283
|
+
}
|
|
284
|
+
return `${param.mode} \`${param.name}\` ${param.data_type}`;
|
|
285
|
+
}).join(', ');
|
|
286
|
+
// Build CREATE PROCEDURE statement
|
|
287
|
+
let createQuery = `CREATE PROCEDURE \`${database}\`.\`${procedure_name}\`(${parameterList})\n`;
|
|
288
|
+
if (comment) {
|
|
289
|
+
createQuery += `COMMENT '${comment.replace(/'/g, "''")}'
|
|
290
|
+
`;
|
|
291
|
+
}
|
|
292
|
+
// Check if body already contains BEGIN/END, if not add them
|
|
293
|
+
const trimmedBody = body.trim();
|
|
294
|
+
if (trimmedBody.toUpperCase().startsWith('BEGIN') && trimmedBody.toUpperCase().endsWith('END')) {
|
|
295
|
+
createQuery += `\n${body}`;
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
createQuery += `BEGIN\n${body}\nEND`;
|
|
299
|
+
}
|
|
300
|
+
// Execute the CREATE PROCEDURE statement
|
|
301
|
+
await this.db.query(createQuery);
|
|
302
|
+
return {
|
|
303
|
+
status: 'success',
|
|
304
|
+
data: {
|
|
305
|
+
message: `Stored procedure '${procedure_name}' created successfully`,
|
|
306
|
+
procedure_name,
|
|
307
|
+
database
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
catch (error) {
|
|
312
|
+
return {
|
|
313
|
+
status: 'error',
|
|
314
|
+
error: error.message
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Drop a stored procedure
|
|
320
|
+
*/
|
|
321
|
+
async dropStoredProcedure(params) {
|
|
322
|
+
try {
|
|
323
|
+
// Validate input
|
|
324
|
+
if (!(0, schemas_1.validateDropStoredProcedure)(params)) {
|
|
325
|
+
return {
|
|
326
|
+
status: 'error',
|
|
327
|
+
error: 'Invalid parameters: ' + JSON.stringify(schemas_1.validateDropStoredProcedure.errors)
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
const { procedure_name, if_exists = false } = params;
|
|
331
|
+
const database = params.database || config_1.dbConfig.database;
|
|
332
|
+
if (!database) {
|
|
333
|
+
return {
|
|
334
|
+
status: 'error',
|
|
335
|
+
error: 'No database specified and no current database selected'
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
// Validate procedure name
|
|
339
|
+
const identifierValidation = this.security.validateIdentifier(procedure_name);
|
|
340
|
+
if (!identifierValidation.valid) {
|
|
341
|
+
return {
|
|
342
|
+
status: 'error',
|
|
343
|
+
error: identifierValidation.error || 'Invalid procedure name'
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
// Build DROP PROCEDURE statement
|
|
347
|
+
const dropQuery = `DROP PROCEDURE ${if_exists ? 'IF EXISTS' : ''} \`${database}\`.\`${procedure_name}\``;
|
|
348
|
+
// Execute the DROP PROCEDURE statement
|
|
349
|
+
await this.db.query(dropQuery);
|
|
350
|
+
return {
|
|
351
|
+
status: 'success',
|
|
352
|
+
message: `Stored procedure '${procedure_name}' dropped successfully`
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
catch (error) {
|
|
356
|
+
return {
|
|
357
|
+
status: 'error',
|
|
358
|
+
error: error.message
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Show the CREATE statement for a stored procedure
|
|
364
|
+
*/
|
|
365
|
+
async showCreateProcedure(params) {
|
|
366
|
+
try {
|
|
367
|
+
// Validate input
|
|
368
|
+
if (!(0, schemas_1.validateShowCreateProcedure)(params)) {
|
|
369
|
+
return {
|
|
370
|
+
status: 'error',
|
|
371
|
+
error: 'Invalid parameters: ' + JSON.stringify(schemas_1.validateShowCreateProcedure.errors)
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
const { procedure_name } = params;
|
|
375
|
+
const database = params.database || config_1.dbConfig.database;
|
|
376
|
+
if (!database) {
|
|
377
|
+
return {
|
|
378
|
+
status: 'error',
|
|
379
|
+
error: 'No database specified and no current database selected'
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
// Validate procedure name
|
|
383
|
+
const identifierValidation = this.security.validateIdentifier(procedure_name);
|
|
384
|
+
if (!identifierValidation.valid) {
|
|
385
|
+
return {
|
|
386
|
+
status: 'error',
|
|
387
|
+
error: identifierValidation.error || 'Invalid procedure name'
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
const query = `SHOW CREATE PROCEDURE \`${database}\`.\`${procedure_name}\``;
|
|
391
|
+
const results = await this.db.query(query);
|
|
392
|
+
if (results.length === 0) {
|
|
393
|
+
return {
|
|
394
|
+
status: 'error',
|
|
395
|
+
error: `Stored procedure '${procedure_name}' not found`
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
return {
|
|
399
|
+
status: 'success',
|
|
400
|
+
data: results[0]
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
catch (error) {
|
|
404
|
+
return {
|
|
405
|
+
status: 'error',
|
|
406
|
+
error: error.message
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
exports.StoredProcedureTools = StoredProcedureTools;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export interface TransactionResult {
|
|
2
|
+
status: 'success' | 'error';
|
|
3
|
+
transactionId?: string;
|
|
4
|
+
message?: string;
|
|
5
|
+
activeTransactions?: string[];
|
|
6
|
+
error?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare class TransactionTools {
|
|
9
|
+
private db;
|
|
10
|
+
constructor();
|
|
11
|
+
/**
|
|
12
|
+
* Begin a new transaction
|
|
13
|
+
*/
|
|
14
|
+
beginTransaction(params?: {
|
|
15
|
+
transactionId?: string;
|
|
16
|
+
}): Promise<TransactionResult>;
|
|
17
|
+
/**
|
|
18
|
+
* Commit a transaction
|
|
19
|
+
*/
|
|
20
|
+
commitTransaction(params: {
|
|
21
|
+
transactionId: string;
|
|
22
|
+
}): Promise<TransactionResult>;
|
|
23
|
+
/**
|
|
24
|
+
* Rollback a transaction
|
|
25
|
+
*/
|
|
26
|
+
rollbackTransaction(params: {
|
|
27
|
+
transactionId: string;
|
|
28
|
+
}): Promise<TransactionResult>;
|
|
29
|
+
/**
|
|
30
|
+
* Get status of active transactions
|
|
31
|
+
*/
|
|
32
|
+
getTransactionStatus(): Promise<TransactionResult>;
|
|
33
|
+
/**
|
|
34
|
+
* Execute a query within a transaction
|
|
35
|
+
*/
|
|
36
|
+
executeInTransaction(params: {
|
|
37
|
+
transactionId: string;
|
|
38
|
+
query: string;
|
|
39
|
+
params?: any[];
|
|
40
|
+
}): Promise<{
|
|
41
|
+
status: 'success' | 'error';
|
|
42
|
+
data?: any;
|
|
43
|
+
error?: string;
|
|
44
|
+
}>;
|
|
45
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.TransactionTools = void 0;
|
|
7
|
+
const connection_1 = __importDefault(require("../db/connection"));
|
|
8
|
+
class TransactionTools {
|
|
9
|
+
constructor() {
|
|
10
|
+
this.db = connection_1.default.getInstance();
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Begin a new transaction
|
|
14
|
+
*/
|
|
15
|
+
async beginTransaction(params) {
|
|
16
|
+
try {
|
|
17
|
+
const transactionId = params?.transactionId || `tx_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
18
|
+
await this.db.beginTransaction(transactionId);
|
|
19
|
+
return {
|
|
20
|
+
status: 'success',
|
|
21
|
+
transactionId,
|
|
22
|
+
message: `Transaction ${transactionId} started successfully`
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
return {
|
|
27
|
+
status: 'error',
|
|
28
|
+
error: error.message
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Commit a transaction
|
|
34
|
+
*/
|
|
35
|
+
async commitTransaction(params) {
|
|
36
|
+
try {
|
|
37
|
+
if (!params.transactionId) {
|
|
38
|
+
return {
|
|
39
|
+
status: 'error',
|
|
40
|
+
error: 'Transaction ID is required'
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
await this.db.commitTransaction(params.transactionId);
|
|
44
|
+
return {
|
|
45
|
+
status: 'success',
|
|
46
|
+
message: `Transaction ${params.transactionId} committed successfully`
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
return {
|
|
51
|
+
status: 'error',
|
|
52
|
+
error: error.message
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Rollback a transaction
|
|
58
|
+
*/
|
|
59
|
+
async rollbackTransaction(params) {
|
|
60
|
+
try {
|
|
61
|
+
if (!params.transactionId) {
|
|
62
|
+
return {
|
|
63
|
+
status: 'error',
|
|
64
|
+
error: 'Transaction ID is required'
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
await this.db.rollbackTransaction(params.transactionId);
|
|
68
|
+
return {
|
|
69
|
+
status: 'success',
|
|
70
|
+
message: `Transaction ${params.transactionId} rolled back successfully`
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
return {
|
|
75
|
+
status: 'error',
|
|
76
|
+
error: error.message
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Get status of active transactions
|
|
82
|
+
*/
|
|
83
|
+
async getTransactionStatus() {
|
|
84
|
+
try {
|
|
85
|
+
const activeTransactions = this.db.getActiveTransactionIds();
|
|
86
|
+
return {
|
|
87
|
+
status: 'success',
|
|
88
|
+
activeTransactions,
|
|
89
|
+
message: `Found ${activeTransactions.length} active transaction(s)`
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
return {
|
|
94
|
+
status: 'error',
|
|
95
|
+
error: error.message
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Execute a query within a transaction
|
|
101
|
+
*/
|
|
102
|
+
async executeInTransaction(params) {
|
|
103
|
+
try {
|
|
104
|
+
if (!params.transactionId) {
|
|
105
|
+
return {
|
|
106
|
+
status: 'error',
|
|
107
|
+
error: 'Transaction ID is required'
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
if (!params.query) {
|
|
111
|
+
return {
|
|
112
|
+
status: 'error',
|
|
113
|
+
error: 'Query is required'
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
const result = await this.db.executeInTransaction(params.transactionId, params.query, params.params);
|
|
117
|
+
return {
|
|
118
|
+
status: 'success',
|
|
119
|
+
data: result
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
return {
|
|
124
|
+
status: 'error',
|
|
125
|
+
error: error.message
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
exports.TransactionTools = TransactionTools;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export declare class UtilityTools {
|
|
2
|
+
private db;
|
|
3
|
+
constructor();
|
|
4
|
+
/**
|
|
5
|
+
* Returns the current database connection info
|
|
6
|
+
*/
|
|
7
|
+
describeConnection(): Promise<{
|
|
8
|
+
status: string;
|
|
9
|
+
data?: any;
|
|
10
|
+
error?: string;
|
|
11
|
+
}>;
|
|
12
|
+
/**
|
|
13
|
+
* Tests the DB connection and returns latency
|
|
14
|
+
*/
|
|
15
|
+
testConnection(): Promise<{
|
|
16
|
+
status: string;
|
|
17
|
+
data?: any;
|
|
18
|
+
error?: string;
|
|
19
|
+
}>;
|
|
20
|
+
/**
|
|
21
|
+
* Detects and describes foreign key relationships between tables
|
|
22
|
+
*/
|
|
23
|
+
getTableRelationships(params: {
|
|
24
|
+
table_name: string;
|
|
25
|
+
}): Promise<{
|
|
26
|
+
status: string;
|
|
27
|
+
data?: any;
|
|
28
|
+
error?: string;
|
|
29
|
+
}>;
|
|
30
|
+
}
|