dbtasker 1.0.0 → 2.1.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/columnop.js ADDED
@@ -0,0 +1,748 @@
1
+ const fncs = require("./function");
2
+ const cstyler = require("cstyler");
3
+ const validateion = require("./validation");
4
+
5
+ const mysqlTypeMetadata = validateion.mysqlTypeMetadata;
6
+
7
+
8
+ function alterColumnQuery(columndata, columnName, tableName) {
9
+ try {
10
+ if (!columndata.columntype) {
11
+ throw new Error("columntype is required for MODIFY COLUMN");
12
+ }
13
+
14
+ let queryText = "";
15
+ queryText += `ALTER TABLE \`${tableName}\` MODIFY COLUMN \`${columnName}\``;
16
+
17
+ queryText += ` ${columndata.columntype}`;
18
+
19
+ if (columndata.hasOwnProperty("length_value")) {
20
+ const lengthval = columndata.length_value;
21
+
22
+ if (typeof lengthval === "number") {
23
+ queryText += `(${lengthval})`;
24
+ } else if (
25
+ Array.isArray(lengthval) &&
26
+ lengthval.length === 2 &&
27
+ lengthval.every(v => typeof v === "number")
28
+ ) {
29
+ queryText += `(${lengthval[0]},${lengthval[1]})`;
30
+ } else if (
31
+ Array.isArray(lengthval) &&
32
+ lengthval.every(v => typeof v === "string")
33
+ ) {
34
+ const escaped = lengthval.map(v => `'${v.replace(/'/g, "''")}'`);
35
+ queryText += `(${escaped.join(",")})`;
36
+ }
37
+ }
38
+ queryText += " ";
39
+ if (columndata.unsigned === true) queryText += "UNSIGNED ";
40
+ if (columndata.zerofill === true) queryText += "ZEROFILL ";
41
+
42
+
43
+ if (columndata.hasOwnProperty("defaults")) {
44
+ const d = columndata.defaults;
45
+ if (d === null) queryText += "DEFAULT NULL ";
46
+ else if (typeof d === "number") queryText += `DEFAULT ${d} `;
47
+ else if (/^CURRENT_TIMESTAMP$/i.test(d)) queryText += `DEFAULT ${d} `;
48
+ else queryText += `DEFAULT '${d.replace(/'/g, "''")}' `;
49
+ }
50
+
51
+ if (columndata.autoincrement === true) {
52
+ queryText += "AUTO_INCREMENT ";
53
+ }
54
+
55
+ if (columndata._charset_) queryText += `CHARACTER SET ${columndata._charset_} `;
56
+ if (columndata._collate_) queryText += `COLLATE ${columndata._collate_} `;
57
+
58
+ if (columndata.hasOwnProperty("nulls")) {
59
+ queryText += columndata.nulls ? "NULL " : "NOT NULL ";
60
+ }
61
+ if (columndata.comment) {
62
+ queryText += `COMMENT '${columndata.comment.replace(/'/g, "''")}' `;
63
+ }
64
+
65
+ return queryText.trim();
66
+ } catch (err) {
67
+ console.error(err.message);
68
+ return null;
69
+ }
70
+ }
71
+ function addColumnQuery(columndata, columnName, tableName) {
72
+ try {
73
+ if (!columndata.columntype) {
74
+ throw new Error("columntype is required to add a column. Table:", tableName, "Column name:", columnName);
75
+ }
76
+
77
+ let queryText = "";
78
+ queryText += `ALTER TABLE \`${tableName}\` ADD COLUMN \`${columnName}\``;
79
+
80
+ // column type
81
+ queryText += ` ${columndata.columntype}`;
82
+
83
+ // length / enum / set
84
+ if (columndata.hasOwnProperty("length_value")) {
85
+ const lengthval = columndata.length_value;
86
+
87
+ if (typeof lengthval === "number") {
88
+ queryText += `(${lengthval})`;
89
+ } else if (
90
+ Array.isArray(lengthval) &&
91
+ lengthval.length === 2 &&
92
+ lengthval.every(v => typeof v === "number")
93
+ ) {
94
+ queryText += `(${lengthval[0]},${lengthval[1]})`;
95
+ } else if (
96
+ Array.isArray(lengthval) &&
97
+ lengthval.every(v => typeof v === "string")
98
+ ) {
99
+ const escaped = lengthval.map(v => `'${v.replace(/'/g, "''")}'`);
100
+ queryText += `(${escaped.join(",")})`;
101
+ }
102
+ }
103
+ queryText += " ";
104
+ if (columndata.unsigned === true) queryText += "UNSIGNED ";
105
+ if (columndata.zerofill === true) queryText += "ZEROFILL ";
106
+
107
+
108
+ if (columndata.hasOwnProperty("defaults")) {
109
+ const d = columndata.defaults;
110
+ if (d === null) queryText += "DEFAULT NULL ";
111
+ else if (typeof d === "number") queryText += `DEFAULT ${d} `;
112
+ else if (/^CURRENT_TIMESTAMP$/i.test(d)) queryText += `DEFAULT ${d} `;
113
+ else queryText += `DEFAULT '${d.replace(/'/g, "''")}' `;
114
+ }
115
+
116
+ if (columndata.autoincrement === true) {
117
+ queryText += "AUTO_INCREMENT ";
118
+ }
119
+
120
+ if (columndata._charset_) queryText += `CHARACTER SET ${columndata._charset_} `;
121
+ if (columndata._collate_) queryText += `COLLATE ${columndata._collate_} `;
122
+
123
+ if (columndata.hasOwnProperty("nulls")) {
124
+ queryText += columndata.nulls ? "NULL " : "NOT NULL ";
125
+ }
126
+ if (columndata.comment) {
127
+ queryText += `COMMENT '${columndata.comment.replace(/'/g, "''")}' `;
128
+ }
129
+
130
+ return queryText.trim();
131
+ } catch (err) {
132
+ console.error(err.message);
133
+ return null;
134
+ }
135
+ }
136
+ function addForeignKeyWithIndexQuery(tableName, columnName, refTable, refColumn, options = {}) {
137
+ const {
138
+ onDelete = "RESTRICT",
139
+ onUpdate = "RESTRICT"
140
+ } = options;
141
+
142
+ const indexName = `idx_${tableName}_${columnName}`;
143
+ const fkName = `fk_${tableName}_${refTable}_${columnName}`;
144
+
145
+ const indexQuery = `
146
+ ALTER TABLE \`${tableName}\`
147
+ ADD INDEX \`${indexName}\` (\`${columnName}\`)
148
+ `.trim();
149
+
150
+ const foreignKeyQuery = `
151
+ ALTER TABLE \`${tableName}\`
152
+ ADD CONSTRAINT \`${fkName}\`
153
+ FOREIGN KEY (\`${columnName}\`)
154
+ REFERENCES \`${refTable}\` (\`${refColumn}\`)
155
+ ON DELETE ${onDelete}
156
+ ON UPDATE ${onUpdate}
157
+ `.trim();
158
+
159
+ return {
160
+ indexQuery,
161
+ foreignKeyQuery
162
+ };
163
+ }
164
+ function isColumnDataSame(columnData, columndetails, fkdetails, tableName, columnName) {
165
+ // 1. Column type
166
+ if (columnData.columntype !== columndetails.columntype) {
167
+ console.log(cstyler.purple("Table:"), cstyler.blue(tableName), cstyler.purple("Column:"), cstyler.blue(columnName));
168
+ console.log(cstyler.red("Column type do not match"));
169
+ return false;
170
+ }
171
+
172
+ // 2. Length / precision / enum-set values
173
+ if (columnData.length_value !== undefined) {
174
+ const a = columnData.length_value;
175
+ const b = columndetails.length_value;
176
+
177
+ // ENUM / SET → array of strings
178
+ if (['ENUM', 'SET'].includes(columnData.columntype)) {
179
+ if (!Array.isArray(a) || !Array.isArray(b)) {
180
+ console.log(cstyler.purple("Table:"), cstyler.blue(tableName), cstyler.purple("Column:"), cstyler.blue(columnName));
181
+ console.log(cstyler.red("ENUM or SET values must be an array"));
182
+ return false;
183
+ }
184
+ if (a.length !== b.length) {
185
+ console.log(cstyler.purple("Table:"), cstyler.blue(tableName), cstyler.purple("Column:"), cstyler.blue(columnName));
186
+ console.log(cstyler.red("ENUM or SET - value length are not same"), cstyler.hex("#00b7ff")("Given data:"), cstyler.hex("#ffffff")(a), cstyler.hex("#00b7ff")("Server data:"), cstyler.hex("#ffffff")(b),);
187
+ return false;
188
+ }
189
+
190
+ for (let i = 0; i < a.length; i++) {
191
+ if (!a.includes(b[i])) {
192
+ console.log(cstyler.purple("Table:"), cstyler.blue(tableName), cstyler.purple("Column:"), cstyler.blue(columnName));
193
+ console.log(cstyler.red("ENUM or SET - Server and given value are not same"), cstyler.hex("#00b7ff")("Given data:"), cstyler.hex("#ffffff")(a), cstyler.hex("#00b7ff")("Server data:"), cstyler.hex("#ffffff")(b),);
194
+ return false;
195
+
196
+ }
197
+ }
198
+ }
199
+ // DECIMAL(p,s) → [number, number]
200
+ else if (Array.isArray(a)) {
201
+ if (!Array.isArray(b) || a.length !== b.length) {
202
+ console.log(cstyler.purple("Table:"), cstyler.blue(tableName), cstyler.purple("Column:"), cstyler.blue(columnName));
203
+ console.log(cstyler.red("Decimal length value are not same"), cstyler.hex("#00b7ff")("Given data:"), cstyler.hex("#ffffff")(a), cstyler.hex("#00b7ff")("Server data:"), cstyler.hex("#ffffff")(b),);
204
+ return false;
205
+ }
206
+ if (a[0] !== b[0] || a[1] !== b[1]) {
207
+ console.log(cstyler.purple("Table:"), cstyler.blue(tableName), cstyler.purple("Column:"), cstyler.blue(columnName));
208
+ console.log(cstyler.red("Decimal length value are not same"), cstyler.hex("#00b7ff")("Given data:"), cstyler.hex("#ffffff")(a), cstyler.hex("#00b7ff")("Server data:"), cstyler.hex("#ffffff")(b),);
209
+ return false;
210
+ }
211
+ }
212
+ // INT, VARCHAR, CHAR, etc. → number
213
+ else {
214
+ if (a !== b && a !== undefined) {
215
+ console.log(cstyler.purple("Table:"), cstyler.blue(tableName), cstyler.purple("Column:"), cstyler.blue(columnName));
216
+ console.log(cstyler.red("Length value are not same"), cstyler.hex("#00b7ff")("Given data:"), cstyler.hex("#ffffff")(a), cstyler.hex("#00b7ff")("Server data:"), cstyler.hex("#ffffff")(b),);
217
+ return false;
218
+ }
219
+ }
220
+ }
221
+
222
+ // 3. UNSIGNED
223
+ if (typeof columnData.unsigned === "boolean" &&
224
+ columnData.unsigned !== columndetails.unsigned) {
225
+ console.log(cstyler.purple("Table:"), cstyler.blue(tableName), cstyler.purple("Column:"), cstyler.blue(columnName));
226
+ console.log(cstyler.red("Unsigned have changed"), cstyler.hex("#00b7ff")("Given data:"), cstyler.hex("#ffffff")(columnData.unsigned), cstyler.hex("#00b7ff")("Server data:"), cstyler.hex("#ffffff")(columndetails.unsigned),);
227
+ return false;
228
+ }
229
+
230
+ // 4. ZEROFILL
231
+ if (typeof columnData.zerofill === "boolean" &&
232
+ columnData.zerofill !== columndetails.zerofill) {
233
+ console.log(cstyler.purple("Table:"), cstyler.blue(tableName), cstyler.purple("Column:"), cstyler.blue(columnName));
234
+ console.log(cstyler.red("Zerofill have changed"), cstyler.hex("#00b7ff")("Given data:"), cstyler.hex("#ffffff")(columnData.zerofill), cstyler.hex("#00b7ff")("Server data:"), cstyler.hex("#ffffff")(columndetails.zerofill),);
235
+ return false;
236
+ }
237
+
238
+ // 5. NULL / NOT NULL
239
+ if (typeof columnData.nulls === "boolean" &&
240
+ columnData.nulls !== columndetails.nulls) {
241
+ console.log(cstyler.purple("Table:"), cstyler.blue(tableName), cstyler.purple("Column:"), cstyler.blue(columnName));
242
+ console.log(cstyler.red("Null have changed"), cstyler.hex("#00b7ff")("Given data:"), cstyler.hex("#ffffff")(columnData.nulls), cstyler.hex("#00b7ff")("Server data:"), cstyler.hex("#ffffff")(columndetails.nulls),);
243
+ return false;
244
+ }
245
+
246
+ // 6. DEFAULT
247
+ const defA = columnData.defaults ?? null;
248
+ const defB = columndetails.defaults ?? null;
249
+ if (defA != defB) {
250
+ console.log(cstyler.purple("Table:"), cstyler.blue(tableName), cstyler.purple("Column:"), cstyler.blue(columnName));
251
+ console.log(cstyler.red("Default need some changes"), cstyler.hex("#00b7ff")("Given data:"), cstyler.hex("#ffffff")(columnData.defaults), cstyler.hex("#00b7ff")("Server data:"), cstyler.hex("#ffffff")(columndetails.defaults),);
252
+ return false;
253
+ }
254
+
255
+ // 7. INDEX (PRIMARY / UNIQUE / "")
256
+ const idxA = columnData.index ?? "";
257
+ const idxB = columndetails.index ?? "";
258
+
259
+ const realfk =
260
+ fncs.isJsonObject(fkdetails) &&
261
+ idxB === "KEY" &&
262
+ (idxA === "" || idxA === undefined);
263
+
264
+ if (idxA !== idxB && !realfk) {
265
+ console.log(cstyler.purple("Table:"), cstyler.blue(tableName), cstyler.purple("Column:"), cstyler.blue(columnName));
266
+ console.log(cstyler.red("Index are not same"), cstyler.hex("#00b7ff")("Given data:"), cstyler.hex("#ffffff")(columnData.index), cstyler.hex("#00b7ff")("Server data:"), cstyler.hex("#ffffff")(columndetails.index),);
267
+ return false;
268
+ }
269
+
270
+ // 8. AUTO_INCREMENT
271
+ if ((columnData.autoincrement !== undefined && columnData.autoincrement !== columndetails.autoincrement) || (columnData.autoincrement === undefined && columndetails.autoincrement === true)) {
272
+ console.log(cstyler.purple("Table:"), cstyler.blue(tableName), cstyler.purple("Column:"), cstyler.blue(columnName));
273
+ console.log(cstyler.red("Autoincrement have some changes"), cstyler.hex("#00b7ff")("Given data:"), cstyler.hex("#ffffff")(columnData.autoincrement), cstyler.hex("#00b7ff")("Server data:"), cstyler.hex("#ffffff")(columndetails.autoincrement),);
274
+ return false;
275
+ }
276
+
277
+ // 9. COMMENT
278
+ const comA = columnData.comment ?? "";
279
+ const comB = columndetails.comment ?? "";
280
+ if (comA !== comB) {
281
+ console.log(cstyler.purple("Table:"), cstyler.blue(tableName), cstyler.purple("Column:"), cstyler.blue(columnName));
282
+ console.log(cstyler.red("Comment have some changes"), cstyler.hex("#00b7ff")("Given data:"), cstyler.hex("#ffffff")(columnData.comment), cstyler.hex("#00b7ff")("Server data:"), cstyler.hex("#ffffff")(columndetails.comment),);
283
+ return false;
284
+ }
285
+
286
+ // 10. CHARACTER SET
287
+ if (columnData._charset_ !== undefined &&
288
+ columnData._charset_ !== columndetails._charset_) {
289
+ console.log(cstyler.purple("Table:"), cstyler.blue(tableName), cstyler.purple("Column:"), cstyler.blue(columnName));
290
+ console.log(cstyler.red("Character set have some changes"), cstyler.hex("#00b7ff")("Given data:"), cstyler.hex("#ffffff")(columnData._charset_), cstyler.hex("#00b7ff")("Server data:"), cstyler.hex("#ffffff")(columndetails._charset_),);
291
+ return false;
292
+ }
293
+
294
+ // 11. COLLATION
295
+ if (columnData._collate_ !== undefined &&
296
+ columnData._collate_ !== columndetails._collate_) {
297
+ console.log(cstyler.purple("Table:"), cstyler.blue(tableName), cstyler.purple("Column:"), cstyler.blue(columnName));
298
+ console.log(cstyler.red("Collate have some changes"), cstyler.hex("#00b7ff")("Given data:"), cstyler.hex("#ffffff")(columnData._collate_), cstyler.hex("#00b7ff")("Server data:"), cstyler.hex("#ffffff")(columndetails._collate_),);
299
+ return false;
300
+ }
301
+
302
+ return true;
303
+ }
304
+
305
+ async function alterTableQuery(config, tabledata, tableName, dbName, dropColumn = false) {
306
+ try {
307
+ let queries = [];
308
+ let idxkey = [];
309
+ let foreignkeys = [];
310
+ let leftfk = [];
311
+ console.log(cstyler.yellow("Lets check if any changes needed on"), cstyler.purple("Database:"), cstyler.blue(dbName), cstyler.purple("Table:"), cstyler.blue(tableName));
312
+ for (const columnName of Object.keys(tabledata)) {
313
+ const columnData = tabledata[columnName];
314
+ const fkData = columnData.foreign_key;
315
+ const columndetails = await fncs.getColumnDetails(config, dbName, tableName, columnName);
316
+ const fkdetails = await fncs.getForeignKeyDetails(config, dbName, tableName, columnName);
317
+ const constraintexist = await fncs.columnHasKey(config, dbName, tableName, columnName);
318
+ if (fkdetails === null) {
319
+ console.error("Server error: Having problem getting foreignkey details of ", cstyler.purple("Database: "), cstyler.blue(dbName), cstyler.purple(" Table: "), cstyler.blue(tableName), cstyler.purple(" Column Name: "), cstyler.blue(columnName));
320
+ return null;
321
+ }
322
+ if (constraintexist === null) {
323
+ console.error("Server error: Having problem removing foreignkey constraint from ", cstyler.purple("Database: "), cstyler.blue(dbName), cstyler.purple(" Table: "), cstyler.blue(tableName), cstyler.purple(" Column Name: "), cstyler.blue(columnName));
324
+ return null;
325
+ }
326
+ if (fncs.isJsonObject(columndetails)) {
327
+ // alter column query
328
+ if (!isColumnDataSame(columnData, columndetails, fkdetails, tableName, columnName)) {
329
+ if (fkdetails) {
330
+ const removefk = await fncs.removeForeignKeyFromColumn(config, dbName, tableName, columnName);
331
+ if (removefk === null) {
332
+ console.error("Having problem removing foreignkey from ", cstyler.purple("Database: "), cstyler.blue(dbName), cstyler.purple(" Table: "), cstyler.blue(tableName), cstyler.purple(" Column Name: "), cstyler.blue(columnName));
333
+ return null;
334
+ }
335
+ }
336
+ if (fkdetails === false && constraintexist.hasKey === true) {
337
+ const delkey = await fncs.removeForeignKeyConstraintFromColumn(config, dbName, tableName, columnName);
338
+ if (delkey === null) {
339
+ console.error("Having problem deleting foreign key constraint from column -", cstyler.purple("Database: "), cstyler.blue(dbName), cstyler.purple(" Table: "), cstyler.blue(tableName), cstyler.purple(" Column Name: "), cstyler.blue(columnName));
340
+ return null;
341
+ }
342
+ }
343
+ const alterquery = alterColumnQuery(columnData, columnName, tableName);
344
+ if (alterquery === null) {
345
+ // Not that important
346
+ console.error("There was an issue when creating alter column query for", cstyler.purple("Database:"), cstyler.blue(dbName), cstyler.purple("Table:"), cstyler.blue(tableName), cstyler.purple("Column:"), cstyler.blue(columnName));
347
+ return null;
348
+ }
349
+ queries.push(alterquery);
350
+ // lets work on foreign key
351
+ if (columnData.hasOwnProperty("foreign_key")) {
352
+ // lets check foreign key table column exist
353
+ const fktcexist = await fncs.columnExists(config, dbName, fkData.table, fkData.column);
354
+ if (fktcexist === true) {
355
+ const fkquery = addForeignKeyWithIndexQuery(tableName, columnName, fkData.table, fkData.column, { onDelete: fkData.deleteOption, onUpdate: fkData.updateOption });
356
+ // lets add foreign key quries
357
+ idxkey.push(fkquery.indexQuery);
358
+ foreignkeys.push(fkquery.foreignKeyQuery);
359
+ } else if (fktcexist === false) {
360
+ leftfk[columnName] = fkData;
361
+ } else {
362
+ console.error("Having problem checking foreignkey table column exist or not from ", cstyler.purple("Database: "), cstyler.blue(dbName), cstyler.purple(" Table: "), cstyler.blue(tableName), cstyler.purple(" Column Name: "), cstyler.blue(columnName));
363
+ return null;
364
+ }
365
+ }
366
+ } else {
367
+ if (columnData.hasOwnProperty("foreign_key")) {
368
+ // is foreignkey same0
369
+ if (fncs.isJsonObject(fkdetails)) {
370
+ let issame = true;
371
+ // lets check if foreign keys are same or not
372
+ if (fkData.table !== fkdetails.table) issame = false;
373
+ if (fkData.column !== fkdetails.column) issame = false;
374
+ if (fkData.deleteOption !== fkdetails.deleteOption) issame = false;
375
+ if (fkData.updateOption !== undefined && fkData.updateOption !== fkdetails.updateOption) issame = false;
376
+ if (issame === false) {
377
+ console.log(cstyler.red("Foreign key server and given value are not same"), cstyler.hex("#00b7ff")("Given data:"), cstyler.hex("#ffffff")(fkData), cstyler.hex("#00b7ff")("Server data:"), cstyler.hex("#ffffff")(fkdetails),);
378
+ const dfk = await fncs.removeForeignKeyFromColumn(config, dbName, tableName, columnName);
379
+ if (dfk === true || dfk === false) {
380
+ const fkquery = addForeignKeyWithIndexQuery(tableName, columnName, fkData.table, fkData.column, { onDelete: fkData.deleteOption, onUpdate: fkData.updateOption });
381
+ // lets add foreign key quries
382
+ idxkey.push(fkquery.indexQuery);
383
+ foreignkeys.push(fkquery.foreignKeyQuery);
384
+ } else {
385
+ console.error("Having problem deleting foreign key from column. Please check your database connection.");
386
+ }
387
+ } else {
388
+ console.log(cstyler.bold.green("No changes needed on "), cstyler.purple("Database: "), cstyler.blue(dbName), cstyler.purple(" Table: "), cstyler.blue(tableName));
389
+ }
390
+ } else if (fkdetails === false) {
391
+ const fktcexist = await fncs.columnExists(config, dbName, fkData.table, fkData.column);
392
+ if (fktcexist === true) {
393
+ const fkquery = addForeignKeyWithIndexQuery(tableName, columnName, fkData.table, fkData.column, { onDelete: fkData.deleteOption, onUpdate: fkData.updateOption });
394
+ // lets add foreign key quries
395
+ idxkey.push(fkquery.indexQuery);
396
+ foreignkeys.push(fkquery.foreignKeyQuery);
397
+ } else if (fktcexist === false) {
398
+ leftfk[columnName] = fkData;
399
+ } else {
400
+ console.error("Having problem checking foreignkey table column exist or not from ", cstyler.purple("Database: "), cstyler.blue(dbName), cstyler.purple(" Table: "), cstyler.blue(tableName), cstyler.purple(" Column Name: "), cstyler.blue(columnName));
401
+ return null;
402
+ }
403
+ } else {
404
+ console.error("Having problem getting foreignkey details of ", cstyler.purple("Database: "), cstyler.blue(dbName), cstyler.purple(" Table: "), cstyler.blue(tableName), cstyler.purple(" Column Name: "), cstyler.blue(columnName));
405
+ return null;
406
+ }
407
+ } else {
408
+ if (constraintexist || fkdetails) {
409
+ const dfk = await fncs.removeForeignKeyFromColumn(config, dbName, tableName, columnName);
410
+ const delkey = await fncs.removeForeignKeyConstraintFromColumn(config, dbName, tableName, columnName);
411
+ if (dfk === null || delkey === null) {
412
+ console.error("Having problem removing foreignkey from ", cstyler.purple("Database: "), cstyler.blue(dbName), cstyler.purple(" Table: "), cstyler.blue(tableName), cstyler.purple(" Column Name: "), cstyler.blue(columnName));
413
+ return null;
414
+ }
415
+ }
416
+ }
417
+ }
418
+ } else if (columndetails === false && !['_charset_', '_collate_'].includes(columnName)) {
419
+ // add column query
420
+ const columnquery = addColumnQuery(columnData, columnName, tableName);
421
+ if (columnquery === null) {
422
+ console.error("There was an issue when creating column query for", cstyler.purple("Database:"), cstyler.blue(dbName), cstyler.purple("Table:"), cstyler.blue(tableName), cstyler.purple("Column:"), cstyler.blue(columnName));
423
+ return null;
424
+ }
425
+ queries.push(columnquery);
426
+ if (columnData.hasOwnProperty("foreign_key")) {
427
+ // lets check if column exist or not
428
+ const colexist = await fncs.columnExists(config, dbName, fkData.table, fkData.column);
429
+ if (colexist === true) {
430
+ const fkquery = addForeignKeyWithIndexQuery(tableName, columnName, fkData.table, fkData.column, { onDelete: fkData.deleteOption, onUpdate: fkData.updateOption });
431
+ // lets add foreign key quries
432
+ idxkey.push(fkquery.indexQuery);
433
+ foreignkeys.push(fkquery.foreignKeyQuery);
434
+ } else if (colexist === false) {
435
+ leftfk[columnName] = fkData;
436
+ } else {
437
+ console.error("Having problem checking foreignkey table column exist or not from ", cstyler.purple("Database: "), cstyler.blue(dbName), cstyler.purple(" Table: "), cstyler.blue(tableName), cstyler.purple(" Column Name: "), cstyler.blue(columnName));
438
+ return null;
439
+ }
440
+ }
441
+ } else if (['_charset_', '_collate_'].includes(columnName)) {
442
+ // used for storing characterset and collate data
443
+ const notacolumn = true;
444
+ } else {
445
+ console.error("Having problem getting column details from the database. Please check your database connection.");
446
+ return null;
447
+ }
448
+ }
449
+ // drop column
450
+ if (dropColumn) {
451
+ const allcols = await fncs.getColumnNames(config, dbName, tableName);
452
+ if (allcols === null) {
453
+ console.error("Having problem getting all the column names of ", tableName, ". Please check database connection.");
454
+ }
455
+ for (const item of allcols) {
456
+ if (!Object.keys(tabledata).includes(item)) {
457
+ // drop column
458
+ const dropcol = await fncs.dropColumn(config, dbName, tableName, item);
459
+ if (dropcol === null) {
460
+ console.error("Haveing problem dropping column. Please check database connection.");
461
+ return null;
462
+ }
463
+ }
464
+ }
465
+ }
466
+ // lets arrange all the query
467
+ for (const item of queries) {
468
+ console.log("Running query: ", cstyler.green(item));
469
+ const runquery = await fncs.runQuery(config, dbName, item);
470
+ if (runquery === null) {
471
+ console.error("Having problem running query. Please check database connection.");
472
+ return null;
473
+ }
474
+ console.log(cstyler.blue("Successful"));
475
+ }
476
+ for (const item of idxkey) {
477
+ console.log("Running query of idxkey: ", cstyler.green(item));
478
+ const runquery = await fncs.runQuery(config, dbName, item);
479
+ if (runquery === null) {
480
+ return null;
481
+ } else if (runquery === false) {
482
+ return null;
483
+ }
484
+ console.log(cstyler.blue("Successful"));
485
+ }
486
+ for (const item of foreignkeys) {
487
+ console.log("Running query of foreignkey: ", cstyler.green(item));
488
+ const runquery = await fncs.runQuery(config, dbName, item);
489
+ if (runquery === null) {
490
+ return null;
491
+ }
492
+ console.log(cstyler.blue("Successful"));
493
+ }
494
+ console.log(cstyler.underline.green("All column checking are done for"), cstyler.purple("Database:"), cstyler.blue(dbName), cstyler.purple("Table:"), cstyler.blue(tableName), "Lets go>>>");
495
+ return leftfk;
496
+ } catch (err) {
497
+ console.error(err.message);
498
+ return null;
499
+ }
500
+ }
501
+ async function createTableQuery(config, tabledata, tableName, dbname) {
502
+ try {
503
+ //let queryText = `CREATE TABLE ${tableName} ( `;
504
+ let quries = [];
505
+ let foreignkeys = {};
506
+ for (const columnName of Object.keys(tabledata)) {
507
+ let queryText = "";
508
+ if (["_engine_", "_charset_", "_collate_"].includes(columnName)) {
509
+ continue;
510
+ }
511
+ queryText += `\`${columnName}\``;
512
+ if (tabledata[columnName].hasOwnProperty("columntype")) {
513
+ queryText += ` ${tabledata[columnName].columntype}`
514
+ }
515
+ if (tabledata[columnName].hasOwnProperty("length_value")) {
516
+ const lengthval = tabledata[columnName].length_value;
517
+
518
+ // INT, VARCHAR, CHAR, BIT, etc.
519
+ if (typeof lengthval === "number") {
520
+ queryText += `(${lengthval})`;
521
+ }
522
+
523
+ // DECIMAL, FLOAT, DOUBLE → [precision, scale]
524
+ else if (
525
+ Array.isArray(lengthval) &&
526
+ lengthval.length === 2 &&
527
+ lengthval.every(v => typeof v === "number")
528
+ ) {
529
+ queryText += `(${lengthval[0]},${lengthval[1]})`;
530
+ }
531
+
532
+ // ENUM / SET → ['a','b','c']
533
+ else if (
534
+ Array.isArray(lengthval) &&
535
+ lengthval.every(v => typeof v === "string")
536
+ ) {
537
+ const escaped = lengthval.map(v => `'${v.replace(/'/g, "''")}'`);
538
+ queryText += `(${escaped.join(",")})`;
539
+ }
540
+ }
541
+ queryText += " ";
542
+ if (tabledata[columnName].hasOwnProperty("unsigned") && tabledata[columnName].unsigned === true) {
543
+ queryText += `UNSIGNED `
544
+ }
545
+ if (tabledata[columnName].zerofill === true) {
546
+ queryText += `ZEROFILL `
547
+ }
548
+ if (tabledata[columnName].autoincrement === true) {
549
+ queryText += `AUTO_INCREMENT `
550
+ }
551
+ if (tabledata[columnName].hasOwnProperty("index")) {
552
+ queryText += `${tabledata[columnName].index} `
553
+ }
554
+ if (tabledata[columnName].hasOwnProperty("_charset_")) {
555
+ queryText += `CHARACTER SET ${tabledata[columnName]._charset_} `
556
+ }
557
+ if (tabledata[columnName].hasOwnProperty("_collate_")) {
558
+ queryText += `COLLATE ${tabledata[columnName]._collate_} `
559
+ }
560
+ if (tabledata[columnName].hasOwnProperty("nulls")) {
561
+ if (tabledata[columnName].nulls === true) {
562
+ queryText += `NULL `
563
+ } else {
564
+ queryText += `NOT NULL `
565
+ }
566
+ }
567
+ if (tabledata[columnName].hasOwnProperty("defaults")) {
568
+ const d = tabledata[columnName].defaults;
569
+ if (d === null) queryText += "DEFAULT NULL ";
570
+ else if (typeof d === "number") queryText += `DEFAULT ${d} `;
571
+ else if (/^CURRENT_TIMESTAMP$/i.test(d)) queryText += `DEFAULT ${d} `;
572
+ else queryText += `DEFAULT '${d.replace(/'/g, "''")}' `;
573
+ }
574
+ if (tabledata[columnName].hasOwnProperty("comment")) {
575
+ queryText += `COMMENT '${tabledata[columnName].comment}' `
576
+ }
577
+ quries.push(queryText);
578
+ // lets sotore foreing keys
579
+ if (tabledata[columnName].hasOwnProperty("foreign_key")) {
580
+ foreignkeys[columnName] = tabledata[columnName].foreign_key;
581
+ }
582
+ }
583
+ // foreign keys
584
+ let fkquery = [];
585
+ let keyidx = [];
586
+ if (Object.keys(foreignkeys).length > 0) {
587
+ for (const fks in foreignkeys) {
588
+ const ifexist = await fncs.columnExists(config, dbname, tabledata[fks].foreign_key.table, tabledata[fks].foreign_key.column);
589
+ if (ifexist === false) {
590
+ console.log(cstyler.red("Foreign key column do not exist."));
591
+ } else if (ifexist === true) {
592
+ let fktext = "";
593
+ fktext +=
594
+ `CONSTRAINT fk_${tableName}_${foreignkeys[fks].table}_${foreignkeys[fks].column} ` +
595
+ `FOREIGN KEY (\`${fks}\`) REFERENCES \`${foreignkeys[fks].table}\`(\`${foreignkeys[fks].column}\`) `;
596
+
597
+ if (foreignkeys[fks].hasOwnProperty("deleteOption")) {
598
+ fktext += `ON DELETE ${foreignkeys[fks].deleteOption} `
599
+ }
600
+ if (foreignkeys[fks].hasOwnProperty("updateOption")) {
601
+ console.log(cstyler.red("has update option"), foreignkeys[fks].updateOption)
602
+ fktext += `ON UPDATE ${foreignkeys[fks].updateOption} `
603
+ }
604
+ fkquery.push(fktext);
605
+ keyidx.push(`KEY \`idx_${tableName}_${fks}\` (\`${fks}\`)`);
606
+ // lets delete used item from the foreign key
607
+ delete foreignkeys[fks];
608
+ } else {
609
+ console.error("Having problem connecting to database.");
610
+ return null;
611
+ }
612
+ }
613
+ }
614
+ let lastqueryText = ``;
615
+ if (tabledata.hasOwnProperty("_engine_")) {
616
+ lastqueryText += `ENGINE=${tabledata._engine_}\n`;
617
+ }
618
+ if (tabledata.hasOwnProperty("_charset_")) {
619
+ lastqueryText += `DEFAULT CHARSET=${tabledata._charset_}\n`;
620
+ }
621
+ if (tabledata.hasOwnProperty("_collate_")) {
622
+ lastqueryText += `COLLATE=${tabledata._collate_}\n`;
623
+ }
624
+ if (tabledata.hasOwnProperty("_comment_")) {
625
+ lastqueryText += `COMMENT=${tabledata._comment_}\n`;
626
+ }
627
+ const fullqueryText = `
628
+ CREATE TABLE IF NOT EXISTS \`${tableName}\` (
629
+ ${[...quries, ...keyidx, ...fkquery].join(",\n ")}
630
+ ) ${lastqueryText};
631
+ `;
632
+ console.log("Running query: ", cstyler.green(fullqueryText));
633
+ const runquery = await fncs.runQuery(config, dbname, fullqueryText);
634
+ if (runquery === null) {
635
+ return null;
636
+ }
637
+ console.log(cstyler.green("Successfully created "), cstyler.purple("Table: "), cstyler.blue(tableName), " on ", cstyler.purple("Database: "), cstyler.blue(dbname));
638
+ return foreignkeys;
639
+ } catch (err) {
640
+ console.error(err.message);
641
+ return null;
642
+ }
643
+ }
644
+ async function columnAddDeleteAlter(allconfig, jsondata, dropcolumn = false, seperator = "_") {
645
+ try {
646
+ console.log(cstyler.bold.blue("Let's initiate table and column operations"));
647
+ if (!fncs.isJsonObject(jsondata)) {
648
+ return false;
649
+ }
650
+ // Lets check config
651
+ let config;
652
+ if (fncs.isValidMySQLConfig(allconfig)) {
653
+ config = { "port": allconfig.port, "host": allconfig.host, "user": allconfig.user, "password": allconfig.password }
654
+ } else {
655
+ console.error(cstyler.bold("Invalid config"));
656
+ return null;
657
+ }
658
+ // get all mysql table engines
659
+ const mysqlEngines = await fncs.getMySQLEngines(config);
660
+ if (!fncs.isJsonObject(mysqlEngines)) {
661
+ console.error(cstyler.red.bold("There is a problem connecting to the database. Please check database info or connection."));
662
+ return null;
663
+ }
664
+ // Lets decleare main variables
665
+ let foreignKeys = {};
666
+ // let work on tables and columns
667
+ for (const dbname of Object.keys(jsondata)) {
668
+ if (fncs.isJsonObject(jsondata[dbname])) {
669
+ if (!foreignKeys.hasOwnProperty(dbname)) foreignKeys[dbname] = {};
670
+ const loopedName = fncs.perseDatabaseNameWithLoop(dbname, seperator);
671
+ if (loopedName === null || loopedName === false) {
672
+ console.error(cstyler.bold("There must be some function error. Please re-install the module and use it.", dbname, loopedName));
673
+ return loopedName;
674
+ }
675
+ const databaseName = loopedName.loopname;
676
+ config.database = databaseName;
677
+ const existingTable = await fncs.getTableNames(config);
678
+ if (!Array.isArray(existingTable)) {
679
+ console.error(cstyler.bold("Having problem getting table name from database: "), cstyler.blue(databaseName));
680
+ return null;
681
+ }
682
+ for (const tableName of Object.keys(jsondata[dbname])) {
683
+ if (!["_charset_", "_collate_"].includes(tableName) || fncs.isJsonObject(jsondata[dbname][tableName])) {
684
+ const loopedTableName = fncs.perseTableNameWithLoop(tableName, seperator);
685
+ if (loopedTableName === null || loopedTableName === false) {
686
+ console.error("There must be some function error. Please re-install the module and use it.");
687
+ return loopedTableName;
688
+ }
689
+ const createdTableName = loopedTableName.loopname;
690
+ const tabledata = jsondata[dbname][tableName];
691
+ if (existingTable.includes(createdTableName)) {
692
+ /**
693
+ * Alter Table
694
+ */
695
+ const altertable = await alterTableQuery(config, tabledata, createdTableName, databaseName, dropcolumn);
696
+ if (altertable === null) return null;
697
+ foreignKeys[dbname][tableName] = altertable;
698
+ } else {
699
+ /**
700
+ * Create table
701
+ */
702
+ const createtable = await createTableQuery(config, tabledata, createdTableName, databaseName);
703
+ if (createtable === null) {
704
+ return null;
705
+ }
706
+ foreignKeys[dbname][tableName] = createtable;
707
+ }
708
+ } else if (["_charset_", "_collate_"].includes(tableName)) {
709
+ // as we already have deal with the database on dbop.js file
710
+ continue;
711
+ } else {
712
+ console.error(cstyler.bold.red("There must be some issue with the module. Please re-install and run the operation."));
713
+ }
714
+
715
+ }
716
+ } else {
717
+ console.error(cstyler.bold.red("There must be some issue with the module. Please re-install and run the operation."));
718
+ }
719
+ }
720
+ // lets work on foreign keys
721
+ let idxes = [];
722
+ let fkses = [];
723
+ for (const dbs of Object.keys(foreignKeys)) {
724
+ config.database = fncs.perseDatabaseNameWithLoop(dbs).loopname;
725
+ for (const tables of Object.keys(foreignKeys[dbs])) {
726
+ const tableName = fncs.perseTableNameWithLoop(tables, seperator).loopname;
727
+ for (const cols of Object.keys(foreignKeys[dbs][tables])) {
728
+ const fk = foreignKeys[dbs][tables][cols];
729
+ const fkquries = addForeignKeyWithIndexQuery(tableName, cols, fk.table, fk.column, { onDelete: fk.deleteOption, onUpdate: fk.updateOption });
730
+ idxes.push(fkquries.indexQuery);
731
+ fkses.push(fkquries.foreignKeyQuery);
732
+ }
733
+ }
734
+ /**
735
+ * run query
736
+ */
737
+ }
738
+ } catch (err) {
739
+ console.error(err.message);
740
+ return null;
741
+ }
742
+ }
743
+
744
+
745
+
746
+ module.exports = {
747
+ columnAddDeleteAlter
748
+ }