@berthojoris/mcp-mysql-server 1.1.0 → 1.2.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 -21
- package/README.md +156 -2
- package/dist/index.d.ts +39 -0
- package/dist/index.js +21 -0
- package/dist/mcp-server.js +133 -0
- package/dist/tools/crudTools.d.ts +39 -0
- package/dist/tools/crudTools.js +410 -0
- package/dist/tools/databaseTools.js +14 -14
- package/dist/tools/utilityTools.js +25 -25
- package/dist/validation/schemas.d.ts +179 -4
- package/dist/validation/schemas.js +192 -6
- package/manifest.json +247 -247
- package/package.json +3 -1
- package/dist/auth/authService.d.ts +0 -29
- package/dist/auth/authService.js +0 -114
package/dist/tools/crudTools.js
CHANGED
|
@@ -439,5 +439,415 @@ class CrudTools {
|
|
|
439
439
|
};
|
|
440
440
|
}
|
|
441
441
|
}
|
|
442
|
+
/**
|
|
443
|
+
* Bulk insert multiple records into the specified table
|
|
444
|
+
*/
|
|
445
|
+
async bulkInsert(params) {
|
|
446
|
+
// Validate input schema
|
|
447
|
+
if (!(0, schemas_1.validateBulkInsert)(params)) {
|
|
448
|
+
return {
|
|
449
|
+
status: 'error',
|
|
450
|
+
error: 'Invalid parameters: ' + JSON.stringify(schemas_1.validateBulkInsert.errors)
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
try {
|
|
454
|
+
const { table_name, data, batch_size = 1000 } = params;
|
|
455
|
+
// Validate table name
|
|
456
|
+
const tableValidation = this.security.validateIdentifier(table_name);
|
|
457
|
+
if (!tableValidation.valid) {
|
|
458
|
+
return {
|
|
459
|
+
status: 'error',
|
|
460
|
+
error: `Invalid table name: ${tableValidation.error}`
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
// Ensure data is not empty
|
|
464
|
+
if (!data || data.length === 0) {
|
|
465
|
+
return {
|
|
466
|
+
status: 'error',
|
|
467
|
+
error: 'Data array cannot be empty'
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
// Validate that all records have the same columns
|
|
471
|
+
const firstRecord = data[0];
|
|
472
|
+
const columns = Object.keys(firstRecord);
|
|
473
|
+
for (let i = 1; i < data.length; i++) {
|
|
474
|
+
const recordColumns = Object.keys(data[i]);
|
|
475
|
+
if (recordColumns.length !== columns.length ||
|
|
476
|
+
!recordColumns.every(col => columns.includes(col))) {
|
|
477
|
+
return {
|
|
478
|
+
status: 'error',
|
|
479
|
+
error: `All records must have the same columns. Record ${i + 1} has different columns.`
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
// Validate column names
|
|
484
|
+
for (const column of columns) {
|
|
485
|
+
const columnValidation = this.security.validateIdentifier(column);
|
|
486
|
+
if (!columnValidation.valid) {
|
|
487
|
+
return {
|
|
488
|
+
status: 'error',
|
|
489
|
+
error: `Invalid column name '${column}': ${columnValidation.error}`
|
|
490
|
+
};
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
// Process in batches
|
|
494
|
+
const results = [];
|
|
495
|
+
let totalInserted = 0;
|
|
496
|
+
for (let i = 0; i < data.length; i += batch_size) {
|
|
497
|
+
const batch = data.slice(i, i + batch_size);
|
|
498
|
+
// Prepare batch values
|
|
499
|
+
const batchValues = [];
|
|
500
|
+
for (const record of batch) {
|
|
501
|
+
const values = columns.map(col => record[col]);
|
|
502
|
+
// Validate and sanitize parameter values for this record
|
|
503
|
+
const paramValidation = this.security.validateParameters(values);
|
|
504
|
+
if (!paramValidation.valid) {
|
|
505
|
+
return {
|
|
506
|
+
status: 'error',
|
|
507
|
+
error: `Invalid parameter values in record ${i + batchValues.length / columns.length + 1}: ${paramValidation.error}`
|
|
508
|
+
};
|
|
509
|
+
}
|
|
510
|
+
batchValues.push(...paramValidation.sanitizedParams);
|
|
511
|
+
}
|
|
512
|
+
// Build the query with escaped identifiers
|
|
513
|
+
const escapedTableName = this.security.escapeIdentifier(table_name);
|
|
514
|
+
const escapedColumns = columns.map(col => this.security.escapeIdentifier(col));
|
|
515
|
+
const valueGroups = batch.map(() => `(${columns.map(() => '?').join(', ')})`).join(', ');
|
|
516
|
+
const query = `INSERT INTO ${escapedTableName} (${escapedColumns.join(', ')}) VALUES ${valueGroups}`;
|
|
517
|
+
// Execute the batch query
|
|
518
|
+
const result = await this.db.query(query, batchValues);
|
|
519
|
+
results.push({
|
|
520
|
+
batchNumber: Math.floor(i / batch_size) + 1,
|
|
521
|
+
recordsInserted: batch.length,
|
|
522
|
+
firstInsertId: result.insertId,
|
|
523
|
+
affectedRows: result.affectedRows
|
|
524
|
+
});
|
|
525
|
+
totalInserted += result.affectedRows;
|
|
526
|
+
}
|
|
527
|
+
return {
|
|
528
|
+
status: 'success',
|
|
529
|
+
data: {
|
|
530
|
+
totalRecords: data.length,
|
|
531
|
+
totalInserted,
|
|
532
|
+
batches: results.length,
|
|
533
|
+
batchResults: results
|
|
534
|
+
}
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
catch (error) {
|
|
538
|
+
return {
|
|
539
|
+
status: 'error',
|
|
540
|
+
error: error.message
|
|
541
|
+
};
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
/**
|
|
545
|
+
* Bulk update multiple records with different conditions and data
|
|
546
|
+
*/
|
|
547
|
+
async bulkUpdate(params) {
|
|
548
|
+
// Validate input schema
|
|
549
|
+
if (!(0, schemas_1.validateBulkUpdate)(params)) {
|
|
550
|
+
return {
|
|
551
|
+
status: 'error',
|
|
552
|
+
error: 'Invalid parameters: ' + JSON.stringify(schemas_1.validateBulkUpdate.errors)
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
try {
|
|
556
|
+
const { table_name, updates, batch_size = 100 } = params;
|
|
557
|
+
// Validate table name
|
|
558
|
+
const tableValidation = this.security.validateIdentifier(table_name);
|
|
559
|
+
if (!tableValidation.valid) {
|
|
560
|
+
return {
|
|
561
|
+
status: 'error',
|
|
562
|
+
error: `Invalid table name: ${tableValidation.error}`
|
|
563
|
+
};
|
|
564
|
+
}
|
|
565
|
+
// Ensure updates is not empty
|
|
566
|
+
if (!updates || updates.length === 0) {
|
|
567
|
+
return {
|
|
568
|
+
status: 'error',
|
|
569
|
+
error: 'Updates array cannot be empty'
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
// Validate each update operation
|
|
573
|
+
for (let i = 0; i < updates.length; i++) {
|
|
574
|
+
const update = updates[i];
|
|
575
|
+
// Validate column names in data
|
|
576
|
+
const columns = Object.keys(update.data);
|
|
577
|
+
for (const column of columns) {
|
|
578
|
+
const columnValidation = this.security.validateIdentifier(column);
|
|
579
|
+
if (!columnValidation.valid) {
|
|
580
|
+
return {
|
|
581
|
+
status: 'error',
|
|
582
|
+
error: `Invalid column name '${column}' in update ${i + 1}: ${columnValidation.error}`
|
|
583
|
+
};
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
// Validate condition fields
|
|
587
|
+
for (const condition of update.conditions) {
|
|
588
|
+
const fieldValidation = this.security.validateIdentifier(condition.field);
|
|
589
|
+
if (!fieldValidation.valid) {
|
|
590
|
+
return {
|
|
591
|
+
status: 'error',
|
|
592
|
+
error: `Invalid condition field '${condition.field}' in update ${i + 1}: ${fieldValidation.error}`
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
// Process in batches using transactions for consistency
|
|
598
|
+
const results = [];
|
|
599
|
+
let totalAffected = 0;
|
|
600
|
+
for (let i = 0; i < updates.length; i += batch_size) {
|
|
601
|
+
const batch = updates.slice(i, i + batch_size);
|
|
602
|
+
// Start a transaction for this batch
|
|
603
|
+
await this.db.query('START TRANSACTION');
|
|
604
|
+
try {
|
|
605
|
+
const batchResults = [];
|
|
606
|
+
for (const update of batch) {
|
|
607
|
+
// Build SET clause
|
|
608
|
+
const setClause = Object.entries(update.data)
|
|
609
|
+
.map(([column, _]) => `${this.security.escapeIdentifier(column)} = ?`)
|
|
610
|
+
.join(', ');
|
|
611
|
+
const setValues = Object.values(update.data);
|
|
612
|
+
// Build WHERE clause
|
|
613
|
+
const whereConditions = [];
|
|
614
|
+
const whereValues = [];
|
|
615
|
+
update.conditions.forEach(condition => {
|
|
616
|
+
const escapedField = this.security.escapeIdentifier(condition.field);
|
|
617
|
+
switch (condition.operator) {
|
|
618
|
+
case 'eq':
|
|
619
|
+
whereConditions.push(`${escapedField} = ?`);
|
|
620
|
+
whereValues.push(condition.value);
|
|
621
|
+
break;
|
|
622
|
+
case 'neq':
|
|
623
|
+
whereConditions.push(`${escapedField} != ?`);
|
|
624
|
+
whereValues.push(condition.value);
|
|
625
|
+
break;
|
|
626
|
+
case 'gt':
|
|
627
|
+
whereConditions.push(`${escapedField} > ?`);
|
|
628
|
+
whereValues.push(condition.value);
|
|
629
|
+
break;
|
|
630
|
+
case 'gte':
|
|
631
|
+
whereConditions.push(`${escapedField} >= ?`);
|
|
632
|
+
whereValues.push(condition.value);
|
|
633
|
+
break;
|
|
634
|
+
case 'lt':
|
|
635
|
+
whereConditions.push(`${escapedField} < ?`);
|
|
636
|
+
whereValues.push(condition.value);
|
|
637
|
+
break;
|
|
638
|
+
case 'lte':
|
|
639
|
+
whereConditions.push(`${escapedField} <= ?`);
|
|
640
|
+
whereValues.push(condition.value);
|
|
641
|
+
break;
|
|
642
|
+
case 'like':
|
|
643
|
+
whereConditions.push(`${escapedField} LIKE ?`);
|
|
644
|
+
whereValues.push(`%${condition.value}%`);
|
|
645
|
+
break;
|
|
646
|
+
case 'in':
|
|
647
|
+
if (Array.isArray(condition.value)) {
|
|
648
|
+
const placeholders = condition.value.map(() => '?').join(', ');
|
|
649
|
+
whereConditions.push(`${escapedField} IN (${placeholders})`);
|
|
650
|
+
whereValues.push(...condition.value);
|
|
651
|
+
}
|
|
652
|
+
break;
|
|
653
|
+
}
|
|
654
|
+
});
|
|
655
|
+
const whereClause = whereConditions.length > 0
|
|
656
|
+
? 'WHERE ' + whereConditions.join(' AND ')
|
|
657
|
+
: '';
|
|
658
|
+
// Validate all parameters
|
|
659
|
+
const allParams = [...setValues, ...whereValues];
|
|
660
|
+
const paramValidation = this.security.validateParameters(allParams);
|
|
661
|
+
if (!paramValidation.valid) {
|
|
662
|
+
throw new Error(`Invalid parameters: ${paramValidation.error}`);
|
|
663
|
+
}
|
|
664
|
+
// Build and execute the query
|
|
665
|
+
const escapedTableName = this.security.escapeIdentifier(table_name);
|
|
666
|
+
const query = `UPDATE ${escapedTableName} SET ${setClause} ${whereClause}`;
|
|
667
|
+
const result = await this.db.query(query, paramValidation.sanitizedParams);
|
|
668
|
+
batchResults.push({
|
|
669
|
+
affectedRows: result.affectedRows
|
|
670
|
+
});
|
|
671
|
+
totalAffected += result.affectedRows;
|
|
672
|
+
}
|
|
673
|
+
// Commit the transaction
|
|
674
|
+
await this.db.query('COMMIT');
|
|
675
|
+
results.push({
|
|
676
|
+
batchNumber: Math.floor(i / batch_size) + 1,
|
|
677
|
+
updatesProcessed: batch.length,
|
|
678
|
+
results: batchResults
|
|
679
|
+
});
|
|
680
|
+
}
|
|
681
|
+
catch (error) {
|
|
682
|
+
// Rollback on error
|
|
683
|
+
await this.db.query('ROLLBACK');
|
|
684
|
+
throw error;
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
return {
|
|
688
|
+
status: 'success',
|
|
689
|
+
data: {
|
|
690
|
+
totalUpdates: updates.length,
|
|
691
|
+
totalAffectedRows: totalAffected,
|
|
692
|
+
batches: results.length,
|
|
693
|
+
batchResults: results
|
|
694
|
+
}
|
|
695
|
+
};
|
|
696
|
+
}
|
|
697
|
+
catch (error) {
|
|
698
|
+
return {
|
|
699
|
+
status: 'error',
|
|
700
|
+
error: error.message
|
|
701
|
+
};
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
/**
|
|
705
|
+
* Bulk delete records based on multiple condition sets
|
|
706
|
+
*/
|
|
707
|
+
async bulkDelete(params) {
|
|
708
|
+
// Validate input schema
|
|
709
|
+
if (!(0, schemas_1.validateBulkDelete)(params)) {
|
|
710
|
+
return {
|
|
711
|
+
status: 'error',
|
|
712
|
+
error: 'Invalid parameters: ' + JSON.stringify(schemas_1.validateBulkDelete.errors)
|
|
713
|
+
};
|
|
714
|
+
}
|
|
715
|
+
try {
|
|
716
|
+
const { table_name, condition_sets, batch_size = 100 } = params;
|
|
717
|
+
// Validate table name
|
|
718
|
+
const tableValidation = this.security.validateIdentifier(table_name);
|
|
719
|
+
if (!tableValidation.valid) {
|
|
720
|
+
return {
|
|
721
|
+
status: 'error',
|
|
722
|
+
error: `Invalid table name: ${tableValidation.error}`
|
|
723
|
+
};
|
|
724
|
+
}
|
|
725
|
+
// Ensure condition_sets is not empty
|
|
726
|
+
if (!condition_sets || condition_sets.length === 0) {
|
|
727
|
+
return {
|
|
728
|
+
status: 'error',
|
|
729
|
+
error: 'Condition sets array cannot be empty'
|
|
730
|
+
};
|
|
731
|
+
}
|
|
732
|
+
// Validate each condition set
|
|
733
|
+
for (let i = 0; i < condition_sets.length; i++) {
|
|
734
|
+
const conditions = condition_sets[i];
|
|
735
|
+
// Ensure there are conditions for safety
|
|
736
|
+
if (!conditions || conditions.length === 0) {
|
|
737
|
+
return {
|
|
738
|
+
status: 'error',
|
|
739
|
+
error: `DELETE operations require at least one condition for safety. Condition set ${i + 1} is empty.`
|
|
740
|
+
};
|
|
741
|
+
}
|
|
742
|
+
// Validate condition fields
|
|
743
|
+
for (const condition of conditions) {
|
|
744
|
+
const fieldValidation = this.security.validateIdentifier(condition.field);
|
|
745
|
+
if (!fieldValidation.valid) {
|
|
746
|
+
return {
|
|
747
|
+
status: 'error',
|
|
748
|
+
error: `Invalid condition field '${condition.field}' in condition set ${i + 1}: ${fieldValidation.error}`
|
|
749
|
+
};
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
// Process in batches using transactions for consistency
|
|
754
|
+
const results = [];
|
|
755
|
+
let totalDeleted = 0;
|
|
756
|
+
for (let i = 0; i < condition_sets.length; i += batch_size) {
|
|
757
|
+
const batch = condition_sets.slice(i, i + batch_size);
|
|
758
|
+
// Start a transaction for this batch
|
|
759
|
+
await this.db.query('START TRANSACTION');
|
|
760
|
+
try {
|
|
761
|
+
const batchResults = [];
|
|
762
|
+
for (const conditions of batch) {
|
|
763
|
+
// Build WHERE clause
|
|
764
|
+
const whereConditions = [];
|
|
765
|
+
const whereValues = [];
|
|
766
|
+
conditions.forEach(condition => {
|
|
767
|
+
const escapedField = this.security.escapeIdentifier(condition.field);
|
|
768
|
+
switch (condition.operator) {
|
|
769
|
+
case 'eq':
|
|
770
|
+
whereConditions.push(`${escapedField} = ?`);
|
|
771
|
+
whereValues.push(condition.value);
|
|
772
|
+
break;
|
|
773
|
+
case 'neq':
|
|
774
|
+
whereConditions.push(`${escapedField} != ?`);
|
|
775
|
+
whereValues.push(condition.value);
|
|
776
|
+
break;
|
|
777
|
+
case 'gt':
|
|
778
|
+
whereConditions.push(`${escapedField} > ?`);
|
|
779
|
+
whereValues.push(condition.value);
|
|
780
|
+
break;
|
|
781
|
+
case 'gte':
|
|
782
|
+
whereConditions.push(`${escapedField} >= ?`);
|
|
783
|
+
whereValues.push(condition.value);
|
|
784
|
+
break;
|
|
785
|
+
case 'lt':
|
|
786
|
+
whereConditions.push(`${escapedField} < ?`);
|
|
787
|
+
whereValues.push(condition.value);
|
|
788
|
+
break;
|
|
789
|
+
case 'lte':
|
|
790
|
+
whereConditions.push(`${escapedField} <= ?`);
|
|
791
|
+
whereValues.push(condition.value);
|
|
792
|
+
break;
|
|
793
|
+
case 'like':
|
|
794
|
+
whereConditions.push(`${escapedField} LIKE ?`);
|
|
795
|
+
whereValues.push(`%${condition.value}%`);
|
|
796
|
+
break;
|
|
797
|
+
case 'in':
|
|
798
|
+
if (Array.isArray(condition.value)) {
|
|
799
|
+
const placeholders = condition.value.map(() => '?').join(', ');
|
|
800
|
+
whereConditions.push(`${escapedField} IN (${placeholders})`);
|
|
801
|
+
whereValues.push(...condition.value);
|
|
802
|
+
}
|
|
803
|
+
break;
|
|
804
|
+
}
|
|
805
|
+
});
|
|
806
|
+
const whereClause = 'WHERE ' + whereConditions.join(' AND ');
|
|
807
|
+
// Validate all parameters
|
|
808
|
+
const paramValidation = this.security.validateParameters(whereValues);
|
|
809
|
+
if (!paramValidation.valid) {
|
|
810
|
+
throw new Error(`Invalid parameters: ${paramValidation.error}`);
|
|
811
|
+
}
|
|
812
|
+
// Build and execute the query
|
|
813
|
+
const escapedTableName = this.security.escapeIdentifier(table_name);
|
|
814
|
+
const query = `DELETE FROM ${escapedTableName} ${whereClause}`;
|
|
815
|
+
const result = await this.db.query(query, paramValidation.sanitizedParams);
|
|
816
|
+
batchResults.push({
|
|
817
|
+
affectedRows: result.affectedRows
|
|
818
|
+
});
|
|
819
|
+
totalDeleted += result.affectedRows;
|
|
820
|
+
}
|
|
821
|
+
// Commit the transaction
|
|
822
|
+
await this.db.query('COMMIT');
|
|
823
|
+
results.push({
|
|
824
|
+
batchNumber: Math.floor(i / batch_size) + 1,
|
|
825
|
+
deletesProcessed: batch.length,
|
|
826
|
+
results: batchResults
|
|
827
|
+
});
|
|
828
|
+
}
|
|
829
|
+
catch (error) {
|
|
830
|
+
// Rollback on error
|
|
831
|
+
await this.db.query('ROLLBACK');
|
|
832
|
+
throw error;
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
return {
|
|
836
|
+
status: 'success',
|
|
837
|
+
data: {
|
|
838
|
+
totalDeletes: condition_sets.length,
|
|
839
|
+
totalDeletedRows: totalDeleted,
|
|
840
|
+
batches: results.length,
|
|
841
|
+
batchResults: results
|
|
842
|
+
}
|
|
843
|
+
};
|
|
844
|
+
}
|
|
845
|
+
catch (error) {
|
|
846
|
+
return {
|
|
847
|
+
status: 'error',
|
|
848
|
+
error: error.message
|
|
849
|
+
};
|
|
850
|
+
}
|
|
851
|
+
}
|
|
442
852
|
}
|
|
443
853
|
exports.CrudTools = CrudTools;
|
|
@@ -108,20 +108,20 @@ class DatabaseTools {
|
|
|
108
108
|
};
|
|
109
109
|
}
|
|
110
110
|
try {
|
|
111
|
-
const query = `
|
|
112
|
-
SELECT
|
|
113
|
-
COLUMN_NAME as column_name,
|
|
114
|
-
DATA_TYPE as data_type,
|
|
115
|
-
IS_NULLABLE as is_nullable,
|
|
116
|
-
COLUMN_KEY as column_key,
|
|
117
|
-
COLUMN_DEFAULT as column_default,
|
|
118
|
-
EXTRA as extra
|
|
119
|
-
FROM
|
|
120
|
-
INFORMATION_SCHEMA.COLUMNS
|
|
121
|
-
WHERE
|
|
122
|
-
TABLE_NAME = ?
|
|
123
|
-
ORDER BY
|
|
124
|
-
ORDINAL_POSITION
|
|
111
|
+
const query = `
|
|
112
|
+
SELECT
|
|
113
|
+
COLUMN_NAME as column_name,
|
|
114
|
+
DATA_TYPE as data_type,
|
|
115
|
+
IS_NULLABLE as is_nullable,
|
|
116
|
+
COLUMN_KEY as column_key,
|
|
117
|
+
COLUMN_DEFAULT as column_default,
|
|
118
|
+
EXTRA as extra
|
|
119
|
+
FROM
|
|
120
|
+
INFORMATION_SCHEMA.COLUMNS
|
|
121
|
+
WHERE
|
|
122
|
+
TABLE_NAME = ?
|
|
123
|
+
ORDER BY
|
|
124
|
+
ORDINAL_POSITION
|
|
125
125
|
`;
|
|
126
126
|
const results = await this.db.query(query, [params.table_name]);
|
|
127
127
|
return {
|
|
@@ -71,33 +71,33 @@ class UtilityTools {
|
|
|
71
71
|
try {
|
|
72
72
|
const { table_name } = params;
|
|
73
73
|
// Query to get foreign keys where this table is the parent
|
|
74
|
-
const parentQuery = `
|
|
75
|
-
SELECT
|
|
76
|
-
TABLE_NAME as child_table,
|
|
77
|
-
COLUMN_NAME as child_column,
|
|
78
|
-
REFERENCED_TABLE_NAME as parent_table,
|
|
79
|
-
REFERENCED_COLUMN_NAME as parent_column,
|
|
80
|
-
CONSTRAINT_NAME as constraint_name
|
|
81
|
-
FROM
|
|
82
|
-
INFORMATION_SCHEMA.KEY_COLUMN_USAGE
|
|
83
|
-
WHERE
|
|
84
|
-
REFERENCED_TABLE_NAME = ?
|
|
85
|
-
AND REFERENCED_TABLE_SCHEMA = DATABASE()
|
|
74
|
+
const parentQuery = `
|
|
75
|
+
SELECT
|
|
76
|
+
TABLE_NAME as child_table,
|
|
77
|
+
COLUMN_NAME as child_column,
|
|
78
|
+
REFERENCED_TABLE_NAME as parent_table,
|
|
79
|
+
REFERENCED_COLUMN_NAME as parent_column,
|
|
80
|
+
CONSTRAINT_NAME as constraint_name
|
|
81
|
+
FROM
|
|
82
|
+
INFORMATION_SCHEMA.KEY_COLUMN_USAGE
|
|
83
|
+
WHERE
|
|
84
|
+
REFERENCED_TABLE_NAME = ?
|
|
85
|
+
AND REFERENCED_TABLE_SCHEMA = DATABASE()
|
|
86
86
|
`;
|
|
87
87
|
// Query to get foreign keys where this table is the child
|
|
88
|
-
const childQuery = `
|
|
89
|
-
SELECT
|
|
90
|
-
TABLE_NAME as child_table,
|
|
91
|
-
COLUMN_NAME as child_column,
|
|
92
|
-
REFERENCED_TABLE_NAME as parent_table,
|
|
93
|
-
REFERENCED_COLUMN_NAME as parent_column,
|
|
94
|
-
CONSTRAINT_NAME as constraint_name
|
|
95
|
-
FROM
|
|
96
|
-
INFORMATION_SCHEMA.KEY_COLUMN_USAGE
|
|
97
|
-
WHERE
|
|
98
|
-
TABLE_NAME = ?
|
|
99
|
-
AND REFERENCED_TABLE_NAME IS NOT NULL
|
|
100
|
-
AND TABLE_SCHEMA = DATABASE()
|
|
88
|
+
const childQuery = `
|
|
89
|
+
SELECT
|
|
90
|
+
TABLE_NAME as child_table,
|
|
91
|
+
COLUMN_NAME as child_column,
|
|
92
|
+
REFERENCED_TABLE_NAME as parent_table,
|
|
93
|
+
REFERENCED_COLUMN_NAME as parent_column,
|
|
94
|
+
CONSTRAINT_NAME as constraint_name
|
|
95
|
+
FROM
|
|
96
|
+
INFORMATION_SCHEMA.KEY_COLUMN_USAGE
|
|
97
|
+
WHERE
|
|
98
|
+
TABLE_NAME = ?
|
|
99
|
+
AND REFERENCED_TABLE_NAME IS NOT NULL
|
|
100
|
+
AND TABLE_SCHEMA = DATABASE()
|
|
101
101
|
`;
|
|
102
102
|
// Execute both queries
|
|
103
103
|
const parentRelationships = await this.db.query(parentQuery, [table_name]);
|