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/dbop.js ADDED
@@ -0,0 +1,236 @@
1
+ const fncs = require("./function");
2
+ const cstyler = require("cstyler");
3
+ const mysql = require('mysql2/promise');
4
+
5
+
6
+
7
+
8
+ const defaultdb = ['information_schema', 'mysql', 'performance_schema', 'sys', 'world'];
9
+
10
+ async function alterDatabaseCharsetCollate(config, databaseName, characterSet, collate) {
11
+ if (!databaseName || typeof databaseName !== "string")
12
+ throw new Error("Invalid database name.");
13
+
14
+ if (!characterSet || typeof characterSet !== "string")
15
+ throw new Error("Invalid character set.");
16
+
17
+ if (!collate || typeof collate !== "string")
18
+ throw new Error("Invalid collation.");
19
+
20
+ // Validate MySQL naming patterns (alphanumeric, underscore, dash)
21
+ const validName = /^[A-Za-z0-9_-]+$/;
22
+ if (!validName.test(databaseName))
23
+ throw new Error(`Invalid database name format: ${databaseName}`);
24
+
25
+ let connection;
26
+ try {
27
+ connection = await mysql.createConnection(config);
28
+
29
+ const query = `
30
+ ALTER DATABASE \`${databaseName}\`
31
+ CHARACTER SET ${characterSet}
32
+ COLLATE ${collate};
33
+ `;
34
+
35
+ await connection.query(query);
36
+ console.log(`${cstyler.purple('Database:')} '${cstyler.blue(databaseName)}' character set changed to '${cstyler.yellow(characterSet)}' and collation to '${cstyler.yellow(collate)}'.`);
37
+ return true;
38
+ } catch (err) {
39
+ console.error("Error altering database:", err.message);
40
+ return null;
41
+ } finally {
42
+ if (connection) await connection.end();
43
+ }
44
+ }
45
+ async function createDatabase(config, databaseName, characterSet = null, collate = null) {
46
+ if (!databaseName || typeof databaseName !== "string")
47
+ throw new Error("Invalid database name.");
48
+
49
+ // Validate MySQL naming patterns (alphanumeric, underscore, dash)
50
+ const validName = /^[A-Za-z0-9_-]+$/;
51
+ if (!validName.test(databaseName))
52
+ throw new Error(`Invalid database name format: ${databaseName}`);
53
+
54
+ // Validate optional charset + collate
55
+ if (characterSet !== null && typeof characterSet !== "string")
56
+ throw new Error("Invalid character set (must be string or null).");
57
+
58
+ if (collate !== null && typeof collate !== "string")
59
+ throw new Error("Invalid collation (must be string or null).");
60
+
61
+ let connection;
62
+ try {
63
+ connection = await mysql.createConnection(config);
64
+
65
+ // Build query dynamically depending on optional charset/collation
66
+ let query = `CREATE DATABASE \`${databaseName}\``;
67
+
68
+ if (characterSet) query += ` CHARACTER SET ${characterSet}`;
69
+ if (collate) query += ` COLLATE ${collate}`;
70
+
71
+ query += ";";
72
+
73
+ await connection.query(query);
74
+
75
+ console.log(
76
+ `${cstyler.purple('Database:')} '${cstyler.blue(databaseName)}'` +
77
+ (characterSet ? ` created with CHARACTER SET '${cstyler.yellow(characterSet)}'` : "") +
78
+ (collate ? ` and COLLATE '${cstyler.yellow(collate)}'` : "")
79
+ );
80
+ return true;
81
+ } catch (err) {
82
+ console.error("Error creating database:", err.message);
83
+ return null;
84
+ } finally {
85
+ if (connection) await connection.end();
86
+ }
87
+ }
88
+ async function dropTable(config, json_data, seperator = "_") {
89
+ try {
90
+ console.log("Starting dropping the table.");
91
+ for (const jsondb of Object.keys(json_data)) {
92
+ let dbname = fncs.perseDatabaseNameWithLoop(jsondb, seperator);
93
+ if (dbname === false) {
94
+ console.error("There must be some mistake. Please re install the module.");
95
+ }
96
+ const alltables = await fncs.getTableNames(config, dbname.loopname);
97
+ if (alltables === null) {
98
+ console.error("Having problem getting all the table name of the Database: ", cstyler.yellow(dbname.loopname), ". Please re-install the module.");
99
+ return null;
100
+ }
101
+ let tables = {};
102
+ for (const tableName of (alltables)) {
103
+ const revlpnm = fncs.reverseLoopName(tableName);
104
+ if (!Object.keys(json_data[jsondb]).includes(revlpnm[0]) && !Object.keys(json_data[jsondb]).includes(revlpnm[1])) {
105
+ const droptable = await fncs.dropTable(config, dbname.loopname, tableName);
106
+ if (droptable === null) {
107
+ console.error("Having problem dropping table. Please check database connection.");
108
+ return null;
109
+ }
110
+ console.log(cstyler.purple("Database: "), cstyler.blue(dbname.loopname), cstyler.purple("Table: "), cstyler.blue(tableName), "- has dropped successfully.")
111
+ }
112
+ }
113
+ console.log(cstyler.green("Successfully dropped all unlisted tables."));
114
+ return true;
115
+ }
116
+ } catch (err) {
117
+ console.error(err.message);
118
+ return null;
119
+ }
120
+ }
121
+ async function databaseAddDeleteAlter(allconfig, jsondata, dropdb = false, donttouchdb = [], seperator = "_") {
122
+ try {
123
+ // lets add databases and drop databases
124
+ let config;
125
+ if (fncs.isValidMySQLConfig(allconfig)) {
126
+ config = { "port": allconfig.port, "host": allconfig.host, "user": allconfig.user, "password": allconfig.password }
127
+ } else {
128
+ console.error(cstyler.bold("Invalid config"));
129
+ return null;
130
+ }
131
+ let jsondbnames = Object.keys(jsondata);
132
+ const avldblist = await fncs.getAllDatabaseNames(config);
133
+ if (!Array.isArray(avldblist)) {
134
+ console.error(cstyler.red.bold("There is a problem connecting to the database. Please check database info or connection."));
135
+ return null;
136
+ }
137
+ // Lets add databases
138
+ for (const jsondb of jsondbnames) {
139
+ let data = {};
140
+ data.name = fncs.perseDatabaseNameWithLoop(jsondb, seperator).loopname;
141
+ if (fncs.isJsonObject(jsondata[jsondb])) {
142
+ if (jsondata[jsondb].hasOwnProperty("_collate_")) {
143
+ data.collate = jsondata[jsondb]._collate_;
144
+ } else {
145
+ data.collate = null;
146
+ }
147
+ if (jsondata[jsondb].hasOwnProperty("_charset_")) {
148
+ data.charset = jsondata[jsondb]._charset_;
149
+ } else {
150
+ data.charset = null;
151
+ }
152
+ } else {
153
+ console.error("Pleaes re-install the module. Some functions are missing.");
154
+ return null;
155
+ }
156
+ if (avldblist.includes(data.name)) {
157
+ // Let's Alter database if needed
158
+ console.log(cstyler.purple("Database Name: "), cstyler.blue(data.name), cstyler.green(" is exist. Checking for charactar set and collate configuration"));
159
+ const dbdetails = await fncs.getDatabaseCharsetAndCollation(config, data.name);
160
+ if (!fncs.isJsonObject(dbdetails)) {
161
+ console.error(cstyler.bold("Having problem getting database character set and collate."));
162
+ return null;
163
+ } else {
164
+ if ((data.charset === null || dbdetails.characterSet === data.charset) && (data.collate === null || dbdetails.collation === data.collate)) {
165
+ console.log(cstyler.purple("Database: "), cstyler.blue(data.name), " no changes needed.");
166
+ } else {
167
+ // lets alter the database charset and collate
168
+ if (data.charset === null) {
169
+ data.charset = dbdetails.characterSet;
170
+ }
171
+ if (data.collate === null) {
172
+ data.collate = dbdetails.collation;
173
+ }
174
+ const altered = await alterDatabaseCharsetCollate(config, data.name, data.charset, data.collate);
175
+ if (altered === null) {
176
+ return null;
177
+ }
178
+ }
179
+ }
180
+
181
+ } else {
182
+ // Let's Create database
183
+ console.log(cstyler.purple("Database Name: "), cstyler.blue(data.name), " do not exist.");
184
+ console.log("Lets create Database: ", cstyler.yellow(jsondb));
185
+ const createdb = await createDatabase(config, data.name, data.charset, data.collate);
186
+ if (createdb === true) {
187
+ console.log(cstyler.purple("Database Name: "), cstyler.blue(jsondb), cstyler.green(" have created successfully"));
188
+ } else if (createdb === false) {
189
+ console.error("Trying to create this ", cstyler.blue(jsondb), " database when it do not exist on the list all existing database. But when creating server says it already exist. There must be a database problem.");
190
+ console.log(cstyler.purple("All available Database names are: "), cstyler.blue(avldblist.join(", ")));
191
+ return null;
192
+ } else {
193
+ return null;
194
+ }
195
+ }
196
+ }
197
+ // Lets drop database
198
+ if (dropdb) {
199
+ // Lets get all database name
200
+ const avldblist = await fncs.getAllDatabaseNames(config);
201
+ if (!Array.isArray(avldblist)) {
202
+ console.error(cstyler.red.bold("There is a problem connecting to the database. Please check database info or connection."));
203
+ return null;
204
+ }
205
+ // Let's arrange database names
206
+ let arrngdbnms = {};
207
+ for (const dbnms of avldblist) {
208
+ if ([...defaultdb, ...donttouchdb].includes(dbnms)) { continue }
209
+ const getrev = fncs.reverseLoopName(dbnms);
210
+ if (arrngdbnms.hasOwnProperty(getrev)[0]) {
211
+ arrngdbnms[getrev[0]].push(dbnms);
212
+ } else if (arrngdbnms.hasOwnProperty(getrev)[1]) {
213
+ arrngdbnms[getrev[1]].push(dbnms);
214
+ } else {
215
+ arrngdbnms[getrev] = [dbnms];
216
+ }
217
+ }
218
+ for (const databaseName of Object.keys(arrngdbnms)) {
219
+ if (!jsondbnames.includes(databaseName)) {
220
+ for (const items of arrngdbnms[databaseName]) {
221
+ await fncs.dropDatabase(config, items);
222
+ }
223
+ }
224
+ }
225
+ }
226
+ return true;
227
+ } catch (err) {
228
+ console.error(err.message);
229
+ return null;
230
+ }
231
+ }
232
+
233
+ module.exports = {
234
+ databaseAddDeleteAlter,
235
+ dropTable
236
+ }
@@ -0,0 +1,237 @@
1
+
2
+
3
+ const ENGINE_COLUMN_TYPES = {
4
+ INNODB: [
5
+ // Numeric
6
+ "BIT","TINYINT","SMALLINT","MEDIUMINT","INT","INTEGER","BIGINT",
7
+ "DECIMAL","NUMERIC","FLOAT","DOUBLE","REAL","BOOL","BOOLEAN",
8
+ // Date & Time
9
+ "DATE","TIME","DATETIME","TIMESTAMP","YEAR",
10
+ // Character
11
+ "CHAR","VARCHAR","TINYTEXT","TEXT","MEDIUMTEXT","LONGTEXT",
12
+ // Binary
13
+ "BINARY","VARBINARY","TINYBLOB","BLOB","MEDIUMBLOB","LONGBLOB",
14
+ // Enum / Set
15
+ "ENUM","SET",
16
+ // JSON
17
+ "JSON",
18
+ // Spatial
19
+ "GEOMETRY","POINT","LINESTRING","POLYGON",
20
+ "MULTIPOINT","MULTILINESTRING","MULTIPOLYGON","GEOMETRYCOLLECTION"
21
+ ],
22
+ MYISAM: [
23
+ // same as InnoDB
24
+ "BIT","TINYINT","SMALLINT","MEDIUMINT","INT","INTEGER","BIGINT",
25
+ "DECIMAL","NUMERIC","FLOAT","DOUBLE","REAL","BOOL","BOOLEAN",
26
+ "DATE","TIME","DATETIME","TIMESTAMP","YEAR",
27
+ "CHAR","VARCHAR","TINYTEXT","TEXT","MEDIUMTEXT","LONGTEXT",
28
+ "BINARY","VARBINARY","TINYBLOB","BLOB","MEDIUMBLOB","LONGBLOB",
29
+ "ENUM","SET",
30
+ "JSON",
31
+ "GEOMETRY","POINT","LINESTRING","POLYGON",
32
+ "MULTIPOINT","MULTILINESTRING","MULTIPOLYGON","GEOMETRYCOLLECTION"
33
+ ],
34
+ MEMORY: [
35
+ "TINYINT","SMALLINT","MEDIUMINT","INT","INTEGER","BIGINT",
36
+ "DECIMAL","NUMERIC","FLOAT","DOUBLE","REAL","BOOL","BOOLEAN",
37
+ "DATE","TIME","DATETIME","TIMESTAMP","YEAR",
38
+ "CHAR","VARCHAR",
39
+ "ENUM","SET"
40
+ ],
41
+ CSV: [
42
+ "TINYINT","SMALLINT","MEDIUMINT","INT","INTEGER","BIGINT",
43
+ "DECIMAL","NUMERIC","FLOAT","DOUBLE","REAL",
44
+ "DATE","TIME","DATETIME","TIMESTAMP","YEAR",
45
+ "CHAR","VARCHAR"
46
+ ],
47
+ ARCHIVE: [
48
+ "TINYINT","SMALLINT","MEDIUMINT","INT","INTEGER","BIGINT",
49
+ "DECIMAL","NUMERIC","FLOAT","DOUBLE","REAL",
50
+ "DATE","TIME","DATETIME","TIMESTAMP","YEAR",
51
+ "CHAR","VARCHAR"
52
+ ],
53
+ BLACKHOLE: [
54
+ "TINYINT","SMALLINT","MEDIUMINT","INT","INTEGER","BIGINT",
55
+ "DECIMAL","NUMERIC","FLOAT","DOUBLE","REAL",
56
+ "CHAR","VARCHAR",
57
+ "DATE","TIME","DATETIME","TIMESTAMP","YEAR"
58
+ ],
59
+ FEDERATED: [
60
+ "TINYINT","SMALLINT","MEDIUMINT","INT","INTEGER","BIGINT",
61
+ "DECIMAL","NUMERIC","FLOAT","DOUBLE","REAL",
62
+ "CHAR","VARCHAR",
63
+ "DATE","TIME","DATETIME","TIMESTAMP","YEAR"
64
+ ],
65
+ MRG_MYISAM: [
66
+ "TINYINT","SMALLINT","MEDIUMINT","INT","INTEGER","BIGINT",
67
+ "DECIMAL","NUMERIC","FLOAT","DOUBLE","REAL",
68
+ "CHAR","VARCHAR","TINYTEXT","TEXT","MEDIUMTEXT","LONGTEXT",
69
+ "BINARY","VARBINARY","TINYBLOB","BLOB","MEDIUMBLOB","LONGBLOB",
70
+ "ENUM","SET",
71
+ "DATE","TIME","DATETIME","TIMESTAMP","YEAR"
72
+ ],
73
+ NDB: [
74
+ "TINYINT","SMALLINT","MEDIUMINT","INT","INTEGER","BIGINT",
75
+ "DECIMAL","NUMERIC","FLOAT","DOUBLE","REAL",
76
+ "CHAR","VARCHAR",
77
+ "DATE","TIME","DATETIME","TIMESTAMP","YEAR",
78
+ "ENUM","SET"
79
+ ],
80
+ NDBCLUSTER: [
81
+ "TINYINT","SMALLINT","MEDIUMINT","INT","INTEGER","BIGINT",
82
+ "DECIMAL","NUMERIC","FLOAT","DOUBLE","REAL",
83
+ "CHAR","VARCHAR",
84
+ "DATE","TIME","DATETIME","TIMESTAMP","YEAR",
85
+ "ENUM","SET"
86
+ ],
87
+ EXAMPLE: [], // stub engine, no real column support
88
+ TOKUDB: [
89
+ "TINYINT","SMALLINT","MEDIUMINT","INT","INTEGER","BIGINT",
90
+ "DECIMAL","NUMERIC","FLOAT","DOUBLE","REAL",
91
+ "CHAR","VARCHAR","TEXT","BLOB","DATE","DATETIME","TIMESTAMP","YEAR",
92
+ "ENUM","SET"
93
+ ],
94
+ ROCKSDB: [
95
+ "TINYINT","SMALLINT","MEDIUMINT","INT","INTEGER","BIGINT",
96
+ "DECIMAL","NUMERIC","FLOAT","DOUBLE","REAL",
97
+ "CHAR","VARCHAR","TEXT","BLOB","DATE","DATETIME","TIMESTAMP","YEAR",
98
+ "ENUM","SET"
99
+ ],
100
+ SPIDER: [
101
+ "TINYINT","SMALLINT","MEDIUMINT","INT","INTEGER","BIGINT",
102
+ "DECIMAL","NUMERIC","FLOAT","DOUBLE","REAL",
103
+ "CHAR","VARCHAR","TEXT","BLOB","DATE","DATETIME","TIMESTAMP","YEAR",
104
+ "ENUM","SET"
105
+ ]
106
+ };
107
+ // Check if a column type is allowed for an engine
108
+ function isColumnTypeAllowed(type, engine) {
109
+ if (!type || !engine) return false;
110
+
111
+ // Ensure type is a string
112
+ const typeStr = String(type);
113
+
114
+ const baseType = typeStr
115
+ .toUpperCase()
116
+ .replace(/\(.*?\)/g, "") // remove length/precision
117
+ .split(/\s+/)[0];
118
+
119
+ const types = ENGINE_COLUMN_TYPES[engine] || [];
120
+ return types.includes(baseType);
121
+ }
122
+ const ENGINE_CAPABILITIES = {
123
+ INNODB: {
124
+ Null: true,
125
+ Index: true,
126
+ AutoIncrement: true,
127
+ ZeroFill: true,
128
+ Default: true
129
+ },
130
+ MYISAM: {
131
+ Null: true,
132
+ Index: true,
133
+ AutoIncrement: true,
134
+ ZeroFill: true,
135
+ Default: true
136
+ },
137
+ MEMORY: {
138
+ Null: true,
139
+ Index: true,
140
+ AutoIncrement: true,
141
+ ZeroFill: true,
142
+ Default: true
143
+ },
144
+ CSV: {
145
+ Null: false,
146
+ Index: false,
147
+ AutoIncrement: false,
148
+ ZeroFill: false,
149
+ Default: true
150
+ },
151
+ ARCHIVE: {
152
+ Null: false,
153
+ Index: false,
154
+ AutoIncrement: false,
155
+ ZeroFill: false,
156
+ Default: true
157
+ },
158
+ BLACKHOLE: {
159
+ Null: true,
160
+ Index: false,
161
+ AutoIncrement: false,
162
+ ZeroFill: false,
163
+ Default: false
164
+ },
165
+ FEDERATED: {
166
+ Null: true,
167
+ Index: false, // depends on remote
168
+ AutoIncrement: false,
169
+ ZeroFill: false,
170
+ Default: true // allows literals
171
+ },
172
+ MRG_MYISAM: {
173
+ Null: true,
174
+ Index: true, // inherits from underlying MyISAM tables
175
+ AutoIncrement: true,
176
+ ZeroFill: true,
177
+ Default: true
178
+ },
179
+ NDB: {
180
+ Null: true,
181
+ Index: true,
182
+ AutoIncrement: true,
183
+ ZeroFill: true,
184
+ Default: true
185
+ },
186
+ NDBCLUSTER: { // same as NDB
187
+ Null: true,
188
+ Index: true,
189
+ AutoIncrement: true,
190
+ ZeroFill: true,
191
+ Default: true
192
+ },
193
+ EXAMPLE: {
194
+ Null: true,
195
+ Index: false,
196
+ AutoIncrement: false,
197
+ ZeroFill: false,
198
+ Default: false
199
+ },
200
+ TOKUDB: {
201
+ Null: true,
202
+ Index: true,
203
+ AutoIncrement: true,
204
+ ZeroFill: true,
205
+ Default: true
206
+ },
207
+ ROCKSDB: {
208
+ Null: true,
209
+ Index: true,
210
+ AutoIncrement: true,
211
+ ZeroFill: true,
212
+ Default: true
213
+ },
214
+ SPIDER: {
215
+ Null: true,
216
+ Index: true,
217
+ AutoIncrement: true,
218
+ ZeroFill: true,
219
+ Default: true
220
+ }
221
+ };
222
+ function isEngineFeatureAllowed(engine, feature) {
223
+ if (!engine) return null;
224
+
225
+ // Ensure engine is a string
226
+ const engineStr = String(engine);
227
+
228
+ const caps = ENGINE_CAPABILITIES[engineStr.toUpperCase()];
229
+ if (!caps) return null; // unknown engine
230
+
231
+ return !!caps[feature];
232
+ }
233
+
234
+ module.exports = {
235
+ isColumnTypeAllowed,
236
+ isEngineFeatureAllowed
237
+ }