Felipe
Felipe

Reputation: 7563

How to use `flatMap` and `map` to fill a `list` on Play framework + Scala?

I am struggling to use flatMap and map with Play framework + Scala. This method has a bunch of other issues, but I am trying to go through them one for each time. The first thing that I cannot figure out how to implement is how to fill a Seq inside nested flatMap and map and return a Json output. Here is my method:

  def getRacks(at: String) = Action.async { implicit request: Request[AnyContent] =>

    var rackSeq: Seq[Rack] = Seq.empty
    var gpuSeq: Seq[Gpu] = Seq.empty

    rackRepository.get(Util.toTime(at)).flatMap { resultRack: Seq[RackRow] =>
      resultRack.map { r: RackRow =>
        gpuRepository.getByRack(r.id).map { result: Seq[GpuRow] =>
          result.map { gpuRow: GpuRow =>
            gpuSeq = gpuSeq :+ Gpu(gpuRow.id, gpuRow.rackId, gpuRow.produced, Util.toDate(gpuRow.installedAt))
            println(gpuRow)
          }
        }
        val rack = Rack(r.id, r.produced, Util.toDate(r.currentHour), gpuSeq)
        rackSeq = rackSeq :+ rack
      }
      println("rackSeq: " + rackSeq)
      Future.successful(Ok(Json.toJson(rackSeq)).as(JSON))
    }.recover {
      case pe: ParseException => BadRequest(Json.toJson("Error on parse String to time."))
      case e: Exception => BadRequest(Json.toJson("Error to get racks."))
      case _ => BadRequest(Json.toJson("Unknow error to get racks."))
    }
  }

I was expecting that rackSeq will be filled with GpuRow. but my output is like this:

rackSeq: List(Rack(rack-1,0.2,2018-01-23T14:15:00.79Z,List()))
GpuRow(rack-1-gpu-0,rack-1,0.2,1515867048515)

How to evaluate both lists to the output?

Upvotes: 0

Views: 298

Answers (1)

Jeffrey Chung
Jeffrey Chung

Reputation: 19517

Instead of mutating variables, stay within the context of a Future and perform transformations until you reach the desired result. Assuming the following types...

rackRepository.get(Util.toTime(at)) // Future[Seq[RackRow]]
gpuRepository.getByRack(r.id)       // Future[Seq[GpuRow]]

...you could do this instead:

def gpuRowToGpu(gpuRow: GpuRow): Gpu = {
  Gpu(gpuRow.id, gpuRow.rackId, gpuRow.produced, Util.toDate(gpuRow.installedAt))
}

def getRacks(at: String) = Action.async { implicit request: Request[AnyContent] =>

  rackRepository.get(Util.toTime(at)).flatMap { resultRack: Seq[RackRow] =>
    val seqFutRack: Seq[Future[Rack]] = resultRack.map { r: RackRow =>
      gpuRepository.getByRack(r.id).map { result: Seq[GpuRow] =>
        val gpus = result.map(gpuRowToGpu) // Seq[Gpu]
        Rack(r.id, r.produced, Util.toDate(r.currentHour), gpus)
      } // Future[Rack]
    }
    val futSeqRack: Future[Seq[Rack]] = Future.sequence(seqFutRack)
    futSeqRack.map(racks => Ok(Json.toJson(racks)).as(JSON))
  }.recover {
    ...
  }
}

Upvotes: 3

Related Questions