Promise returns undefined and data after - node.js

For some reason I am getting undefined before the actual data using the following code
async findOne(query: string, parameters: string): Promise<T> {
const stmt: sqlite3.Statement = await this.db.prepare(query)
const info: T = stmt.get(parameters)
this.db.close()
return info
}
const user = await respository.findOne('SELECT * FROM users WHERE id = ?', targetUser.id)
console.log(user)
The console log outputs undefined and a object after that, what is the reason for this?

Probably you will also need await here:
const info: T = await stmt.get(parameters);
From the documentation here it seems that .get is a classic callback function, so you will probably need to wrap it inside a Promise before using it with await.
Probably the same is true about this.db.prepare(query)? Checkout util.promisify from the standard node library if you don't want to do the promise wrapping yourself.
Also, you can't call an async function in open code. Try this:
(async () => {
const user = await respository.findOne('SELECT * FROM users WHERE id = ?', targetUser.id)
})();
Hope this helps!

Related

How to increment a field value in Firestore using Cloud Functions using Javascript?

I have a Cloud function which I am trying to get to increment a field in Firestore:
exports.incrementUpvotes = functions.https.onCall((data, context) => {
async function incrementValue() {
const Id = data.thisId;
const increment = firebase.firestore.FieldValue.increment(1);
const docRef = admin.firestore().collection('posts').doc(Id)
docRef.update({ upvoteCount: increment })
};
return incrementValue()
})
I have tried lots of variations of the above. Each time it fails with this error: Uncaught (in promise) Error: INTERNAL
I'm calling it just using this:
const incrementUpvotes = getFunctions.httpsCallable('incrementUpvotes')
EDIT: getFunctions is an export from my Firebase.js ie. firebase.functions()
and then this in a function:
incrementUpvotes({thisId})
Can anyone see what I'm doing wrong?
You're neither returning anything nor using await in your incrementValue function, which means that it ends up returning undefined.
Since docRef.update is an asynchronous call, you'll want to either await that or return the promise it returns.
So:
function incrementValue() { // 👈 Removed async
const Id = data.thisId;
const increment = admin.firestore.FieldValue.increment(1); // 👈 Use admin
const docRef = admin.firestore().collection('posts').doc(Id)
return docRef.update({ upvoteCount: increment }) // 👈 Added return
};

How to get functions to be sychronous, in nodeJs

I am building a backend with nodeJS.
Since the database call is asynchronous and I want to return its results I have to await the querys result. But then I would have to use await again making the function asynchronous. Is it possible to break this somehow and have synchronous functions?
My goal would be to have something like this.
function persistenceFunction(params){
// Do something to await without this persistenceFunction having to be async
return await pool.query('SELECT stuff FROM table WHERE a=?;',params);
}
function serviceFunction(params){
validate(params);
// do stuff
return persistenceFunction(params);
}
For the database connection I am using the node db module.
Considerations:
The following function will not work because in order for you to be able to use await you have to declare your function as async
function persistenceFunction (params){
// Do something to await without this persistenceFunction having to be async
return await pool.query('SELECT stuff FROM table WHERE a=?;',params);
}
But since you are returning pool.query you don't actually need the await there, so a better alternative would be this.
function persistenceFunction (params){
// Do something to await without this persistenceFunction having to be async
return pool.query('SELECT stuff FROM table WHERE a=?;',params);
}
Just remember that whatever part of your code that is calling serviceFunction will receive a Promise as a result, so it will have to be called in one of the following ways:
function async something () {
const params = {...}
const res = await serviceFunction(params)
// do something with res
}
OR
function something () {
const params = {...}
serviceFunction(params).then((res) => {
// do something with res
})
}

cannot make an async function using sequelize

I'm trying to get information from my model but it always returns me Promise { <pending> } or undefined (on all the ways I had tried)
Heres the code that I'm trying to use to retrieve information from DB
const cnabBody = require('../controller/cnabBody');
let resultado = cnabBody.encontrarUm().then((r) => {
console.log(r);
});
Heres my controller
const CnabBody = require ('../model/cnabBody');
exports.encontrarUm = async () => {
const { nome_campo } = await CnabBody.findOne({where:{nome_campo: "Nome do Campo"}});
return nome_campo;
}
I would need to know more about the object structure that's resolved from the findOne function, but it sounds like the nome_campo object being returned is a Promise object rather than a value. If that's the case then you'd also have to await on the nome_campo (assuming it's not undefined).
If CnabBody.findOne() returns this:
{
nome_campo: somePromise
}
then you should either change findOne to await on that Promise and send back the object it resolves to, or you need to await on it after receiving it in your controller. The latter could be done like this:
const CnabBody = require ('../model/cnabBody');
exports.encontrarUm = async () => {
const { nome_campo } = await CnabBody.findOne({where:{nome_campo: "Nome do Campo"}});
if (nome_campo) return await nome_campo; // <--- add await here if defined
}
However I'd say it's nicer if findOne could be changed (assuming you have access to the code) so that calling await CnabBody.findOne() returned the actual result and not a Promise. Having Promise that resolves another Promise seems redundant, but if you are not the author of findOne then you might not have the option to change its resolved object.
In your controller change const { nome_campo } to const nome_campo. it will work
const CnabBody = require ('../model/cnabBody');
exports.encontrarUm = async () => {
// const { nome_campo } = await CnabBody.findOne({where:{nome_campo: "Nome do Campo"}}); <== problem is here
const nome_campo = await CnabBody.findOne({where:{nome_campo: "Nome do Campo"}});
return nome_campo;
}
I was calling my async functions inside a function that wasnt async soo when i tried any await method it wasnt awaiting or returning a error soo i changed my first line
wb.xlsx.readFile(filePath).then(function(){
to
wb.xlsx.readFile(filePath).then(async function(){
soo my code looks like this now and it is working fine. (:
wb.xlsx.readFile(filePath).then(async function(){
var sh = wb.getWorksheet("Sheet1");
// console.log(sh.getCell("A1").value);
const field = await cnabContent.findOne({where: {nome_campo: "Nome do Campos"}});
console.log(field);
});
Thanks for all that tried to help me, made me do alot of searchs and read about promises, async and await and get this solution.

Proper way using async/await making parallel calls

I am struggling with how to do this properly in nodejs. This tries to do two things in parallel:
downloads a webpage using axios
creates a directory
When those are finished:
save result asynchronously to a file in de created directory
Then waits until done
const uuidv1 = require('uuid/v1')
const fs = require('fs')
const util = require('util')
const axios = require('axios')
const path = require('path')
const mkdir = util.promisify(fs.mkdir)
const writeFile = util.promisify(fs.writeFile)
const downloadPage = async (url='http://nodeprogram.com') => {
console.log('downloading ', url)
const fetchPage = async function() {
const folderName = uuidv1()
return axios
.all([
mkdir(folderName),
axios.get(url)
])
.then(axios.spread(function (f, r) {
writeFile(path.join(__dirname, folderName, 'file.html'), r.data);
}));
}
await fetchPage()
}
downloadPage(process.argv[2])
Your question and sample are looking contradictory. Question says, you need to make use of async and await to make parallel calls, but your sample code shows you need sequential calls instead of parallel.
Best use of Async/Awaits are for making sequential calls.
async function is a kind of shorthand function for 'Promise', were things are done implicitly like returning will be considered as 'resolve'.
await should always be within async function, add await on functions you need to wait for before proceeding further.
Syntax change in await function is, instead of
somePromiseFunctionCall().then( (someVarible) => {...}).catch(e => {})
you need to use
const asyncFunction = async (parameters) => {
try {
// First Function call that returns Promise / async
someVariable = await somePromiseFunctionCall();
// Second (sequential) call that returns Promise / async
someNewVariable = await someotherPromiseFunctionCall();
} catch(e) {
throw new Error(e);
}
}
Now, in your sample, if your requirement is to wait for axios to return and then create folder and then write the result to file, that can be done using async and await.
Change this:
writeFile(path.join(__dirname, folderName, 'file.html'), r.data);
to this:
return writeFile(path.join(__dirname, folderName, 'file.html'), r.data);
You need to return the promise from writeFile so it is added to the chain so that the promise you're returning from fetchPage() is linked to the writeFile() operation. As your code was originally, the writeFile() operation is proceeding on it's own and is not connected at all to the promise you were returning from fetchPage() so when you do:
await fetchPage()
it wasn't awaiting the writeFile() operation.
A cleaned up version could look like this:
const downloadPage = (url='http://nodeprogram.com') => {
console.log('downloading ', url)
// don't really need this separate fetchPage() function
const fetchPage = function() {
const folderName = uuidv1()
return axios
.all([
mkdir(folderName),
axios.get(url)
])
.then(axios.spread(function (f, r) {
return writeFile(path.join(__dirname, folderName, 'file.html'), r.data);
}));
}
return fetchPage()
}
Then, you would use it like this:
downloadPage().then(() => {
// page is downloaded now
});
Or, inside an async function, you could do:
await downloadPage();
// page is downloaded here
Note, that I removed several cases of async and await as they weren't needed. await fetchPage() wasn't doing you any good at the end of downloadPage(). From a timing point of view, that does the exact same thing as return fetchPage() and this way, you're actually resolving with the resolved value of fetchPage() which can be more useful. There did not appear to be any reason to use async or await in downloadPage(). Keep in mind that an async function still returns a promise and the caller of that function still has to use .then() or await on the return value from that function. So, using await inside of downloadPage() doesn't change that for the caller.

How to export async function from a node module

I'm trying to write a node module, to handle my various db calls.
I want to use async/await where ever I can, but I'm having some issues with it.
I've been using promises a bit, and export those functions fine.
Example:
function GetUsernames() {
return new Promise(function (resolve, reject) {
sql.connect(config).then(function () {
new sql.Request()
.query("SELECT [UserName] FROM [Users] ORDER BY [LastLogin] ASC").then(function (recordset) {
resolve(recordset);
}).catch(function (err) {
reject(err);
});
});
});
}
And then I export in the following:
module.exports = {
GetUsernames: GetUsernames,
GetScopes: GetScopes,
UpdateToken: UpdateToken,
SetOwner: SetOwner
};
But, how should I do this, with an async function, to use the async/await that is available in node7?
Do I still just return a promise? I tried doing that, but when I then call it in my code, it doesn't work.
const db = require("dataprovider");
...
var result = await db.GetUsernames();
It gives me:
SyntaxError: Unexpected identifier
on the db name (works fine if I just use the promise functions, with then().)
Maybe my google skills are terrible, but I haven't managed to google anything I could use, on this issue.
How on earth do I make an async function, in my module, that I can await elsewhere?
To turn on the await keyword, you need to have it inside an async function.
const db = require("dataprovider");
...
let result = getUserNames();
async function getUserNames() {
return await db.GetUsernames();
}
See http://javascriptrambling.blogspot.com/2017/04/to-promised-land-with-asyncawait-and.html for more information.
Also, just as an FYI, it a code convention to start function with lowercase, unless you are returning a class from it.
async - await pattern really makes your code easier to read. But node do not allow for global awaits. You can only await an asynchronous flow. What you trying to do is to await outside async flow. This is not permitted. This is kind of anti-pattern for node application. When dealing with promises, what we actually do is generate an asynchronous flow in our program. Our program continue without waiting for promise. So you can export your functions as async but cannot await for them outside async flow. for example.
const db = require('dataprovider');
...
let result = (async () => await db.GetUserNames())();
console.log(result); // outputs: Promise { <pending> }
Thus, async-await pattern works for async flow. Thus use them inside async functions, so that node can execute them asynchronously. Also, you can await for Promises as well. for example.
let fn = async () => await new Promise( (resolve, reject)=>{...} );
fn().then(...);
Here you have created async function 'fn'. This function is thenable. also you can await for 'fn' inside another async function.
let anotherFn = async () => await fn();
anotherFn().then(...);
Here we are waiting for async function inside a async function. Async-Await pattern makes your code readable and concise. This is reflected in large projects.
lets say that you have below function in baseoperation.ts
async function GetAllwithFilter(keyword?: any){
//... async job here
}
then simply you can add below code on the end of baseoperation.ta
module.exports = { GetAllOrAnyName: GetAllwithFilter}
and in the required class you can call it using
const objname = require('./baseoperation');
and to call it in the api using express and router you can use route function with get because it's accept promise call direct
router.route('/').get((req,res) => { objname.GetUsernames().then(then(result => {
res.json(result[0]);
});

Resources