nodejs sqlite3 db.run as a bluebird promise

2019-07-17 22:33发布

问题:

I'm attempting to use sqlite3 in a express app. Basically, I get a rest request, based on the rest request, I query an external REST request. Between the response from the external request & the data passed in from the original REST request, I then do an update or insert into one of my sqlite3 tables.

The problem I'm running into, is that in db.run(sqlStatement, paramArray, function(err)), the function(err) is a callback where err is either an error, or a nil. In addition to that, IF the err param is null, then the this reference contains 2 properties, one of which tells me the number of rows modified by the statement. (https://github.com/mapbox/node-sqlite3/wiki/API#databaserunsql-param--callback for reference)

Thing is, I run bluebird's promisifyAll on the sqlite3 module, and then use the resultant

db.runAsync(sqlStatement, paramArray).then(err) {
    console.log(this) //results in a null
}

So I'm unable to actually figure out whether anything was updated.

My entire section of code looks a little like this:

function handleRequest(req, res) {

    //this returns the response as the first object
    request.getAsync('http://www.example.com', reqObj)         
        .then(prepareDbObjects) //prepares an array of objects to update the DB with
        .then(attemptUpdate)
        .then(function(rowsUpdated) {
            res.json(rowsUpdated)
        }
}

function attemptUpdate(updateObjs) {
    var promiseMap = Promise.map(updateObjs, function(singleObj) {
        return updateOrInsertObj(singleObj)
    }
    return promiseMap
}


function updateOrInsertObj(singleObj) {
    return db.runAsync(sqlStatement, singleObj)
        .then(function(err) {
            if(err) {
                //handle error
            } else {
                console.log("this should be an object with 2 properties", this)
                //but instead it is null
            }
        }
}

回答1:

I went looking in the node-sqlite3 code, and I'm pretty sure the way it returns this in the successful callback function, rather than as an actual param, is the problem. Which means even attempting to use bluebird's multiArgs=true parameter didn't work since there wasn't a proper return value.

So I attempted to wrap the db.run function in my own custom promise method, and that seemed to do the trick.

Specifically, I did:

function runCustomAsync(sql, params) {
    return new Promise(function(resolve, reject) {
        db.run(sql, params, function cb(err) {
            if(err) {
                var responseObj = {
                    'error': err
                }
                reject(responseObj);
            } else {
                var responseObj = {
                    'statement': this
                }
                resolve(responseObj);
            }
        });
    });
}

db.runCustomAsync = runCustomAsync;
module.exports = db;

It IS a little different from how it's normally handled. I'm now returning an object that may contain either the this object, or it might contain the err object.

In my original request, I now do

db.runCustomAsync(sqlStatement, params)
    .then(function(dbResponseObj) {
        if(dbResponseObj.error) {
            //handle error
        } else {
            //do stuff with dbResponseObj.statement
        }
    })