How Can I add A call back to a module - node.js

I create this small module to import in other node js modules.
However my callback function is giving me an error. "callback is not a function".
How can I make it work.
exports.saveConnection = function dao(action, callback){
pool.getConnection(function(err,conn){
if (err) {
console.log(err);
return callback('');
}
//create tables
var createTables = function(conn){
conn.release();
var rl = readline.createInterface({
input: fs.createReadStream('struct.sql'),
terminal: false
});
rl.on('line', function(chunk){
conn.query(chunk.toString('ascii'), function(err, sets, fields){
if(err){
console.log(err);
}else{
console.log("Table created");
}
});
});
console.log("Table created");
}
var findByPrimaryKey = conn.query("select * from user",function(err,rows){
conn.release();
if(err) {
console.log(err);
}
});
conn.on('error', function(err) {
console.log(err);
return;
});
callback(findByPrimaryKey);
});
};

When ever you are about to call callback you have to check if its a function or not. you can do that by following check
if (typeof(callback) === 'function') {
// call callback here
} else {
// just return because callback is not supplied
}
and when you call exports.saveConnection you have to supply callback as second param if you want to do something in that callback

Related

i have come across a strange error in nodejs filesystem

i am working with the filesystem protocol of nodejs. i did writing the file, reading the file and now trying to rename it. it actually renames the file but throws me this error and my localhost stops running.
this is the error:
_http_outgoing.js:690
throw new ERR_INVALID_ARG_TYPE('chunk', ['string', 'Buffer'], chunk);
TypeError [ERR_INVALID_ARG_TYPE]: The "chunk" argument must be one of type string or Buffer. Received type object
file1: var fs = require('fs');
// write
function write(fileName, content) {
return new Promise(function (resolve, reject) {
fs.writeFile(`./test/${fileName}`, content, function (err, done) {
if (err) {
reject(err);
return;
}
resolve(done);
// console.log('file created >>', done);
});
})
}
function readFile(fileName, cb) {
fs.readFile(`./test/${fileName}`, 'utf-8', function (err, done) {
if (err) {
cb(err);
return;
}
cb(null, done);
})
}
function rename(oldname, newname, cb){
fs.rename(`./bands/${oldname}`, `./bands/${newname}`, function(err,done){
if(err){
cb(err)
return
}
cb(null,done)
})
}
rename('pinkfloyd.txt', 'tool.txt', function(err, done){
if(err){
console.log('error in renaming')
}
else{
console.log('renamed>>')
}
})
readFile('kisor.txt', function(err,done){
if(err){
console.log("error in file reading >>",err);
}else{
console.log('success >>',done);
}
})
write('kisor.txt', 'i am javascript')
.then(function (data) {
console.log('write success ', data);
})
.catch(function (err) {
console.log('error in wirte >>', err);
})
// objec short hand
module.exports = {
write, readFile, rename
}
i have imported the exported stuff from file 1 here in this file:
//var { write,readFile, } = require('./file');// object destruct
var fileOp = require('./file1');
//console.log('file operation >>', fileOp);
fileOp.write('brodway.txt', 'i am infosys of nepal')
.then(function (data) {
console.log('done >>>', data);
})
.catch(function(err){
console.log('err',err);
})
fileOp.readFile('kisor.txt',function(err,done){
if(err){
console.log('err',err);
}else{
console.log('success >>',done);
}
and lastly, here is the server:
var http = require('http');
var fileOp = require('./file1');
var server = http.createServer(function (request, response) {
// this function will be executed whenever a client is connected
// request or 1st argument is http request object
// response or 2nd argument is http response object
var url = request.url;
if (url == '/write') {
fileOp.write('abcd.js', 'hi')
.then(function (data) {
response.end('data', data);
})
.catch(function (err) {
response.end(err);
})
} else if (url == '/read') {
fileOp.readFile('abcd.js', function (err, done) {
if (err) {
response.end(err);
} else {
response.end('done' + done);
}
})
} else if(url == '/rename'){
fileOp.rename('pinkfloyd.txt', 'tool.txt', function(err, done){
if(err){
response.end(err)
}
else{
response.end('done', done)
}
})
} else {
response.end('form default page');
}
console.log('client connected to server');
console.log('request url >>', request.url);
// request response cycle must be completed
// response.end('hi from node server'); response cannot sent more than once
});
server.listen(8080, function (err, done) {
if (err) {
console.log('server listening failed');
}
else {
console.log('server listening at port 8080');
console.log('press CTRL + C to exit from server');
}
});
In this section of code:
fileOp.rename('pinkfloyd.txt', 'tool.txt', function(err, done){
if(err){
response.end(err)
}
else{
response.end('done', done)
}
You are calling response.end('done', done). But, the fs.rename() callback does not have a done argument - it only has the err argument because there's no data to communicate back - the rename either succeeded or it didn't . So, done will be undefined. So you're calling:
response.end('done', undefined);
The function signature for response.end() is this:
response.end([data[, encoding]][, callback])
So, you're trying to send undefined for the encoding. That is not correct.
Your rename function should be change from this:
function rename(oldname, newname, cb){
fs.rename(`./bands/${oldname}`, `./bands/${newname}`, function(err,done){
if(err){
cb(err)
return
}
cb(null,done)
})
}
to this:
function rename(oldname, newname, cb){
fs.rename(`./bands/${oldname}`, `./bands/${newname}`, function(err){
if(err){
cb(err);
return
}
cb(null); // no 2nd argument here
})
}
or even simpler:
function rename(oldname, newname, cb){
fs.rename(`./bands/${oldname}`, `./bands/${newname}`, cb);
}
FYI, it appears you're using .end() improperly a bunch of places in your code where you do this:
response.end('done', someData);
That's not how it works. You aren't emitting an event. You're commanding the end of the http response and you need to follow this function signature:
response.end([data[, encoding]][, callback])
So, you'd probably just do response.end(data), if data was a string.

Node js nested async call

I want to do async call from my getData function to getImage function but i am unable to get return data from getImage().Since the getData() does't wait for the completion of getImage(),as getImage() has further async db calls and therefore getData() always returns undefined.
What is the best way to do this instead doing nested callbacks?
var getData = function(id){
async.series([
function(callback){
var res = getImages(id);
callback(null, res);
}
],
// optional callback
function(err, results){
if (err) {
console.log("ERROR : " + err);
}else
{
console.log("Result: "+results);
}
});
}
var getImages = function(id){
async.series([
function(callback){
Image.find({id: id }).exec(
function(err, image) {
if (err) {
console.log(err);
callback(err, 0);
}else
{ console.log("Count: "+ image.length);
callback(null, image);
}
});
}
],
// optional callback
function(err, results){
if (err) {
console.log("ERROR : " + err);
}else
{
return results;
}
});
}
getData(1);
As you said you need to wait for getImages() to return, and you do that using promises.
Use any promise library, like q for instance:
var q = require('q')
...
var getImages = function(id){
var deferred = q.defer();
...
//do async logic that that evaluates some res obj you wish to return
db.find(..., function() {
deferred.resolve(res);
}
return deferred.promise;
}
Then, from getData(), you call it in the following matter:
getImages(id).then(
function(res) {
callback(null, res);
},
function(err) {
console.log("error:" + err);
}
);
As you are already using async - just use the waterfall functionality: https://github.com/caolan/async#waterfalltasks-callback
This way you will be able to run functions one after another and wait for the previous to finish, while still getting it's return value.

NodeJS Returning Data

I have the following code which isn't returning data properly.
app.post('/login',function(req,res){
sess=req.session;
var au = authme(req.body.name,req.body.pass, function(err,data) {
if(err) {
return 'error';
}
console.log(data);
return data;
});
if(au) {
sess.username = au.name;
}
res.end('done');
});
Data is passed all the way to console.log(data); but when I try to use in in the au statement, its returning undefined.
This is the classic async problem. authme is running asynchronously so the code isn't running simply from top to bottom.
var au = authme(req.body.name,req.body.pass, function(err,data) {
console.log('I am second!')
});
console.log('I am first!')
You need to restructure the code a bit to get the desired behavior.
app.post('/login',function (req,res) {
authme(req.body.name,req.body.pass, function(err, data) {
if (err) {
return 'error';
}
if (data) {
req.session.username = data.name;
}
res.end('done');
});
});
Probably the functional call to authme is asynchronous. Put your if statement in the callback of the function call, to assure it is always validated after the asynchronous function has completed execution.
app.post('/login',function(req,res){
sess=req.session;
(authme(req.body.name,req.body.pass, function(err,data) {
if(err) {
return 'error';
}
console.log(data);
if(data) {
sess.username = au.name;
}
}))();
res.end('done');
});
In Nodejs operations are asynchronous - in short it means that result is resolved later, you don't know exactly when, while code execution goes on, not waiting for it. The way to handle such call are the callbacks. More on that topic here and here.
So with your code you fall into that classical trap. This part of the code
var au = authme(req.body.name,req.body.pass, function(err,data) {
if(err) {
return 'error';
}
console.log(data);
return data;
});
is an asynchronous call, that means that this part
function(err,data) {
if(err) {
return 'error';
}
console.log(data);
return data;
}
is a callback that runs only when result is obtained. While this part
if(au) {
sess.username = au.name;
}
is executed immediately after var au = authme(req.body.name,req.body.pass) is done.
By that moment there is no au resolved so that is why you're getting this error.
In your case you should put au check into the callback:
authme(req.body.name,req.body.pass, function(err,data) {
if(err) {
return 'error';
}
if(au) {
req.session.username = au.name;
}
res.end('done');
});

Convert to using promises in DB wrapper module function with Bluebird

I anticipate a callback hell is beginning to form in my code so I decided to start using promises. But I can't wrap my head around implementing it. For example I have a function:
DB.prototype = {
findUser: function (username) {
this._pool.getConnection(function (err, connection) {
if (err) { return callback(true, false); }
connection.query('SELECT password_hash, password_salt FROM users WHERE email = ? AND admin = 1', username,
function (err, rows) {
connection.release();
if (rows.length === 1) { callback(false, rows[0]); }
else { callback(false, false); }
});
connection.on('error', function () { callback(true, false); });
});
}
};
How would I adapt this to using promises instead of callbacks? And how would I use this adapted db.findUser() ?
EDIT:
I got something working. It looks like this:
DB.prototype = {
getConnection: function() {
return this._pool.getConnectionAsync();
}
}
And the usage:
Promise.using(db.getConnection(), function(connection) {
return connection.queryAsync("SELECT password_hash, password_salt FROM users WHERE email = ? AND admin = 1", "exampleUser")
.then(function(rows) {
connection.release();
console.log("is there a row?", rows.length === 1, rows);
// do something with results
});
}).catch(function(err) {
// This is only run if an error is thrown
console.log("error is", err);
});
Is this a good implementation or could something be improved?

Mongoose .findOne not working as an internal function call

With this as a URL:
'api/support-tag/name/myTagName'
This function works properly:
getByName: function (req, res) {
model.Shared_SupportTag.findOne({name: req.params.name}).exec(function (err, results) {
if (err) {
return res.status(400).send({
message: errMsg.Util_ErrorMsg.getErrorMessage(err)
});
}
res.send(results);
})
}
But when I try to call a similar function from within the node server:
supportDoc.category = GetById(item.category);
function GetById(name){
model.Shared_SupportTag.findOne({name: name}).exec(function(err, result){
if(err){
console.log(err)
}else{
console.log(result);
}
})
}
The function does not execute, nor does the error catch, intellisense shows:
err= Reference error; err is not defined
result = Reference error; result is not defined
All I am trying to accomplish is a function call from within the server and not via a URL.
Any solution here? Thanks in advance
In the case of the findOne() method, the positive response (sans error) will either hold a mongoose object or null.
If the same query had been sent using just find(), the result would have been an empty array.
function GetById(name){
model.Shared_SupportTag.findOne({name: name}).exec(function(err, result){
if(err){
console.log(err)
}else{
if (result) console.log(result); //Check whether object exists.
else console.log('Not found!');
}
})
}
Solved:
model.Shared_SupportDoc.find({}).exec(function (err, collection) {
var supportDocs = require('../../data/_seed/support/supportDocs.json');
if (collection.length === 0) {
supportDocs.forEach(function (item) {
var supportDoc = new model.Shared_SupportDoc;
supportDoc.title = item.title;
supportDoc.created = item.date;
supportDoc.icon = item.icon;
supportDoc.likeCount = item.likeCount || 7;
-----> // requires callback - ie asynchronous
GetByName(item.category, function(tagId) {
supportDoc.categoryId = tagId;
-----> // must put save in the callback
supportDoc.save(function (err) {
if (err) {
console.log(supportDoc.categoryId)
console.log('Error: ' + err);
} else {
console.log('Support Doc Seed Complete');
}
});
});
})
}
});}
function GetByName(name, next) {
model.Shared_SupportTag.findOne({name : name}).exec(function (err, result) {
if (!result) {
console.log('Not Found');
next();
} else {
console.log(result._id);
next(result._id);
}
});}

Resources