@berthojoris/mcp-mysql-server 1.5.0 → 1.6.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/DOCUMENTATIONS.md +477 -17
- package/README.md +102 -5
- package/dist/index.d.ts +401 -0
- package/dist/index.js +311 -0
- package/dist/mcp-server.js +1067 -0
- package/dist/tools/constraintTools.d.ts +108 -0
- package/dist/tools/constraintTools.js +405 -0
- package/dist/tools/functionTools.d.ts +93 -0
- package/dist/tools/functionTools.js +351 -0
- package/dist/tools/indexTools.d.ts +81 -0
- package/dist/tools/indexTools.js +345 -0
- package/dist/tools/maintenanceTools.d.ts +111 -0
- package/dist/tools/maintenanceTools.js +371 -0
- package/dist/tools/processTools.d.ts +106 -0
- package/dist/tools/processTools.js +305 -0
- package/dist/tools/triggerTools.d.ts +76 -0
- package/dist/tools/triggerTools.js +294 -0
- package/dist/tools/viewTools.d.ts +91 -0
- package/dist/tools/viewTools.js +330 -0
- package/package.json +1 -1
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { SecurityLayer } from '../security/securityLayer';
|
|
2
|
+
export declare class ConstraintTools {
|
|
3
|
+
private db;
|
|
4
|
+
private security;
|
|
5
|
+
constructor(security: SecurityLayer);
|
|
6
|
+
/**
|
|
7
|
+
* Validate database access - ensures only the connected database can be accessed
|
|
8
|
+
*/
|
|
9
|
+
private validateDatabaseAccess;
|
|
10
|
+
/**
|
|
11
|
+
* List all foreign keys for a table
|
|
12
|
+
*/
|
|
13
|
+
listForeignKeys(params: {
|
|
14
|
+
table_name: string;
|
|
15
|
+
database?: string;
|
|
16
|
+
}): Promise<{
|
|
17
|
+
status: string;
|
|
18
|
+
data?: any[];
|
|
19
|
+
error?: string;
|
|
20
|
+
queryLog?: string;
|
|
21
|
+
}>;
|
|
22
|
+
/**
|
|
23
|
+
* List all constraints (PK, FK, UNIQUE, CHECK) for a table
|
|
24
|
+
*/
|
|
25
|
+
listConstraints(params: {
|
|
26
|
+
table_name: string;
|
|
27
|
+
database?: string;
|
|
28
|
+
}): Promise<{
|
|
29
|
+
status: string;
|
|
30
|
+
data?: any[];
|
|
31
|
+
error?: string;
|
|
32
|
+
queryLog?: string;
|
|
33
|
+
}>;
|
|
34
|
+
/**
|
|
35
|
+
* Add a foreign key constraint
|
|
36
|
+
*/
|
|
37
|
+
addForeignKey(params: {
|
|
38
|
+
table_name: string;
|
|
39
|
+
constraint_name: string;
|
|
40
|
+
columns: string[];
|
|
41
|
+
referenced_table: string;
|
|
42
|
+
referenced_columns: string[];
|
|
43
|
+
on_delete?: 'CASCADE' | 'SET NULL' | 'RESTRICT' | 'NO ACTION' | 'SET DEFAULT';
|
|
44
|
+
on_update?: 'CASCADE' | 'SET NULL' | 'RESTRICT' | 'NO ACTION' | 'SET DEFAULT';
|
|
45
|
+
database?: string;
|
|
46
|
+
}): Promise<{
|
|
47
|
+
status: string;
|
|
48
|
+
data?: any;
|
|
49
|
+
error?: string;
|
|
50
|
+
queryLog?: string;
|
|
51
|
+
}>;
|
|
52
|
+
/**
|
|
53
|
+
* Drop a foreign key constraint
|
|
54
|
+
*/
|
|
55
|
+
dropForeignKey(params: {
|
|
56
|
+
table_name: string;
|
|
57
|
+
constraint_name: string;
|
|
58
|
+
database?: string;
|
|
59
|
+
}): Promise<{
|
|
60
|
+
status: string;
|
|
61
|
+
message?: string;
|
|
62
|
+
error?: string;
|
|
63
|
+
queryLog?: string;
|
|
64
|
+
}>;
|
|
65
|
+
/**
|
|
66
|
+
* Add a unique constraint
|
|
67
|
+
*/
|
|
68
|
+
addUniqueConstraint(params: {
|
|
69
|
+
table_name: string;
|
|
70
|
+
constraint_name: string;
|
|
71
|
+
columns: string[];
|
|
72
|
+
database?: string;
|
|
73
|
+
}): Promise<{
|
|
74
|
+
status: string;
|
|
75
|
+
data?: any;
|
|
76
|
+
error?: string;
|
|
77
|
+
queryLog?: string;
|
|
78
|
+
}>;
|
|
79
|
+
/**
|
|
80
|
+
* Drop a constraint (UNIQUE or CHECK)
|
|
81
|
+
*/
|
|
82
|
+
dropConstraint(params: {
|
|
83
|
+
table_name: string;
|
|
84
|
+
constraint_name: string;
|
|
85
|
+
constraint_type: 'UNIQUE' | 'CHECK';
|
|
86
|
+
database?: string;
|
|
87
|
+
}): Promise<{
|
|
88
|
+
status: string;
|
|
89
|
+
message?: string;
|
|
90
|
+
error?: string;
|
|
91
|
+
queryLog?: string;
|
|
92
|
+
}>;
|
|
93
|
+
/**
|
|
94
|
+
* Add a check constraint (MySQL 8.0.16+)
|
|
95
|
+
*/
|
|
96
|
+
addCheckConstraint(params: {
|
|
97
|
+
table_name: string;
|
|
98
|
+
constraint_name: string;
|
|
99
|
+
expression: string;
|
|
100
|
+
enforced?: boolean;
|
|
101
|
+
database?: string;
|
|
102
|
+
}): Promise<{
|
|
103
|
+
status: string;
|
|
104
|
+
data?: any;
|
|
105
|
+
error?: string;
|
|
106
|
+
queryLog?: string;
|
|
107
|
+
}>;
|
|
108
|
+
}
|
|
@@ -0,0 +1,405 @@
|
|
|
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.ConstraintTools = void 0;
|
|
7
|
+
const connection_1 = __importDefault(require("../db/connection"));
|
|
8
|
+
const config_1 = require("../config/config");
|
|
9
|
+
class ConstraintTools {
|
|
10
|
+
constructor(security) {
|
|
11
|
+
this.db = connection_1.default.getInstance();
|
|
12
|
+
this.security = security;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Validate database access - ensures only the connected database can be accessed
|
|
16
|
+
*/
|
|
17
|
+
validateDatabaseAccess(requestedDatabase) {
|
|
18
|
+
const connectedDatabase = config_1.dbConfig.database;
|
|
19
|
+
if (!connectedDatabase) {
|
|
20
|
+
return {
|
|
21
|
+
valid: false,
|
|
22
|
+
database: '',
|
|
23
|
+
error: 'No database specified in connection string. Cannot access any database.'
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
if (!requestedDatabase) {
|
|
27
|
+
return {
|
|
28
|
+
valid: true,
|
|
29
|
+
database: connectedDatabase
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
if (requestedDatabase !== connectedDatabase) {
|
|
33
|
+
return {
|
|
34
|
+
valid: false,
|
|
35
|
+
database: '',
|
|
36
|
+
error: `Access denied. You can only access the connected database '${connectedDatabase}'. Requested database '${requestedDatabase}' is not allowed.`
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
valid: true,
|
|
41
|
+
database: connectedDatabase
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* List all foreign keys for a table
|
|
46
|
+
*/
|
|
47
|
+
async listForeignKeys(params) {
|
|
48
|
+
try {
|
|
49
|
+
const dbValidation = this.validateDatabaseAccess(params?.database);
|
|
50
|
+
if (!dbValidation.valid) {
|
|
51
|
+
return { status: 'error', error: dbValidation.error };
|
|
52
|
+
}
|
|
53
|
+
const { table_name } = params;
|
|
54
|
+
const database = dbValidation.database;
|
|
55
|
+
// Validate table name
|
|
56
|
+
if (!this.security.validateIdentifier(table_name).valid) {
|
|
57
|
+
return { status: 'error', error: 'Invalid table name' };
|
|
58
|
+
}
|
|
59
|
+
const query = `
|
|
60
|
+
SELECT
|
|
61
|
+
kcu.CONSTRAINT_NAME as constraint_name,
|
|
62
|
+
kcu.COLUMN_NAME as column_name,
|
|
63
|
+
kcu.REFERENCED_TABLE_SCHEMA as referenced_schema,
|
|
64
|
+
kcu.REFERENCED_TABLE_NAME as referenced_table,
|
|
65
|
+
kcu.REFERENCED_COLUMN_NAME as referenced_column,
|
|
66
|
+
kcu.ORDINAL_POSITION as ordinal_position,
|
|
67
|
+
rc.UPDATE_RULE as on_update,
|
|
68
|
+
rc.DELETE_RULE as on_delete
|
|
69
|
+
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu
|
|
70
|
+
JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc
|
|
71
|
+
ON kcu.CONSTRAINT_NAME = rc.CONSTRAINT_NAME
|
|
72
|
+
AND kcu.CONSTRAINT_SCHEMA = rc.CONSTRAINT_SCHEMA
|
|
73
|
+
WHERE kcu.TABLE_SCHEMA = ?
|
|
74
|
+
AND kcu.TABLE_NAME = ?
|
|
75
|
+
AND kcu.REFERENCED_TABLE_NAME IS NOT NULL
|
|
76
|
+
ORDER BY kcu.CONSTRAINT_NAME, kcu.ORDINAL_POSITION
|
|
77
|
+
`;
|
|
78
|
+
const results = await this.db.query(query, [database, table_name]);
|
|
79
|
+
// Group by constraint name
|
|
80
|
+
const fkMap = new Map();
|
|
81
|
+
for (const row of results) {
|
|
82
|
+
const constraintName = row.constraint_name;
|
|
83
|
+
if (!fkMap.has(constraintName)) {
|
|
84
|
+
fkMap.set(constraintName, {
|
|
85
|
+
constraint_name: constraintName,
|
|
86
|
+
table_name: table_name,
|
|
87
|
+
referenced_schema: row.referenced_schema,
|
|
88
|
+
referenced_table: row.referenced_table,
|
|
89
|
+
on_update: row.on_update,
|
|
90
|
+
on_delete: row.on_delete,
|
|
91
|
+
columns: []
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
fkMap.get(constraintName).columns.push({
|
|
95
|
+
column_name: row.column_name,
|
|
96
|
+
referenced_column: row.referenced_column,
|
|
97
|
+
ordinal_position: row.ordinal_position
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
status: 'success',
|
|
102
|
+
data: Array.from(fkMap.values()),
|
|
103
|
+
queryLog: this.db.getFormattedQueryLogs(1)
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
return {
|
|
108
|
+
status: 'error',
|
|
109
|
+
error: error.message,
|
|
110
|
+
queryLog: this.db.getFormattedQueryLogs(1)
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* List all constraints (PK, FK, UNIQUE, CHECK) for a table
|
|
116
|
+
*/
|
|
117
|
+
async listConstraints(params) {
|
|
118
|
+
try {
|
|
119
|
+
const dbValidation = this.validateDatabaseAccess(params?.database);
|
|
120
|
+
if (!dbValidation.valid) {
|
|
121
|
+
return { status: 'error', error: dbValidation.error };
|
|
122
|
+
}
|
|
123
|
+
const { table_name } = params;
|
|
124
|
+
const database = dbValidation.database;
|
|
125
|
+
// Validate table name
|
|
126
|
+
if (!this.security.validateIdentifier(table_name).valid) {
|
|
127
|
+
return { status: 'error', error: 'Invalid table name' };
|
|
128
|
+
}
|
|
129
|
+
const query = `
|
|
130
|
+
SELECT
|
|
131
|
+
tc.CONSTRAINT_NAME as constraint_name,
|
|
132
|
+
tc.CONSTRAINT_TYPE as constraint_type,
|
|
133
|
+
GROUP_CONCAT(kcu.COLUMN_NAME ORDER BY kcu.ORDINAL_POSITION) as columns,
|
|
134
|
+
kcu.REFERENCED_TABLE_NAME as referenced_table,
|
|
135
|
+
GROUP_CONCAT(kcu.REFERENCED_COLUMN_NAME ORDER BY kcu.ORDINAL_POSITION) as referenced_columns
|
|
136
|
+
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc
|
|
137
|
+
LEFT JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu
|
|
138
|
+
ON tc.CONSTRAINT_NAME = kcu.CONSTRAINT_NAME
|
|
139
|
+
AND tc.TABLE_SCHEMA = kcu.TABLE_SCHEMA
|
|
140
|
+
AND tc.TABLE_NAME = kcu.TABLE_NAME
|
|
141
|
+
WHERE tc.TABLE_SCHEMA = ? AND tc.TABLE_NAME = ?
|
|
142
|
+
GROUP BY tc.CONSTRAINT_NAME, tc.CONSTRAINT_TYPE, kcu.REFERENCED_TABLE_NAME
|
|
143
|
+
ORDER BY tc.CONSTRAINT_TYPE, tc.CONSTRAINT_NAME
|
|
144
|
+
`;
|
|
145
|
+
const results = await this.db.query(query, [database, table_name]);
|
|
146
|
+
// Format results
|
|
147
|
+
const constraints = results.map(row => ({
|
|
148
|
+
constraint_name: row.constraint_name,
|
|
149
|
+
constraint_type: row.constraint_type,
|
|
150
|
+
columns: row.columns ? row.columns.split(',') : [],
|
|
151
|
+
referenced_table: row.referenced_table || null,
|
|
152
|
+
referenced_columns: row.referenced_columns ? row.referenced_columns.split(',') : null
|
|
153
|
+
}));
|
|
154
|
+
return {
|
|
155
|
+
status: 'success',
|
|
156
|
+
data: constraints,
|
|
157
|
+
queryLog: this.db.getFormattedQueryLogs(1)
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
catch (error) {
|
|
161
|
+
return {
|
|
162
|
+
status: 'error',
|
|
163
|
+
error: error.message,
|
|
164
|
+
queryLog: this.db.getFormattedQueryLogs(1)
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Add a foreign key constraint
|
|
170
|
+
*/
|
|
171
|
+
async addForeignKey(params) {
|
|
172
|
+
try {
|
|
173
|
+
const dbValidation = this.validateDatabaseAccess(params?.database);
|
|
174
|
+
if (!dbValidation.valid) {
|
|
175
|
+
return { status: 'error', error: dbValidation.error };
|
|
176
|
+
}
|
|
177
|
+
const { table_name, constraint_name, columns, referenced_table, referenced_columns, on_delete = 'RESTRICT', on_update = 'RESTRICT' } = params;
|
|
178
|
+
const database = dbValidation.database;
|
|
179
|
+
// Validate names
|
|
180
|
+
if (!this.security.validateIdentifier(table_name).valid) {
|
|
181
|
+
return { status: 'error', error: 'Invalid table name' };
|
|
182
|
+
}
|
|
183
|
+
if (!this.security.validateIdentifier(constraint_name).valid) {
|
|
184
|
+
return { status: 'error', error: 'Invalid constraint name' };
|
|
185
|
+
}
|
|
186
|
+
if (!this.security.validateIdentifier(referenced_table).valid) {
|
|
187
|
+
return { status: 'error', error: 'Invalid referenced table name' };
|
|
188
|
+
}
|
|
189
|
+
// Validate column names
|
|
190
|
+
for (const col of columns) {
|
|
191
|
+
if (!this.security.validateIdentifier(col).valid) {
|
|
192
|
+
return { status: 'error', error: `Invalid column name: ${col}` };
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
for (const col of referenced_columns) {
|
|
196
|
+
if (!this.security.validateIdentifier(col).valid) {
|
|
197
|
+
return { status: 'error', error: `Invalid referenced column name: ${col}` };
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
// Column counts must match
|
|
201
|
+
if (columns.length !== referenced_columns.length) {
|
|
202
|
+
return { status: 'error', error: 'Column count must match referenced column count' };
|
|
203
|
+
}
|
|
204
|
+
const columnList = columns.map(c => `\`${c}\``).join(', ');
|
|
205
|
+
const refColumnList = referenced_columns.map(c => `\`${c}\``).join(', ');
|
|
206
|
+
const alterQuery = `
|
|
207
|
+
ALTER TABLE \`${database}\`.\`${table_name}\`
|
|
208
|
+
ADD CONSTRAINT \`${constraint_name}\`
|
|
209
|
+
FOREIGN KEY (${columnList})
|
|
210
|
+
REFERENCES \`${database}\`.\`${referenced_table}\` (${refColumnList})
|
|
211
|
+
ON DELETE ${on_delete}
|
|
212
|
+
ON UPDATE ${on_update}
|
|
213
|
+
`;
|
|
214
|
+
await this.db.query(alterQuery);
|
|
215
|
+
return {
|
|
216
|
+
status: 'success',
|
|
217
|
+
data: {
|
|
218
|
+
message: `Foreign key '${constraint_name}' added successfully`,
|
|
219
|
+
constraint_name,
|
|
220
|
+
table_name,
|
|
221
|
+
referenced_table,
|
|
222
|
+
database
|
|
223
|
+
},
|
|
224
|
+
queryLog: this.db.getFormattedQueryLogs(1)
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
catch (error) {
|
|
228
|
+
return {
|
|
229
|
+
status: 'error',
|
|
230
|
+
error: error.message,
|
|
231
|
+
queryLog: this.db.getFormattedQueryLogs(1)
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Drop a foreign key constraint
|
|
237
|
+
*/
|
|
238
|
+
async dropForeignKey(params) {
|
|
239
|
+
try {
|
|
240
|
+
const dbValidation = this.validateDatabaseAccess(params?.database);
|
|
241
|
+
if (!dbValidation.valid) {
|
|
242
|
+
return { status: 'error', error: dbValidation.error };
|
|
243
|
+
}
|
|
244
|
+
const { table_name, constraint_name } = params;
|
|
245
|
+
const database = dbValidation.database;
|
|
246
|
+
// Validate names
|
|
247
|
+
if (!this.security.validateIdentifier(table_name).valid) {
|
|
248
|
+
return { status: 'error', error: 'Invalid table name' };
|
|
249
|
+
}
|
|
250
|
+
if (!this.security.validateIdentifier(constraint_name).valid) {
|
|
251
|
+
return { status: 'error', error: 'Invalid constraint name' };
|
|
252
|
+
}
|
|
253
|
+
const alterQuery = `ALTER TABLE \`${database}\`.\`${table_name}\` DROP FOREIGN KEY \`${constraint_name}\``;
|
|
254
|
+
await this.db.query(alterQuery);
|
|
255
|
+
return {
|
|
256
|
+
status: 'success',
|
|
257
|
+
message: `Foreign key '${constraint_name}' dropped successfully from table '${table_name}'`,
|
|
258
|
+
queryLog: this.db.getFormattedQueryLogs(1)
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
catch (error) {
|
|
262
|
+
return {
|
|
263
|
+
status: 'error',
|
|
264
|
+
error: error.message,
|
|
265
|
+
queryLog: this.db.getFormattedQueryLogs(1)
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Add a unique constraint
|
|
271
|
+
*/
|
|
272
|
+
async addUniqueConstraint(params) {
|
|
273
|
+
try {
|
|
274
|
+
const dbValidation = this.validateDatabaseAccess(params?.database);
|
|
275
|
+
if (!dbValidation.valid) {
|
|
276
|
+
return { status: 'error', error: dbValidation.error };
|
|
277
|
+
}
|
|
278
|
+
const { table_name, constraint_name, columns } = params;
|
|
279
|
+
const database = dbValidation.database;
|
|
280
|
+
// Validate names
|
|
281
|
+
if (!this.security.validateIdentifier(table_name).valid) {
|
|
282
|
+
return { status: 'error', error: 'Invalid table name' };
|
|
283
|
+
}
|
|
284
|
+
if (!this.security.validateIdentifier(constraint_name).valid) {
|
|
285
|
+
return { status: 'error', error: 'Invalid constraint name' };
|
|
286
|
+
}
|
|
287
|
+
// Validate column names
|
|
288
|
+
for (const col of columns) {
|
|
289
|
+
if (!this.security.validateIdentifier(col).valid) {
|
|
290
|
+
return { status: 'error', error: `Invalid column name: ${col}` };
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
const columnList = columns.map(c => `\`${c}\``).join(', ');
|
|
294
|
+
const alterQuery = `ALTER TABLE \`${database}\`.\`${table_name}\` ADD CONSTRAINT \`${constraint_name}\` UNIQUE (${columnList})`;
|
|
295
|
+
await this.db.query(alterQuery);
|
|
296
|
+
return {
|
|
297
|
+
status: 'success',
|
|
298
|
+
data: {
|
|
299
|
+
message: `Unique constraint '${constraint_name}' added successfully`,
|
|
300
|
+
constraint_name,
|
|
301
|
+
table_name,
|
|
302
|
+
columns,
|
|
303
|
+
database
|
|
304
|
+
},
|
|
305
|
+
queryLog: this.db.getFormattedQueryLogs(1)
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
catch (error) {
|
|
309
|
+
return {
|
|
310
|
+
status: 'error',
|
|
311
|
+
error: error.message,
|
|
312
|
+
queryLog: this.db.getFormattedQueryLogs(1)
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Drop a constraint (UNIQUE or CHECK)
|
|
318
|
+
*/
|
|
319
|
+
async dropConstraint(params) {
|
|
320
|
+
try {
|
|
321
|
+
const dbValidation = this.validateDatabaseAccess(params?.database);
|
|
322
|
+
if (!dbValidation.valid) {
|
|
323
|
+
return { status: 'error', error: dbValidation.error };
|
|
324
|
+
}
|
|
325
|
+
const { table_name, constraint_name, constraint_type } = params;
|
|
326
|
+
const database = dbValidation.database;
|
|
327
|
+
// Validate names
|
|
328
|
+
if (!this.security.validateIdentifier(table_name).valid) {
|
|
329
|
+
return { status: 'error', error: 'Invalid table name' };
|
|
330
|
+
}
|
|
331
|
+
if (!this.security.validateIdentifier(constraint_name).valid) {
|
|
332
|
+
return { status: 'error', error: 'Invalid constraint name' };
|
|
333
|
+
}
|
|
334
|
+
let alterQuery;
|
|
335
|
+
if (constraint_type === 'UNIQUE') {
|
|
336
|
+
// UNIQUE constraints are implemented as indexes in MySQL
|
|
337
|
+
alterQuery = `ALTER TABLE \`${database}\`.\`${table_name}\` DROP INDEX \`${constraint_name}\``;
|
|
338
|
+
}
|
|
339
|
+
else if (constraint_type === 'CHECK') {
|
|
340
|
+
alterQuery = `ALTER TABLE \`${database}\`.\`${table_name}\` DROP CHECK \`${constraint_name}\``;
|
|
341
|
+
}
|
|
342
|
+
else {
|
|
343
|
+
return { status: 'error', error: 'Invalid constraint type. Use UNIQUE or CHECK.' };
|
|
344
|
+
}
|
|
345
|
+
await this.db.query(alterQuery);
|
|
346
|
+
return {
|
|
347
|
+
status: 'success',
|
|
348
|
+
message: `${constraint_type} constraint '${constraint_name}' dropped successfully from table '${table_name}'`,
|
|
349
|
+
queryLog: this.db.getFormattedQueryLogs(1)
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
catch (error) {
|
|
353
|
+
return {
|
|
354
|
+
status: 'error',
|
|
355
|
+
error: error.message,
|
|
356
|
+
queryLog: this.db.getFormattedQueryLogs(1)
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Add a check constraint (MySQL 8.0.16+)
|
|
362
|
+
*/
|
|
363
|
+
async addCheckConstraint(params) {
|
|
364
|
+
try {
|
|
365
|
+
const dbValidation = this.validateDatabaseAccess(params?.database);
|
|
366
|
+
if (!dbValidation.valid) {
|
|
367
|
+
return { status: 'error', error: dbValidation.error };
|
|
368
|
+
}
|
|
369
|
+
const { table_name, constraint_name, expression, enforced = true } = params;
|
|
370
|
+
const database = dbValidation.database;
|
|
371
|
+
// Validate names
|
|
372
|
+
if (!this.security.validateIdentifier(table_name).valid) {
|
|
373
|
+
return { status: 'error', error: 'Invalid table name' };
|
|
374
|
+
}
|
|
375
|
+
if (!this.security.validateIdentifier(constraint_name).valid) {
|
|
376
|
+
return { status: 'error', error: 'Invalid constraint name' };
|
|
377
|
+
}
|
|
378
|
+
let alterQuery = `ALTER TABLE \`${database}\`.\`${table_name}\` ADD CONSTRAINT \`${constraint_name}\` CHECK (${expression})`;
|
|
379
|
+
if (!enforced) {
|
|
380
|
+
alterQuery += ' NOT ENFORCED';
|
|
381
|
+
}
|
|
382
|
+
await this.db.query(alterQuery);
|
|
383
|
+
return {
|
|
384
|
+
status: 'success',
|
|
385
|
+
data: {
|
|
386
|
+
message: `Check constraint '${constraint_name}' added successfully`,
|
|
387
|
+
constraint_name,
|
|
388
|
+
table_name,
|
|
389
|
+
expression,
|
|
390
|
+
enforced,
|
|
391
|
+
database
|
|
392
|
+
},
|
|
393
|
+
queryLog: this.db.getFormattedQueryLogs(1)
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
catch (error) {
|
|
397
|
+
return {
|
|
398
|
+
status: 'error',
|
|
399
|
+
error: error.message,
|
|
400
|
+
queryLog: this.db.getFormattedQueryLogs(1)
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
exports.ConstraintTools = ConstraintTools;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { SecurityLayer } from '../security/securityLayer';
|
|
2
|
+
export declare class FunctionTools {
|
|
3
|
+
private db;
|
|
4
|
+
private security;
|
|
5
|
+
constructor(security: SecurityLayer);
|
|
6
|
+
/**
|
|
7
|
+
* Validate database access - ensures only the connected database can be accessed
|
|
8
|
+
*/
|
|
9
|
+
private validateDatabaseAccess;
|
|
10
|
+
/**
|
|
11
|
+
* List all functions in the current database
|
|
12
|
+
*/
|
|
13
|
+
listFunctions(params: {
|
|
14
|
+
database?: string;
|
|
15
|
+
}): Promise<{
|
|
16
|
+
status: string;
|
|
17
|
+
data?: any[];
|
|
18
|
+
error?: string;
|
|
19
|
+
queryLog?: string;
|
|
20
|
+
}>;
|
|
21
|
+
/**
|
|
22
|
+
* Get detailed information about a specific function
|
|
23
|
+
*/
|
|
24
|
+
getFunctionInfo(params: {
|
|
25
|
+
function_name: string;
|
|
26
|
+
database?: string;
|
|
27
|
+
}): Promise<{
|
|
28
|
+
status: string;
|
|
29
|
+
data?: any;
|
|
30
|
+
error?: string;
|
|
31
|
+
queryLog?: string;
|
|
32
|
+
}>;
|
|
33
|
+
/**
|
|
34
|
+
* Create a new function
|
|
35
|
+
*/
|
|
36
|
+
createFunction(params: {
|
|
37
|
+
function_name: string;
|
|
38
|
+
parameters?: Array<{
|
|
39
|
+
name: string;
|
|
40
|
+
data_type: string;
|
|
41
|
+
}>;
|
|
42
|
+
returns: string;
|
|
43
|
+
body: string;
|
|
44
|
+
deterministic?: boolean;
|
|
45
|
+
data_access?: 'CONTAINS SQL' | 'NO SQL' | 'READS SQL DATA' | 'MODIFIES SQL DATA';
|
|
46
|
+
security?: 'DEFINER' | 'INVOKER';
|
|
47
|
+
comment?: string;
|
|
48
|
+
database?: string;
|
|
49
|
+
}): Promise<{
|
|
50
|
+
status: string;
|
|
51
|
+
data?: any;
|
|
52
|
+
error?: string;
|
|
53
|
+
queryLog?: string;
|
|
54
|
+
}>;
|
|
55
|
+
/**
|
|
56
|
+
* Drop a function
|
|
57
|
+
*/
|
|
58
|
+
dropFunction(params: {
|
|
59
|
+
function_name: string;
|
|
60
|
+
if_exists?: boolean;
|
|
61
|
+
database?: string;
|
|
62
|
+
}): Promise<{
|
|
63
|
+
status: string;
|
|
64
|
+
message?: string;
|
|
65
|
+
error?: string;
|
|
66
|
+
queryLog?: string;
|
|
67
|
+
}>;
|
|
68
|
+
/**
|
|
69
|
+
* Show the CREATE statement for a function
|
|
70
|
+
*/
|
|
71
|
+
showCreateFunction(params: {
|
|
72
|
+
function_name: string;
|
|
73
|
+
database?: string;
|
|
74
|
+
}): Promise<{
|
|
75
|
+
status: string;
|
|
76
|
+
data?: any;
|
|
77
|
+
error?: string;
|
|
78
|
+
queryLog?: string;
|
|
79
|
+
}>;
|
|
80
|
+
/**
|
|
81
|
+
* Execute a function and return its result
|
|
82
|
+
*/
|
|
83
|
+
executeFunction(params: {
|
|
84
|
+
function_name: string;
|
|
85
|
+
parameters?: any[];
|
|
86
|
+
database?: string;
|
|
87
|
+
}): Promise<{
|
|
88
|
+
status: string;
|
|
89
|
+
data?: any;
|
|
90
|
+
error?: string;
|
|
91
|
+
queryLog?: string;
|
|
92
|
+
}>;
|
|
93
|
+
}
|