lune-climate / ts-results-es

A TypeScript implementation of Rust's Result and Option.
MIT License
93 stars 8 forks source link

How do you manage processing of AsyncResult array #145

Open savrielynck opened 2 months ago

savrielynck commented 2 months ago

Hey currently using the library quite extensively in an express app and it makes the data flow really easy to reason about. Right now though I think it can either improve my code, or contribute to the library for some piece of code that seems to be recurring and need some inspiration from you folks

Here is the use-case

  const arrayData: AsyncResult<Array> = getDataAsyncResult();

  arrayData.andThen(async (array) =>
    Result.all(
      await Promise.all(
        array.map((p) => {
          return p.andThen((refinedData) => processDataAsyncResult(refinedData)).promise;
        }),
      ),
    ),
  );

Most of Right now I need to translate from AsyncResult to Result most of the time in order to aggregate all of the AsyncResult into a single result (Which I can then do an toAsyncResult() if necessary)

The idea would be to have a method on AsyncResult.aggregate which would be able to process the array received and return an AsyncResult or a Result (The same way Result.all does).

What do you think? Or am I using the library in a weird way?

jstasiak commented 2 months ago

Hey @savrielynck,

this is definitely a pain point with the async support we have so far. You're not doing anything weird as far as I can see, it's just that there's no good API for this right now.

I've already wanted to add an async equivalents of

If you want to contribute any of the above it'll be much appreciated.

As far as the public API is concerned I imagine it will look something like (probably needs to be slightly more sophisticated, just off the top of my head):


class AsyncResult {
    static all<T, E>(
        results: Iterable<Result<T, E> | AsyncResult<T, E> | Promise<Result<T, E>>>
    ): AsyncResult<T[], E>
}
savrielynck commented 2 months ago

Gotcha, gives me re-assurance I'm indeed facing a weird pattern which isn't driven by me :D I'll try to give it a shot. I assume the implementations wouldn't be to different from something like this:

    return new AsyncResult(
      Promise.all(promises).then((results) => {
        const values: T[] = [];

        for (const result of results) {
          if (result.isError()) {
             return Err(...);
          } else {
            values.push(result.unwrap());
          }
        }
        return Ok(values);
      })

Just for my own understanding of what you mean by Iterable, since I'm not a JavaScript expert in any means.

jstasiak commented 2 months ago

So it's all about what promises is:

But you know what, maybe I'm overthinking it. Implement it with an array, we can iterate on that when/if needed.