链接(或映射)包含单个数据数组的任务到任务数组

时间:2015-11-24 16:34:28

标签: javascript functional-programming monads folktale fantasyland

部分学习Fanatasy Land / Folk Tale引导我创建一些代码。我正在寻找我的网络(通过someLib)并将结果上传到mongo存储库。扫描返回一个结果数组,而upsert进入mongo需要独立处理结果(猫鼬 - 这是我第一次使用这个lib,所以我可能会在那里弄错)。在传统的承诺基础模型中,我会

// step 0: setup
const someLibPomise = makePromiseOf(someLib)

//set 1: get data
const dataArray = yield someLibPomise()

//set 2: convert to array of promises to upsert
const promiseArray = _.map(dataArray, makeUpsertPromise)

//step 3: wait on results
const upsertResults = yield promiseArray

就其本身而言,这是一个非常干净的表现形式,但我希望能够理解这些功能性技术。我的工作版本有点不尽如人意,因为我似乎无法从someLibTask函数返回的Task获取,该函数包含一个对象数组,表示各个upserts的Tasks数组。我觉得必须有一个更好的方法是什么工作:

// step 0: setup
const someLibTask = Async.liftNode(someLib)

const cleanUpData = (dataArray) => {
   return _.map(dataArray, (data) => { 
         // cleanup data object
         return data 
   })
}

const upsertTask = (collection) => {
    return (criteria, record) => {

        return new Task( (reject, resolve) => {
            const callback =  (error, data) => {
                if (error)  reject(error)
                else        resolve(data)
            }

            collection.findOneAndUpdate(criteria, record, 
                 {upsert: true}, callback)
        })

    }
}

const persist = (data) => {
    mongoose.connect('mongodb://localhost/db');
    const someUpsert = adapt.upsertTask(Some.collection)

    const tasks = _.map(data, (record) => {
        const criteria = { "id": record.id }
        return serverUpsert(criteria, record)
    })

    return Async.parallel(tasks).fork(console.error, process.exit)
}

// step 1: make a query and return an array of objects
// () => Task(object[]) 
const dataTask = someLibTask().map(cleanUpData)

// step 2: for the results to error log or persist method
// (d) => (), (d) => ()
dataTask.fork(console.error, persist)

理想情况下,我可以将dataTask中的结果链接(或映射)为persist,后者将该单个任务转换为upsert任务数组。然后我可以等待。我很想看到类似的东西:

// step 1: make a query and return an array of objects
const dataTask = someLibTask().map(cleanUpData)

// step 2: chain the results into upsert
const upsertTasks = dataTask.chain(persist)

//step 3: wait on the upsert tasks, and then log results
Async.parallel(upsertTasks).fork(console.error, process.exit)

2 个答案:

答案 0 :(得分:1)

  

从一个包含一个对象数组的任务到一个任务数组

这是不可能的。你不能离开Task monad。要知道您将在该数组中获得多少任务,您需要先运行初始任务。

你想要的似乎是

someLibTask().map(cleanUpData).chain(persist)

返回所有upserts结果的另一个Task。

答案 1 :(得分:0)

欢迎有关如何进一步清理此事的建议。也许删除lodash地图,支持更惯用的东西,也可以将最终的persisAllTask​​.fork写得更好?

设置:

const someLibTask = Async.liftNode(someLib)

// cleanUpData :: [{}] => [{}]
const cleanUpData = (dataArray) => {
   return _.map(dataArray, (data) => { 
         // cleanup data object
         return data 
   })
}

// upsertTask :: {} => ( {}, {} => Task {} )
const upsertTask = (collection) => {
    return (criteria, record) => {

        return new Task( (reject, resolve) => {
            const callback =  (error, data) => {
                if (error)  reject(error)
                else        resolve(data)
            }

            collection.findOneAndUpdate(criteria, record, 
                 {upsert: true}, callback)
        })

    }
}

 // persist :: [{id :: string, ...}] => [Task {id :: string, ...}]
const persist = (data) => {
    mongoose.connect('mongodb://localhost/db');
    const someUpsert = upsertTask(Some.collection)

    const performUpsert = (serverRecord) => {
        const criteria = { "id": record.id }
        return serverUpsert(criteria, serverRecord)
    }

    return _.map(data, performUpsert)

}

// noop :: _ => unit
const noop = () => {}

// [Task] => unit
const waitOnThenExit = (waitingOn) => {
    Async.parallel(waitingOn).fork(console.error, logThenExit)
}

过程:

// {} => Task [{id :: string, ...}]
const dataTask = someLibTask({}).map(cleanUpData)

// Task [{id :: string, ...}] => Task [Task {id :: string, ...}]
const persistAllTask = dataTask.map(persist)

persistAllTask.fork(
    noop,
    waitOnThenExit)