Return value in PDF-HTML npm package - node.js

I am trying to upload the pdf created with pdf-html npm package and return a value. But pdf.create() always returns undefined. How can I force pdf.create() to return a value?
My method is as below:
return await pdf.create(stocksReport({})).toFile(`./dist/${storestocks.store.storename}.pdf`, async (err, stream)=>{
if(err) console.log(err)
const serviceS3Result = await this.s3Service.uploadFileFromSystem(`${storestocks.store.storename}`, fs.readFileSync(`../${storestocks.store.storename}.pdf`), `${storestocks.store.storename}.pdf`);
fs.unlinkSync(`../${storestocks.store.storename}.pdf`);
return serviceS3Result;
});
but this always returns undefined.
Just to make things clear:
var x = pdf.create(html).toFile(`./dist/test.pdf`, function (err, res){
if(err) console.log(err)
console.log(res);
return 'something'
)};
return x;
this always returns undefined.
Is there a way around this?

Related

async.waterfall() breaks on passing callback to bcrypt.hash()

I am new to async/await and have set up a basic node.js server that handles form data for user registration. Below is my code
async.waterfall([async function(callback){ //Method 1
const hash = await bcrypt.hash(password, 10/*, () => { //breakpoint
console.log("Hash Generated Successfully");
}*/);
return hash;
}, function(hash, callback){ //Method 2
console.log(`The value of passed arg is: ${hash}`);
callback(null, 'success');
}], function(err, result){
if(err){
throw err
}
else {
console.log(result);
}
});
In Method 1, if i don't provide the callback to bcrypt.hash(), the code works correctly and the value of hash is printed. However, if i do provide the callback, i get this output:
The value of passed arg is: undefined.
So, i have two questions here.
1) Why does async.waterfall() break on providing callback to bcrypt.hash()?
2) What is the other way to do error handling, other than callbacks?
Passing the requisite parameters to the bcrypt callback function is a necessity if you plan on including the anonymous function as a parameter. For ex:
const hash = await bcrypt.hash(password, 10, (err, hash) => { // Added err, hash params.
console.log("Hash Generated Successfully");
});
return hash;

AWS Lambda query with async waterfall in node.js 8.10

I send two query sequentially
Query the data from A tables, and then accoring to the result, query the data from B table.
So, I query the data like that,
var async = require('async');
var mysql = require('mysql');
var config = require('./config.json');
var connection = mysql.createConnection({
host : config.dbhost,
user : config.dbuser,
password : config.dbpassword,
database : config.dbname
});
exports.handler = (event, context, callback) => {
// TODO implement
var tasks = [
function (callback) {
connection.query("SELECT email FROM Visitor WHERE id =?;", [1], function (err, row) {
if (err) return callback(err);
if (row.length == 0) return callback('No Result Error');
callback(null, row[0]);
})
},
function (data, callback) {
connection.query("SELECT id,signtime FROM Board WHERE email =?;", data.email, function (err, row) {
if (err) return callback(err);
if (row.length == 0) {
return callback('No Result Error');
}else {
callback(null, row[0])
}
})
}
];
async.waterfall(tasks, function (err, result) {
if (err)
console.log('err');
else
***return result;***
console.log('done');
connection.end();
});
};
I log the data with console.log(), it take the data in command line.
But in lambda, put the function into exports.handler, it response null.
If I change the 'return result' to callback(result), it occurs error.
I think it maybe too simple to solve this problem
If you know about that, please help me
In the first case, response is null because you didn't use neither Promise, nor callback to let the Lambda sandbox know that the job is done. In the second case, you used the callback, but you passed the result as the first argument to it. Lambda programming model for Node.js follows a principle called "error first callback". Long story short, if any error occurred during execution, you should go with callback(error), and if everything is ok and you need to return some result from lambda, you should go with callback(null, result). So basically on your line before console.log('done'); use callback(null, result) and it will work for you.

Node.js async map over MongoDB queries

I'm having a problem with async Node.js module. In my Node.js app, I'm trying to get an array of JSON objects returned by a MongoDB request:
var fruits = ["Peach", "Banana", "Strawberry"];
var finalTab = [];
fruits.forEach(function(fruit) {
db.collection('mycollection').distinct("column1", {"column2":{$regex :fruit}}, (function(err, result) {
finalTab[fruit] = result;
console.log(result); // -> display the desired content
db.close();
if (err) throw err;
}));
});
console.log(finalTab); // -> []
At the moment, I'm at this point.
I'm trying to implement the async.map to iterate through Fruits collection.
https://caolan.github.io/async/docs.html#map
Can someone help? :)
Thanks by advance for help.
EDIT:
As I need all results returned by my db.collection functions, I'm trying to add these async commands to a queue, execute it and get a callback function.
You can try this:
async.map(fruits , function (fruit, callback) {
db.collection('mycollection').distinct("column1", {"column2":{$regex :fruit}}, (function(err, result) {
//here you are assigning value as array property
//finalTab[fruit] = result;
// but you need to push the value in array
finalTab.push(result);
console.log(result); // -> display the desired content
db.close();
if (err) throw err;
//callback once you have result
callback();
}));
}.bind(this), function () {
console.log(finalTab); // finally call
}, function (err, result) {
return Promise.reject(err);
});

Sending response after forEach

(Please note this is not a duplicate of two similarly titled questions, those two questions use Mongoose and the answers apply to Mongoose queries only)
I have a list of directories, each of these directories contains a file. I want to return a JSON list with the contents of each of these files. I can load the files no problem, but because I'm looping over the array with forEach, my empty response is sent before I've actually loaded the contents of the files:
function getInputDirectories() {
return fs.readdirSync(src_path).filter(function(file) {
return fs.statSync(path.join(src_path, file)).isDirectory();
});
}
router.get('/list', function(req, res, next) {
var modules = [];
var input_dirs = getInputDirectories();
input_dirs.forEach(function(dir) {
path = __dirname+'/../../modules/input/'+dir+'/module.json'
fs.readFile(path, 'utf8', function(err, data) {
modules.push(data);
});
});
res.status(200).json(modules);
});
How can I make sure that I only send down the modules array once it's fully loaded, ie: once the forEach is done.
Since fs.readFile is asynchronous, the behaviour that you are having is most likely the expected one.
What you need to do is return your modules when all modules have been read. You could do this inside fs.readFile.
As far as I have understood, you can obtain the total number of directories through input_dirs.length (since I guess getInputDirectories() is returning an array). Now you need some kind of a counter that helps you understand if you have read the last directory or not, and if yes, then you return your modules. Something like this should work:
router.get('/list', function(req, res, next) {
var modules = [];
var input_dirs = getInputDirectories();
var c = 0;
input_dirs.forEach(function(dir) {
path = __dirname+'/../../modules/input/' + dir + '/module.json'
fs.readFile(path, 'utf8', function(err, data) {
c++;
modules.push(data);
if(c == input_dirs.length) {
return res.status(200).json(modules);
}
});
});
});
I suggest you use Promises, example:
var Promise = require('bluebird');
router.get('/list', function(req, res, next) {
var modules = [];
var input_dirs = getInputDirectories();
// 'each' will try to fulfill all promises, if one fails, it returns a
// failed promise.
return Promise.each(input_dirs, function(dir){
path = __dirname+'/../../modules/input/'+dir+'/module.json';
return new Promise(function(resolve, reject){
fs.readFile(path, 'utf8', function(err, data) {
if (err) return reject(err);
return resolve(data);
});
});
}).then(function(modules){
return res.status(200).json(modules);
})
.catch(function(err){
if (err) {
//handle error
}
});
});
This way you move one once you fulfilled your promises.
Instead of fs.readFile use fs.readFileSync

How to properly export/require

I'm trying to export one function this way:
exports.query = function(request){
conn.query(request, function(err, rows, fields){
if(err) console.log(err);
return rows[0].id;
});
}
and using it:
var mysql = require('./mysql');
console.log(mysql.query('SELECT * FROM tablename'));
Proceeding this way for getting a result involves undefined as output.
How do I to fix this, please?
Note that when I just type console.log(rows[0].id) instead of return rows[0].id it sends back 123.
Thanks in advance!
In your example, the output is being returned to the anonymous function of the database query instead of the caller of the module. You can use a callback to return output to the caller of the module.
exports.query = function(request, callback){
conn.query(request, function(err, rows, fields){
if (err) {
callback(err);
} else {
callback(null, rows[0].id);
}
});
}
Then call it like
var mysql = require('./mysql');
mysql.query('SELECT * FROM tablename', function(err, results){
if (err) {
console.error(err);
} else {
console.log(results);
}
});
That's a problem of synchrony.
the conn.query function returns undefined because it finish its execution before the results are fetched (like almost any i/o related operation on js/node).
One possible solution to that, is to provide a callback to your query function.
exports.query = function(request, cb){
conn.query(request, function(err, rows, fields){
// some "special" processing
cb(err, rows, fields);
});
};
If you're not familiar with async functions, take a look on some articles about that:
http://justinklemm.com/node-js-async-tutorial/
https://www.promisejs.org/

Resources