beech-api 3.8.0 → 3.9.0-beta.8-rc
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 +498 -130
- package/package.json +12 -12
- package/packages/cli/bin/beech-app.js +3 -3
- package/packages/cli/bin/beech-service.js +61 -25
- package/packages/cli/core/auth/Credentials.js +92 -87
- package/packages/cli/core/auth/Passport.js +111 -39
- package/packages/cli/core/configure/passport.config.js +1 -1
- package/packages/cli/core/databases/mysql.js +1 -1
- package/packages/cli/core/databases/sequelize.js +15 -6
- package/packages/cli/core/databases/test.js +124 -38
- package/packages/cli/core/generator/_models +3 -26
- package/packages/cli/core/generator/_models_basic +0 -9
- package/packages/cli/core/generator/_package +2 -2
- package/packages/cli/core/generator/index.js +197 -23
- package/packages/cli/core/helpers/2fa.js +22 -1
- package/packages/cli/core/helpers/math.js +14 -2
- package/packages/cli/core/helpers/poolEntity.js +70 -26
- package/packages/cli/core/index.js +8 -3
- package/packages/cli/core/middleware/express/jwtCheckAllow.js +52 -34
- package/packages/cli/core/middleware/origin/guard/advance.js +5 -4
- package/packages/cli/core/services/http.express.js +0 -2
- package/packages/lib/src/endpoint.js +306 -103
- package/packages/lib/src/schema.js +4 -1
|
@@ -27,7 +27,7 @@ connectInProcess = async (database_config, headDbShow, cb) => {
|
|
|
27
27
|
// check hash ?
|
|
28
28
|
if(val.username && val.password) {
|
|
29
29
|
if(val.username.length < 55 || val.password < 55) {
|
|
30
|
-
return cb("Error:
|
|
30
|
+
return cb("Error: Incorrect Hash access for connect to database.\n", null);
|
|
31
31
|
}
|
|
32
32
|
let accessDb = [];
|
|
33
33
|
[val.username, val.password].map((e, k) => {
|
|
@@ -102,7 +102,7 @@ connectInProcess = async (database_config, headDbShow, cb) => {
|
|
|
102
102
|
freezeTableName: ((val.define) ? ((val.define.freezeTableName === false) ? val.define.freezeTableName : true) : true),
|
|
103
103
|
charset: ((val.define) ? ((val.define.charset) ? val.define.charset : "utf8") : "utf8"),
|
|
104
104
|
dialectOptions: {
|
|
105
|
-
collate: ((val.define) ? ((val.define.dialectOptions) ? ((val.define.dialectOptions.
|
|
105
|
+
collate: ((val.define) ? ((val.define.dialectOptions) ? ((val.define.dialectOptions.collate) ? val.define.dialectOptions.collate : "utf8_general_ci") : "utf8_general_ci") : "utf8_general_ci"),
|
|
106
106
|
},
|
|
107
107
|
timestamps: ((val.define) ? ((val.define.timestamps) ? val.define.timestamps : false) : false),
|
|
108
108
|
},
|
|
@@ -125,11 +125,19 @@ connectInProcess = async (database_config, headDbShow, cb) => {
|
|
|
125
125
|
|
|
126
126
|
// JSON response
|
|
127
127
|
query: {
|
|
128
|
-
raw: ((val.query) ? ((val.query.raw) ? val.query.raw :
|
|
128
|
+
raw: ((val.query) ? ((val.query.raw) ? val.query.raw : false) : false),
|
|
129
129
|
nest: ((val.query) ? ((val.query.nest) ? val.query.nest : true) : true),
|
|
130
130
|
}
|
|
131
131
|
});
|
|
132
|
-
|
|
132
|
+
|
|
133
|
+
// Hook to set `SET NAMES xxx` (ONLY MySQL)
|
|
134
|
+
await sq.addHook('afterConnect', async (connection) => {
|
|
135
|
+
if(val.dialect == "mysql") {
|
|
136
|
+
let charset = ["SET NAMES", ((val.define) ? ((val.define.charset) ? val.define.charset : "utf8") : "utf8")].join(" ");
|
|
137
|
+
connection.query(charset);
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
|
|
133
141
|
// show only one text db connnections
|
|
134
142
|
if (headDbShow) {
|
|
135
143
|
console.log('[102m[90m Passed [0m [0mDatabase is connected at:');
|
|
@@ -144,7 +152,7 @@ connectInProcess = async (database_config, headDbShow, cb) => {
|
|
|
144
152
|
// shuout
|
|
145
153
|
console.log('- [91m[' + val.dialect + '] [0m[36m' + val.name + ' [0m->[93m ' + sq.config.database + ':' + sq.config.port + '[0m');
|
|
146
154
|
}
|
|
147
|
-
|
|
155
|
+
|
|
148
156
|
// connection
|
|
149
157
|
await sq.authenticate()
|
|
150
158
|
.then(() => {
|
|
@@ -161,7 +169,8 @@ connectInProcess = async (database_config, headDbShow, cb) => {
|
|
|
161
169
|
}
|
|
162
170
|
})
|
|
163
171
|
.catch(err => {
|
|
164
|
-
console.
|
|
172
|
+
console.log("Unable to connect to the database:", err);
|
|
173
|
+
cb(err, null);
|
|
165
174
|
});
|
|
166
175
|
});
|
|
167
176
|
} else {
|
|
@@ -2,6 +2,7 @@ const logUpdate = require("log-update");
|
|
|
2
2
|
const emoji = require('node-emoji')
|
|
3
3
|
const { DeHashIt, M, X } = require(__dirname + "/../helpers/math");
|
|
4
4
|
const Sequelize = require('sequelize');
|
|
5
|
+
const fs = require("fs");
|
|
5
6
|
let testSql = {};
|
|
6
7
|
|
|
7
8
|
function filterDbIsTrue(dbConfig, cb) {
|
|
@@ -25,42 +26,44 @@ function filterDbIsTrue(dbConfig, cb) {
|
|
|
25
26
|
}
|
|
26
27
|
}
|
|
27
28
|
|
|
28
|
-
function testConnectInProcess
|
|
29
|
+
function testConnectInProcess(database_config, dbConnTotal, cb) {
|
|
29
30
|
try {
|
|
31
|
+
// Recursive test connection
|
|
30
32
|
let val = database_config.shift();
|
|
31
33
|
if (val) {
|
|
32
|
-
initSequelize(val, async (err, sq) => {
|
|
34
|
+
initSequelize(val, true, async (err, sq) => {
|
|
33
35
|
if (err) {
|
|
34
|
-
console.
|
|
35
|
-
cb(err, null, null);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
36
|
+
//console.log("[101m Failed [0m Can't connect to connection name:[36m", val.name, "[0m\n", err);
|
|
37
|
+
return cb(err, null, null);
|
|
38
|
+
} else {
|
|
39
|
+
// Test connection
|
|
40
|
+
await sq.authenticate()
|
|
41
|
+
.then(() => {
|
|
42
|
+
// Database some is true perfectly.
|
|
43
|
+
if (database_config.length == 0) {
|
|
44
|
+
if (sq) {
|
|
45
|
+
testSql[ val.name ] = sq;
|
|
46
|
+
//console.log("DB true, Perfectly.", val.name);
|
|
47
|
+
return cb(null, true, testSql);
|
|
48
|
+
}
|
|
49
|
+
} else {
|
|
43
50
|
testSql[ val.name ] = sq;
|
|
44
|
-
|
|
45
|
-
cb(null, true, testSql);
|
|
51
|
+
testConnectInProcess(database_config, dbConnTotal, cb);
|
|
46
52
|
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
console.error("[101m Failed [0m Unable to connect to the database:[36m", val.name, "[0m\n", err);
|
|
54
|
-
cb(err, null, null);
|
|
55
|
-
});
|
|
53
|
+
})
|
|
54
|
+
.catch(err => {
|
|
55
|
+
console.log("[101m Failed [0m Unable to connect to the database:[36m", val.name, "[0m\n", err);
|
|
56
|
+
return cb(err, null, null);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
56
59
|
});
|
|
57
60
|
} else if (!dbConnTotal) {
|
|
58
61
|
// All Database is falsly perfectly.
|
|
59
62
|
//console.log("DB all false, Perfectly.");
|
|
60
|
-
cb(null, true, testSql);
|
|
63
|
+
return cb(null, true, testSql);
|
|
61
64
|
}
|
|
62
65
|
} catch (error) {
|
|
63
|
-
cb(error, null, null);
|
|
66
|
+
return cb(error, null, null);
|
|
64
67
|
}
|
|
65
68
|
}
|
|
66
69
|
|
|
@@ -88,33 +91,69 @@ function logit(msg, next = false) {
|
|
|
88
91
|
}
|
|
89
92
|
}
|
|
90
93
|
|
|
91
|
-
function initSequelize(val, cb) {
|
|
94
|
+
function initSequelize(val, testConn = true, cb) {
|
|
92
95
|
try {
|
|
93
96
|
const promise = new Promise((resolve) => {
|
|
94
97
|
// check hash ?
|
|
95
98
|
if(val.username && val.password) {
|
|
96
99
|
if(val.username.length < 55 || val.password < 55) {
|
|
97
|
-
return cb("[
|
|
100
|
+
return cb("[91mERR:[0m Incorrect Hash access for connect to database, Please Hashing your access by command `beech hash:<your_access>`\n", null);
|
|
98
101
|
}
|
|
99
102
|
let accessDb = [];
|
|
100
|
-
[val.username, val.password].map((e, k) => {
|
|
101
|
-
DeHashIt(e.toString(), null, (17).toString().slice(0,-1).length, (err, d) => {
|
|
102
|
-
if(
|
|
103
|
-
|
|
103
|
+
[val.username, val.password].map(async (e, k) => {
|
|
104
|
+
await DeHashIt(e.toString(), null, (17).toString().slice(0,-1).length, async (err, d) => {
|
|
105
|
+
if(err) {
|
|
106
|
+
cb("[91mERR:[0m Hash access error,", err);
|
|
107
|
+
throw err;
|
|
108
|
+
}
|
|
109
|
+
accessDb.push(d.split("sh,")[1].split(M(X).toString().slice(0,2)+M(X).toString())[0].slice(0,-1));
|
|
110
|
+
// Finally username & password
|
|
111
|
+
if(k+1==2) {
|
|
112
|
+
// Last push dialect connection
|
|
113
|
+
accessDb.push(val.dialect);
|
|
114
|
+
// resolve it
|
|
115
|
+
resolve(accessDb);
|
|
104
116
|
}
|
|
105
117
|
});
|
|
106
|
-
if(k+1==2) {
|
|
107
|
-
resolve(accessDb);
|
|
108
|
-
}
|
|
109
118
|
});
|
|
110
119
|
} else {
|
|
111
120
|
resolve([null, null]);
|
|
112
121
|
}
|
|
113
122
|
});
|
|
114
123
|
Promise.all([promise]).then(final => {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
124
|
+
/**
|
|
125
|
+
* The final callback variable : [['hashed', 'hashed', 'dialect']]
|
|
126
|
+
*
|
|
127
|
+
* final[0][0] : username hashed
|
|
128
|
+
* final[0][1] : password hashed
|
|
129
|
+
* final[0][2] : dialect
|
|
130
|
+
*
|
|
131
|
+
*/
|
|
132
|
+
|
|
133
|
+
// Check test connection for stdout pre-flight
|
|
134
|
+
if(testConn) {
|
|
135
|
+
// stdout pre-flight connection
|
|
136
|
+
logit(`- [91m[${val.dialect}] [0m[36m${val.name}[0m`);
|
|
137
|
+
logit(emoji.get('heavy_multiplication_x') + ` [91m[${val.dialect}] [0m[36m${val.name}[0m`);
|
|
138
|
+
}
|
|
139
|
+
fs.readFile("./global.config.js", 'utf8', (err, data) => {
|
|
140
|
+
if (err) {
|
|
141
|
+
console.log("\n[101m Faltal [0m Can't read `global.config.js` file.\n", err);
|
|
142
|
+
return; // break;
|
|
143
|
+
} else {
|
|
144
|
+
let buffer = Buffer.from(data);
|
|
145
|
+
let buf2str = buffer.toString();
|
|
146
|
+
let buf2json = JSON.parse(JSON.stringify(buf2str));
|
|
147
|
+
let pool_base = /global.pool_base\s+=\s+(?:"|')([^"]+)(?:"|')(?:\r|\n|$|;|\r)/i.exec(buf2json);
|
|
148
|
+
if (pool_base) {
|
|
149
|
+
if(pool_base == "basic") {
|
|
150
|
+
if(final[0][2] != "mysql") {
|
|
151
|
+
return cb(`The Basic pool engine not support with: ${val.dialect}, Please use Sequelize engine.`, null);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
});
|
|
118
157
|
// create connection
|
|
119
158
|
const sq = new Sequelize({
|
|
120
159
|
dialect: val.dialect || "mysql",
|
|
@@ -157,7 +196,10 @@ function initSequelize(val, cb) {
|
|
|
157
196
|
nest: ((val.query) ? ((val.query.nest) ? val.query.nest : true) : true),
|
|
158
197
|
}
|
|
159
198
|
});
|
|
160
|
-
|
|
199
|
+
// Check test connection for stdout pre-flight (mark)
|
|
200
|
+
if(testConn) {
|
|
201
|
+
logit(emoji.get('heavy_check_mark') + ` [91m[${val.dialect}] [0m[36m${val.name}[0m`, true);
|
|
202
|
+
}
|
|
161
203
|
cb(false, sq);
|
|
162
204
|
}).catch(err => {
|
|
163
205
|
console.log(`[103m[90m Warning [0m[0m Connection name \`[93m${val.name}[0m\``, err);
|
|
@@ -167,4 +209,48 @@ function initSequelize(val, cb) {
|
|
|
167
209
|
}
|
|
168
210
|
}
|
|
169
211
|
|
|
170
|
-
|
|
212
|
+
function connectForGenerateModel(dbConnectName, tableName, databaseConfig, cb) {
|
|
213
|
+
/**
|
|
214
|
+
* Callback
|
|
215
|
+
*
|
|
216
|
+
* err String : Error message
|
|
217
|
+
* tableSchema Object : Schema of table
|
|
218
|
+
* tableName String : table name
|
|
219
|
+
*
|
|
220
|
+
*/
|
|
221
|
+
const connectionChoose = databaseConfig.filter((e) => e.name == dbConnectName)[0];
|
|
222
|
+
initSequelize(connectionChoose, false, async (err, sq) => {
|
|
223
|
+
if (err) {
|
|
224
|
+
cb(err, null, null);
|
|
225
|
+
}
|
|
226
|
+
// Connection
|
|
227
|
+
await sq.authenticate()
|
|
228
|
+
.then(() => {
|
|
229
|
+
getTableSchema(sq, tableName, (errSchema, tableSchema) => {
|
|
230
|
+
if(errSchema) {
|
|
231
|
+
cb(errSchema, null, null);
|
|
232
|
+
} else {
|
|
233
|
+
// Closing database
|
|
234
|
+
sq.close();
|
|
235
|
+
// Callback
|
|
236
|
+
cb(null, tableSchema, tableName);
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
})
|
|
240
|
+
.catch(err => {
|
|
241
|
+
cb(err, null, null);
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
async function getTableSchema(sq, tableName, cb) {
|
|
247
|
+
try {
|
|
248
|
+
const queryInterface = sq.getQueryInterface();
|
|
249
|
+
const schema = await queryInterface.describeTable(tableName);
|
|
250
|
+
cb(null, schema);
|
|
251
|
+
} catch (error) {
|
|
252
|
+
cb("Fetching table schema " + error, null);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
module.exports = { filterDbIsTrue, testConnectInProcess, disConnectTestDB, connectForGenerateModel }
|
|
@@ -1,29 +1,6 @@
|
|
|
1
1
|
const { Schema } = require("beech-api");
|
|
2
2
|
// {{modelNameUppercase}} structure
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
field: "id",
|
|
6
|
-
type: DataTypes.INTEGER,
|
|
7
|
-
autoIncrement: true,
|
|
8
|
-
primaryKey: true,
|
|
9
|
-
},
|
|
10
|
-
examField1: DataTypes.STRING,
|
|
11
|
-
examField3: DataTypes.DATE,
|
|
12
|
-
examField4: {
|
|
13
|
-
type: DataTypes.STRING,
|
|
14
|
-
allowNull: false,
|
|
15
|
-
// set(value) {
|
|
16
|
-
// this.setDataValue("examField4", md5(value));
|
|
17
|
-
// },
|
|
18
|
-
},
|
|
19
|
-
createdAt: DataTypes.DATE,
|
|
20
|
-
updatedAt: DataTypes.DATE,
|
|
21
|
-
// Asign more DataTypes, Learn more: https://sequelize.org/docs/v6/core-concepts/model-basics/#data-types
|
|
22
|
-
});
|
|
3
|
+
{{modelStructure}}
|
|
4
|
+
// Asign more DataTypes, Learn more: https://sequelize.org/docs/v6/core-concepts/model-basics/#data-types
|
|
23
5
|
|
|
24
|
-
|
|
25
|
-
function exampleFindOne{{modelNameUppercase}}ById(id) {
|
|
26
|
-
return {{modelNameUppercase}}.findOne({ where: { id: id } });
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
module.exports = { {{modelNameUppercase}}, exampleFindOne{{modelNameUppercase}}ById };
|
|
6
|
+
module.exports = { {{modelNameUppercase}} };
|
|
@@ -1,14 +1,5 @@
|
|
|
1
1
|
module.exports = {
|
|
2
2
|
|
|
3
|
-
// Example basic function return exam data
|
|
4
|
-
getData() {
|
|
5
|
-
return [
|
|
6
|
-
{ "id": 1, "name": "Oggy" },
|
|
7
|
-
{ "id": 2, "name": "Jack" },
|
|
8
|
-
{ "id": 3, "name": "The Cockroaches Gang" }
|
|
9
|
-
];
|
|
10
|
-
},
|
|
11
|
-
|
|
12
3
|
// Example basic function get data from table {{modelName}}
|
|
13
4
|
findAll() {
|
|
14
5
|
return new Promise((resolve, reject) => {
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
const logUpdate = require("log-update");
|
|
3
3
|
const inquirer = require('inquirer');
|
|
4
4
|
const walk = require("walk");
|
|
5
|
+
const { connectForGenerateModel } = require("../databases/test");
|
|
5
6
|
|
|
6
7
|
class Generator {
|
|
7
8
|
constructor() {
|
|
@@ -190,21 +191,42 @@ class Generator {
|
|
|
190
191
|
this.generateKeyConfigFile()
|
|
191
192
|
.then(resGenKey => resolve(resGenKey))
|
|
192
193
|
.catch(err => reject(err));
|
|
193
|
-
} else if (this.option && this.option.slice(0, 5) ==
|
|
194
|
+
} else if (this.option && this.option.slice(0, 5) == "hash:") {
|
|
195
|
+
const { HashIt, Z } = require(__dirname + "/../helpers/math");
|
|
194
196
|
if(this.option.length > 5) {
|
|
195
|
-
const { HashIt, Z } = require(__dirname + "/../helpers/math");
|
|
196
197
|
Z((err, ak) => {
|
|
197
198
|
if(err) {
|
|
198
199
|
logUpdate(err);
|
|
199
200
|
} else {
|
|
200
201
|
let txt = this.option.split(":");
|
|
201
202
|
HashIt(txt, ak, null, (5).toString().length, (hashed) => {
|
|
202
|
-
logUpdate(hashed);
|
|
203
|
+
logUpdate("\n" + hashed);
|
|
203
204
|
});
|
|
204
205
|
}
|
|
205
206
|
});
|
|
206
207
|
} else {
|
|
207
|
-
|
|
208
|
+
inquirer.prompt([ {
|
|
209
|
+
type: "confirm",
|
|
210
|
+
name: "confirmHashNoText",
|
|
211
|
+
message: "[93mNo text to hash, Do you want to continue ?:[0m",
|
|
212
|
+
} ]).then(confirm => {
|
|
213
|
+
if(confirm.confirmHashNoText) {
|
|
214
|
+
Z((err, ak) => {
|
|
215
|
+
if(err) {
|
|
216
|
+
logUpdate(err);
|
|
217
|
+
} else {
|
|
218
|
+
let txt = this.option.split(":");
|
|
219
|
+
HashIt(txt, ak, null, (5).toString().length, (hashed) => {
|
|
220
|
+
logUpdate("\n" + hashed);
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
} else {
|
|
225
|
+
// no text to hash say no.
|
|
226
|
+
resolve(": Say no.");
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
|
|
208
230
|
}
|
|
209
231
|
} else if (this.option == "skd") {
|
|
210
232
|
if (this.argument == "init") {
|
|
@@ -404,12 +426,12 @@ class Generator {
|
|
|
404
426
|
// check pool_base
|
|
405
427
|
if (pool_base[ 1 ] == "basic") {
|
|
406
428
|
tmpModelsPath += '/_models_basic';
|
|
407
|
-
this.generateModel(tmpModelsPath, dbSelected.selectDbConnect)
|
|
429
|
+
this.generateModel(tmpModelsPath, dbSelected.selectDbConnect, appBuf2eval, pool_base[1])
|
|
408
430
|
.then(console.log)
|
|
409
431
|
.catch(console.log);
|
|
410
432
|
} else if (pool_base[ 1 ] == "sequelize") {
|
|
411
433
|
tmpModelsPath += '/_models';
|
|
412
|
-
this.generateModel(tmpModelsPath, dbSelected.selectDbConnect)
|
|
434
|
+
this.generateModel(tmpModelsPath, dbSelected.selectDbConnect, appBuf2eval, pool_base[1])
|
|
413
435
|
.then(console.log)
|
|
414
436
|
.catch(console.log);
|
|
415
437
|
} else {
|
|
@@ -429,35 +451,114 @@ class Generator {
|
|
|
429
451
|
});
|
|
430
452
|
}
|
|
431
453
|
|
|
432
|
-
generateModel(tmpModelsPath, dbSelected) {
|
|
454
|
+
generateModel(tmpModelsPath, dbSelected, appBuf2eval, pool_base) {
|
|
433
455
|
return new Promise((resolve, reject) => {
|
|
434
456
|
try {
|
|
457
|
+
// Show generating msg
|
|
458
|
+
const frames = [
|
|
459
|
+
'\n[36m[-] Generating[0m',
|
|
460
|
+
'\n[36m[\\] Generating.[0m',
|
|
461
|
+
'\n[36m[|] Generating..[0m',
|
|
462
|
+
'\n[36m[/] Generating...[0m'
|
|
463
|
+
];
|
|
464
|
+
let i = 0;
|
|
465
|
+
var refreshGenerateIntervalId = null;
|
|
466
|
+
// Save model folder
|
|
435
467
|
let modelPath = './src/models/';
|
|
436
|
-
//
|
|
468
|
+
// Argument join `slash`
|
|
437
469
|
let arg = this.argument.replace(/^\/+|\/+$/g, '');
|
|
438
470
|
arg = arg.split('/');
|
|
439
471
|
let models = arg.pop();
|
|
472
|
+
let oriModelsName = models.slice(0);
|
|
440
473
|
models = models.charAt(0).toUpperCase() + models.slice(1);
|
|
441
474
|
let newModel = models.split("_").map(e => e.charAt(0).toUpperCase() + e.slice(1)).join("");
|
|
442
475
|
let subFolder = arg.join('/');
|
|
443
|
-
// models
|
|
476
|
+
// Declare models
|
|
444
477
|
let fullModels = modelPath + subFolder.concat('/') + models.concat('.js');
|
|
445
478
|
|
|
446
|
-
|
|
479
|
+
/**
|
|
480
|
+
* All properties
|
|
481
|
+
*
|
|
482
|
+
* @tmpModelPath String : path to keep generate model file
|
|
483
|
+
* @dbSelect String : database connection name
|
|
484
|
+
* @appBug2eval Object : database connection object
|
|
485
|
+
* @pool_base Object : pool base connection
|
|
486
|
+
*
|
|
487
|
+
* @i Number : loop count running...
|
|
488
|
+
* @refreshGenerateIntervalId Object : for clear interval id
|
|
489
|
+
*
|
|
490
|
+
* @arg String : argument from typing
|
|
491
|
+
* @models String : model name
|
|
492
|
+
* @oriModelsName String : original model name from typing
|
|
493
|
+
* @newModel String : model first upper case
|
|
494
|
+
* @subFolder String : agument sub folder
|
|
495
|
+
* @fullModels String : full model path and model file name
|
|
496
|
+
*
|
|
497
|
+
*/
|
|
498
|
+
// Check file exists
|
|
447
499
|
if (!this.fs.existsSync(fullModels)) {
|
|
448
|
-
//
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
500
|
+
// Check pool base is basic|sequelize
|
|
501
|
+
if(pool_base == "basic") {
|
|
502
|
+
// Generate basic model
|
|
503
|
+
this.makeFolder(modelPath + subFolder)
|
|
504
|
+
.then(this.copy.bind(this, tmpModelsPath, fullModels))
|
|
505
|
+
.then(this.modelContentReplace.bind(this, fullModels, {
|
|
506
|
+
'modelName': oriModelsName,
|
|
507
|
+
'dbSelected': dbSelected,
|
|
508
|
+
}))
|
|
509
|
+
.then(
|
|
510
|
+
refreshGenerateIntervalId = setInterval(() => {
|
|
511
|
+
const frame = frames[i = ++i % frames.length];
|
|
512
|
+
logUpdate(`${frame}`);
|
|
513
|
+
}, 300)
|
|
514
|
+
)
|
|
515
|
+
.then(generated => {
|
|
516
|
+
logUpdate(generated);
|
|
517
|
+
clearInterval(refreshGenerateIntervalId);
|
|
518
|
+
})
|
|
519
|
+
.catch(err => {
|
|
520
|
+
throw err;
|
|
521
|
+
});
|
|
522
|
+
} else if(pool_base == "sequelize") {
|
|
523
|
+
// Gether table schema
|
|
524
|
+
connectForGenerateModel(dbSelected, oriModelsName, appBuf2eval.database_config, (err, tableSchema, tableName) => {
|
|
525
|
+
if(err) {
|
|
526
|
+
throw logUpdate("\n[101m Faltal [0m", String(err), "\n");
|
|
527
|
+
} else {
|
|
528
|
+
// Raw model schema
|
|
529
|
+
this.rawSchemaTable(dbSelected, newModel, tableName, tableSchema, (SchemaErr, rawSchema) => {
|
|
530
|
+
if(err) {
|
|
531
|
+
throw logUpdate("\n[101m Faltal [0m RAW Schema ERR:", String(SchemaErr), "\n");
|
|
532
|
+
} else {
|
|
533
|
+
// Generate sequelize model
|
|
534
|
+
this.makeFolder(modelPath + subFolder)
|
|
535
|
+
.then(this.copy.bind(this, tmpModelsPath, fullModels))
|
|
536
|
+
.then(this.modelContentReplace.bind(this, fullModels, {
|
|
537
|
+
'modelName': oriModelsName,
|
|
538
|
+
'modelNameUppercase': newModel,
|
|
539
|
+
'modelStructure': rawSchema,
|
|
540
|
+
}))
|
|
541
|
+
.then(
|
|
542
|
+
refreshGenerateIntervalId = setInterval(() => {
|
|
543
|
+
const frame = frames[i = ++i % frames.length];
|
|
544
|
+
logUpdate(`${frame}`);
|
|
545
|
+
}, 300)
|
|
546
|
+
)
|
|
547
|
+
.then(generated => {
|
|
548
|
+
logUpdate(generated);
|
|
549
|
+
clearInterval(refreshGenerateIntervalId);
|
|
550
|
+
})
|
|
551
|
+
.catch(err => {
|
|
552
|
+
throw err;
|
|
553
|
+
});
|
|
554
|
+
}
|
|
555
|
+
});
|
|
556
|
+
}
|
|
460
557
|
});
|
|
558
|
+
} else {
|
|
559
|
+
// Fallback (When Accident)
|
|
560
|
+
resolve("\n[101m Faltal [0m The pool_base in `global.config.js` file does not match the specific.");
|
|
561
|
+
}
|
|
461
562
|
} else {
|
|
462
563
|
resolve("\n[103m[90m Warning [0m[0m The model `" + models + "` it's duplicated.");
|
|
463
564
|
}
|
|
@@ -467,6 +568,78 @@ class Generator {
|
|
|
467
568
|
});
|
|
468
569
|
}
|
|
469
570
|
|
|
571
|
+
rawSchemaTable(dbNameSelected, newModelName, tableName, modelSchema, cb) {
|
|
572
|
+
try {
|
|
573
|
+
// Function map type
|
|
574
|
+
const mapToSequelizeType = (rawType) => {
|
|
575
|
+
const type = rawType.toUpperCase();
|
|
576
|
+
// Assign all conditions
|
|
577
|
+
if (type.includes('INT')) return 'DataTypes.INTEGER';
|
|
578
|
+
if (type.includes('BIGINT')) return 'DataTypes.BIGINT';
|
|
579
|
+
if (type.includes('FLOAT')) return 'DataTypes.FLOAT';
|
|
580
|
+
if (type.includes('DOUBLE')) return 'DataTypes.DOUBLE';
|
|
581
|
+
if (type.includes('DECIMAL')) return 'DataTypes.DECIMAL';
|
|
582
|
+
if (type.includes('BOOLEAN') || type === 'TINYINT(1)') return 'DataTypes.BOOLEAN';
|
|
583
|
+
if (type.includes('CHAR')) {
|
|
584
|
+
const match = type.match(/\((\d+)\)/);
|
|
585
|
+
const length = match ? match[1] : '255';
|
|
586
|
+
return `DataTypes.STRING(${length})`;
|
|
587
|
+
}
|
|
588
|
+
if (type.includes('VARCHAR')) {
|
|
589
|
+
const match = type.match(/\((\d+)\)/);
|
|
590
|
+
const length = match ? match[1] : '255';
|
|
591
|
+
return `DataTypes.STRING(${length})`;
|
|
592
|
+
}
|
|
593
|
+
if (type.includes('TEXT')) return 'DataTypes.TEXT';
|
|
594
|
+
if (type.includes('DATE')) return 'DataTypes.DATE';
|
|
595
|
+
if (type.includes('TIME')) return 'DataTypes.TIME';
|
|
596
|
+
if (type.includes('JSON')) return 'DataTypes.JSON';
|
|
597
|
+
if (type.includes('UUID')) return 'DataTypes.UUID';
|
|
598
|
+
if (type.includes('BLOB')) return 'DataTypes.BLOB';
|
|
599
|
+
if (type.includes('ENUM')) return 'DataTypes.ENUM'; // Needs manual values
|
|
600
|
+
if (type.includes('GEOMETRY')) return 'DataTypes.GEOMETRY';
|
|
601
|
+
// Fallback
|
|
602
|
+
return `DataTypes.STRING`;
|
|
603
|
+
};
|
|
604
|
+
// Looping key fields
|
|
605
|
+
const fields = Object.entries(modelSchema).map(([name, props]) => {
|
|
606
|
+
// Declare line
|
|
607
|
+
const lines = [];
|
|
608
|
+
// Push line and assign space for beautiful
|
|
609
|
+
lines.push(` type: ${mapToSequelizeType(props.type)},`);
|
|
610
|
+
lines.push(` allowNull: ${props.allowNull},`);
|
|
611
|
+
// Check is primary key
|
|
612
|
+
if (props.primaryKey) lines.push(` primaryKey: true,`);
|
|
613
|
+
if (props.autoIncrement) lines.push(` autoIncrement: true,`);
|
|
614
|
+
//if (props.comment) lines.push(` comment: '${props.comment}',`);
|
|
615
|
+
|
|
616
|
+
// Handle defaultValue
|
|
617
|
+
if (props.defaultValue !== null && props.defaultValue !== undefined) {
|
|
618
|
+
const defaultVal = String(props.defaultValue).toUpperCase();
|
|
619
|
+
if (
|
|
620
|
+
defaultVal === 'CURRENT_TIMESTAMP' ||
|
|
621
|
+
defaultVal === 'NOW()' ||
|
|
622
|
+
defaultVal.includes('CURRENT_TIMESTAMP')
|
|
623
|
+
) {
|
|
624
|
+
lines.push(` defaultValue: DataTypes.NOW,`);
|
|
625
|
+
} else if (defaultVal === 'UUID()' || defaultVal === 'uuid()' || defaultVal === 'UUID') {
|
|
626
|
+
lines.push(` defaultValue: DataTypes.UUIDV4,`);
|
|
627
|
+
} else if (typeof props.defaultValue === 'string') {
|
|
628
|
+
lines.push(` defaultValue: '${props.defaultValue}',`);
|
|
629
|
+
} else {
|
|
630
|
+
lines.push(` defaultValue: ${props.defaultValue},`);
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
// Finally
|
|
634
|
+
return ` ${name}: {\n${lines.join('\n')}\n }`;
|
|
635
|
+
});
|
|
636
|
+
// Callback
|
|
637
|
+
cb(null, `const ${newModelName} = Schema(sql.${dbNameSelected}).define("${tableName}", {\n${fields.join(',\n')}\n});`);
|
|
638
|
+
} catch (error) {
|
|
639
|
+
cb(error, null);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
|
|
470
643
|
makeHelper() {
|
|
471
644
|
return new Promise((resolve, reject) => {
|
|
472
645
|
try {
|
|
@@ -632,6 +805,7 @@ class Generator {
|
|
|
632
805
|
text = text.replace(new RegExp('{{dbSelected}}', 'g'), textCondition.dbSelected);
|
|
633
806
|
// check add model name text uppercase
|
|
634
807
|
if (Object.keys(textCondition).length > 1) {
|
|
808
|
+
text = text.replace(new RegExp('{{modelStructure}}', 'g'), textCondition.modelStructure);
|
|
635
809
|
text = text.replace(new RegExp('{{modelNameUppercase}}', 'g'), textCondition.modelNameUppercase);
|
|
636
810
|
}
|
|
637
811
|
// writing the file
|
|
@@ -644,7 +818,7 @@ class Generator {
|
|
|
644
818
|
});
|
|
645
819
|
}
|
|
646
820
|
})
|
|
647
|
-
},
|
|
821
|
+
}, 2000);
|
|
648
822
|
} catch (error) {
|
|
649
823
|
reject(error);
|
|
650
824
|
}
|