1

I have a function that makes a database query, then needs to return the result.

The query is to a mysql database, using Node.js, the result is then returned to an Inquirer (NPM module) prompt.

If this was a front end issue, I would use the built in promises of jquery: (example). $.ajax.done(). However the mysql NPM package doesn't have built in promises for the query() method.

// OPTION 1, wait for query to complete before returning choicesArray (this example returns an empty array)

choices() {
  let choicesArray = [];
  connection.query(`SELECT * FROM products`, (err, res)=>{
    for (item of res) {
      choicesArray.push(`${item.product} | ${item.price}`);
    };
  });
  // wait here for query to complete
  return choicesArray;
}



// OPTION 2, change the syntax to take advantage of the query callback, something more like below (this example does not return the choicesArray all the way to the enclosing function)

choices() {
  connection.query(`SELECT * FROM products`, (err, res)=>{
    let choicesArray = [];
    for (item of res) {
      choicesArray.push(`${item.product} | ${item.price}`);
    };
    return choicesArray;
  });
} // (node:3877) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: You must provide a `choices` parameter
Gerard
  • 768
  • 5
  • 20
  • You should probably use a promise or callback (or async if you're using node). – Andy Dec 02 '17 at 21:27
  • @Quentin provided a good resource for front end ajax calls: https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call. I think this issue is sufficiently different to merit specific answers. Will you unmark this as a duplicate? – Gerard Dec 02 '17 at 21:52
  • This not being a front-end ajax call doesn't matter. It's an asynchronous call, and the solutions are the same. – Quentin Dec 02 '17 at 22:00

1 Answers1

1

You can't return a value from an async function like that. The function returns before your async values are ready. You either need to use a callback like:

function choices(cb) {
    let choicesArray = [];
    connection.query(`SELECT * FROM products`, (err, res)=>{
    if (err) {
        cb(err)
        return
    }
    for (item of res) {
        choicesArray.push(`${item.product} | ${item.price}`);
    };
    });
    // wait here for query to complete
    cb(null, choicesArray);
}

choices((err, value) =>{
    if (err) {
        // handle error
    } 
    // use value here
})

Or return a promise like:

function choices() {
    return new Promise((resolve, reject) => {
        connection.query(`SELECT * FROM products`, (err, res)=>{        
            if (err) return reject(err)
            let choicesArray = [];            
            for (item of res) {
                choicesArray.push(`${item.product} | ${item.price}`);
            }
            resolve(choicesArray)
        });

    })
}

choices()
.then(value => {
    // use value here
})
.catch(err =>{
    // handle error
})
Mark
  • 90,562
  • 7
  • 108
  • 148