here we have are trying to make a lot of calls in a functional way with javascript, the problem is that we end up with Reader.of(Task.of(Reader.of(Task.of))), so we need to map(map(map(map))) the values that we need to operate.
The computation needs to go to a DynamoDB table, get a specific property, then go again to DynamoDB and get another property, after that go to facebook api to get a collection, finally store that info in a table in Dynamo. So each of this calls use an AWS javascript plugin and the facebook Graph plugin in node. So we need to pass AWS dependency on run, and then we need to fork, then pass again AWS and fork again, then pass FBGraph on run and fork again, this is kind of tedious if you are building a computation.
Anyway here is the code:
require('pointfree-fantasy').expose(global)
import Reader from 'fantasy-readers'
import Task from 'data.task'
import _ from 'ramda'
const log = x => {console.log(x); return x}
const ReaderTask = Reader.ReaderT(Task)
// scan :: string -> [a]
const scan = x => Reader.ask.map(env => env.aws.scanAsync({tableName: x}))
// batchGetItems :: [a] -> [b]
const batchGetItem = x => Reader.ask.map(env => env.aws.batchGetItemAsync(x))
// batchWriteItem :: [a] -> [b]
const batchWriteItem = x => Reader.ask.map(env => env.aws.batchWriteItemAsync(x))
// scanCampaigns :: null -> [a]
const scanCampaigns = () => scan('CampaignStats')
const FBBatchGetItem = x => Reader.ask.map(env => env.fb.batchAsync(x))
const getCampaigns = compose(scanCampaigns, Reader.of)
const groupUsers = _.groupBy(x => x.user_fbid)
const batchGetAccessToken = chain(batchGetItem, ReaderTask.of)
const getCampaignsInsights = chain(FBBatchGetItem, ReaderTask.of)
const saveInsights = chain(batchWriteItem, ReaderTask.of)
const updateCampaignStats = chain(batchWriteItem, ReaderTask.of)
const taskOfEvery = (Task, num) => compose(map(Task.of),_.splitEvery(num))
const runTaskWithFn = (fn, task) => fn(task.fork(err => 'err', x => x))
const filterActive = _.filter(x => x.active === 'true')
const getItems = x => x.Items
const groupAndFilter = compose(groupUsers, filterActive, getItems)
// filterByLastFetch :: ([a], string) => [a]
const filterByLastFetch = (x, y) => x.filter(x => x.last_fetch < y)
export {getCampaigns, batchGetAccessToken, getCampaignsInsights, saveInsights,
groupUsers,filterByLastFetch, updateCampaignStats, taskOfEvery,
runTaskWithFn, filterActive, groupAndFilter,
getItems}
The objective is to pass the AWS plugin and FBGraph plugin only once to the computation, an build an elegant composition like:
const computation = compose(saveIntoDynamo3, fetchFromFacebook,fetchFromDynamo2,fetchFromDynamo)
and then:
computation().run({aws: AWSService, FB: FBGraph})