3
\$\begingroup\$

I have a use case where I need to run multiple tasks in series. Each task is required to perform some database operations. In my code step_1, step_2 and step_3 are these task which get executed in series (Async Waterfall)

Following is my code

const config = require('config.json');
var mysql = require('mysql');
var async = require("async");

const pool = mysql.createPool({
  host: config.database.dbhost,
  user: config.database.dbuser,
  password: config.database.dbpassword,
  database: config.database.dbname
});

exports.handler = (event, context, callback) => {
    
    pool.getConnection((err, connection) => {
    if (err) throw new Error("Unable to get connection " + JSON.stringify(err));
    
      async.waterfall([
            step_1,
            step_2,
            step_3
        ], function (err, result) {
            if(err){                
                throw new Error("something went south : "+ JSON.stringify(err));
            }else{
                connection.release();
                callback(null, "SUCCESS: " + JSON.stringify(result));
            }           
        });

        function step_1(cb){
            connection.query("step 1 query", function (error, response) {
                      if (error){
                        cb(null,error,null);
                      }
                      let id=result.insertId;
                      cb(null,null,id);
            });
        }

        function step_2(error,id,cb){
            if(error){
                cb(null,error);
            }else{
                connection.query("step 2 query",,function (err,result){
                        if (err){
                          connection.query("error logging query",
                          function(er,result){
                            if (er) cb(null,er,null);                    
                          });
                          cb(null,err,null);
                        }
                    cb(null,null, id, result);
                });
            }
        }

        function step_3(error, id,result,cb){
            if(error){
                cb(error,null);
            }else{
                connection.query("step 3 query",function(err,result){
                    if (err) cb(err,null);                  
                    cb(null,result);
                });
            }
        }

    });
};

Although I have used a library to avoid nesting callbacks within callbacks, it still feels like bit callback-ish. Is there a better way to achieve my use case? Anything I can improve in my code, any suggestions please.

I have only included relevant parts of code, kindly let me know if any additional information is required.

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

A couple of helper functions will aid in flattening your callback chain:

function getConnection() {
  return new Promise((res, rej) => {
    pool.getConnection(function (err, connection) {
      if (err) {
        rej(err);
      } else {
        res(connection);
      }
    });
  });
}

function query(connection, sql, params) {
  return new Promise((res, rej) => {
    connection.query(sql, params, function (err, rows) {
      if (err) {
        rej(err);
      } else {
        res(rows);
      }
    });
  });
}

Then you can do something like:

async function step_1(connection) {
  const rows = await query(connection, 'step 1 query');
  return rows.insertId;
}

function step_2(connection, id) {
  return query(connection, 'step 2 query', id);
}

function step_3(connection, id, result) {
  return query(connection, 'step 3 query', id, result);
}

exports.handler = async (event) => {
  const connection = await getConnection();
  try {
    const id = await step_1(connection);
    const rows = await step_2(connection, id);
    const result = await step_3(connection, id, rows);
    return JSON.stringify(result);
  } finally {
    connection.release();
  }
};
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Welcome to Code Review, answers that merely provide an alternate solution with no explanation or justification do not constitute valid Code Review answers and may be deleted. To avoid this possibility you can check how to answer. \$\endgroup\$ Jun 22, 2020 at 10:01
  • \$\begingroup\$ Thank you for your time. returning promises and using them with await is quite useful +1 for that. \$\endgroup\$
    – Dakait
    Jun 22, 2020 at 22:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.