What I want to accomplish:
What I got:
I`m working with Node and mysql. To insert the relations I have to wait for the artists to insert or create. I try to accomplish with the following code:
let promises = [];
if (artists.length != 0) {
for (key in artists) {
promises.push( find_artist_id_or_create_new_artist(artists[key]) )
}
}
await Promise.all(promises);
Returning an id:
async function find_artist_id_or_create_new_artist(artist_name) {
return await find_artist_return_id(artist_name, create_artist_return_id)
}
Finding an artist:
async function find_artist_return_id(artist_name, callback) {
var sql = "SELECT * FROM `artists` WHERE `name` LIKE "+con.escape(artist_name)+" LIMIT 1;"
con.query(sql, (err,row) => {
if(err) throw err;
if (row.length == 0) {
return callback(artist_name)
} else {
return row[0].id
}
});
}
Creating an artist
async function create_artist_return_id(artist_name) {
var sql = "INSERT INTO `artists` (`id`, `name`, `meta_1`, `meta_2`) VALUES (NULL, "+con.escape(artist_name)+", NULL, NULL)";
con.query(sql, (err, result) => {
if(err) throw err;
return result.insertId
});
}
I understand that I cant return in a con.query function, but I dont how to properly setup the code to get this done. A link to, or help how to search for an answer is appreciated.
No. It is not safe to resolve/reject promise multiple times. It is basically a bug, that is hard to catch, becasue it can be not always reproducible.
In this approach, we will use Promise. all() method which takes all promises in a single array as its input. As a result, this method executes all the promises in itself and returns a new single promise in which the values of all the other promises are combined together.
So, to run all these APIs in parallel, we can use Promise. all() like so. As you can tell, now we're running all the three APIs in parallel through Promise. all() through a single await .
allSettled(promises) is a helper function that runs promises in parallel and aggregates the settled statuses (either fulfilled or rejected) into a result array.
Your fundamental SQL functions
need to be converted to promises
in order to be awaited
.
See Async Function
, Promise
and Array.prototype.map()
for more info.
// Artist Ids.
const artistIds = await Promise.all(artists.map(async (artist) => await findArtist(artist) || await createArtist(artist)))
// Find Artist.
const findArtist = artist => new Promise((resolve, reject) => con.query(`SELECT * FROM \`artists\` WHERE \`name\` LIKE ${con.escape(artist)} LIMIT 1;`, async (error, row) => {
if(error) return reject(error)
if (!row.length) return resolve(await createArtist(artist))
return resolve(row[0].id)
}))
// Create Artist.
const createArtist = artist => new Promise((resolve, reject) => con.query(`INSERT INTO \`artists\` (\`id\`, \`name\`, \`meta_1\`, \`meta_2\`) VALUES (NULL, ${con.escape(artist)}, NULL, NULL)`, (error, result) => {
if (error) return reject(error)
return resolve(result.insertId)
}))
You just need to wrap the mysql callbacks into promises:
function find_artist_return_id(artist_name) {
return new Promise((resolve, reject) => {
var sql = "SELECT * FROM `artists` WHERE `name` LIKE "+con.escape(artist_name)+" LIMIT 1;"
con.query(sql, (err,row) => {
if(err) return reject(err);
if (row.length == 0) {
return resolve(artist_name);
return resolve(row[0].id);
});
});
}
And by the way, this is very ugly:
if (artists.length != 0) {
for (key in artists) {
Just do:
for(const artist of artists)
promises.push(someApiCall(artist));
or:
const promises = artists.map(someApiCall);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With