Doing an sequential operation in Node.js

I built myself a helper-function with node.js to prepare a database, where I currently often do changes in the table structure. So I defined my database structure in an global object "tables" and built the tables using the mssql library via sql-queries. All in all it worked out fine so for. But I now added an process.exit(1) to the end of my init function, which showed me that the interpreter runs through the operations without waiting for sql-execution. How can I modify the code, that the interpreter will execute all steps correctly and quit the program afterwards?

const tables = {

    table_name_1: {
        "key1": "nvarchar(25)",
        "key2": "int",
        "..": "bit",
    },
    table_name_2: {
        "key1": "int",
        "key2": "nvarchar(50)",
        "..": "int",
    },
    table_name_3: {
        "key1": "int",
        "key2": "int",
        "..": "int",
    }
    
}

init_environment();

function init_environment() {

    console.log("Init started...");

    delete_table(Object.keys(tables));
    create_table(Object.keys(tables));

    console.log("Init finished");
    process.exit(1);
}

function delete_table(tables_to_delete) {

    sql.connect(SQL_CONFIG, function () {

        for (var i = 0; i < tables_to_delete.length; i++) {

            var request = new sql.Request();
            var query = "DROP TABLE " + tables_to_delete[i];

            request.query(query, function (err, recordset) {
                if (err) {
                    console.log(err);
                } 
            });

        }

    })

}

function create_table(tables_to_create) {

    sql.connect(SQL_CONFIG, function () {

        for (var i = 0; i < tables_to_create.length; i++) {

            var request = new sql.Request();

            var query = "CREATE TABLE " + tables_to_create[i] + " (id INT IDENTITY(1,1) PRIMARY KEY, ";

            for (var key in tables[tables_to_create[i]]) {
                query += key + " " + tables[tables_to_create[i]][key] + ", ";
            }

            query += ")";

            request.query(query, function (err, recordset) {
                if (err) {
                    console.log(err);
                }
            });

        }

    })

}

15 thoughts on “Doing an sequential operation in Node.js”

  1. You should be able to use async / await for this purpose. If your delete_table / create_table functions return a promise you can await the results of these functions.

    I’ve mocked out the sql functions (as well as process.exit()) for the purpose of demonstration. You can see that the queries will run in order, then the process will exit.

    Node.js code

    const tables = {
    
        table_name_1: {
            "key1": "nvarchar(25)",
            "key2": "int",
            "..": "bit",
        },
        table_name_2: {
            "key1": "int",
            "key2": "nvarchar(50)",
            "..": "int",
        },
        table_name_3: {
            "key1": "int",
            "key2": "int",
            "..": "int",
        }
        
    }
    
    init_environment();
    
    async function init_environment() {
    
        console.log("Init started...");
    
        await delete_table(Object.keys(tables));
        await create_table(Object.keys(tables));
    
        console.log("Init finished");
        process.exit(1);
    }
    
    async function delete_table(tables_to_delete) {
        await asyncConnect();
        for (var i = 0; i < tables_to_delete.length; i++) {
            var query = "DROP TABLE " + tables_to_delete[i];
            await runQuery(query);
        }
    }
    
    async function create_table(tables_to_create) {
        await asyncConnect();
        
        for (var i = 0; i < tables_to_create.length; i++) {
            var query = "CREATE TABLE " + tables_to_create[i] + " (id INT IDENTITY(1,1) PRIMARY KEY, ";
    
            for (var key in tables[tables_to_create[i]]) {
                query += key + " " + tables[tables_to_create[i]][key] + ", ";
            }
    
            query += ")";
            
            await runQuery(query);
        }
    }
    
    function asyncConnect() {
        return new Promise((resolve) => { 
            sql.connect(SQL_CONFIG, resolve);
        });
    }
    
    function runQuery(query) {
         console.log("runQuery: Running query: " + query)
         return new Promise((resolve, reject) => {
             var request = new sql.Request();
             request.query(query, function (err, recordset) {
                 if (err) {
                     console.log(err);
                     reject(err);
                 } else {
                     resolve();
                 }
             });
         })
    }
    

    Demonstration Snippet

    /* Mock code */
    const SQL_CONFIG = "Some config"
    const sql = { 
       connect(config, cb) {
           setTimeout(cb, 1000);
       }
    }
    
    class Request {
        query(query, cb) {
            setTimeout(cb, 500, null, {})
        }
    }
    
    sql.Request = Request;
    
    process = { 
        exit() {
            console.log("Exiting process...");
        }
    }
    
    /* End Mock code */
    
    const tables = {
    
        table_name_1: {
            "key1": "nvarchar(25)",
            "key2": "int",
            "..": "bit",
        },
        table_name_2: {
            "key1": "int",
            "key2": "nvarchar(50)",
            "..": "int",
        },
        table_name_3: {
            "key1": "int",
            "key2": "int",
            "..": "int",
        }
        
    }
    
    init_environment();
    
    async function init_environment() {
    
        console.log("Init started...");
    
        await delete_table(Object.keys(tables));
        await create_table(Object.keys(tables));
    
        console.log("Init finished");
        process.exit(1);
    }
    
    async function delete_table(tables_to_delete) {
        await asyncConnect();
        for (var i = 0; i < tables_to_delete.length; i++) {
            var query = "DROP TABLE " + tables_to_delete[i];
            await runQuery(query);
        }
    }
    
    async function create_table(tables_to_create) {
        await asyncConnect();
        
        for (var i = 0; i < tables_to_create.length; i++) {
            var query = "CREATE TABLE " + tables_to_create[i] + " (id INT IDENTITY(1,1) PRIMARY KEY, ";
    
            for (var key in tables[tables_to_create[i]]) {
                query += key + " " + tables[tables_to_create[i]][key] + ", ";
            }
    
            query += ")";
            
            await runQuery(query);
        }
    }
    
    function asyncConnect() {
        return new Promise((resolve) => { 
            sql.connect(SQL_CONFIG, resolve);
        });
    }
    
    function runQuery(query) {
         console.log("runQuery: Running query: " + query)
         return new Promise((resolve, reject) => {
             var request = new sql.Request();
             request.query(query, function (err, recordset) {
                 if (err) {
                     console.log(err);
                     reject(err);
                 } else {
                     resolve();
                 }
             });
         })
    }
    Reply

Leave a Comment