Search code examples
node.jsloopbackjsstrongloop

Promisfy loopback models


In unit testing Loopback it is necessary to use callbacks with the upsert methods. So for example ... instead of writing something along the lines of this:

before(function () {

    Student = server.models.Student
    Course = server.models.Course


    Course.upsert({id: 1, key: 'A', department: 'Original department'})
    Student.upsert({id: 1, points: 5000})


})

it is necessary to ensure that callbacks are used with the upsert. Since I have a lot of models I am initializing below I use async:

before(function (done) {

    Student = server.models.Student
    Course = server.models.Course


    async.waterfall([
            function (callback) {
                Course.upsert({id: 1, key: 'A', department: 'Original department'}, callback)
            },
            function (f, callback) {
                Student.upsert({id: 1, points: 5000}, callback)
            },

        ],
        function (err, results) {
            done(err)
        })

})

Instead of async, how would the code above be changed to use Promises?

My thought is that with promises, I would be able to write some code that looks like this:

before(function (done) {

    Student = server.models.Student
    Course = server.models.Course


    Course.upsert({id: 1, key: 'A', department: 'Original department'})
      .then(Student.upsert({id: 1, points: 5000})
      .then(function(err) { done(err) } 


})

but I have been unsuccessful tying into promises.

EDIT from answers below ...

 before(function (done) {


    Course = server.models.Course

    Course.upsertWithPromise = Promise.promisify(Course.upsert)

    Course.upsertWithPromise({id: 1, key: 'A', department: 'Original department'})
        .then(done)

  } 




it.only('Course upsert', function (done) {

    Course.findById(1, function (err, course) {

        expect(course.id).to.equal(1)
        expect(course.department).to.equal('Original department')

        done()


    })
})

Solution

  • There are two possible solutions. First is manual promisification. Your functions will look like this:

    server.models.Student.upsert = function(data) {  // Note NO CALLBACK
      return new Promise(function(resolve, reject) {
        // Here can do all async staff and when done sucessfully call:
        resolve(result);
        // OR on error call:
        reject(err);
      });
    }
    

    Second solution will be use library for the same purpose.

    1. var q = require('q'); // Use q library
    2. DO NOT modify your models. They must take callback as last argument (follow node convention)
    3. var server.models.Student.upsertWithPromice = q.denodeify(server.models.Student.upsert);
    4. profit.

    Then your code from your example should work fine.