dbtasker 3.1.2 → 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,10 +26,10 @@ 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 (e.g., `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. |
@@ -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
  }
@@ -442,7 +443,13 @@ async function alterColumnIfNeeded(config, jsondata, forceupdatecolumn, separato
442
443
  if (!fncs.isJsonObject(jsondata[jsondb][jsontable][jsoncolumn])) { continue; }
443
444
  if (!allcols.includes(jsoncolumn)) {
444
445
  // column does not exist, skip it
445
- 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
+ }
446
453
  continue;
447
454
  }
448
455
  // lets add the column
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.2",
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