dbtasker 3.1.1 → 3.1.3

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/README.md CHANGED
@@ -26,16 +26,16 @@ npm install dbtasker
26
26
  btasker requires a configuration object to manage connection credentials and safety behaviors.
27
27
  Property | Description
28
28
  | :--- | :--- |
29
- | **host** | MySQL Host (e.g., `localhost`) |
30
- | **user** | Database Username |
31
- | **password** | Database Password |
32
- | **port** | Connection Port (Default: `3306`) |
29
+ | **host** | MySQL Host (e.g., `localhost`) `(required)`|
30
+ | **user** | Database Username `(required)` |
31
+ | **password** | Database Password `(required)` |
32
+ | **port** | Connection Port (e.g., `3306`) `(required)` |
33
33
  | **drop database** | `Boolean`: If true, allows dropping databases. |
34
34
  | **drop table** | `Boolean`: If true, allows dropping tables. |
35
35
  | **drop column** | `Boolean`: If true, allows dropping columns. |
36
36
  | **do not touch** | `Array`: List of database names protected from deletion. |
37
37
  | **force delete column** | `Boolean`: If true, allow dropping column even if referanced by any other column. |
38
- | **force update column** | `Boolean`: It is set `default: false` If true, allow updating column even if referanced by any other column. This one is very powerful. If you turn it on it will remove any foreign key that is referanced to the column is being updated then update the column then add the foreign key to those column again and if the column is set to `UNIQUE` it will remove all the column value that are simillar. |
38
+ | **force update column** | `Boolean`: It is set `default: false` If true, allow updating column even if referanced by any other column. This one is very powerful. If you turn it on it will remove any foreign key that is referanced to the column is being updated then update the column then add the foreign key to those column again and if the column is set to `UNIQUE` it will remove all the column value that are same. |
39
39
 
40
40
  ### Configuration Example
41
41
  `JavaScript`
@@ -49,6 +49,8 @@ const config = {
49
49
  droptable: true,
50
50
  dropcol: false,
51
51
  donttouch: ["production_db", "analytics_db"],
52
+ forceupdatecolumn: true,
53
+ forcedeletecolumn: true,
52
54
  sep: "_"
53
55
  };
54
56
  ```
@@ -82,10 +84,30 @@ const schema = {
82
84
  defaults: "CURRENT_TIMESTAMP"
83
85
  }
84
86
  }
87
+ },
88
+ "(year)web_db": {
89
+ "tableName(month)": {
90
+ id: {
91
+ type: "int",
92
+ primarykey: true,
93
+ autoincrement: true
94
+ }
95
+ }
85
96
  }
86
97
  };
87
98
  ```
88
99
 
100
+ ### The Amazing and powerful one
101
+ When you use years, months or days as parameter when declering database name or in table name the system will generate date as extension of the name with a seperator. Such as:
102
+
103
+ ```js
104
+ const sep = "_"
105
+ if(name == "(year)name" || "name(year)") generated == "name_2026_";
106
+ if(name == "(month)name" || "name(month)") generated == "name_2026_12_";
107
+ if(name == "(day)name" || "name(day)") generated == "name_2026_12_26_";
108
+ ```
109
+
110
+ Now if the schema have any of this kind of name then you must run the function after that particular periode. So that funciton can create that database or table each time for your particular need.
89
111
 
90
112
 
91
113
  ## 🔗 Foreign Keys
@@ -154,9 +176,10 @@ ColumnTwo: {
154
176
  const dbtasker = require("dbtasker");
155
177
 
156
178
  const config = {
157
- host: "localhost",
179
+ host: "localhost",
180
+ port: 3306,
158
181
  user: "root",
159
- password: "password"
182
+ password: "password"
160
183
  };
161
184
 
162
185
  const schema = {
package/addcolumn.js CHANGED
@@ -30,39 +30,31 @@ async function addForeignKeyWithIndexQuery(config, databaseName, tableName, colu
30
30
  async function addColumnQuery(columndata, columnName, tableName, databaseName, config) {
31
31
  try {
32
32
  if (!columndata || !columndata.columntype) {
33
- throw new Error("columntype is required to add a column. Table: " + tableName + " Column name: " + columnName);
33
+ throw new Error(`columntype is required to add a column. Table: ${tableName} Column name: ${columnName}`);
34
34
  }
35
35
 
36
- // Simple identifier escaping for MySQL identifiers
36
+ // Helper to escape backticks in names
37
37
  const escId = (s) => `\`${String(s).replace(/`/g, '``')}\``;
38
38
 
39
- let queryText = `ALTER TABLE ${escId(tableName)} ADD COLUMN ${escId(columnName)}`;
39
+ // 1. Base query to add the column
40
+ let queryText = `ALTER TABLE ${escId(tableName)} ADD COLUMN ${escId(columnName)} ${columndata.columntype}`;
40
41
 
41
- // column type
42
- queryText += ` ${columndata.columntype}`;
43
-
44
- // length / enum / set
42
+ // 2. Handle length / enum / set
45
43
  if (columndata.hasOwnProperty("length_value")) {
46
44
  const lengthval = columndata.length_value;
47
-
48
45
  if (typeof lengthval === "number") {
49
46
  queryText += `(${lengthval})`;
50
- } else if (
51
- Array.isArray(lengthval) &&
52
- lengthval.length === 2 &&
53
- lengthval.every(v => typeof v === "number")
54
- ) {
47
+ } else if (Array.isArray(lengthval) && lengthval.length === 2 && lengthval.every(v => typeof v === "number")) {
55
48
  queryText += `(${lengthval[0]},${lengthval[1]})`;
56
- } else if (
57
- Array.isArray(lengthval) &&
58
- lengthval.every(v => typeof v === "string")
59
- ) {
49
+ } else if (Array.isArray(lengthval) && lengthval.every(v => typeof v === "string")) {
60
50
  const escaped = lengthval.map(v => `'${v.replace(/'/g, "''")}'`);
61
51
  queryText += `(${escaped.join(",")})`;
62
52
  }
63
53
  }
54
+
64
55
  queryText += " ";
65
56
 
57
+ // 3. Handle attributes
66
58
  if (columndata.unsigned === true) queryText += "UNSIGNED ";
67
59
  if (columndata.zerofill === true) queryText += "ZEROFILL ";
68
60
 
@@ -74,96 +66,66 @@ async function addColumnQuery(columndata, columnName, tableName, databaseName, c
74
66
  else queryText += `DEFAULT '${String(d).replace(/'/g, "''")}' `;
75
67
  }
76
68
 
77
- if (columndata.autoincrement === true) {
78
- queryText += "AUTO_INCREMENT ";
79
- }
80
-
69
+ if (columndata.autoincrement === true) queryText += "AUTO_INCREMENT ";
81
70
  if (columndata._charset_) queryText += `CHARACTER SET ${columndata._charset_} `;
82
71
  if (columndata._collate_) queryText += `COLLATE ${columndata._collate_} `;
83
72
 
84
73
  if (columndata.hasOwnProperty("nulls")) {
85
74
  queryText += columndata.nulls ? "NULL " : "NOT NULL ";
86
75
  }
76
+
87
77
  if (columndata.comment) {
88
78
  queryText += `COMMENT '${String(columndata.comment).replace(/'/g, "''")}' `;
89
79
  }
90
80
 
91
- // If no index specified, return the column add SQL
92
- if (!columndata.hasOwnProperty("index") || columndata.index === undefined || columndata.index === null || columndata.index === '') {
93
- return queryText.trim();
94
- }
95
-
96
- // index is provided interpret it as a string describing index type
97
- let rawIndex = columndata.index;
98
- if (typeof rawIndex !== 'string') {
99
- // defensively convert to string if possible
100
- rawIndex = String(rawIndex);
101
- }
102
- const idxToken = rawIndex.trim().toUpperCase();
103
-
104
- // Optional explicit index name
105
- const idxNameRaw = columndata.index_name || columndata.indexName || null;
106
- const idxName = idxNameRaw ? escId(idxNameRaw) : null;
107
-
108
- // Optional prefix length for index (integer)
109
- let idxLength = null;
110
- if (Number.isInteger(columndata.index_length) && columndata.index_length > 0) {
111
- idxLength = columndata.index_length;
112
- } else if (Number.isInteger(columndata.indexLength) && columndata.indexLength > 0) {
113
- idxLength = columndata.indexLength;
114
- }
115
-
116
- const colRef = idxLength ? `${escId(columnName)}(${idxLength})` : escId(columnName);
117
-
118
- // normalize common variants to canonical type
119
- let idxType = 'INDEX';
120
- if (idxToken === 'PRIMARY' || idxToken === 'PRIMARY KEY') idxType = 'PRIMARY';
121
- else if (idxToken === 'UNIQUE' || idxToken === 'UNIQUE KEY' || idxToken === 'UNIQUE INDEX') idxType = 'UNIQUE';
122
- else if (idxToken === 'FULLTEXT' || idxToken === 'FULLTEXT KEY' || idxToken === 'FULLTEXT INDEX') idxType = 'FULLTEXT';
123
- else if (idxToken === 'SPATIAL' || idxToken === 'SPATIAL KEY' || idxToken === 'SPATIAL INDEX') idxType = 'SPATIAL';
124
- else idxType = 'INDEX'; // covers INDEX, KEY and others
125
-
126
- // Build index clause. Prepend with comma because we already used ALTER TABLE ... ADD COLUMN ...
127
- let indexClause = '';
128
- switch (idxType) {
129
- case 'PRIMARY':
130
- // primary key doesn't accept a name
131
- indexClause = `, ADD PRIMARY KEY (${colRef})`;
132
- break;
133
- case 'UNIQUE':
134
- {
135
- const name = idxName || escId(`uniq_${String(tableName).replace(/\W+/g, '_')}_${String(columnName).replace(/\W+/g, '_')}`);
136
- indexClause = `, ADD UNIQUE KEY ${name} (${colRef})`;
137
- }
138
- break;
139
- case 'FULLTEXT':
140
- {
141
- const name = idxName || escId(`ft_${String(tableName).replace(/\W+/g, '_')}_${String(columnName).replace(/\W+/g, '_')}`);
142
- indexClause = `, ADD FULLTEXT KEY ${name} (${colRef})`;
143
- }
144
- break;
145
- case 'SPATIAL':
146
- {
147
- const name = idxName || escId(`sp_${String(tableName).replace(/\W+/g, '_')}_${String(columnName).replace(/\W+/g, '_')}`);
148
- indexClause = `, ADD SPATIAL KEY ${name} (${colRef})`;
149
- }
150
- break;
151
- case 'INDEX':
152
- default:
153
- {
154
- const name = idxName || escId(`idx_${String(tableName).replace(/\W+/g, '_')}_${String(columnName).replace(/\W+/g, '_')}`);
155
- indexClause = `, ADD INDEX ${name} (${colRef})`;
156
- }
157
- break;
81
+ // 4. Handle Index (Optional)
82
+ const hasIndex = columndata.hasOwnProperty("index") && columndata.index !== undefined && columndata.index !== null && columndata.index !== '';
83
+
84
+ if (hasIndex) {
85
+ let rawIndex = String(columndata.index).trim().toUpperCase();
86
+ const idxNameRaw = columndata.index_name || columndata.indexName || null;
87
+ const idxName = idxNameRaw ? escId(idxNameRaw) : null;
88
+
89
+ let idxLength = null;
90
+ if (Number.isInteger(columndata.index_length) && columndata.index_length > 0) idxLength = columndata.index_length;
91
+ else if (Number.isInteger(columndata.indexLength) && columndata.indexLength > 0) idxLength = columndata.indexLength;
92
+
93
+ const colRef = idxLength ? `${escId(columnName)}(${idxLength})` : escId(columnName);
94
+
95
+ let idxType = 'INDEX';
96
+ if (rawIndex === 'PRIMARY' || rawIndex === 'PRIMARY KEY') idxType = 'PRIMARY';
97
+ else if (rawIndex.includes('UNIQUE')) idxType = 'UNIQUE';
98
+ else if (rawIndex.includes('FULLTEXT')) idxType = 'FULLTEXT';
99
+ else if (rawIndex.includes('SPATIAL')) idxType = 'SPATIAL';
100
+
101
+ switch (idxType) {
102
+ case 'PRIMARY':
103
+ queryText += `, ADD PRIMARY KEY (${colRef})`;
104
+ break;
105
+ case 'UNIQUE':
106
+ queryText += `, ADD UNIQUE KEY ${idxName || escId(`uniq_${tableName}_${columnName}`)} (${colRef})`;
107
+ break;
108
+ case 'FULLTEXT':
109
+ queryText += `, ADD FULLTEXT KEY ${idxName || escId(`ft_${tableName}_${columnName}`)} (${colRef})`;
110
+ break;
111
+ case 'SPATIAL':
112
+ queryText += `, ADD SPATIAL KEY ${idxName || escId(`sp_${tableName}_${columnName}`)} (${colRef})`;
113
+ break;
114
+ default:
115
+ queryText += `, ADD INDEX ${idxName || escId(`idx_${tableName}_${columnName}`)} (${colRef})`;
116
+ break;
117
+ }
158
118
  }
159
119
 
160
- queryText += indexClause + ' ';
161
-
120
+ // 5. Final Execution (Happens every time)
162
121
  queryText = queryText.trim();
163
122
  const runquery = await fncs.runQuery(config, databaseName, queryText);
123
+
124
+ console.log(`Success: Added column ${columnName} to ${tableName}`);
164
125
  return runquery;
126
+
165
127
  } catch (err) {
166
- console.error(err && err.message ? err.message : String(err));
128
+ console.error("Error in addColumnQuery:", err && err.message ? err.message : String(err));
167
129
  return null;
168
130
  }
169
131
  }
@@ -252,7 +214,7 @@ async function addColumnIfNeeded(config, jsondata, separator) {
252
214
  }
253
215
  }
254
216
  }
255
- if(count > 0){
217
+ if (count > 0) {
256
218
  console.log(cstyler.green.bold("Successfully added " + count + " columns."));
257
219
  } else {
258
220
  console.log("No column found to be added. All the column are added already.");
package/altercolumn.js CHANGED
@@ -1,6 +1,7 @@
1
1
  const fncs = require("./function");
2
2
  const cstyler = require("cstyler");
3
3
  const crypto = require('crypto');
4
+ const addcolumn = require("./addcolumn");
4
5
 
5
6
 
6
7
 
@@ -8,13 +9,13 @@ const crypto = require('crypto');
8
9
 
9
10
  function generateSafeIndexName(prefix, table, column) {
10
11
  const fullName = `${prefix}_${table}_${column}`;
11
-
12
+
12
13
  // If it fits, just return it
13
14
  if (fullName.length <= 64) return fullName;
14
15
 
15
16
  // If too long, hash the full string and append it to a slice
16
17
  const hash = crypto.createHash('sha256').update(fullName).digest('hex').slice(0, 8);
17
-
18
+
18
19
  // 55 chars + 1 underscore + 8 chars hash = 64 chars total
19
20
  return `${fullName.slice(0, 55)}_${hash}`;
20
21
  }
@@ -310,7 +311,9 @@ async function alterColumnQuery(dbConfig, columndata, columnName, tableName, dat
310
311
  }
311
312
  if (hasdupes === true) {
312
313
  if (forceupdatecolumn) {
314
+ console.log(cstyler.bold.underline.yellow("********************************************************"));
313
315
  console.log(cstyler.bold.underline.yellow("***Cleaning duplicate rows before adding UNIQUE index***"));
316
+ console.log(cstyler.bold.underline.yellow("********************************************************"));
314
317
  const cleancol = await fncs.cleanDuplicateRows(dbConfig, database, tableName, columnName);
315
318
  if (cleancol === null) {
316
319
  console.error("Having server connection problem cleaning duplicate rows from database");
@@ -404,6 +407,7 @@ async function addForeignKeyWithIndexQuery(config, databaseName, tableName, colu
404
407
  async function alterColumnIfNeeded(config, jsondata, forceupdatecolumn, separator) {
405
408
  try {
406
409
  console.log(cstyler.bold.yellow("Let's initiate Alter Column to table if needed..."));
410
+ console.log(cstyler.bold.blue("Please wait..."));
407
411
  let count = 0;
408
412
  for (const jsondb of Object.keys(jsondata)) {
409
413
  const loopdb = fncs.perseTableNameWithLoop(jsondb, separator);
@@ -439,7 +443,13 @@ async function alterColumnIfNeeded(config, jsondata, forceupdatecolumn, separato
439
443
  if (!fncs.isJsonObject(jsondata[jsondb][jsontable][jsoncolumn])) { continue; }
440
444
  if (!allcols.includes(jsoncolumn)) {
441
445
  // column does not exist, skip it
442
- console.error(cstyler.red(`Column ${jsoncolumn} does not exist in table ${tableName} of database ${databaseName}. Skipping...`));
446
+ console.error(cstyler.red(`Column ${jsoncolumn} does not exist in table ${tableName} of database ${databaseName}. Adding the column...`));
447
+ const addcol = await addcolumn.addColumnQuery(jsondata[jsondb][jsontable][jsoncolumn], jsoncolumn, tableName, databaseName, config);
448
+ if (addcol === null) {
449
+ console.error(cstyler.red(`Failed to add column ${jsoncolumn} to table ${tableName} in database ${databaseName}. Skipping...`));
450
+ } else if (addcol === true) {
451
+ console.log(cstyler.green(`Successfully added column ${jsoncolumn} to table ${tableName} in database ${databaseName}.`));
452
+ }
443
453
  continue;
444
454
  }
445
455
  // lets add the column
@@ -550,10 +560,8 @@ async function alterColumnIfNeeded(config, jsondata, forceupdatecolumn, separato
550
560
  }
551
561
  }
552
562
  } else {
553
- console.log(cstyler.blue("Database:"), cstyler.hex("#00d9ffff")(databaseName), cstyler.blue("Table:"), cstyler.hex("#00d9ffff")(tableName), cstyler.blue("Column Name:"), cstyler.hex("#00d9ffff")(jsoncolumn), cstyler.yellow("- Given column data and server data are same."));
554
563
  // lets check if foreign key need update
555
564
  if (fkdetails === false && !columndata.hasOwnProperty("foreign_key")) {
556
- console.log(cstyler.underline("Column do not have foreign key."));
557
565
  continue;
558
566
  } else if (fkdetails === false && columndata.hasOwnProperty("foreign_key")) {
559
567
  console.log(cstyler.yellow("Foreign key need to be added for "), cstyler.blue("Database: "), cstyler.hex("#00d9ffff")(databaseName), cstyler.blue(" Table: "), cstyler.hex("#00d9ffff")(tableName), cstyler.blue(" Column Name: "), cstyler.hex("#00d9ffff")(jsoncolumn));
@@ -575,7 +583,6 @@ async function alterColumnIfNeeded(config, jsondata, forceupdatecolumn, separato
575
583
  fkdetails.column === fkdt.column &&
576
584
  fkdetails.deleteOption === fkdt.deleteOption &&
577
585
  (fkdt.updateOption === undefined || fkdetails.updateOption === fkdt.updateOption)) {
578
- console.log(cstyler.underline("Foreign key details are matched. No changes needed."))
579
586
  continue;
580
587
  }
581
588
  console.log(cstyler.blue("Database: "), cstyler.hex("#00d9ffff")(databaseName), cstyler.blue(" Table: "), cstyler.hex("#00d9ffff")(tableName), cstyler.blue(" Column Name: "), cstyler.hex("#00d9ffff")(jsoncolumn), cstyler.yellow("- Foreign key details are different, updating foreign key."));
package/dropcolumn.js CHANGED
@@ -17,11 +17,7 @@ async function dropcolumn(config, tableJson, forceDropColumn, separator = "_") {
17
17
  for (const jsDb of Object.keys(tableJson)) {
18
18
  const parsedDb = fncs.perseDatabaseNameWithLoop(jsDb, separator);
19
19
  if (!parsedDb) {
20
- console.error(
21
- cstyler.bold.red("Cannot parse database name."),
22
- jsDb,
23
- parsedDb
24
- );
20
+ console.error(cstyler.bold.red("Cannot parse database name."), jsDb, parsedDb);
25
21
  return null;
26
22
  }
27
23
 
@@ -34,20 +30,13 @@ async function dropcolumn(config, tableJson, forceDropColumn, separator = "_") {
34
30
 
35
31
  const parsedTable = fncs.perseTableNameWithLoop(jsTable, separator);
36
32
  if (!parsedTable) {
37
- console.error(
38
- cstyler.bold.red("Cannot parse table name."),
39
- jsTable
40
- );
33
+ console.error(cstyler.bold.red("Cannot parse table name."), jsTable);
41
34
  return null;
42
35
  }
43
36
 
44
37
  const tableName = parsedTable.loopname;
45
38
 
46
- const existingColumns = await fncs.getColumnNames(
47
- config,
48
- databaseName,
49
- tableName
50
- );
39
+ const existingColumns = await fncs.getColumnNames(config, databaseName, tableName);
51
40
 
52
41
  if (!existingColumns) {
53
42
  console.error(
@@ -60,14 +49,10 @@ async function dropcolumn(config, tableJson, forceDropColumn, separator = "_") {
60
49
  }
61
50
 
62
51
  for (const column of existingColumns) {
63
- const definedInJson = Object.prototype.hasOwnProperty.call(
64
- tableDef,
65
- column
66
- );
67
-
68
- const isValidDefinition =
69
- definedInJson && fncs.isJsonObject(tableDef[column]);
52
+ const definedInJson = Object.prototype.hasOwnProperty.call(tableDef, column);
70
53
 
54
+ const isValidDefinition = definedInJson && fncs.isJsonObject(tableDef[column]);
55
+
71
56
  if (isValidDefinition) continue;
72
57
 
73
58
  console.log(
@@ -79,19 +64,10 @@ async function dropcolumn(config, tableJson, forceDropColumn, separator = "_") {
79
64
  cstyler.yellow(column)
80
65
  );
81
66
 
82
- const referencingColumns =
83
- await fncs.findReferencingFromColumns(
84
- config,
85
- databaseName,
86
- tableName,
87
- column
88
- );
67
+ const referencingColumns = await fncs.findReferencingFromColumns(config, databaseName, tableName, column);
89
68
 
90
69
  if (referencingColumns === null) {
91
- console.error(
92
- cstyler.bold.red("Failed to resolve FK references for column:"),
93
- cstyler.hex("#00d9ffff")(column)
94
- );
70
+ console.error(cstyler.bold.red("Failed to resolve FK references for column:"), cstyler.hex("#00d9ffff")(column));
95
71
  return null;
96
72
  }
97
73
 
@@ -108,12 +84,7 @@ async function dropcolumn(config, tableJson, forceDropColumn, separator = "_") {
108
84
  let allFkRemoved = true;
109
85
 
110
86
  for (const ref of referencingColumns) {
111
- const removed = await fncs.removeForeignKeyFromColumn(
112
- config,
113
- ref.child_schema,
114
- ref.child_table,
115
- ref.child_columns[0]
116
- );
87
+ const removed = await fncs.removeForeignKeyFromColumn(config, ref.child_schema, ref.child_table, ref.child_columns[0]);
117
88
 
118
89
  if (removed === null) {
119
90
  console.error(
@@ -127,21 +98,12 @@ async function dropcolumn(config, tableJson, forceDropColumn, separator = "_") {
127
98
  }
128
99
 
129
100
  if (!allFkRemoved) {
130
- console.error(
131
- cstyler.bold.red("Aborting column drop due to FK failures:"),
132
- cstyler.hex("#00d9ffff")(column)
133
- );
101
+ console.error(cstyler.bold.red("Aborting column drop due to FK failures:"), cstyler.hex("#00d9ffff")(column));
134
102
  continue;
135
103
  }
136
104
  }
137
105
 
138
- const dropped = await fncs.dropColumn(
139
- config,
140
- databaseName,
141
- tableName,
142
- column
143
- );
144
-
106
+ const dropped = await fncs.dropColumn(config, databaseName, tableName, column);
145
107
  if (dropped === null) {
146
108
  console.error(
147
109
  cstyler.bold.red("Failed to drop column:"),
@@ -151,17 +113,11 @@ async function dropcolumn(config, tableJson, forceDropColumn, separator = "_") {
151
113
  }
152
114
  console.log(cstyler.blue("Database: "), cstyler.hex("#00d9ffff")(databaseName), cstyler.blue(" Table: "), cstyler.hex("#00d9ffff")(tableName), cstyler.blue("Column: "), cstyler.hex("#00d9ffff")(column), cstyler.green("- dropped successfully."))
153
115
  count += 1;
154
- console.log(
155
- cstyler.bold.green("Successfully dropped column:"),
156
- cstyler.hex("#00d9ffff")(column),
157
- cstyler.bold.green("from table:"),
158
- cstyler.hex("#00d9ffff")(tableName)
159
- );
160
116
  }
161
117
  }
162
118
  }
163
119
  if (count > 0) {
164
- console.log(cstyler.green("Successfully dropped ", count, " columns."));
120
+ console.log(cstyler.bold.green("Successfully dropped " + count + " columns."));
165
121
  } else {
166
122
  console.log("There is not column found to be dropped.");
167
123
  }
package/function.js CHANGED
@@ -289,35 +289,33 @@ async function dropTable(config, databaseName, tableName) {
289
289
  async function dropColumn(config, databaseName, tableName, columnName) {
290
290
  let connection;
291
291
  try {
292
- config.database = databaseName;
293
- connection = await mysql.createConnection(config);
292
+ // Ensure the database is selected in the config
293
+ const dbConfig = { ...config, database: databaseName };
294
+ connection = await mysql.createConnection(dbConfig);
294
295
 
295
- // 1️⃣ Check if column exists
296
+ // 1️⃣ Check if column exists and get its metadata
296
297
  const [columns] = await connection.query(
297
- `SELECT COLUMN_NAME, COLUMN_KEY
298
- FROM INFORMATION_SCHEMA.COLUMNS
298
+ `SELECT COLUMN_NAME, COLUMN_KEY, COLUMN_TYPE, EXTRA
299
+ FROM INFORMATION_SCHEMA.COLUMNS
299
300
  WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ? AND COLUMN_NAME = ?`,
300
301
  [databaseName, tableName, columnName]
301
302
  );
302
303
 
303
- // ❌ Column does not exist → return false
304
304
  if (columns.length === 0) {
305
- console.log(
306
- `Column '${columnName}' does not exist in ${databaseName}.${tableName}`
307
- );
305
+ console.log(`Column '${columnName}' does not exist in ${tableName}.`);
308
306
  return false;
309
307
  }
310
308
 
311
- const columnKey = columns[0].COLUMN_KEY;
309
+ const columnKey = columns[0].COLUMN_KEY; // "PRI", "UNI", or ""
310
+ const columnType = columns[0].COLUMN_TYPE; // e.g., "int(11)"
311
+ const isAutoIncrement = columns[0].EXTRA.toLowerCase().includes('auto_increment');
312
312
 
313
- // 2️⃣ Drop foreign key constraints
313
+ // 2️⃣ Drop Foreign Key constraints first
314
314
  const [fkConstraints] = await connection.query(
315
315
  `SELECT CONSTRAINT_NAME
316
316
  FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
317
- WHERE TABLE_SCHEMA = ?
318
- AND TABLE_NAME = ?
319
- AND COLUMN_NAME = ?
320
- AND REFERENCED_TABLE_NAME IS NOT NULL`,
317
+ WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ? AND COLUMN_NAME = ?
318
+ AND REFERENCED_TABLE_NAME IS NOT NULL`,
321
319
  [databaseName, tableName, columnName]
322
320
  );
323
321
 
@@ -327,23 +325,28 @@ async function dropColumn(config, databaseName, tableName, columnName) {
327
325
  );
328
326
  }
329
327
 
330
- // 3️⃣ Drop primary key if needed
331
- if (columnKey === "PRI") {
328
+ // 3️⃣ Handle Primary Key and Auto-Increment Conflict
329
+ // If it's Auto-Increment, we MUST remove that attribute before dropping the key
330
+ if (isAutoIncrement) {
331
+ // Modifying without the 'AUTO_INCREMENT' keyword
332
332
  await connection.query(
333
- `ALTER TABLE \`${tableName}\` DROP PRIMARY KEY`
333
+ `ALTER TABLE \`${tableName}\` MODIFY COLUMN \`${columnName}\` ${columnType}`
334
334
  );
335
335
  }
336
336
 
337
- // 4️⃣ Drop column
337
+ // Now it is safe to drop the Primary Key constraint if it was one
338
+ if (columnKey === "PRI") {
339
+ await connection.query(`ALTER TABLE \`${tableName}\` DROP PRIMARY KEY`);
340
+ }
341
+
342
+ // 4️⃣ Final Step: Drop the column
338
343
  await connection.query(
339
344
  `ALTER TABLE \`${tableName}\` DROP COLUMN \`${columnName}\``
340
345
  );
341
346
 
342
- console.log(
343
- `Column '${columnName}' dropped successfully from ${databaseName}.${tableName}`
344
- );
345
-
347
+ console.log(`Column '${columnName}' dropped successfully from ${tableName}`);
346
348
  return true;
349
+
347
350
  } catch (err) {
348
351
  console.error("Error dropping column:", err.message);
349
352
  return null;
@@ -1873,7 +1876,7 @@ async function checkDuplicates(config, databaseName, tableName, columnName) {
1873
1876
  ) AS dup_query`;
1874
1877
 
1875
1878
  const [rows] = await connection.execute(sql);
1876
-
1879
+
1877
1880
  // Returns true if duplicates exist, false if not
1878
1881
  return rows[0].duplicateCount > 0;
1879
1882
 
@@ -1901,7 +1904,7 @@ async function cleanDuplicateRows(config, databaseName, tableName, columnName) {
1901
1904
  AND t1.id > t2.id`;
1902
1905
 
1903
1906
  const [result] = await connection.execute(sql);
1904
-
1907
+
1905
1908
  // Returns the number of deleted rows
1906
1909
  return result.affectedRows;
1907
1910
 
package/index.js CHANGED
@@ -1,7 +1,6 @@
1
1
  const fncs = require("./function");
2
- const recordedjson = require("./tableop");
3
2
  const cstyler = require("cstyler");
4
- const checker = require("./validation");
3
+ const checker = require("./mysqlvalidation");
5
4
 
6
5
 
7
6
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dbtasker",
3
- "version": "3.1.1",
3
+ "version": "3.1.3",
4
4
  "funding": {
5
5
  "type": "patreon",
6
6
  "url": "https://www.patreon.com/kormoi/gift"
@@ -45,7 +45,8 @@
45
45
  "cstyler": "^4.0.0",
46
46
  "fs": "^0.0.1-security",
47
47
  "mysql2": "^3.14.3",
48
- "path": "^0.12.7"
48
+ "path": "^0.12.7",
49
+ "pg": "^8.16.3"
49
50
  },
50
51
  "repository": {
51
52
  "type": "git",
package/pgfunctions.js ADDED
@@ -0,0 +1,54 @@
1
+ const { Client } = require('pg');
2
+
3
+
4
+
5
+
6
+ const client = new Client({
7
+ user: 'postgres',
8
+ host: 'localhost',
9
+ database: 'postgres', // Connect to the default db first
10
+ password: 'your_password',
11
+ port: 5432,
12
+ });
13
+
14
+ async function test() {
15
+ await client.connect();
16
+ const res = await client.query('SELECT NOW()');
17
+ console.log("Postgres Time:", res.rows[0].now);
18
+ await client.end();
19
+ }
20
+ /**
21
+ * Connects to Postgres and returns the Locale and Encoding settings.
22
+ */
23
+ async function getPostgresLocale(config) {
24
+ const client = new Client(config);
25
+
26
+ try {
27
+ await client.connect();
28
+
29
+ // We query three specific system settings:
30
+ // 1. server_encoding: The character set (e.g., UTF8)
31
+ // 2. lc_collate: The alphabetical sorting rules
32
+ // 3. lc_ctype: The character classification (language)
33
+ const query = `
34
+ SELECT
35
+ current_setting('server_encoding') as encoding,
36
+ current_setting('lc_collate') as collate,
37
+ current_setting('lc_ctype') as ctype
38
+ `;
39
+
40
+ const res = await client.query(query);
41
+
42
+ return {
43
+ success: true,
44
+ data: res.rows[0]
45
+ };
46
+
47
+ } catch (error) {
48
+ console.error("Error fetching Postgres settings:", error.message);
49
+ return { success: false, error: error.message };
50
+ } finally {
51
+ // Always close the client!
52
+ await client.end();
53
+ }
54
+ }
File without changes
File without changes