node js calling same deferred function from client and another node module - javascript

Is there a better way to call the same function from the client and another node js module. Without having 2 separate functions. The only difference method the value is returned?
exports.getFiles = function(req,res){
var globPattern = req.body.globPattern;
var globOptions =req.body.globOptions;
glob(globPattern, globOptions, function (err, files) {
if(err)
{
res.status(400);
winston.log('error', err);
return res.send({success:false,reason: err});
}
res.send({success:true,data:files});
});
};
exports.getFilesFunc = function(payload){
var deferred = q.defer();
var globPattern = payload.globPattern;
var globOptions = payload.globOptions;
glob(globPattern, globOptions, function (err, files) {
if(err)
deferred.resolve({success:false,reason: err});
deferred.resolve({success:true,data: files});
});
return deferred.promise;
};

You can basically call getFilesFunc from getFiles:
exports.getFilesFunc = function(payload){
return Q.nfcall(glob, payload.globPattern, payload.globOptions);
};
exports.getFiles = function(req,res){
this.getFilesFunct(req.body).then(function(files) {
res.send({success:true, data:files});
}, function(err) {
res.status(400);
winston.log('error', err);
return res.send({success:false, reason: err});
});
};

Since you're using Promises, you can shorten your code to the following:
var Q = require('q'),
glob = Q.denodeify(require('glob'));
exports.getFiles = function(pattern, options) {
return glob(pattern, options);
};
Then in your controller, or wherever you're calling the function you'd control what you're going to do with your retured data:
module
.getfiles(req.body.globPattern, req.body.globOptions)
//or .getFiles(payload.globPattern, payload.globOptions)
.then(function (files) {
}, function (error) {
});

Related

how to return array in Node.js from module

getting undefined all the time "main.js":
var dbAccess = require('../dao/dbAccess');
dbaInstance = new dbAccess();
var wordPool = dbaInstance.getWordPool();
console.log (wordPool);
and "dbAccess.js" contains:
var DatabaseAccess = function() {}
DatabaseAccess.prototype.getWordPool = function () {
RoundWord.find({},'words decoys', function(err, wordPoolFromDB) {
if (err) throw err;
//console.log(wordPoolFromDB); -working ok
return (wordPoolFromDB);
});
}
module.exports = DatabaseAccess;
why is it not working?
DatabaseAccess.prototype.getWordPool is not returning any result.
Since you are using an asynchronous function, you need do one of these things:
a) Take a callback as parameter and invoke the callback with a result
DatabaseAccess.prototype.getWordPool = function (cb) {
RoundWord.find({}, 'words decoys', function(err, results) {
if (err) {
return cb(err, null);
}
cb(null, results);
});
}
The callback convention is: cb(error, results...)
b) Use promises
DatabaseAccess.prototype.getWordPool = function () {
return RoundWord.find({}, 'words decoys', function (err, results) {
if (err) {
throw err; // however you might want to sanitize it
}
return results;
});
}
To consume this result you will need to do it as a promise
databaseAccess.getWordPool()
.catch(function (err) {
// process the error here
})
.then(function (results) {
// something with results
});
It will work if you change to this:
var dbAccess = require('../dao/dbAccess');
dbaInstance = new dbAccess();
dbaInstance.getWordPool(function(wordPool){console.log (wordPool);});
And:
var DatabaseAccess = function() {}
DatabaseAccess.prototype.getWordPool = function (cb) {
RoundWord.find({},'words decoys', function(err, wordPoolFromDB) {
if (err) throw err;
//console.log(wordPoolFromDB); -working ok
cb(wordPoolFromDB);
});
}
module.exports = DatabaseAccess;
If the function is Asynchronous you need to pass a callback to find to get the result:
DatabaseAccess.prototype.getWordPool = function (callback) {
RoundWord.find({},'words decoys', function(err, wordPoolFromDB) {
if (err) throw err;
callback(err, wordPoolFromDB);
});
}
and call it as follows in main:
dbaInstance.getWordPool(function (err, wordPool) {
console.log (wordPool);
// wordPool is only available inside this scope,
//unless assigned to another external variable
});
// cannot access wordPool here

returning data from node mssql execute functions

I'm using mssql(Microsoft SQL Server client for Node.js) package from npm.I'm trying to execute a stored procedure residing in my sql server database.Everything works fine.However what I want to do is return the recordsets so that i can export this to be used in other module.Below is what I'm trying to do.
function monthlyIceCreamSalesReport (scope){
var connObj = connConfig();
connObj.conn.connect(function(err){
if(err){
console.log(err);
return;
}
connObj.req.input('Month',4);
connObj.req.input('Year',2016);
connObj.req.execute('<myStoredProcedure>', function(err, recordsets, returnValue){
if(err){
console.log(err);
}
else {
console.log(recordsets[0]); // successfully receiving the value
}
connObj.conn.close();
});
});
console.log('check for recordsets', recordsets[0]); // undefined
return recordsets[0];
}
var sqlServerObj = {
monICSalesReport : monthlyIceCreamSalesReport,
};
module.exports = sqlServerObj;
As shown in the code snippet, since the value of recordsets[0] is undefined, exporting this function is of no use.
You can't return this way in async nature. You can get it by passing the callback function
Try to give a callback function like this
function monthlyIceCreamSalesReport(scope, callback) { // pass a callback to get value
var connObj = connConfig();
connObj.conn.connect(function(err) {
if (err) {
console.log(err);
return;
}
connObj.req.input('Month', 4);
connObj.req.input('Year', 2016);
connObj.req.execute('<myStoredProcedure>', function(err, recordsets, returnValue) {
if (err) {
console.log(err);
} else {
console.log(recordsets[0]);
connObj.conn.close();
return callback(null, recordsets[0]); //return as a callback here and get that value in callback from where you called this function
}
});
});
}
var sqlServerObj = {
monICSalesReport: monthlyIceCreamSalesReport,
};
module.exports = sqlServerObj;
Note: See the comment to understand the changes
recordsets[0] is undefinded, because is defined only in connObj.req.execute function scope. You may do this in this way:
function monthlyIceCreamSalesReport (scope, cb){
var connObj = connConfig();
connObj.conn.connect(function(err){
if(err){
console.log(err);
return cb(Error("Something wrong"));
}
connObj.req.input('Month',4);
connObj.req.input('Year',2016);
connObj.req.execute('<myStoredProcedure>', function(err, recordsets, returnValue){
if(err){
console.log(err);
connObj.conn.close();
return cb(Error("Something wrong"));
}
else {
console.log(recordsets[0]); // successfully receiving the value
connObj.conn.close();
return cb(recordsets[0]);
}
});
});
}
var sqlServerObj = {
monICSalesReport : monthlyIceCreamSalesReport,
};
module.exports = sqlServerObj;

Using Q promises - is there a way to make this code less repetitive?

I'm starting an integration test suite for my Node.js app. I'm currently trying to write a setup script that wipes the test database and populates it with some test data. I'm trying to avoid the dreaded "Pyramid of Doom", and I was hoping to use promises as a way of preventing my code from getting out of hand. I'm very new to promises, and I'm still trying to wrap my head around them - it's possible I'm not using them correctly.
Here is my initial version without promises. This works, but has nested callbacks up the wazoo:
var mongoose = require('mongoose');
var User = require('./user');
var MONGODB_URL = process.env.MONGODB_TEST_URL || 'localhost:27017/swot_test';
console.log('\nRunning e2e test preparation script');
console.log('-----------------------------------\n');
console.log('Connecting to database:', MONGODB_URL, '...')
mongoose.connect(MONGODB_URL, function () {
console.log('Wiping database...')
mongoose.connection.db.dropDatabase(function () {
console.log('Setting up test user...')
User.createUser({
email: 'test#example.com',
password: 'tester'
}, function (err, user) {
if (err) throw err;
// If there was more setup, it would have to go here... pyramid of doom!
console.log('Finished.');
process.exit();
});
});
});
Here is a version that uses Q promises:
var Q = require('q');
var mongoose = require('mongoose');
var User = require('./user');
var MONGODB_URL = process.env.MONGODB_TEST_URL || 'localhost:27017/swot_test';
console.log('\nRunning e2e test preparation script');
console.log('-----------------------------------\n');
Q.fcall(function () {
var deferred = Q.defer();
console.log('Connecting to database:', MONGODB_URL, '...');
mongoose.connect(MONGODB_URL, function (err) {
if (err) deferred.reject(new Error(err));
else deferred.resolve();
});
return deferred.promise;
})
.then(function () {
var deferred = Q.defer();
console.log('Wiping database...');
mongoose.connection.db.dropDatabase(function (err) {
if (err) deferred.reject(new Error(err));
else deferred.resolve();
});
return deferred.promise;
})
.then(function () {
var deferred = Q.defer();
console.log('Setting up test user...');
User.createUser({
email: 'test#example.com',
password: 'tester'
}, function (err, user) {
if (err) deferred.reject(new Error(err));
else deferred.resolve();
});
return deferred.promise;
})
.done(function () {
console.log('Finished.');
process.exit();
}, function (err) {
console.error('An error occurred:', err.stack);
});
I like that it has less nesting, but there's a lot of repetition in there. Is there a way I could use the helper functions in the Q API to make this code more concise and less repetitive? Especially this part:
if (err) deferred.reject(new Error(err));
else deferred.resolve();
I would appreciate any help with cleaning up this code.
Q.ninvoke(mongoose,'connect', MONGODB_URL)
.then(function () {
console.log('Wiping database...');
return Q.ninvoke(mongoose.connection.db, 'dropDatabase');
})
.then(function () {
console.log('Setting up test user...')
return Q.ninvoke(User, 'createUser', {
email: 'test#example.com',
password: 'tester'
});
})
.then(function (user) {
console.log('Finished.');
process.exit();
})
.catch(function(err) {
console.log(err);
});
You can possibly shorten it with reusable oncomplete helper like this:
function oncomplete(deferred) {
return function (err, result) {
if (err) deferred.reject(new Error(err));
else deferred.resolve(result);
}
}
Q.fcall(function () {
var deferred = Q.defer();
console.log('Connecting to database:', MONGODB_URL, '...');
mongoose.connect(MONGODB_URL, oncomplete(deferred));
return deferred.promise;
})
.then(function () {
var deferred = Q.defer();
console.log('Wiping database...');
mongoose.connection.db.dropDatabase(oncomplete(deferred));
return deferred.promise;
})
.then(function () {
var deferred = Q.defer();
console.log('Setting up test user...');
User.createUser({
email: 'test#example.com',
password: 'tester'
}, oncomplete(deferred));
return deferred.promise;
})
.done(function () {
console.log('Finished.');
process.exit();
}, function (err) {
console.error('An error occurred:', err.stack);
});
If you're brave enough, you can drastically simplify it with Node v0.11 beta and yield keyword. That would implement an asynchronous state machine, so you could have pseudo-liner code flow without explicit callbacks.
Check out the async module, specifically waterfall. You can read about it here:
https://github.com/caolan/async#waterfalltasks-callback
Basically it allows you to chain a set of nested callbacks in a nice and concise manner.

Create an api which accepts a callback, and also returns a promise

So I'm trying to upgrade an existing api to support promises, but I want to maintain backwards compatibility. So, let's say this is my api:
module.exports = {
deliverPost: function(callback) {
someAsyncFunction(function(err) {
if (err)
console.log(err);
callback(err);
});
}
}
That's great, I can call it and pass a callback, and everything works.
Now we do the same thing with promises:
var q = require('q');
module.exports = {
deliverPost: function() {
return q.nfcall(someAsyncFunction).catch(function(err) {
console.log(err);
throw err;
});
}
}
Great, now it returns a promise, but my problem is, any old clients of this api expect to be able to pass in a callback!
So what I really need is something like this:
var q = require('q');
module.exports = {
deliverPost: function(callback) {
return q.nfcall(someAsyncFunction).catch(function(err) {
console.log(err);
throw err;
}).attachNodeStyleCallback(callback);
}
}
So new callers can leverage the promise support, but everything still works if you pass in a callback.
This is a pattern used by, e.g. jQuery.ajax -- how can I do the same with Q.js?
Here's an implementation of attachNodeStyleCallback for reference:
q.makePromise.prototype.attachNodeStyleCallback = function(callback) {
if (!callback)
return this;
return this.then(function(result) {
callback(null, result);
return result;
}, function(err) {
callback(err);
throw err;
})
}
The answer is to use promise.nodeify:
var q = require('q');
module.exports = {
deliverPost: function(callback) {
return q.nfcall(someAsyncFunction).catch(function(err) {
console.log(err);
throw err;
}).nodeify(callback);
}
}
You could just test for a callback and run the callback code if it is present:
var q = require('q');
module.exports = {
deliverPost: function(callback) {
if(typeof callback === 'function'){
someAsyncFunction(function(err) {
if (err)
console.log(err);
callback(err);
});
}else{
return q.nfcall(someAsyncFunction).catch(function(err) {
console.log(err);
throw err;
});
}
}

How can convert this node.async code to using q? Do I need to return a promise?

In "view" method within my controller was previously using node-async but I wanted to try out using q.
I'm currently trying to convert this
exports.view = function (req, res) {
var category = req.params.category,
id = req.params.id,
ip = req.connection.remoteAddress,
slug = req.params.slug,
submission,
userId = typeof req.session.user !== 'undefined' && req.session.user.id ? req.session.user.id : null,
views;
var getSubmission = function (submissionId, callback) {
Submission.getSubmission({
id: submissionId
}, function (err, submission) {
if (err) {
callback(err);
} else if (submission) {
callback(null, submission);
} else {
callback(err);
}
});
};
async.waterfall([
function (callback) {
getSubmission(id, callback);
},
function (submission, callback) {
res.render('submission', {
title: submission.title + ' -',
submission: submission
});
}]);
To using q... I started doing something like:
var getSubmission = function(id) {
return Submission.getSubmission({
id : submissionId
}).then(function(submission) {
return submission;
});
};
q.fcall(getSubmission).then(function(submission) {
console.log(submission);
});
But it's not quite working as I intended. Am I doing something wrong here? How can I do this?
Is Submission.getSubmission a call to a database? Then you can't "chain" promises to that. You'll have to use the deferred method:
var getSubmission = function(id) {
var deferred = Q.defer();
Submission.getSubmission({
id: id
}, function(err, data){
if (err) {
deferred.reject(err);
} else {
deferred.resolve(data);
}
});
return deferred.promise;
}
getSubmission(some_id).then(successCallback, failureCallback);
You can also use Q#denodeify to convert a function using nodejs-style callbacks (function(err, data)) into a promise based function. Thus, the above can also be achieved by the following:
getSubmissionPromise = Q.denodeify(Submission.getSubmission);
getSubmissionPromise({id: some_id}).then(successCallback, failureCallback);

Categories

Resources