@intecoag/inteco-cli 0.5.1
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 +3 -0
- package/package.json +35 -0
- package/src/index.js +85 -0
- package/src/modules/adbBridge.js +52 -0
- package/src/modules/adbIntentSender.js +82 -0
- package/src/modules/bundleProduct.js +161 -0
- package/src/modules/csvMerger.js +118 -0
- package/src/modules/deleteDB.js +84 -0
- package/src/modules/dumpDB.js +216 -0
- package/src/modules/dumpTableToCSV.js +154 -0
- package/src/modules/extdSearch.js +226 -0
- package/src/modules/graphqlSchemaExport.js +61 -0
- package/src/modules/importDB.js +121 -0
- package/src/modules/rewriteConfig.js +79 -0
- package/src/modules/setCLIConfig.js +33 -0
- package/src/modules/syncConfig.js +264 -0
- package/src/modules/t003Rewrite.js +64 -0
- package/src/ressources/cmds.json +47 -0
- package/src/ressources/wegas_p.ico +0 -0
- package/src/utils/config/config.js +70 -0
- package/src/utils/config/default.json +9 -0
- package/src/utils/db/DB.js +54 -0
- package/src/utils/fs/FS.js +88 -0
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import prompts from "prompts"
|
|
2
|
+
import { rmSync } from "fs";
|
|
3
|
+
import ora from "ora";
|
|
4
|
+
import { DB } from "../utils/db/DB.js";
|
|
5
|
+
import { Config } from "../utils/config/config.js";
|
|
6
|
+
import chalk from "chalk";
|
|
7
|
+
import path from "path";
|
|
8
|
+
import { exec, execSync } from "child_process";
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
export async function dumpDB(cli) {
|
|
12
|
+
console.log()
|
|
13
|
+
|
|
14
|
+
const config = await Config.getConfig();
|
|
15
|
+
|
|
16
|
+
const databaseNames = await DB.getDatabaseNames();
|
|
17
|
+
|
|
18
|
+
let success = true;
|
|
19
|
+
|
|
20
|
+
const resultsDB = await prompts([
|
|
21
|
+
{
|
|
22
|
+
// DB-Auswahl von DB
|
|
23
|
+
type: 'autocomplete',
|
|
24
|
+
name: 'dbName',
|
|
25
|
+
message: 'DB-Name?',
|
|
26
|
+
choices: databaseNames.map(name => { return { title: name.name } })
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
type: 'toggle',
|
|
30
|
+
name: 'dataOnly',
|
|
31
|
+
message: 'Dump data only (no table recreation)?',
|
|
32
|
+
initial: false,
|
|
33
|
+
active: 'yes',
|
|
34
|
+
inactive: 'no'
|
|
35
|
+
}
|
|
36
|
+
, {
|
|
37
|
+
type: 'toggle',
|
|
38
|
+
name: 'selectIndividualTables',
|
|
39
|
+
message: 'Select individual tables?',
|
|
40
|
+
initial: false,
|
|
41
|
+
active: 'yes',
|
|
42
|
+
inactive: 'no'
|
|
43
|
+
}], {
|
|
44
|
+
onCancel: () => {
|
|
45
|
+
console.log()
|
|
46
|
+
console.log(chalk.red("Cancelled Import!"))
|
|
47
|
+
console.log()
|
|
48
|
+
success = false
|
|
49
|
+
}
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
if (success) {
|
|
53
|
+
let selectedTables = [];
|
|
54
|
+
if (resultsDB.selectIndividualTables) {
|
|
55
|
+
|
|
56
|
+
let tables = await DB.executeQueryOnDB("SHOW TABLES;", resultsDB.dbName);
|
|
57
|
+
const tableKey = Object.keys(tables[0])[0];
|
|
58
|
+
tables = tables.map(row => row[tableKey])
|
|
59
|
+
let continuePrompt = true;
|
|
60
|
+
while (continuePrompt) {
|
|
61
|
+
const resultsTable = await prompts([
|
|
62
|
+
{
|
|
63
|
+
// DB-Auswahl von DB
|
|
64
|
+
type: 'autocomplete',
|
|
65
|
+
name: 'table',
|
|
66
|
+
message: 'Table?',
|
|
67
|
+
choices: tables.map(name => { return { title: name } }),
|
|
68
|
+
default: ""
|
|
69
|
+
}, {
|
|
70
|
+
type: 'toggle',
|
|
71
|
+
name: 'continue',
|
|
72
|
+
message: 'Add another table?',
|
|
73
|
+
initial: false,
|
|
74
|
+
active: 'yes',
|
|
75
|
+
inactive: 'no'
|
|
76
|
+
}], {
|
|
77
|
+
onCancel: () => {
|
|
78
|
+
console.log()
|
|
79
|
+
console.log(chalk.red("Cancelled Import!"))
|
|
80
|
+
console.log()
|
|
81
|
+
success = false
|
|
82
|
+
}
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
selectedTables.push(resultsTable.table)
|
|
86
|
+
continuePrompt = resultsTable.continue
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const results = await prompts([
|
|
92
|
+
{
|
|
93
|
+
// Ordnerauswahl von vorhandenen Ordner in configIndividual
|
|
94
|
+
type: 'text',
|
|
95
|
+
name: 'dumpName',
|
|
96
|
+
message: 'Dump-Name?',
|
|
97
|
+
initial: 'dump.sql'
|
|
98
|
+
}
|
|
99
|
+
], {
|
|
100
|
+
onCancel: () => {
|
|
101
|
+
console.log()
|
|
102
|
+
console.log(chalk.red("Cancelled Import!"))
|
|
103
|
+
console.log()
|
|
104
|
+
success = false
|
|
105
|
+
}
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
if (success) {
|
|
109
|
+
console.log()
|
|
110
|
+
const spinner = ora('Dumping DB').start();
|
|
111
|
+
|
|
112
|
+
const dumpCommand = `mysqldump ${resultsDB.dataOnly?'--no-create-info':''} -u${config.dbUser} -p${config.dbPassword} -h${config.dbURL} ${resultsDB.dbName} ${selectedTables.join(" ")} > ${results.dumpName}`;
|
|
113
|
+
|
|
114
|
+
exec(dumpCommand, (error, stdout, stderr) => {
|
|
115
|
+
if (error) {
|
|
116
|
+
spinner.fail('Failed to dump DB');
|
|
117
|
+
console.error(error);
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
spinner.succeed("Dumped DB to " + results.dumpName);
|
|
122
|
+
console.log();
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export async function dumpDBMand(cli) {
|
|
131
|
+
console.log()
|
|
132
|
+
|
|
133
|
+
const config = await Config.getConfig();
|
|
134
|
+
|
|
135
|
+
const databaseNames = await DB.getDatabaseNames();
|
|
136
|
+
|
|
137
|
+
let success = true;
|
|
138
|
+
|
|
139
|
+
const results = await prompts([
|
|
140
|
+
{
|
|
141
|
+
// DB-Auswahl von DB
|
|
142
|
+
type: 'autocomplete',
|
|
143
|
+
name: 'dbName',
|
|
144
|
+
message: 'DB-Name?',
|
|
145
|
+
choices: databaseNames.map(name => { return { title: name.name } })
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
type: 'number',
|
|
149
|
+
name: 'mnr',
|
|
150
|
+
message: 'Mandant?',
|
|
151
|
+
initial: '1'
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
// Ordnerauswahl von vorhandenen Ordner in configIndividual
|
|
155
|
+
type: 'text',
|
|
156
|
+
name: 'dumpName',
|
|
157
|
+
message: 'Dump-Name?',
|
|
158
|
+
initial: 'dump.sql'
|
|
159
|
+
}
|
|
160
|
+
], {
|
|
161
|
+
onCancel: () => {
|
|
162
|
+
console.log()
|
|
163
|
+
console.log(chalk.red("Cancelled Import!"))
|
|
164
|
+
console.log()
|
|
165
|
+
success = false
|
|
166
|
+
}
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
if (success) {
|
|
170
|
+
console.log()
|
|
171
|
+
|
|
172
|
+
const spinner = ora('Dumping DB').start();
|
|
173
|
+
|
|
174
|
+
// Load table names
|
|
175
|
+
let tables = await DB.executeQueryOnDB("SHOW TABLES;", results.dbName);
|
|
176
|
+
const tableKey = Object.keys(tables[0])[0];
|
|
177
|
+
tables = tables.map(row => row[tableKey])
|
|
178
|
+
|
|
179
|
+
if (tables == null || tables.length == 0) {
|
|
180
|
+
spinner.fail("Database has no tables: " + results.dbName)
|
|
181
|
+
} else {
|
|
182
|
+
// Remove previous dump
|
|
183
|
+
rmSync("." + path.sep + results.dumpName, { recursive: true, force: true })
|
|
184
|
+
for (const table of tables) {
|
|
185
|
+
// Check if Mand-Column exists
|
|
186
|
+
const tableSpinner = ora("Dumping data: " + table).start();
|
|
187
|
+
const tableCol = table + "_mnr"
|
|
188
|
+
const columnExists = await DB.executeQueryOnDB("SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = '" + results.dbName + "' AND table_name = '" + table + "' AND column_name = '" + tableCol + "';")
|
|
189
|
+
|
|
190
|
+
if (columnExists[0]['COUNT(*)'] != 0) {
|
|
191
|
+
// Check if Mand-Data is present
|
|
192
|
+
const dataExists = await DB.executeQueryOnDB("SELECT COUNT(*) FROM " + table + " WHERE " + tableCol + " = '" + results.mnr + "';", results.dbName);
|
|
193
|
+
|
|
194
|
+
if (dataExists[0]['COUNT(*)'] != 0) {
|
|
195
|
+
// Dump table
|
|
196
|
+
execSync("mysqldump -u" + config.dbUser + " -p" + config.dbPassword + " -h" + config.dbURL + " --no-create-info --where=\"" + tableCol + " = '" + results.mnr + "'\" " + results.dbName + " " + table + " >> " + results.dumpName);
|
|
197
|
+
|
|
198
|
+
tableSpinner.succeed("Data dumped: " + table);
|
|
199
|
+
} else {
|
|
200
|
+
tableSpinner.info("No data present, Skipping table: " + table)
|
|
201
|
+
}
|
|
202
|
+
} else {
|
|
203
|
+
tableSpinner.info("Column " + tableCol + " not found, Skipping table: " + table)
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
// Dump mand-table (special field name)
|
|
207
|
+
const tableSpinner = ora("Dumping mand (custom logic)")
|
|
208
|
+
execSync("mysqldump -u" + config.dbUser + " -p" + config.dbPassword + " -h" + config.dbURL + " --no-create-info --where=\"mand_mandant = '" + results.mnr + "'\" " + results.dbName + " mand >> " + results.dumpName);
|
|
209
|
+
tableSpinner.succeed("Data dumped: mand")
|
|
210
|
+
spinner.succeed("Dumped DB to " + results.dumpName);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
console.log();
|
|
215
|
+
}
|
|
216
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import nReadlines from 'n-readlines';
|
|
3
|
+
import prompts from "prompts";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import ora from "ora";
|
|
6
|
+
import Seven from 'node-7z'
|
|
7
|
+
import sevenBin from '7zip-bin'
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
export default async function dumpTableToCSV() {
|
|
11
|
+
console.log()
|
|
12
|
+
|
|
13
|
+
let success = true;
|
|
14
|
+
|
|
15
|
+
const results = await prompts([
|
|
16
|
+
{
|
|
17
|
+
// Tabelle die exportiert werden soll
|
|
18
|
+
type: 'text',
|
|
19
|
+
name: 'table',
|
|
20
|
+
message: 'Tabellen-Name?'
|
|
21
|
+
}
|
|
22
|
+
], {
|
|
23
|
+
onCancel: () => {
|
|
24
|
+
console.log()
|
|
25
|
+
console.log(chalk.red("Cancelled Dump!"))
|
|
26
|
+
console.log()
|
|
27
|
+
success = false
|
|
28
|
+
}
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
if (success) {
|
|
33
|
+
console.log()
|
|
34
|
+
|
|
35
|
+
// Unpack archives
|
|
36
|
+
let archives = fs.readdirSync(process.cwd(), { withFileTypes: true }).filter(dirent => dirent.isFile() && (dirent.name.split(".")[dirent.name.split(".").length-1] == "gz") || (dirent.name.split(".")[dirent.name.split(".").length-1] == "7z")).map(dirent => { return dirent.name });
|
|
37
|
+
for (const archive of archives){
|
|
38
|
+
await extractDumpsFromArchive(archive)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
console.log()
|
|
42
|
+
|
|
43
|
+
// Read Files and create csv
|
|
44
|
+
let files = fs.readdirSync(process.cwd(), { withFileTypes: true }).filter(dirent => dirent.isFile() && dirent.name.split(".")[dirent.name.split(".").length-1] == "sql").map(dirent => { return dirent.name });
|
|
45
|
+
|
|
46
|
+
await Promise.all(files.map(async (file) => {
|
|
47
|
+
await createCSVDump(file, results.table)
|
|
48
|
+
}));
|
|
49
|
+
|
|
50
|
+
console.log()
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function getPromiseFromEvent(item, event) {
|
|
55
|
+
return new Promise((resolve) => {
|
|
56
|
+
const listener = (data) => {
|
|
57
|
+
resolve(data);
|
|
58
|
+
}
|
|
59
|
+
item.on(event, listener);
|
|
60
|
+
})
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async function extractDumpsFromArchive(archive){
|
|
64
|
+
const spinnerZIP = ora('Unpacking Archive: '+archive).start();
|
|
65
|
+
|
|
66
|
+
const list = Seven.list(process.cwd() + path.sep + archive, {
|
|
67
|
+
$bin: sevenBin.path7za
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
const data = await getPromiseFromEvent(list, "data")
|
|
71
|
+
|
|
72
|
+
let file = data.file
|
|
73
|
+
|
|
74
|
+
if(file.split(".").length == 1){
|
|
75
|
+
const rename = Seven.rename(process.cwd() + path.sep + archive,[[file, file+".sql"]], {
|
|
76
|
+
$bin: sevenBin.path7za
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
await getPromiseFromEvent(rename, "end")
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const unpack = Seven.extract(process.cwd() + path.sep + archive,"."+path.sep, {
|
|
83
|
+
$bin: sevenBin.path7za
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
await getPromiseFromEvent(unpack, "end")
|
|
87
|
+
|
|
88
|
+
spinnerZIP.succeed("Archive unpacked: "+archive)
|
|
89
|
+
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async function createCSVDump(file, table) {
|
|
93
|
+
let count = 0;
|
|
94
|
+
const spinner = ora('Reading file (' + file +"): "+count).start();
|
|
95
|
+
const readFile = new nReadlines(process.cwd() + path.sep + file);
|
|
96
|
+
|
|
97
|
+
let line = "";
|
|
98
|
+
let data = "";
|
|
99
|
+
let readHeader = false;
|
|
100
|
+
let headerData = "";
|
|
101
|
+
|
|
102
|
+
while ((line = readFile.next())) {
|
|
103
|
+
line = line.toString('utf-8').trim()
|
|
104
|
+
|
|
105
|
+
if (line.includes("INSERT INTO `" + table + "` VALUES")) {
|
|
106
|
+
data = data + line;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (line.includes("CREATE TABLE `" + table + "`")) {
|
|
110
|
+
readHeader = true;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (readHeader) {
|
|
114
|
+
if (line.includes("PRIMARY KEY")) {
|
|
115
|
+
readHeader = false;
|
|
116
|
+
} else {
|
|
117
|
+
headerData = headerData.concat(line);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
count++;
|
|
123
|
+
spinner.text = 'Reading file (' + file +"): "+count
|
|
124
|
+
spinner.render()
|
|
125
|
+
}
|
|
126
|
+
spinner.text = 'Writing file (' + file +")"
|
|
127
|
+
spinner.render()
|
|
128
|
+
|
|
129
|
+
let headers = []
|
|
130
|
+
let matchHeader = new RegExp(/`(.*?)`/g);
|
|
131
|
+
var found;
|
|
132
|
+
while (found = matchHeader.exec(headerData)) {
|
|
133
|
+
if (found[0] != "`" + table + "`") {
|
|
134
|
+
headers.push(found[0]);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
let records = [];
|
|
140
|
+
var reBrackets = /\((.*?)\)/g;
|
|
141
|
+
var found;
|
|
142
|
+
while (found = reBrackets.exec(data)) {
|
|
143
|
+
records.push(found[1]);
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
let recordsString = records.join("\n").replaceAll(",", ";");
|
|
147
|
+
let headersString = headers.join(";")
|
|
148
|
+
|
|
149
|
+
if (!fs.existsSync(process.cwd() + path.sep + "csv")) {
|
|
150
|
+
fs.mkdirSync(process.cwd() + path.sep + "csv")
|
|
151
|
+
}
|
|
152
|
+
fs.writeFileSync(process.cwd() + path.sep + "csv" + path.sep + file.split(".")[0] + ".csv", headersString + "\n" + recordsString)
|
|
153
|
+
spinner.succeed("CSV created: "+file.split(".")[0] + ".csv")
|
|
154
|
+
}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { DB } from "../utils/db/DB.js";
|
|
2
|
+
import prompts from "prompts";
|
|
3
|
+
import CliTable3 from "cli-table3";
|
|
4
|
+
import readline from "readline";
|
|
5
|
+
import chalk from "chalk";
|
|
6
|
+
import fuzzysort from "fuzzysort";
|
|
7
|
+
|
|
8
|
+
// Entry point
|
|
9
|
+
export default async function extdSearch() {
|
|
10
|
+
const responses = await configureDB();
|
|
11
|
+
|
|
12
|
+
if (!responses.dbName) return;
|
|
13
|
+
|
|
14
|
+
let currentSearchType = configs[0];
|
|
15
|
+
let lastQuery = '';
|
|
16
|
+
|
|
17
|
+
const baseData = await loadData(responses.dbName, responses.tables);
|
|
18
|
+
const rl = createReadline();
|
|
19
|
+
|
|
20
|
+
console.log(chalk.green("Interactive Search Started."));
|
|
21
|
+
rl.prompt();
|
|
22
|
+
|
|
23
|
+
rl.on('line', async (input) => {
|
|
24
|
+
const query = input.trim();
|
|
25
|
+
|
|
26
|
+
if (handleBuiltInCommands(query, rl)) return;
|
|
27
|
+
|
|
28
|
+
const matchedConfig = configs.find(c => query === `:${c.cmd}`);
|
|
29
|
+
if (matchedConfig) {
|
|
30
|
+
currentSearchType = matchedConfig;
|
|
31
|
+
} else {
|
|
32
|
+
lastQuery = query;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const results = await fuzzySearch(baseData, lastQuery, currentSearchType);
|
|
36
|
+
renderTable(results, currentSearchType);
|
|
37
|
+
rl.prompt();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
rl.on('close', () => {
|
|
41
|
+
console.log(chalk.yellow("Search session ended."));
|
|
42
|
+
process.exit(0);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function createReadline() {
|
|
47
|
+
return readline.createInterface({
|
|
48
|
+
input: process.stdin,
|
|
49
|
+
output: process.stdout,
|
|
50
|
+
prompt: 'Search query (show help with :?)> '
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function handleBuiltInCommands(query, rl) {
|
|
55
|
+
switch (query) {
|
|
56
|
+
case ':q':
|
|
57
|
+
rl.close();
|
|
58
|
+
return true;
|
|
59
|
+
case ':?':
|
|
60
|
+
printHelp();
|
|
61
|
+
rl.prompt();
|
|
62
|
+
return true;
|
|
63
|
+
default:
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function printHelp() {
|
|
69
|
+
console.log("\n" + chalk.cyan("Available Commands:"));
|
|
70
|
+
console.log(chalk.yellow(":q") + " - Exit the application");
|
|
71
|
+
console.log(chalk.yellow(":?") + " - Show this help");
|
|
72
|
+
configs.forEach(config =>
|
|
73
|
+
console.log(`${chalk.yellow(`:${config.cmd}`)} - Switch to ${config.name}`)
|
|
74
|
+
);
|
|
75
|
+
console.log();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async function configureDB() {
|
|
79
|
+
console.log();
|
|
80
|
+
const databaseNames = await DB.getDatabaseNames();
|
|
81
|
+
|
|
82
|
+
return await prompts([
|
|
83
|
+
{
|
|
84
|
+
type: 'autocomplete',
|
|
85
|
+
name: 'dbName',
|
|
86
|
+
message: 'DB-Name?',
|
|
87
|
+
choices: databaseNames.map(db => ({ title: db.name }))
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
type: 'select',
|
|
91
|
+
name: 'tables',
|
|
92
|
+
message: 'Search-Type?',
|
|
93
|
+
choices: [
|
|
94
|
+
{ title: 'EXTD/EXTI', value: 'EXTD/EXTI' },
|
|
95
|
+
{ title: 'EXTI only', value: 'EXTI' },
|
|
96
|
+
{ title: 'EXTD only', value: 'EXTD' }
|
|
97
|
+
]
|
|
98
|
+
}
|
|
99
|
+
], {
|
|
100
|
+
onCancel: () => {
|
|
101
|
+
console.log("\n" + chalk.red("Cancelled Search!\n"));
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async function loadData(db, tableChoice) {
|
|
107
|
+
const extd = await getTableData('extd', db);
|
|
108
|
+
const exti = await getTableData('exti', db);
|
|
109
|
+
|
|
110
|
+
const cleaned = [
|
|
111
|
+
...cleanData(extd, 'extd'),
|
|
112
|
+
...cleanData(exti, 'exti')
|
|
113
|
+
];
|
|
114
|
+
|
|
115
|
+
if (tableChoice === 'EXTD') return cleaned.filter(e => e.table === 'extd');
|
|
116
|
+
if (tableChoice === 'EXTI') return cleaned.filter(e => e.table === 'exti');
|
|
117
|
+
return cleaned;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function cleanData(entries, tableName) {
|
|
121
|
+
return entries.map(entry => {
|
|
122
|
+
const stripped = Object.fromEntries(Object.entries(entry).map(([k, v]) => {
|
|
123
|
+
return [k.replace(/^ext[di]_/, ''), v];
|
|
124
|
+
}));
|
|
125
|
+
return { ...stripped, table: tableName };
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async function getTableData(table, db) {
|
|
130
|
+
const query = `SELECT * FROM ${table};`;
|
|
131
|
+
return await DB.executeQueryOnDB(query, db);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async function fuzzySearch(data, query, config) {
|
|
135
|
+
if (!query) return data.slice(0, 1000);
|
|
136
|
+
return fuzzysort.go(query, data, {
|
|
137
|
+
keys: config.searchKeys,
|
|
138
|
+
limit: 1000,
|
|
139
|
+
threshold: config.threshold
|
|
140
|
+
}).map(r => ({ ...r.obj, score: r.score }));
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function renderTable(data, config) {
|
|
144
|
+
const table = new CliTable3({ head: config.tableHeader });
|
|
145
|
+
data.forEach(row => table.push(config.tableFormatter(row)));
|
|
146
|
+
console.log(table.toString());
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// ---------- Configurations & Helpers ----------
|
|
150
|
+
|
|
151
|
+
const configs = [
|
|
152
|
+
{
|
|
153
|
+
name: "Overview",
|
|
154
|
+
cmd: "ow",
|
|
155
|
+
searchKeys: ['name', 'bez_d', 'bez_f', 'bez_i'],
|
|
156
|
+
threshold: 0.7,
|
|
157
|
+
tableHeader: ['Table', 'Name', 'Bezeichnung Deutsch', 'Bezeichnung Französisch', 'Bezeichnung Italieniesch'],
|
|
158
|
+
tableFormatter: p => [p.table, p.name, p.bez_d, p.bez_f, p.bez_i]
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
name: "Field-Information",
|
|
162
|
+
cmd: "fi",
|
|
163
|
+
searchKeys: [
|
|
164
|
+
'name', 'bez_d', 'bez_f', 'bez_i',
|
|
165
|
+
'b_dtext_1', 'b_dtext_2', 'b_dtext_3',
|
|
166
|
+
'b_dtext_4', 'b_dtext_5', 'b_dtext_6',
|
|
167
|
+
'b_dtext_7', 'b_dtext_8', 'b_dtext_9'
|
|
168
|
+
],
|
|
169
|
+
threshold: 0.7,
|
|
170
|
+
tableHeader: ['Table', 'Name', 'Feldtyp', 'Flag', 'Testflag', 'Wert 1', 'Wert 2', 'Wert 3', 'Wert 4', 'Wert 5', 'Wert 6', 'Wert 7', 'Wert 8', 'Wert 9'],
|
|
171
|
+
tableFormatter: p => [
|
|
172
|
+
p.table, p.name,
|
|
173
|
+
formatFieldType(p.special),
|
|
174
|
+
formatFlag(p.flag),
|
|
175
|
+
formatTestFlag(p.testflag),
|
|
176
|
+
...Array.from({ length: 9 }, (_, i) => formatWert(p[`b_value_${i + 1}`], p[`b_dtext_${i + 1}`]))
|
|
177
|
+
]
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
name: "Disp-Fields",
|
|
181
|
+
cmd: "df",
|
|
182
|
+
searchKeys: [
|
|
183
|
+
'name', 'bez_d', 'testfeld',
|
|
184
|
+
'disp_feld_1', 'disp_feld_2', 'disp_feld_3',
|
|
185
|
+
'disp_feld_4', 'disp_feld_5', 'disp_feld_6',
|
|
186
|
+
'disp_feld_7', 'disp_feld_8', 'disp_feld_9'
|
|
187
|
+
],
|
|
188
|
+
threshold: 0.7,
|
|
189
|
+
tableHeader: ['Table', 'Name', 'Test-Feld', 'Dispmask', 'Dispfeld 1', 'Dispfeld 2', 'Dispfeld 3', 'Dispfeld 4', 'Dispfeld 5', 'Dispfeld 6', 'Dispfeld 7', 'Dispfeld 8', 'Dispfeld 9'],
|
|
190
|
+
tableFormatter: p => [
|
|
191
|
+
p.table, p.name, p.testfeld, p.dispmask,
|
|
192
|
+
p.disp_feld_1, p.disp_feld_2, p.disp_feld_3,
|
|
193
|
+
p.disp_feld_4, p.disp_feld_5, p.disp_feld_6,
|
|
194
|
+
p.disp_feld_7, p.disp_feld_8, p.disp_feld_9
|
|
195
|
+
]
|
|
196
|
+
}
|
|
197
|
+
];
|
|
198
|
+
|
|
199
|
+
function formatWert(value, bez) {
|
|
200
|
+
return value || bez ? `'${value}'='${bez}'` : '';
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function formatFieldType(type) {
|
|
204
|
+
return {
|
|
205
|
+
'0': 'Custom',
|
|
206
|
+
'1': 'Checkbox',
|
|
207
|
+
'2': 'Radiobutton',
|
|
208
|
+
'4': 'Text'
|
|
209
|
+
}[type] || '';
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function formatFlag(flag) {
|
|
213
|
+
return {
|
|
214
|
+
'0': 'Optional',
|
|
215
|
+
'1': 'Zwingend',
|
|
216
|
+
'2': 'Aus',
|
|
217
|
+
'3': 'Dialog aus'
|
|
218
|
+
}[flag] || '';
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function formatTestFlag(flag) {
|
|
222
|
+
return {
|
|
223
|
+
'0': 'Zwingend',
|
|
224
|
+
'1': 'Null/Space erlaubt'
|
|
225
|
+
}[flag] || '';
|
|
226
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import prompts from "prompts";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import graphql from "graphql"
|
|
4
|
+
import { writeFileSync, readFileSync, readdirSync, writeFile, unlinkSync, mkdirSync, renameSync, rmSync } from "fs";
|
|
5
|
+
|
|
6
|
+
export default async function qraphqlSchemaExport(){
|
|
7
|
+
console.log()
|
|
8
|
+
|
|
9
|
+
let success = true;
|
|
10
|
+
|
|
11
|
+
const responses = await prompts([{
|
|
12
|
+
type: 'text',
|
|
13
|
+
name: 'url',
|
|
14
|
+
message: 'URL?',
|
|
15
|
+
initial: "http://localhost:8080/graphql"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
type: 'text',
|
|
19
|
+
name: 'token',
|
|
20
|
+
message: 'AUTH-Token?'
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
type: 'text',
|
|
24
|
+
name: 'file',
|
|
25
|
+
message: 'File-Name?',
|
|
26
|
+
initial: 'schema.graphqls'
|
|
27
|
+
}], {
|
|
28
|
+
onCancel: () => {
|
|
29
|
+
console.log()
|
|
30
|
+
console.log(chalk.red("Cancelled GraphQL-Schema-Export!"))
|
|
31
|
+
console.log()
|
|
32
|
+
success = false
|
|
33
|
+
}
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
if(success){
|
|
37
|
+
console.log()
|
|
38
|
+
|
|
39
|
+
try{
|
|
40
|
+
const {data, errors} = await fetch(responses.url, {
|
|
41
|
+
method: "POST",
|
|
42
|
+
headers: {
|
|
43
|
+
"Content-Type": "application/json",
|
|
44
|
+
"Accept": "application/json",
|
|
45
|
+
"Authorization": "Bearer "+responses.token
|
|
46
|
+
},
|
|
47
|
+
body: JSON.stringify({query: graphql.getIntrospectionQuery()})
|
|
48
|
+
}).then(res => res.json())
|
|
49
|
+
|
|
50
|
+
const schema = graphql.buildClientSchema(data)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
writeFileSync(responses.file, graphql.printSchema(schema))
|
|
54
|
+
console.log(chalk.green("Schema loaded: "+responses.file))
|
|
55
|
+
console.log();
|
|
56
|
+
}catch(e){
|
|
57
|
+
console.log(chalk.red("Error loading schema: "+e))
|
|
58
|
+
console.log();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|