How to run code only after query has finished? - javascript

I have the following code:
var userFound = false;
let sql = `SELECT box_id, cubby_id, comport, deliveredToUser
FROM recipients
WHERE package_password = ?`;
connection.query(sql, [req.session.sessionUserPackagePassword],
function(err, rows, fields) {
if (!err) {
for (var i = 0; i < rows.length; i++) {
// Make the comparaison case insensitive
if ((rows[i].deliveredToUser).toLowerCase() == `no`) {
userFound = true;
console.log(userFound);
var comport = rows[i].comport;
var command = "open" + rows[i].cubby_id;
var commandClose = "close" + rows[i].cubby_id;
var commandStatus = "status" + rows[i].cubby_id;
console.log(command);
console.log(comport);
var options = {
scriptPath: 'python/scripts',
// pass arguments to the script here
args: [command, comport, commandClose, commandStatus]
};
PythonShell.run('controlLock.py', options, function(err, results) {
if (err) {
res.render('errorConnection', {});
}
console.log('results: %j', results);
});
}
}
console.log(userFound);
// If the query fails to execute
} else {
console.log('Error while performing Query.');
res.render('errorConnection', {});
}
});
connection.end();
if (!userFound) {
//
res.render('pickup/errorAlreadyDelivered', {});
connection.end();
}
I would want this part at the end to be run only once the query has finished:
if (!userFound) {
//
res.render('pickup/errorAlreadyDelivered', {});
connection.end();
}
console.log("connection ended " + userFound);
I placed a console.log outside of the query and at the bottom and despite the query value changing to true it prints out false first, and comes out first because the console.log didn't wait until the query has finish to be able to store the value.

Related

how to call an array which is in a function from the another function in javascript?

This is the async function:
async function getpackages(conn, childId, callback) {
var childId = childId;
var request6 = new sql.Request(conn);
var packageQuery = "select OrderId,ChildID from dbo.tbl_Scheduler where NoOfMealsLeft>0 and ChildId=" + childId;
await request6.query(packageQuery, function (err, packagelist) {
if (!err && packagelist.recordsets.length > 0) {
console.log("Error:" + err + "Result:" + util.inspect(packagelist.recordsets[0]));
var orderdetail_ = [];
for (i = 0; i < packagelist.recordsets[0].length; i++) {
orderdetail_.push(packagelist.recordsets[0][i].OrderId);
}
console.log("-->" + orderdetail_);
callback(null, packagelist.recordsets[0]);
} else if (packagelist.recordsets.length < 1) {
callback("Not a valid id input", null);
}
});
};
I need to call the orderdetails_ array in the query. The array contains four data and I need to iterate over 4 data one by one, using the or in the SQL query.
module.exports.newscheduledmeal = function (req, res, next, callback) {
let entered_date = req.query.date;
let childId = req.query.id;
let current_date = new Date().toISOString().slice(0, 10);
if (entered_date < current_date) {
return callback('Please enter date more than or equal to current date.', null);
} else
var conn = new sql.ConnectionPool(dbConfig);
try {
conn.connect().then(function () {
var request = new sql.Request(conn);
getpackages(conn, childId, function (err, orderid) {
if (err) {
callback(err, null);
} else
var PackageidQuery = "select PackageId from dbo.tbl_Order where OrderId=";
request.query(PackageidQuery, function (err, packagelist) {
if (!err) {
conn.close();
callback(null, packagelist.recordsets);
} else {
conn.close();
callback("Error", null);
}
});
});
});
} catch (err) {
console.log("Exception occured:" + err);
conn.close();
callback(err, null);
}
};
I want to get the details of the array which is in getpackages to be used in the module section and specifically in the SQL query section.

Mysql select clause in Node.js

hello i wannna create sql caluse using this function
function selectFrom(reqContents, callback) {
connection.query('SELECT ?? FROM ?? WHERE ?', [ reqContents.attribute,
reqContents.table, reqContents.GET ], function(err, tuple, result) {
if (err) {
console.log(err);
} else {
callback(tuple);
}
});
}
First parameter(reqContents) is array and i have to use this function. But when i wrote multiple where conditions(below example), this query can't operate well.
Example :
reqContents.GET = {
id : user1,
passwd : 1
}
Here is a function I wrote to take the .GET params from reqContents and generate the where clause from its key, values
function buildQuery(params){
// Join the attributes to be in the form of att1,att2,att3
params.attribute = params.attribute.join(",");
// Generate WHERE clause conditions with AND between them
params.GET = (function generateWhere(keyValues){
var str = "";
for(var key in keyValues) {
str += key + " = " + (isNaN(keyValues[key])? '"'+keyValues[key]+'"': keyValues[key]);
if(Object.keys(keyValues).indexOf(key) != Object.keys(keyValues).length-1)
str+= " AND ";
};
return str;
})(params.GET);
return params;
}
This is what you need to do:
function selectFrom(reqContents, callback) {
reqContents = buildQuery(reqContents);
connection.query('SELECT ?? FROM ?? WHERE ?', [ reqContents.attribute,
reqContents.table, reqContents.GET ], function(err, tuple, result) {
if (err) {
console.log(err);
} else {
callback(tuple);
}
});

Javascript for loop wait for callback

I have this function:
function tryStartLocalTrendsFetch(woeid) {
var userIds = Object.keys(twitClientsMap);
var isStarted = false;
for (var i = 0; i < userIds.length; i++) {
var userId = userIds[i];
var twitClientData = twitClientsMap[userId];
var isWoeidMatch = (woeid === twitClientData.woeid);
if (isWoeidMatch) {
startLocalTrendsFetch(woeid, twitClientData, function (err, data) {
if (err) {
// Couldn't start local trends fetch for userId: and woeid:
isStarted = false;
} else {
isStarted = true;
}
});
// This will not obviously work because startLocalTrendsFetch method is async and will execute immediately
if (isStarted) {
break;
}
}
}
console.log("No users are fetching woeid: " + woeid);
}
The gist of this method is that I want the line if (isStarted) { break; } to work. The reason is that if it's started it should not continue the loop and try to start another one.
I'm doing this in NodeJS.
try to use a recursive definition instead
function tryStartLocalTrendsFetch(woeid) {
var userIds = Object.keys(twitClientsMap);
recursiveDefinition (userIds, woeid);
}
function recursiveDefinition (userIds, woeid, userIndex)
var userId = userIds[userIndex = userIndex || 0];
var twitClientData = twitClientsMap[userId];
var isWoeidMatch = (woeid === twitClientData.woeid);
if (isWoeidMatch && userIndex<userIds.length) {
startLocalTrendsFetch(woeid, twitClientData, function (err, data) {
if (err) {
recursiveDefinition(userIds, woeid, userIndex + 1)
} else {
console.log("No users are fetching woeid: " + woeid);
}
});
} else {
console.log("No users are fetching woeid: " + woeid);
}
}
You may also use async (npm install async):
var async = require('async');
async.forEach(row, function(col, callback){
// Do your magic here
callback(); // indicates the end of loop - exit out of loop
}, function(err){
if(err) throw err;
});
More material to help you out: Node.js - Using the async lib - async.foreach with object

node.js async function in loop?

I am having some problems with node.js. What I'm trying to do is get an array of the directories in "./"+req.user.email and loop through them finding out their size and adding a table row to output, as you can see in the code. At the end I wan't to send all the table rows using res.send().
However the only output I am getting is:
<tr></tr>
for each file in the array. It seems that the forEach function is not waiting for readSizeRecursive at all. The readSizeRecursive function is asynchronous, and I believe that is what's causing the problem, but I don't know how I can fix this.
Any help would be greatly appreciated, I have included the readSizeRecursive function too. Thank you!
var output = "";
fs.readdir("./" + req.user.email, function (err, files) {
files.forEach(function(file){
output += "<tr>";
readSizeRecursive("./"+req.user.email+"/"+file, function (err, total){
output += '<td>' + file + '</td><td>' + total + '</td>';
});
output += "</tr>"
});
res.send(output)
});
readSizeRecursive() :
// Function to find the size of a directory
function readSizeRecursive(item, cb) {
fs.lstat(item, function(err, stats) {
var total = stats.size;
if (!err && stats.isDirectory()) {
fs.readdir(item, function(err, list) {
async.forEach(
list,
function(diritem, callback) {
readSizeRecursive(path.join(item, diritem), function(err, size) {
total += size;
callback(err);
});
},
function(err) {
cb(err, total);
}
);
});
}
else {
cb(err, total);
}
});
}
Please use the async module for this kind of pattern. Using async.each will allow you to compute the size for each folder asynchronously, and then return the sizes once you're done computing everything individually.
var output = [];
fs.readdir('./' + req.user.email, function (err, files) {
async.each(compute, report);
});
function compute (file, done) {
// calculate size, then callback to signal completion
// produce a result like below, then invoke done()
var obj = { files: [
{ name: file, size: size },
{ name: file, size: size },
{ name: file, size: size }
]};
output.push(obj);
done();
}
// doesn't need to be this awful
function format (list) {
var result = [];
list.forEach(function (item) {
var description = item.files.map(function (file) {
return util.format('<td>%s</td><td>%s</td>', file.name, file.size);
});
result.push(description);
});
result.unshift('<tr>');
result.push('</tr>');
return result.join('</tr><tr>');
}
function report (err) {
if (err) { return next(err); }
var result = format(output);
res.send(result);
}
This way you can easily swap out the different pieces of functionality, changing the formatting without altering the computing of the file size tree, for example.
Your main issue was control flow. You return with res.send while you are asynchronously looping and figuring out the sizes.
var fs = require ("fs");
var createTableContent = function (p, cb){
var read = function (p, cb){
//Prevent recursion if error
if (err) return cb ();
fs.stat (p, function (error, stats){
if (error){
err = error;
return cb ();
}
if (stats.isDirectory ()){
var dirSize = 0;
fs.readdir (p, function (error, entries){
if (error){
err = error;
return cb ();
}
var pending = entries.length;
//Empty dir
if (!pending) return cb (0);
entries.forEach (function (entry){
read (p + "/" + entry, function (entrySize){
dirSize += entrySize;
if (!--pending) return cb (dirSize);
});
});
});
}else{
cb (stats.size);
}
});
};
//A lot of errors can be produced, return only the first one
var err = null;
//Suppose p is a dir
fs.readdir (p, function (error, entries){
if (error) return cb (error);
var content = "";
var pending = entries.length;
if (!pending) return cb (null, content);
entries.forEach (function (entry){
read (p + "/" + entry, function (totalSize){
if (err) return cb (err);
content += "<tr><td>" + entry + "</td><td>" + totalSize + "</td></tr>";
if (!--pending){
//End
cb (null, content);
}
});
});
});
};
//Here goes the "email" path
createTableContent (".", function (error, content){
if (error) return console.error (error);
console.log (content);
});

How to use global error handling code in node.js for entire api call

I have a api call which has more than one functions. Instead of applying error-handling for each and every method, is it possible to use global error handling code that send the error to UI developers.
The code is given below:
app.post('/billing/pricingdetails', function (req, res) {
console.log('pricing api called');
var workload = req.body;
var resourcelevelPricing = {};
var response = {};
var workloadinfo = {
workloadId: workload.workloadId,
ownerId: workload.ownerId,
uniqueName: workload.uniqueName,
name: workload.name
}
var pricing = {}
var allresourceIdentifiers;
if (workload.elements && workload.elements.length > 0) {
var elementlevelpricingSummary = {};
var elementArray = [];
var allresourceIdentifierArray = [];
var elementinfo = {};
var metadataModified = {};
var elementsParam = workload.elements;
// handle configurable resource
var configurableElementarray = [];
// create array of all the elements in workloadjson - to be used for resourcelevel (instance/image), charamountunitlevel, resourcetypelevel pricing detail
for (var index in elementsParam) {
// if condition skips the uri of configurable resources - handle configurable resource
if(!elementsParam[index].parameters.ResourceParameters)
{
allresourceIdentifierArray.push(elementsParam[index].uri);
if (elementsParam[index].parameters.imageUri) {
allresourceIdentifierArray.push(elementsParam[index].parameters.imageUri);
}
}
}
var allresourceIdentifiers = allresourceIdentifierArray.join(',');
// call the functionalities that gives the each level of pricing detail synchronously to construct the workload json
async.series([
function (callback) {
getpricingSummary(elementsParam, function (err, workloadinfo) {
if(err){
}
else
{
callback(null, workloadinfo);
}
});
},
function (callback) {
getPricingforResourceIdentifiers(allresourceIdentifiers, function (err, pricingDetail) {
pricing.resourceLevel = pricingDetail;
callback(null, pricingDetail);
});
},
function (callback) {
getchargeamountunitlevelPricing(allresourceIdentifiers, function (err, pricingDetail) {
//merge configurable resource with concrete resource pricing details - handle configurable resource
if(configurableElementarray.length > 0)
{
var concatednatedArray = pricingDetail.concat(configurableElementarray);
var finalResult = [];
var i = concatednatedArray.reduce(function (result, o) {
var key = o.chargeAmountUnit + o.currencyCode;
if (!(key in result)) {
result.arr.push(result[key] = o);
finalResult.push(result);
}
else {
result[key].chargeAmount += Number(o.chargeAmount);
}
return result;
}, { arr: [] }).arr;
pricing.chargeamountunitLevel = i;
trace.info(i);
}
else
{
pricing.chargeamountunitLevel = pricingDetail;
}
callback(null, pricingDetail);
});
},
function (callback) {
getresourcetypelevelPricing(allresourceIdentifiers, function (err, pricingDetail) {
if(configurableElementarray.length > 0)
{
var concatednatedArray = pricingDetail.concat(configurableElementarray);
var i = concatednatedArray.reduce(function (result, o) {
var key = o.chargeAmountUnit + o.currencyCode + o.Name;
if (!(key in result)) {
result.arr.push(result[key] = o);
}
else {
result[key].chargeAmount += o.chargeAmount;
}
return result;
}, { arr: [] }).arr;
pricing.resourcetypeLevel = i;
trace.info(i);
}
else
{
pricing.resourcetypeLevel = pricingDetail;
}
callback(null, pricingDetail);
});
}
],
function (err, result) {
workloadinfo.pricing = pricing;
res.send(workloadinfo);
});
// get element level pricing summary for each elements (vm/vs) in the array within workload json - the output to be appended within metadata of workload json
function getpricingSummary(elementsParam, callback) {
async.forEachSeries(elementsParam, createResponse, function (err,result) {
return callback(null, result);
});
};
// this method called by async.forEachSeries passing each elements (vm/vs) of workload
function createResponse(elements, callback) {
var resourceIdentifierArray = [];
elementinfo = elements;
resourceIdentifierArray.push(elements.uri);
if (elements.parameters.imageUri) {
resourceIdentifierArray.push(elements.parameters.imageUri);
}
// build string of resourceIdentifier (instance/image) for input element
var resourceIdentifiers = resourceIdentifierArray.join(',');
console.log(resourceIdentifiers);
if(elements.parameters.ResourceParameters)
{
trace.info('1');
trace.info(elements.parameters.ResourceParameters);
var configJson = JSON.parse(elements.parameters.ResourceParameters);
trace.info(Number(configJson.cpuCount));
metadataModified = elements.metadata;
// TODO : Remove this hard-coding
elementlevelpricingSummary.Name = 'Hardware';
if(configJson.totalUnitPrice)
{
var chargeAmount = configJson.totalUnitPrice;
elementlevelpricingSummary.chargeAmount = Math.round(chargeAmount * 100)/100;
}
if(configJson.ChargeAmountUnit)
{
var chargeAmountUnit = configJson.ChargeAmountUnit;
elementlevelpricingSummary.chargeAmountUnit = configJson.ChargeAmountUnit;
}
if(configJson.CurrencyCode)
{
var currencyCode = configJson.CurrencyCode;
elementlevelpricingSummary.currencyCode = configJson.CurrencyCode;
}
metadataModified.pricingSummary = elementlevelpricingSummary;
configurableElementarray.push(elementlevelpricingSummary);
// delete original metadata from workload json (to be replaced by metadata containing pricing summary)
delete elementinfo.metadata;
elementinfo.metadata = metadataModified;
elementArray.push(elementinfo);
// global workloadinfo variable is appended with array of elements with its pricing summary within metadata of respective elements
workloadinfo.elements = elementArray;
return callback();
}
else
{
// Get element level pricing summary
mysql.elementlevelpricing(resourceIdentifiers, conn, function (result) {
elementlevelpricingSummary = result;
metadataModified = elements.metadata;
metadataModified.pricingSummary = elementlevelpricingSummary;
// delete original metadata from workload json (to be replaced by metadata containing pricing summary)
delete elementinfo.metadata;
elementinfo.metadata = metadataModified;
elementArray.push(elementinfo);
// global workloadinfo variable is appended with array of elements with its pricing summary within metadata of respective elements
workloadinfo.elements = elementArray;
return callback(null,workloadinfo);
});
}
};
function getPricingforResourceIdentifiers(resourceIdentifiers, callback) {
mysql.pricingDetail(resourceIdentifiers, conn, function (result) {
return callback(null, result);
});
};
function getchargeamountunitlevelPricing(resourceIdentifiers, callback) {
mysql.chargeamountunitlevelPricing(resourceIdentifiers, conn, function (result) {
return callback(null, result);
});
};
function getresourcetypelevelPricing(resourceIdentifiers, callback) {
mysql.resourcetypelevelPricing(resourceIdentifiers, conn, function (result) {
return callback(null, result);
});
};
};
});
With Express, you can install an error handler which will be called when an error occurs in any of your routes:
// somewhere at the end of your middleware/route chain
app.use(function(err, req, res, next) {
res.send(500, err.message); // or whatever you want to send back
});
It would still be best to rethrow any errors that occur in your code:
if (err) throw err;
Also, since you're using async, you can always propagate errors back to it:
if (err) return callback(err);
And handle the errors in the final callback.

Categories

Resources