Calling two Promises within each other in Node - javascript

So I have a MySQL query that I need to call within another MySQL query in the following format:
var sql = "some sql code";
const queryResult = await new Promise((resolve) => {
connection.query(sql, (err, rows, fields) => {
// do some stuff here
var secondSql = "Another sql command";
const queryTwo = await new Promise((resolve) => {
connection.query(secondSql, (err, rows, fields) => {
// do some more stuff
resolve(something);
)});
resovle(something);
}
)});
But, when I try to run this, I keep getting the error:
"errorMessage": "await is only valid in async function",
"errorType": "SyntaxError",
I know this has something to do with the "await new Promise((resolve) => {" not being async, but how do I fix this to actually run? I previously would just insert an async function outside of this code and call it where I have the second SQL query, but that does not work in AWS Lambdas for some reason.
Could someone please show me another way of doing this?

In order for await to work, it has to be called from inside an async function. Try this:
var sql = "some sql code";
const queryResult = await new Promise((resolve) => {
connection.query(sql, async (err, rows, fields) => {
// do some stuff here
var secondSql = "Another sql command";
const queryTwo = await new Promise((resolve) => {
connection.query(secondSql, (err, rows, fields) => {
// do some more stuff
resolve(something);
)});
resolve(something);
}
)});

You could try the approach:
const sql1 = 'some sql code';
const sql2 = 'Another sql command';
const query1 = () => {
return new Promise((resolve) => {
connection.query(sql1, (err, rows, fields) => {
resolve('something')
});
})
};
const query2 = () => {
return new Promise((resolve) => {
connection.query(sql2, (err, rows, fields) => {
resolve('something')
});
})
};
[query1, query2].forEach(async request => {
await request();
});

Related

Passing multiple query objects with res.render

I want to pass multiple query objects with res.render() inside my route.js. I have a select.js which contains the SQL statements and delivers the objects to my route.js. This works fine until I want to pass multiple query objects with res.render().
Any ideas on how I can pass multiple objects at once?
snippet route.js (I need to pass get_PriceData here as well)
I already query get_KategorieData but I have no clue how to handle multiple queries in one route.
router.get('/edit', (req, res, next) => {
var speisenEintragenData = {};
db.get_KategorieData()
.then(({ data: kategorie_data }) => {
res.render('speiseEintragen', { kategorie_data }); //maybe putting res.render() after the db.get?
})
.catch((error) => {
console.log(error);
});
});
select.js
const db = require('./config');
//KATEGORIEN LADEN
const get_KategorieData=()=>{
var sql = 'SELECT * FROM Kategorie';
return new Promise((resolve,reject) => {
db.query(sql, function (err, data, fields) {
if (err) reject(err);
resolve({data});
});
})
}
//PREISE LADEN
const get_PriceData=()=>{
var sql = 'SELECT * FROM preise';
return new Promise((resolve,reject) => {
db.query(sql, function (err, data, fields) {
if (err) reject(err);
resolve({data});
});
})
}
module.exports={
get_KategorieData,
get_PriceData
}
There are two ways to go about this. One is to stick with promises and other is to use async/await.
Using promise
Create a new function to query database. This is if the module you are using does not support async/await and requires a callback.
const query = ( sql ) => {
return new Promise(( resolve, reject) => {
db.query(sql, function (err, data, fields) {
if (err) reject(err);
resolve(data);
});
})
}
// and then you can write an async/await function to call n queries like
const get_data = async () => {
const sql1 = '...';
const a = await query( sql1 );
const sql2 = '...';
const b = await query( sql2 );
....
....
....
const sqln = '...';
const n = await query( sqln );
return { a ,b,... ,n};
}
Or with async/await you can directly call db.query and use the response
const get_data = async () => {
const sql1 = '...';
const res_1 = await db.query(sql1);
const sql2 = '...';
const res_2 = await db.query(sql2);
return { a: res_1 ,b: res_2 };
}
router.js can rewritten as
router.get('/edit', async (req, res, next) => {
const {a:rename_a,b:rename_b and so on}=await db.get_data();
res.render('view', { rename_a,rename_b and so on })
});

How to write functions sequentially in JavaScript/typescript?

I have problems in the following funcitons' orders, sometimes fun2() perform before fun1().
What I would like is writing the functions in order.
This my code:
const fun1 = () => new Promise(resolve => {
db.run(
'INSERT INTO header (name,email) VALUES ("' +
name +
'","' +
email +
'")',
function(err, row) {
if (err) {
return console.error(err);
}
console.log('Entry Added');
resolve('Inserted into header');
}
);
});
const fun2 = () => new Promise(resolve => {
let sql = `SELECT id FROM header ORDER BY id DESC LIMIT 1;`;
db.all(
`SELECT id FROM header ORDER BY id DESC LIMIT 1;`,
[],
(err, rows) => {
if (err) {
return console.error(err);
}
rows.forEach(row => {
resolve(row['id']);
});
}
);
});
fun1().then(fun2).then(messages => console.log(messages));
It showing me this error filename.tsx:389 Uncaught (in promise) TypeError: fun1.then is not a function
fun1 and fun2 should be functions that return Promises. That way, the Promises are instantiated when calling the corresponding function
fun1 and fun2 aren't functions, they're promises, and they both kick off the moment you say new Promise(...).
If you want to run them in sequence, make them functions:
// functions that return promises
const fun1 = () => new Promise( ... )
const fun2 = () => new Promise( ... )
fun1().then(fun2).then(messages => console.log(messages));
I would suggest to use promisify. It will do a lot of heavy lifting for you. As it turns out, it is actually tricky to turn callback functions into proper promises.
const util = require('util');
const db = require('some/sql/package');
const query = util.promisify(db.all)
// then either
query('some sql expression')
.then((data1) => {
console.log(data1)
return query('other statement')
})
.then((data2) => console.log(data2))
.catch(console.warn);
// or
(async () => {
data1 = await query('some sql expression')
data2 = await query('other statement')
})().catch(console.warn)
note that you MUST have a semicolon on the line before when using the iife like that.

Javascript get returned value of inside functions

I have the following function that gets a username and by making a query to mssql checks if already exists in databse. I want the checkForUsername() to return true if recordSet.recordset.length >= 1. How can I do that? I am a bit confused about async/await. Thanks.
function checkForUsername(UserIn) {
var dbConn = new sql.ConnectionPool(config);
dbConn.connect().then(function () {
var request = new sql.Request(dbConn);
request.query("SELECT * from Admins WHERE username='"+UserIn+"';").then(function (recordSet) {
console.log(recordSet.recordset.length);
if(recordSet.recordset.length >= 1)
//checkForUsername return true
dbConn.close();
}).catch(function (err) {
dbConn.close();
});
}).catch(function (err) {
console.log(err);
});
}
Of course I can't check if the following code works, but you can try rewriting your code for something like this:
const checkForUsername = async user => {
try {
const
dbConn = new sql.ConnectionPool(config),
sqlObj = await dbConn.connect(),
query = `SELECT * FROM Admins WHERE username='${user}';`, // Note that creating a query explicitly is not recommended as it is vulnerable to SQL injection attack!
recordSet = await new sqlObj.Request(dbConn)query(query),
hasRecords = !!recordSet.recordset.length;
return hasRecords;
} catch (error) {
console.log(error);
} finally {
dbConn.close();
}
}
// Call it
(async () => {
console.log(await checkForUsername('Jhon due');
})();
const checkForUsername = async UserIn => {
try {
var dbConn = new sql.ConnectionPool(config);
const sqlObj = await dbConn.connect();
const recordSet = await new sql.Request(dbConn).query(`SELECT * FROM Admins WHERE username='${UserIn}';`);
const hasRecords = !!recordSet.recordset.length;
return hasRecords;
}catch (error) {
console.log(error);
}finally{
dbConn.close();
}
}
// Call it
(async () => {
console.log(await checkForUsername('John'));
})();

Doing Aysnc tasks in AWS Lambda inside map loop

I need to fetch user details from the database, where the user list is provided in an Array.
await userList.map(async (usr, index) => {
let sql = "SELECT `id`,`email`, `firstname`, `lastname` FROM `users` WHERE `id` = '"+usr.user_id+"'";
let user_info = await getData(sql,0);
userData.push(userObj);
});
Get Data function :-
let getData = async (sql, params) => {
return new Promise((resolve, reject) => {
pool.getConnection((err, connection) => {
if (err){
reject(err);
}
connection.query(sql, params, (err, results) => {
if (err){
reject(err);
}
connection.release();
resolve(results);
});
});
});
};
Now the problem is function is getting exited before the results are pulled from the database.
If I remove the loop & pull a single record everything is working fine.
But, i need to get data for all users.
Try this and let me know if it helps:
await Promise.all(userList.map(async (usr, index) => {
let sql = "SELECT `id`,`email`, `firstname`, `lastname` FROM `users` WHERE `id` = '"+usr.user_id+"'";
let user_info = await getData(sql,0);
userData.push(user_info);
}));
In this case you can avoid map and rather use a for loop to achieve the result.
You can try the below SO snippet, to see if this is the desired outcome you needed.
getData = (userId) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve("user"+ userId);
}, 500)
})
}
ids = [1,2,3];
//Final results
results = [];
async function getAllDataAsync(){
for(let i = 0; i < ids.length; i++ ){
let user_info = await getData(ids[i]);
results.push(user_info);
}
return Promise.resolve(results);
}
async function start(){
const res = await getAllDataAsync();
console.log(res);
console.log("Got the results. Put rest of the logic here");
}
start();
console.log("Function will exit first");

Is this a good way to run multiple mysql queries with Promise.all

So I am running a few insert queries using the mysql npm package and I'm doing so with Promise.all to try and run them at the same time. I have a function that creates a new connection for each query and returns a promise. I am also wrapping the mysql queries with promises. Here is the code that builds the queries and calls them with Promise.all
const Database = require('./database');
const queryBuilder = record =>
new Promise((resolve, reject) => {
try {
const filename = record.s3.object.key.split('/').pop();
const filesize = record.s3.object.size;
const s3path = `${record.s3.bucket.name}/${record.s3.object.key}`;
const createdAt = record.eventTime.split('T').shift();
const sql = 'INSERT INTO raw_files (filename, filesize, s3path, created_at, client_subdomain) ' +
`VALUES ('${filename}', ${filesize}, '${s3path}', '${createdAt}', '${record.s3.bucket.name}')`;
resolve(sql);
} catch (err) {
reject(err);
}
});
const connectionWrapper = (params, record) =>
new Promise((resolve, reject) => {
const db = new Database(params);
db.connect()
.then(res => queryBuilder(record))
.then(sql => db.query(sql))
.then((res) => {
db.close();
resolve(res);
})
.catch((err) => {
db.close();
reject(err);
});
});
exports.handler = (event, context, callback) => {
const connectionParams = {
host: '127.0.0.1',
port: 3306,
user: 'root',
password: 'some_password',
database: 'space_util',
};
Promise.all(event.Records.map(record => connectionWrapper(connectionParams, record)))
.then(res => callback(null, res))
.catch(err => callback(err));
};
And then here is the wrapper module
const mysql = require('mysql');
// Promise-ify the mysql connection
const Database = function Database(connectionParams) {
this.connection = mysql.createConnection(connectionParams);
};
Database.prototype.connect = function connect() {
return new Promise((resolve, reject) => {
this.connection.connect((err) => {
if (err) reject(err);
resolve();
});
});
};
Database.prototype.query = function query(sql) {
return new Promise((resolve, reject) => {
this.connection.query(sql, (err, results, field) => {
if (err) reject(err);
resolve(results);
});
});
};
Database.prototype.close = function close() {
return new Promise((resolve, reject) => {
this.connection.close((err) => {
if (err) reject(err);
resolve('Connection closed');
});
});
};
module.exports = Database;
It works, but I am curious if the way I am doing this seems like a hack or not? Specifically the way I am calling the Promise.all with a map function as the argument. I didn't know how to make an array of connectionWrappers with their params without invoking them, hence the map function in Promise.all(). Any advice would be appreciated!

Categories