Async iterators with fp-ts and mongo db

639 Views Asked by At

With mongodb in node we can use async iterators. Basic example:

const documents: Record<string, any>[] = [];
let cursor = db.collection('randomcollection').find();

for await (let doc of cursor) {
  documents.push(document);
}

How does async iterators translate to functional programming, using fp-ts? Is it possible to express the for loop above in fp-ts? I have searched, but found no documentation regarding async iterators.

  const whereIamRightNow = pipe(
    TE.bindTo('db')(createMongoClientWithEncryption),
    TE.bind('cursor', ({ db }) => TE.of(getQueryCursor(dateRange)(db.client))),

    // how to async iterate over query cursor and call a processing function for each record?
  );
1

There are 1 best solutions below

2
Souperman On

My suggestion for how to write this with fp-ts change a little bit depending on the exact desired flow, but if you want to collect up all the awaited values of a collection of Promises I think you could do something like:

import { pipe } from 'fp-ts/lib/function';
// Task is the `fp-ts` way of tracking asynchronous work
import * as T from 'fp-ts/lib/Task';

const documents: T.Task<readonly any[]> = pipe(
  // For simplicity let's assume the db's find method returns a Task[]
  db.collection('randomcollection').find(),
  T.sequenceArray
);

sequenceArray is similar to awaiting all items in the array with Promise.all before adding them to documents.

I don't believe there's any better way in vanilla fp-ts. A comment indicated additional libraries which likely have better support specifically for iterators, but I wanted to introduce Task which is the fp-ts monad for asynchronous work. Once you have defined an entire Task you call it like a function and it transforms the value into a Promise.

const docs = await documents();