I’m running the alpha build with async/await. As I posted in some other thread, I don’t really find async/await as useful in ReScript as in JS. I’m still unsure why. Usually, I end up doing a series of promise then’s with flatmap to carry to the error quickly to the end or do some work.
That gives quite a bit of nested scopes. Sometimes it’s a problem, sometimes not. What I’m thinking is, couldn’t we combine the two to have the neatness of async/await and still the utility of Results?
I’m imagining something like this:
let db = flat Db.getConn()
let user = flat db->Db.User.findByEmail("some@email.com")
let config = flat db->Db.Config.findForUser(user)
switch config {
| Ok(cfg) => // ...
| Error(#COULD_NOT_CONNECT_TO_DB) => // would from let db = ... line
| Error(#NO_SUCH_USER) => // would from let user = ... line
| Error(_) => // ...
}
Where each op returns a Result and the flat keyword (whatever keyword is chosen) is basically an async Result.flatMap op. Is this a good idea? Is it a bad idea? What do you think?
Hi, I am new here and haven’t used async/await so far. But I was wondering if it is possible to chain these promises together
let config = await Db.getConn()
->then(async db => await Db.User.findByEmail("some@email.com"))
->then(async user => await db->Db.Config.findForUser(user))
switch config {
| Ok(cfg) => // ...
| Error(#COULD_NOT_CONNECT_TO_DB) => // would from let db = ... line
| Error(#NO_SUCH_USER) => // would from let user = ... line
| Error(_) => // ...
}
Although it could be rewritten similarly to your code (and also because the example code I gave was trivial), you do not have the db binding in the second closure in your code
->then(async user => await db->Db.Config.findForUser(user))
There is no db there, so it won’t compile. So you need to introduce nesting, which is what I’m trying to avoid.
Here’s an alternative way how to write your code. It uses exception, but since it’s not thrown outside, the code is pretty-much safe.
let main = {
exception Internal('a)
() => {
try {
let db = (await Db.getConn())->ResultX.fold(error => {
switch error {
| #OUT_OF_MEMORY => raise(Internal(#COULD_NOT_CONNECT_TO_DB))
}
})
let user = (await db->Db.User.findByEmail("some@email.com"))->OptionX.foldOrRaise(Internal(#NO_SUCH_USER))
let config = (await db->Db.Config.findForUser(user))->OptionX.foldOrRaise(Internal(#USER_WITHOUT_CONFIG))
config
} catch {
| Internal(#COULD_NOT_CONNECT_TO_DB) => // would from let db = ... line
| Internal(#NO_SUCH_USER) => // would from let user = ... line
| Internal(_) => // ...
}
}
}
let config = await Db.getConn()
->Belt.Result.flatMap(async db => await Db.User.findByEmail("some@email.com")->Belt.Result.Map(user => (db, user)))
->Belt.Result.flatMap(async (db, user) => await db->Db.Config.findForUser(user)))
switch config {
| Ok(cfg) => // ...
| Error(#COULD_NOT_CONNECT_TO_DB) => // would from let db = ... line
| Error(#NO_SUCH_USER) => // would from let user = ... line
| Error(_) => // ...
}