If each query returns a different type it’s nearly impossible to write a generic function for any scenario to combine all of the resulting data.
But if I understand correctly, your main goal is to have one single value describing your overall state of the queries (loading/done/error). If you don’t merge your resulting data together you could write a function which takes n query results and just returns the combined state. Handling the individual results would need to be done per request, since the query result is different for every query.
For example: ReScript Playground
type firestoreError
type queryResult<'documentdata> = (option<'documentdata>, bool, option<firestoreError>)
type overallState =
| Loading({loading: int, done: int, error: int, errors: array<firestoreError>})
| Done
| Error(array<firestoreError>)
type abstractQueryResult = (option<unknown>, bool, option<firestoreError>)
external toAbstractQueryResult: queryResult<'a> => abstractQueryResult = "%identity"
let overallState: array<abstractQueryResult> => overallState = queries => {
let (lc, dc, errs) = queries->RescriptCore.Array.reduce((0, 0, ([]: array<firestoreError>)), (
s,
q,
) => {
let (lc, dc, errs) = s
switch q {
| (_, true, _) => (lc + 1, dc, errs)
| (_, false, None) => (lc, dc + 1, errs)
| (_, _, Some(err)) =>
errs->RescriptCore.Array.push(err)
(lc, dc, errs)
}
})
if errs->RescriptCore.Array.length > 0 {
Error(errs)
} else if lc > 0 {
Loading({loading: lc, done: dc, error: errs->RescriptCore.Array.length, errors: errs})
} else {
Done
}
}
module ExampleUsage = {
module Q1 = {
type r = {name: string, age: int}
type t = queryResult<r>
let result: t = (Some({name: "me", age: 99}), false, None)
}
module Q2 = {
type r = {weight: int, color: string}
type t = queryResult<r>
let result: t = (None, true, None)
}
module CombinedState = {
let overallState =
[Q1.result->toAbstractQueryResult, Q2.result->toAbstractQueryResult]->overallState
}
Console.log(CombinedState.overallState)
}