new(basic.gblib): TABLE keyword #375 fixes.

This commit is contained in:
Rodrigo Rodriguez 2023-10-05 10:06:03 -03:00
parent 90e0688cd6
commit 7163c077fe
6 changed files with 199 additions and 149 deletions

View file

@ -644,6 +644,19 @@ export class DialogKeywords {
await DialogKeywords.setOption({ pid, name, value }); await DialogKeywords.setOption({ pid, name, value });
} }
/**
* Returns current if any continuation token for paginated HTTP requests.
*
* @example CONTINUATION TOKEN
*
*/
public async getContinuationToken({ pid }) {
let { min, user, params, proc } = await DialogKeywords.getProcessInfo(pid);
return DialogKeywords.getOption({ pid, name: `${proc.executable}-continuationToken` });
}
/** /**
* Returns bot param persisted on storage. * Returns bot param persisted on storage.
* *

View file

@ -174,16 +174,39 @@ export class GBVMService extends GBService {
// Syncronizes Database Objects with the ones returned from "Word". // Syncronizes Database Objects with the ones returned from "Word".
const tablesFile = urlJoin(folder, 'tables.json'); const tablesFile = urlJoin(folder, `${filename}.tables.json`);
if (Fs.existsSync(tablesFile)) { if (Fs.existsSync(tablesFile)) {
const minBoot = GBServer.globals.minBoot; const minBoot = GBServer.globals.minBoot;
GBLogEx.info(min, `BASIC: Reading tables and sync storage for ${min.botId}...`); GBLogEx.info(min, `BASIC: Reading tables and sync storage for ${min.botId}...`);
const tables = JSON.parse(Fs.readFileSync(tablesFile, 'utf8')); const t = JSON.parse(Fs.readFileSync(tablesFile, 'utf8'));
tables.forEach(t => {
minBoot.core.sequelize.define(t.name, t.fields); const getTypeBasedOnCondition = (t) => {
switch (t) {
case 'string':
return { key: 'STRING' };
case 'key':
return { key: 'STRING' }; // Assuming key is a string data type
case 'integer':
return { key: 'INTEGER' };
case 'double':
return { key: 'FLOAT' };
case 'date':
return { key: 'DATE' };
case 'boolean':
return { key: 'BOOLEAN' };
default:
return { key: 'STRING' }; // Default to string if the type is unknown
}
};
Object.keys(t.fields).forEach(key => {
let obj = t.fields[key];
obj.type = getTypeBasedOnCondition(obj.type);
}); });
minBoot.core.sequelize.define(t.name, t.fields);
await minBoot.core.sequelize.sync(); await minBoot.core.sequelize.sync();
} }
@ -194,6 +217,7 @@ export class GBVMService extends GBService {
} }
public async translateBASIC(mainName, filename: any, min: GBMinInstance) { public async translateBASIC(mainName, filename: any, min: GBMinInstance) {
// Converts General Bots BASIC into regular VBS // Converts General Bots BASIC into regular VBS
let basicCode: string = Fs.readFileSync(filename, 'utf8'); let basicCode: string = Fs.readFileSync(filename, 'utf8');
@ -218,7 +242,7 @@ export class GBVMService extends GBService {
} }
} while (include); } while (include);
let { code, map, metadata, tasks } = await this.convert(mainName, basicCode); let { code, map, metadata, tasks } = await this.convert(filename, mainName, basicCode);
// Generates function JSON metadata to be used later. // Generates function JSON metadata to be used later.
@ -231,7 +255,7 @@ export class GBVMService extends GBService {
// Execute off-line code tasks // Execute off-line code tasks
await this.executeTasks(tasks); await this.executeTasks(min, tasks);
// Run JS into the GB context. // Run JS into the GB context.
@ -310,6 +334,15 @@ export class GBVMService extends GBService {
const hour = (v) => { return (async () => { return await dk.getHourFromDate({v}) })(); }; const hour = (v) => { return (async () => { return await dk.getHourFromDate({v}) })(); };
const base64 = (v) => { return (async () => { return await dk.getCoded({v}) })(); }; const base64 = (v) => { return (async () => { return await dk.getCoded({v}) })(); };
const tolist = (v) => { return (async () => { return await dk.getToLst({v}) })(); }; const tolist = (v) => { return (async () => { return await dk.getToLst({v}) })(); };
const uuid = () => {
var dt = new Date().getTime();
var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
var r = (dt + Math.random()*16)%16 | 0;
dt = Math.floor(dt/16);
return (c=='x' ? r :(r&0x3|0x8)).toString(16);
});
return uuid;
};
// Setups interprocess communication from .gbdialog run-time to the BotServer API. // Setups interprocess communication from .gbdialog run-time to the BotServer API.
@ -338,7 +371,7 @@ export class GBVMService extends GBService {
} }
private async executeTasks(tasks) { private async executeTasks(min, tasks) {
for (let i = 0; i < tasks.length; i++) { for (let i = 0; i < tasks.length; i++) {
const task = tasks[i]; const task = tasks[i];
@ -346,21 +379,12 @@ export class GBVMService extends GBService {
// Creates an empty object that will receive Sequelize fields. // Creates an empty object that will receive Sequelize fields.
let obj = {name: task.name}; let obj = { name: task.name };
obj['fields'] = []; obj['fields'] = task.fields;
const path = DialogKeywords.getGBAIPath(min.botId, `gbdialog`);
const tablesFile = `${task.file}.tables.json`;
const fields = task.fields; Fs.writeFileSync(tablesFile, JSON.stringify(obj));
fields.forEach(f => {
let field = {};
field[f.name] = f;
obj['fields'].push(field);
});
const jsonFile = `${task.name}.table.json`;
Fs.writeFileSync(jsonFile, JSON.stringify(obj));
} }
@ -454,42 +478,20 @@ export class GBVMService extends GBService {
let required = line.indexOf('*') !== -1; let required = line.indexOf('*') !== -1;
line = line.replace('*', ''); line = line.replace('*', '');
const fieldRegExp = /^\s*(\w+)\s*(\w+)(\((\d+)\))?/gim; const fieldRegExp = /^\s*(\w+)\s*(\w+)(?:\((\d+)\))?/gim;
let reg = fieldRegExp.exec(line); let reg = fieldRegExp.exec(line);
const t = reg[2]; const t = reg[2];
const n = reg[1]; const name = reg[1];
let obj = {}; let definition = { allowNull: !required };
let field = {allowNull: !required }; definition['type'] = t;
obj[n] = field;
const getTypeBasedOnCondition = (t) => { if (reg[3]) {
switch (t) { definition['size'] = Number.parseInt(reg[3]);
case 'string':
return DataTypes.STRING;
case 'key':
return DataTypes.STRING; // Assuming key is a string data type
case 'integer':
return DataTypes.INTEGER;
case 'double':
return DataTypes.FLOAT;
case 'date':
return DataTypes.DATE;
case 'boolean':
return DataTypes.BOOLEAN;
default:
return DataTypes.STRING; // Default to string if the type is unknown
}
};
field['type'] = getTypeBasedOnCondition(t);
if (reg[3]){
field['size'] = getTypeBasedOnCondition(t);
} }
return obj; return { name, definition };
} }
/** /**
@ -498,7 +500,7 @@ export class GBVMService extends GBService {
* *
* @param code General Bots BASIC * @param code General Bots BASIC
*/ */
public async convert(mainName: string, code: string) { public async convert(filename: string, mainName: string, code: string) {
// Start and End of VB2TS tags of processing. // Start and End of VB2TS tags of processing.
@ -511,9 +513,10 @@ export class GBVMService extends GBService {
let description; let description;
let table = null; // Used for TABLE keyword. let table = null; // Used for TABLE keyword.
const tasks = []; const tasks = [];
let fields = []; let fields = {};
for (let i = 1; i <= lines.length; i++) { for (let i = 1; i <= lines.length; i++) {
let line = lines[i - 1]; let line = lines[i - 1];
// Remove lines before statments. // Remove lines before statments.
@ -541,27 +544,12 @@ export class GBVMService extends GBService {
emmit = false; emmit = false;
} }
// Inside BEGIN/END table pair containing FIELDS. const endTableKeyword = /^\s*END TABLE\s*/gim;
if (table) {
const field = this.parseField(line);
fields.push(field);
}
const tableKeyword = /^\s*TABLE\s*\"(.*)\"/gim;
let tableReg = tableKeyword.exec(line);
if (tableReg) {
table = tableReg[1];
emmit = false;
}
const endTableKeyword = /^\s*END TABLE"/gim;
let endTableReg = endTableKeyword.exec(line); let endTableReg = endTableKeyword.exec(line);
if (endTableReg) { if (endTableReg && table) {
tasks.push({ tasks.push({
kind: 'writeTableDefinition', name: table, fields: fields kind: 'writeTableDefinition', file: filename, name: table, fields: fields
}); });
fields = []; fields = [];
@ -569,16 +557,27 @@ export class GBVMService extends GBService {
emmit = false; emmit = false;
} }
// Inside BEGIN/END table pair containing FIELDS.
if (emmit) { if (table && line.trim() !== '') {
const field = await this.parseField(line);
fields[field.name] = field.definition;
emmit = false;
}
const tableKeyword = /^\s*TABLE\s*(.*)/gim;
let tableReg = tableKeyword.exec(line);
if (tableReg && !table) {
table = tableReg[1];
emmit = false;
}
// Add additional lines returned from replacement. // Add additional lines returned from replacement.
let add = line.split(/\r\n|\r|\n/).length; let add = emmit ? line.split(/\r\n|\r|\n/).length : 0;
current = current + (add ? add : 0); current = current + (add ? add : 0);
map[i] = current; map[i] = current;
lines[i - 1] = line; lines[i - 1] = emmit ? line : '';
}
} }
code = `${lines.join('\n')}\n`; code = `${lines.join('\n')}\n`;
@ -650,7 +649,7 @@ export class GBVMService extends GBService {
let code = min.sandBoxMap[text]; let code = min.sandBoxMap[text];
const channel = step ? step.context.activity.channelId : 'web'; const channel = step ? step.context.activity.channelId : 'web';
const pid = GBVMService.createProcessInfo(user, min, channel); const pid = GBVMService.createProcessInfo(user, min, channel, text);
const dk = new DialogKeywords(); const dk = new DialogKeywords();
const sys = new SystemKeywords(); const sys = new SystemKeywords();
await dk.setFilter({ pid: pid, value: null }); await dk.setFilter({ pid: pid, value: null });
@ -723,14 +722,15 @@ export class GBVMService extends GBService {
return result; return result;
} }
public static createProcessInfo(user: GuaribasUser, min: GBMinInstance, channel: any) { public static createProcessInfo(user: GuaribasUser, min: GBMinInstance, channel: any, executable: string) {
const pid = GBAdminService.getNumberIdentifier(); const pid = GBAdminService.getNumberIdentifier();
GBServer.globals.processes[pid] = { GBServer.globals.processes[pid] = {
pid: pid, pid: pid,
userId: user ? user.userId : 0, userId: user ? user.userId : 0,
instanceId: min.instance.instanceId, instanceId: min.instance.instanceId,
channel: channel, channel: channel,
roles: 'everyone' roles: 'everyone',
executable: executable
}; };
return pid; return pid;
} }

View file

@ -93,6 +93,7 @@ export class KeywordsExpressions {
const convertConditions = input => { const convertConditions = input => {
var result = input.replace(/ +and +/gim, ' && '); var result = input.replace(/ +and +/gim, ' && ');
result = result.replace(/ +or +/gim, ' || '); result = result.replace(/ +or +/gim, ' || ');
result = result.replace(/ +not +/gim, ' !');
result = result.replace(/ +<> +/gim, ' !== '); result = result.replace(/ +<> +/gim, ' !== ');
result = result.replace(/ += +/gim, ' === '); result = result.replace(/ += +/gim, ' === ');
return result; return result;
@ -320,6 +321,12 @@ export class KeywordsExpressions {
} }
]; ];
keywords[i++] = [
/\s*CONTINUATION TOKEN\s*/gim,
() => {
return `await dk.getContinuationToken ({pid: pid})`;
}
];
keywords[i++] = [ keywords[i++] = [
/^\s*(set hear on)(\s*)(.*)/gim, /^\s*(set hear on)(\s*)(.*)/gim,
@ -340,14 +347,15 @@ export class KeywordsExpressions {
__next = true; __next = true;
__calls = 0; __calls = 0;
__index = 0; __index = 0;
__data = ${$2};
__url = $2.links?.next?.uri; __url = __data.links?.next?.uri;
__seekToken = $2.links?.self?.headers["MS-ContinuationToken"] __seekToken = __data.links?.self?.headers["MS-ContinuationToken"]
__totalCount = $2["totalCount"]; __totalCount = __data["totalCount"];
while (__next) while (__next)
{ {
let $1 = $2[__index]; let ${$1} = __data[__index];
`; `;
} }
]; ];
@ -368,13 +376,13 @@ export class KeywordsExpressions {
// Perform GET request using the constructed URL // Perform GET request using the constructed URL
$2 = await sys.get ({pid: pid, file: __url, addressOrHeaders: headers, httpUsername, httpPs}); __data = await sys.get ({pid: pid, file: __url, addressOrHeaders: headers, httpUsername, httpPs});
// Update current variable handlers. // Update current variable handlers.
__url = $2.links?.next?.uri; __url = __data.links?.next?.uri;
__seekToken = $2.links?.self?.headers["MS-ContinuationToken"] __seekToken = __data.links?.self?.headers["MS-ContinuationToken"]
__totalCount = $2["totalCount"]; __totalCount = __data["totalCount"];
index = 0; index = 0;
__calls++; __calls++;
@ -387,7 +395,7 @@ export class KeywordsExpressions {
index = index + 1; index = index + 1;
} }
`; }`;
} }
]; ];
@ -690,7 +698,7 @@ export class KeywordsExpressions {
keywords[i++] = [ keywords[i++] = [
/^\s*(set page mode)(\s*)(.*)/gim, /^\s*(set page mode)(\s*)(.*)/gim,
($0, $1, $2, $3) => { ($0, $1, $2, $3) => {
return `await dk.setPageMode ({pid: pid, ${$3}})`; return `await dk.setPageMode ({pid: pid, value: ${$3}})`;
} }
]; ];
@ -704,7 +712,7 @@ export class KeywordsExpressions {
keywords[i++] = [ keywords[i++] = [
/^\s*set header\s*(.*)\s*as\s*(.*)/gim, /^\s*set header\s*(.*)\s*as\s*(.*)/gim,
($0, $1, $2) => { ($0, $1, $2) => {
return `headers[${$1}]=${$2})`; return `headers[${$1.trim()}] = ${$2}`;
} }
]; ];
@ -845,14 +853,14 @@ export class KeywordsExpressions {
]; ];
keywords[i++] = [ keywords[i++] = [
/^\s*(\bexit\b)\s*/gim, /^\sEXIT\s*$/gim,
() => { () => {
return `return;`; return `return;`;
} }
]; ];
keywords[i++] = [ keywords[i++] = [
/^\s*(\bEND\b)\s*/gim, /^\s*END\s*$/gim,
() => { () => {
return `return;`; return `return;`;
} }
@ -1072,10 +1080,29 @@ export class KeywordsExpressions {
($0, $1, $2, $3, $4) => { ($0, $1, $2, $3, $4) => {
$3 = $3.replace(/\'/g, ''); $3 = $3.replace(/\'/g, '');
$3 = $3.replace(/\"/g, ''); $3 = $3.replace(/\"/g, '');
$4 = $4.substr(2); let fields = $3.split(',');
const fields = $4.split(','); const table = fields[0].trim();
fields.shift();
return `await sys.saveToStorage({pid: pid, file: "${$3}", args: [${$4}]}, fields)`; const fieldsAsText = fields.join(',');
let fieldsNamesOnly = [];
let index = 0;
fields.forEach(field => {
// Extracts only the last part of the variable like 'column'
// from 'row.column'.
const fieldRegExp = /(?:.*\.)(.*)/gim;
let name = fieldRegExp.exec(field)[1]
fieldsNamesOnly.push (name);
});
let fieldsNames = fieldsNamesOnly.join(',');
return `await sys.saveToStorage({pid: pid, table: "${table}", fields: [${fieldsAsText}], fieldsNames: [${fieldsNames}] })`;
} }
]; ];

View file

@ -656,24 +656,18 @@ export class SystemKeywords {
*/ */
public async saveToStorage({ pid, table, fields, fieldsNames }) { public async saveToStorage({ pid, table, fields, fieldsNames }) {
const fieldRegExp = /(?:.*\.)(.*)/gim; GBLog.info(`BASIC: Saving '${table}' (SAVE). Values: ${fields.join(',')}.`);
const minBoot = GBServer.globals.minBoot as any; const minBoot = GBServer.globals.minBoot as any;
const definition = minBoot.core.sequelize.models[table]; const definition = minBoot.core.sequelize.models[table];
let data = {}; let data = {};
let index = 0; let index = 0;
fields.forEach(field => { fieldsNames.forEach(field => {
data[fieldsNames] = fields[index++];
// Extracts only the last part of the variable like 'column'
// from 'row.column'.
let name = fieldsNames[index];
name = fieldRegExp.exec(name)[2];
data[name] = field;
}); });
return await definition.create(data); return await definition.create(data);
} }
@ -1509,7 +1503,7 @@ export class SystemKeywords {
public generatePassword(pid) { public generatePassword(pid) {
return GBAdminService.getRndPassword(); return GBAdminService.getRndPassword();
} }
static aa;
/** /**
* Calls any REST API by using GET HTTP method. * Calls any REST API by using GET HTTP method.
* *
@ -1519,11 +1513,12 @@ export class SystemKeywords {
public async getByHttp({ pid, url, headers, username, ps, qs }) { public async getByHttp({ pid, url, headers, username, ps, qs }) {
let options = {}; let options = {};
const { min, user, params } = await DialogKeywords.getProcessInfo(pid); const { min, user, params, proc } = await DialogKeywords.getProcessInfo(pid);
GBLogEx.info(min, `GET: ${url}`); GBLogEx.info(min, `GET: ${url}`);
const pageMode = await DialogKeywords.getOption({ pid, name: 'pageMode' }); const pageMode = await DialogKeywords.getOption({ pid, name: 'pageMode' });
let continuationToken = await DialogKeywords.getOption({ pid, name: 'continuationToken' }); let continuationToken = await
DialogKeywords.getOption({ pid, name: `${proc.executable}-continuationToken` });
if (pageMode === "auto" && continuationToken) { if (pageMode === "auto" && continuationToken) {
headers = headers ? headers : {}; headers = headers ? headers : {};
@ -1775,7 +1770,17 @@ export class SystemKeywords {
} }
}; };
const result = await fetch(url, options);
let result;
if (!SystemKeywords.aa){
SystemKeywords.aa = 1;
return r1;
} else {
SystemKeywords.aa = null;
return r2;
}
//const result = await fetch(url, options);
try { try {
@ -1783,7 +1788,7 @@ export class SystemKeywords {
// Token expired. // Token expired.
GBLog.info(`Expired Token for ${url}.`); GBLog.info(`Expired Token for ${url}.`);
await DialogKeywords.setOption({ pid, name: 'continuationToken', value: null }); await DialogKeywords.setOption({ pid, name: `${proc.executable}-continuationToken`, value: null });
return null; return null;
} }

View file

@ -76,11 +76,14 @@ export class GBLogEx {
* Finds and update user agent information to a next available person. * Finds and update user agent information to a next available person.
*/ */
public static async log(instance: IGBInstance, kind: string, message: string): Promise<GuaribasLog> { public static async log(instance: IGBInstance, kind: string, message: string): Promise<GuaribasLog> {
if (process.env.LOG_ON_STORAGE) {
message = message ? message.substring(0, 1023) : null; message = message ? message.substring(0, 1023) : null;
return await GuaribasLog.create(<GuaribasLog>{ return await GuaribasLog.create(<GuaribasLog>{
instanceId: instance ? instance.instanceId : 1, instanceId: instance ? instance.instanceId : 1,
message: message, message: message,
kind: kind kind: kind
}); });
} }
}
} }

View file

@ -1031,8 +1031,10 @@ export class GBMinService {
return; return;
} }
} else if (context.activity.type === 'message') { } else if (context.activity.type === 'message') {
// Processes messages activities. // Processes messages activities.
const pid = GBVMService.createProcessInfo(user, min, step.context.activity.channelId);
const pid = GBVMService.createProcessInfo(user, min, step.context.activity.channelId, null);
step.context.activity['pid'] = pid; step.context.activity['pid'] = pid;
await this.processMessageActivity(context, min, step, pid); await this.processMessageActivity(context, min, step, pid);