HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptMinor

Refactoring node.js database code

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
refactoringnodedatabasecode

Problem

I have a user model.

It basically forwards get/create/delete requests into my database client.

The problem I have is the error handling, it screams not DRY to me, but I can't find an elegant way to clean it up.

var UserModel = pd.make(Model, {
    get: function _get(id, cb) {
        // nano is a database client
        this.nano.get(id, 
            // whitelist runs every error through the white list,
            // if it fails (false) throw it
            // if it succeeds (true) pass it to cb
            // if the return value is undefined it does nothing
            error.whitelist(function _errors(err) {
                // getaddrinfo is a random DNS error I have to swallow
                // no clue where the bug comes from, trying again is the easy fix
                if (err.syscall === 'getaddrinfo') {
                    UserModel.get(id, cb);
                } else if (err.error === "not_found") {
                    return true;
                } else {
                    return false;
                }
            }, cb)
        );
    },
    insert: function _create(json, cb) {
        this.nano.insert(json, json._id, 
            error.whitelist(function _errors(err) {
                if (err.syscall === 'getaddrinfo') {
                    UserModel.insert(json, cb);
                } else if (err.error === "conflict") {
                    return true;
                } else {
                    return false;
                }
            }, cb)
        );
    },
    delete: function _delete(name, cb) {
        var that = this;
        this.get(name, function _getRev(err, body) {
            that.nano.destroy(name, body._rev, 
                error.whitelist(function _errors(err) {
                    if (err.syscall === 'getaddrinfo') {
                        UserModel.delete(name, cb);
                    } else {
                        return false;
                    }
                }, cb)
            );
        });
    }
});

Solution

Based on feedback from JavaScript chat. Credit to @Zirak and @Chris

You want a hash of white listed error messages for each method

var whitelistMap = {
    "get": ["not_found"],
    "insert": ["conflict"],
    "delete": []
}


You want a whitelist error handler factory. This will include the "getaddrinfo" code for every method which is basically a try again short cutting.

It will check whether the error message is in the whitelistMap for that method and if so will let that error through.

otherwise it simply throws

function makeWhitelistCallback(method, thing, cb) {
    return error.whitelist(function _errors(err) {
        if (err.syscall === "getaddrinfo") {
            UserModel[method](thing, cb);
        } else if (whitelistMap[method].indexOf(err.error) !== -1) {
            return true;
        } else {
            return false;
        }
    }, cb);
}


And the rest of the code simply calls the whitelist callback factory

var UserModel = pd.make(Model,{
    get: function _get(id, cb) {
        this.nano.get(id, 
            makeWhitelistCallback("get", id, cb)
        );
    },
    insert: function _create(json, cb) {
        this.nano.insert(json, json._id, 
            makeWhitelistCallback("insert", json, cb)
        );
    },
    delete: function _delete(name, cb) {
        var that = this;
        this.get(name, function _getRev(err, body) {
            that.nano.destroy(name, body._rev, 
                makeWhitelistCallback("delete", name, cb)
            );
        });
    }
});

Code Snippets

var whitelistMap = {
    "get": ["not_found"],
    "insert": ["conflict"],
    "delete": []
}
function makeWhitelistCallback(method, thing, cb) {
    return error.whitelist(function _errors(err) {
        if (err.syscall === "getaddrinfo") {
            UserModel[method](thing, cb);
        } else if (whitelistMap[method].indexOf(err.error) !== -1) {
            return true;
        } else {
            return false;
        }
    }, cb);
}
var UserModel = pd.make(Model,{
    get: function _get(id, cb) {
        this.nano.get(id, 
            makeWhitelistCallback("get", id, cb)
        );
    },
    insert: function _create(json, cb) {
        this.nano.insert(json, json._id, 
            makeWhitelistCallback("insert", json, cb)
        );
    },
    delete: function _delete(name, cb) {
        var that = this;
        this.get(name, function _getRev(err, body) {
            that.nano.destroy(name, body._rev, 
                makeWhitelistCallback("delete", name, cb)
            );
        });
    }
});

Context

StackExchange Code Review Q#6127, answer score: 2

Revisions (0)

No revisions yet.