mysqlsyncr 1.0.30 → 1.0.34
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/__tests__/parser.test.js +119 -118
- package/__tests__/parser2.test.js +153 -0
- package/package.json +1 -1
- package/src/apply.js +10 -0
- package/src/differences.js +6 -6
- package/src/dump.js +2 -1
- package/src/index.js +6 -4
- package/src/parsers.js +21 -6
- package/src/socketServer.js +28 -10
- package/ui/dist/spa/assets/{MainLayout-YzGyCzG4.js → MainLayout-CZr2X219.js} +1 -1
- package/ui/dist/spa/assets/{axios-BuG1eMVg.js → axios-tvpRgcMA.js} +1 -1
- package/ui/dist/spa/assets/{index-VXDnlybg.js → index-B4uAEdad.js} +7 -7
- package/ui/dist/spa/assets/{index-C3SFaSRt.css → index-DzBasYg9.css} +1 -1
- package/ui/dist/spa/index.html +2 -2
- package/ui/src/components/FolderBrowser.vue +1 -1
- package/ui/src/pages/MainComponent.vue +7 -2
package/__tests__/parser.test.js
CHANGED
|
@@ -25,136 +25,137 @@ describe('Create Table Parser', () => {
|
|
|
25
25
|
CONSTRAINT \`CaseDX\` FOREIGN KEY (\`idCaseDX\`) REFERENCES \`Case_DX\` (\`idCaseDX\`) ON DELETE NO ACTION ON UPDATE NO ACTION
|
|
26
26
|
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COMMENT='Keeps track of all active/inactive alarm rules used for the assets.\n';`;
|
|
27
27
|
|
|
28
|
-
const expectedOutput =
|
|
28
|
+
const expectedOutput = {
|
|
29
29
|
"name": "AlarmRuleHistory",
|
|
30
30
|
"columns": [
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
31
|
+
{
|
|
32
|
+
"Field": "idAlarmHistory",
|
|
33
|
+
"Type": "int(11)",
|
|
34
|
+
"NotNull": true,
|
|
35
|
+
"AutoIncrement": true
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"Field": "idAsset",
|
|
39
|
+
"Type": "int(11)",
|
|
40
|
+
"NotNull": true
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"Field": "idCaseDX",
|
|
44
|
+
"Type": "int(11)",
|
|
45
|
+
"Default": "NULL"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"Field": "idAlertRule",
|
|
49
|
+
"Type": "int(11)",
|
|
50
|
+
"Default": "NULL"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"Field": "activeAlarmRule",
|
|
54
|
+
"Type": "smallint(1)",
|
|
55
|
+
"NotNull": true,
|
|
56
|
+
"Default": "0"
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"Field": "alarmRule_StartDate",
|
|
60
|
+
"Type": "timestamp",
|
|
61
|
+
"Default": "NULL"
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"Field": "alarmRule_EndDate",
|
|
65
|
+
"Type": "timestamp",
|
|
66
|
+
"Default": "NULL"
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"Field": "dateCreated",
|
|
70
|
+
"Type": "timestamp",
|
|
71
|
+
"NotNull": true,
|
|
72
|
+
"Default": "CURRENT_TIMESTAMP"
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"Field": "dateUpdated",
|
|
76
|
+
"Type": "timestamp",
|
|
77
|
+
"NotNull": true,
|
|
78
|
+
"Default": "CURRENT_TIMESTAMP"
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"Field": "lastModifiedBy",
|
|
82
|
+
"Type": "varchar(32)",
|
|
83
|
+
"NotNull": true,
|
|
84
|
+
"Default": "System"
|
|
85
|
+
}
|
|
86
86
|
],
|
|
87
87
|
"indexes": [
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
88
|
+
{
|
|
89
|
+
"ColumnName": [
|
|
90
|
+
"idAlarmHistory"
|
|
91
|
+
],
|
|
92
|
+
"Primary": true,
|
|
93
|
+
"Name": "PRIMARY"
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"ColumnName": [
|
|
97
|
+
"idAlertRule"
|
|
98
|
+
],
|
|
99
|
+
"Name": "AlertRule_idx"
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"ColumnName": [
|
|
103
|
+
"idCaseDX"
|
|
104
|
+
],
|
|
105
|
+
"Name": "CaseDX_idx"
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"ColumnName": [
|
|
109
|
+
"idAsset"
|
|
110
|
+
],
|
|
111
|
+
"Name": "Asset_idx"
|
|
112
|
+
}
|
|
112
113
|
],
|
|
113
114
|
"constraints": [
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
115
|
+
{
|
|
116
|
+
"Name": "AlertRule",
|
|
117
|
+
"Type": "FOREIGN KEY",
|
|
118
|
+
"ColumnName": [
|
|
119
|
+
"idAlertRule"
|
|
120
|
+
],
|
|
121
|
+
"References": {
|
|
122
|
+
"Table": "AlertRules",
|
|
123
|
+
"Column": "idAlertRule"
|
|
124
|
+
},
|
|
125
|
+
"OnDelete": "NO ACTION",
|
|
126
|
+
"OnUpdate": "NO ACTION"
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
"Name": "AlertRule",
|
|
130
|
+
"Type": "FOREIGN KEY",
|
|
131
|
+
"ColumnName": [
|
|
132
|
+
"idAsset"
|
|
133
|
+
],
|
|
134
|
+
"References": {
|
|
135
|
+
"Table": "Assets",
|
|
136
|
+
"Column": "idAsset"
|
|
126
137
|
},
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
138
|
+
"OnDelete": "NO ACTION",
|
|
139
|
+
"OnUpdate": "NO ACTION"
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
"Name": "AlertRule",
|
|
143
|
+
"Type": "FOREIGN KEY",
|
|
144
|
+
"ColumnName": [
|
|
145
|
+
"idCaseDX"
|
|
146
|
+
],
|
|
147
|
+
"References": {
|
|
148
|
+
"Table": "Case_DX",
|
|
149
|
+
"Column": "idCaseDX"
|
|
139
150
|
},
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
"ColumnName": [
|
|
144
|
-
"`idCaseDX`"
|
|
145
|
-
],
|
|
146
|
-
"References": {
|
|
147
|
-
"Table": "`Case_DX`",
|
|
148
|
-
"Column": "`idCaseDX`"
|
|
149
|
-
},
|
|
150
|
-
"OnDelete": "NO ACTION",
|
|
151
|
-
"OnUpdate": "NO ACTION"
|
|
152
|
-
}
|
|
151
|
+
"OnDelete": "NO ACTION",
|
|
152
|
+
"OnUpdate": "NO ACTION"
|
|
153
|
+
}
|
|
153
154
|
],
|
|
154
155
|
"engine": "InnoDB",
|
|
155
156
|
"charset": "latin1",
|
|
156
157
|
"collate": null
|
|
157
|
-
|
|
158
|
+
}
|
|
158
159
|
|
|
159
160
|
|
|
160
161
|
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { parseCreateTableSQL, parseDatabaseStructure } from '../src/parsers';
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
describe('Create Table Parser', () => {
|
|
6
|
+
|
|
7
|
+
test('should correctly parse a valid create table statement. Check #1', () => {
|
|
8
|
+
const input = `CREATE TABLE \`Alarms\` (
|
|
9
|
+
\`alarmId\` int NOT NULL AUTO_INCREMENT,
|
|
10
|
+
\`alarmRuleId\` int NOT NULL,
|
|
11
|
+
\`alarmStatus\` int NOT NULL,
|
|
12
|
+
\`alarmStatus_Text\` varchar(50) NOT NULL,
|
|
13
|
+
\`alarmCreated_Date\` timestamp NULL DEFAULT NULL,
|
|
14
|
+
\`alarmConfirmed_Date\` timestamp NULL DEFAULT NULL,
|
|
15
|
+
\`alarmRecall_Date\` timestamp NULL DEFAULT NULL,
|
|
16
|
+
\`activeAlarm\` tinyint(1) NOT NULL DEFAULT '0',
|
|
17
|
+
\`emailSent\` tinyint(1) DEFAULT '0',
|
|
18
|
+
\`emailSent_AnswerPlus\` tinyint(1) DEFAULT '0',
|
|
19
|
+
\`ticketEmailSent\` tinyint(1) DEFAULT '0',
|
|
20
|
+
\`type\` varchar(45) DEFAULT NULL,
|
|
21
|
+
\`oorValue\` float(10,2) DEFAULT NULL,
|
|
22
|
+
\`thresholdValue\` float(10,2) DEFAULT NULL,
|
|
23
|
+
\`dateCreated\` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
|
|
24
|
+
\`dateUpdated\` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
25
|
+
PRIMARY KEY (\`alarmId\`),
|
|
26
|
+
UNIQUE KEY \`UniqueAlarmRules\` (\`alarmRuleId\`),
|
|
27
|
+
KEY \`idx_alarms_alarmruleid_alarmstatus\` (\`alarmRuleId\`, \`alarmStatus\`)
|
|
28
|
+
) ENGINE=InnoDB AUTO_INCREMENT=117 DEFAULT CHARSET=latin1 COMMENT='Alarm table for alarms '`;
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
const expectedOutput = {
|
|
32
|
+
"name": "Alarms",
|
|
33
|
+
"columns": [
|
|
34
|
+
{
|
|
35
|
+
"Field": "alarmId",
|
|
36
|
+
"Type": "int",
|
|
37
|
+
"NotNull": true,
|
|
38
|
+
"AutoIncrement": true
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"Field": "alarmRuleId",
|
|
42
|
+
"Type": "int",
|
|
43
|
+
"NotNull": true
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"Field": "alarmStatus",
|
|
47
|
+
"Type": "int",
|
|
48
|
+
"NotNull": true
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"Field": "alarmStatus_Text",
|
|
52
|
+
"Type": "varchar(50)",
|
|
53
|
+
"NotNull": true
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"Field": "alarmCreated_Date",
|
|
57
|
+
"Type": "timestamp",
|
|
58
|
+
"Default": "NULL"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"Field": "alarmConfirmed_Date",
|
|
62
|
+
"Type": "timestamp",
|
|
63
|
+
"Default": "NULL"
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"Field": "alarmRecall_Date",
|
|
67
|
+
"Type": "timestamp",
|
|
68
|
+
"Default": "NULL"
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"Field": "activeAlarm",
|
|
72
|
+
"Type": "tinyint(1)",
|
|
73
|
+
"NotNull": true,
|
|
74
|
+
"Default": "0"
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"Field": "emailSent",
|
|
78
|
+
"Type": "tinyint(1)",
|
|
79
|
+
"Default": "0"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"Field": "emailSent_AnswerPlus",
|
|
83
|
+
"Type": "tinyint(1)",
|
|
84
|
+
"Default": "0"
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"Field": "ticketEmailSent",
|
|
88
|
+
"Type": "tinyint(1)",
|
|
89
|
+
"Default": "0"
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"Field": "type",
|
|
93
|
+
"Type": "varchar(45)",
|
|
94
|
+
"Default": "NULL"
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"Field": "oorValue",
|
|
98
|
+
"Type": "float(10,2)"
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"Field": "thresholdValue",
|
|
102
|
+
"Type": "float(10,2)"
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
"Field": "dateCreated",
|
|
106
|
+
"Type": "timestamp",
|
|
107
|
+
"Default": "CURRENT_TIMESTAMP"
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"Field": "dateUpdated",
|
|
111
|
+
"Type": "timestamp",
|
|
112
|
+
"NotNull": true,
|
|
113
|
+
"Default": "CURRENT_TIMESTAMP"
|
|
114
|
+
}
|
|
115
|
+
],
|
|
116
|
+
"indexes": [
|
|
117
|
+
{
|
|
118
|
+
"ColumnName": [
|
|
119
|
+
"alarmId"
|
|
120
|
+
],
|
|
121
|
+
"Primary": true,
|
|
122
|
+
"Name": "PRIMARY"
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
"ColumnName": [
|
|
126
|
+
"alarmRuleId"
|
|
127
|
+
],
|
|
128
|
+
"Unique": true,
|
|
129
|
+
"Name": "UniqueAlarmRules"
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
"ColumnName": [
|
|
133
|
+
"alarmRuleId",
|
|
134
|
+
"alarmStatus"
|
|
135
|
+
],
|
|
136
|
+
"Name": "idx_alarms_alarmruleid_alarmstatus"
|
|
137
|
+
}
|
|
138
|
+
],
|
|
139
|
+
"constraints": [],
|
|
140
|
+
"engine": null,
|
|
141
|
+
"charset": null,
|
|
142
|
+
"collate": null
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
const result = parseCreateTableSQL(input);
|
|
148
|
+
console.log('Result:', JSON.stringify(result, null, 2))
|
|
149
|
+
expect(result).toEqual(expectedOutput);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
});
|
package/package.json
CHANGED
package/src/apply.js
CHANGED
|
@@ -65,6 +65,16 @@ export const applyDifferences = async (connection, database, differences) => {
|
|
|
65
65
|
console.log(`Executing: ${modifyFieldSQL}`);
|
|
66
66
|
await connection.query(modifyFieldSQL);
|
|
67
67
|
}
|
|
68
|
+
if(diff.field.Default){
|
|
69
|
+
const defaultClause = diff.field.Default === 'CURRENT_TIMESTAMP'
|
|
70
|
+
? 'DEFAULT CURRENT_TIMESTAMP'
|
|
71
|
+
: diff.field.Default !== undefined && diff.field.Default !== null
|
|
72
|
+
? `DEFAULT '${diff.field.Default}'`
|
|
73
|
+
: '';
|
|
74
|
+
const modifyFieldSQL = `ALTER TABLE \`${diff.tableName}\` MODIFY \`${diff.field.Field}\` ${diff.field.Type} ${defaultClause};`;
|
|
75
|
+
console.log(`Executing: ${modifyFieldSQL}`);
|
|
76
|
+
await connection.query(modifyFieldSQL);
|
|
77
|
+
}
|
|
68
78
|
|
|
69
79
|
} else if (diff.type === 'extra_field') {
|
|
70
80
|
const dropFieldSQL = `ALTER TABLE \`${diff.tableName}\` DROP COLUMN \`${diff.field.Field}\`;`;
|
package/src/differences.js
CHANGED
|
@@ -38,12 +38,12 @@ export const findDifferences = (expected, current) => {
|
|
|
38
38
|
const expectedFieldNames = columns.map(f => f.Field);
|
|
39
39
|
|
|
40
40
|
logger('Detecting missing fields for table', tableName);
|
|
41
|
-
// Detect missing fields
|
|
42
|
-
for (const field of columns) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
41
|
+
// // Detect missing fields
|
|
42
|
+
// for (const field of columns) {
|
|
43
|
+
// if (!currentFieldNames.includes(field.Field)) {
|
|
44
|
+
// differences.push({ type: 'missing_field', tableName, field });
|
|
45
|
+
// }
|
|
46
|
+
// }
|
|
47
47
|
|
|
48
48
|
logger('Detecting extra fields for table', tableName);
|
|
49
49
|
// Detect extra fields
|
package/src/dump.js
CHANGED
|
@@ -16,6 +16,7 @@ export const dumpAllDatabases = async (connection, command, options) => {
|
|
|
16
16
|
await fs.writeFile(path.join(options.output , database, `${database}.json`), JSON.stringify(dbStructure, null, 4), 'utf-8');
|
|
17
17
|
response[database] = dbStructure;
|
|
18
18
|
}
|
|
19
|
+
await fs.writeFile(path.join(options.output, 'dumpInfo.json'), JSON.stringify({timestamp: new Date().toISOString(), version: process.env.npm_package_version}, null, 4), 'utf-8');
|
|
19
20
|
return response;
|
|
20
21
|
}
|
|
21
22
|
|
|
@@ -33,7 +34,7 @@ export const getDatabasesFromExistingDumps = async (options) => {
|
|
|
33
34
|
let response = {}
|
|
34
35
|
const databases = await fs.readdir(path.join(options.output));
|
|
35
36
|
for (const database of databases) {
|
|
36
|
-
if(database.includes('diffs')){
|
|
37
|
+
if(database.includes('diffs') || database.includes('dumpInfo')){
|
|
37
38
|
console.log('Skipping diffs folder')
|
|
38
39
|
continue
|
|
39
40
|
}
|
package/src/index.js
CHANGED
|
@@ -14,17 +14,19 @@ class DBStructureChecker {
|
|
|
14
14
|
constructor(config, targetDatabase = null) {
|
|
15
15
|
this.config = config;
|
|
16
16
|
this.targetDatabase = targetDatabase;
|
|
17
|
-
this.connection = mysql.createConnection(this.config)
|
|
17
|
+
this.connection = mysql.createConnection(this.config)
|
|
18
18
|
this.dumpAllDatabases = dumpAllDatabases;
|
|
19
19
|
this.compareAllDatabases = compareAllDatabases;
|
|
20
20
|
this.getDatabases = () => {
|
|
21
21
|
|
|
22
22
|
fs.readFileSync(path.join(__dirname, 'databases.json'), 'utf8');
|
|
23
23
|
}
|
|
24
|
-
this.connection.on('error', (err) => {
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
// this.connection.on('error', (err) => {
|
|
25
|
+
// this.emit('error', err);
|
|
26
|
+
// console.error('Database connection error:', err);
|
|
27
|
+
// });
|
|
27
28
|
this.connection.query = util.promisify(this.connection.query); // Promisify for async/await
|
|
29
|
+
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
async reconnect() {
|
package/src/parsers.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
export const parseCreateTableSQL = (createTableSQL) => {
|
|
3
2
|
if(!createTableSQL) return null;
|
|
4
3
|
const name = createTableSQL.match(/CREATE TABLE\s+`([^`]+)`/)[1];
|
|
@@ -32,9 +31,10 @@ export const parseCreateTableSQL = (createTableSQL) => {
|
|
|
32
31
|
const indexMatch = indexRegex.exec(line);
|
|
33
32
|
const constraintMatch = parseConstraint(line);
|
|
34
33
|
if (columnMatch && !indexMatch && !constraintMatch) {
|
|
34
|
+
const columnType = parseColumnType(line);
|
|
35
35
|
const column = {
|
|
36
36
|
Field: columnMatch[1],
|
|
37
|
-
Type:
|
|
37
|
+
Type: columnType
|
|
38
38
|
};
|
|
39
39
|
|
|
40
40
|
// Set Null property based on NOT NULL presence
|
|
@@ -116,15 +116,30 @@ export const parseConstraint = (sql) => {
|
|
|
116
116
|
}else{
|
|
117
117
|
onUpdate = 'NO ACTION';
|
|
118
118
|
}
|
|
119
|
+
let columnName = match[1] || ''
|
|
120
|
+
columnName = columnName.replace(/`/g, '')
|
|
121
|
+
let table = match[2] || ''
|
|
122
|
+
table = table.replace(/`/g, '')
|
|
123
|
+
let column = match[3] || ''
|
|
124
|
+
column = column.replace(/`/g, '')
|
|
119
125
|
return {
|
|
120
126
|
Name: "AlertRule", // Replace with actual constraint name if needed
|
|
121
127
|
Type: "FOREIGN KEY",
|
|
122
|
-
ColumnName: [
|
|
128
|
+
ColumnName: [columnName], // Column in the current table
|
|
123
129
|
References: {
|
|
124
|
-
Table:
|
|
125
|
-
Column:
|
|
130
|
+
Table: table, // Referenced table
|
|
131
|
+
Column: column, // Referenced column
|
|
126
132
|
},
|
|
127
133
|
OnDelete: onDelete,
|
|
128
134
|
OnUpdate: onUpdate,
|
|
129
135
|
};
|
|
130
|
-
};
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
const parseColumnType = (line) => {
|
|
139
|
+
// Match type pattern including parameters, handling both single and double parameter types
|
|
140
|
+
const typeRegex = /`[^`]+`\s+([a-zA-Z]+(?:\([0-9]+(?:,[0-9]+)?\))?)/i;
|
|
141
|
+
const match = line.match(typeRegex);
|
|
142
|
+
|
|
143
|
+
if (!match) return null;
|
|
144
|
+
return match[1]; // Returns the full type including parameters
|
|
145
|
+
};
|
package/src/socketServer.js
CHANGED
|
@@ -12,7 +12,7 @@ import { resolve } from 'path';
|
|
|
12
12
|
|
|
13
13
|
export const startApiServer = (port) => {
|
|
14
14
|
const app = express();
|
|
15
|
-
app.use(cors({origin:'*'}));
|
|
15
|
+
app.use(cors({ origin: '*' }));
|
|
16
16
|
const server = http.createServer(app);
|
|
17
17
|
app.use(express.json({ limit: '50mb' })); // Increased payload limit
|
|
18
18
|
app.use(express.urlencoded({ limit: '50mb', extended: true })); // Also handle URL-encoded data
|
|
@@ -31,6 +31,12 @@ export const startApiServer = (port) => {
|
|
|
31
31
|
app.post('/api/dump', async (req, res) => {
|
|
32
32
|
const { config, database } = req.body;
|
|
33
33
|
const checker = new DBStructureChecker(config, database);
|
|
34
|
+
|
|
35
|
+
checker.connection.on('error', (err) => {
|
|
36
|
+
console.error('Database connection error in route dump:', err);
|
|
37
|
+
res.status(500).json({ message: 'Database connection failed', error: err.message });
|
|
38
|
+
});
|
|
39
|
+
|
|
34
40
|
checker.connection.on('connect', async () => {
|
|
35
41
|
console.log('Connected to the database');
|
|
36
42
|
checker.targetDatabase = database;
|
|
@@ -52,6 +58,12 @@ export const startApiServer = (port) => {
|
|
|
52
58
|
app.post('/api/compare', async (req, res) => {
|
|
53
59
|
const { config } = req.body;
|
|
54
60
|
const checker = new DBStructureChecker(config, config.database);
|
|
61
|
+
|
|
62
|
+
checker.connection.on('error', (err) => {
|
|
63
|
+
console.error('Database connection error in route compare:', err);
|
|
64
|
+
res.status(500).json({ message: 'Database connection failed', error: err.message });
|
|
65
|
+
});
|
|
66
|
+
|
|
55
67
|
checker.connection.on('connect', async () => {
|
|
56
68
|
console.log('Connected to the database');
|
|
57
69
|
checker.targetDatabase = config.database;
|
|
@@ -61,7 +73,7 @@ export const startApiServer = (port) => {
|
|
|
61
73
|
delete req.body.output;
|
|
62
74
|
console.log('Comparing the database structure with JSON dumps (dry run)');
|
|
63
75
|
let diffs = await compareAllDatabases(checker.connection, config.output, false, 'compare', config);
|
|
64
|
-
res.json(diffs);
|
|
76
|
+
res.json(diffs);
|
|
65
77
|
} catch (err) {
|
|
66
78
|
console.log(err);
|
|
67
79
|
console.log(req.body);
|
|
@@ -70,7 +82,7 @@ export const startApiServer = (port) => {
|
|
|
70
82
|
await checker.closeConnection();
|
|
71
83
|
}
|
|
72
84
|
})
|
|
73
|
-
|
|
85
|
+
|
|
74
86
|
});
|
|
75
87
|
|
|
76
88
|
// API endpoint to apply differences
|
|
@@ -78,6 +90,12 @@ export const startApiServer = (port) => {
|
|
|
78
90
|
const { config, database, diffs } = req.body;
|
|
79
91
|
console.log('Applying differences:', diffs);
|
|
80
92
|
const checker = new DBStructureChecker(config, database);
|
|
93
|
+
|
|
94
|
+
checker.connection.on('error', (err) => {
|
|
95
|
+
console.error('Database connection error in route apply:', err);
|
|
96
|
+
res.status(500).json({ message: 'Database connection failed', error: err.message });
|
|
97
|
+
});
|
|
98
|
+
|
|
81
99
|
checker.connection.on('connect', async () => {
|
|
82
100
|
console.log('Connected to the database');
|
|
83
101
|
checker.targetDatabase = database;
|
|
@@ -97,17 +115,17 @@ export const startApiServer = (port) => {
|
|
|
97
115
|
|
|
98
116
|
app.post('/api/browse-folders', async (req, res) => {
|
|
99
117
|
try {
|
|
100
|
-
const { currentPath = process.cwd() } = req.body;
|
|
118
|
+
const { currentPath = process.cwd() } = req.body;
|
|
101
119
|
console.log('Browsing folder:', currentPath);
|
|
102
|
-
|
|
120
|
+
|
|
103
121
|
const resolvedPath = currentPath.startsWith('/') || currentPath.match(/^[A-Z]:\\/)
|
|
104
122
|
? resolve(currentPath)
|
|
105
123
|
: resolve(process.cwd(), currentPath);
|
|
106
124
|
|
|
107
125
|
console.log('Resolved path:', resolvedPath);
|
|
108
|
-
|
|
126
|
+
|
|
109
127
|
const contents = await readdir(resolvedPath, { withFileTypes: true });
|
|
110
|
-
|
|
128
|
+
|
|
111
129
|
// Separate directories and files
|
|
112
130
|
const items = contents.map(dirent => ({
|
|
113
131
|
name: dirent.name,
|
|
@@ -147,13 +165,13 @@ export const startApiServer = (port) => {
|
|
|
147
165
|
try {
|
|
148
166
|
const { folderPath } = req.body;
|
|
149
167
|
console.log('Creating folder:', folderPath);
|
|
150
|
-
|
|
168
|
+
|
|
151
169
|
const resolvedPath = folderPath.startsWith('/') || folderPath.match(/^[A-Z]:\\/)
|
|
152
170
|
? resolve(folderPath)
|
|
153
171
|
: resolve(process.cwd(), folderPath);
|
|
154
172
|
|
|
155
173
|
await mkdir(resolvedPath, { recursive: true });
|
|
156
|
-
|
|
174
|
+
|
|
157
175
|
res.json({
|
|
158
176
|
success: true,
|
|
159
177
|
path: resolvedPath
|
|
@@ -162,7 +180,7 @@ export const startApiServer = (port) => {
|
|
|
162
180
|
res.status(500).json({ error: error.message });
|
|
163
181
|
}
|
|
164
182
|
});
|
|
165
|
-
|
|
183
|
+
|
|
166
184
|
// Start the server
|
|
167
185
|
server.listen(port, () => {
|
|
168
186
|
console.log(`Server is running on http://localhost:${port}`);
|