Async function in Node.JS calling SQL Server not working properly - node.js

I have a function Im calling to login a user, as follows:
async function loginUser(username, password) {
let msg = {
success: 0,
message: '',
};
sql.connect(process.env.DB_CONNSTRING, function (err) {
if (err) {
res.json(err);
return;
msg.success = '0';
msg.message = 'ERR_04: Could not connect to server.';
return msg;
}
let sqlString = ` SELECT userid
FROM dbo.users
WHERE (email = #username) AND (password = #password)`;
request = new sql.Request();
request.input('username', sql.NVarChar, username);
request.input('password', sql.NVarChar, password);
request.query(sqlString, function (err, results) {
if (err) {
msg.success = '0';
msg.message = 'ERR_011: Could not connect to server.';
return msg;
}
if (results.rowsAffected[0] != 0) {
console.log(results.recordset[0]);
return results.recordset[0];
} else {
msg.success = '0';
msg.message = 'Invalid username and password combination.';
return msg;
}
});
});
}
Please notice a console.log if the query brings back results.
Im calling that function as follows:
await loginUser(username, encryptedPassword)
.then((result) => {
console.log(result);
})
.catch((err) => {
msg.message = 'API Error.';
res.json(msg);
});
Where I also have a console.log()
The problem is that the console.log for the call is coming as undefined, but the one inside the function is throwing the data.
I do not know what I'm missing here, so any help will be appreciated.
Thanks.

If you don't need to call a function, you can try this out.
let sqlString = ` SELECT userid FROM dbo.users WHERE (email ='${username}') AND (password = '${password}')`;
let conn = await sql.connect(process.env.DB_CONNSTRING)
let recordset = await conn.query(sqlString)
res.json(recordset)

In JS if function doesn't have explicit return, it returns undefined.
So, you have a function async function loginUser: async here indicates your function might be ran asynchronous(as promise), but it doesn't return any values;
So, instead of marking you function as async, you need promisify your callbacks and return promise;
It might be something like:
const { promisify } = require('util');
async function loginUser(username, password) {
let msg = {
success: 0,
message: '',
};
await promisify(sql.connect(process.env.DB_CONNSTRING));
let sqlString = `SELECT userid
FROM dbo.users
WHERE (email = #username) AND (password = #password)`;
request = new sql.Request();
request.input('username', sql.NVarChar, username);
request.input('password', sql.NVarChar, password);
return await promisify(request.query(sqlString));
}
Pay special attention on error handling, and where you want(need) call await, and where you don't;

Related

How can I get the error from a callback function? (Node.js)

I want to catch the error from "revokeToken" function and return it as json response in the api.post . But I'm not getting how this to be done. Can anyone help me out with this? Is there any better way of wring it?
app.post('/api/logout', (req, res)=>{
var request = new Request(req);
var response = new Response(res);
var tokenArray = request.headers.authorization.split(" ");
var token = tokenArray[1];
var tokenObj = {
accessToken : token
}
let errmsg = '';
revokeToken(tokenObj, (obj)=>{
errmsg = obj;
});
res.json({
data: null,
result:{
isError: false,
status: 200,
errorMsg: errmsg
}
});
});
var revokeToken = function(token, callback) {
tokenModel.deleteOne({
accessToken: token.accessToken
}).exec((function(callback, err, results) {
var deleteSuccess = results && results.deletedCount === 1;
let result = '';
if (!deleteSuccess) {
return err;
}
else{
return err;
}
}).bind(null, callback));
callback("Token Deleted!")
};
You should be able to retrieve the error object by passing the msg property as parameter to the callback function.
Also, rename the exec function callback to something other than callback:
var revokeToken = function (token, callback) {
tokenModel
.deleteOne({
accessToken: token.accessToken,
})
.exec(
function (done, err, results) {
var deleteSuccess = results && results.deletedCount === 1;
let result = '';
if (!deleteSuccess) {
callback(err.msg);
return;
}
callback('Token Deleted!');
}.bind(null, callback)
);
};

Return items from text file as list in nodeJS

Can someone tell me how to return items in a text file as a list. I'm writing code for basic authentication. It registers users then stores their information(first name, last name, gender, password) in a .txt file. I want to be able to confirm a user's password from their file in order to log them in. I'm using the str.split method but it just returns 'undefined'. The 'username' argument in the code below indicates the file name without .txt added to it
const read = (username) => {
fs.readFile(`${dirPath}/${username}.txt`, 'utf8', (err, item) => {
console.log(item);
})
};
const authenticatedUser = (username) => {
var validUser = doesUserExist("./Database", username);
if (validUser = true) {
var user = read(username);
var userArray = String(user).split(",");
console.log(userArray);
}
};
function doesUserExist (userPath, username) {
fs.readdir(userPath, (err, files) => {
if (err) {
console.log("error");
} else {
files.forEach(file => {
if (file == `${username}.txt`) {
return true;
} else if (file !== `${username}.txt`) {
return false;
}
});
}
});
};
You are calling read() as a function that returns a string when it in fact just executes a fs.readFile() and then returns nothing.
The quickest way to fix this would be to use fs.readFileSync() and make sure to return that value from read().
const read = (username) => {
return fs.readFileSync(`${dirPath}/${username}.txt`, {encoding:'utf8'});
};
A function that does not return a value intrinsically returns undefined.
A more idiomatically correct solution might involve switching to async code:
const read = async (username) => {
return await fs.promises.readFile(`${dirPath}/${username}.txt`, {encoding:'utf8'});
};
const authenticatedUser = async (username) => {
var validUser = await doesUserExist("./Database", username);
if (validUser = true) {
var user = await read(username);
var userArray = String(user).split(",");
console.log(userArray);
}
};
const doesUserExist = async (userPath, username) {
let returnVal = false;
const files = await fs.promises.readdir(userPath);
files.forEach(file => {
if (file == `${username}.txt`) {
returnVal = true;
});
return returnVal;
};
Using async and await, you can read your code as if it was synchronous.

Why is my return variable value not being recognised in node module

I have got a node file requesting a return variable from another module page. All the data functions "work" but the "return query" is not sending the query value back to my initial request and my existingUser variable is undefined. In the console logs checks I put in the existingUser ones displays before the query one. It is like the await request is being ignored.
Any help appreciated...and I'm a newbie to all this!
Request page -
const sqlRequests1 = require('./sqlAdmin/sqlRequests1');
.
.
.
app.post('/', async (req, res) => {
const { club, first_name, last_name, email, tel, address, post_code, password, passwordConfirmation} = req.body;
let existingUser = await new sqlRequests1.Queries('contact',email).getAll();
console.log(`existingUser is ${existingUser}`); //THIS CONSOLE LOG RETURNS "undefined"
if (existingUser) {
return res.send('Email in use');
}
if (password !== passwordConfirmation) {
return res.send('Passwords must match');
}
res.send('Account created!!!');
});
Module page - sqlRequests1
class Queries {
constructor(table, selection) {
this.table = table;
this.selection = selection;
console.log(selection); //THIS DATA CHECK WORKS
if(!table) {
throw new Error('Need a table to connect to');
};
};
getAll() {
//Confirm if the emasil exists - if it does then give error message
let q = 'SELECT * FROM ?? ';
connection.query(q, this.table, function (error, results,fields) {
if (error) throw error;
const query = (results[0].email);
console.log(`query is ${query}`); //THIS PROVIDES THE CORRECT DATA
return query; //THIS RETURN IS NOT GETTING BACK TO existingUser variable?
});
};
};
module.exports.Queries = Queries;
If you want to use await and block the code from moving further, you have to convert your get all function to return a promise....
getAll() {
new Promise((resolve,reject) => {
//Confirm if the emasil exists - if it does then give error message
let q = 'SELECT * FROM ?? ';
connection.query(q, this.table, function (error, results,fields) {
if (error) reject(error);
const query = (results[0].email);
console.log(`query is ${query}`); //THIS PROVIDES THE CORRECT DATA
resolve(query) //THIS RETURN IS NOT GETTING BACK TO existingUser variable?
});
})
}
Promise was the way to go but it just missed the return
getAll() {
return new Promise((resolve,reject) => { //ADDING return here fixed it
//Confirm if the emasil exists - if it does then give error message
let q = 'SELECT * FROM ?? ';
connection.query(q, this.table, function (error, results,fields) {
if (error) reject(error);
const query = (results[0].email);
console.log(`query is ${query}`); //THIS PROVIDES THE CORRECT DATA
resolve(query) //THIS RETURN IS NOT GETTING BACK TO existingUser variable?
});
})
}

use async - await with socket.io nodejs

I'm developing a web application using nodejs socket.io and angular 9. In my backend code I have written sockets in socket.connect.service.
Follows is a socket I'm using
socket.on('request-to-sit-on-the-table', async function (data, callback) { //Previously Register
let table = persistence.getTable(tableToken);
if (typeof table === 'undefined') {
let errMsg = 'This table does not exists or already closed.'
callback(prepareResponse({}, errMsg, new Error(errMsg)));
return;
}
//TODO: Get the displayName from the token.
let guest = await guestUserService.getGuestUserByPlayerToken(JSON.parse(data.userToken));***//Here is the issue***
// let displayName = 'DisplayName-' + guest;
let displayName = 'DisplayName-' + Math.random();
//TODO: Check whether the seat is available
// If the new screen name is not an empty string
let isPlayerInCurrentTable = persistence.isPlayerInCurrentTable(tableToken, userToken);
if (displayName && !isPlayerInCurrentTable) {
var nameExists = false;
let currentPlayersTokenArr = persistence.getTableObjectPlayersToken(table)
for (var token in currentPlayersTokenArr) {
let gamePlayer = persistence.getPlayerPlayer(currentPlayersTokenArr[token])
if (typeof gamePlayer !== "undefined" && gamePlayer.public.name === displayName) {
nameExists = true;
break;
}
}
if (!nameExists) {
//Emit event to inform the admin for requesting to sit on the table.
let ownerToken = persistence.getTableObjectOwnerToken(table);
let ownerSocket = persistence.getPlayerSocket(ownerToken);
ownerSocket.emit('requested-to-sit', {
seat: data.seat,
secondaryUserToken: userToken,
displayName,
numberOfChips: envConfig.defaultNumberOfChips
});
callback(prepareResponse({userToken}, 'Player connected successfully.'));
} else {
callback(prepareResponse({}, 'This name is already taken'));
}
} else {
callback(prepareResponse({}, 'This user has already joined to a game. Try clear caching'));
}
});
In my code I'm getting data from another code in guest.user.service. But I get undefined to the value of "guest"
Follows are the methods I have used in guest.user.service
exports.findById = (id) => {
return new Promise(function(resolve, reject) {
guestUserModel.findById(id, (err, data) =>{
if(err){
reject(err);
} else {
resolve(data);
}
});
});
};
exports.getGuestUserByPlayerToken = (playerToken) => {
var player = playerService.findOne({ token: playerToken })
.then(function (data) {
return self.findById(data.guestUser._id.toString());
})
.then(function (guestUser) {
return guestUser.displayName;
})
.catch(function (err) {
throw new Error(err);
})
};
Although I get my displayName for the return value It is not passed to the "guest" in my socket.Is there any syntax issue to get data as I'm using promises.please help
exports.getGuestUserByPlayerToken = async playerToken => {
try {
let player = await playerService.findOne({token:playerToken});
return playerService.findById(player.guestUser._id)
} catch(error) {
console.log(error);
return null;
}
};
This is just handle error on awaited promise not returned one. You need to handle that in caller side.

why mongoose queries dos not work when put inside promise function

My code is as shown below:
checkAndCreateUser(customer_id, email_id).then(result => {
console.log("result is " + result);
});
var checkAndCreateUser = function (custom_id, email) {
return new Promise(function (resolve, reject) {
if ((!custom_id) && (custom_id.trim() == '')) {
var creatUser = new user();
// creatUser._id = user_id;
creatUser.ph_no = ph_no;
creatUser.email_id = email;
console.log("fn works");
user.findOne({
'email_id': email
}, function (err, user) {
console.log("db test");
if (!user) {
creatUser.save(function (err, userInfo) {
if (err) {
reject("no id found");
} else {
customer_id = userInfo._id;
resolve(customer_id);
}
});
} else {
customer_id = user._id;
resolve(customer_id);
}
});
}
});
}
Now what happens here is I am not able to successfully run db query. I am able to get console.log("fn works") printed , but it does not print console.log("db test"). So what exactly is going wrong?
You forgot save your user, besides Mongoose already returned promise, you don't need use callbacks:
var checkAndCreateUser = function (custom_id, email) {
return User.create({ ph_no :ph_no,
email_id :email})
.then(result=>{
return User.findOne({'email_id': email})
})
.then(user=>{
return user._id;
})
};
As for mistake in your function:
...
let user = new User({email_id: email, ph_no: phone});
user.save();//you forgot about this
...
You can use save() with callback:
user.save((err, result)=>{...});
Or with promise:
user.save().then(result=>{...}).catch(err=>{...});

Resources