influentialpublishers/jigawatt

View on GitHub
index.js

Summary

Maintainability
A
0 mins
Test Coverage

const debug       = require('debug')('jigawatt');
const { inspect } = require('util');

const _         = require('ramda');
const Bluebird  = require('bluebird');
const awesomize = require('./lib/awesomize');
const Validate  = require('./lib/validate');

const defaultSpec = _.always(_.compose(Bluebird.resolve, _.prop('data')))


const awesomizeSpec = _.curry((req, spec) => awesomize(req, spec))


const getSpec = _.curry((current, req) => _.compose(
  _.ifElse(_.is(Function), awesomizeSpec(req), defaultSpec)
, _.prop('awesomize')
)(current));


const getIO = _.propOr((req, data) => data, 'io');


const getTransform = _.propOr((req, data) => data, 'transform');


const mergeDataIntoReq = (req) => _.compose(_.merge(req), _.objOf('data'));


const mergeIOData = (middleware, req) => _.compose(
  Bluebird.props
, _.merge(_.propOr({}, 'data', req))
, getIO(middleware).bind(middleware, req)
);


const mergeReqArray = (initial_req) => _.reduce((acc, x) => {
  acc.data = _.merge(acc.data, x.data)
  return acc;
}, initial_req);


const runSingle = _.curry((current, req) => _.composeP(
  mergeDataIntoReq(req)
, getTransform(current).bind(current, req)
, mergeIOData(current, req)
, getSpec(current, req)
)(req));


const runParallel = _.curry((current, req) => _.composeP(
  mergeReqArray(req)
, _.compose(Bluebird.all, _.map((x) => runSingle(x, req)))
)(current));


const rethrowError = (e) => { throw e; };


const run = _.curry(([current, ...rest], req) => _.composeP(
  (res) => _.length(rest) ? run(rest, res) : res.data
, _.ifElse(
    _.always(Array.isArray(current))
  , runParallel(current)
  , runSingle(current)
))(req).catch(rethrowError));


const Middleware = (...middleware) => {
  Validate.testMiddleware(middleware)

  return (req, res, next) =>
    run(middleware, req)

    .then( res.json.bind(res) )
    
    .catch(next);

};


Middleware.csv = (...middleware) => {
  Validate.testMiddleware(middleware)

  return (req, res, next) =>
    run(middleware, req)

    .then((csv) => {

      res.set({
        'Content-Type'        : 'application/csv'
      , 'Content-Disposition' : 'attachment; filename=vetting.csv'
      , 'Pragma'              : 'no-cache'
      })

      res.send(csv)

    })

    .catch(next)

};


Middleware.debug = (label) => ({
  transform: (req, data) => {
    const data_as_string = inspect(data);
    debug(`${label}: ${data_as_string}`);

    return data;
  }
});


Middleware.tap = (fn) => ({
  transform: (req, data) => Bluebird.resolve(fn(req, data)).return(data)
});


Middleware.branch = (predicate, ifTrue, otherwise) => ({
  transform: (req, data) =>
    Bluebird.resolve(predicate(req, data))

    .then((branch) => run([ branch ? ifTrue : otherwise ], req))

});


Middleware.promisify = (...middleware) => (req) => run(middleware, req)


Middleware.pipe = (...middleware) => ({
  transform: (req) => run(middleware, req)
})


Middleware.pick = (keys) => ({ 
  transform: (req, data) => Bluebird.resolve( _.pick(keys, data)) 
}); 

module.exports = Middleware;