I'm quite new to node (for more than a toy project) and I'm struggling to get my head around how to use Sequelize correctly. It has a promise-driven API, with 'error' and 'success' methods consistently used on the promises it returns.
I have written a custom finder that involves three queries to find a record, do an atomic update, and if that succeeds, reload the record afresh.
I've written this initially using the easy to understand callback approach, but because this doesn't have a contract that matches the one Sequelize uses, I want to rewrite it to return a Promise with success/error methods. Any pointers? It looks like Sequelize has taken Bluebird and customized it, but I'm not sure if there's an intended way for developers to tap into that functionality themselves.
/**
* Acquire a build in the 'queued' state and transition it to 'pending'.
*
* @return {Promise}
* a promise for the executed query
*/
Build.acquireQueued = function(callback) {
Build
.find({where: {status:'queued'}})
.success(function(build){
if (!build)
return callback();
Build
.update(
{status:'pending'},
{id:build.id, status:build.status},
{returning:true}
)
.success(function(result){
var affectedRows = result[0];
if (affectedRows == 0)
return callback();
build.reload().success(function(build){
callback(undefined, build);
});
})
.error(callback);
})
.error(callback);
};
I currently have to call this as follows:
Build.acquireQueued(function(err, build){
// maybe got a build
});
But because that does not look like Sequelize, I want to be able to call it like this:
Build
.acquireQueued()
.success(function(build){
// definitely got a build
})
.error(function(err){
// splosion!
});
As is always the case, I figured it out soon after posting the question. You need to use Sequelize.Utils.CustomEventEmitter. You give it a function that accept an EventEmitter, then you call emitter.emit('success', things) when you're done.
/**
* Acquire a job in the 'queued' state and mark it 'pending'.
*
* @return {Promise}
* a promise for the executed query
*/
Build.acquireQueued = function() {
return new db.CustomEventEmitter(function(emitter){
Build
.find({where: {status:'queued'}})
.success(function(build){
if (!build)
return emitter.emit('success');
Build
.update(
{status:'pending'},
{id:build.id, status:build.status},
{returning:true}
)
.success(function(result){
var affectedRows = result[0];
if (affectedRows == 0)
return emitter.emit('success');
// Final return value
build.reload().proxy(emitter);
})
})
})
.run();
};