// This demo supports flowing together async and non async methods
// If nothing is async, it *stays sync*
// also handles arrays of promises (e.g. from _.map) and objects of promises (e.g. from _.mapValues)
// does NOT handle promises for keys
let _ = require('lodash/fp')
let Promise = require('bluebird')
let promisedProps =
Promise.props ||
(async x => _.zipObject(_.keys(x), await Promise.all(_.values(x))))
let isPromiseArray = _.overEvery([_.some('then'), _.isArray])
let isPromiseObject = _.overEvery([_.some('then'), _.isPlainObject])
// calls then conditionally, allowing flow to be used synchronously, too
let callOnAsync = (value, f) => (value.then ? value.then(f) : f(value))
let asyncCall = (prop, f) => {
if (_.some('then', prop)) {
if (_.isArray(prop)) return Promise.all(prop).then(f)
if (_.isPlainObject(prop)) return promisedProps(prop).then(f)
}
if (prop.then) return prop.then(f)
return f(prop)
}
let flowWith = call => (fn0, ...fns) => (...x) => [...fns, x => x].reduce(call, fn0(...x))
let flowAsync = flowWith(asyncCall)
let slowDouble = async x => {
await Promise.delay(10)
return x * 2
}
let testMidAsync = flowAsync(_.get('a'), slowDouble, x => x * 3)
console.log(await testMidAsync({ a: 4 }))
let testSync = flowAsync(_.get('a'), x => x + 2)
console.log(testSync({ a: 1 }))
let testArrayAsync = flowAsync(_.map(slowDouble), _.map(x => x * 2))
console.log(await testArrayAsync([1, 2]))
// let testAsyncObj = flowAsync(_.mapValues(slowDouble), _.mapKeys(slowDouble))
// console.log(await testAsyncObj({ a:1 }))