How to await on class constructor in Node js - node.js

I have two classes as below
class AClient
class AClient {
constructor(AHeaderObj) {
logger.info("inside tenant client constructor");
this.tenant_uri = tenantHeaderObj.tenant_uri || config.TENANT_URI;
this.refresh_token = tenantHeaderObj.refresh_token;
this.tenant_header = tenantHeaderObj.tenant_header;
}
Class BClient
class BClient {
constructor(b_client) {
logger.info("Inside mongoClient/constructor ");
this.tenant_client = tenant_client;
}
async find(db_name, collection_name, selectorQuery) {
try {
logger.info("Inside mongoClient find records");
let dbName = await getDB(db_name, this.tenant_client);
let db = await getConnection(dbName, this.tenant_client);
logger.info("selectorQuery"+JSON.stringify(selectorQuery));
let doc = db.collection(collection_name).find(selectorQuery).toArray();
logger.info("****************doc**********"+JSON.stringify(doc));
return await promiseWrapper(null, doc);
} catch (err) {
logger.info("Caught error in mongoClient find records ", err);
return await promiseWrapper(err, null);
}
}
async findSome(db_name, collection_name, query, projection, sort, limit){
logger.info("Inside mongoClient findSome records");
try{
let dbName = await gettDB(db_name, this.tenant_client);
let db = await getConnection(dbName, this.tenant_client);
var selector = [{ $match : query},
{ $project : projection},
{ $sort : sort}];
if(limit > 0){
selector.push({ $limit : limit})
}
let docs = db.collection(collection_name).aggregate(selector).toArray();
return await promiseWrapper(null, docs);
} catch (err) {
logger.info("Caught error in mongoClient findSome records ", err);
return await promiseWrapper(err, null);
}
}
Now I am using it in below 2 ways . One way it works another it is not.
Case1: When it is not working
var searchAll = function (type, text, sortBy, sort, Code, AHeaderObj) {
logger.info("Inside searchAll function.");
var selector = mongoQuery.searchAll(type, text, sortBy, sort, Code);
var AObj = new AClient(AHeaderObj);
logger.info("123");
var mongoObj = new BClient(AObj);
logger.info("1235");
var findSome = callbackify(mongoObj.findSome)
logger.info("12356");
return new Promise((resolve1, reject1) => {
logger.info("123567");
findSome(dBName, collectionName, selector.query, selector.projection, selector.sort, 999999999, function (err1, res1) {
if (err1) {
logger.error("Failed to find");
reject1(err1);
} else {
logger.info("Successfully found");
resolve1(res1)
}
});
})
}
Case2: Where it is working as charm.
var getId = function (id, headerObj, callback) {
logger.info("inside getAccountById() START:");
let selector = mongoQuery.GetAccByIdQueryWithIdModelVersion("Id", id, “version", "v2.1")
let index = 0;
var AObj = new AClient(AHeaderObj);
logger.info("123");
var mongoObj = new BClient(AObj);
logger.info("1235");
mongoObj.find(dBName, collectionName, selector).then((result) => {
logger.info("123568");
if (result && result.length > 0) {
logger.info("a");
logger.info("Found an with id: " + id);
if (result[index].credentials.length > 0) {
logger.info("getById() END:"+JSON.stringify(result));
callback(null, result);
}else {
logger.info("b");
let error = {
"message": "Unable to fetch the with id: " + id
};
logger.warn(error.message);
logger.info("getById() END:");
callback(error, null);
}
}).catch((err) => {
logger.info("c");
logger.info("error" + JSON.stringify(err));
callback(err, null);
});
}
Can someone help what am I doing wrong in Case1 . I observed that ion Case 1 object creation is not awaited and db function is been called where I get below error.
Caught error in mongoClient findSome records TypeError: Cannot read property 'tenant_client' of undefined

Instead of trying to await on class initialization, make the constructor empty and provide and async init method which does the same thing as what the constructor would do.
Make sure that other methods check if the object has been instantiated via the init method and throw an error if not :)

Related

Get and return value outside function - Nodejs

I'm working on some method that have a callback with value, that I need to return and response, but value is null outside callback funciton
How can I solve?
async function createChannel(req) {
let user_id = req.query.user_id;
let chat_name = req.query.chat_name;
var chimesdkmessaging = new AWS.ChimeSDKMessaging({region: region});
var channel = null;
try {
let dateNow = new Date();
const params = {
Name: chat_name,
AppInstanceArn: config.aws_chime_app_istance,
ClientRequestToken: dateNow.getHours().toString() + dateNow.getMinutes().toString(),
ChimeBearer: await AppInstanceUserArn(user_id),
AppInstanceUserArn of the user making the API call.
Mode: 'RESTRICTED',
Privacy: 'PRIVATE'
};
chimesdkmessaging.createChannel(params, function (err, data) {
if (err) {
console.log(err, err.stack);
} // an error occurred
else {
console.log(data); // successful response
console.log('Assegno il canale: ' + data.ChannelArn);
channel = data.ChannelArn; // <----- VALUE I WANT TO RETURN OUTSIDE
}
});
} catch (e) {
return response({error: e}, 500);
}
return response({data: channel},200); // <---- but this channel is null
}
wrap with Promise
let user_id = req.query.user_id;
let chat_name = req.query.chat_name;
var chimesdkmessaging = new AWS.ChimeSDKMessaging({region: region});
let channel = null;
try {
let dateNow = new Date();
const params = {
Name: chat_name,
AppInstanceArn: config.aws_chime_app_istance,
ClientRequestToken: dateNow.getHours().toString() + dateNow.getMinutes().toString(),
ChimeBearer: await AppInstanceUserArn(user_id),
AppInstanceUserArn of the user making the API call.
Mode: 'RESTRICTED',
Privacy: 'PRIVATE'
};
channel = await new Promise((resolve,reject)=>{
chimesdkmessaging.createChannel(params, function (err, data) {
if (err) {
console.log(err, err.stack);
reject(err)
} // an error occurred
else {
console.log(data); // successful response
console.log('Assegno il canale: ' + data.ChannelArn);
resolve(data.ChannelArn)// <----- VALUE I WANT TO RETURN OUTSIDE
}
});
})
} catch (e) {
return response({error: e}, 500);
}
return response({data: channel},200); // <---- but this channel is null
}

get the return value of function calling from an another function node js

I have a function called uploadData in which i am calling getClientId to get the clientid. Inside the getclientId function i can get the return value. But i cant access that return value in the uploadData function. In console i am getting undefined.
uploadData(con, data, callback) {
var total = parseFloat(data.pricelist) + parseFloat(data.print)
var ac = parseFloat(total)*parseFloat(data.quantity)
var sold = parseFloat(data.soldprice)*parseFloat(data.quantity)
var rd = parseFloat(data.sold) - parseFloat(total)
var rt = parseFloat(rd) * parseFloat(data.quantity)
var client =data.client.toLowerCase()
var clientId = this.getClientId(con, data,callback)
console.log(clientId)
}
getClientId(con, data,callback) {
var client =data.client.toLowerCase()
con.query(`SELECT * from client where lower(name) = '${client}'`, function(err, rows) {
if(err) {
return err
}
else{
if(rows.length>0){
return rows[0].id
}
else{
con.query(
`INSERT INTO client SET
name = '${data.client}',
created_by = '${data.user_id}'`,
function(er, row) {
if(er){
return er
}
else{
return row.insertId
}
}
)
}
}
});
}
You can convert your function to Promise and then use async/await it will be much more readable in terms of using async call functions
getClientId(con, data,callback) {
return new Promise((resolve,reject)=>{
var client =data.client.toLowerCase()
con.query(`SELECT * from client where lower(name) = '${client}'`, function(err, rows) {
if(err) {
reject(err)
}
else{
if(rows.length>0){
resolve(rows[0].id)
}
else{
con.query(
`INSERT INTO client SET
name = '${data.client}',
created_by = '${data.user_id}'`,
function(er, row) {
if(er){
reject(er)
}
else{
resolve(row.insertId)
}
}
)
}
}
});
}
)
}
and then consume this function as
const clientId = await this.getClientId(con, data,callback);

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.

pass mysql value from node js to angular

Hi i have this post function to call create function which will insert to database
router.post('/', async (req, res, next) =>
{
const body = req.body;
console.log("tu sam todo_task",req.body);
try
{
const todo_task = await TodoTaskService.create(body);
console.log(todo_task, "function")
// created the todo_task!
return res.status(201).json({ todo_task: todo_task });
}
catch(err)
{
}
});
Then in second snippet i have this create function in service class where i want to return result from mysql query
class TodoTaskService
{
static create(data)
{
console.log("tu sam service todo_task create");
var vres = todoTaskValidator.validate(data, todo_taskVSchema);
/* validation failed */
if(!(vres === true))
{
let errors = {}, item;
for(const index in vres)
{
item = vres[index];
errors[item.field] = item.message;
}
throw {
name: "ValidationError",
message: errors
};
}
console.log("tu sam service todo_task validation passed");
let todo_task = new TodoTaskModel(data.todo_task_name, data.todo_task_complete_f);
let connection = mysql.createConnection(dev);
// insert statment
let sql = `INSERT INTO todo_task (todo_task_name,todo_task_complete_f) VALUES (?);`
let values = [data.todo_task_name, data.todo_task_complete_f];
// execute the insert statment
connection.query(sql, [values], (err, results, fields) => {
if (err) {
global.query = "Database error";
console.log(err.message + "zasto");
return err
}
else{
// get inserted rows
global.query = "OK";
todo_task.todo_task_id = results.insertId
console.log("rows inserted",todo_task);
return todo_task;
}
});
}
}
How can i pass return todo_task from connection.query back to the first post function and send it to angular?
I've found a solution on my own, don't know how if it's the best practice but here is my solution, I'm using callback to pass the value
router.post('/', async (req, res, next) =>
{
const body = req.body;
try
{
return await TodoTaskService.create(body,function (result){
console.log(result, "function result")
todo_task = result;
return res.status(201).json({ todo_task: todo_task });
});
// created the todo_task!
//return res.status(201).json({ todo_task: todo_task });
}
returning callback with result
class TodoTaskService
{
static create(data,callback)
{
var vres = todoTaskValidator.validate(data, todo_taskVSchema);
/* validation failed */
if(!(vres === true))
{
let errors = {}, item;
for(const index in vres)
{
item = vres[index];
errors[item.field] = item.message;
}
throw {
name: "ValidationError",
message: errors
};
}
console.log("tu sam service todo_task validation passed");
let todo_task = new TodoTaskModel(data.todo_task_name, data.todo_task_complete_f);
/* todo_task.uid = 'c' + counter++;
todo_tasks[todo_task.uid] = todo_task; */
let connection = mysql.createConnection(dev);
// insert statment
let sql = `INSERT INTO todo_task (todo_task_name,todo_task_complete_f) VALUES (?);`
let values = [data.todo_task_name, data.todo_task_complete_f];
// execute the insert statment
connection.query(sql, [values], (err, results, fields) => {
if (err) {
global.query = "Database error";
console.log(err.message + "zasto");
return err
}
else{
// get inserted rows
global.query = "OK";
todo_task.todo_task_id = results.insertId
console.log("rows inserted",todo_task);
return callback(todo_task);
}
});
}

exports return null before executing mongodb save when i call it from another controller?

I have to call one controller function from another, but other function is not returning a proper value.
I called a function from one controller in line 'a',line 'b' is another controller.but inside forEach loop when it comes to line 'c', its not executing inside code instead it return null before executing the code from line 'd'.
a. var invoiceItemResp = InvoiceItemController.createInvoiceItems(itemList, doc.id);
b. exports.createInvoiceItems = (itemList, invoiceId) => {
var counter = 0;
var success = false;
itemList.forEach(element => {
var invoiceItem = new InvoiceItem({
_id: new mongoose.Types.ObjectId(),
invoice_id: invoiceId,
item: element.item,
amount: element.amount
});
c. invoiceItem.save((err, doc) => {
d. if(!err){
++counter;
if(counter == itemList.length){
response = {
"message": "success"
}
return response;
}
}else{
response = {
"message": "failed"
}
return response;
}
});
});
}
Your needs the loop to be async and wait for DB to write,
const invoiceItemResp = await InvoiceItemController.createInvoiceItems(itemList, doc.id);
exports.createInvoiceItems = async (itemList, invoiceId) =>
{
var counter = 0;
var success = false;
let resposneArray = [];
let response= {};
try
{
for (const element of itemList)
{
var invoiceItem = new InvoiceItem({
_id: new mongoose.Types.ObjectId(),
invoice_id: invoiceId,
item: element.item,
amount: element.amount
});
const err = await invoiceItem.save();
if (!err)
{
++counter;
if (counter == itemList.length)
{
response = {
"message": "success"
};
resposneArray.push(response);
}
} else
{
response = {
"message": "failed"
};
resposneArray.push(response)
}
});
return resposneArray;
}
catch (e)
{
throw e;
}
};
You should use async await while writing to db.
var invoiceItemResp = await InvoiceItemController.createInvoiceItems(itemList, doc.id);
exports.createInvoiceItems = async (itemList, invoiceId) => {
var counter = 0;
var success = false;
itemList.forEach(element => {
var invoiceItem = new InvoiceItem({
_id: new mongoose.Types.ObjectId(),
invoice_id: invoiceId,
item: element.item,
amount: element.amount
});
invoiceItem.save((err, doc) => {
if(!err){
++counter;
if(counter == itemList.length){
response = {
"message": "success"
}
return response;
}
}else{
response = {
"message": "failed"
}
return response;
}
});
});
}

Resources