I'm currently trying to build a discord bot, and I want to use a database for some aspects of it. Currently, I'm trying to add a command that would return the names of all the tables I have in the database, and for the most part I have it down.
The part that I'm struggling with is actually getting the names back out as a var. Every guide and stackoverflow question that I've been able to find on it assume that you just want to get that result and then print it to the console, but I need to return it back to the method that called this.
My previous attempt was setting an outside variable and using a promise to wait for it to change, but I couldn't get that to work, most likely because I don't fully understand how Promises work. My current attempt uses setTimeout() to check, but that just returns the asyncID of either the first or second iteration.
Any help either in making either of these work or completely scrapping them and doing this a different way is very welcome.
Previous code:
function listTables() {
db.query('SELECT table_name FROM information_schema.tables WHERE table_schema=\'' + dbName + '\'', (error, results) => {
if(error) throw error;
let temp = '';
results.forEach((item) => {
temp += item.table_name + ', ';
}); temp = temp.slice(0, -2);
setReturn(temp);
});
let out = checkReturn().then((value) => {
return value();
}).catch((error) => {
console.log(error);
return '';
});
returnValue = null;
return out;
}
var returnValue = null;
function setReturn(value) {
returnValue = value;
}
async function checkReturn() {
console.log('Checking Return: ' + returnValue);
let promise = new Promise((resolve, reject) => {
if(returnValue === null) reject('Var not set');
else resolve(returnValue)
});
return await promise;
}
Current Code:
function listTables() {
setReturn(null);
db.query('SELECT table_name FROM information_schema.tables WHERE table_schema=\'' + dbName + '\'', (error, results) => {
if(error) throw error;
let temp = '';
results.forEach((item) => {
temp += item.table_name + ', ';
}); temp = temp.slice(0, -2);
setReturn(temp);
});
return checkReturn();
}
var returnValue = null;
function setReturn(value) {
returnValue = value;
}
function checkReturn() {
console.log('Checking Return: ' + returnValue);
if(returnValue === null) {
return setTimeout(checkReturn, 50);
} else {
return returnValue;
}
}
You need to modify the listTables function to return a promise.
function listTables() {
return new Promise((resolve, reject) => {
db.query('SELECT table_name FROM information_schema.tables WHERE table_schema=\'' + dbName + '\'', (error, results) => {
if(error) {
reject(error);
return;
}
let temp = '';
results.forEach((item) => {
temp += item.table_name + ', ';
}); temp = temp.slice(0, -2);
resolve(temp);
});
});
}
// Usage of `listTables()`
listTables()
.then(result -> {
// Do process result
});
Related
I have the following code:
function makeid(length) {
var result = '';
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var charactersLength = characters.length;
for ( var i = 0; i < length; i++ ) {
result += characters.charAt(Math.floor(Math.random() *
charactersLength));
};
return result;
};
var instance = "{{ user }}" + makeid(16);
var checksum = "First Request Not recieved";
console.log(instance);
function downloadPlay(){
console.log("\ndownloadPlay - Begin\n")
try{
fetch("/file?instance=" + instance + "&checksum=" + checksum)
.then(function(resp) {
resp.headers.forEach(
function(val, key) {
// console.log("key, val: " + key + ", " + val);
if(key == "checksum"){
console.log("checksum: " + val);
checksum = val;
};
}
);
}
)
.then(file => {
var audio = new Audio("/file?instance=" + instance + "&checksum=" + checksum);
console.log("Done");
audio.addEventListener('ended', (event) => {
delete audio;
downloadPlay();
});
audio.play();
}
)
} catch (error) {
console.log("Something went wrong, Retrying: " + error);
}
console.log("downloadPlay - Complete\n")
};
downloadPlay();
This works perfectly when the promise succeeds. However when it fails(such as when the client device switches networks, i.e. wifi to data or just different access points on the same wifi network) it stops dead and never resumes no matter how many while loops, extra recursion points or try and catch statements I use. The best I could do so far is get it to play ever increasing numbers of the audio mostly in sync with each other and I just dont understand why. It seems I have a general lack of understanding of how this promise thing actually functions, but no matter how many tutorials I read/watch my lack of understanding seems to remain unchanged.
Heres the code that somewhat worked if that helps:
function makeid(length) {
var result = '';
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var charactersLength = characters.length;
for ( var i = 0; i < length; i++ ) {
result += characters.charAt(Math.floor(Math.random() *
charactersLength));
};
return result;
};
var instance = "{{ user }}" + makeid(16);
var checksum = "First Request Not recieved";
console.log(instance);
function downloadPlay(){
console.log("\ndownloadPlay - Begin\n")
try{
console.log('fetching')
fetch("/file?instance=" + instance + "&checksum=" + checksum)
.then(function(resp) {
resp.headers.forEach(
function(val, key) {
// console.log("key, val: " + key + ", " + val);
if(key == "checksum"){
console.log("checksum: " + val);
checksum = val;
};
}
);
}
).catch(function(error) {
console.log('request failed', error)
console.log('retrying')
downloadPlay();
return;
})
.then(file => {
var audio = new Audio("/file?instance=" + instance + "&checksum=" + checksum);
console.log("Done");
audio.addEventListener('ended', (event) => {
delete audio;
downloadPlay();
});
audio.play();
}
)
} catch (error) {
console.log("Something went wrong, Retrying: " + error);
}
console.log("downloadPlay - Complete\n")
};
downloadPlay();
Any solution or very simple explanation on what im doing wrong would be much appreciated
Thanks in advance :)
You can do something like this
Just remove the comment and use your original fetching function
You can't use try catch with promises unless you use async await
const fakeChecking = Promise.resolve({headers: {checksum: 'aaaa'}})
const errorChecking = Promise.reject('error')
function downloadPlay(fetching) {
console.log("\ndownloadPlay - Begin\n")
console.log('fetching')
fetching
.then((resp) => resp.headers.checksum)
.then(checksum => {
/*var audio = new Audio("/file?instance=" + instance + "&checksum=" + checksum);
console.log("Done");
/*audio.addEventListener('ended', (event) => {
delete audio;
downloadPlay();
console.log("downloadPlay - Complete\n")
});
audio.play();*/
console.log("downloadPlay - Complete\n")
})
.catch(function(error) {
console.log('request failed', error)
console.log('retrying')
downloadPlay(fakeChecking);
})
};
downloadPlay(errorChecking);
i having Api Call which execute in For Loop some of the value which returns 10 sec itself some may take nearly 60 sec i have to maintain proper Timeout and clear session (i.e if results comes at 15 sec means it should goes to next input values and run the code) but currenly its waiting for 45 sec each single record how to optimize it
here my sample code :
if (selectedrows.length >= 1) {
for (var i = 0; i < selectedrows.length; i++) {
var myVar = setTimeout (function (k) {
var ob = { results: "Appending ..." };
child.update(selectedrows[k][4], selectedrows[k][4], ob);
var fullName = selectedrows[k][1] + ' ' + selectedrows[k][2];
math.ResultCall.async(fullName,function (err, res) {
if (err) throw err;
var returnedValue = JSON.parse(res);
console.log(returnedValue);
if(returnedValue.Result == null || returnedValue.Result.FOUND_Result == null)
{
console.log("None found")
}
else{
var obj = { results: “res” };
child.update(selectedrows[k][4], selectedrows[k][4], obj);
}
}
});
}, i * 45000,i);
}
}
Rephrasing your question, you need to return the data when your api gets resolved.
For this please go through https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve
JavaScript, by default it work asynchronously because of its event loop.
You have promises and resolve to get notified when your api returns a data
Hope I helped :)
There are several approaches to implement the solution
1. Async-Await: in-case the records-processing order is important
for( let i=0; i<selectedrows.length; i++)
{
let ob = { results: "Appending ..." };
child.update(selectedrows[i][4], selectedrows[i][4], ob);
let fullName = selectedrows[i][1] + ' ' + selectedrows[i][2];
await new Promise((resolve,reject)=>
{
math.ResultCall.async(fullName,(err, res) => {
if (err) reject(err);
let returnedValue = JSON.parse(res);
console.log(returnedValue);
if(returnedValue.Result == null || returnedValue.Result.FOUND_Result == null) {
console.log("None found")
} else {
let obj = { results: “res” };
child.update(selectedrows[i][4], selectedrows[i][4], obj);
}
resolve();
});
}
**don't forget this means the wrapping function should be async as well (which returns a promise that can be resolved if necessary)
2.Promise.All: if the order is not important
let promArray = [];
for( let i=0; i<selectedrows.length; i++)
{
let ob = { results: "Appending ..." };
child.update(selectedrows[i][4], selectedrows[i][4], ob);
let fullName = selectedrows[i][1] + ' ' + selectedrows[i][2];
promArray.push( new Promise((resolve,reject)=>
{
math.ResultCall.async(fullName,(err, res) => {
if (err) reject(err);
let returnedValue = JSON.parse(res);
console.log(returnedValue);
if(returnedValue.Result == null || returnedValue.Result.FOUND_Result == null) {
console.log("None found")
} else {
let obj = { results: “res” };
child.update(selectedrows[i][4], selectedrows[i][4], obj);
}
resolve();
});
);
}
Promise.all(promArray);
** this will also return a Promise that can be resolved if necessary.
I am still pretty new to this, so forgive me if I dont' say this correctly. We have an array.reduce that calls a method with a returning promise that iterates through a list of files and post results to the db. Everything was working great, until it ran into a field that had an apostrophe in it and then the db insert fails. This is the field value. 'Expected 100002822' to be 100002822.'
I tried adding a replaceAll on the field and now get an error in the array.reduce.
Here is the .reduce
console.log('Found test results in ' + matches.length + ' files. Parsing and posting to the database now...');
var startTime = moment();
var parser = new Parser();
matches.reduce(function (p, val) {
return p.then(function () {
return parser.parseResults(val);
});
}, Promise.resolve()).then(function (finalResult) {
var endTime = moment();
var testDuration = moment.duration(endTime.diff(startTime));
console.log(chalk.blue('*** File parsing time: ' + testDuration.humanize() + ' ***'));
if (finalResult.insertSuccess == matches.length) {
var publishOut = {
totalFiles: matches.length,
totalTests: 0,
totalTestsSuccess: 0,
totalTestsFailed: 0
}
publishOut.totalTests += finalResult.totalTests;
publishOut.totalTestsSuccess += finalResult.testPassedCount;
publishOut.totalTestsFailed += finalResult.testFailedCount;
console.log(`Successfully inserted ${finalResult.insertSuccess} of ${publishOut.totalTests} test results.`);
// for (var i = 0; i < matches.length; i++) {
// var currentFile = `./testing/results/${matches[i]}`;
// fs.unlinkSync(currentFile);
// }
resolve(publishOut);
} else {
reject('Only ' + finalResult.insertSuccess + ' of ' + matches.length + ' successfully posted to the database');
}
}, function (err) {
reject('error in reduce', err);
});
I have tried several different ways of using the replaceAll with the same failure. It hits this code from the array.reduce
}, function (err) {
reject('error in reduce', err);
});
And this is the called method. The added code causing the failure in the .reduce is this Message = expectation.message.replaceAll("'", "");
protractorParser.prototype.parseResults = function (fileName) {
return new Promise((resolve, reject) => {
//console.log('In parseresults', fileName);
var currentFile = './testing/results/' + fileName
json.readFile(currentFile, function (err, obj) {
if (err != null) {
console.log('error reading file', err);
reject(err);
} else {
resolve(obj);
}
});
}).then(function (obj) {
var results = [];
for (var suite in obj) {
var specs = obj[suite].specs;
for (let i = 0; i < specs.length; i++) {
const assert = specs[i];
const tcR = /TC[\d]+/;
const tc = assert.description.match(tcR);
let Passed = 1;
let Message = '';
let Stack = '';
testResults.totalTests++;
if (assert.failedExpectations.length) {
const expectation = assert.failedExpectations[assert.failedExpectations.length - 1];
Passed = 0;
Message = expectation.message.replaceAll("'", "");
Stack = expectation.stack.split('\n')[1].trim();
testResults.testFailedCount++
} else {
testResults.testPassedCount++
}
if (tc != null) {
const time = moment().utcOffset(config.get('settings.timeOffset')).format('YYYY-MM-DDTHH:mm:ss');
const promise = utility.TestDataManager.insertAutomationResults(tc[0], assert.description, Passed, process.env.testBuild, 'P', Message, Stack, 0, time, '');
results.push(promise.then(() => {
//fs.unlinkSync(currentFile);
testResults.insertSuccess++;
//console.log('insertSuccess', testResults.insertSuccess);
},
err => { console.log('… failed', err); throw err; }
));
} else {
console.log('no test case found for test: ' + assert.description + ' -- skipping');
// I don't think you want to `throw err` here, right?
}
}
}
return Promise.all(results).then(() => testResults);
});
};
I am trying to iterate through the JSON files generated by the protractor tests. I pull all the file names into an array and call a method that opens and parses through the each file, post the results to the database and pass back a passed/failed flag.
I have tried all the examples here
Make angular.forEach wait for promise after going to next object and still get the same results.
The method is actually called, but the results are not posted to the db. I have tested the parser.parseResults on an individual file and it successfully posted to the db, so it has to have something to do with the promise not resolving correctly.
Is it not possible to do something like this in the jasmine/protractor framework? Or do I have something wrong in the code?
I have included the code for my latest attempt.
Thank You
Christine
matches.reduce(function (p, val) {
console.log('val', val);
return p.then(function () {
return parser.parseResults(val);
});
}, Promise.resolve()).then(function (finalResult) {
console.log('finalResult = ', finalResult);
}, function (err) {
console.log('error in reduce',err);
});
parser.parseResults code
protractorParser.prototype.parseResults = function (fileName) {
return new Promise((resolve, reject) => {
console.log('In parseresults', fileName);
json.readFile(fileName, function (err, obj) {
try {
if (err != null) {
console.log('error reading file',err);
reject(err);
}
console.log('obj - ',obj);
var results = [];
var Passed = 0;
var Message = '';
var Stack = '';
for (var suite in obj) {
var specs = obj[suite].specs;
console.log('spec - ', specs);
if (specs.length > 0) {
for (var i = 0; i < specs.length; i++) {
var assert = specs[i];
var tcR = new RegExp(/TC[\d]+/);
var tc = assert.description.match(tcR);
if (!assert.failedExpectations.length) {
Passed = 1;
}
else {
assert.failedExpectations.forEach((expectation) => {
Message = expectation.message;
Stack = expectation.stack.split('\n')[1].trim();
})
Passed = 0;
}
if (tc != null) {
utility.TestDataManager.insertAutomationResults(tc[0], assert.description, Passed, process.env.testBuild,
'P', Message, Stack, 0, moment().utcOffset(config.get('settings.timeOffset')).format('YYYY-MM-DDTHH:mm:ss'), '')
.then(function (resp) {
resolve(Passed);
}, (err) => {
console.log('Posting to Database failed ', err);
reject(err);
});
} else {
console.log('no test case found for test: ' + assert.description + ' -- skipping');
reject(err);
}
}
}
}
}
catch (err) {
console.log('rejecting opening file');
reject(err);
}
});
})
}
If there is not exactly one suite in the obj, with exactly one spec, then your promise is either resolved not at all or multiple times.
Avoid wrapping too many things in the new Promise constructor - always promisify on the smallest possible level, and use promise chaining afterwards.
protractorParser.prototype.parseResults = function (fileName) {
return new Promise((resolve, reject) => {
console.log('In parseresults', fileName);
json.readFile(fileName, function (err, obj) {
if (err != null) {
console.log('error reading file', err);
reject(err);
} else {
resolve(obj);
}
});
}).then(function(obj) {
console.log('obj - ',obj);
var results = [];
for (var suite in obj) {
var specs = obj[suite].specs;
console.log('spec - ', specs);
for (let i = 0; i < specs.length; i++) {
const assert = specs[i];
const tcR = /TC[\d]+/;
const tc = assert.description.match(tcR);
let Passed = 1;
let Message = '';
let Stack = '';
if (assert.failedExpectations.length) {
const expectation = assert.failedExpectations[assert.failedExpectations.length-1];
Passed = 0;
Message = expectation.message;
Stack = expectation.stack.split('\n')[1].trim();
}
if (tc != null) {
const time = moment().utcOffset(config.get('settings.timeOffset')).format('YYYY-MM-DDTHH:mm:ss');
const promise = utility.TestDataManager.insertAutomationResults(tc[0], assert.description, Passed, process.env.testBuild, 'P', Message, Stack, 0, time, '');
results.push(promise.catch(err => {
console.log('Posting to Database failed ', err);
throw err;
}));
} else {
console.log('no test case found for test: ' + assert.description + ' -- skipping');
// I don't think you want to `throw err` here, right?
}
}
}
return Promise.all(results);
});
};
I switched to using the Node JS mssql tedious drivers with the STREAM.
The arrow syntax is throwing me off big time with scope and the loops etc...
I am successful in taking the 1st query result and then appending nested data to it. However this make no sense to me
request.on('row', row => { // so "row" is object of data in scope but how to access?
console.log(row); // I see that I am giving it to spit out the records on each loop
obj = extend({}, row); // this was a hail mary move to try to copy the object from more of a global object declaration.
Problem is the request.on('row', row => { is a loop that is isolated :/
SOOO , what I want to do it RETURN THAT FINISHED recordset of "row" ...
I have this code
request.on('done', results => {
// this code cannot see "row"
before the arrow function etc... , I would return my data with
res.json(mydata); // how I did in the past
});
Complete code
(function () {
'use strict';
var sql = require('mssql');
var xconfig = require('../../config.js');
var newConfig = xconfig.database.liberty;
var extend = require('util')._extend;
exports.getLibScriptQuestions = function (connection, req, res) {
//console.log('conn',connection);
const poolLiberty = new sql.ConnectionPool(newConfig, err => {
var obj = "";
var responseData = [];
var request = new sql.Request(poolLiberty);
request.stream = true;
var query = 'SELECT * FROM ' +
' dbo.vwScriptQuestions vwsq';
request.query(query);
request.on('recordset', columns => {
// emit once
});
request.on('row', row => {
var requestOD = new sql.Request(poolLiberty);
requestOD.input('QuestionId', sql.Int, row.QuestionId);
var sqlquery = 'SELECT q.id AS QuestionId, d.* FROM ' +
' Scripts.Question q ' +
' JOIN Scripts.QustionDirectiveAssoc qda ON q.Id = qda.QuestionId' +
' JOIN Scripts.Directives d on qda.DirectiveId = d.Id ' +
' WHERE q.Id = #QuestionId';
requestOD.query(sqlquery, (err, result) => {
row.directives = result.recordset;
//console.log('row', row)
//console.log(row.directives[0].Tag);
obj = row.directives[0].Tag;
//obj.push(row.directives);
//obj = extend({}, row.directives);
responseData.push(row);
//console.log(result.recordset);
//console.log('directives',row.directives);
});
//console.log(row);
//
})
request.on('error', err => {
// May be emitted multiple times
console.log('err', err);
})
request.on('done', result => {
console.log('done x records', result);
console.log('request',request.query.recordsets);
console.log(responseData);
console.log('obj', obj)
//res.json(vm);
res.json(responseData);
})
})
sql.on('error', err => {
console.log('err happened', err);
})
}
}());
See if this is what you want to achieve.
let responseData = [];
request.on('row', row => {
responseData.push(row);
});
request.on('done', results => {
res.json(responseData);
});