avenger
avenger copied to clipboard
add "Alternative" operator into query DSL
Imagine a scenario where you have 2 different queries, and those queryies take 2 different times to resolve. A real world scenario would be having the same query which one fetches from a local storage, and one fetches from a REST api.
Those 2 queries have the same signature (userId: string) => User
, and I would love to compose them so that if the first one is pending or returned an error, the result of the second one is returned.
Something along the lines of:
const userQuery = alternative(userFromRestQuery, userFromLocalStorageQuery)
and the behaviour of alternative would be the same as https://github.com/devex-web-frontend/remote-data-ts/blob/master/src/remote-data.ts#L408
Thanks again for the great library!
The use case makes sense to me, and I think adding an alternative
operator would be pretty straightforward 👍 (EDIT: pushed a quick POC here: https://github.com/buildo/avenger/commit/5e74a82cd920b21e65c6322ce07c176bcc562ad7)
As a side note, adding new operators would be an even simpler process if Query
was encoded as an fp-ts data-type with all the implemented instances. As of now, we conceptually have Monad
, but the encoding is custom since we want:
- to have query inputs aggregated as products, and errors as sums, while fp-ts has them both fixed (see e.g. the related discussion in https://github.com/gcanti/fp-ts/issues/904#issuecomment-510433571)
- on top of 1, there are a few additional overloads to make usage simpler when declaring product queries from the UI: https://github.com/buildo/avenger/blob/master/src/util.ts#L32
Query
could otherwise just be a plain ReaderTaskEither
, and compose
would just be chain
, product
->sequenceS
, and we could easily add an Alternative
instance
I would love to compose them so that if the first one is pending or returned an error, the result of the second one is returned
Actually re-reading this better, this is not what I'd expect by using alt/orElse
from Alternative
: it would fallback on the second only in case of failure, not also while "loading"
Uhm, yeah that makes sense too! I'm my usecase example that means you'll need to put the localStorage as first, and rest as second, which makes sense
instances for Alternatives
could also be used to simulate a local state. If a locally updated value is present it is used, else the remotely fetched one is returned. This could be a very interesting feature :)