How to set nodejs to work synchronously? - mysql

var job = new cronJob('* * * * * *', function () {
Draft.find().then(data => {
var finalData = data;
finalData.forEach(function(item2) {
if (item2.scheduledTime === 'now') {
finalData.forEach(function (item) {
var psms = {
phoneno: item.senderdata,
sender: item.senderName,
message: item.message
}
var obj = psms;
var finalpostsms = obj.phoneno.split("\n").map(s => ({ ...obj,
phoneno: +s
}));
Profsms.bulkCreate(finalpostsms).then(function (data) {
if (data) {
console.log("successfully moved in profsms mysql");
} else {
console.log("failed");
}
})
});
} else {
console.log('Better you be in drafts..manual input');
}
//delete from draft
if (item2.scheduledTime === 'now') {
Draft.findOneAndRemove({
_id: item2._id
}, function (err, employee) {
if (err)
console.log('err');
console.log('Successfully deleted from draft');
});
} else {
console.log('You cant delete from drafts hahaha because no sendnow statement');
}
});
});
}, function () {
console.log('DelCron Job finished.');
}, true, 'Asia/Calcutta');
This above code, working as asynchronously.
I want the above code to be work as synchronous, need some answers. I am a newbie for JS development
Is it possible to do with async await? i dont know how to write async await code.

Your callback should be
async function(){
let data = await Draft.find();
...process data;
}

This is an async await sample code, you can modify based on your need. But first you need to use Node that support async syntax. I believe node 8 LTS is already have async/await feature.
function get() {
// your db code block
return Promise.resolve(7);
}
async function main() {
const r = await get();
console.log(r);
}
main();

Related

Mocking/Stubbing/unit testing mysql streaming query rows node js

I have a following function which uses streaming-query-rows of mysql node js module. How can i unit test the below function and also i want to mock the database behavior instead of connecting to database while unit test.
'processRow' and ''wirteCsvFile'' function both are synchronous task.
function executeTask(sql_connection,sql_query) {
let query = sql_connection.query(sql_query);
let showInfo = {};
let showids = [];
query
.on('error', (error) => {
console.error(`error executing query --> ${error}`);
})
.on('result', function (row) {
sql_connection.pause();
processRow(row, showInfo, showids, function () {
sql_connection.resume();
});
})
.on('end', function () {
showids.forEach(showid => {
if (showInfo[showid].faults.length === 0) {
delete showInfo[showid];
}
});
wirteCsvFile(showInfo, (error, done) => {
if (error) {
console.error(error);
} else {
console.log("done");
process.exit();
}
})
});
}
You can stub the query function to return whatever you want instead of making request to database:
sinon.stub(connection, "query").callsFake(() => /* whatever you want here */);
You should also break executeTask into smaller functions, for ex:
function errorHandler(error) {
console.error(`error executing query --> ${error}`);
}
function resultHandler(data, row) {
sql_connection.pause();
processRow(row, data.showInfo, data.showids, function() {
sql_connection.resume();
});
}
function endHandler(data) {
data.showids.forEach(showid => {
if (data.showInfo[showid].faults.length === 0) {
delete data.showInfo[showid];
}
});
wirteCsvFile(data.showInfo, (error, done) => {
if (error) {
console.error(error);
} else {
console.log("done");
process.exit();
}
})
}
function executeTask(sql_connection, sql_query) {
let query = sql_connection.query(sql_query);
let data = {
showInfo: {},
showids: [],
};
query.on('error', errorHandler)
.on('result', resultHandler.bind(null, data))
.on('end', endHandler.bind(null, data));
}
Now you can test errorHandler, resultHandler, endHandler separately
What I'm thinking is we can mock the sql_connection with a class of Event Emitter.
const sinon = require("sinon");
const assert = require('assert');
const EventEmitter = require('events');
const src = require('....'); // your source file that contain `executeTask`
// Create mock emitter
class QueryEmitter extends EventEmitter {}
describe('test execute task', function() {
const queryEmitter = new QueryEmitter();
// we build mock connection that contains all methods used as in `sql_connection`
const conn = {
query: sinon.stub().returns(queryEmitter),
pause: sinon.spy(),
resume: sinon.spy()
};
const query = 'SELECT *';
before(function() {
src.executeTask(conn, query);
});
it('calls query', function() {
assert(conn.query.calledWith(query));
});
it('on result', function() {
queryEmitter.emit('result');
assert(conn.pause.called);
// assert if processRow is called with correct arguments
// assert if conn.resume is called
});
it('on end', function() {
queryEmitter.emit('end');
// assert if writeCsvFile is called
});
// probably is not needed since you only call console.log here
it('on error', function() {
queryEmitter.emit('error');
});
});
Hope it helps

How can I execute the SQL query first then the rest of the code?

static listFunc() {
let funclist = [];
const queryList = "SELECT * FROM func";
mysqlModule.queryDB(database, queryList, (err, result) => {
console.log(result[0].id);
if (err) {
res.status(500).json({
"status_code": 500,
"status_message": "internal server error"
});
} else {
for (var i = 0; i < result.length; i++) {
let func = {
'id': result[i].id,
'psw': result[i].senha,
'nome': result[i].nome,
'DoB': result[i].dataNascimento,
'sexo': result[i].genero,
'morada': result[i].morada,
'permissoes': result[i].permissoes
}
funclist.push(func);
}
return funclist;
}
});
}
I created a function to give me all the workers from my DataBase and then store them inside funclist array.
The problem is the for loop is running before the query.
How can I run the loop only after query as finished?
Pass a callback function into listFunc:
static listFunc(callback){...}
Instead of returning the list just invoke the callback:
callback(funclist);
static listFunc() {
return new Promise((resolve,reject)=>{
let funclist = [];
mysqlModule.queryDB(database,"SELECT * FROM func", (err, result) => {
if (err) throw err;
result.forEach((result) => {
let func = {
'id': result.id,
'psw': result.senha,
'nome': result.nome,
'DoB': result.dataNascimento,
'sexo': result.genero,
'morada': result.morada,
'permissoes': result.permissoes
}
funclist.push(func);
});
resolve(funclist);
});
});
}
First i changed the "for" loop to a "each" loop and i used the promise to give me the data only after i get the query and the loop finished.
function clistFunc(req, res){
Func.listFunc().then((data)=>{
res.render('admin/adminListFunc', { funclist: data});
console.log(data);
}).catch(()=>{
console.log('Error');
});
}
Then i just rendered the jade only after my listFunc() return the pretended data.

How to store data in MongoDb using mongoose and async waterfall model

Hello i am new to node and i am trying to save data in mongoose. The problem is that there are 3 collections Units, Building and Section. The Schema of Building is :
var buildingsSchema=new Schema({
buildingname:String,
status:String
});
Schema of Section is :
var sectionsSchema=new Schema({
section_type:String,
buildings:{ type: Schema.Types.ObjectId, ref: 'buildings' },
status:String
});
Schema of Units is :
var unitsSchema=new Schema({
unit_type:String,
unit_num:String,
unit_ac_num:Number,
buildings:{ type: Schema.Types.ObjectId, ref: 'buildings' },
sections:{ type: Schema.Types.ObjectId, ref: 'sections' },
shares:Number
});
in Section there is an Id of Building and in Units there is Id's of both Building & Section
now i have used xlsx plugin to convert uploaded excel file to json by :-
var wb = XLSX.readFile("uploads/xls/" + req.file.filename);
data = XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]], {header:1});
and to map it into json object and saving i am using Async Waterfall Model
for (var index = 1; index < data.length - 1 ; index++) {
var ele= data[index];
// console.log(ele);
var d = { // this is an object which will hold data
record_id: ele[0],
residenceone_unit_id : ele[1],
official_unit_id: ele[2],
building: ele[3],
unit_type : ele[4],
section: ele[5],
shares: ele[6],
unit_style : ele[7]
}
// console.log(d);
var unt = new Units(); // to save units
unt = {
unit_type: d.unit_type,
unit_num: d.residenceone_unit_id,
unit_ac_num: d.official_unit_id,
buildings: '', // empty because need to put id of that particular building
sections: '', // empty because need to put id of that particular sections
shares:d.shares
}
async.waterfall([
function (callback) {
// find building first
Buildings.findOne({buildingname : ele.building})
.exec(function (err,doc) {
if (err) {
return callback(err);
}
// if no building then save one
else if (!doc) {
// console.log("Building is going to save")
var build = new Buildings();
build.buildingname = d.building;
build.status = "active";
build.save(function (err,dc) {
if (err) {
return callback(err);
}
else {
// assign id of building to unit
unt.buildings = dc._id ;
callback(null);
}
})
}
else {
// if building is there then no need to save assign id of it to units
// console.log("Building already exists;")
unt.buildings = doc._id ;
// execute second function
callback(null);
}
// callback(null);
})
},
function (callback) {
// same as building find section of that building first with building Id and section type
Sections.findOne({buildings : unt.buildings,section_type: d.section})
.exec(function (err,doc) {
if (err) {
return callback(err);
}
if (!doc) {
// if no section of that building is there then save one
// console.log("Section needs to be save")
var sect = new Sections();
sect.section_type = d.section;
sect.buildings = unt.buildings;
sect.status = "active";
sect.save(function (err,dc) {
if (err) {
return callback(err);
}
else {
// assign its id to unit
// console.log("Section is saved")
unt.sections = dc._id;
// execute third function
callback(null);
}
})
}
else {
// if there is section of that building id is available than assign id to units
// console.log("Section already exists");
unt.sections = doc._id;
// execute third function
callback(null);
}
})
},
function (callback) {
// there is no need to seaarch just need to save unit
// console.log("Units is going to save")
// console.log(unt);
unt.save(function (err, doc) {
if (err) {
} else if (doc){
// console.log("Unit Saved");
// console.log(doc);
}
})
}
])
}
}
its working but every time instead of searching of data in mongodb it save everytime. Duplication is the main problem if any other way to save units in mongodb will help me a lot.
first i have save Buildings and section :
async.every(uniqueSection,function (uS,callback) {
if (uS != undefined) {
console.log(uS);
Buildings.findOne({buildingname:uS.building}, function (err,doc) {
if (doc) {
// console.log(doc);
Sections.findOne({buildings:doc._id,section_type:uS.section},function (er,sd) {
if (sd) {
// then dont save
console.log(sd);
}
if (er) {
console.log(er);
}
if (!sd) {
// then save
var sect = new Sections();
sect.buildings = doc._id;
sect.section_type = uS.section;
sect.status = 'active';
sect.save(function (err,st) {
if(err) console.log(err);
console.log(st);
})
}
})
}
if (!doc) {
if (uS.building != undefined) {
var building = new Buildings();
building.buildingname = uS.building;
building.status = "active";
building.save(function (er,dc) {
if (dc) {
// console.log(dc);
Sections.findOne({buildings:dc._id,section_type:uS.section},function (er,sd) {
if (sd) {
// then dont save
console.log(sd);
}
if (er) {
console.log(er);
}
if (!sd) {
// then save
var sect = new Sections();
sect.buildings = dc._id;
sect.section_type = uS.section;
sect.status = 'active';
sect.save(function (err,st) {
if(err) console.log(err);
console.log(st);
})
}
})
}
if (er) {
console.log(er);
}
})
}
}
if (err) {
console.log(err);
}
})
}
})
then i have saved Units by :
async.waterfall([
function(callback) {
Buildings.findOne({buildingname:d.building}, function (err,doc) {
if (doc) {
buildingId = doc._id;
callback(null, doc);
}
if (err) {
console.log(err);
}
})
},
function(doc,callback) {
Sections.findOne({buildings: buildingId,section_type:d.section},function (er,sd) {
if (sd) {
sectionId = sd._id;
callback(null,doc,sd);
}
if (er) {
console.log(er);
}
})
},
function (bld,st,callback) {
var s = d.shares.replace(",","");
var unit = {
unit_type: d.unit_type,
unit_num: d.residenceone_unit_id,
unit_ac_num: d.official_unit_id,
buildings: bld._id,
sections: st._id,
shares: s
}
Units.findOne(unit,function (err,unt) {
if (err) {
console.log(err);
}
if(unt) {
console.log(unt)
}
if (!unt) {
var units = new Units();
units.unit_type = d.unit_type;
units.unit_num = d.residenceone_unit_id;
units.unit_ac_num = d.official_unit_id;
units.buildings = bld._id;
units.sections = st._id;
units.shares = s;
units.save(function (er,doc) {
if (er) console.log(er);
console.log(doc);
})
}
})
}
], function(err) {
console.log(err)
});

$http.post within a $http.post, return response is not updated directly

I have a function, it has a $http.post for login purpose. If success, another $http.post will call a php file that fetches data from database. The problem is that, when I am trying to load the data from localStorage it returns me null. Why is it so?
$scope.loginUser = function ()
{
var data =
{
username: $scope.loginInfo.username,
password: $scope.loginInfo.password
}
$http.post("endpoints/login.php", data).success(function(response)
{
if(response==="ERROR")
{
//DONT DO ANYTHING
}
else
{
localStorage.setItem("token", JSON.stringify(response));
console.log("loginController: name is this " + localStorage);
fetchDataFunction(data);
$state.go("application");
//$state.go("application", result);
}
}).error(function(error)
{
console.error(error);
});
}
fetchDataFunction = function(data)
{
$http.post("endpoints/fetchData.php", data).success(function(response)
{
localStorage.setItem("data", JSON.stringify(response));
}).error(function(error)
{
console.error(error);
});
}
You can return the $http.post, which will return a promise, and then all your code will work in the correct order:
$scope.loginUser = function () {
login($scope.loginInfo).then(function (response) {
localStorage.setItem("token", JSON.stringify(response));
console.log("loginController: name is this " + localStorage.getItem("token"));
fetchDataFunction(data).then(function () {
localStorage.setItem("data", JSON.stringify(response));
console.log(localStorage.getItem("data"));
$state.go("application");
}).catch(function (error) {
console.error(error);
});
}).catch(function (response) {
console.error(error);
});
};
var login = function (user) {
return post("endpoints/login.php", user);
};
var fetchDataFunction = function (data) {
return post("endpoints/fetchData.php", data);
};
var post = function (url, data) {
var deferred = $q.defer;
$http.post(url, data).then(function (response) {
if (response === "ERROR") {
deferred.reject(response);
}
else {
deferred.resolve(response);
}
}).catch(function (error) {
deferred.reject(error);
});
return deferred;
};
Notes:
You will need to make sure you inject $q into your controller along with $http
You should use localStorage.getItem() when recalling information from the global object
You should use then/catch instead of success/error, as these are now depreciated: https://docs.angularjs.org/api/ng/service/$http

waiting for json response in angularjs factory

I am getting closer in my quest for a JSON response. In this example, the events variable gets populated AFTER it's returned, causing a blank output. I need it to wait. I have read that a promise is the way to go... but not sure how that would work... in my console.log you can see the array but Events.all(); returns null.
.factory('Events', function($http) {
var events="";
$http.get('http://appserver.falconinet.com/events.lasso').then(function(resp) {
events = resp.data;
console.log(events);
}, function(err) {
console.error('ERR', err);
// err.status will contain the status code
})
return {
all: function() {
return events;
},
get: function(eventId) {
for (var i = 0; i < events.length; i++) {
if (events[i].id === parseInt(eventId)) {
return events[i];
}
}
return null;
}
}
})
and here is my controller:
// events
.controller('EventsCtrl', function($scope, Events) {
$scope.events = Events.all();
})
.controller('EventDetailCtrl', function($scope, $stateParams, Events) {
$scope.event = Events.get($stateParams.eventId);
})
Following will return the promise created by $http as well as caches the loading of all events.
.factory('Events', function ($http, $q) {
function loadEvents(id) {
var promise = $http.get('http://appserver.falconinet.com/events.lasso', {cache: true});
// return the promise
return promise.then(function (resp) {
var events = resp.data;
if (id) {
// returns item or promise rejection
return getEventById(id, events);
} else {
return events;
}
}).catch (function (err) {
console.log('Events error ', err);
});
}
// helper function , returns event or promise rejection
function getEventById(id, events) {
for (var i = 0; i < events.length; i++) {
if (events[i].id === parseInt(eventId)) {
return events[i];
}
}
return $q.reject('None found');
}
return {
all: function () {
return loadEvents();
},
get: function (eventId) {
return loadEvents(eventId);
}
}
});
Then in controllers you need to resove your data in the promise then callback
.controller('EventsCtrl', function($scope, Events) {
Events.all().then(function(events){
$scope.events = events;
});
})
.controller('EventDetailCtrl', function($scope, $stateParams, Events) {
Events.get($stateParams.eventId).then(function(event){
$scope.event = event;
});
})
As you mentioned, wrapping your actual process in a new promise is the way to go. In order to do so, the usage of this factory needs some tweaks. Lemme try to write a sample from your script, but I don't promise to get it working on the first try :)
.factory('Events', function($http, $q) {
return {
all: function() {
var myPromise = $q.defer();
$http.get('http://appserver.falconinet.com/events.lasso')
.then(function(resp) {
myPromise.resolve(resp.data);
}, function(err) {
myPromise.reject(err);
});
return myPromise.promise;
},
get: function(eventId) {
var myPromise = $q.defer();
$http.get('http://appserver.falconinet.com/events.lasso')
.then(function(resp) {
var events = resp.data;
for (var i = 0; i < events.length; i++) {
if (events[i].id === parseInt(eventId)) {
myPromise.resolve(events[i]);
}
}
}, function(err) {
myPromise.reject(err);
});
return myPromise.promise;
}
}
});
Besides everything, this can be improved as you placer but I found pretty straightforward to do so after knowing how to handle promises.
Using them would be like this:
// Get all
Events.all().then(function(events){
$scope.events = events;
});
// Get one
Events.get(eventId).then(function(event){
$scope.events = event;
});