dbtasker 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/app.js +32 -0
- package/backup-tableoperation.js +717 -0
- package/check.js +18 -0
- package/checker.js +359 -0
- package/function.js +673 -0
- package/index.js +99 -0
- package/package.json +26 -0
- package/tableOperations.js +614 -0
- package/tables.js +1 -0
- package/user_tables.js +1655 -0
|
@@ -0,0 +1,717 @@
|
|
|
1
|
+
const path = require("path");
|
|
2
|
+
const fs = require("fs/promises"); // Importing fs.promises for async operations
|
|
3
|
+
const { pool, DBInfo } = require("./server_setup.js"); // Import the promise-based pool
|
|
4
|
+
const fncs = require("./functions.js");
|
|
5
|
+
const { table, error } = require("console");
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
const jsonClientfilePath = path.join(__dirname, "../tables.json");
|
|
9
|
+
let matchDatabase = path.join(__dirname, "./readonly");
|
|
10
|
+
const dropTable = false;
|
|
11
|
+
const dropColumn = true;
|
|
12
|
+
const createTable = true;
|
|
13
|
+
const alterTable = true;
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
//generate table query
|
|
23
|
+
function generateCreateTableQuery(tableName, schemaObject) {
|
|
24
|
+
const errors = [];
|
|
25
|
+
|
|
26
|
+
// Validate table name
|
|
27
|
+
if (!tableName || typeof tableName !== "string") {
|
|
28
|
+
errors.push("Invalid table name.");
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Validate schema object
|
|
32
|
+
if (
|
|
33
|
+
!schemaObject ||
|
|
34
|
+
typeof schemaObject !== "object" ||
|
|
35
|
+
Array.isArray(schemaObject)
|
|
36
|
+
) {
|
|
37
|
+
errors.push("Invalid schema object.");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// If there are critical validation errors, return immediately
|
|
41
|
+
if (errors.length > 0) {
|
|
42
|
+
throw new Error(errors.join("\n"));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const columns = [];
|
|
46
|
+
const foreignKeys = [];
|
|
47
|
+
|
|
48
|
+
for (let columnName in schemaObject) {
|
|
49
|
+
const columnInfo = schemaObject[columnName];
|
|
50
|
+
|
|
51
|
+
if (
|
|
52
|
+
typeof columnInfo === "object" &&
|
|
53
|
+
columnInfo !== null &&
|
|
54
|
+
!Array.isArray(columnInfo)
|
|
55
|
+
) {
|
|
56
|
+
const type = columnInfo.type;
|
|
57
|
+
|
|
58
|
+
if (!type || typeof type.name !== "string") {
|
|
59
|
+
errors.push(`Invalid type for column: ${columnName}`);
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
let columnDef = `${columnName} ${type.name}`;
|
|
64
|
+
|
|
65
|
+
// Handle LengthValues if defined
|
|
66
|
+
if (type["LengthValues"] !== undefined) {
|
|
67
|
+
columnDef += `(${type["LengthValues"]})`;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Handle NULL/NOT NULL
|
|
71
|
+
columnDef += columnInfo.NULL === false ? " NOT NULL" : " NULL";
|
|
72
|
+
|
|
73
|
+
// Handle DEFAULT
|
|
74
|
+
if (columnInfo.DEFAULT !== undefined) {
|
|
75
|
+
let defaultValue = columnInfo.DEFAULT;
|
|
76
|
+
|
|
77
|
+
// Check if it's a string and matches the CURRENT_TIMESTAMP pattern
|
|
78
|
+
if (
|
|
79
|
+
typeof defaultValue === "string" &&
|
|
80
|
+
defaultValue.match(/CURRENT_TIMESTAMP/i)
|
|
81
|
+
) {
|
|
82
|
+
defaultValue = columnInfo.DEFAULT; // Keep it as is if it's CURRENT_TIMESTAMP
|
|
83
|
+
} else {
|
|
84
|
+
defaultValue = `'${defaultValue}'`; // Otherwise, wrap it in single quotes
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
columnDef += ` DEFAULT ${defaultValue}`;
|
|
88
|
+
}
|
|
89
|
+
//Handle onupdate
|
|
90
|
+
if (columnInfo.on_update) {
|
|
91
|
+
if (typeof columnInfo.on_update === "string") {
|
|
92
|
+
columnDef += ` ON UPDATE ${columnInfo.on_update}`; // Keep it as is if it's CURRENT_TIMESTAMP
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Handle COMMENT
|
|
97
|
+
if (columnInfo.comment) {
|
|
98
|
+
let cmnt = columnInfo.comment.replace(/'/g, "");
|
|
99
|
+
columnDef += ` COMMENT '${cmnt}'`;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Handle AUTO_INCREMENT
|
|
103
|
+
if (columnInfo.AUTO_INCREMENT) {
|
|
104
|
+
columnDef += " AUTO_INCREMENT";
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Handle PRIMARY KEY/UNIQUE directly
|
|
108
|
+
if (columnInfo.index) {
|
|
109
|
+
columnDef += ` ${columnInfo.index}`;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Push column definition
|
|
113
|
+
columns.push(columnDef);
|
|
114
|
+
|
|
115
|
+
// Handle foreign keys
|
|
116
|
+
if (columnInfo.foreign_key) {
|
|
117
|
+
const fk = columnInfo.foreign_key;
|
|
118
|
+
if (
|
|
119
|
+
fk &&
|
|
120
|
+
typeof fk === "object" &&
|
|
121
|
+
fk.REFERENCES &&
|
|
122
|
+
fk.REFERENCES.table &&
|
|
123
|
+
fk.REFERENCES.column
|
|
124
|
+
) {
|
|
125
|
+
let foreignKeyDef = `FOREIGN KEY (${columnName}) REFERENCES ${fk.REFERENCES.table}(${fk.REFERENCES.column})`;
|
|
126
|
+
|
|
127
|
+
// Handle ON DELETE
|
|
128
|
+
if (fk.delete === true) {
|
|
129
|
+
foreignKeyDef += " ON DELETE CASCADE";
|
|
130
|
+
} else if (fk.delete === null) {
|
|
131
|
+
foreignKeyDef += " ON DELETE SET NULL";
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Handle ON UPDATE
|
|
135
|
+
if (fk.update === "CASCADE") {
|
|
136
|
+
foreignKeyDef += " ON UPDATE CASCADE";
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
foreignKeys.push(foreignKeyDef);
|
|
140
|
+
} else {
|
|
141
|
+
errors.push(
|
|
142
|
+
`Invalid foreign key definition for column "${columnName}": ${JSON.stringify(
|
|
143
|
+
fk
|
|
144
|
+
)}`
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
} else {
|
|
149
|
+
errors.push(`Invalid column definition for: ${columnName}`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// If errors were collected during column validation, throw them
|
|
154
|
+
if (errors.length > 0) {
|
|
155
|
+
throw new Error(errors.join("\n"));
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Combine columns and foreign keys into the table definition
|
|
159
|
+
const tableDefinition = [...columns, ...foreignKeys].join(", ");
|
|
160
|
+
const createTableQuery = `CREATE TABLE IF NOT EXISTS ${tableName} (${tableDefinition}) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;`;
|
|
161
|
+
|
|
162
|
+
return createTableQuery.replace(/''/g, "'");
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
//Generate modifying and droping table query
|
|
166
|
+
async function generateAlterTableQuery(tableName, schema, dropColumn) {
|
|
167
|
+
try {
|
|
168
|
+
if (!schema) {
|
|
169
|
+
throw new Error(`Schema for table ${tableName} is undefined or null`);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const existingColumns = await getColumnDetails(tableName);
|
|
173
|
+
console.log(`Fetched column details for table: ${tableName}`);
|
|
174
|
+
const existingForeignKey = await getForeignKeyDetails(tableName);
|
|
175
|
+
console.log(`Fetched foreign key details for table: ${tableName}`);
|
|
176
|
+
if (!existingColumns) {
|
|
177
|
+
throw new Error(`Failed to fetch column details for table ${tableName}`);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
let alterStatements = [];
|
|
181
|
+
let isModifyIncludefk = []; //keeps the column_name if column modified
|
|
182
|
+
let isIncludefk = []; //keeps all column_name in the table
|
|
183
|
+
let dropforeignkeyconstraint = [];
|
|
184
|
+
let unmatchedforeignkey = [];
|
|
185
|
+
|
|
186
|
+
for (const [columnName, columnDetails] of Object.entries(schema)) {
|
|
187
|
+
if (!columnDetails) {
|
|
188
|
+
console.log(`Column details are undefined for column ${columnName}`);
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const existingColumn = existingColumns.find(
|
|
193
|
+
(col) => col.column_name === columnName
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
if (existingColumn) {
|
|
197
|
+
let isSameType = false;
|
|
198
|
+
if (
|
|
199
|
+
existingColumn.data_type.toLowerCase() ===
|
|
200
|
+
columnDetails.type?.name.toLowerCase()
|
|
201
|
+
) {
|
|
202
|
+
isSameType = true;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
let isSameLength = false;
|
|
206
|
+
if (
|
|
207
|
+
(existingColumn.character_maximum_length > 50000 &&
|
|
208
|
+
columnDetails.type?.LengthValues === undefined) ||
|
|
209
|
+
(existingColumn.character_maximum_length === null &&
|
|
210
|
+
columnDetails.type?.LengthValues === undefined) ||
|
|
211
|
+
existingColumn.character_maximum_length ===
|
|
212
|
+
columnDetails.type?.LengthValues
|
|
213
|
+
) {
|
|
214
|
+
isSameLength = true;
|
|
215
|
+
} else if (columnDetails.type?.name === "ENUM") {
|
|
216
|
+
let length_val = columnDetails.type?.LengthValues;
|
|
217
|
+
length_val = length_val.replace(/,\s+/g, ",");
|
|
218
|
+
if (`enum(${length_val})` === existingColumn.column_type) {
|
|
219
|
+
isSameLength = true;
|
|
220
|
+
} else {
|
|
221
|
+
isSameLength = false;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
let isSameNull = false;
|
|
225
|
+
if (
|
|
226
|
+
existingColumn.is_nullable === "YES" &&
|
|
227
|
+
columnDetails.NULL !== false
|
|
228
|
+
) {
|
|
229
|
+
isSameNull = true;
|
|
230
|
+
} else if (
|
|
231
|
+
existingColumn.is_nullable === "NO" &&
|
|
232
|
+
columnDetails.NULL === false
|
|
233
|
+
) {
|
|
234
|
+
isSameNull = true;
|
|
235
|
+
}
|
|
236
|
+
let isDefaultMatch = false;
|
|
237
|
+
if (isNumber(columnDetails.DEFAULT)) {
|
|
238
|
+
columnDetails.DEFAULT = columnDetails.DEFAULT.toString();
|
|
239
|
+
}
|
|
240
|
+
if (
|
|
241
|
+
existingColumn.default_value === `'${columnDetails.DEFAULT}'` ||
|
|
242
|
+
existingColumn.default_value === columnDetails.DEFAULT ||
|
|
243
|
+
(existingColumn.default_value === "NULL" &&
|
|
244
|
+
columnDetails.DEFAULT === undefined) ||
|
|
245
|
+
(existingColumn.default_value === null &&
|
|
246
|
+
columnDetails.DEFAULT === undefined) ||
|
|
247
|
+
(existingColumn.default_value === "current_timestamp()" &&
|
|
248
|
+
columnDetails.DEFAULT === "CURRENT_TIMESTAMP")
|
|
249
|
+
) {
|
|
250
|
+
isDefaultMatch = true;
|
|
251
|
+
} else if (columnDetails.DEFAULT || columnDetails.DEFAULT === 0) {
|
|
252
|
+
if (
|
|
253
|
+
existingColumn.default_value === columnDetails.DEFAULT.toString()
|
|
254
|
+
) {
|
|
255
|
+
isDefaultMatch = true;
|
|
256
|
+
} else {
|
|
257
|
+
isDefaultMatch = false;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
let isSameComment = false;
|
|
261
|
+
if (
|
|
262
|
+
existingColumn.column_comment === columnDetails.comment?.replace(/'/g, "") ||
|
|
263
|
+
(existingColumn.column_comment === "" &&
|
|
264
|
+
columnDetails.comment === undefined)
|
|
265
|
+
) {
|
|
266
|
+
isSameComment = true;
|
|
267
|
+
}
|
|
268
|
+
if (columnDetails.foreign_key) {
|
|
269
|
+
isIncludefk.push(columnName);
|
|
270
|
+
for (const keys of existingForeignKey) {
|
|
271
|
+
if (keys.COLUMN_NAME == columnName) {
|
|
272
|
+
if (
|
|
273
|
+
keys.REFERENCED_TABLE_NAME ===
|
|
274
|
+
columnDetails.foreign_key.REFERENCES.table &&
|
|
275
|
+
keys.REFERENCED_COLUMN_NAME ===
|
|
276
|
+
columnDetails.foreign_key.REFERENCES.column
|
|
277
|
+
) {
|
|
278
|
+
if (
|
|
279
|
+
keys.DELETE_RULE === "CASCADE" &&
|
|
280
|
+
columnDetails.foreign_key.delete !== true
|
|
281
|
+
) {
|
|
282
|
+
dropforeignkeyconstraint.push(keys.CONSTRAINT_NAME);
|
|
283
|
+
unmatchedforeignkey.push(keys.COLUMN_NAME);
|
|
284
|
+
} else if (
|
|
285
|
+
keys.DELETE_RULE !== "CASCADE" &&
|
|
286
|
+
columnDetails.foreign_key.delete === true
|
|
287
|
+
) {
|
|
288
|
+
dropforeignkeyconstraint.push(keys.CONSTRAINT_NAME);
|
|
289
|
+
unmatchedforeignkey.push(keys.COLUMN_NAME);
|
|
290
|
+
}
|
|
291
|
+
} else {
|
|
292
|
+
dropforeignkeyconstraint.push(keys.CONSTRAINT_NAME);
|
|
293
|
+
unmatchedforeignkey.push(keys.COLUMN_NAME);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
if (
|
|
299
|
+
isSameType &&
|
|
300
|
+
isSameLength &&
|
|
301
|
+
isSameNull &&
|
|
302
|
+
isDefaultMatch &&
|
|
303
|
+
isSameComment
|
|
304
|
+
) {
|
|
305
|
+
//console.log(`No modification needed for column "${columnName}"`);
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
console.log(
|
|
309
|
+
columnName,
|
|
310
|
+
isSameType,
|
|
311
|
+
isSameLength,
|
|
312
|
+
isSameNull,
|
|
313
|
+
isDefaultMatch,
|
|
314
|
+
isSameComment
|
|
315
|
+
);
|
|
316
|
+
if (columnDetails.foreign_key) {
|
|
317
|
+
isModifyIncludefk.push(columnName);
|
|
318
|
+
}
|
|
319
|
+
let modifyStatement = `ALTER TABLE ${tableName} MODIFY COLUMN ${columnName} ${columnDetails.type?.name}`;
|
|
320
|
+
|
|
321
|
+
if (
|
|
322
|
+
columnDetails.type?.name === "enum" ||
|
|
323
|
+
columnDetails.type?.name === "varchar"
|
|
324
|
+
) {
|
|
325
|
+
if (!columnDetails.type?.LengthValues) {
|
|
326
|
+
throw new Error(
|
|
327
|
+
`ENUM or VARCHAR column "${columnName}" needs a LengthValues definition.`
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
modifyStatement += `(${columnDetails.type?.LengthValues})`;
|
|
331
|
+
} else if (columnDetails.type?.LengthValues !== undefined) {
|
|
332
|
+
modifyStatement += `(${columnDetails.type?.LengthValues})`;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
if (columnDetails.NULL === false) {
|
|
336
|
+
modifyStatement += " NOT NULL";
|
|
337
|
+
} else {
|
|
338
|
+
modifyStatement += " NULL";
|
|
339
|
+
}
|
|
340
|
+
if (columnDetails.DEFAULT || columnDetails.DEFAULT === 0) {
|
|
341
|
+
if (columnDetails.DEFAULT === "CURRENT_TIMESTAMP") {
|
|
342
|
+
modifyStatement += ` DEFAULT CURRENT_TIMESTAMP`;
|
|
343
|
+
} else if (isJsonObject(columnDetails.DEFAULT)) {
|
|
344
|
+
throw new Error(
|
|
345
|
+
"Having default value is restricted by database for BLOB, TEXT, GEOMETRY or JSON column"
|
|
346
|
+
);
|
|
347
|
+
} else {
|
|
348
|
+
modifyStatement += ` DEFAULT '${columnDetails.DEFAULT}'`;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
if (columnDetails.on_update) {
|
|
352
|
+
modifyStatement += ` ON UPDATE ${columnDetails.on_update}`;
|
|
353
|
+
}
|
|
354
|
+
if (columnDetails.comment)
|
|
355
|
+
modifyStatement += ` COMMENT '${bypassQuotes(columnDetails.comment)}'`;
|
|
356
|
+
|
|
357
|
+
// Handle AUTO_INCREMENT
|
|
358
|
+
if (columnDetails.AUTO_INCREMENT) {
|
|
359
|
+
modifyStatement += " AUTO_INCREMENT";
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
console.log(`Modified existing column: ${columnName}`);
|
|
363
|
+
console.log("modify statement is: ", modifyStatement);
|
|
364
|
+
alterStatements.push(modifyStatement);
|
|
365
|
+
} else {
|
|
366
|
+
let addStatement = `ALTER TABLE ${tableName} ADD COLUMN ${columnName} ${columnDetails.type?.name}`;
|
|
367
|
+
|
|
368
|
+
if (
|
|
369
|
+
columnDetails.type?.name === "enum" ||
|
|
370
|
+
columnDetails.type?.name === "varchar"
|
|
371
|
+
) {
|
|
372
|
+
if (!columnDetails.type?.LengthValues) {
|
|
373
|
+
throw new Error(
|
|
374
|
+
`ENUM or VARCHAR column "${columnName}" needs a LengthValues definition.`
|
|
375
|
+
);
|
|
376
|
+
}
|
|
377
|
+
addStatement += `(${columnDetails.type?.LengthValues})`;
|
|
378
|
+
} else if (columnDetails.type?.LengthValues !== undefined) {
|
|
379
|
+
addStatement += `(${columnDetails.type?.LengthValues})`;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
if (columnDetails.NULL === false) addStatement += " NOT NULL";
|
|
383
|
+
if (columnDetails.DEFAULT || columnDetails.DEFAULT === 0) {
|
|
384
|
+
if (columnDetails.DEFAULT === "CURRENT_TIMESTAMP") {
|
|
385
|
+
addStatement += ` DEFAULT CURRENT_TIMESTAMP`;
|
|
386
|
+
} else if (isJsonObject(columnDetails.DEFAULT)) {
|
|
387
|
+
throw new Error(
|
|
388
|
+
"Having default value is restricted by database for BLOB, TEXT, GEOMETRY or JSON column"
|
|
389
|
+
);
|
|
390
|
+
} else {
|
|
391
|
+
addStatement += ` DEFAULT '${columnDetails.DEFAULT}'`;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
if (columnDetails.on_update) {
|
|
395
|
+
addStatement += ` ON UPDATE ${columnDetails.on_update}`;
|
|
396
|
+
}
|
|
397
|
+
if (columnDetails.comment) {
|
|
398
|
+
addStatement += ` COMMENT '${bypassQuotes(columnDetails.comment)}'`;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// Handle AUTO_INCREMENT
|
|
402
|
+
if (columnDetails.AUTO_INCREMENT) {
|
|
403
|
+
addStatement += " AUTO_INCREMENT";
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
alterStatements.push(addStatement);
|
|
407
|
+
if (columnDetails.foreign_key) {
|
|
408
|
+
isIncludefk.push(columnName);
|
|
409
|
+
for (const keys of existingForeignKey) {
|
|
410
|
+
if (keys.COLUMN_NAME == columnName) {
|
|
411
|
+
if (
|
|
412
|
+
keys.REFERENCED_TABLE_NAME ===
|
|
413
|
+
columnDetails.foreign_key.REFERENCES.table &&
|
|
414
|
+
keys.REFERENCED_COLUMN_NAME ===
|
|
415
|
+
columnDetails.foreign_key.REFERENCES.column
|
|
416
|
+
) {
|
|
417
|
+
if (
|
|
418
|
+
keys.DELETE_RULE === "CASCADE" &&
|
|
419
|
+
columnDetails.foreign_key.delete !== true
|
|
420
|
+
) {
|
|
421
|
+
dropforeignkeyconstraint.push(keys.CONSTRAINT_NAME);
|
|
422
|
+
unmatchedforeignkey.push(keys.COLUMN_NAME);
|
|
423
|
+
} else if (
|
|
424
|
+
keys.DELETE_RULE !== "CASCADE" &&
|
|
425
|
+
columnDetails.foreign_key.delete === true
|
|
426
|
+
) {
|
|
427
|
+
dropforeignkeyconstraint.push(keys.CONSTRAINT_NAME);
|
|
428
|
+
unmatchedforeignkey.push(keys.COLUMN_NAME);
|
|
429
|
+
}
|
|
430
|
+
} else {
|
|
431
|
+
dropforeignkeyconstraint.push(keys.CONSTRAINT_NAME);
|
|
432
|
+
unmatchedforeignkey.push(keys.COLUMN_NAME);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
//ALTER TABLE table_name DROP FOREIGN KEY foreign_key_name;
|
|
440
|
+
//foreign keys query create operations
|
|
441
|
+
let addForeignkeyquery = [];
|
|
442
|
+
let dropForeignkeyquery = [];
|
|
443
|
+
let findnewfk = isIncludefk;
|
|
444
|
+
|
|
445
|
+
if (existingForeignKey.length > 0) {
|
|
446
|
+
for (const existingforeigncolumn of existingForeignKey) {
|
|
447
|
+
if (
|
|
448
|
+
isModifyIncludefk.includes(existingforeigncolumn.COLUMN_NAME) ||
|
|
449
|
+
!isIncludefk.includes(existingforeigncolumn.COLUMN_NAME)
|
|
450
|
+
) {
|
|
451
|
+
if (
|
|
452
|
+
!dropforeignkeyconstraint.includes(
|
|
453
|
+
existingforeigncolumn.CONSTRAINT_NAME
|
|
454
|
+
)
|
|
455
|
+
) {
|
|
456
|
+
dropforeignkeyconstraint.push(
|
|
457
|
+
existingforeigncolumn.CONSTRAINT_NAME
|
|
458
|
+
);
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
if (findnewfk.includes(existingforeigncolumn.COLUMN_NAME)) {
|
|
462
|
+
findnewfk = removefromarray(
|
|
463
|
+
findnewfk,
|
|
464
|
+
existingforeigncolumn.COLUMN_NAME
|
|
465
|
+
);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
//what is not modified those are not needed to delete or added newly. but what is not in existing is new to be added. if any need to drop then drop
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
//create drop foreign key queries
|
|
472
|
+
if (dropforeignkeyconstraint.length > 0) {
|
|
473
|
+
for (const dropkeys of dropforeignkeyconstraint) {
|
|
474
|
+
dropForeignkeyquery.push(
|
|
475
|
+
`ALTER TABLE ${tableName} DROP FOREIGN KEY ${dropkeys}`
|
|
476
|
+
);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
//create add foreign key queries
|
|
480
|
+
let ibfk = 1
|
|
481
|
+
if (findnewfk.length > 0) {
|
|
482
|
+
for (const newfk of findnewfk) {
|
|
483
|
+
let newstatement = `ALTER TABLE ${tableName} ADD CONSTRAINT ${tableName}_ibfk${ibfk} FOREIGN KEY (${newfk}) REFERENCES ${schema[newfk].foreign_key.REFERENCES.table}(${schema[newfk].foreign_key.REFERENCES.column})`;
|
|
484
|
+
ibfk += 1;
|
|
485
|
+
if (schema[newfk].foreign_key.delete) {
|
|
486
|
+
newstatement += ` ON DELETE CASCADE`;
|
|
487
|
+
} else if (schema[newfk].foreign_key.delete === null) {
|
|
488
|
+
newstatement += ` ON DELETE SET NULL`;
|
|
489
|
+
}
|
|
490
|
+
if (schema[newfk].foreign_key.on_update === null) {
|
|
491
|
+
newstatement += ` ON UPDATE SET NULL`;
|
|
492
|
+
}
|
|
493
|
+
addForeignkeyquery.push(newstatement);
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
if (isModifyIncludefk.length > 0) {
|
|
497
|
+
for (const newfk of isModifyIncludefk) {
|
|
498
|
+
let newstatement = `ALTER TABLE ${tableName} ADD CONSTRAINT ${tableName}_ibfk${ibfk} FOREIGN KEY (${newfk}) REFERENCES ${schema[newfk].foreign_key.REFERENCES.table}(${schema[newfk].foreign_key.REFERENCES.column})`;
|
|
499
|
+
ibfk += 1;
|
|
500
|
+
if (schema[newfk].foreign_key.delete) {
|
|
501
|
+
newstatement += ` ON DELETE CASCADE`;
|
|
502
|
+
} else if (schema[newfk].foreign_key.delete === null) {
|
|
503
|
+
newstatement += ` ON DELETE SET NULL`;
|
|
504
|
+
}
|
|
505
|
+
if (schema[newfk].foreign_key.on_update === null) {
|
|
506
|
+
newstatement += ` ON UPDATE SET NULL`;
|
|
507
|
+
}
|
|
508
|
+
addForeignkeyquery.push(newstatement);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
if (unmatchedforeignkey.length > 0) {
|
|
512
|
+
for (const newfk of unmatchedforeignkey) {
|
|
513
|
+
let newstatement = `ALTER TABLE ${tableName} ADD CONSTRAINT ${tableName}_ibfk${ibfk} FOREIGN KEY (${newfk}) REFERENCES ${schema[newfk].foreign_key.REFERENCES.table}(${schema[newfk].foreign_key.REFERENCES.column})`;
|
|
514
|
+
ibfk += 1;
|
|
515
|
+
if (schema[newfk].foreign_key.delete) {
|
|
516
|
+
newstatement += ` ON DELETE CASCADE`;
|
|
517
|
+
} else if (schema[newfk].foreign_key.delete === null) {
|
|
518
|
+
newstatement += ` ON DELETE SET NULL`;
|
|
519
|
+
}
|
|
520
|
+
if (schema[newfk].foreign_key.on_update === null) {
|
|
521
|
+
newstatement += ` ON UPDATE SET NULL`;
|
|
522
|
+
}
|
|
523
|
+
addForeignkeyquery.push(newstatement);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
if (dropColumn) {
|
|
528
|
+
for (const col of existingColumns) {
|
|
529
|
+
if (!schema[col.column_name]) {
|
|
530
|
+
alterStatements.push(
|
|
531
|
+
`ALTER TABLE ${tableName} DROP COLUMN ${col.column_name}`
|
|
532
|
+
);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
let newalterStatements = [];
|
|
537
|
+
newalterStatements.push(dropForeignkeyquery);
|
|
538
|
+
newalterStatements.push(alterStatements);
|
|
539
|
+
newalterStatements.push(addForeignkeyquery);
|
|
540
|
+
alterStatements = newalterStatements;
|
|
541
|
+
if (alterStatements.length === 0) {
|
|
542
|
+
console.log(`No changes needed for table "${tableName}".`);
|
|
543
|
+
return [];
|
|
544
|
+
}
|
|
545
|
+
return alterStatements.flat();
|
|
546
|
+
} catch (err) {
|
|
547
|
+
console.error(
|
|
548
|
+
`Error generating alter table queries for ${tableName}:`,
|
|
549
|
+
err.message
|
|
550
|
+
);
|
|
551
|
+
throw err;
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
async function createTables(tableQueries) {
|
|
556
|
+
console.log("Creating or Modifiying Table");
|
|
557
|
+
for (const query of tableQueries) {
|
|
558
|
+
console.log("Operating query is:");
|
|
559
|
+
let console_query = [];
|
|
560
|
+
console_query.push(query);
|
|
561
|
+
console.log(console_query);
|
|
562
|
+
console.log("...");
|
|
563
|
+
const result = await createOrModifyTable(query);
|
|
564
|
+
if (!result.success) {
|
|
565
|
+
console.error(
|
|
566
|
+
"Error creating table:",
|
|
567
|
+
result.message,
|
|
568
|
+
"queryText: ",
|
|
569
|
+
result.querytext
|
|
570
|
+
);
|
|
571
|
+
throw new Error("Error creating table");
|
|
572
|
+
} else {
|
|
573
|
+
console.log(result.message);
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
async function tableOperation(createTable, alterTable, dropTable, dropColumn) {
|
|
579
|
+
try {
|
|
580
|
+
let isTableCreated = false;
|
|
581
|
+
let newJsonStoreFilePath = "";
|
|
582
|
+
if ((await getLastSavedFile(matchDatabase)) == null) {
|
|
583
|
+
newJsonStoreFilePath = matchDatabase + path.join(__dirname, "/file.json");
|
|
584
|
+
} else {
|
|
585
|
+
newJsonStoreFilePath =
|
|
586
|
+
matchDatabase + "/" + (await getLastSavedFile(matchDatabase));
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
const compareTable = await compareJsonFiles(
|
|
590
|
+
jsonClientfilePath,
|
|
591
|
+
newJsonStoreFilePath
|
|
592
|
+
);
|
|
593
|
+
if (!compareTable) {
|
|
594
|
+
console.log(
|
|
595
|
+
"The JSON files are different. Updating the database and the store file..."
|
|
596
|
+
);
|
|
597
|
+
const jsonData = await readJsonFile(jsonClientfilePath);
|
|
598
|
+
const objectTableNames = Object.keys(jsonData.tables);
|
|
599
|
+
const dbTableNames = await getTableNames();
|
|
600
|
+
|
|
601
|
+
//Creating and altering table
|
|
602
|
+
if (createTable || alterTable) {
|
|
603
|
+
let queryList = [];
|
|
604
|
+
//Lets generate the query
|
|
605
|
+
for (const ObjTable of objectTableNames) {
|
|
606
|
+
try {
|
|
607
|
+
let generatedQuery;
|
|
608
|
+
// Check if the table exists in the database table names
|
|
609
|
+
if (dbTableNames.includes(ObjTable.toLowerCase()) && alterTable) {
|
|
610
|
+
console.log("db table names includes", ObjTable);
|
|
611
|
+
// Generate alter table query if it exists
|
|
612
|
+
generatedQuery = await generateAlterTableQuery(
|
|
613
|
+
ObjTable.toLowerCase(),
|
|
614
|
+
jsonData.tables[ObjTable],
|
|
615
|
+
dropColumn
|
|
616
|
+
);
|
|
617
|
+
console.log(
|
|
618
|
+
`Query generated for the existing table: ${ObjTable}`
|
|
619
|
+
);
|
|
620
|
+
console.log("Generated Query: ", generatedQuery);
|
|
621
|
+
} else if (createTable) {
|
|
622
|
+
// Generate create table query if it does not exist
|
|
623
|
+
generatedQuery = await generateCreateTableQuery(
|
|
624
|
+
ObjTable.toLowerCase(),
|
|
625
|
+
jsonData.tables[ObjTable]
|
|
626
|
+
);
|
|
627
|
+
console.log("db table names do not includes", ObjTable);
|
|
628
|
+
console.log(`Query generated for the new table: ${ObjTable}`);
|
|
629
|
+
console.log(generatedQuery);
|
|
630
|
+
}
|
|
631
|
+
// Push the generated query to the list
|
|
632
|
+
queryList.push(generatedQuery);
|
|
633
|
+
} catch (err) {
|
|
634
|
+
console.error(
|
|
635
|
+
`Error generating query for table ${ObjTable}: \n${err.message}`
|
|
636
|
+
);
|
|
637
|
+
return;
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
//lets create and modify tables
|
|
641
|
+
try {
|
|
642
|
+
await createTables(queryList.flat());
|
|
643
|
+
let query_length = 0;
|
|
644
|
+
for (const query_text of queryList) {
|
|
645
|
+
if (query_text.length > 0) {
|
|
646
|
+
query_length += 1;
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
if (query_length > 0) {
|
|
650
|
+
console.log(
|
|
651
|
+
"All tables created or modified or both done successfully."
|
|
652
|
+
);
|
|
653
|
+
} else {
|
|
654
|
+
console.log("All tables are good to go. No modifications needed.");
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
isTableCreated = true;
|
|
658
|
+
} catch (err) {
|
|
659
|
+
console.error("Error in creating tables:", err.message);
|
|
660
|
+
return;
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
//Dropping all the tables that are not on the object
|
|
665
|
+
if (dropTable) {
|
|
666
|
+
try {
|
|
667
|
+
let dropTableList = [];
|
|
668
|
+
for (const table of dbTableNames) {
|
|
669
|
+
if (objectTableNames.includes(table)) {
|
|
670
|
+
// Check if table exists in the list
|
|
671
|
+
console.log(`Table name "${table}" exists in objectTableNames`);
|
|
672
|
+
} else {
|
|
673
|
+
dropTableList.push(table); // Add table to the drop list
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
console.log("Drop Table list is: ", dropTableList);
|
|
678
|
+
|
|
679
|
+
// Call the dropTables function
|
|
680
|
+
if (dropTableList.length > 0) {
|
|
681
|
+
await dropTables(dropTableList);
|
|
682
|
+
console.log("All of these tables are dropped: ", dropTableList);
|
|
683
|
+
} else {
|
|
684
|
+
console.log("No tables to drop.");
|
|
685
|
+
}
|
|
686
|
+
} catch (err) {
|
|
687
|
+
console.error("Error processing dropTable operation:", err.message);
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
//Creating file with objecet ware used to create tables
|
|
691
|
+
if (isTableCreated) {
|
|
692
|
+
try {
|
|
693
|
+
matchDatabase =
|
|
694
|
+
matchDatabase +
|
|
695
|
+
"/" +
|
|
696
|
+
getDateTime("_").date +
|
|
697
|
+
"__" +
|
|
698
|
+
getDateTime("_").time +
|
|
699
|
+
"_storeTableJSON.json";
|
|
700
|
+
const json_Data = await readJsonFile(jsonClientfilePath);
|
|
701
|
+
await writeJsonFile(matchDatabase, json_Data);
|
|
702
|
+
console.log("Table JSON file has been created at: ", matchDatabase);
|
|
703
|
+
console.log("Table operations completed successfully");
|
|
704
|
+
} catch (err) {
|
|
705
|
+
console.error("Cannot Update store file", err.message);
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
} else {
|
|
709
|
+
console.log("\x1b[1m\x1b[32mThe JSON files are the same. No update needed. We are good to go...\x1b[0m");
|
|
710
|
+
}
|
|
711
|
+
} catch (error) {
|
|
712
|
+
console.error("An error occurred in tableOperation:", error.message);
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
//tableOperation(true, true, true, true);
|
|
716
|
+
module.exports = { tableOperation };
|
|
717
|
+
//tableOperation(createTable, alterTable, dropTable, dropColumn);
|