fix(basic.gblib): Databases. #392 @othonlima.
This commit is contained in:
parent
d8de3b8778
commit
5dd2cc3a29
5 changed files with 154 additions and 102 deletions
|
@ -125,6 +125,7 @@
|
||||||
"lodash": "4.17.21",
|
"lodash": "4.17.21",
|
||||||
"luxon": "3.1.0",
|
"luxon": "3.1.0",
|
||||||
"mammoth": "1.5.1",
|
"mammoth": "1.5.1",
|
||||||
|
"mariadb": "3.2.2",
|
||||||
"mime-types": "2.1.35",
|
"mime-types": "2.1.35",
|
||||||
"moment": "1.3.0",
|
"moment": "1.3.0",
|
||||||
"ms-rest-azure": "3.0.0",
|
"ms-rest-azure": "3.0.0",
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import { GBMinInstance, GBService, IGBCoreService, GBDialogStep, GBLog } from 'botlib';
|
import { GBMinInstance, GBService, IGBCoreService, GBDialogStep, GBLog, GBError } from 'botlib';
|
||||||
import * as Fs from 'fs';
|
import * as Fs from 'fs';
|
||||||
import { GBServer } from '../../../src/app.js';
|
import { GBServer } from '../../../src/app.js';
|
||||||
import { GBDeployer } from '../../core.gbapp/services/GBDeployer.js';
|
import { GBDeployer } from '../../core.gbapp/services/GBDeployer.js';
|
||||||
|
@ -205,7 +205,33 @@ export class GBVMService extends GBService {
|
||||||
|
|
||||||
const tableDef = JSON.parse(Fs.readFileSync(tablesFile, 'utf8')) as any;
|
const tableDef = JSON.parse(Fs.readFileSync(tablesFile, 'utf8')) as any;
|
||||||
|
|
||||||
const getTypeBasedOnCondition = (t) => {
|
const getTypeBasedOnCondition = (t, size) => {
|
||||||
|
|
||||||
|
if (1) {
|
||||||
|
switch (t) {
|
||||||
|
case 'string':
|
||||||
|
return `varchar(${size})`;
|
||||||
|
case 'guid':
|
||||||
|
return 'UUID';
|
||||||
|
case 'key':
|
||||||
|
return `varchar(${size})`;
|
||||||
|
case 'number':
|
||||||
|
return 'BIGINT';
|
||||||
|
case 'integer':
|
||||||
|
return 'INTEGER';
|
||||||
|
case 'double':
|
||||||
|
return 'FLOAT';
|
||||||
|
case 'float':
|
||||||
|
return 'FLOAT';
|
||||||
|
case 'date':
|
||||||
|
return 'DATE';
|
||||||
|
case 'boolean':
|
||||||
|
return 'BOOLEAN';
|
||||||
|
default:
|
||||||
|
return { type: 'TABLE', name: t };
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
switch (t) {
|
switch (t) {
|
||||||
case 'string':
|
case 'string':
|
||||||
return { key: 'STRING' };
|
return { key: 'STRING' };
|
||||||
|
@ -228,33 +254,30 @@ export class GBVMService extends GBService {
|
||||||
default:
|
default:
|
||||||
return { key: 'TABLE', name: t };
|
return { key: 'TABLE', name: t };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const associations = [];
|
const associations = [];
|
||||||
|
|
||||||
const tables = await min.core.sequelize.query(`SELECT table_name, table_schema
|
|
||||||
FROM information_schema.tables
|
|
||||||
WHERE table_type = 'BASE TABLE'
|
|
||||||
ORDER BY table_name ASC`, {
|
|
||||||
type: QueryTypes.RAW
|
|
||||||
})
|
|
||||||
|
|
||||||
// Loads storage custom connections.
|
// Loads storage custom connections.
|
||||||
|
|
||||||
const path = DialogKeywords.getGBAIPath(min.botId, null);
|
const path = DialogKeywords.getGBAIPath(min.botId, null);
|
||||||
const filePath = Path.join('work', path, 'connections.json');
|
const filePath = Path.join('work', path, 'connections.json');
|
||||||
let connections = null;
|
let connections = null;
|
||||||
if(Fs.existsSync(filePath)){
|
if (Fs.existsSync(filePath)) {
|
||||||
connections = Fs.readFileSync(filePath, 'utf8');
|
connections = JSON.parse(Fs.readFileSync(filePath, 'utf8'));
|
||||||
|
|
||||||
}
|
}
|
||||||
tableDef.forEach(t => {
|
tableDef.forEach(async t => {
|
||||||
const tableName = t.name;
|
|
||||||
|
const tableName = t.name.trim();
|
||||||
|
|
||||||
// Determines autorelationship.
|
// Determines autorelationship.
|
||||||
|
|
||||||
Object.keys(t.fields).forEach(key => {
|
Object.keys(t.fields).forEach(key => {
|
||||||
let obj = t.fields[key];
|
let obj = t.fields[key];
|
||||||
obj.type = getTypeBasedOnCondition(obj.type);
|
obj.type = getTypeBasedOnCondition(obj.type, obj.size);
|
||||||
if (obj.type.key === "TABLE") {
|
if (obj.type.key === "TABLE") {
|
||||||
obj.type.key = "BIGINT"
|
obj.type.key = "BIGINT"
|
||||||
associations.push({ from: tableName, to: obj.type.name });
|
associations.push({ from: tableName, to: obj.type.name });
|
||||||
|
@ -267,16 +290,17 @@ export class GBVMService extends GBService {
|
||||||
// Cutom connection for TABLE.
|
// Cutom connection for TABLE.
|
||||||
|
|
||||||
const connectionName = t.connection;
|
const connectionName = t.connection;
|
||||||
if (connectionName) {
|
let con;
|
||||||
|
|
||||||
const con = connections[connectionName];
|
if (connectionName && connections) {
|
||||||
|
con = connections.filter(p => p.name === connectionName)[0];
|
||||||
|
|
||||||
const dialect = con['storageDialect'];
|
const dialect = con['storageDriver'];
|
||||||
const host = con['storageHost'];
|
const host = con['storageServer'];
|
||||||
const port = con['storagePort'];
|
const port = con['storagePort'];
|
||||||
const storageName = con['storageName'];
|
const storageName = con['storageName'];
|
||||||
const username = con['storageUsername'];
|
const username = con['storageUsername'];
|
||||||
const password = con['password'];
|
const password = con['storagePassword'];
|
||||||
|
|
||||||
const logging: boolean | Function =
|
const logging: boolean | Function =
|
||||||
GBConfigService.get('STORAGE_LOGGING') === 'true'
|
GBConfigService.get('STORAGE_LOGGING') === 'true'
|
||||||
|
@ -312,14 +336,25 @@ export class GBVMService extends GBService {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!min[connectionName]) {
|
||||||
|
GBLogEx.info(min, `Loading custom connection ${connectionName}...`);
|
||||||
min[connectionName] = new Sequelize(storageName, username, password, sequelizeOptions);
|
min[connectionName] = new Sequelize(storageName, username, password, sequelizeOptions);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!con) {
|
||||||
|
throw new Error(`Invalid connection specified: ${connectionName}.`);
|
||||||
|
}
|
||||||
|
|
||||||
// Field checking, syncs if there is any difference.
|
// Field checking, syncs if there is any difference.
|
||||||
|
|
||||||
const model = min[connectionName] ? min[connectionName].models[tableName] : minBoot.core.sequelize;
|
const seq = min[connectionName] ? min[connectionName]
|
||||||
if (model) {
|
: minBoot.core.sequelize;
|
||||||
|
|
||||||
|
if (seq) {
|
||||||
|
|
||||||
|
const model = seq.models[tableName];
|
||||||
|
if (model) {
|
||||||
// Except Id, checks if has same number of fields.
|
// Except Id, checks if has same number of fields.
|
||||||
|
|
||||||
let equals = 0;
|
let equals = 0;
|
||||||
|
@ -340,12 +375,25 @@ export class GBVMService extends GBService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
minBoot.core.sequelize.define(tableName, t.fields);
|
seq.define(tableName, t.fields);
|
||||||
|
|
||||||
// New table checking, if needs sync.
|
// New table checking, if needs sync.
|
||||||
|
let tables;
|
||||||
|
|
||||||
|
if (con.storageDriver === 'mssql') {
|
||||||
|
tables = await seq.query(`SELECT table_name, table_schema
|
||||||
|
FROM information_schema.tables
|
||||||
|
WHERE table_type = 'BASE TABLE'
|
||||||
|
ORDER BY table_name ASC`, {
|
||||||
|
type: QueryTypes.RAW
|
||||||
|
})[0]
|
||||||
|
}
|
||||||
|
else if (con.storageDriver === 'mariadb') {
|
||||||
|
tables = await seq.getQueryInterface().showAllTables();
|
||||||
|
}
|
||||||
|
|
||||||
let found = false;
|
let found = false;
|
||||||
tables[0].forEach((storageTable) => {
|
tables.forEach((storageTable) => {
|
||||||
if (storageTable['table_name'] === tableName) {
|
if (storageTable['table_name'] === tableName) {
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
|
@ -353,11 +401,10 @@ export class GBVMService extends GBService {
|
||||||
|
|
||||||
sync = sync ? sync : !found;
|
sync = sync ? sync : !found;
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
associations.forEach(e => {
|
associations.forEach(e => {
|
||||||
const from = minBoot.core.sequelize.models[e.from];
|
const from = seq.models[e.from];
|
||||||
const to = minBoot.core.sequelize.models[e.to];
|
const to = seq.models[e.to];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
to.hasMany(from);
|
to.hasMany(from);
|
||||||
|
@ -368,18 +415,20 @@ export class GBVMService extends GBService {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (sync) {
|
if (sync) {
|
||||||
GBLogEx.info(min, `BASIC: Syncing changes for TABLE keywords (${min.botId})...`);
|
GBLogEx.info(min, `BASIC: Syncing changes for TABLE ${connectionName} ${tableName} keyword (${min.botId})...`);
|
||||||
|
|
||||||
await minBoot.core.sequelize.sync({
|
await seq.sync({
|
||||||
alter: true,
|
alter: true,
|
||||||
force: false // Keep it false due to data loss danger.
|
force: false // Keep it false due to data loss danger.
|
||||||
});
|
});
|
||||||
GBLogEx.info(min, `BASIC: Done sync for ${min.botId} storage tables...`);
|
GBLogEx.info(min, `BASIC: Done sync for ${min.botId} ${connectionName} ${tableName} storage table...`);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
GBLogEx.verbose(min, `BASIC: TABLE keywords already up to date (${min.botId})...`);
|
GBLogEx.verbose(min, `BASIC: TABLE ${tableName} keywords already up to date ${connectionName} (${min.botId})...`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const parsedCode: string = Fs.readFileSync(jsfile, 'utf8');
|
const parsedCode: string = Fs.readFileSync(jsfile, 'utf8');
|
||||||
min.sandBoxMap[mainName.toLowerCase().trim()] = parsedCode;
|
min.sandBoxMap[mainName.toLowerCase().trim()] = parsedCode;
|
||||||
|
@ -721,7 +770,7 @@ export class GBVMService extends GBService {
|
||||||
if (endTableReg && table) {
|
if (endTableReg && table) {
|
||||||
|
|
||||||
tables.push({
|
tables.push({
|
||||||
name: table, fields: fields, connection:connection
|
name: table, fields: fields, connection: connection
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -743,7 +792,7 @@ export class GBVMService extends GBService {
|
||||||
let tableReg = tableKeyword.exec(line);
|
let tableReg = tableKeyword.exec(line);
|
||||||
if (tableReg && !table) {
|
if (tableReg && !table) {
|
||||||
table = tableReg[1];
|
table = tableReg[1];
|
||||||
connection= tableReg[2];
|
connection = tableReg[2];
|
||||||
emmit = false;
|
emmit = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -675,7 +675,8 @@ ENDPOINT_UPDATE=true
|
||||||
public getParam<T>(instance: IGBInstance, name: string, defaultValue?: T): any {
|
public getParam<T>(instance: IGBInstance, name: string, defaultValue?: T): any {
|
||||||
let value = null;
|
let value = null;
|
||||||
if (instance.params) {
|
if (instance.params) {
|
||||||
const params = JSON.parse(instance.params);
|
|
||||||
|
const params = typeof (instance.params) === 'object' ? instance.params: JSON.parse(instance.params);
|
||||||
value = params ? params[name] : defaultValue;
|
value = params ? params[name] : defaultValue;
|
||||||
}
|
}
|
||||||
if (typeof defaultValue === 'boolean') {
|
if (typeof defaultValue === 'boolean') {
|
||||||
|
@ -709,7 +710,7 @@ ENDPOINT_UPDATE=true
|
||||||
let params = null;
|
let params = null;
|
||||||
const list = [];
|
const list = [];
|
||||||
if (instance.params) {
|
if (instance.params) {
|
||||||
params = JSON.parse(instance.params);
|
params = typeof (instance.params) === 'object' ? instance.params : JSON.parse(instance.params);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.keys(params).forEach(e => {
|
Object.keys(params).forEach(e => {
|
||||||
|
|
|
@ -619,10 +619,11 @@ export class GBDeployer implements IGBDeployer {
|
||||||
|
|
||||||
// Find all tokens in .gbot Config.
|
// Find all tokens in .gbot Config.
|
||||||
const strFind = ' Driver';
|
const strFind = ' Driver';
|
||||||
const tokens = await min.core['findParam'](min.instance, strFind);
|
const conns = await min.core['findParam'](min.instance, strFind);
|
||||||
await CollectionUtil.asyncForEach(tokens,async t => {
|
await CollectionUtil.asyncForEach(conns, async t => {
|
||||||
const connectionName = t.replace(strFind, '');
|
const connectionName = t.replace(strFind, '');
|
||||||
let con = {};
|
let con = {};
|
||||||
|
con['name'] = connectionName;
|
||||||
con['storageServer']= min.core.getParam<string>(min.instance, `${connectionName} Server`, null),
|
con['storageServer']= min.core.getParam<string>(min.instance, `${connectionName} Server`, null),
|
||||||
con['storageName']= min.core.getParam<string>(min.instance, `${connectionName} Name`, null),
|
con['storageName']= min.core.getParam<string>(min.instance, `${connectionName} Name`, null),
|
||||||
con['storageUsername']= min.core.getParam<string>(min.instance, `${connectionName} Username`, null),
|
con['storageUsername']= min.core.getParam<string>(min.instance, `${connectionName} Username`, null),
|
||||||
|
|
|
@ -111,7 +111,7 @@ export class GBServer {
|
||||||
|
|
||||||
process.on('unhandledRejection', (err, p) => {
|
process.on('unhandledRejection', (err, p) => {
|
||||||
err = err['e'] ? err['e'] : err;
|
err = err['e'] ? err['e'] : err;
|
||||||
GBLog.error(`UNHANDLED_REJECTION(promises): ${err.toString()} ${err['stack'] ? '\n' + err['stack'] : ''}`);
|
GBLog.error(`UNHANDLED_REJECTION(promises): ${err.toString()} ${err['stack'] ? '\n' + err['stack'] : ''} ${err['cause'] ? '\n' + err['cause']?.message : ''}`);
|
||||||
if (err['response']?.obj?.httpStatusCode === 404) {
|
if (err['response']?.obj?.httpStatusCode === 404) {
|
||||||
GBLog.warn(`Check reverse proxy: ${process.env.BOT_URL} as it seems to be invalid.`);
|
GBLog.warn(`Check reverse proxy: ${process.env.BOT_URL} as it seems to be invalid.`);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue