Search code examples
f#tasksaturn-framework

How to convert a sequence of Task<MyType> to a sequence of MyType


So I currently have a sequence of type seq<System.Threading.Tasks.Task<Restaurant>> and I want to turn it into a sequence of type seq<Restaurant>.

I'm currently using TaskBuilder.fs library and from my research, I need to use either let! or do! for this situation but they require task {} which when used with Seq.map bring back the same Task type.

let joinWithReviews (r : Restaurant) =
    task {
        let! reviewResult = Reviews.Database.getByLocationId cnf.connectionString r.Restaurant_Id
        match reviewResult with
        | Ok reviewResult ->
            let restaurant = { r with Reviews = (List.ofSeq reviewResult)}
            return restaurant
        | Error ex ->
            return raise ex
    }

let indexAction (ctx : HttpContext) =
    task {
        let (cnf:Config) = Controller.getConfig ctx
        let! result = Restaurants.Database.getAll cnf.connectionString
        match result with
        | Ok result ->
            let restaurantWithReviews = (Seq.map joinWithReviews result)
            return index ctx (List.ofSeq restaurantWithReviews)
        | Error ex ->
            return raise ex
    }

So my result is of type Seq<Restaurant> and I need to add reviews to each restaurant so I use Seq.map to get restaurantWithReviews which is type seq<System.Threading.Tasks.Task<Restaurant>> which I won't be able to use.


Solution

  • The .NET method System.Threading.Tasks.Task.WhenAll will convert seq<Task<'a>> to Task<'a[]>. You can get the result with let! if you're inside a task { } block.

    let restaurants: seq<Restaurant>
    
    let! withReviews: Restaurant[] =
        restaurants
        |> Seq.map joinWithReviews
        |> Task.WhenAll