Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Database call in a function without callback with Node.js and Postgresql

I'm trying out the framework node.js on one of my projects. I'm really seeing some good advantages on what they called "event-driven, non-blocking I/O model" however if my project there are some moments where I don't necessarily want to have some asynchronous calls and to be able to several operation before launching some asynchronous call.

Especially when I want to do some factorization and create some functions.

Typically I have the following case: I know that in several part of my program I have to check if a media is existing in my database for a given string or id.

So as a guy who tried to stay organize I want to create a function that I will call each time I need to check this. However, I did not find the way to do that with node.js and pg (the npm PostgreSQL library (https://github.com/brianc/node-postgres/) . Indeed, there is always a callback in the function and the return is null because of the callback. Here is an example below

/*
    Function which is supposed to check if a media existing
 */
function is_media_existing (url_or_id){
    log.debug("is_media_existing : begin of the function", {"Parameter" : url_or_id});
    pg.connect(connectionstring, function (err, client, done) {
        if (err) {
            log.warning("is_media_existing : Problem with Database connection", {
                "Parameter": url_or_id,
                "Error": err
            });
        }
        if (isNaN(url_or_id)) {
            // Case is parameter is not a number (string)
            var query = client.query('SELECT COUNT(*) as count FROM media WHERE url = $1::string ', url_or_id);
            query.on('error', function (error) {
                log.warning("is_media_existing : Problem with Database query (connection to db passed but not query " +
                    "", {"Parameter": url_or_id, "Error": error});
            });
            return query;
        } else {
            // Case is parameter is a int
            log.debug("is_media_existing : Type of Parameter is a string");
            // Case is parameter is not a number (string)
            var query = client.query('SELECT COUNT(*) as count FROM media WHERE id = $1::id ', url_or_id);
            query.on('error', function (error) {
                log.warning("is_media_existing : Problem with Database query (connection to db passed but not query " +
                    "", {"Parameter": url_or_id, "Error": error});
            });
            return query;
        }
    });
}


// Executing the function 
var test = is_media_existing("http://random_url_existing_in_db");
// test is always null as the return is in a callback and the callback is asynchronous 

i have the feeling my question is touching the core concepts of node.js, and perhaps my approach is wrong and I apologize in advance. I know it's not good to wait for a response before doing something. But what's the alternative? How can I factorize my code into functions when I need some functionalities in several part of my code?

So if there would be anyone who could explain how to do that with a best practice of programming it would be great.

Thanks

Anselme

like image 497
Anselme Avatar asked Apr 17 '26 18:04

Anselme


1 Answers

As Cody says, you probably dont want to do synchronous function.

The way you should handle the situation in your example is to pass in your own callback like this

function is_media_existing (url_or_id, callback){

and then instead of return query; use your callback like this-

callback(query);

or probably better to follow the node convention for callback functions to have two parameters (err, result) so your callback would look like this

callback(null, query);

Here is a rework of your sample

function is_media_existing (url_or_id, callback){       /* callback(err, result) */
    log.debug("is_media_existing : begin of the function", {"Parameter" : url_or_id});
    pg.connect(connectionstring, function (err, client, done) {
        if (err) {
            done(err);
            log.warning("is_media_existing : Problem with Database connection", {
                "Parameter": url_or_id,
                "Error": err
            });
            return callback(err, null);     
                /* note that this return is simply used to exit the connect's callback and the return value is typically 
                 * not used it is the call to callback() that returns the error value */
        } 
        var qrystr;

        if (isNaN(url_or_id)) {
            log.debug("is_media_existing : Type of Parameter is a string");
            qrystr = 'SELECT COUNT(*) as count FROM media WHERE url = $1::string;';
        } else {
            qrystr = 'SELECT COUNT(*) as count FROM media WHERE id = $1::id;';
        }
        client.query(qrystr, [url_or_id], function(err, result){
            done();
            if(err){
                /* .. */
            }
            callback(err, result);
        });
    });
}


// Executing the function 
var test = is_media_existing("http://random_url_existing_in_db", function(err, result){
    if(err){

    }else {

    }
});

If you end up with a hard nest of callbacks, promises are really worth looking into.

like image 173
Dave Pile Avatar answered Apr 20 '26 07:04

Dave Pile



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!