UNPKG

seneca-promisified-core

Version:
270 lines (249 loc) 6.07 kB
/* jshint esversion: 6 */ const Promise = require('any-promise'); const completesPromise = (resolve, reject) => { return (err, res) => { if(err) return reject(err); resolve(res); }; }; /** * Automatically patched on the SenecaPromisified instance. * @memberof SenecaPromisified.prototype * @param {Object} args - Is the args object to pass to the next handler * * @example * seneca.add({ foo: 'bar' }, (args) => { * return { response: 1 }; * }); * seneca.add({ foo: 'bar' }, (args, seneca) => { * return seneca.prior(args).then(({ response }) => { * return { * response: response + 1 * }; * }); * }); * * seneca.act({ foo: 'bar' }).then(console.log); // => `{ response: 2 }` */ const prior = function(args) { const seneca = this._seneca; return new Promise((resolve, reject) => { seneca.prior(args, completesPromise(resolve, reject)); }); }; /** * Meant to wrap the global seneca instance. * * @class SenecaPromisified */ class SenecaPromisified { constructor(seneca) { Object.defineProperties(this, { _seneca: { value: seneca }, log: { value: seneca.log } }); } /** * Calls a seneca handler. * * @public * @returns {Promise} * @example * // These all do the same thing... * seneca.act('foo:true,bar:false').then(console.log); * seneca.act({ foo: true, bar: false }).then(console.log); * seneca.act('foo:true', { bar: false }).then(console.log); */ act(...args) { return new Promise((resolve, reject) => { this._seneca.act.apply( this._seneca, args.concat(completesPromise(resolve, reject)) ); }); } /** * This is only there to allow classes which inherit from this one to * override what the methods return. If you extend this class you should * override this method to return a new instance of this one for the * internals to work properly. * * @public * @param {Object} seneca - Is the callback-base seneca instance. * @returns {SenecaPromisified} */ create(seneca) { return new SenecaPromisified(seneca); } /** * @private */ _handleResult(res, done) { if(typeof res.then === 'function') { res.then(done.bind(null, null), done); } else if(res instanceof Error) { done(err); } else { done(null, res); } } /** * Adds a handler to the internal seneca instance. * * @public * @example * this.add({ cmd: 'foobar' }, function(args) { * return Promise.resolve('FOOBAR'); * }); */ add(pat, ...rest) { const handler = rest.length > 1 ? rest[1] : rest[0]; const handleResult = this._handleResult; const create = this.create; const wrappedHandler = function(args, done) { const seneca = this; const wrapped = create(seneca); wrapped.prior = prior; const res = handler.call(wrapped, args, wrapped); handleResult(res, done); }; if(rest.length > 1) { this._seneca.add(pat, rest[0], wrappedHandler); } else { this._seneca.add(pat, wrappedHandler); } } /** * @public * @returns {Undefined} * @example * seneca.use((seneca) => { * seneca.add({ cmd: 'ping' }, (args, seneca) => { * return seneca.act({ cmd: '' }); * }); * }); * * Or: * seneca.use(function() { * this.add({ cmd: 'pong' }, function(args) { * return this.act({ cmd: 'ping' }); * }); * }); */ use(...args) { // For now call the regular context... if(typeof args[0] === 'string') { return this._seneca.use.apply(this._seneca, args); } const plugin = typeof args[0] === 'string' ? args[1] : args[0]; const create = this.create; const loader = function() { const seneca = this; const wrapped = create(seneca); plugin.call(wrapped, wrapped); }; if(args.length > 1) { this._seneca.use(args[0], loader); } else { this._seneca.use(loader); } } /** * Returns a new seneca object which will automatically add the given * properties to the object you send. * * @public * @param {Object} opts - The properties to automatically add. * @returns {SenecaPromisified} * @example * const delegated = seneca.delegate({ safe: false }); * // The object submitted will also have the `safe` property. * delegated.act({ cmd: 'ping' }); */ delegate(opts) { const del = this._seneca.delegate(opts); return this.create(del); } /** * Closes the connection established by `listen`. * * @public * @returns {Promise} */ close() { return new Promise((resolve, reject) => { this._seneca.close((err) => err ? reject(err) : resolve()); }); } /** * Similar to delegate. * * @public * @returns {Object} * * @example * seneca.add({ cmd: 'save', entity: 'person' }, (args) => { * return { saved: true }; * }); * seneca.add({ cmd: 'load', entity: 'person' }, (args) => { * return { loaded: true }; * }); * * const pin = seneca.pin({ cmd: '*', entity: 'person' }); * * pin.load({}).then(console.log); // => `{ loaded: true }` * pin.save({}).then(console.log); // => `{ saved: true }` */ pin(pat) { const pinned = this._seneca.pin(pat); return Object.keys(pinned).reduce((accu, key) => { accu[key] = (args) => { return new Promise((resolve, reject) => { pinned[key](args, completesPromise(resolve, reject)); }); }; return accu; }, {}); } /** * Opens a connection. * @public * @returns {Undefined} */ listen(opts) { this._seneca.listen(opts); } /** * Returns a promise which will be resolved when seneca is loaded. * @public * @returns {Promise} */ ready() { return new Promise((resolve, reject) => { this._seneca.ready((err) => err ? reject(err) : resolve()); }); } /** * Modifies the prototype to add new methods. * * @public * @static * @param {Function} fn - Side effecting function which changes the * prototype. */ static use(fn) { return fn(SenecaPromisified.prototype); } /** * Just an alternate way to instantiate the class... * @static */ static create(seneca) { return new SenecaPromisified(seneca); } } module.exports = SenecaPromisified;