Async

One situation for me is enriching table data from an external source, that is perhaps a network call away.

Making all those calls in sequence can be slow...

But it we call the addColumn method on an already materialised collection... we can get async behaviour. The strategy below works, but is naive... useful for a quick and dirty

import io.github.quafadas.table.*
import scala.concurrent._  
import scala.concurrent.duration._  
import ExecutionContext.Implicits.global 

val data = CSV.fromString("id\n1\n2\n3").toSeq
// data: Seq[NamedTuple[Tuple1["id"], *:[String, EmptyTuple]]] = List(
//   Tuple1(_1 = "1"),
//   Tuple1(_1 = "2"),
//   Tuple1(_1 = "3")
// )

def slowNetworkFetch(id: String) = {
    blocking {
      Thread.sleep(1000)
      s"The Answer $id"
    }
}

println(
data
  .addColumn["answer", Future[String]](
    row => 
      Future(slowNetworkFetch(row.id))
  )
  .mapColumn["answer", String](Await.result(_, Duration.Inf))
  .consoleFormatNt(fansi = false)
)
// | |id|      answer|
// +-+--+------------+
// |0| 1|The Answer 1|
// |1| 2|The Answer 2|
// |2| 3|The Answer 3|
// +-+--+------------+

If we want something more "idiomatic" in terms of Future handling, we can drop down into our knowledge of stdlib, traverse, map, zip and join...

val d2 = data
  .addColumn["answer_tmp", Future[String]](
    row => 
      Future(slowNetworkFetch(row.id))
  )
// d2: Seq[NamedTuple[*:["id", *:["answer_tmp", EmptyTuple]], *:[String, *:[Future[String], EmptyTuple]]]] = List(
//   ("1", Future(Success(The Answer 1))),
//   ("2", Future(Success(The Answer 2))),
//   ("3", Future(Success(The Answer 3)))
// )

val resolved = Await.result(Future.traverse(d2.column["answer_tmp"])(identity), Duration.Inf)
// resolved: Seq[String] = List("The Answer 1", "The Answer 2", "The Answer 3")

println(
d2.zip(resolved).map{ (row, res) => 
  row ++ (answer = res)
}
.dropColumn["answer_tmp"]
.consoleFormatNt(fansi = false)
)
// | |id|      answer|
// +-+--+------------+
// |0| 1|The Answer 1|
// |1| 2|The Answer 2|
// |2| 3|The Answer 3|
// +-+--+------------+