2

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);
                }
            });

        }

    })

}

1 Answer 1

2

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.

Turns out that sql.connect() and sql.close() will return Promises if no callback is passed. This makes the code much simpler to write.

Node.js code

const tables = {

    table_name_1: {
        "key1": "nvarchar(25)",
        "key2": "int"
    },
    table_name_2: {
        "key1": "int",
        "key2": "nvarchar(50)",
    },
    table_name_3: {
        "key1": "int",
        "key2": "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 sql.connect(SQL_CONFIG);
    for (var i = 0; i < tables_to_delete.length; i++) {
        var query = "DROP TABLE IF EXISTS " + tables_to_delete[i];
        await runQuery(query);
    }
    await sql.close();
}

async function create_table(tables_to_create) {
    await sql.connect(SQL_CONFIG);
    
    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);
    }
    await sql.close();
}

function runQuery(query) {
     console.log("runQuery: Running query: " + query);
     var request = new sql.Request();
     return request.query(query);
}

Demonstration Snippet

/* Mock code */
const SQL_CONFIG = "Some config"
const sql = { 
   connect(config) {
       return new Promise(resolve => setTimeout(resolve, 1000));
   },
   close() { 
       return new Promise(resolve => setTimeout(resolve, 1000));
   }
}

class Request {
    query(query) {
        return new Promise(resolve => setTimeout(resolve, 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 sql.connect(SQL_CONFIG);
    for (var i = 0; i < tables_to_delete.length; i++) {
        var query = "DROP TABLE " + tables_to_delete[i];
        await runQuery(query);
    }
    await sql.close();
}

async function create_table(tables_to_create) {
    await sql.connect(SQL_CONFIG);
    
    for (var i = 0; i < tables_to_create.length; i++) {
        let lastQuery = i === tables_to_create.length -1;

        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);
    }
    await sql.close();
}

function runQuery(query) {
     console.log("runQuery: Running query: " + query)
     var request = new sql.Request();
     return request.query(query)
}

Sign up to request clarification or add additional context in comments.

5 Comments

I am sorry but I have absolute no idea how your mocked code comes together with my problem. I am sure the problem is on my site, but why are you doing timeouts and where are your menitioned promises? I also assumed that "promise and await" is the way to go, but I did't get a solution working. Could you extend your answer, so that I see what needs to be changed?
Sure, yes, apologies if the answer is unclear. I will update to indicate the node.js code!
thank you so much. Now I clearly understand what you did with the timeouts and what you meant with mockup. Sorry for my stubbornness and thank you very much for your answer. Works like a charm!!
I only added this to the query line, to get rid of problems, if the requestet table isnt available. try { await runQuery(query); } catch (e) { //Just accept it }
Glad to help ! Yes, you might need to look a little at failure modes / error handling

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.