NodeJs: Await inside mssql 'done' emitter - javascript

I am using the 'mssql' package to process a sql query, calling an async function when the 'row' emitter fires.
When the 'done' emitter fires, I want to wait for all tasks to complete... this is where i am having a problem.
EXAMPLE:
const sql = require('mssql')
let tasks = [];
sql.connect(config, err => {
const request = new sql.Request()
request.stream = true;
request.query('select * from theTable')
request.on('row', row => {
task.push( callAsyncFunction(row) );
})
request.on('error', err => {
// Do something
})
request.on('done', result => {
await Promise.all(tasks);
//THIS IS WHERE THE PROBLEM IS:
//SyntaxError: await is only valid in
// async function
})
})
sql.on('error', err => {
// handle error
})
Can anyone help with my syntax here?
Thank you!

try making anonymous function async
you can make anonymous functions async too
request.on('done', async(result) => {
await Promise.all(tasks);
})

You need to annotate the anonymous function with async:
const sql = require('mssql')
let tasks = [];
sql.connect(config, err => {
const request = new sql.Request()
request.stream = true;
request.query('select * from theTable')
request.on('row', row => {
task.push( callAsyncFunction(row) );
})
request.on('error', err => {
// Do something
})
request.on('done', async (result) => {
await Promise.all(tasks);
//THIS IS WHERE THE PROBLEM IS:
//SyntaxError: await is only valid in
// async function
})
})
sql.on('error', err => {
// handle error
})

Related

Promisify a curried (higher order function) callback

I am trying to promisify (or leverage async await feature) the callback in the function getId, using new Promise(resolve => ..., but because of the usage of the higher order function getAddresses, I am a bit stumped. I am not great at functional programming. Any suggestions on how do I promisify this one?
const {queryRecord, getData} = require(“#xyzLib”);
const getId = (callback) => {
getData(“attr1”,”attr2”,getAddresses(callback));
}
const getAddresses = (callback) => (result) => {
if (!result.success) {
callback(new Error(‘Exception details’))
} else {
queryRecord(objectName, (result) => {
callback(null, result.name);
});
}
}
// invoking call
getId(async (error, zip, state) => {
if (error) {
console.log(error.message)
} else {
await fetch(encodeURI(settingsUrl), {
method: 'GET',
});
....
Since getId() accepts a callback as the last argument and that callback uses the nodejs calling convention, you can just directly use util.promisify() on getId like this:
const { promisify } = require('util');
const getIdPromise = promisify(getId);
getIdPromise().then(result => {
console.log(result);
let fetchResult = await fetch(...);
...
}).catch(err => {
console.log(err);
});
Or, if you're already inside an async function body:
try {
const result = await getIdPromise();
console.log(result);
const fetchResult = await fetch(...);
...
} catch (err) {
console.log(err);
}
You should promisify on the lowest level available, i.e. the imported functions from the library. Then you don't even need that currying. With
const { promisify } = require('util');
const xyz = require(“#xyzLib”);
const queryRecord = promisify(xyz.queryRecord);
const getData = promisify(xyz.getData);
you can write simply
async function getId() {
return getAddresses(await getData("attr1", "attr2"));
}
async function getAddresses(data) {
if (!data.success) throw new Error("Exception details");
const result = await queryRecord(objectName);
return result.name;
}
// invoking call
try {
const zip = getId();
await fetch(encodeURI(settingsUrl), {
method: 'GET',
});
} catch(error) {
console.log(error.message);
}

How to return promise in case of multiple transactions?

I am trying to learn to work with firestore transactions.
Here is my code:
const handleSubmit = (e) => {
e.preventDefault();
console.log(message);
let mergedId = loggedUserId + toBeContactedUserId;
let loggedUserRef = db.collection('users').doc(loggedUserId);
let toBeContactedUserRef = db.collection('users').doc(toBeContactedUserId);
let messageDbRef = db.collection('messages').doc();
db.runTransaction((transaction) => {
transaction.get(loggedUserRef) //First transaction
.then(userDoc => {
let userData = {
...userDoc.data(),
contacts: {
...userDoc.data().contacts,
[toBeContactedUserId]: {
...userDoc.data().contacts[toBeContactedUserId],
lastMsg: message,
unreadMsg: 0
}
}
}
loggedUserRef.set(userData);
})
transaction.get(toBeContactedUserRef) //Second transaction
.then(userDoc => {
let unreadMsgInc = userDoc.data().contacts[loggedUserId].unreadMsg + 1;
let userData = {
...userDoc.data(),
contacts: {
...userDoc.data().contacts,
[loggedUserId]: {
...userDoc.data().contacts[loggedUserId],
lastMsg: message,
unreadMsg: unreadMsgInc
}
}
}
toBeContactedUserRef.set(userData);
})
transaction.get(messageDbRef) ////Third transaction
.then(msgDoc => {
messageDbRef.set({
from: loggedUserId,
to: toBeContactedUserId,
content: message,
reaction: false,
seen: false,
searchId: mergedId,
time: firebase.firestore.FieldValue.serverTimestamp()
})
}
)
})
.then(res=>{
console.log(res);
})
.catch(err=>{
console.log(err);
})
}
handleSubmit() is the function which is invoked upon clicking a button.
In the first transaction.get() I am doing a write operation. In the second transaction.get() I am doing a read and a write operation and in the third, I am doing a write operation.
When I am running the code I get error as: Error: Transaction callback must return a Promise
I am not clear if I am using transactions the right way. Is there a way I can write all this logic in a single transaction.get()
Please guide me on how to resolve this error.
You can use Promise.all to wrap all three promises:
db.runTransaction((transaction) => {
const p1 = transaction.get(loggedUserRef)
.then(userDoc => {
...
})
const p2 = transaction.get(toBeContactedUserRef)
.then(userDoc => {
...
})
const p3 = transaction.get(messageDbRef)
.then(msgDoc => {
...
})
return Promise.all([p1, p2, p3]); // 👈
})
.then(res=>{
console.log(res);
})
.catch(err=>{
console.log(err);
})
Alternatively, you can use async / await to have the compiler generate that for you and get rid of some of the nesting:
db.runTransaction((transaction) => async { // 👈
let userDoc = await transaction.get(loggedUserRef);
...
userDoc = await transaction.get(toBeContactedUserRef);
...
const msgDoc = await transaction.get(messageDbRef)
...
})
.then(res=>{
console.log(res);
})
.catch(err=>{
console.log(err);
})

(JavaScript) How to return result from another function?

imagem printscreen ---------
Platform: NodeJS
I have two roles in the nodejs project
I'm having trouble inserting the result of the second function into the first function.
How to insert the result of the RUN function within the first function
start (client)?
function start (client)
...
.sendText (message.from, 'Example' + result.rows + 'Text text')
...
function run ()
...
Console.log (result.rows);
...
Full code
'use strict';
const venom = require('venom-bot');
const oracledb = require('oracledb');
const dbConfig = require('./dbconfig.js');
venom
.create()
.then((client) => start(client))
.catch((erro) => { console.log(erro); });
function start(client)
{
client.onMessage((message) =>
{
if (message.body === 'Vendas' && message.isGroupMsg === false)
{ client
.sendText(message.from, 'Example text' + result.rows + 'Etc etc')
.then((result) => {console.log('Result: ', result); })
.catch((erro) => { console.error('Error when sending: ', erro); });
}});
}
//----------------------------------------------------------------
async function run() {
let connection;
try {
connection = await oracledb.getConnection(dbConfig);
const sql =`SELECT 'Testeee' FROM dual`;
let result;
result = await connection.execute(sql);
Console.log(result.rows);
} catch (err) {
console.error(err);
} finally {
if (connection) {
try {
await connection.close();
} catch (err) {
console.error(err);
}
}
}
}
Try making start() async either and apply wait.
async function start(client){
const result = await run();
// the rest of your code
}
In run() you let the method return the value.
async function run() {
let connection;
try {
connection = await oracledb.getConnection(dbConfig);
const sql =`SELECT 'Testeee' FROM dual`;
return await connection.execute(sql);
} // rest of your code

Capturing errors with Async/Await

I have a part of my code that makes several API calls to different endpoints and I want to know if any of those calls fail so I can display an appropriate error message. Right now, if an error happens in one() it will stop all other calls from happening, but that's not what I want; If an error occurs, I want it to populate the errors object and have the program continue on.
async function gatherData() {
let errors = { one: null, two: null, three: null };
const responseOne = await one(errors);
const responseTwo = await two(errors);
const responseThree = await three(errors);
if (!_.isNil(errors.one) || !_.isNil(errors.two) || !_.isNil(errors.three)) {
// an error exists, do something with it
} else {
// data is good, do things with responses
}
}
gatherData();
async function one(errors) {
await axios
.get("https://jsonplaceholder.typicode.com/comment")
.then(res => {
return res;
})
.catch(err => {
errors.one = err;
return err;
});
}
async function two(errors) {
await axios
.get("https://jsonplaceholder.typicode.com/comments")
.then(res => {
return res;
})
.catch(err => {
errors.two = err;
return err;
});
}
async function three(errors) {
await axios
.get("https://jsonplaceholder.typicode.com/comments")
.then(res => {
return res;
})
.catch(err => {
errors.three = err;
return err;
});
}
If you pass the errors to the async functions, so pass the errors object as parameter
const responseOne = await one(errors);
const responseTwo = await two(errors);
const responseThree = await three(errors);

Function not returning pg-pool results

I'm trying to use pg-pool to query a Postgresql database. And then export this data to a Node.js express rest API.
Here's my exports function.
exports.getDashboard = function(req, response, next) {
let returnData = fetchData();
return response.status(200).json(returnData);
};
Which calls fetchData();
fetchData = async function() {
let returnData = [];
returnData.languages = await getLatestLanguages();
return returnData;
};
Which calls getLatestLanguages()
getLatestLanguages = function() {
pgPool.pool.query(
'SELECT * FROM "WordLanguage" ORDER BY id DESC LIMIT 30 ;',
(error, results) => {
if (error) {
throw error;
}
return results.rows;
}
);
}
If i place a console.log(results.rows) before getLatestLanguages() returns results.rows, then I get the data logged to the console.
However the object isn't being returned to fetchData. I tested this by logging the returnData to console before it is returned to exports.getDashboard();
I believe my problem is something to do with the async nature of pg-pool so I tried making my function async with an await but that didn't help.
What am I doing wrong?
you need getLatestLanguages to return a Promise, so you can await it from the caller
getLatestLanguages = function() {
return new Promise((resolve, reject) => {
pgPool.pool.query(
'SELECT * FROM "WordLanguage" ORDER BY id DESC LIMIT 30 ;',
(error, results) => {
if (error) {
reject(error);
}
resolve(results.rows);
}
);
})
}
you also need to await fetchData(), therefore getDashboard should be async
exports.getDashboard = async function(req, response, next) {
let returnData = await fetchData();
return response.status(200).json(returnData);
};
getLatestLanguages() should return a promise. For example
getLatestLanguages = function() {
return new Promise((resolve, reject) => {
pgPool.pool.query(
'SELECT * FROM "WordLanguage" ORDER BY id DESC LIMIT 30 ;',
(error, results) => {
if (error) {
reject(error);
}
resolve(results.rows);
}
);
});
};
fetchData() is async and therefore should be awaited
exports.getDashboard = async function(req, response, next) {
let returnData = await fetchData();
return response.status(200).json({ languages: returnData.languages });
};
Also make sure that you return returnData.languages in the correct format as above instead of ...json(returnData);

Categories

Resources