loading...

Discussion on: Code Challenge: Follow the Dirty Money

Collapse
tobias_salzmann profile image
Tobias Salzmann

Here's a Scala version, asynchronous, concurrent, non-blocking with async/await.
Using dispatch for requests and circe for json decoding.

import dispatch.Defaults._
import dispatch._
import io.circe.generic.auto._
import io.circe.parser._

import scala.async.Async.{async, await}
import scala.concurrent.Future

object TransactionTotal {
  val initialUrl = "https://gist.githubusercontent.com/jorinvo/6f68380dd07e5db3cf5fd48b2465bb04/raw/c02b1e0b45ecb2e54b36e4410d0631a66d474323/fd0d929f-966f-4d1a-89cd-feee5a1c5347.json"

  def futureTotal(url: String = initialUrl): Future[BigDecimal] =
      getAllTransactions(url)
          .map(totalAmount)

  private case class Transaction(id: String, content: String, links: List[String]) {
    def amount = {
      val pattern = ".*\\$([0-9\\.\\,]+[0-9]).*".r
      val pattern(value) = content
      BigDecimal(value.replaceAll(",", "."))
    }
  }

  private def getTransaction(requestUrl: String): Future[Transaction] = async {
    val json = await(Http.default(url(requestUrl) OK as.String))
    decode[Transaction](json).toTry.get
  }

  private def getAllTransactions(url: String): Future[List[Transaction]] = async {
    val transaction = await(getTransaction(url))
    val nestedTransactions = await(Future.sequence(transaction.links.map(getAllTransactions)))
    val transactions = nestedTransactions.flatten
    transaction :: transactions
  }

  private def totalAmount(transactions: List[Transaction]) = {
    transactions
      .distinct
      .map(_.amount)
      .sum
  }
}